xuanzhu 0.4.3 → 0.4.5

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 CHANGED
@@ -1,7 +1,5 @@
1
1
  # 玄猪 XuanZhu
2
2
 
3
- [English](https://github.com/amble311/xuanzhu/blob/main/docs/README.en.md) | **中文**
4
-
5
3
  > 专为终端打造的 AI 编码 Agent —— 一条 `xzh` 命令,把 AI 编程助手带进你的终端。
6
4
 
7
5
  ## 快速上手
@@ -166,6 +164,9 @@ xzh
166
164
  | `xzh skill list` | 列出全部技能(来源与状态,含已禁用项) |
167
165
  | `xzh skill enable/disable <名称>` | 启用 / 禁用技能 |
168
166
  | `xzh skill delete <名称> [--yes]` | 删除技能(仅限用户技能;内置技能请用 disable) |
167
+ | `xzh errors` | 查看玄猪自动记录的错误报告(`~/.xzh/errors/`) |
168
+ | `xzh errors show <序号\|签名>` | 查看一份报告的完整内容(JSON) |
169
+ | `xzh errors clear [--yes]` | 清空错误报告 |
169
170
  | `xzh device connect <手机IP>` | 连接手机上的 AutoJs6(服务器模式)并常驻 |
170
171
  | `xzh device serve` | 反向:等手机上的 AutoX.js 连过来 |
171
172
  | `xzh device run <文件>` | 把脚本推到手机并运行(`push` 则只保存不运行) |
@@ -198,6 +199,8 @@ XZH_HOME=/path/to/dir xzh # 改用 /path/to/dir/config.json
198
199
  "temperature": 0.2,
199
200
  "maxToolRounds": 200,
200
201
  "autoApprove": true,
202
+ "mouseCapture": true,
203
+ "confirmSensitiveRead": false,
201
204
  "memoryMaxChars": 12000,
202
205
  "maxParallelAgents": 4,
203
206
  "intent": { "enabled": false },
@@ -210,6 +213,21 @@ XZH_HOME=/path/to/dir xzh # 改用 /path/to/dir/config.json
210
213
  }
211
214
  ```
212
215
 
216
+ | 字段 | 默认 | 说明 |
217
+ | --- | --- | --- |
218
+ | `provider` / `model` | — | 「上次使用」的模型(每次切换由玄猪写回) |
219
+ | `models` | `[]` | 已配置模型,**顺序即回退优先级** |
220
+ | `temperature` | `0.2` | 采样温度 |
221
+ | `maxToolRounds` | `200` | 单轮任务内工具调用轮数上限(用尽时询问是否追加) |
222
+ | `autoApprove` | `true` | 自动批准工具(`false` 时写文件/执行命令前询问) |
223
+ | `mouseCapture` | `true` | 接管鼠标:滚轮滚动 + 输出区拖拽选中复制(`/mouse` 切换) |
224
+ | `confirmSensitiveRead` | `false` | 读取凭据类文件(`.env`、`~/.ssh`、`config.json` 等)时是否确认 |
225
+ | `memoryMaxChars` | `12000` | 长期记忆字符上限,超出即自动精简(`0` = 不限制长度,仍去重) |
226
+ | `maxParallelAgents` | `4` | 并行子代理数量上限(`1` = 串行,硬上限 16) |
227
+ | `intent.enabled` | `false` | 意图分析(每条消息先分析再处理) |
228
+ | `intent.prompt` | 内置模板 | 意图分析模板,占位符 `{{'用户发送过来的消息'}}` |
229
+ | `systemPromptExtra` | — | 追加到系统提示词的额外内容 |
230
+
213
231
  > 旧版配置(只有 `provider` / `model`、没有 `models`)依然可用:会被视为唯一的一个模型。
214
232
  > 旧配置里的 `weight` / `decayed` 字段已废弃,读取时会被忽略、下次保存时自动清掉。
215
233
 
@@ -224,6 +242,7 @@ XZH_HOME=/path/to/dir xzh # 改用 /path/to/dir/config.json
224
242
  | 调用失败 | 自动切换到列表里的**下一个**(走到末尾会绕回表头),单次请求内每个模型最多试一次 |
225
243
  | 全部失败 | 直到所有模型都试过才报错,并说明「已配置的模型都试过了」 |
226
244
  | 记住结果 | 每次切换都会写回配置,下次启动直接用最后成功的那个 |
245
+ | 会话内手动切换 | `/model` 列出已配置模型并让你选(↑ ↓ 或数字直选,Enter 确认、Esc 取消);也可 `/model 2`、`/model <id / 模型名>` 一步到位。选中即写回配置 —— 与自动回退共用同一个「上次使用」的记录 |
227
246
  | 配置错误不回退 | 密钥无效 / 无权限 / 模型名或端点不存在时**不切换、不写盘**,只提示检查配置 —— 配置不改就永远失败,换模型只会把整条回退链白走一遍 |
228
247
  | 上下文超限不回退 | 超出模型窗口时**收敛历史后自动重试**,也不切换模型(见上一节) |
229
248
  | `Ctrl+C` / `Ctrl+D` 中断 | 不算失败,不触发回退 |
@@ -241,9 +260,9 @@ xzh model remove openai/gpt-4o # 删除(id / 模型名 / 序号均可
241
260
  ```
242
261
 
243
262
  想让某个模型**不参与回退**,直接 `xzh model remove` 删掉即可。当前使用的模型显示在界面顶部与状态栏,
244
- 发生回退时输出区会给出提示。
263
+ 发生回退时输出区会给出提示;想临时换一个用,直接在对话里 `/model` 选(`xzh model` 仍是增删改的入口)。
245
264
 
246
- > ⚠️ `xzh model add` 的位置参数自 v0.5 起**整体前移一位**(原来的 `[权重]` 已取消):
265
+ > ⚠️ `xzh model add` 的位置参数自 **0.4.2** 起**整体前移一位**(原来的 `[权重]` 已取消):
247
266
  > 现在是 `add <provider> <model> [上下文窗口] [on|off]`。
248
267
 
249
268
  ### 上下文窗口的作用
@@ -260,6 +279,10 @@ xzh model remove openai/gpt-4o # 删除(id / 模型名 / 序号均可
260
279
  推断表只覆盖常见模型,小众或私有部署的模型名会退回保守的 32k ——
261
280
  若你的模型窗口更大,请用 `xzh model context <id> <大小>` 显式指定,
262
281
  否则历史会被裁得比必要得更短。
282
+ - **裁剪后会明确告诉模型「这不是完整历史」**:历史一旦被裁过,之后每次请求都会附上一条说明,
283
+ 要求它不要拿残缺的旧任务当依据接着做,先回应用户**当前**这条消息。原因是裁剪是静默的,
284
+ 模型看到一段从中途开始的历史时,很容易把上文里没做完的旧任务当成「用户正等我做完」——
285
+ 实测中用户只发了句「在吗」,它却接着去起服务、查凭据。
263
286
 
264
287
  > 裁剪依据是**估算**的 token 数(中文约 1 字符/token,英文与代码约 3.5 字符/token),
265
288
  > 不依赖 tokenizer,属保守近似。项目规则(`.xuanzhu/rules.md`)与 `systemPromptExtra`
@@ -349,6 +372,8 @@ API Key 也可以来自环境变量,优先级低于配置文件:
349
372
  | `device_run` | 把脚本推到手机并立即运行 | 是 |
350
373
  | `device_stop` | 停止手机上的脚本(默认全部) | 是 |
351
374
  | `device_logs` | 读取手机上的脚本日志 | 否 |
375
+ | `device_read_screen` | 读取手机当前界面(包名 / 控件文本与位置),**以文字返回** | 否 |
376
+ | `device_screenshot` | 截取手机屏幕,**图片随结果附给模型**(控件读不到时用它,再按坐标点击) | 否 |
352
377
 
353
378
  ## 任务拆分与子代理
354
379
 
@@ -367,11 +392,12 @@ API Key 也可以来自环境变量,优先级低于配置文件:
367
392
  > 只有声明了 `parallelSafe` 的工具会进入并行批次(目前仅 `task`)。写文件、编辑、
368
393
  > 执行命令这类工具有副作用且可能互相依赖,始终按顺序串行执行,不会被并行化。
369
394
 
370
- 内置一个子代理,通过 `subagent_name` 指定(默认即它):
395
+ 内置两个子代理,通过 `subagent_name` 指定(默认 `code-explorer`):
371
396
 
372
397
  | 子代理 | 能力 | 何时用 |
373
398
  | --- | --- | --- |
374
399
  | `code-explorer` | **只读**(`read_file` / `list_dir` / `glob` / `grep` / `list_skills` / `load_skill`) | 跨多个文件、目录或命名约定的搜索;单次 `read_file` / `grep` 覆盖不了的探索 |
400
+ | `test-runner` | **只运行、不修改**(`bash` + 读取类工具):跑全量或指定测试,汇报通过/失败清单、失败原因与可复跑命令 | 测试输出会很长时;改完代码想确认是否全绿;只想拿到「哪几条挂了、为什么」而不想自己翻日志 |
375
401
 
376
402
  `task` 的参数:
377
403
 
@@ -659,12 +685,17 @@ description: 一句话说明该技能的用途与适用场景
659
685
  | `Shift+Tab` | 切换焦点(对话 ⇄ 右侧终端) |
660
686
  | 鼠标点击 | 焦点跟随点击的栏 |
661
687
  | 鼠标滚轮 | 按区域滚动(左:对话区;右:终端输出) |
688
+ | `Ctrl+A` / `Ctrl+E` | 光标移到行首 / 行尾 |
662
689
  | `Ctrl+C` | 中断当前任务 / 清空输入 / 退出(空闲且输入为空时退出) |
663
690
  | `Ctrl+D` | 结束本轮正在进行的对话(**任何情况下都不会退出玄猪**);终端面板内为中断运行中的命令 |
664
691
  | `Ctrl+L` | 清屏(终端面板内为清空命令输出) |
665
692
 
666
693
  > `Ctrl+D` 只做「结束本轮对话」这一件事:没有对话在进行时按它不会有任何反应,也**永远不会退出界面**。
667
694
  > 退出请用 `Ctrl+C`(空闲且输入为空时)或 `/exit`。
695
+ >
696
+ > **SSH 断线 / 进程被终止**:sshd 关闭终端时会发 `SIGHUP`,玄猪按正常流程退出 ——
697
+ > 右侧终端里在运行的命令会一并终止(不会留成孤儿进程);若当时这一轮还没答完,
698
+ > 会在会话文件里补一条「上一轮已中止」的说明,重连后 `/resume` 不会把半截任务当成仍在进行。
668
699
 
669
700
  ### 让 Ctrl+Enter / Shift+Enter 生效
670
701
 
@@ -689,7 +720,7 @@ description: 一句话说明该技能的用途与适用场景
689
720
  kitty / Ghostty 会把该 xterm 兼容序列映射成「所有按键都用转义码上报」而破坏普通输入,
690
721
  故玄猪对这两类终端不发送请求,请改用 `Alt+Enter` 或在终端侧自行配置。
691
722
 
692
- 界面内命令:`/help`、`/clear`、`/tools`、`/image`、`/copy [N|all]`、`/mouse`、`/reset`、`/cwd`、`/switch <目录>`、`/term`、`/model`、`/auto [on|off]`、`/intent [on|off]`、`/exit`。
723
+ 界面内命令:`/help`、`/clear`、`/tools`、`/device`、`/image`(`/paste`)、`/copy [N|A-B|last|all]`、`/mouse`、`/reset`、`/undo`、`/resume [编号]`、`/cwd`、`/switch <目录>`、`/term`、`/model [编号|id|模型名]`、`/auto [on|off]`、`/intent [on|off]`、`/exit`。
693
724
 
694
725
  ### 选中与复制
695
726
 
@@ -755,21 +786,48 @@ XZH_KITTY_KEYS=1 xzh
755
786
  (会话文件也随之换到该项目名下;当前对话已存档在原项目,切回后 `/resume` 可找回)。
756
787
  若该项目还没有历史会话,则是全新开局。
757
788
 
789
+ ## 遇到问题(错误报告)
790
+
791
+ 玄猪会在**出现异常时自动留一份现场**,方便你反馈 bug:
792
+
793
+ | 触发 | 行为 |
794
+ | --- | --- |
795
+ | 未捕获异常 / 未处理的 Promise 拒绝 | 退出前记录(同时写 `crash.log`) |
796
+ | 工具实现抛异常 | 该工具返回失败、对话继续,同时留一份报告 |
797
+ | 整轮对话失败(回退链走完仍失败) | 界面上提示「已记录错误报告:…」 |
798
+
799
+ 报告存放在 `~/.xzh/errors/`,每份包含:版本 / Node / 平台 / 项目目录 / 当前模型与 provider /
800
+ 错误消息与堆栈 / 最近几条消息(均截断)。写入前会**对常见密钥格式脱敏**
801
+ (`sk-*`、`AIza*`、`gh*_`、`Bearer …`、`api_key=` 等),但发到公开 issue 前仍建议自己扫一眼。
802
+ 同一类错误只保留一份并累加次数,最多 50 份。
803
+
804
+ ```bash
805
+ xzh errors # 列表:时间 / 次数 / 类别 / 摘要
806
+ xzh errors show 1 # 第 1 份的完整 JSON
807
+ xzh errors path # 报告目录
808
+ xzh errors clear --yes # 清空
809
+ ```
810
+
811
+ 反馈时把 `xzh errors show <序号>` 的输出(或整个 `~/.xzh/errors/` 目录)附上即可。
812
+
758
813
  ## 项目结构
759
814
 
760
815
  ```
761
816
  src/
762
- ├── cli/ 命令行入口与命令
763
- ├── core/ Agent 循环与提示词
764
- ├── llm/ LLM Provider 抽象与实现
765
- ├── tools/ 终端工具集(含 list_skills / load_skill)
766
- ├── skills/ 技能发现与加载
767
- ├── tui/ 全屏终端界面
768
- ├── config/ 配置读写
769
- └── utils/ ANSI 与路径工具
817
+ ├── cli/ 命令行入口与子命令(model / config / skill / device / setup)
818
+ ├── core/ Agent 循环、系统提示词、会话持久化
819
+ ├── llm/ LLM Provider 抽象与实现、上下文裁剪、token 校正
820
+ ├── tools/ 终端工具集(文件 / bash / 记忆 / 技能 / 任务列表 / 子代理 / 设备桥)
821
+ ├── subagents/ 子代理注册表(code-explorer / test-runner)
822
+ ├── device/ 手机设备桥(AutoJs6 协议、服务端、APK 探测、截图、界面树)
823
+ ├── skills/ 技能发现、依赖检测与安装
824
+ ├── tui/ 全屏终端界面
825
+ ├── workspace/ 项目级工作区(.xuanzhu:记忆 + 规则)
826
+ ├── config/ 配置读写
827
+ └── utils/ ANSI / 备份 / 剪贴板 / 并发 / 崩溃诊断 / 路径
770
828
  ```
771
829
 
772
- 详见 [docs/ARCHITECTURE.md](https://github.com/amble311/xuanzhu/blob/main/docs/ARCHITECTURE.md)。
830
+ 架构说明与设计取舍由开发者**本地维护**(`AGENTS.md` 与 `docs/`),**不随包分发、也不在 GitHub 仓库中**。
773
831
 
774
832
  ## 开发
775
833
 
@@ -786,12 +844,13 @@ node bin/xzh.js # 本地运行
786
844
  ```bash
787
845
  ./release.sh # 版本尾号 +1(0.1.4 → 0.1.5)
788
846
  ./release.sh minor # 0.1.4 → 0.2.0
789
- ./release.sh 1.0.0 # 指定版本
847
+ ./release.sh major # 0.1.4 → 1.0.0
848
+ ./release.sh 1.2.3 # 指定版本
790
849
  XZH_RELEASE_DRY_RUN=1 ./release.sh # 先演练一遍,不做任何写入
791
850
  ```
792
851
 
793
- 脚本会依次完成:**版本号 +1 → `npm publish` → 等待 registry 同步 → 提交并推送 GitHub
794
- → 更新本机全局安装**。
852
+ 脚本会依次完成:**bump 版本号(含 lock)→ 把 `CHANGELOG.md` 的 `[未发布]` 段收成本次版本
853
+ → `npm publish` → 等待 registry 同步 → `git add -A` + 提交 + 推送 GitHub → 更新本机全局安装**。
795
854
 
796
855
  之所以需要脚本,是因为这条链路有几个反直觉的地方:`npm publish` 返回成功**不等于**
797
856
  registry 已可见(npm 有 staging 阶段,期间 `npm view` / `npm install` 会报 `notarget`),
@@ -803,7 +862,8 @@ registry 已可见(npm 有 staging 阶段,期间 `npm view` / `npm install`
803
862
  | `XZH_RELEASE_YES=1` | 跳过发布前的确认提示 |
804
863
  | `XZH_RELEASE_SKIP_GIT=1` | 不推送 GitHub |
805
864
  | `XZH_RELEASE_SKIP_LOCAL=1` | 不更新本机全局安装 |
806
- | `XZH_RELEASE_WAIT=<秒>` | 等待 registry 同步的上限(默认 300) |
865
+ | `XZH_RELEASE_WAIT=<秒>` | 等待 registry 同步的上限(默认 300;超时后仍可手工 `npm i -g xuanzhu@<版本>`) |
866
+ | `NO_COLOR=1` | 输出不带颜色(适合日志 / CI) |
807
867
 
808
868
  ## 致谢
809
869