dsh-db-tool 1.3.0 → 1.3.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.
package/README.md CHANGED
@@ -38,6 +38,26 @@ dsh plugin --profile web add "link:E:\path\to\dsh-db-tool"
38
38
 
39
39
  GaussDB 官方驱动未发布 npm,需先构建 vendor:`npm run build:gaussdb`(PowerShell)或 `bash scripts/build-gaussdb.sh`;运行要求 Node ≥ 22.12(产物依赖 p-limit@7 纯 ESM)。oracledb 安装脚本需 `npm approve-scripts oracledb`。mongodb 驱动已 bundle 进发布包(`vendor/mongodb-driver.cjs`,esbuild 构建,`npm run build:mongodb` 可重建),依赖树中不含 mongodb/punycode,详见 [docs/install.md](docs/install.md)。
40
40
 
41
+ ### 桌面端安装
42
+
43
+ DSH 桌面端 0.2.0-rc.2+ 捆绑了 `dsh` 命令,全程无需另装 Node 或 pnpm:
44
+
45
+ 1. **首次使用**:打开桌面端菜单栏,点 **"Manage dsh command"(管理 dsh 命令)**,安装捆绑的 CLI——该操作把 `dsh` 命令注册到系统 PATH。
46
+ 2. **安装插件**(必须钉精确版本:`@latest` 会因 release-age 校验回落到旧版):
47
+
48
+ ```bash
49
+ dsh plugin --profile desktop add dsh-db-tool@1.3.1 --registry=https://registry.npmjs.org/
50
+ ```
51
+
52
+ 已有 npm 镜像源偏好的用户,可把 `--registry` 替换为自己的镜像地址。
53
+ 3. **重启桌面端**生效。
54
+
55
+ 桌面端补充说明:
56
+
57
+ - **免补丁路径**:桌面端宿主代码打包在 `app.asar` 内,无法应用 `patch:dsh` 热补丁;但本插件 0.1.9+ 走免补丁路径(mongodb 驱动已 bundle 为 `vendor/mongodb-driver.cjs` 随包发布,依赖树不含 punycode),桌面端可直接安装加载,无需任何补丁。
58
+ - **GaussDB**:npm 发布包不含 GaussDB vendor 驱动。需要 GaussDB 的用户请改从源码安装(`dsh plugin --profile desktop add "dsh-db-tool@github:mengqi1436/dsh-db-tool"`),并在插件目录自行 `npm run build:gaussdb`(要求 Node ≥ 22.12)。
59
+ - **Oracle**:安装后需 `npm approve-scripts oracledb` 放行 oracledb 安装脚本(或按 DSH 插件安装界面的脚本审批提示放行)。
60
+
41
61
  ## 安全模型
42
62
 
43
63
  - HTTP API 仅同源(`ctx.webServer` prefix `/dsh-db-tool/api`)+ 宿主 Connection 栅栏(`ctx.connection.requestRejection`:Host/Origin + 浏览器 token 鉴权。0.2.0-rc.1 起插件前缀路由不经宿主栅栏,故在 handler 顶层显式应用;宿主无 connection 服务时回退 loopback/Origin trust 校验,等价 ssh-tunnel `http-trust`),body 限 2MB
@@ -52,7 +72,7 @@ GaussDB 官方驱动未发布 npm,需先构建 vendor:`npm run build:gaussdb
52
72
 
53
73
  症状:DSH 启动后插件加载报 `failed to import`,伴随 `TypeError: Cannot read properties of null (reading 'Symbol(Symbol.iterator)')`,栈指向 `dsh-app-boot` 的 `routeScoped`。
54
74
 
55
- 根因:上游 `@deepseek-ai/dsh-app-boot` 对 `createRequire(parent).resolve.paths(name)` 直接做 `for..of`,而 Node 对 core-module 同名包(`punycode` 等)返回 `null`,hoisted profile 下凡依赖树含此类 npm 包的插件都会炸。`0.1.7-rc.2` 与 `0.2.0-rc.1` 中同型缺陷两处(锚点行逐字节一致,仅整体行号偏移 1 行):`routeScoped()` 与 `nativePackageDir()`,本补丁一并修复(两处分别独立判定,已打过旧版单处补丁的机器只会补上缺的那处)。
75
+ 根因:上游 `@deepseek-ai/dsh-app-boot` 对 `createRequire(parent).resolve.paths(name)` 直接做 `for..of`,而 Node 对 core-module 同名包(`punycode` 等)返回 `null`,hoisted profile 下凡依赖树含此类 npm 包的插件都会炸。`0.1.7-rc.2`、`0.2.0-rc.1` 与 `0.2.0-rc.2` 中同型缺陷两处(`0.2.0-rc.2` 的 `lib/index.js` 与 `0.2.0-rc.1` 逐字节相同,尚未修复;锚点行均与 `0.1.7-rc.2` 一致,仅整体行号偏移 1 行):`routeScoped()` 与 `nativePackageDir()`,本补丁一并修复(两处分别独立判定,已打过旧版单处补丁的机器只会补上缺的那处)。
56
76
 
57
77
  一键修复(幂等,应用前自动备份为 `index.js.bak-hotfix`;`--revert` 可还原):
58
78
 
@@ -61,7 +81,7 @@ npm run patch:dsh # Windows(PowerShell)
61
81
  npm run patch:dsh:sh # macOS / Linux
62
82
  ```
63
83
 
64
- 脚本自动探测 DSH 安装根(`--dsh-root` 可显式指定);补丁文件按安装版本自动选择:`patches/dsh-app-boot-route-scoped-hotfix.patch`(`0.1.7-rc.2`)、`patches/dsh-app-boot-route-scoped-hotfix-0.2.0-rc.1.patch`(`0.2.0-rc.1`,与内建替换路径逐字节等价已验证);不支持的版本会警告(`--force` 覆盖)。上游 issue:<https://github.com/mengqi1436/dsh-db-tool/issues>(占位,待上游仓库开放后替换)。
84
+ 脚本自动探测 DSH 安装根(`--dsh-root` 可显式指定);补丁文件按安装版本自动选择:`patches/dsh-app-boot-route-scoped-hotfix.patch`(`0.1.7-rc.2`)、`patches/dsh-app-boot-route-scoped-hotfix-0.2.0-rc.1.patch`(`0.2.0-rc.1`)、`patches/dsh-app-boot-route-scoped-hotfix-0.2.0-rc.2.patch`(`0.2.0-rc.2`,其 `lib/index.js` 与 `0.2.0-rc.1` 逐字节相同,故 hunk 完全一致;均与内建替换路径逐字节等价已验证);不支持的版本会警告(`--force` 覆盖)。上游 issue:<https://github.com/mengqi1436/dsh-db-tool/issues>(占位,待上游仓库开放后替换)。
65
85
 
66
86
  **本插件的免补丁路径(0.1.9+)**:该 bug 的触发条件是依赖树中出现 core-module 同名包,mongodb 链(`mongodb-connection-string-url → whatwg-url → tr46 → punycode`)正是元凶。0.1.9 起 mongodb 驱动经 esbuild bundle 为 `vendor/mongodb-driver.cjs` 随包发布,生产依赖树不再含 mongodb 与 punycode——在**未修复宿主**(含桌面版 app.asar,无法打补丁)上也能正常安装加载。守卫测试 `tests/guard/deps-core-collision.spec.ts` 断言依赖树永不回退(dependencies 白名单 + lockfile 生产树 core 同名包零交集)。`patch:dsh` 仍保留,用于修复**其他**含同类依赖的插件或宿主自身报错。
67
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-db-tool",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "DSH community plugin: chat-operated multi-database admin tool with sidebar management, project-scoped grants, ro/rw modes and dangerous-operation confirmation",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,41 @@
1
+ # DSH dsh-app-boot resolve.paths hotfix (upstream bug: createRequire(parent).resolve.paths(name)
2
+ # returns null for core-module names like "punycode", breaking hoisted profile installs).
3
+ # Covers BOTH unguarded for..of sites in 0.2.0-rc.2: routeScoped() (@@ -1423,14) and
4
+ # nativePackageDir() (@@ -1245,10). lib/index.js is byte-identical to 0.2.0-rc.1
5
+ # (anchor lines identical to 0.1.7-rc.2, overall +1 shift) — hunks shared verbatim.
6
+ # Target-Version: 0.2.0-rc.2
7
+ # Apply manually: git apply -p1 -d <dsh-app-boot package root> <this file>
8
+ # Or one command: npm run patch:dsh (scripts/apply-dsh-hotfix.ps1)
9
+ # Generated from @deepseek-ai/dsh-app-boot@0.2.0-rc.2 npm tarball vs patched local copy.
10
+ diff --git a/lib/index.js b/lib/index.js
11
+ index e60aac4..fcd1a38 100644
12
+ --- a/lib/index.js
13
+ +++ b/lib/index.js
14
+ @@ -1245,7 +1245,10 @@ function profileChild(path, treePrefix) {
15
+ return treePrefix + (end < 0 ? rest : rest.slice(0, end));
16
+ }
17
+ function nativePackageDir(parent, name) {
18
+ - for (const searchPath of createRequire(parent).resolve.paths(name)) {
19
+ + /* local hotfix: nativePackageDir: resolve.paths returns null for core-module names
20
+ + (fs, node:fs, ...); an empty list means no local candidate, matching the
21
+ + guard in profile.ts:596. */
22
+ + for (const searchPath of createRequire(parent).resolve.paths(name) ?? []) {
23
+ const candidate = join(searchPath, name);
24
+ if (existsSync(join(candidate, "package.json"))) return candidate;
25
+ }
26
+ @@ -1420,7 +1423,14 @@ var ResolutionRouter = class {
27
+ const target = resolution.entries.get(name);
28
+ const candidates = [];
29
+ const localSearchPaths = [];
30
+ - for (const searchPath of createRequire(parent).resolve.paths(name)) {
31
+ + /* local hotfix: resolve.paths returns null for core-module names (e.g. "punycode"),
32
+ + which made the for..of throw TypeError and broke every hoisted profile install
33
+ + whose dependency tree requires such an npm package. Fall back to the standard
34
+ + node_modules search chain so the local candidate can still be found. */
35
+ + const _hotReq = createRequire(parent);
36
+ + const _hotPaths = _hotReq.resolve.paths(name)
37
+ + ?? _hotReq("node:module")._nodeModulePaths(_hotReq("node:path").dirname(parent));
38
+ + for (const searchPath of _hotPaths) {
39
+ if (!searchPath.startsWith(layer.localPrefix)) break;
40
+ localSearchPaths.push(searchPath);
41
+ const candidate = localPackageCandidate(searchPath, name, flavor);
@@ -5,9 +5,9 @@
5
5
  * 修复的 bug:@deepseek-ai/dsh-app-boot 对
6
6
  * `createRequire(parent).resolve.paths(name)` 的 for..of 无保护,而 Node 对
7
7
  * core-module 同名包(punycode 等)返回 null,for..of null 直接抛 TypeError,
8
- * 导致 hoisted profile 下 npm 安装插件导入失败。rc.2 起共两处同型缺陷:
9
- * 1. routeScoped()(rc.2 L1419 区域 / 0.2.0-rc.1 L1423 区域)—— 症状直接暴露;
10
- * 2. nativePackageDir()(rc.2 L1244 区域 / 0.2.0-rc.1 L1248 区域)—— 症状相同,一并修复。
8
+ * 导致 hoisted profile 下 npm 安装插件导入失败。0.1.7-rc.2 起共两处同型缺陷:
9
+ * 1. routeScoped()(0.1.7-rc.2 L1419 区域 / 0.2.0-rc.1 与 0.2.0-rc.2 L1423 区域)—— 症状直接暴露;
10
+ * 2. nativePackageDir()(0.1.7-rc.2 L1244 区域 / 0.2.0-rc.1 与 0.2.0-rc.2 L1248 区域)—— 症状相同,一并修复。
11
11
  *
12
12
  * 版本支持:锚点行在 TARGET_VERSIONS 列出的版本中逐字节一致(仅整体行号偏移),
13
13
  * 内建替换路径与版本无关;git-apply 路径按安装版本选择 patches/ 下行号匹配的补丁。
@@ -23,12 +23,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
23
23
 
24
24
  /** 补丁文件里的目标版本声明行(patches/*.patch 注释头)。 */
25
25
  export const TARGET_VERSION = '0.1.7-rc.2';
26
- /** 锚点行逐字节一致的受支持版本列表(仅整体行号偏移;0.2.0-rc.1 = rc.2 行号 +1)。 */
27
- export const TARGET_VERSIONS = ['0.1.7-rc.2', '0.2.0-rc.1'];
26
+ /** 锚点行逐字节一致的受支持版本列表(仅整体行号偏移;0.2.0-rc.1/0.2.0-rc.2 的 lib/index.js 逐字节相同)。 */
27
+ export const TARGET_VERSIONS = ['0.1.7-rc.2', '0.2.0-rc.1', '0.2.0-rc.2'];
28
28
  /** 各受支持版本对应的默认补丁文件名(patches/ 下;git-apply 路径按版本选择)。 */
29
29
  export const PATCH_BY_VERSION = {
30
30
  '0.1.7-rc.2': 'dsh-app-boot-route-scoped-hotfix.patch',
31
31
  '0.2.0-rc.1': 'dsh-app-boot-route-scoped-hotfix-0.2.0-rc.1.patch',
32
+ '0.2.0-rc.2': 'dsh-app-boot-route-scoped-hotfix-0.2.0-rc.2.patch',
32
33
  };
33
34
  /** 判断目标文件是否已打补丁的标识串(hotfix 注释首行片段)。 */
34
35
  export const HOTFIX_MARKER = 'local hotfix: resolve.paths returns null';
@@ -1,76 +0,0 @@
1
- # dsh-db-tool HTTP API 契约(v1)
2
-
3
- 侧边栏 client 与 lib/http 实现共同遵守。API 仅监听 loopback(127.0.0.1),校验 `Origin`/`Referer` 必须来自 DSH 本地 web(同源 fenced)。所有请求/响应 JSON。
4
-
5
- ## 通用约定
6
-
7
- - 成功:`200 { "ok": true, "data": ... }`
8
- - 失败:`{ "ok": false, "error": string, "code": string }`,code ∈ `UNAUTHORIZED_PROJECT`(项目未授权该连接)/ `READ_ONLY`(ro 连接拒绝 execute)/ `NEEDS_CONFIRMATION`(危险操作待确认)/ `INVALID_CHALLENGE` / `NOT_FOUND` / `INVALID_ARGUMENT`(参数非法;插件 dispose 后的新请求同样返回此 code,error 为「服务已关闭」)/ `DRIVER_ERROR`
9
- - `projectPath`:前端传入当前 workspace 绝对路径,服务端用 `normalizeProjectKey` 归一后校验 grants;**不传视为匿名项目**(仅连接管理可用,业务操作一律拒)
10
- - 人工确认通道:SQL 控制台是人工操作,危险语句同样走 challenge 流程——前端展示确认对话框后携 `challengeId` 重发
11
- - 除注明外,业务端点均需 projectPath 且该连接已授权
12
-
13
- ## 路由
14
-
15
- ### 连接管理(无需 projectPath)
16
-
17
- | 方法/路径 | 说明 |
18
- |---|---|
19
- | `GET /api/connections` | 全量连接列表(脱敏 ConnectionMeta[],含每库 kind) |
20
- | `POST /api/connections` | 创建 `{ id, kind, name?, url?, fields?, ssl? }`;密码自动拆入 secrets |
21
- | `PUT /api/connections/:id` | 更新(同上字段可选) |
22
- | `DELETE /api/connections/:id` | 删除(级联 secrets + 全项目 grants) |
23
- | `POST /api/connections/:id/test` | 测试连接 → `TestConnectResult` |
24
-
25
- ### 项目授权
26
-
27
- | 方法/路径 | 说明 |
28
- |---|---|
29
- | `GET /api/grants?project=<path>` | 该项目授权列表 `{ connId, mode }[]` |
30
- | `PUT /api/grants` | `{ projectPath, connId, mode: "ro"\|"rw" }` 授权/改模式 |
31
- | `DELETE /api/grants` | `{ projectPath, connId }` 撤销 |
32
-
33
- ### 浏览(需授权,ro 即可)
34
-
35
- | 方法/路径 | 说明 |
36
- |---|---|
37
- | `GET /api/databases?project=<path>&connId=` | 库/schema 清单 string[] |
38
- | `GET /api/tables?project=<path>&connId=&database=` | TableInfo[] |
39
- | `GET /api/schema?project=<path>&connId=&database=&table=` | ColumnInfo[] |
40
- | `GET /api/preview?project=<path>&connId=&database=&table=&limit=&offset=` | QueryResult(limit≤50 强制;offset 为行偏移,翻页用,默认 0) |
41
-
42
- ### SQL 控制台 / 脚本(需授权,execute 需 rw)
43
-
44
- | 方法/路径 | 说明 |
45
- |---|---|
46
- | `POST /api/query` | `{ projectPath, connId, sql, params?, challengeId? }` → QueryResult;危险读(如 KEYS)同样触发 NEEDS_CONFIRMATION |
47
- | `POST /api/execute` | `{ projectPath, connId, statement, params?, challengeId? }` → ExecResult 或 `NEEDS_CONFIRMATION { challengeId, statement, danger, reason }` |
48
- | `POST /api/script` | `{ projectPath, connId, code, challengeId? }` → 子进程沙箱执行(Node permission model 禁 fs + 新 vm realm 双层隔离),60s 强超时;db 句柄经 IPC 走完整 guard/审计链路 |
49
-
50
- ### 审计
51
-
52
- | 方法/路径 | 说明 |
53
- |---|---|
54
- | `GET /api/audit?project=<path>&limit=` | AuditEntry[](最近 n 条,默认 50) |
55
-
56
- ### 状态
57
-
58
- | 方法/路径 | 说明 |
59
- |---|---|
60
- | `GET /api/state?project=<path>` | 面板初始化:`{ connections, grants, auditTail }` |
61
-
62
- ## NEEDS_CONFIRMATION 语义
63
-
64
- ```json
65
- {
66
- "ok": false,
67
- "code": "NEEDS_CONFIRMATION",
68
- "challengeId": "c_9f3a…",
69
- "statement": "DROP TABLE users",
70
- "danger": "danger",
71
- "reason": "DDL 不可回滚(隐式提交)"
72
- }
73
- ```
74
-
75
- - `challengeId` 一次性、绑定语句 hash、5 分钟过期;重发请求带同 `challengeId` 且语句 hash 一致才放行
76
- - 模型工具(对话内)用同一 guard/challenge 实现,确认经 ask_user 完成
@@ -1,80 +0,0 @@
1
- # dsh-db-tool 侧边栏 Apple 风格重设计规范(单一真相)
2
-
3
- 所有参与者必须遵守本规范。目标:贴合 Apple 官方视觉语言(macOS/iOS 系统 UI、HIG),在 DSH 侧边栏窄容器(约 380-420px)内呈现。
4
-
5
- ## 硬性约束(所有 teammate)
6
- - **只改自己分配的行区段**,区段外一律不动(edit 基于 old_string 精确匹配)。
7
- - **i18n key 冻结**(client/client.js L18-264):不得新增/删除/改名 key;如确需新文案,在汇报中列出由 Lead 决定。
8
- - **不新增任何 npm 依赖**(单文件 bundle 无构建步骤)。图标只用极简内联 SVG 几何图形(chevron/加号/三角等 primitives)或纯排版。
9
- - 保持 `React.createElement` 形态、保持组件对外 props/签名不变、保持 `dbt-` 类名前缀。
10
- - 保留对宿主变量的 fallback:`var(--dsh-accent, <apple值>)` 形式可保留,但视觉基线以本规范的 Apple token 为准。
11
- - 尊重 `prefers-color-scheme`(light/dark 双模式)与 `prefers-reduced-motion`。
12
- - 完成后 `node --check client/client.js` 必须通过。
13
-
14
- ## 1. Design Tokens(CSS 变量,定义在 .dbt-panel 根)
15
-
16
- 字体:
17
- - UI 字体:`-apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif`
18
- - 等宽(SQL/数据):`ui-monospace, "SF Mono", Menlo, Consolas, monospace`
19
- - 字号阶梯:caption 11px / 正文 13px / 小标题 13px semibold / 标题 15px semibold。行高 1.45。
20
-
21
- 颜色(dark 模式为基线,light 模式对应反转):
22
- | token | dark | light |
23
- |---|---|---|
24
- | --dbt-accent | #0A84FF(系统蓝) | #007AFF |
25
- | --dbt-bg | 透明(继承宿主) | 同 |
26
- | --dbt-surface | rgba(120,120,128,.12) | rgba(120,120,128,.08) |
27
- | --dbt-surface-strong | rgba(120,120,128,.18) | rgba(120,120,128,.14) |
28
- | --dbt-separator | rgba(120,120,128,.24) | rgba(60,60,67,.18) |
29
- | --dbt-text-secondary | rgba(235,235,245,.6) | rgba(60,60,67,.6) |
30
- | --dbt-danger | #FF453A | #FF3B30 |
31
- | --dbt-success | #30D158 | #34C759 |
32
- | --dbt-warning | #FFD60A | #FF9F0A |
33
-
34
- 材质(Apple 毛玻璃近似,非官方 Liquid Glass):
35
- - 对话框/粘性表头可用 `backdrop-filter: blur(20px) saturate(180%)` + 半透明背景;提供 `@media (prefers-reduced-transparency: reduce)` 下降级为实色。
36
- - 阴影一律带色调(不用纯黑):`0 8px 32px rgba(0,0,0,.28)`(dark)。
37
-
38
- 圆角系统(Shape Consistency Lock):
39
- - 卡片/对话框 12px;按钮/输入/segmented 容器 8px;小 pill 6px。全站只用这三档。
40
-
41
- 间距:8pt 网格。面板 padding 16px;卡片内 12px;元素间 gap 8px(紧凑 4px)。
42
-
43
- 动效:`transition: all .18s cubic-bezier(0.25, 0.1, 0.25, 1)`;仅 transform/opacity;`:active` 时 `transform: scale(.97)`;MOTION 强度低(侧边栏工具,动效仅为反馈)。
44
-
45
- ## 2. 组件契约(类名 → Apple 形态)
46
-
47
- 类名全部保留,视觉重定义:
48
-
49
- - `.dbt-panel`:根容器。font 13px,padding 16px,gap 12px,flex column,overflow-y auto。
50
- - `.dbt-tabs`:**iOS segmented control**。容器 `background: var(--dbt-surface); border-radius: 8px; padding: 2px; gap: 2px; display: flex;` 内 button `flex: 1; border: none; background: transparent; border-radius: 6px; padding: 5px 8px; font-size: 12px;` active:`background: rgba(255,255,255,.14)`(light 模式 rgba(255,255,255,.9)+细阴影)+ `font-weight: 600`,不用蓝色填充。
51
- - `.dbt-card`:**inset grouped 卡片**。`background: var(--dbt-surface); border: none; border-radius: 12px; padding: 12px; gap: 10px;`
52
- - `.dbt-row`:flex row,gap 8px,wrap。
53
- - 输入(`.dbt-row input/select/textarea`、`.dbt-card` 同类):**填充式无边框**。`background: var(--dbt-surface-strong); border: none; border-radius: 8px; padding: 6px 10px; font-size: 13px;` focus:`outline: 2px solid var(--dbt-accent); outline-offset: -1px;`(或 box-shadow ring)。
54
- - `.dbt-btn`:普通= `background: var(--dbt-surface); border: none; border-radius: 8px; padding: 5px 12px; font-size: 13px; font-weight: 500;` hover 提亮(surface-strong);active scale(.97)。
55
- - `.dbt-btn.primary`:`background: var(--dbt-accent); color: #fff; border: none;` 无渐变无发光。
56
- - `.dbt-btn.danger`:`color: var(--dbt-danger); background: transparent; border: 1px solid var(--dbt-danger);`(或 `background: rgba(255,69,58,.12); border: none`,二选一全站统一)。
57
- - `.dbt-btn:disabled`:opacity .4。
58
- - `.dbt-muted`:`color: var(--dbt-text-secondary); font-size: 11px;`
59
- - `.dbt-err`:`color: var(--dbt-danger); font-size: 12px;`(白底黑字对比达标)。
60
- - `.dbt-msg`:`color: var(--dbt-success); font-size: 12px;`
61
- - `.dbt-table`:**去全边框,行 hairline 式**。`th, td: border: none; border-bottom: 1px solid var(--dbt-separator); padding: 6px 8px; font-size: 12px;` th `position: sticky; top: 0; backdrop-filter: blur(20px); background: <半透明宿主底色>; font-weight: 600; font-size: 11px; text-transform: uppercase 可选(不强制)`。td 数字/数据列用等宽字体。
62
- - `.dbt-tablewrap`:`border: none; border-radius: 12px; overflow: auto; max-height: 320px; background: var(--dbt-surface);`
63
- - `.dbt-overlay`:`background: rgba(0,0,0,.4); backdrop-filter: blur(8px);`
64
- - `.dbt-dialog`:**macOS alert 风格**。`background: rgba(40,40,44,.85)(light: rgba(252,252,252,.9)); backdrop-filter: blur(20px) saturate(180%); border: 1px solid var(--dbt-separator); border-radius: 14px; padding: 16px; box-shadow: 0 8px 32px rgba(0,0,0,.28);` 标题 13px semibold 居中可选;按钮区 `.dbt-row` 改为右对齐。
65
- - `.dbt-grant`:列表行式。`padding: 8px 0; border-bottom: 1px solid var(--dbt-separator);`(去 dashed,实 hairline)。
66
- - `.dbt-seg`:与 `.dbt-tabs` 同构的 mini segmented(ro/rw/未授权切换)。
67
-
68
- ## 3. 各面板布局指引(结构重排方向)
69
-
70
- - **ManageView**:连接列表改为列表行卡(每连接一张 inset card:kind 徽标(小 pill 6px、surface 底)、名称 13px semibold、safeUrl 等宽 11px muted、右侧「编辑/删除」为图标化次要按钮);「新建连接」为 accent 主按钮置顶右侧;表单字段分组;审计表保持 resultTable。
71
- - **GrantsView**:每连接一行(列表行式),ro/rw/未授权用 `.dbt-seg` mini segmented;说明文字 muted。
72
- - **BrowseView**:库/表选择器用填充式 select;结构/预览切换可用 mini segmented;表格遵循新 table 契约。
73
- - **ConsoleView**:SQL 输入区用等宽字体 + 填充式输入(min-height 加大、focus ring);执行按钮 accent 主按钮;结果表新契约;challenge 流程与 DangerDialog 样式统一。
74
- - DangerDialog:标题不再用 emoji ⚠️,改为纯文字 + danger 色 accent(左侧 3px 色条或标题色)。
75
-
76
- ## 4. 验收
77
- - `node --check client/client.js` 通过;
78
- - 全站只有一个 accent(系统蓝)、一套圆角、一套材质;
79
- - dark/light 均可读(WCAG AA);
80
- - 无 emoji 图标、无渐变、无发光、无多余装饰 pill。
@@ -1,154 +0,0 @@
1
- # dsh-db-tool 项目架构图
2
-
3
- > 由 cbm(codebase-memory)索引数据绘制:843 节点 / 2702 边,模块分层见各图。
4
- > 索引项目名:`E-Code-dsh-dsh-db-tool`。
5
-
6
- ## 1. 总体分层架构
7
-
8
- ```mermaid
9
- flowchart TB
10
- subgraph UI["客户端层(DSH 侧边栏)"]
11
- CLIENT["client/client.js<br/>连接管理 · 对象树浏览 · SQL 控制台 · 授权面板"]
12
- end
13
-
14
- subgraph API["接入层"]
15
- HTTP["lib/http<br/>HTTP API(13 条路由)"]
16
- TOOL["lib/index.ts<br/>DatabaseManager 工具定义<br/>list_connections / query / execute /<br/>schema / preview / run_script"]
17
- end
18
-
19
- subgraph SVC["服务编排层"]
20
- MGR["lib/manager.ts<br/>ro/rw 项目授权校验 · 适配器生命周期 · 事务编排"]
21
- end
22
-
23
- subgraph SEC["安全层"]
24
- GUARD["lib/guard<br/>SQL/命令分类 · 危险操作识别 ·<br/>一次性 challenge 确认(5 分钟有效)"]
25
- STORE["lib/store<br/>connections · grants · secrets(脱敏)·<br/>audit 审计 · normalize · io"]
26
- SCRIPT["lib/script<br/>runner.ts + worker.cjs<br/>子进程沙箱(vm realm · 禁文件 · 60s 超时)"]
27
- end
28
-
29
- subgraph ADPT["适配器层 lib/adapters(8 库)"]
30
- REG["index.ts<br/>kind → 工厂注册表 + driverMissingError"]
31
- SQLSHARED["sql-shared/<br/>common.ts(标识符/分页/规范化)<br/>pg-like.ts(PostgreSQL + GaussDB 共享)"]
32
- A1["mysql"]
33
- A2["postgresql"]
34
- A3["gaussdb<br/>vendor/gaussdb-pg 驱动加载"]
35
- A4["sqlite"]
36
- A5["redis"]
37
- A6["mongodb"]
38
- A7["oracle"]
39
- A8["dmdb"]
40
- TYPES["types.ts<br/>DatabaseAdapter 契约"]
41
- end
42
-
43
- subgraph DRV["驱动层"]
44
- D1["pg / mysql2 / sqlite3 / redis<br/>mongodb / oracledb / dmdb"]
45
- D2["vendor/gaussdb-pg<br/>openGauss-connector-nodejs 构建产物"]
46
- end
47
-
48
- CLIENT -->|HTTP| HTTP
49
- CLIENT -.->|注入| TOOL
50
- TOOL --> MGR
51
- MGR --> GUARD
52
- MGR --> STORE
53
- MGR --> SCRIPT
54
- MGR --> REG
55
- REG --> SQLSHARED
56
- REG --> A1 & A4 & A5 & A6 & A7 & A8
57
- A2 --> SQLSHARED
58
- A3 --> SQLSHARED
59
- SQLSHARED --> TYPES
60
- A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 -.-> DRV
61
- SCRIPT -.->|db.query / db.execute 经完整 guard 链路| MGR
62
- ```
63
-
64
- ## 2. 请求时序(query 与危险操作确认流)
65
-
66
- ```mermaid
67
- sequenceDiagram
68
- autonumber
69
- participant U as 用户(聊天)
70
- participant T as DatabaseManager 工具
71
- participant M as lib/manager.ts
72
- participant G as lib/guard
73
- participant S as lib/store
74
- participant A as 适配器(8 库)
75
- participant DB as 数据库
76
-
77
- U->>T: query/execute(conn_id, sql)
78
- T->>S: 授权校验(项目路径 → 连接 → ro/rw)
79
- alt 未授权
80
- S-->>T: UNAUTHORIZED_PROJECT
81
- else ro 授权 + 写操作
82
- S-->>T: READ_ONLY(拒绝)
83
- else 通过
84
- T->>G: 语句分类
85
- alt 危险操作(DDL/DML/维护命令)
86
- G-->>T: NEEDS_CONFIRMATION + challengeId(一次性,5 分钟)
87
- T-->>U: 说明语句与风险,等待明确同意
88
- U->>T: 携同一 challengeId 重试
89
- T->>G: 校验 challenge(绑定语句 hash)
90
- end
91
- T->>M: 执行
92
- M->>A: query/execute(可选 database 跨库路由,pg/gaussdb)
93
- A->>DB: 参数化 SQL(ro 会话级 READ ONLY 双保险)
94
- DB-->>A: 结果
95
- A-->>T: 规范化结果(DECIMAL→string 等)
96
- T->>S: 审计记录
97
- T-->>U: {columns, rows, rowCount} / {affectedRows, message}
98
- end
99
- ```
100
-
101
- ## 3. 适配器体系(8 库 × 共享实现)
102
-
103
- ```mermaid
104
- flowchart LR
105
- subgraph 契约
106
- T["types.ts<br/>DatabaseAdapter / TableInfo / ColumnInfo<br/>DbKind = 8 种"]
107
- end
108
- subgraph 工厂注册
109
- R["adapters/index.ts<br/>kind → lazy import 工厂<br/>缺失驱动 → driverMissingError(附构建提示)"]
110
- end
111
- subgraph SQL系共享
112
- PG["pg-like.ts<br/>PostgreSQL + GaussDB<br/>pool · ro 会话 · 跨库路由 ·<br/>库→schema→表 三层浏览"]
113
- CM["common.ts<br/>assertIdent · quoteIdent<br/>clampLimit/Offset · normalizeCell"]
114
- end
115
- subgraph 独立实现
116
- MY["mysql"]
117
- SQ["sqlite"]
118
- RD["redis(SCAN 禁 KEYS)"]
119
- MG["mongodb(强制显式 filter)"]
120
- OR["oracle"]
121
- DM["dmdb"]
122
- end
123
- PG --> CM
124
- MY & SQ & RD & MG & OR & DM -.-> CM
125
- R --> PG & MY & SQ & RD & MG & OR & DM
126
- PG -.->|"gaussdb 差异仅驱动加载<br/>createRequire vendor/gaussdb-pg"| G["gaussdb/index.ts"]
127
- T --- R
128
- ```
129
-
130
- ## 4. 模块分层职责(cbm layers 数据)
131
-
132
- | 层 | 模块 | 特征 |
133
- |---|---|---|
134
- | entry | lib、script、e2e-mock | 仅出边(调用下游) |
135
- | api | http | 含 13 条 HTTP 路由定义 |
136
- | core | adapters(4 入 0 出)、store(12 入 0 出) | 高扇入核心,不依赖上层 |
137
- | internal | manager(7 入 12 出)、tool、http | 编排枢纽 |
138
- | leaf | guard | 仅入边,纯分类/判定 |
139
-
140
- ## 5. GaussDB 专项链路
141
-
142
- ```mermaid
143
- flowchart TB
144
- T["DatabaseManager(query/execute/schema/preview, database=...)"] --> M["manager"]
145
- M --> A3["gaussdb/index.ts<br/>loadGaussDriver():createRequire<br/>vendor/gaussdb-pg/packages/pg(CJS)"]
146
- A3 --> PL["sql-shared/pg-like.ts<br/>kind='gaussdb'"]
147
- PL -->|poolConfig:host/port 8000/user/password/database/ssl| P["PgLikePool"]
148
- PL -->|database 参数| PF["poolFor(db):按库缓存池(Navicat 式跨库)"]
149
- PL -->|ro 模式| SRO["每个新连接 SET SESSION CHARACTERISTICS<br/>AS TRANSACTION READ ONLY(fail-closed)"]
150
- P --> DB[("GaussDB 服务端<br/>openGauss 协议")]
151
- ```
152
-
153
- - 驱动构建:`scripts/build-gaussdb.sh` / `.ps1` → 克隆 openGauss-connector-nodejs → `vendor/gaussdb-pg/packages/pg`(gitignore)。
154
- - 测试:`tests/adapters-sql/gaussdb.test.ts`(驱动加载/工厂,mock 离线)+ `pg-like.test.ts`(pg/gaussdb 共享行为)。
@@ -1,66 +0,0 @@
1
- DSH 插件 dsh-db-tool 加载错误记录
2
- =====================================
3
- 记录时间:2026-09-28
4
- 当前状态:已从 desktop profile 卸载;卸载后该错误归零,其余 12 个第三方插件全部正常。
5
-
6
- 一、错误原文
7
- -------------------------------------
8
- dsh: error: [/197] createRequire.resolve.paths is not a function or its return value is not iterable
9
-
10
- 对应条目:/197 id=db-tool name=dsh-db-tool status=error
11
-
12
- 出现场景:DSH 0.1.7-rc.2 桌面版,desktop profile 的插件组合检查
13
- (等价 `dsh --profile desktop --dump-config-schema` 的官方加载路径)。
14
- 同一检查中,其余 12 个第三方插件均无错误。
15
-
16
- 二、根因(DSH 0.1.7-rc.2 自带代码的 bug)
17
- -------------------------------------
18
- 1) DSH 自带 @deepseek-ai/dsh-app-boot 的 lib/index.js 里有 6 处
19
- `createRequire(parent).resolve.paths(name)` 调用,其中 5 处未做空值防护。
20
- 2) Node 对「内置模块同名包」调用该 API 会返回 null
21
- (本机实测:resolve.paths('punycode') 返回 null;普通包返回数组)。
22
- 对 null 做 for..of 即抛 TypeError —— 这就是上面的错误消息。
23
- 3) dsh-db-tool 的依赖链包含 npm 包 punycode:
24
- dsh-db-tool → mongodb → mongodb-connection-string-url → whatwg-url → tr46 → punycode
25
- 因此该插件的加载路径必然触发这个 bug。
26
-
27
- 三、本机复现证据
28
- -------------------------------------
29
- 运行环境:Electron Node(DeepSeek Harness.exe 加 --expose-internals),可直接访问 asar 内模块。
30
-
31
- 复现结果(最小用例):
32
- createRequire('.../node_modules/dsh-db-tool/dist/index.js').resolve.paths('punycode') => null
33
- createRequire('.../node_modules/tr46/index.js').resolve.paths('punycode') => null
34
- createRequire('.../node_modules/dsh-db-tool/dist/index.js').resolve.paths('ssh2') => array[11]
35
-
36
- DSH 官方检查的诊断输出:
37
- 卸载前:F:\DSH\_recon\dump-schema-err.txt (含 /197 db-tool 错误)
38
- 卸载后:F:\DSH\_recon\dump-schema-err-2.txt (该错误消失,只剩 DSH 内置 agent-preset 的 4 条既有诊断)
39
-
40
- 四、插件作者已知该问题(包内自带 hotfix)
41
- -------------------------------------
42
- dsh-db-tool 包内提供:
43
- scripts/hotfix-core.mjs
44
- patches/dsh-app-boot-route-scoped-hotfix.patch
45
- 目标:@deepseek-ai/dsh-app-boot 0.1.7-rc.2 中未防护的那行 for..of。
46
- 修法:resolve.paths 返回 null 时回退到标准 node_modules 搜索链。
47
-
48
- 限制(本机为何没能直接用):
49
- 该脚本按「文件系统安装的 DSH」定位目标(找 DSH_HOME、PATH 上的 dsh、全局 npm 目录),
50
- 而桌面版把 dsh-app-boot 打包在 F:\DSH\resources\app.asar 内,脚本找不到文件,无法应用。
51
-
52
- 五、可选修复路径(供向 DSH/插件作者反馈)
53
- -------------------------------------
54
- 1) 等 DSH 上游修复(推荐):该 bug 属于 0.1.7-rc.2 自带代码,任意「依赖树含 core-module 同名包」的插件都会触发。
55
- 2) 重打包 app.asar 应用该 hotfix:需先关闭 DSH 应用,修改应用安装文件,版本更新时会被覆盖,有风险。
56
- 3) 插件侧规避:依赖树中避免引入 core-module 同名包(例如替换 punycode 的实现)。
57
-
58
- 六、本次卸载记录
59
- -------------------------------------
60
- 卸载方式:DSH plugin-manager operations(pnpm remove + 从 dsh.profile.bundles 移除,等价插件页卸载)。
61
- 结果核对:依赖 13 → 12;bundles 17 → 16;传递依赖 mongodb / punycode 等已一并清理。
62
- 其余 12 个插件的运行时依赖健康检查全部通过(ssh2 纯 JS 可用、better-sqlite3/oracledb 可用、rtk 0.50.0 可用)。
63
-
64
- 相关产物:
65
- 报告目录:F:\DSH\_recon\(install-results.json、各 recon 报告、dump 诊断、验证脚本)
66
- 安装前备份:F:\DSH\_backup\profile-20260928-162128\
@@ -1,6 +0,0 @@
1
- url: https://github.com/mengqi1436/dsh-db-tool
2
- name: mengqi1436/dsh-db-tool
3
- category: tools
4
- description:
5
- en: Chat-operated database admin for 8 databases (MySQL, PostgreSQL, GaussDB, SQLite, Oracle, DM, Redis, MongoDB): a DatabaseManager tool with read-only/read-write per-connection modes, per-project grants, one-time challenge confirmation for dangerous operations, sandboxed script execution, plus a sidebar with connection management, project authorization, a Navicat-style object browser and an SQL console.
6
- zh: 聊天操作数据库的管理插件,支持 8 种数据库(MySQL、PostgreSQL、GaussDB、SQLite、Oracle、达梦、Redis、MongoDB):DatabaseManager 工具带连接级只读/读写分级、项目级授权、危险操作一次性 challenge 对话内确认与沙箱脚本执行;侧边栏提供连接管理、项目授权、Navicat 式对象树浏览和 SQL 控制台。