a4phone 在 AI 助手一轮任务结束时(Claude Code / Codex 的 Stop 事件,DSH 的 turn/end 事件)自动触发通知:电脑弹出系统通知,同时把任务结果与 AI 最后输出的一段话推送到手机,让你离开电脑也能看到任务的实际产出。本文章介绍该功能的触发机制、通知内容构成与去重规则。
1. 功能概述
| 维度 | 说明 |
|---|---|
| 触发事件 | Claude Code / Codex:Stop;DSH:turn/end(reason.kind 为 completed) |
| 电脑端 | 系统弹窗通知(Windows 气泡 / macOS 通知 / Linux notify-send) |
| 手机端 | ntfy.sh 推送,含目录、会话 ID 与 AI 最后输出 |
| 是否可关闭 | 配置 topic 为空时只弹电脑通知,不推手机 |
| 适用版本 | 全部版本,DSH 支持自 1.1.6 起 |
1.1 事件流程
完成任务] --> B[Stop / turn/end
事件触发] B --> C[读取会话记录
transcript] C --> D[抽取 AI
最后输出] D --> E[截断到
1000 字符] E --> F[电脑系统通知] E --> G[ntfy.sh 推送手机] B --> H[记录最近会话
last.json] H --> I[供远程续聊使用] style A fill:#e8f4f8,stroke:#1a6b8a,stroke-width:2px style B fill:#ebdef0,stroke:#8e44ad,stroke-width:2px style C fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px style D fill:#ffecd6,stroke:#e67e22,stroke-width:2px style E fill:#fdebd0,stroke:#b7950b,stroke-width:2px style F fill:#d5f5e3,stroke:#27ae60,stroke-width:2px style G fill:#fadbd8,stroke:#c0392b,stroke-width:2px style H fill:#fdebd0,stroke:#b7950b,stroke-width:2px style I fill:#d5f5e3,stroke:#27ae60,stroke-width:2px
2. 通知内容构成
手机推送消息由三部分组成:
- 任务状态:固定为
任务已完成 - 上下文信息:工作目录(
目录: {cwd})与会话 ID 前 8 位(会话: {session_id}) - AI 最后输出:从会话记录中抽取的 AI 最后一条回复文本,超出 1000 字符时截断并在末尾添加省略号
任务已完成
目录: C:\my-project
会话: ab12cd34
AI 最后输出:
已完成全部重构,测试通过。主要改动包括:
1. 拆分配置模块,消除循环依赖
2. 补充 3 个单元测试用例
...
2.1 消息标题
推送标题按触发方动态显示,便于区分来源:
| 触发方 | 标题 |
|---|---|
| Claude Code | Claude Code |
| Codex | Codex |
| DSH | DSH |
3. AI 最后输出的抽取机制
a4phone 读取 Stop 事件输入中的 transcript_path(会话 JSONL 记录),按 Agent 不同解析最后一条 AI 回复文本。
3.1 各 Agent 的解析规则
| Agent | 记录类型 | 抽取方式 |
|---|---|---|
| Claude Code | type="assistant" 消息 |
message.content[] 中 type="text" 的 text 块 |
| Codex | type="response_item" 的 assistant 消息 |
payload.content[] 中 type="output_text" 的 text 块 |
| Codex 兜底 | type="event_msg" 的 task_complete |
payload.last_agent_message 字段 |
| DSH | 会话事件缓存 | 插件缓存最近一次 assistant/message 的文本输出 |
Codex 的
task_complete事件比 assistant 消息晚约 1.4 秒落盘,Stop 触发时往往尚未写入,因此 a4phone 优先读取随消息即时写入的response_item,task_complete仅作文件稳定时的兜底。
3.2 截断策略
会话记录可能非常大,a4phone 只取最后一段文本并截断到前 1000 字符(约 3000 字节,留足 ntfy 4KB 消息上限余量),兼顾推送长度限制与可读性。
4. 最近会话记录
Stop 事件触发时,a4phone 同时把最近会话信息写入 ~/.a4phone/last.json:
{
"session_id": "ab12cd34ef56...",
"cwd": "C:\\my-project",
"agent": "Claude Code",
"transcript_path": "C:\\Users\\xxx\\.claude\\projects\\...\\xxx.jsonl",
"ts": 1755324000000
}
该记录是远程续聊路由的核心依据:守护进程按 agent 字段自动选择续聊方式(Claude Code / Codex / DSH),按 session_id 恢复会话。
5. 去重与抑制
| 场景 | 处理方式 |
|---|---|
续聊子进程(A4P_RESUME=1) |
Stop 事件不再重复推送"任务已完成",结果由续聊流程统一推回手机 |
| DSH 续聊轮次 | 插件检测到会话正在被续聊服务驱动(inflight),跳过重复的任务完成通知 |
| DSH subagent 轮次 | 仅日志记录,不推送(避免 subagent 完成导致刷屏) |
6. 关闭手机推送
如果只想保留电脑弹窗、不推送手机,把 ~/.a4phone/config.json 中的 topic 置空即可。恢复推送时重新运行 a4p setup 重新生成话题,或手动填写话题名称。
{
"topic": "",
"server": "https://ntfy.sh"
}
详细配置项见配置说明。
举手提问