pi-proactive 0.2.0-beta.3 → 0.2.0-beta.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/CHANGELOG.md +27 -0
- package/README.md +46 -29
- package/build/cli.mjs +70 -6
- package/build/extensions/proactive.js +187 -2
- package/build/src/assistant.js +572 -0
- package/build/src/commands.js +13 -0
- package/build/src/config.js +20 -0
- package/build/src/content.js +2 -0
- package/build/src/daemon-host.js +2 -0
- package/build/src/daemon.js +2 -0
- package/build/src/dedupe.js +2 -0
- package/build/src/health.js +2 -0
- package/build/src/lineage.js +2 -0
- package/build/src/mailbox.js +2 -0
- package/build/src/notify.js +2 -0
- package/build/src/peer-spawn.js +2 -0
- package/build/src/peer.js +2 -0
- package/build/src/registry.js +2 -0
- package/build/src/socket.js +2 -0
- package/build/src/supervisor-state.js +355 -0
- package/build/src/supervisor-tui.js +85 -0
- package/build/src/supervisor-web.js +262 -0
- package/build/src/task-store.js +2 -0
- package/build/src/thread.js +2 -0
- package/package.json +7 -6
- package/skills/pi-proactive/SKILL.md +92 -27
- package/tools/cli.mjs +70 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## 0.2.0-beta.5 — 2026-10-31(hotfix)
|
|
11
|
+
|
|
12
|
+
### 修复
|
|
13
|
+
- **阻断级**:`pendingConfigError` 声明晚于模块级 `config = safeConfig()` → TDZ(暂时性死区)→
|
|
14
|
+
每次会话抛 `Cannot access 'pendingConfigError' before initialization`;**用户自定义配置被静默忽略**(一律回落 default);
|
|
15
|
+
若配置含拼错键,该分支同样抛错并逃出 → 整个扩展加载失败。修复:声明上移到模块级初始化之前。
|
|
16
|
+
- `typebox` 同时列入 peerDependencies 与 bundledDependencies(包内自带)→ 兼容 `--legacy-peer-deps` 安装的机器
|
|
17
|
+
(此前报 Cannot find package 'typebox')。
|
|
18
|
+
|
|
19
|
+
### 证据来源
|
|
20
|
+
由 ai-native 项目(跨项目协作)提供第一手证据(真实宿主加载 stderr + 产物源码行号),我方独立复核确认。
|
|
21
|
+
## 0.2.0-beta.4 — 2026-10-31
|
|
22
|
+
|
|
23
|
+
### 新增
|
|
24
|
+
- **会话内常驻助理入口**:`/proactive assistant on|off|status|restart`(+ 模型工具 `proactive_assistant`),与命令面**同源逐字一致**。
|
|
25
|
+
- **托付与对话闭环**:`/proactive trust add|list|cancel`、`/proactive ask`、`/proactive inbox` —— 人话与斜杠命令同源。
|
|
26
|
+
- **Web + TUI 双监督面**:`pi-proactive web`(本地 127.0.0.1)+ pi-agent 内状态栏摘要与面板;两���数字**逐字一致**(同一状态聚合模块)。
|
|
27
|
+
- **配置三层作用域**:会话 > agent > 全局;安全类键**取最严**(护栏不可被局部放宽)。
|
|
28
|
+
- **产品设计面**(独立工程目录 `docs/product/digital-employee/`):8 页详细设计 HTML + 2 个高保真可交互原型 + ADR 决策记录。
|
|
29
|
+
- **S0 内核面契约**:`docs/project/kernel-contract-s0.md` + 边界机检(内核适配 pi-agent 但不耦合)。
|
|
30
|
+
|
|
31
|
+
### 修复
|
|
32
|
+
- npm 包 `bin` 入口丢失(`.npmignore` 覆盖 `.gitignore`,使 `build/` 得以进包)。
|
|
33
|
+
- `typebox` 归位 `peerDependencies`(符合 host-provided 扩展约定,消除加载告警)。
|
|
34
|
+
- 产物构建链:每次先清空再构建,杜绝沿用陈旧产物;产物清单核对缺件即失败。
|
|
35
|
+
- 安装失败自动回滚;卸载失败报告残留并给出清理命令。
|
|
36
|
+
|
|
10
37
|
## 0.2.0-beta.3 — 2026-10-29
|
|
11
38
|
|
|
12
39
|
### 新增
|
package/README.md
CHANGED
|
@@ -63,6 +63,21 @@ pi --extension ./pi-proactive/extensions/proactive.ts
|
|
|
63
63
|
|
|
64
64
|
需要一个**人不在场也在干活**的常驻代理时再开(它会真花你的账号额度):
|
|
65
65
|
|
|
66
|
+
**在会话里开 / 关(推荐:不用切终端)**:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
/proactive assistant on # 打开常驻助理(后台装,不阻塞会话;装完看 status)
|
|
70
|
+
/proactive assistant status # 常驻状态:宿主 / 进程 / 心跳 / 上次联系
|
|
71
|
+
/proactive assistant off # 关闭(回执含残留终检:任务 / 进程 / 单元)
|
|
72
|
+
/proactive assistant restart # 重装
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `on` **立即回执「正在安装…」**(不等 launchd/systemd 冷启动)→ 装完用 `assistant status` 看结果;
|
|
76
|
+
- 会话内与终端 CLI **共用同一套安装/卸载实现**(`tools/daemon-install.sh` / `tools/daemon-uninstall.sh`);
|
|
77
|
+
- 装不上时回执会给出**缺什么、怎么手动跑、怎么清理**三条可操作信息。
|
|
78
|
+
|
|
79
|
+
**在终端里开 / 关(等价路径)**:
|
|
80
|
+
|
|
66
81
|
```bash
|
|
67
82
|
# 安装(幂等;macOS 用 launchd,Linux 用 systemd --user)
|
|
68
83
|
bash <安装目录>/tools/daemon-install.sh
|
|
@@ -380,30 +395,31 @@ Usage: `/proactive <子命令>`。下表**逐条对应实现里实际注册的
|
|
|
380
395
|
`switch`),未列出的子命令会被拒绝并提示可用清单。
|
|
381
396
|
|
|
382
397
|
> **命令面真源 = 实现**:下表由 `scripts/gen-doc-tables.sh` 从 `pi-proactive/src/commands.ts` 的
|
|
383
|
-
> `SUBCOMMANDS` + `switch (sub)` 的 case 分派**自动生成**(共 **
|
|
398
|
+
> `SUBCOMMANDS` + `switch (sub)` 的 case 分派**自动生成**(共 **19 个命令**),**不要手改**;
|
|
384
399
|
> 要改命令面请改实现,然后跑 `bash scripts/gen-doc-tables.sh --apply`(门禁 `scripts/check-doc-tables.sh` 校验)。
|
|
385
400
|
|
|
386
401
|
<!-- BEGIN:GEN commands -->
|
|
387
402
|
| 命令 | 参数形态 | 做什么 | 状态 |
|
|
388
403
|
| --- | --- | --- | --- |
|
|
389
|
-
| `/proactive status` | `无` | 总览:开关、空闲计时、待触发任务、对端在线、上次主动、本小时用量。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
390
|
-
| `/proactive on` | `无` | 打开全部「代理自发」行为(空闲触发、模型自调度、跨会话自发请求)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
391
|
-
| `/proactive off` | `无` | 关闭全部「代理自发」行为;已排期任务保留但不再触发。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
392
|
-
| `/proactive test` | `无` | 立即模拟一次触发(走完整「护栏 → 投递」链路),用于验证主动能力是否真的生效。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
393
|
-
| `/proactive tasks` | `无` | 列出所有待触发任务(编号 / 类型 / 下次到期 / 归属 / 触发次数)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
394
|
-
| `/proactive cancel` | `<id>` | 取消一个任务。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
395
|
-
| `/proactive idle` | `on\|off` | 打开 / 关闭空闲触发并设定阈值(on 可带时长参数,省略 = 用上次设定)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
396
|
-
| `/proactive peers` | `[--all\|--idle\|--name <子串>\|--detail <agentId>]` | 列出已注册的对端与在线状态(名字 / 忙闲 / 最后心跳);可加 --all / --idle / --name / --detail。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
397
|
-
| `/proactive spawn` | `[名字]` | 创建一个对端会话(子进程 pi --mode rpc);本会话退出时一并终止。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
398
|
-
| `/proactive in` | `<时长> <内容>` | 排一个延迟任务(默认只属于当前会话)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
399
|
-
| `/proactive at` | `<HH:MM> <内容>` | 排一个绝对时间任务。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
400
|
-
| `/proactive every` | `<时长> <内容>` | 排一个周期任务。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
401
|
-
| `/proactive help` | `无` | 打印命令速查表(命令表 / 配置键 / 最常见故障 / 详细文档路径)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
402
|
-
| `/proactive history` | `[peer\|me] [条数]` | 查看最近的主动行为记录(时间 / 类型 / 目标 / 结果 / 被护栏拦下的原因)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
403
|
-
| `/proactive doctor` | `[--json]` | 只读体检:逐项健康判定 + 处置建议(--json 机器可读);不打扰、不耗额度。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
404
|
-
| `/proactive progress` | `无` | 项目进度 + ETA:区间 + 置信度 + 归因 + 阻塞项(不给单点数字;口径 = scripts/progress-clock.py)。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
405
|
-
| `/proactive tell` | `<peer> <内容> [--kind ask\|task\|notify]` | 人侧给另一个会话下指令(--kind ask\|task\|notify,缺省 ask 要回话);回信落回本会话。 | 已实现 · `pi-proactive/src/commands.ts:
|
|
406
|
-
| `/proactive
|
|
404
|
+
| `/proactive status` | `无` | 总览:开关、空闲计时、待触发任务、对端在线、上次主动、本小时用量。 | 已实现 · `pi-proactive/src/commands.ts:632` |
|
|
405
|
+
| `/proactive on` | `无` | 打开全部「代理自发」行为(空闲触发、模型自调度、跨会话自发请求)。 | 已实现 · `pi-proactive/src/commands.ts:668` |
|
|
406
|
+
| `/proactive off` | `无` | 关闭全部「代理自发」行为;已排期任务保留但不再触发。 | 已实现 · `pi-proactive/src/commands.ts:669` |
|
|
407
|
+
| `/proactive test` | `无` | 立即模拟一次触发(走完整「护栏 → 投递」链路),用于验证主动能力是否真的生效。 | 已实现 · `pi-proactive/src/commands.ts:758` |
|
|
408
|
+
| `/proactive tasks` | `无` | 列出所有待触发任务(编号 / 类型 / 下次到期 / 归属 / 触发次数)。 | 已实现 · `pi-proactive/src/commands.ts:761` |
|
|
409
|
+
| `/proactive cancel` | `<id>` | 取消一个任务。 | 已实现 · `pi-proactive/src/commands.ts:787` |
|
|
410
|
+
| `/proactive idle` | `on\|off` | 打开 / 关闭空闲触发并设定阈值(on 可带时长参数,省略 = 用上次设定)。 | 已实现 · `pi-proactive/src/commands.ts:827` |
|
|
411
|
+
| `/proactive peers` | `[--all\|--idle\|--name <子串>\|--detail <agentId>]` | 列出已注册的对端与在线状态(名字 / 忙闲 / 最后心跳);可加 --all / --idle / --name / --detail。 | 已实现 · `pi-proactive/src/commands.ts:689` |
|
|
412
|
+
| `/proactive spawn` | `[名字]` | 创建一个对端会话(子进程 pi --mode rpc);本会话退出时一并终止。 | 已实现 · `pi-proactive/src/commands.ts:735` |
|
|
413
|
+
| `/proactive in` | `<时长> <内容>` | 排一个延迟任务(默认只属于当前会话)。 | 已实现 · `pi-proactive/src/commands.ts:805` |
|
|
414
|
+
| `/proactive at` | `<HH:MM> <内容>` | 排一个绝对时间任务。 | 已实现 · `pi-proactive/src/commands.ts:806` |
|
|
415
|
+
| `/proactive every` | `<时长> <内容>` | 排一个周期任务。 | 已实现 · `pi-proactive/src/commands.ts:807` |
|
|
416
|
+
| `/proactive help` | `无` | 打印命令速查表(命令表 / 配置键 / 最常见故障 / 详细文档路径)。 | 已实现 · `pi-proactive/src/commands.ts:842` |
|
|
417
|
+
| `/proactive history` | `[peer\|me] [条数]` | 查看最近的主动行为记录(时间 / 类型 / 目标 / 结果 / 被护栏拦下的原因)。 | 已实现 · `pi-proactive/src/commands.ts:765` |
|
|
418
|
+
| `/proactive doctor` | `[--json]` | 只读体检:逐项健康判定 + 处置建议(--json 机器可读);不打扰、不耗额度。 | 已实现 · `pi-proactive/src/commands.ts:640` |
|
|
419
|
+
| `/proactive progress` | `无` | 项目进度 + ETA:区间 + 置信度 + 归因 + 阻塞项(不给单点数字;口径 = scripts/progress-clock.py)。 | 已实现 · `pi-proactive/src/commands.ts:648` |
|
|
420
|
+
| `/proactive tell` | `<peer> <内容> [--kind ask\|task\|notify]` | 人侧给另一个会话下指令(--kind ask\|task\|notify,缺省 ask 要回话);回信落回本会话。 | 已实现 · `pi-proactive/src/commands.ts:755` |
|
|
421
|
+
| `/proactive assistant` | `on\|off\|status\|restart` | 常驻助理(7×24)控制:on 打开(后台装,不阻塞会话)/ off 关闭(回执含残留终检)/ status 看宿主·进程·心跳·上次联系 / restart 重装。与终端 CLI 共用同一套安装/卸载实现。 | 已实现 · `pi-proactive/src/commands.ts:724` |
|
|
422
|
+
| `/proactive config` | `[undo] [--json]` | 列出全部配置项(当前值 / 缺省值 / 取值范围 / 一句说明),先报警写错的项;config undo 撤销上一次配置改动。 | 已实现 · `pi-proactive/src/commands.ts:655` |
|
|
407
423
|
<!-- END:GEN commands -->
|
|
408
424
|
|
|
409
425
|
排期命令的排期结果会**当场回执**(任务 id、相对到期、绝对到期),任务**落盘**在任务表里,进程退出后仍在,
|
|
@@ -421,18 +437,19 @@ Usage: `/proactive <子命令>`。下表**逐条对应实现里实际注册的
|
|
|
421
437
|
<!-- BEGIN:GEN tools -->
|
|
422
438
|
| 工具 | 参数 | 作用 | 定义位置 |
|
|
423
439
|
| --- | --- | --- | --- |
|
|
424
|
-
| `schedule_task` | prompt(必填):任务提示词<br>intent(可选):投递意图,默认 wake(取值:wake \| interrupt \| queue \| notify)<br>askUser(可选):触发时是否向用户提问(仅本地)<br>when(可选):触发时间:时长(10m)/ 时刻(18:30)/ ISO 8601;缺省按 10m 处理 | 预约一个稍后触发的任务(真正落库到任务表,到点由调度器投递)。when 支持时长(10m)、时刻(18:30)或 ISO 时间;缺省按 10m 处理。 | `pi-proactive/extensions/proactive.ts:
|
|
425
|
-
| `message_agent` | to(必填):目标 agent 的名字或 agentId<br>kind(可选):消息语义(对方要不要回我);缺省 notify(取值:notify \| ask \| task \| reply \| broadcast)<br>subject(可选):标题<br>body(必填):正文<br>intent(可选):投递意图(怎么投给对方);缺省 wake(取值:wake \| interrupt \| queue \| notify)<br>threadId(可选):话题 / 会话 id(可选) | 给另一个正在运行的 agent 会话发消息(跨进程协作)。对端在线时走 socket 直达;不在线时消息落盘到对端邮箱,待其上线后处理。 | `pi-proactive/extensions/proactive.ts:
|
|
426
|
-
| `list_peers` | name(可选):名字子串(大小写敏感;也命中 agentId)。同名歧义时返回与 message_agent 报错完全一致的候选<br>status(可选):按在场状态过滤(online = 在线 = 空闲 ∪ 忙碌)(取值:online \| idle \| busy \| offline)<br>capability(可选):按能力标签过滤(如 message_agent)<br>includeOffline(可选):是否包含离线对端(缺省 false = 只给在线) | 列出本机可见的其它 agent 对端(名字 / agentId / 在场状态 / 心跳龄 / 能力标签 / 在途任务数 / 传输方式),可按名字、状态、能力过滤。**只读**:不产生任何对外行为。发消息前先查它(先查后发),别盲发 —— 离线对端现在打扰它不合适。 | `pi-proactive/extensions/proactive.ts:
|
|
427
|
-
| `proactive_query` | action(必填):查询动作(与 /proactive 子命令同名)(取值:peers \| history \| status \| tasks \| doctor \| help \| config)<br>name(可选):peers:名字子串过滤<br>all(可选):peers:是否包含离线对端<br>idle(可选):peers:只看空闲对端<br>detail(可选):peers:只看这一个 agentId<br>scope(可选):history:范围(对端 / 我)(取值:peer \| me)<br>peer(可选):history:按对端 agentId 过滤<br>limit(可选):history:条数(1-200 的整数)<br>json(可选):doctor / config:输出 JSON | 查询域:查对端(peers)/ 看主动行为历史(history)/ 看状态(status)/ 看任务(tasks)/ 只读体检(doctor)/ 看命令手册(help)/ 查配置清单(config)。**只读**:不产生任何对外行为。 | `pi-proactive/extensions/proactive.ts:
|
|
428
|
-
| `progress_query` | | 查项目进度与 ETA:返回**区间 + 置信度 + 归因 + 阻塞项**(不给单点数字)。口径唯一(scripts/progress-clock.py),与人侧 `/proactive progress` 同源同口径、逐字一致。**只读**:不产生任何对外行为。 | `pi-proactive/extensions/proactive.ts:
|
|
429
|
-
| `proactive_schedule` | action(必填):排程动作(与 /proactive 子命令同名)(取值:in \| at \| every \| cancel)<br>when(可选):in/at/every:触发时间(时长 10m / 时刻 18:30)<br>content(可选):in/at/every:任务内容<br>id(可选):cancel:任务 id | 排程域:定时(in)/ 定点(at)/ 周期(every)/ 取消(cancel)。落到真实任务表,到点由调度器投递;与命令面 `/proactive in\|at\|every\|cancel` 同源。 | `pi-proactive/extensions/proactive.ts:
|
|
430
|
-
| `proactive_peer` | action(必填):对端动作(与 /proactive 子命令同名)(取值:tell \| spawn)<br>peer(可选):tell:目标对端(名字或 agentId)<br>content(可选):tell:指令内容<br>kind(可选):tell:指令类型(缺省 ask)(取值:ask \| task \| notify)<br>subject(可选):tell:标题<br>thread(可选):tell:线程 id<br>name(可选):spawn:对端名字 | 对端协作域:给对端下指令(tell)/ 创建对端会话(spawn,受同时存活数上限)。tell 的目标解析与回执三态与命令面 `/proactive tell` 完全同源。 | `pi-proactive/extensions/proactive.ts:
|
|
431
|
-
| `proactive_manage` | action(必填):管理动作(与 /proactive 子命令同名)(取值:on \| off \| idle \| test)<br>state(可选):idle:开 / 关(取值:on \| off) | 管理域:主动性总开关(on/off)、空闲触发开关(idle)、自检(test)。这些能力属 human-gated:调用只会回报「需人工确认」并给出可复制的人工指令,**不会**自行改动全局开关。 | `pi-proactive/extensions/proactive.ts:
|
|
440
|
+
| `schedule_task` | prompt(必填):任务提示词<br>intent(可选):投递意图,默认 wake(取值:wake \| interrupt \| queue \| notify)<br>askUser(可选):触发时是否向用户提问(仅本地)<br>when(可选):触发时间:时长(10m)/ 时刻(18:30)/ ISO 8601;缺省按 10m 处理 | 预约一个稍后触发的任务(真正落库到任务表,到点由调度器投递)。when 支持时长(10m)、时刻(18:30)或 ISO 时间;缺省按 10m 处理。 | `pi-proactive/extensions/proactive.ts:647` |
|
|
441
|
+
| `message_agent` | to(必填):目标 agent 的名字或 agentId<br>kind(可选):消息语义(对方要不要回我);缺省 notify(取值:notify \| ask \| task \| reply \| broadcast)<br>subject(可选):标题<br>body(必填):正文<br>intent(可选):投递意图(怎么投给对方);缺省 wake(取值:wake \| interrupt \| queue \| notify)<br>threadId(可选):话题 / 会话 id(可选) | 给另一个正在运行的 agent 会话发消息(跨进程协作)。对端在线时走 socket 直达;不在线时消息落盘到对端邮箱,待其上线后处理。 | `pi-proactive/extensions/proactive.ts:692` |
|
|
442
|
+
| `list_peers` | name(可选):名字子串(大小写敏感;也命中 agentId)。同名歧义时返回与 message_agent 报错完全一致的候选<br>status(可选):按在场状态过滤(online = 在线 = 空闲 ∪ 忙碌)(取值:online \| idle \| busy \| offline)<br>capability(可选):按能力标签过滤(如 message_agent)<br>includeOffline(可选):是否包含离线对端(缺省 false = 只给在线) | 列出本机可见的其它 agent 对端(名字 / agentId / 在场状态 / 心跳龄 / 能力标签 / 在途任务数 / 传输方式),可按名字、状态、能力过滤。**只读**:不产生任何对外行为。发消息前先查它(先查后发),别盲发 —— 离线对端现在打扰它不合适。 | `pi-proactive/extensions/proactive.ts:766` |
|
|
443
|
+
| `proactive_query` | action(必填):查询动作(与 /proactive 子命令同名)(取值:peers \| history \| status \| tasks \| doctor \| help \| config \| supervisor)<br>name(可选):peers:名字子串过滤<br>all(可选):peers:是否包含离线对端<br>idle(可选):peers:只看空闲对端<br>detail(可选):peers:只看这一个 agentId<br>scope(可选):history:范围(对端 / 我)(取值:peer \| me)<br>peer(可选):history:按对端 agentId 过滤<br>limit(可选):history:条数(1-200 的整数)<br>json(可选):doctor / config:输出 JSON | 查询域:查对端(peers)/ 看主动行为历史(history)/ 看状态(status)/ 看任务(tasks)/ 只读体检(doctor)/ 看命令手册(help)/ 查配置清单(config)/ 看监督面(supervisor)。**只读**:不产生任何对外行为。 | `pi-proactive/extensions/proactive.ts:803` |
|
|
444
|
+
| `progress_query` | | 查项目进度与 ETA:返回**区间 + 置信度 + 归因 + 阻塞项**(不给单点数字)。口径唯一(scripts/progress-clock.py),与人侧 `/proactive progress` 同源同口径、逐字一致。**只读**:不产生任何对外行为。 | `pi-proactive/extensions/proactive.ts:841` |
|
|
445
|
+
| `proactive_schedule` | action(必填):排程动作(与 /proactive 子命令同名)(取值:in \| at \| every \| cancel)<br>when(可选):in/at/every:触发时间(时长 10m / 时刻 18:30)<br>content(可选):in/at/every:任务内容<br>id(可选):cancel:任务 id | 排程域:定时(in)/ 定点(at)/ 周期(every)/ 取消(cancel)。落到真实任务表,到点由调度器投递;与命令面 `/proactive in\|at\|every\|cancel` 同源。 | `pi-proactive/extensions/proactive.ts:855` |
|
|
446
|
+
| `proactive_peer` | action(必填):对端动作(与 /proactive 子命令同名)(取值:tell \| spawn)<br>peer(可选):tell:目标对端(名字或 agentId)<br>content(可选):tell:指令内容<br>kind(可选):tell:指令类型(缺省 ask)(取值:ask \| task \| notify)<br>subject(可选):tell:标题<br>thread(可选):tell:线程 id<br>name(可选):spawn:对端名字 | 对端协作域:给对端下指令(tell)/ 创建对端会话(spawn,受同时存活数上限)。tell 的目标解析与回执三态与命令面 `/proactive tell` 完全同源。 | `pi-proactive/extensions/proactive.ts:874` |
|
|
447
|
+
| `proactive_manage` | action(必填):管理动作(与 /proactive 子命令同名)(取值:on \| off \| idle \| test)<br>state(可选):idle:开 / 关(取值:on \| off) | 管理域:主动性总开关(on/off)、空闲触发开关(idle)、自检(test)。这些能力属 human-gated:调用只会回报「需人工确认」并给出可复制的人工指令,**不会**自行改动全局开关。 | `pi-proactive/extensions/proactive.ts:913` |
|
|
448
|
+
| `proactive_assistant` | action(必填):常驻助理动作:on 打开 / off 关闭 / status 看状态 / restart 重装(与 /proactive assistant 同名)(取值:on \| off \| status \| restart) | 常驻助理(7×24)控制:on 打开 / off 关闭 / status 看状态 / restart 重装。与人侧 `/proactive assistant …` 同源同分派 → 逐字一致;安装**不阻塞**(立即回执「正在安装…」,结果用 status 查)。装上默认 enabled=false + 干跑 → 不花钱、不主动打扰。 | `pi-proactive/extensions/proactive.ts:925` |
|
|
432
449
|
<!-- END:GEN tools -->
|
|
433
450
|
|
|
434
451
|
> **模型工具面真源 = 实现**:上表由 `scripts/gen-doc-tables.sh` 从 `pi-proactive/extensions/proactive.ts` 的
|
|
435
|
-
> `pi.registerTool({ name: … })` 注册项与参数 schema **自动生成**(共 **
|
|
452
|
+
> `pi.registerTool({ name: … })` 注册项与参数 schema **自动生成**(共 **9 个模型工具**),**不要手改**;
|
|
436
453
|
> 表中参数即真实 schema。下面三个小节是逐个工具的展开说明。
|
|
437
454
|
|
|
438
455
|
### `schedule_task`
|
|
@@ -537,7 +554,7 @@ Usage: `/proactive <子命令>`。下表**逐条对应实现里实际注册的
|
|
|
537
554
|
| `limits.quietHours` | `未设` | 静默时段 {from,to}(HH:MM,from 大于 to 表示跨零点),时段内不主动打扰。 | `pi-proactive/src/config.ts:386` |
|
|
538
555
|
| `peerWatch.enabled` | `false` | 跨会话空闲协作(peer watch)开关。 | `pi-proactive/src/config.ts:351` |
|
|
539
556
|
| `peerWatch.afterIdleMs` | `600000` | 连续空闲多久后才去询问 peer(毫秒)。 | `pi-proactive/src/config.ts:352` |
|
|
540
|
-
| `version` | `"v1"` | 落盘格式版本;无法识别时拒绝按已知格式解析(保留原文件,不覆盖)。 | `pi-proactive/src/config.ts:
|
|
557
|
+
| `version` | `"v1"` | 落盘格式版本;无法识别时拒绝按已知格式解析(保留原文件,不覆盖)。 | `pi-proactive/src/config.ts:1121` |
|
|
541
558
|
<!-- END:GEN config -->
|
|
542
559
|
|
|
543
560
|
> **配置面真源 = 实现**:上表由 `scripts/gen-doc-tables.sh` 从 `pi-proactive/src/config.ts` 的
|
package/build/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// 单一真源:本文件是 build/cli.mjs 的**源文件**(build/ 是编译产物,不入库)。
|
|
6
6
|
// build-release.sh 负责把它复制到 build/cli.mjs → npm 包的 bin 入口。
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
|
|
@@ -39,9 +39,18 @@ const CLI_FLAGS = {
|
|
|
39
39
|
"--service-name",
|
|
40
40
|
"--no-start",
|
|
41
41
|
"--purge-data",
|
|
42
|
+
"--purge-data",
|
|
42
43
|
],
|
|
43
44
|
};
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* `web` 子命令自己的参数(**不进 CLI_FLAGS**)。
|
|
48
|
+
*
|
|
49
|
+
* 为什么单独一张表:CLI_FLAGS 是「**转发给 .sh 脚本**的参数契约」(T1 逐条核对
|
|
50
|
+
* cli 声明的每个参数都被对应 .sh 接受);web 不转发给任何 .sh → 不属于那张表。
|
|
51
|
+
*/
|
|
52
|
+
const WEB_FLAGS = ["--port", "--agent-dir", "--json"];
|
|
53
|
+
|
|
45
54
|
const USAGE = `pi-proactive — 给 Pi 增加主动性(空闲主动、按点主动、多会话协作)
|
|
46
55
|
|
|
47
56
|
用法:
|
|
@@ -51,6 +60,7 @@ const USAGE = `pi-proactive — 给 Pi 增加主动性(空闲主动、按点
|
|
|
51
60
|
pi-proactive progress 进度与 ETA(区间/置信度/阻塞项)
|
|
52
61
|
pi-proactive config 查看配置(全部项/当前值/默认值/范围/说明)
|
|
53
62
|
pi-proactive history 主动行为与应答的血缘记录
|
|
63
|
+
pi-proactive web 本地 Web 监督面(只读;只监听 127.0.0.1;--port/--agent-dir/--json)
|
|
54
64
|
|
|
55
65
|
安装(任选其一):
|
|
56
66
|
npx pi-proactive daemon install
|
|
@@ -76,8 +86,8 @@ const script = (name) => {
|
|
|
76
86
|
};
|
|
77
87
|
|
|
78
88
|
/** 参数白名单校验(**转发前**拦下未知参数 → 不把错误留给脚本去猜)。 */
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
/** 参数白名单校验(**转发前**拦下未知参数 → 不把错误留给脚本去猜)。 */
|
|
90
|
+
function checkFlags(allowed, args) {
|
|
81
91
|
for (const a of args) {
|
|
82
92
|
if (!a.startsWith("--")) continue;
|
|
83
93
|
const name = a.split("=")[0];
|
|
@@ -105,7 +115,7 @@ if (cmd === "daemon") {
|
|
|
105
115
|
process.exit(2);
|
|
106
116
|
}
|
|
107
117
|
const rest = argv.slice(2);
|
|
108
|
-
checkFlags(sub, rest);
|
|
118
|
+
checkFlags(CLI_FLAGS[sub] ?? [], rest);
|
|
109
119
|
const code = await run("bash", [s, ...rest]);
|
|
110
120
|
if (code !== 0 && sub === "install") {
|
|
111
121
|
// 失败即回滚(不给自己留 launchd 任务 / 进程 / 单元文件)。
|
|
@@ -116,6 +126,60 @@ if (cmd === "daemon") {
|
|
|
116
126
|
process.exit(code);
|
|
117
127
|
}
|
|
118
128
|
|
|
129
|
+
/**
|
|
130
|
+
* 定位监督面模块(**两种落位**都要认:源码态 .ts / 产物态 .js)。
|
|
131
|
+
*
|
|
132
|
+
* 产物态:cli 在 <pkg>/build/cli.mjs → 模块在 <pkg>/build/src/*.js;
|
|
133
|
+
* 源码态:cli 在 <pkg>/tools/cli.mjs → 模块在 <pkg>/src/*.ts。
|
|
134
|
+
*/
|
|
135
|
+
async function loadSupervisorModule(base) {
|
|
136
|
+
const candidates = [
|
|
137
|
+
path.join(here, "src", `${base}.js`),
|
|
138
|
+
path.join(here, "..", "src", `${base}.ts`),
|
|
139
|
+
];
|
|
140
|
+
for (const file of candidates) {
|
|
141
|
+
if (!fs.existsSync(file)) continue;
|
|
142
|
+
return await import(pathToFileURL(file).href);
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`包内缺少监督面模块(${base})—— 请重新安装 pi-proactive`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** `pi-proactive web`:本地 Web 监督面(**只读**;只监听 127.0.0.1)。 */
|
|
148
|
+
if (cmd === "web") {
|
|
149
|
+
const rest = argv.slice(1);
|
|
150
|
+
checkFlags(WEB_FLAGS, rest);
|
|
151
|
+
const portIdx = rest.indexOf("--port");
|
|
152
|
+
let port = 7799;
|
|
153
|
+
if (portIdx >= 0) {
|
|
154
|
+
port = Number(rest[portIdx + 1]);
|
|
155
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
156
|
+
console.error(`--port 需要 0-65535 的整数(实际:${rest[portIdx + 1]})`);
|
|
157
|
+
process.exit(2);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const dirIdx = rest.indexOf("--agent-dir");
|
|
161
|
+
const agentDir = dirIdx >= 0 ? rest[dirIdx + 1] : undefined;
|
|
162
|
+
const stateMod = await loadSupervisorModule("supervisor-state");
|
|
163
|
+
const webMod = await loadSupervisorModule("supervisor-web");
|
|
164
|
+
// --json:非交互取数(不开服务)→ 监督信息在无 TUI 的环境里同样可取。
|
|
165
|
+
if (rest.includes("--json")) {
|
|
166
|
+
const state = stateMod.collectSupervisorState(agentDir !== undefined ? { agentDir } : {});
|
|
167
|
+
console.log(JSON.stringify(state, null, 2));
|
|
168
|
+
process.exit(0);
|
|
169
|
+
}
|
|
170
|
+
const handle = await webMod.startSupervisorWeb({ port, ...(agentDir !== undefined ? { agentDir } : {}) });
|
|
171
|
+
console.log(`[pi-proactive] 监督面已启动:${handle.url}`);
|
|
172
|
+
console.log("[pi-proactive] 只读(改配置请回 Pi 会话);只监听 127.0.0.1;Ctrl-C 退出");
|
|
173
|
+
const shutdown = async () => {
|
|
174
|
+
await handle.close();
|
|
175
|
+
process.exit(0);
|
|
176
|
+
};
|
|
177
|
+
process.on("SIGINT", () => void shutdown());
|
|
178
|
+
process.on("SIGTERM", () => void shutdown());
|
|
179
|
+
}
|
|
180
|
+
|
|
119
181
|
// 其余子命令暂由宿主命令面提供(保持"同一分派"口径);此处给出明确指引而非另写实现
|
|
120
|
-
|
|
121
|
-
|
|
182
|
+
else {
|
|
183
|
+
console.error(`「${cmd}」由 Pi 宿主内的 /proactive ${cmd} 提供;请在 Pi 会话中执行。`);
|
|
184
|
+
process.exit(2);
|
|
185
|
+
}
|
|
@@ -44,6 +44,8 @@ import { SeenSet } from "../src/dedupe.js";
|
|
|
44
44
|
import { Mailbox, gcStaleTemporaries } from "../src/mailbox.js";
|
|
45
45
|
import { createEnvelope, nextHop } from "../src/envelope.js";
|
|
46
46
|
import { writeToMailbox } from "../src/outbox.js";
|
|
47
|
+
import { collectSupervisorState, formatSupervisorSummary } from "../src/supervisor-state.js";
|
|
48
|
+
import { formatSupervisorPanel } from "../src/supervisor-tui.js";
|
|
47
49
|
import { deliverCrossProcess, startSocketServer, } from "../src/socket.js";
|
|
48
50
|
import { createScheduledTask, dispatchProactiveCommand, errText, formatHumanGatedNotice, formatIdleDecision, formatScheduleResult, queryPeerDirectory, SUBCOMMANDS, } from "../src/commands.js";
|
|
49
51
|
const TICK_MS = 1000;
|
|
@@ -198,6 +200,8 @@ let currentStore;
|
|
|
198
200
|
let currentScheduler;
|
|
199
201
|
/** 当前会话 id(宿主 `ctx.sessionManager.getSessionId()`)→ **跨进程重启稳定**(session 作用域归属依据)。 */
|
|
200
202
|
let currentSessionId;
|
|
203
|
+
// TDZ 修复:必须早于模块级 config 初始化(会调用 safeConfig)声明
|
|
204
|
+
let pendingConfigError;
|
|
201
205
|
let config = safeConfig();
|
|
202
206
|
let tracker = new ActivityTracker({ idleDetect: config.idleDetect });
|
|
203
207
|
let guard = new Guard(config);
|
|
@@ -292,7 +296,6 @@ let lastPeerWatchAt = 0;
|
|
|
292
296
|
* 通道限制:配置加载发生在宿主给出 `ctx` 之前 → 先存起来,
|
|
293
297
|
* 由 `session_start`(拿得到 `ctx.ui.notify`)呈现给用户(stderr 亦有一份)。
|
|
294
298
|
*/
|
|
295
|
-
let pendingConfigError;
|
|
296
299
|
function safeConfig() {
|
|
297
300
|
try {
|
|
298
301
|
pendingConfigError = undefined;
|
|
@@ -358,6 +361,7 @@ const proactiveQueryParameters = Type.Object({
|
|
|
358
361
|
Type.Literal("doctor"),
|
|
359
362
|
Type.Literal("help"),
|
|
360
363
|
Type.Literal("config"),
|
|
364
|
+
Type.Literal("supervisor"),
|
|
361
365
|
], { description: "查询动作(与 /proactive 子命令同名)" }),
|
|
362
366
|
name: Type.Optional(Type.String({ description: "peers:名字子串过滤" })),
|
|
363
367
|
all: Type.Optional(Type.Boolean({ description: "peers:是否包含离线对端" })),
|
|
@@ -453,6 +457,10 @@ function commandContext() {
|
|
|
453
457
|
},
|
|
454
458
|
tellPeer: (args) => runTell(args),
|
|
455
459
|
selfTest: () => runSelfTest(),
|
|
460
|
+
// 常驻助理后台装完 → 用户可见通道(命令面回执;工具面无此通道时静默落盘)。
|
|
461
|
+
assistantDone: (text) => {
|
|
462
|
+
currentCtx?.ui.notify(text);
|
|
463
|
+
},
|
|
456
464
|
};
|
|
457
465
|
}
|
|
458
466
|
/**
|
|
@@ -675,10 +683,22 @@ export default function proactiveExtension(pi) {
|
|
|
675
683
|
pi.registerTool({
|
|
676
684
|
name: "proactive_query",
|
|
677
685
|
label: "Proactive Query",
|
|
678
|
-
description: "查询域:查对端(peers)/ 看主动行为历史(history)/ 看状态(status)/ 看任务(tasks)/ 只读体检(doctor)/ 看命令手册(help)/ 查配置清单(config)。" +
|
|
686
|
+
description: "查询域:查对端(peers)/ 看主动行为历史(history)/ 看状态(status)/ 看任务(tasks)/ 只读体检(doctor)/ 看命令手册(help)/ 查配置清单(config)/ 看监督面(supervisor)。" +
|
|
679
687
|
"**只读**:不产生任何对外行为。",
|
|
680
688
|
parameters: proactiveQueryParameters,
|
|
681
689
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
690
|
+
// 监督面(只读):**就地呈现**(不走命令面分派 —— 它不产生任何对外行为)。
|
|
691
|
+
// 数字与 Web 看板**同源**(同一份聚合模块)→ 两个面逐字一致。
|
|
692
|
+
if (params.action === "supervisor") {
|
|
693
|
+
const state = readSupervisorState();
|
|
694
|
+
if (state === undefined) {
|
|
695
|
+
return { content: [{ type: "text", text: "proactive: 监督面读取失败(事实源不可读)" }], details: { level: "error" } };
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
content: [{ type: "text", text: formatSupervisorPanel(state).join("\n") }],
|
|
699
|
+
details: { level: "info" },
|
|
700
|
+
};
|
|
701
|
+
}
|
|
682
702
|
const parts = [params.action];
|
|
683
703
|
if (params.action === "peers") {
|
|
684
704
|
if (params.all === true)
|
|
@@ -764,6 +784,19 @@ export default function proactiveExtension(pi) {
|
|
|
764
784
|
return dispatchTool(parts.join(" "), { action: params.action });
|
|
765
785
|
},
|
|
766
786
|
});
|
|
787
|
+
/**
|
|
788
|
+
* 常驻域:会话内开 / 关 / 看常驻助理(7×24)。
|
|
789
|
+
*
|
|
790
|
+
* 与人侧 `/proactive assistant …` **共用同一分派**(`dispatchProactiveCommand`)→ 输出逐字一致。
|
|
791
|
+
*/
|
|
792
|
+
const proactiveAssistantParameters = Type.Object({
|
|
793
|
+
action: Type.Union([
|
|
794
|
+
Type.Literal("on"),
|
|
795
|
+
Type.Literal("off"),
|
|
796
|
+
Type.Literal("status"),
|
|
797
|
+
Type.Literal("restart"),
|
|
798
|
+
], { description: "常驻助理动作:on 打开 / off 关闭 / status 看状态 / restart 重装(与 /proactive assistant 同名)" }),
|
|
799
|
+
});
|
|
767
800
|
pi.registerTool({
|
|
768
801
|
name: "proactive_manage",
|
|
769
802
|
label: "Proactive Manage",
|
|
@@ -774,6 +807,17 @@ export default function proactiveExtension(pi) {
|
|
|
774
807
|
return manageTool(params.action, params.state);
|
|
775
808
|
},
|
|
776
809
|
});
|
|
810
|
+
pi.registerTool({
|
|
811
|
+
name: "proactive_assistant",
|
|
812
|
+
label: "Proactive Assistant",
|
|
813
|
+
description: "常驻助理(7×24)控制:on 打开 / off 关闭 / status 看状态 / restart 重装。" +
|
|
814
|
+
"与人侧 `/proactive assistant …` 同源同分派 → 逐字一致;安装**不阻塞**(立即回执「正在安装…」,结果用 status 查)。" +
|
|
815
|
+
"装上默认 enabled=false + 干跑 → 不花钱、不主动打扰。",
|
|
816
|
+
parameters: proactiveAssistantParameters,
|
|
817
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
818
|
+
return dispatchTool(`assistant ${params.action}`, { action: params.action });
|
|
819
|
+
},
|
|
820
|
+
});
|
|
777
821
|
pi.registerCommand("proactive", {
|
|
778
822
|
description: `proactive 主动机制:${SUBCOMMANDS}`,
|
|
779
823
|
handler: async (args, cmdCtx) => {
|
|
@@ -787,6 +831,14 @@ export default function proactiveExtension(pi) {
|
|
|
787
831
|
catch {
|
|
788
832
|
// ignore: 活动标记失败不得影响命令处理
|
|
789
833
|
}
|
|
834
|
+
// 监督面(只读):TUI 面板 / 非交互模式的纯文本;数字与 Web 看板**同源**。
|
|
835
|
+
//
|
|
836
|
+
// 为什么在这里就地处理(不走 commands.ts 的分派):监督面是**只读呈现**,
|
|
837
|
+
// 不产生任何对外行为、不落盘 → 不需要进入命令面的能力分派表。
|
|
838
|
+
if (sub === "supervisor") {
|
|
839
|
+
await showSupervisorPanel(cmdCtx);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
790
842
|
// 命令面子命令 → **能力 id**(与 `docs/project/capability-catalog.json` 逐字一致)。
|
|
791
843
|
//
|
|
792
844
|
// 为什么需要这张表:能力是**语义**,命令/工具只是入口;这张表是「命令面 ↔ 能力目录」的
|
|
@@ -827,6 +879,8 @@ export default function proactiveExtension(pi) {
|
|
|
827
879
|
return "manual-help";
|
|
828
880
|
case "config":
|
|
829
881
|
return "config-inspect";
|
|
882
|
+
case "assistant":
|
|
883
|
+
return "assistant-resident";
|
|
830
884
|
default:
|
|
831
885
|
return "unknown";
|
|
832
886
|
}
|
|
@@ -1064,6 +1118,7 @@ export default function proactiveExtension(pi) {
|
|
|
1064
1118
|
// 退订终端输入(setIdleDetect("off") 会解除订阅)。
|
|
1065
1119
|
tracker.setIdleDetect("off");
|
|
1066
1120
|
currentCtx?.ui.setStatus(STATUS_KEY, undefined);
|
|
1121
|
+
currentCtx?.ui.setStatus(SUPERVISOR_STATUS_KEY, undefined);
|
|
1067
1122
|
currentCtx = undefined;
|
|
1068
1123
|
currentPi = undefined;
|
|
1069
1124
|
}
|
|
@@ -1130,6 +1185,8 @@ async function tick() {
|
|
|
1130
1185
|
}
|
|
1131
1186
|
// 未触发时用判定原因填状态栏。
|
|
1132
1187
|
setStatus(ctx, evaluateIdle({ config, tracker, guard, runtimeMode: ctx.mode }));
|
|
1188
|
+
// 监督面状态栏(助理在不在 · 上次联系 · 预算余量;与 Web 看板同源,内建节流)。
|
|
1189
|
+
setSupervisorStatus(ctx);
|
|
1133
1190
|
}
|
|
1134
1191
|
catch (err) {
|
|
1135
1192
|
console.error("[proactive] tick 失败:", err);
|
|
@@ -1153,6 +1210,129 @@ function setStatus(ctx, decision) {
|
|
|
1153
1210
|
// ignore: 状态栏失败不得让宿主崩溃
|
|
1154
1211
|
}
|
|
1155
1212
|
}
|
|
1213
|
+
/**
|
|
1214
|
+
* 监督面的状态栏(**第二个状态栏 key**):助理在不在 · 上次联系 · 预算余量。
|
|
1215
|
+
*
|
|
1216
|
+
* 与主动机制的状态栏分开:前者是「我现在为什么(没)触发」,后者是「它对我做了什么」。
|
|
1217
|
+
* 数字全部来自 `src/supervisor-state.ts` 的**同一份聚合**(与 Web 看板逐字一致)。
|
|
1218
|
+
*/
|
|
1219
|
+
const SUPERVISOR_STATUS_KEY = "proactive-supervisor";
|
|
1220
|
+
/** 上次写监督面状态栏的时刻(节流:最多每 5s 采集一次)。 */
|
|
1221
|
+
let lastSupervisorStatusAt = 0;
|
|
1222
|
+
/** 上次写进监督面状态栏的文本(内容未变不重写 → 不刷噪声)。 */
|
|
1223
|
+
let lastSupervisorStatusText = "";
|
|
1224
|
+
/** 写监督面状态栏(失败不得冒泡;内容未变不重写)。 */
|
|
1225
|
+
function setSupervisorStatus(ctx) {
|
|
1226
|
+
try {
|
|
1227
|
+
const now = Date.now();
|
|
1228
|
+
if (now - lastSupervisorStatusAt < STATUS_THROTTLE_MS)
|
|
1229
|
+
return;
|
|
1230
|
+
lastSupervisorStatusAt = now;
|
|
1231
|
+
const text = formatSupervisorSummary(collectSupervisorState({ agentDir: resolveAgentDir() }));
|
|
1232
|
+
if (text === lastSupervisorStatusText)
|
|
1233
|
+
return;
|
|
1234
|
+
lastSupervisorStatusText = text;
|
|
1235
|
+
ctx.ui.setStatus(SUPERVISOR_STATUS_KEY, text);
|
|
1236
|
+
}
|
|
1237
|
+
catch {
|
|
1238
|
+
// ignore: 监督面状态栏失败不得让宿主崩溃
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* 采集监督面状态(**只读**;聚合失败 → undefined,调用方如实回执)。
|
|
1243
|
+
*/
|
|
1244
|
+
function readSupervisorState() {
|
|
1245
|
+
try {
|
|
1246
|
+
return collectSupervisorState({ agentDir: resolveAgentDir() });
|
|
1247
|
+
}
|
|
1248
|
+
catch {
|
|
1249
|
+
return undefined;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* 展示监督面(TUI 面板;非交互模式 → 同样的纯文本)。
|
|
1254
|
+
*
|
|
1255
|
+
* 只读:面板里没有任何可点/可改的操作(写操作只在 Pi 会话的自然语言/命令面)。
|
|
1256
|
+
*/
|
|
1257
|
+
async function showSupervisorPanel(ctx) {
|
|
1258
|
+
const state = readSupervisorState();
|
|
1259
|
+
if (state === undefined) {
|
|
1260
|
+
ctx.ui.notify("proactive: 监督面读取失败(事实源不可读)", "error");
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
const lines = formatSupervisorPanel(state);
|
|
1264
|
+
// 非交互模式(json / print / rpc 无 TUI):同样内容以纯文本给出 → 不依赖 TUI 能力。
|
|
1265
|
+
if (ctx.mode !== "tui") {
|
|
1266
|
+
console.log(lines.join("\n"));
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
await ctx.ui.custom((tui, theme, keybindings, done) => {
|
|
1270
|
+
let cachedWidth;
|
|
1271
|
+
let cachedLines;
|
|
1272
|
+
const invalidate = () => {
|
|
1273
|
+
cachedWidth = undefined;
|
|
1274
|
+
cachedLines = undefined;
|
|
1275
|
+
};
|
|
1276
|
+
return {
|
|
1277
|
+
render(width) {
|
|
1278
|
+
if (cachedLines !== undefined && cachedWidth === width)
|
|
1279
|
+
return cachedLines;
|
|
1280
|
+
cachedWidth = width;
|
|
1281
|
+
cachedLines = [...lines, theme.fg("dim", "按 Esc 关闭")].map((line) => truncateToColumns(line, width));
|
|
1282
|
+
return cachedLines;
|
|
1283
|
+
},
|
|
1284
|
+
handleInput(data) {
|
|
1285
|
+
const close = (() => {
|
|
1286
|
+
try {
|
|
1287
|
+
return keybindings.matches(data, "tui.select.cancel") || keybindings.matches(data, "tui.select.confirm");
|
|
1288
|
+
}
|
|
1289
|
+
catch {
|
|
1290
|
+
return data === "\x1b";
|
|
1291
|
+
}
|
|
1292
|
+
})();
|
|
1293
|
+
if (close) {
|
|
1294
|
+
done(undefined);
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
invalidate();
|
|
1298
|
+
tui.requestRender();
|
|
1299
|
+
},
|
|
1300
|
+
invalidate,
|
|
1301
|
+
};
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* 按**可见列宽**裁剪一行(CJK 算 2 列)。
|
|
1306
|
+
*
|
|
1307
|
+
* 为什么自己算:宿主有 `truncateToWidth`,但那是宿主包里的模块 → 扩展产物不依赖它
|
|
1308
|
+
* (打包后扩展只保证 peerDependencies 可解析)。宽字符按 1 列裁会溢出 → 这里按 2 列算。
|
|
1309
|
+
*/
|
|
1310
|
+
function truncateToColumns(line, width) {
|
|
1311
|
+
if (width <= 0)
|
|
1312
|
+
return "";
|
|
1313
|
+
let used = 0;
|
|
1314
|
+
let out = "";
|
|
1315
|
+
for (const ch of line) {
|
|
1316
|
+
const w = isWideChar(ch) ? 2 : 1;
|
|
1317
|
+
if (used + w > width)
|
|
1318
|
+
break;
|
|
1319
|
+
used += w;
|
|
1320
|
+
out += ch;
|
|
1321
|
+
}
|
|
1322
|
+
return out;
|
|
1323
|
+
}
|
|
1324
|
+
/** 是否是宽字符(CJK / 全角)。 */
|
|
1325
|
+
function isWideChar(ch) {
|
|
1326
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
1327
|
+
return ((code >= 0x1100 && code <= 0x115f) ||
|
|
1328
|
+
(code >= 0x2e80 && code <= 0xa4cf) ||
|
|
1329
|
+
(code >= 0xac00 && code <= 0xd7a3) ||
|
|
1330
|
+
(code >= 0xf900 && code <= 0xfaff) ||
|
|
1331
|
+
(code >= 0xfe30 && code <= 0xfe6f) ||
|
|
1332
|
+
(code >= 0xff00 && code <= 0xff60) ||
|
|
1333
|
+
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
1334
|
+
(code >= 0x20000 && code <= 0x3fffd));
|
|
1335
|
+
}
|
|
1156
1336
|
/**
|
|
1157
1337
|
* `/proactive test`:强制投递一次自检消息。
|
|
1158
1338
|
*
|
|
@@ -2226,7 +2406,12 @@ function formatHelp() {
|
|
|
2226
2406
|
" doctor [--json] 只读体检:插件面各面状态 + 判据 + 处置建议(不打扰、不耗额度)",
|
|
2227
2407
|
" progress 项目进度 + ETA:区间 + 置信度 + 归因 + 阻塞项(不给单点数字)",
|
|
2228
2408
|
" tell <peer> <内容> 人侧给对端 agent 下指令(--kind ask|task|notify;缺省 ask)",
|
|
2409
|
+
" assistant on 打开常驻助理(7×24;后台装,不阻塞会话;装完看 assistant status)",
|
|
2410
|
+
" assistant off 关闭常驻助理(回执含残留终检:任务 / 进程 / 单元)",
|
|
2411
|
+
" assistant status 常驻状态:宿主 / 进程 / 心跳 / 上次联系",
|
|
2412
|
+
" assistant restart 重装常驻助理(等价于再跑一次 on)",
|
|
2229
2413
|
" help 本页",
|
|
2414
|
+
" supervisor 监督面(只读):助理在不在 / 联系时间线 / 托付 / 阻塞 / 预算 / 守恒等式",
|
|
2230
2415
|
"",
|
|
2231
2416
|
"【配置键速查】(详表见 <安装目录>/README.md「配置」)",
|
|
2232
2417
|
" enabled 主动性总开关(默认 true)",
|