dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Project secret management for the DeepSeek Harness: monorepo .env discovery, comment-preserving edits, and a DSH_ENV_FILES pointer your shell commands can source
DeepSeek Harness(下称 DSH)插件。
项目密钥管理:扫描 monorepo 里所有 .env(根目录 + 各 workspace 包)加上一层全局 $DSH_HOME/.env,在 Settings 页面里安全编辑,并把 DSH_ENV_FILE / DSH_ENV_FILES 交给 bash。
最省事的方式是用 DSH 自带的 plugin_manager 工具安装(会自动写 profile 并把插件行插进 composition):
# 或者手工装进当前 profile
cd "$DSH_HOME/profiles/<profile>"
pnpm add github:lifecoder1988/dsh-secrets-manager
本仓库自带的 cordis.patch.yml 就是它的 composition 行;手工接的话在 profile 的 cordis.patch.yml 里加:
- insert:
- id: secrets-manager
name: '@local/dsh-secrets-manager'
装完重启 DSH(host 半边改动需要重启;只有 client 半边的话刷新页面即可)。
「项目要有密钥」和「密钥不能进对话」是矛盾的:模型要用某个 token,就得知道它存在、并且能在 bash 里直接用,但不能把值念出来。本插件把密钥留在 .env 里,只给模型指针:
装好之后,每个 bash 调用都会拿到三个环境变量:
| 变量 | 内容 |
|---|---|
DSH_ENV_FILE | 离 cwd 最近的那个 .env;项目里一个都没有时就是全局 $DSH_HOME/.env |
DSH_ENV_FILES | 完整链(: 分隔):全局文件在最前,然后是仓库根→cwd 的项目文件 |
DSH_ENV_KEYS | 链上所有 key 的名字(去重,不含值) |
于是模型可以这样用,而永远看不到值:
set -a; for f in ${DSH_ENV_FILES//:/ }; do [ -f "$f" ] && . "$f"; done; set +a
$DSH_HOME/.env 是 DSH 自己启动时也读的那个文件(DSH_HOME 默认 ~/.dsh),所以它是唯一真正「对每个项目都生效」的 dotenv 路径。本插件把它排在链首:后加载的覆盖先加载的,项目就自然覆盖全局——同一个 key 在全局放默认值、在项目里放真值,是一条正常用法。
注意两件事:
.env 都没有时,那个目录照样拿到全局文件(这是加它的主要理由)。NEW_API_KEY)是启动时读的,改完要重启 dsh web 才生效;给 bash 用的密钥是每次调用现source,改完立刻生效。$DSH_HOME/.env 单独一张卡片/一个芯片,和项目文件一样可增删改;它排在链首,对所有项目生效。pnpm-workspace.yaml / package.json workspaces 里的每个包目录,各自的 .env / .env.local / .env.<mode> 都进索引(maxPackages 兜底)。.env***两种。.env 后一键重建索引(全局文件每次 shell 调用现读,不需要刷新)。project_secrets| action | 关键参数 | 说明 |
|---|---|---|
list | cwd? | 索引到的目录与各自的 key 名 + global 那层;带 cwd 时同时给 shell facts |
files | — | 所有 .env 文件路径 |
set | path?, scope?, key, value | 写入(保留注释与顺序);scope: "global" 写全局文件 |
remove | path?, scope?, key | 删除 key;scope: "global" 删全局的 |
scope: "global" 目标就是 $DSH_HOME/.env,不带 cwd 也能用(全局层不属于任何工作区)。scope 和 path 只能给一个,同时给会被拒绝。
/secrets-manager)| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /state?cwd=&sessionId= | 发现索引 + global 那层 + 每个目录的 key 名 |
| POST | /file | 读一个文件的 key(值遮蔽);全局文件同样走这里 |
| POST | /write | 写入 / 删除 key(项目文件或全局文件) |
| POST | /refresh | 重建项目索引 |
| slot | id | order |
|---|---|---|
settings.section | secrets-manager | 32 |
conversation.session.header.utilities | plugin-secrets | 53 |
.env.local)打头,下面依次是所属目录、键数、键名(超过 4 个折叠成「等 N 个」);点卡片会把下面的键列表带进视野。$DSH_HOME/.env 永远是网格里的第一张卡(标「全局」),和项目文件一样可增删改;它没被创建时卡片显示「未创建」,选中后给一个**「创建空文件」按钮(或者直接加第一个键,会一并创建)。选中全局文件时键列表上方会说明:它排在链首、项目覆盖它,以及DSH 进程自己也在启动时读它**。/file 读进了内存,所以这里的眼睛是纯本地切换;「复制值」整段进剪贴板,「编辑」写新值。.env 都没有时只有一张说明卡(含「在仓库根目录创建 .env」),不再出现「变量文件 · 0」这种空分组。图标点开就是一个可写的密钥面板,不用进设置页:
$DSH_HOME/.env 永远是第一个芯片(标成「全局 .env」),后面是当前项目发现到的每个 .env(含各有几个键);默认落在 shell 真正会用的那个文件上。POST /file 取一次并渲染,再点一次立刻把它从内存和 DOM 里丢掉;「复制值」同样只在点击时读一次。两种情况值都不会进模型上下文。KEY_NAME + 值;键名按 [A-Za-z_][A-Za-z0-9_]* 校验。选中全局文件时也会提示它「对所有项目生效、DSH 进程配置改完要重启」;文件还没创建时说明「保存第一个键时就会建」。.env 都没有时,面板会说明「当前只有全局层」,设置页仍提供**「在仓库根创建 .env」**。config:
maxPackages: 200 # 单次索引的包目录上限
dshHome: /path/to/.dsh # 全局层所在目录;默认 $DSH_HOME,再默认 ~/.dsh
globalEnv: /path/to/env # 直接指定全局 env 文件,优先级最高
node test/local-check.mjs
index.js host 半边:发现索引、注释保留写入、shellEnv 贡献、路由、project_secrets 工具
client.js 浏览器半边:Settings 页面 + 会话头部速查
cordis.patch.yml bundle patch
package.json dsh.bundle.patch / dsh.client 声明
test/local-check.mjs 离线自检
/write 的请求体与 .env 文件,不进任何模型可见的输出(list / /state 只给 key 名)。.env* 的文件——全局目录里的 credentials.yaml 之类一律拒绝(自检里有这条用例)。MIT