dsh-tool-database
souleymoni1/dsh-tool-database
DeepSeek Harness 数据库插件:SQL Server / PostgreSQL / MySQL 查询与执行,内置数据库面板
インストール
dsh plugin --profile web add github:souleymoni1/dsh-tool-databaseREADME
dsh-tool-database
DSH(DeepSeek Harness)数据库插件:一套 db_* 工具同时连 SQL Server / PostgreSQL / MySQL,
模型直接读(可选写)你配置的库,不经过 MCP、不起子进程;左侧栏「数据库」面板负责管连接、跑 SQL、看结果。
支持的引擎
| 引擎 | engine | 驱动 | 默认端口 | DSN 前缀 |
|---|---|---|---|---|
| SQL Server | sqlserver(默认,兼容老清单) | mssql(tedious) | 1433 | sqlserver:// / mssql:// / tds:// |
| PostgreSQL | postgres | pg | 5432 | postgres:// / postgresql:// / pg:// |
| MySQL / MariaDB | mysql | mysql2 | 3306 | mysql:// |
每个源独立选引擎;同一个插件里可以同时放 SQL Server 生产库、PostgreSQL 报表库、MySQL 业务库。
注册工具
| 工具 | 功能 |
|---|---|
db_sources | 列出已配置的源(id / 引擎 / 主机 / 端口 / 库 / 账号 / 是否可写),可 probe: true 实测连通性 |
db_databases | 列出该实例上的数据库(SQL Server sys.databases / PostgreSQL pg_database / MySQL SHOW DATABASES) |
db_tables | 列出表与视图(schema / 类型 / 行数估算),支持 schema / filter 过滤 |
db_schema | 单表列结构:类型(带长度精度)/ 可空 / 自增 / 主键 / 默认值 |
db_query | 只读查询,支持多条语句(逐条执行、各自成一个结果集),参数绑定只对单条生效;page + limit 控制翻页(limit = 每页行数),返回 { statements: [{ columns, rows, page, pageSize, hasNext, paged, elapsedMs }] } |
db_execute | 写通道,需源开启 writable 且显式 allowWrite: true;DDL 另需 allowDdl |
省 token 工作流:
db_sources→db_tables filter:→db_schema→db_query。先看结构再取数,避免SELECT *全表灌进上下文。
参数占位按引擎走:SQL Server 用 @p0, @p1 …;PostgreSQL 用 $1, $2 …;MySQL 用 ?,值都放 params 数组。
左侧栏「数据库」面板(0.2.1 起在左侧栏,0.2.0 曾在会话标签页)
左侧栏全局面板区多一个 数据库(挨着「插件 / 自动化任务」),点开就是:
- 左栏:连接列表(搜索、类型标签、引擎徽标、可写标记,宽窄可用中间分隔条左右拖动,宽度记在浏览器本地),点一条即在右侧打开;
- 右栏 · 查询:多页签 SQL 编辑器(语法高亮 / 关键字与字段补全 / 页签与历史,见下节)+ 「执行」(Ctrl / Cmd + Enter),结果表格显示列名、行数、耗时,超限标「已截断」,状态行右侧一键复制整表;
- 右栏 · 连接表单:新建 / 编辑连接用表单填(引擎、类型、主机、端口、库、账号、密码、TLS、可写、允许 DDL), 「测试连接」当场试连;密码框右侧的眼睛可以显示/隐藏密码(编辑已有连接时会把本机保存的密码读回框里,点眼睛就能看到原值);连接字符串收在「高级」里,不想填字段时再展开。



展开「高级」可以直接贴连接字符串(填了它就忽略上面的主机表单):

类型与分组(0.3.0)
每个连接有一个类型,只有三档:开发 / 测试 / 正式(stage: dev | test | prod)。
- 搜索框下面有 不分组 / 按类型分组 两个单选项,选择会记在浏览器本地,下次打开还是这个状态;
- 列表每条右侧靠右排列,从右往左依次是 类型 / 数据库(引擎)/ 可写;默认按**别名(id)**排序,开了分组就先按类型(开发 → 测试 → 正式),组内再按别名排序,空分组不显示;
- 老清单(没有 stage)读进来时按别名 / 描述 / 库名推断:含 DEV 记开发,含 TEST / QA / UAT / STAGING 记测试,其余记正式; 保存任意一条连接时,推断结果会作为 stage 写回清单固定下来,之后以清单为准。

查询页签(0.3.4 起)
每个连接下面可以开多个查询页签,互相独立,页签和 SQL 都自动保存在本机($DSH_HOME/database-tool/queries.json,和 sources.json 放一起):
| 操作 | 说明 |
|---|---|
+ | 新建一个空白查询页签 |
| 点页签 | 切到这个页签(切之前会把当前输入落盘) |
页签上的 × | 关闭页签:不删数据,进「历史页签」 |
| 历史页签 | 下拉列出关闭过的页签(标题 + SQL 前 60 字),点一条原样恢复;右侧 × 才是彻底删除 |
| 双击页签标题 | 就地改名(回车确认、Esc 取消、清空恢复按 SQL 自动命名),改名后的页签不再被 SQL 首行覆盖;重命名也会存进 queries.json(named: true) |
| 编辑器 / 结果之间的分隔条 | 上下拖动调整两块高度(90px ~ 底部留 170px),拖完记住位置(localStorage: dbx-editor-height),下次打开还是这个比例 |
页签标题取 SQL 第一行有效内容(去掉 -- 注释、超过 28 字截断),没写内容时显示「查询」。输入停顿 700ms 自动保存,关窗口/重启 DSH 后页签原样回来。
{
"version": 1,
"sources": {
"local_dev": [
{ "id": "qmw94f2z6ips3", "title": "SELECT TOP 5 name FROM sys…", "sql": "SELECT TOP 5 name FROM sys.databases", "updatedAt": 1794220272601, "closed": false, "named": false }
]
}
}
页签按连接(source id)分开存,切到别的连接看到的是它自己的页签。
编辑器和结果共用一块区域,中间的分隔条可以上下拖动;结果的行数/耗时靠右、复制按钮靠左,都贴在结果表格下方。
SQL 控制台(0.3.4 起,0.3.5 加多语句 / 分页 / 序号 / 列宽 / 执行选中)
输入框是「高亮层 + 透明 textarea」叠出来的,所以既有语法着色,又是原生输入(光标、选中、输入法、撤销都正常):
| 能力 | 说明 |
|---|---|
| 语法高亮 | 关键字 / 字符串 / 数字 / 注释四种颜色;两层字体度量锁死,光标与选中位置和看到的字严格对齐 |
| 补全 | 关键字 + 当前库的表名 + 当前表(FROM / JOIN 后面那张)的字段名,字段排最前并标「字段」、表名标「表」;输入 1~2 个字符自动弹,Ctrl + 空格 强制弹,↑ ↓ 选、Enter / Tab 确认、Esc 关闭,列表跟随光标并自动翻页;别名. 之后直接列该表字段 |
| 复制结果 | 结果表格左下角复制图标,导出 TSV(含表头),粘到 Excel 直接分列;行数与耗时放在右下角 |
| 多语句 | 一个输入框里写多条语句,按顺序逐条执行,每条一个结果集;没写分号也能识别(换行后以 SELECT/UPDATE/INSERT/… 开头即视为新语句,; 和单独一行 GO 同样支持);结果区上方出现「结果 1 / 结果 2 / 执行 3」切换条,查询和写可混在一个脚本里 |
| 行号 | 结果表第一列固定是 # 序号(跟着翻页连续编号:第 2 页从 101 开始),列宽压到 34px;复制 TSV 也带这一列 |
| 列宽 | 表头右侧边缘可左右拖动调列宽,# 列不参与;同样几列的结果重跑会沿用上次拖出来的宽度(刷新页面重置),列总宽超出时表格横向滚动 |
| 分页 | 结果不再截断:默认每页 100 行;上一页 / 下一页、第 N 页 · 行数 · 耗时、50/100/200/500 行/页 都在结果区右下角同一行;翻页由引擎自己拼 OFFSET/FETCH(PostgreSQL / MySQL 拼 LIMIT/OFFSET),不会把整表拉回内存 |
| 执行选中 | 在编辑器里选中一段 SQL,右上角按钮变成「执行已选择」,只跑选中的那一段(Ctrl / Cmd + Enter 同样只跑选中);取消选中又变回「执行」 |
| 快捷键 | Ctrl / Cmd + Enter 执行(有选中就只跑选中),Tab 缩进两格 |
结果表格高度跟随窗口剩余空间、只在自己区域内滚动,页面不会整体滚动;表头 13px 加粗淡灰底并吸顶,数据 12px。 设置页里只留「数据库连接」一节:控制台的写策略与默认行数。

所有改动都写回宿主侧清单文件(临时文件 + rename),宿主按 mtime 热加载,不用重启。
安装
已发布到 npm:dsh-tool-database(源码仓库:https://github.com/SouleyMoni1/dsh-tool-database )。
Web profile
dsh plugin --profile web add dsh-tool-database@0.3.5
建议带上显式版本号:npm 上还留着一个早期占位版本
0.0.0-stage(tarball 已损坏,删不掉), 不带版本号时 pnpm 有机会解析到它并报ERR_PNPM_TARBALL_EXTRACT。
桌面端(desktop profile,由 Electron 应用独占管理)
dsh plugin --profile desktop ... 会被 CLI 直接拒绝:
profile "desktop" is managed exclusively by the Electron application。
桌面端要么走市场面板装 npm 上的包,要么手工做一遍 CLI 的等价操作:
~/.dsh/profiles/desktop/package.json的dependencies加"dsh-tool-database": "^0.3.5";- 同一文件的
dsh.profile.bundles数组加"dsh-tool-database"; - 在 profile 目录里用与该 profile 同大版本的 pnpm 执行安装,然后重启 DSH:
桌面 profile 当前是 pnpm
11.28.5(store 在~/AppData/Local/pnpm/store/v11), 用 v10 会报 “node_modules was installed with a different major version of pnpm”, 直接cd ~/.dsh/profiles/desktop && npx --yes pnpm@11.28.5 add dsh-tool-database@0.3.5最稳。
装完重启 DSH:6 个工具、侧栏面板、设置页标签都要重启后才出现(sources.json 的改动不用重启)。
从 dsh-tool-mssql 升级
旧的 dsh-tool-mssql 与新的 dsh-tool-database 不要同时装(会同时出现 mssql_* 和 db_* 两套工具):
dsh plugin --profile web remove dsh-tool-mssql
dsh plugin --profile web add dsh-tool-database
首次启动会自动把 $DSH_HOME/mssql-tool/sources.json 复制到 $DSH_HOME/database-tool/sources.json
(只复制不删除,老清单留着随时回退);老字段 server 仍然认,缺省引擎按 sqlserver 处理。
关于入口 shim(为什么以前装进 profile 会 failed to import)
DSH 0.2.x 的 profile 层解析器(@deepseek-ai/dsh-app-boot 的 ResolutionRouter.routeScoped)
把 require('process/') 归一成裸名 process 后直接
for (const p of createRequire(parent).resolve.paths(name));Node 对内建模块名返回 null,
这段没有 ?? [] 兜底,于是抛 TypeError: createRequire.resolve.paths is not a function or its return value is not iterable。
各数据库驱动的 CJS 依赖链里都有这种写法,插件会在 import 阶段失败,启动日志只有一行
failed to import。
0.1.1 起入口改为 lib/boot.js:先加载一小段 shim,把内建模块请求直接短路(解析结果与 Node 原生一致),
再动态 import 真正实现,因此正常装进 profile 即可。宿主修好这段解析代码后,这层 shim 可以删掉。
本地目录安装(开发调试,改代码即时生效)
link: 的目标是相对 profile 目录解析的:跨盘符直接写 link:F:\... 会生成坏联接。
先在 ~/.dsh/profiles 下建一个指向仓库的目录联接,各 profile 都用相对路径引用:
mkdir "%USERPROFILE%\.dsh\profiles\.local-links"
mklink /J "%USERPROFILE%\.dsh\profiles\.local-links\dsh-tool-database" "F:\EdenOS\AI\DSH插件\dsh-tool-mssql"
link: 不跑 prepack,装之前先 npm run build 出 lib/。
dsh plugin --profile web add "link:../.local-links/dsh-tool-database"
配置
源清单两种配法,config.sources 非空时优先:
方式一:插件 config(profile 的 cordis.patch.yml)
- insert:
- id: tool-database
name: 'dsh-tool-database'
config:
defaultSource: erp_prod
sources:
- id: erp_prod
engine: sqlserver
stage: prod
description: 【正式·只读】db.example.com/demo_erp
host: db.example.com
port: 1433
database: demo_erp
user: reader
passwordEnv: MSSQL_PROD_PW
writable: false
- id: pg_report
engine: postgres
stage: test
description: 【报表】pg.internal/report
host: pg.internal
database: report
user: readonly
passwordEnv: PG_REPORT_PW
ssl: true
方式二:独立 JSON 文件(推荐,改完即时生效)
$DSH_HOME/database-tool/sources.json(默认 C:\Users\<你>\.dsh\database-tool\sources.json):
[
{
"id": "erp_prod",
"engine": "sqlserver",
"stage": "prod",
"description": "【正式·只读】db.example.com/demo_erp",
"host": "db.example.com",
"port": 1433,
"database": "demo_erp",
"user": "reader",
"passwordEnv": "MSSQL_PROD_PW",
"writable": false
},
{
"id": "mysql_shop",
"engine": "mysql",
"stage": "test",
"host": "10.0.0.9",
"port": 3306,
"database": "shop",
"user": "reader",
"password": "仅本机可见的明文密码",
"writable": false
}
]
文件按 mtime 热加载:改完不用重启,下一次工具调用即生效。插件启动时若清单文件不存在也不报错,只是没有可用源。 日常维护直接用左侧栏的「数据库」面板,不用手写 JSON。
字段
| 字段 | 必填 | 说明 |
|---|---|---|
id | ✅ | 源句柄,模型用它在各工具里选库;清单内不可重复 |
engine | sqlserver(默认)/ postgres / mysql | |
stage | 类型:dev 开发 / test 测试 / prod 正式(默认;不写时按别名推断,见「类型与分组」) | |
host | ✅ | 主机名或 IP(老字段名 server 仍然认) |
port | 默认按引擎:1433 / 5432 / 3306 | |
database | 默认库;不填则由账号默认库决定(MySQL 建议填) | |
user | 登录名 | |
passwordEnv | 推荐:环境变量名,密码从 process.env 取 | |
password | 备选:明文写在配置里(仍只在宿主侧,但会落盘) | |
writable | 默认 false。只有 true 才允许 db_execute | |
allowDdl | 默认 false。允许 CREATE/ALTER/DROP/TRUNCATE | |
allowBatch | 默认 true。写通道允许分号分隔的批量语句;显式 false 锁成单条 | |
ssl | 默认 false。PostgreSQL / MySQL 走 TLS;SQL Server 等价于 encrypt | |
encrypt | SQL Server 专用;ssl: true 会一起打开 | |
trustServerCertificate | 默认 true;云库用自签证书时保留 true | |
requestTimeoutMs | 单语句超时,默认 15000 |
密码用环境变量时要让 DSH 进程能读到(桌面端可在启动前设置系统环境变量,或改用 password)。
控制台写策略
侧栏「数据库」面板里跑 SQL 时,写语句受两层控制:
- 控制台写策略(设置 → 数据库连接,或
$DSH_HOME/database-tool/config.json的writeMode):source(默认):跟随数据源的writable/allowDdl;readonly:一律只读,写语句直接拒绝(排查时最稳);always:允许写(仍然要过单语句 / 提权关键字检查)。
- 数据源开关:源的
writable、allowDdl、allowBatch。
模型工具 db_execute 不受 writeMode 影响(它有自己的 writable + allowWrite 双闸门),
控制台策略只约束人在界面里敲的 SQL。
安全模型
- 只读白名单:只读通道仅放行以
SELECT/WITH/VALUES开头的语句; - 危险词拦截:
SELECT ... INTO、EXEC、OPENROWSET、DBCC、WAITFOR、DDL/DML 关键字直接拒绝 (判定前先剥离字符串、注释与[]/""/ 反引号标识符,不会误伤字面量里的关键字); - 逐条校验:
;分隔的多条语句会先逐条过白名单 / 禁词 / 类别判定,任意一条不合规整段拒绝(不会只看第一条);查询和写可以混在一个脚本里,写语句照样受writable/writeMode/allowDdl约束; - 写通道双闸门:源必须
writable: true,调用方还要显式allowWrite: true;DDL 另需源开启allowDdl;xp_*/OPENROWSET/BACKUP/GRANT等提权关键字一律拒绝; - 参数绑定:
db_query/db_execute用引擎各自的占位符 +params数组绑定,不做字符串拼接; - 输出预算:默认 100 行、硬上限 500 行,超限明确标注
truncated; - 凭据边界:
db_sources只输出「是否已配密码」,不含密码、不含passwordEnv的取值、不含完整连接串; 设置页列表里的 DSN 恒为******,只有本机同源、经 DSH 会话鉴权的编辑表单才拿得到明文回填。
使用示例
db_sources probe: true
db_tables source: "prod_WMS" filter: "Order"
db_schema source: "prod_WMS" table: "dbo.Sys_Log"
db_query source: "prod_WMS" sql: "SELECT TOP 10 Url, CreateTime FROM Sys_Log WHERE CreateTime >= @p0 ORDER BY CreateTime DESC" params: ["2026-01-01"]
db_query source: "pg_report" sql: "SELECT * FROM orders WHERE created_at >= $1 LIMIT 20" params: ["2026-01-01"]
db_query source: "mysql_shop" sql: "SELECT id, name FROM goods WHERE id = ?" params: [42]
开发
npm install
npm run check # typecheck + vitest + tsc 构建
src/core.ts—— 纯函数:引擎元数据、源清单校验、类型格式化、凭据解析、路径约定;src/sql-guard.ts—— 方言无关的 SQL 护栏(白名单 / 单语句 / 写闸门 / 提权禁词,全部可单测);src/engines/{sqlserver,postgres,mysql}.ts—— 各引擎适配器(连接、查询、写、元数据);src/pool.ts—— 连接池缓存与统一执行层;src/dsn.ts—— 连接字符串 ⇄ 源配置(三种 scheme + ADO 写法 + 掩码);src/settings-store.ts——sources.json/config.json的原子读写、增删改、老清单迁移;src/index.ts—— 插件入口,注册 6 个工具;src/settings-rpc.ts—— 面板 / 设置页的宿主侧 RPC(sources/*+query/run+console/save);client/client.js—— 浏览器侧单文件客户端(侧栏面板 + 设置页节,无构建步骤);tests/—— vitest:SQL 守卫、清单校验、连接字符串、控制台配置、迁移。
已知限制
- 批量写不开事务:多条写语句按顺序逐条提交,中途报错前面的不会回滚(需要原子性请自己包
BEGIN TRAN / COMMIT); - 无分号切分是启发式:按「行首语句关键字」判断新语句,括号未闭合 / 上一行以逗号、运算符、
UNION结尾时不会切;复杂脚本建议写;; - TOP / DISTINCT / UNION 不能翻页:这几种语句拼不了
OFFSET,只显示当前页并提示原因,加WHERE或改写后再取; - 翻页顺序:语句本身没写
ORDER BY时补的是ORDER BY (SELECT NULL),只保证取到不同行,不保证跨页稳定顺序,介意就自己写ORDER BY; - 元数据查询依赖各引擎的系统目录视图,账号若无元数据可见性权限会返回空列表;
- 连接池按「引擎 + 源 id + 主机 + 端口 + 库 + 账号」缓存,改这几项后要重启 DSH 才换池
(改
sources.json的密码/开关不影响已建立的池); ssl: false时流量不加密,跨公网请打开 TLS。
许可
MIT