@carllee1983/dbcli 10.0.0 → 12.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.
Files changed (36) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.cursor/rules/dbcli.mdc +5 -4
  4. package/.cursor/skills/dbcli/reference.md +8 -5
  5. package/.cursor-plugin/plugin.json +1 -1
  6. package/.github/skills/dbcli/SKILL.md +5 -4
  7. package/.github/skills/dbcli/reference.md +8 -5
  8. package/CHANGELOG.md +107 -0
  9. package/assets/SKILL.md +5 -4
  10. package/assets/reference.md +8 -5
  11. package/assets/tasks/README.md +1 -1
  12. package/assets/tasks/analyze-table-perf.md +1 -1
  13. package/assets/tasks/audit-permissions.md +1 -1
  14. package/assets/tasks/connection-health.md +1 -2
  15. package/assets/tasks/design-review.md +1 -1
  16. package/assets/tasks/diagnose-slow-query.md +1 -1
  17. package/assets/tasks/migration-review.md +5 -3
  18. package/assets/tasks/mongo-safe-backfill.md +1 -1
  19. package/assets/tasks/mongo-schema-drift-review.md +1 -1
  20. package/assets/tasks/orm-drift-review.md +1 -1
  21. package/assets/tasks/pr-database-review.md +1 -1
  22. package/assets/tasks/safe-backfill-verify.md +1 -1
  23. package/assets/tasks/safe-backfill.md +13 -7
  24. package/assets/tasks/schema-drift-review.md +1 -1
  25. package/assets/tasks/slow-endpoint-investigation.md +1 -1
  26. package/dist/cli-runtime.mjs +15760 -20099
  27. package/dist/cli.mjs +2 -1
  28. package/dist/core.d.ts +25 -1
  29. package/dist/core.mjs +123 -0
  30. package/gemini-extension.json +1 -1
  31. package/package.json +2 -1
  32. package/plugins/dbcli-agent/.codex-plugin/plugin.json +1 -1
  33. package/plugins/dbcli-agent/skills/dbcli/SKILL.md +5 -4
  34. package/plugins/dbcli-agent/skills/dbcli/reference.md +8 -5
  35. package/skills/dbcli/SKILL.md +5 -4
  36. package/skills/dbcli/reference.md +8 -5
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: "10.0.0",
6
+ version: "12.0.0",
7
7
  description: "Database CLI for AI agents",
8
8
  type: "module",
9
9
  publishConfig: {
@@ -103,6 +103,7 @@ var package_default = {
103
103
  "lru-cache": "^11.4.0",
104
104
  "lucide-react": "^1.16.0",
105
105
  mongodb: "^7.2.0",
106
+ "mongodb-connection-string-url": "^7.0.1",
106
107
  mysql2: "^3.24.3",
107
108
  "node-sql-parser": "5",
108
109
  open: "^11.0.0",
package/dist/core.d.ts CHANGED
@@ -36,6 +36,8 @@ export interface ConnectionOptions {
36
36
  replicaSet?: string;
37
37
  /** MongoDB TLS switch (optional, field-based config; implied true when srv) */
38
38
  tls?: boolean;
39
+ /** MongoDB extra driver options appended to the URI query string (field-based config, plain strings only) */
40
+ options?: Record<string, string>;
39
41
  /** MongoDB SRV lookup — build a mongodb+srv:// URI from host (optional, field-based config) */
40
42
  srv?: boolean;
41
43
  /** Connection timeout in milliseconds (default: 5000) */
@@ -99,6 +101,8 @@ export interface ColumnSchema {
99
101
  * Complete schema information for a table
100
102
  */
101
103
  export interface TableSchema {
104
+ /** Some metadata was omitted to protect blacklisted identities. No protected names. */
105
+ metadataOmitted?: boolean;
102
106
  /** Table name */
103
107
  name: string;
104
108
  /** Exact database schema/catalog namespace, when reliably available */
@@ -124,6 +128,8 @@ export interface TableSchema {
124
128
  name: string;
125
129
  columns: string[];
126
130
  unique: boolean;
131
+ /** False when expressions/predicates prevent complete column-only representation. */
132
+ columnsComplete?: boolean;
127
133
  }>;
128
134
  /** Column count (used by listTables when full column details are not loaded) */
129
135
  columnCount?: number;
@@ -132,7 +138,7 @@ export interface TableSchema {
132
138
  /** Type of table (table or view) */
133
139
  tableType?: "table" | "view";
134
140
  }
135
- type ConnectionErrorCode = "ECONNREFUSED" | "ETIMEDOUT" | "AUTH_FAILED" | "ENOTFOUND" | "EHOSTUNREACH" | "CONNECTION_LOST" | "TOO_MANY_CONNECTIONS" | "TLS_ERROR" | "SERVER_NOT_READY" | "CONNECTION_REJECTED" | "SQL_SYNTAX_ERROR" | "STATEMENT_TIMEOUT" | "TABLE_NOT_FOUND" | "COLUMN_NOT_FOUND" | "QUERY_ONLY_BOUNDARY_FAILED" | "UNKNOWN";
141
+ type ConnectionErrorCode = "ECONNREFUSED" | "ETIMEDOUT" | "AUTH_FAILED" | "DB_PERMISSION_DENIED" | "ENOTFOUND" | "EHOSTUNREACH" | "CONNECTION_LOST" | "TOO_MANY_CONNECTIONS" | "TLS_ERROR" | "SERVER_NOT_READY" | "CONNECTION_REJECTED" | "SQL_SYNTAX_ERROR" | "STATEMENT_TIMEOUT" | "TABLE_NOT_FOUND" | "COLUMN_NOT_FOUND" | "QUERY_ONLY_BOUNDARY_FAILED" | "UNKNOWN";
136
142
  export declare class ConnectionError extends Error {
137
143
  /** Error category code */
138
144
  code: ConnectionErrorCode;
@@ -194,6 +200,10 @@ type RedisWarning = {
194
200
  count: number;
195
201
  };
196
202
  interface TableSchemaOptions {
203
+ /** Single-object schema command: validate presence/type and mark incomplete index metadata. */
204
+ metadataProtection?: boolean;
205
+ /** Explicit SQL namespace; local tableName remains literal. Never performs an exact count. */
206
+ namespace?: string;
197
207
  /** MongoDB: 取樣文件數 */
198
208
  sampleSize?: number;
199
209
  /** MongoDB: 取樣方式 */
@@ -440,6 +450,8 @@ interface MongoDBConnectionConfig {
440
450
  $env: string;
441
451
  };
442
452
  tls?: boolean;
453
+ /** Extra driver options appended to the URI query string; plain strings, no env-ref */
454
+ options?: Record<string, string>;
443
455
  /** Build a mongodb+srv:// URI from host and expand it via DNS SRV lookup */
444
456
  srv?: boolean;
445
457
  }
@@ -1105,6 +1117,7 @@ declare const DbcliConfigSchema: z.ZodObject<{
1105
1117
  }>
1106
1118
  ]>>;
1107
1119
  tls: z.ZodOptional<z.ZodBoolean>;
1120
+ options: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodString>, Record<string, string>, Record<string, string>>>;
1108
1121
  srv: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1109
1122
  }, "strip", z.ZodTypeAny, {
1110
1123
  password: string | {
@@ -1134,6 +1147,7 @@ declare const DbcliConfigSchema: z.ZodObject<{
1134
1147
  $env: string;
1135
1148
  } | undefined;
1136
1149
  tls?: boolean | undefined;
1150
+ options?: Record<string, string> | undefined;
1137
1151
  timeout?: number | undefined;
1138
1152
  statementTimeout?: number | undefined;
1139
1153
  }, {
@@ -1163,6 +1177,7 @@ declare const DbcliConfigSchema: z.ZodObject<{
1163
1177
  $env: string;
1164
1178
  } | undefined;
1165
1179
  tls?: boolean | undefined;
1180
+ options?: Record<string, string> | undefined;
1166
1181
  srv?: boolean | undefined;
1167
1182
  timeout?: number | undefined;
1168
1183
  statementTimeout?: number | undefined;
@@ -1569,6 +1584,7 @@ declare const DbcliConfigSchema: z.ZodObject<{
1569
1584
  $env: string;
1570
1585
  } | undefined;
1571
1586
  tls?: boolean | undefined;
1587
+ options?: Record<string, string> | undefined;
1572
1588
  timeout?: number | undefined;
1573
1589
  statementTimeout?: number | undefined;
1574
1590
  } | {
@@ -1701,6 +1717,7 @@ declare const DbcliConfigSchema: z.ZodObject<{
1701
1717
  $env: string;
1702
1718
  } | undefined;
1703
1719
  tls?: boolean | undefined;
1720
+ options?: Record<string, string> | undefined;
1704
1721
  srv?: boolean | undefined;
1705
1722
  timeout?: number | undefined;
1706
1723
  statementTimeout?: number | undefined;
@@ -2154,6 +2171,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2154
2171
  }>
2155
2172
  ]>>;
2156
2173
  tls: z.ZodOptional<z.ZodBoolean>;
2174
+ options: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodString>, Record<string, string>, Record<string, string>>>;
2157
2175
  srv: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
2158
2176
  } & {
2159
2177
  permission: z.ZodDefault<z.ZodEnum<[
@@ -2193,6 +2211,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2193
2211
  $env: string;
2194
2212
  } | undefined;
2195
2213
  tls?: boolean | undefined;
2214
+ options?: Record<string, string> | undefined;
2196
2215
  timeout?: number | undefined;
2197
2216
  statementTimeout?: number | undefined;
2198
2217
  envFile?: string | undefined;
@@ -2224,6 +2243,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2224
2243
  $env: string;
2225
2244
  } | undefined;
2226
2245
  tls?: boolean | undefined;
2246
+ options?: Record<string, string> | undefined;
2227
2247
  srv?: boolean | undefined;
2228
2248
  timeout?: number | undefined;
2229
2249
  permission?: "admin" | "query-only" | "read-write" | "data-admin" | undefined;
@@ -2570,6 +2590,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2570
2590
  $env: string;
2571
2591
  } | undefined;
2572
2592
  tls?: boolean | undefined;
2593
+ options?: Record<string, string> | undefined;
2573
2594
  timeout?: number | undefined;
2574
2595
  statementTimeout?: number | undefined;
2575
2596
  envFile?: string | undefined;
@@ -2704,6 +2725,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2704
2725
  $env: string;
2705
2726
  } | undefined;
2706
2727
  tls?: boolean | undefined;
2728
+ options?: Record<string, string> | undefined;
2707
2729
  timeout?: number | undefined;
2708
2730
  statementTimeout?: number | undefined;
2709
2731
  envFile?: string | undefined;
@@ -2980,6 +3002,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
2980
3002
  $env: string;
2981
3003
  } | undefined;
2982
3004
  tls?: boolean | undefined;
3005
+ options?: Record<string, string> | undefined;
2983
3006
  timeout?: number | undefined;
2984
3007
  statementTimeout?: number | undefined;
2985
3008
  envFile?: string | undefined;
@@ -3174,6 +3197,7 @@ declare const DbcliConfigV2Schema: z.ZodEffects<z.ZodObject<{
3174
3197
  $env: string;
3175
3198
  } | undefined;
3176
3199
  tls?: boolean | undefined;
3200
+ options?: Record<string, string> | undefined;
3177
3201
  timeout?: number | undefined;
3178
3202
  statementTimeout?: number | undefined;
3179
3203
  envFile?: string | undefined;
package/dist/core.mjs CHANGED
@@ -1028,6 +1028,7 @@ var COMMAND_CAPABILITY_KEYS = Object.freeze([
1028
1028
  "update",
1029
1029
  "delete",
1030
1030
  "export",
1031
+ "blacklistRead",
1031
1032
  "blacklist",
1032
1033
  "check",
1033
1034
  "diff",
@@ -1096,6 +1097,7 @@ var SQL_BASE = {
1096
1097
  update: cap("supported", "db-write", "Dedicated UPDATE command is supported."),
1097
1098
  delete: cap("supported", "db-write", "Dedicated DELETE command is supported."),
1098
1099
  export: cap("supported", "readonly", "SQL export is supported."),
1100
+ blacklistRead: cap("supported", "readonly", "Reads the configured blacklist rules."),
1099
1101
  blacklist: cap("supported", "local-write", "Blacklist management and enforcement are supported."),
1100
1102
  check: cap("supported", "readonly", "Data health checks are SQL-only."),
1101
1103
  diff: cap("supported", "readonly", "Relational schema snapshots are supported."),
@@ -1196,6 +1198,7 @@ var ENGINE_CAPABILITIES = Object.freeze({
1196
1198
  update: cap("limited", "db-write", "Document update is supported with Mongo-specific behavior."),
1197
1199
  delete: cap("limited", "db-write", "Document delete is supported with Mongo-specific behavior."),
1198
1200
  export: cap("limited", "readonly", "MongoDB export is supported with document-query syntax."),
1201
+ blacklistRead: cap("limited", "readonly", "Reads the engine-specific blacklist rules."),
1199
1202
  blacklist: cap("limited", "local-write", "Rule management works; enforcement differs from SQL column enforcement."),
1200
1203
  check: cap("unsupported", "none", "Data health check is SQL-only."),
1201
1204
  diff: cap("unsupported", "none", "Schema snapshots are relational only."),
@@ -1216,6 +1219,7 @@ var ENGINE_CAPABILITIES = Object.freeze({
1216
1219
  update: cap("unsupported", "none", "Dedicated write subcommand is not exposed."),
1217
1220
  delete: cap("limited", "db-write", "Basic delete via DEL/HDEL/LREM/SREM/ZREM (needs data-admin); supports --dry-run."),
1218
1221
  export: cap("unsupported", "none", "Redis export is not supported."),
1222
+ blacklistRead: cap("limited", "readonly", "Reads the engine-specific blacklist rules."),
1219
1223
  blacklist: cap("limited", "local-write", "Key-glob rejection (Redis-native pattern) plus value/hash-field masking ([REDACTED])."),
1220
1224
  check: cap("unsupported", "none", "Data health check is SQL-only."),
1221
1225
  diff: cap("unsupported", "none", "Schema snapshots are relational only."),
@@ -1236,6 +1240,7 @@ var ENGINE_CAPABILITIES = Object.freeze({
1236
1240
  update: cap("unsupported", "none", "Dedicated write subcommand is not exposed."),
1237
1241
  delete: cap("unsupported", "none", "Dedicated write subcommand is not exposed."),
1238
1242
  export: cap("limited", "readonly", "Exports DSL hits or a full index via scroll, capped at 1000 rows (use --no-limit)."),
1243
+ blacklistRead: cap("limited", "readonly", "Reads the engine-specific blacklist rules."),
1239
1244
  blacklist: cap("limited", "local-write", "Index-level and flattened-column enforcement differ from SQL."),
1240
1245
  check: cap("unsupported", "none", "Data health check is SQL-only."),
1241
1246
  diff: cap("unsupported", "none", "Schema snapshots are relational only."),
@@ -1261,6 +1266,23 @@ var messages_default = {
1261
1266
  secret_alternatives_sql: "pass --password, supply the credential through .env or the process environment, or store a reference with --use-env-refs",
1262
1267
  secret_alternatives_mongo_password: "pass --password, supply the credential through .env or the process environment, or paste the connection string with --uri",
1263
1268
  secret_alternatives_mongo_uri: "pass the connection string with --uri",
1269
+ mongo_uri_conflicts_fields: "--uri cannot be combined with {flags}: the connection string already carries those settings. Use one or the other (--name may be combined to override the database name).",
1270
+ mongo_uri_with_env_refs: "--uri cannot be combined with --use-env-refs: the connection string is decomposed into config fields, and its credentials are not moved into environment variables. Either remove --use-env-refs so dbcli decomposes the string into the field config, or use the --env-* flags (--env-host, --env-user, --env-password, ...) to name one variable per field.",
1271
+ mongo_uri_fallback_warning: "\u26A0\uFE0F This connection string {reasons}, so it cannot become fields. It is stored as-is in uri, and its credentials will sit in plaintext in the config file.",
1272
+ mongo_uri_reason_unix_socket: "uses a Unix domain socket",
1273
+ mongo_uri_reason_multi_host: "contains more than one host (a field config holds only one)",
1274
+ mongo_uri_reason_secret_option: "contains secret option(s) ({keys}) that would land in plaintext options",
1275
+ mongo_uri_reason_duplicate_key: "repeats the query key(s) {keys} (a field config can hold only one value per key)",
1276
+ mongo_uri_reason_non_scram: "uses the non-SCRAM auth mechanism {mechanism} (field config cannot express it)",
1277
+ mongo_decomposed_header: "Connection string decomposed into these fields (password hidden):",
1278
+ mongo_paste_env_refs_warning: "\u26A0\uFE0F --use-env-refs does not apply to a pasted connection string: its credentials are written to the config file as they are, not as environment-variable references.",
1279
+ mongo_setup_mode_paste: "Paste a connection string (copied from Atlas / Compass)",
1280
+ mongo_string_invalid: "Not a valid MongoDB connection string (it is not echoed because it may carry credentials).",
1281
+ mongo_string_bad_host: "The connection string has an invalid host or port (the port must be an integer from 1 to 65535).",
1282
+ mongo_string_bad_credentials: "The connection string's credentials contain an unescaped reserved character such as @, : or /. Percent-encode it (for example @ as %40).",
1283
+ mongo_string_tls_conflict: "The connection string sets tls and ssl to different values.",
1284
+ mongo_string_bad_tls: "The connection string's {key} must be true or false.",
1285
+ mongo_string_empty_option: "The connection string sets {key} but leaves it empty. Give it a value or remove it.",
1264
1286
  prompt_name: "Database name: ",
1265
1287
  prompt_permission: "Permission level (query-only, read-write, data-admin, admin): ",
1266
1288
  env_parse_note: "Note: Unable to parse .env configuration, using interactive prompts",
@@ -1598,6 +1620,23 @@ var messages_default2 = {
1598
1620
  secret_alternatives_sql: "\u6539\u7528 --password\u3001\u628A\u6191\u8B49\u653E\u9032 .env \u6216\u884C\u7A0B\u74B0\u5883\u8B8A\u6578\uFF0C\u6216\u4EE5 --use-env-refs \u5B58\u6210\u53C3\u7167",
1599
1621
  secret_alternatives_mongo_password: "\u6539\u7528 --password\u3001\u628A\u6191\u8B49\u653E\u9032 .env \u6216\u884C\u7A0B\u74B0\u5883\u8B8A\u6578\uFF0C\u6216\u4EE5 --uri \u8CBC\u4E0A\u9023\u7DDA\u5B57\u4E32",
1600
1622
  secret_alternatives_mongo_uri: "\u4EE5 --uri \u50B3\u5165\u9023\u7DDA\u5B57\u4E32",
1623
+ mongo_uri_conflicts_fields: "--uri \u4E0D\u80FD\u8207 {flags} \u4E26\u7528\uFF1A\u9023\u7DDA\u5B57\u4E32\u5DF2\u5305\u542B\u9019\u4E9B\u8A2D\u5B9A\u3002\u8ACB\u64C7\u4E00\u4F7F\u7528\uFF08--name \u53EF\u4E26\u7528\uFF0C\u7528\u4F86\u8986\u84CB\u8CC7\u6599\u5EAB\u540D\u7A31\uFF09\u3002",
1624
+ mongo_uri_with_env_refs: "--uri \u4E0D\u80FD\u8207 --use-env-refs \u4E26\u7528\uFF1A\u9023\u7DDA\u5B57\u4E32\u6703\u88AB\u62C6\u89E3\u6210\u6B04\u4F4D\u8A2D\u5B9A\u5BEB\u5165\uFF0C\u5E33\u5BC6\u4E0D\u6703\u88AB\u62BD\u6210\u74B0\u5883\u8B8A\u6578\u53C3\u7167\u3002\u8ACB\u6539\u8D70\u4E0B\u5217\u4EFB\u4E00\u505A\u6CD5\uFF1A\u62FF\u6389 --use-env-refs\uFF0C\u8B93 dbcli \u62C6\u89E3\u5B57\u4E32\u5BEB\u5165\u6B04\u4F4D\u8A2D\u5B9A\uFF1B\u6216\u6539\u7528 --env-* flag\uFF08--env-host\u3001--env-user\u3001--env-password \u7B49\uFF09\u9010\u6B04\u7D66\u8B8A\u6578\u540D\u7A31\u3002",
1625
+ mongo_uri_fallback_warning: "\u26A0\uFE0F \u6B64\u9023\u7DDA\u5B57\u4E32{reasons}\uFF0C\u7121\u6CD5\u62C6\u6210\u6B04\u4F4D\u8A2D\u5B9A\uFF0C\u5DF2\u539F\u6A23\u5B58\u5165 uri\uFF1B\u5E33\u5BC6\u5C07\u660E\u6587\u5B58\u653E\u65BC\u8A2D\u5B9A\u6A94\u3002",
1626
+ mongo_uri_reason_unix_socket: "\u4F7F\u7528 Unix domain socket\uFF08\u672C\u6A5F\u901A\u8A0A\u7AEF\uFF09",
1627
+ mongo_uri_reason_multi_host: "\u542B\u591A\u7D44 host\uFF08\u6B04\u4F4D\u8A2D\u5B9A\u53EA\u80FD\u8868\u9054\u4E00\u7D44\uFF09",
1628
+ mongo_uri_reason_secret_option: "\u542B\u6A5F\u5BC6 option\uFF08{keys}\uFF09\uFF0C\u62C6\u9032 options \u6703\u660E\u6587\u843D\u76E4",
1629
+ mongo_uri_reason_duplicate_key: "\u542B\u91CD\u8907\u7684 query \u9375\uFF08{keys}\uFF09\uFF08\u6B04\u4F4D\u8A2D\u5B9A\u6BCF\u500B\u9375\u53EA\u80FD\u5B58\u4E00\u500B\u503C\uFF09",
1630
+ mongo_uri_reason_non_scram: "\u4F7F\u7528\u975E SCRAM \u7684\u8A8D\u8B49\u6A5F\u5236 {mechanism}\uFF08\u6B04\u4F4D\u8A2D\u5B9A\u7121\u6CD5\u8868\u9054\uFF09",
1631
+ mongo_decomposed_header: "\u9023\u7DDA\u5B57\u4E32\u5DF2\u62C6\u89E3\u6210\u4E0B\u5217\u6B04\u4F4D\uFF08\u5BC6\u78BC\u5DF2\u906E\u853D\uFF09\uFF1A",
1632
+ mongo_paste_env_refs_warning: "\u26A0\uFE0F --use-env-refs \u4E0D\u9069\u7528\u65BC\u8CBC\u4E0A\u7684\u9023\u7DDA\u5B57\u4E32\uFF1A\u5E33\u5BC6\u6703\u4EE5\u5B57\u9762\u503C\u5BEB\u5165\u8A2D\u5B9A\u6A94\uFF0C\u4E0D\u6703\u8B8A\u6210\u74B0\u5883\u8B8A\u6578\u53C3\u7167\u3002",
1633
+ mongo_setup_mode_paste: "\u8CBC\u4E0A\u9023\u7DDA\u5B57\u4E32\uFF08Atlas / Compass \u8907\u88FD\u7684\uFF09",
1634
+ mongo_string_invalid: "\u4E0D\u662F\u5408\u6CD5\u7684 MongoDB \u9023\u7DDA\u5B57\u4E32\uFF08\u5B57\u4E32\u53EF\u80FD\u5E36\u6709\u5E33\u5BC6\uFF0C\u6240\u4EE5\u4E0D\u5370\u51FA\uFF09\u3002",
1635
+ mongo_string_bad_host: "\u9023\u7DDA\u5B57\u4E32\u7684 host \u6216\u57E0\u865F\u4E0D\u5408\u6CD5\uFF08\u57E0\u865F\u9808\u70BA 1 \u81F3 65535 \u7684\u6574\u6578\uFF09\u3002",
1636
+ mongo_string_bad_credentials: "\u9023\u7DDA\u5B57\u4E32\u7684\u5E33\u865F\u6216\u5BC6\u78BC\u542B\u6709\u672A\u8DF3\u812B\u7684\u4FDD\u7559\u5B57\u5143\uFF08\u5982 @\u3001:\u3001/\uFF09\u3002\u8ACB\u505A\u767E\u5206\u6BD4\u7DE8\u78BC\uFF08\u4F8B\u5982 @ \u5BEB\u6210 %40\uFF09\u3002",
1637
+ mongo_string_tls_conflict: "\u9023\u7DDA\u5B57\u4E32\u540C\u6642\u6307\u5B9A\u4E86 tls \u8207 ssl \u4E14\u503C\u4E0D\u540C\u3002",
1638
+ mongo_string_bad_tls: "\u9023\u7DDA\u5B57\u4E32\u7684 {key} \u53EA\u63A5\u53D7 true \u6216 false\u3002",
1639
+ mongo_string_empty_option: "\u9023\u7DDA\u5B57\u4E32\u6307\u5B9A\u4E86 {key} \u537B\u6C92\u6709\u503C\u3002\u8ACB\u7D66\u503C\u6216\u79FB\u9664\u3002",
1601
1640
  prompt_name: "\u8CC7\u6599\u5EAB\u540D\u7A31\uFF1A",
1602
1641
  prompt_permission: "\u6B0A\u9650\u7B49\u7D1A\uFF08query-only, read-write, data-admin, admin\uFF09\uFF1A",
1603
1642
  env_parse_note: "\u63D0\u793A\uFF1A\u7121\u6CD5\u89E3\u6790 .env \u914D\u7F6E\uFF0C\u4F7F\u7528\u4E92\u52D5\u5F0F\u63D0\u793A",
@@ -2168,6 +2207,61 @@ var messageLoader = MessageLoader.getInstance();
2168
2207
  var t = (key) => messageLoader.t(key);
2169
2208
  var t_vars = (key, vars) => messageLoader.interpolate(key, vars);
2170
2209
 
2210
+ // src/adapters/grant-redaction.ts
2211
+ var PRIVILEGES = new Set([
2212
+ "ALL",
2213
+ "ALL PRIVILEGES",
2214
+ "ALTER",
2215
+ "ALTER ROUTINE",
2216
+ "BINLOG ADMIN",
2217
+ "BINLOG MONITOR",
2218
+ "BINLOG REPLAY",
2219
+ "CONNECTION ADMIN",
2220
+ "CREATE",
2221
+ "CREATE ROUTINE",
2222
+ "CREATE TABLESPACE",
2223
+ "CREATE TEMPORARY TABLES",
2224
+ "CREATE USER",
2225
+ "CREATE VIEW",
2226
+ "DELETE",
2227
+ "DELETE HISTORY",
2228
+ "DROP",
2229
+ "EVENT",
2230
+ "EXECUTE",
2231
+ "FEDERATED ADMIN",
2232
+ "FILE",
2233
+ "GRANT OPTION",
2234
+ "INDEX",
2235
+ "INSERT",
2236
+ "LOCK TABLES",
2237
+ "PROCESS",
2238
+ "READ ONLY ADMIN",
2239
+ "RELOAD",
2240
+ "REPLICATION CLIENT",
2241
+ "REPLICATION MASTER ADMIN",
2242
+ "REPLICATION SLAVE",
2243
+ "REPLICATION SLAVE ADMIN",
2244
+ "REFERENCES",
2245
+ "SELECT",
2246
+ "SET USER",
2247
+ "SHOW CREATE ROUTINE",
2248
+ "SHOW DATABASES",
2249
+ "SHOW VIEW",
2250
+ "SHUTDOWN",
2251
+ "SLAVE MONITOR",
2252
+ "SUPER",
2253
+ "TRIGGER",
2254
+ "UPDATE",
2255
+ "USAGE"
2256
+ ]);
2257
+ var RESOURCE_OPTIONS = new Set([
2258
+ "MAX_QUERIES_PER_HOUR",
2259
+ "MAX_UPDATES_PER_HOUR",
2260
+ "MAX_CONNECTIONS_PER_HOUR",
2261
+ "MAX_USER_CONNECTIONS",
2262
+ "MAX_STATEMENT_TIME"
2263
+ ]);
2264
+
2171
2265
  // src/utils/case-fold.ts
2172
2266
  function foldCase(text) {
2173
2267
  const lowered = (text.includes("\u0130") ? text.replaceAll("\u0130", "i") : text).toLowerCase();
@@ -8496,6 +8590,24 @@ var TimeoutField = {
8496
8590
  timeout: numberType().int().min(MIN_CONNECTION_TIMEOUT_MS).max(MAX_CONNECTION_TIMEOUT_MS).optional(),
8497
8591
  statementTimeout: numberType().int().min(MIN_STATEMENT_TIMEOUT_MS).max(MAX_STATEMENT_TIMEOUT_MS).optional()
8498
8592
  };
8593
+ var RESERVED_MONGODB_OPTION_KEYS = {
8594
+ authsource: "authSource",
8595
+ replicaset: "replicaSet",
8596
+ tls: "tls",
8597
+ ssl: "tls"
8598
+ };
8599
+ var MongoDBOptionsSchema = recordType(stringType(), stringType()).superRefine((options, ctx) => {
8600
+ for (const key of Object.keys(options)) {
8601
+ const field = RESERVED_MONGODB_OPTION_KEYS[key.toLowerCase()];
8602
+ if (field) {
8603
+ ctx.addIssue({
8604
+ code: ZodIssueCode.custom,
8605
+ path: [key],
8606
+ message: `options.${key} duplicates the dedicated '${field}' field; set '${field}' instead`
8607
+ });
8608
+ }
8609
+ }
8610
+ });
8499
8611
  var MongoDBConnectionConfigSchema = objectType({
8500
8612
  system: literalType("mongodb"),
8501
8613
  uri: unionType([stringType(), EnvRefSchema]).optional(),
@@ -8507,6 +8619,7 @@ var MongoDBConnectionConfigSchema = objectType({
8507
8619
  authSource: unionType([stringType(), EnvRefSchema]).optional(),
8508
8620
  replicaSet: unionType([stringType(), EnvRefSchema]).optional(),
8509
8621
  tls: booleanType().optional(),
8622
+ options: MongoDBOptionsSchema.optional(),
8510
8623
  srv: booleanType().optional().default(false),
8511
8624
  ...TimeoutField
8512
8625
  });
@@ -9877,6 +9990,15 @@ var DECLARATIONS = [
9877
9990
  permission: "query-only",
9878
9991
  requiresConnection: true
9879
9992
  },
9993
+ {
9994
+ id: "blacklist.read",
9995
+ key: "blacklistRead",
9996
+ command: "blacklist list",
9997
+ description: "Read the configured table, column and key rules that hide sensitive data.",
9998
+ permission: "query-only",
9999
+ requiresConnection: false,
10000
+ mutatesConfiguration: false
10001
+ },
9880
10002
  {
9881
10003
  id: "blacklist.manage",
9882
10004
  key: "blacklist",
@@ -10191,6 +10313,7 @@ var COMMAND_SURFACE = Object.freeze({
10191
10313
  "delete",
10192
10314
  "export",
10193
10315
  "check",
10316
+ "blacklist list",
10194
10317
  "inspect",
10195
10318
  "report",
10196
10319
  "guide",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "10.0.0",
3
+ "version": "12.0.0",
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": "10.0.0",
3
+ "version": "12.0.0",
4
4
  "description": "Database CLI for AI agents",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -100,6 +100,7 @@
100
100
  "lru-cache": "^11.4.0",
101
101
  "lucide-react": "^1.16.0",
102
102
  "mongodb": "^7.2.0",
103
+ "mongodb-connection-string-url": "^7.0.1",
103
104
  "mysql2": "^3.24.3",
104
105
  "node-sql-parser": "5",
105
106
  "open": "^11.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcli-agent",
3
- "version": "10.0.0",
3
+ "version": "12.0.0",
4
4
  "description": "Database CLI skill and command reference for AI agents",
5
5
  "author": {
6
6
  "name": "Carl Lee",
@@ -372,7 +372,7 @@ dbcli init # parses .env in cwd
372
372
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --name mydb
373
373
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 \
374
374
  --user admin --password '<secret>' --auth-source admin --name mydb
375
- # MongoDB — full URI (advanced escape hatch: multi-host, non-standard driver options)
375
+ # MongoDB — full URI (decomposed into fields on write; multi-host / secret-option strings stay as `uri` with a warning)
376
376
  dbcli init --conn-name local --system mongodb \
377
377
  --uri "mongodb+srv://user:pw@cluster.example.mongodb.net/mydb?authSource=admin"
378
378
 
@@ -494,9 +494,10 @@ refs have no value to connect with yet.
494
494
  natively or via the DoH fallback; useful when the runtime restricts DNS.
495
495
  - **MongoDB `authSource` / `replicaSet` / `tls` / `srv`** — `init` asks for
496
496
  these interactively (`authSource` only when a user is set; `replicaSet` /
497
- `tls` behind an "advanced options?" prompt); `--auth-source <db>` is the
498
- only one with a dedicated non-interactive flag, so set `replicaSet` / `tls`
499
- interactively or edit `.dbcli` afterward. If a config has both `uri` and
497
+ `tls` behind an "advanced options?" prompt); non-interactive flags are
498
+ `--auth-source <db>`, `--replica-set <name>`, `--srv` (no `port` written) and
499
+ `--tls` / `--no-tls` (neither given writes no `tls`); a flag you pass skips
500
+ its prompt. If a config has both `uri` and
500
501
  per-field values, `uri` wins silently — `dbcli doctor` flags this and also
501
502
  warns when `srv: true` is combined with a non-default `port`.
502
503
  - **MySQL/Postgres password with `@` `:` `/`** — when using `DATABASE_URL`,
@@ -127,7 +127,7 @@ dbcli init --conn-name local --no-interactive --force # Non-interactive; cred
127
127
  # MongoDB — field-by-field (primary path, same shape as SQL)
128
128
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --user admin --password secret --auth-source admin --name mydb
129
129
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --name mydb # No auth
130
- # MongoDB — full URI (advanced fallback: multi-host, non-standard driver options)
130
+ # MongoDB — full URI (decomposed into fields on write; multi-host / secret-option strings stay as `uri` with a warning)
131
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)
@@ -161,7 +161,7 @@ New initialization always creates named v2 configuration, including plain `init`
161
161
 
162
162
  **Environment-reference options:** `--env-host <var>`, `--env-port <var>`, `--env-user <var>`, `--env-password <var>`, `--env-database <var>`
163
163
 
164
- **MongoDB-specific options:** `--uri <uri>` (full connection URI — advanced fallback), `--auth-source <db>` (auth database, default: `admin` when user/password set). Interactive `init` also asks for `replicaSet` and `tls` under an "advanced options?" prompt; there is no dedicated non-interactive flag for either yet — set them interactively or edit `.dbcli` afterward. `srv` (boolean, builds `mongodb+srv://` and resolves hosts via DNS SRV, ignoring `port`) is asked right after `host`, before `port`, since it decides whether `port` is even relevant.
164
+ **MongoDB-specific options:** `--uri <uri>` (full connection URI, decomposed into field config on write: `authSource`/`replicaSet`/`tls`(`ssl`) become dedicated fields, `mongodb+srv` becomes `srv: true`, the path database becomes `database`, other parameters go to `options`; multi-host strings, strings carrying `authMechanismProperties`/`tlsCertificateKeyFilePassword`/`proxyPassword`, strings repeating a query key, and strings whose `authMechanism` is not SCRAM-SHA-1/SCRAM-SHA-256 are stored as-is in `uri` with a plaintext-credentials warning; cannot be combined with `--host`/`--port`/`--user`/`--password`/`--auth-source`/`--replica-set`/`--srv`/`--tls`/`--no-tls` or `--use-env-refs`; `--name` may be combined), `--auth-source <db>` (auth database, default: `admin` when user/password set). `--replica-set <name>` (writes `replicaSet`), `--srv` (writes `srv: true` and no `port`; builds `mongodb+srv://` and resolves hosts via DNS SRV), `--tls` / `--no-tls` (writes `tls: true` / `tls: false`; neither flag writes no `tls` key, so the driver default applies). Interactive `init` skips the prompt for any of these given as a flag; otherwise it asks `srv` right after `host` (before `port`) and `replicaSet` / `tls` under an "advanced options?" prompt. The flags also apply with `--use-env-refs`.
165
165
 
166
166
  **Elasticsearch-specific options:** `--cloud-id <id>` (Elastic Cloud), `--api-key <key>` (ApiKey auth). Other ES fields (`nodes[]`, `protocol`, `caPath`, `rejectUnauthorized`) can be edited directly in `.dbcli`.
167
167
 
@@ -1868,8 +1868,11 @@ at execution time, and no human has agreed to anything. `admin` in a config file
1868
1868
  is a permission level, not a DBA sign-off.
1869
1869
 
1870
1870
  `schema.read` is available under `DBCLI_AGENT_MODE=1`, and `dbcli schema` runs
1871
- there: storing the schema cache is not a configuration change. Agent mode still
1872
- refuses every change to connection identity, permission and credentials.
1871
+ there: storing the schema cache is not a configuration change. `blacklist.read`
1872
+ (`blacklist list`) is available there too, so read-only Task Packs that inspect
1873
+ the blacklist can plan; `blacklist.manage`, which adds and removes rules, is
1874
+ refused. Agent mode still refuses every change to connection identity,
1875
+ permission and credentials.
1873
1876
 
1874
1877
  **Permission:** query-only+ (no connection is made)
1875
1878
 
@@ -3644,7 +3647,7 @@ Parser behaviour (`src/core/saved-queries/parser.ts::normaliseVisual`):
3644
3647
 
3645
3648
  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.
3646
3649
 
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>`.
3650
+ `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 (stored as-is) and the non-interactive path via `--uri` (with the required `--conn-name`), where the string is decomposed into the field config on write. 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>`.
3648
3651
 
3649
3652
  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`.
3650
3653
 
@@ -372,7 +372,7 @@ dbcli init # parses .env in cwd
372
372
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --name mydb
373
373
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 \
374
374
  --user admin --password '<secret>' --auth-source admin --name mydb
375
- # MongoDB — full URI (advanced escape hatch: multi-host, non-standard driver options)
375
+ # MongoDB — full URI (decomposed into fields on write; multi-host / secret-option strings stay as `uri` with a warning)
376
376
  dbcli init --conn-name local --system mongodb \
377
377
  --uri "mongodb+srv://user:pw@cluster.example.mongodb.net/mydb?authSource=admin"
378
378
 
@@ -494,9 +494,10 @@ refs have no value to connect with yet.
494
494
  natively or via the DoH fallback; useful when the runtime restricts DNS.
495
495
  - **MongoDB `authSource` / `replicaSet` / `tls` / `srv`** — `init` asks for
496
496
  these interactively (`authSource` only when a user is set; `replicaSet` /
497
- `tls` behind an "advanced options?" prompt); `--auth-source <db>` is the
498
- only one with a dedicated non-interactive flag, so set `replicaSet` / `tls`
499
- interactively or edit `.dbcli` afterward. If a config has both `uri` and
497
+ `tls` behind an "advanced options?" prompt); non-interactive flags are
498
+ `--auth-source <db>`, `--replica-set <name>`, `--srv` (no `port` written) and
499
+ `--tls` / `--no-tls` (neither given writes no `tls`); a flag you pass skips
500
+ its prompt. If a config has both `uri` and
500
501
  per-field values, `uri` wins silently — `dbcli doctor` flags this and also
501
502
  warns when `srv: true` is combined with a non-default `port`.
502
503
  - **MySQL/Postgres password with `@` `:` `/`** — when using `DATABASE_URL`,
@@ -127,7 +127,7 @@ dbcli init --conn-name local --no-interactive --force # Non-interactive; cred
127
127
  # MongoDB — field-by-field (primary path, same shape as SQL)
128
128
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --user admin --password secret --auth-source admin --name mydb
129
129
  dbcli init --conn-name local --system mongodb --host localhost --port 27017 --name mydb # No auth
130
- # MongoDB — full URI (advanced fallback: multi-host, non-standard driver options)
130
+ # MongoDB — full URI (decomposed into fields on write; multi-host / secret-option strings stay as `uri` with a warning)
131
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)
@@ -161,7 +161,7 @@ New initialization always creates named v2 configuration, including plain `init`
161
161
 
162
162
  **Environment-reference options:** `--env-host <var>`, `--env-port <var>`, `--env-user <var>`, `--env-password <var>`, `--env-database <var>`
163
163
 
164
- **MongoDB-specific options:** `--uri <uri>` (full connection URI — advanced fallback), `--auth-source <db>` (auth database, default: `admin` when user/password set). Interactive `init` also asks for `replicaSet` and `tls` under an "advanced options?" prompt; there is no dedicated non-interactive flag for either yet — set them interactively or edit `.dbcli` afterward. `srv` (boolean, builds `mongodb+srv://` and resolves hosts via DNS SRV, ignoring `port`) is asked right after `host`, before `port`, since it decides whether `port` is even relevant.
164
+ **MongoDB-specific options:** `--uri <uri>` (full connection URI, decomposed into field config on write: `authSource`/`replicaSet`/`tls`(`ssl`) become dedicated fields, `mongodb+srv` becomes `srv: true`, the path database becomes `database`, other parameters go to `options`; multi-host strings, strings carrying `authMechanismProperties`/`tlsCertificateKeyFilePassword`/`proxyPassword`, strings repeating a query key, and strings whose `authMechanism` is not SCRAM-SHA-1/SCRAM-SHA-256 are stored as-is in `uri` with a plaintext-credentials warning; cannot be combined with `--host`/`--port`/`--user`/`--password`/`--auth-source`/`--replica-set`/`--srv`/`--tls`/`--no-tls` or `--use-env-refs`; `--name` may be combined), `--auth-source <db>` (auth database, default: `admin` when user/password set). `--replica-set <name>` (writes `replicaSet`), `--srv` (writes `srv: true` and no `port`; builds `mongodb+srv://` and resolves hosts via DNS SRV), `--tls` / `--no-tls` (writes `tls: true` / `tls: false`; neither flag writes no `tls` key, so the driver default applies). Interactive `init` skips the prompt for any of these given as a flag; otherwise it asks `srv` right after `host` (before `port`) and `replicaSet` / `tls` under an "advanced options?" prompt. The flags also apply with `--use-env-refs`.
165
165
 
166
166
  **Elasticsearch-specific options:** `--cloud-id <id>` (Elastic Cloud), `--api-key <key>` (ApiKey auth). Other ES fields (`nodes[]`, `protocol`, `caPath`, `rejectUnauthorized`) can be edited directly in `.dbcli`.
167
167
 
@@ -1868,8 +1868,11 @@ at execution time, and no human has agreed to anything. `admin` in a config file
1868
1868
  is a permission level, not a DBA sign-off.
1869
1869
 
1870
1870
  `schema.read` is available under `DBCLI_AGENT_MODE=1`, and `dbcli schema` runs
1871
- there: storing the schema cache is not a configuration change. Agent mode still
1872
- refuses every change to connection identity, permission and credentials.
1871
+ there: storing the schema cache is not a configuration change. `blacklist.read`
1872
+ (`blacklist list`) is available there too, so read-only Task Packs that inspect
1873
+ the blacklist can plan; `blacklist.manage`, which adds and removes rules, is
1874
+ refused. Agent mode still refuses every change to connection identity,
1875
+ permission and credentials.
1873
1876
 
1874
1877
  **Permission:** query-only+ (no connection is made)
1875
1878
 
@@ -3644,7 +3647,7 @@ Parser behaviour (`src/core/saved-queries/parser.ts::normaliseVisual`):
3644
3647
 
3645
3648
  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.
3646
3649
 
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>`.
3650
+ `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 (stored as-is) and the non-interactive path via `--uri` (with the required `--conn-name`), where the string is decomposed into the field config on write. 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>`.
3648
3651
 
3649
3652
  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`.
3650
3653