min-agent 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -216
- package/dist/agent.js +1119 -256
- package/dist/cli/commands/chat.js +10 -0
- package/dist/cli/commands/exec.js +32 -0
- package/dist/cli/commands/history.js +58 -0
- package/dist/cli/commands/index.js +224 -0
- package/dist/cli/commands/init.js +18 -0
- package/dist/cli/commands/mcp.js +173 -0
- package/dist/cli/commands/memory.js +69 -0
- package/dist/cli/commands/models.js +21 -0
- package/dist/cli/commands/permission.js +12 -0
- package/dist/cli/commands/rules.js +33 -0
- package/dist/cli/commands/sandbox.js +13 -0
- package/dist/cli/commands/serve.js +9 -0
- package/dist/cli/commands/setup.js +4 -0
- package/dist/cli/commands/shared.js +16 -0
- package/dist/cli/commands/skills.js +119 -0
- package/dist/cli/commands/update.js +7 -0
- package/dist/cli/commands/write-config.js +30 -0
- package/dist/cli/errors.js +36 -0
- package/dist/cli/exec-prompt.js +26 -0
- package/dist/cli/option-helpers.js +53 -0
- package/dist/cli/program.js +180 -0
- package/dist/cli.js +5 -888
- package/dist/code-mode.js +32 -14
- package/dist/compaction.js +347 -160
- package/dist/config.js +119 -10
- package/dist/confirm.js +56 -9
- package/dist/context-window.js +107 -39
- package/dist/doom-loop.js +264 -29
- package/dist/fetch-timeout.js +152 -0
- package/dist/http-approvals.js +60 -0
- package/dist/instructions.js +21 -0
- package/dist/logger.js +33 -4
- package/dist/markdown.js +37 -11
- package/dist/mcp.js +328 -30
- package/dist/memory.js +97 -56
- package/dist/output.js +7 -5
- package/dist/permission-cli.js +43 -0
- package/dist/plugins.js +46 -8
- package/dist/pricing.js +4 -4
- package/dist/provider.js +23 -6
- package/dist/question-format.js +60 -0
- package/dist/sandbox-cli.js +82 -0
- package/dist/sandbox.js +403 -0
- package/dist/save-throttle.js +45 -0
- package/dist/serve/common.js +404 -0
- package/dist/serve/routes-chat.js +347 -0
- package/dist/serve/routes-mcp.js +212 -0
- package/dist/serve/routes-memory.js +66 -0
- package/dist/serve/routes-meta.js +205 -0
- package/dist/serve/routes-sessions.js +61 -0
- package/dist/serve/routes-skills.js +70 -0
- package/dist/serve.js +33 -883
- package/dist/sessions.js +53 -9
- package/dist/skills.js +82 -18
- package/dist/title-gen.js +8 -2
- package/dist/token-display.js +36 -0
- package/dist/tool-display.js +5 -0
- package/dist/tool-output.js +1 -3
- package/dist/tools/apply_patch.js +85 -11
- package/dist/tools/atomic-file.js +35 -0
- package/dist/tools/backend.js +2 -2
- package/dist/tools/bash.js +57 -19
- package/dist/tools/code_search.js +7 -1
- package/dist/tools/edit.js +11 -10
- package/dist/tools/explore.js +74 -14
- package/dist/tools/glob.js +4 -0
- package/dist/tools/grep.js +17 -10
- package/dist/tools/index.js +6 -21
- package/dist/tools/question.js +28 -9
- package/dist/tools/read.js +6 -4
- package/dist/tools/search-searxng.js +223 -0
- package/dist/tools/search-serper.js +189 -0
- package/dist/tools/task.js +84 -30
- package/dist/tools/todo.js +120 -19
- package/dist/tools/web_fetch.js +11 -3
- package/dist/tools/web_search.js +66 -556
- package/dist/tools/write.js +23 -6
- package/dist/tui/App.js +63 -14
- package/dist/tui/ConfirmBar.js +45 -13
- package/dist/tui/InputBar.js +150 -35
- package/dist/tui/MessageList.js +266 -125
- package/dist/tui/ModelPicker.js +8 -3
- package/dist/tui/QuestionBar.js +51 -19
- package/dist/tui/SessionPicker.js +79 -0
- package/dist/tui/StatusBar.js +8 -14
- package/dist/tui/agent-runner.js +142 -22
- package/dist/tui/caret-pos.js +48 -5
- package/dist/tui/caret.js +1 -1
- package/dist/tui/click-count.js +13 -0
- package/dist/tui/drag-state.js +8 -3
- package/dist/tui/hydrate.js +129 -0
- package/dist/tui/index.js +42 -13
- package/dist/tui/input-history.js +92 -11
- package/dist/tui/layout.js +75 -4
- package/dist/tui/prompt-queue.js +24 -0
- package/dist/tui/selection.js +113 -21
- package/dist/tui/session-switch.js +28 -0
- package/dist/tui/slash-commands.js +22 -6
- package/dist/tui/slash-handler.js +233 -58
- package/dist/tui/text-width.js +38 -16
- package/dist/tui/token-info.js +7 -0
- package/dist/tui/tool-children.js +19 -0
- package/dist/tui/undo-stack.js +1 -1
- package/dist/tui/use-sgr-mouse.js +3 -1
- package/dist/tui-chat.js +276 -40
- package/dist/updater.js +88 -29
- package/dist/xml-search.js +194 -0
- package/docs/API.md +257 -25
- package/docs/superpowers/plans/2026-08-20-tui-completeness.md +873 -0
- package/docs/superpowers/plans/2026-08-20-unified-tui-default.md +631 -0
- package/docs/superpowers/specs/2026-08-20-config-http-alignment-design.md +47 -0
- package/docs/superpowers/specs/2026-08-20-mcp-plugins-alignment-design.md +37 -0
- package/docs/superpowers/specs/2026-08-20-sandbox-permissions-design.md +68 -0
- package/docs/superpowers/specs/2026-08-20-tui-completeness-design.md +273 -0
- package/docs/superpowers/specs/2026-08-20-unified-tui-default-design.md +165 -0
- package/package.json +6 -1
- package/skills/self-config/SKILL.md +90 -0
- package/skills/self-config/reference.md +149 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# MCP 与插件对齐(第 3 批)— 设计文档
|
|
2
|
+
|
|
3
|
+
**日期:** 2026-08-20
|
|
4
|
+
**状态:** 已批准(范围来自五批拆分;语义对齐现有 TUI / 内置工具)
|
|
5
|
+
**范围:** MCP resources / prompts、插件危险操作走确认;计划模式只保留只读 MCP/插件
|
|
6
|
+
|
|
7
|
+
后续批次不在本文:沙箱、exec JSON 流、原生 Anthropic/Google、hooks、Browser/LSP/Notebook、主题。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 设计决策
|
|
12
|
+
|
|
13
|
+
| 决策 | 结论 |
|
|
14
|
+
|------|------|
|
|
15
|
+
| resources/prompts 暴露方式 | 四个只读 agent 工具(`mcp_list_resources` / `mcp_read_resource` / `mcp_list_prompts` / `mcp_get_prompt`),不把每条 resource 注册成独立工具 |
|
|
16
|
+
| 连接失败面 | 服务器未声明或 list 失败时记空列表,**不**让整次 MCP 连接失败 |
|
|
17
|
+
| 列表上限 | resources 200、templates 100、prompts 100;工具输出仍走 `truncateToolOutput` |
|
|
18
|
+
| 插件确认 | 默认确认;`readOnly: true` 或 `dangerous: false` 跳过 |
|
|
19
|
+
| 计划模式 | 去掉无 `readOnlyHint` 的 MCP 工具、非 `readOnly` 插件;catalog 工具保留 |
|
|
20
|
+
| HTTP | `GET /v1/mcp` 增加计数;`GET .../resources`、`GET .../prompts`、`POST .../resources/read`、`POST .../prompts/get` |
|
|
21
|
+
| serve 默认 | 仍自动批准(与第 2 批一致);未设 `readOnly` 的插件在 TUI/`exec`(无 `-y`)会询问 |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. MCP resources / prompts
|
|
26
|
+
|
|
27
|
+
连接成功后根据 `getServerCapabilities()` 分页拉取。缓存供状态栏/HTTP 列表;`read` / `get` 走实时 RPC。
|
|
28
|
+
|
|
29
|
+
多个已连接服务器时,`read`/`get` 若 URI/名称不唯一则必须带 `server`。二进制 resource 不把大段 base64 塞进上下文。
|
|
30
|
+
|
|
31
|
+
## 2. 插件确认
|
|
32
|
+
|
|
33
|
+
`PluginToolDef` 增加 `readOnly?: boolean`、`dangerous?: boolean`。确认文案面向用户:「运行自定义工具 {id}」加参数摘要。拒绝则工具返回说明,不抛错。
|
|
34
|
+
|
|
35
|
+
## 3. 文档与测试
|
|
36
|
+
|
|
37
|
+
README 插件示例标明 `readOnly`;`/mcp` 与 `mcp info` 显示资源/提示计数;API.md 同步新端点。测试覆盖:无 capability 的服务器仍能连;带 resources/prompts 的 stdio 服务器可 list/read;插件默认确认、`readOnly` 跳过。
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 沙箱与权限分级(第 4 批)— 设计文档
|
|
2
|
+
|
|
3
|
+
**日期:** 2026-08-20
|
|
4
|
+
**状态:** 已批准(范围来自五批拆分;语义对齐现有 TUI / `confirm` / `/plan`)
|
|
5
|
+
**范围:** 权限档位、工作区文件隔离、命令级网络/写盘隔离;HTTP/CLI/TUI 同步
|
|
6
|
+
|
|
7
|
+
后续批次不在本文:exec JSON 流、原生 Anthropic/Google、hooks、Browser/LSP/Notebook、主题。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 设计决策
|
|
12
|
+
|
|
13
|
+
| 决策 | 结论 |
|
|
14
|
+
|------|------|
|
|
15
|
+
| 两轴分开 | **确认**(`permission`)与 **隔离**(`sandbox`)正交。`--yes` / `allow-all` 只跳过确认,不自动关掉隔离 |
|
|
16
|
+
| 确认档位 | `ask`(默认)/ `accept-edits` / `allow-all`。`accept-edits` 自动放行 write/edit/apply_patch,危险命令与自定义工具仍询问 |
|
|
17
|
+
| 隔离档位 | `off`(默认)/ `workspace` / `strict`。`workspace`:文件工具可任意读(凭据除外)、只写入工作区+临时目录+包管理缓存;`strict`:读和写都限制在工作区(及 extra 根) |
|
|
18
|
+
| 默认 | 未配置时 `sandbox.mode=off`、`network=allow`。`MIN_AGENT_SANDBOX` 覆盖当前进程;单独 `--sandbox` / `--network` 写入配置并退出;带消息时才作为本轮覆盖 |
|
|
19
|
+
| 凭据 | 即使 `sandbox=off`,文件工具也禁止读写密钥类路径(`~/.ssh` 私钥、`~/.min-agent/config.json` 等) |
|
|
20
|
+
| 命令隔离 | macOS 用 `sandbox-exec`,Linux 有 `bwrap` 时用 bubblewrap;没有则仍执行路径策略 + 网络命令启发式,不悄悄降级成无隔离执行 |
|
|
21
|
+
| 网络 | `network=deny` 时:OS 配置禁止命令出网;无 OS 后端则拦截常见联网命令;`search_web` / `web_fetch` 一并拒绝。MCP 进程不受本批约束 |
|
|
22
|
+
| `/plan` | 仍是去掉写入类工具;与 sandbox 叠加,不互相替代 |
|
|
23
|
+
| HTTP | 请求可收紧、不可放宽。`serve` 默认仍自动批准,隔离默认仍为 off |
|
|
24
|
+
| 自定义工具 | 进程内执行,文件隔离管不到;继续靠 `readOnly` / 确认。文案不提实现细节 |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. 配置
|
|
29
|
+
|
|
30
|
+
全局与项目 `.min-agent/config.json` 均可写(项目覆盖全局,字段级合并):
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"permission": "ask",
|
|
35
|
+
"sandbox": {
|
|
36
|
+
"mode": "off",
|
|
37
|
+
"network": "allow",
|
|
38
|
+
"extraWriteRoots": [],
|
|
39
|
+
"extraReadRoots": []
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`sandbox` 也可写成字符串 `"workspace"`。未配置时默认 `off`。密钥仍只存在全局配置。
|
|
45
|
+
|
|
46
|
+
生效顺序:环境变量 / CLI 覆盖 → 配置合并 → 每请求 ALS(只收紧)。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. 工具行为
|
|
51
|
+
|
|
52
|
+
- `read` / `write` / `edit` / `apply_patch` / `glob` / `grep`:解析 realpath(含符号链接逃逸),按档位拒绝并返回面向用户的说明。
|
|
53
|
+
- `bash` / explore 只读 bash:工作目录必须落在允许的写根;按档位套 OS 配置。
|
|
54
|
+
- `search_web` / `web_fetch`:`network=deny` 时直接拒绝。
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. 界面与 HTTP
|
|
59
|
+
|
|
60
|
+
- TUI:`/permission`、`/sandbox`(可 `--project` / `--global` 写入配置);`/help` 同步。
|
|
61
|
+
- CLI:`sandbox` 子命令;单独 `--sandbox` / `--network` 写入配置并退出;带消息/`--resume`/`--model`/`--provider` 时才作为本轮覆盖;`--permission`;`--yes` 仍只表示自动批准。
|
|
62
|
+
- HTTP:`GET/POST /v1/permission`、`GET/POST /v1/sandbox`;`/v1/chat` 增加 `sandbox`、`network`(只收紧)。`GET /v1/meta` 附带当前隔离摘要。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. 文档与测试
|
|
67
|
+
|
|
68
|
+
README / API.md / AGENTS.md / `/help` 同步。测试覆盖:路径策略、凭据拒绝、symlink 逃逸、档位收紧、`accept-edits`、无 OS 后端时的网络启发式、HTTP 只收紧。有系统隔离后端时加一条写盘拒绝的集成断言。
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# TUI 补齐(第 1 批)— 设计文档
|
|
2
|
+
|
|
3
|
+
**日期:** 2026-08-20
|
|
4
|
+
**状态:** 已批准
|
|
5
|
+
**范围:** 会话内恢复、`/reload`、输入历史持久化、编辑键、消息区选择增强、子 agent 工具行
|
|
6
|
+
**实现路径:** 在现有 TUI 上按模块补;新文件只放纯函数,界面仍走 `slash-handler` / `InputBar` / `MessageList` / `task`
|
|
7
|
+
|
|
8
|
+
后续批次不在本文:项目级 config、HTTP plan/budget、MCP resources、沙箱、exec JSON、原生 Anthropic/Google、hooks、Browser/LSP、主题可配。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 背景
|
|
13
|
+
|
|
14
|
+
TUI 已能拖拽复制、`/model` 选择器、内存输入历史、`task` 子 agent。缺口是:
|
|
15
|
+
|
|
16
|
+
- `/sessions` 只能列表,恢复必须退出再 `--resume`
|
|
17
|
+
- `--resume` 只把 `ModelMessage[]` 灌进 agent,消息区仍是空的
|
|
18
|
+
- 没有 `/reload` 重读规则
|
|
19
|
+
- 输入历史上次退出即丢
|
|
20
|
+
- Home/End、折行上下、点击斜杠菜单未接
|
|
21
|
+
- 双击选词、三击选段、复制去装饰前缀、键盘选择模式未做
|
|
22
|
+
- 子 agent 进度打在 stderr,TUI 里只看到一条 `task` 结果
|
|
23
|
+
|
|
24
|
+
## 设计决策(已与用户确认)
|
|
25
|
+
|
|
26
|
+
| 决策 | 结论 |
|
|
27
|
+
|------|------|
|
|
28
|
+
| 会话恢复 UX | `/sessions` 与 `/resume` 无参打开选择器(像 `/model`),带 id 直接切换 |
|
|
29
|
+
| 切换当前会话 | 有消息则自动保存,再加载目标 |
|
|
30
|
+
| 输入历史 | 全局 `~/.min-agent/input-history.json`,上限 1000 |
|
|
31
|
+
| 子 agent | 普通工具行,点开看子工具调用和结果 |
|
|
32
|
+
| 键盘选择 | 消息区模式,**Ctrl+B** 进入;不在输入框做 Shift 选区 |
|
|
33
|
+
| 双击/三击 | 选中后立刻复制(与拖拽松手一致) |
|
|
34
|
+
|
|
35
|
+
## 目标与非目标
|
|
36
|
+
|
|
37
|
+
**目标:**
|
|
38
|
+
|
|
39
|
+
- 会话内切换并画出历史;`--resume` 启动同样画出历史
|
|
40
|
+
- `/reload` 重读规则并更新 runner 的 system prompt
|
|
41
|
+
- 输入历史上限 1000、原子落盘
|
|
42
|
+
- Home/End、折行 ↑↓(到顶/底再翻历史)、点击斜杠/参数菜单
|
|
43
|
+
- 双击选词、三击选段、复制去掉 `> ` / `⚡ name ▸ ` / 结果缩进
|
|
44
|
+
- Ctrl+B 消息区选择模式:方向键扩选,Enter 复制退出,Esc 取消
|
|
45
|
+
- TUI 中 `task` 可展开子工具列表;非 TUI 仍用 stderr
|
|
46
|
+
|
|
47
|
+
**非目标:**
|
|
48
|
+
|
|
49
|
+
- 输入框 Shift 选区、主题可配、项目级记忆/config、HTTP 新端点
|
|
50
|
+
- 恢复思考过程、子 agent 思考文本、子 agent 再调 `task`/`explore`
|
|
51
|
+
- 改会话文件格式
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 1. 会话切换与 `/reload`
|
|
56
|
+
|
|
57
|
+
### 1.1 选择器
|
|
58
|
+
|
|
59
|
+
新增 `SessionPicker.tsx`,交互对齐 `ModelPicker`(替换输入框、输入过滤、↑↓/PgUpDn、Enter、Esc)。列表来自 `listSessions()`,展示 `id`、日期、标题、消息数;当前会话标 `←`。过滤匹配 id 或标题。无会话时不打开选择器,系统提示「无已保存的会话」。
|
|
60
|
+
|
|
61
|
+
`TuiState` 增加 `sessionPicker?: boolean`。`TuiRenderer.showSessionPicker()` / `hideSessionPicker()`。`TuiCallbacks` 增加 `onSessionPick(id)` / `onSessionCancel()`。`App` footer 与 `modelPicker` 互斥:同一时刻只出现一种 picker / confirm / question / input。
|
|
62
|
+
|
|
63
|
+
### 1.2 命令
|
|
64
|
+
|
|
65
|
+
| 输入 | 行为 |
|
|
66
|
+
|------|------|
|
|
67
|
+
| `/sessions` 或 `/resume` | 打开选择器 |
|
|
68
|
+
| `/sessions <id>` 或 `/resume <id>` | 立即切换 |
|
|
69
|
+
| `/resume` | `/sessions` 的别名(`slash-commands.ts` 的 `aliases`) |
|
|
70
|
+
|
|
71
|
+
为 `sessions` / `resume` 注册 Tab 补全:`listSessions()` 的 id,description 用标题。
|
|
72
|
+
|
|
73
|
+
`/help` 与菜单文案改为「列出/切换已保存会话」。
|
|
74
|
+
|
|
75
|
+
### 1.3 `switchSession(id)`
|
|
76
|
+
|
|
77
|
+
抽到 `src/tui/session-switch.ts`(协调逻辑)+ `src/tui/hydrate.ts`(纯函数)。步骤:
|
|
78
|
+
|
|
79
|
+
1. agent 正在跑(`runner.getController()` 非空)→ 拒绝:「请先等待当前回合结束或按 Esc 取消」
|
|
80
|
+
2. `id === sessionId` → 「已是当前会话」
|
|
81
|
+
3. `loadSession(id)` 为空 → 「会话不存在」
|
|
82
|
+
4. `messages.length > 0` → `sessionId = saveSession(messages, sessionId)`
|
|
83
|
+
5. 就地替换:`messages.length = 0`;`messages.push(...session.messages)`(runner 持有同一引用)
|
|
84
|
+
6. `setSessionId(id)`;`clearStack(undo)`;`tracker.resetContext()`
|
|
85
|
+
7. `lastUserMessage` = 最后一条 user 文本(无则 `null`)
|
|
86
|
+
8. `tui.update({ messages: hydrateMessages(session.messages) })`
|
|
87
|
+
9. 系统提示 `✓ 已切换到: {title}`
|
|
88
|
+
|
|
89
|
+
`planMode` 不随会话重置。不重建 system prompt。
|
|
90
|
+
|
|
91
|
+
### 1.4 hydrate
|
|
92
|
+
|
|
93
|
+
`hydrateMessages(messages: ModelMessage[]): TuiMessage[]` 有损映射:
|
|
94
|
+
|
|
95
|
+
- `user`:文本拼接;仅图片 parts 时内容为 `[📎 图片]`
|
|
96
|
+
- `assistant`:只保留 text parts;tool-call parts 忽略(工具结果走 `tool` 角色)
|
|
97
|
+
- `tool`:一条工具行,`toolName` + 结果摘要(复用 `summarizeToolResult` / `toolResultText`);无 name 则跳过
|
|
98
|
+
- 其它 / 无法解析:跳过,不抛
|
|
99
|
+
|
|
100
|
+
不恢复 `thinking`。用于 `--resume` 启动(`tui.start()` 之后立刻 `tui.update({ messages: hydrate(...) })`)和会话内切换。
|
|
101
|
+
|
|
102
|
+
### 1.5 `/reload`
|
|
103
|
+
|
|
104
|
+
- `loadInstructions()` + `scanProject()` + `buildCodeSystemPrompt()`
|
|
105
|
+
- `AgentRunnerDeps.codeSystemPrompt: string` 改为 `getSystemPrompt: () => string`;`tui-chat` 用可变闭包持有最新 prompt
|
|
106
|
+
- 系统提示 `✓ 已重载规则(N 字符)`
|
|
107
|
+
- 不重连 MCP、不重扫 skills
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 2. 输入历史与编辑键
|
|
112
|
+
|
|
113
|
+
### 2.1 持久化
|
|
114
|
+
|
|
115
|
+
文件:`~/.min-agent/input-history.json`
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{ "entries": ["...", "..."] }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
最新在末尾。`HISTORY_LIMIT = 1000`(现为 500)。连续重复仍去重。斜杠命令也记录。
|
|
122
|
+
|
|
123
|
+
- 读:`InputBar` 挂载时 `loadInputHistory()` → `createHistory()` 填 `entries`
|
|
124
|
+
- 写:`pushInput` 之后 `saveInputHistory(entries)`,原子写(tmp + rename),与 `memory.ts` 相同
|
|
125
|
+
- 坏 JSON / 非数组:备份为 `input-history.json.corrupt-{ts}`,当空历史
|
|
126
|
+
- 写失败:静默,不挡输入
|
|
127
|
+
- 不写 logger(避免把用户输入打进运行日志)
|
|
128
|
+
|
|
129
|
+
纯函数放在现有 `input-history.ts`:`parseHistoryFile` / `serializeHistoryFile`。
|
|
130
|
+
|
|
131
|
+
### 2.2 Home / End
|
|
132
|
+
|
|
133
|
+
与现有 Ctrl+A / Ctrl+E 相同:`moveToLineStart` / `moveToLineEnd`(逻辑行,按 `\n`)。Ink 若提供 `key.home` / `key.end` 则用;否则在 raw stdin 里解析 CSI `H` / `F` / `1~` / `4~`(与 Delete 扫描同一通道)。
|
|
134
|
+
|
|
135
|
+
### 2.3 折行 ↑↓
|
|
136
|
+
|
|
137
|
+
菜单或参数菜单打开时:↑↓ 仍只移动菜单(现状)。
|
|
138
|
+
|
|
139
|
+
否则:
|
|
140
|
+
|
|
141
|
+
- 先按视觉行移动光标(`visualRows` + 保持显示列,换算用现有 `caretIndexFromClick` 同类逻辑)
|
|
142
|
+
- 已在第一视觉行再 ↑ → 翻更早历史
|
|
143
|
+
- 已在最后视觉行再 ↓ → 翻更新历史
|
|
144
|
+
|
|
145
|
+
新增 `moveCaretVertical(value, caretIndex, direction, maxWidth): number`(`caret-pos.ts`)。
|
|
146
|
+
|
|
147
|
+
### 2.4 点击菜单
|
|
148
|
+
|
|
149
|
+
SGR 点击落在斜杠菜单或参数菜单的某一选项行 → 与键盘选中后 Enter(命令菜单)或 Tab(参数菜单)相同:`acceptCommand` / `acceptArg`。点击菜单框外仍按现有逻辑(点输入区定位光标)。用 footer 行数反推菜单绝对行,与输入框点击定位同一套坐标。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 3. 消息区选择
|
|
154
|
+
|
|
155
|
+
拖拽选择状态机保留。复制路径统一走 `copySelection(text)`:去前缀 → `writeClipboard` → 成功且非空才 `showCopyNotice`。
|
|
156
|
+
|
|
157
|
+
### 3.1 去前缀(只影响剪贴板)
|
|
158
|
+
|
|
159
|
+
对 `areaRows` 里被选中的每一行,剥 ANSI 后:
|
|
160
|
+
|
|
161
|
+
- 用户消息首行:去掉开头 `> `
|
|
162
|
+
- 工具消息首行:去掉从 `⚡ ` 起到第一个 `▸ ` 或 `▾ `(含其后一个空格)
|
|
163
|
+
- 工具展开结果行:去掉开头两个空格
|
|
164
|
+
- 其它行不变
|
|
165
|
+
|
|
166
|
+
高亮仍按屏幕所见(含前缀)。函数:`stripCopyDecorations(line: string, kind: "user-head" | "tool-head" | "tool-body" | "plain"): string`。`kind` 由该行对应的 `TuiMessage.role` 与是否为首行/结果行决定。
|
|
167
|
+
|
|
168
|
+
### 3.2 双击 / 三击
|
|
169
|
+
|
|
170
|
+
SGR 不带 click count。在 `click` outcome 上记 `{ row, col, at, count }`:
|
|
171
|
+
|
|
172
|
+
- 400ms 内、同一行、列差 ≤ 2 → `count++`,否则重置为 1
|
|
173
|
+
- `count === 2`:该行(剥 ANSI)按空白界选词,高亮并复制
|
|
174
|
+
- `count === 3`:该行所属那条消息当前可见的全部行,高亮并复制
|
|
175
|
+
- `count === 1`:保持现有单击(工具行展开)
|
|
176
|
+
|
|
177
|
+
词界:连续非空白为一个词;行首/行尾夹紧。CJK 与拉丁一样按空白切,不按字素再切。
|
|
178
|
+
|
|
179
|
+
### 3.3 Ctrl+B 选择模式
|
|
180
|
+
|
|
181
|
+
`TuiState.selectionMode?: boolean`。`App` 在处理 Ctrl+C 旁监听 Ctrl+B:
|
|
182
|
+
|
|
183
|
+
- 确认框 / 提问 / picker 打开时忽略
|
|
184
|
+
- agent 正在跑时拒绝进入(避免与 Esc 取消抢键),不提示或仅短提示「请先结束或取消当前回合」
|
|
185
|
+
- 进入后:`InputBar` 视为 disabled(不接收编辑键);状态栏分隔线提示 `选择模式 ↑↓←→扩选 Enter复制 Esc退出`
|
|
186
|
+
|
|
187
|
+
起点:上次成功的消息区点击坐标;若无,则可见区第一条非空文本行、列 0。`anchor` 固定,方向键只动 `cur`(与拖拽扩选同一套 `selectionRanges`)。Home/End 在模式内:行首 / 行尾显示列。
|
|
188
|
+
|
|
189
|
+
- Enter:复制(去前缀)并退出模式,选区保持到下次点击/按键(与拖拽相同)
|
|
190
|
+
- Esc:退出模式,清除选区,不复制
|
|
191
|
+
- Ctrl+C:仍中断/退出进程,顺带退出选择模式
|
|
192
|
+
- 滚轮:与现有一样清选区;选择模式保持,光标行随滚动夹紧
|
|
193
|
+
|
|
194
|
+
Ctrl+B 在 `InputBar` 里目前被 `key.ctrl` 总拦截吞掉;改为由 `App` 先处理,或 `InputBar` 在 Ctrl+B 时 `onSelectionMode()`。
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 4. 子 agent 工具行
|
|
199
|
+
|
|
200
|
+
`src/tools/task.ts` 的 `runSubAgent` 增加可选:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
onSubToolCall?: (name: string, input: unknown) => void
|
|
204
|
+
onSubToolResult?: (name: string, output: unknown, isError: boolean) => void
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
有回调时不写 stderr 进度;无回调时保持现有 `console.error`(`exec` / 测试)。
|
|
208
|
+
|
|
209
|
+
`TuiMessage` 增加:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
toolChildren?: { name: string; summary: string; result?: string; isError?: boolean }[]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
`createTaskTool` 在 TUI 路径由 `agent-runner` 传入回调:按父级 `toolCallId` 调用 `tui.appendToolChild(...)`。未展开:仍只显示 `description` 与最终 `→ 摘要`(不在摘要行刷当前子工具名)。展开:在结果之上列出子工具名、参数摘要、结果(截断规则同普通工具行)。
|
|
216
|
+
|
|
217
|
+
子 agent 仍删除 `task` / `explore`。最终回复仍是父级 `task` 的 `toolResult`。思考文本不展示。
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 5. 错误处理
|
|
222
|
+
|
|
223
|
+
| 场景 | 行为 |
|
|
224
|
+
|------|------|
|
|
225
|
+
| 切换 id 不存在 | 提示,留在当前会话 |
|
|
226
|
+
| 切换时 agent 在跑 | 拒绝 |
|
|
227
|
+
| `--resume` 指向不存在的 id | 维持现状(当新会话) |
|
|
228
|
+
| 历史文件损坏 | 备份后空历史 |
|
|
229
|
+
| 历史写入失败 | 静默 |
|
|
230
|
+
| 复制失败 | 不高亮「已复制」 |
|
|
231
|
+
| hydrate 未知形状 | 跳过该条 |
|
|
232
|
+
| Ctrl+B 时 picker/confirm 开着 | 忽略 |
|
|
233
|
+
| Ctrl+B 时 agent 在跑 | 不进入选择模式 |
|
|
234
|
+
|
|
235
|
+
## 6. 测试
|
|
236
|
+
|
|
237
|
+
| 文件 | 覆盖 |
|
|
238
|
+
|------|------|
|
|
239
|
+
| `tests/hydrate.test.ts` | user 文本/图片、assistant 去掉 tool-call、tool 行、未知跳过 |
|
|
240
|
+
| `tests/input-history.test.ts`(改) | 解析/序列化、上限 1000、坏文件 |
|
|
241
|
+
| `tests/caret-pos.test.ts`(改) | `moveCaretVertical` 折行、顶/底夹紧;Home/End 已有则补物理键映射若抽出 |
|
|
242
|
+
| `tests/selection.test.ts`(改) | 去前缀、选词范围、三击=整条可见行 |
|
|
243
|
+
| `tests/drag-state.test.ts`(改)或新文件 | 400ms 双击计数(若把点击计数抽成纯函数) |
|
|
244
|
+
| `tests/session-switch` 或 hydrate+save 组合 | 拒绝运行中切换的守卫可测则测;picker 不测 Ink |
|
|
245
|
+
|
|
246
|
+
仓库根 `bun run typecheck`;`packages/min-agent` 下 `bun test`。
|
|
247
|
+
|
|
248
|
+
## 7. 文档同步
|
|
249
|
+
|
|
250
|
+
- `README.md` 交互命令表:`/sessions`、`/resume`、`/reload`;快捷键补 Ctrl+B、Home/End、鼠标双击/三击
|
|
251
|
+
- `/help` 与 `slash-commands.ts`
|
|
252
|
+
- Configuration 或日志旁注明输入历史路径 `~/.min-agent/input-history.json`
|
|
253
|
+
- `AGENTS.md`:用户配置目录补一条 input-history(若该文件已列 `~/.min-agent/` 内容)
|
|
254
|
+
|
|
255
|
+
无新 HTTP 端点,不改 `docs/API.md`。
|
|
256
|
+
|
|
257
|
+
## 影响范围
|
|
258
|
+
|
|
259
|
+
- `src/tui-chat.ts`、`src/tui/agent-runner.ts`、`src/tui/slash-handler.ts`、`src/tui/slash-commands.ts`
|
|
260
|
+
- `src/tui/App.tsx`、`src/tui/index.tsx`、`src/tui/types.ts`、`src/tui/InputBar.tsx`、`src/tui/MessageList.tsx`、`src/tui/StatusBar.tsx`
|
|
261
|
+
- 新:`src/tui/SessionPicker.tsx`、`src/tui/hydrate.ts`、`src/tui/session-switch.ts`(若逻辑超过 slash-handler 可读范围)
|
|
262
|
+
- `src/tui/input-history.ts`、`src/tui/caret-pos.ts`、`src/tui/selection.ts`、`src/tui/drag-state.ts`
|
|
263
|
+
- `src/tools/task.ts`、`src/tool-display.ts`(子工具摘要复用)
|
|
264
|
+
- `README.md`、`/help`、`packages/min-agent/AGENTS.md`
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 自审
|
|
269
|
+
|
|
270
|
+
- 无 TBD:选择模式起点、双击时限、历史路径与上限、hydrate 规则、`/reload` 不含 MCP/skills 已写死
|
|
271
|
+
- 与「增量补模块」一致:新 UI 只加 SessionPicker;选择模式复用 `selectionRanges`
|
|
272
|
+
- 单批可落地:不包含后四批
|
|
273
|
+
- `--resume` 画历史与会话内切换共用 hydrate,避免两套映射
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# 根命令默认 TUI + 合并 chat/code — 设计文档
|
|
2
|
+
|
|
3
|
+
**日期:** 2026-08-20
|
|
4
|
+
**状态:** 已批准
|
|
5
|
+
**范围:** CLI 对齐 Codex(根命令进 TUI、`exec` 非交互);取消 chat/code 双模式,统一为原 code 能力
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 背景
|
|
10
|
+
|
|
11
|
+
当前 `min-agent` 无参数会打印 Usage 并退出;对话必须 `min-agent chat`,项目感知必须 `min-agent code`。Codex 的根命令就是交互 TUI,子命令才是特殊模式。
|
|
12
|
+
|
|
13
|
+
两套模式的实现差异很小:工具几乎相同,code 额外有项目扫描、coding system prompt、`task` 工具,以及存在 `EXA_API_KEY` 时的 `codesearch`。用户确认不再保留 chat/code 概念,以 code 为准。
|
|
14
|
+
|
|
15
|
+
## 设计决策(已与用户确认)
|
|
16
|
+
|
|
17
|
+
| 决策 | 结论 |
|
|
18
|
+
|------|------|
|
|
19
|
+
| 空参数 | `min-agent` 直接进入交互 TUI(不再打印 Usage) |
|
|
20
|
+
| 根命令带消息 | `min-agent "修 lint"` 进 TUI,并把该文本作为第一轮立刻提交 |
|
|
21
|
+
| 非交互 | 新增 `min-agent exec <message>`(脚本/CI);根命令一律不跑完即退 |
|
|
22
|
+
| 模式 | 取消 chat/code 双模式,全程原 code 能力 |
|
|
23
|
+
| `chat` / `code` 子命令 | 静默别名,行为与根命令 TUI 相同,文案不再提两种模式 |
|
|
24
|
+
| HTTP | `/v1/chat` 走原 code 路径;`/v1/code` 保留为别名 |
|
|
25
|
+
|
|
26
|
+
## 目标与非目标
|
|
27
|
+
|
|
28
|
+
**目标:**
|
|
29
|
+
|
|
30
|
+
- 根命令默认进入与现在 `min-agent code` 同等能力的 TUI
|
|
31
|
+
- 根命令可选首条 prompt、顶层 flag(`-m` / `--provider` / `-i` / `--resume` / `-y`)
|
|
32
|
+
- `exec` 单次运行后退出,使用同一套 agent 能力
|
|
33
|
+
- 删除运行时 `mode: "chat" \| "code"` 分支
|
|
34
|
+
- README、`printUsage`、`/help`、`docs/API.md`、serve 测试同步
|
|
35
|
+
|
|
36
|
+
**非目标:**
|
|
37
|
+
|
|
38
|
+
- 不引入 Codex 的 sandbox / profile / `exec resume` / ephemeral
|
|
39
|
+
- 不把 `exec` 做成 JSON event stream(保持现有 `runAgent` 终端输出)
|
|
40
|
+
- 不新增 TUI 内「切换模式」斜杠命令
|
|
41
|
+
- 不把 `history` / `mcp` 等子命令改成 Codex 同名结构
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. CLI 分发
|
|
46
|
+
|
|
47
|
+
从 argv 里跳过「带值 flag 及其参数」和布尔 flag,得到第一个位置参数。已知带值 flag:`--model`/`-m`、`--provider`、`--resume`、`--image`/`-i`、`--port`/`-p`、`--host`。布尔:`--yes`/`-y`。
|
|
48
|
+
|
|
49
|
+
**保留子命令(第一个位置参数匹配则走原子命令,不把后续词当 prompt):**
|
|
50
|
+
|
|
51
|
+
`setup`、`models`、`serve`、`mcp`、`history`、`memory`、`skills`、`update`、`init`、`rules`、`exec`、`chat`、`code`
|
|
52
|
+
|
|
53
|
+
分发规则:
|
|
54
|
+
|
|
55
|
+
| argv | 行为 |
|
|
56
|
+
|------|------|
|
|
57
|
+
| (空) | TUI,无首条消息 |
|
|
58
|
+
| `-h` / `--help` 作为第一个 token | 打印 Usage,退出 0 |
|
|
59
|
+
| `-v` / `--version` 作为第一个 token | 打印版本,退出 0 |
|
|
60
|
+
| 第一个位置参数 ∈ 保留子命令 | 现有分支;`chat`/`code` 见下 |
|
|
61
|
+
| 其余 | 视为交互会话:`parseFlags(args)` 后 `positionals.join(" ")` 作为可选首条 prompt |
|
|
62
|
+
|
|
63
|
+
抽出纯函数 `resolveCliInvocation(argv: string[]): CliInvocation`,便于单测、避免把「未知命令」误打成 prompt 或把 prompt 误打成未知命令。
|
|
64
|
+
|
|
65
|
+
`chat` / `code`:解析其后 flag 与剩余位置参数,调用与根命令相同的 `runTui(...)`。`min-agent chat "你好"` ≡ `min-agent "你好"`。不打印弃用警告。
|
|
66
|
+
|
|
67
|
+
未配置时(`!isConfigured()`):TUI 与 `exec` 都与现在 `chat` 相同——打印 `Not configured. Run: min-agent setup` 并退出 1。
|
|
68
|
+
|
|
69
|
+
`--resume` 仅作用于 TUI(根命令 / `chat` / `code`)。与非空首条 prompt 同时出现时:先加载会话,再把 prompt 作为新的一轮提交(允许「恢复后立刻跟一句」)。`exec` 不支持 `--resume`。
|
|
70
|
+
|
|
71
|
+
## 2. TUI 首条 prompt
|
|
72
|
+
|
|
73
|
+
`TuiOptions` 增加 `initialPrompt?: string`,去掉 `mode`。始终 `scanProject()` + `buildCodeSystemPrompt()`。
|
|
74
|
+
|
|
75
|
+
启动后、进入输入循环前:
|
|
76
|
+
|
|
77
|
+
- 仅 prompt:追加一条 user 文本消息,立刻 `runner.run()`
|
|
78
|
+
- 仅 `-i` 图片:保持现有逻辑(空文本 + 图片,立刻 run)
|
|
79
|
+
- prompt + 图片:同一条 user 消息里文本 + 图片,立刻 run
|
|
80
|
+
- `--resume` 且有 prompt:在已加载消息后追加上述 user 消息再 run
|
|
81
|
+
- 皆无:空会话,等用户输入
|
|
82
|
+
|
|
83
|
+
## 3. `min-agent exec`
|
|
84
|
+
|
|
85
|
+
非交互、跑完退出。能力与 TUI 相同(coding prompt + 完整工具)。危险操作仍走 `confirm`;脚本需显式 `-y` / `--yes`(不默认放开)。
|
|
86
|
+
|
|
87
|
+
**Prompt 来源(与 Codex exec 同序):**
|
|
88
|
+
|
|
89
|
+
1. 位置参数拼成 prompt(可多词)
|
|
90
|
+
2. prompt 为 `-`:从 stdin 读全部
|
|
91
|
+
3. 无位置参数且 stdin 非 TTY:从 stdin 读全部
|
|
92
|
+
4. 无位置参数且 stdin 是 TTY:打印用法到 stderr,退出 1
|
|
93
|
+
5. 既有位置参数(且不是单独的 `-`)又有管道 stdin:prompt 正文后追加 `\n\n` + stdin
|
|
94
|
+
|
|
95
|
+
支持与现有 `chat` 单次调用相同的 `--model`、`--provider`、`--image`、`-y`。不支持 `--resume`、`--port`、`--host`。
|
|
96
|
+
|
|
97
|
+
实现:现有 `runAgent` 改为使用统一后的 `runOnce`(coding prompt)。`exec` 在 agent 以错误结束时进程退出码为 1(当前 `runAgent` 打印错误后仍可能以 0 退出,本项一并修掉)。未配置退出 1。stdin 读失败退出 1。
|
|
98
|
+
|
|
99
|
+
不把会话写入 `history`(与当前 `runAgent` 一致)。
|
|
100
|
+
|
|
101
|
+
## 4. 运行时去掉双模式
|
|
102
|
+
|
|
103
|
+
| 现状 | 目标 |
|
|
104
|
+
|------|------|
|
|
105
|
+
| `createChatTools` / `createCodeTools` | 只保留一套 `createTools()`(原 `createCodeTools`:含条件 `codesearch`) |
|
|
106
|
+
| `buildTools(mode)` | 无 mode;始终挂 `explore` + `task`;`todo` 仍每轮替换 |
|
|
107
|
+
| `runOnce` vs `runOnceWithSystem` | `runOnce` 内部 `scanProject` + `buildCodeSystemPrompt`;`runOnceWithSystem` 仅测试/自定义 system 仍可用 |
|
|
108
|
+
| `runOnceCore(..., mode)` | 去掉 mode 参数;日志不再写 `mode=chat/code` |
|
|
109
|
+
| `AgentRunnerDeps.mode` / `codeSystemPrompt?` | 始终传入 system prompt;runner 只走 `runOnceWithSystem`(或合并后的单一入口) |
|
|
110
|
+
|
|
111
|
+
`src/tools/task.ts` 改为调用 `createTools()`。
|
|
112
|
+
|
|
113
|
+
## 5. HTTP API
|
|
114
|
+
|
|
115
|
+
- `POST /v1/chat`:始终原 code 路径(扫描项目、coding prompt、完整工具)
|
|
116
|
+
- `POST /v1/code`:路径保留,内部与 `/v1/chat` 同一 handler,不再有 `codeMode` 布尔
|
|
117
|
+
- 非流式/SSE `done`:**去掉 `mode` 字段**;**始终带 `project`**
|
|
118
|
+
- `POST /v1/paste`:去掉对 `code` 的分支,始终项目感知;请求里多传 `code` 忽略,不 400
|
|
119
|
+
- `GET /v1/project` 不变
|
|
120
|
+
|
|
121
|
+
文档与测试同步:`tests/serve.test.ts` 里「paste + `code: true` 期望 `mode: "code"`」改为期望有 `project`、无 `mode`。`/v1/chat` 成功响应同样有 `project`。
|
|
122
|
+
|
|
123
|
+
## 6. 文档与用户可见文案
|
|
124
|
+
|
|
125
|
+
`printUsage`、README Quick Start / Commands、`docs/API.md`:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
min-agent # 交互会话
|
|
129
|
+
min-agent "hello" # 交互会话,并立刻发送
|
|
130
|
+
min-agent exec "hello" # 非交互,跑完退出
|
|
131
|
+
min-agent --resume <id> # 恢复会话
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
不再出现「Chat 模式」「Code 模式」「project-aware coding mode」作为两种产品模式。`/help` 无需加新斜杠命令(无新 `/` 命令)。`chat`/`code` 可在 Usage 里写成「同无子命令的交互会话(兼容)」一行,或不列出——推荐仍列一行以免旧脚本使用者找不到,但不解释模式差异。
|
|
135
|
+
|
|
136
|
+
## 7. 错误处理
|
|
137
|
+
|
|
138
|
+
- 未知子命令不再存在:非保留词一律当 prompt(包括看起来像拼错的 `setpu`,会进 TUI 并发送该词)。Usage 必须把保留子命令列清楚,避免误触。
|
|
139
|
+
- 空 prompt 的 TUI 合法;空 prompt 的 `exec` 在 TTY 上不合法(见 §3)
|
|
140
|
+
- `--resume` 指向不存在的 id:保持现有 TUI 行为(当新会话),不另造错误
|
|
141
|
+
|
|
142
|
+
## 8. 测试
|
|
143
|
+
|
|
144
|
+
- 新增 `tests/cli-invoke.test.ts`(或同等):覆盖 `resolveCliInvocation`——空 argv、help/version、`setup`、`exec`、`chat` 别名、纯 prompt、flag+prompt、`--resume`、`-m` 在子命令前
|
|
145
|
+
- 更新 `tests/serve.test.ts`:chat/paste 均有 `project`、无 `mode`;`/v1/code` 与 `/v1/chat` 结构一致
|
|
146
|
+
- agent 循环测试继续用 `runOnceWithSystem`,不强制扫项目
|
|
147
|
+
- 仓库根目录 `bun run typecheck`
|
|
148
|
+
|
|
149
|
+
## 影响范围(实现时必须改到)
|
|
150
|
+
|
|
151
|
+
- `src/cli.ts` — 分发、Usage、`exec`
|
|
152
|
+
- `src/tui-chat.ts`、`src/tui/agent-runner.ts` — 去 mode、首条 prompt
|
|
153
|
+
- `src/agent.ts`、`src/tools/index.ts`、`src/tools/task.ts` — 统一工具与 prompt
|
|
154
|
+
- `src/serve.ts`、`docs/API.md`、`tests/serve.test.ts`
|
|
155
|
+
- `packages/min-agent/README.md`
|
|
156
|
+
- 无新斜杠命令,`slash-commands.ts` / `/help` 仅当文案里还写着 chat/code 时删掉
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 自审
|
|
161
|
+
|
|
162
|
+
- 无 TBD:`exec` 的 stdin 规则、退出码、与 `--resume` 的边界已写死
|
|
163
|
+
- 与「根命令永远 TUI」一致:`exec` 是唯一 CLI 单次出口
|
|
164
|
+
- 范围可一次落地:CLI 分发 + 运行时去 mode + HTTP 文档测试,不拆第二期
|
|
165
|
+
- 「第一个位置参数」与「带值 flag」的跳过规则写明,避免 `min-agent --model x exec hi` 被当成 prompt
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "min-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Minimal AI coding agent with tool use, MCP, and skills support",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"bin",
|
|
15
15
|
"dist",
|
|
16
16
|
"docs",
|
|
17
|
+
"skills",
|
|
17
18
|
"README.md",
|
|
18
19
|
"LICENSE"
|
|
19
20
|
],
|
|
@@ -32,6 +33,9 @@
|
|
|
32
33
|
"dev": "bun run src/cli.ts",
|
|
33
34
|
"build": "tsc",
|
|
34
35
|
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "bun test",
|
|
37
|
+
"lint": "biome check src tests",
|
|
38
|
+
"format": "biome format --write src tests",
|
|
35
39
|
"prepack": "npm run typecheck && npm run build"
|
|
36
40
|
},
|
|
37
41
|
"keywords": [
|
|
@@ -50,6 +54,7 @@
|
|
|
50
54
|
"@ai-sdk/provider": "~3.0.8",
|
|
51
55
|
"@modelcontextprotocol/sdk": "~1.27.1",
|
|
52
56
|
"ai": "~6.0.168",
|
|
57
|
+
"commander": "14.0.3",
|
|
53
58
|
"glob": "~13.0.5",
|
|
54
59
|
"ink": "5",
|
|
55
60
|
"ink-spinner": "5",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: self-config
|
|
3
|
+
description: >
|
|
4
|
+
Configures min-agent itself: providers, MCP servers, skills, rules, memory,
|
|
5
|
+
permission, sandbox, plugins, and files under ~/.min-agent/ and .min-agent/.
|
|
6
|
+
Use when the user asks to install, enable, disable, or change min-agent settings.
|
|
7
|
+
always-load: true
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Configure min-agent
|
|
12
|
+
|
|
13
|
+
This skill is already loaded. Follow it whenever the user asks to change min-agent itself. Do not read README.md for this. Field catalogs: [reference.md](reference.md).
|
|
14
|
+
|
|
15
|
+
## Scope first
|
|
16
|
+
|
|
17
|
+
| Scope | Directory | When to use |
|
|
18
|
+
|-------|-----------|-------------|
|
|
19
|
+
| Global | `~/.min-agent/` (`MIN_AGENT_CONFIG_DIR` replaces this) | All projects; API keys live only here |
|
|
20
|
+
| Project | `<cwd>/.min-agent/` | This repo only |
|
|
21
|
+
|
|
22
|
+
If the user does not say which scope: use **project** when `.min-agent/` exists, otherwise **global**. Never put `apiKey`, `token`, `serperApiKey`, or other secrets in project files.
|
|
23
|
+
|
|
24
|
+
Config files are **strict JSON** (no comments). Read the file before editing. Prefer the `edit` tool for existing files; `write` only when creating a new file. Keep unrelated keys. Create parent directories when needed.
|
|
25
|
+
|
|
26
|
+
## What goes where
|
|
27
|
+
|
|
28
|
+
| Goal | File | Notes |
|
|
29
|
+
|------|------|--------|
|
|
30
|
+
| Providers, keys, search backends, pricing, extra instruction paths, global skill disables | `~/.min-agent/config.json` | Keys only here |
|
|
31
|
+
| Project skill toggles; overlay `activeProvider` / `defaultModel` / `sampling` / `budget` / `permission` / `sandbox` / `compaction` / `agent` | `.min-agent/config.json` | Overlay is field-by-field; `sampling`/`budget`/`sandbox`/`compaction`/`agent` merge keys |
|
|
32
|
+
| MCP servers | `~/.min-agent/mcp.json` or `.min-agent/mcp.json` | Merge by server **name**; project replaces the same name |
|
|
33
|
+
| Memories | `memory.json` in the same dirs | Prefer `memory_save` / `memory_search` tools over editing the file |
|
|
34
|
+
| Global rules | `~/.min-agent/rules.md` | Always loaded |
|
|
35
|
+
| Project rules | `AGENTS.md`, `RULES.md`, or `CLAUDE.md` in cwd (or `.min-agent/AGENTS.md`) | First match wins when walking up from cwd |
|
|
36
|
+
| Extra instruction files | `instructions` array in global `config.json` | Paths or URLs |
|
|
37
|
+
| Custom tools | `.min-agent/tools/*.ts` or `~/.min-agent/tools/*.ts` | See reference.md |
|
|
38
|
+
| Project skills | `.min-agent/skills/<name>/SKILL.md` | Or `min-agent skills new <name>` |
|
|
39
|
+
| Global skills | `~/.agents/skills/<name>/SKILL.md` | `min-agent skills new <name> --global` |
|
|
40
|
+
|
|
41
|
+
## MCP
|
|
42
|
+
|
|
43
|
+
Write `{ "mcpServers": { "<name>": { ... } } }`.
|
|
44
|
+
|
|
45
|
+
- Local: `"command": ["npx", "-y", "@scope/server", "..."]` plus optional `environment`, `enabled`, `connectTimeout`, `callTimeout`.
|
|
46
|
+
- Remote: `"url": "https://..."`. Optional `token`, `headers`, `remoteTransport` (`auto` default, or `streamable-http` / `sse`), `oauth` (`{}` to login in a browser, or `false` to disable).
|
|
47
|
+
- `enabled: false` disables without deleting. Project `.min-agent/mcp.json` wins on the same name.
|
|
48
|
+
|
|
49
|
+
CLI (user shell, not a substitute for writing the file in this session): `min-agent mcp add|list|info|enable|disable|remove|check` with `--project` for repo scope.
|
|
50
|
+
|
|
51
|
+
**This session:** editing `mcp.json` is persisted, but connected servers will not change until the user restarts. Say so after you write the file. HTTP `POST /v1/mcp` on a running `min-agent serve` reconnects; a coding session does not.
|
|
52
|
+
|
|
53
|
+
Connected servers already expose `mcp_list_resources`, `mcp_read_resource`, `mcp_list_prompts`, `mcp_get_prompt`. Do not invent per-resource tools.
|
|
54
|
+
|
|
55
|
+
## Skills
|
|
56
|
+
|
|
57
|
+
User-skill roots, later overriding earlier: `~/.agents/skills/` → `.min-agent/skills/` → `.agents/skills/` → `.opencode/skills/` → `.claude/skills/`. Symlinks are followed. `MIN_AGENT_SKILLS_DIRS` (path-delimiter separated) replaces that user list. Built-in skills shipped with min-agent still load and **win on name**; they are not overridden by user copies. `MIN_AGENT_NO_BUILTIN_SKILLS=1` skips built-ins.
|
|
58
|
+
|
|
59
|
+
Enable/disable:
|
|
60
|
+
|
|
61
|
+
- Global disable: `disabledSkills` in `~/.min-agent/config.json`
|
|
62
|
+
- Project disable: `disabledSkills` in `.min-agent/config.json` (wins)
|
|
63
|
+
- Re-enable a globally disabled skill in this repo: add the name to project `enabledSkills`
|
|
64
|
+
|
|
65
|
+
Toggles take effect on the next turn. A **new** `SKILL.md` is invisible until skills are rediscovered (`/skills` in the interactive session, `POST /v1/skills/reload` on serve, or restart).
|
|
66
|
+
|
|
67
|
+
Scaffold:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
---
|
|
71
|
+
name: my-skill
|
|
72
|
+
description: What it does
|
|
73
|
+
---
|
|
74
|
+
Instructions...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`description` may be a YAML `|` / `>` block. Optional: `version`, `allowed-tools`, `always-load`, `metadata.requires.bins`. Do not disable `self-config` unless the user explicitly asks.
|
|
78
|
+
|
|
79
|
+
## Rules, memory, permission, sandbox
|
|
80
|
+
|
|
81
|
+
- Rules: edit the files in the table above. `/reload` reloads rules only, not MCP.
|
|
82
|
+
- Memory: use memory tools. Default save scope is project when `.min-agent/` exists. Shape: `{ "content": string, "tags": string[], "created": ISO string }` array.
|
|
83
|
+
- Permission: `ask` (default) | `accept-edits` | `allow-all` in config `permission`. CLI `min-agent permission …` / `--permission` without a message writes config and exits; with a message it is this session only. `--yes` is this session only and does not write config.
|
|
84
|
+
- Sandbox default is **off**. `mode`: `off` | `workspace` | `strict`. Optional `network`, `extraWriteRoots`, `extraReadRoots`. Isolation is independent of permission. `--sandbox` / `--network` without a message write config and exit.
|
|
85
|
+
|
|
86
|
+
## Providers
|
|
87
|
+
|
|
88
|
+
Only in global `config.json`: `providers[]` with `name`, `type` (`openai-compatible` | `openai` | `ollama`), `baseURL`, `apiKey`, optional `defaultModel`, `contextWindow`. `activeProvider` selects one. Project config may set `activeProvider` and `defaultModel` (no keys).
|
|
89
|
+
|
|
90
|
+
After changing keys or MCP connections, tell the user if a restart is required. Do not print full secrets back in chat.
|