dsh-dbhub-live 2.0.0 → 3.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/AGENTS.md ADDED
@@ -0,0 +1,86 @@
1
+ # AGENTS.md — dsh-dbhub-live 开发与调试说明
2
+
3
+ > 本文件面向在本仓库上继续开发/调试本插件的 AI 与人。业务需求见 [doc/REQUIREMENTS.md](doc/REQUIREMENTS.md),用户安装使用见 [README.md](README.md)。
4
+
5
+ ## 一句话定位
6
+
7
+ DSH host 插件(Node/E SM)+ Web client 插件(浏览器半):把 dbhub(Bytebase 的数据库 MCP 服务器)接入 DSH,提供按工作区的常驻连接工具、临时连接工具,外加设置在「设置 → 插件」里的实时状态卡片与启用/禁用开关。
8
+
9
+ ## 目录结构
10
+
11
+ ```
12
+ lib/
13
+ index.mjs 入口:name/inject/apply、状态命名空间(schemastery+dsh-settings)接线、懒加载编排
14
+ config.mjs 路径/持久化(store,runtime)/DSN 解析/工作区发现/小工具(纯函数)
15
+ state.mjs 运行时状态机:enabled/phase/toolCount/lastError/mode + 订阅发布
16
+ runtime.mjs dbhub 可执行文件发现、按需自动安装、定期自动更新、孤儿进程清理
17
+ mcp.mjs MCP JSON-RPC 客户端 + 常驻多源 dbhub 服务生命周期 + 按工作区工具同步
18
+ adhoc.mjs 临时连接(每次调用一条一次性 dbhub 进程)
19
+ collect.mjs 授权扫描项目配置文件并提取 DSN 候选(含 askUser 桥接)
20
+ tools.mjs host 自有工具定义与注册(dbhub_configure/dbhub_query/dbhub_query_objects)
21
+ client.js Web 半(手写 lazy-CJS bundle,无构建步骤)
22
+ test/ node:test 单元测试(纯逻辑 + client bundle 格式契约)
23
+ doc/ 需求文档
24
+ cordis.patch.yml bundle patch:`name: dsh-dbhub-live` 挂载本包
25
+ ```
26
+
27
+ ## 关键架构事实
28
+
29
+ - **模块依赖只进不出**:`config ← state ← runtime ← mcp ← tools ← index`,`adhoc ← mcp`,`collect ← tools`;禁止反向 or 循环 import(HMR/装载顺序依赖它)。
30
+ - **状态单一来源**:`state.mjs` 是唯一事实源;`index.mjs` 订阅它来启动/停止 dbhub 进程、并向 settings 命名空间发布快照;卡片只能通过命名空间的 `enabled` 字段写回。
31
+ - **状态命名空间**:Host 注册 `dsh-dbhub-live` 命名空间(通过 `ctx.inject(['settings'], …)` + schema);Web 端 Plugins 选项卡按“Host 服务的命名空间”分发 `settings.plugin.item` 卡片(key = 命名空间)。命名空间值 = `{enabled, phase, toolCount, lastError, mode}`。
32
+ - **schema 弹性依赖**:优先用真实 `@deepseek-ai/schemastery` schema(`await import`);解析失败时降级为 `lib/index.mjs` 内建的最小 callable schema(`schema(v)` 合默认值 + `toJSON()`),保证**链路安装(`dsh plugin add <本地目录>`,Node ESM 按源码真实路径解析裸导入)下插件照样启动、卡片照常工作**。tarball/npm 安装(真实目录在 profile node_modules 下)走真实 schemastery 路径。不要把这个 import 改回静态顶层 import——会重新引入链路安装时启动失败。
33
+ - **懒加载**:`apply()` 只注册核心工具 + 后台异步初始化(`startLazyInit`);任何工具调用先 `ensureRunning`(共享 `server.starting`,并发调用自动排队等待);启动失败进入 `phase:'error'` 并记录 `lastError`,下次调用自动重试。**无工作区数据源时恒不拉起 dbhub 进程**(空 `[[sources]]` toml 对 dbhub 是致命的;空指纹若被当成“已同步”会在二次调用时绕过 toml 直接 spawn——`ensureRunning` 的 `sources.length === 0` 早退必须在指纹判断之外)。
34
+ - **启用/禁用**:`state.setEnabled` 持久化到 `credentials.json`(权威值);禁用时立即 `terminateServer()` 释放进程,所有工具 execute 首行返回「插件已禁用」;重新启用触发懒加载初始化。
35
+ - **密码脱敏**:`maskDsn` 是唯一出口——工具描述、结果前缀、扫描候选一律走它。
36
+
37
+ ## 存储与容错(初始化即处理)
38
+
39
+ - **实例隔离**:所有持久化都在 `$DSH_HOME/storages/dsh-dbhub-live/`(`credentials.json` 凭据+enabled、`runtime.json`、`dbhub.toml`、`dbhub-runtime/` 自动安装前缀)。隔离粒度 = `DSH_HOME`(同一 home 的多个 profile 共享,与 dsh 自身 workspace.json 约定一致);dbhub 进程、状态机、工具注册天然按进程隔离。**进程环境变量不参与连接解析**。
40
+ - **升级/手改遗留兼容**:`loadStore`/`loadRuntime` 先用纯函数 `normalizeStore`/`normalizeRuntime` 清洗:丢弃非布尔 `enabled`、非对象/空 dsn 条目、非法 `dbhubExe`/`dbhubInstallAt`;`dsn` 统一 trim;**未知字段保留**(向前兼容,不因旧版加载剥离新版写入)。清洗结果与原文不同时**一次性回写迁移**,之后每次启动都是规范化文件。
41
+ - **空值安全**:解析器对缺失/空值全部有兜底(`resolveWorkspaceDsn` 判空、`maskDsn` 对不可解析 DSN 正则兜底、状态 schema 默认值、settings 镜像的 `enabled` 只认布尔),清洗后不存在半吊子条目。
42
+ - **运行目录被删 / 写入被拦截**:每次 JSON/toml 写入前自动 `mkdirSync` 重建目录;写入失败**不抛致命**,`warnOnce` 一次性告警并继续内存态运行(凭据持久化失效但工具可用);`dbhub.toml` 写入失败按**初始化错误**记录(状态卡片 🔴 + `lastError`)并下次调用自动重试;npm 自动安装前同样重建目录。注意:以上全是 best-effort,被拦截时重启会丢「仅内存态」的修改,属预期。
43
+
44
+ ## 调试方法(不影响正在运行的 Harness)
45
+
46
+ DSH 启动是 fail-loud:任一插件激活失败整树拒绝启动、GUI 打不开。因此**永远不要在配置/源码上直接动主实例**,按下面阶梯来:
47
+
48
+ 1. **静态校验(30 秒,零风险)** — `npm run check`(node --check 全部 lib)→ `npm test`(node:test 单测)。单测会自己建临时 `DSH_HOME`,不会碰真实 store。
49
+ 2. **会话内跑通逻辑(不重启)** — 用动态插件工具连(`cordis_define`/`cordis_run`/`cordis_stop`/`cordis_undefine`):把要验证的纯逻辑(如 configure 流程、状态机)以无 import 的 Host 代码贴进动态包,在会话里跑,`cordis_stop` 即清场。动态包只活在进程内存 + 当前会话,改动/出错都不影响主进程。
50
+ - 注意:动态 Host 代码不能用 `import`,所以带 `@deepseek-ai/schemastery` / `dsh-settings` import 的 `lib/index.mjs` 不能整文件贴进动态包;只对纯逻辑做动态验证。
51
+ 3. **冷启动验证(隔离实例)** — 用独立 `DSH_HOME` 起测试实例:
52
+ ```powershell
53
+ $env:DSH_HOME = "D:\path\.dsh-test" # 放工作区内即可免越权
54
+ dsh web --port 3081 --no-open # 首次自动初始化 web 模板
55
+ dsh plugin --profile web add D:/path/to/dsh-dbhub-live
56
+ dsh web --port 3081 --no-open
57
+ # 验证:日志出现 [dsh-dbhub-live] 初始化/服务已加载;GET /plugins/dsh-dbhub-live/client.js 返回 bundle
58
+ ```
59
+ 4. **在位热更新(有失败保护,谨慎)** — 主实例的 `cordis.patch.yml` 支持 HMR,读取/解析失败时保留最后一个可用树,GUI 不会挂。但 HMR 不监听插件源码,只适合挂载/卸载验证,代码迭代请用 1/2/3。
60
+ 5. **安全网** — `$DSH_SNAPSHOT=replay` 可从 `cordis.snapshot.yml` 启动回放点;改动主 profile 前先备份 `cordis.patch.yml`。
61
+
62
+ ## 修改 client 半(lib/client.js)
63
+
64
+ `lib/client.js` 是**手写 lazy-CJS bundle**,DSH client 模块系统按 `dsh.client` 声明 + `exports["./client"]` 直接服务它,**没有构建步骤**。遵守以下契约(改完跑 `node test/client-format.test.mjs` 守护):
65
+
66
+ - 必须以 `window.__ModuleLoader__.load({ id: "dsh-dbhub-live", factory: (require) => { … } })` 注册;
67
+ - `id` 必须等于 Loader entry 名(`dsh-dbhub-live`,见 cordis.patch.yml 的 `name`),不是行 id;
68
+ - factory 只允许 `require("react")` 等 baseline 模块;不 import 其他插件的值(bundle-purity);
69
+ - 导出 `name/inject/apply`,结尾 `return module.exports`;
70
+ - 组件不得接触 `ctx`,数据/回调一律通过注册时的 `inject: () => face` 传入 props;用内联样式,不依赖 CSS 文件。
71
+ - 若本包脱离仓库(发布 npm),`dsh.client` 与 `exports["./client"]` 必须保留,否则 client-modules 扫描会启动报错。
72
+
73
+ ## 质量门
74
+
75
+ ```bash
76
+ npm run check # 全部 lib 语法
77
+ npm test # 单元测试(node:test;沙箱内请逐个文件跑:node test/x.test.mjs)
78
+ ```
79
+
80
+ 发布前:按「调试方法」第 3 步在隔离实例完整冷启动一遍,确认 Host 无报错、`/plugins/dsh-dbhub-live/client.js` 可访问。
81
+
82
+ ## 约定
83
+
84
+ - 产品文案中文、代码注释英文;密码脱敏不可绕过;扫描必须经 `askUser` 授权。
85
+ - `state.*` 之外不要直接改 `store`/`runtime` 之外的持久化。
86
+ - 增加行为时同步更新本文件、README(用户侧)与 doc/REQUIREMENTS.md(业务侧)。
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 mr-mihu
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mr-mihu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,110 +1,134 @@
1
- # dsh-dbhub-live
2
-
3
- > 让 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/DeepSeek-Harness) 直接、安全地操作数据库:常驻多源连接 + 按工作区工具 + 临时动态连接。
4
-
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![DSH](https://img.shields.io/badge/DSH-plugin-blue.svg)](#安装)
7
- [![DBHub](https://img.shields.io/badge/Built_on-DBHub-22a05a)](https://github.com/bytebase/dbhub)
8
-
9
- `dsh-dbhub-live` 是一个 DSH 插件,基于 [DBHub](https://dbhub.ai)(数据库 MCP 服务器)让模型直接查询数据库:既能在已配置的工作区上复用常驻连接,也能临时连任意库做一次性排查。
10
-
11
- ## ✨ 特性
12
-
13
- - **常驻多源服务** — 后台一个 dbhub 服务同时接入多个数据源,连接复用、查询更快。
14
- - **按工作区工具** — `dbhub_execute_sql_<工作区>` / `dbhub_search_objects_<工作区>`,工具名即工作区,多工作区不混淆,连接标注(密码打码)清晰可见。
15
- - **临时动态连接** — `dbhub_query` / `dbhub_query_objects` 每次独立连任意库,可并行查多个不同库,便于跨环境排查。
16
- - **开箱即用**未安装 `dbhub` 时首次使用自动安装,之后自动保持更新,无需手动处理。
17
- - **多种配置方式** 显式 DSN / 填写分项 / 授权扫描项目配置文件,凭据仅存本机用户目录,密码全程脱敏。
18
-
19
- ## 支持的数据源
20
-
21
- MySQL · PostgreSQL · MariaDB · SQLite · SQL Server
22
-
23
- ## 环境要求
24
-
25
- - DeepSeek Harness 的 `dsh` CLI(`dsh web` 负责 GUI 运行)
26
- - 推荐本机有 Node.js ≥ 18(含 `npm`)——首次使用会自动安装 `dbhub`
27
-
28
- ## 安装
29
-
30
- ```bash
31
- # 方式一:使用本机已安装的 dsh
32
- dsh plugin --profile web add github:mr-mihu/dsh-dbhub-live
33
-
34
- # 方式二:通过 npx 调用 dsh(无需本机全局安装 dsh)
35
- npx @deepseek-ai/dsh plugin --profile web add github:mr-mihu/dsh-dbhub-live
36
- ```
37
-
38
- 安装后**重启 `dsh web`** 生效。
39
-
40
- ## 快速开始
41
-
42
- ```text
43
- # 1) 为当前工作区配置数据库连接(三种方式任选其一)
44
- dbhub_configure
45
-
46
- # 2) 在已配置工作区的常驻连接上执行查询
47
- dbhub_execute_sql_myapp SELECT * FROM users LIMIT 10;
48
-
49
- # 3) 临时连任意库做一次性排查
50
- dbhub_query dsn=mysql://root:pass@192.168.77.6:3306/tx_sd_jinengshu sql="SHOW TABLES;"
51
- ```
52
-
53
- ## 工具
54
-
55
- | 工具 | 说明 |
56
- | --- | --- |
57
- | `dbhub_configure(workspace?, dsn?)` | 为工作区配置/持久化数据库连接。 |
58
- | `dbhub_execute_sql_<工作区>` | 在指定工作区的常驻连接上执行 SQL。 |
59
- | `dbhub_search_objects_<工作区>` | 在指定工作区搜索数据库对象(表/视图/列/索引等)。 |
60
- | `dbhub_query(dsn, sql)` | 临时连接任意库执行 SQL(多语句用 `;` 分隔)。 |
61
- | `dbhub_query_objects(dsn, ...)` | 临时连接任意库搜索数据库对象。 |
62
-
63
- > 注:`search_objects` 仅对 SQLite 开放;MySQL / PostgreSQL 等请用 `dbhub_query` 直接查(如 `SHOW TABLES`)。
64
-
65
- ### 配置方式
66
-
67
- 1. **显式 DSN** — 传入完整连接串,如 `mysql://user:pass@host:3306/db`。
68
- 2. **填写分项** — 按类型 / 主机 / 端口 / 账号 / 密码 / 库名依次填写。
69
- 3. **授权扫描** — 授权后扫描项目配置文件(`.env`、`application*.yml`、`docker-compose`、`jdbc.properties` 等),列出候选(密码打码)供你确认。
70
-
71
- 工作区若已有 `mise env` `.env`(`DSN` / `DB_*`),插件会自动发现,无需手动配置。
72
-
73
- ## 🔄 dbhub 自动安装与更新
74
-
75
- - **首次使用自动安装**:本机没有 `dbhub` 时,插件会在第一次查询时自动安装,之后离线也可用。
76
- - **自动保持更新**:每 7 天在后台静默更新到最新版,失败则沿用现有版本。
77
- - **不碰你的配置**:通过 PATH / mise 自行安装的 `dbhub` 不会被插件改动。
78
-
79
- | 环境变量 | 说明 | 默认 |
80
- | --- | --- | --- |
81
- | `DSH_DBHUB_PACKAGE` | 自动安装使用的 npm 包名 | `@bytebase/dbhub` |
82
- | `DSH_DBHUB_UPDATE_DAYS` | 自动更新间隔天数,`0` 关闭 | `7` |
83
-
84
- ## 数据位置
85
-
86
- 所有配置与凭据存放在模块目录之外(不受 pnpm 打包影响),删除该目录即可完整清空:
87
-
88
- ```
89
- ~/.dsh/storages/dsh-dbhub-live/
90
- ```
91
-
92
- ## 卸载
93
-
94
- ```bash
95
- dsh plugin --profile web remove dsh-dbhub-live
96
- ```
97
-
98
- ## 故障排查
99
-
100
- | 现象 | 处理 |
101
- | --- | --- |
102
- | 首次使用报「无法获取 dbhub」 | 确认本机有 npm 且能联网;离线可手动安装 `dbhub` 并加入 PATH。 |
103
- | 工具显示「dbhub 服务不可用」 | 查看 `dsh web` 日志;进程异常退出时插件会在下次调用自动重启。 |
104
- | 扫描不到配置文件 | 默认跳过 `node_modules` / `.git` / `target` / `dist` 等目录,可改用「输入 DSN」或「填写分项」。 |
105
- | 需要自定义 dbhub 版本 | 删除 `~/.dsh/storages/dsh-dbhub-live` 后设置 `DSH_DBHUB_PACKAGE` 指定包/版本。 |
106
- | 不希望自动更新 dbhub | 设置环境变量 `DSH_DBHUB_UPDATE_DAYS=0`。 |
107
-
108
- ## 许可证
109
-
110
- [MIT](./LICENSE)
1
+ # dsh-dbhub-live
2
+
3
+ > 让 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/DeepSeek-Harness) 直接、安全地操作数据库:常驻多源连接 + 按工作区工具 + 临时动态连接 + 懒加载与浏览器状态卡片。
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![DSH](https://img.shields.io/badge/DSH-plugin-blue.svg)](#安装)
7
+ [![DBHub](https://img.shields.io/badge/Built_on-DBHub-22a05a)](https://github.com/bytebase/dbhub)
8
+
9
+ `dsh-dbhub-live` 是一个 DSH 插件,基于 [DBHub](https://dbhub.ai)(数据库 MCP 服务器)让模型直接查询数据库:既能在已配置的工作区上复用常驻连接,也能临时连任意库做一次性排查。
10
+
11
+ ## ✨ 特性
12
+
13
+ - **常驻多源服务** — 后台一个 dbhub 服务同时接入多个数据源,连接复用、查询更快。
14
+ - **按工作区工具** — `dbhub_execute_sql_<工作区>` / `dbhub_search_objects_<工作区>`,工具名即工作区,多工作区不混淆,连接标注(密码打码)清晰可见。
15
+ - **临时动态连接** — `dbhub_query` / `dbhub_query_objects` 每次独立连任意库,可并行查多个不同库,便于跨环境排查。
16
+ - **懒加载启动**插件启动不阻塞 GUI,工具立即可用;环境初始化推迟到首次调用(初始化期间查询自动等待就绪)。
17
+ - **启用 / 禁用开关** 关闭后所有 dbhub 工具立即返回「插件已禁用」友好提示,无需重启;再次开启立即可用。
18
+ - **浏览器状态卡片** — 设置 → 插件 → dsh-dbhub-live 面板实时展示:运行状态徽章(🟢 运行中 / 🟡 初始化中 / 🔴 异常)、已注册工具数、工作模式、最近错误(红色),并提供启用/禁用开关。
19
+ - **开箱即用** — 未安装 `dbhub` 时首次使用自动安装,之后自动保持更新,无需手动处理。
20
+ - **多种配置方式** — 显式 DSN / 填写分项 / 授权扫描项目配置文件,凭据仅存本机用户目录,密码全程脱敏。
21
+
22
+ ## 支持的数据源
23
+
24
+ MySQL · PostgreSQL · MariaDB · SQLite · SQL Server
25
+
26
+ ## 环境要求
27
+
28
+ - DeepSeek Harness 的 `dsh` CLI(`dsh web` 负责 GUI 运行)
29
+ - 推荐本机有 Node.js ≥ 18(含 `npm`)——首次使用会自动安装 `dbhub`
30
+
31
+ ## 安装
32
+
33
+ ```bash
34
+ # 方式一:使用本机已安装的 dsh
35
+ dsh plugin --profile web add dsh-dbhub-live
36
+
37
+ # 方式二:通过 npx 调用 dsh(无需本机全局安装 dsh)
38
+ npx @deepseek-ai/dsh plugin --profile web add dsh-dbhub-live
39
+ ```
40
+
41
+ 安装后**重启 `dsh web`** 生效(重启后到 设置 → 插件 → dsh-dbhub-live 可看到状态卡片)。
42
+
43
+ ## 快速开始
44
+
45
+ ```text
46
+ # 1) 为当前工作区配置数据库连接(三种方式任选其一)
47
+ dbhub_configure
48
+
49
+ # 2) 在已配置工作区的常驻连接上执行查询
50
+ dbhub_execute_sql_myapp SELECT * FROM users LIMIT 10;
51
+
52
+ # 3) 临时连任意库做一次性排查
53
+ dbhub_query dsn=mysql://root:pass@192.168.77.6:3306/tx_sd_jinengshu sql="SHOW TABLES;"
54
+ ```
55
+
56
+ ## 工具
57
+
58
+ | 工具 | 说明 |
59
+ | --- | --- |
60
+ | `dbhub_configure(workspace?, dsn?)` | 为工作区配置/持久化数据库连接。 |
61
+ | `dbhub_execute_sql_<工作区>` | 在指定工作区的常驻连接上执行 SQL。 |
62
+ | `dbhub_search_objects_<工作区>` | 在指定工作区搜索数据库对象(表/视图/列/索引等)。 |
63
+ | `dbhub_query(dsn, sql)` | 临时连接任意库执行 SQL(多语句用 `;` 分隔)。 |
64
+ | `dbhub_query_objects(dsn, ...)` | 临时连接任意库搜索数据库对象。 |
65
+
66
+ > 注:`search_objects` 仅对 SQLite 开放;MySQL / PostgreSQL 等请用 `dbhub_query` 直接查(如 `SHOW TABLES`)。
67
+
68
+ ### 配置方式
69
+
70
+ 1. **显式 DSN** — 传入完整连接串,如 `mysql://user:pass@host:3306/db`。
71
+ 2. **填写分项** 按类型 / 主机 / 端口 / 账号 / 密码 / 库名依次填写。
72
+ 3. **授权扫描** — 授权后扫描项目配置文件(`.env`、`application*.yml`、`docker-compose`、`jdbc.properties` 等),列出候选(密码打码)供你确认。
73
+
74
+ 工作区若已有 `mise env` 或 `.env`(`DSN` / `DB_*`),插件会自动发现,无需手动配置。
75
+
76
+ ## 状态卡片
77
+
78
+ 设置 → 插件 → dsh-dbhub-live(依赖 Web 端设置面板,Host 半侧的 `dsh-dbhub-live` 设置命名空间会实时镜像插件状态):
79
+
80
+ - 🟢 运行中 / 🟡 初始化中 / 🔴 异常(异常时展示最近错误,红色)。
81
+ - 已注册工具数(随工作区配置 / 服务同步实时变化)。
82
+ - 工作模式:懒加载(首次调用时初始化)。
83
+ - **启用 / 禁用开关**:关闭后所有 dbhub 工具立即返回「插件已禁用」,不消耗任何进程资源;重新开启后按需自动初始化。开关状态持久化,重启后保留。
84
+
85
+ ## 🔄 dbhub 自动安装与更新
86
+
87
+ - **首次使用自动安装**:本机没有 `dbhub` 时,插件会在第一次查询时自动安装,之后离线也可用。
88
+ - **自动保持更新**:每 7 天在后台静默更新到最新版,失败则沿用现有版本。
89
+ - **不碰你的配置**:通过 PATH / mise 自行安装的 `dbhub` 不会被插件改动。
90
+
91
+ | 环境变量 | 说明 | 默认 |
92
+ | --- | --- | --- |
93
+ | `DSH_DBHUB_PACKAGE` | 自动安装使用的 npm 包名 | `@bytebase/dbhub` |
94
+ | `DSH_DBHUB_UPDATE_DAYS` | 自动更新间隔天数,`0` 关闭 | `7` |
95
+
96
+ ## 数据位置
97
+
98
+ 所有配置与凭据存放在模块目录之外(不受 pnpm 打包影响),删除该目录即可完整清空:
99
+
100
+ ```
101
+ ~/.dsh/storages/dsh-dbhub-live/
102
+ ```
103
+
104
+ `DSH_HOME` 实例隔离,同一实例的多个 profile 共享(与 dsh 自身 `workspace.json` 同一约定)。插件对升级/手改遗留的旧格式配置自动清洗并一次性迁移;运行目录被误删或写入被系统拦截时不会崩溃——自动重建目录、写入失败仅告警并继续内存态运行,`dbhub.toml` 写入失败则显示为初始化错误并自动重试。
105
+
106
+ ## 卸载
107
+
108
+ ```bash
109
+ dsh plugin --profile web remove dsh-dbhub-live
110
+ ```
111
+
112
+ ## 故障排查
113
+
114
+ | 现象 | 处理 |
115
+ | --- | --- |
116
+ | 首次使用报「无法获取 dbhub」 | 确认本机有 npm 且能联网;离线可手动安装 `dbhub` 并加入 PATH。 |
117
+ | 状态卡片显示 🔴 异常 | 查看状态卡片中的「最近错误」与 `dsh web` 日志;进程异常退出时插件会在下次调用自动重启。 |
118
+ | 工具显示「插件已禁用」 | 打开 设置 → 插件 → dsh-dbhub-live 卡片,点击「启用」。 |
119
+ | 看不到状态卡片 | 确认插件已安装并重启 `dsh web`;Host 半侧未注册状态命名空间时卡片不显示(无设置面板的环境不影响工具使用)。 |
120
+ | 扫描不到配置文件 | 默认跳过 `node_modules` / `.git` / `target` / `dist` 等目录,可改用「输入 DSN」或「填写分项」。 |
121
+ | 需要自定义 dbhub 版本 | 删除 `~/.dsh/storages/dsh-dbhub-live` 后设置 `DSH_DBHUB_PACKAGE` 指定包/版本。 |
122
+ | 不希望自动更新 dbhub | 设置环境变量 `DSH_DBHUB_UPDATE_DAYS=0`。 |
123
+
124
+ ## 开发与测试(不影响主进程)
125
+
126
+ 开发说明见 [AGENTS.md](./AGENTS.md)。推荐的调试路径(详见测试方案 `/插件开发文档/DSH插件测试方案.md`):
127
+
128
+ - **日常改代码** → 静态校验(`npm run check`)+ 单元测试(`npm test`),零风险;
129
+ - **会话内跑通逻辑** → 动态插件 `cordis_define/run` 快速迭代,不重启 Harness;
130
+ - **冷启动验证** → 隔离 `DSH_HOME` 起一个测试实例(如 `dsh web --port 3081`)安装本插件验证启动与客户端 bundle,主实例零影响。
131
+
132
+ ## 许可证
133
+
134
+ [MIT](./LICENSE)
package/cordis.patch.yml CHANGED
@@ -1,8 +1,8 @@
1
- # dsh-dbhub-live bundle patch — declares the plugin row this package mounts.
2
- # `dsh plugin --profile web add dsh-dbhub-live` installs this package into the
3
- # profile; reconcilePlugins sees `dsh.bundle.patch` and appends the package to
4
- # `dsh.profile.bundles`, then this patch layer inserts the row. The bare name
5
- # resolves the package's main (lib/index.mjs) from the profile's node_modules.
6
- - insert:
7
- - id: dbhub-live
8
- name: 'dsh-dbhub-live'
1
+ # dsh-dbhub-live bundle patch — declares the plugin row this package mounts.
2
+ # `dsh plugin --profile web add dsh-dbhub-live` installs this package into the
3
+ # profile; reconcilePlugins sees `dsh.bundle.patch` and appends the package to
4
+ # `dsh.profile.bundles`, then this patch layer inserts the row. The bare name
5
+ # resolves the package's main (lib/index.mjs) from the profile's node_modules.
6
+ - insert:
7
+ - id: dbhub-live
8
+ name: 'dsh-dbhub-live'
@@ -0,0 +1,45 @@
1
+ # dsh-dbhub-live 需求文档(业务层面)
2
+
3
+ > 说明:本文只描述业务需求,不涉及实现原理;详细开发说明见 `AGENTS.md`,用户安装使用见 `README.md`。
4
+
5
+ ## 产品定位
6
+
7
+ 为 DSH(DeepSeek Harness)提供数据库操作能力:模型在对话中可以直接查询、搜索、管理数据库连接;支持按工作区配置专属连接,也支持临时连接任意数据库做一次性排查。
8
+
9
+ ## 一、既有功能
10
+
11
+ ### 1. 数据库连接管理
12
+ - **支持的数据库**:MySQL、PostgreSQL、MariaDB、SQLite、SQL Server。
13
+ - **按工作区配置**:每个工作区可配置并持久化专属连接,一次配置长期复用。
14
+ - **三种配置方式**:
15
+ 1. 直接填写完整连接串(DSN);
16
+ 2. 按分项填写(类型 / 主机 / 端口 / 账号 / 密码 / 库名);
17
+ 3. 授权扫描项目配置文件(`.env`、`application*.yml`、`docker-compose`、`jdbc.properties` 等),列出候选项供确认后采用。
18
+ - **自动发现**:工作区已有 `mise env` 或 `.env`(`DSN` / `DB_*`)时自动识别,无需手动配置。
19
+ - **安全约束**:凭据仅存本机用户目录;任何展示/结果中的密码一律打码;扫描敏感文件必须先经用户授权。
20
+
21
+ ### 2. 查询与对象搜索
22
+ - **按工作区查询**:在已配置工作区的连接上执行 SQL、搜索数据库对象(表 / 视图 / 列 / 索引 / 函数等),工具名体现工作区身份,多工作区互不混淆。
23
+ - **临时连接查询**:对任意未配置的库传入连接串即可查询/搜索(多语句用 `;` 分隔),每次调用独立连接,可同时连多个不同库,便于跨环境对比排查。
24
+ - **环境提示**:工具描述和结果中标注目标连接环境(主机/端口/库,密码打码),避免误操作生产库。
25
+
26
+ ### 3. 运行时保障
27
+ - 常驻连接复用,提升多次查询效率;空闲一段时间自动回收。
28
+ - 首次使用若缺少依赖则自动安装,之后定期自动更新;用户自行安装的版本不受影响。
29
+ - 服务异常退出后,下次调用自动恢复,无需人工干预。
30
+
31
+ ## 二、本次新增功能
32
+
33
+ ### 1. 懒加载启动优化
34
+ - 插件启动不阻塞 GUI,工具立即可用。
35
+ - 环境初始化推迟到首次调用时进行;初始化期间界面提示「初始化中」,查询请求自动等待就绪。
36
+
37
+ ### 2. 插件状态管理
38
+ - **启用 / 禁用开关**:关闭后所有 dbhub 相关工具立即返回「插件已禁用」友好提示,无需重启;再次开启立即可用。
39
+ - **运行状态**:运行中 / 初始化中 / 异常 三态,实时反映插件可用性。
40
+ - **工具数量**:当前已注册工具总数实时展示。
41
+ - **错误摘要**:最近一次初始化或运行错误简要信息,异常时展示。
42
+
43
+ ### 3. 浏览器状态卡片(设置在插件的状态面板)
44
+ - 展示:运行状态徽章(🟢 运行中 / 🟡 初始化中 / 🔴 异常)、已注册工具数、工作模式(懒加载)、最近错误(红色展示)。
45
+ - 提供启用 / 禁用开关,即时生效。
package/lib/adhoc.mjs ADDED
@@ -0,0 +1,81 @@
1
+ // dsh-dbhub-live: ad-hoc temporary connections.
2
+ //
3
+ // Each call spawns a fresh throwaway `dbhub --transport stdio --dsn <dsn>`,
4
+ // runs one MCP tools/call against an ad-hoc target (ip/account/password/db
5
+ // supplied by the model per request), then kills it. Independent per call, so
6
+ // two parallel calls can query two different databases at once. Nothing is
7
+ // persisted and the persistent multi-source server is untouched.
8
+
9
+ import { DATA_DIR, maskDsn } from './config.mjs'
10
+ import { buildSpawnArgv, resolveDbhubExe } from './runtime.mjs'
11
+ import { createMcpClient, disabledMessage } from './mcp.mjs'
12
+ import * as state from './state.mjs'
13
+
14
+ export async function runAdhoc(subprocess, dsn, rawName, mcpArgs, exec) {
15
+ if (!state.isEnabled()) {
16
+ return { ok: false, text: disabledMessage() }
17
+ }
18
+ if (!dsn || typeof dsn !== 'string' || !dsn.trim()) {
19
+ return { ok: false, text: '缺少 dsn 参数(如 mysql://user:pass@host:3306/db)' }
20
+ }
21
+ let exe
22
+ try {
23
+ exe = await resolveDbhubExe(subprocess, exec.signal)
24
+ } catch (e) {
25
+ return { ok: false, text: '无法获取 dbhub: ' + String((e && e.message) || e) }
26
+ }
27
+ let handle
28
+ try {
29
+ handle = subprocess.spawn({
30
+ argv: buildSpawnArgv(subprocess, exe, ['--transport', 'stdio', '--dsn', dsn.trim()]),
31
+ cwd: DATA_DIR,
32
+ stdio: { stdin: 'pipe', stdout: 'pipe', stderr: 'pipe' },
33
+ graceMs: 3000,
34
+ signal: exec.signal,
35
+ })
36
+ } catch (e) {
37
+ return { ok: false, text: '启动临时 dbhub 失败: ' + String((e && e.message) || e) }
38
+ }
39
+ let stderrTail = ''
40
+ try {
41
+ const client = createMcpClient(handle, (c) => {
42
+ stderrTail = (stderrTail + String(c)).slice(-2000)
43
+ })
44
+ await client.request('initialize', {
45
+ protocolVersion: '2025-03-26',
46
+ capabilities: {},
47
+ clientInfo: { name: 'dsh-dbhub-adhoc', version: '3.0.0' },
48
+ })
49
+ client.notify('notifications/initialized')
50
+ const res = await client.request('tools/call', { name: rawName, arguments: mcpArgs })
51
+ const textOf = (r) => {
52
+ if (r && Array.isArray(r.content)) {
53
+ const parts = []
54
+ for (const b of r.content) if (b && typeof b.text === 'string') parts.push(b.text)
55
+ return parts.join('\n')
56
+ }
57
+ return JSON.stringify(r)
58
+ }
59
+ const prefix = '{临时连接: ' + maskDsn(dsn) + '}\n'
60
+ if (res && res.isError) return { ok: false, text: '临时连接执行错误: ' + textOf(res) }
61
+ if (res && res.structuredContent !== undefined) {
62
+ return { ok: true, text: prefix + JSON.stringify(res.structuredContent, null, 2) }
63
+ }
64
+ return { ok: true, text: prefix + textOf(res) }
65
+ } catch (e) {
66
+ let detail = String((e && e.message) || e)
67
+ if (stderrTail) detail += '\n[dbhub stderr] ' + stderrTail
68
+ return { ok: false, text: detail }
69
+ } finally {
70
+ try {
71
+ handle.terminate()
72
+ } catch (e) {
73
+ /* ignore */
74
+ }
75
+ try {
76
+ await handle.waitForExit(exec.signal)
77
+ } catch (e) {
78
+ /* ignore */
79
+ }
80
+ }
81
+ }