@swifty.js/swifty 0.0.1 → 0.0.2

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/docs/ch13.md DELETED
@@ -1,320 +0,0 @@
1
- # Subagent
2
-
3
- 一个大的重构任务中, 插入一个小的更新 README.md 任务: Agent 上下文污染
4
-
5
- ## 关键洞察: Agent 也是一种工具
6
-
7
- Agent 和 Tool 抽象同构, 可以将 Agent 包装为 Tool, 注册到 ToolRegistry
8
-
9
- <!-- 源码: src/tools/types.ts -->
10
-
11
- ```ts
12
- export type ToolCategory = "read" | "write" | "command";
13
-
14
- interface Tool {
15
- name: string; // Subagent 的名字
16
- description: string; // Subagent 的描述
17
- category: ToolCategory;
18
- deferred?: boolean;
19
- system?: boolean;
20
- schema(): ToolSchema; // 参数: Subagent 的任务
21
- // 返回 Subagent 的执行结果
22
- execute(ctx: ToolContext, args: Record<string, unknown>): Promise<ToolResult>;
23
- }
24
- ```
25
-
26
- ## properties (parameters)
27
-
28
- <!-- 源码: src/subagent/agent-tool.ts -->
29
-
30
- ```json
31
- {
32
- "name": "code-review",
33
- "description": "负责代码审查的 subagent",
34
- "prompt": "",
35
- "subagent_type": "", // 预定义的 agent 角色, 例如 explore, plan, code-review
36
- "model": "", // 模型
37
- "run_in_background": false, // 同步执行/异步执行
38
- "isolation": "", // undefined | "worktree", 见 ch14
39
- "team_name": "" // 见 ch14
40
- }
41
- ```
42
-
43
- - 多 Agent 框架 (CrewAI、AutoGen): 中心化编排
44
- - AutoGen 的 GroupChat 使用 GroupChatManager, 按策略决定 agent chat 顺序
45
- - CrewAI 使用 Crew 对象编排 agent 和任务调度
46
- - Swifty: 主从模式, coding 场景下主从模式更稳定, 避免多 Agent 循环等待
47
-
48
- ## 两种创建模式
49
-
50
- - 预定义的 subagent (Definition-based): 预定义的 subagent 角色, 无对话历史
51
- - fork 的 subagent (Fork-based): spawn (fork) 一个 subagent, 继承父 Agent 的完整对话历史
52
-
53
- ### 预定义的 subagent (Definition-based)
54
-
55
- subagent_type 不能为空, 是预定义的 subagent 角色
56
-
57
- 示例: .swifty/agents/code-review.md
58
-
59
- 负责代码审查的 subagent 不能再 fork 一个 subagent、不能写文件、不能执行 Bash 命令, 是只读的代码审查专家
60
-
61
- <!-- 源码: src/subagent/loader.ts -->
62
-
63
- ```md
64
- ---
65
- name: code-review
66
- description: 负责代码审查的 subagent
67
- disallowed_tools:
68
- - EditFile
69
- - WriteFile
70
- - Bash
71
- max_turns: 20
72
- ---
73
-
74
- 你是一个负责代码审查的 subagent
75
-
76
- ## 职责
77
-
78
- ...
79
-
80
- ## 规则
81
-
82
- ...
83
- ```
84
-
85
- ### fork 的 subagent (Fork-based)
86
-
87
- - subagent_type 为空时, 创建 fork 的 subagent
88
- - 典型场景: 将一个 react 类组件迁移到函数组件后, fork 3 个 subagent 迁移剩余的类组件
89
- - 降低成本: fork 的 subagent 和 父 Agent 使用相同的 tools、system、messages (prompt cache 按前缀匹配, 顺序是 tools -> system -> messages), fork 的 subagent 首次 LLM API 请求可以命中 prompt cache, 降低 input_tokens 成本
90
-
91
- > 继承父 Agent 的完整对话历史
92
-
93
- 1. 复制父 Agent 的完整对话历史
94
- 2. 对话历史的最后一条 assistant 消息中, 对「请求调用 AgentTool 的 tool_use 内容块 tu」, push 一个 tool_result 内容块, 保持 messages 格式 (user 和 assistant 两个 role 交替出现)
95
- 3. 将 Agent 的任务指令作为 user 消息, 追加到对话历史, 使用 `<fork_boilerplate />` 标签包裹对 subagent 的行为约束
96
-
97
- ```json
98
- {
99
- "tool_use_id": "${tu.tool_use_id}",
100
- "content": "(tool execution interrupted by fork)",
101
- "is_error": false
102
- }
103
- ```
104
-
105
- > 为什么需要使用 `<fork_boilerplate />` 标签包裹对 subagent 的行为约束?
106
-
107
- fork 的 subagent 继承父 Agent 的 system prompt, system prompt 可能包含: "你可以创建 subagent", "你需要向用户确认" 等, 使用 `<fork_boilerplate />` 覆盖继承的默认行为
108
-
109
- ```md
110
- <fork_boilerplate>
111
- You are a forked worker process. You are NOT the main agent.
112
- Rules (non-negotiable):
113
-
114
- 1. Do NOT fork again.
115
- 2. Do NOT converse, ask questions, or request confirmation.
116
- 3. Use tools directly: read files, search code, make changes.
117
- 4. Stay strictly within your assigned task scope.
118
- 5. Final report must be under 500 characters, starting with "Scope:".
119
- </fork_boilerplate>
120
-
121
- Your task: ${prompt}
122
- ```
123
-
124
- fork 的 subagent 必须后台异步运行, 执行结束后使用 `<task-notification />` 标签包裹执行结果, 作为一条 user 消息注入到主 agent 的上下文 (TODO)
125
-
126
- > 为什么 fork 的 subagent 必须后台异步运行?
127
-
128
- 1. fork 的场景是主 agent 分发多个子任务, 并发执行
129
- 2. fork 的 subagent 继承父 Agent 的完整对话历史, 首次 API 请求耗时长; 前台同步等待, 父 Agent 阻塞, 用户体验很差
130
-
131
- > 定义式 subagent 默认前台同步运行
132
-
133
- 定义式 subagent 默认前台同步运行, 除非
134
-
135
- - subagent 配置的 frontmatter 中指定 `background: true`
136
- - 调用 subagent 时指定 `run_in_background: true`
137
-
138
- ```yaml
139
- name: code-review
140
- description: 负责代码审查的 subagent
141
- disallowed_tools:
142
- - EditFile
143
- - WriteFile
144
- - Bash
145
- max_turns: 20
146
- background: true
147
- ```
148
-
149
- ## 选择哪种创建模式: Definition-based / Fork-based
150
-
151
- - 如果任务通用、固定角色、固定职责, 例如 plan 指定计划、explore 代码探索、code-review 代码审查, 使用定义式 subagent, 指定 subagent_type:
152
- - 可以精确控制 subagent 的能力边界
153
- - 可以限制 subagent 调用的工具
154
- - 可以指定一个更小更快的模型: haiku, sonnet, deepseek...
155
- - 如果任务不通用、与主 agent 的当前工作高度相关, 例如: 迁移一个组件的 useImperativeHandle 从 react18 到 react19, fork 3 个 subagent 迁移剩余的类组件, 使用 fork 的 subagent, subagent_type 为空
156
-
157
- ## 上下文隔离
158
-
159
- - 基础设施共享: API Key、LLM API 连接池、工具集、MCP、Skill、Hook
160
- - 权限 (permissionMode) 隔离
161
- - 文件系统: 默认共享, 使用 `isolation: "worktree"` 时隔离
162
-
163
- ## Subagent markdown 配置
164
-
165
- <!-- 源码: src/subagent/loader.ts -->
166
-
167
- | | Skill | Subagent |
168
- | ---------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
169
- | body | 注入 messages 的 SOP 指令 | 对于定义式 subagent, 作为 system prompt; 对于 fork 的 subagent, body 使用 `<fork_boilerplate />` 标签包裹注入到 user 消息 |
170
- | frontmatter.name | name | name, 映射到 AgentDefinition 的 agentType |
171
- | frontmatter.description | description | description, 映射到 AgentDefinition 的 whenToUse |
172
- | frontmatter.model | model | model |
173
- | frontmatter.system_prompt | X | 覆盖默认 system prompt |
174
- | frontmatter.subagent_type | X | 预定义的 agent 角色, 例如 explore, plan, code-review |
175
- | frontmatter.background | X | 是否后台异步运行, fork 的 subagent 必须后台异步运行, 为了对齐 Claude, properties (parameters) 中是 run_in_background |
176
- | frontmatter.isolation | X | `isolation: undefined \| 'worktree'`, 是否使用 git worktree 文件系统隔离 |
177
- | frontmatter.memory | X | 记忆范围: `"user" \| "project" \| "local"` |
178
- | frontmatter.tools | X | 工具白名单 |
179
- | frontmatter.disallowed_tools | X | 工具黑名单 |
180
- | frontmatter.permission_mode | X | 例如 `permissionMode: "acceptEdits"` 调用工具, 不弹出对话框 |
181
- | frontmatter.max_turns | X | 最大 agent loop 次数数 |
182
-
183
- <!-- 源码: src/subagent/definition.ts -->
184
-
185
- ```ts
186
- /** Memory scope for a subagent. Mirrors Go's AgentMemoryScope. */
187
- export type AgentMemoryScope = "user" | "project" | "local";
188
-
189
- export interface AgentDefinition {
190
- name: string; // Agent type
191
- description: string; // When to use
192
- tools?: string[];
193
- disallowedTools?: string[];
194
- systemPromptOverride?: string;
195
- maxTurns?: number;
196
- model?: string;
197
- permissionMode?: PermissionMode; // "default" | "acceptEdits" | "plan" | "bypassPermissions"
198
- background?: boolean;
199
- isolation?: "worktree";
200
- initialPrompt?: string;
201
- omitMarkdown?: boolean;
202
- skills?: string[];
203
- /** Memory scope — "user" | "project" | "local" */
204
- memory?: AgentMemoryScope;
205
- mcpServers?: string[];
206
- // ...
207
- }
208
- ```
209
-
210
- <!-- 源码: src/subagent/loader.ts -->
211
-
212
- Agent 定义文件, 优先级从低到高
213
-
214
- - 内置级: Swifty 内置 (BUILTIN_AGENTS)
215
- - 用户级: ~/.swifty/agents/
216
- - 项目级: ${workDir}/.swifty/agents/
217
-
218
- ## Subagent Loop
219
-
220
- subagent loop 和主 agent loop 的区别
221
-
222
- 1. subagent loop turn 不等待用户输入
223
- 2. LLM 不再调用工具, subagent loop 结束, 返回执行结果
224
- 3. pre_tool_use hook -> 调用 AgentTool -> subagent loop -> post_tool_use hook
225
-
226
- ## Subagent 不能继续 spawn
227
-
228
- <!-- 源码: src/subagent/tool-filter.ts -->
229
-
230
- 1. 全局 subagent: 工具黑名单 ALL_AGENT_DISALLOWED_TOOLS, 该黑名单包含 Agent, AskUserQuestion, ...
231
- 2. 后台异步运行的 subagent: 工具白名单 ASYNC_AGENT_ALLOWED_TOOLS, 该白名单不包括 AgentTool、AskUserQuestion
232
- 3. 自定义 subagent: 额外工具黑名单 CUSTOM_AGENT_DISALLOWED_TOOLS
233
- 4. Subagent markdown 配置 frontmatter 中的 tools、disallowed_tools
234
-
235
- 具体的
236
-
237
- <!-- 源码: src/subagent/tool-filter.ts -->
238
-
239
- - 预定义的 subagent 不能继续 spawn: 通过全局 subagent 工具黑名单 ALL_AGENT_DISALLOWED_TOOLS, 该黑名单包含 Agent, AskUserQuestion, ...
240
- - fork 的 subagent 不能继续 fork
241
- - fork 一个 subagent 会克隆主 agent 的 tools, 克隆得到的 AgentTool 有 querySource 标记, 如果某个 agent 的 AgentTool 有 querySource 标记, 则是 fork 的 subagent, 不能继续 fork
242
- - 如果对话历史中包含 fork 标记 `<fork_boilerplate />`, 则是 fork 的 subagent, 不能继续 fork
243
- - 后台异步运行的 subagent 不能继续 spawn: 通过硬编码的工具白名单 ASYNC_AGENT_ALLOWED_TOOLS, 该白名单不包括 AgentTool、AskUserQuestion
244
-
245
- ## 后台异步运行模式
246
-
247
- 1. 调用 AgentTool 时指定 `run_in_background: true`, subagent 以后台异步任务启动, 主 agent 收到 subagent 的 agentId 和 async_launched 状态
248
- 2. 前台同步运行的 subagent 120s 还未结束, 自动切换到后台异步运行
249
- 3. 按 esc 键将前台同步运行的 subagent 手动切换到后台异步运行
250
- 4. fork 的 subagent 无条件后台异步运行
251
-
252
- swifty 没有管理后台异步任务的 Slash Command, 后台异步任务通过 4 个内置工具暴露给 agent:
253
-
254
- - TaskList 任务列表
255
- - TaskGet 获取某个任务的状态或结果
256
- - TaskCreate 创建任务, 提供给 hook 使用
257
- - TaskUpdate 更新任务状态
258
-
259
- ## 内置 subagent_type
260
-
261
- ### Explore
262
-
263
- <!-- 源码: src/subagent/definition.ts -->
264
-
265
- ```md
266
- ---
267
- name: explore
268
- description: You are a code exploration expert. This is a read-only exploration task.
269
- disallowed_tools: ["EditFile", "WriteFile"]
270
- model: haiku
271
- permission_mode: plan
272
- ---
273
-
274
- 你是代码探索专家, 这是一个只读探索任务
275
-
276
- 禁止: 创建文件、修改文件、删除文件、提问
277
-
278
- 工具调用策略:
279
-
280
- - 使用 Glob 搜索文件
281
- - 使用 Grep 搜索内容
282
- - 使用 ReadFile 读取指定路径的文件
283
- - 只允许执行只读的 Bash 命令
284
- - 尽可能并发调用多个工具以提高效率
285
- ```
286
-
287
- ### Plan
288
-
289
- <!-- 源码: src/subagent/definition.ts -->
290
-
291
- ```md
292
- ---
293
- name: plan
294
- description: You are a software architect. This is a read-only planning task.
295
- disallowed_tools: ["EditFile", "WriteFile"]
296
- permission_mode: plan
297
- ---
298
-
299
- 你是软件架构师, 这是一个只读规划任务
300
-
301
- 禁止: 创建文件、修改文件、删除文件、提问
302
-
303
- 工作流程
304
-
305
- 1. 理户需求
306
- 2. 探索代码库, 了解项目约定、开发范式
307
- 3. 设计方案
308
- 4. 输出计划, 划分里程碑, 明确风险
309
- ```
310
-
311
- ### General Purpose
312
-
313
- <!-- 源码: src/subagent/definition.ts -->
314
-
315
- ```md
316
- ---
317
- name: general-purpose
318
- description: 你是 Swifty 的 Subagent, 不是主 agent
319
- ---
320
- ```
package/docs/ch14.md DELETED
@@ -1,152 +0,0 @@
1
- # worktree
2
-
3
- 文件系统隔离
4
-
5
- subagent 的会话被持久化到 .swifty/worktree_session.json, 如果 swifty 进程崩溃, 重新启动时可以通过 --resume 切换回 worktree 会话, 跳过 git worktree add 创建 worktree
6
-
7
- ## git 命令的环境变量
8
-
9
- <!-- 源码: src/worktree/env.ts -->
10
-
11
- ```bash
12
- # 禁止 git 提示输入用户名或密码
13
- GIT_ASKPASS=""
14
- # 禁止 git 的交互式提示
15
- GIT_TERMINAL_PROMPT=0
16
- ```
17
-
18
- ## git worktree 命令
19
-
20
- <!-- 源码: src/worktree/worktree.ts -->
21
-
22
- ```bash
23
- git worktree add <worktreePath> <worktreeBranch>
24
-
25
- # -B: worktree 分支存在时, 强制覆盖旧的 worktree 分支
26
- git worktree add -B <worktreeBranch> <worktreePath> <baseBranch>
27
- # 等价于
28
- git branch -f <worktreeBranch> <baseBranch>
29
- git worktree add <worktreePath> <worktreeBranch>
30
- ```
31
-
32
- - 需要 slug 安全验证, 防止路径遍历 ../../etc/password
33
- - worktree 目录在 .swifty/worktrees
34
- - 分支名加 `worktree-` 前缀
35
-
36
- <!-- 源码: src/worktree/worktree.ts -->
37
-
38
- ```js
39
- const worktreeDir = join(projectRoot, ".swifty", "worktrees", slug);
40
- const branch = `worktree-${slug}`;
41
- ```
42
-
43
- 脆弱实现
44
-
45
- <!-- 源码: src/worktree/worktree.ts -->
46
-
47
- 如果 worktree 目录已存在, 则跳过 git worktree add 创建 worktree, 直接复用
48
-
49
- - 先读 worktree 目录下的 .git 指针文件, 得到 gitdir 路径
50
- - 再读 HEAD 文件, 如果 HEAD 是符号引用 ref: refs/head/..., 则继续读 refs 得到 commit SHA
51
- git worktree add 创建 worktree 对于大型仓库需要数秒: 检出全量文件树、写入 worktree 目录
52
-
53
- 后续优化
54
-
55
- ```bash
56
- # 列出所有 worktree、路径、分支、commit SHA
57
- git worktree list --porcelain
58
- # 查询某个 worktree 当前的 commit SHA
59
- git -C <worktree-path> rev-parse HEAD
60
- ```
61
-
62
- ## worktree 创建后
63
-
64
- ```bash
65
- # 列出被 .gitignore 忽略的文件和目录
66
- # --directory: 如果整个目录被忽略, 则只打印目录
67
- git ls-files --other --ignored --exclude-standard --directory
68
- ```
69
-
70
- <!-- 源码: src/worktree/worktree.ts, src/worktree/setup.ts -->
71
-
72
- `performPostCreationSetup` worktree 创建后执行:
73
-
74
- 1. 复制 `.swifty/` 配置目录到 worktree
75
- 2. 设置 git hooks: 先使用 `.husky/`, 再使用 `.git/hooks/`, 通过 `git config core.hooksPath` 共享主仓库的 hooks (源码: src/worktree/worktree.ts)
76
- 3. 安装依赖 (pnpm install、go mod tidy): 源码缺陷 TODO
77
- 4. 读取 `.worktreeinclude` 文件 (每行一个路径, 跳过空行和 `#` 注释), 将 include 的文件和目录复制到 worktree; 跳过以 / 开头或包含 .. 的路径, 防止路径遍历
78
-
79
- ## 进入 worktree
80
-
81
- <!-- 源码: src/tools/enter-worktree.ts -->
82
-
83
- - 不切换进程级 cwd: 防止后台异步 subagent、agent team 并发调用 Bash 工具切换进程级 cwd;
84
- - 将 worktree 路径保存到 session 状态, (sub)agent 调用 Bash、ReadFile、WriteFile 等工具时, 显式的从 `session.worktreePath` 拿到 worktree 路径
85
-
86
- ## 退出 worktree
87
-
88
- <!-- 源码: src/worktree/worktree.ts, src/worktree/changes.ts -->
89
-
90
- ```bash
91
- # 是否有未 commit 的修改
92
- git status --porcelain
93
-
94
- # 是否有新增的 commit (相对 worktree 创建时的 HEAD)
95
- git rev-list --count ${headCommit}..HEAD
96
- ```
97
-
98
- - `hasWorktreeChanges` 两种实现:
99
- - worktree.ts: 先执行 `git status --porcelain`, 再对比当前 HEAD SHA 与 `headCommit` (worktree 创建时的 HEAD) 是否相同, 不使用 `git rev-list` <!-- 源码: src/worktree/worktree.ts -->
100
- - changes.ts: 执行 `git rev-list --count ${headCommit}..HEAD` 统计新增 commit 数量, `headCommit` 是 worktree 创建时的 HEAD
101
- - 是否删除 worktree: worktree 中是否有未 commit 的修改、是否有新增的 commit
102
- - 清空 session 状态
103
-
104
- ## 清理过期的 worktree
105
-
106
- <!-- 源码: src/worktree/worktree.ts, src/worktree/cleanup.ts -->
107
-
108
- - 进程崩溃、用户强制退出, 会导致 .swifty/worktree 堆积大量的 worktree 目录
109
- - workflow 创建的 worktree: `wf-[hash]`, 会被自动清理
110
- - subagent 创建的 worktree: `agent-[hash]`, 会被自动清理
111
- - agent team leader 指定 teammate `isolation: "worktree"`, leader 创建的 worktree: `team-${teamNae}/${teammateName}`, 见 ch15
112
- - 用户手动创建的 worktree, 不会被自动清理
113
- - 如果 worktree 没有未 commit 的修改, 也没有新增的 commit, 则可以自动清理
114
- - 如果 worktree 已过期、有新增的 commit 并且推送到远端, 则可以自动清理
115
-
116
- ## worktree 与 subagent
117
-
118
- <!-- 源码: src/tools/enter-worktree.ts, src/worktree/worktree.ts -->
119
-
120
- subagent 使用 `isolation: "worktree"` 时, subagent 的启动流程
121
-
122
- 1. 创建 worktree
123
- 2. 创建 subagent, 将 worktree 路径保存到 session 状态
124
- 3. 运行 subagent
125
- 4. subagent loop 结束后在 worktree 中提交
126
- 5. 离开、清理 worktree
127
- 6. 返回结果给主 agent
128
- 7. 主 agent cr, 决定是否合并
129
-
130
- ```ts
131
- export function buildWorktreeNotice(parentCwd: string, wtPath: string): string {
132
- return (
133
- `You are working in a git worktree at: ${wtPath}\n` +
134
- `The parent project is at: ${parentCwd}\n` +
135
- `Changes made here are isolated from the parent working tree.`
136
- );
137
- }
138
- ```
139
-
140
- - 你 (subagent) 继承父 agent 的对话历史
141
- - 你 (subagent) 在 git worktree 工作, 你需要翻译父 agent 对话历史中的路径为 worktree 中的路径, 修改文件前重新读取文件
142
-
143
- > 考虑以下场景
144
-
145
- subagent 在 worktree 中修改并提交了 server.ts, 主 agent 期望将该 subagent 的变更merge/rebase/cherry-pick 到主分支; Swifty 没有内置的 merge/rebase/cherry-pick 工具, 主 agent 调用 Bash 工具, 执行 `git merge/rebase/cherry-pick`
146
-
147
- 为什么 Swifty 没有将 merge/rebase/cherry-pick 作为内置工具?
148
-
149
- - merge/rebase/cherry-pick 不是 Agent 的原子操作
150
- - 主 agent 可以调用 Bash 工具执行 git 命令
151
- - 主 agent 需要调用 ReadFile 工具查看冲突文件, 以确定 merge/rebase/cherry-pick 顺序和冲突解决策略
152
- - merge/rebase/cherry-pick 失败时, 主 agent 需要调用 Bash 工具 abort