@carllee1983/dbcli 1.51.2 → 1.52.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/.cursor/rules/dbcli.mdc +2 -2
- package/.cursor/skills/dbcli/reference.md +170 -1
- package/.github/skills/dbcli/SKILL.md +2 -2
- package/.github/skills/dbcli/reference.md +170 -1
- package/CHANGELOG.md +17 -0
- package/README.md +1 -0
- package/README.zh-TW.md +1 -0
- package/assets/SKILL.md +2 -2
- package/assets/reference.md +170 -1
- package/assets/tasks/design-review.md +42 -0
- package/dist/cli.mjs +790 -35
- package/dist/core.d.ts +8 -0
- package/package.json +4 -1
- package/plugins/dbcli-agent/skills/dbcli/SKILL.md +2 -2
- package/plugins/dbcli-agent/skills/dbcli/reference.md +170 -1
- package/skills/dbcli/SKILL.md +2 -2
- package/skills/dbcli/reference.md +170 -1
package/assets/reference.md
CHANGED
|
@@ -220,9 +220,44 @@ dbcli query "SELECT day, dau FROM dau_daily" --ui # open in brows
|
|
|
220
220
|
dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdout
|
|
221
221
|
```
|
|
222
222
|
|
|
223
|
-
**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`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--recovery`
|
|
223
|
+
**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`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--slow-ms <number>`, `--recovery`
|
|
224
224
|
**Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
|
|
225
225
|
|
|
226
|
+
#### Passive slow-query hint (`--slow-ms`)
|
|
227
|
+
|
|
228
|
+
`query` and `q` read the execution time they already measured for a finished
|
|
229
|
+
query and, at or above the threshold, add a hint. Default `1000`; `--slow-ms 0`
|
|
230
|
+
disables it for that invocation. This is **not** the `proxy` / `proxy analyze`
|
|
231
|
+
flag of the same name — that one flags events in the proxy log; this one only
|
|
232
|
+
annotates a single command's own result.
|
|
233
|
+
|
|
234
|
+
The hint performs no extra work: it never runs `EXPLAIN`, reads a schema, or
|
|
235
|
+
issues a second request. It is suppressed entirely under `--recovery`, so the
|
|
236
|
+
recovery envelope keeps its exact machine contract.
|
|
237
|
+
|
|
238
|
+
- `--format table` appends `Performance hint: <recommendation>` to the footer.
|
|
239
|
+
- `--format json` adds `metadata.performanceAdvisory`:
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"metadata": {
|
|
244
|
+
"statement": "SELECT",
|
|
245
|
+
"performanceAdvisory": {
|
|
246
|
+
"code": "SLOW_QUERY",
|
|
247
|
+
"executionTimeMs": 1250,
|
|
248
|
+
"thresholdMs": 1000,
|
|
249
|
+
"recommendation": "Review safely with: dbcli guide slow-query --format markdown. This hint runs no additional database diagnostics."
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The recommendation is engine-aware: PostgreSQL, MySQL, MariaDB, and Redis are
|
|
256
|
+
pointed at `dbcli guide slow-query`, because that goal resolves to real
|
|
257
|
+
diagnostic snippets for them. MongoDB and Elasticsearch ship no snippet for its
|
|
258
|
+
intents, so their hint states the timing and says so instead of naming a command
|
|
259
|
+
that would come back empty. `csv` and `html` output are unchanged.
|
|
260
|
+
|
|
226
261
|
Below `admin`, SQL holding more than one statement is rejected, because only the
|
|
227
262
|
first statement would decide the permission check while a driver on the simple
|
|
228
263
|
query protocol executes them all. Semicolons inside string literals, backtick
|
|
@@ -529,6 +564,7 @@ dbcli q @analytics/revenue --param days=30 --format html > report.html
|
|
|
529
564
|
- `--no-limit` — skip the `SELECT * FROM (…) AS _dbcli_guard LIMIT 1000` wrap
|
|
530
565
|
- `--dry-run` — print the bound SQL + values without executing
|
|
531
566
|
- `--use <name>` — pick a v2 named connection
|
|
567
|
+
- `--slow-ms <number>` — passive slow-query hint threshold (default `1000`; `0` disables). Same contract as `query` — see "Passive slow-query hint" there
|
|
532
568
|
- `--recovery` — emit a `RecoveryEnvelope` on failure (see `recover`)
|
|
533
569
|
- `--verify` — run the snippet's verification assertions after execution (only if the snippet defines them)
|
|
534
570
|
|
|
@@ -1077,6 +1113,139 @@ Both parameters are required. Keep each expansion as one quoted shell argument;
|
|
|
1077
1113
|
never use `eval`, and consider `--execute` only after the plan and captured DDL
|
|
1078
1114
|
have been reviewed.
|
|
1079
1115
|
|
|
1116
|
+
### design
|
|
1117
|
+
|
|
1118
|
+
Author, validate, render, and review a version-controlled SQL database design
|
|
1119
|
+
kept beside the code as `dbcli.design.json`. Every subcommand is offline: none
|
|
1120
|
+
opens a database connection, executes DDL, or calls an LLM. `design init` is the
|
|
1121
|
+
only writer, and it writes only to the explicit `--output` path.
|
|
1122
|
+
|
|
1123
|
+
```text
|
|
1124
|
+
dbcli design init --output <path> [--dialect <dialect>]
|
|
1125
|
+
dbcli design validate [--file <path>] [--format <format>]
|
|
1126
|
+
dbcli design render [--file <path>] [--format <format>]
|
|
1127
|
+
dbcli design diff (--against-cache | --against-orm <paths>) [options]
|
|
1128
|
+
dbcli design propose (--against-cache | --against-orm <paths>) [options]
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
```bash
|
|
1132
|
+
# Writes only to this explicit, missing path; edit the starter before validating.
|
|
1133
|
+
dbcli design init --output ./dbcli.design.json --dialect postgresql
|
|
1134
|
+
|
|
1135
|
+
dbcli design validate --format json
|
|
1136
|
+
dbcli design render --format mermaid
|
|
1137
|
+
dbcli design diff --against-cache --format markdown
|
|
1138
|
+
dbcli design diff --against-orm ./prisma/schema.prisma --format markdown
|
|
1139
|
+
dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
| Option | Applies to | Default | Meaning |
|
|
1143
|
+
|---|---|---|---|
|
|
1144
|
+
| `--output <path>` | `init` | required | Destination for the new artifact; refuses to overwrite an existing file. |
|
|
1145
|
+
| `--dialect <postgresql\|mysql\|mariadb>` | `init` | `postgresql` | Target SQL dialect recorded in the artifact. |
|
|
1146
|
+
| `--file <path>` | all but `init` | `dbcli.design.json` | Design artifact to read. |
|
|
1147
|
+
| `--format <format>` | all but `init` | see below | `validate`/`propose`: `json`, `markdown`. `render`: `json`, `markdown`, `mermaid` (default `markdown`). `diff`: `json` (default), `table`, `markdown`. |
|
|
1148
|
+
| `--against-cache` | `diff`, `propose` | off | Compare with the local schema cache; requires a configured PostgreSQL/MySQL/MariaDB connection whose system matches the artifact dialect, and a non-empty cache (run `dbcli schema` first). |
|
|
1149
|
+
| `--against-orm <paths>` | `diff`, `propose` | none | Compare with local ORM definition(s); repeatable or comma-separated, DDL paths support globs. Needs no config and no connection. |
|
|
1150
|
+
| `--orm-format <format>` | `diff`, `propose` | auto-detect | Force `prisma`, `ddl`, `json`, `drizzle`, `typeorm`, or `sequelize`. |
|
|
1151
|
+
| `--ignore <globs>` | `diff`, `propose` | none | Comma-separated table globs excluded from drift. |
|
|
1152
|
+
|
|
1153
|
+
`diff` and `propose` require **exactly one** comparison target; passing both or
|
|
1154
|
+
neither is an error.
|
|
1155
|
+
|
|
1156
|
+
#### Artifact shape
|
|
1157
|
+
|
|
1158
|
+
```json
|
|
1159
|
+
{
|
|
1160
|
+
"version": 1,
|
|
1161
|
+
"dialect": "postgresql",
|
|
1162
|
+
"models": [
|
|
1163
|
+
{
|
|
1164
|
+
"name": "orders",
|
|
1165
|
+
"table": "orders",
|
|
1166
|
+
"description": "Completed purchases.",
|
|
1167
|
+
"fields": [
|
|
1168
|
+
{ "name": "id", "type": "bigint", "nullable": false, "primaryKey": true, "unique": true },
|
|
1169
|
+
{ "name": "customer_id", "type": "bigint", "nullable": false, "primaryKey": false, "unique": false }
|
|
1170
|
+
],
|
|
1171
|
+
"indexes": [{ "name": "orders_customer_idx", "columns": ["customer_id"], "unique": false }]
|
|
1172
|
+
}
|
|
1173
|
+
],
|
|
1174
|
+
"relationships": [
|
|
1175
|
+
{
|
|
1176
|
+
"name": "orders_customer",
|
|
1177
|
+
"from": { "model": "orders", "field": "customer_id" },
|
|
1178
|
+
"to": { "model": "customers", "field": "id" },
|
|
1179
|
+
"cardinality": "many-to-one"
|
|
1180
|
+
}
|
|
1181
|
+
],
|
|
1182
|
+
"accessPatterns": [{ "model": "orders", "filters": ["customer_id"], "sort": ["created_at"] }],
|
|
1183
|
+
"decisions": [{ "name": "single-currency", "rationale": "Amounts are stored in minor units, USD only." }]
|
|
1184
|
+
}
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
It holds no SQL, credentials, rows, or provider configuration. `design init`
|
|
1188
|
+
emits this envelope with empty `models`, `relationships`, `accessPatterns`, and
|
|
1189
|
+
`decisions`.
|
|
1190
|
+
|
|
1191
|
+
#### Review findings
|
|
1192
|
+
|
|
1193
|
+
`validate` is fail-closed: any `error` finding exits `1`, and `render`, `diff`,
|
|
1194
|
+
and `propose` refuse to do their work while errors remain.
|
|
1195
|
+
|
|
1196
|
+
| Severity | Codes |
|
|
1197
|
+
|---|---|
|
|
1198
|
+
| `error` | `NO_MODELS`, `DUPLICATE_MODEL`, `DUPLICATE_TABLE`, `DUPLICATE_FIELD`, `PRIMARY_KEY_COUNT`, `NULLABLE_PRIMARY_KEY`, `UNKNOWN_INDEX_FIELD`, `DUPLICATE_RELATIONSHIP`, `REVERSE_RELATIONSHIP`, `UNKNOWN_RELATIONSHIP_MODEL`, `UNKNOWN_RELATIONSHIP_FIELD`, `RELATIONSHIP_TYPE_MISMATCH`, `MANY_TO_MANY_REQUIRES_BRIDGE`, `ONE_TO_ONE_REQUIRES_UNIQUE_FK`, `UNKNOWN_ACCESS_MODEL`, `UNKNOWN_ACCESS_FIELD` |
|
|
1199
|
+
| `warn` | `DUPLICATE_INDEX`, `REDUNDANT_PRIMARY_KEY_INDEX`, `PREFIX_REDUNDANT_INDEX`, `ACCESS_PATTERN_INDEX` |
|
|
1200
|
+
|
|
1201
|
+
`REVERSE_RELATIONSHIP` fires when the same endpoints are declared again in the
|
|
1202
|
+
opposite direction; `PREFIX_REDUNDANT_INDEX` fires when a non-unique index is a
|
|
1203
|
+
leading-column prefix of a longer index. `v1` requires exactly one primary-key
|
|
1204
|
+
field per model and an explicit bridge model for `many-to-many`.
|
|
1205
|
+
|
|
1206
|
+
#### `design propose` (review-only)
|
|
1207
|
+
|
|
1208
|
+
`propose` turns drift into a plan a human reviews; it never applies a write. Each
|
|
1209
|
+
entry carries a `safety` of `dry-run` (an existing `migrate` command can represent
|
|
1210
|
+
the change losslessly) or `migration-review` (everything else), plus `preflight`,
|
|
1211
|
+
`rollback`, and `verification` steps:
|
|
1212
|
+
|
|
1213
|
+
```json
|
|
1214
|
+
{
|
|
1215
|
+
"table": "orders",
|
|
1216
|
+
"object": "total_cents",
|
|
1217
|
+
"safety": "migration-review",
|
|
1218
|
+
"commands": ["..."],
|
|
1219
|
+
"preflight": [
|
|
1220
|
+
"dbcli blacklist list",
|
|
1221
|
+
"Confirm the exact affected table with: dbcli schema <exact-table> --format json"
|
|
1222
|
+
],
|
|
1223
|
+
"rollback": "Capture the current schema and generated DDL before any approved write; define the inverse migration before execution.",
|
|
1224
|
+
"verification": [
|
|
1225
|
+
"After an approved write, run: dbcli schema <exact-table> --format json",
|
|
1226
|
+
"Re-run this same design diff command and review the remaining drift."
|
|
1227
|
+
]
|
|
1228
|
+
}
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
**Workflows:**
|
|
1232
|
+
|
|
1233
|
+
- **New project** — `design init` → edit the artifact → `design validate` →
|
|
1234
|
+
`design render`. If application models already exist, use the offline
|
|
1235
|
+
`design diff --against-orm <path>` to reconcile the artifact and the ORM before
|
|
1236
|
+
any database exists.
|
|
1237
|
+
- **Existing database** — `blacklist list` → refresh the cache with
|
|
1238
|
+
`schema --format json` → `design diff --against-cache` →
|
|
1239
|
+
`design propose --against-cache`. Review the plan, perform any approved
|
|
1240
|
+
migration separately, then refresh the schema and rerun the same diff.
|
|
1241
|
+
|
|
1242
|
+
**Exit codes:** `0` when no errors, `1` when the artifact has review errors, an
|
|
1243
|
+
invalid target selection, an unreadable file, or reported drift errors.
|
|
1244
|
+
|
|
1245
|
+
An external coding agent may draft the artifact, but a human should review it
|
|
1246
|
+
before it is relied upon. Do not create or rewrite `dbcli.design.json` without an
|
|
1247
|
+
explicit human request.
|
|
1248
|
+
|
|
1080
1249
|
### snapshot
|
|
1081
1250
|
|
|
1082
1251
|
Capture a **result fingerprint** of a query (not schema): `rowCount` plus per-column
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-review
|
|
3
|
+
description: Validate and render a version-controlled SQL database design before comparing it with the local schema cache and preparing review-only proposals.
|
|
4
|
+
tags: [design, schema, readonly]
|
|
5
|
+
engines: [postgres, mysql]
|
|
6
|
+
safety:
|
|
7
|
+
mode: plan-only
|
|
8
|
+
requires:
|
|
9
|
+
- blacklist-list
|
|
10
|
+
- schema-check
|
|
11
|
+
steps:
|
|
12
|
+
- type: command
|
|
13
|
+
command: blacklist list
|
|
14
|
+
reason: Confirm sensitive-data boundaries before reading cached schema details or preparing migration review.
|
|
15
|
+
risk: readonly
|
|
16
|
+
- type: command
|
|
17
|
+
command: design validate --format json
|
|
18
|
+
reason: Fail closed on incomplete keys, invalid relationships, and unsafe indexes before the design is used.
|
|
19
|
+
risk: readonly
|
|
20
|
+
- type: command
|
|
21
|
+
command: design render --format mermaid
|
|
22
|
+
reason: Produce a reviewable ERD from the validated local artifact.
|
|
23
|
+
risk: readonly
|
|
24
|
+
- type: command
|
|
25
|
+
command: schema --format json
|
|
26
|
+
reason: Refresh the local SQL schema cache before comparing an existing database with the target design.
|
|
27
|
+
risk: readonly
|
|
28
|
+
- type: command
|
|
29
|
+
command: design diff --against-cache --format markdown
|
|
30
|
+
reason: Report columns, indexes, and foreign keys that differ without opening a new connection or executing DDL.
|
|
31
|
+
risk: readonly
|
|
32
|
+
- type: command
|
|
33
|
+
command: design propose --against-cache --format markdown
|
|
34
|
+
reason: Prepare only dry-run proposals or migration-review escalations with preflight, rollback, and verification reminders.
|
|
35
|
+
risk: readonly
|
|
36
|
+
---
|
|
37
|
+
# Agent Notes
|
|
38
|
+
|
|
39
|
+
`dbcli.design.json` is a review artifact, not an execution request. Do not add
|
|
40
|
+
`--execute` to any command in this plan. If a design differs from the cache,
|
|
41
|
+
review the drift and prepare an explicit migration separately; this task neither
|
|
42
|
+
creates a migration nor applies one.
|