Bundle
artifact-center
Cross-session artifact center for DeepSeek Harness: agent tools that register deliverable files, plus a sidebar panel that filters them by category, extension or keyword.
- Source
- lishuo4096
- License
- MIT
- Updated
- Updated 8 days ago
Readme
# 产物中心 · Artifact Center
> DeepSeek Harness(DSH / Cordis)插件:**agent 每次产出重要文件都会登记进一个跨会话的产物中心**,
> 左侧边栏提供面板,按分类 / 后缀 / 关键词即时筛选。
每个对话都在产出文件——报告 PDF、Excel 数据表、PPT、脚本、JSON——但它们散落在各会话的工作目录里,换个对话就找不到了。
本插件把「值得留下的产物」集中到一处:
- **agent 侧**:4 个工具。产出文件时调用 `artifact_save` 登记,默认**复制一份**到统一目录,原目录被清理也不丢。
- **用户侧**:左侧边栏「产物中心」面板。分类 chip + 后缀 chip + 关键词搜索,可复制路径、在文件夹中显示、删除。
- **跨会话**:索引与副本都在 `~/.dsh/artifact-center/`,所有对话共用同一份。
```
┌ 左侧边栏 ────────┐
│ 对话 │
│ 自动化任务 │
│ 产物中心 ← 面板行 │──┐
│ 插件管理 │ │
└──────────────────┘ │
▼
┌ 产物中心 ───────────────────────────────────────┐
│ 分类 [全部] [pdf 3] [excel 2] [code 5] … 刷新│
│ 后缀 [.pdf 3] [.xlsx 2] [.py 4] [.json 1] │
│ 搜索标题 / 文件名 / 路径 / 备注 / 标签 │
│ ─────────────────────────────────────────────── │
│ 季度报告.pdf PDF 2.0 MB 复制路径 显示 删除 │
│ train.py 代码 4.1 KB … │
└─────────────────────────────────────────────────┘
```
## 安装
```sh
# 从 GitHub 安装(推荐)
dsh plugin --profile desktop add github:lishuo4096/artifact-center
# 本地开发:link 到源码目录
dsh plugin --profile desktop add link:/path/to/artifact-center
```
也可以在插件市场(dshmarket)里搜索 `artifact-center` 一键安装。
装完**重启 DSH**(宿主的插件模块走 ESM 缓存,改完源码或新装插件都需要重启才加载新代码);
重启后左侧边栏出现「产物中心」,对 agent 说话时 `artifact_save` 等工具即可用。
## agent 工具
| 工具 | 参数 | 作用 |
| --- | --- | --- |
| `artifact_save` | `path`(必填)、`title`、`note`、`tags[]`、`mode`(`copy` 默认 / `link`) | 登记一个产物。`copy` 会把文件复制进统一目录;`link` 只记路径不动文件 |
| `artifact_list` | `ext`、`category`、`keyword` | 列出/筛选产物,三个过滤条件可组合 |
| `artifact_stats` | — | 按分类、按后缀的计数 |
| `artifact_remove` | `id`(必填) | 删除条目。`copy` 产物连副本一起删;`link` 产物只删条目,**永不碰原文件** |
工具的返回值是结构化 JSON;`artifact_save` 的 `path` 不存在或不是文件时返回 `{ok:false,message}`,不会抛异常打断对话。
## 面板
左侧边栏「产物中心」,与工具读写同一份索引:
- **分类 chip**:`pdf` / `excel` / `ppt` / `word` / `image` / `code` / `data` / `archive` / `other`,带计数,计数为 0 且未选中的不显示。
- **后缀 chip**:按真实后缀分组(`.pdf`、`.py`、`.json`…),按数量降序。
- **搜索框**:服务端匹配标题、文件名、路径、备注、标签(输入 220ms 防抖)。
- **每行操作**:复制路径 · 在文件夹中显示(Windows `explorer /select`、macOS `open`、Linux `xdg-open`)· 删除(二次确认)。
## 数据与配置
```
~/.dsh/artifact-center/
├── index.json # 索引:id / 原标题 / 原路径 / 存储路径 / mode / 分类 / 后缀 / 大小 / 备注 / 标签 / 所属会话 / 时间
└── files/ # copy 模式的副本
```
索引写入是串行队列(不会两个 tool 调用互相覆盖)。默认根目录是 `~/.dsh/artifact-center`,
可用插件配置 `rootDir` 覆盖:
```yaml
# cordis.patch.yml(用户覆盖层)
- id: artifact-center
config:
rootDir: D:/artifacts
```
## HTTP 路由(面板的数据通道)
面板通过宿主 `webServer` 的同源路由取数据,不需要额外服务:
| 路由 | 方法 | 说明 |
| --- | --- | --- |
| `/artifact-center/api/state` | GET | `?ext=&category=&keyword=` → `{ok, items, stats, rootDir, categories}` |
| `/artifact-center/api/remove` | POST | `{id}` → 删除条目 |
| `/artifact-center/api/reveal` | POST | `{id}` → 在文件管理器里定位;只接受索引里的 id,路径由服务端解析 |
三条路由都带**同源栅栏**:带跨站 `Origin` 的请求直接 403;写操作必须 `content-type: application/json`
(跨站表单这类「简单请求」不触发预检,声明 JSON 则会预检,而预检打到本路由必然 405/415);
非浏览器调用(curl / node,没有 Origin)照常可用。`reveal` 不接受任意路径参数,所以无法被用来打开任意文件。
没有 `webServer` 的形态(纯 CLI)下,面板这段不激活,4 个工具照常工作。
## 目录结构
```
artifact-center/
├── package.json # dsh.bundle.patch + dsh.client(web)
├── cordis.patch.yml # 注册进 profile 的 patch 行
├── index.js # 宿主半边:4 个工具 + 3 条同源路由
├── client.js # 浏览器半边:侧边栏面板行 + 面板页(window.__ModuleLoader__ 形态)
├── lib/
│ ├── defineTool.js # 作者侧工具 DSL → 宿主 JSON Schema(零依赖,必须带)
│ └── store.js # 索引与副本的存储层(串行写、分类规则)
└── test/
└── local-smoke.mjs # 离线自检:81 项断言,不需要 DSH 就能跑
```
`lib/defineTool.js` 不是可选的装饰:宿主真正加载的是 `@deepseek-ai/dsh-tools` 的 `defineTool`,
但在 profile 里以 `link:` 安装的插件**不能 import 任何 `@deepseek-ai/*`**(它们只在 app.asar 内,Node 解析不到),
所以插件必须自带一份等价实现。作者的 `parameters` 用 `required: true` 这种 DSL 写法,`output.schema: {type:'json'}` 表示无约束 JSON。
## 开发与自检
```sh
node test/local-smoke.mjs
```
零依赖,不需要启动 DSH:伪造 `ctx` / `req` / `res` 后覆盖工具行为(复制落盘、link 不复制、删除 link 不动原文件、
筛选与统计)、三条路由(含同源/方法/content-type 栅栏)、`client.js` 的装载与渲染(用 stub React 渲染空态、
有数据、筛选无命中、错误态),以及**工具 schema 必须通过宿主 `assertSupportedJsonSchema`** 这条回归护栏
(作者侧 `type:'json'` 若被原样透传,宿主 `register()` 会同步抛错,进而中断整个 `apply()`——本插件踩过这个坑)。
## 兼容性
- 面板需要 Web GUI(宿主 `webServer` 同源路由 + `sidebar.panellist` / `main` 插槽)。
- 纯 CLI 形态下工具可用,面板不显示。
- 已在本机 DSH 桌面版(Electron,Web GUI `http://127.0.0.1:19387`)上实测:面板渲染、筛选、删除、
在文件夹中显示,以及 4 个工具均正常。
## License
MIT
---
# Artifact Center (English)
A DeepSeek Harness (DSH / Cordis) plugin that gives every conversation a **shared artifact center**.
Agents produce files all the time — reports, spreadsheets, slides, scripts, JSON — and they end up scattered across
per-session working directories, effectively lost the moment the conversation changes. This plugin registers the
artifacts worth keeping, in one place:
- **Agent tools** — `artifact_save` (copies the file into a shared directory by default, or just records the path with
`mode:"link"`), `artifact_list` (filter by `ext` / `category` / `keyword`), `artifact_stats`, `artifact_remove`.
- **Sidebar panel** — category chips with counts, extension chips with counts, keyword search, copy path,
reveal in file manager, delete with confirmation.
- **Cross-session** — index and copies live in `~/.dsh/artifact-center/`, shared by every conversation.
```sh
dsh plugin --profile desktop add github:lishuo4096/artifact-center
```
Restart DSH afterwards. The panel talks to the host over three same-origin routes under `/artifact-center/api/`
(`state`, `remove`, `reveal`); cross-origin requests are rejected, writes require `application/json`, and `reveal`
resolves paths server-side from the index so it cannot be used to open arbitrary files.
Run `node test/local-smoke.mjs` for the dependency-free self-check (81 assertions covering the tools, the routes,
the browser bundle and the tool-schema contract).
MIT licensed.
Install
dsh plugin --profile web add github:lishuo4096/artifact-center
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install artifact-center from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.