a4phone 在 AI 助手请求执行敏感操作(运行命令、读写文件、修改代码等)时,把权限请求推送到手机:外出模式下手机端显示 Approve / Deny / Always Approve 三个决策按钮,点选后决策回传会话,AI 按你的选择继续执行或中止。功能覆盖 Claude Code、Codex、ZCode 的 PermissionRequest 事件与 DSH 的 approval/request 事件,推送正文按工具类型格式化——Bash 显示待执行命令,Read/Write/Edit 显示目标文件路径;当请求附带权限建议时提供 Always Approve 按钮批量授权,后续同类操作不再逐次询问。手机超时未决策或推送失败时自动回退终端原生审批,计划确认类请求的超时时长更长。本文章介绍权限请求的触发范围、消息格式化、决策按钮与回传机制。
1. 功能概述
| 维度 | 说明 |
|---|---|
| 触发事件 | Claude Code / Codex / ZCode:PermissionRequest;DSH:approval/request |
| 拦截方式 | Claude Code / Codex / ZCode:PermissionRequest Hook;DSH:approval/request 事件拦截 |
| 决策选项 | Approve(允许)/ Deny(拒绝)/ Always Approve(总是允许,按建议批量授权) |
| 生效模式 | 仅外出模式(a4p out);桌面提醒两种模式均触发 |
| 超时回退 | 手机超时未决策自动回退终端审批 |
| 适用版本 | ZCode 支持自 1.6.0 起 |
1.1 事件流程
PermissionRequest] --> B{当前模式} B -->|终端优先| C[终端原生审批] B -->|外出模式| D{工具类型} D -->|AskUserQuestion| E[直接放行
提问由提问功能处理] D -->|其他工具| F[格式化请求内容] F --> G[推送手机
Approve / Deny] G --> H{存在权限建议} H -->|是| I[附加 Always Approve
按钮] H -->|否| J[仅两个按钮] I --> K[手机点选决策] J --> K K --> L[决策回传会话] L --> M[AI 继续或中止] style A fill:#e8f4f8,stroke:#1a6b8a,stroke-width:2px style B fill:#ebdef0,stroke:#8e44ad,stroke-width:2px style C fill:#fdebd0,stroke:#b7950b,stroke-width:2px style D fill:#ebdef0,stroke:#8e44ad,stroke-width:2px style E fill:#d5f5e3,stroke:#27ae60,stroke-width:2px style F fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px style G fill:#fadbd8,stroke:#c0392b,stroke-width:2px style H fill:#ebdef0,stroke:#8e44ad,stroke-width:2px style I fill:#fdebd0,stroke:#b7950b,stroke-width:2px style J fill:#fdebd0,stroke:#b7950b,stroke-width:2px style K fill:#e8f4f8,stroke:#1a6b8a,stroke-width:2px style L fill:#d5f5e3,stroke:#27ae60,stroke-width:2px style M fill:#ffecd6,stroke:#e67e22,stroke-width:2px
2. 请求内容格式化
推送标题为 {Agent}: {工具名}(如 Claude Code: Bash),正文按工具类型格式化展示请求内容:
| 工具类型 | 展示内容 |
|---|---|
ExitPlanMode |
计划全文(截断到 1000 字符) |
Bash |
要执行的命令 |
Read / Write / Edit |
目标文件路径 |
| 其他工具 | 工具输入的 JSON 序列化 |
请求内容超过 1000 字符时截断并添加省略号,避免超出 ntfy 推送上限。
3. 决策按钮
| 按钮 | 行为 |
|---|---|
| Approve | 允许本次操作(decision.behavior = "allow") |
| Deny | 拒绝本次操作(decision.behavior = "deny") |
| Always Approve | 允许本次操作,并批量授权工具返回的所有权限建议(仅当请求携带 permission_suggestions 时出现) |
当工具的权限请求附带建议列表(如 Bash 工具建议的一批可执行命令)时,推送会插入 Always Approve 按钮,点击后 a4phone 把建议写入 updatedPermissions,AI 后续同类操作不再逐次询问。
4. 特殊处理
4.1 AskUserQuestion 直接放行
AskUserQuestion(Claude Code / ZCode 的提问工具)触发的权限请求不推送手机、也不弹桌面通知——提问的完整交互由AI提问交互功能负责,a4phone 直接返回 allow 放行(ZCode 对一次提问会同时触发 PreToolUse 与 PermissionRequest 两次 Hook,跳过弹窗避免重复通知)。
4.2 计划审批超时更长
ExitPlanMode(计划确认)使用独立的 planTimeout(默认 300 秒),比普通权限请求的 timeout(默认 60 秒)更长,给离开电脑的用户更充足的决策时间。
5. 超时与失败回退
| 场景 | 处理方式 |
|---|---|
| 手机超时未决策 | 等待超时后回退终端原生审批 |
| 推送失败 | 回退终端原生审批 |
| 终端优先模式 | 不推送手机,直接走终端审批(桌面弹窗仍提示"有权限请求需要处理") |
| DSH 手机决策 | Approve 映射为 allowed-once,Deny 映射为 rejected |
权限请求的桌面弹窗在两种模式下都会触发(1.5.0 起);1.6.0 起弹窗由守护进程从
~/.a4phone/notify-queue/代发。
举手提问