# dsh-agent-prompt 编辑 DeepSeek Harness 实际加载的 `AGENTS.md` 指令文件——用户全局的和每个工作区的 ——直接在 GUI 左侧边栏的面板里完成。 [English](README.md) | **中文** [![License](https://img.shields.io/github/license/icrefin/dsh-agent-prompt?style=flat-square)](LICENSE) [![Release](https://img.shields.io/github/v/release/icrefin/dsh-agent-prompt?style=flat-square)](https://github.com/icrefin/dsh-agent-prompt/releases/tag/v0.1.0) [![CI](https://img.shields.io/github/actions/workflow/status/icrefin/dsh-agent-prompt/ci.yml?branch=main&style=flat-square)](https://github.com/icrefin/dsh-agent-prompt/actions/workflows/ci.yml) [![Last commit](https://img.shields.io/github/last-commit/icrefin/dsh-agent-prompt?style=flat-square)](https://github.com/icrefin/dsh-agent-prompt/commits/main) [![Stars](https://img.shields.io/github/stars/icrefin/dsh-agent-prompt?style=flat-square)](https://github.com/icrefin/dsh-agent-prompt/stargazers) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](https://github.com/icrefin/dsh-agent-prompt/pulls) [![Node](https://img.shields.io/badge/node-%3E%3D22.17-339933?style=flat-square&logo=node.js)](https://nodejs.org) [![dsh](https://img.shields.io/badge/dsh-0.2.0--rc.2-4B5563?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness) **Agent Prompt** —— 在 GUI 左侧边栏的面板里,编辑 DeepSeek Harness 实际加载的 `AGENTS.md` 指令文件。 DSH 会在每个会话开始时注入工作区指引,内容取自与 `AGENTS.md` 兼容的文件: 一个用户全局文件,外加一条项目链。平时改这些文件,得开外部编辑器、进终端, 一次只处理一个路径。本插件把它们收进同一个页面:左边是全部全局与各工作区 指令文件的树,右边是纯文本编辑器,再加上一个 Save 按钮——它写下的正是 agent 下个会话将要读到的那些字节。 ![Agent Prompt 面板:左侧文件树,右侧纯文本编辑器](docs/preview.png) ``` ┌── Agent Prompt ────────────────────────────────────────────────────────────┐ │ Filter workspaces… │ ~/workspace/dsh-plugins/AGENTS.md │ │ │ ┌───────────────────────────────────────────┐ │ │ GLOBAL │ │ Save Reload │ Undo Redo │ Wrap │ │ │ ● User-global │ ├───────────────────────────────────────────┤ │ │ ~/.dsh/AGENTS.md │ │ # dsh-plugins │ │ │ WORKSPACES │ │ │ │ │ ● dsh-plugins │ │ Instructions for agents working in this │ │ │ ○ harness (new) │ │ repository. │ │ │ │ └───────────────────────────────────────────┘ │ │ │ 20 lines 531 chars Saved │ └────────────────────────────────────────────────────────────────────────────┘ ``` ## 它贡献了什么 | 界面 | 作用 | |---|---| | 侧边栏行 **Agent Prompt** | 图标栏里的一行全局面板,就排在 **Schedules** 正下方 | | **Agent Prompt** 页面 | 左侧文件树(全局 + 每个已注册工作区一个节点,带过滤器)和右侧编辑器 | | `GET /api/agent-prompt/tree` | 解析后的文件清单,含每个文件的存在性、大小和 mtime | | `GET /api/agent-prompt/file?key=…` | 读取一个指令文件 | | `POST /api/agent-prompt/file` | 写入一个指令文件,文件或其目录缺失时一并创建 | ## 它编辑哪些文件,以及为什么是这些 宿主这一半用与加载这些文件的包 [`@deepseek-ai/dsh-agent-instructions`](https://www.npmjs.com/package/@deepseek-ai/dsh-agent-instructions) 完全相同的规则解析路径。它随包发布的默认值是 `projectRootMarkers: ['.git']`、`instructionFileCandidates: ['AGENTS.md', 'CLAUDE.md']` 和 `dshHome: $DSH_HOME || ~/.dsh`;`@deepseek-ai/dsh-base` 里的 `agent-instructions` 行只设置了 `maxBytes`,所以这套部署里没有任何路径被覆盖。 | 节点 | 解析规则 | |---|---| | **用户全局** | `$DSH_HOME/AGENTS.md`,回退到 `~/.dsh/AGENTS.md`。空或全空白的 `$DSH_HOME` 都算作未设置,与加载器保持一致。 | | **某个工作区** | 从已注册的工作区目录向上走,直到第一个含 `.git` 的祖先目录;文件即 `/AGENTS.md`。一路都没有标记时,向上查找终止于工作区目录本身。 | 树中每个节点都显示解析后的绝对路径,文件尚不存在时会标上 `not created` ——保存即创建它。如果某个工作区的项目根与它自身的目录不同(比如 monorepo 里的一个包),显示的是它的仓库根,而不是那个包。 **只提供 `AGENTS.md`。** 加载器在项目链的每一层还接受 `CLAUDE.md`、 `AGENTS.local.md` 和 `CLAUDE.local.md`,并且同样会编辑它们。这些不在本插件的 范围内;这个面板刻意做到每个作用域只对应一个文件。 ## 页面 两处注册,key 都是 `agentPrompt`: | Slot | 注册 | 效果 | |---|---|---| | `sidebar.panellist` | `id: 'agentPrompt'`、`order: 11` | 那一行图标 | | `main` | `key: 'agentPrompt'` | 该行在中间栏打开的页面 | 页面标题带着面板版本和作者署名——`Agent Prompt v0.1.0 Author: icrefin [icrefinai@gmail.com]`——作为 `20px/500` 标题旁的一枚弱化标签,与 `dsh-skill-mgr`、`dsh-mcp-mgr` 一致。 与那两个不同,**这个版本号是构建时内联进浏览器 bundle 的**,而不是从宿主取。 一个插件的前后两半并不同步更新:浏览器 bundle 一旦 revision 变化就立刻被重新 导入,而宿主这一半是启动时的 ESM 导入,会一直提供进程启动时载入的那份代码。 所以只要客户端跑到了正在运行的宿主前面,从宿主取来的标签就会变空——这个面板 当初渲染出一个光秃秃的 `v`,就是这么来的。`tsdown.config.ts` 读取 `package.json` 并定义 `__DSH_AGENT_PROMPT_VERSION__`;`src/client/version.ts` 导出它,值为空时 该标签直接不渲染。 选择这一行调用的是 `ctx.layout.selectPanel('agentPrompt')`,即在运行中的 `main` 注册表里做一次查找,因此两者从构造上就共用同一个 id。`dsh.client.inject` 把 bundle 排在 `dsh-client-ui-sidebar` 和 `dsh-client-ui-layout` 之后,也就是声明 这两个 slot 的那两个包之后。 ### 编辑器命令 | 命令 | 快捷键 | 说明 | |---|---|---| | Save | `⌘S` / `Ctrl+S` **页面任意位置** | 草稿与磁盘内容一致前禁用 | | Reload | — | 丢弃草稿并重新读取文件;有未保存修改时先弹确认 | | Undo / Redo | `⌘Z` / `⇧⌘Z`(原生) | 本地历史记录,因为平台的撤销栈无法由按钮驱动;一串连续输入会折叠成一步 | | Wrap | — | 软换行开关,记录在 `localStorage` 里 | 剪贴板**一个按钮都没有**:`⌘X`、`⌘C`、`⌘V` 和 `⌘A` 本来就能到达获得焦点的 textarea,而在工具栏上放一份可用平台快捷键的副本纯属噪音。剩下的,恰好就是 textarea 自己够不到的那些。 ### 样式契约 面板遵循工作区的 `STYLES.md`: - **颜色只用 `--dsw-alias-*`**——样式表里没有任何字面 hex,也没有非 alias 的 token。状态芯片是自身状态色叠在 10% 的 `color-mix(… transparent)` 着色上; 表面用的是 `bg-layer-1`(树那一列)、`bg-layer-3`(编辑器输入区)和 `bg-module-platform`(过滤器、芯片)。 - **按钮**用契约里的两族:中性按钮是 8px/12.5px 的裸控件,悬停时依次填充 `interactive-bg-hover` → `-active`;主操作 Save 用 `button-primary-fill`/`-hover` 配 `label-primary-foreground`。`brand-primary` 只出现在 `:focus-visible` 描边上 ——从不作为填充色。 - **字体与几何**:标题 20px/500/28,简介 13px/20,芯片 11px;header 自带 `padding-top: 28px`,在 Darwin 下还要加上 `--dsh-frame-top-clearance`;页面的 横向节奏是 `clamp(24px, 4vw, 48px)`。 - **页面根节点上的 `color-scheme: light dark`**,没有任何暗色模式覆盖:token 本身就同时承载两种模式。 两栏主体是唯一一处刻意的偏离:契约描述的是居中的 960px 单栏页面,而那样会把 「树 + 编辑器」的分栏饿死。header 保留契约的内缩,好让标题与它的兄弟面板对齐, 主体则在它下方满宽铺开。 编辑器就是一个等宽字体的普通 `