dsh-webfile
S3, FDS & FTP file tools for DeepSeek Harness: 8 agent tools (list, stat, mkdir, delete, move, copy, download, upload) — approval-gated mutations, transfer jobs with progress & cancel.
让 Agent 在对话中直接浏览与操作 S3(含 MinIO 等兼容对象存储)、小米 FDS 与 FTP/FTPS 上的文件:
- 只读直通:
webfile_list/webfile_stat免审批; - 变更逐次审批:其余 6 个工具每次调用都经用户确认,拒绝即零副作用;
- 传输走后台任务:下载/上传在 Jobs 面板流式展示进度,可随时取消;
- 凭据只存引用:密钥值永不进入配置或会话日志,轮换后下一次调用即生效。
安装
dsh plugin --profile <name> add dsh-webfile插件声明了 dsh.bundle,安装后自动挂载进该 profile 的 layer 栈(无需手写任何挂载行)。升级:
dsh plugin --profile <name> update配置
在 profile 的 cordis.patch.yml($DSH_HOME/profiles/<name>/cordis.patch.yml)中按 id 覆盖配置:
- id: dsh-webfile
config:
connections:
prod-logs:
protocol: s3
endpoint: https://oss.example.com # 省略走 AWS 公有云
region: cn-north-1
bucket: prod-logs
pathStyle: true # MinIO 需要 true
accessKeyRef: OSS_ACCESS_KEY # 凭据引用名,见下节
secretKeyRef: OSS_SECRET_KEY
legacy-ftp:
protocol: ftp
host: ftp.example.com
port: 21
userRef: FTP_USER
passwordRef: FTP_PASSWORD
tls: explicit # none | explicit | implicit
mi-fds:
protocol: fds
endpoint: https://cnbj2.fds.api.xiaomi.com # 最小配置:endpoint + bucket + ak/sk
bucket: mi-bucket
accessKeyRef: FDS_ACCESS_KEY # 必填:FDS 没有环境凭据链
secretKeyRef: FDS_SECRET_KEY
# region: cnbj2 # 不想写完整 endpoint 时,可用 region 推导域名
# https: false # 默认 true;明文 HTTP 时置 false
maxTransferBytes: 2147483648 # 单文件传输上限,默认 2 GiB
multipartThresholdBytes: 67108864 # S3/FDS 分片上传阈值,默认 64 MiB连接字段
| 字段 | 协议 | 说明 |
|---|---|---|
protocol | 三者 | s3 / fds / ftp(必填) |
endpoint | s3 | 自定义 endpoint(MinIO 等);省略走 AWS 公有云 |
region | s3 | 区域(必填) |
bucket | s3 | 默认 bucket |
pathStyle | s3 | path-style 寻址,MinIO 需要 true |
accessKeyRef / secretKeyRef / sessionTokenRef | s3 | 凭据引用名,见下节 |
region | fds | FDS 区域(cnbj2 / awsbj0 / awsusor0 / awssgp0 / awsde0 / ksyru0-eco / awsind0-eco);与 endpoint 二选一 |
endpoint | fds | 完整域名(可带或省略 scheme),优先级高于 region;只配 endpoint 时 region 可省略 |
bucket | fds | 默认 bucket |
https | fds | 默认 true;FDS 也提供明文 HTTP |
accessKeyRef / secretKeyRef | fds | 凭据引用名(必填,FDS 没有环境凭据链),见下节 |
host | ftp | 服务器地址(必填) |
port | ftp | 默认 21;隐式 FTPS 默认 990 |
userRef / passwordRef | ftp | 凭据引用名;省略走匿名登录 |
tls | ftp | none / explicit / implicit(必填) |
passive | ftp | 默认 true;当前仅支持被动模式 |
patch 语义要点
- 按 id 定位:不带
id的 patch 行会被跳过并告警; - 整体替换:
config浅覆盖整份替换,未写字段回落插件默认值; - 不要重复挂载:不要在用户层再
insert同名行,配置一律走 id 覆盖; - 禁用:
- id: dsh-webfile / disabled: true可在该 profile 关闭插件; - 热生效:web 等长生命周期表面监视该文件,保存即经 HMR 事务性重载,无需重启;解析失败响亮报错并保留上一份好的配置。
凭据
配置中只写凭据引用名(环境变量名,POSIX 标识符),密钥值放在 $DSH_HOME/.credentials.yaml:
OSS_ACCESS_KEY: AKIAxxxxxxxx
OSS_SECRET_KEY: xxxxxxxxxxxx
FDS_ACCESS_KEY: 你的 FDS Access Key # dev.mi.com / 小米融合云控制台创建
FDS_SECRET_KEY: 你的 FDS Secret Key
FTP_USER: logbot
FTP_PASSWORD: xxxxxxxx- 四层优先级:进程环境 > 凭据文件 > 项目
.env> 用户.env;进程环境只读且遮蔽同名文件条目; - 热发布:凭据文件被监视(100 ms 去抖),外部编辑后下一次工具调用即用新值,轮换零重启;
- 格式:严格
引用名: 字符串值映射(不是 dotenv 语法);值必须非空;文件权限必须0600; - 密钥值永不进入配置面或会话日志。
工具一览
| 工具 | 参数 | 权限 | 后台任务 |
|---|---|---|---|
webfile_list | connection·remotePath·maxEntries(默认 200,上限 1000)·nextToken | 免审批 | 否 |
webfile_stat | connection·remotePath | 免审批 | 否 |
webfile_mkdir | connection·remotePath | 需审批 | 否 |
webfile_delete | connection·remotePath·recursive(默认 false) | 需审批 | 否 |
webfile_move | connection·sourcePath·targetPath·overwrite(默认 false) | 需审批 | 否 |
webfile_copy | connection·sourcePath·targetPath·overwrite(默认 false) | 需审批 | 否 |
webfile_download | connection·remotePath·localPath(可选,默认镜像到工作区根) | 需审批 | 是 |
webfile_upload | connection·localPath·remotePath·overwrite(默认 false) | 需审批 | 是 |
行为语义
- S3 没有真目录:目录 = key 前缀聚合;
mkdir写零字节key/标记对象;stat对无对象但有子项的前缀合成目录。 - FDS 与 S3 同模型:FDS 同样以
/模拟目录;协议差异在 provider 内部消化(见下节 FDS 细节)。 - 列表分页:结果截断时返回
truncated: true与nextToken(S3ContinuationToken/ FDSmarker透传),把nextToken传回即可续页;FTP 无服务端续页,截断时改大maxEntries重试。 - 覆盖保护:
overwrite默认false,目标已存在时报WEBBUF_EXISTS并提示显式开启。 - 递归保护:
delete对非空目录默认报WEBBUF_DIR_NOT_EMPTY;recursive: true删除整棵子树。 - 传输上限:
maxTransferBytes(默认 2 GiB)操作前前置校验,超限报WEBBUF_TOO_LARGE且不产生任何远端副作用。 - S3/FDS 大上传:≥
multipartThresholdBytes(默认 64 MiB)自动走 multipart,进度单调上报。 - 取消:传输中在 Jobs 面板 kill → 中止、清理本地半成品、job 终态
killed。 - S3 目录 move/copy:逐对象 copy(+delete),大目录耗时且中断可能留下半成品——工具描述与审批文案中已明示。
- FDS 目录 move/copy:同样逐对象 copy+批量删除,原因见下节;单文件 move 走原生 rename,零拷贝开销。
- FTP 符号链接:
list/stat以type=link呈现;递归删除只删链接自身、绝不跟随;copy 遇链接整体拒绝。
FDS 实现细节
- 协议与签名:FDS 是自有 REST API,不是 S3 线上协议。请求带
Authorization: Galaxy-V2 {AK}:{Sig},Sig = Base64(Hmac-SHA1(SK, StringToSign)),签名字符串覆盖 Method / Content-MD5 / Content-Type / Date(必填,请保持系统时钟与 FDS 同步)与规范化后的x-xiaomi-*头和 subresource(acl/quota/uploads/partNumber/uploadId/storageAccessToken/metadata)。 - 端点:缺省
{region}.fds.api.xiaomi.com;可用endpoint覆盖(内网xxx-fds.api.xiaomi.net);https: false走明文。 - 原生能力:单文件 move 使用
renameTo(服务端重命名,无需 copy+delete);目录递归删除使用deleteObjects批量端点。 - 分片上传:片大小固定 16 MiB(FDS 要求单片 5–50 MiB、片号连续);取消时 best-effort 调
abort避免残留分片计费。 - 平台限制:对象最大 100 GiB(cnbj2 等,cnbj0 已停用仅 2 GiB);Bucket 名 3–63 字节、域名规则;目录下文件多时 FDS 无 S3 式原子性保证,请知悉。
Web 传输卡片
在 Web GUI 中,每次 download / upload 会在对话流里生成一张传输卡片(webfile-transfer conversation node):方向、label、实时状态点(传输中带活动动画)、耗时、起止路径与终态结果。数据分两层:
- 持久层:host 半边在传输起止时向会话日志记录
webfile/transfer-start/webfile/transfer-end事件对,卡片据此在消息流中定位,并在 job 被 registry 丢弃后仍可回放终态。 - 实时层:客户端渲染器从
jobsBySession镜像读取该 job 的实时状态、时间戳与终态 detail,registry 丢弃后回落到持久事件数据。
卡片随 dsh.client 声明(package.json → dsh.client + exports["./client"])由浏览器端插件提供;pnpm build 产出 lib/client.js。它只在使用方 profile 组合了本包、且 Web 服务重启并刷新页面后生效(客户端插件表在启动时扫描);未组合进 Web 树时零影响——事件照常记录、模型侧 Jobs 面板不受影响。
安全说明
- 逐次授权:每个变更操作独立审批,无会话级豁免;
allowed-once是唯一放行态。 - 失败关闭:无审批通道(如纯 headless 未挂 answerer)或会话策略
approval/policy: never时,变更工具一律拒绝,绝不默认放行。 - 会话日志:工具参数(连接 id、remotePath 等)会随调用进入会话日志——路径敏感时请留意;密钥值永不进入。
- S3
CopyObject不可中止:服务端复制一旦发出无法取消,涉及大目录 move/copy 时请知悉。 - 下载落盘:一律经
ctx.fs写入工作区,受 DSH 文件沙箱策略管控。
错误码
| 码 | 含义 |
|---|---|
WEBBUF_UNKNOWN_CONNECTION | 连接 id 未配置(文案列出可用 id) |
WEBBUF_CREDENTIAL_MISSING | 声明的凭据引用没有值(文案点名变量名) |
WEBBUF_NOT_FOUND | 路径不存在 |
WEBBUF_EXISTS | 目标已存在且 overwrite: false |
WEBBUF_DIR_NOT_EMPTY | 非空目录且 recursive: false |
WEBBUF_PATH_TRAVERSAL | 路径含 .. 或为绝对路径 |
WEBBUF_TOO_LARGE | 超过 maxTransferBytes |
WEBBUF_PROTOCOL_ERROR | 协议层错误(如 FTP 拒绝跟随符号链接) |
兼容性
- Node:
^22.19.0 || >=24.0.0(与 DeepSeek Harness 对齐)。 - S3:任何实现 ListObjectsV2 / HeadObject / GetObject / PutObject / DeleteObject(s) / CopyObject / multipart 接口的对象存储(AWS、MinIO、各类 S3 兼容服务)。
- FDS:小米 Galaxy FDS 的 cnbj2 / awsbj0 / awsusor0 / awssgp0 / awsde0 / ksyru0-eco / awsind0-eco 区域(原生 REST + Galaxy-V2 签名,密钥在 dev.mi.com 创建)。
- FTP/FTPS:支持 MLSD 的服务器字段最全(修改时间精确);仅支持 LIST 的老服务器可用但时间字段缺失、目录类型靠权限推断;TLS 支持显式与隐式两种模式。
- 每操作短连接(v1 无连接池),超大规模高频场景见后续版本。
开发
仓库提交的 manifest 和 lockfile 统一使用 registry 包,确保本地开发与 CI 解析同一套依赖:
pnpm install
pnpm check # build + lint + 测试跨仓库联调时,使用 pnpm link <package-dir>... 在 node_modules 中替换指定包,不要修改 package.json 或 pnpm-lock.yaml。
提交规范:<type>(<scope>): <summary>。执行 pnpm exec lefthook install 后,lefthook commit-msg hook 会校验本地提交;CI 使用同一规则校验 PR 标题。
发布:完全自动化,由 semantic-release 驱动——每次合入 main 都会分析符合规范的提交历史,自动 bump 版本(fix → patch,feat → minor,如 0.1.1 → 0.2.0)、发布到 npm、推送版本 tag,并按提交自动生成 GitHub Release 的 release notes。源码中的 manifest 有意保持 0.0.0;Git tag 是版本记录。
首次发布需要在 GitHub Actions 的 NPM_TOKEN secret 中配置 granular automation token。包创建后,为 modestoma/dsh-webfile 和 ci.yml 配置 npm Trusted Publishing,再删除该 secret 以及工作流中的环境变量。后续发布使用短期 OIDC 凭据,并自动携带 npm provenance 证明。
License
[MIT](LICENSE) © 2026 modesto