@carllee1983/dbcli 9.1.1 → 10.0.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 +55 -17
- package/.cursor/skills/dbcli/reference.md +71 -18
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/skills/dbcli/SKILL.md +55 -17
- package/.github/skills/dbcli/reference.md +71 -18
- package/CHANGELOG.md +157 -0
- package/README.dev.md +19 -6
- package/README.md +68 -56
- package/README.zh-TW.md +45 -12
- package/assets/SKILL.md +55 -17
- package/assets/reference.md +71 -18
- package/assets/ui-template.html +24 -24
- package/dist/agent-core.mjs +5 -5
- package/dist/cli-runtime.mjs +2683 -3425
- package/dist/cli.mjs +5 -7
- package/dist/core.d.ts +7 -9
- package/dist/core.mjs +537 -1537
- package/gemini-extension.json +1 -1
- package/package.json +3 -5
- package/plugins/dbcli-agent/.codex-plugin/plugin.json +1 -1
- package/plugins/dbcli-agent/skills/dbcli/SKILL.md +55 -17
- package/plugins/dbcli-agent/skills/dbcli/reference.md +71 -18
- package/scripts/postinstall-check-bun.mjs +1 -1
- package/skills/dbcli/SKILL.md +55 -17
- package/skills/dbcli/reference.md +71 -18
- package/.agents/skills/story-development/SKILL.md +0 -70
|
@@ -119,24 +119,24 @@ dbcli query '{}' --collection events --format json 2>/dev/null | jq '.rows | len
|
|
|
119
119
|
Initialize `.dbcli` configuration file. Typically run manually by the developer — avoid running on behalf of the user unless explicitly requested.
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
dbcli init #
|
|
123
|
-
dbcli init --system mysql --host localhost --port 3306 --user root --name mydb
|
|
122
|
+
dbcli init # Prompt for a name; create named v2
|
|
123
|
+
dbcli init --conn-name local --system mysql --host localhost --port 3306 --user root --name mydb
|
|
124
124
|
dbcli init --use-env-refs # Store env var references
|
|
125
|
-
dbcli init --no-interactive --force
|
|
125
|
+
dbcli init --conn-name local --no-interactive --force # Non-interactive; credentials from environment
|
|
126
126
|
|
|
127
127
|
# MongoDB — field-by-field (primary path, same shape as SQL)
|
|
128
|
-
dbcli init --system mongodb --host localhost --port 27017 --user admin --password secret --auth-source admin --name mydb
|
|
129
|
-
dbcli init --system mongodb --host localhost --port 27017 --name mydb # No auth
|
|
128
|
+
dbcli init --conn-name local --system mongodb --host localhost --port 27017 --user admin --password secret --auth-source admin --name mydb
|
|
129
|
+
dbcli init --conn-name local --system mongodb --host localhost --port 27017 --name mydb # No auth
|
|
130
130
|
# MongoDB — full URI (advanced fallback: multi-host, non-standard driver options)
|
|
131
|
-
dbcli init --system mongodb --uri "mongodb://user:pass@host:27017/mydb?authSource=admin"
|
|
131
|
+
dbcli init --conn-name local --system mongodb --uri "mongodb://user:pass@host:27017/mydb?authSource=admin"
|
|
132
132
|
|
|
133
133
|
# Redis (database = logical DB index)
|
|
134
|
-
dbcli init --system redis --host localhost --port 6379
|
|
135
|
-
dbcli init --system redis --host localhost --port 6379 --password secret --name 0
|
|
134
|
+
dbcli init --conn-name local --system redis --host localhost --port 6379
|
|
135
|
+
dbcli init --conn-name local --system redis --host localhost --port 6379 --password secret --name 0
|
|
136
136
|
|
|
137
137
|
# Elasticsearch
|
|
138
|
-
dbcli init --system elasticsearch --host localhost --port 9200 --user elastic --password changeme
|
|
139
|
-
dbcli init --system elasticsearch --cloud-id "myCluster:dXMtZWFzdC0xLmF3..." --api-key "<base64>"
|
|
138
|
+
dbcli init --conn-name local --system elasticsearch --host localhost --port 9200 --user elastic --password changeme
|
|
139
|
+
dbcli init --conn-name local --system elasticsearch --cloud-id "myCluster:dXMtZWFzdC0xLmF3..." --api-key "<base64>"
|
|
140
140
|
|
|
141
141
|
# Multi-connection (v2 format)
|
|
142
142
|
dbcli init --conn-name staging --env-file .env.staging # Named connection with custom env file
|
|
@@ -151,6 +151,12 @@ dbcli --global init --conn-name shared --system postgresql --host db.example.com
|
|
|
151
151
|
dbcli --global use --list
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
Every new or additional connection needs a nonblank connection name. Pass `--conn-name <name>`, or run `dbcli init` in an interactive terminal to be asked for one. The name prompt has no suggested `default`; empty or whitespace-only answers explain the requirement and prompt again. Cancelling or ending the name prompt stops before any connection test or configuration/credential write. An explicit nonblank `--conn-name` skips this prompt, and `--conn-name default` is valid. An explicitly blank `--conn-name` is an error in every mode, before connection tests or writes. `--name` still means the database name (the logical DB index for Redis), never the connection name.
|
|
155
|
+
|
|
156
|
+
Without a TTY, with `--no-interactive`, or when `--use-env-refs` plus all five `--env-*` options automatically disables interaction, a missing or blank `--conn-name` fails with guidance to supply it, before database access or configuration/credential writes. Complete credentials, `--name`, `--env-file`, and `--force` do not supply a connection name.
|
|
157
|
+
|
|
158
|
+
New initialization always creates named v2 configuration, including plain `init` and explicit `--config` paths; it no longer creates an unnamed v1 configuration. Existing v1 configurations remain readable and their established named v2 import is retained. The first explicitly named connection is still the default in a new registry; adding a connection preserves an existing registry's default or no-default state. An explicitly chosen duplicate name still requires interactive overwrite confirmation or `--force`; a noninteractive duplicate without `--force`, or a declined confirmation, leaves files untouched. `--remove` and `--rename` do not ask for a new connection name.
|
|
159
|
+
|
|
154
160
|
**Key options:** `--system`, `--permission`, `--use-env-refs`, `--skip-test`, `--no-interactive`, `--force`, `--conn-name <name>`, `--env-file <path>`, `--remove <name>`, `--rename <old:new>`
|
|
155
161
|
|
|
156
162
|
**Environment-reference options:** `--env-host <var>`, `--env-port <var>`, `--env-user <var>`, `--env-password <var>`, `--env-database <var>`
|
|
@@ -161,7 +167,27 @@ dbcli --global use --list
|
|
|
161
167
|
|
|
162
168
|
**Redis note:** the `database` (or `--name`) field is the logical DB index (`"0"` … `"15"`), not a database name.
|
|
163
169
|
|
|
164
|
-
**Multi-connection:**
|
|
170
|
+
**Multi-connection:** Every newly created connection uses v2 with an explicitly supplied or interactively entered name. Each connection can have its own env file and permission level; `--env-file` does not replace the name requirement. Existing v1 configs are automatically imported as the `default` connection when upgrading.
|
|
171
|
+
|
|
172
|
+
V2 may omit the top-level `default` field; if supplied, it must be a nonempty
|
|
173
|
+
string naming an existing connection. `null`, `""`, and nonexistent names are
|
|
174
|
+
invalid. The first explicitly named connection defaults a new registry; adding
|
|
175
|
+
another preserves the existing default or no-default state. Existing v1 reads
|
|
176
|
+
and named v1 imports remain supported; neither configuration version changes.
|
|
177
|
+
|
|
178
|
+
Legacy project configuration compatibility: adding a connection cannot import a
|
|
179
|
+
direct-project v2 registry when an existing connection uses an `envFile` other
|
|
180
|
+
than `.env.local`. `init` refuses before writing and retains the existing config
|
|
181
|
+
and env files. An administrator must migrate the registry and custom env files
|
|
182
|
+
to supported home storage before retrying. Bound/home-storage v2 configs and
|
|
183
|
+
direct-project v2 configs with no `envFile` or only `.env.local` remain supported.
|
|
184
|
+
|
|
185
|
+
`init --remove <name>` clears `default` and reports that change when removing its
|
|
186
|
+
connection; it never chooses another connection. Removing a non-default keeps
|
|
187
|
+
the saved default, and removing a connection from a no-default config keeps that
|
|
188
|
+
state. The public `removeConnection` helper follows the same rules. Deleting
|
|
189
|
+
the last connection is rejected without changing the config. Renaming preserves
|
|
190
|
+
the no-default state, or updates the default name when renaming that connection.
|
|
165
191
|
|
|
166
192
|
Use root-level `--global` with `init`, `use`, `status`, `query`, or any other command to read or mutate the user-global v2 registry at `~/.config/dbcli/config.json`. Without it, the current project binding remains the source of truth. The global registry uses the same private file mode and integrity record as project home storage.
|
|
167
193
|
|
|
@@ -169,11 +195,12 @@ Use root-level `--global` with `init`, `use`, `status`, `query`, or any other co
|
|
|
169
195
|
|
|
170
196
|
### use
|
|
171
197
|
|
|
172
|
-
|
|
198
|
+
Set, clear, or display the default database connection (v2 multi-connection config).
|
|
173
199
|
|
|
174
200
|
```bash
|
|
175
|
-
dbcli use # Show current default
|
|
201
|
+
dbcli use # Show the current default, or describe no default
|
|
176
202
|
dbcli use staging # Switch default to 'staging'
|
|
203
|
+
dbcli use --unset # Clear the saved default; connections are unchanged
|
|
177
204
|
dbcli use --list # List all connections (* marks default)
|
|
178
205
|
dbcli use --list --format json # Credential-free connection identity inventory
|
|
179
206
|
```
|
|
@@ -188,17 +215,43 @@ Cloud ID-only Elasticsearch connections also return `null` instead of default
|
|
|
188
215
|
placeholders. It deliberately excludes user names, passwords, URIs, Cloud IDs,
|
|
189
216
|
API keys, and env variable names.
|
|
190
217
|
Misspelled selectors suggest nearby configured connection names.
|
|
218
|
+
Without a default, text inventory marks no connection as default and every JSON
|
|
219
|
+
item has `isDefault: false`. Inventory remains usable, and `doctor` accepts an
|
|
220
|
+
omitted default as valid v2 configuration. Its connection checks still require
|
|
221
|
+
an explicit selector, for example `dbcli --use staging doctor`.
|
|
191
222
|
|
|
192
|
-
Any command can also use `--use <name>`
|
|
223
|
+
Any command can also use root-level `--use <name>` before the command to
|
|
224
|
+
temporarily select a connection without changing the default. `query`, `schema`,
|
|
225
|
+
`list`, `export`, and `check` also accept it after the command:
|
|
193
226
|
|
|
194
227
|
```bash
|
|
195
228
|
dbcli query --use staging "SELECT * FROM users LIMIT 10"
|
|
196
229
|
dbcli list --use prod
|
|
197
230
|
```
|
|
198
231
|
|
|
232
|
+
Selection precedence is explicit `--use`, then `DBCLI_CONNECTION`, then the
|
|
233
|
+
saved default. Conflicting root-level and command-level selectors are an error;
|
|
234
|
+
blank CLI selectors are invalid, while a blank environment selector is ignored.
|
|
235
|
+
Without a default, connection-dependent commands require an explicit `--use` or
|
|
236
|
+
`DBCLI_CONNECTION` selection. Otherwise they fail before database access with
|
|
237
|
+
an error naming both selectors and listing available connection names, never
|
|
238
|
+
endpoints or credentials. No caller selects the first connection automatically.
|
|
239
|
+
Unknown names and production targets retain their validation and explicit
|
|
240
|
+
selection safeguards.
|
|
241
|
+
|
|
242
|
+
`use --unset` removes only the persisted v2 `default` field and reports that it
|
|
243
|
+
was cleared. It also succeeds when the field is already absent without changing
|
|
244
|
+
connections. It rejects a connection name, `--list`, `--confirm-production`, or
|
|
245
|
+
`--format json` in the same invocation before writing, and never converts or
|
|
246
|
+
overwrites v1. It uses the existing approved, integrity-protected configuration
|
|
247
|
+
write path and is blocked under `DBCLI_AGENT_MODE=1`. To set a default again, use
|
|
248
|
+
`dbcli use <name>`; production defaults still require the exact name repeated in
|
|
249
|
+
`--confirm-production <name>`, and production database access still requires an
|
|
250
|
+
explicit selector even if that connection is the saved default.
|
|
251
|
+
|
|
199
252
|
**Requires v2 config** (created with `dbcli init --conn-name`).
|
|
200
253
|
|
|
201
|
-
**Options:** `--list`, `--format <text|json>`, `--confirm-production <name>` (required when explicitly selecting a production connection as the default).
|
|
254
|
+
**Options:** `--list`, `--unset`, `--format <text|json>`, `--confirm-production <name>` (required when explicitly selecting a production connection as the default).
|
|
202
255
|
|
|
203
256
|
### password
|
|
204
257
|
|
|
@@ -3591,7 +3644,7 @@ Parser behaviour (`src/core/saved-queries/parser.ts::normaliseVisual`):
|
|
|
3591
3644
|
|
|
3592
3645
|
MongoDB connections use a JSON-based query model instead of SQL. Treat MongoDB support as a narrower document-database path, not as a full SQL feature equivalent.
|
|
3593
3646
|
|
|
3594
|
-
`init --system mongodb` defaults to a field-by-field wizard (`host`, `srv`, `port`, `user`, `password` + `authSource`, then optional `replicaSet` / `tls`); a full `uri` is an explicit advanced choice in the interactive flow and the
|
|
3647
|
+
`init --system mongodb` defaults to a field-by-field wizard (`host`, `srv`, `port`, `user`, `password` + `authSource`, then optional `replicaSet` / `tls`); a full `uri` is an explicit advanced choice in the interactive flow and the non-interactive path via `--uri` (with the required `--conn-name`). Optional fields `authSource`, `replicaSet`, `tls`, and `srv` express what previously required embedding options in the `uri` query string. Atlas-style `mongodb+srv://` URIs are supported both as a full `uri` and via the per-field `srv: true` option. `list` and `query` run against the database configured for the connection, and `query` always requires `--collection <name>`.
|
|
3595
3648
|
|
|
3596
3649
|
The 5000ms default server-selection timeout is often too tight for a connection over a VPN or to Atlas. Set a `timeout` field (ms) in the connection config, or override it per invocation with root-level `--timeout`, e.g. `dbcli --timeout 20000 --use <conn> list`.
|
|
3597
3650
|
|
|
@@ -3617,10 +3670,10 @@ The 5000ms default server-selection timeout is often too tight for a connection
|
|
|
3617
3670
|
|
|
3618
3671
|
```bash
|
|
3619
3672
|
# 1. Initialize — field-by-field (primary path)
|
|
3620
|
-
dbcli init --system mongodb --host localhost --port 27017 \
|
|
3673
|
+
dbcli init --conn-name local --system mongodb --host localhost --port 27017 \
|
|
3621
3674
|
--user admin --password '<secret>' --auth-source admin --name mydb
|
|
3622
3675
|
# ...or a full URI (advanced fallback, e.g. Atlas SRV clusters)
|
|
3623
|
-
dbcli init --system mongodb --uri "mongodb+srv://user:pass@cluster.example.mongodb.net/mydb"
|
|
3676
|
+
dbcli init --conn-name local --system mongodb --uri "mongodb+srv://user:pass@cluster.example.mongodb.net/mydb"
|
|
3624
3677
|
|
|
3625
3678
|
# 2. List collections
|
|
3626
3679
|
dbcli list --format json
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,163 @@ All notable changes to dbcli are documented here.
|
|
|
5
5
|
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
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [10.0.0] - 2026-10-13
|
|
11
|
+
|
|
12
|
+
這次發布整合 npm 9.1.2 之後合併的變更:明確命名連線、可不設預設連線、Bun 1.4.0
|
|
13
|
+
最低版本、PostgreSQL schema 修正、帶期限的 audit 豁免,以及實錄的 agent 操作影片。
|
|
14
|
+
9.2.0 曾完成發布準備,但未發布到 npm;原本的 9.2.0 與 Unreleased 更新紀錄合併於此。
|
|
15
|
+
|
|
16
|
+
版本為 **10.0.0**。新連線不再自動取名,刪除預設連線也不再自動改選另一條;這兩項
|
|
17
|
+
行為會影響既有腳本,所以採用 major 版本。
|
|
18
|
+
|
|
19
|
+
### Breaking changes and upgrade notes
|
|
20
|
+
|
|
21
|
+
- **非互動式初始化必須指定 `--conn-name <連線名稱>`。** 適用於非 TTY、
|
|
22
|
+
`--no-interactive` 與完整 env-reference 自動非互動模式;互動模式會詢問名稱。
|
|
23
|
+
`--name` 仍表示資料庫名稱,不能拿它代替 `--conn-name`。原先依賴自動命名的腳本
|
|
24
|
+
須補上連線名稱;明確指定 `--conn-name default` 仍合法。
|
|
25
|
+
- **升級 Bun 至 1.4.0 以上。** 仍使用 1.3.x 的環境須先升級,原因與相依套件細節見下方。
|
|
26
|
+
- **既有 v1 設定讀取與具名匯入仍保留。** 單純 `init` 與明確 `--config` 新建連線
|
|
27
|
+
改用具名 v2;全新 registry 的第一條具名連線仍會成為預設,追加連線則保留既有的
|
|
28
|
+
default/no-default 狀態,不會偷偷建立或替換預設。
|
|
29
|
+
- **預設連線可以清除,刪除後不再自動補選。** 使用 `dbcli use --unset` 清除預設;
|
|
30
|
+
刪除預設連線也會留下無預設狀態,而不是選取下一條。之後須透過 `--use` 或
|
|
31
|
+
`DBCLI_CONNECTION` 選取,或以 `dbcli use <連線名稱>` 明確設定新預設;仍禁止刪除
|
|
32
|
+
最後一條連線。
|
|
33
|
+
- **帶自訂 `envFile` 的直接專案 v2 設定須先遷移。** 若新增連線需要匯入舊版直接
|
|
34
|
+
專案 v2 設定,而它的 `envFile` 不是 `.env.local`,`init` 會在寫入前拒絕並保留
|
|
35
|
+
原檔。須先由管理員完成 home storage 遷移,再新增連線。
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **介紹頁與 README 加上一段實錄的 agent 操作影片。** 一段真實的 Claude Code session
|
|
40
|
+
對著一個用完即丟的 PostgreSQL 操作:agent 透過 dbcli 讀資料,被列入黑名單的
|
|
41
|
+
`password_hash` 欄位帶著 dbcli 的安全提示被略去,它在 query-only 連線上的寫入被拒絕。
|
|
42
|
+
影片放在兩個語系介紹頁的 #safety 區,兩份 README 各以縮圖連到自己語系的頁面。
|
|
43
|
+
`scripts/demo/` 保留 seed、設定、錄製與剪輯腳本,CLI 輸出改變時可以重錄。
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **新建或新增連線必須明確命名。** `init` 未提供 `--conn-name` 時會在互動式
|
|
48
|
+
終端機主動詢問名稱,不再代填 `default`;空白回答會說明並再次詢問,取消或
|
|
49
|
+
結束提示不會寫入;明確傳入空白名稱則在任何模式都報錯。非 TTY、
|
|
50
|
+
`--no-interactive` 或完整 env-reference 自動非互動
|
|
51
|
+
模式缺少名稱時,會在連線測試、設定及憑證寫入前報錯。`--name` 仍是資料庫名,
|
|
52
|
+
明確指定 `--conn-name default` 仍合法。單純 `init` 與明確 `--config` 都改用
|
|
53
|
+
具名 v2 新建,既有 v1 讀取與具名匯入保留。全新 registry 仍以第一條具名連線
|
|
54
|
+
為預設,追加連線保留既有 default/no-default;同名覆寫確認及 `--force` 保護
|
|
55
|
+
維持不變(#212)。
|
|
56
|
+
|
|
57
|
+
- **v2 可以不設定預設連線。** 省略 `default` 即可要求每次透過 `--use` 或
|
|
58
|
+
`DBCLI_CONNECTION` 明確選取;未選取時會在連線前失敗,列出可用名稱而不洩漏
|
|
59
|
+
端點或憑證。新增 `dbcli use --unset`,透過既有核准與 integrity record 保護
|
|
60
|
+
流程清除預設值,重複執行也安全。刪除預設連線會清除預設值,不再依 JSON
|
|
61
|
+
順序改選另一條;仍禁止刪除最後一條連線。清單與 doctor 支援無預設狀態,
|
|
62
|
+
初始化與 v1 遷移建立預設值的方式、selector 優先序與正式環境防護不變(#212)。
|
|
63
|
+
若新增連線會匯入帶有自訂 `envFile`(非 `.env.local`)的舊版直接專案 v2
|
|
64
|
+
設定,`init` 會在寫入前拒絕並保留原檔,須先由管理員完成 home storage 遷移。
|
|
65
|
+
|
|
66
|
+
- **Bun 最低版本從 1.3.3 提高到 1.4.0。** `mongodb@7.2.0` 依賴 `bson: "^7.2.0"`,
|
|
67
|
+
不帶 lockfile 的使用者安裝會解析到 bson 7.3+。bson 7.3.0 起,`ObjectId` 載入時會呼叫
|
|
68
|
+
`v8.startupSnapshot.isBuildingSnapshot()`,Bun 1.3.x 對此丟出
|
|
69
|
+
`NotImplementedError: node:v8 isBuildingSnapshot is not yet implemented in Bun.`,
|
|
70
|
+
任何碰到 MongoDB 的指令都會失敗。實測 Bun 1.3.3 與 1.3.10–1.3.14 都會失敗,
|
|
71
|
+
1.4.0–1.4.3 都正常。本 repo 的 `bun.lock` 把 bson 鎖在 7.2.0,所以 CI 的 1.3.3 那一列
|
|
72
|
+
從來沒碰到這個問題。`engines.bun`、CI 最低版本、postinstall 提示、`doctor` 的預設值與
|
|
73
|
+
使用者文件都改為 1.4.0。
|
|
74
|
+
|
|
75
|
+
- **audit gate 可以帶有期限、附理由的豁免。** `scripts/audit-exemptions.json` 逐筆列出
|
|
76
|
+
GHSA id、套件、理由與 UTC 到期日。未到期的項目轉成 `bun audit --ignore` 參數,每次執行
|
|
77
|
+
都印出來;過期或格式錯誤的項目讓 gate 失敗,所以豁免不會悄悄變成永久。第一筆豁免
|
|
78
|
+
GHSA-vfj7-8cjw-p6xm(`braces` <= 3.0.3,沒有修正版,只經由建置期的 tailwindcss 引入)
|
|
79
|
+
到 2026-11-30。決定記在 ADR-0042。
|
|
80
|
+
|
|
81
|
+
- **發布流程改由版本 tag 驅動。** 合併發布準備 PR 後才在 `main` 建立 `vX.Y.Z`;
|
|
82
|
+
工作流程核對版本與來源、啟動測試資料庫並執行 `make verify`,通過後等待
|
|
83
|
+
`npm-publish` 環境審批,再透過 npm trusted publishing 發布附 provenance 的套件,
|
|
84
|
+
最後從本檔對應版本章節建立 GitHub Release。須先完成 trusted publisher 與審批環境
|
|
85
|
+
設定(#214)。
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- **Elasticsearch 整合驗證不再把未執行的 roundtrip 算成通過。** 測試的 DOM preload
|
|
90
|
+
同時保留 Bun 的 `fetch`、`AbortController` 與 `AbortSignal`,避免混用不同實作而在
|
|
91
|
+
HTTP 送出前失敗。有服務時的連線/初始化錯誤會讓測試失敗;只有明確停用整合測試,
|
|
92
|
+
或本機未要求必備服務且 TCP 端點不存在時,才記為真正的 skip。CI 必須實跑建立索引、
|
|
93
|
+
寫入、refresh、查詢、schema 斷言與清理,完成後才輸出 roundtrip 驗證紀錄。
|
|
94
|
+
這是測試基礎設施修正,沒有改變發布套件的 adapter 行為。
|
|
95
|
+
|
|
96
|
+
- **PostgreSQL 的 schema 重新回報主鍵、索引與外鍵欄位。** 對 `pg_attribute.attname` 做
|
|
97
|
+
`array_agg` 得到的是 `name[]`,node-postgres 把它當字串回傳,schema 因此丟掉了這些欄位,
|
|
98
|
+
寫入閘門也就拒絕了每一筆結構化寫入。改為先轉成 `text`。
|
|
99
|
+
|
|
100
|
+
- **PostgreSQL 的 enum 欄位重新回報 `enumValues`。** `pg_enum.enumlabel` 的 `array_agg`
|
|
101
|
+
同樣是 `name[]`,以相同方式修正。
|
|
102
|
+
|
|
103
|
+
- **SQL 引擎的 `update` 先檢查權限等級再連線。** 與 Redis、MongoDB 分支以及 `delete`
|
|
104
|
+
一致:query-only 連線現在因為權限不足被拒,而不是被寫入閘門擋下;權限檢查也排在
|
|
105
|
+
executor 的黑名單檢查之前。
|
|
106
|
+
|
|
107
|
+
### Security
|
|
108
|
+
|
|
109
|
+
- **兩筆開發依賴的安全公告。** `source-map-js` 1.2.1 → 1.2.2(high,GHSA-68fv-2mgg-jv7q),
|
|
110
|
+
修正版在 `postcss` 的 `^1.2.1` 範圍內,只更新 lockfile。`postcss-selector-parser`
|
|
111
|
+
(moderate,GHSA-rj75-hqrm-r3gf)只在 7.1.6 修正,但 `tailwindcss@3.4.19` 與
|
|
112
|
+
`postcss-nested@6.2.0` 都要求 6.x,因此依 ADR-0042 在 `scripts/audit-exemptions.json`
|
|
113
|
+
豁免到 2026-11-30:它只在建置時解析本 repo 自己的樣式表,執行期與使用者輸入都碰不到。
|
|
114
|
+
|
|
115
|
+
## [9.1.2] - 2026-10-01
|
|
116
|
+
|
|
117
|
+
一個開發依賴的安全公告、工作規格協定從 ForgeFlow 換成 Warrant,以及三個讓測試與建置
|
|
118
|
+
不再依賴執行順序或在磁碟上留下東西的修正。
|
|
119
|
+
|
|
120
|
+
版本為 **9.1.2**。沒有任何指令、旗標、engine 或輸出改變。npm 套件唯一的差別是不再
|
|
121
|
+
附帶 `.agents/skills/story-development/SKILL.md`——那是 dbcli 自己開發流程用的
|
|
122
|
+
skill,不是給使用者的。
|
|
123
|
+
|
|
124
|
+
### Changed
|
|
125
|
+
|
|
126
|
+
- **工作規格改用 Warrant,ForgeFlow 的機制整套移除。** Story 從一個裝著
|
|
127
|
+
`story.md`/`acceptance.md`/`task.md` 的目錄,變成一個只有 Goal、Out of Scope、
|
|
128
|
+
Acceptance Criteria 三節的 `specs/stories/<slug>.md`;核准由人 commit 或在當次
|
|
129
|
+
session 明確指派,完成由 `make verify` 證明。ForgeFlow 留下的每一個決定都是在維護
|
|
130
|
+
協定本身而不是 dbcli:adoption marker、範本、上游 contract job、`Story:` trailer
|
|
131
|
+
對帳與 handoff 結構要彼此一致,代價是 `make verify` 裡的一道門、CI 的第二次
|
|
132
|
+
checkout、三支 checker 加上它們的函式庫與測試。這些都刪掉而不是停用,連同
|
|
133
|
+
`story-development` skill——它隨 `.agents/` 一起打包,所以已安裝的套件裡會少掉
|
|
134
|
+
它。ForgePilot 仍是控制面,`DBCLI-*` 舊目錄原封保留為歷史紀錄。決定記在
|
|
135
|
+
ADR-0040,取代 ADR-0025、0027、0029、0031、0032 與 0036。
|
|
136
|
+
|
|
137
|
+
- **`assets/ui-template.html` 改為建置產物,不再進版控。** 每次 `bun run build` 都會
|
|
138
|
+
重新產生並覆寫它,`prepublishOnly` 也在每次發佈前重建,所以 commit 裡那份從來不是
|
|
139
|
+
使用者拿到的那份,只會跟建置結果漂移——每跑一次 `make verify` 就把 worktree 弄髒。
|
|
140
|
+
現在它和 `dist/` 一樣列在 `.gitignore`,由 `build:determinism` 檢查兩次建置產出
|
|
141
|
+
相同位元組,而每個會渲染 HTML 的測試自己建置所需的東西,不再靠前面的測試檔先建好。
|
|
142
|
+
發佈出去的 template 仍由 `prepublishOnly` 建置,內容不變。決定記在 ADR-0041。
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- **Skill Author Integration Kit 的測試不再依賴執行順序。** 它以套件名
|
|
147
|
+
(`@carllee1983/dbcli/core`)import,解析到的是未進版控的 `dist/core.mjs`;靜態
|
|
148
|
+
import 只在更早的測試檔已建好 `dist/` 時才載入得了,CI 先跑它就在載入模組時失敗。
|
|
149
|
+
改為在 `beforeAll` 建置後動態 import。
|
|
150
|
+
|
|
151
|
+
- **測試套件不再在 OS 暫存目錄留下東西。** 一次完整測試會在 `TMPDIR` 留下約 130 個
|
|
152
|
+
目錄與檔案:每個測試都呼叫的 seed helper、`beforeAll`/`beforeEach` 建了卻沒有對應
|
|
153
|
+
刪除的目錄、只還原 `HOME` 的 `finally`,以及直接寫進 `tmpdir()` 的設定檔。每個會
|
|
154
|
+
外洩的檔案現在都以 repo 既有的寫法清掉自己建的東西;從空的 `TMPDIR` 開始跑,只剩
|
|
155
|
+
第三方的 node-jiti 快取。
|
|
156
|
+
|
|
157
|
+
### Security
|
|
158
|
+
|
|
159
|
+
- **`brace-expansion` 的 override 提高到 `^5.0.12`。** `bun run audit` 在
|
|
160
|
+
`brace-expansion@5.0.9` 回報三個漏洞(兩個 high、一個 moderate):
|
|
161
|
+
GHSA-qhr7-859c-m2p7、GHSA-6j4f-fj2g-mc7p、GHSA-q2hr-2g5m-vwhr。它經由 eslint 與
|
|
162
|
+
typescript-eslint 的 minimatch 引入,只存在於開發依賴,不在發佈的套件裡;提高既有的
|
|
163
|
+
override 就全部清掉。
|
|
164
|
+
|
|
8
165
|
## [9.1.1] - 2026-09-15
|
|
9
166
|
|
|
10
167
|
一個使用者回報的查詢缺陷(#197),一條會把人導向無效權限階的拒絕訊息,以及兩個
|
package/README.dev.md
CHANGED
|
@@ -6,7 +6,7 @@ Scoped package: **`@carllee1983/dbcli`**. All `npm` / `npx` examples below use t
|
|
|
6
6
|
|
|
7
7
|
### Pre-Publication Checklist
|
|
8
8
|
|
|
9
|
-
Before
|
|
9
|
+
Before tagging a release (the tag triggers `npm publish` in CI):
|
|
10
10
|
|
|
11
11
|
1. **Verify build is clean:**
|
|
12
12
|
```bash
|
|
@@ -34,7 +34,7 @@ Before running `npm publish`:
|
|
|
34
34
|
|
|
35
35
|
3. **Update version in package.json:**
|
|
36
36
|
```bash
|
|
37
|
-
npm version minor # bumps version
|
|
37
|
+
npm version minor --no-git-tag-version # bumps version without creating a tag
|
|
38
38
|
# OR edit the "version" field in package.json by hand
|
|
39
39
|
```
|
|
40
40
|
|
|
@@ -53,13 +53,26 @@ Before running `npm publish`:
|
|
|
53
53
|
|
|
54
54
|
### Publication
|
|
55
55
|
|
|
56
|
-
Publication
|
|
56
|
+
Publication is tag-driven. After the release PR is merged, tag `main` and push the tag:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
|
|
59
|
+
git checkout main && git pull
|
|
60
|
+
git tag vX.Y.Z
|
|
61
|
+
git push origin vX.Y.Z
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
`.github/workflows/release.yml` then runs `check-tag` (tag equals `v` + `package.json` version, commit is an ancestor of `origin/main`), `verify` (`docker-compose.test.yml` databases, `bun run services:check`, `make verify`, attestation artifact), `publish` (waits for approval in the `npm-publish` environment, then `npm publish` through npm trusted publishing with provenance, no stored token), and `github-release` (GitHub Release whose notes are the `## [X.Y.Z]` section of `CHANGELOG.md`, extracted by `scripts/changelog-section.ts`).
|
|
65
|
+
|
|
66
|
+
**One-time owner setup:**
|
|
67
|
+
|
|
68
|
+
- On npmjs.com, add a trusted publisher for `@carllee1983/dbcli`: owner `CarlLee1983`, repository `dbcli`, workflow `release.yml`, environment `npm-publish`, allowed action `npm publish`. npm expires a configuration that has not published within 2 days.
|
|
69
|
+
- In GitHub repository Settings → Environments, create `npm-publish` with a required reviewer, and set "Deployment branches and tags" to "Selected branches and tags" with only a tag rule `v*.*.*`.
|
|
70
|
+
|
|
71
|
+
**Recovery:** if `check-tag` or `verify` fails, nothing was published; fix the cause, delete the tag remotely and locally (`git push origin :refs/tags/vX.Y.Z` and `git tag -d vX.Y.Z`), and tag again. If `publish` succeeded but `github-release` failed, use "Re-run failed jobs", not "Re-run all jobs" (which would fail at `npm publish` because the version exists). Only plain `vX.Y.Z` tags are accepted; pre-release and build tags are rejected.
|
|
72
|
+
|
|
73
|
+
**Emergency fallback only** (workflow cannot run): from a clean checkout of the tagged commit on `main`, `npm login` and `npm publish` locally. That ships without provenance.
|
|
74
|
+
|
|
75
|
+
What `npm publish` does (in CI or locally):
|
|
63
76
|
|
|
64
77
|
1. **`prepublishOnly`:** `bun run build` — rebuilds `dist/cli.mjs` from `src/cli.ts` via `scripts/build.ts`.
|
|
65
78
|
2. **Tarball** — paths from the **`files`** field in `package.json`, further filtered by **`.npmignore`**. (Some npm versions also merge in extra root `README*` files; use dry-run to see exactly what will ship.)
|
|
@@ -106,7 +119,7 @@ Then ship a patch version with the fix. Prefer **deprecate** over **unpublish**
|
|
|
106
119
|
|
|
107
120
|
- **`files` (in `package.json`):** Publishes `dist/`, `assets/`, `README.md`, `CHANGELOG.md`, `LICENSE`. The `assets/` tree is required for `dbcli skill` to copy bundled `SKILL.md` / `reference.md` from the installed package.
|
|
108
121
|
- **`prepublishOnly`:** `bun run build` so `dist/cli.mjs` matches current source.
|
|
109
|
-
- **`engines`:** Declares `bun >= 1.
|
|
122
|
+
- **`engines`:** Declares `bun >= 1.4.0` only. `node` was removed because the published bundles cannot run on Node: `dist/cli.mjs` dynamic-imports the extensionless `./cli-runtime` (Bun's resolver appends `.mjs`, Node's does not) and `dist/core.mjs` calls Bun globals. `tests/integration/runtime-contract.test.ts` fails if `engines.node` comes back without the bundles being fixed to match, and if `dist/agent-core.mjs` — the one entry point that is Node-importable — regresses. See `docs/adr/ADR-0008-dbcli-is-a-bun-program-and-engines-says-so.md`.
|
|
110
123
|
- **Shebang:** `scripts/build.ts` prepends `#!/usr/bin/env bun` to `dist/cli.mjs`; the `bin` field in `package.json` points at that file.
|
|
111
124
|
- **`exports`:** `./core` and `./agent-core` only — there is deliberately no `.` entry. It used to point at `dist/cli.mjs`, and `src/cli-runtime.ts` calls `outputHelp()` and `parseAsync(process.argv)` at module top level, so importing the package ran the CLI against the host's argv and never returned. `bin` does not resolve through `exports`, so the executable is unaffected. `tests/integration/runtime-contract.test.ts` pins both the absence of `.` and the side effect that justifies it.
|
|
112
125
|
- **`postinstall`:** `scripts/postinstall-check-bun.mjs` reports a missing Bun — npm ignores `engines.bun`, so this is the only signal an npm-only machine gets before `dbcli` refuses to start. The command is `bun … || node …` so it runs under whichever runtime is present: Bun-only machines have no `node` to invoke it with, and a hard `node` dependency there would break the primary install path. It must **not** end in `|| exit 0`; v1.55.0 shipped with that mask and npm, which hides lifecycle output unless a script fails, therefore showed nothing at all. On a global install (`npm_config_global === 'true'`) a missing Bun exits 1, so the reason is printed and npm rolls the `bin` back; a dependency install only warns, because that is the `./agent-core` consumer. Both outcomes are pinned in `tests/integration/runtime-contract.test.ts`.
|
package/README.md
CHANGED
|
@@ -6,6 +6,10 @@ A unified database CLI tool that enables AI agents (Claude Code, Gemini, Copilot
|
|
|
6
6
|
|
|
7
7
|
**Core Value:** AI agents can safely and intelligently access project databases through a single, permission-controlled CLI tool with sensitive data protection.
|
|
8
8
|
|
|
9
|
+
[](https://carllee1983.github.io/dbcli/dbcli-intro.en.html#safety)
|
|
10
|
+
|
|
11
|
+
*Watch a real session (42 s): the blacklist hides a sensitive column, and the agent's write is refused on a query-only connection.*
|
|
12
|
+
|
|
9
13
|
> **Security update:** `dbcli init` now writes only a small project binding stub into `./.dbcli/config.json`. The full connection configuration is stored under `~/.config/dbcli/projects/<project-id>/config.json`, so sensitive settings do not live inside the project workspace by default.
|
|
10
14
|
|
|
11
15
|
## Internationalization (i18n)
|
|
@@ -43,7 +47,7 @@ bun install -g @carllee1983/dbcli
|
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
**dbcli runs on Bun.** npm and npx are supported as distribution channels, but the
|
|
46
|
-
installed `dbcli` executable requires Bun 1.
|
|
50
|
+
installed `dbcli` executable requires Bun 1.4.0+ on your `PATH` — install it first with
|
|
47
51
|
`curl -fsSL https://bun.sh/install | bash`. Only the `./agent-core` subpath export is
|
|
48
52
|
importable from a plain Node process.
|
|
49
53
|
|
|
@@ -224,7 +228,7 @@ dbcli extends its unified interface to Redis and Elasticsearch, providing consis
|
|
|
224
228
|
|
|
225
229
|
```bash
|
|
226
230
|
# Connect to Redis
|
|
227
|
-
dbcli init --system redis --host localhost --port 6379
|
|
231
|
+
dbcli init --conn-name local --system redis --host localhost --port 6379
|
|
228
232
|
|
|
229
233
|
# List keys (uses SCAN)
|
|
230
234
|
dbcli list
|
|
@@ -241,7 +245,7 @@ dbcli query "HGETALL user:1"
|
|
|
241
245
|
|
|
242
246
|
```bash
|
|
243
247
|
# Connect to Elasticsearch
|
|
244
|
-
dbcli init --system elasticsearch --host localhost --port 9200
|
|
248
|
+
dbcli init --conn-name local --system elasticsearch --host localhost --port 9200
|
|
245
249
|
|
|
246
250
|
# List indices and document counts
|
|
247
251
|
dbcli list
|
|
@@ -264,7 +268,13 @@ The project `.dbcli` directory now acts as a binding + cache layer. The actual c
|
|
|
264
268
|
|
|
265
269
|
### Initializing Named Connections
|
|
266
270
|
|
|
267
|
-
|
|
271
|
+
Every new or additional connection needs a nonblank connection name. Pass `--conn-name <name>`, or run `dbcli init` in an interactive terminal to be asked for one. The name prompt has no suggested `default`; empty or whitespace-only answers explain the requirement and prompt again. Cancelling or ending the name prompt stops before any connection test or configuration/credential write. An explicit nonblank `--conn-name` skips this prompt, and `--conn-name default` is valid. An explicitly blank `--conn-name` is an error in every mode, before connection tests or writes. `--name` still means the database name (the logical DB index for Redis), never the connection name.
|
|
272
|
+
|
|
273
|
+
Without a TTY, with `--no-interactive`, or when `--use-env-refs` plus all five `--env-*` options automatically disables interaction, a missing or blank `--conn-name` fails with guidance to supply it, before database access or configuration/credential writes. Complete credentials, `--name`, `--env-file`, and `--force` do not supply a connection name.
|
|
274
|
+
|
|
275
|
+
New initialization always creates named v2 configuration, including plain `init` and explicit `--config` paths; it no longer creates an unnamed v1 configuration. Existing v1 configurations remain readable and their established named v2 import is retained. The first explicitly named connection is still the default in a new registry; adding a connection preserves an existing registry's default or no-default state. An explicitly chosen duplicate name still requires interactive overwrite confirmation or `--force`; a noninteractive duplicate without `--force`, or a declined confirmation, leaves files untouched. `--remove` and `--rename` do not ask for a new connection name.
|
|
276
|
+
|
|
277
|
+
Use `--env-file` to specify a custom `.env` file for a named connection:
|
|
268
278
|
|
|
269
279
|
```bash
|
|
270
280
|
# Add a staging connection using .env.staging
|
|
@@ -300,6 +310,9 @@ dbcli use staging
|
|
|
300
310
|
# Show the current default connection
|
|
301
311
|
dbcli use
|
|
302
312
|
|
|
313
|
+
# Clear the default without removing any connection (v2)
|
|
314
|
+
dbcli use --unset
|
|
315
|
+
|
|
303
316
|
# Remove a connection
|
|
304
317
|
dbcli init --remove staging
|
|
305
318
|
|
|
@@ -307,6 +320,21 @@ dbcli init --remove staging
|
|
|
307
320
|
dbcli init --rename staging:production
|
|
308
321
|
```
|
|
309
322
|
|
|
323
|
+
V2 configurations may omit `default`; when present, it must be a nonempty name
|
|
324
|
+
of an existing connection, not `null` or `""`. Without a default, commands that
|
|
325
|
+
need a connection require `--use` or `DBCLI_CONNECTION`; otherwise they fail
|
|
326
|
+
before database access and list available names without endpoints or credentials.
|
|
327
|
+
`dbcli use` describes this state, text lists mark no default, and JSON inventory
|
|
328
|
+
uses `isDefault: false` for every connection. `doctor` accepts this configuration;
|
|
329
|
+
its connection checks still require a selector, such as `dbcli --use staging doctor`.
|
|
330
|
+
|
|
331
|
+
Removing the current default clears it and reports that change, without choosing
|
|
332
|
+
a replacement. Other removals preserve the default or its absence; deleting the
|
|
333
|
+
last connection is refused without writing. Renaming preserves a missing default
|
|
334
|
+
or updates its name as needed. A new registry defaults to its first explicitly
|
|
335
|
+
named connection; adding another preserves the existing default or no-default
|
|
336
|
+
state. Existing v1 imports and production safeguards remain unchanged.
|
|
337
|
+
|
|
310
338
|
### Using a Specific Connection Temporarily
|
|
311
339
|
|
|
312
340
|
You can use the `--use <name>` global flag, the supported command-level form, or `DBCLI_CONNECTION` to execute against a specific connection without changing the default. Selection precedence is explicit `--use`, then `DBCLI_CONNECTION`, then the configured default. A selector is rejected for legacy v1 single-connection configuration instead of being silently ignored.
|
|
@@ -350,23 +378,23 @@ dbcli init [OPTIONS]
|
|
|
350
378
|
- `--port <port>` — Database port
|
|
351
379
|
- `--user <user>` — Database user
|
|
352
380
|
- `--password <pass>` — Database password
|
|
353
|
-
- `--name <db>` — Database name
|
|
381
|
+
- `--name <db>` — Database name, distinct from the required `--conn-name`
|
|
354
382
|
- `--permission <level>` — Permission level: `query-only`, `read-write`, `data-admin`, `admin`
|
|
355
383
|
- **MongoDB only:** `--uri <uri>` — full connection URI (`mongodb://…` or `mongodb+srv://…`); `--auth-source <db>` — auth database (default `admin` when using user/password)
|
|
356
384
|
- `--use-env-refs` — Store environment variable references instead of actual values in config
|
|
357
385
|
- `--skip-test` — Skip connection test
|
|
358
386
|
- `--no-interactive` — Non-interactive mode (requires all options)
|
|
359
|
-
- `--force` — Overwrite existing
|
|
387
|
+
- `--force` — Overwrite the explicitly named existing connection without confirmation
|
|
360
388
|
|
|
361
389
|
**Options (Multi-connection v2):**
|
|
362
|
-
- `--conn-name <name>` —
|
|
390
|
+
- `--conn-name <name>` — Required connection name (e.g., `staging`, `prod`); prompts when omitted in an interactive terminal
|
|
363
391
|
- `--env-file <path>` — Load credentials from a specific `.env` file for this connection
|
|
364
392
|
- `--remove <name>` — Remove a named connection from the config
|
|
365
393
|
- `--rename <old:new>` — Rename an existing connection (format: `old:new`)
|
|
366
394
|
|
|
367
395
|
**Behavior:**
|
|
368
396
|
- Reads `.env` file if present (auto-fills DATABASE_URL, DB_* variables)
|
|
369
|
-
-
|
|
397
|
+
- Obtains a nonblank connection name first; interactive terminals then prompt for missing values (host, port, user, password, database name, permission level)
|
|
370
398
|
- Creates a project binding stub in `.dbcli/config.json` and stores the full config under `~/.config/dbcli/projects/<project-id>/`
|
|
371
399
|
- Tests database connection before saving
|
|
372
400
|
|
|
@@ -380,7 +408,7 @@ dbcli init --conn-name staging --env-file .env.staging
|
|
|
380
408
|
dbcli init --conn-name prod --env-file .env.production --use-env-refs
|
|
381
409
|
|
|
382
410
|
# Store env var references (non-interactive)
|
|
383
|
-
dbcli init --use-env-refs --system mysql \
|
|
411
|
+
dbcli init --conn-name local --use-env-refs --system mysql \
|
|
384
412
|
--env-host DB_HOST --env-port DB_PORT \
|
|
385
413
|
--env-user DB_USER --env-password DB_PASSWORD \
|
|
386
414
|
--env-database DB_DATABASE \
|
|
@@ -400,6 +428,17 @@ dbcli use [connection-name] [OPTIONS]
|
|
|
400
428
|
|
|
401
429
|
**Options:**
|
|
402
430
|
- `--list` — List all connections and show the current default
|
|
431
|
+
- `--unset` — Clear the saved default; succeeds if already absent
|
|
432
|
+
- `--format <text|json>` — Select inventory output format
|
|
433
|
+
- `--confirm-production <name>` — Repeat the exact name to set a production default
|
|
434
|
+
|
|
435
|
+
`--unset` rejects a connection name, `--list`, `--confirm-production`, or
|
|
436
|
+
`--format json` in the same invocation without writing. It never converts or
|
|
437
|
+
overwrites v1 and uses the same approved, integrity-protected write path as
|
|
438
|
+
switching the default; it is blocked in agent mode. Selection still follows
|
|
439
|
+
`--use` > `DBCLI_CONNECTION` > saved default. Conflicting root/command selectors
|
|
440
|
+
and blank CLI selectors fail; blank environment selectors are ignored. See
|
|
441
|
+
[Connection Management](docs/user/en/index.md#connection-management) for details.
|
|
403
442
|
|
|
404
443
|
**Examples:**
|
|
405
444
|
```bash
|
|
@@ -1329,7 +1368,7 @@ After installation, the AI agent will have access to dbcli commands and can use
|
|
|
1329
1368
|
|
|
1330
1369
|
### Platform-Specific Setup
|
|
1331
1370
|
|
|
1332
|
-
Every flow below assumes Bun 1.
|
|
1371
|
+
Every flow below assumes Bun 1.4.0+ on your `PATH`: the installed `dbcli` executable runs under Bun regardless of which package manager fetched it.
|
|
1333
1372
|
|
|
1334
1373
|
#### Claude Code (Anthropic)
|
|
1335
1374
|
|
|
@@ -1658,7 +1697,7 @@ chmod +x dist/cli.mjs
|
|
|
1658
1697
|
|
|
1659
1698
|
### Runtime
|
|
1660
1699
|
|
|
1661
|
-
- **Bun:** 1.
|
|
1700
|
+
- **Bun:** 1.4.0+ — required. The published bundles use Bun APIs and Bun module
|
|
1662
1701
|
resolution; `dbcli` does not run on Node.
|
|
1663
1702
|
- **Node.js:** only for the `./agent-core` subpath export, which is Node-importable
|
|
1664
1703
|
(18.0.0+). `npm install -g` / `npx` work as distribution channels but still shell out
|
|
@@ -1722,28 +1761,20 @@ below: `package.json` and `src/` never mention them, `.forgepilot/` is
|
|
|
1722
1761
|
gitignored local state, and a clone without any of them runs `make verify`
|
|
1723
1762
|
normally.
|
|
1724
1763
|
|
|
1725
|
-
### How work is specified
|
|
1726
|
-
|
|
1727
|
-
Each unit of work is a Story
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
`
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
rather than prose. That rule catches more than wording: clearing the last of it
|
|
1740
|
-
turned up three fixture rows that asserted nothing at all, and one row
|
|
1741
|
-
describing a mechanism that does not exist.
|
|
1742
|
-
|
|
1743
|
-
The exemption list in `scripts/lib/forgeflow-contract.ts` is a ratchet that may
|
|
1744
|
-
shrink and never grow. It is currently empty, so any finding at all fails the
|
|
1745
|
-
gate; adding an entry back requires lowering — never raising — the two counts
|
|
1746
|
-
beside it, which a test enforces.
|
|
1764
|
+
### How work is specified: Warrant
|
|
1765
|
+
|
|
1766
|
+
Each unit of work is a Story: one file, `specs/stories/<slug>.md`, with exactly
|
|
1767
|
+
three sections — Goal, Out of Scope, and Acceptance Criteria. A Story is
|
|
1768
|
+
approved only when a human commits it to the default branch or explicitly
|
|
1769
|
+
assigns it in the current session; an agent never approves its own. The
|
|
1770
|
+
contract agents follow is the `## Warrant` section of `AGENTS.md`, and
|
|
1771
|
+
`specs/stories/README.md` describes the format. The `DBCLI-*` directories under
|
|
1772
|
+
`specs/stories/` are legacy records from an earlier protocol, not pending work.
|
|
1773
|
+
|
|
1774
|
+
Warrant defines what a Story must contain and what counts as evidence: every
|
|
1775
|
+
acceptance criterion needs a reproducible observation, and the requirements,
|
|
1776
|
+
criteria, and scope stay as the human approved them. ForgePilot and
|
|
1777
|
+
`make verify` decide when it is done.
|
|
1747
1778
|
|
|
1748
1779
|
### When work is done: ForgePilot and `make verify`
|
|
1749
1780
|
|
|
@@ -1761,35 +1792,16 @@ no completion command — only a human can approve.
|
|
|
1761
1792
|
|
|
1762
1793
|
A decision that is hard to reverse, surprising without context, or the result of
|
|
1763
1794
|
a real trade-off gets a record in `docs/adr/`, named `ADR-<digits>-<slug>.md`
|
|
1764
|
-
with its status as a `* Status:` bullet rather than front matter.
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
to be storable.
|
|
1795
|
+
with its status as a `* Status:` bullet rather than front matter. A record that
|
|
1796
|
+
is replaced stays in `docs/adr/` with `* Status: superseded` and a
|
|
1797
|
+
`* Superseded by:` bullet naming its successor. Open questions live there as
|
|
1798
|
+
`status: proposed`; undecided is a state that has to be storable.
|
|
1768
1799
|
|
|
1769
1800
|
Prefer closing a record with a falsification condition — one sentence saying
|
|
1770
1801
|
when the decision would no longer hold — naming the files it depends on in
|
|
1771
1802
|
backticks. Tooling reads the boundary list from those backticks, so the marker
|
|
1772
1803
|
is load-bearing rather than decorative.
|
|
1773
1804
|
|
|
1774
|
-
### The principle behind all of it
|
|
1775
|
-
|
|
1776
|
-
Every gate here is a variation on one lesson: **a declaration nothing compares
|
|
1777
|
-
to anything is not a control.** Delivery claims in the handoff are reconciled
|
|
1778
|
-
against commit trailers; the adopted ForgeFlow version is reconciled against
|
|
1779
|
-
every place that restates it; the ForgeFlow contract itself is run against a
|
|
1780
|
-
pinned upstream revision.
|
|
1781
|
-
|
|
1782
|
-
The lesson has a limit, and finding it cost a decision. A Story's `## Authority`
|
|
1783
|
-
was briefly reconciled against the fact of its delivery, on the reasoning that
|
|
1784
|
-
reaching `main` requires commits on a pushed branch (ADR-0030). It does — but
|
|
1785
|
-
`completed_stories` records that a Story was delivered, not **who** performed
|
|
1786
|
-
each operation, and the normal flow here is an agent that is granted `modify` and
|
|
1787
|
-
a local `commit` handing its branch to a human who pushes and merges. The gate
|
|
1788
|
-
refused that flow by name, so the rule was removed (ADR-0031). Whether an
|
|
1789
|
-
Authority declaration is true is a question this repository cannot observe and
|
|
1790
|
-
Human Review can; a gate that guesses at it is worse than an unchecked
|
|
1791
|
-
declaration, because its verdict looks like evidence.
|
|
1792
|
-
|
|
1793
1805
|
---
|
|
1794
1806
|
|
|
1795
1807
|
## License
|