@carllee1983/dbcli 1.39.1 → 1.41.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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/dbcli.mdc +38 -14
- package/.cursor/skills/dbcli/reference.md +307 -8
- package/.cursor-plugin/plugin.json +2 -1
- package/.github/skills/dbcli/SKILL.md +38 -14
- package/.github/skills/dbcli/reference.md +307 -8
- package/CHANGELOG.md +64 -1
- package/README.zh-TW.md +1 -1
- package/assets/SKILL.md +38 -14
- package/assets/SKILL.zh-TW.md +29 -9
- package/assets/reference.md +307 -8
- package/assets/tasks/diagnose-slow-query.md +8 -0
- package/assets/tasks/mongo-safe-backfill.md +56 -0
- package/assets/tasks/mongo-schema-drift-review.md +51 -0
- package/assets/tasks/orm-drift-review.md +55 -0
- package/dist/cli.mjs +10793 -6509
- package/dist/core.d.ts +3 -0
- package/dist/core.mjs +223 -64
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/dbcli-agent/.codex-plugin/plugin.json +1 -1
- package/plugins/dbcli-agent/INSTALL.md +19 -10
- package/plugins/dbcli-agent/skills/dbcli/SKILL.md +38 -14
- package/plugins/dbcli-agent/skills/dbcli/reference.md +307 -8
- package/skills/dbcli/SKILL.md +38 -14
- package/skills/dbcli/reference.md +307 -8
package/skills/dbcli/SKILL.md
CHANGED
|
@@ -18,7 +18,16 @@ the CLI package has not been installed globally.
|
|
|
18
18
|
|
|
19
19
|
1. `dbcli blacklist list` — confirm sensitive-data boundaries.
|
|
20
20
|
2. `dbcli schema <object> --format json` — confirm real column/field names. **Never guess.**
|
|
21
|
-
3. All writes: `--dry-run` (SQL/Mongo) → run → `query` read-back to confirm.
|
|
21
|
+
3. All writes: `--dry-run` (SQL/Mongo) → run → `query` read-back to confirm. Redis
|
|
22
|
+
`query` has **no `--dry-run`** (see **Redis**); Elasticsearch is **read-only**.
|
|
23
|
+
|
|
24
|
+
**`update` / `delete` `--where` is equality-only (SQL).** It accepts **only** `col=val` or
|
|
25
|
+
`col1=v1 AND col2=v2`. A comparison / pattern operator (`>`, `>=`, `<`, `!=`, `LIKE`, `IN`)
|
|
26
|
+
is a **parse error**; worse, `OR` is **silently swallowed into the value** — `a=1 OR b=2`
|
|
27
|
+
parses as `a = "1 OR b=2"` and matches the wrong rows (or none). For a range or compound
|
|
28
|
+
condition, first `query` / `export` the target rows' primary keys, then run one
|
|
29
|
+
`update` / `delete --where "id=<pk>"` per key — or escalate to a human. (MongoDB `--where`
|
|
30
|
+
takes a full JSON filter and is exempt.)
|
|
22
31
|
|
|
23
32
|
> `report` and `guide` already embed an `inspect` snapshot — you do **not** need to run
|
|
24
33
|
> `dbcli inspect` first. Run `dbcli inspect --for-agent` manually only when you want the
|
|
@@ -36,7 +45,7 @@ the CLI package has not been installed globally.
|
|
|
36
45
|
|
|
37
46
|
Slow-query diagnosis has three canonical paths (pick by what you already know):
|
|
38
47
|
|
|
39
|
-
- Known slow SQL → `skill tasks plan diagnose-slow-query --param query="<SQL>"` → `guide missing-index-for "<SQL>"`
|
|
48
|
+
- Known slow SQL → `skill tasks plan diagnose-slow-query --param query="<SQL>"` → `lint "<SQL>"` → `guide missing-index-for "<SQL>"`
|
|
40
49
|
- Known hot table → `skill tasks plan analyze-table-perf --param table=<table>`
|
|
41
50
|
- Whole-environment scan → `report --section perf` → `guide slow-query`
|
|
42
51
|
|
|
@@ -45,7 +54,7 @@ afterwards add only the `@diag/*` it does not cover (`missing-indexes`, `locks`,
|
|
|
45
54
|
`table-sizes`). Once you have a specific slow statement, `explain --analyze "<SQL>"` shows its plan.
|
|
46
55
|
|
|
47
56
|
**On failure:** pass `--recovery` to `query` / `q` / `insert` / `update` / `delete` /
|
|
48
|
-
`export` / `schema` / `inspect`. The command emits a `RecoveryEnvelope` to stdout and saves
|
|
57
|
+
`export` / `schema` / `inspect` / `lint` / `diff --against-orm`. The command emits a `RecoveryEnvelope` to stdout and saves
|
|
49
58
|
it to `.dbcli/last-recovery.json`; then `dbcli recover` inspects it and `dbcli recover --apply`
|
|
50
59
|
runs the saved plan under risk gating. Multi-turn `--next`, connection branching, and the
|
|
51
60
|
post-apply verify probe are documented in reference.md §Recovery Cookbook.
|
|
@@ -72,12 +81,16 @@ The plan is an ordered list of dbcli commands with rationale and risk labels. Ex
|
|
|
72
81
|
one at a time — task plans do **not** override blacklist, schema, dry-run, or confirmation
|
|
73
82
|
requirements.
|
|
74
83
|
|
|
75
|
-
Builtin packs: `diagnose-slow-query` (targets a specific SQL),
|
|
76
|
-
a specific table; `dbcli inspect` auto-suggests it for the
|
|
77
|
-
activity), `audit-permissions`, `safe-backfill`,
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
84
|
+
Builtin packs (SQL — postgres/mysql): `diagnose-slow-query` (targets a specific SQL),
|
|
85
|
+
`analyze-table-perf` (targets a specific table; `dbcli inspect` auto-suggests it for the
|
|
86
|
+
hottest table in recent audit activity), `audit-permissions`, `safe-backfill`,
|
|
87
|
+
`schema-drift-review`, `orm-drift-review` (ORM definition vs cached DB schema),
|
|
88
|
+
`connection-health`. Review/verify packs: `pr-database-review`,
|
|
89
|
+
`migration-review`, `safe-backfill-verify`, `slow-endpoint-investigation`. MongoDB packs:
|
|
90
|
+
`mongo-safe-backfill` (dry-run–previewed backfill), `mongo-schema-drift-review` (sampled
|
|
91
|
+
dot-path drift). All are read-only `plan-only` — pick the pack matching the situation, and
|
|
92
|
+
run any index/DDL proposal through `migration-review` before writing. Redis/Elasticsearch
|
|
93
|
+
have no packs yet — lead with `guide` / `report` there.
|
|
81
94
|
|
|
82
95
|
Tasks live under `assets/tasks/` (builtin), `.dbcli-shared/tasks/` (shared), and
|
|
83
96
|
`.dbcli/tasks/` (local override).
|
|
@@ -92,9 +105,9 @@ in **How to use dbcli** still applies.
|
|
|
92
105
|
| DB-backed feature | `blacklist list` → `schema <object>` → `queries suggest <intent>` |
|
|
93
106
|
| DB report / dashboard request | `blacklist list` → `queries search <keywords>` / `queries suggest <intent>` → `queries show @<name>` → `q @<name> --ui` or `--format html` |
|
|
94
107
|
| Application data bug | `audit tail --for-agent --n 10` → `blacklist list` → `schema <object>` → narrow query |
|
|
95
|
-
| ORM or migration work | `schema --format json` → `diff --
|
|
108
|
+
| ORM or migration work | `schema --format json` → `diff --against-orm <orm-schema>` → review error-level drift → proposals via `migrate` (dry-run) → `migration-review` task pack → `diff --against <snapshot>` after applying. |
|
|
96
109
|
| PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
|
|
97
|
-
| Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
|
|
110
|
+
| Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
|
|
98
111
|
| Safe data backfill | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back or snippet `--verify`. |
|
|
99
112
|
| Environment validation | `status --format json` → `doctor --format json` → `inspect --for-agent --no-connect`. |
|
|
100
113
|
|
|
@@ -112,9 +125,13 @@ dbcli q @<name> --param k=v --format html > report.html
|
|
|
112
125
|
dbcli export "<SQL>" --format html --output report.html
|
|
113
126
|
dbcli audit tail --for-agent --n 10
|
|
114
127
|
dbcli diff --snapshot <name>
|
|
128
|
+
dbcli diff --against-orm prisma/schema.prisma --format json
|
|
129
|
+
dbcli diff --against-orm "migrations/*.sql" --format markdown
|
|
130
|
+
dbcli skill tasks plan orm-drift-review --param orm_path=prisma/schema.prisma --format json
|
|
115
131
|
dbcli report --section perf --format json
|
|
116
132
|
dbcli skill tasks plan analyze-table-perf --param table=<table> --format json
|
|
117
133
|
dbcli guide missing-index-for "<query>" --format json
|
|
134
|
+
dbcli lint "<SQL>" --format json
|
|
118
135
|
dbcli update <object> --where "<bounded predicate>" --set '<json>' --dry-run --format json
|
|
119
136
|
dbcli inspect --for-agent --no-connect --format json
|
|
120
137
|
```
|
|
@@ -281,6 +298,7 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
|
|
|
281
298
|
| `schema` | query-only+ | SQL: per-table or full scan into `.dbcli/schemas/`. MongoDB: sampled. ES: flattened mapping. Redis: per-key only (type/TTL/size). Supports `--recovery`. |
|
|
282
299
|
| `query` | query-only+ | SQL, Mongo JSON (`--collection`), Redis command, or ES DSL/Lucene (`--collection`). `--format table\|json\|csv\|html`, `--ui` to open the interactive dashboard in a browser. Supports `--recovery`. |
|
|
283
300
|
| `explain` | query-only+ | **(v1.23)** Read-only query plan with annotations. SQL only. Single query, `@saved-query`, `@file.sql`, or `--bulk @glob/*`. `--analyze` (EXPLAIN ANALYZE / MariaDB ANALYZE SELECT), `--format markdown\|json\|table`. |
|
|
301
|
+
| `lint` | n/a | Static SQL anti-pattern advisor (no DB connection). 9 rules incl. schema-aware implicit-cast / NOT IN-nullable checks via the layered `.dbcli/schemas/` cache; global `--use <conn>` selects a named cache. Findings carry rewrite drafts + guarded `explain` verify commands (`--analyze` only for proven read-only SQL) — report-only, never executes. `--format text\|json\|markdown`, `--min-severity`, `--no-schema`, `--bulk`. Supports `--recovery`. |
|
|
284
302
|
| `plan` | n/a | Static SQL risk analyzer (`--format text\|json`); classifies a statement without connecting to the database. |
|
|
285
303
|
| `q` | query-only+ | Run a saved snippet by `@name` with `--param k=v`. Supports `--verify` to run assertions. |
|
|
286
304
|
| `queries` | n/a | Manage saved snippets: `list` / `show` / `search` / `suggest` / `new` / `edit` / `check` / `delete` / `rename` / `copy` / `import` / `export`. |
|
|
@@ -289,7 +307,7 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
|
|
|
289
307
|
| `export` | query-only+ | SQL, MongoDB, or **(v1.22)** Elasticsearch (DSL `--index` or whole-index scroll). Query → `--format json\|jsonl\|csv\|html` file or stdout. `html` emits a standalone interactive dashboard. Supports `--recovery`. |
|
|
290
308
|
| `blacklist` | n/a | `list` / `table` / `column` subcommands redact sensitive data from query results. |
|
|
291
309
|
| `check` | query-only+ | SQL only (best on MySQL/MariaDB). |
|
|
292
|
-
| `diff` | query-only+ | SQL only. Save/compare schema snapshots. |
|
|
310
|
+
| `diff` | query-only+ | SQL only. Save/compare schema snapshots. **(P1b)** `--against-orm <path>` compares a Prisma schema / DDL file / normalized JSON against the local schema cache (no DB connection): categorized drift (`missing_in_db` = error, `missing_in_orm` = warn, `mismatch` per tolerance table, `unmanaged`) with dry-run `migrate` proposals; exit 1 on error-level drift. `--orm-format prisma\|ddl\|json`, `--ignore <globs>`, `--format json\|table\|markdown`. |
|
|
293
311
|
| `snapshot` | query-only+ | **(v1.25)** SQL only. Capture a result fingerprint (`rowCount` + per-column null/distinct/min/max/sum + order-independent checksum). `--out` (default `.dbcli/snapshots/snap-<ts>.json`), `--rows`, `--stdout`, `--format`, `--no-limit`. Baseline for `assert --against`. |
|
|
294
312
|
| `assert` | query-only+ | **(v1.25)** SQL only. Verify an invariant; exit 1 on failure unless `--no-fail`. `--expect "rows>0\|value==X\|col:c not null\|unique\|between a and b\|>= n"`, `--vs <query> --compare rows\|value` (reconcile), `--against <snapshot> --tolerance <pct>`. |
|
|
295
313
|
| `verification` | n/a | Inspect and manage local verification artifacts. `list` / `show <id-or-path>` / `summary` are read-only; `prune` is dry-run by default and deletes only with `--execute --force`. Reads `<cwd>/.dbcli/verification/`; no DB connection, no audit writes. |
|
|
@@ -309,7 +327,7 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
|
|
|
309
327
|
|
|
310
328
|
`--use <name>` on any subcommand (including `status` / `doctor`) targets a v2 connection
|
|
311
329
|
without changing the default. `--recovery` is honoured by `query`, `q`, `insert`, `update`,
|
|
312
|
-
`delete`, `export`, `schema`, and `
|
|
330
|
+
`delete`, `export`, `schema`, `inspect`, `lint`, and `diff --against-orm` (see **On failure** above).
|
|
313
331
|
|
|
314
332
|
**Write & query flag semantics** (SQL/Mongo `insert`/`update`):
|
|
315
333
|
|
|
@@ -364,12 +382,18 @@ without changing the default. `--recovery` is honoured by `query`, `q`, `insert`
|
|
|
364
382
|
→ `data-admin`. A command not in the whitelist is refused.
|
|
365
383
|
- **No `--dry-run` for Redis `query`** — write safety comes from the permission gate and key
|
|
366
384
|
blacklist (matching reads/writes are rejected). To preview a delete, use `delete <key> --dry-run`.
|
|
367
|
-
- `database` is the logical DB index (default `0`). `dbcli blacklist add 'secrets:*'`
|
|
385
|
+
- `database` is the logical DB index (default `0`). `dbcli blacklist table add 'secrets:*'`
|
|
368
386
|
registers a key glob; an optional `redis.mask` block masks values on read. Size guards
|
|
369
387
|
(SCAN/HGETALL truncation, `--no-limit` to bypass) and masking details: reference.md Redis section.
|
|
370
388
|
|
|
371
389
|
## Elasticsearch
|
|
372
390
|
|
|
391
|
+
**dbcli is read-only against Elasticsearch — `insert` / `update` / `delete` are not supported.**
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
dbcli query '{"query":{"match":{"status":"active"}}}' --collection orders
|
|
395
|
+
```
|
|
396
|
+
|
|
373
397
|
- `query` takes a DSL (JSON body) or Lucene query string; `--collection <index>` is required.
|
|
374
398
|
- **Supported:** `init`, `list` (indices with doc count), `schema [index]` (flattened mapping),
|
|
375
399
|
`query`, `export` (v1.22), `shell` (v1.22), `status`, `use`, `doctor`. **Not supported:**
|
|
@@ -105,6 +105,7 @@ dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod
|
|
|
105
105
|
|
|
106
106
|
**Schema storage (v1.4+):** Schema is persisted as layered files under `.dbcli/schemas/`. With v2 multi-connection config each connection gets its own subdirectory (`.dbcli/schemas/<connection>/`). Run `dbcli schema --use <connection>` once per connection before querying it — otherwise `schema <table>` may return data from the wrong connection's cache.
|
|
107
107
|
|
|
108
|
+
> **PostgreSQL:** Introspection uses the exact `public` catalog identity throughout. Full catalog/schema/table joins prevent a reused constraint name from contaminating another table; enum lookup includes its namespace; composite primary-key order comes from the exact table OID and index ordinality; and row estimates are scoped to the exact `public` relation. Row-count SQL qualifies and quotes both `"public"` and the exact table identifier, escaping embedded quotes so mixed-case or punctuation-bearing names remain distinct and safe.
|
|
108
109
|
> **Redis:** `schema <key>` is required (no full scan). The output exposes `type`, `ttl`, `size`, and a small `sample` (e.g. first 5 hash keys). `--reset` / `--refresh` are rejected — Redis caches no schema.
|
|
109
110
|
> **Elasticsearch:** `schema [index]` flattens the `_mapping` properties (nested `a.b.c`) and emits each `.fields` multi-field as a separate column (e.g. `text` + `text.keyword`). Full scan iterates all non-system indices and stores per-connection caches alongside SQL engines.
|
|
110
111
|
> **MongoDB:** schema is sampled via `$sample` (default 100, max 1000). `--sample-method natural` switches to `find().limit()`; `random` (default) falls back to natural order on driver error. Output columns surface nested dot-paths with `presence` (0..1) and `redacted: true` flags for blacklist-matched paths. The persisted cache records `sampleMethod` and `sampleSize`; `dbcli doctor` reports them via a `sampled: method=…, size=…` line.
|
|
@@ -192,9 +193,134 @@ dbcli explain --bulk @analytics/* # glob over saved queries
|
|
|
192
193
|
| `nested-loop-large` | yellow | PG `Nested Loop` with planner rows > 10,000 |
|
|
193
194
|
|
|
194
195
|
> Notes:
|
|
195
|
-
> - `--analyze` executes the statement
|
|
196
|
+
> - `--analyze` executes the statement, so dbcli accepts it only for SQL that is
|
|
197
|
+
> structurally proven to be a read-only, function-free `SELECT` (including
|
|
198
|
+
> SELECT-only CTEs). Explicit function and table-function calls are unproven
|
|
199
|
+
> because user-defined and built-in functions may have side effects. DML, DDL,
|
|
200
|
+
> data-modifying CTEs, session assignments, function-bearing SQL, and
|
|
201
|
+
> unrecognized SQL are rejected before the adapter is invoked; use plain
|
|
202
|
+
> `dbcli explain` for those statements.
|
|
196
203
|
> - Auto-`LIMIT` is **not** applied to EXPLAIN statements (since v1.23 P1).
|
|
197
204
|
|
|
205
|
+
### lint
|
|
206
|
+
|
|
207
|
+
Static, report-only SQL anti-pattern analysis for PostgreSQL, MySQL, and
|
|
208
|
+
MariaDB. `lint` never opens a database connection, never runs the SQL, and
|
|
209
|
+
never applies a rewrite. Schema-aware findings use only the layered schema
|
|
210
|
+
cache under `.dbcli/schemas/`.
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
dbcli lint [queries...]
|
|
214
|
+
dbcli lint --bulk <input>
|
|
215
|
+
dbcli --use <conn> lint [queries...]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
An input may be inline SQL, a saved query such as `@analytics/live-summary`, a
|
|
219
|
+
SQL file such as `@queries.sql`, or a saved-query/filesystem glob such as
|
|
220
|
+
`@analytics/*` or `@queries/**/*.sql`. `--bulk` accepts a comma-separated mix
|
|
221
|
+
of those `@file`, `@glob`, and `@saved-query` inputs; quote a filesystem glob
|
|
222
|
+
in a shell so the `@` reference reaches dbcli unchanged.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
dbcli lint "SELECT * FROM users WHERE email LIKE '%@example.com'" --format json
|
|
226
|
+
dbcli lint --bulk '@queries/**/*.sql' --format markdown
|
|
227
|
+
dbcli --use staging lint @analytics/live-summary --min-severity warn
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
| Option | Default | Meaning |
|
|
231
|
+
|---|---|---|
|
|
232
|
+
| `--format <text\|json\|markdown>` | `text` | Render one report per resolved input. |
|
|
233
|
+
| `--min-severity <info\|warn\|error>` | `info` | Omit findings below the selected severity. |
|
|
234
|
+
| `--no-schema` | off | Skip schema-only checks without reading schema-cache paths; static `NOT IN` NULL checks still run. |
|
|
235
|
+
| `--bulk <input>` | none | Resolve a comma-separated list of `@file`, `@glob`, or `@saved-query` inputs. |
|
|
236
|
+
| `--recovery` | off | On command failure, emit and save a linked `RecoveryEnvelope`. |
|
|
237
|
+
| global `--use <conn>` | configured default | Select a v2 named connection and its isolated cache; place it before `lint`: `dbcli --use <conn> lint …`. |
|
|
238
|
+
|
|
239
|
+
**Rules:**
|
|
240
|
+
|
|
241
|
+
| Rule | Severity | What it reports |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `select-star` | warn | A top-level `SELECT *`; when one table and its cached columns are unambiguous, the finding may include a column-list rewrite draft. |
|
|
244
|
+
| `unanchored-like` | warn | A `LIKE` / `ILIKE` pattern beginning with `%`, which a conventional B-tree index cannot anchor. |
|
|
245
|
+
| `missing-limit-offset` | info | Deep pagination with `OFFSET >= 1000`; prefer keyset pagination. |
|
|
246
|
+
| `non-sargable-where` | warn | A function or arithmetic expression applied to the column side of a predicate. |
|
|
247
|
+
| `or-to-union` | info | A top-level `OR` across different columns that can complicate index selection; any UNION alternative must preserve identity and multiplicity. |
|
|
248
|
+
| `subquery-to-join` | info | `IN (SELECT …)` where an equivalent `EXISTS`, or a JOIN with proven uniqueness/deduplication, may plan better. |
|
|
249
|
+
| `distinct-groupby-abuse` | warn | Redundant `DISTINCT` when simple projected columns exactly cover the `GROUP BY` columns. |
|
|
250
|
+
| `implicit-cast` | warn | A schema-verified column/literal type mismatch that can disable index use; safe, unambiguous numeric drafts may be included. |
|
|
251
|
+
| `not-in-nullable` | warn | A right-hand `NOT IN` value that can be NULL: explicit `NULL`, outer-join null extension, a nullable subquery projection, or a known nullable CASE/cast/aggregate expression. A nullable left-hand column is not this rule. |
|
|
252
|
+
|
|
253
|
+
`implicit-cast` and the schema-enriched portion of `not-in-nullable` read the
|
|
254
|
+
selected cache through the schema loader abstraction. Static `not-in-nullable`
|
|
255
|
+
checks still run without it. All schema caches live beneath `.dbcli/schemas/`. A v2
|
|
256
|
+
configuration always uses `.dbcli/schemas/<resolved-connection>/`, including
|
|
257
|
+
the configured default. The root `.dbcli/schemas/` directory is only the
|
|
258
|
+
v1/legacy unnamed cache. Global `dbcli --use <conn> lint …` selects another
|
|
259
|
+
named v2 slot. The command never refreshes the cache and never falls back to
|
|
260
|
+
schema embedded in config.
|
|
261
|
+
|
|
262
|
+
Skipped rules are returned with machine-readable `blocked:` reasons:
|
|
263
|
+
|
|
264
|
+
- Invalid SQL blocks all nine rules with `blocked: parse failed` and includes
|
|
265
|
+
`parseError`.
|
|
266
|
+
- `--no-schema` blocks `implicit-cast` and the schema-dependent portion of
|
|
267
|
+
`not-in-nullable` with `blocked: --no-schema`; static RHS hazards still run.
|
|
268
|
+
- A missing layered cache records
|
|
269
|
+
`blocked: schema cache unavailable (run dbcli schema)` for those unavailable
|
|
270
|
+
schema checks while retaining static RHS findings.
|
|
271
|
+
|
|
272
|
+
Every finding includes its rule, severity, source span, message, and
|
|
273
|
+
`schemaVerified` state. Some findings also carry a confidence-labelled rewrite
|
|
274
|
+
draft and a shell-safe verification command. It uses
|
|
275
|
+
`dbcli explain --analyze` only when the statement is structurally proven read-only;
|
|
276
|
+
function-bearing and session-assignment statements are unproven, so lint
|
|
277
|
+
falls back to plain `dbcli explain`. These are suggestions only: `lint` neither
|
|
278
|
+
executes the verification command nor changes the query.
|
|
279
|
+
|
|
280
|
+
When schema identifiers collide after case folding, schema-aware findings and
|
|
281
|
+
rewrites are withheld. The SQL parser does not preserve reliable quote
|
|
282
|
+
provenance, so an exact-looking mixed-case AST identifier cannot disambiguate
|
|
283
|
+
that collision. CTE, derived, schema-qualified, and database-qualified
|
|
284
|
+
relations also never borrow facts from the unqualified cache.
|
|
285
|
+
|
|
286
|
+
For `not-in-nullable`, remove or filter right-hand NULL values. In a subquery,
|
|
287
|
+
filter the projected value with `IS NOT NULL`; `NOT EXISTS` may be a better
|
|
288
|
+
semantic form when appropriate. dbcli does not automatically rewrite this case
|
|
289
|
+
unless correlation, type classification, qualified-column resolution, and the
|
|
290
|
+
rewrite target are all unambiguous. A direct or `AND`-conjoined `IS NOT NULL`
|
|
291
|
+
filter on the exact projected expression suppresses the finding; aggregates
|
|
292
|
+
apply the same proof in `HAVING`. Filters under `OR` or ambiguous expression
|
|
293
|
+
matches do not. The rule recursively checks projection, JOIN `ON`, `WHERE`, and
|
|
294
|
+
`HAVING` expressions, using each nested SELECT/CTE/derived statement's own
|
|
295
|
+
scope. Qualified outer-join null extension remains detectable without a cache,
|
|
296
|
+
but a join's synthetic NULL row is not applied inside that join's own `ON`;
|
|
297
|
+
declared nullability and completed earlier joins still apply there.
|
|
298
|
+
|
|
299
|
+
Trimmed JSON example:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
[
|
|
303
|
+
{
|
|
304
|
+
"sql": "SELECT * FROM users",
|
|
305
|
+
"dialect": "postgresql",
|
|
306
|
+
"findings": [
|
|
307
|
+
{
|
|
308
|
+
"rule": "select-star",
|
|
309
|
+
"severity": "warn",
|
|
310
|
+
"message": "SELECT * fetches every column; list the columns you need.",
|
|
311
|
+
"span": { "start": 0, "end": 8 },
|
|
312
|
+
"schemaVerified": false
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
"skippedRules": [],
|
|
316
|
+
"relatedCommands": [
|
|
317
|
+
"dbcli guide missing-index-for \"SELECT * FROM users\"",
|
|
318
|
+
"dbcli explain --analyze \"SELECT * FROM users\""
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
]
|
|
322
|
+
```
|
|
323
|
+
|
|
198
324
|
### plan
|
|
199
325
|
|
|
200
326
|
Static SQL risk analyzer. Classifies a statement into the same permission tiers
|
|
@@ -249,6 +375,7 @@ dbcli q @analytics/revenue --param days=30 --format html > report.html
|
|
|
249
375
|
- `--dry-run` — print the bound SQL + values without executing
|
|
250
376
|
- `--use <name>` — pick a v2 named connection
|
|
251
377
|
- `--recovery` — emit a `RecoveryEnvelope` on failure (see `recover`)
|
|
378
|
+
- `--verify` — run the snippet's verification assertions after execution (only if the snippet defines them)
|
|
252
379
|
|
|
253
380
|
**Permission:** query-only+
|
|
254
381
|
|
|
@@ -474,9 +601,10 @@ Insert data into a table.
|
|
|
474
601
|
dbcli insert users --data '{"name":"Alice","email":"alice@example.com"}'
|
|
475
602
|
dbcli insert users --data '{"name":"Alice"}' --dry-run
|
|
476
603
|
dbcli insert users --data '{"name":"Alice"}' --force
|
|
604
|
+
dbcli insert users --data '{"name":"Alice"}' --plan --format json # risk analysis only; no DB connection
|
|
477
605
|
```
|
|
478
606
|
|
|
479
|
-
**Options:** `--data <json>`, `--dry-run`, `--force`
|
|
607
|
+
**Options:** `--data <json>`, `--dry-run`, `--force`, `--plan` (analyze risk without connecting or executing), `--format <text|json>` (`--plan` output), `--recovery`
|
|
480
608
|
**Permission:** read-write+
|
|
481
609
|
|
|
482
610
|
### update
|
|
@@ -486,11 +614,19 @@ Update existing data.
|
|
|
486
614
|
```bash
|
|
487
615
|
dbcli update users --where "id=1" --set '{"name":"Bob"}'
|
|
488
616
|
dbcli update users --where "id=1" --set '{"name":"Bob"}' --dry-run
|
|
617
|
+
dbcli update users --where "id=1" --set '{"name":"Bob"}' --plan --format json # risk analysis only; no DB connection
|
|
489
618
|
```
|
|
490
619
|
|
|
491
|
-
**Options:** `--where <condition>` (required), `--set <json>` (required), `--dry-run`, `--force`
|
|
620
|
+
**Options:** `--where <condition>` (required), `--set <json>` (required), `--dry-run`, `--force`, `--plan` (analyze risk without connecting or executing), `--format <text|json>` (`--plan` output), `--recovery`
|
|
492
621
|
**Permission:** read-write+
|
|
493
622
|
|
|
623
|
+
> **`--where` grammar (SQL `update` / `delete`)** — equality only: `col=val` or
|
|
624
|
+
> `col1=v1 AND col2=v2`. Comparison / pattern operators (`>`, `>=`, `<`, `!=`, `LIKE`, `IN`)
|
|
625
|
+
> raise a parse error, and `OR` is **silently folded into the value** (`a=1 OR b=2` parses as
|
|
626
|
+
> `a = "1 OR b=2"`, matching nothing intended). For ranges or compound predicates, select the
|
|
627
|
+
> target primary keys first, then issue one `update` / `delete --where "id=<pk>"` per key.
|
|
628
|
+
> (MongoDB `--where` accepts a full JSON filter and is exempt.)
|
|
629
|
+
|
|
494
630
|
### delete
|
|
495
631
|
|
|
496
632
|
Delete data from a table.
|
|
@@ -499,9 +635,10 @@ Delete data from a table.
|
|
|
499
635
|
dbcli delete users --where "id=1"
|
|
500
636
|
dbcli delete users --where "id=1" --dry-run
|
|
501
637
|
dbcli delete users --where "id=1" --force
|
|
638
|
+
dbcli delete users --where "id=1" --plan --format json # risk analysis only; no DB connection
|
|
502
639
|
```
|
|
503
640
|
|
|
504
|
-
**Options:** `--where <condition>` (required), `--dry-run`, `--force`
|
|
641
|
+
**Options:** `--where <condition>` (required), `--dry-run`, `--force`, `--plan` (analyze risk without connecting or executing), `--format <text|json>` (`--plan` output), `--recovery`
|
|
505
642
|
**Permission:** data-admin+
|
|
506
643
|
|
|
507
644
|
### export
|
|
@@ -521,7 +658,7 @@ dbcli export orders --format csv --output orders.csv # index name as query
|
|
|
521
658
|
dbcli export orders --no-limit --format jsonl # scroll the whole index in batches
|
|
522
659
|
```
|
|
523
660
|
|
|
524
|
-
**Options:** `--format <json|jsonl|csv|html>` (required), `--output <path>`, `--force`, `--recovery`, `--index <name>` (Elasticsearch), `--no-limit` (Elasticsearch full-index scroll)
|
|
661
|
+
**Options:** `--format <json|jsonl|csv|html>` (required), `--output <path>`, `--force`, `--recovery`, `--collection <name>` (MongoDB collection) / `--index <name>` (Elasticsearch index; alias for `--collection`), `--limit <number>` (overrides auto-limit), `--no-limit` (Elasticsearch full-index scroll)
|
|
525
662
|
**Permission:** query-only+ — SQL, MongoDB, and **(v1.22)** Elasticsearch.
|
|
526
663
|
|
|
527
664
|
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.
|
|
@@ -572,6 +709,147 @@ dbcli diff --against before.json --format json
|
|
|
572
709
|
**Options:** `--snapshot <path>`, `--against <path>`, `--format <json|table>`
|
|
573
710
|
**Permission:** query-only+
|
|
574
711
|
|
|
712
|
+
#### `diff --against-orm`
|
|
713
|
+
|
|
714
|
+
Compare an ORM definition with the local SQL schema cache. This mode reads
|
|
715
|
+
`config.schema`; it does not open a database connection, refresh the cache, or
|
|
716
|
+
execute a proposal. An empty cache fails with
|
|
717
|
+
`Schema cache is empty. Run 'dbcli schema' first.` Snapshot mode remains a
|
|
718
|
+
separate `--snapshot` / `--against` workflow.
|
|
719
|
+
|
|
720
|
+
```bash
|
|
721
|
+
# Prisma and normalized JSON accept exactly one file
|
|
722
|
+
dbcli diff --against-orm prisma/schema.prisma --format json
|
|
723
|
+
dbcli diff --against-orm schema.normalized.json --orm-format json --format table
|
|
724
|
+
|
|
725
|
+
# DDL accepts repeatable or comma-separated paths and real filesystem globs
|
|
726
|
+
dbcli diff --against-orm "migrations/*.sql" --format markdown
|
|
727
|
+
dbcli diff --against-orm migrations/base.sql,migrations/accounts.sql \
|
|
728
|
+
--against-orm migrations/orders.sql --orm-format ddl --format json
|
|
729
|
+
|
|
730
|
+
# Ignore patterns are comma-separated and match qualified table identity
|
|
731
|
+
dbcli diff --against-orm prisma/schema.prisma --ignore 'public.audit_*,public.Legacy'
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
| Option | Behavior |
|
|
735
|
+
| :--- | :--- |
|
|
736
|
+
| `--against-orm <paths>` | Repeatable or comma-separated input. DDL inputs support real filesystem globs; matches are deduplicated and put in deterministic path order, then parsed as one shared ordered context so an index in a later file can attach to a table declared in an earlier file. Prisma and normalized JSON accept exactly one file, and globs are rejected for those formats. |
|
|
737
|
+
| `--orm-format prisma\|ddl\|json` | Override extension/content detection. Without it, dbcli detects Prisma, DDL, or normalized JSON from the path and content. |
|
|
738
|
+
| `--ignore <globs>` | Comma-separated, case-sensitive table globs. Patterns match the qualified display identity (for example `public.Users`). `_prisma_migrations` is always unmanaged. |
|
|
739
|
+
| `--format json\|table\|markdown` | Select machine JSON, human table, or Markdown output. Markdown is available only in ORM drift mode. |
|
|
740
|
+
| `--recovery` | On an I/O, configuration, empty-cache, invalid-format, or unsupported-engine failure, emit and save a structured recovery envelope. Invalid Prisma/DDL constructs normally become `unparsed` entries instead of throwing. |
|
|
741
|
+
|
|
742
|
+
The command supports PostgreSQL, MySQL, and MariaDB configurations. Only
|
|
743
|
+
error-level **scored drift** determines the report's drift exit code: one or more
|
|
744
|
+
scored errors exits `1`; warnings, infos, `unmanaged`, or `unparsed` entries alone
|
|
745
|
+
exit `0`. Command/configuration failures independently exit code `1`. The four
|
|
746
|
+
drift categories and tolerance rules are:
|
|
747
|
+
|
|
748
|
+
| Category | Severity and comparison rule |
|
|
749
|
+
| :--- | :--- |
|
|
750
|
+
| `missing_in_db` | `error` — a table, column, or index exists in the ORM definition but not in the cached DB schema. |
|
|
751
|
+
| `missing_in_orm` | `warn` — a table, column, or index exists in the cached DB schema but not in the ORM definition. |
|
|
752
|
+
| `mismatch` | `error` when the type family or nullability differs; `info` for same-family type spelling, default, or primary-key differences. |
|
|
753
|
+
| `unmanaged` | `info`, excluded from error/warn scoring — the table matched the built-in or user `--ignore` patterns. |
|
|
754
|
+
|
|
755
|
+
Type-family tolerance deliberately treats engine spellings such as `text` and
|
|
756
|
+
`varchar(191)` as the same family: the spelling difference is still visible as
|
|
757
|
+
`info`, while an integer/text family difference is an `error`. Indexes compare
|
|
758
|
+
by structural index signatures — ordered, case-folded column names plus
|
|
759
|
+
uniqueness — rather than by engine-specific index names. Duplicate signatures
|
|
760
|
+
are emitted once. Drift entries sort deterministically by table, object, category,
|
|
761
|
+
and detail using Unicode code-point order, never locale-dependent collation.
|
|
762
|
+
|
|
763
|
+
**Schema and table identity.** Storage preserves exact, case-sensitive schema
|
|
764
|
+
and table names from the database catalog. Exact, case-sensitive `(schema, table)`
|
|
765
|
+
tuples are the comparison key, so PostgreSQL `users` and `"Users"` can coexist.
|
|
766
|
+
DDL resolution rules: unquoted SQL identifiers fold to lowercase; quoted identifiers match exactly.
|
|
767
|
+
For example, unquoted `Users` resolves to `users`, and quoted
|
|
768
|
+
`"Users"` resolves only to `Users`. Quote state comes from the parsed identifier representation;
|
|
769
|
+
dbcli never infers it from display text, catalog spelling, or a
|
|
770
|
+
Prisma mapping. Qualified components resolve independently, and unqualified ORM
|
|
771
|
+
identities use the cached DB default schema when one is known. Qualified display
|
|
772
|
+
names and `--ignore` matching remain case-sensitive. Duplicate exact or
|
|
773
|
+
duplicate resolved table identities fail closed instead of overwriting one
|
|
774
|
+
another.
|
|
775
|
+
|
|
776
|
+
**Prisma subset.** The parser supports `model` blocks; scalar `String`, `Int`,
|
|
777
|
+
`BigInt`, `Float`, `Decimal`, `Boolean`, `DateTime`, `Json`, and `Bytes` fields;
|
|
778
|
+
`?`; relation-side `[]`; `@id`, `@unique`, `@default(...)`, `@map("...")`,
|
|
779
|
+
`@@map("...")`, `@@index([...])`, `@@unique([...])`; relations with
|
|
780
|
+
`fields` / `references`; and the validated native mappings `@db.Text`,
|
|
781
|
+
`@db.VarChar(n)`, `@db.Uuid`, `@db.Timestamptz([precision])`, `@db.Date`,
|
|
782
|
+
`@db.SmallInt`, and `@db.JsonB`. Views, composite types, enums used as scalar
|
|
783
|
+
columns, multi-schema datasource configuration, malformed declarations, unknown
|
|
784
|
+
attributes, and unsupported native mappings are never guessed.
|
|
785
|
+
|
|
786
|
+
Prisma and DDL constructs outside the supported subset are retained in
|
|
787
|
+
`unparsed` with a `blocked:` reason. These entries are separate from scored drift:
|
|
788
|
+
inspect and resolve them before treating an otherwise clean summary as complete.
|
|
789
|
+
Multi-file DDL is consumed as one deterministic shared ordered statement context,
|
|
790
|
+
so later `CREATE INDEX` statements can reference tables declared in earlier
|
|
791
|
+
files. PostgreSQL `PARTITION BY` and MySQL/MariaDB table engine, charset, and
|
|
792
|
+
other `CREATE TABLE` table options are unsupported: the construct produces a
|
|
793
|
+
`blocked:` `unparsed` entry and does not emit a managed ORM table.
|
|
794
|
+
The normalized JSON escape hatch is Zod-validated and uses an array of tables
|
|
795
|
+
with explicit exact `identity` objects; optional parsed identifiers must include
|
|
796
|
+
their `quoted` flags, and every normalized JSON `unparsed.reason` must start with
|
|
797
|
+
`blocked:`.
|
|
798
|
+
|
|
799
|
+
```json
|
|
800
|
+
{
|
|
801
|
+
"ormSource": "prisma",
|
|
802
|
+
"entries": [
|
|
803
|
+
{
|
|
804
|
+
"category": "missing_in_db",
|
|
805
|
+
"severity": "error",
|
|
806
|
+
"table": "public.users",
|
|
807
|
+
"object": "email",
|
|
808
|
+
"detail": "column 'email' (text) is defined in prisma but absent in the database",
|
|
809
|
+
"proposedCommands": [
|
|
810
|
+
"# escalate: schema-qualified table 'public.users' is not losslessly representable by dbcli migrate — run: dbcli skill tasks plan migration-review"
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
],
|
|
814
|
+
"unparsed": [],
|
|
815
|
+
"summary": { "errors": 1, "warns": 0, "infos": 0, "unmanaged": 0 }
|
|
816
|
+
}
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
Missing unqualified columns and indexes may receive shell-safe, dry-run-by-default
|
|
820
|
+
`dbcli migrate add-column` or `add-index` proposal strings. Simple arguments stay
|
|
821
|
+
unquoted; unsafe shell characters are POSIX single-quoted. Table creation,
|
|
822
|
+
removal, mismatch, and DB-only drift escalate to `migration-review`. A
|
|
823
|
+
schema-qualified target, or index columns that the current `migrate --columns`
|
|
824
|
+
CLI cannot represent losslessly, also escalates instead of emitting a corrupt
|
|
825
|
+
command. Any table, column, or type positional beginning with `-` also escalates
|
|
826
|
+
so Commander cannot reinterpret it as an option. A leading-dash option value is
|
|
827
|
+
rendered with option-safe attached syntax, for example `--default=-1` or
|
|
828
|
+
`--columns=--config,email`. Proposals are text only and never add `--execute`.
|
|
829
|
+
|
|
830
|
+
For a guided, cache-refreshing review, use the built-in `orm-drift-review` pack:
|
|
831
|
+
|
|
832
|
+
```bash
|
|
833
|
+
dbcli skill tasks plan orm-drift-review \
|
|
834
|
+
--param orm_path=prisma/schema.prisma \
|
|
835
|
+
--format json
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
The plan is `blacklist list` → `schema --format json` →
|
|
839
|
+
`diff --against-orm ... --format json`. Run any proposed `migrate` command in its
|
|
840
|
+
default dry-run mode, capture the emitted DDL, confirm its exact target, and pass
|
|
841
|
+
both values to the separate migration review:
|
|
842
|
+
|
|
843
|
+
```sh
|
|
844
|
+
dbcli skill tasks plan migration-review \
|
|
845
|
+
--param "table=${exact_table}" \
|
|
846
|
+
--param "ddl=${captured_ddl}"
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
Both parameters are required. Keep each expansion as one quoted shell argument;
|
|
850
|
+
never use `eval`, and consider `--execute` only after the plan and captured DDL
|
|
851
|
+
have been reviewed.
|
|
852
|
+
|
|
575
853
|
### snapshot
|
|
576
854
|
|
|
577
855
|
Capture a **result fingerprint** of a query (not schema): `rowCount` plus per-column
|
|
@@ -892,6 +1170,7 @@ Boundaries:
|
|
|
892
1170
|
| `--from <path>` | Read the envelope from this file instead of `.dbcli/last-recovery.json`. Accepts raw `RecoveryEnvelope` or `SavedRecoveryEnvelope`. | — |
|
|
893
1171
|
| `--allow-write <tier>` | Open the risk gate. Values: `readonly-cmd` (local-side writes) \| `write-cmd` (database writes). | `none` |
|
|
894
1172
|
| `--no-verify` | Skip the verify step appended after a successful `--apply`. | off (verify runs by default) |
|
|
1173
|
+
| `--write-verification-artifact` | After a successful `--apply`, persist a secret-free `VerificationArtifact` JSON under `.dbcli/verification/`. | off |
|
|
895
1174
|
| `--format <format>` | `markdown` \| `json`. | `markdown` for inspect, `json` for `--apply` |
|
|
896
1175
|
|
|
897
1176
|
#### Plan source resolution
|
|
@@ -1650,6 +1929,7 @@ dbcli skill --install codex # install to ~/.codex/skills/dbcli/
|
|
|
1650
1929
|
**Options:**
|
|
1651
1930
|
- `--install <platform>` — `claude` | `gemini` | `antigravity` | `copilot` | `cursor` | `codex` | `windsurf`. Writes `SKILL.md` plus `reference.md` next to it so the agent gets progressive disclosure.
|
|
1652
1931
|
- `--output <path>` — write `SKILL.md` to a file instead of stdout. Does not install `reference.md`.
|
|
1932
|
+
- `--lang <en|zh-TW>` — source language for the emitted SKILL content (default `en`). It selects `assets/SKILL.md` vs `assets/SKILL.zh-TW.md`; the install/output filename stays `SKILL.md` regardless.
|
|
1653
1933
|
|
|
1654
1934
|
**Notes:**
|
|
1655
1935
|
- 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.
|
|
@@ -1662,6 +1942,21 @@ dbcli skill --install codex # install to ~/.codex/skills/dbcli/
|
|
|
1662
1942
|
|
|
1663
1943
|
**Permission:** n/a.
|
|
1664
1944
|
|
|
1945
|
+
### skill context
|
|
1946
|
+
|
|
1947
|
+
Emit an AI-friendly snapshot of the connected database's schema and saved-query snippets (blacklist-filtered) so an agent can be primed with the current context.
|
|
1948
|
+
|
|
1949
|
+
```bash
|
|
1950
|
+
dbcli skill context # XML (default)
|
|
1951
|
+
dbcli skill context --format json
|
|
1952
|
+
dbcli skill context --format markdown
|
|
1953
|
+
```
|
|
1954
|
+
|
|
1955
|
+
**Options:**
|
|
1956
|
+
- `--format <xml|json|markdown>` — output format (default: `xml`)
|
|
1957
|
+
|
|
1958
|
+
**Permission:** query-only+ — read-only; blacklisted objects are never emitted.
|
|
1959
|
+
|
|
1665
1960
|
### skill tasks (Agent Task Packs)
|
|
1666
1961
|
|
|
1667
1962
|
```bash
|
|
@@ -1685,8 +1980,12 @@ a read-only (`plan-only`) pack taking a required `table` parameter that walks
|
|
|
1685
1980
|
in recent audit activity. Additional read-only packs ship for common agent
|
|
1686
1981
|
workflows: `audit-permissions` (permission/blacklist audit), `safe-backfill`
|
|
1687
1982
|
(plan a write with blacklist+schema+risk checks), `schema-drift-review` (cached
|
|
1688
|
-
vs live schema diff),
|
|
1689
|
-
|
|
1983
|
+
vs live schema diff), `orm-drift-review` (ORM definition vs cached DB schema),
|
|
1984
|
+
and `connection-health` (reachability/config/capacity
|
|
1985
|
+
triage). **MongoDB packs:** `mongo-safe-backfill` (dry-run–previewed backfill)
|
|
1986
|
+
and `mongo-schema-drift-review` (sampled dot-path drift, with a `sample_size` knob
|
|
1987
|
+
to damp sampling noise); filter them with `dbcli skill tasks list --engine mongodb`.
|
|
1988
|
+
Run `dbcli skill tasks list` for the full set.
|
|
1690
1989
|
|
|
1691
1990
|
```bash
|
|
1692
1991
|
dbcli skill tasks plan analyze-table-perf --param table=betting_logs --format json
|
|
@@ -2201,7 +2500,7 @@ Rewrites emit a `REDIS_SIZE_REWRITE` warning; truncations emit `REDIS_SIZE_TRUNC
|
|
|
2201
2500
|
Blacklist rules are enforced as **Redis-native key globs** (`*`, `?`, `[abc]`, `[a-z]`):
|
|
2202
2501
|
|
|
2203
2502
|
```bash
|
|
2204
|
-
dbcli blacklist add 'secrets:*'
|
|
2503
|
+
dbcli blacklist table add 'secrets:*' # register a key-glob rule
|
|
2205
2504
|
dbcli query "GET secrets:api_key" # → BlacklistRejection (exit non-zero)
|
|
2206
2505
|
dbcli query "MGET safe:k secrets:api" # → rejected (any matching key fails the whole command)
|
|
2207
2506
|
dbcli query "KEYS secrets:*" # → rejected (pattern overlaps a rule)
|