@carllee1983/dbcli 1.20.0 → 1.20.2
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 +20 -1
- package/README.md +11 -6
- package/assets/SKILL.md +15 -8
- package/assets/SKILL.zh-TW.md +10 -5
- package/assets/reference.md +339 -5
- package/assets/snippets/diag/active-users.mongodb.sql +14 -0
- package/assets/snippets/diag/top-orders-by-city.mongodb.sql +20 -0
- package/dist/cli.mjs +2775 -1648
- package/package.json +10 -7
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [1.20.1] - 2026-05-18
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Phase 23-04 follow-up closure — full DML/DDL audit coverage.** `insert / update / delete / export / q / schema` now invoke `writeAuditEntry` on every happy / failure / rejection branch (BlacklistError / PermissionError / ConnectionError / validation all flow through the wired catch block). This closes the v1.20.0 INTEGRATE-01 / INTEGRATE-04 partial gap noted in v1.20.0's Known limitation paragraph.
|
|
14
|
+
- **Bi-directional `audit_ref` ⇄ `recovery_ref` linkage on every `--recovery`-capable command.** When any of the 6 newly-wired commands fails with `--recovery`, the audit entry's `recovery_ref` and the recovery envelope's `audit_ref` carry matching UUIDs — identical in shape to the Phase 25 `query` / `inspect` round-trip wiring. Agents can pivot from `.dbcli/last-recovery.json` to the audit entry via `dbcli audit tail --recovery-ref <id>`.
|
|
15
|
+
- **AI-agent skill docs (`assets/SKILL.md`, `assets/SKILL.zh-TW.md`, `assets/reference.md`)** updated to advertise full 8-command bi-directional coverage; bilingual user docs (`docs/user/en/index.{md,html}`, `docs/user/zh-TW/index.{md,html}`) gained a `--recovery` row noting the cross-command linkage.
|
|
16
|
+
|
|
17
|
+
### Tests
|
|
18
|
+
|
|
19
|
+
- `tests/integration/recovery-audit-link.test.ts` — the legacy "J1 asymmetry guard" `describe` block (which asserted `'audit_ref' in envelope === false` for the 6 deferred commands) is replaced with a consolidated **6-command positive bi-directional round-trip** block. For each of `schema / q / export / insert / update / delete`, the test asserts `envelope.audit_ref === audit.id` AND `audit.recovery_ref === envelope.id`, with both refs matching `/^[0-9a-f-]{36}$/`.
|
|
20
|
+
|
|
21
|
+
### Internal
|
|
22
|
+
|
|
23
|
+
- `src/commands/{insert,update,delete,export,q,schema}.ts` — adopt the D-J catch-block template from Phase 25: pre-generate `envelopeId = crypto.randomUUID()` only when `options.recovery === true`, call `writeAuditEntry({ success: false, error, recovery_ref: envelopeId })` and capture the returned `auditId`, then call `emitRecoveryEnvelope(err, ctx, { envelopeId, auditRef: auditId ?? undefined })`. Success branches add `await writeAuditEntry(config, '<cmd>', options, { success: true, ... })`.
|
|
24
|
+
- `src/commands/q.ts` — `handleQError` refactored to accept `config` so audit + envelope can be written together inside the same try/catch.
|
|
25
|
+
- `src/adapters/capabilities.ts` — narrow `ExportOptions` / `QCommandOptions` shapes opened so the shared audit helper can read `--recovery` and `--config` without per-command type casts.
|
|
26
|
+
- `.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md` — coverage table refreshed; all 6 previously-deferred rows flipped to `YES (Phase 23-04 wired)`; Round-Trip Contract section replaces the old Asymmetry Guard section.
|
|
27
|
+
|
|
9
28
|
## [1.20.0] - 2026-05-17
|
|
10
29
|
|
|
11
30
|
### Added
|
|
@@ -26,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
26
45
|
|
|
27
46
|
- **Default-on, upgrade impact:** `audit.enabled = true` by default. Existing projects will begin creating `.dbcli/audit/<connection>.jsonl` on first command after upgrading. Set `audit.enabled = false` in `.dbcli` to opt out. The audit directory is gitignored by default; entries are metadata-only (D3) — never raw SQL bodies, `--param` values, or result cell contents. (D1)
|
|
28
47
|
- `inspect` / `guide` / `recover` / `recover --apply` agent JSON output adds an `audit_recent` field (additive; shape stable; not a breaking change). v1.19.x consumers ignore the field.
|
|
29
|
-
- _Known limitation (Phase 23-04 follow-up):_ Audit log captures `query`, `inspect`, and diagnostic-surface commands in v1.20.0; coverage for `insert / update / delete / export / q / schema` failure paths is tracked as Phase 23-04 follow-up (see `.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md`). Recovery envelope linkage from the envelope side is unaffected — those commands continue to emit `.dbcli/last-recovery.json` envelopes; only the `audit_ref` back-pointer is missing in v1.20.0.
|
|
48
|
+
- _Known limitation (Phase 23-04 follow-up):_ Audit log captures `query`, `inspect`, and diagnostic-surface commands in v1.20.0; coverage for `insert / update / delete / export / q / schema` failure paths is tracked as Phase 23-04 follow-up (see `.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md`). Recovery envelope linkage from the envelope side is unaffected — those commands continue to emit `.dbcli/last-recovery.json` envelopes; only the `audit_ref` back-pointer is missing in v1.20.0. (Closed in v1.20.1 — see entry above.)
|
|
30
49
|
|
|
31
50
|
### Internal
|
|
32
51
|
|
package/README.md
CHANGED
|
@@ -1283,12 +1283,17 @@ audit history and recovery envelopes from either direction. The
|
|
|
1283
1283
|
`audit_recent: AuditEntryBrief[]` (last 5 entries) so a fresh session has
|
|
1284
1284
|
immediate context.
|
|
1285
1285
|
|
|
1286
|
-
**
|
|
1287
|
-
|
|
1288
|
-
export
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1286
|
+
**Full bi-directional coverage (v1.20.1+):** Recovery ↔ audit linkage is
|
|
1287
|
+
wired on every `--recovery`-capable command — `query`, `inspect`, `insert`,
|
|
1288
|
+
`update`, `delete`, `export`, `q`, and `schema`. The audit entry's
|
|
1289
|
+
`recovery_ref` and the envelope's `audit_ref` carry matching UUIDs on every
|
|
1290
|
+
failure path, so agents can pivot from a saved envelope
|
|
1291
|
+
(`.dbcli/last-recovery.json`) to its audit entry via
|
|
1292
|
+
`dbcli audit tail --recovery-ref <id>` (and back via
|
|
1293
|
+
`dbcli audit show --recovery-ref <id>`). The v1.20.0 partial-coverage gap
|
|
1294
|
+
on the 6 DML/DDL commands was closed in v1.20.1. The coverage matrix lives
|
|
1295
|
+
in
|
|
1296
|
+
[`.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md`](./.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md).
|
|
1292
1297
|
|
|
1293
1298
|
For deeper agent workflows (session handoff, forensics walk-through), see
|
|
1294
1299
|
[`assets/SKILL.md`](./assets/SKILL.md) §Audit Log usage.
|
package/assets/SKILL.md
CHANGED
|
@@ -43,6 +43,8 @@ Database CLI for AI agents with permission-based access control.
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
`--result` accepts inline JSON `StepResultSummary` or `@<path>` to read from a file. `stdoutSummary` and `stderrSummary` are capped at 4 KB each — pre-truncate to the **last** 4 KB before passing. `--next` is mutually exclusive with `--apply`. Each call is independent (no persisted cursor) — the agent tracks `--after-step` itself.
|
|
46
|
+
|
|
47
|
+
**Connection branching.** For `CONN_*` codes, the envelope ships a `branches` map + `branchFork` descriptor. Step 1 (`dbcli doctor --format json`) is the fork point: pass the doctor JSON in `--result.stdoutSummary` and `--next` will pick one of four labeled branches (`doctor-clean` / `doctor-config-missing` / `doctor-auth-error` / `doctor-network-error`). NextResult then carries `branchId` and `branchDescription`; subsequent calls must echo `--branch <id>` to walk that branch. Parse failure / unmatched keywords fall back to linear `recovery`. `--apply` ignores branches entirely.
|
|
46
48
|
5. `dbcli blacklist list` — sensitive data boundaries.
|
|
47
49
|
6. `dbcli schema <table> --format json` — real column names (SQL/Mongo/ES) or `schema <key>` (Redis). **Never guess.**
|
|
48
50
|
7. Run `query` / `insert` / `update` / `delete` / `export` within permission.
|
|
@@ -100,15 +102,17 @@ The `inspect` / `guide` / `recover` / `recover --apply` agent JSON output embeds
|
|
|
100
102
|
history context. The envelope's `audit_ref` and the audit entry's `recovery_ref`
|
|
101
103
|
point at each other; agents can pivot either direction.
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
export
|
|
106
|
-
|
|
107
|
-
linkage from the envelope side is unaffected.
|
|
105
|
+
Bi-directional `recovery_ref` / `audit_ref` linkage is wired on every command
|
|
106
|
+
that accepts `--recovery`: `query`, `inspect`, `insert`, `update`, `delete`,
|
|
107
|
+
`export`, `q`, and `schema`. Agents can pivot from an envelope to its audit
|
|
108
|
+
entry via `audit tail --recovery-ref <id>`.
|
|
108
109
|
|
|
109
110
|
Audit entries are written to `.dbcli/audit/<connection>.jsonl` with rotation at
|
|
110
111
|
~10 MB or 1000 entries. `audit.enabled = false` in `.dbcli` opts out (default ON
|
|
111
112
|
since v1.20.0). For flag reference see [`reference.md`](./reference.md) §audit.
|
|
113
|
+
For end-to-end recovery walkthroughs (per-code scenarios, `--next` multi-turn,
|
|
114
|
+
envelope ⇄ audit pivot, risk-gate cheat sheet) see
|
|
115
|
+
[`reference.md`](./reference.md) §Recovery Cookbook.
|
|
112
116
|
|
|
113
117
|
## Quick start
|
|
114
118
|
|
|
@@ -271,9 +275,12 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
|
|
|
271
275
|
## MongoDB
|
|
272
276
|
|
|
273
277
|
- JSON filter object (`find`) or JSON array (`aggregate`); SQL is rejected. `--collection <name>` is required on `query`.
|
|
274
|
-
- **Supported:** `init`, `list`, `schema` (sampled), `query`, `insert`, `update`, `delete`, `export`, `status`, `use`, `shell`, `doctor`, `upgrade`, `completion`.
|
|
275
|
-
- **Not supported:** `
|
|
276
|
-
- Schema is **sampled** (default
|
|
278
|
+
- **Supported:** `init`, `list`, `schema` (sampled), `query`, `insert`, `update`, `delete`, `export`, `q` (saved queries), `status`, `use`, `shell`, `doctor`, `upgrade`, `completion`.
|
|
279
|
+
- **Not supported:** `diff`, `migrate`, `check`.
|
|
280
|
+
- Schema is **sampled** by `$sample` (default 100 docs, max 1000). Pass `--sample-method natural` to use `find().limit()` instead. Columns surface as dot-paths (e.g. `profile.tokens.access`) with `presence` (0..1) and `redacted: true` flags for blacklist hits.
|
|
281
|
+
- **Write planner tiers:** `$set`/`$unset` → `ALLOW`; `$rename` → `WARN` (informational); `$inc`/`$mul`/`$min`/`$max`/`$currentDate` → `WARN`; `$push`/`$pull`/`$pullAll`/`$pop`/`$addToSet` → `WARN`; `$bit` → `WARN`; `$where` and unknown operators → `BLOCK`.
|
|
282
|
+
- **Nested blacklist:** `blacklist.columns[<collection>]` accepts dotted paths (`profile.email`) and trailing-wildcard prefixes (`profile.tokens.*`); middle wildcards are rejected with a warning at `dbcli blacklist list`. Read paths replace matched values with the literal string `[REDACTED]`.
|
|
283
|
+
- **Saved queries:** snippet file ends in `.mongodb.sql`. Frontmatter requires `engine: mongodb` and `operation: find` or `operation: aggregate`. `target: <collection>` is the default collection (override with `--collection`). Body is JSON (object for `find`, array for `aggregate`); `{{param}}` placeholders are JSON-encoded.
|
|
277
284
|
- See reference.md MongoDB section for full syntax and examples.
|
|
278
285
|
|
|
279
286
|
## Redis
|
package/assets/SKILL.zh-TW.md
CHANGED
|
@@ -45,6 +45,8 @@ description: 為 AI 代理設計、具權限控管的資料庫 CLI。可用於
|
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
`--result` 接受 inline JSON `StepResultSummary`,或 `@<path>` 從檔案讀取。`stdoutSummary` 與 `stderrSummary` 各上限 4 KB — 請先把結果截到 **最後** 4 KB 再傳入。`--next` 與 `--apply` 互斥。每次呼叫獨立(不持久化 cursor)— 代理自行追蹤 `--after-step`。
|
|
48
|
+
|
|
49
|
+
**連線錯誤分支。** 針對 `CONN_*` 代碼,envelope 會額外帶 `branches` 與 `branchFork`。步驟 1(`dbcli doctor --format json`)即為分支點:把 doctor JSON 透過 `--result.stdoutSummary` 傳入,`--next` 會挑選四個分支之一(`doctor-clean` / `doctor-config-missing` / `doctor-auth-error` / `doctor-network-error`)。NextResult 會帶 `branchId` 與 `branchDescription`;後續呼叫必須以 `--branch <id>` 走訪該分支。解析失敗或關鍵字不匹配時回落為線性 `recovery`。`--apply` 不使用 `branches`。
|
|
48
50
|
5. `dbcli blacklist list` — 敏感資料邊界。
|
|
49
51
|
6. `dbcli schema <table> --format json` — 取得真實欄位名稱(SQL / Mongo / ES)或 `schema <key>`(Redis)。**禁止猜測。**
|
|
50
52
|
7. 在允許的權限範圍內執行 `query` / `insert` / `update` / `delete` / `export`。
|
|
@@ -89,9 +91,9 @@ dbcli audit show --recovery-ref <envelope-id> # 反向找出觸發 envelope 的
|
|
|
89
91
|
|
|
90
92
|
`inspect` / `guide` / `recover` / `recover --apply` 的 agent JSON 內嵌 `audit_recent: AuditEntryBrief[]`(最近 5 筆),無須額外呼叫 audit CLI 即可看到歷史脈絡。Envelope 的 `audit_ref` 與 audit entry 的 `recovery_ref` 互為雙向指標。
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
**完整雙向覆蓋(v1.20.1+):** `recovery_ref` / `audit_ref` 雙向連結已在所有支援 `--recovery` 的指令上佈線:`query`、`inspect`、`insert`、`update`、`delete`、`export`、`q`、`schema`。Agent 可透過 `dbcli audit tail --recovery-ref <id>` 從 envelope 反查 audit entry(反方向用 `dbcli audit show --recovery-ref <id>`)。v1.20.0 中 6 個 DML/DDL 指令的部分覆蓋缺口已於 v1.20.1 關閉。
|
|
93
95
|
|
|
94
|
-
詳細指令參考:[`reference.md`](./reference.md) §audit(英文)。
|
|
96
|
+
詳細指令參考:[`reference.md`](./reference.md) §audit(英文)。完整 agent 復原 walkthrough(各錯誤碼 end-to-end 情境、`--next` 多輪逐步、envelope ⇄ audit pivot、risk gate cheat sheet)見 [`reference.md`](./reference.md) §Recovery Cookbook(英文)。
|
|
95
97
|
|
|
96
98
|
完整旗標、每個指令的可貼上範例、`migrate` DDL、互動式 `shell` 與 MongoDB / Redis / ES 教學在 [reference.md](reference.md)(安裝時與本檔放在一起)。
|
|
97
99
|
|
|
@@ -239,9 +241,12 @@ dbcli init --use-env-refs \
|
|
|
239
241
|
## MongoDB
|
|
240
242
|
|
|
241
243
|
- 用 JSON filter 物件(`find`)或 JSON 陣列(`aggregate`);SQL 會被拒絕。`query` 必填 `--collection <name>`。
|
|
242
|
-
- **支援:** `init`、`list`、`schema`(sampled)、`query`、`insert`、`update`、`delete`、`export`、`status`、`use`、`shell`、`doctor`、`upgrade`、`completion`。
|
|
243
|
-
- **不支援:** `
|
|
244
|
-
- Schema
|
|
244
|
+
- **支援:** `init`、`list`、`schema`(sampled)、`query`、`insert`、`update`、`delete`、`export`、`q`(saved queries)、`status`、`use`、`shell`、`doctor`、`upgrade`、`completion`。
|
|
245
|
+
- **不支援:** `diff`、`migrate`、`check`。
|
|
246
|
+
- Schema 由 `$sample` **採樣**(預設 100 份文件,上限 1000)。可加 `--sample-method natural` 改用 `find().limit()`。欄位以 dot-path 呈現(如 `profile.tokens.access`),附帶 `presence`(0..1)與命中黑名單時的 `redacted: true`。
|
|
247
|
+
- **寫入規劃器分層:** `$set`/`$unset` → `ALLOW`;`$rename` → `WARN`(資訊提示);`$inc`/`$mul`/`$min`/`$max`/`$currentDate` → `WARN`;`$push`/`$pull`/`$pullAll`/`$pop`/`$addToSet` → `WARN`;`$bit` → `WARN`;`$where` 與未知運算子 → `BLOCK`。
|
|
248
|
+
- **巢狀黑名單:** `blacklist.columns[<collection>]` 接受點分路徑(`profile.email`)與結尾萬用字元(`profile.tokens.*`);中間萬用字元會在 `dbcli blacklist list` 警告並略過。讀取路徑會將命中值取代為字串字面值 `[REDACTED]`。
|
|
249
|
+
- **儲存查詢:** snippet 檔名以 `.mongodb.sql` 結尾。Frontmatter 必填 `engine: mongodb` 與 `operation: find` 或 `operation: aggregate`。`target: <collection>` 為預設集合,可由 `--collection` 覆蓋。主體為 JSON(`find` 為物件、`aggregate` 為陣列);`{{param}}` 佔位符會 JSON 編碼。
|
|
245
250
|
- 完整語法與範例見 reference.md MongoDB 段落。
|
|
246
251
|
|
|
247
252
|
## Redis
|
package/assets/reference.md
CHANGED
|
@@ -100,13 +100,14 @@ dbcli schema --use staging # Scan staging DB; saves to .dbcli/schemas/s
|
|
|
100
100
|
dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod/
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
**Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`
|
|
103
|
+
**Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`, `--sample-size <n>` (mongo only), `--sample-method <random|natural>` (mongo only)
|
|
104
104
|
**Permission:** query-only+
|
|
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
108
|
> **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
109
|
> **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
|
+
> **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.
|
|
110
111
|
|
|
111
112
|
### query
|
|
112
113
|
|
|
@@ -328,6 +329,57 @@ Substitution rules: pure raw text — `:name` becomes the value's `String()` for
|
|
|
328
329
|
|
|
329
330
|
Size guard: `LRANGE` / `ZRANGE` stop overridden when `< 0` or `> 1000`; `SCAN` / `HSCAN` / `SSCAN` / `ZSCAN` get `COUNT 1000` injected if absent. `--no-limit` disables.
|
|
330
331
|
|
|
332
|
+
##### MongoDB snippets
|
|
333
|
+
|
|
334
|
+
File extension: `.mongodb.sql`. Frontmatter must declare `engine: mongodb` and
|
|
335
|
+
`operation: find` or `operation: aggregate`. `target: <collection>` provides a default
|
|
336
|
+
collection that `dbcli q --collection <name>` can override. The body is JSON: an object
|
|
337
|
+
for `find` and an array for `aggregate`. Each `{{param}}` placeholder is JSON-encoded
|
|
338
|
+
at substitution time — strings are quoted and escaped, so an attacker-supplied string
|
|
339
|
+
cannot escape into operator position.
|
|
340
|
+
|
|
341
|
+
Find example (`active-users.mongodb.sql`):
|
|
342
|
+
|
|
343
|
+
-- ---
|
|
344
|
+
-- name: active-users
|
|
345
|
+
-- engine: mongodb
|
|
346
|
+
-- operation: find
|
|
347
|
+
-- target: users
|
|
348
|
+
-- description: Active users matching the given status
|
|
349
|
+
-- params:
|
|
350
|
+
-- status:
|
|
351
|
+
-- type: string
|
|
352
|
+
-- required: true
|
|
353
|
+
-- ---
|
|
354
|
+
{
|
|
355
|
+
"status": {{status}}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
Aggregate example (`top-orders-by-city.mongodb.sql`):
|
|
359
|
+
|
|
360
|
+
-- ---
|
|
361
|
+
-- name: top-orders-by-city
|
|
362
|
+
-- engine: mongodb
|
|
363
|
+
-- operation: aggregate
|
|
364
|
+
-- target: orders
|
|
365
|
+
-- description: Top order counts per city for a given status
|
|
366
|
+
-- params:
|
|
367
|
+
-- status:
|
|
368
|
+
-- type: string
|
|
369
|
+
-- required: true
|
|
370
|
+
-- limit:
|
|
371
|
+
-- type: int
|
|
372
|
+
-- default: 10
|
|
373
|
+
-- ---
|
|
374
|
+
[
|
|
375
|
+
{ "$match": { "status": {{status}} } },
|
|
376
|
+
{ "$group": { "_id": "$city", "n": { "$sum": 1 } } },
|
|
377
|
+
{ "$sort": { "n": -1 } },
|
|
378
|
+
{ "$limit": {{limit}} }
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
Run with `dbcli q @active-users -p status=active` or `dbcli q @top-orders-by-city -p status=open -p limit=5`. The `q` command applies the same nested-blacklist redaction to results that `query` and `export` do.
|
|
382
|
+
|
|
331
383
|
### queries
|
|
332
384
|
|
|
333
385
|
Manage saved snippets — discover, inspect, scaffold, and edit local copies. Mutating
|
|
@@ -727,8 +779,9 @@ deterministically.
|
|
|
727
779
|
| Flag | Required | Description |
|
|
728
780
|
|---|---|---|
|
|
729
781
|
| `--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]
|
|
782
|
+
| `--after-step <n>` | yes | 1-based order of the step the agent just executed. Range: `[1, envelope.recovery.length]` (or `[1, branches[id].steps.length]` when `--branch` is set). |
|
|
731
783
|
| `--result <value>` | yes | JSON `StepResultSummary` (inline) or `@<path>` to read from a file. |
|
|
784
|
+
| `--branch <id>` | no | Walk a specific branch by id (required on `--next` calls after a fork). See *Connection branching* below. |
|
|
732
785
|
| `--from <path>` | no | Override the auto-saved envelope. |
|
|
733
786
|
| `--format <fmt>` | no | `json` (default) or `markdown`. |
|
|
734
787
|
|
|
@@ -760,9 +813,24 @@ interface NextResult {
|
|
|
760
813
|
cursor: number // step.order when kind='step'; totalSteps when 'done'
|
|
761
814
|
totalSteps: number
|
|
762
815
|
step?: GuideStep // present iff kind='step'
|
|
816
|
+
branchId?: string // set iff agent is currently traversing a branch
|
|
817
|
+
branchDescription?: string // mirror of branches[branchId].description
|
|
763
818
|
}
|
|
764
819
|
```
|
|
765
820
|
|
|
821
|
+
**Connection branching**
|
|
822
|
+
|
|
823
|
+
For `CONN_*` recovery codes, the envelope ships an additional `branches` map and a `branchFork` descriptor. Step 1 (`dbcli doctor --format json`) is the fork point: pass the doctor JSON in `--result.stdoutSummary` and `--next` will pick one of four labeled branches:
|
|
824
|
+
|
|
825
|
+
| Branch id | When chosen |
|
|
826
|
+
|---|---|
|
|
827
|
+
| `doctor-clean` | Doctor reports no errors — likely transient; verify baseline state, then retry. |
|
|
828
|
+
| `doctor-config-missing` | Doctor flagged a config-level failure (missing / invalid config). Re-init before reconnecting. |
|
|
829
|
+
| `doctor-auth-error` | Doctor confirms credentials were rejected. Re-init with `--force` to overwrite credentials. |
|
|
830
|
+
| `doctor-network-error` | Doctor confirms a network-level failure (host / port / DNS / timeout). Inspect and re-init host/port. |
|
|
831
|
+
|
|
832
|
+
NextResult sets `branchId` and `branchDescription` after the fork; subsequent `--next` calls must echo `--branch <id>` to walk that branch. If the doctor JSON cannot be parsed or no keyword matches, `--next` falls back to the linear `recovery` plan — branching never causes `--next` to fail. `--apply` ignores `branches` entirely (linear walk unchanged).
|
|
833
|
+
|
|
766
834
|
**Exit codes**
|
|
767
835
|
|
|
768
836
|
| Exit | Condition |
|
|
@@ -859,7 +927,7 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
|
|
|
859
927
|
#### Boundaries
|
|
860
928
|
|
|
861
929
|
- Entries are append-only JSONL; rotation triggers at `~10 MB` or `~1000` entries (whichever first). Previous segment is preserved as `.jsonl.1`.
|
|
862
|
-
- Bi-directional `recovery_ref` / `audit_ref` linkage is wired on
|
|
930
|
+
- Bi-directional `recovery_ref` / `audit_ref` linkage is wired on every command that accepts `--recovery`: `query`, `inspect`, `insert`, `update`, `delete`, `export`, `q`, and `schema`. Use `audit tail --recovery-ref <id>` to find the audit entry an envelope was emitted alongside.
|
|
863
931
|
- Audit writer failures are non-fatal (D6): main command result and exit code are preserved; a stderr warning is emitted. `audit health` surfaces the failure reason.
|
|
864
932
|
- Reader truncation tolerance: a crash-truncated last line is skipped with a stderr warn `[dbcli audit] skipping truncated last line in <file>`; a mid-file non-JSON line is treated as corruption, exits 1, and points at `dbcli audit clear`.
|
|
865
933
|
|
|
@@ -1042,6 +1110,270 @@ Task storage layers:
|
|
|
1042
1110
|
Higher tiers override lower tiers by task name. Task name is derived from the
|
|
1043
1111
|
file path under the tier root (e.g. `diag/inspect.md` → `diag/inspect`).
|
|
1044
1112
|
|
|
1113
|
+
## Recovery Cookbook (agent walkthroughs)
|
|
1114
|
+
|
|
1115
|
+
End-to-end recovery sessions for the most common failure codes. All examples
|
|
1116
|
+
assume the agent invoked a `--recovery`-capable command and received a
|
|
1117
|
+
`RecoveryEnvelope` (or hit the same envelope via `dbcli recovery --code <CODE>`
|
|
1118
|
+
lookup). See [§recovery](#recovery) for the envelope shape, [§recover](#recover)
|
|
1119
|
+
for `--apply` / `--next` / risk-gate semantics, and [§audit](#audit) for the
|
|
1120
|
+
bi-directional `audit_ref` ⇄ `recovery_ref` pivot.
|
|
1121
|
+
|
|
1122
|
+
### Scenario index
|
|
1123
|
+
|
|
1124
|
+
| Code | Trigger | Primary remediation | Risk tier |
|
|
1125
|
+
|------|---------|---------------------|-----------|
|
|
1126
|
+
| `CONN_REFUSED` | Database process down or wrong host/port. | `dbcli doctor` → fix host/port → retry. | `readonly` |
|
|
1127
|
+
| `CONN_AUTH_FAILED` | Credentials rejected. | Re-check `.dbcli`/env, rotate credentials, `dbcli init --force` only on explicit user nod. | `readonly` → `interactive` |
|
|
1128
|
+
| `PERMISSION_DENIED` | Active permission level forbids the verb. | `dbcli inspect` to confirm level → escalate via `dbcli init` (human) or run a `--dry-run` instead. | `readonly` + `dry-run` |
|
|
1129
|
+
| `BLACKLIST_TABLE` | Target table is blacklisted. | `dbcli blacklist list` → `blacklist table remove <name>` (local-write tier). | `readonly` + `local-write` |
|
|
1130
|
+
| `BLACKLIST_COLUMN_WRITE` | INSERT/UPDATE touches a blacklisted column. | Re-shape payload to drop the column, or `blacklist column remove`. Envelope prepends a `--dry-run` preview step. | `dry-run` + `local-write` |
|
|
1131
|
+
| `SCHEMA_CACHE_MISSING` | Fresh checkout / new v2 connection / cache wiped. | `dbcli schema --refresh --force` (or `--use <conn>` per-connection). | `readonly` |
|
|
1132
|
+
| `SNIPPET_NOT_FOUND` / `SNIPPET_AMBIGUOUS` | Typo or duplicate snippet name. | `dbcli queries list` → `queries search <kw>` → run correct `@name`. | `readonly` |
|
|
1133
|
+
| `SNIPPET_PARAM_MISSING` | `--param k=v` not supplied. | `dbcli queries show @name` lists required params → re-run with full set. | `readonly` |
|
|
1134
|
+
| `CONFIG_MISSING` | No `.dbcli` in cwd. | `dbcli init` (human-driven). | `interactive` |
|
|
1135
|
+
|
|
1136
|
+
`risk` enum: `readonly` / `dry-run` / `write` / `unknown` (see §recovery boundaries).
|
|
1137
|
+
Allowlist tier: `readonly` / `dry-run` / `local-write` / `db-write` / `interactive` (see [§recover Risk gate matrix](#risk-gate-matrix)).
|
|
1138
|
+
|
|
1139
|
+
### S1 — CONN_REFUSED end-to-end
|
|
1140
|
+
|
|
1141
|
+
```bash
|
|
1142
|
+
# 1. Failing call writes envelope to stdout AND .dbcli/last-recovery.json
|
|
1143
|
+
$ dbcli query "SELECT 1" --recovery --format json
|
|
1144
|
+
{
|
|
1145
|
+
"schemaVersion": 1,
|
|
1146
|
+
"error": { "code": "CONN_REFUSED", "message": "..." },
|
|
1147
|
+
"audit_ref": "1f8e...c4d2",
|
|
1148
|
+
"recovery": [
|
|
1149
|
+
{ "order": 1, "command": "dbcli doctor --format json", "risk": "readonly", ... },
|
|
1150
|
+
{ "order": 2, "command": "dbcli inspect --for-agent", "risk": "readonly", ... }
|
|
1151
|
+
],
|
|
1152
|
+
"verify": { "command": "dbcli doctor --format json", "risk": "readonly", ... }
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
# 2. One-shot apply (only readonly + dry-run run by default)
|
|
1156
|
+
$ dbcli recover --apply --format json
|
|
1157
|
+
{ "finalStatus": "ok", "executed": [...], "verifyStatus": "passed" }
|
|
1158
|
+
# Exit 0 → root cause cleared (verify probe succeeded).
|
|
1159
|
+
|
|
1160
|
+
# 3. If verify reported `failed` / `indeterminate`, drop into --next for control
|
|
1161
|
+
$ dbcli recover --next --after-step 1 --result '{"status":"failed","exitCode":1}'
|
|
1162
|
+
# → returns a refined step 2 or `kind:"done"` based on the prevResult
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
### S2 — PERMISSION_DENIED with implicit `--dry-run` preview
|
|
1166
|
+
|
|
1167
|
+
```bash
|
|
1168
|
+
$ dbcli update orders --where "id=1" --set '{"status":"shipped"}' --recovery --format json
|
|
1169
|
+
{
|
|
1170
|
+
"error": { "code": "PERMISSION_DENIED", ... },
|
|
1171
|
+
"audit_ref": "9ab0...e711",
|
|
1172
|
+
"recovery": [
|
|
1173
|
+
{ "order": 1, "command": "dbcli update orders --where 'id=1' --set '<redacted>' --dry-run", "risk": "dry-run" },
|
|
1174
|
+
{ "order": 2, "command": "dbcli inspect --for-agent", "risk": "readonly" }
|
|
1175
|
+
]
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
# Default apply runs both steps (dry-run is in-tier).
|
|
1179
|
+
$ dbcli recover --apply
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
When the failing operation is INSERT/UPDATE/DELETE, the envelope prepends a
|
|
1183
|
+
`risk: 'dry-run'` step (the same write subcommand with `--dry-run`). Run it
|
|
1184
|
+
before any escalation — it both teaches the agent what the SQL looks like and
|
|
1185
|
+
proves the change is well-formed before raising the permission tier.
|
|
1186
|
+
|
|
1187
|
+
### S3 — BLACKLIST_TABLE (local-write remediation)
|
|
1188
|
+
|
|
1189
|
+
```bash
|
|
1190
|
+
$ dbcli query "SELECT * FROM audit_logs" --recovery --format json
|
|
1191
|
+
# error.code: BLACKLIST_TABLE
|
|
1192
|
+
# recovery[0]: dbcli blacklist list (risk: readonly)
|
|
1193
|
+
# recovery[1]: dbcli blacklist table remove audit_logs (risk: write — local-write tier)
|
|
1194
|
+
|
|
1195
|
+
# Default --apply: step 1 runs, step 2 skipped:risk → exit 3.
|
|
1196
|
+
$ dbcli recover --apply
|
|
1197
|
+
# To proceed: open the gate to local-write tier ONLY (does not touch DB).
|
|
1198
|
+
$ dbcli recover --apply --allow-write=readonly-cmd
|
|
1199
|
+
{ "finalStatus": "ok", "executed": [step1, step2], "verifyStatus": "passed" }
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
### S4 — BLACKLIST_COLUMN_WRITE (preview-then-drop)
|
|
1203
|
+
|
|
1204
|
+
```bash
|
|
1205
|
+
$ dbcli insert users --data '{"name":"a","ssn":"123"}' --recovery
|
|
1206
|
+
# recovery[0]: dbcli insert users --data '<redacted>' --dry-run (risk: dry-run)
|
|
1207
|
+
# recovery[1]: dbcli blacklist list (risk: readonly)
|
|
1208
|
+
# recovery[2]: dbcli blacklist column remove users.ssn (risk: write — local-write)
|
|
1209
|
+
|
|
1210
|
+
# Preferred path: don't widen the blacklist — re-shape the agent's payload to drop ssn.
|
|
1211
|
+
# Apply only the diagnostic prefix (steps 1+2) to confirm what columns are masked:
|
|
1212
|
+
$ dbcli recover --apply
|
|
1213
|
+
# Then re-issue insert without `ssn`.
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
### S5 — SCHEMA_CACHE_MISSING (fresh / multi-conn)
|
|
1217
|
+
|
|
1218
|
+
```bash
|
|
1219
|
+
$ dbcli inspect --require-schema-cache --recovery --format json
|
|
1220
|
+
# error.code: SCHEMA_CACHE_MISSING
|
|
1221
|
+
# recovery[0]: dbcli schema --refresh --force (risk: readonly — populates .dbcli/schemas/)
|
|
1222
|
+
# verify: dbcli inspect --format json (schemaCache.available === true)
|
|
1223
|
+
|
|
1224
|
+
$ dbcli recover --apply
|
|
1225
|
+
# Per-connection cache lives at .dbcli/schemas/<connection>/. If the failure was on
|
|
1226
|
+
# a v2 named connection, the envelope's command already carries `--use <name>`.
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
### S6 — SNIPPET_NOT_FOUND with disambiguation
|
|
1230
|
+
|
|
1231
|
+
```bash
|
|
1232
|
+
$ dbcli q @anaytics/revenue --recovery
|
|
1233
|
+
# typo: anaytics → analytics
|
|
1234
|
+
# recovery[0]: dbcli queries list --format json
|
|
1235
|
+
# recovery[1]: dbcli queries search analytics (or whatever --hint suggests)
|
|
1236
|
+
$ dbcli recover --apply
|
|
1237
|
+
# Agent reads stdoutSummary, identifies the correct @name, then re-issues:
|
|
1238
|
+
$ dbcli q @analytics/revenue --param days=30
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
### Multi-turn `--next` walkthrough (3-step plan)
|
|
1242
|
+
|
|
1243
|
+
Use `--next` instead of `--apply` when:
|
|
1244
|
+
|
|
1245
|
+
- `--apply` is too coarse-grained (the agent wants step-by-step inspection).
|
|
1246
|
+
- The plan contains an `interactive` step that `--apply` would skip.
|
|
1247
|
+
- The agent uses its own runner / sandbox and just wants dbcli to drive cursoring.
|
|
1248
|
+
|
|
1249
|
+
`--next` returns one step at a time, given which step the agent **just executed**
|
|
1250
|
+
and a `StepResultSummary` of how it went. dbcli does not persist the cursor —
|
|
1251
|
+
the agent owns `--after-step`.
|
|
1252
|
+
|
|
1253
|
+
```bash
|
|
1254
|
+
# Envelope already saved at .dbcli/last-recovery.json (3-step plan, CONN_REFUSED).
|
|
1255
|
+
|
|
1256
|
+
# Round 1 — agent reads step 1 from the envelope, executes it itself, then asks
|
|
1257
|
+
# dbcli for the next step.
|
|
1258
|
+
$ dbcli recover --next --after-step 1 --result '{"status":"ok","exitCode":0}' --format json
|
|
1259
|
+
{
|
|
1260
|
+
"schemaVersion": 1,
|
|
1261
|
+
"kind": "step",
|
|
1262
|
+
"errorCode": "CONN_REFUSED",
|
|
1263
|
+
"cursor": 2,
|
|
1264
|
+
"totalSteps": 3,
|
|
1265
|
+
"step": { "order": 2, "command": "dbcli inspect --for-agent", "risk": "readonly", ... }
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
# Round 2 — bigger stdout, save to file and reference it.
|
|
1269
|
+
$ ./run-step.sh > /tmp/r2.json # agent's own runner; result is StepResultSummary JSON
|
|
1270
|
+
$ dbcli recover --next --after-step 2 --result @/tmp/r2.json
|
|
1271
|
+
{ "kind": "step", "cursor": 3, "step": { "order": 3, ... } }
|
|
1272
|
+
|
|
1273
|
+
# Round 3 — last step done.
|
|
1274
|
+
$ dbcli recover --next --after-step 3 --result '{"status":"ok"}'
|
|
1275
|
+
{ "kind": "done", "cursor": 3, "totalSteps": 3 }
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
`StepResultSummary` contract (recap of [§recover Multi-turn](#multi-turn---next-p2)):
|
|
1279
|
+
|
|
1280
|
+
```ts
|
|
1281
|
+
interface StepResultSummary {
|
|
1282
|
+
status: 'ok' | 'failed' | 'skipped'
|
|
1283
|
+
exitCode?: number
|
|
1284
|
+
stdoutSummary?: string // last 4 KB
|
|
1285
|
+
stderrSummary?: string // last 4 KB
|
|
1286
|
+
}
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
Truncate to the **last** 4 KB before passing — the head of a huge stdout is
|
|
1290
|
+
usually not what disambiguates next steps.
|
|
1291
|
+
|
|
1292
|
+
Verification is **not** automatic under `--next`. If the agent wants the same
|
|
1293
|
+
verify probe `--apply` runs, it must execute the envelope's `verify` step
|
|
1294
|
+
itself after the plan completes.
|
|
1295
|
+
|
|
1296
|
+
### Bi-directional pivot (envelope ⇄ audit)
|
|
1297
|
+
|
|
1298
|
+
Every `--recovery`-capable failure (`query`, `inspect`, `insert`, `update`,
|
|
1299
|
+
`delete`, `export`, `q`, `schema`) writes **both** sides of a UUID link:
|
|
1300
|
+
|
|
1301
|
+
- `RecoveryEnvelope.audit_ref` → the `audit.id` for the same failure.
|
|
1302
|
+
- `AuditEntry.recovery_ref` → the envelope's id (also the auto-saved
|
|
1303
|
+
`.dbcli/last-recovery.json` filename trace).
|
|
1304
|
+
|
|
1305
|
+
```bash
|
|
1306
|
+
# From envelope → audit (forensics on a saved failure)
|
|
1307
|
+
$ ENV_ID=$(jq -r '.id' .dbcli/last-recovery.json) # or read from stdout
|
|
1308
|
+
$ dbcli audit show --recovery-ref "$ENV_ID" --format json
|
|
1309
|
+
# Returns the matching audit entry (full, not brief).
|
|
1310
|
+
|
|
1311
|
+
# From audit → envelope (you have an audit hit, want the structured plan)
|
|
1312
|
+
$ AUDIT_ID=$(dbcli audit tail --for-agent --n 1 | jq -r '.[0].id')
|
|
1313
|
+
$ dbcli audit show "$AUDIT_ID" --format json
|
|
1314
|
+
# Read `recovery_ref` from the entry, then either re-run --recovery against
|
|
1315
|
+
# the original command or load the saved envelope:
|
|
1316
|
+
$ jq '.recovery_ref' .dbcli/last-recovery.json | grep -q "$RECOVERY_REF" \
|
|
1317
|
+
&& dbcli recover --format markdown # human inspect
|
|
1318
|
+
|| dbcli recover --from /path/to/archived.json --format markdown
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
Session handoff: a fresh agent that opens `dbcli inspect --for-agent`,
|
|
1322
|
+
`dbcli guide`, `dbcli recover`, or `dbcli recover --apply` gets an
|
|
1323
|
+
`audit_recent: AuditEntryBrief[]` field (last 5 entries) embedded in the JSON
|
|
1324
|
+
output — no extra round-trip to the audit CLI needed for immediate history
|
|
1325
|
+
context.
|
|
1326
|
+
|
|
1327
|
+
### Risk gate cheat sheet
|
|
1328
|
+
|
|
1329
|
+
Quick reference for what `--apply` runs at each `--allow-write` level. The
|
|
1330
|
+
canonical matrix lives at [§recover Risk gate matrix](#risk-gate-matrix); this
|
|
1331
|
+
table maps it onto common agent intents.
|
|
1332
|
+
|
|
1333
|
+
| Agent intent | Recommended flag | What runs | What's skipped |
|
|
1334
|
+
|---|---|---|---|
|
|
1335
|
+
| Probe-only (read state, learn) | `--apply` (default) | `readonly` + `dry-run` steps | `local-write`, `db-write`, `interactive` |
|
|
1336
|
+
| Local config remediation (e.g. `blacklist remove`) | `--apply --allow-write=readonly-cmd` | + `local-write` | `db-write`, `interactive` |
|
|
1337
|
+
| Database write recovery (rare; trusted plan) | `--apply --allow-write=write-cmd` | + `db-write` | `interactive` |
|
|
1338
|
+
| Interactive step (e.g. `dbcli init`) | Drive manually OR use `--next` | n/a | All interactive steps always skip under `--apply` |
|
|
1339
|
+
| Walk plan step-by-step with own runner | `--next --after-step N --result …` | one step per call | n/a — agent owns cursor + execution |
|
|
1340
|
+
|
|
1341
|
+
Three rules that always apply regardless of `--allow-write`:
|
|
1342
|
+
|
|
1343
|
+
1. **Tier is code-owned, not envelope-claimed.** The risk gate reads the
|
|
1344
|
+
per-error-code allowlist after parsing argv. An envelope cannot escalate
|
|
1345
|
+
itself by setting `risk: 'readonly'` on a write subcommand — argv decides.
|
|
1346
|
+
2. **Placeholders block.** A step with unresolved `<token>` placeholders is
|
|
1347
|
+
skipped as `skipped:placeholder` even at `--allow-write=write-cmd`. Bind
|
|
1348
|
+
them at `recovery` lookup time with `--hint` / `--snippet` / `--table`, or
|
|
1349
|
+
ask the user.
|
|
1350
|
+
3. **Verify is signal, not gate.** `verifyStatus` ∈ `{passed, failed,
|
|
1351
|
+
indeterminate}` reports whether the original failure looks resolved.
|
|
1352
|
+
`recover --apply` exit code is set by step execution, not verification.
|
|
1353
|
+
|
|
1354
|
+
### Common pitfalls
|
|
1355
|
+
|
|
1356
|
+
- **Stale `.dbcli/last-recovery.json`.** `recover` (no `--apply`) shows the
|
|
1357
|
+
*saved* plan, which may be hours old. Re-run the original command with
|
|
1358
|
+
`--recovery` to refresh it, or pass `--from <file>` to load an archived one.
|
|
1359
|
+
- **`.dbcli/` is gitignored.** Do not check `last-recovery.json` into a repo
|
|
1360
|
+
for "reproducibility"; it contains sanitized command snapshots but the
|
|
1361
|
+
workspace `cwd` only makes sense locally. Use `recover --from <archived.json>`
|
|
1362
|
+
for cross-machine replay.
|
|
1363
|
+
- **`--apply` exit 3 means every step skipped.** Not a failure — it means the
|
|
1364
|
+
default gate was too tight. Either widen with `--allow-write`, fill
|
|
1365
|
+
placeholders, or fall back to `--next` and drive steps manually.
|
|
1366
|
+
- **`--next` does not run verify.** Re-run the original failing command with
|
|
1367
|
+
`--recovery` once the plan is done; if it now succeeds (no envelope on
|
|
1368
|
+
stdout), recovery is complete. Or invoke `envelope.verify.command` yourself.
|
|
1369
|
+
- **Audit writer failures are non-fatal.** If `audit health` reports
|
|
1370
|
+
`lastWriteOk: false`, the main command still completed — but `recovery_ref`
|
|
1371
|
+
⇄ `audit_ref` linkage is broken for that one call. `audit health` surfaces
|
|
1372
|
+
the underlying error (disk full, EACCES, etc.).
|
|
1373
|
+
- **Cross-connection forensics.** `audit tail --all --for-agent` merges all
|
|
1374
|
+
connections; `audit show <id-prefix> --all` returns an envelope `{connection,
|
|
1375
|
+
entry}` so a fresh agent can tell which DB the failure was against.
|
|
1376
|
+
|
|
1045
1377
|
## Interactive HTML dashboard
|
|
1046
1378
|
|
|
1047
1379
|
`query`, `q`, and `export` can render results as a single, fully self-contained
|
|
@@ -1150,19 +1482,21 @@ MongoDB connections use a JSON-based query model instead of SQL. Treat MongoDB s
|
|
|
1150
1482
|
|
|
1151
1483
|
Atlas-style `mongodb+srv://` URIs are supported. `list` and `query` run against the database configured for the connection, and `query` always requires `--collection <name>`.
|
|
1152
1484
|
|
|
1153
|
-
**Supported commands:** `init`, `use`, `list`, `schema`, `query`, `insert`, `update`, `delete`, `status`, `shell`, `doctor`, `upgrade`, `completion`
|
|
1485
|
+
**Supported commands:** `init`, `use`, `list`, `schema`, `query`, `q`, `insert`, `update`, `delete`, `export`, `status`, `shell`, `doctor`, `upgrade`, `completion`
|
|
1154
1486
|
|
|
1155
1487
|
**Limited support:**
|
|
1156
1488
|
|
|
1157
1489
|
- `schema` samples collection documents to infer field names/types. It does not provide relational constraints, primary keys, foreign keys, or reliable index metadata.
|
|
1158
1490
|
- `query` accepts only JSON object filters or aggregation pipeline arrays and always requires `--collection <name>`.
|
|
1491
|
+
- `q` saved-query execution accepts JSON `find` / `aggregate` bodies, requires a `collection` frontmatter field (CLI `--collection` overrides), JSON-encodes every `{{param}}` substitution, and enforces table-level blacklist plus document field masking before rendering.
|
|
1159
1492
|
- `insert` inserts one JSON document into the named collection.
|
|
1160
1493
|
- `update` accepts a JSON filter in `--where` or simple `key=value` conditions. If `--set` does not use MongoDB update operators such as `$set`, dbcli wraps it in `$set`.
|
|
1161
1494
|
- `delete` deletes all documents matching the JSON/simple filter.
|
|
1495
|
+
- `export` accepts the same JSON filter / aggregation syntax as `query`.
|
|
1162
1496
|
- MongoDB write paths do not currently provide the same SQL dry-run, relational schema validation, or column-level blacklist filtering guarantees as SQL writes.
|
|
1163
1497
|
- `shell` blocks raw SQL for MongoDB; use `query <json> --collection <name>` inside the shell.
|
|
1164
1498
|
|
|
1165
|
-
**Not supported (exit with error):** `
|
|
1499
|
+
**Not supported (exit with error):** `diff`, `migrate`
|
|
1166
1500
|
|
|
1167
1501
|
**Not a supported MongoDB target:** `check` is designed for relational health checks and emits SQL-style checks.
|
|
1168
1502
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: active-users
|
|
3
|
+
-- engine: mongodb
|
|
4
|
+
-- operation: find
|
|
5
|
+
-- target: users
|
|
6
|
+
-- description: Active users matching the given status
|
|
7
|
+
-- params:
|
|
8
|
+
-- status:
|
|
9
|
+
-- type: string
|
|
10
|
+
-- required: true
|
|
11
|
+
-- ---
|
|
12
|
+
{
|
|
13
|
+
"status": {{status}}
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: top-orders-by-city
|
|
3
|
+
-- engine: mongodb
|
|
4
|
+
-- operation: aggregate
|
|
5
|
+
-- target: orders
|
|
6
|
+
-- description: Top order counts per city for a given status
|
|
7
|
+
-- params:
|
|
8
|
+
-- status:
|
|
9
|
+
-- type: string
|
|
10
|
+
-- required: true
|
|
11
|
+
-- limit:
|
|
12
|
+
-- type: int
|
|
13
|
+
-- default: 10
|
|
14
|
+
-- ---
|
|
15
|
+
[
|
|
16
|
+
{ "$match": { "status": {{status}} } },
|
|
17
|
+
{ "$group": { "_id": "$city", "n": { "$sum": 1 } } },
|
|
18
|
+
{ "$sort": { "n": -1 } },
|
|
19
|
+
{ "$limit": {{limit}} }
|
|
20
|
+
]
|