@nsyan/db 1.0.0 → 1.2.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/README.md CHANGED
@@ -2,125 +2,100 @@
2
2
 
3
3
  # db
4
4
 
5
- **AI 接入数据库插件 —— 方言化架构,原生 Node.js 实现,无需 Python**
5
+ **AI 接入数据库插件 —— 方言化架构,原生 Node.js 实现**
6
6
 
7
- 支持关系型 / KV / 搜索 / 大数据四大家族,共 8 种数据库的查询、表结构浏览与项目配置扫描建连。
8
-
9
- ![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)
7
+ [![npm](https://img.shields.io/npm/v/@nsyan/db?color=blue)](https://www.npmjs.com/package/@nsyan/db)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](../../LICENSE)
10
9
 
11
10
  </div>
12
11
 
12
+ 为 [pi](https://github.com/earendilofficial/pi) 提供 10 种数据库的查询、表结构浏览、扫描建连与安全管控:AI 通过 5 个工具读写数据库,用户通过 `/db` 菜单管理连接。
13
+
13
14
  ## ✨ 特性
14
15
 
15
- - **方言化架构**:`core/` + `dialects/` pi 运行时依赖,为 MCP server 复用铺路
16
- - **8 种数据库**:PostgreSQL · MySQL · Oracle · 达梦 DM8 · Redis · Elasticsearch · Hive · Spark(Thrift Server)
17
- - **四大家族**:关系型 / KV / 搜索 / 大数据,各有一套共享基类
18
- - **安全强化**:
19
- - 多语句**逐条**检查,`SELECT 1; DROP TABLE x` 无法绕过
20
- - 注释剥离后再匹配,`/* c */ DELETE` 无法绕过
21
- - CTE-DML / `FOR UPDATE` 识别为写操作
22
- - Redis 命令白名单(只读模式放行读命令,`FLUSHALL/CONFIG/SHUTDOWN` 恒拒)
23
- - ES 端点白名单(只读模式放行读端点,`DELETE index` 恒拒)
24
- - **代码扫描建连** `/db scan`:从 Spring 配置 / docker-compose / .env 自动抽取连接候选
25
- - **P0 体验**:一键连接串(自动识别家族)、默认连接(`database` 参数可选)、`list_tables` pattern 过滤、超 50 行结果自动导出 CSV/JSON
16
+ - **10 种数据库 · 6 家族**:PostgreSQL · MySQL · Oracle · 达梦 · Redis · Elasticsearch · MongoDB · Neo4j · Hive · Spark
17
+ - **AI 工具**:查询 / 表结构 / 连接清单 / 扫描建连,读多写少场景的 token 友好输出
18
+ - **扫描建连**:从 Spring / docker-compose / .env 自动抽取连接候选,终端确认后写入
19
+ - **安全模型**:只读模式、写确认 + 执行理由、连接级强制只读、家族白名单、管理命令恒拒
20
+ - **审计**(可选):写操作按天落盘,含理由与完整 SQL
21
+ - **零构建**:TypeScript pi/tsx 直接加载,core/dialects 零 pi 运行时依赖
26
22
 
27
23
  ## 📦 安装
28
24
 
29
25
  ```bash
30
- pi install ./packages/db
26
+ pi install npm:@nsyan/db # npm 安装(推荐)
27
+ pi install ./packages/db # 本仓库开发者
31
28
  ```
32
29
 
33
- > 依赖 `pg` / `mysql2` / `oracledb` / `dmdb` / `ioredis` / `@elastic/elasticsearch` / `es7` / `hive-driver` / `typebox`,`pi install` 自动安装。
34
-
35
30
  ## 🚀 快速开始
36
31
 
37
- ```bash
38
- /db add # 新增连接(一键粘贴连接串,或按家族逐步填写)
39
- /db ls # 列出所有连接
40
- /db scan # 扫描项目源码自动建连
41
- /db config # 查看/修改全局设置
42
- ```
43
-
44
- AI 侧接入后,直接用 `query_database` / `list_tables` / `describe_table` / `scan_project_configs` 四个工具即可。
32
+ 1. `/db add` 粘贴连接串一键建连(支持 `postgresql://` · `jdbc:*` · `redis://` · `mongodb+srv://` · `bolt://`/`neo4j://` · `http://host:9200`)
33
+ 2. 直接让 AI 查询:*「查一下订单表最近 10 条」*
34
+ 3. `/db scan` 从项目源码自动发现数据库连接(密码只在终端补录,不进模型上下文)
45
35
 
46
36
  ## 🗄️ 支持的数据库
47
37
 
48
- | 数据库 | 家族 | 驱动 | 支持版本 | 备注 |
49
- |--------|------|------|---------|------|
50
- | PostgreSQL | 关系型 | `pg` | 9.6 ~ 17 全系 | `statement_timeout` 全版本可用 |
51
- | MySQL | 关系型 | `mysql2` v3 | 5.7 / 8.0 / 8.4 | `max_execution_time` 需 ≥5.7.8,低版本自动忽略(客户端超时仍生效) |
52
- | Oracle | 关系型 | `oracledb`(Thin,零依赖) | ≥12.1 | Thin 模式硬性要求 DB ≥12.1,11g 及以下不支持(会给出版本原因指引);Thick 模式列入后续迭代 |
53
- | 达梦 DM | 关系型 | `dmdb` | DM8 全系;DM9 未验证 | 纯 JS 依赖,macOS/Linux/Windows 可用 |
54
- | Redis | KV | `ioredis` | 2.8 ~ 8.x | `SCAN` 需 ≥2.8;`MEMORY USAGE` 需 ≥4.0,低版本自动跳过;生产库一律 SCAN,禁 `KEYS` |
55
- | Elasticsearch | 搜索 | `@elastic/elasticsearch` v8 + v7(npm 别名 `es7`) | 7.x / 8.x / 更新大版本 | 连接时探测大版本分发对应客户端;未知大版本用最新客户端尝试并给出版本警告 |
56
- | Hive | 大数据 | `hive-driver` | 目标 2.x;4.x 未实测 | HS2 Thrift 协议;无 4.x 环境前声明仅支持 2/3 |
57
- | Spark(Thrift Server) | 大数据 | `hive-driver`(复用) | 2.x ~ 4.x | Hive 同协议栈;Spark Connect(DataFrame/gRPC)不支持 |
58
-
59
- > 版本兼容采用**端点抽测**:每个支持项只实测「最老支持版 + 最新版」两个端点,中间版本声明兼容不实测。
60
-
61
- ## ⚙️ 新增连接
62
-
63
- `/db add` 首问选择「粘贴连接串(一键)」或「逐步填写」。连接串自动识别家族:
64
-
65
- ```
66
- postgresql://user:pass@host:5432/db → PostgreSQL
67
- jdbc:mysql://host:3306/db → MySQL
68
- jdbc:oracle:thin:@//host:1521/svc → Oracle(也支持 SID 形式)
69
- jdbc:dm://host:5236/schema → 达梦
70
- redis://:pass@host:6379/0 → Redis(含 rediss:// TLS)
71
- http://host:9200 → Elasticsearch
72
- jdbc:hive2://host:10000/db → Hive / Spark
73
- ```
74
-
75
- 逐步填写按家族分支:Redis 无账号要求、需库号(dbIndex);ES 账号/密码;其余 URL + 账号 + 密码。
38
+ | 数据库 | 家族 | 支持版本 |
39
+ |--------|------|---------|
40
+ | PostgreSQL | 关系型 | 9.6 ~ 17 |
41
+ | MySQL | 关系型 | 5.7 / 8.0 / 8.4 |
42
+ | Oracle | 关系型 | ≥12.1Thin 零依赖) |
43
+ | 达梦 DM | 关系型 | DM8 全系;DM9 未验证 |
44
+ | Redis | KV | 2.8 ~ 8.x |
45
+ | Elasticsearch | 搜索 | 7.x / 8.x+(自动探测大版本) |
46
+ | MongoDB | 文档 | 已验证 6.0 / 7.0 / 8.0;4.2+ 可用 |
47
+ | Neo4j | | 官方兼容矩阵 4.4 ~ 2025.x;已验证 4.4.29 community |
48
+ | Hive | 大数据 | 2.x / 3.x;4.x 未实测 |
49
+ | Spark(Thrift Server) | 大数据 | 2.x ~ 4.x |
50
+
51
+ > 版本采用**端点抽测**:只实测「最老支持版 + 最新版」,中间版本声明兼容。
52
+
53
+ ## 🧾 sql 参数形态
54
+
55
+ `query_database` 的 `sql` 参数按家族填对应形态:
56
+
57
+ | 家族 | 形态 | 示例 |
58
+ |------|------|------|
59
+ | KV · Redis | 空格分隔命令 | `GET key` / `SCAN 0 MATCH user:*` |
60
+ | 搜索 · ES | JSON DSL | `{"query": {"match_all": {}}}` |
61
+ | 文档 · MongoDB | JSON 命令信封 | `{"find": "users", "filter": {}}` |
62
+ | 图 · Neo4j | Cypher | `MATCH (n:Person) RETURN n LIMIT 10` |
63
+
64
+ 关系型直接填 SQL。各家族示例与实现要点 → [docs/USAGE.md](./docs/USAGE.md)。
65
+
66
+ ## 🔐 安全模型
67
+
68
+ | 机制 | 行为 |
69
+ |------|------|
70
+ | AI 只读模式 | **默认开**;关闭后允许写 |
71
+ | 写确认 | 写操作弹框展示:理由 + 命令摘要 + SQL |
72
+ | 写执行理由 | AI 必须附 `reason`(动机+影响范围),缺失直接拒绝 |
73
+ | 连接级强制只读 | 标记的连接(如生产库)无视全局开关,永远只读 |
74
+ | 家族白名单 | Redis/ES/Mongo 只读白名单;`DROP`、管理 DDL、服务端 JS、`CALL dbms.*` 恒拒 |
75
+ | 审计日志 | 默认关;`/db config` 开启后写操作按天落盘(完整 SQL,0600) |
76
+ | 凭据 | 配置文件 `0600`;扫描场景密码掩码,不进模型上下文 |
76
77
 
77
- ## 🔎 代码扫描建连 `/db scan`
78
-
79
- 从项目源码自动抽取连接信息(Spring `application*.yml/properties`、`docker-compose.yml`、`.env`、通用 URL 正则):
80
-
81
- ```bash
82
- /db scan # 扫描当前工作目录
83
- /db scan ./backend # 扫描指定子目录(越界拒绝)
84
- ```
85
-
86
- 扫描结果按状态分组:✅ 可直接建 / ✏️ 待补字段 / 🔒 jasypt 加密(只标注不建)/ ⏭️ 同名已存在。逐个确认后才写入配置——**绝不静默建连、绝不静默覆盖**。占位符 `${KEY:default}` 取 default,`${KEY}` 依次查同目录 `.env` → 进程环境变量,缺省在终端追问。
87
-
88
- AI 侧说「连一下这个项目的数据库」等,会调用 `scan_project_configs` 展示**掩码后**的候选(不写盘),建连仍需你在终端确认,密码不进模型上下文。
89
-
90
- ## ⭐ 默认连接
91
-
92
- `/db` → 打开连接 → `⭐ 设为默认`。AI 调用工具时 `database` 参数可省略,缺省走默认连接;未设默认时给出指引。
93
-
94
- ## 💾 查询结果导出
95
-
96
- 查询结果超过 50 行时,完整结果自动导出到 `/tmp`(CSV + JSON 双格式),只返回文件路径。结果达到 `max_rows` 上限截断时有明确标注。
97
-
98
- ## 🔐 安全控制
78
+ ## ⚙️ 设置
99
79
 
100
- - **执行策略同步**:系统提示动态注入当前 AI 只读模式与执行确认设置
101
- - **逐语句检查**:多语句 SQL 逐条检查,注释剥离后再匹配
102
- - **硬限制**:DROP TABLE/DATABASE(关系型/大数据)、`FLUSHALL/FLUSHDB/CONFIG/SHUTDOWN`(Redis)、`DELETE <index>`(ES)
103
- - **只读白名单**:Redis 读命令白名单、ES 读端点白名单
104
- - **确认策略**:不确认 / 写操作确认 / 每次确认;无 UI 环境自动取消
105
- - **手工查询一致**:`/db` 菜单手工执行与 AI 工具使用相同的策略裁决
80
+ `/db config` 修改,每轮注入系统提示:
106
81
 
107
- ## ⚙️ 设置
82
+ | 设置项 | 默认值 |
83
+ |--------|--------|
84
+ | AI 只读模式 | 是 |
85
+ | 执行确认 | 写操作确认 |
86
+ | 最大行数 | 100 |
87
+ | 查询超时 | 30s |
88
+ | 审计日志 | 关 |
108
89
 
109
- 通过 `/db config` 修改,每轮注入系统提示:
90
+ ## 📚 详细文档
110
91
 
111
- | 设置项 | 默认值 | 说明 |
112
- |--------|--------|------|
113
- | AI 只读模式 | 是 | 开启时 AI 只能执行查询;关闭时允许写操作 |
114
- | 执行确认 | 写操作确认 | 不确认 / 写操作确认 / 每次都确认 |
115
- | 最大行数 | 100 | 查询返回的最大行数 |
116
- | 查询超时 | 30s | 单条语句超时(服务端设置失败时客户端兜底) |
92
+ 连接管理(三种建连路径 / 环境标签 / 自动回测)、扫描建连、各家族 sql 详解、审计配置 → **[docs/USAGE.md](./docs/USAGE.md)**
93
+ 更新记录 → [CHANGELOG](../../CHANGELOG.md)
117
94
 
118
95
  ## 📁 开发
119
96
 
120
97
  ```bash
121
- pnpm install
122
- cd packages/db
123
- NODE_ENV=development pnpm test # 运行全部单测(tsx + node:test)
98
+ pnpm install && cd packages/db && pnpm test # tsx + node:test,无构建产物
124
99
  ```
125
100
 
126
101
  ## 📄 许可
package/docs/USAGE.md ADDED
@@ -0,0 +1,138 @@
1
+ # db 使用手册
2
+
3
+ 主 README 是能力速览;本页承接全部使用细节。遇到本文未覆盖的行为,以 `src/` 代码与测试为准。
4
+
5
+ ## 🔗 连接管理
6
+
7
+ ### 新增连接(/db add)
8
+
9
+ 首问三选一:
10
+
11
+ 1. **⚡ 粘贴连接串(一键)**——自动识别家族:
12
+
13
+ ```
14
+ postgresql://user:pass@host:5432/db → PostgreSQL
15
+ jdbc:mysql://host:3306/db → MySQL
16
+ jdbc:oracle:thin:@//host:1521/svc → Oracle(也支持 SID 形式)
17
+ jdbc:dm://host:5236/schema → 达梦
18
+ redis://:pass@host:6379/0 → Redis(含 rediss:// TLS)
19
+ mongodb://user:pass@host:27017/db → MongoDB(含 +srv Atlas 形态)
20
+ bolt://user:pass@host:7687/db → Neo4j(也认 neo4j://、bolt+s(ssc)://、neo4j+s(ssc)://)
21
+ http://host:9200 → Elasticsearch
22
+ jdbc:hive2://host:10000/db → Hive / Spark
23
+ ```
24
+
25
+ 2. **📝 逐步填写**——按家族分支:Redis 无账号要求、需库号(dbIndex);MongoDB 账号可空(本地无认证常见);ES/其余 URL + 账号 + 密码。
26
+
27
+ 3. **📋 从现有复制**——复制现有连接的全部设置(类型/账号/options/环境标签),仅需改名,可选立即编辑。
28
+
29
+ 所有路径在测试连接通过后,会追问「环境标签」(dev/test/prod,可跳过);选 prod 时主动建议开启**强制只读**。
30
+
31
+ ### 编辑与测试
32
+
33
+ - `/db edit` 编辑器支持修改名称/URL/账号/密码/环境标签/强制只读/说明
34
+ - **保存后自动回测**连接,结果即时回显并记录
35
+ - 连接动作菜单含独立「🧪 测试连接」,结果(版本/延迟)写入连接摘要
36
+
37
+ ### 状态摘要与默认连接
38
+
39
+ - 所有连接选择器展示:`名称 [类型] ⭐默认 [prod·强制只读] · 上次使用 2 天前 · 测试 ✓45ms`
40
+ - 最近使用时间与测试结果自动回写,无需手工维护
41
+ - 一级菜单「⚡ 切换默认」选中即切;AI 调用工具时 `database` 参数可省略,缺省走默认连接
42
+
43
+ ### 环境标签与强制只读
44
+
45
+ - 连接可标 `dev / test / prod`,列表与 AI 系统提示均可见
46
+ - `强制只读` 的连接**无视全局只读开关**,永远只接受查询;AI 侧写入会被拒并提示原因
47
+ - 典型用法:全局允许写(开发库随便改),生产库连接强制只读
48
+
49
+ ## 🔎 扫描建连(/db scan)
50
+
51
+ 从项目源码自动抽取连接信息(Spring `application*.yml/properties`、`docker-compose.yml`、`.env`、通用 URL 正则):
52
+
53
+ ```bash
54
+ /db scan # 扫描当前工作目录
55
+ /db scan ./backend # 扫描指定子目录(越界拒绝)
56
+ ```
57
+
58
+ - 结果状态:✅ 可直接建 / ✏️ 待补字段 / 🔒 jasypt 加密(只标注不建)/ ⏭️ 同名已存在
59
+ - **绝不静默建连、绝不静默覆盖**:逐个确认后才写入;占位符 `${KEY:default}` 取 default,`${KEY}` 依次查同目录 `.env` → 进程环境变量
60
+ - AI 侧说「连一下这个项目的数据库」会调用 `scan_project_configs` 展示**掩码后**候选,建连仍需终端确认
61
+
62
+ ## 🧾 各家族 sql 形态详解
63
+
64
+ ### Redis(KV)
65
+
66
+ `sql` 填空格分隔的命令,整体视为一条:
67
+
68
+ ```
69
+ GET mykey
70
+ SCAN 0 MATCH user:* COUNT 100 # 生产库一律 SCAN,禁 KEYS
71
+ HGETALL myhash
72
+ ```
73
+
74
+ 只读白名单:GET/HGETALL/LRANGE/ZRANGE/SCAN/INFO 等;`FLUSHALL/FLUSHDB/CONFIG/SHUTDOWN` 恒拒。`describe_table` 对 key 返回类型/长度/TTL/内存/编码/值预览。
75
+
76
+ ### Elasticsearch(搜索)
77
+
78
+ `sql` 填 JSON DSL(端点信封):
79
+
80
+ ```json
81
+ {"query": {"match_all": {}}}
82
+ {"count": {"query": {"match": {"status": "paid"}}}}
83
+ ```
84
+
85
+ 顶层 key 决定端点:`query/count/mget` → 读;`bulk/delete/update` → 写;未知 key 保守按写。`DELETE <index>` 字符串恒拒。
86
+
87
+ ### MongoDB(文档)
88
+
89
+ `sql` 填 JSON 命令信封(`db.runCommand` 文档形态,单命令一次执行):
90
+
91
+ ```json
92
+ {"find": "users", "filter": {"age": {"$gt": 18}}, "sort": {"created_at": -1}}
93
+ {"count": "users"}
94
+ {"aggregate": "orders", "pipeline": [{"$group": {"_id": "$status", "n": {"$sum": 1}}}]}
95
+ {"insert": "users", "documents": [{"name": "x"}]}
96
+ ```
97
+
98
+ 实现要点:
99
+
100
+ - **limit 注入**:未写 limit 的读命令自动补 `maxRows`(aggregate 自动追加 `$limit` 阶段),超限标 `truncated`
101
+ - **结果拍平**:返回文档拍平为列——顶层字段并集,封顶 50 列,嵌套转 JSON 字符串;`_id` 取 hex
102
+ - **list_tables** → `listCollections`;**describe_table** → `collStats` + 索引 + `$jsonSchema` validator(缺失时采样 ≤100 文档推断字段,非权威 schema)
103
+ - **硬限制**:`drop*`/`create*` 等管理 DDL、服务端 JS(`$where`/`$function`/`$accumulator`)恒拒;aggregate 含 `$out`/`$merge` 按写分类;未知命令保守按写
104
+ - 连接串:`mongodb://` 与 `mongodb+srv://`(SRV 默认 TLS);`authSource` 缺省 `admin`,`replicaSet`/`authMechanism` 等经 options 贯通
105
+
106
+ ### Neo4j(图)
107
+
108
+ `sql` 填 Cypher 原文,支持分号分隔多语句(逐条执行,返回最后一条结果):
109
+
110
+ ```cypher
111
+ MATCH (n:Person) RETURN n LIMIT 10
112
+ MATCH (n:Person)-[r:KNOWS]->(m) WHERE n.age > 18 RETURN n, r, m
113
+ CALL db.labels() YIELD label RETURN label
114
+ SHOW INDEXES
115
+ ```
116
+
117
+ 实现要点:
118
+
119
+ - **图结构即表**:`list_tables` 返回 node label(NODE LABEL)与关系类型(RELATIONSHIP,`rel:` 前缀);`describe_table` 目标填 label 名或 `rel:类型`
120
+ - **describe_table**:实体计数 + `SHOW INDEXES/CONSTRAINTS`(过滤目标)+ 采样 ≤100 推断属性键与类型分布(非权威 schema);唯一约束属性标主键;只依赖核心过程,**不依赖 APOC**
121
+ - **读写管控**:CREATE/MERGE/DELETE/DETACH/SET/REMOVE/DROP/FOREACH/LOAD CSV 任意深度出现即按写(`MATCH (n) DETACH DELETE n` 这类读外壳夹写拦得住);字符串字面量与注释内的写词不误判;`CALL dbms.*` 管理过程**恒拒**;未知 CALL 过程(含 apoc.*)保守按写
122
+ - **结果拍平**:Node 渲染为 `:Label {属性}`,Relationship 为 `-(TYPE)-> {属性}`,Path 为 `<path:n>`;无返回记录的写语句回显变更计数(创建节点 n,设置属性 m)
123
+ - **limit 封顶**:客户端截断对齐关系型方言(不做 Cypher LIMIT 注入,任意语句尾部加 LIMIT 不总合法)
124
+ - **连接串**:`bolt://`/`neo4j://`/`bolt+s://`/`neo4j+s://` 等;建连统一走 Bolt 直连(`bolt://`/`bolt+s://`)——单机社区版无路由服务,`neo4j://` 路由 scheme 会报 No routing servers available;URL 路径段 = 图数据库名(缺省 `neo4j`)
125
+ - **扫描建连**:Spring `spring.neo4j.uri`(Boot 3)/ `spring.data.neo4j.uri`(Boot 2)+ authentication 账号密码键、`.env` `NEO4J_URI`/`NEO4J_URL`/`BOLT_URL`、docker-compose `neo4j` 镜像(`NEO4J_AUTH`/`NEO4J_PASSWORD`)、通用 URL 正则
126
+
127
+ ## ✍️ 写操作:理由与审计
128
+
129
+ - AI 发起写操作必须附 `reason` 参数(动机 + 影响范围,如 *"将 status=2 的历史订单归档,预计影响 1.2 万行"*)
130
+ - 确认框**首行展示理由**,执行结果末尾回显;缺失时拒绝并引导补充(与确认策略无关)
131
+ - 开启审计(`/db config → 审计日志`)后,写成功追加 `~/.pi/agent/db-audit/<YYYY-MM-DD>.jsonl`:
132
+ - 一天一个文件;字段含时间/项目路径/连接/摘要/理由/**完整 SQL 不截断**
133
+ - 文件 `0600`;审计失败静默降级,不阻断主流程
134
+ - 清理示例:`find ~/.pi/agent/db-audit -name "*.jsonl" -mtime +90 -delete`
135
+
136
+ ## 💾 查询结果导出
137
+
138
+ 结果超过 50 行时自动导出 `/tmp`(CSV + JSON 双格式),只回文件路径;达到 `max_rows` 截断时有明确标注。