- Home
- Plugins
- Tools & Capabilities
- dsh-plugin-oss-backup
dsh-plugin-oss-backup
kairoslll/dsh-plugin-oss-backup
DeepSeek Harness 插件:把工作区文件备份到 S3 兼容对象存储(RustFS / 阿里云 OSS / AWS S3)。AK/SK 只从环境变量读取,绝不落盘、绝不进日志。
Install
dsh plugin --profile web add github:kairoslll/dsh-plugin-oss-backupREADME
dsh-plugin-oss-backup
把文件备份到对象存储的 DeepSeek Harness 插件。支持 RustFS / MinIO 等自建 S3 兼容服务、 阿里云 OSS、AWS S3 —— 一次配置,之后在设置界面点几下就能把整个文件夹传上云。
⚠️ 安全须知(先读这一段)
- 优先用密钥管理器把凭证注入环境变量。 1Password CLI(
op run -- dsh web)、 HashiCorp Vault、AWS Secrets Manager、Azure Key Vault、Doppler、direnv 都行 —— 插件只读process.env,所以让密钥留在它该待的地方, 远比复制粘贴到某个文件里安全。具体接法见 凭证接入指南。 - 不要用主账号密钥。 请新建一个只能读写指定桶的子账号,只给它
PutObject权限。 本文「第 2 步」有现成的配置可抄。 - 别把密钥写进会被提交的文件 —— README、issue、脚本、截图、Dockerfile 都算。
本插件支持
.env(启动时自动读、只读不写),但它只适合本地临时使用; 用之前务必确认.env在.gitignore里(本仓库已挡.env/.env.*/*.key/*.pem)。 - 密钥一旦出现在聊天记录、日志或提交历史里,就当它已经泄漏 —— 立刻去服务商后台轮换掉。
- 本插件自己不会把密钥写到磁盘上。 密钥只在内存里流转,界面永远只显示"已设置 / 未设置",
日志里也只会出现变量名,不会出现变量值。(
.env是你写的、插件只读 —— 落不落盘由你决定。) - 想确认这一点,可以在配好之后自己检查:
~/.dsh/oss-backup/config.json里 只会有开关、目录、桶名这类非机密信息,不会有任何密钥。
一、它能做什么
四个用法
| 用法 | 说明 |
|---|---|
| 手动备份整个文件夹 | 在设置界面填一个目录,点「立即备份」,它就会把该目录(含所有子目录)递归传上去 |
| 定期全量备份 | 按时间表(每 N 分钟 / 小时 / 天,或每天、每月固定时刻)自动把整个目录完整传一遍 |
| 文件改动自动备份 | 打开开关后,每次保存文件(模型用 write / edit 改文件)都会在 2 秒后自动上传 |
| 让模型上传单个文件 | 模型可以直接调用 oss_backup 工具,把一个本地文件传到指定的对象路径 |
| 《接数据》(趣味) | 点「立即备份」时先在「上传状态」框里玩一局节奏小游戏,通关才真的开始备份。不想要可以在设置里关掉 |
支持的对象存储
| provider | 适用 | 寻址方式 |
|---|---|---|
rustfs(默认) | RustFS、MinIO 等自建 S3 兼容服务 | path-style |
aliyun | 阿里云 OSS | 虚拟主机风格 |
aws | AWS S3(也可指向其它 S3 兼容服务) | 虚拟主机风格 |
已实测通过:RustFS 真实上传(本机)、阿里云连通性。AWS 与阿里云的完整上传流程 依赖你自己的账号环境,仓库里的配置示例可直接照抄。
界面上有什么
- 设置 → 对象存储备份(与主面板内容一致):
- 顶部两张卡片:存储端点、环境状态(是否配好、密钥是否已设置);
- 上传状态:进度条 + 最近几次上传的大小;;
- 云端备份按钮:打开当前 provider 的网页控制台,方便核对桶里的内容;
- 设置:自动备份开关、备份目录、「跳过依赖 / 缓存目录」开关,以及折叠的「高级设置」;
- 凭证:在界面里临时填写密钥(见第四节);
- 手动备份:「立即备份」按钮 + 进度条 + 上次结果;
- 环境自检:provider / 端点 / 桶 / 区域 / 密钥是否已设置;
- 最近上传:时间、对象路径、大小。
- 左侧栏:一栏状态提示(
已就绪/上传中/缺配置/未连接)。
二、安装
cd <你的插件目录>
pnpm add dsh-plugin-oss-backup # 或把打好的 .tgz 装进 DSH profile
装完后重启 dsh web,设置页里就会出现「对象存储备份」。
本地开发时安装的坑(点开看)
不要用 link: 安装本地包。 症状是启动时报 dsh-plugin-oss-backup: failed to import:
link: 会在 profile 里建一个指向源码目录的软链接,而 Node 解析模块时会先取真实路径,
于是解析起点跳出了 ~/.dsh/profiles 目录树,插件依赖的宿主模块就找不到了。
正确做法是先打包再安装:
pnpm pack # 产出 dsh-plugin-oss-backup-x.y.z.tgz
pnpm add file:<绝对路径>/dsh-plugin-oss-backup-x.y.z.tgz
三、配置(照着做就行)
第 1 步:决定用哪个 provider
选一个就好:
OSS_PROVIDER=rustfs # 默认值,自建服务(RustFS / MinIO)
OSS_PROVIDER=aliyun # 阿里云 OSS
OSS_PROVIDER=aws # AWS S3
不设置 OSS_PROVIDER 时按 rustfs 处理。
第 2 步:创建最小权限子账号(必做)
不要跳过这一步。 用主账号密钥意味着一旦泄漏,整个云账号都危险。
阿里云 OSS(RAM 子账号)
- 控制台 → RAM 访问控制 → 用户 → 创建用户,勾选"OpenAPI 调用访问" (只拿 AccessKey,不要开控制台登录);
- 创建自定义权限策略(不要用
AliyunOSSFullAccess这类系统策略),把dsh-backup换成你自己的桶名:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": ["oss:PutObject", "oss:GetObject", "oss:HeadObject"],
"Resource": ["acs:oss:*:*:dsh-backup/*"]
},
{
"Effect": "Allow",
"Action": ["oss:ListObjects", "oss:GetBucketInfo"],
"Resource": ["acs:oss:*:*:dsh-backup"]
}
]
}
- 把这个策略授权给刚建的用户;
- 记下它的 AccessKey ID 与 Secret,下一步要用。
AWS S3(IAM 用户)
把上面的策略换成 IAM 语法即可(Resource 形如 arn:aws:s3:::dsh-backup/*):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowBackupObjectsOnly",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::dsh-backup/*"]
},
{
"Sid": "AllowListOwnBucket",
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::dsh-backup"]
}
]
}
RustFS / MinIO
mc admin user add <alias> dsh-backup-bot '<一个强随机密码>'
mc admin policy create <alias> dsh-backup-rw ./dsh-backup-rw.json # 内容即上面的通用策略
mc admin policy attach <alias> dsh-backup-rw --user dsh-backup-bot
第 3 步:设置环境变量
挑你自己那一档,把值换成上面拿到的密钥。
强烈建议优先用密钥管理器接入。 下面的
setx示例只是"最不依赖任何工具"的写法; 更好的做法是让 1Password / Vault / AWS Secrets Manager 这类工具在启动dsh web时 把凭证注入环境变量 —— 密钥就不用出现在 shell 历史、脚本或任何磁盘文件里。 完整的接入清单(1Password / Bitwarden / Vault / AWS / Azure / Doppler / direnv / Docker / systemd)见 凭证接入指南。
先说清一件事:值从哪来都行。 插件只关心"这个键在你的进程环境里存不存在", 不关心它怎么来的。下面这些完全等价,用你顺手的那个:
| 来源 | 怎么做 |
|---|---|
| 密钥管理器(推荐) | op run -- dsh web(1Password)、doppler run -- dsh web、Vault / AWS Secrets Manager 等 —— 见接入指南 |
| 系统环境变量 | Windows setx、macOS / Linux export(下面就是这一种) |
.env 文件 | 复制 .env.example 改成 .env,放到 <DSH home>/oss-backup/.env 或当前工作目录 —— 插件启动时自动读(只适合本地临时用,务必确认它被 gitignore) |
| Docker | docker run -e RUSTFS_ACCESS_KEY=... |
| CI | GitHub Actions Secrets / GitLab CI Variables 之类 |
.env 的几条规则(只读,插件永不写入):
- 优先级:
.env> 系统环境变量。.env是你显式写下来的那份,比机器上残留的 旧export更权威 —— 否则"我在.env里改了却毫无效果"会非常难查。 被覆盖的键名会进日志与界面(只有名字,没有值); - 只采用第一个能读到的文件(先看
<DSH home>/oss-backup/.env,再看当前工作目录), 不做多层合并 —— 否则出问题时没法解释某个值来自哪份文件; - 解析规则就那几条:
KEY=value、KEY="value"、export KEY=value、#注释。 不支持行内注释、多行值、变量展开 —— 支持它们只会让"值被悄悄改掉"成为可能的解释; - 改了
.env要重启dsh web才生效(和系统环境变量一样)。
① RustFS / MinIO
setx OSS_PROVIDER "rustfs"
setx RUSTFS_ENDPOINT "http://127.0.0.1:9000"
setx RUSTFS_BUCKET "dsh-backup"
setx RUSTFS_ACCESS_KEY "<子账号 AK>"
setx RUSTFS_SECRET_KEY "<子账号 SK>"
② 阿里云 OSS
setx OSS_PROVIDER "aliyun"
setx OSS_BUCKET "dsh-backup"
setx OSS_REGION "oss-cn-hangzhou" # 默认就是这个
# OSS_ENDPOINT 可以留空:会自动拼成 https://oss-cn-hangzhou.aliyuncs.com
setx OSS_ACCESS_KEY_ID "<RAM 子账号 AccessKey ID>"
setx OSS_ACCESS_KEY_SECRET "<RAM 子账号 AccessKey Secret>"
如果你显式设
OSS_ENDPOINT,一定要带上https://。不带协议头时会被当成http://处理,连接必然失败。
③ AWS S3
setx OSS_PROVIDER "aws"
setx AWS_BUCKET "my-backup-bucket"
setx AWS_REGION "us-east-1" # 必填
setx AWS_ACCESS_KEY_ID "<IAM 用户 AccessKey ID>"
setx AWS_SECRET_ACCESS_KEY "<IAM 用户 Secret Access Key>"
# AWS_ENDPOINT 一般留空,表示用 AWS 官方端点
macOS / Linux 把
setx X "v"换成export X="v",并写进你的 shell 配置文件。
第 4 步:重启 dsh web
这一步不能省。 环境变量是进程启动时读取的,正在运行的 dsh web 不会自动感知新变量。
第 5 步:确认配置成功
重启后打开 设置 → 对象存储备份,看「环境自检」:
- 状态应显示「就绪」;
provider一行会写明当前用的是哪一档(例如RustFS / MinIO 等自建 S3 兼容端点 · path-style);- 密钥两行应显示「已设置(值不显示)」。
⚠️ 「就绪」不只看变量配没配齐:插件会真的对存储桶发一次 HeadBucket 去确认服务能连上
(结果缓存 30 秒)。所以还有第三种状态:
| 状态 | 含义 | 怎么办 |
|---|---|---|
| 就绪 | 变量齐了,服务也连得上 | 可以直接用 |
| 变量齐了,但服务连不上 | 端点/桶/密钥有一处不对,或者服务根本没启动 | 看下方红字里的具体原因 |
| 缺少 N 个变量 | 环境变量没配齐 | 那一行会列出缺哪个变量名 |
「服务连不上」这一条是专门为下面这种情况加的:变量都填好了、但 RustFS 没开 —— 以前会显示成"就绪",看着一切正常,实际上每次上传都在连接被拒。
小贴士:
setx设了但插件说"未配置"?setx写入的是用户级环境变量,而已启动的进程(尤其是从快捷方式、启动器拉起来的dsh web)不一定继承得到它。所以插件每次启动都会主动去读一遍系统里的环境变量 (先看进程已有的,再看用户级,最后看系统级),缺什么补什么 —— 不会覆盖你已经设好的值。 界面上会标注「当前来自系统环境变量(启动时自动补读:…)」,看到它就说明补读成功了。 你只需要保证设过值 + 重启过一次。
四、使用
手动备份一个文件夹
- 打开 设置 → 对象存储备份 → 设置;
- 在「备份目录」里填要备份的目录(例如
D:\projects\my-project); - 点「保存」;
- 回到「手动备份」块,点「立即备份」。
它会递归备份整个文件夹,完成后显示:共多少个文件 → 成功几个 / 失败几个 · 总大小。
没变化的文件会自动跳过。 插件在 ~/.dsh/oss-backup/uploaded.json 里记着每个对象键对应的
(文件大小, 修改时间),下次备份时一致的直接跳过 —— 所以重复点「立即备份」只会传真正改过的
那几个,不会再把你几千个没动过的文件重传一遍。界面会显示「跳过 N 个未变化的」。
判定依据是大小 + 修改时间。改了内容一般也就会改修改时间,所以会被正确重传; 只有"内容变了但大小和修改时间都没变"这种刻意为之的情况才会漏判。 换机器或删掉那个索引文件也不影响正确性 —— 只是会重传一次,之后恢复正常。
上传后的对象路径规则是 前缀 + 被备份目录自己的名字 + 相对路径。例如备份
D:\projects\projects\yy(里面是 11、22 两个子文件夹),桶里会出现:
workspace-backup/yy/11/...
workspace-backup/yy/22/...
yy 这一层会保留,这样在桶里一眼就能看出这批文件属于哪个目录。
会自动跳过的目录:
node_modules、.git、.hg、.svn、.pnpm-store、.npm-cache、__pycache__、.venv。这些要么体积巨大,要么是可再生的产物。 想让备份"一个文件都不少",把设置里的「跳过依赖 / 缓存目录」开关关掉即可。限额:最多 2000 个文件、单个文件最大 5 GB、总量 50 GB。触发上限时界面会提示 「已触到文件数上限」。
超过 8 MB 的文件走分片上传(
@aws-sdk/lib-storage,每片 8 MB、4 片并发), 内存占用恒定、与文件大小无关 —— 所以单文件上限敢放到 5 GB(S3 单次 PUT 的上限; 分片协议本身允许到 5 TB)。这几个数只是防呆,用来拦住"误选了整个磁盘"。误选了也没关系:备份途中可以点「强行打断」。 它会立刻停下 —— 正在传的那个文件 被掐断(在途的分片请求一并中止),已经传完的不受影响,也不会被记成"失败"。 下次备份会从没传完的地方继续(查重会跳过已成功的那部分)。
《接数据》(备份前的小游戏)
点「立即备份」时,如果游戏开关是开着的,会先在「上传状态」那一格里来一局节奏小游戏 《接数据》—— 通关了才真的开始备份。 不想玩的话,把设置里的开关关掉,之后点按钮直接开始。
怎么玩
- 四条轨道,方块从右往左滑;键盘
DFJK对应四条轨道(键位标在判定线左侧,一直在), 也可以直接用鼠标点那条轨道; - 左侧有一条判定线,方块经过它的一瞬间点掉它;
- 判定分三级,窗口挺严的:
| 判定 | 条件 | 扣分 |
|---|---|---|
| PERFECT | ±0.09 秒内点中 | 不扣分 |
| GOOD | ±0.175 秒内(不够准) | 扣 0.5 个 |
| LOST | 过了 0.175 秒都没点 | 扣 1 个 |
命中时判定线会亮起、对应轨道扫过一层光、判定处扩散一圈光环 —— PERFECT 是品牌色、GOOD 是灰色, 一眼就能看出自己准不准。
四档难度
| 难度 | 一局时长 | 特点 |
|---|---|---|
| 杂鱼 | 约 22 秒 | |
| 简单 | 约 29 秒 | |
| 中等 | 约 36 秒 | |
| 齁哦哦哦 | 约 45 秒 |
难度会记住,下次打开还是这一档。
计分规则
满分 100 分,扣分按总方块数分摊:
扣分 = (GOOD × 0.5 + LOST × 1) ÷ 总方块数 × 100
也就是 PERFECT 完全不扣分,GOOD 扣半个,LOST 扣一个。参考:
- 全部 PERFECT → 100 分;
- 全部 GOOD → 50 分(这也会失败);
- 全部 LOST → 0 分。
结果为:
- 扣分 < 30 → 通过,备份自动开始;
- 扣分 ≥ 30 → 失败,备份不会触发
用"按总数分摊"而不是"每个失败固定扣几分",是为了让四档难度的容错率一致 —— 高难度方块多得多,固定扣分会让它直接变成不可能完成。
文件改动自动备份
在设置里把「自动备份」开关打开(点一下立即生效)。
之后每次模型保存文件,该文件会在停止改动 2 秒后自动上传;上传失败会自动重试 3 次 (间隔 1 秒 / 2 秒 / 4 秒),仍失败就只记一条日志,不会影响你正常的写文件操作。 开关关闭时完全不生效,这是默认状态。
连不上时直接不提供上传
- 确认连不上之后,所有上传入口一起停:模型调
oss_backup会被直接拒绝、 「立即备份」按钮变灰并说明原因、自动备份与定期备份都不再排期; - 连接 / 凭证 / 桶名这类错误不重试 —— 它们不会因为多等 4 秒就变好,直接失败;
- 连续失败 3 次也会熔断,暂停 60 秒,期间的文件改动直接跳过、不排队;
- 界面上写明原因(例如
ECONNREFUSED),服务恢复后自动重新可用,不用重启。
注意:这个开关监听的是模型的文件写入操作。如果你用命令行工具(例如
git、 脚本)直接改文件,不会触发自动备份 —— 那种情况请用手动备份。
定期全量备份
在设置界面的「定期全量备份」一行选模式(改完点「保存」生效),宿主会按时间表把整个备份目录 完整传一遍 —— 与上面「文件改动自动备份」是两套独立的机制,可以只开一个,也可以都开。
| 模式 | 说明 | 例子 |
|---|---|---|
| 关闭 | 默认,不排期 | — |
| 按间隔 | 每 N 分钟 / 小时 / 天 | 每 6 小时 |
| 每天 | 每天固定时刻 | 每天 03:00 |
| 每月 | 每月固定几号的固定时刻 | 每月 1 日 03:00 |
设置那一行下面会显示下次实际触发时间,方便确认排期对不对。
几个刻意的设计,避免你踩坑:
- 固定节拍:「按间隔」对齐到排定时刻,不是"从现在往后加一段"。每 30 分钟就是
:00和:30,每 6 小时就是00/06/12/18,「每 N 天」对齐到当地零点 —— 一次备份跑多久都不会把后续时间点往后推; - 内部用的是"跑完再排下一次"的链式定时器(不是
setInterval),所以也不会堆叠出好几次备份; - 上一次还在跑就跳过这一轮(不排队),日志里会记一条"跳过";
- 每月只支持 1-28 号:这样每个月都一定存在,不会遇到"2 月没有 30 号"那种要么跳过一个月、 要么被顺延到 3 月 1 号的情况;
- 还没设置备份目录时不会排期,只记一条日志提醒你;
- 时间点用的是本机时区。
备份范围、排除规则(
node_modules/__pycache__等)和文件数 / 体积限额, 与「手动备份」完全一致 —— 它俩共用同一套逻辑。
凭证(在设置界面里临时填写密钥)
如果你不想用 setx,也可以在设置界面的「凭证」块里直接填 AK/SK,点
「应用到本次进程」:
- 填完立刻生效,可以马上试一次手动备份;
- 只对本次运行有效 —— 重启
dsh web后需要重新填; - 提交后输入框会立即清空,界面上永远不会回显你填过的值;
- 想让配置永久有效、以后都不用填,还是用
setx(见第三节)。
高级设置
展开「高级设置」,可以改这些非机密项(会保存下来,重启后仍在):
| 项 | 说明 |
|---|---|
| 对象键前缀 | 桶里的目录层级,默认 workspace-backup/ |
| Provider | 覆盖 OSS_PROVIDER(留空则用环境变量) |
| 端点 | 覆盖端点(留空则用环境变量或按区域自动推导) |
| 存储桶 | 覆盖桶名(留空则用环境变量) |
| 区域 | 覆盖区域(留空则用环境变量或默认值) |
优先级:Provider 以设置页为准(这是你在界面上明确选的),端点 / 桶 / 区域 以环境变量为准(已经设过的不会被悄悄改掉)。
让模型上传单个文件
模型可以直接调用 oss_backup 工具,传一个本地文件和目标对象路径,例如:
把
D:\backup\report.tar.gz上传到对象存储,objectKey用backups/report.tar.gz
这是单文件上传;要备份整个文件夹请用上面的「手动备份」。
云端备份按钮
「云端备份」按钮会打开当前 provider 对应的网页控制台,方便你在网页里核对桶里的内容。 地址由插件按你的配置推导,换 provider 之后按钮自己就指对了:
| provider | 打开哪里 |
|---|---|
| rustfs(自建 / MinIO) | 本机网页控制台 —— 由端点端口 +1 推出来(http://127.0.0.1:9000 → http://127.0.0.1:9001/) |
| aliyun | 阿里云 OSS 控制台,直达当前这个桶的对象列表 |
| aws | AWS S3 控制台,直达当前这个桶(带上你配的 region) |
按钮旁边会显示完整地址并做成真链接 —— 万一浏览器拦下了新窗口,点链接照样能打开。 端点或桶还没配好时,这一块会直说"地址推导不出来",而不是给一个打不开的链接。
五、常见问题
Q:环境自检显示「缺少 N 个变量」怎么办?
那一行会列出具体缺哪个变量名。按第三节补上,然后重启 dsh web。
Q:明明 setx 过了,为什么还说未配置?
两个常见原因:① 设完没有重启 dsh web;② 变量设到了别的账户下
(例如你在管理员终端里 setx,但 dsh web 跑在普通用户下)。
插件启动时会主动补读系统环境变量,所以只要"设过 + 重启过"就会生效。
Q:上传失败,怎么排查? 界面的「手动备份」块会显示失败条数,以及最多 5 条失败原因;「最近上传」里也有记录。 常见原因:密钥没有目标桶的写权限、桶名写错、端点地址不对、网络不通。
Q:备份目录里文件太多,会不会传很久? 会。手动备份是逐个文件上传的,且带上面说的限额。建议备份项目目录, 而不是整个磁盘根目录。
Q:重启后设置还在吗?
在。「开关 / 备份目录 / 前缀 / 跳过缓存 / provider / 端点 / 桶 / 区域」都保存在
~/.dsh/oss-backup/config.json,重启后自动恢复。
只有密钥在"界面临时填写"那种方式下需要重填 —— 用 setx 就没这个问题。
Q:界面上会显示我的密钥吗? 不会,任何时候都不会。界面只显示「已设置」或「未设置」。
Q:备份上去的文件怎么恢复? 直接用你对象存储服务商的控制台或命令行下载即可(对象路径见上面的规则)。 本插件只负责上传。
Q:能同时配多个桶 / 多套账号吗? 不能。插件一次只对一个存储目标生效,切换需要改环境变量或「高级设置」里的覆盖值。
六、安全说明
你的密钥是怎么被处理的
这个插件按四条原则设计,每一条都由代码结构保证,而不是靠"记得别打印":
| 原则 | 具体做法 |
|---|---|
| 代码里没有明文密钥 | 整个仓库里只有变量名(如 RUSTFS_ACCESS_KEY),没有任何真实值;.env.example 里全是空占位 |
| 日志和错误里不出现密钥 | 加载日志只报变量名;报错只说缺哪个变量;所有对外文本在出口还会再走一遍脱敏,抹掉密钥字面量以及签名形态(X-Amz-Signature、Signature=、Credential=、URL 里的用户名密码等) |
| 密钥不写入本地文件 | 插件不读 .env;config.json 只保存非机密项;界面上临时填写的密钥只存在于进程内存里 |
| 前端拿不到密钥 | 界面跑在浏览器沙箱里,没有读取环境变量的能力。它唯一的数据来源是一条只读的脱敏状态接口,密钥部分只有"是 / 否"。界面填写的密钥是单向送进宿主的,宿主永远不回传 |
你应该注意什么
-一定一定优先用密钥管理器接入!!!本插件不自带密钥管理器功能。
- 务必用最小权限子账号,并且只授权你真正需要的那个桶;
- 不要在共享电脑、共享屏幕上操作「凭证」块,也不要在填完后让别人看你的浏览器;
- 定期在服务商后台轮换密钥;
- 如果怀疑泄漏,先吊销再排查,不要抱侥幸心理;
- 本插件只能保护"它自己不泄露密钥",无法保护你把它贴到聊天窗口或提交进 Git。
仓库自带的检查
如果你要参与开发或二次分发,仓库里有两道自动检查:
pnpm run check:secrets # 扫描仓库里有没有明文密钥(会与环境里真实的凭证值比对)
pnpm run check:load # 构建产物能否正常加载
CI(GitHub Actions)里还跑 Gitleaks,会扫描提交历史,一旦发现疑似密钥就让构建失败。
七、开发者信息
pnpm install
pnpm run build # 编译 host(tsc)+ 打包 client(esbuild)
pnpm test # 258 个单元测试
pnpm run typecheck:client
pnpm run check:secrets
pnpm run check:load
项目结构
src/
index.ts host 入口:注册工具 + 四条 HTTP 路由(状态 / 设置 / 凭证 / 手动备份)
env.ts provider 档案(rustfs / aliyun / aws)与环境变量校验
env-source.ts 启动时补读系统环境变量(Windows)
dotenv.ts 启动时补读 `.env`(**只读,永不写入**;优先级高于系统环境)
settings.ts 设置读写(只存非机密项)
auto-backup.ts 自动备份:防抖 + 指数退避重试 + 对象键净化
manual-backup.ts 批量备份:目录遍历、排除名单、限额、查重、逐个上传
upload-index.ts 已上传文件索引(只存大小与修改时间,用于跳过没变化的文件)
upload.ts S3 客户端构造 + PutObject
redact.ts 出口脱敏
client/ 界面(设置页 / 侧边栏 / 主面板)
assets/
code-uploading.jpg 上传中弹出的那张图
scripts/ 构建、真实上传冒烟、密钥自检、加载自检
tests/ vitest
发布
pnpm run build && pnpm test && pnpm run check:secrets && pnpm run check:load
npm pack --dry-run # 确认包里有 lib/、assets/、cordis.patch.yml、README.md、LICENSE
npm publish
设计上的两个注意点
webServer必须是硬依赖(inject里列上)。用软取(ctx.get)时,apply阶段该服务 可能还没就绪,会导致路由静默不注册,症状是设置页永远"未连接"。- client bundle 的模块 id 必须是包名。
client-modules按最近归属的package.json判定浏览器模块 id,写错会报loaded without registering并让界面半边失效。
License
MIT —— 见仓库根目录的 LICENSE 文件。
形象来源与许可
「接数据」小游戏与界面中出现的鲸鱼娘等形象取自 @ZipZipPipe, 基于 @上善无形 原创角色二创,依 CC BY-NC-SA 4.0 协议非商业使用。
这些形象不在本项目的 MIT 许可范围内 —— MIT 只覆盖代码。
Related plugins
archify (deepseek-harness)
tt-a1i/archify
WeKnora (dsh-weknora)
tencent/weknora
weknora
tencent/weknora
BrowserSkill (dsh-plugin-browserskill)
tencent/browserskill