2026-06-09 23:15:17 +08:00
|
|
|
|
---
|
|
|
|
|
|
tags: [daemon, 重构, bg-sessions, 命令层级, 跨平台]
|
|
|
|
|
|
create time: 2026-06-09 22:30
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-08 23:08:57 +08:00
|
|
|
|
# Daemon 重构设计方案
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
针对当前后台进程命令散乱、Windows 不支持、无 REPL 入口三个问题,提出将 daemon + bg sessions 合并为统一 `/daemon` 命名空间、模板任务收归 `/job`、引入跨平台后台引擎的重构方案。
|
|
|
|
|
|
|
|
|
|
|
|
> [!info]
|
2026-06-08 23:08:57 +08:00
|
|
|
|
> 分支: `feat/integrate-5-branches`
|
|
|
|
|
|
> 基于: `f41745cb` (= main `11bb3f62` 内容)
|
|
|
|
|
|
> 日期: 2026-04-13
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
## 正文
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 一、问题概述
|
|
|
|
|
|
|
|
|
|
|
|
#### 1.1 命令结构散乱
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
当前后台进程相关的命令分布在三个不同的位置,没有统一的命名空间:
|
|
|
|
|
|
|
|
|
|
|
|
| 命令 | 注册位置 | 入口 |
|
|
|
|
|
|
|------|---------|------|
|
|
|
|
|
|
| `claude daemon start/status/stop` | `cli.tsx` 快速路径 L203 | `daemon/main.ts` |
|
|
|
|
|
|
| `claude ps` | `cli.tsx` 快速路径 L220 | `cli/bg.ts` |
|
|
|
|
|
|
| `claude logs <x>` | `cli.tsx` 快速路径 L232 | `cli/bg.ts` |
|
|
|
|
|
|
| `claude attach <x>` | `cli.tsx` 快速路径 L236 | `cli/bg.ts` |
|
|
|
|
|
|
| `claude kill <x>` | `cli.tsx` 快速路径 L238 | `cli/bg.ts` |
|
|
|
|
|
|
| `claude --bg` | `cli.tsx` 快速路径 L244 | `cli/bg.ts` |
|
|
|
|
|
|
| `claude new/list/reply` | `cli.tsx` 快速路径 L250 | `cli/handlers/templateJobs.ts` |
|
|
|
|
|
|
| `claude rollback` | `main.tsx` Commander.js L6525 | `cli/rollback.ts` |
|
|
|
|
|
|
| `claude up` | `main.tsx` Commander.js L6511 | `cli/up.ts` |
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
**问题**:
|
|
|
|
|
|
|
2026-06-08 23:08:57 +08:00
|
|
|
|
- `ps/logs/attach/kill` 与 `daemon` 逻辑上都是后台进程管理,但互不关联
|
|
|
|
|
|
- 这些命令都**只有 CLI 入口**,REPL 里输入 `/daemon` 或 `/ps` 不存在
|
2026-06-09 23:15:17 +08:00
|
|
|
|
- `new/list/reply` 是模板任务系统的顶级命令,容易与其他命令冲突
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 1.2 Windows 不支持
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
`--bg` 和 `attach` 硬依赖 tmux:
|
2026-06-09 23:15:17 +08:00
|
|
|
|
|
2026-06-08 23:08:57 +08:00
|
|
|
|
- `bg.ts:handleBgFlag()` 第一步就检查 tmux,不可用直接报错退出
|
|
|
|
|
|
- `bg.ts:attachHandler()` 用 `tmux attach-session`,无 tmux 替代方案
|
2026-06-09 23:15:17 +08:00
|
|
|
|
- Windows 完全无法使用后台会话功能
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 1.3 无 REPL 入口
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
对比 `/mcp` 的双注册模式(CLI + REPL),`daemon`/`bg`/`job` 系列只有 CLI 快速路径,REPL 中完全不可用。
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 二、目标
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
1. **层级化命令结构**: 参照 `/mcp` 模式,将后台管理收归 `/daemon`,模板任务收归 `/job`
|
|
|
|
|
|
2. **跨平台后台会话**: Windows / macOS / Linux 都能启动、附着、终止后台会话
|
|
|
|
|
|
3. **双注册**: CLI (`claude daemon ...`) + REPL (`/daemon ...`) 同时可用
|
|
|
|
|
|
4. **向后兼容**: 旧命令保留但输出 deprecation 提示
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 三、命令结构设计
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 3.1 `/daemon` — 后台进程管理
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
合并 daemon supervisor + bg sessions 为统一命名空间:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
claude daemon <subcommand> ← CLI 入口 (cli.tsx 快速路径)
|
|
|
|
|
|
/daemon <subcommand> ← REPL 入口 (slash command, local-jsx)
|
|
|
|
|
|
|
|
|
|
|
|
子命令:
|
|
|
|
|
|
status 综合状态面板 (daemon + 所有会话)
|
|
|
|
|
|
start [--dir <path>] 启动 daemon supervisor
|
|
|
|
|
|
stop 停止 daemon
|
|
|
|
|
|
bg [args...] 启动后台会话
|
|
|
|
|
|
attach [target] 附着到后台会话
|
|
|
|
|
|
logs [target] 查看会话日志
|
|
|
|
|
|
kill [target] 终止会话
|
|
|
|
|
|
(无参数) 等同于 status
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**CLI 快速路径路由** (`cli.tsx`):
|
2026-06-09 23:15:17 +08:00
|
|
|
|
|
2026-06-08 23:08:57 +08:00
|
|
|
|
```typescript
|
|
|
|
|
|
// 新: 统一入口
|
|
|
|
|
|
if (feature('DAEMON') && args[0] === 'daemon') {
|
|
|
|
|
|
const sub = args[1] || 'status'
|
|
|
|
|
|
switch (sub) {
|
|
|
|
|
|
case 'start': case 'stop': case 'status':
|
|
|
|
|
|
await daemonMain([sub, ...args.slice(2)])
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bg':
|
|
|
|
|
|
await bg.handleBgStart(args.slice(2))
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'attach': case 'logs': case 'kill':
|
|
|
|
|
|
await bg[`${sub}Handler`](args[2])
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 向后兼容 (deprecated)
|
|
|
|
|
|
if (feature('BG_SESSIONS') && ['ps','logs','attach','kill'].includes(args[0])) {
|
|
|
|
|
|
console.warn(`[deprecated] Use: claude daemon ${args[0] === 'ps' ? 'status' : args[0]}`)
|
|
|
|
|
|
// ... delegate to daemon subcommand
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**REPL 斜杠命令** (`commands/daemon/index.ts`):
|
2026-06-09 23:15:17 +08:00
|
|
|
|
|
2026-06-08 23:08:57 +08:00
|
|
|
|
```typescript
|
|
|
|
|
|
const daemon = {
|
|
|
|
|
|
type: 'local-jsx',
|
|
|
|
|
|
name: 'daemon',
|
|
|
|
|
|
description: 'Manage background sessions and daemon',
|
|
|
|
|
|
argumentHint: '[status|start|stop|bg|attach|logs|kill]',
|
|
|
|
|
|
isEnabled: () => feature('DAEMON') || feature('BG_SESSIONS'),
|
|
|
|
|
|
load: () => import('./daemon.js'),
|
|
|
|
|
|
} satisfies Command
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 3.2 `/job` — 模板任务管理
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
claude job <subcommand> ← CLI 入口
|
|
|
|
|
|
/job <subcommand> ← REPL 入口
|
|
|
|
|
|
|
|
|
|
|
|
子命令:
|
|
|
|
|
|
list 列出模板和活跃任务
|
|
|
|
|
|
new <template> [args] 从模板创建任务
|
|
|
|
|
|
reply <id> <text> 回复任务
|
|
|
|
|
|
status <id> 查看任务状态
|
|
|
|
|
|
(无参数) 等同于 list
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 3.3 独立命令 (不变)
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
claude up 保持顶级 (简短的 bootstrap 命令)
|
|
|
|
|
|
claude rollback [target] 保持顶级 (低频运维命令)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 四、跨平台后台引擎
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 4.1 引擎抽象
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// src/cli/bg/engine.ts
|
|
|
|
|
|
export interface BgEngine {
|
|
|
|
|
|
readonly name: string
|
|
|
|
|
|
available(): Promise<boolean>
|
|
|
|
|
|
start(opts: BgStartOptions): Promise<BgStartResult>
|
|
|
|
|
|
attach(session: SessionEntry): Promise<void>
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 4.2 两种引擎实现
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
| 引擎 | 平台 | 启动方式 | attach 方式 |
|
|
|
|
|
|
|------|------|---------|------------|
|
|
|
|
|
|
| TmuxEngine | macOS/Linux (有 tmux) | `tmux new-session -d` | `tmux attach-session` |
|
|
|
|
|
|
| DetachedEngine | Windows / 无 tmux 的 macOS/Linux | `spawn({ detached, stdio→logFile })` | `tail -f` 日志文件 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 引擎选择逻辑
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
export async function selectEngine(): Promise<BgEngine> {
|
|
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
|
|
return new DetachedEngine()
|
|
|
|
|
|
}
|
|
|
|
|
|
const tmux = new TmuxEngine()
|
|
|
|
|
|
if (await tmux.available()) {
|
|
|
|
|
|
return tmux
|
|
|
|
|
|
}
|
|
|
|
|
|
return new DetachedEngine()
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 4.3 SessionEntry 扩展
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
interface SessionEntry {
|
|
|
|
|
|
// ... 现有字段
|
|
|
|
|
|
engine: 'tmux' | 'detached' // 新增: 记录使用的引擎
|
|
|
|
|
|
tmuxSessionName?: string // tmux 引擎才有
|
|
|
|
|
|
logPath?: string // 两种引擎都有
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 五、文件变更清单
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 新增文件 (10 个)
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
src/cli/bg/engine.ts BgEngine 接口定义
|
|
|
|
|
|
src/cli/bg/engines/tmux.ts TmuxEngine (从 bg.ts 提取)
|
|
|
|
|
|
src/cli/bg/engines/detached.ts DetachedEngine (新实现)
|
|
|
|
|
|
src/cli/bg/engines/index.ts 引擎选择 + re-export
|
|
|
|
|
|
src/cli/bg/tail.ts 跨平台日志 tail (用于 detached attach)
|
|
|
|
|
|
src/commands/daemon/index.ts /daemon REPL 斜杠命令注册
|
|
|
|
|
|
src/commands/daemon/daemon.tsx /daemon 子命令路由 + status UI
|
|
|
|
|
|
src/commands/job/index.ts /job REPL 斜杠命令注册
|
|
|
|
|
|
src/commands/job/job.tsx /job 子命令路由 + UI
|
|
|
|
|
|
docs/features/daemon-restructure-design.md 本设计文档
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 修改文件 (6 个)
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
src/cli/bg.ts 重构: handler 函数改为调用 BgEngine
|
|
|
|
|
|
src/entrypoints/cli.tsx 快速路径: daemon 统一入口 + 向后兼容
|
|
|
|
|
|
src/commands.ts 注册 /daemon 和 /job 斜杠命令
|
|
|
|
|
|
src/daemon/main.ts daemonMain() 增加 bg/ps/logs 子命令分发
|
|
|
|
|
|
src/main.tsx Commander.js: 可选注册 daemon/job 子命令
|
2026-06-09 23:15:17 +08:00
|
|
|
|
src/cli/handlers/templateJobs.ts 适配 /job 入口
|
2026-06-08 23:08:57 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 六、可行性分析
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 6.1 风险评估
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
| 风险 | 级别 | 缓解措施 |
|
|
|
|
|
|
|------|------|---------|
|
|
|
|
|
|
| cli.tsx 快速路径修改影响启动性能 | 低 | 仅改路由逻辑,import 仍然 lazy |
|
|
|
|
|
|
| DetachedEngine 的 attach 在 Windows 上 fs.watch 不可靠 | 中 | 使用轮询 fallback (setInterval + fs.stat) |
|
|
|
|
|
|
| 向后兼容的 deprecation 可能破坏脚本 | 低 | 旧命令保持可用,仅输出 stderr 警告 |
|
|
|
|
|
|
| REPL 中 /daemon bg 需要 spawn 子进程 | 中 | 参考 /assistant 的 NewInstallWizard (已有 spawn 先例) |
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 6.2 工作量估计
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
| Task | 文件数 | 复杂度 |
|
|
|
|
|
|
|------|--------|--------|
|
|
|
|
|
|
| Task 013: BgEngine 抽象 + 引擎实现 | 5 新增 + 1 修改 | 中 |
|
|
|
|
|
|
| Task 014: /daemon 命令层级化 | 3 新增 + 3 修改 | 中 |
|
|
|
|
|
|
| Task 015: /job 命令层级化 | 2 新增 + 2 修改 | 低 |
|
|
|
|
|
|
| Task 016: 向后兼容 + 测试 | 0 新增 + 2 修改 | 低 |
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### 6.3 依赖关系
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
```mermaid
|
|
|
|
|
|
graph TD
|
|
|
|
|
|
A["Task 013 BgEngine 无依赖,可独立开发"] --> C["Task 014 /daemon 依赖 Task 013"]
|
|
|
|
|
|
B["Task 015 /job 无依赖,可与 013 并行"] --> D["Task 016 兼容 依赖 Task 014 + 015"]
|
|
|
|
|
|
C --> D
|
2026-06-08 23:08:57 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
### 七、设计决策记录
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### D1: 为什么 daemon + bg sessions 合为一个命名空间?
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
用户视角:都是"后台运行的东西"。分开会导致 `claude daemon status` 看 supervisor + `claude ps` 看会话,割裂感强。合并后 `claude daemon status` 一次性展示 supervisor 状态 + 所有会话列表。
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### D2: 为什么 rollback/up 不收入 daemon?
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
它们本质是**版本管理/环境初始化**,不是后台进程管理。`claude up` 是同步阻塞的 setup 脚本,不涉及 daemon 或后台会话。保持顶级更直观。
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### D3: 为什么 DetachedEngine 的 attach 用 tail 而不是 IPC?
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
1. 日志文件是最简单的跨平台方案,无需额外依赖
|
2026-06-09 23:15:17 +08:00
|
|
|
|
2. UDS Pipe IPC 系统设计用于实例间通信,不是终端附着
|
2026-06-08 23:08:57 +08:00
|
|
|
|
3. tmux attach 的体验(完整 PTY)无法在纯 detached 模式下复制,tail 是最诚实的替代
|
|
|
|
|
|
|
2026-06-09 23:15:17 +08:00
|
|
|
|
#### D4: 为什么不用 Windows Terminal 的 tab/pane API?
|
2026-06-08 23:08:57 +08:00
|
|
|
|
|
|
|
|
|
|
Windows Terminal 的 `wt.exe` 新窗口/标签功能不够通用——用户可能在 VS Code、ConEmu、cmder 等终端中。detached + log 是唯一跨终端方案。
|
2026-06-09 23:15:17 +08:00
|
|
|
|
|
|
|
|
|
|
## 关联笔记
|
|
|
|
|
|
|
|
|
|
|
|
- [[daemon]]
|
|
|
|
|
|
- [[bridge-mode]]
|