Skip to content

Commit c8d08d2

Browse files
Feat/integrate lint preview (#285)
* feat: 适配 zed acp 协议 * docs: 完善 acp 文档 * feat: integrate feature branches + daemon/job 命令层级化 + 跨平台后台引擎 Cherry-picked from origin/lint/preview (637c908), excluding lint-only changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct detectMimeFromBase64 to decode raw bytes from base64 Cherry-picked from origin/lint/preview (ee36954). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: daemon 子进程 spawn 跨平台修复 + CliLaunchSpec 集中化重构 Cherry-picked from origin/lint/preview (c5f52cd), excluding lint-only formatting changes. - 新建 src/utils/cliLaunch.ts: 集中化 CLI 子进程启动层 - 修复 --daemon-worker=kind 等号格式解析 - 修复 daemon/bg fast path 缺少 setShellIfWindows() - 修复 checkPathExists 用 existsSync 替代 execSync('dir') - 7 个 spawn 站点迁移到 CliLaunchSpec Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: merge tsconfig.base.json into tsconfig.json with full compiler options The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing tsconfig.base.json. This commit restores them in a single tsconfig.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: merge tsconfig.base.json into tsconfig.json with full compiler options The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing tsconfig.base.json. This commit restores them in a single tsconfig.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a02dc0b commit c8d08d2

137 files changed

Lines changed: 13265 additions & 835 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ src/utils/vendor/
1515
.claude/
1616
.codex/
1717
.omx/
18-
18+
.docs/task/
1919
# Binary / screenshot files (root only)
2020
/*.png
2121
*.bmp

build.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const DEFAULT_BUILD_FEATURES = [
4242
'KAIROS',
4343
'COORDINATOR_MODE',
4444
'LAN_PIPES',
45+
'BG_SESSIONS',
46+
'TEMPLATES',
4547
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
4648
// P3: poor mode (disable extract_memories + prompt_suggestion)
4749
'POOR',
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
# Daemon 重构设计方案
2+
3+
> 分支: `feat/integrate-5-branches`
4+
> 基于: `f41745cb` (= main `11bb3f62` 内容)
5+
> 日期: 2026-04-13
6+
7+
## 一、问题概述
8+
9+
### 1.1 命令结构散乱
10+
11+
当前后台进程相关的命令分布在三个不同的位置,没有统一的命名空间:
12+
13+
| 命令 | 注册位置 | 入口 |
14+
|------|---------|------|
15+
| `claude daemon start/status/stop` | `cli.tsx` 快速路径 L203 | `daemon/main.ts` |
16+
| `claude ps` | `cli.tsx` 快速路径 L220 | `cli/bg.ts` |
17+
| `claude logs <x>` | `cli.tsx` 快速路径 L232 | `cli/bg.ts` |
18+
| `claude attach <x>` | `cli.tsx` 快速路径 L236 | `cli/bg.ts` |
19+
| `claude kill <x>` | `cli.tsx` 快速路径 L238 | `cli/bg.ts` |
20+
| `claude --bg` | `cli.tsx` 快速路径 L244 | `cli/bg.ts` |
21+
| `claude new/list/reply` | `cli.tsx` 快速路径 L250 | `cli/handlers/templateJobs.ts` |
22+
| `claude rollback` | `main.tsx` Commander.js L6525 | `cli/rollback.ts` |
23+
| `claude up` | `main.tsx` Commander.js L6511 | `cli/up.ts` |
24+
25+
**问题**:
26+
- `ps/logs/attach/kill``daemon` 逻辑上都是后台进程管理,但互不关联
27+
- 这些命令都**只有 CLI 入口**,REPL 里输入 `/daemon``/ps` 不存在
28+
- `new/list/reply` 是模板任务系统的顶级命令,容易与其他命令冲突(特别是 `list`
29+
30+
### 1.2 Windows 不支持
31+
32+
`--bg``attach` 硬依赖 tmux:
33+
- `bg.ts:handleBgFlag()` 第一步就检查 tmux,不可用直接报错退出
34+
- `bg.ts:attachHandler()``tmux attach-session`,无 tmux 替代方案
35+
- Windows (包括 VS Code 终端) 完全无法使用后台会话功能
36+
37+
### 1.3 无 REPL 入口
38+
39+
对比 `/mcp` 的双注册模式:
40+
- **CLI**: `claude mcp serve/add/remove/list` (Commander.js, `main.tsx:5760`)
41+
- **REPL**: `/mcp enable/disable/reconnect` (slash command, `commands/mcp/index.ts`)
42+
43+
`daemon`/`bg`/`job` 系列只有 CLI 快速路径,REPL 中完全不可用。
44+
45+
## 二、目标
46+
47+
1. **层级化命令结构**: 参照 `/mcp` 模式,将后台管理收归 `/daemon`,模板任务收归 `/job`
48+
2. **跨平台后台会话**: Windows / macOS / Linux 都能启动、附着、终止后台会话
49+
3. **双注册**: CLI (`claude daemon ...`) + REPL (`/daemon ...`) 同时可用
50+
4. **向后兼容**: 旧命令保留但输出 deprecation 提示
51+
52+
## 三、命令结构设计
53+
54+
### 3.1 `/daemon` — 后台进程管理
55+
56+
合并 daemon supervisor + bg sessions 为统一命名空间:
57+
58+
```
59+
claude daemon <subcommand> ← CLI 入口 (cli.tsx 快速路径)
60+
/daemon <subcommand> ← REPL 入口 (slash command, local-jsx)
61+
62+
子命令:
63+
status 综合状态面板 (daemon + 所有会话)
64+
start [--dir <path>] 启动 daemon supervisor
65+
stop 停止 daemon
66+
bg [args...] 启动后台会话
67+
attach [target] 附着到后台会话
68+
logs [target] 查看会话日志
69+
kill [target] 终止会话
70+
(无参数) 等同于 status
71+
```
72+
73+
**CLI 快速路径路由** (`cli.tsx`):
74+
```typescript
75+
// 新: 统一入口
76+
if (feature('DAEMON') && args[0] === 'daemon') {
77+
const sub = args[1] || 'status'
78+
switch (sub) {
79+
case 'start': case 'stop': case 'status':
80+
await daemonMain([sub, ...args.slice(2)])
81+
break
82+
case 'bg':
83+
await bg.handleBgStart(args.slice(2))
84+
break
85+
case 'attach': case 'logs': case 'kill':
86+
await bg[`${sub}Handler`](args[2])
87+
break
88+
}
89+
}
90+
91+
// 向后兼容 (deprecated)
92+
if (feature('BG_SESSIONS') && ['ps','logs','attach','kill'].includes(args[0])) {
93+
console.warn(`[deprecated] Use: claude daemon ${args[0] === 'ps' ? 'status' : args[0]}`)
94+
// ... delegate to daemon subcommand
95+
}
96+
```
97+
98+
**REPL 斜杠命令** (`commands/daemon/index.ts`):
99+
```typescript
100+
const daemon = {
101+
type: 'local-jsx',
102+
name: 'daemon',
103+
description: 'Manage background sessions and daemon',
104+
argumentHint: '[status|start|stop|bg|attach|logs|kill]',
105+
isEnabled: () => feature('DAEMON') || feature('BG_SESSIONS'),
106+
load: () => import('./daemon.js'),
107+
} satisfies Command
108+
```
109+
110+
### 3.2 `/job` — 模板任务管理
111+
112+
```
113+
claude job <subcommand> ← CLI 入口
114+
/job <subcommand> ← REPL 入口
115+
116+
子命令:
117+
list 列出模板和活跃任务
118+
new <template> [args] 从模板创建任务
119+
reply <id> <text> 回复任务
120+
status <id> 查看任务状态
121+
(无参数) 等同于 list
122+
```
123+
124+
### 3.3 独立命令 (不变)
125+
126+
```
127+
claude up 保持顶级 (简短的 bootstrap 命令)
128+
claude rollback [target] 保持顶级 (低频运维命令)
129+
```
130+
131+
## 四、跨平台后台引擎
132+
133+
### 4.1 引擎抽象
134+
135+
```typescript
136+
// src/cli/bg/engine.ts
137+
export interface BgEngine {
138+
readonly name: string
139+
140+
/** 当前平台是否可用 */
141+
available(): Promise<boolean>
142+
143+
/** 启动后台会话 */
144+
start(opts: BgStartOptions): Promise<BgStartResult>
145+
146+
/** 附着到后台会话(blocking) */
147+
attach(session: SessionEntry): Promise<void>
148+
}
149+
150+
export interface BgStartOptions {
151+
sessionName: string
152+
args: string[]
153+
env: Record<string, string | undefined>
154+
logPath: string
155+
cwd: string
156+
}
157+
158+
export interface BgStartResult {
159+
pid: number
160+
sessionName: string
161+
logPath: string
162+
engineUsed: string
163+
}
164+
```
165+
166+
### 4.2 三种引擎实现
167+
168+
| 引擎 | 平台 | 启动方式 | attach 方式 |
169+
|------|------|---------|------------|
170+
| TmuxEngine | macOS/Linux (有 tmux) | `tmux new-session -d` | `tmux attach-session` |
171+
| DetachedEngine | Windows / 无 tmux 的 macOS/Linux | `spawn({ detached, stdio→logFile })` | `tail -f` 日志文件 |
172+
173+
#### DetachedEngine 详细设计
174+
175+
**启动 (`start`)**:
176+
```typescript
177+
// 1. 打开日志文件 fd
178+
const logFd = fs.openSync(logPath, 'a')
179+
// 2. detached spawn, stdout/stderr 重定向到日志
180+
const child = spawn(process.execPath, execArgs, {
181+
detached: true,
182+
stdio: ['ignore', logFd, logFd],
183+
env,
184+
cwd,
185+
})
186+
child.unref()
187+
fs.closeSync(logFd)
188+
// 3. 写 sessions/<PID>.json
189+
```
190+
191+
**附着 (`attach`)**:
192+
```typescript
193+
// 跨平台 tail -f 实现
194+
// 1. 读取已有日志内容输出到 stdout
195+
// 2. fs.watch(logPath) 监听变化
196+
// 3. 每次变化读取新增内容
197+
// 4. Ctrl+C 退出 tail(不杀后台进程)
198+
```
199+
200+
#### 引擎选择逻辑
201+
202+
```typescript
203+
// src/cli/bg/engines/index.ts
204+
export async function selectEngine(): Promise<BgEngine> {
205+
if (process.platform === 'win32') {
206+
return new DetachedEngine()
207+
}
208+
209+
const tmux = new TmuxEngine()
210+
if (await tmux.available()) {
211+
return tmux
212+
}
213+
214+
return new DetachedEngine()
215+
}
216+
```
217+
218+
### 4.3 SessionEntry 扩展
219+
220+
```typescript
221+
interface SessionEntry {
222+
// ... 现有字段
223+
engine: 'tmux' | 'detached' // 新增: 记录使用的引擎
224+
tmuxSessionName?: string // tmux 引擎才有
225+
logPath?: string // 两种引擎都有
226+
}
227+
```
228+
229+
`attach` 时根据 `session.engine` 选择对应的 attach 策略。
230+
231+
## 五、文件变更清单
232+
233+
### 新增文件 (10 个)
234+
235+
```
236+
src/cli/bg/engine.ts BgEngine 接口定义
237+
src/cli/bg/engines/tmux.ts TmuxEngine (从 bg.ts 提取)
238+
src/cli/bg/engines/detached.ts DetachedEngine (新实现)
239+
src/cli/bg/engines/index.ts 引擎选择 + re-export
240+
src/cli/bg/tail.ts 跨平台日志 tail (用于 detached attach)
241+
src/commands/daemon/index.ts /daemon REPL 斜杠命令注册
242+
src/commands/daemon/daemon.tsx /daemon 子命令路由 + status UI
243+
src/commands/job/index.ts /job REPL 斜杠命令注册
244+
src/commands/job/job.tsx /job 子命令路由 + UI
245+
docs/features/daemon-restructure-design.md 本设计文档
246+
```
247+
248+
### 修改文件 (6 个)
249+
250+
```
251+
src/cli/bg.ts 重构: handler 函数改为调用 BgEngine
252+
src/entrypoints/cli.tsx 快速路径: daemon 统一入口 + 向后兼容
253+
src/commands.ts 注册 /daemon 和 /job 斜杠命令
254+
src/daemon/main.ts daemonMain() 增加 bg/ps/logs 子命令分发
255+
src/main.tsx Commander.js: 可选注册 daemon/job 子命令
256+
src/cli/handlers/templateJobs.ts 适配 /job 入口 (可能不需改)
257+
```
258+
259+
### 不动的文件
260+
261+
```
262+
src/daemon/state.ts daemon PID 状态管理 (无需改)
263+
src/jobs/state.ts job 状态管理 (无需改)
264+
src/jobs/templates.ts 模板发现 (无需改)
265+
src/jobs/classifier.ts 任务分类器 (无需改)
266+
src/cli/rollback.ts 保持顶级命令 (无需改)
267+
src/cli/up.ts 保持顶级命令 (无需改)
268+
```
269+
270+
## 六、可行性分析
271+
272+
### 6.1 风险评估
273+
274+
| 风险 | 级别 | 缓解措施 |
275+
|------|------|---------|
276+
| cli.tsx 快速路径修改影响启动性能 || 仅改路由逻辑,import 仍然 lazy |
277+
| DetachedEngine 的 attach 在 Windows 上 fs.watch 不可靠 || 使用轮询 fallback (setInterval + fs.stat) |
278+
| 向后兼容的 deprecation 可能破坏脚本 || 旧命令保持可用,仅输出 stderr 警告 |
279+
| REPL 中 /daemon bg 需要 spawn 子进程 || 参考 /assistant 的 NewInstallWizard (已有 spawn 先例) |
280+
| tsc 类型兼容 || 接口定义清晰,不引入 any |
281+
282+
### 6.2 工作量估计
283+
284+
| Task | 文件数 | 复杂度 |
285+
|------|--------|--------|
286+
| Task 013: BgEngine 抽象 + 引擎实现 | 5 新增 + 1 修改 ||
287+
| Task 014: /daemon 命令层级化 | 3 新增 + 3 修改 ||
288+
| Task 015: /job 命令层级化 | 2 新增 + 2 修改 ||
289+
| Task 016: 向后兼容 + 测试 | 0 新增 + 2 修改 ||
290+
291+
### 6.3 依赖关系
292+
293+
```
294+
Task 013 (BgEngine) ← 无依赖,可独立开发
295+
Task 014 (/daemon) ← 依赖 Task 013 (引擎选择)
296+
Task 015 (/job) ← 无依赖,可与 013 并行
297+
Task 016 (兼容) ← 依赖 Task 014 + 015
298+
```
299+
300+
## 七、设计决策记录
301+
302+
### D1: 为什么 daemon + bg sessions 合为一个命名空间?
303+
304+
用户视角:都是"后台运行的东西"。分开会导致 `claude daemon status` 看 supervisor + `claude ps` 看会话,割裂感强。合并后 `claude daemon status` 一次性展示 supervisor 状态 + 所有会话列表。
305+
306+
### D2: 为什么 rollback/up 不收入 daemon?
307+
308+
它们本质是**版本管理/环境初始化**,不是后台进程管理。`claude up` 是同步阻塞的 setup 脚本,不涉及 daemon 或后台会话。保持顶级更直观。
309+
310+
### D3: 为什么 DetachedEngine 的 attach 用 tail 而不是 IPC?
311+
312+
1. 日志文件是最简单的跨平台方案,无需额外依赖
313+
2. UDS Pipe IPC 系统 (usePipeIpc) 设计用于实例间通信,不是终端附着
314+
3. tmux attach 的体验(完整 PTY)无法在纯 detached 模式下复制,tail 是最诚实的替代
315+
316+
### D4: 为什么不用 Windows Terminal 的 tab/pane API?
317+
318+
Windows Terminal 的 `wt.exe` 新窗口/标签功能不够通用——用户可能在 VS Code、ConEmu、cmder 等终端中。detached + log 是唯一跨终端方案。

0 commit comments

Comments
 (0)