@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/README.md +183 -0
- package/dist/agent-MICFDGUF.js +4 -0
- package/dist/anthropic-JDAGNAPR.js +4 -0
- package/dist/checker-PF3FEOF2.js +4 -0
- package/dist/chunk-4KVSJNS6.js +90 -0
- package/dist/chunk-6ARDOHBL.js +4 -0
- package/dist/chunk-7MHXMDYC.js +35 -0
- package/dist/chunk-F6HLYUZ4.js +355 -0
- package/dist/chunk-FZPTNGTU.js +4 -0
- package/dist/chunk-LPLPMGWW.js +336 -0
- package/dist/chunk-MQ5XOYLD.js +4 -0
- package/dist/chunk-RD3MICOU.js +4 -0
- package/dist/{cleanup-4R3534Z3.js → cleanup-BQJDUOKA.js} +1 -1
- package/dist/glob_addon.node +0 -0
- package/dist/main.js +240 -240
- package/dist/openai-I4WTRNNT.js +26 -0
- package/dist/{server-XPKSROM2.js → server-OGPKL2U2.js} +22 -21
- package/package.json +17 -24
- package/dist/anthropic-737END4X.js +0 -4
- package/dist/chunk-NCPOPA4A.js +0 -4
- package/dist/chunk-SC34YHMX.js +0 -521
- package/dist/chunk-Z3E5YV3P.js +0 -121
- package/dist/openai-4KX74QBZ.js +0 -27
- package/docs/ch1.md +0 -25
- package/docs/ch10.md +0 -122
- package/docs/ch11.md +0 -163
- package/docs/ch12.md +0 -289
- package/docs/ch13.md +0 -320
- package/docs/ch14.md +0 -152
- package/docs/ch15.md +0 -547
- package/docs/ch2.md +0 -273
- package/docs/ch3.md +0 -206
- package/docs/ch4.md +0 -125
- package/docs/ch5.md +0 -165
- package/docs/ch6.md +0 -201
- package/docs/ch7.md +0 -448
- package/docs/ch8.md +0 -217
- package/docs/ch9.md +0 -351
- package/docs/index.css +0 -23
- package/docs/index.md +0 -21
- package/docs/swifty.mdx +0 -7
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
|