dsh-plugin-db-explorer
Verified@hanshu-ai/dsh-plugin-db-explorer · v0.2.0 · MIT · Web UI
DeepSeek Harness plugin for read-only database exploration: schema, table sizes, row counts, column distributions, and inferred table relationships (SQLite, PostgreSQL, MySQL, SQL Server, Oracle). Includes a local SQLite e-commerce demo and a Web GUI page
Install
dsh plugin add @hanshu-ai/dsh-plugin-db-explorer Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Creators
Readme
@hanshu-ai/dsh-plugin-db-explorer
一个面向 DeepSeek Harness(DSH)的只读数据库探索插件。它把数据库目录、表结构、数据分布和表间关联整理成模型可直接推理的 Markdown 报告,并注册为一组 db_* 工具。
支持:
| 数据库 | 驱动 | 额外依赖 | 说明 |
|---|---|---|---|
| SQLite | Node 内置 node:sqlite |
无 | 开发验证目标;支持 dbstat 精确到表和索引的空间统计 |
| PostgreSQL | pg |
pg |
使用 pg_* 系统目录与 information_schema |
| MySQL / MariaDB | mysql2 |
mysql2 |
使用 information_schema |
| SQL Server | mssql |
mssql |
使用 sys.* 目录视图 |
| Oracle | oracledb |
oracledb |
使用 ALL_* 数据字典视图 |
安全边界:插件默认以只读方式打开数据库(SQLite 使用
readOnly,PG/MySQL 设置只读事务),db_query只接受单条SELECT/WITH语句,并拒绝 DML/DDL、事务控制、SELECT ... INTO、FOR UPDATE等。请仍然使用数据库侧的只读账号;SQL 关键字过滤只是纵深防御,不是权限系统。
1. 能力
- 库/表总览:schema、表/视图、行数、数据大小、索引大小、列数。
- 表结构:字段类型、可空性、默认值、主键、唯一键、索引、声明外键。
- 数据画像:每张表的精确行数、空间占用;每个字段的空值率、去重数、最小/最大、数值均值与标准差、P25/P50/P75/P90、直方图、文本长度、Top-K 高频值。
- 关联推测:同时给出
- 数据库声明的外键(置信度 1.0),以及孤儿行比例、父表覆盖率;
- 基于命名、类型、值重叠推测出的隐含关联(如
orders.customer_email → customers.email); - 可直接粘贴到文档中的 Mermaid ER 图。
- 只读 SQL:在确认字段名后执行单条查询,自动截断超长结果。
- 采样可控:小表全量扫描,大表自动采样;所有统计都会明确标记是否采样,避免把估算当成事实。
2. 注册的工具
| 工具 | 作用 | 关键参数 |
|---|---|---|
db_connections |
列出配置的连接(凭据脱敏);test: true 逐个 ping |
test, url |
db_overview |
表清单 + 行数 + 空间 + 列数;探索起点 | schema, tables, pattern, includeViews, exactCounts |
db_schema |
字段、主键、索引、声明外键 | schema, tables, pattern, includeIndexes |
db_profile |
行数、空间、字段分布、Top-K、分位数、采样行 | schema, tables, sampleSize, topValues, includeSamples |
db_relationships |
已声明 + 推测关联、覆盖率、Mermaid ER 图 | schema, tables, deep, minConfidence, overlapSample, maxPairs |
db_query |
单条只读 SQL | sql, limit |
所有工具都接受:
connection:插件配置中命名的连接;url:临时 DSN,例如postgres://user:pass@host:5432/db、sqlite:demo/ecommerce.db。
推荐调用顺序:
db_overview → db_schema → db_profile → db_relationships → db_query
Web GUI 页面
插件同时声明了 dsh.client,会在 Web 侧边栏注册一个 数据库 入口,主面板提供五个页签:
- 总览:表/视图、行数、空间、列数,点击行直接跳到该表结构;
- 结构:字段、主键、唯一键、索引、声明外键;
- 数据画像:每列空值率/去重数/min/max/均值/分位数/Top-K,带简单占比条;
- 关联:声明外键、推测关联、覆盖率/孤儿率、Mermaid ER 图(可复制);
- SQL:只读查询编辑器与结果表。
页面通过 Host 的 dbExplorer Remote 服务调用同一个 engine.js,因此和模型工具共享只读守卫、采样策略和连接配置。连接下拉框来自 db_connections,也可以直接在“临时 URL”里输入 DSN。
页面是浏览器插件:已经运行的
dsh web需要重启一次(或重新启动桌面端),客户端模块元数据才会重新扫描并加载新的dsh.client声明。重启后在左侧边栏底部/面板列表中看到“数据库”。
3. 快速开始(本仓库的 SQLite 电商库)
仓库自带一个可复现的电商示例库:客户、地址、商品、分类、仓库、库存、订单、订单明细、交易、发货、评价。
# 进入本仓库目录(替换成你的实际路径)
cd /path/to/dsh-plugin-db-explorer
# 1) 重新生成 demo/ecommerce.db(确定性数据)
npm run seed
# 2) 安装到当前 DSH web profile(本地路径安装)
dsh plugin --profile web add "$PWD"
# 3) 在 profile 配置中登记连接
# ~/.dsh/profiles/web/cordis.patch.yml
在 cordis.patch.yml 末尾加入:
- id: db-explorer
config:
defaultConnection: demo
connections:
demo:
driver: sqlite
# 绝对路径(推荐,替换成你的仓库路径)
url: /path/to/dsh-plugin-db-explorer/demo/ecommerce.db
# 如果 DSH 的 session workspace 就是本仓库根目录,也可以写相对路径:
# url: demo/ecommerce.db
如果 DSH 启用了 HMR,配置会热加载;否则重启 dsh web。安装本身也可以直接在 Web 的 Plugins 页面完成:选择本地路径或包名,安装后启用 @hanshu-ai/dsh-plugin-db-explorer bundle,再在 profile patch 中加连接配置。
侧边栏的“数据库”页面属于浏览器插件:首次安装/升级后需要重启一次
dsh web,客户端模块才会重新扫描dsh.client并加载页面;模型工具和 Host Remote 不受影响。
然后可以直接对模型说:
用 db_overview 看一下 demo 库,列出最大的五张表;用 db_profile 分析 orders 的 status 和 total_amount;用 db_relationships 看看订单和客户、商品之间有哪些关联,并给出 Mermaid ER 图。
示例输出
db_overview:
| Schema | Table | Type | Rows | Size | Cols |
| main | order_items | table | 2,213 | 148 KiB | 7 |
| main | orders | table | 900 | 156 KiB | 9 |
| main | transactions | table | 950 | 116 KiB | 9 |
db_profile:
## main.products — 88 rows, 28.0 KiB (scanned all 88 rows)
| Column | Type | Nulls | Distinct | Min | Max | Mean ± SD | Top values |
| price | NUMERIC | 0 (0%) | 88 (100%) | 14.01 | 2135.42 | 337.97 ± 465.39 | ... |
Numeric quantiles:
- price: p25=... p50=... p75=... p90=...
db_relationships:
## Declared foreign keys
- orders.customer_id → customers.customer_id (N:1) · orphan rows 0% · parent coverage 92.2%
## Inferred relationships
- orders.customer_email → customers.email (N:1) · score 0.99 (high) · child coverage 100% · parent coverage 92.2%
- order_items.product_sku → products.sku (N:1) · score 1 (high)
- inventory.warehouse_code → warehouses.code (N:1) · score 1 (high)
- transactions.customer_id → customers.customer_id (N:1) · score 0.99 (high)
## Mermaid ER diagram
```mermaid
erDiagram
ORDERS ||--o{ ORDER_ITEMS : "order_id"
CUSTOMERS ||--o{ ORDERS : "customer_email"
```
完整示例报告见仓库中的 demo/exploration-report.md。npm 发布包不包含这份生成报告;本地执行 npm run seed && npm run smoke 可以重新生成。
4. 安装与配置
4.1 安装插件
# 本地路径(开发;替换成你的实际仓库路径)
dsh plugin --profile web add /path/to/dsh-plugin-db-explorer
# 或发布到 registry 后
dsh plugin --profile web add @hanshu-ai/dsh-plugin-db-explorer
安装会写入 profile 的 package.json,并把本插件 bundle 追加到 dsh.profile.bundles。插件声明了 dsh.bundle.patch,因此安装后会自动插入 db-explorer 这一行。
4.2 安装非 SQLite 驱动
SQLite 使用 Node 22.5+ 内置的 node:sqlite,无需安装任何包。其他数据库按需安装:
dsh plugin --profile web add pg # PostgreSQL
dsh plugin --profile web add mysql2 # MySQL / MariaDB
dsh plugin --profile web add mssql # SQL Server
dsh plugin --profile web add oracledb # Oracle
这些包被插件在真正用到对应驱动时才动态 import();没有安装时只有该驱动报出明确的安装提示,不影响 SQLite 使用。
4.3 配置参考
- id: db-explorer
config:
# 工具调用省略 connection/url 时使用哪个命名连接
defaultConnection: shop
connections:
# SQLite:路径可以是绝对路径,或相对当前 session workspace 的路径
shop:
driver: sqlite
url: /data/shop.db
analytics:
driver: postgres
url: postgres://reader:${PG_PASSWORD}@db.internal:5432/analytics?sslmode=require&schema=public
legacy:
driver: mysql
host: mysql.internal
port: 3306
database: legacy
user: readonly
passwordEnv: MYSQL_PASSWORD
ssl: false
warehouse:
driver: sqlserver
host: mssql.internal
port: 1433
database: warehouse
user: readonly
passwordEnv: MSSQL_PASSWORD
ssl: true
erp:
driver: oracle
host: oracle.internal
port: 1521
database: FREEPDB1 # 作为 service name 拼成 host:port/service
user: READONLY
passwordEnv: ORACLE_PASSWORD
schema: ERP
# 资源与安全上限
maxRows: 500 # db_query / 显式 sample 的行数上限
maxTables: 200 # 多表工具最多处理多少张表
maxColumnsPerTable: 80 # 单表画像最多分析多少列
profileRows: 20000 # 小表全量扫描阈值
autoSampleRows: 5000 # 超过阈值时的默认采样行数
topValues: 10 # 每列 Top-K
relationshipPairs: 150 # 关系推测最多评估多少对候选
overlapRows: 5000 # 值重叠检查每侧最多读取多少行
minConfidence: 0.45 # 推测关联的最低分
allowQuery: true # 是否允许 db_query
sampleRows: 5 # includeSamples=true 时返回的样本行数
readOnly: true # 尽可能以只读句柄打开
4.4 连接 URL 格式
| 驱动 | 示例 |
|---|---|
| SQLite | sqlite:/abs/path/shop.db、sqlite:demo/ecommerce.db、sqlite::memory: |
| PostgreSQL | postgres://user:pass@host:5432/db?sslmode=require&schema=public |
| MySQL | mysql://user:pass@host:3306/db |
| SQL Server | mssql://user:pass@host:1433/db |
| Oracle | oracle://user:pass@host:1521/FREEPDB1 |
字符串里的 ${ENV_VAR} 会在连接时展开;也可以对密码使用 passwordEnv 指向环境变量。错误信息中会替换掉密码和 URL 中的凭据。
5. 关系推测是怎么做的
db_relationships 同时做两件事:
5.1 已声明外键
从各数据库的目录读取外键,置信度固定为 1。对单列外键还会计算:
orphanRate:子表中找不到父记录的行占比;childCoverage/parentCoverage:子表值命中的比例、父表键被引用的比例;cardinality:子表列是主键/唯一键时为1:1,否则为N:1。
这些数字能直接暴露“数据质量”问题,例如订单引用了不存在的客户。
5.2 隐含关联
对每个“子表列 × 父表单列主键/唯一键”候选:
- 命名证据(0 ~ 0.5)
orders.customer_id→customers.customer_id:前缀customer匹配customers的单数形式,且目标是主键;orders.customer_email→customers.email:前缀匹配表名,后缀匹配目标列;order_items.product_sku→products.sku;inventory.warehouse_code→warehouses.code;- 同一列名也只给较低权重,避免把每个
id都连到每个id。
- 类型兼容(0.1):数值 / 字符串 / 日期 / 布尔 / 二进制 家族必须一致。
- 值重叠(0.4):对两侧各采样最多
overlapRows行,计算子表去重值覆盖率、父表键覆盖率。
score = nameScore + 0.1 (类型) + 0.3 × 子表去重覆盖率 + 0.1 × 父表覆盖率
score ≥ minConfidence 的候选进入结果,并标为 low / medium / high。
- 默认只评估有命名证据的候选,避免在大库上做 N×N 全量两两比较;
deep: true会评估所有类型兼容的组合,仍受maxPairs限制;- 大表上
overlapRows是采样,父表覆盖率是近似值; - 推断结果不是数据库约束,只是探索线索,写业务逻辑前应人工确认。
6. Demo 数据库
demo/schema.sql + demo/seed.mjs 会生成确定性的电商库:
| 表 | 行数 | 说明 |
|---|---|---|
customers |
320 | 客户与会员等级 |
addresses |
496 | 客户地址 |
categories |
32 | 两级分类(自关联) |
products |
88 | 商品、SKU、价格、成本、状态 |
warehouses |
4 | 仓库 |
inventory |
258 | 商品 × 仓库库存 |
orders |
900 | 订单(7 种状态、4 种渠道) |
order_items |
2,213 | 订单明细(折扣、数量、单价) |
transactions |
950 | 支付/退款/拒付 |
shipments |
643 | 发货与签收 |
reviews |
248 | 商品评价 |
数据库中特意放了四条没有声明外键的冗余列,用来验证关系推测:
orders.customer_email→customers.emailorder_items.product_sku→products.skuinventory.warehouse_code→warehouses.codetransactions.customer_id→customers.customer_id
重新生成:
npm run seed
# 或指定目标文件
node demo/seed.mjs /tmp/shop.db
7. 开发与验证
# 进入本仓库目录(替换成你的实际路径)
cd /path/to/dsh-plugin-db-explorer
npm run setup:dev # 仅为脱离 DSH profile 运行 test/smoke 建立最小依赖符号链接
npm test # 26 个单元 + 集成 + 客户端/Remote 测试(会先重新 seed demo 库)
npm run smoke # 直接调用 engine 探索 demo 库,生成 demo/exploration-report.md
npm run verify # seed + test + smoke
测试重点:
- 五种 URL 解析、环境变量、密码脱敏、连接选择错误提示;
- SQL 只读守卫(多语句、DML/DDL、
SELECT INTO、FOR UPDATE、字符串里的关键字); - 标识符引用、类型家族、值归一化、分布统计与分位数;
- 命名证据和单数化规则;
- 通过伪造 Cordis context 注册真实
defineTool工具并逐个执行; - 总览行数/空间、表结构、画像采样、声明外键、四条隐含关联、Mermaid、查询行数上限;
- 客户端 bundle 的模块注册、Remote 贡献、
main/sidebar.panellist槽位和 React 渲染冒烟。
本仓库只在 SQLite 上做了端到端验证。其他四个驱动按各数据库系统目录实现,未在本机连接真实服务器执行;首次接入时建议先用
db_connections({test:true})和db_overview验证权限与系统目录版本。建议版本:PostgreSQL 12+、MySQL 8.0+ / MariaDB 10.5+、SQL Server 2017+(STRING_AGG)、Oracle 12c+(FETCH FIRST)。
8. 目录结构
.
├── lib/
│ ├── index.js # DSH 插件入口:Config、defineTool 注册、system prompt
│ ├── remote.js # Host Remote 服务 dbExplorer(Web 页面调用入口)
│ ├── client.js # Web 客户端:侧边栏入口 + 数据库探索页面
│ ├── engine.js # 无 DSH 依赖的探索引擎(总览/结构/画像/关系/查询)
│ ├── config.js # 配置归一化、URL 解析、连接选择、凭据脱敏
│ ├── sql.js # 标识符/字面量引用、只读 SQL 守卫、LIMIT 包装
│ ├── stats.js # 分布、分位数、直方图、字节/数字格式化
│ ├── values.js # 类型分类与 JSON 安全的值归一化
│ ├── render.js # 面向模型的 Markdown 渲染
│ └── drivers/
│ ├── index.js # 懒加载驱动
│ ├── sqlite.js # node:sqlite + dbstat
│ ├── postgres.js # pg
│ ├── mysql.js # mysql2/promise
│ ├── sqlserver.js # mssql
│ └── oracle.js # oracledb
├── demo/
│ ├── schema.sql # 电商 schema
│ ├── seed.mjs # 确定性造数
│ ├── ecommerce.db # 生成物
│ └── exploration-report.md
├── scripts/
│ ├── setup-dev.mjs # 测试用最小依赖链接
│ └── smoke.mjs # 独立 engine 冒烟与报告
├── test/
│ ├── unit.test.mjs
│ ├── integration.test.mjs
│ ├── client.test.mjs
│ └── helpers.mjs
├── examples/
│ └── cordis.patch.example.yml
├── cordis.patch.yml # bundle patch(插入 db-explorer 行)
└── package.json
9. 安全与限制
- 只读:SQLite
readOnly句柄;PostgreSQL 会话default_transaction_read_only=on;MySQL 会话只读事务;db_query拒绝写语句。SQL Server / Oracle 没有通用会话级只读开关,依赖 SQL 守卫 + 只读账号。 - Web 页面权限:页面通过 DSH 已认证的 Remote 通道访问 Host,不额外开放端口;能打开该 DSH Web UI 的用户即可对已配置连接执行同样的只读探索。
- 行数上限:
db_query默认 500 行;db_profile小表全量、大表采样;关系值重叠默认每侧 5000 行。 - 标识符引用:所有 schema/table/column 都按方言引用(
"..."/`...`/[...]),避免目录名中的特殊字符破坏 SQL。 - 错误脱敏:报错信息会移除密码和 URL 凭据。
- 不生成写操作:插件没有写入工具,也不会自动创建索引或统计信息。
- 采样不是精确值:
sampled: true/scannedRows会明确展示;distinct在采样表上是下界估计。 - Oracle/SQL Server 权限:部分系统目录(如
ALL_SEGMENTS、sys.dm_db_partition_stats)可能因账号权限不可见;插件会回退到ALL_TABLES.BLOCKS * 8192等估算并给出sizeSource。 - Node 版本:SQLite 依赖
node:sqlite,需要 Node 22.5+;Node 22 会打印ExperimentalWarning: SQLite is an experimental feature,不影响功能。 - SQL Server:
STRING_AGG需要 2017+;更早版本索引列会为空但不影响其他功能。 - Oracle:分位数/关系查询使用 12c+ 语法;
db_query直接执行用户 SQL 并设置maxRows,不包裹内联视图。
10. License
MIT。非 SQLite 驱动通过动态 import() 使用 pg、mysql2、mssql、oracledb,它们各自遵循自己的许可证;本包不把它们作为强制依赖打包。