Extensions: skills, plugins, MCP, sub-agents; configurable keys
ci / linux (clang) (push) Canceled after 0s
ci / linux (gcc) (push) Canceled after 0s
ci / sanitizers (push) Canceled after 0s
ci / musl (push) Canceled after 0s
ci / macos (push) Canceled after 0s

- Skills (SKILL.md discovery, skill tool, /skills /skill)
- plugin.json exec tools with permission prompts, timeouts and workspace trust (/plugins)
- MCP stdio client: JSON-RPC initialize/tools/list/tools/call, mcp__server__tool, /mcp and sidebar status
- task tool with general/explore/plan and .agent/agents/*.md roles, parallel read-only runs, cancel propagation, /agents
- Keymap with Ctrl+X leader, keybinds.json overrides and /keys panel
- Collapsed thinking, throttled streaming Markdown, leaner tool output, parallel read-only tools
- Spawn: close-on-exec pipes and a process-wide fork lock
- Tests for keymap, skills, plugins, MCP, sub-agents, shell compaction; docs/plugins.md
This commit is contained in:
WHC
2026-10-05 14:55:31 +08:00
parent c81df42f0b
commit 7d3ec9fcb9
38 changed files with 8356 additions and 399 deletions
+186
View File
@@ -0,0 +1,186 @@
# 扩展:Skills、插件、MCP 与自定义子 agent
所有扩展只在默认工具档(`--tools default`)下加载;`--tools minimal` 完全不受影响。
下文的“配置目录”指 `~/.config/cst-agent/`(`$XDG_CONFIG_HOME/cst-agent/`;Windows 为 `%APPDATA%\cst-agent\`)。
| 放在哪 | 什么 | 何时加载 |
|---|---|---|
| `<ws>/.agent/skills/*/SKILL.md`、`<ws>/.claude/skills/*/SKILL.md` | skill | 总是 |
| `<配置目录>/skills/*/SKILL.md` | skill | 总是 |
| `<ws>/.agent/plugins/*/plugin.json` | 插件 | 工作区被信任后(`/plugins trust`) |
| `<配置目录>/plugins/*/plugin.json` | 插件 | 总是 |
| `<ws>/.agent/mcp.json` | MCP 服务器 | 工作区被信任后 |
| `<配置目录>/mcp.json` | MCP 服务器 | 总是 |
| `<ws>/.agent/agents/*.md`、`<配置目录>/agents/*.md` | 子 agent 角色 | 总是 |
同名时先出现的生效:工作区 > 配置目录 > 插件。改完后 `/skills reload`、`/plugins reload` 或 `/mcp reload`
重新加载(会重启 MCP 服务器)。启动时首页和 headless 的 stderr 会打印一行汇总,例如
`2 skills · 1 plugin (3 tools) · 1 MCP server`。
## Skills
一个 skill 是一个目录,里面有 `SKILL.md`,可以附带脚本、参考资料等文件:
```
.agent/skills/pdf-forms/
├── SKILL.md
├── reference.md
└── scripts/fill.py
```
```markdown
---
name: pdf-forms
description: Fill PDF forms with the bundled script; use when the user asks to fill or inspect a PDF form.
---
# PDF forms
1. List the fields: `python3 scripts/fill.py --list form.pdf`
2. ...
```
- system prompt 里只有一张索引(`- pdf-forms: Fill PDF forms…`,总长 ≤ 4 KB),模型认为相关时调用
`skill(name)` 读正文和文件列表,再用 `skill(name, file="reference.md")` 读附带文件(只能读 skill 目录内的文件)。
- 没有 frontmatter 时,名字取目录名,描述取正文第一行非标题文字。
- `/skill pdf-forms 把 a.pdf 填好` 会把 skill 正文直接放进这条消息再发送。
## 插件(plugin.json)
```
~/.config/cst-agent/plugins/jira/
├── plugin.json
├── issue.py
└── skills/ # 可选:插件自带的 skills
```
```json
{
"name": "jira",
"description": "Read Jira issues.",
"tools": [
{
"name": "jira_issue",
"description": "Fetch one Jira issue (summary, status, comments).",
"command": ["python3", "issue.py"],
"parameters": {
"type": "object",
"properties": {
"key": {"type": "string", "description": "issue key, e.g. CST-42"},
"comments": {"type": "integer", "description": "how many comments"}
},
"required": ["key"]
},
"perm": "net",
"timeout": 30
}
],
"skills": "skills",
"mcpServers": {
"jira-search": {"command": "npx", "args": ["-y", "some-jira-mcp"]}
}
}
```
工具字段:
| 字段 | 说明 |
|---|---|
| `name` | 工具名(非 `[A-Za-z0-9_-]` 的字符换成 `_`,≤ 63 字节),不能和已有工具重名 |
| `description` | 给模型看的说明 |
| `command` | 字符串数组:直接执行,数组里能在插件目录找到的相对路径会换成绝对路径;或一个字符串:交给 `sh` 执行(可以用管道) |
| `parameters`(或 `inputSchema`) | JSON Schema;`required` 会在执行前校验 |
| `perm` | `read`(不询问,可并行)/ `write` / `net` / `shell`(默认),按对应类别审批 |
| `timeout` | 秒,默认 60,最多 600;超时整组进程被杀,退出码 124 |
执行约定:
- 参数按 schema 转成类型正确的 JSON 对象(`{"key":"CST-42","comments":3}`),**从 stdin 读**。
- 工作目录是工作区根目录;环境变量 `CST_PLUGIN_DIR`(插件目录)、`CST_WORKSPACE`、`CST_TOOL`。
- stdout + stderr 就是工具结果(上限 512 KB),退出码非 0 视为失败。
- `perm` 为 `shell` 且审批模式是 `auto`、系统有沙箱时,命令在沙箱里运行(只能写工作区和临时目录)。
- 目前插件工具只支持 POSIX 系统(Linux / macOS / Termux)。
一个最小的 Python 工具:
```python
import json, sys
args = json.load(sys.stdin)
print(f"hello {args['name']}")
```
## MCP 服务器(mcp.json)
格式与 Claude Desktop / Cursor 相同:
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"github": {
"command": "github-mcp-server",
"args": ["stdio"],
"env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"},
"autoApprove": ["get_issue", "search_code"]
},
"old": {"command": "foo", "disabled": true}
}
}
```
| 字段 | 说明 |
|---|---|
| `command`、`args` | 启动命令(按 `PATH` 查找);只支持 stdio 传输,带 `url` 的服务器会显示为 failed |
| `env` | 追加的环境变量;`${NAME}` 取当前环境里的值,密钥不必写进文件 |
| `cwd` | 工作目录(相对路径相对于工作区;插件里的服务器默认在插件目录) |
| `disabled` | `true` 时不启动 |
| `autoApprove` | `true` 或工具名数组:这些工具按只读处理(不询问、可并行) |
- 服务器在后台启动(握手、分页 `tools/list`),TUI 不等待;工具在握手完成后出现。headless 运行会先等最多 30 s。
- 工具注册为 `mcp__<server>__<tool>`,参数 schema 原样交给模型;默认按网络工具审批(`auto` 模式下会询问,`a` 可记住)。
- 结果里的 text 内容拼接返回;图片/音频只给出类型和大小;`isError` 视为失败。单次调用 60 s 超时,Esc 会发送
`notifications/cancelled`。
- 服务器退出后状态变为 exited(`/mcp` 显示 stderr 最后一行),之后的调用直接报错;`/mcp reload` 重启。
- 侧栏显示 `MCP 就绪数/总数` 和每个服务器的工具数。
## 工作区信任
工作区里的 `.agent/plugins/` 和 `.agent/mcp.json` 会在你的机器上执行命令,clone 下来的仓库可能带着它们,
所以默认不加载,首页会提示 “untrusted workspace: /plugins trust”。
- `/plugins trust`:信任当前工作区(按真实路径记在 `settings.json` 的 `trusted_workspaces`),立即加载。
- `/plugins untrust`:取消信任。
- skills 和子 agent 角色只是文本,不受信任设置影响。
## 自定义子 agent 角色
`.agent/agents/reviewer.md`:
```markdown
---
name: reviewer
description: Reviews a diff for bugs and missing tests; read-only.
tools: read_file, grep, glob, run_shell
readonly: true
model: deepseek-v4-pro
max_steps: 12
---
You review changes. Run `git diff` first, read the touched files around each
hunk, and report concrete problems with file:line and a suggested fix.
Do not restate the diff.
```
| 字段 | 说明 |
|---|---|
| `name` | 角色名(默认取文件名);与内置 `general` / `explore` / `plan` 同名时覆盖内置角色 |
| `description` | 写进主 agent 的角色索引,决定它什么时候选这个角色 |
| `tools` | 允许的工具白名单(默认全部,`task` 和 `ask_user` 始终不给子 agent) |
| `readonly` | `true` 时去掉写文件和 shell 工具,并允许多个同类 task 并行 |
| `model` | 用别的模型(同一 provider) |
| `max_steps` | 子 agent 每轮的模型调用上限 |
正文是角色说明,追加在子 agent 的 system prompt 末尾。主 agent 调用
`task(description="review auth", prompt="…", agent="reviewer")`;子 agent 的转录保存在
`.agent/sessions/<会话 id>/sub-N.jsonl`,`/agents` 里选中一条记录可以查看它的提示、工具调用和报告。