Workflow & Automation
dsh-agent-instructions
Bay-Zeddie/dsh-agent-instructions · ★ 3
在 dsh Web 设置页里编辑原生 AGENTS.md 的面板:指令链上每一层都是可点击的编辑入口,三种生效范围(工作区 + 全局 / 仅工作区 / 仅全局)通过给文件名加 .disabled 切换(内容不删),并可视化官方指令预算与分层占用。
README body is shown in Chinese.
Manifest details
安装
dsh plugin --profile web add 'github:Bay-Zeddie/dsh-agent-instructions#41d51a77c8729ddd7b01205eb0431aa794e17a62'GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试
For install and environment setup, plus plugin development tutorials, see DSH community docs ↗
README
Table of contents
给 dsh 原生的 AGENTS.md 加一个图形编辑面板,并把官方的指令加载语义如实反映到界面上。
人格、称呼、语气这些内容就写在 AGENTS.md 里,由你自己撰写 —— 插件不管内容语义。
# 桌面端安装:在应用的「插件」页添加本插件(GitHub 地址或本地路径),
# 或直接改 desktop profile 的 package.json(link: 依赖 + bundles 条目)。
# 重启应用后生效
装好后在 侧边栏 → Agent 指令(MCP 之下)打开。
想改代码:
git clone后在桌面端「插件」页以本地路径安装,改完刷新页面即可(client 侧热生效;host 侧改动需重启应用)。
- ✅ 侧边栏一级入口:官方
sidebar.panellist+main槽位注册(排在 MCP 之下),与「插件 / 自动化任务」同机制 - ✅ 读 / 改 / 存 任意一层:
<DSH_HOME>/AGENTS.md与工作区链上每一层的 4 个候选名 - ✅ 指令预算可视化:复刻官方发现链 + 官方渲染器(逐字节),按「全局链 / 项目链各一份
maxBytes」算真实注入量、丢弃与截断 - ✅ 列表即编辑器:按读取顺序列出每一层,点哪一行就在下面编辑那一份(每个标作用范围 + 字节 + 状态点:生效 / 已暂停 / 太长会被丢掉 / 太长会被截断 / 不会被读取 / 内容重复)
- ✅ 三种生效范围:
工作区 + 全局/仅工作区/仅全局—— 暂停即改名(加.disabled),内容一字节不丢,随时恢复 - ✅ 每一层都能单独暂停/启用(全局层与项目层走同一套机制,不再有"只有全局能暂停"的特例)
- ✅ 手写 React bundle(
React.createElement,不用 JSX)+ 官方ui-primitives控件,无构建步骤、无第三方依赖 - ✅ 样式全部读取 dsh 的
--dsw-*设计 token,自动跟随明暗主题与字号;磨砂配方与dsh-sunfragment-skin统一 —— 经--dts-glass-blur→--dsw-menu-backdrop-filter令牌链取同一个值(皮肤未启用时用同一字面量兜底),插件内只有--dsh-agent-glass一处定义,皮肤调档即跟随 - ✅ 界面语言跟随 dsh:中英双语,语言取自 dsh 自己的语言设置 —— 在 dsh 里切成英文,本插件跟着变,无需单独设
- ❌ 不修改任何 dsh 源码,只做适配
- ❌ 不注入系统提示词、不写入第二份身份文件、不改动 dsh 原生行为
想改代码 / 了解内部实现?见 CONTRIBUTING.md。
入口
唯一入口:侧边栏 → Agent 指令(与官方「插件 / 自动化任务」同一套一级面板机制,排在 MCP 之下)。
旧版的右下角浮动按钮已移除;v0.4.18 起设置页入口(
settings.section)也按主人裁决移除, 面板代码里不再保留设置页 / 回退行 / 模态外壳的任何残留。
访问范围(这个插件碰什么、不碰什么)
收录指南要求 README 讲清"插件访问什么",这里如实列出。host 侧只
import了node:crypto/node:fs/node:fs/promises/node:os/node:path—— 没有任何网络模块。
| 类别 | 具体范围 |
|---|---|
| 读 | ① 指令链上的候选文件(AGENTS.md / CLAUDE.md / AGENTS.local.md / CLAUDE.local.md 及其 .disabled 变体;全局层含 ~/.dsh 与 ~/.agents 两个根)② profile cordis.patch.yml —— 只读 id: agent-instructions 行的 maxBytes(渲染预算上限,可选覆盖)③ .git —— 仅作为"项目根"的存在性标记探测,不读其内容 |
| 写 | 仅限指令链白名单内的文件:AGENTS.md / AGENTS.local.md 及其 .disabled 变体。落盘走原子写(同目录临时文件 + rename,中途崩溃不会截断原文件);写入前会弹确认框 |
| 改名 | 同上白名单 —— 「暂停/恢复」靠加/去 .disabled 后缀实现,内容一个字节不删 |
| 网络 | 零外部请求。不发任何出站连接;也不向任何第三方上报数据 |
| 会话 | 不读取。插件不碰 session 记录、不读对话内容 |
| 拒绝的路径 | 链外路径一律拒绝(实测 6 类链外路径必须返回 403);base 必须是官方候选名位置,.disabled 由 base 推导、不接受外部直接指定 |
安装 / 卸载
# 安装:在桌面端应用的「插件」页添加本仓库(本地路径或 GitHub 地址);
# 或在 desktop profile 的 package.json 里加 link: 依赖 + bundles 条目,然后重启应用。
# 重启生效(host 侧代码在应用启动时装载)
# 卸载:先在「插件」页移除(或删掉 desktop profile 的 package.json 里的
# 依赖与 bundles 条目),再删链接与源码 —— 顺序不要反,否则会在 profile 里留下断链
pnpm remove不会清理node_modules/dsh-agent-instructions符号链接(link 安装的通病),需手动删除该链接。 link 安装时依赖必须装在插件源码目录(Node 从源码 realpath 解析)。
两级 AGENTS.md(官方机制)
| 层级 | 路径 | 生效范围 | 本插件入口 |
|---|---|---|---|
| 用户全局 | <DSH_HOME>/AGENTS.md(默认 ~/.dsh/AGENTS.md) |
该用户所有工作区 | 列表第 1 行 —— 点它即编辑,右侧开关即暂停/启用 |
| agents 全局(v0.5.1 新增适配) | ~/.agents/AGENTS.md(解析 DSH_AGENTS_HOME 环境变量 > ~/.agents) |
同上,所有工作区;与 dsh 全局同属同一去重组(同内容只加载 dsh 层那份) | 存在时出现在全局行之下 —— 点它即编辑,开关即暂停/启用;不存在不占位(官方 absent 即跳过) |
| 项目级 | <工作区>/AGENTS.md 等 4 个候选名,逐层 |
该工作区(含更深层) | 列表其余每一层 —— 每行一个编辑入口 + 一个开关 |
| 个性化(本地叠加) | <工作区>/AGENTS.local.md |
该工作区;在 AGENTS.md 之后加载 ⇒ 优先级更高;仅全局模式下不可用 |
工作区那层的额外一行「个性化规则」 —— 不存在也显示,点它写入即创建;编辑器给的是「我的偏好 + 补充约定」预设;通常不进版本控制 |
- 顺序:从宽泛到具体(全局 → agents 全局 → 项目根 → … → 会话工作目录)
- 预算:每条链各一份上限,由宿主组合行声明(dsh 44.7.0 的 dsh-base patch 默认
65536 字节;可在 profile patch 里用
id: agent-instructions行的maxBytes覆盖,maxBytes ≤ 0表示禁用预算——一个文件都不注入)。全局链与项目链各自受这一份上限约束 (合计最多 2×maxBytes);链内超出时从最宽泛的开始省略,只剩一份仍放不下才截断它 - 项目根靠
.git识别;AGENTS.local.md/CLAUDE.local.md是本地叠加层 - ⚠️ 本地叠加层只在项目 scope 存在,全局 scope 没有(官方
agent-instructions/README.zh.md原文: "项目 scope 默认加载 … overlay,但用户全局$DSH_HOMEscope 没有本地 overlay")。代码上files.ts:285的全局发现用的是写死的USER_GLOBAL_FILE = 'AGENTS.md'(render.ts:98), 完全不遍历候选列表 —— 所以连localInstructionFileCandidates配置项也覆盖不到它。 ⇒ 想让规则对所有工作区生效,只能写进~/.dsh/AGENTS.md本身(那是唯一文件,不是叠加层) - 补充实测:若会话 cwd 恰为
$DSH_HOME,则~/.dsh/AGENTS.local.md会被读到 —— 但它的层身份 仍是project(被"项目目录"逻辑捡到的),不是全局层。换句话说:文件能读到 ≠ 全局层支持它 - 生效时机:官方挂的是
ctx.on('agent/pre-step', …)钩子 —— 每一步请求前都会重新合成, 并按内容摘要(baseline.changes)检测变化后增量替换 ⇒ 改名/改内容不需要重启,对之后的请求即时生效, 同一会话内也会刷新(与 preset 层不同) $DSH_HOME解析(复刻官方优先级):显式配置 →$DSH_HOME环境变量 →~/.dsh;纯空白视为未设置
已知取舍
已接入官方 slot 体系(侧边栏一级面板
sidebar.panellist+main)。这不需要构建链:官方客户端产物的依赖形式 就是普通require——require("react")/require("react-dom/client")/require("@deepseek-ai/dsh-client-ui-primitives"),实测无需在package.json里声明即可解析(走共享静态表), 组件用React.createElement写、不用 JSX。官方注册形式(行与页面成对,id/key 同值):ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({ name: 'sidebar.panellist', id: PANEL_ID, order: 22, label: () => <文案 thunk>, }, IconComponent)) ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: PANEL_ID, }, PageComponent))⚠️
ctx.slots.register(options, component)只有两个参数(社区某插件传的第三个true是多余实参,别照抄); slot 名未被父节点声明时会throw⇒ 注册必须包try/catch并重试(slots.inject会随父声明自动执行, 重试只兜「已声明但抛错」这一种情况)。 ⚠️ 注意两处同名但语义不同的inject:bundle 里的exports.inject是 cordis 服务注入表 (要用ctx.slots就得写['slots']);package.json的dsh.client.inject才是模块/包级别声明。不做格式化 / 预览 —— 有意为之:AGENTS.md 是纯文本契约,插件不该重新排版它。
预算不是近似值,而是按官方渲染器逐字节模拟 —— 含
<system-reminder>边框、intro、 每文件的Instructions from:段头与 omitted marker,并复刻「两条链各自裁剪 + 合并」的规则。 唯一未模拟的是「会话中文件被改动」那一帧的Updated instructions from:段头(只影响措辞, 不影响字节量级)。tests/budget-parity.test.mjs用官方实现跑出的黄金样本盯着这条一致性。暂停靠改名,会在磁盘上留痕 ——
.disabled是真实的文件名变更。若该目录是 git 仓库,git status会显示一行改名; 不git add就只停在工作区,不进索引、不进历史(所以"误提交"不是会自动发生的风险,而是需要你主动做的动作)。 这是"不改官方源码、不写配置"的必然代价,换来的是随时可逆、内容零损失。未处理工作区目录不存在 —— 保存到不存在的目录会返回 404。
面板容器本身不加磨砂,只有卡片/编辑器/对话框有 —— 与官方一级页面同构(容器
background:transparent+ 无backdrop-filter,实测官方插件页容器同样是 transparent + bf:none)。皮肤明确警告:backdrop-filter加在容器上会成为 backdrop root、把 fixed 后代(气泡/弹层)的采样圈死在容器内。