@carllee1983/dbcli 9.1.0 → 9.1.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Database CLI skill and command reference for AI agents.",
5
5
  "author": {
6
6
  "name": "Carl Lee",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Database CLI skill and command reference for AI agents",
5
5
  "author": {
6
6
  "name": "Carl Lee",
@@ -2,7 +2,7 @@
2
2
  "name": "dbcli-agent",
3
3
  "displayName": "dbcli Agent",
4
4
  "description": "Database CLI skill and command reference for AI agents.",
5
- "version": "9.1.0",
5
+ "version": "9.1.1",
6
6
  "author": {
7
7
  "name": "Carl Lee",
8
8
  "url": "https://github.com/CarlLee1983"
package/CHANGELOG.md CHANGED
@@ -5,6 +5,50 @@ 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
+ ## [9.1.1] - 2026-09-15
9
+
10
+ 一個使用者回報的查詢缺陷(#197),一條會把人導向無效權限階的拒絕訊息,以及兩個
11
+ 會對同一個 commit 給出兩種答案、或只會叫「東西變了」的測試門檻。
12
+
13
+ 版本為 **9.1.1**。沒有新增指令、旗標或 engine;沒有任何一處拒絕先前被接受的輸入。
14
+ 唯一改變輸出的是拒絕訊息裡的 `required:` 欄位與它的句子——那個值先前是錯的,照它
15
+ 去要權限會被再拒一次,所以修正它不是相容性變更,是讓它開始為真。
16
+
17
+ ### Fixed
18
+
19
+ - **snippet 裡重複使用同一個具名參數,在 MySQL / MariaDB / SQLite 上不再炸。**
20
+ `rewriteToBind()` 對每一次 `:name` 出現輸出一個 placeholder,但 bind values 是由
21
+ 去重後的名稱清單映射出來的。PostgreSQL 重用 `$1`,一個值對一個索引本來就對;`?`
22
+ 沒有索引可以重用,所以 placeholder 數量跟著出現次數走、values 數量跟著相異名稱數
23
+ 走,兩者在有重複參數時必然對不上,MariaDB 以 `ER_WRONG_ARGUMENTS` 拒絕整條
24
+ statement。
25
+
26
+ 實務影響是「參數為 0 就查全部、否則查單一」這類條件在 snippet 裡寫不出來,只能
27
+ 繞道 CTE 讓參數只出現一次。`--dry-run` 看得到 SQL 與 bind values 不匹配,但不會
28
+ 報錯,所以問題要到真的執行才炸。非 PostgreSQL 引擎現在每一次出現送一個值,
29
+ PostgreSQL 的去重行為不變。(#197)
30
+
31
+ - **拒絕訊息指向的權限階,現在是真的會通過的那一階。** 無法分類的語句(`REPLACE
32
+ INTO`、`PRAGMA`、`VACUUM`、`REINDEX` 等)在 `query-only` 下被拒時宣稱需要
33
+ `read-write`,但沒有任何一階授予未知語句,取得 read-write 之後會再被拒一次。訊息
34
+ 與 `required:` 欄位現在都說 `admin`,en 與 zh-TW 同步。判決完全沒變:本來拒絕的仍
35
+ 然拒絕,本來允許的仍然允許。(DBCLI-037)
36
+
37
+ ### Changed
38
+
39
+ - **capability catalog 的輸出改由契約守住,不再由 sha256 守住。** 三份渲染
40
+ (JSON/text/Markdown)的凍結雜湊換成結構性斷言:文件在釘住的 schema 版本下
41
+ parse 得過、三份渲染列出同一組 capability、每個 capability 指的 command 是 CLI 真的
42
+ 帶得動的。catalog 是從 engine 矩陣推導出來的(ADR-0022),所以每次矩陣變動都會
43
+ 移動那三個雜湊,而修法永遠是把現在的值抄回去——連續三次之後,它報告的是 diff
44
+ 本來就說了的事。決定與被否決的選項記在 ADR-0039。使用者可見的輸出沒有變。
45
+ (DBCLI-038)
46
+
47
+ - **驗證 artifact 的秘密洩漏檢查改成逐欄檢查。** 原本在整份文件裡搜尋連線 port 的
48
+ 四位數字,而 artifact 帶一個隨機後綴的 id,後綴湊出那四位數字時測試會紅——什麼都
49
+ 沒洩漏,重跑就過。改為解析後逐欄走訪並指名帶著 port 的欄位;判準仍是包含而非
50
+ 相等,藏在連線字串裡的 port 照樣抓得到。(DBCLI-039)
51
+
8
52
  ## [9.1.0] - 2026-09-11
9
53
 
10
54
  ForgeFlow Story DBCLI-014 到 DBCLI-036 在 `v9.0.0` 之後交付。其中只有最後三張
@@ -2087,7 +2087,7 @@ var package_default;
2087
2087
  var init_package = __esm(() => {
2088
2088
  package_default = {
2089
2089
  name: "@carllee1983/dbcli",
2090
- version: "9.1.0",
2090
+ version: "9.1.1",
2091
2091
  description: "Database CLI for AI agents",
2092
2092
  type: "module",
2093
2093
  publishConfig: {
@@ -8997,7 +8997,7 @@ var init_messages = __esm(() => {
8997
8997
  elasticsearch_requires_level: "Elasticsearch {type} operation requires {minimum} permission or higher (current level: {permission})",
8998
8998
  escalated_write_requires_admin: "This statement opens as a read but contains an executable {keyword}. A write hidden inside a read statement requires admin permission (current level: {permission}).",
8999
8999
  multiple_statements_refused: "SQL containing multiple statements is refused below admin permission, because only the first statement determines the permission check. Run each statement separately.",
9000
- unknown_statement_query_only: "Unrecognised SQL statement (current level: query-only). Security policy requires read-write+ for unknown statements. If this is a legitimate read-only statement, please open an issue at https://github.com/CarlLee1983/dbcli/issues.",
9000
+ unknown_statement_query_only: "Unrecognised SQL statement (current level: query-only). Security policy requires admin for unknown statements. If this is a legitimate read-only statement, please open an issue at https://github.com/CarlLee1983/dbcli/issues.",
9001
9001
  permission_denied_reason: "Permission denied: {reason}",
9002
9002
  table_not_found: "Table not found: {table}",
9003
9003
  unsupported_lang: "Language '{lang}' not supported, using English",
@@ -9333,7 +9333,7 @@ var init_messages2 = __esm(() => {
9333
9333
  elasticsearch_requires_level: "Elasticsearch {type} \u64CD\u4F5C\u9700\u8981 {minimum} \u4EE5\u4E0A\u7684\u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09",
9334
9334
  escalated_write_requires_admin: "\u6B64\u8A9E\u53E5\u8868\u9762\u4E0A\u662F\u8B80\u53D6\uFF0C\u4F46\u5BE6\u969B\u5305\u542B\u53EF\u57F7\u884C\u7684 {keyword}\u3002\u8B80\u53D6\u8A9E\u53E5\u4E2D\u96B1\u85CF\u5BEB\u5165\u64CD\u4F5C\u9700\u8981 admin \u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09\u3002",
9335
9335
  multiple_statements_refused: "\u4F4E\u65BC admin \u6B0A\u9650\u6642\u62D2\u7D55\u57F7\u884C\u5305\u542B\u591A\u500B\u8A9E\u53E5\u7684 SQL\uFF0C\u56E0\u70BA\u6B0A\u9650\u6AA2\u67E5\u53EA\u6703\u4F9D\u64DA\u7B2C\u4E00\u500B\u8A9E\u53E5\u5224\u65B7\u3002\u8ACB\u5C07\u5404\u8A9E\u53E5\u5206\u958B\u57F7\u884C\u3002",
9336
- unknown_statement_query_only: "\u7121\u6CD5\u8FA8\u8B58\u7684 SQL \u8A9E\u53E5\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1Aquery-only\uFF09\u3002\u5B89\u5168\u653F\u7B56\u8981\u6C42\u672A\u77E5\u8A9E\u53E5\u81F3\u5C11\u9700\u8981 read-write \u4EE5\u4E0A\u6B0A\u9650\u3002\u82E5\u9019\u5176\u5BE6\u662F\u5408\u6CD5\u7684\u552F\u8B80\u8A9E\u53E5\uFF0C\u8ACB\u81F3 https://github.com/CarlLee1983/dbcli/issues \u63D0\u51FA\u8B70\u984C\u3002",
9336
+ unknown_statement_query_only: "\u7121\u6CD5\u8FA8\u8B58\u7684 SQL \u8A9E\u53E5\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1Aquery-only\uFF09\u3002\u5B89\u5168\u653F\u7B56\u8981\u6C42\u672A\u77E5\u8A9E\u53E5\u9700\u8981 admin \u6B0A\u9650\u3002\u82E5\u9019\u5176\u5BE6\u662F\u5408\u6CD5\u7684\u552F\u8B80\u8A9E\u53E5\uFF0C\u8ACB\u81F3 https://github.com/CarlLee1983/dbcli/issues \u63D0\u51FA\u8B70\u984C\u3002",
9337
9337
  permission_denied_reason: "\u6B0A\u9650\u88AB\u62D2\uFF1A{reason}",
9338
9338
  table_not_found: "\u627E\u4E0D\u5230\u8868\u683C\uFF1A{table}",
9339
9339
  unsupported_lang: "\u4E0D\u652F\u63F4\u7684\u8A9E\u8A00 '{lang}'\uFF0C\u4F7F\u7528\u82F1\u6587",
@@ -18719,6 +18719,7 @@ function paramErr(spec, raw, expected) {
18719
18719
  function rewriteToBind(sqlBody, params, engine) {
18720
18720
  const masked = stripCommentsAndStrings(sqlBody);
18721
18721
  const order = [];
18722
+ const occurrences = [];
18722
18723
  const indexByName = new Map;
18723
18724
  let m;
18724
18725
  NAME_RE.lastIndex = 0;
@@ -18737,19 +18738,18 @@ function rewriteToBind(sqlBody, params, engine) {
18737
18738
  const start = m.index;
18738
18739
  const end = start + m[0].length;
18739
18740
  outSql += sqlBody.slice(cursor, start);
18740
- const idx = indexByName.get(name);
18741
- outSql += engine === "postgres" ? `$${idx}` : "?";
18741
+ if (engine === "postgres") {
18742
+ outSql += `$${indexByName.get(name)}`;
18743
+ } else {
18744
+ outSql += "?";
18745
+ occurrences.push(name);
18746
+ }
18742
18747
  cursor = end;
18743
18748
  }
18744
18749
  outSql += sqlBody.slice(cursor);
18745
- const undeclared = [];
18746
- const values = order.map((n) => {
18747
- if (!Object.prototype.hasOwnProperty.call(params, n)) {
18748
- undeclared.push(n);
18749
- return null;
18750
- }
18751
- return params[n];
18752
- });
18750
+ const undeclared = order.filter((n) => !Object.prototype.hasOwnProperty.call(params, n));
18751
+ const bindOrder = engine === "postgres" ? order : occurrences;
18752
+ const values = bindOrder.map((n) => Object.prototype.hasOwnProperty.call(params, n) ? params[n] : null);
18753
18753
  return { sql: outSql, values, undeclared };
18754
18754
  }
18755
18755
  var NAME_RE;
@@ -19548,7 +19548,7 @@ function checkPermissionForClassification(classification, permission) {
19548
19548
  allowed: false,
19549
19549
  reason: isUnknown ? t("errors.unknown_statement_query_only") : refusalReason(classification.type, permission),
19550
19550
  classification,
19551
- requiredPermission: isUnknown ? "read-write" : minimumPermissionFor(classification.type)
19551
+ requiredPermission: minimumPermissionFor(classification.type)
19552
19552
  };
19553
19553
  }
19554
19554
  return {
package/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@carllee1983/dbcli",
6
- version: "9.1.0",
6
+ version: "9.1.1",
7
7
  description: "Database CLI for AI agents",
8
8
  type: "module",
9
9
  publishConfig: {
package/dist/core.mjs CHANGED
@@ -1800,7 +1800,7 @@ var messages_default = {
1800
1800
  elasticsearch_requires_level: "Elasticsearch {type} operation requires {minimum} permission or higher (current level: {permission})",
1801
1801
  escalated_write_requires_admin: "This statement opens as a read but contains an executable {keyword}. A write hidden inside a read statement requires admin permission (current level: {permission}).",
1802
1802
  multiple_statements_refused: "SQL containing multiple statements is refused below admin permission, because only the first statement determines the permission check. Run each statement separately.",
1803
- unknown_statement_query_only: "Unrecognised SQL statement (current level: query-only). Security policy requires read-write+ for unknown statements. If this is a legitimate read-only statement, please open an issue at https://github.com/CarlLee1983/dbcli/issues.",
1803
+ unknown_statement_query_only: "Unrecognised SQL statement (current level: query-only). Security policy requires admin for unknown statements. If this is a legitimate read-only statement, please open an issue at https://github.com/CarlLee1983/dbcli/issues.",
1804
1804
  permission_denied_reason: "Permission denied: {reason}",
1805
1805
  table_not_found: "Table not found: {table}",
1806
1806
  unsupported_lang: "Language '{lang}' not supported, using English",
@@ -2132,7 +2132,7 @@ var messages_default2 = {
2132
2132
  elasticsearch_requires_level: "Elasticsearch {type} \u64CD\u4F5C\u9700\u8981 {minimum} \u4EE5\u4E0A\u7684\u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09",
2133
2133
  escalated_write_requires_admin: "\u6B64\u8A9E\u53E5\u8868\u9762\u4E0A\u662F\u8B80\u53D6\uFF0C\u4F46\u5BE6\u969B\u5305\u542B\u53EF\u57F7\u884C\u7684 {keyword}\u3002\u8B80\u53D6\u8A9E\u53E5\u4E2D\u96B1\u85CF\u5BEB\u5165\u64CD\u4F5C\u9700\u8981 admin \u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09\u3002",
2134
2134
  multiple_statements_refused: "\u4F4E\u65BC admin \u6B0A\u9650\u6642\u62D2\u7D55\u57F7\u884C\u5305\u542B\u591A\u500B\u8A9E\u53E5\u7684 SQL\uFF0C\u56E0\u70BA\u6B0A\u9650\u6AA2\u67E5\u53EA\u6703\u4F9D\u64DA\u7B2C\u4E00\u500B\u8A9E\u53E5\u5224\u65B7\u3002\u8ACB\u5C07\u5404\u8A9E\u53E5\u5206\u958B\u57F7\u884C\u3002",
2135
- unknown_statement_query_only: "\u7121\u6CD5\u8FA8\u8B58\u7684 SQL \u8A9E\u53E5\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1Aquery-only\uFF09\u3002\u5B89\u5168\u653F\u7B56\u8981\u6C42\u672A\u77E5\u8A9E\u53E5\u81F3\u5C11\u9700\u8981 read-write \u4EE5\u4E0A\u6B0A\u9650\u3002\u82E5\u9019\u5176\u5BE6\u662F\u5408\u6CD5\u7684\u552F\u8B80\u8A9E\u53E5\uFF0C\u8ACB\u81F3 https://github.com/CarlLee1983/dbcli/issues \u63D0\u51FA\u8B70\u984C\u3002",
2135
+ unknown_statement_query_only: "\u7121\u6CD5\u8FA8\u8B58\u7684 SQL \u8A9E\u53E5\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1Aquery-only\uFF09\u3002\u5B89\u5168\u653F\u7B56\u8981\u6C42\u672A\u77E5\u8A9E\u53E5\u9700\u8981 admin \u6B0A\u9650\u3002\u82E5\u9019\u5176\u5BE6\u662F\u5408\u6CD5\u7684\u552F\u8B80\u8A9E\u53E5\uFF0C\u8ACB\u81F3 https://github.com/CarlLee1983/dbcli/issues \u63D0\u51FA\u8B70\u984C\u3002",
2136
2136
  permission_denied_reason: "\u6B0A\u9650\u88AB\u62D2\uFF1A{reason}",
2137
2137
  table_not_found: "\u627E\u4E0D\u5230\u8868\u683C\uFF1A{table}",
2138
2138
  unsupported_lang: "\u4E0D\u652F\u63F4\u7684\u8A9E\u8A00 '{lang}'\uFF0C\u4F7F\u7528\u82F1\u6587",
@@ -4359,7 +4359,7 @@ function checkPermissionForClassification(classification, permission) {
4359
4359
  allowed: false,
4360
4360
  reason: isUnknown ? t("errors.unknown_statement_query_only") : refusalReason(classification.type, permission),
4361
4361
  classification,
4362
- requiredPermission: isUnknown ? "read-write" : minimumPermissionFor(classification.type)
4362
+ requiredPermission: minimumPermissionFor(classification.type)
4363
4363
  };
4364
4364
  }
4365
4365
  return {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Database CLI skill and command reference for AI agents.",
5
5
  "contextFileName": "AGENTS.md"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carllee1983/dbcli",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Database CLI for AI agents",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Database CLI skill and command reference for AI agents",
5
5
  "author": {
6
6
  "name": "Carl Lee",