@yejiming/dsh-data-agent 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
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.en.md ADDED
@@ -0,0 +1,185 @@
1
+ # Data Agent · Let AI Connect Your Database and Write SQL
2
+
3
+ [中文](README.md) | **English**
4
+
5
+ ![Data Agent session](assets/session.png)
6
+
7
+ This plugin is a Data Agent built on DeepSeek Harness, letting DeepSeek focus on database operations.
8
+
9
+ Leveraging the agent-preset capability of DeepSeek Harness, it adds a Data Agent preset. The preset keeps only the three DSH built-in tools — read, edit, write — and adds a custom sqlcmd tool in place of the bash tool, free from irrelevant tools and prompts.
10
+
11
+ With this preset, you can configure a database connection right in the conversation UI, grant the AI access to the database, and complete CRUD operations.
12
+
13
+ ## Features
14
+
15
+ - **Database connection management**: per-session connections to MySQL / PostgreSQL / SQLite / Oracle / Hive / Impala (SQLite uses a file path, Oracle a service name/SID, Hive/Impala a default database). Connection state lives in server memory and survives layout switches; passwords stay in memory and travel to the client via environment variables or stdin connect prefixes — never written to disk on the server.
16
+
17
+ ![Database connection](assets/connection.png)
18
+
19
+ - **Database workbench** (embedded above the session's input bar): connection config card (collapses into a summary row after connecting, expandable for review); schema explorer (a "Tables" button opens a Modal — single-click a database to expand its table list, up to 5 rows visible with a built-in scrollbar, click a table to inspect its columns); SQL command box (write and run SQL on the non-agent channel, monospace output). The connection config is persisted to browser localStorage — switching pages or restarting restores the form and auto-reconnects. Once the conversation starts, the workbench becomes the left column and the chat records + input bar sit on the right.
20
+ - **sqlcmd tool**: runs SQL/commands through the database clients (mysql / psql / sqlite3 / sqlplus / beeline / impala-shell); no shell layer (argv arrays + SQL via stdin), timeouts terminate the process tree, output is bounded and truncated.
21
+ - **Data Agent preset**: choose "Data Agent" when creating a session — the tool surface is exactly `sqlcmd`/`read`/`write`/`edit`, and every other project tool (bash, grep, skill, todo, goal, web, subagent, …) is simply absent, i.e. disabled; non-Data-Agent sessions render no workbench at all.
22
+
23
+ ![Data Agent preset](assets/settings.png)
24
+
25
+ - **Standard agent loop**: a data-agent session is an ordinary DSH session — standard turn/step, streaming, tool scheduling, and persistence, with zero host changes.
26
+
27
+ ## Quick Install
28
+
29
+ The repository ships its prebuilt output in `lib/` and declares no
30
+ `prepare`/`prepack` scripts, so git, tarball, and local-directory installs all
31
+ use the committed artifacts — **no build step at install time**.
32
+
33
+ ```sh
34
+ # Install from git (recommended; initializes the profile on first use)
35
+ dsh plugin --profile demo add github:omdsh-dev/dsh-data-agent
36
+
37
+ # Or install from the local source directory (lib/ is committed, no build needed)
38
+ dsh plugin --profile demo add .
39
+ ```
40
+
41
+ Verify the install:
42
+
43
+ ```sh
44
+ dsh --profile demo --dump-config # the data-agent layer should appear
45
+ ls $DSH_HOME/.agent-presets/data-agent/ # agent.cordis.yml + preset.yml (auto-installed)
46
+ ```
47
+
48
+ Start the Web GUI:
49
+
50
+ ```sh
51
+ dsh --profile demo
52
+ ```
53
+
54
+ In the Web GUI: create a session → choose the "Data Agent" preset → the database workbench appears above the input bar → fill in the connection info (type/host/port/user/password/database; SQLite uses a file path) → after connecting, browse schemas (double… single-click a database to expand tables, click a table for its structure) or run SQL directly in the command box → once the conversation starts the workbench moves to the left; in Chat ask the AI to "list all tables and count rows" or "write a SQL query for orders in the last 30 days, save it to orders.sql and run it".
55
+
56
+ > Database client binaries: sqlite3 usually ships with macOS/Linux; mysql / psql / sqlplus / beeline / impala-shell must be provided by the deployment and can be overridden per type via the `clients` config (missing clients are named in the connect error).
57
+
58
+ ## Architecture
59
+
60
+ ```text
61
+ Browser (apps/web) Host process (dsh --profile demo)
62
+ ┌─────────────────────────────┐ ┌──────────────────────────────────────┐
63
+ │ Database workbench (input.dock) │ fetch │ @yejiming/dsh-data-agent (host row)│
64
+ │ · connection config (6 types) │ ─────▶ │ · /plugins/data-agent/* routes │
65
+ │ · schema explorer + SQL box │ │ · dataAgentConnections store │
66
+ │ · hero stacked / active rail │ │ · preset self-install → $DSH_HOME/ │
67
+ └─────────────────────────────┘ └──────────────┬───────────────────────┘
68
+ │ same process
69
+ data-agent session (full agent loop reuse) ▼
70
+ ┌──────────────────────────────────────────────────────────────────────────┐
71
+ │ agent.cordis.yml (preset layer, only 3 rows) │
72
+ │ · persona → data-engineer system prompt │
73
+ │ · dsh-tool-fs → read / write / edit (project built-ins) │
74
+ │ · dsh-data-agent/tool → sqlcmd (this package's tool half) │
75
+ └──────────────────────────────────────────────────────────────────────────┘
76
+ ```
77
+
78
+ One npm package, three loadable faces, two host rows:
79
+
80
+ | Face | Entry | Loaded by |
81
+ |---|---|---|
82
+ | Server half (connection store / preset self-install) | `lib/index.js` (host row `data-agent`) | Host composition: provides `dataAgentConnections`, seeds connections, self-installs the preset; works headless too |
83
+ | Server half (HTTP routes) | `lib/routes.js` (host row `data-agent-routes`, exports subpath `./routes`) | Host composition: registers routes via a nested inject only where a webserver exists (skipped automatically headless) |
84
+ | Tool half | `lib/tool.js` (exports subpath `./tool`) | Only mounted by the data-agent preset (`tool-sqlcmd` row) |
85
+ | Browser half | `lib/client.js` (`dsh.client` declaration) | Browser: the database workbench in the input dock (`conversation.input.dock`) |
86
+
87
+ The tool half only consumes host services (`subprocess`, `dataAgentConnections`) and provides none, so the preset guard needs no `isolate` realm.
88
+
89
+ ## Configuration
90
+
91
+ Every field has a loader default; there are no library-level defaults. Host row `data-agent`:
92
+
93
+ | Key | Meaning |
94
+ |---|---|
95
+ | `presetId` | Preset directory name installed under `$DSH_HOME/.agent-presets/` (default `data-agent`) |
96
+ | `installPreset` | Whether to self-install the preset on startup (default true; existing directories are skipped, keeping user edits) |
97
+ | `connectTimeoutMs` | End-to-end deadline for one /connect connectivity check (default 10000 ms) |
98
+ | `introspectMaxTables` | Cap on the table list returned by /connect and /status (default 500) |
99
+ | `queryTimeoutMs` | Deadline for one sqlcmd query (default 30000 ms) |
100
+ | `maxResultChars` | In-memory cap on captured sqlcmd output, per stream (default 20000 chars) |
101
+ | `clients` | Per-type CLI client overrides: `{ command?, args? }` for keys `mysql` / `postgres` / `sqlite` / `oracle` / `hive` / `impala` (built-in defaults mysql/psql/sqlite3/sqlplus/beeline/impala-shell) |
102
+ | `connections` | Config-seeded connections keyed by session id (`'*'` = wildcard default for any session without its own; headless/keyless runs and deployments pinning one database). **No password field** — passwords only enter memory via the /connect route |
103
+
104
+ The `tool-sqlcmd` row (inside the data-agent preset) additionally has `maxRows` (default 100, injected into the tool description as LIMIT guidance); `queryTimeoutMs` / `maxResultChars` / `clients` share the host row's names and defaults.
105
+
106
+ The `data-agent-routes` row has its own config: `connectTimeoutMs` / `introspectMaxTables` / `maxResultChars` mirror the main row; plus `queryTimeoutMs` (for /query and metadata queries, default 30000) and `maxQueryChars` (single-SQL length cap for /query, default 65536).
107
+
108
+ ```yaml
109
+ # Example override in cordis.patch.yml or a profile layer
110
+ - id: data-agent
111
+ name: '@yejiming/dsh-data-agent'
112
+ config:
113
+ clients:
114
+ mysql:
115
+ command: /usr/local/bin/mysql-client
116
+ # Wildcard default connection: sessions without an explicit /connect fall back
117
+ # to this database (password-free scenario only)
118
+ connections:
119
+ '*':
120
+ type: sqlite
121
+ database: /tmp/analytics.db
122
+ ```
123
+
124
+ ## Headless / One-shot Runs
125
+
126
+ **Important**: `dsh run` (the headless bundle) does not mount the agent-presets roster and never mounts presets for sessions — preset mounting belongs to the web surface (the api-proxy mounts on session creation). Therefore **headless sessions cannot use the sqlcmd/read/write/edit tool surface**; sqlcmd is verified and used on the web surface. Headless database work is limited to the host base's own tools (e.g. calling clients via bash).
127
+
128
+ (Note: inserting the roster row plus disabling the base tool rows cannot reproduce the preset tool surface headless — the agent ends up with an empty, zero-tool composition. For a headless smoke test, verify "seeded connections + host tools work" only.)
129
+
130
+ The `data-agent-routes` row is skipped automatically in profiles without a webserver (nested inject), so nothing needs special handling.
131
+
132
+ ## HTTP API
133
+
134
+ Prefix `/plugins/data-agent` (same-origin calls from the browser half):
135
+
136
+ | Method/Path | Meaning |
137
+ |---|---|
138
+ | `POST /connect` | body `{ sessionId, type, host?, port?, user?, database, password? }`; validate → connectivity check (list tables) → save only on success, returns `{ ok, tables }`, failure returns `{ ok: false, error }` without saving |
139
+ | `POST /disconnect` | body `{ sessionId }`; drop the session's connection |
140
+ | `GET /status?sessionId=` | `{ connected, summary? }`; summary is the password-stripped connection plus the table list |
141
+ | `GET /schemas?sessionId=` | `{ ok, schemas: string[] }`; database list (sqlite returns `['main']`) |
142
+ | `GET /tables?sessionId=&schema=` | `{ ok, tables: string[] }`; tables of one schema (sqlite ignores the schema param) |
143
+ | `GET /describe?sessionId=&schema=&table=` | `{ ok, columns: [{ name, type, nullable? }] }`; table structure (sqlite ignores schema) |
144
+ | `POST /query` | body `{ sessionId, sql }`; run arbitrary SQL (the workbench command box, non-agent channel), returns `{ ok, result: { exitCode, stdout, stderr, truncated } }`; `sql` length capped by `maxQueryChars` |
145
+
146
+ Schema/table identifiers allow only `[A-Za-z0-9_$#.-]` (server-side whitelist; injection-shaped input is rejected).
147
+
148
+ ## Security Notes
149
+
150
+ - **Passwords**: server-side, memory only; transport per type — mysql via `MYSQL_PWD`, postgres via `PGPASSWORD` environment variables; oracle via the sqlplus `connect user/pass@...` stdin prefix, hive via the beeline `!connect` stdin prefix (never argv); impala sends no password by default (LDAP/kerberos configured through `clients`). `/status` and the public connection-store reads strip passwords.
151
+ - **Connection-config persistence**: the workbench saves the connection config (**including the password**, in plain text) to browser localStorage (key `dsh-data-agent.connection.v1`, per the confirmed local single-user scenario) after a successful connect, to restore the form and auto-reconnect once on page switches/restarts; disconnecting does not clear it. To clear: run `localStorage.removeItem('dsh-data-agent.connection.v1')` in the browser console.
152
+ - **No shell layer**: `ctx.subprocess.spawn` uses argv arrays, SQL and connect prefixes travel via stdin — no shell concatenation injection surface; metadata route identifiers pass the whitelist.
153
+ - **SQL execution authority**: with the approval policy set to `never`, sqlcmd and `/query` execute DDL/DML directly — connections are session-isolated; assess the data-plane risk yourself (a `readonly` mode is a later version).
154
+ - **Timeouts & caps**: query timeouts, output truncation, table-list caps, and the /query SQL length are all config items — no hard-coded tunables.
155
+
156
+ ## Uninstall & Rollback
157
+
158
+ ```sh
159
+ dsh plugin --profile demo remove @yejiming/dsh-data-agent # removes the dependency and its layer
160
+ rm -rf $DSH_HOME/.agent-presets/data-agent # manually delete the self-installed preset
161
+ ```
162
+
163
+ Connections are in-memory; there is no persisted data to clean up.
164
+
165
+ ## Development
166
+
167
+ Build and test:
168
+
169
+ ```sh
170
+ pnpm build # cleans and rebuilds lib/ (tsdown: lib/index.js, lib/routes.js, lib/tool.js, lib/invariant.js, lib/client.js) + tsc declarations
171
+ pnpm test # vitest: connection store / CLI templates / sqlcmd execution (mocked subprocess)
172
+ ```
173
+
174
+ `lib/` is committed, so installing and debugging (including `dsh plugin add .`)
175
+ never requires a build. To rebuild the artifacts, just run `pnpm install`: all
176
+ `@deepseek-ai/*` dependencies are published on npm, so there is no need to copy
177
+ or symlink `node_modules` from a local DSH checkout anymore.
178
+ `pnpm-workspace.yaml` follows the dsh convention (`nodeLinker: hoisted`); pnpm
179
+ 11's supply-chain policy blocks freshly published packages and dependency build
180
+ scripts, so the repository pre-declares `minimumReleaseAgeExclude` (the rc.6
181
+ family) and `allowBuilds: esbuild`.
182
+
183
+ ## License
184
+
185
+ MIT
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # 数据Agent(Data Agent)· 让 AI 帮你连数据库、写 SQL
2
+
3
+ [English](README.en.md) | **中文**
4
+
5
+ ![数据Agent 会话](assets/session.png)
6
+
7
+ 用AI写过SQL的同学都有这种体验,AI现在写代码能力已经很强了,但SQL逻辑老写不对。**原因是AI并没有与数据库操作形成Agent Loop**,它只能根据静态指令生成SQL,却无法感知执行结果、无法根据报错或返回数据动态调优。
8
+
9
+ 这个插件就是来填这个坑的。它复用DeepSeek Harness强大的Agent主循环能力,让AI连上数据库并获得实时反馈,同时删掉所有跟数据无关的上下文和工具,让AI专注于SQL生成和业务数据分析。
10
+
11
+ 我利用DeepSeek Harness的Agent预设功能,定义了专用的Data Agent预设。仅保留read、edit、write三个DSH自带的 tools,并自定义sqlcmd tool替代bash tool。
12
+
13
+ 懂行的朋友一眼就能看出,这是借鉴了Pi Agent的设计,只使用最基本的工具。
14
+
15
+ 用起来也很简单:在对话界面配好数据库连接,授权AI访问权限,然后就可以向AI提问,让AI帮你查询、更新、分析。
16
+
17
+ ## 主要功能
18
+
19
+ - **数据库连接管理**:按会话连接 MySQL / PostgreSQL / SQLite / Oracle / Hive / Impala(SQLite 走文件路径,Oracle 填服务名/SID,Hive/Impala 填默认库),连接状态驻留服务端内存,布局切换不丢;密码仅内存、经环境变量或 stdin 连接前缀传给客户端,绝不落盘。
20
+
21
+ ![数据库连接](assets/connection.png)
22
+ - **数据库工作台**(内嵌于会话输入框上方):连接配置卡(连接成功后折叠为摘要行,可展开查看);库表浏览(点击「库表」按钮弹出 Modal:单击库展开表列表,表列表单页 5 条可滚动,点击表查看结构);SQL 命令框(编辑并运行 SQL,非 agent 通道,结果等宽展示)。连接配置持久化到浏览器 localStorage,切换页面/重启自动回填并重连。开始对话后工作台自动变为左侧栏,对话记录与输入框在右侧。
23
+
24
+ ![数据库工作台](assets/tables.png)
25
+ - **sqlcmd 工具**:在数据库客户端(mysql / psql / sqlite3 / sqlplus / beeline / impala-shell)执行 SQL/命令;无 shell 层(argv 数组化 + SQL 走 stdin),超时自动终止进程树,输出有界截断。
26
+ - **数据Agent 预设**:新建会话可选「数据Agent」——工具面恰好是 `sqlcmd`/`read`/`write`/`edit` 四个,项目其他工具(bash、grep、skill、todo、goal、web、subagent 等)全部缺席即禁用;非数据Agent 会话不渲染工作台,零影响。
27
+
28
+ ![数据Agent 预设](assets/settings.png)
29
+ - **标准 agent loop**:data-agent 会话就是普通 DSH 会话,走标准 turn/step、流式输出、工具调度与持久化,零宿主改动。
30
+
31
+ ## 快速安装
32
+
33
+ 仓库已提交构建产物 `lib/`(且不设 `prepare`/`prepack` 脚本),因此 git、tarball
34
+ 与本地目录安装都直接使用产物,**无需在安装时构建**。
35
+
36
+ ```sh
37
+ # 从 git 安装(推荐;首次使用会初始化该 profile)
38
+ dsh plugin --profile demo add github:omdsh-dev/dsh-data-agent
39
+
40
+ # 或从本地源码目录安装(lib/ 已提交,同样无需构建)
41
+ dsh plugin --profile demo add .
42
+ ```
43
+
44
+ 安装后验证:
45
+
46
+ ```sh
47
+ dsh --profile demo --dump-config # 输出中应出现 data-agent 层
48
+ ls $DSH_HOME/.agent-presets/data-agent/ # 应有 agent.cordis.yml + preset.yml(由插件自动安装)
49
+ ```
50
+
51
+ 启动 Web GUI:
52
+
53
+ ```sh
54
+ dsh --profile demo
55
+ ```
56
+
57
+ 在 Web GUI 中:新建会话 → 选择「数据Agent」预设 → 输入框上方出现数据库工作台 → 填写连接信息(类型/主机/端口/用户/密码/库名;SQLite 填文件路径)→ 连接成功后浏览库表(双击库看表、点击表看结构),或在 SQL 命令框直接运行 SQL → 开始对话后工作台移到左侧,在 Chat 让 AI「列出所有表并统计行数」或「写一条 SQL 查出近 30 天订单,保存到 orders.sql 并执行」。
58
+
59
+ > 数据库客户端二进制要求:sqlite3 一般系统自带(macOS/Linux);mysql / psql / sqlplus / beeline / impala-shell 需部署方安装,且可在插件配置 `clients` 中覆盖命令名或绝对路径(缺失时连接报错会点名缺失的命令)。
60
+
61
+ ## 架构
62
+
63
+ ```text
64
+ 浏览器 (apps/web) 宿主进程 (dsh --profile demo)
65
+ ┌─────────────────────────────┐ ┌──────────────────────────────────────┐
66
+ │ 数据库工作台 (input.dock) │ fetch │ @yejiming/dsh-data-agent (宿主行) │
67
+ │ · 连接配置 (6 类型) │ ───────▶ │ · /plugins/data-agent/* 路由 │
68
+ │ · 库表浏览 + SQL 命令框 │ │ · 连接存储服务 dataAgentConnections │
69
+ │ · hero 堆叠 / active 左栏 │ │ · 预设自安装 → $DSH_HOME/.agent-presets│
70
+ └─────────────────────────────┘ └──────────────┬───────────────────────┘
71
+ │ 同一进程
72
+ data-agent 会话 (agent loop 全复用) ▼
73
+ ┌──────────────────────────────────────────────────────────────────────────┐
74
+ │ agent.cordis.yml (预设层,仅 3 行) │
75
+ │ · persona → 数据工程师系统提示词 │
76
+ │ · dsh-tool-fs → read / write / edit(项目自带) │
77
+ │ · dsh-data-agent/tool → sqlcmd(本包工具半体) │
78
+ └──────────────────────────────────────────────────────────────────────────┘
79
+ ```
80
+
81
+ 一个 npm 包三个装载面、宿主两条行:
82
+
83
+ | 面 | 入口 | 装载位置 |
84
+ |---|---|---|
85
+ | 服务端半体(连接存储/预设自安装) | `lib/index.js`(宿主行 `data-agent`) | 宿主组合:提供 `dataAgentConnections` 服务、预置连接、自安装预设;headless 也可用 |
86
+ | 服务端半体(HTTP 路由) | `lib/routes.js`(宿主行 `data-agent-routes`,exports 子路径 `./routes`) | 宿主组合:仅在 webserver 存在时经嵌套 inject 注册路由(headless 无 webserver 时自动跳过) |
87
+ | 工具半体 | `lib/tool.js`(exports 子路径 `./tool`) | 仅 data-agent 预设装载(`tool-sqlcmd` 行) |
88
+ | 浏览器半体 | `lib/client.js`(package.json `dsh.client` 声明) | 浏览器:输入条带内嵌数据库工作台(`conversation.input.dock`) |
89
+
90
+ 工具半体只消费宿主服务(`subprocess`、`dataAgentConnections`),不提供服务,因此预设守卫无需 `isolate` realm。
91
+
92
+ ## 配置
93
+
94
+ 所有字段都有 loader 默认值;无库级默认值。宿主行 `data-agent`:
95
+
96
+ | 键 | 说明 |
97
+ |---|---|
98
+ | `presetId` | 自安装的预设目录名(默认 `data-agent`) |
99
+ | `installPreset` | 是否在启动时自安装预设(默认 true;已存在则跳过,保留用户编辑) |
100
+ | `connectTimeoutMs` | /connect 连通性检查的端到端超时(默认 10000 毫秒) |
101
+ | `introspectMaxTables` | 表清单上限(默认 500) |
102
+ | `queryTimeoutMs` | sqlcmd 单次查询超时(默认 30000 毫秒) |
103
+ | `maxResultChars` | sqlcmd 捕获输出上限(stdout/stderr 各自,默认 20000 字符) |
104
+ | `clients` | 各数据库类型 CLI 客户端覆盖:`{ command?, args? }`,键为 `mysql` / `postgres` / `sqlite` / `oracle` / `hive` / `impala`(内置默认 mysql/psql/sqlite3/sqlplus/beeline/impala-shell) |
105
+ | `connections` | 配置预置连接,键为 sessionId(`'*'` = 通配符默认,任何无自有连接的会话回落它;headless/keyless 运行与部署固定默认库场景)。**不含 password 字段**——密码只允许经 /connect 路由进入内存 |
106
+
107
+ 工具行 `tool-sqlcmd`(data-agent 预设内)另有 `maxRows`(默认 100,注入工具描述的 LIMIT 引导),`queryTimeoutMs` / `maxResultChars` / `clients` 与宿主行同名可配。
108
+
109
+ 路由行 `data-agent-routes` 独立配置:`connectTimeoutMs` / `introspectMaxTables` / `maxResultChars` 与主行同名同默认;另有 `queryTimeoutMs`(/query 与元数据查询超时,默认 30000)与 `maxQueryChars`(/query 单条 SQL 长度上限,默认 65536)。
110
+
111
+ ```yaml
112
+ # cordis.patch.yml 或 profile 层覆盖示例
113
+ - id: data-agent
114
+ name: '@yejiming/dsh-data-agent'
115
+ config:
116
+ clients:
117
+ mysql:
118
+ command: /usr/local/bin/mysql-client
119
+ # 通配符默认连接:任何未显式 /connect 的会话回落到该库(仅限无密码场景)
120
+ connections:
121
+ '*':
122
+ type: sqlite
123
+ database: /tmp/analytics.db
124
+ ```
125
+
126
+ ## Headless / 一次性运行
127
+
128
+ **重要**:`dsh run`(headless bundle)不装载 agent-presets roster,也不会为会话挂载预设——预设机制属于 web 面(apiproxy 在会话创建时 mount)。因此 **headless 会话无法使用 sqlcmd/read/write/edit 四工具面**,sqlcmd 的验证与使用都在 web 面完成;headless 中如需数据库能力,只能靠宿主 base 自带工具(如 bash 直接调用客户端)。
129
+
130
+ (注:插入 roster 行 + 禁用 base 工具行的 patch 组合无法在 headless 中复现预设工具面——agent 会得到一个零工具的空组合,模型无工具可调。如需 headless 冒烟,仅验证「连接配置预置 + 宿主工具可用」即可。)
131
+
132
+ `data-agent-routes` 行在无 webserver 的 profile 中经嵌套 inject 自动跳过,无需处理。
133
+
134
+ ## HTTP 接口
135
+
136
+ 前缀 `/plugins/data-agent`(浏览器半体同源调用):
137
+
138
+ | 方法/路径 | 说明 |
139
+ |---|---|
140
+ | `POST /connect` | body `{ sessionId, type, host?, port?, user?, database, password? }`;校验 → 连通性验证(列出所有表)→ 成功才保存连接,返回 `{ ok, tables }`,失败返回 `{ ok: false, error }` 且不保存 |
141
+ | `POST /disconnect` | body `{ sessionId }`;清除该会话连接 |
142
+ | `GET /status?sessionId=` | `{ connected, summary? }`;summary 为脱敏连接概要(无密码)+ 表清单 |
143
+ | `GET /schemas?sessionId=` | `{ ok, schemas: string[] }`;库/数据库列表(sqlite 为 `['main']`) |
144
+ | `GET /tables?sessionId=&schema=` | `{ ok, tables: string[] }`;某库的表列表(sqlite 忽略 schema 参数) |
145
+ | `GET /describe?sessionId=&schema=&table=` | `{ ok, columns: [{ name, type, nullable? }] }`;表结构(sqlite 忽略 schema) |
146
+ | `POST /query` | body `{ sessionId, sql }`;运行任意 SQL(工作台命令框,非 agent 通道),返回 `{ ok, result: { exitCode, stdout, stderr, truncated } }`;`sql` 长度上限 `maxQueryChars` |
147
+
148
+ schema/table 标识符仅允许 `[A-Za-z0-9_$#.-]`(服务端白名单校验,拒绝注入形字符)。
149
+
150
+ ## 安全说明
151
+
152
+ - **密码**:服务端仅存内存,传递通道按类型:mysql 经 `MYSQL_PWD`、postgres 经 `PGPASSWORD` 环境变量;oracle 经 sqlplus `connect user/pass@...` stdin 前缀、hive 经 beeline `!connect` stdin 前缀(均不进 argv);impala 默认不传密码(LDAP/kerberos 由部署侧 `clients` 覆盖)。`/status` 与连接存储的公开读取面均剥离密码。
153
+ - **连接配置持久化**:工作台在连接成功后把连接配置(**含密码**,明文)保存到浏览器 localStorage(键 `dsh-data-agent.connection.v1`,用户确认的本机单用户场景),用于切换页面/重启后回填表单并自动重连一次;断开不清除。如需清除:浏览器控制台执行 `localStorage.removeItem('dsh-data-agent.connection.v1')`。
154
+ - **无 shell 层**:`ctx.subprocess.spawn` 参数数组化,SQL 与连接前缀经 stdin 传入,不存在 shell 拼接注入面;元数据路由的 schema/table 标识符过白名单校验。
155
+ - **SQL 执行权**:审批策略为 never 时,sqlcmd 与 `/query` 的 DDL/DML 会直接执行——连接按 session 隔离,请自行评估数据面风险(只读模式 `readonly` 列为后续版本)。
156
+ - **超时与上限**:查询超时、输出截断、表清单上限、/query 单条 SQL 长度均为配置项,无硬编码 tunables。
157
+
158
+ ## 卸载与回滚
159
+
160
+ ```sh
161
+ dsh plugin --profile demo remove @yejiming/dsh-data-agent # 移除依赖与对应层
162
+ rm -rf $DSH_HOME/.agent-presets/data-agent # 手动删除自安装的预设
163
+ ```
164
+
165
+ 连接为内存态,无持久化数据需要清理。
166
+
167
+ ## 本地开发
168
+
169
+ 构建与测试:
170
+
171
+ ```sh
172
+ pnpm build # 清空并重建 lib/(tsdown:lib/index.js、lib/routes.js、lib/tool.js、lib/invariant.js、lib/client.js)+ tsc 声明
173
+ pnpm test # vitest:连接存储 / CLI 模板 / sqlcmd 执行(mock subprocess)
174
+ ```
175
+
176
+ `lib/` 已提交进仓库,安装与调试(含 `dsh plugin add .`)都不需要先构建。重新
177
+ 构建产物时直接 `pnpm install` 即可:`@deepseek-ai/*` 等依赖均已发布到 npm,
178
+ 无需再从本地 DSH checkout 复制/链接 node_modules。`pnpm-workspace.yaml` 采用
179
+ dsh 同款约定(`nodeLinker: hoisted`);pnpm 11 的供应链策略会拦截「发布不久」
180
+ 的包与依赖构建脚本,仓库已预置 `minimumReleaseAgeExclude`(rc.6 全家桶)与
181
+ `allowBuilds: esbuild`。
182
+
183
+ ## 许可
184
+
185
+ MIT
@@ -0,0 +1,16 @@
1
+ # The dsh-data-agent bundle patch: activates the plugin as a profile layer.
2
+ #
3
+ # Two host rows: `data-agent` provides the connection store, seeds config
4
+ # connections, and self-installs the agent preset (works in every profile,
5
+ # headless included); `data-agent-routes` mounts the HTTP routes and only
6
+ # activates where the webserver exists (web profiles). The browser half
7
+ # (lib/client.js) ships in the same package and loads under the data-agent id
8
+ # through the `dsh.client` declaration in package.json; the tool half
9
+ # (lib/tool.js) is mounted only by the `data-agent` agent preset as the
10
+ # `@yejiming/dsh-data-agent/tool` row, so no further rows belong here
11
+ # (duplicate ids fail the load).
12
+ - insert:
13
+ - id: data-agent
14
+ name: '@yejiming/dsh-data-agent'
15
+ - id: data-agent-routes
16
+ name: '@yejiming/dsh-data-agent/routes'