@shgroup/dsh-serenity-hooks 1.32.0 → 1.34.1

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.
Files changed (100) hide show
  1. package/README.md +12 -11
  2. package/dsh.plugin.json +5 -5
  3. package/lib/acp-core.d.ts +2 -22
  4. package/lib/acp-http.d.ts +8 -0
  5. package/lib/api.d.ts +12 -4
  6. package/lib/autopilot-chain.d.ts +76 -0
  7. package/lib/autopilot-core-DCRkiWEe.js +229 -0
  8. package/lib/autopilot-core.d.ts +132 -0
  9. package/lib/autopilot-ops.d.ts +48 -0
  10. package/lib/autopilot-trajectory-D9Znxo75.js +782 -0
  11. package/lib/autopilot-trajectory.d.ts +79 -83
  12. package/lib/{ccc-DAsSHsub.js → ccc-NlLr_sxy.js} +18 -2
  13. package/lib/ccc-roots-Bd_SjEs7.js +152 -0
  14. package/lib/ccc-roots.d.ts +105 -0
  15. package/lib/ccc.d.ts +23 -6
  16. package/lib/client.js +30 -10
  17. package/lib/clock-runtime.d.ts +197 -0
  18. package/lib/config-ops.d.ts +9 -14
  19. package/lib/constants.d.ts +0 -2
  20. package/lib/container-status.d.ts +183 -0
  21. package/lib/diag-ops.d.ts +76 -0
  22. package/lib/face-host.d.ts +110 -0
  23. package/lib/fs-ops.d.ts +3 -2
  24. package/lib/gateway-auth.d.ts +2 -5
  25. package/lib/gateway.d.ts +0 -34
  26. package/lib/git-ops.d.ts +3 -2
  27. package/lib/handyman-ops.d.ts +3 -2
  28. package/lib/handyman-preset-inherit.d.ts +2 -1
  29. package/lib/host/access.d.ts +8 -7
  30. package/lib/host/contract.d.ts +17 -6
  31. package/lib/host/type-contract.d.ts +1 -2
  32. package/lib/im-bridge.d.ts +6 -5
  33. package/lib/index.d.ts +1 -1
  34. package/lib/index.js +11053 -8305
  35. package/lib/invariant.d.ts +5 -16
  36. package/lib/invariant.js +8 -4
  37. package/lib/json.d.ts +1 -1
  38. package/lib/kit-ops.d.ts +11 -31
  39. package/lib/localstore-ops.d.ts +3 -17
  40. package/lib/msm-ops.d.ts +34 -52
  41. package/lib/opencode-provider.d.ts +4 -5
  42. package/lib/output-guard-seam.d.ts +1 -4
  43. package/lib/output-guard.d.ts +12 -3
  44. package/lib/ports.d.ts +59 -0
  45. package/lib/rebuild.d.ts +5 -4
  46. package/lib/seams/bootstrap.d.ts +4 -3
  47. package/lib/seams/compact.d.ts +2 -1
  48. package/lib/seams/context.d.ts +2 -4
  49. package/lib/seams/env.d.ts +2 -1
  50. package/lib/seams/guards.d.ts +22 -34
  51. package/lib/seams/keeper.d.ts +4 -4
  52. package/lib/seams/system-prompt.d.ts +1 -5
  53. package/lib/session-cleanup.d.ts +3 -2
  54. package/lib/{settings-section-Bm-xG-NR.js → settings-section-DTYZjwUs.js} +70 -15
  55. package/lib/settings-section.d.ts +14 -35
  56. package/lib/skiff-core.d.ts +5 -10
  57. package/lib/skiff-debug.d.ts +15 -21
  58. package/lib/skiff-registry-FTjoWQTQ.js +25 -0
  59. package/lib/skiff-registry.d.ts +2 -1
  60. package/lib/{skiff-role-BYvNnwv1.js → skiff-role-CEHL5cek.js} +1 -1
  61. package/lib/skiff-role.d.ts +2 -2
  62. package/lib/skills/opencode-scan.d.ts +3 -2
  63. package/lib/skills-discovery.d.ts +15 -2
  64. package/lib/status.d.ts +2 -1
  65. package/lib/tools/acc-diag.d.ts +22 -0
  66. package/lib/tools/cce.d.ts +1 -2
  67. package/lib/tools/container-admin.d.ts +7 -3
  68. package/lib/tools/eap.d.ts +2 -3
  69. package/lib/tools/handyman.d.ts +0 -29
  70. package/lib/tools/msm.d.ts +0 -4
  71. package/lib/tools/neat.d.ts +1 -2
  72. package/lib/tools/praxis.d.ts +0 -1
  73. package/lib/tools/skiff-admin.d.ts +2 -2
  74. package/lib/tools/{session.d.ts → trajectory.d.ts} +25 -17
  75. package/lib/totp.d.ts +0 -4
  76. package/lib/trajectory-assistant.d.ts +2 -1
  77. package/lib/trajectory-bound-Cax1p9ut.js +190 -0
  78. package/lib/{session-bound.d.ts → trajectory-bound.d.ts} +5 -6
  79. package/lib/trajectory-ops-mrXK0H0I.js +410 -0
  80. package/lib/{session-ops.d.ts → trajectory-ops.d.ts} +27 -36
  81. package/lib/trajectory-skills.d.ts +71 -0
  82. package/lib/wake-registry-CYxIb484.js +257 -0
  83. package/lib/wake-registry.d.ts +3 -11
  84. package/lib/wake-scheduler.d.ts +23 -20
  85. package/lib/web-fetch-provider.d.ts +0 -21
  86. package/lib/{weixin-api-PjEhmjlZ.js → weixin-api-CtFYm53S.js} +3 -9
  87. package/lib/weixin-api.d.ts +6 -37
  88. package/lib/weixin-bridge.d.ts +5 -24
  89. package/lib/weixin-hook.d.ts +6 -12
  90. package/lib/weixin-output-guard.d.ts +2 -1
  91. package/lib/{weixin-route-wWk4AIwV.js → weixin-route-B2ajFypI.js} +4 -5
  92. package/lib/weixin-route.d.ts +0 -2
  93. package/lib/weixin-send-api.d.ts +15 -6
  94. package/package.json +3 -5
  95. package/experiments/autopilot-trajectory/SKILL.md +0 -115
  96. package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +0 -522
  97. package/lib/session-bound-NHozeLFc.js +0 -822
  98. package/lib/skiff-debug-K2k1JnGj.js +0 -2867
  99. package/lib/tools/autopilot-trajectory.d.ts +0 -25
  100. package/lib/{session-cleanup-CMT4mHWt.js → session-cleanup-B6IHZgww.js} +1 -1
package/README.md CHANGED
@@ -65,23 +65,23 @@ dsh plugin --profile web add link:$(pwd)/hooks/dsh-serenity-hooks
65
65
 
66
66
  ## 3. 装完之后你多了什么
67
67
 
68
- ### 3.1 十一个工具
68
+ ### 3.1 十一个工具(其中两个按条件出现)
69
69
 
70
70
  | 工具 | 干什么 | 什么时候用 |
71
71
  |---|---|---|
72
72
  | `container_fs` | 在工作区里管文件:列目录、找文件、复制、移动、新建、追加、在文件管理器里打开 | 需要看/整理工作区里的文件时 |
73
- | `logbook` | 工作日志的全生命周期:新建、查看、切换、关闭、归档,还有"原地重建" | 任何多步骤的活儿,第一步就是它 |
73
+ | `container_trajectory` | **一条轨迹**:它的身体(SESSION.md)+ 它的时间轴。建/看/切换/原地重建之外,还能登记**未来唤醒**(= 未来某时刻 + 一条消息,可唤醒自己,也可唤醒别的轨迹) | 任何多步骤的活儿,第一步就是它;想让 AI 未来某刻自动接着干也用它 |
74
74
  | `dashboard` | 仪表盘:工作区健康检查(三项)、当前时间、等待 | 进工作区先自查一下;等外部服务时用 |
75
75
  | `container_git` | git 操作:status / commit / push / log / pull / diff | 提交和推送代码;它绝不自动强推 |
76
76
  | `msm` | 小工具执行入口:`msm("名字", ["参数"])`;名字记不全就给候选;`inspect=true` 看用法 | 调用工作区里注册的任何小工具 |
77
77
  | `praxis` | 按需给 AI 注入三套"做事方法":输出自检(eap)、设计对齐(neat)、认知连续性(cce) | 要它把话说清楚 / 先对齐再动手时 |
78
78
  | `handyman` | 杂工:派一个便宜模型的助手干活。**默认模式(foreground)**= 一次串行委派、拿回结果;**background 模式**= 循环干活直到完成(完成码校验 / 轮次上限 / 自动重启 / 进度文件),也可一次派多个并行 | 大批量、重复性的活(扫描几十个技能、逐用例回归) |
79
79
  | `localstore` | 存密钥和配置(凭据、偏好两个命名空间) | API key、密码集中放一处,不进 git |
80
- | `container_admin` | 机务舱:管理子角色、管理小工具注册表、查看全部配置 | 定义"子角色"、注册新小工具时 |
81
- | `trajectory` | 轨迹管理:登记**未来唤醒**(唤醒 = 未来某时刻 + 一条消息,可唤醒自己,也可唤醒别的轨迹);定时自动巡航(到点唤醒工作区、注入当前焦点),支持多个工作区各自独立 | 想让 AI 定时自己干活、或安排它未来某刻自动接着干(见 §6.5) |
80
+ | `container_admin` | 机务舱:管理子角色、管理小工具注册表、查看全部配置,以及**定时自动巡航**(autopilot:状态 / 初始化 / 生成先验偏见) | 定义"子角色"、注册新小工具、开自动巡航时 |
82
81
  | `im-bridge` | 给 IM 联系人发消息(目前是微信):发文本、发文件、查已配置联系人、查通道状态。每次成功发送自动进工作区的消息记录 | 想让 AI 主动给家人/同事发消息(见 §6.6)。**只在工作区配了微信桥时才出现**,且只能发本工作区的消息 |
82
+ | `acc-diag` | ACC 运行态诊断:一次调用出全报告——当前有多少会话活着、各自属于哪个工作区、自动巡航的到点判断与 agent 定位、唤醒登记表的每一条、以及"这一轮为什么没被唤起"的条件链 | **ACC 维护者专用**。**默认对所有工作区隐藏**,只有在工作区配置里点名(`exclusiveTools`)才出现 |
83
83
 
84
- > **改过名**(旧名已彻底停用,没有兼容别名):`cc_fs` → `container_fs` · `cc_git` → `container_git` · `session`+`session_rebuild` → `logbook` · `acc_kit` → `dashboard` · `acc_msm` → `msm`(执行)+ `container_admin`(管理)· `eap`/`neat`/`cce` → `praxis` · `skiff_admin` → `container_admin role` · `autopilot-trajectory` → `trajectory`。老会话里看到旧名,照这张表对照即可。
84
+ > **改过名**(旧名已彻底停用,没有兼容别名):下面每组的箭头链是**逐个发布版本**的名字,**末项才是今名**——`cc_fs` → `container_fs` · `cc_git` → `container_git` · `session`+`session_rebuild` → `logbook`(v1.30/1.31)→ `trajectory`(v1.32)→ **`container_trajectory`**(v1.34,今名) · `acc_kit` → `dashboard` · `acc_msm` → `msm`(执行)+ `container_admin`(管理)· `eap`/`neat`/`cce` → `praxis` · `skiff_admin` → `container_admin role` · `autopilot-trajectory` → `trajectory`(v1.32)→ **`container_trajectory`**(v1.34,今名;其自动巡航面现归 `container_admin`)。老会话里看到旧名,**一律取所在那一组的末项**。
85
85
 
86
86
  ### 3.2 机械约束(AI 绕不过去)
87
87
 
@@ -163,7 +163,7 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
163
163
 
164
164
  | # | 你想干的事 | 实际怎么走 |
165
165
  |---|---|---|
166
- | 1 | **长期项目不断线** | `logbook create` 建日志 → 每推进一段写进去 → 中断后 `logbook use` 接上 → 上下文满了 `logbook rebuild` 原地重建并自动继续 |
166
+ | 1 | **长期项目不断线** | `container_trajectory create` 建轨迹 → 每推进一段写进去 → 中断后 `container_trajectory use` 接上 → 上下文满了 `container_trajectory rebuild` 原地重建并自动继续 |
167
167
  | 2 | **批量同步代码** | 当前仓库 `container_git commit/push`;多个子仓库一条命令全同步(自动提交 + 推送) |
168
168
  | 3 | **做一集字幕** | 搜片源 → 下载 → Whisper 转写 → 翻译 → 双语 SRT → 机械质检(7 项)→ 推送订阅/邮件 |
169
169
  | 4 | **服务器巡检** | 一条命令出 CPU/内存/GPU/容器/服务报告;重启容器也在同一条白名单通道里 |
@@ -266,7 +266,7 @@ DSH 一个进程可以同时带多个工作区,每个工作区各自对接自
266
266
 
267
267
  ### 6.5 轨迹与自主巡航(trajectory)
268
268
 
269
- `trajectory`(轨迹)是一等概念:一个工作区里可以有任意多条轨迹并行;**autopilot(自主巡航)是它的一个子集**——"周期自唤醒"的特例。
269
+ `trajectory`(轨迹)是一等概念:一个工作区里可以有任意多条轨迹并行;**autopilot(自主巡航)是它的一个子集**——"周期自唤醒"的特例(开关与控制归 `container_admin autopilot`)。
270
270
 
271
271
  **自主巡航**:让工作区**到点自己醒过来干活**,全程在你眼前发生(前台注入,随时可介入):
272
272
 
@@ -274,7 +274,8 @@ DSH 一个进程可以同时带多个工作区,每个工作区各自对接自
274
274
  - **醒了先看什么**:先看你自己写的"焦点"(`topPrompt`,每轮最先注入,防跑偏),再看随机生成的"偏见内容"(你写的脚本,负责探索方向)
275
275
  - **多个工作区各自独立**:每个工作区自己的间隔/会话/焦点/窗口,互不干扰
276
276
  - **有审计**:每次唤醒都记一笔,面板里能看到最近几次;失败会指数退避重试
277
- - **还能预约未来某一刻**:登记一条"唤醒"= 未来某时刻 + 一条消息——可以给自己预约,也可以唤醒别的轨迹;落在工作区内的 `AGENT_SESSIONS/wake-registry.json`(可读可审计),到点由中心调度器投递,不阻塞、不等待
277
+ - **还能预约未来某一刻**:用 `container_trajectory wake-later` 登记一条"唤醒"= 未来某时刻 + 一条消息——可以给自己预约,也可以唤醒别的轨迹;落在工作区内的 `AGENT_SESSIONS/wake-registry.json`(可读可审计),到点由中心调度器投递,不阻塞、不等待、也不回执
278
+ - **轨迹可以自带 skill**:在它的 `SESSION.md` 顶部 frontmatter 写 `skills: [名字, …]`,这条轨迹**被绑定期间**的每个请求都会注入这些 skill 的全文(适合把某个领域的做事方法直接挂在轨迹上);skill 名来自工作区数据,**先过安全校验才会用于拼路径**,找不到会在提示里明说"缺失"而**不静默跳过**
278
279
  - 没有"每天最多唤醒几次"的限制——频率只由间隔和窗口决定
279
280
 
280
281
  ### 6.6 安全模型
@@ -310,7 +311,7 @@ AI 一次能"记住"的内容有上限。满了不用你手动开新会话:
310
311
  | 机制 | 说人话 |
311
312
  |---|---|
312
313
  | **工作日志(SESSION.md)** | AI 的"笔记本",永远留在原地。目标、决定、进度都写这儿 |
313
- | **原地重建(logbook rebuild)** | 快满时它会提示 AI 主动重建:把这一轮对话清空,但重新注入"你是谁 + 继续 S### 的工作"——**载体换了,活儿接着干**。重建后的 token 计量也正确回落 |
314
+ | **原地重建(container_trajectory rebuild)** | 快满时它会提示 AI 主动重建:把这一轮对话清空,但重新注入"你是谁 + 继续 S### 的工作"——**载体换了,活儿接着干**。重建后的 token 计量也正确回落 |
314
315
  | **进度提醒** | 做久了会按计分提醒 AI 把进度写回日志,并要求它回确认码 |
315
316
  | **沉淀纪律** | 重建前如果产生了有价值的认知,先把它写进相关技能(而不是丢掉) |
316
317
 
@@ -347,7 +348,7 @@ pnpm build # 打包(lib/index.js + client.js)
347
348
  | 跑在 | OpenCode | DeepSeek Harness |
348
349
  | 实现 | 独立 | **独立**(不复用源码,但遵循同一套标准) |
349
350
  | 系统提示词 | `system.transform` | `systemPrompt.section`,平台无关的部分逐字对齐 |
350
- | 工具 | msm / container_fs / logbook 等 | container_fs / logbook / dashboard / container_git / msm / praxis / handyman / localstore / container_admin / trajectory / im-bridge |
351
+ | 工具 | msm / container_fs / logbook 等 | container_fs / container_trajectory / dashboard / container_git / msm / praxis / handyman / localstore / container_admin 两个条件出现的(`im-bridge` / `acc-diag`) |
351
352
 
352
353
  **同一个工作区可以随时换运行时**:`.serenity` 标记、`.opencode/skills/`、配置、`AGENT_SESSIONS/` 的文件格式都一致;
353
354
  差别只在平台层(工具名、注入方式),换过去以后 AI 收到的约束是一样的。
@@ -366,7 +367,7 @@ pnpm build # 打包(lib/index.js + client.js)
366
367
  连续失败 5 次锁 15 分钟(指数退避)。等锁过期,或检查账号的验证码绑定状态。
367
368
 
368
369
  **Q:上下文快满了怎么办?**
369
- 先让 AI 把进度写回 SESSION.md,然后按提示调用 `logbook rebuild`。轨迹会自动接续,不用手动开新会话。
370
+ 先让 AI 把进度写回 SESSION.md,然后按提示调用 `container_trajectory rebuild`。轨迹会自动接续,不用手动开新会话。
370
371
 
371
372
  **Q:对外问答页会返回内部信息吗?**
372
373
  不会。只返回答案本身,内部轨迹和工具结果都不出去。
package/dsh.plugin.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.32.0",
3
+ "version": "1.34.1",
4
4
  "main": "lib/index.js",
5
- "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/trajectory/im-bridge)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
5
+ "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag;后两个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
7
7
  "dsh": ">=0.1.5-rc.2"
8
8
  },
9
9
  "contributes": {
10
10
  "tools": [
11
11
  "container_fs",
12
- "logbook",
12
+ "container_trajectory",
13
13
  "dashboard",
14
14
  "container_git",
15
15
  "msm",
@@ -17,8 +17,8 @@
17
17
  "handyman",
18
18
  "localstore",
19
19
  "container_admin",
20
- "trajectory",
21
- "im-bridge"
20
+ "im-bridge",
21
+ "acc-diag"
22
22
  ],
23
23
  "skills": []
24
24
  }
package/lib/acp-core.d.ts CHANGED
@@ -17,14 +17,7 @@
17
17
  * 未启用时本模块零副作用(无监听、无 agent)。
18
18
  */
19
19
  import type { Context } from 'cordis';
20
- import type { SessionId } from '@deepseek-ai/dsh-session';
21
- export interface JsonRpcRequest {
22
- jsonrpc: '2.0';
23
- id?: string | number;
24
- method: string;
25
- params?: Record<string, unknown>;
26
- }
27
- export interface JsonRpcResponse {
20
+ interface JsonRpcResponse {
28
21
  jsonrpc: '2.0';
29
22
  id: string | number | null;
30
23
  result?: unknown;
@@ -34,11 +27,6 @@ export interface JsonRpcResponse {
34
27
  data?: unknown;
35
28
  };
36
29
  }
37
- export interface JsonRpcNotification {
38
- jsonrpc: '2.0';
39
- method: string;
40
- params?: Record<string, unknown>;
41
- }
42
30
  /** JSON-RPC 错误码(对齐标准) */
43
31
  export declare const RPC_ERROR: {
44
32
  readonly PARSE: -32700;
@@ -47,13 +35,6 @@ export declare const RPC_ERROR: {
47
35
  readonly INVALID_PARAMS: -32602;
48
36
  readonly INTERNAL: -32603;
49
37
  };
50
- export interface AcpSessionHandle {
51
- sessionId: string;
52
- role: string;
53
- ccc: string;
54
- /** 会话是否可复用(进程内延续) */
55
- continued: boolean;
56
- }
57
38
  /**
58
39
  * ACP 会话管理器:持有 skiff agent 会话(与 skiff-core 注册表同源——
59
40
  * 创建走 createSkiffAgent(自动注册),关闭走 unregisterSkiffSession)。
@@ -96,5 +77,4 @@ export declare class RpcInvalidParams extends Error {
96
77
  * @returns 响应帧数组(请求有响应;通知无;解析失败 → 单错误响应)
97
78
  */
98
79
  export declare function dispatchRpc(server: AcpServer, frame: unknown): Promise<JsonRpcResponse[]>;
99
- /** 断言 SessionId 类型(ACP 会话 id 即 skiff sessionId) */
100
- export type { SessionId };
80
+ export {};
package/lib/acp-http.d.ts CHANGED
@@ -17,10 +17,18 @@
17
17
  * 实验性质:未开启时零资源占用(无监听、无 agent 创建)。
18
18
  */
19
19
  import type { Context } from 'cordis';
20
+ import { type FaceSpec } from './face-host.js';
20
21
  export declare function acpHttpActive(): boolean;
21
22
  export declare function acpHttpPort(): number | null;
23
+ /**
24
+ * 本面的规格(C4 块 A/④:**只提供** name/port/host/enabled/handler)。
25
+ * 两个子面(ACP JSON-RPC / 对外问答页)的路由与鉴权仍全部归 {@link handle}——
26
+ * 面宿主不介入面语义,也**不合并** D/E 两面(两者共用会话核心但各有独立 listener/路由/HTML)。
27
+ */
28
+ export declare function acpHttpSpec(ctx: Context, port: number, defaultRoot?: string): FaceSpec;
22
29
  /**
23
30
  * 启动 ACP HTTP JSON-RPC + 建议问答页服务(单实例;重复启动幂等返回既有实例)。
31
+ * C4 块 A:listener 的创建/监听/错误/端口占用/关闭归 `face-host`。
24
32
  * @param ctx 插件上下文(AcpServer 内部经 skiff-core 创建 agent)
25
33
  * @param port 监听端口(仅 127.0.0.1)
26
34
  * @param defaultRoot 默认 CCC 根(问答页候选发现兜底;resolveSkiffRoot 传入)
package/lib/api.d.ts CHANGED
@@ -10,13 +10,11 @@
10
10
  * 经 ctx.webServer(webserver 服务,公开版由 httpServer 改名)注册;客户端与服务器同源,调用无信任围栏问题。
11
11
  */
12
12
  import type { Context } from 'cordis';
13
+ import type { IncomingMessage } from 'node:http';
13
14
  /** 图片落盘目录(CCC 根相对;S142 图片自动识别基础设施——粘贴图片落盘供 agent 经 CCC vlm MSM 自主处理) */
14
15
  export declare const IMAGE_UPLOAD_DIR = "_tmp/images_from_user";
15
- export declare const IMAGE_MEDIA_TYPES: Set<string>;
16
16
  /** 文件落盘目录(CCC 根相对;v1.24.1 粘贴任意文件自动落盘——agent 经 CCC 既有 MSM(pdf-extract/archive-extract 等)自主处理) */
17
17
  export declare const FILE_UPLOAD_DIR = "_tmp/files_from_user";
18
- /** 拒绝的可执行/危险扩展名(安全边界:不落盘可执行文件,防 agent 被诱导执行) */
19
- export declare const BLOCKED_FILE_EXTS: Set<string>;
20
18
  /**
21
19
  * 图片落盘核心逻辑(可测):校验 mediaType 白名单 + base64 解码 + 大小上限 →
22
20
  * 写 CCC 根 _tmp/images_from_user/<ts>-<rand>.<ext>,返回相对路径。
@@ -34,7 +32,16 @@ export declare function sanitizeFileName(name: string): string;
34
32
  * 校验失败抛 Error(handler 转 400)。
35
33
  */
36
34
  export declare function saveFileToTmp(root: string, fileName: string, data: string): string;
37
- export interface StatusApiRegistration {
35
+ /**
36
+ * WebUI 专属动作的来源判别(C4 块 C:此前 **9 处内联** `req.headers['x-serenity-ui'] !== '1'`)。
37
+ *
38
+ * ⚠️ 语义边界(勿误读为认证):这是**客户端判别头**——任何本机能发 HTTP 的进程都可自带它
39
+ * (无密钥、无签名、不校验来源,见现状取证 §② 面 A "认证与守卫")。它区分的是
40
+ * "WebUI 触发的动作"与"agent/curl 触发的动作"(如 safe-mode 不可由 agent 自行开关)。
41
+ * 本 helper 只做**同一判据的归一**,不放宽也不收紧:判据、状态码、文案均由调用方给出。
42
+ */
43
+ export declare function senderIsWebUi(req: IncomingMessage): boolean;
44
+ interface StatusApiRegistration {
38
45
  configPaths?: string[];
39
46
  }
40
47
  /**
@@ -45,3 +52,4 @@ export interface StatusApiRegistration {
45
52
  */
46
53
  export declare function resolveWorkspaceCore(sessionCwd: string | undefined, workspaceParam: string | undefined, listCwds: () => string[], fallback: string): string;
47
54
  export declare function registerStatusApi(ctx: Context, opts?: StatusApiRegistration): void;
55
+ export {};
@@ -0,0 +1,76 @@
1
+ /**
2
+ * autopilot-chain.ts — **唤起条件链的唯一实现**("为什么这轮没被唤起")
3
+ *
4
+ * 为什么单独成模块(R↓,⑥ C6a 的硬约束):
5
+ * C6 裁决把 autopilot 拆两半——**入口**分两处(CCC 工具面 / 开发面),但**判据只能有一份**。
6
+ * 若开发面另写"文件读取版",刚消掉的分歧会在开发面复活。故:
7
+ * · `acc-diag` ④ 段(进程内,带运行态事实)—— `./diag-ops.ts` 调 {@link buildWakeChain}
8
+ * · 开发面 `dsh-develop diag [--ccc <path>]`(离线 bun 进程,无运行态事实)—— **import 同一实现**
9
+ * 两者的差别**只是传入的 facts**(进程内三项已知 / 离线三项不可知),判据本身不复制。
10
+ *
11
+ * 本模块**零 DSH 依赖**(只 node:fs/path + `ccc.js` + `autopilot-core.js`)——离线 bun 进程
12
+ * 才 import 得动。判据一律取自 {@link judgeWake}(判据唯一真相源),本模块只做**分解与分类**。
13
+ *
14
+ * 判决语义(§12.7 修复,**不得回退**):
15
+ * `✗` = 配置/环境问题(需人改,如 enabled=false / session 未命中 / agent 未加载)
16
+ * `⏸` = 等待中(到点/出窗口/上一轮跑完自会满足——**非**配置问题)
17
+ * `?` = 不可知(离线通道看不到的运行态;**不**当成满足)
18
+ * **只有 `✗` 与 `⏸` 都为空、且无 `?` 时才印 ✅**——旧实现只统计 `✗` ⇒ 每天北京 8~18 点
19
+ * (10 小时)都印「✅ 唤起条件全部满足」而插件实际不唤起(假阳性,已实测复现)。
20
+ */
21
+ /**
22
+ * 条件链的**运行态事实**(只有插件进程知道的那部分;离线通道传 null = 不可知)。
23
+ * 由 `autopilot-trajectory.ts` 的 `autopilotRuntimeFacts(ctx, root)` 产出。
24
+ */
25
+ export interface WakeChainFacts {
26
+ /** 周期自唤醒全局闸(`autopilotGloballyEnabled()`);null = 不可知(离线通道) */
27
+ globalGate: boolean | null;
28
+ /** 该 CCC 是否已有唤起轮在进行中(重入守卫);null = 不可知 */
29
+ running: boolean | null;
30
+ /** live 运行态;null = 不可知(离线通道) */
31
+ live: {
32
+ /** 该 CCC 的 live 会话数 */
33
+ sessionCount: number;
34
+ /** 目标 agent 能否解析;null = 不适用(目标会话未命中,已由 session 条件判 ✗) */
35
+ agentResolved: boolean | null;
36
+ /** agent 不可解析时的诊断文本(`diagnoseTargetUnavailable`) */
37
+ diagnosis: string | null;
38
+ } | null;
39
+ }
40
+ /** 离线通道事实(三项运行态全不可知) */
41
+ export declare const NO_RUNTIME_FACTS: WakeChainFacts;
42
+ /** 判决档(`ready` 只有在**没有** unknowns 时才可能给出——离线通道永远不会印 ✅) */
43
+ export type WakeChainVerdict = 'ready' | 'waiting' | 'blocked' | 'unknown';
44
+ export interface WakeChainReport {
45
+ root: string;
46
+ /** 逐条件行(人读;行首 = ✓/✗/⏸/?/·) */
47
+ lines: string[];
48
+ /** `✗` 行(配置/环境问题,需人改) */
49
+ blockers: string[];
50
+ /** `⏸` 行(等待中) */
51
+ waiting: string[];
52
+ /** `?` 行(不可知——不当作满足) */
53
+ unknowns: string[];
54
+ /** 修复建议(仅在存在阻断点时输出) */
55
+ suggestions: string[];
56
+ verdict: WakeChainVerdict;
57
+ /** 判决行原文 */
58
+ judgement: string;
59
+ }
60
+ /** 运行偏见脚本的注入点(测试可替换;生产 = `fetchBiasContent`——插件 tick 的同一执行路径) */
61
+ export type BiasProbe = (root: string, providerRel: string) => Promise<{
62
+ text: string | null;
63
+ error: string | null;
64
+ }>;
65
+ /**
66
+ * 组装条件链(**唯一实现**)。
67
+ *
68
+ * @param root CCC 根
69
+ * @param facts 运行态事实(离线通道传 {@link NO_RUNTIME_FACTS})
70
+ * @param now 当前时刻(测试注入)
71
+ * @param biasProbe 偏见执行(默认 {@link fetchBiasContent}——**不另写 spawn**)
72
+ * @returns 结构化报告(渲染见 {@link renderWakeChain})
73
+ */
74
+ export declare function buildWakeChain(root: string, facts?: WakeChainFacts, now?: number, biasProbe?: BiasProbe): Promise<WakeChainReport>;
75
+ /** 条件链渲染(④ 段文本;`renderAccDiag` 与开发面 `diag` 共用) */
76
+ export declare function renderWakeChain(r: WakeChainReport): string;
@@ -0,0 +1,229 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { h as resolveInside, s as loadSerenityConfig } from "./ccc-NlLr_sxy.js";
3
+ import { m as sessionsRoot, o as findSession } from "./trajectory-ops-mrXK0H0I.js";
4
+ import { basename, dirname, join } from "node:path";
5
+ import { existsSync, readFileSync, statSync } from "node:fs";
6
+ import { spawnSync } from "node:child_process";
7
+ //#region src/autopilot-core.ts
8
+ /**
9
+ * autopilot-core.ts — autopilot **纯判据层**(零 DSH 依赖,可独立单测、可被开发面脚本 import)
10
+ *
11
+ * 为什么单独成模块(R↓,S142 §12.13 ⑥ C6a):
12
+ * C6 裁决把 autopilot 拆两半——**机制那半**(配置读写 / 状态报告 / 偏见执行 / 唤起判据)
13
+ * 进插件进程,**排障那半**(完整条件链)留开发面。但两侧**必须用同一份判据**——若各自
14
+ * 实现一遍,"为什么这轮没唤起"的报告就会与实际唤起行为分歧(这正是旧
15
+ * `experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts` 的病:它只能读文件,
16
+ * 看不到 live 会话 / 全局闸 / agent 可解析性 ⇒ 8 项结构性分歧)。
17
+ *
18
+ * ⇒ 本模块承载**判据原语**(读配置 / 目标定位 / 间隔+窗口判决 / 偏见脚本执行),
19
+ * 由三个消费方共用,**没有任何一方自算**:
20
+ * · tick 与面板 —— `autopilot-trajectory.ts`(`shouldWake` / `getAutopilotStatus`)
21
+ * · CCC 工具面 —— `autopilot-ops.ts`(`container_admin autopilot status|init|generate-bias`)
22
+ * · 条件链报告 —— `autopilot-chain.ts`(`acc-diag` ④ 段 + 开发面 `dsh-develop diag`)
23
+ *
24
+ * 本模块**零 DSH 依赖**(只 node:fs/path/child_process + `ccc.ts` + `trajectory-ops.ts`)
25
+ * ——这是刻意的:开发面 `dsh-develop diag` 是独立 bun 进程,import 不了 cordis/DSH 面。
26
+ */
27
+ var autopilot_core_exports = /* @__PURE__ */ __exportAll({
28
+ AUTO_DIR_SUFFIX: () => AUTO_DIR_SUFFIX,
29
+ DEFAULT_AVOID_HOURS: () => DEFAULT_AVOID_HOURS,
30
+ DEFAULT_BIAS_PROVIDER: () => DEFAULT_BIAS_PROVIDER,
31
+ LEGACY_BIAS_PROVIDER: () => LEGACY_BIAS_PROVIDER,
32
+ MIN_INTERVAL_HOURS: () => MIN_INTERVAL_HOURS,
33
+ MOTIVATION_MARKER: () => MOTIVATION_MARKER,
34
+ TICK_MINUTES: () => 5,
35
+ TICK_MS: () => TICK_MS,
36
+ beijingHour: () => beijingHour,
37
+ biasProviderAbsPath: () => biasProviderAbsPath,
38
+ fetchBiasContent: () => fetchBiasContent,
39
+ inAllowedWakeWindow: () => inAllowedWakeWindow,
40
+ isAutopilotSession: () => isAutopilotSession,
41
+ judgeWake: () => judgeWake,
42
+ readAutopilotSettings: () => readAutopilotSettings,
43
+ readSelfGeneratedMotivation: () => readSelfGeneratedMotivation,
44
+ readUtf8: () => readUtf8,
45
+ resolveTargetMd: () => resolveTargetMd,
46
+ shouldWake: () => shouldWake
47
+ });
48
+ /** 偏见内容提供者脚本缺省名(CCC 根目录下;正式版 autopilot-bias.ts) */
49
+ const DEFAULT_BIAS_PROVIDER = "autopilot-bias.ts";
50
+ /** 旧默认偏见脚本名(autotrajectory 时代;未显式配置时回退——pangu 等已配置 CCC 零迁移) */
51
+ const LEGACY_BIAS_PROVIDER = "autotrajectory-bias.ts";
52
+ /** 自主轨迹会话目录后缀标志(--auto 保留——简短且历史会话 S060--auto 已存在) */
53
+ const AUTO_DIR_SUFFIX = "--auto";
54
+ /** 调度 tick 周期(5min——用户"tick改为5分钟吧";0.01h 间隔下每 5min 评估一次) */
55
+ const TICK_MS = 3e5;
56
+ /** 间隔下限(支持小数——用户"让它支持小数行吗,这样可以配0.01";0.01h ≈ 36s) */
57
+ const MIN_INTERVAL_HOURS = .01;
58
+ /** SESSION.md 内「下一轮动机」段标记(自生偏见载体——轨迹预设自己的未来) */
59
+ const MOTIVATION_MARKER = "下一轮动机";
60
+ /** 缺省避开的高峰时段(北京时间 [start, end) 不唤起——用量峰谷省钱) */
61
+ const DEFAULT_AVOID_HOURS = {
62
+ start: 8,
63
+ end: 18
64
+ };
65
+ /** 偏见脚本输出上限(沙箱:截断防失控——正式版 v1.27.4) */
66
+ const BIAS_OUTPUT_MAX = 8192;
67
+ /** 偏见脚本执行超时(正式版沙箱;原 600s 过长阻塞 tick) */
68
+ const BIAS_RUN_TIMEOUT_MS = 6e4;
69
+ /** 读配置:`trajectory.autopilot`(D58 新键)优先 → 旧键 autopilotTrajectory → 旧键 autotrajectory */
70
+ function readAutopilotSettings(root) {
71
+ const cfg = loadSerenityConfig(root);
72
+ return cfg.trajectory?.autopilot ?? cfg.autopilotTrajectory ?? cfg.autotrajectory ?? null;
73
+ }
74
+ /**
75
+ * 北京时间(UTC+8)当前小时——不依赖服务器时区(服务器可能 UTC/本地任意)。
76
+ */
77
+ function beijingHour(nowMs) {
78
+ return Math.floor((nowMs + 288e5) % 864e5 / 36e5);
79
+ }
80
+ /**
81
+ * 唤起窗口判定:北京时间 [avoidStart, avoidEnd) 内不唤起(缺省 8~18)。
82
+ * 单段避开(start<=end):窗口 = [0,start) ∪ [end,24);跨零点避开(start>end):窗口 = [end,start)。
83
+ */
84
+ function inAllowedWakeWindow(nowMs, avoid) {
85
+ const start = avoid?.start ?? DEFAULT_AVOID_HOURS.start;
86
+ const end = avoid?.end ?? DEFAULT_AVOID_HOURS.end;
87
+ const h = beijingHour(nowMs);
88
+ if (start <= end) return h < start || h >= end;
89
+ return h >= end && h < start;
90
+ }
91
+ /** 标志位判定:SESSION.md 所在目录名以 --auto 结尾 → 自主轨迹形态 */
92
+ function isAutopilotSession(mdPath) {
93
+ return basename(dirname(mdPath)).endsWith(AUTO_DIR_SUFFIX);
94
+ }
95
+ /**
96
+ * 目标会话定位:**必须配置 cfg.session**(S###/目录名)——CCC 日常有多条 trajectory 在跑,
97
+ * 绝不默认唤起(缺省最近活跃会误伤其他正在运行的轨迹;用户拍板:必须配置才生效)。
98
+ * 未配置 session 或未命中 → null(不唤起)。
99
+ */
100
+ function resolveTargetMd(root, cfg) {
101
+ if (!cfg?.session) return null;
102
+ const found = findSession(sessionsRoot(root), cfg.session);
103
+ if (!found) return null;
104
+ const md = join(found.path, "SESSION.md");
105
+ return existsSync(md) ? md : null;
106
+ }
107
+ /**
108
+ * **唤起判据唯一真相源**(间隔 + 窗口):`shouldWake`(tick / 面板)、`autopilot-ops`
109
+ * (status/check)、`autopilot-chain`(条件链)三处共用本函数——**没有任何一方自算**。
110
+ *
111
+ * 为什么必须共用(v1.34.1 事故留档):旧实现在同一个脚本里存在**两份判断**——
112
+ * `status()` 算 `intervalOk && windowOk` 而条件链的判决行只统计 `✗` 开头项,把 `⏸`
113
+ * (间隔未到 / 高峰避开)排除在阻断之外 ⇒ **每天北京 8~18 点(10 小时)都印
114
+ * 「✅ 唤起条件全部满足」而插件实际不唤起**(假阳性,已实测复现)。合成一处后不可能再分叉。
115
+ *
116
+ * 间隔下限取 `MIN_INTERVAL_HOURS`(=0.01,与 tick 同源)。旧脚本取 `1`(`SCRIPT_MIN_INTERVAL_HOURS`)
117
+ * ——那会让配置 `intervalHours < 1` 的 CCC 在报告里**假阴性**(报"未到"而插件已唤起);
118
+ * 该分歧随独立脚本退场一并消失(报告与真实唤起行为同源,正是本轮的目标)。
119
+ */
120
+ function judgeWake(settings, mdPath, now = Date.now()) {
121
+ const interval = Math.max(MIN_INTERVAL_HOURS, settings?.intervalHours ?? 12);
122
+ let idleHours = null;
123
+ if (mdPath) try {
124
+ idleHours = (now - statSync(mdPath).mtimeMs) / 36e5;
125
+ } catch {
126
+ idleHours = null;
127
+ }
128
+ const intervalOk = idleHours !== null && idleHours >= interval;
129
+ const windowOk = inAllowedWakeWindow(now, settings?.avoidWakeHours);
130
+ return {
131
+ interval,
132
+ idleHours,
133
+ intervalOk,
134
+ windowOk,
135
+ wakeable: intervalOk && windowOk
136
+ };
137
+ }
138
+ /**
139
+ * 唤起条件(纯逻辑,可测):enabled + 未在运行 + 目录标志 + mtime 超间隔 + 窗口允许。
140
+ * v1.27.12:移除每日唤起预算上限(用户"把这个上限删了吧,没意义"——高频实验不受限)。
141
+ *
142
+ * 判据来源全部来自本模块(`judgeWake` / `isAutopilotSession`)——本函数只做**组合**,
143
+ * 不重复实现时间/窗口计算。
144
+ */
145
+ function shouldWake(settings, mdPath, nowMs, running, _history = []) {
146
+ if (!settings?.enabled || running) return false;
147
+ if (!mdPath || !isAutopilotSession(mdPath)) return false;
148
+ return judgeWake(settings, mdPath, nowMs).wakeable;
149
+ }
150
+ /** 自生动机读取:SESSION.md「下一轮动机」段内容(到下一个二级标题或文件尾;无 → null) */
151
+ function readSelfGeneratedMotivation(mdPath) {
152
+ try {
153
+ const content = readFileSync(mdPath, "utf-8");
154
+ const idx = content.indexOf(MOTIVATION_MARKER);
155
+ if (idx < 0) return null;
156
+ const rest = content.slice(idx + 5);
157
+ const nextHeading = rest.search(/\n## /);
158
+ return (nextHeading >= 0 ? rest.slice(0, nextHeading) : rest).trim() || null;
159
+ } catch {
160
+ return null;
161
+ }
162
+ }
163
+ /**
164
+ * 偏见内容:直接运行 CCC 根目录下偏见提供者脚本(biasProvider,缺省 autopilot-bias.ts;
165
+ * 未显式配置且新默认缺失 → 回退旧默认 autotrajectory-bias.ts——pangu 兼容)→ stdout。
166
+ * 脚本缺失 → 返回 { text: null, error: 提示实现 }(唤起侧报错要求实现,不静默跳过)。
167
+ * 路径逃逸校验(resolveInside);bun 优先,node 兜底;**60s 超时 + 8KB 输出截断(沙箱)**。
168
+ *
169
+ * 唯一执行点(不另写 spawn):tick 的唤起路径(`performAutopilotWake`)、`container_admin
170
+ * autopilot generate-bias`、条件链的偏见就绪探测**三处都调本函数**(§12.13:`random` → 复用
171
+ * 插件 tick 里既有的偏见执行代码)。旧脚本另有一套 spawn 且**参数不同**(600s 超时、无 8KB
172
+ * 截断、无旧默认名回退)⇒ 那是"bias 运行参数"与"仅存旧名 bias 脚本时报假阴性"两项分歧的由来。
173
+ */
174
+ async function fetchBiasContent(root, providerRel) {
175
+ let scriptAbs;
176
+ try {
177
+ scriptAbs = resolveInside(root, providerRel);
178
+ } catch {
179
+ return {
180
+ text: null,
181
+ error: `biasProvider 路径逃逸(须在 CCC 根内): ${providerRel}`
182
+ };
183
+ }
184
+ if (!existsSync(scriptAbs) && providerRel === "autopilot-bias.ts") {
185
+ const legacy = resolveInside(root, LEGACY_BIAS_PROVIDER);
186
+ if (existsSync(legacy)) scriptAbs = legacy;
187
+ }
188
+ if (!existsSync(scriptAbs)) return {
189
+ text: null,
190
+ error: `请在 CCC 根目录实现偏见内容提供者脚本: ${providerRel}(或旧默认 ${LEGACY_BIAS_PROVIDER};stdout 输出偏见内容一行;container_admin autopilot init 可生成模板)`
191
+ };
192
+ const runs = [["bun", [scriptAbs]], [process.execPath, [scriptAbs]]];
193
+ for (const [cmd, args] of runs) try {
194
+ const r = spawnSync(cmd, args, {
195
+ encoding: "utf-8",
196
+ timeout: BIAS_RUN_TIMEOUT_MS,
197
+ stdio: [
198
+ "ignore",
199
+ "pipe",
200
+ "pipe"
201
+ ]
202
+ });
203
+ if (r.status === 0) return {
204
+ text: (r.stdout ?? "").trim().slice(0, BIAS_OUTPUT_MAX) || null,
205
+ error: null
206
+ };
207
+ if (r.error?.code === "ENOENT") continue;
208
+ return {
209
+ text: null,
210
+ error: `偏见内容提供者脚本执行失败(exit ${r.status ?? "?"}): ${r.stderr?.trim() || r.stdout?.trim() || ""}`
211
+ };
212
+ } catch {
213
+ continue;
214
+ }
215
+ return {
216
+ text: null,
217
+ error: "偏见内容提供者脚本无法运行(bun 与 node 均不可用)"
218
+ };
219
+ }
220
+ /** 偏见提供者脚本绝对路径(根内强制——逃逸拒绝);供文件写入侧(init 生成模板)使用 */
221
+ function biasProviderAbsPath(root, providerRel) {
222
+ return resolveInside(root, providerRel);
223
+ }
224
+ /** 读 UTF-8(去 BOM)——init 写配置前的读回 */
225
+ function readUtf8(p) {
226
+ return readFileSync(p, "utf-8").replace(/^\uFEFF/, "");
227
+ }
228
+ //#endregion
229
+ export { shouldWake as _, TICK_MS as a, biasProviderAbsPath as c, isAutopilotSession as d, judgeWake as f, resolveTargetMd as g, readUtf8 as h, MIN_INTERVAL_HOURS as i, fetchBiasContent as l, readSelfGeneratedMotivation as m, DEFAULT_AVOID_HOURS as n, autopilot_core_exports as o, readAutopilotSettings as p, DEFAULT_BIAS_PROVIDER as r, beijingHour as s, AUTO_DIR_SUFFIX as t, inAllowedWakeWindow as u };