dsh-dbhub-live 5.0.1 → 5.2.0-dev.3
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 +95 -209
- package/README.en.md +251 -169
- package/README.md +251 -169
- package/doc/ARCHITECTURE.md +108 -0
- package/doc/CLIENT.md +124 -0
- package/doc/DESENSITIZE.md +56 -0
- package/doc/DEVELOPMENT.md +139 -0
- package/doc/IMPACT-MATRIX.md +36 -0
- package/doc/RELEASE.md +93 -0
- package/doc/REQUIREMENTS.md +177 -105
- package/doc/images/chat-query.png +0 -0
- package/doc/images/row-editor.png +0 -0
- package/doc/images/settings-page.png +0 -0
- package/lib/adhoc.mjs +412 -34
- package/lib/capability.mjs +157 -0
- package/lib/client.js +1243 -80
- package/lib/config.mjs +370 -21
- package/lib/i18n.mjs +119 -4
- package/lib/index.mjs +401 -43
- package/lib/mcp.mjs +496 -391
- package/lib/meta.mjs +267 -0
- package/lib/options.mjs +25 -5
- package/lib/policy.mjs +92 -0
- package/lib/toml.mjs +188 -0
- package/lib/tools.mjs +1093 -827
- package/lib/update.mjs +244 -0
- package/package.json +34 -10
- package/scripts/desensitize-check.mjs +10 -3
- package/scripts/desensitize.config.mjs +255 -237
- package/scripts/docs-check.mjs +214 -0
- package/scripts/release-preflight.mjs +180 -0
- package/scripts/render-check.mjs +1366 -843
- package/test/adhoc-toml.test.mjs +365 -0
- package/test/bridge.test.mjs +227 -185
- package/test/capability.test.mjs +231 -0
- package/test/client-format.test.mjs +515 -352
- package/test/configure-options.test.mjs +244 -0
- package/test/configure-ssh.test.mjs +232 -0
- package/test/copy-from.test.mjs +155 -0
- package/test/env-options.test.mjs +456 -0
- package/test/meta.test.mjs +234 -0
- package/test/options.test.mjs +160 -123
- package/test/policy.test.mjs +132 -0
- package/test/row-cache.test.mjs +237 -138
- package/test/ssh-probe.test.mjs +834 -0
- package/test/test-op-fastpath.test.mjs +208 -0
- package/test/toml.test.mjs +352 -0
- package/test/update.test.mjs +270 -0
- package/test/util.test.mjs +17 -0
- package/test/zero-knowledge.test.mjs +120 -78
package/doc/REQUIREMENTS.md
CHANGED
|
@@ -1,105 +1,177 @@
|
|
|
1
|
-
# dsh-dbhub-live 需求事实记录
|
|
2
|
-
|
|
3
|
-
> 本文只记录「产品必须满足什么」的**需求事实**(概念层面),不含实现细节;开发实现说明见 `AGENTS.md`,用户安装使用见 `README.md`。
|
|
4
|
-
> 版本基线:5.0
|
|
5
|
-
>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
##
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
1
|
+
# dsh-dbhub-live 需求事实记录
|
|
2
|
+
|
|
3
|
+
> 本文只记录「产品必须满足什么」的**需求事实**(概念层面),不含实现细节;开发实现说明见 `AGENTS.md`,用户安装使用见 `README.md`。
|
|
4
|
+
> 版本基线:5.1.0(最近一次正式发布)。5.1 迭代已发布:在 5.0 的零知识凭据 + 一次性进程执行 + dsh 双栈配置页之上,新增环境级只读、手动 SSH 隧道、侧边栏入口开关(与启用状态取交集)、SSH 层独立连通性测试、连接测试分层诊断,以及连接测试快路径。
|
|
5
|
+
> 5.2 迭代(测试版 5.2.0-dev.1,正式版目标 5.2.0):为配置页补上**版本展示与更新检查**(页头当前版本 + 低调的「↑ 可升级到 <latest>」文字链接 + 检查更新按钮;npm registry 为主、GitHub Releases 兜底)与**三套响应式布局**(弹窗 / 宽屏整页 / 手机小屏),把设置收进宽屏页、把只读开关放到连接行内,并补上**桌面端**(desktop profile + 可视化插件页)的安装/更新路径。新界面只在 **DSH 0.2.1+**(含预发布版)渲染,0.1.x 保持旧布局与行为。
|
|
6
|
+
> 该迭代范围:5.1 见第四节 R66、第五节 R67、第十节 R43/R44/R56-R58、第十一节 R49/R68、第十二节 R59-R65/R69 与第十三节 R70;5.2 见第十节 R73-R79。
|
|
7
|
+
|
|
8
|
+
## 一、产品定位
|
|
9
|
+
|
|
10
|
+
- R1. 插件为 DSH 提供数据库查询、对象搜索与连接管理能力。
|
|
11
|
+
- R2. 连接配置是长期资产,被维护与复用;每一次数据库执行是一次性的、相互独立的劳务行为。
|
|
12
|
+
|
|
13
|
+
## 二、凭据零知识(安全红线)
|
|
14
|
+
|
|
15
|
+
- R3. 密码、用户名与完整连接串(DSN)不得出现在模型上下文中的任何位置:工具参数、工具描述、查询结果、错误文本、来源列表均不得包含。
|
|
16
|
+
- R4. 模型仅凭「工作区/环境标识(source)」与元数据(数据库类型、主机、端口、库名)完成定位与执行,由插件在宿主侧解析真实凭据并自行执行。
|
|
17
|
+
- R5. 凭据的录入与修改必须由人在界面完成(或经授权后由插件仅在本机读取,如项目文件扫描),不得经模型转述。
|
|
18
|
+
- R6. 查询因鉴权/连接失败时,系统应给出「凭据或连接信息可能有误」的明确指引,引导用户在界面更新,而非要求模型提供密码。
|
|
19
|
+
- R7. 任何底层工具返回的文本在呈现给模型之前必须经过清洗,防止异常路径泄漏密码。
|
|
20
|
+
|
|
21
|
+
## 三、连接管理
|
|
22
|
+
|
|
23
|
+
- R8. 支持按工作区配置专属连接,一次配置长期复用。
|
|
24
|
+
- R9. 同一工作区可配置多个环境(默认环境与命名环境),彼此独立、可区分、不混淆。
|
|
25
|
+
- R10. 连接录入支持三种方式:直接输入连接串、按分项填写、授权扫描项目配置文件后确认;扫描敏感文件必须先经用户授权。
|
|
26
|
+
- R11. 工作区已有自动配置(mise env / .env)时可自动识别连接、免手工配置;自动识别项不被持久化。
|
|
27
|
+
- R12. 用户可在设置界面查看、新增、修改、删除连接,并可测试连接可达性;测试结果不持久化、仅即时反馈。
|
|
28
|
+
|
|
29
|
+
## 四、查询与对象搜索
|
|
30
|
+
|
|
31
|
+
- R13. 模型可通过来源标识执行 SQL,以及搜索数据库对象(表、视图、列、索引等)。
|
|
32
|
+
- R14. 支持以分号分隔的多语句 SQL。
|
|
33
|
+
- R15. 工具声明数量恒定,不随连接(工作区 × 环境)数量增长。
|
|
34
|
+
- R66. 工具集必须**封闭且恒定**:恰好 4 个工具(`dbhub_configure`、`dbhub_list_sources`、`dbhub_execute_sql`、`dbhub_search_objects`),不得按工作区 × 环境注册独有工具;**任何工具都不得声明 `dsn` 参数**(模型一旦把连接串当参数传入,密码就进了模型上下文),模型经 `dbhub_configure` 传入 `dsn` 时必须被明确拒绝并给出指引(延续 R3/R4/R5)。
|
|
35
|
+
|
|
36
|
+
## 五、执行与运行保障
|
|
37
|
+
|
|
38
|
+
- R16. 每次执行独立、一次性,不共享长期进程状态;单次执行失败不影响其他执行。
|
|
39
|
+
- R17. 支持多任务并发执行,互不影响。
|
|
40
|
+
- R18. 支持多个 DSH 实例并存运行,互不影响、无冲突。
|
|
41
|
+
- R19. 首次执行缺少依赖时自动安装 dbhub,并按设定间隔自动更新;用户自装版本不受影响。
|
|
42
|
+
- R20. 插件可启用/禁用;禁用后所有工具应立即返回友好提示。
|
|
43
|
+
- R67. 执行必须按环境选择连接表达方式:未开启只读、也没有隧道的环境继续用 `--dsn`;开启只读**和/或**配置了隧道的环境必须改用**当次生成、用完即弃的 TOML 配置**(`--dsn` 与 `--config` 互斥,且只有 TOML 方言能表达 `[[tools]] readonly` 与 `ssh_*` 字段)。三条硬约束:
|
|
44
|
+
- **生成文件绝不含任何秘密**:连接串与隧道秘密在文件里只以占位符出现,真值随该次子进程的环境传入——因此即使文件残留也不构成泄漏。
|
|
45
|
+
- **只读必须同时声明两条工具**(`execute_sql` 与 `search_objects`):`[[tools]]` 是白名单而不是补丁,只写一条会让该环境的对象搜索直接不可用(这是 R59「开启只读不得让对象搜索失效」的执行面)。
|
|
46
|
+
- **生命周期**:临时文件只存在于 `$DSH_HOME/storages/dsh-dbhub-live/tmp/`,每次调用结束(**含失败**)都必须尽力删除,插件启动时清扫崩溃残留;不得退化成常驻配置文件、热重载或多源配置(延续 R16)。
|
|
47
|
+
|
|
48
|
+
## 六、设置与状态界面
|
|
49
|
+
|
|
50
|
+
- R21. 浏览器端提供配置页:展示启用状态、工具声明数、环境数、最近错误(工作模式作为状态行提示),并支持启用/禁用开关、连接的增删改查、环境改名与连接测试。该页面有**三个入口**且都指向同一页面与同一份状态:设置面板的一级页面(主入口,见 R42)、侧边栏快捷入口(见 R43)与官方「插件」页该行的配置槽(dsh 0.1.6 及以后为 `plugins.row.config`);后者只是多一个入口,**不得**被当成唯一承载位,也不得替代设置面板里的页面。
|
|
51
|
+
- R22. 面板文案与模型侧反馈跟随 DSH 界面语言(中/英)。
|
|
52
|
+
|
|
53
|
+
## 七、存储与实例隔离
|
|
54
|
+
|
|
55
|
+
- R23. 配置与凭据仅存本机用户目录,按实例(DSH_HOME)隔离;共享同一主目录的并发实例写入互不破坏(不产生半写文件)。
|
|
56
|
+
- R24. 配置持久化失败不应导致崩溃,可降级继续运行。
|
|
57
|
+
- R25. 升级或手工修改遗留的旧格式配置应被自动清洗/迁移,未知字段予以保留。
|
|
58
|
+
|
|
59
|
+
## 八、连接配置交互原则(零打扰优先)
|
|
60
|
+
|
|
61
|
+
> 本节由 4.0.x 交互优化迭代(探连优先 + 凭据最小询问)沉淀,覆盖用户侧三轮反馈:①可用直接可用、缺什么问什么;②已存连接凭据缺失时应诊断并只补缺失项;③连接信息本身不对或重新描述了目标时应能脱身并按新信息重走判断。
|
|
62
|
+
|
|
63
|
+
- R26. 对**已配置且校验可用的连接**,配置过程必须自动校验;通过时直接确认「已配置可连通」并提供使用指引,**不要求用户重新输入任何信息**。
|
|
64
|
+
- R27. 仅当环境未配置、校验失败或自动试连未成功时才向用户提问;**提问不得索要已知或重复信息**——完整连接串已含密码时,不得再次索取密码。
|
|
65
|
+
- R28. 未配置环境下,若已从对话中得知足够的连接事实(类型/主机/库名;SQLite 除外),应**先自动试连**、按结果分流,而不是直接提问:
|
|
66
|
+
- 试连成功 → 按已有信息完成配置并返回可用来源标识,**全程零输入**(免密码连接、信息即用即存);
|
|
67
|
+
- 试连提示缺凭据 → **只询问缺失项**(账号未知时连账号一起问),其余信息自动沿用,补完即生效;
|
|
68
|
+
- 信息不完整或试连因其它原因失败 → 才提供完整录入方式(输入连接串 / 分项填写 / 授权扫描)。
|
|
69
|
+
- R29. 凭据询问必须**说明为什么需要**(试连失败原因),并允许用户表明「连接信息本身不对」从而改走完整录入,避免用户被困在反复补凭据的循环中。**若试连诊断明确指向“空账号被拒”(如 `Access denied for user ''@…`),账号为必填**:凭据询问不得提供「留空(使用空账号)」选择,用户仍提交空账号时应拒绝保存并说明原因,避免把同一个必失败的 DSN 再存回去。
|
|
70
|
+
- R30. 用户重新描述的目标(库/主机/端口等)与已存连接不同时,必须**按新描述重新执行判断流程**,不得沿用旧连接的结果。
|
|
71
|
+
- R31. 「使用现有连接」是**字面沿用**:不修改、不补填任何缺失字段(如账号/密码);其文案必须让用户明确这一点,不得暗示会修复缺失项。
|
|
72
|
+
- R32. 录入表单与凭据询问都应**预先带入已从对话中得知的字段**,用户只需补充缺失项,避免重复录入。
|
|
73
|
+
- R33. 连接保存或被采纳后,应**立即自检连通性**并把结果(可连通 / 失败原因)随回执一并返回,避免用户通过后续尝试才得知失败。
|
|
74
|
+
- R34. 连接信息输入界面只提供一个取消入口(由界面自身提供),不得出现重复取消项。
|
|
75
|
+
|
|
76
|
+
## 九、工作区隔离与来源解析
|
|
77
|
+
|
|
78
|
+
> 本节由 4.1 迭代沉淀:多工作区各自配置了相似(甚至同名)连接时,模型必须能分辨「这是哪个工作区的哪个环境」,不允许把不同工作区的连接当成同一个使用。
|
|
79
|
+
|
|
80
|
+
- R35. 每条连接只属于一个工作区;不同工作区的连接是彼此独立的目标,即使连接信息看起来相同也不得视为同一条(不共享、不互相覆盖、不互相替代)。
|
|
81
|
+
- R36. 模型侧应优先使用**当前会话工作区**的连接;连接清单必须按工作区分组并显式标出当前工作区。
|
|
82
|
+
- R37. 当模型给出的来源标识可能命中多个工作区(同名工作区、同名环境或仅给标题)时,系统必须返回候选清单要求明确指定,**不得按列表顺序或长度猜测**。
|
|
83
|
+
- R38. 需要复用其他工作区已配置的连接时,必须先取得用户确认,再由插件在宿主侧把连接**复制**到当前工作区(新建一条属于当前工作区的连接);凭据与连接串不得因此进入模型上下文,也不得直接用其他工作区的来源标识执行查询。**复制是整体复制**:源连接若带有环境选项(只读、SSH 隧道),这些选项必须一并复制到新连接,不得只复制连接串而丢掉用户的安全设置。
|
|
84
|
+
- R39. 环境名支持非 ASCII(如中文「线上」「测试」):显示与存储保留原名,而用于来源标识的环境段必须**唯一且稳定**——不同中文环境名不得解析到同一个来源;纯 ASCII 名的既有来源标识保持不变。
|
|
85
|
+
- R40. 环境可改名(模型可调、界面可改):改名只更换名字,连接与凭据原样保留、无需重新输入;目标名已存在时必须先经用户确认(该操作会覆盖目标环境的连接)。
|
|
86
|
+
- R41. 配置目标必须明确:显式给出的工作区不存在时应报错并列出可用工作区,不得静默改用其他工作区;未给出工作区时以当前会话工作区为准,无法确定时应要求明确指定。
|
|
87
|
+
|
|
88
|
+
## 十、配置页与桌面端承载(dsh 版本适配)
|
|
89
|
+
|
|
90
|
+
- R42. 配置页必须可通过**设置**进入:插件在设置面板注册一级页面(设置 → DBHub 数据库工具),该承载位属核心界面、任何部署都存在,用户也在此寻找连接管理;同时在官方「插件」页按当前 dsh 版本提供的单插件配置槽位(0.1.6 起为 `<包名>#<行 id>` 的配置页)再挂一份。三处进入的是同一个页面与同一份状态。
|
|
91
|
+
- R43. 插件另提供**侧边栏快捷入口**,其显示由**两个条件同时成立**决定:插件处于启用状态,**且**用户在设置条(设置 → DBHub 数据库工具 → ⚙ 设置)里打开了「在侧边栏显示入口」开关(默认开启,随其他选项持久化)。任一条件不成立即隐藏,改动即时生效、无需重启或刷新。
|
|
92
|
+
- **「隐藏快捷入口」与「禁用插件」是两件事**:关掉开关只是不显示入口,插件继续工作、模型仍可正常使用工具;禁用插件则一律不显示入口——禁用中的插件不贡献任何侧边栏入口。
|
|
93
|
+
- R44. 侧边栏入口的显隐(无论是被上述开关关闭,还是因插件禁用而消失)**不得**造成自锁——设置页与插件页入口必须始终可用,用户必须能据此重新打开开关或启用插件;官方槽位变化或缺失(如 dsh 升级移除旧槽位)同样不得导致配置页不可达。
|
|
94
|
+
- R56. 插件必须同时支持两条 dsh 版本线(0.1.x 与 0.2.x)的配置页数据通道:dsh 升级删除插件所依赖的宿主接口时(如 0.1.7 起 settings 命名空间被 Config 表单取代、0.2.x 删除浏览器侧 `settingsScope` 服务),插件**不得**因等待一个永远不会出现的服务而静默失活(表现为配置页/侧边栏/插件页入口全部消失且无任何报错)。浏览器半必须主动探测可用通道并降级;页面数据与写入能力在两条通道上必须等价。
|
|
95
|
+
- R57. 新增通道不得削弱既有安全边界:浏览器↔宿主的状态读取只承载元数据(延续 R3/R4),连接串只在写入方向从浏览器直达宿主;写入路由必须与 dsh 自身的接口鉴权一致(未鉴权的请求必须被拒绝),不得因为"插件自有路由"而绕过鉴权。
|
|
96
|
+
- R58. 插件选项(自动更新间隔、**在侧边栏显示入口**)必须在两条版本线上都能持久化,并且升级插件不得静默重置用户已保存的值(旧版本的设置文档作为更低一层被读入)。在 0.1.7 及以后,这些项同时作为插件的声明式配置暴露(`updateIntervalDays` / `showSidebarEntry`):可经 `cordis.patch.yml` 或官方插件表单设置,且**与插件自有配置页共享同一个有效值**——任一处的改动都必须在另一处立刻可见(不得出现"改了表单但页面不变"或反之)。侧边栏开关只决定入口显隐,不改变插件的启用状态(见 R43)。
|
|
97
|
+
- R73. **桌面端安装与维护路径**:插件必须同时在 **web profile 与 desktop profile** 上可用,两个 profile 的安装/卸载都支持 CLI(`dsh plugin --profile web|desktop add|remove dsh-dbhub-live`,无 dsh 时用 npx 前缀)。桌面端还必须能**全程经可视化「插件」页**完成:左侧菜单 → 插件 → 新增 → 输入 `dsh-dbhub-live`(或从插件市场搜索)→ 安装;安装/更新/卸载都不依赖命令行。同一插件在两处的能力与界面一致。**升级/重装/卸载不得丢失连接与凭据**:数据位于 `$DSH_HOME/storages/dsh-dbhub-live`,与模块目录无关(延续 R23/R25)。
|
|
98
|
+
- R74. **三套响应式布局(同一组件、能力等价)**:配置页必须按承载位与实测宽度渲染三种布局:
|
|
99
|
+
- **弹窗模式**(设置 → DBHub 数据库工具,原承载位):窄列,密度与既有布局保持一致;
|
|
100
|
+
- **宽屏整页模式**(左侧菜单的 DBHub 入口、插件页该行的「配置」):整页宽列,页头显示插件名与当前版本,设置项在页面内直接可见;
|
|
101
|
+
- **手机浏览器小屏**(宽度 < ~700px):纵向堆叠的紧凑布局,控件按触摸尺寸排布。
|
|
102
|
+
|
|
103
|
+
三种布局下的数据、权限与安全语义必须一致,任何布局都不得显示密码或完整 DSN(延续 R3)。
|
|
104
|
+
- R75. **版本展示与更新检查(页头)**:页头必须显示插件名与当前版本(版本为低调小字)。检测到更新时**不得使用报错语义**(红底、红框、error 色),只出现一行低调的「**↑ 可升级到 <latest>**」文字链接;**点击才展开**中性说明面板,面板内含可直接安装的包规格 `dsh-dbhub-live@<latest>`(点击复制)、按部署方式给出的可执行更新指引(**Web**:`dsh plugin --profile web up dsh-dbhub-live@<latest>` 后重启 `dsh web`;**桌面端**:在「插件」页卸载后重装最新版本,配置/凭据保留,见 R73)以及更新说明链接。页面提供图标式「检查更新」入口,并在页面打开时自动检查一次(必须节流,不得每次打开都请求网络)。检查源以 **npm registry 为主、GitHub Releases 为兜底**;失败只作为提示,不得影响插件任何功能。发布说明以 GitHub Releases 为准。
|
|
105
|
+
- R76. **设置项位置与控件形态**:宽屏页必须承载完整设置区(与弹窗模式**同一有效值、同一写入口**,延续 R58):**插件启用/停用**、**dbhub 自动更新间隔(天)**、**侧边栏入口 显示/隐藏**、**向模型注入数据库访问策略**。设置区必须收成**一行紧凑设置条**(标签与控件相邻,不出现"标签在左端、控件在右端"的大段空白);**宽屏页、插件页以及窄桌面窗口都必须保持横排**(窄列可隐藏状态词/标题并压缩间距,但不得退化为竖排列表);只有弹窗与手机使用紧凑设置行。字号与控件必须**弱化**(不得抢占连接列表的视觉主体)。控件使用 DSH 原生开关(跟随主题/皮肤)并配**两字汉字状态词**(启用/停用、显示/隐藏、开启/关闭,不得使用"已启用/已开启"这类歧义写法);「自动更新间隔」的输入框、单位与保存必须在同一行内,不得换行。弹窗模式里同一批设置收在状态行的「设置」折叠里,展开后与宽屏同一形态。
|
|
106
|
+
- R77. **连接行内只读开关(所有布局)**:三种布局(弹窗 / 宽屏 / 手机)下,每个连接的只读开关都必须直接出现在该行**数据源旁边**,可就地即时切换,不再需要打开编辑表单;只读的权限不对称不得改变(模型只能开、不能关,延续 R59/R69),且只读状态的标识在所有布局下都可辨认。编辑表单里的勾选可保留,但不得是唯一入口。只读 chip 必须用**开锁 + 「可写」/ 闭锁 + 「只读」**两种状态(同一线性图标风格),不得只靠颜色或灰字区分,否则首次使用者会把可写连接误认为只读。**连接串本身不得带锁形图标**(避免被误读为"需要密码",也与只读锁语义冲突)——锁只用于表达只读。
|
|
107
|
+
- R78. **DSH 版本门槛(新界面)**:上述版本/更新入口、宽屏整页布局、行内只读开关与开关样式的设置区,自插件 **5.2.0** 起提供,且**只在 DSH 0.2.1 及以上**(含 0.2.1 的预发布版本)渲染。**DSH 0.1.x 上必须保持既有布局与行为**——不出现升级提示、不改动旧 DOM 结构,避免旧版本线上出现半套新界面;旧版的通道降级与安全边界(R56/R57)照旧生效。环境要求文案必须同时说明「新界面需 0.2.1+」与「0.1.x 仍受支持」。
|
|
108
|
+
- R79. **设置页信息层级**:状态行只显示「运行状态 + 连接数量」,不得在首屏展示工具数量、"固定"模式、部署类型等实现细节;这些内容与长段说明统一收进默认收起的「说明与技术详情」折叠区(深度用户可展开)。设置页首屏应以"一眼知道能操作什么"为准。
|
|
109
|
+
|
|
110
|
+
## 十一、配置页布局与空间占用
|
|
111
|
+
|
|
112
|
+
> 本节由 4.2 迭代沉淀:连接数量增长后,原「每个连接三到四行 + 常显添加表单」的平铺列表把大量高度花在重复的工作区标题与固定块上;下列要求把列表改为按工作区组织、每连接一行。
|
|
113
|
+
|
|
114
|
+
- R45. 连接列表必须**按工作区组织**,并在两种呈现间自动选择:**所有工作区都恰好只有一个环境**时使用**平铺**(一格一个工作区,信息全露、无需展开);**任一工作区有多个环境**时使用**按工作区分组**。判定只取决于"是否存在多环境工作区",不引入数量阈值。
|
|
115
|
+
- R46. 工作区分组必须支持**点击组头展开/折叠**,组头显示该工作区的环境数与已保存数;分组以**工作区路径**为身份(同名工作区是不同目标,不得仅凭标题合并,同名时必须可见地消歧)。
|
|
116
|
+
- R47. 默认展开态:单个工作区自动展开;多工作区时展开**用户最近使用的工作区**,其余折叠;无法判定最近工作区时全部折叠。必须提供「全部展开 / 全部折叠」总控。用户的展开/折叠选择在同一次页面会话内保留(跨重挂载有效),**不跨刷新持久化**。
|
|
117
|
+
- R48. 列表中**每条连接只占一行**:环境名、连接元数据(类型/主机/端口/库名)与操作;`source` 句柄不得再单独占据整行,改为**可复制入口**(保持可复制性,且必须让人看得出复制的是 source 句柄而不是整行连接信息)。**库名必须始终可见**:窄行下可截断主机/端口前缀,不得把库名截掉。行内操作以图标承载(必须带 `title`/`aria-label` 说明),不得用文字按钮占掉行宽。**连接的「来源」(手填/扫描/复制/自动发现)不得作为行内徽章常显**——它对绝大多数行都一样,却会抢走行的视觉焦点;应改为按需查看(悬浮提示),其中「自动发现且未持久化」这一例外需明确提示(该条尚未保存)。列表内不得出现密码或完整 DSN(延续 R3)。
|
|
118
|
+
- R49. 低频内容必须收拢:状态与开关收成页面顶部一行,自动更新间隔与**「在侧边栏显示入口」开关**(默认开启)一起放进默认收起的设置条(**宽屏模式下改为页面内直接展开的设置区,见 R76**);**添加连接表单默认收起**。分组内新增连接必须自动带入该工作区(不要求用户重复填写/选择工作区)。关闭该开关只影响侧边栏入口的显隐(见 R43),不影响插件的启用状态与工具可用性。
|
|
119
|
+
- R50. 界面配色必须使用 DSH 主题令牌,随主题/皮肤与**半透明背景**自适应:样式表中不得出现不透明色字面量(含兜底值),正文与操作文案的对比度不得依赖固定浅灰。用户可能安装主题/皮肤插件覆盖或省略令牌,此时界面仍需可读(表面继承页面背景而不是涂上白块)。
|
|
120
|
+
- R51. 工作区分组与其环境行之间必须有**可见的层级区分**(缩进、引导线、边框或阴影等),不得让组头与环境行看起来是同一层。
|
|
121
|
+
- R52. 界面写入连接时,若目标工作区的目标环境名**已经存在**(新增落到已存在环境,或改名落到已存在环境),必须**先提示"将覆盖该连接"并要求用户确认**;取消则不得产生任何写入,并保留用户已填内容以便改名。判定必须使用与宿主一致的环境名规范化规则(去控制字符、trim、空值→`default`、限长),否则会出现"看起来不同、实际是同一个键"的漏判。仅修改**同一个环境**的连接不属此列(那正是编辑的目的,不需二次确认)。
|
|
122
|
+
- R53. 界面操作的**结果必须即时可见**:新增/删除/改名/连接测试提交后,列表不得等到"重新扫描全部工作区"才更新,也不得出现"先整块消失、稍后再出现"的空窗。理想顺序是:宿主应用写入后立刻按已知状态回推,再以权威扫描校正(扫描失败时保留最后一次可用列表)。
|
|
123
|
+
- R54. 从界面复制连接信息(连接串标签等)必须得到**可直接使用**的字符串:不得因为渲染分层(例如把类型/主机段与库名拆成两个盒子)而混入空格、换行等分隔符。
|
|
124
|
+
- R55. **连接发现不得被单个工作区拖死**:自动发现(mise env / .env)的每一次外部探测都必须在有限时间内返回(超时即放弃该工作区的自动发现,不影响其他工作区与已配置连接),且同一目录的结果在短时间内可复用(避免每次列表/执行都重新探测)。**界面显示连接与模型侧看到连接必须一致**:卡片写入所用的工作区标识必须与发现/查询所用的同一份注册表,不得出现"设置里有、模型列不出来"。
|
|
125
|
+
- R68. 并发的发现与解析必须**在途去重**:同一时刻只跑一趟工作区扫描(卡片发布、模型列源/执行与连接测试同时落下时共享同一在途结果),同一目录的自动发现解析同样共享在途结果;**共享的失败不得被缓存**——一次失败之后的下一次调用必须真实重试。显式重扫是唯一例外,且必须真的重新扫描。
|
|
126
|
+
|
|
127
|
+
## 十二、环境选项与上游能力门槛
|
|
128
|
+
|
|
129
|
+
> 本节由 5.1 迭代沉淀:只读与 SSH 隧道都是**环境级**(工作区 × 环境)的连接属性,交给 dbhub 自身的原生能力执行;插件不自行判定 SQL 是否可写、也不自建隧道实现。
|
|
130
|
+
|
|
131
|
+
- R59. 支持按环境开启**只读模式**,且只读必须由**上游(dbhub)原生拒绝**写操作来保证(返回 `READONLY_VIOLATION` 一类明确错误),不得以插件自制的 SQL 分类替代上游判定(避免与上游语义漂移、绕过面扩大)。只读是**逐环境**属性,不是插件级全局开关("整体关停"由禁用承担)。**模型可以开启只读、绝不能关闭**:关闭只读必须由用户在配置页执行(否则模型等于自行提权),模型尝试关闭时应被拒绝并给出指引;界面上必须能看到哪些环境处于只读。开启只读不得使该环境的只读能力(如对象搜索)失效。只读环境放行的语句集**完全以上游为准**(MySQL 实测为 `select`/`with`/`explain`/`show`/`describe`/`desc`,其他连接器略有不同),插件不得自行判定、增减或改写这份白名单。
|
|
132
|
+
- R60. 支持为环境配置**手动 SSH 隧道**:主机、端口、用户、认证方式(密钥 / 密码)、密钥路径与口令、可选的**单跳** ProxyJump;隧道由 dbhub 原生能力建立,插件只负责收集、落库与传递。**隧道凭据(SSH 密码、密钥口令)只能由用户在界面输入,绝不进入模型上下文**;模型只能提供/修改非密字段(主机、端口、用户、认证方式、密钥路径、ProxyJump)并可解除隧道。编辑时秘密字段**留空表示保持原值**,已存秘密不得回显;已存的**密钥路径**同样不回显(编辑态只提供"密钥是否就位"这类布尔状态),避免把宿主侧的文件路径带回浏览器。隧道只支持**单跳**:多跳跳板机、`ProxyCommand`、ssh-agent 不予支持,命中时必须明确报"不支持"并给出指引,不得静默降级。插件**不复用也不读取**任何其他插件(包括 DSH 自带的 SSH 工具)的 SSH 配置。
|
|
133
|
+
- R61. 连接测试必须验证**有效连接**:即该环境在开启只读 / 配置隧道之后真正会被执行使用的那套连接(包含隧道与只读组合),而不是只测裸连接串;测试结果只是一次性反馈,不得改变连接状态、不得影响其他环境。测试取"待测连接"时**不得为此重扫全部工作区**:已保存的环境直接读持久化的连接,界面上已展示的环境用当前显示的那一行,只有从未扫描到的环境才做一次真实发现;测试进行中必须让等待**可感知**(显示已耗时)。宿主侧的探测预算必须严格低于浏览器侧的兜底等待(无隧道约 25 秒 / 有隧道约 45 秒,对应界面兜底 30 秒 / 60 秒),避免界面已超时而宿主仍在跑。显示已耗时的计时器**只在有探测在途时存在**:空闲页面不得保留任何计时器或轮询(残留计时器会让界面永不空闲)。
|
|
134
|
+
- R62. **dbhub 能力门槛**:只读与 SSH 隧道依赖 dbhub **1.4.0 及以上**的原生配置能力;低于 **1.0.0** 的版本必须**明确拒绝**(那条版本线还没有这些配置方言),**1.0.0–1.3.x** 放行但必须给出"未实测"警告,让用户知道风险所在。检测到版本不满足时必须给出**明确错误与升级指引**(升级 dbhub,或改用插件自动安装的版本),**绝不静默降级**——尤其不得退回会被上游静默忽略的旧写法,否则会出现"看起来开了只读、实际仍可写"的危险状态。版本无法判定时放行,并在真实失败时给出指引;不满足门槛时配置页应禁用相关控件并说明原因,而不是等用户操作后才失败。
|
|
135
|
+
- R63. 自动发现的环境(未持久化,来自 mise env / .env)在被**显式**设置环境选项(只读 / SSH)时,必须把它**提升为持久化连接**(以当时解析到的连接串落库)并同时写入选项,且必须**明确告知用户**这次提升(此后该环境不再随源文件变化);提升只能由用户或模型的显式操作触发——列出来源、执行查询、发布状态本身都不得触发持久化。
|
|
136
|
+
- R64. 必须提供**独立的 SSH 层连通性测试**(配置页行编辑器的「高级:SSH 隧道」区内、与「测试该配置」并列的「测试 SSH 隧道」),让用户能判断失败出在隧道还是数据库,并**如实说明它能证明什么、不能证明什么**:
|
|
137
|
+
- 先拒绝不完整的隧道配置(缺主机、缺用户或缺凭据时不发起探测,直接说明缺什么);**但「认证方式 = 密钥 + 密钥路径留空」不算缺凭据**:它按 SSH 客户端惯例落到默认身份文件 **`~/.ssh/id_ed25519`**(即该字段占位符显示的同一个值,插件侧常量 `DEFAULT_SSH_KEY_PATH`)。该默认**只作用于密钥认证且路径为空**:字段填了路径绝不覆盖,密码认证不受影响;「留空 = 保持原值」对秘密字段(密钥口令 / SSH 密码)与已存密钥路径照旧生效(已存路径存在时不会套用默认)。**保存与测试必须用同一条规则**——否则会出现"测试通过、保存却把隧道静默丢掉",这正是修复前的现场。探测结论里必须**写明这次实际尝试的路径**(附一句"未填密钥路径,已按默认 … 尝试"),避免用户去猜是不是少打了一个字符。**诚实边界**:默认文件在那台机器上可能并不存在,此时结论应是可执行的 `SSH 密钥文件不存在或不可读:~/.ssh/id_ed25519`(并带同一句说明),而不是含糊的"配置不完整";
|
|
138
|
+
- 先做 **TCP 可达性**探测(插件宿主 → `ssh_host:ssh_port`,约 5 秒预算),给出「主机不可达 / 端口未开放」的明确结论并附**套接字错误码**(ENOTFOUND / ECONNREFUSED / ETIMEDOUT 等)——这一步单独就能把"DNS / 防火墙 / 端口"问题与其他问题分开;
|
|
139
|
+
- 密钥认证时另做本地检查:私钥**文件存在且可读**;
|
|
140
|
+
- 然后**故意**让 dbhub 对一个不可能在监听的地址(`127.0.0.1:1`)建立隧道,并**按证据判定,顺序固定且不得颠倒**:① 报错里出现 **SSH 层特征**(`SSH connection error` / `__dbhubSSHTunnelError` / 认证方式全部失败 / 私钥无法解析 / 加密私钥缺口令 / 握手 / ProxyJump / ssh2)时**单独即可判定隧道这一层断**(这类特征只会由隧道级问题产生);② 否则出现 **数据库层特征**(`PROTOCOL_CONNECTION_LOST`、`Connection lost`、`server closed the connection`、`Access denied`、`Unknown database`、`ER_*`、`ECONNREFUSED`/`ECONNRESET`/`ETIMEDOUT`/`EHOSTUNREACH`、`SSH tunnel closed`)时判定**隧道可用**——驱动只有在转发连接建立之后才会说话(`SSH tunnel closed` + `Connection lost` + `PROTOCOL_CONNECTION_LOST` 正是"隧道通了、隧道后面的库不可用"的形状,且**不会**指名转发目标,所以"是否指名目标"不能作为唯一证据,这正是曾经的误判现场);③ 否则若报错**指名了转发目标**,同样判定隧道可用;④ 两者都没有时才如实给「SSH 层结果无法判定」并附输出末尾,**不得猜测**;<!-- desensitize:allow (`__dbhubSSHTunnelError` 是 dbhub 自己的错误属性名,不是凭据) -->
|
|
141
|
+
- **诚实边界(必须写明)**:该测试证明的是"网络可达 + 本地密钥就位 + SSH 层能否起来",**不是**一次带真实数据库的完整 SSH 会话验证;隧道能建立不等于隧道后面那个库一定连得上(那仍由 R61 的有效连接测试回答)。
|
|
142
|
+
- R65. 连接测试失败时的**诊断必须分层归因,且只取 dbhub 输出的末尾**:
|
|
143
|
+
- 诊断保留 dbhub 输出的**尾部**(多行、约 600 字符、保留换行原样展示)——致命行在输出的末尾,只取开头(如 dbhub 的启动横幅)会把真正的错误截掉,用户就看不出失败原因;尾部必须**丢掉栈帧行及其折行残片**(` at …`,以及以 `file.js:L:C)` 结尾的续行),并按**行边界**截断:宁可少几个字符,也不得让消息以半行/半段路径开头(从半行开始的诊断读起来像乱码,也会让人误以为消息被截坏了);
|
|
144
|
+
- 配置了隧道时,消息前必须标出失败的层:「【SSH 层】隧道未建立:…」或「【数据库层】隧道可能已建立,失败发生在数据库连接/认证:…」;后者必须**措辞谨慎**(只能说"可能"),因为只有 R64 的独立测试才能证明隧道确实起来了;插件自身无法启动 dbhub / 生成配置时另用「【插件层】…」前缀(该情形既不属于隧道层也不属于数据库层);同时必须给出可操作结论:**报【数据库层】即表示失败出在隧道后面的数据库(隧道这一层没有报错),用户不必再怀疑 SSH**——要把"可能"钉成确定结论,由 R64 的独立测试回答;
|
|
145
|
+
- **用户名与密码都不得出现在诊断中**:dbhub 自身的横幅打印只掩了密码的 DSN(`mysql://user:****@host:3306/db`),因此清洗必须把**任意 URL 形态连接串的整个 userinfo** 折叠掉(`scheme://user:pass@host` 与 `scheme://user@host` → `scheme://****:****@host`),使诊断呈现为 `mysql://****:****@host:3306/db`。这是既有零知识契约的实际执行:密码与用户名不仅不得进模型上下文(R3),也不得出现在配置页的诊断文本里。
|
|
146
|
+
- R69. 只读的**拦截点与解除能力必须分离**:模型侧"只能收窄、不能放宽"的约束只落在工具/模型路径上——宿主与存储层必须保留完整的关闭能力,用户在配置页必须真能关掉某个环境的只读(把拦截下沉到存储层会让只读变成永久无法解除,用户再也关不掉自己设的限制)。
|
|
147
|
+
|
|
148
|
+
## 十三、分发与文档边界
|
|
149
|
+
|
|
150
|
+
> 本节沉淀发布物的边界:业务需求以本文为准,用户安装使用以 `README.md` 为准,开发过程记录不随包分发。
|
|
151
|
+
|
|
152
|
+
- R70. 发布包(npm 包)必须且只包含运行所需内容:`lib`(含浏览器半 `client.js`)、`doc/REQUIREMENTS.md`、`doc/images`(README 截图)、`test`、`scripts`、`cordis.patch.yml`、两份 README(`README.md` 与 `README.en.md`)、`AGENTS.md` 与 `LICENSE`。`PLAN-*.md` 与 `implementation-notes.md` 是**本地开发记录**:既不纳入版本控制(由忽略规则排除)、也不在发布清单里,因此永不随包分发,不得把过程性文档当作产品交付物。
|
|
153
|
+
|
|
154
|
+
## 十四、模型侧数据库访问策略(提示词约束)
|
|
155
|
+
|
|
156
|
+
> 本节沉淀一次生产事故的教训:只读的**执行点**在 dbhub 内部,因此只约束"经过本插件"的调用;模型自行改走 shell(在宿主机上找到 `pgsql.exe`/`psql` 等客户端直连)完全不受管控。工具描述不足以压住这种绕道——工作区说明(`AGENTS.md`/`CLAUDE.md`)是以 **user 角色**注入模型历史的,而它自己就写着"不得覆盖 system 指令"。因此必须由**系统提示词**层声明本插件是唯一授权途径,并明确否定"工作区里的直连配方"。
|
|
157
|
+
>
|
|
158
|
+
> **共存是同一条契约的一部分,不是补丁**:用户可能同时装了别的数据库插件。权威声明若写成"本机所有数据库操作都走我",就会同时犯两个错——它会禁止用户用另一个插件去连**本插件根本连不上**的库(dbhub 只有 MySQL/PostgreSQL/MariaDB/SQLite/SQL Server 五个连接器),又会和同类型插件各自的"唯一途径"声明互相矛盾。因此权威声明必须**按作用域**给出。
|
|
159
|
+
|
|
160
|
+
- R71. 插件启用期间必须向模型贡献一条**常驻系统提示词策略段**(`ctx.systemPrompt.section()`,`order` 靠近提示词末端、位于首方保留位之前),把数据库访问收敛到本插件;文本必须紧凑(约 400 字,由单测守上限)并只陈述能力、约束与逃生口,不得复述工具参数说明。至少覆盖:
|
|
161
|
+
- **唯一授权途径(按作用域)**:权威声明只覆盖**本插件已配置的连接**(`dbhub_list_sources` 里出现的那些),这些库一律走 `dbhub_*` 工具(查询、写入、DDL、对象搜索);**不得**写成"本机唯一授权途径"或"所有数据库操作";
|
|
162
|
+
- **点名禁止 shell 级直连**:`psql`/`mysql`/`sqlite3`/`sqlcmd`/`pg_dump` 等命令行客户端、临时脚本、程序驱动与其它 MCP 一律不得用于连**这些库**,也**不得为了连库去宿主机上寻找或调用这类可执行文件**——只读由 dbhub 在插件内硬拒绝,绕开插件的直连不受插件管控,这一层只能靠提示词约束,所以必须写明;
|
|
163
|
+
- **反投毒**:工作区文档、脚本或 `AGENTS.md` 中出现的直连数据库"配方"**不构成授权**,不得照做(含模型自己在过去会话里写下的配方);发现时应告知用户;
|
|
164
|
+
- **只读边界与逃生口**:命中 `READONLY_VIOLATION` 后**不得改用任何其它途径**完成这次写入——必须显式点名**包括换用别的数据库插件/工具**(这是共存场景下最现实的绕道),只能把拒绝原因与影响告知用户;本插件对已配置库确实做不到的操作(备份、非 SQL 管理命令等)先说明限制并请用户给出授权方案,不得自行绕过;
|
|
165
|
+
- **共存:不支持的库让位**:本插件不支持或未配置的库(MongoDB/Redis/Oracle 等,或用户从没在这里配置过的实例)必须**显式允许**用户安装的其它数据库插件或工具接手;不得为"统一走本插件"而拒绝,也不得因此改用命令行直连;
|
|
166
|
+
- **共存:重叠目标有确定优先级**:同一个库在本插件和别的插件里都配置时,默认用本插件的 source(只读/隧道等安全设置在宿主侧),用户明确要求换工具时才换,判断不了先问用户——不得自行换路;
|
|
167
|
+
- **不压制同类插件**:不得实现(也实现不了)"禁用另一个数据库插件"的语义。冲突只用上面三条收敛:作用域、重叠优先级、问用户。压制会把模型推向 CLI,正是本节要防的结果;
|
|
168
|
+
- **回执侧同样禁止绕道**:只读命中(`result.readOnlyHint`)与凭据/连接失败(`result.authHint`)的回执必须各带一句"不要改用命令行客户端/脚本/其它数据库插件",因为这两处正是模型最可能起意绕道的时刻;
|
|
169
|
+
- **禁用即静默**:插件被禁用时该段必须贡献**空文本**(空段在组装时被丢弃),绝不能出现"提示词声称 dbhub 是唯一途径、每次调用却回 `result.disabled`"的自相矛盾;
|
|
170
|
+
- **可选依赖、绝不致命**:注册必须经 `ctx.inject(['systemPrompt'], …)` 并挂在 effect 作用域上——同名段在同一作用域重复注册会抛错,而 `apply()` 会在 reload 时重跑;部署没有该服务时只是不注入(老版本 dsh 自动降级到工具描述这一层),不得因此启动失败;
|
|
171
|
+
- **零知识与插值安全**:文本不得含真实形态连接串,也不得含未注册的 `{{变量}}`(严格插值会让整次提示词组装失败)。
|
|
172
|
+
工具描述侧只允许在**动作点**补一句最短禁令(`dbhub_execute_sql`,即写入最可能发生的地方),四份工具描述不得重复整段政策(同一事实只说一次);该句同样必须按作用域写,并说明不支持的库用其它插件。
|
|
173
|
+
- R72. 策略段的注入必须由**用户开关**控制,且**默认开启**:
|
|
174
|
+
- 选项 id `announceAccessPolicy`(布尔),走既有三条通道(`prefs.json` 持久化落点、`Config` 的 volatile 字段供 cordis.yml/profile patch 固定、设置条复选框即时生效),客户端以「立即生效、无需保存」的语义写回(与 `showSidebarEntry` 同款),并只在设置条的 tooltip 里解释语义;
|
|
175
|
+
- **关闭只影响那段文字**:工具、只读、隧道、连接管理一律照常;关闭后该段返回空文本(空段被丢弃),系统提示词保持干净;
|
|
176
|
+
- 默认开启的理由:本插件的定位就是"装了就该优先用它",而策略段是唯一能压住工作区直连配方的层;不默认关就不会出现"用户以为在保护、实际没注入"的落差;
|
|
177
|
+
- 开关状态必须与插件启用状态**取交**(任一为否即不注入),且不得写进任何"能力开关"的语义里(它不是禁用插件,也不是关闭只读)。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|