@shgroup/dsh-serenity-hooks 1.42.0 → 1.43.0

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/lib/index.js CHANGED
@@ -2,12 +2,12 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { a as hostSettings, c as hostWebServer, i as hostSessions, n as hostInjected, o as hostSubagents, r as hostService, s as hostWeb, t as hostAgents } from "./access-fiehjxV6.js";
3
3
  import { a as findSerenityRoot, c as matchBlacklist, d as readCccName$1, f as readExclusiveTools, h as resolveInside, i as findGitRoot, l as pathInside, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readHandymanConfig, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-NlLr_sxy.js";
4
4
  import { i as cccRootForExec, n as agentCwdFor, o as listCccs, r as cccRootForCwd, t as NO_CCC_FROM_AGENT_CWD } from "./ccc-roots-Bd_SjEs7.js";
5
- import { C as summarize, E as localFileStamp, S as showSession, T as isoLocal, _ as readActiveSessionMd, a as resolveSessionTrajectoryLabel, b as sessionsRoot, c as DEFAULT_SESSION_SCOPE, d as createSession, f as extractSessionMdPathFromText, g as parseSessionContextFromEvents, h as listSessions, i as readLastBound, l as TRAJECTORY_ACTIONS, m as getActiveSessionInfo, o as setBindingStore, p as findSession, r as pruneMissingBindings, s as supersedeOtherBindings, t as appendBound, u as clearActiveSessionInfo, v as resolveSessionByTitle, w as useSession, x as setActiveSessionInfo, y as sessionEvents$1 } from "./trajectory-bound-4xkZDfmO.js";
5
+ import { C as summarize, E as localFileStamp, S as showSession, T as isoLocal, _ as readActiveSessionMd, a as resolveSessionTrajectoryLabel, b as sessionsRoot, c as DEFAULT_SESSION_SCOPE, d as createSession, f as extractSessionMdPathFromText, g as parseSessionContextFromEvents, h as listSessions, i as readLastBound, l as TRAJECTORY_ACTIONS, m as getActiveSessionInfo, o as setBindingStore, p as findSession, r as pruneMissingBindings, s as supersedeOtherBindings, t as appendBound, u as clearActiveSessionInfo, v as resolveSessionByTitle, w as useSession, x as setActiveSessionInfo, y as sessionEvents$1 } from "./trajectory-bound-kxvMuCui.js";
6
6
  import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-B2ajFypI.js";
7
7
  import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-CEHL5cek.js";
8
8
  import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-FTjoWQTQ.js";
9
9
  import { r as sessionsRootDir, t as hasSessionLogById } from "./session-cleanup-BtkSmry8.js";
10
- import { a as WAKE_CATCH_UP_MS, i as registerDisposer, n as sendToTrajectory, o as addWake, r as wakeSchedulerState, s as listWakes, t as registerWakeScheduler } from "./wake-scheduler-1AsvNQPW.js";
10
+ import { a as registerDisposer, c as addWake, i as registerCroTurnTracking, l as listWakes, n as sendToTrajectory, o as buildCroSnapshot, r as wakeSchedulerState, s as WAKE_CATCH_UP_MS, t as registerWakeScheduler } from "./wake-scheduler-DC4-imVO.js";
11
11
  import { a as FACE_PORTS, c as MECHANISM_PORTS, i as ACP_HTTP_PORT, l as SKIFF_DEBUG_PORT, n as registerSettingsSection, o as GATEWAY_PORT, s as MAIN_WEB_PORT, t as readSimpleSettings, u as WEIXIN_SEND_PORT } from "./settings-section-DMDUoQum.js";
12
12
  import { a as markdownToPlainText, c as sendTyping, i as getUpdates, l as sniffImageExt, n as downloadMedia, o as sendFileMessage, r as getConfig, s as sendTextMessage, t as TypingStatus } from "./weixin-api-CtFYm53S.js";
13
13
  import z from "@deepseek-ai/schemastery";
@@ -956,7 +956,8 @@ const NPX_BIN = process.platform === "win32" ? "npx.cmd" : "npx";
956
956
  const ACC_CATALOG = `═══ ACC Usage Catalog ═══
957
957
  Directory of ACC capabilities — each area lists where to go for details (guides live with their feature; this catalog only points).
958
958
 
959
- ① 轨迹本体 → container_trajectory(list/show/create/use + rebuild 超限重建 + send-now 即时投递 + send-later 未来一次性唤醒)
959
+ ① 轨迹本体 → container_trajectory(list/show/create/use + rebuild 超限重建 + send-now 即时投递 + send-later 未来一次性唤醒
960
+ + cro-guide CRO 编写指南)
960
961
  原 logbook 已并入(v1.33 用户裁决:废除 logbook 词);close/archive 删(归档走 container_fs mv),
961
962
  health/qa/summary 分别并入 use / list,hook-develop-guide 并进 container_admin msm guide
962
963
  ② 认知质量框架 → praxis(eap/neat/cce 三合一——可实践理论注入,section 渐进披露,无参即目录)
@@ -3010,6 +3011,205 @@ function createHandymanTool(ctx) {
3010
3011
  });
3011
3012
  }
3012
3013
  //#endregion
3014
+ //#region src/cro-guide.ts
3015
+ /**
3016
+ * cro-guide.ts — CRO 编写指南(**ACC 内置**,S142 §7.8,2026-09-19)
3017
+ *
3018
+ * ## 为什么指南在 ACC 而不在 CCC(所有者令)
3019
+ *
3020
+ * 所有者 2026-09-19:「**ACC 内置,整个机制属于 ACC,CCC 是用户**」。
3021
+ * ⇒ 契约 / 调度 / 执行 / 状态暴露 / 容错 / **编写指南** 全在 ACC;
3022
+ * CCC(用户)只负责**写那段程序**。
3023
+ *
3024
+ * ## 🔴 单真相源纪律(本文件的核心约束)
3025
+ *
3026
+ * 指南**不复制**契约条款,且**样例快照是"派生"而非"手抄"**:
3027
+ * {@link CRO_SAMPLE_SNAPSHOT} 由 {@link buildCroSnapshot} **真正装配**出来 ⇒
3028
+ * **schema 一变,样例自动跟着变**,不存在"文档里的样例过期"这一失效模式。
3029
+ * (本容器栽过多次"第二真相源",此处用代码结构而不是纪律去防它。)
3030
+ *
3031
+ * ## 所有者对本指南的两条明示要求(2026-09-19)
3032
+ *
3033
+ * 1. 🔴 **必须备注:CRO 程序是可自测的;测试通过再把文件名改成正式名**;
3034
+ * 2. 🔴 **要一并给出测试用的参数**。
3035
+ */
3036
+ /**
3037
+ * 样例快照输入 —— **代表性数据**(不是真实某条轨迹的现状)。
3038
+ *
3039
+ * 取值刻意让它能演示所有者举的 S185 场景(天亮/有人/非高峰 + 已在干活 + 日志过大)。
3040
+ */
3041
+ const CRO_SAMPLE_SNAPSHOT_INPUT = {
3042
+ dirName: "2026-09-13--S185--desk-camera",
3043
+ cccRoot: "/home/yh/home/home-serenity",
3044
+ nowMs: 17898e8,
3045
+ sessionMdPath: "/home/yh/home/home-serenity/AGENT_SESSIONS/2026-09-13--S185--desk-camera/SESSION.md",
3046
+ sessionMdBytes: 182e3,
3047
+ sessionMdMtimeMs: 1789799e6,
3048
+ references: [{
3049
+ name: "campaign-100.md",
3050
+ bytes: 41200,
3051
+ mtimeMs: 178979e7
3052
+ }, {
3053
+ name: "auto-exposure.md",
3054
+ bytes: 8400,
3055
+ mtimeMs: 17897e8
3056
+ }],
3057
+ boundSessionIds: ["session-adccc461-9f32-4d9a-a688-9da81fa1ca35"],
3058
+ liveSessionIds: ["session-adccc461-9f32-4d9a-a688-9da81fa1ca35"],
3059
+ runningSessionIds: [],
3060
+ pendingWakes: [{
3061
+ id: "w-20260919-0900-aaaa",
3062
+ at: "2026-09-19T09:30:00+08:00",
3063
+ createdAt: "2026-09-19T07:00:00+08:00",
3064
+ createdBy: "S185"
3065
+ }],
3066
+ scheduler: {
3067
+ armed: true,
3068
+ enabled: true,
3069
+ ticks: 128,
3070
+ lastSkipReason: null
3071
+ }
3072
+ };
3073
+ /**
3074
+ * 🔴 **样例快照(测试参数)** —— **由真实装配器生成**,故**永不与 schema 漂移**。
3075
+ *
3076
+ * 用途:写 CRO 程序时把它喂给你的程序做自测(见指南 §8「自测」)。
3077
+ * @returns 缩进过的快照 JSON 文本
3078
+ */
3079
+ function renderCroSampleSnapshot() {
3080
+ return JSON.stringify(buildCroSnapshot(CRO_SAMPLE_SNAPSHOT_INPUT), null, 2);
3081
+ }
3082
+ /**
3083
+ * CRO 编写指南正文(ACC 内置手册;由工具的 guide 动作输出)。
3084
+ *
3085
+ * 结构照既有 guide 惯例(`MSM_GUIDE` / `handyman(guide=true)`):
3086
+ * 用途 → 位置 → 我给什么 → 你给我什么 → 骨架 → 常见模式 → 坑 → **自测**。
3087
+ */
3088
+ const CRO_GUIDE = `CRO(Continuous Re-Occurrence · 持续再发生)编写指南
3089
+
3090
+ ## 0. 这是什么(一句话)
3091
+ 让一条轨迹**自己带一段程序**,由 ACC 在每次检查时跑它,
3092
+ **由这段程序决定「现在该不该叫我、叫我的时候说什么」**。
3093
+
3094
+ 今天的唤醒只认时间("3 点叫我");CRO 让它认**情况**("天亮且家里有人才叫我")。
3095
+
3096
+ ## 1. 它在系统里的位置
3097
+ · **机制属 ACC**(本指南、契约、调度、执行、容错都在 ACC)
3098
+ · **程序属 CCC**(你写的那段 TS,放在**你自己轨迹的目录**里)
3099
+ · **执行者** = ACC 的唤醒调度器(每 5 分钟一次 tick)
3100
+
3101
+ ## 2. 文件放哪、叫什么
3102
+ <CCC 根>/AGENT_SESSIONS/<轨迹目录>/continuous-re-occurrence.ts
3103
+
3104
+ 🔴 **文件名必须全写**(不许用缩写)。
3105
+ 🔴 **程序只有一个**:**文件在 = 启用;文件不在 = 禁用**。
3106
+ —— 没有开关、没有注册表、没有 enabled 字段。
3107
+
3108
+ ## 3. 我给你什么(输入)
3109
+ ACC 把这条轨迹的状态做成一个 **JSON 快照**,从 **stdin** 喂给你的程序。
3110
+ 字段分四组:identity(身份)/ time(时间)/ body(轨迹身体)/ binding + scheduling(绑定与调度)。
3111
+
3112
+ ⚠️ **给的是"快照",不是"无限能力"**:ACC 看不见的东西(比如"你上次判了什么")
3113
+ **物理上给不了**(那是你进程里的内存)。那类状态**归你自己**——
3114
+ 写在你自己的轨迹目录里(例如一个 state.json),自己读自己写。
3115
+
3116
+ ## 4. 你给我什么(输出)
3117
+ 向 **stdout** 写 **一行 JSON**:
3118
+
3119
+ { "wake": true, "prompt": "唤起时的提示词", "reason": "判定理由(可选)" }
3120
+ { "wake": false } // 不唤起
3121
+
3122
+ · \`wake\` 缺省 / false ⇒ **不唤起**(**这是常态**,缺省是"不打扰")
3123
+ · \`wake: true\` 时 \`prompt\` **必须非空**(否则视为非法,本轮跳过、不投递空消息)
3124
+ · 🔴 \`reason\` **强烈建议填**:见 §7 坑 3
3125
+
3126
+ ## 5. 骨架
3127
+
3128
+ // continuous-re-occurrence.ts
3129
+ let raw = ''
3130
+ process.stdin.on('data', (d) => { raw += d })
3131
+ process.stdin.on('end', () => {
3132
+ const s = JSON.parse(raw) // 轨迹状态快照
3133
+ // ... 在这里写你的判定 ...
3134
+ process.stdout.write(JSON.stringify({ wake: false }))
3135
+ })
3136
+
3137
+ 例(所有者举的 S185 那类情形,仅示意):
3138
+
3139
+ const tooBig = (s.body.sessionMdBytes ?? 0) > 150_000
3140
+ const busy = s.binding.runningSessionIds.length > 0
3141
+ if (busy) return out({ wake: false, reason: '已在干活' })
3142
+ if (tooBig) return out({ wake: true, prompt: '你的 SESSION.md 已很大,请先压缩再继续。', reason: '日志超限' })
3143
+
3144
+ ## 6. 常见模式
3145
+ · **环境谓词**(天亮/有人/非高峰):ACC 给不了这些 —— **你自己去拿**(查设备、读传感器、
3146
+ 查你自己的程序)。这就是"程序和程序可以互相访问"的用法。快照里的 \`time\` 只是给你一个时间锚。
3147
+ · **已在工作就别叫**:看 \`binding.runningSessionIds\`(非空 = 有载体正在跑轮次)。
3148
+ ⚠️ 注意它和 \`liveSessionIds\` 不同:**会话活着 ≠ 在干活**。
3149
+ · **要求它先自整理**:不需要新机制 —— **就是 \`prompt\` 的一种写法**
3150
+ (如"你的 SESSION.md 已 180 KB,请先压缩再继续")。
3151
+ · **次数上限 / 连续 N 次才叫**:ACC 不给你计数器(**给不了**)⇒ **自己目录里写状态文件**。
3152
+
3153
+ ## 7. 坑
3154
+ 1. **不许阻塞等输入**:你只从 stdin 拿一次快照,不要在程序里 readline / prompt 等用户输入。
3155
+ 2. **硬超时 60 秒**:超时会被 SIGKILL、本轮跳过。外部查询请自己设更短的超时。
3156
+ 3. 🔴 **一定要填 \`reason\`**:改成程序判定之后,"当时为什么叫了"**不再能从时间表重建**——
3157
+ 原因在**你的程序肚子里**(可能有随机、可能看了外部数据)。不写 reason,
3158
+ 以后出事**无法复现**。这条不是形式主义,是**可重建性**的要求。
3159
+ 4. **失败只影响你自己**:程序报错/超时/输出非法 ⇒ 记一行 + **跳过本轮**,
3160
+ **绝不会影响** \`send-later\` / \`send-now\` 等既有机制。所以你可以放心试。
3161
+ 5. 🔴 **不要提前用正式文件名**:见 §8。
3162
+
3163
+ ## 8. 🔴 自测(**测试通过再把文件名改成正式的**)
3164
+ CRO 程序**是可以自测的** —— 因为它只做一件事:**吃一份快照 JSON,吐一行决策 JSON**。
3165
+ (纯函数式的边界 ⇒ 不需要真机、不需要等 5 分钟 tick、不需要调度器。)
3166
+
3167
+ ### 8.1 推荐流程:**用开发名写,绿了再改名**
3168
+ 因为「**文件在 = 启用**」没有开关,**改名这个动作本身就是上线动作**:
3169
+
3170
+ 1. 先用**开发名**写(如 \`continuous-re-occurrence.dev.ts\`)
3171
+ —— 开发名**不会**被 ACC 启用(启用只认正式名 exact match),可以放心留一半
3172
+ 2. 配一个自测(如 \`continuous-re-occurrence.dev.test.ts\`),喂几份快照断言输出
3173
+ 3. **全部绿了** ⇒ 改名为 \`continuous-re-occurrence.ts\` ⇒ **这一刻才生效**
3174
+
3175
+ ⚠️ 若你跳过自测直接上正式名:半成品会被当成生效程序,**报错并跳过本轮**(不会搞坏系统,
3176
+ 但那条轨迹的 CRO 就是空转的)。**报错是安全网,不是工作流。**
3177
+
3178
+ ### 8.2 手工试跑(最快的一条路)
3179
+ 把样例快照喂给你的程序,看它吐什么:
3180
+
3181
+ # 用开发名试跑(推荐 bun;node 需能跑 TS)
3182
+ bun continuous-re-occurrence.dev.ts < sample-snapshot.json
3183
+
3184
+ # 或直接管道
3185
+ echo '<一行快照 JSON>' | bun continuous-re-occurrence.dev.ts
3186
+
3187
+ ### 8.3 测试用的参数
3188
+ **样例快照 = 由 ACC 的装配器实时生成**(故**永不与 schema 漂移**,schema 一变它跟着变)。
3189
+ 取法:**运行本指南所在工具的 guide 动作**,或用同一机制导出;内容是:
3190
+
3191
+ \`\`\`json
3192
+ ${renderCroSampleSnapshot()}
3193
+ \`\`\`
3194
+
3195
+ 该样例刻意覆盖了:
3196
+ · \`body.sessionMdBytes\` = 182000(**日志过大**那一档)
3197
+ · \`binding.runningSessionIds\` = [](**空闲**;把它填成一个 id 就能测"已在干活"分支)
3198
+ · \`scheduling.pendingWakes\` 非空(**已有待办唤醒**)
3199
+ · 无 S 前缀格式的情形请自己造 \`dirName\`(\`identity.code\` 会是空串——那是**正常**的,
3200
+ 编号不是固定格式,硬锚永远是 \`dirName\`)
3201
+
3202
+ ### 8.4 自测该断言什么(建议清单)
3203
+ · 快照缺字段(\`null\` 体积)时不崩 —— 用 \`?? 0\` 之类兜底
3204
+ · \`wake:true\` 时 \`prompt\` **确实非空**
3205
+ · "已在干活"分支:\`runningSessionIds\` 非空 ⇒ \`wake:false\`
3206
+ · 同一个程序**连跑两次**给同样输入 ⇒ 同样输出(除非你刻意用了随机/外部状态,
3207
+ 那就必须写进 \`reason\`)
3208
+
3209
+ ## 9. 一句话
3210
+ **吃一份快照,吐一行决策。先自测,绿了再改名。**
3211
+ `;
3212
+ //#endregion
3013
3213
  //#region src/tools/trajectory.ts
3014
3214
  /**
3015
3215
  * trajectory.ts — `container_trajectory` 真实 DSH 工具定义(defineTool)
@@ -3017,7 +3217,7 @@ function createHandymanTool(ctx) {
3017
3217
  * v1.33(S142 §32 用户裁决):由 `logbook` **更名并收敛为 `trajectory`**(v1.34:工具名再硬切为
3018
3218
  * `container_trajectory`,无别名)——trajectory 是一等概念
3019
3219
  * (SESSION.md 是它的持久身体),本工具管它的**载体生命周期 + 一次性时间安排**。
3020
- * 动作面现行 **7 个**:list / show / create / use / rebuild / **`send-now`** / **`send-later`**。
3220
+ * 动作面现行 **8 个**:list / show / create / use / rebuild / **`send-now`** / **`send-later`** / **`cro-guide`**。
3021
3221
  * 🔴 2026-09-16(所有者裁决):**第 7 个动作 `send-message`(即时投递)**
3022
3222
  * ——与 `wake-later` 共用取用通路,差别只在**时刻**(现在 vs 未来)与**回执**(有 vs 无);
3023
3223
  * 实现落在 `wake-scheduler.ts` 的 `sendToTrajectory()`("怎么把一句话送到一条轨迹"是调度器的知识)。
@@ -3040,6 +3240,9 @@ function createHandymanTool(ctx) {
3040
3240
  * `systemPrompt.section` 注入,见 `docs/trajectory-skill-injection.md`)
3041
3241
  * · autopilot 面(all/init/random/diag/doc/check/status/guide)→ `container_admin` 的 autopilot 域
3042
3242
  * · `wake-add`/`wake-list`/`wake-rm` → **`wake-later`**(v1.33 收敛;**2026-09-17 更名 `send-later`**)
3243
+ * · 2026-09-20(CRO 落地):新增 **`cro-guide`** —— CRO 编写指南的出口(纯读)。
3244
+ * 判据(R↓,为何在此而不新增域):CRO 程序放在**轨迹自己的目录**里 ⇒ "怎么写它"是
3245
+ * **逐轨迹**的知识,而管轨迹的人正是用本工具的人(设计 §9-5「既有 guide 位置,不新增域」)。
3043
3246
  *
3044
3247
  * 保留 osp 对齐语义的部分:create 的 `--desc`/`--issue` 二选一、use 激活即重命名 dsh 会话标题(F3)。
3045
3248
  * 活跃会话跟踪:内存 Map(按 dsh 会话 id 隔离)+ 从 events 恢复(S134)。
@@ -3170,13 +3373,13 @@ function renderText$3(value) {
3170
3373
  function createTrajectoryTool(ctx) {
3171
3374
  return defineTool({
3172
3375
  name: "container_trajectory",
3173
- description: "Trajectory (AGENT_SESSIONS/ — the persistent body of a trajectory; the dsh conversation is only its rebuildable carrier). Lifecycle + delivery: list (inventory with stats and anomaly marks) / show (read one SESSION.md) / create / use (activate for this conversation, with inline integrity check) / rebuild (clear-and-rebuild the current conversation in place, Ship of Theseus) / send-now (deliver ONE message to a trajectory RIGHT NOW — live: injected immediately; not live: cold-resumed, i.e. equivalent to a direct wake; returns a synchronous receipt) / send-later (schedule ONE message to any trajectory at a future instant — fire-and-forget: no receipt, no recall, no panel). create requires --desc <desc> [--goal] or --issue <ticket> (exactly one) plus --summary (≤20 chars). use requires --summary (≤20 chars) and may pass --force to switch away from the currently-bound trajectory. rebuild requires --summary (next-phase summary ≤20 chars) + optional --note (task focus for the rebuilt self). send-later requires target (S### or AGENT_SESSIONS dir name) + at (RFC3339 or +30m/+2h) + message. send-now requires target + message. It delivers IMMEDIATELY (never queued behind the current turn): a busy target is steered mid-turn so it reads the message in the CURRENT turn, and an idle target starts a turn right away. Its receipt means the message was injected into the target (it does NOT mean the target ran or replied). The summary is appended to the dsh session title (S###-YYYY-MM-DD-<summary>); the S### id and date stay server-derived.",
3376
+ description: "Trajectory (AGENT_SESSIONS/ — the persistent body of a trajectory; the dsh conversation is only its rebuildable carrier). Lifecycle + delivery: list (inventory with stats and anomaly marks) / show (read one SESSION.md) / create / use (activate for this conversation, with inline integrity check) / rebuild (clear-and-rebuild the current conversation in place, Ship of Theseus) / send-now (deliver ONE message to a trajectory RIGHT NOW — live: injected immediately; not live: cold-resumed, i.e. equivalent to a direct wake; returns a synchronous receipt) / send-later (schedule ONE message to any trajectory at a future instant — fire-and-forget: no receipt, no recall, no panel) / cro-guide (the CRO programming guide: how to give THIS trajectory its own program that decides when it should be woken). create requires --desc <desc> [--goal] or --issue <ticket> (exactly one) plus --summary (≤20 chars). use requires --summary (≤20 chars) and may pass --force to switch away from the currently-bound trajectory. rebuild requires --summary (next-phase summary ≤20 chars) + optional --note (task focus for the rebuilt self). send-later requires target (S### or AGENT_SESSIONS dir name) + at (RFC3339 or +30m/+2h) + message. send-now requires target + message. It delivers IMMEDIATELY (never queued behind the current turn): a busy target is steered mid-turn so it reads the message in the CURRENT turn, and an idle target starts a turn right away. Its receipt means the message was injected into the target (it does NOT mean the target ran or replied). The summary is appended to the dsh session title (S###-YYYY-MM-DD-<summary>); the S### id and date stay server-derived.",
3174
3377
  parameters: {
3175
3378
  action: {
3176
3379
  type: "string",
3177
3380
  enum: [...TRAJECTORY_ACTIONS],
3178
3381
  required: true,
3179
- description: "Subcommand: list (inventory + stats + anomaly marks) / show (S### or dir name or fuzzy keyword) / create (--desc or --issue) / use (activate context; inline integrity check — pass silent, problems reported as hints, not errors) / rebuild (clear-and-rebuild current conversation — requires --summary + optional --note) / send-now (deliver one message RIGHT NOW: live target injected immediately, non-live cold-resumed like a direct wake; returns a synchronous receipt) / send-later (one future instant + one message, delivered to target trajectory)"
3382
+ description: "Subcommand: list (inventory + stats + anomaly marks) / show (S### or dir name or fuzzy keyword) / create (--desc or --issue) / use (activate context; inline integrity check — pass silent, problems reported as hints, not errors) / rebuild (clear-and-rebuild current conversation — requires --summary + optional --note) / send-now (deliver one message RIGHT NOW: live target injected immediately, non-live cold-resumed like a direct wake; returns a synchronous receipt) / send-later (one future instant + one message, delivered to target trajectory) / cro-guide (no parameters: prints the CRO programming guide, including a ready-to-use sample snapshot)"
3180
3383
  },
3181
3384
  name: {
3182
3385
  type: "string",
@@ -3352,6 +3555,7 @@ function createTrajectoryTool(ctx) {
3352
3555
  ].join("\n")
3353
3556
  };
3354
3557
  }
3558
+ case "cro-guide": return CRO_GUIDE;
3355
3559
  default: throw new Error(`Unknown action: ${args.action}`);
3356
3560
  }
3357
3561
  }
@@ -5656,7 +5860,7 @@ function toolsBlock() {
5656
5860
  "The ACC (this plugin) provides the following built-in tools:",
5657
5861
  "",
5658
5862
  " container_fs — container filesystem operations (15 subcommands: root/resolve/exists/list/tree/relative/mkdir/rm/mv/cp/touch/append/reveal/info/find)",
5659
- " container_trajectory — one trajectory: its persistent body (SESSION.md) + its timeline. Lifecycle: list (inventory + stats) / show / create / use (activate; inline integrity check — silent when fine) / rebuild (clear-and-rebuild this conversation in place, Ship of Theseus); delivery: send-now (deliver one message RIGHT NOW; live target injected immediately, non-live cold-resumed like a direct wake — returns a synchronous receipt) / send-later (one future instant + one message to any trajectory; fire-and-forget — no receipt, no recall)",
5863
+ " container_trajectory — one trajectory: its persistent body (SESSION.md) + its timeline. Lifecycle: list (inventory + stats) / show / create / use (activate; inline integrity check — silent when fine) / rebuild (clear-and-rebuild this conversation in place, Ship of Theseus); delivery: send-now (deliver one message RIGHT NOW; live target injected immediately, non-live cold-resumed like a direct wake — returns a synchronous receipt) / send-later (one future instant + one message to any trajectory; fire-and-forget — no receipt, no recall) / cro-guide (the CRO programming guide: how to give THIS trajectory its own program that decides when it should be woken)",
5660
5864
  " dashboard — always-on container instruments: health (CCC three-principle check + registry integrity) / time (now) / wait (N seconds)",
5661
5865
  " container_git— git operations (status/commit/push/log)",
5662
5866
  " msm — execute a registered CCC MSM: msm(name, args); partial name returns candidates; inspect=true shows usage",
@@ -14958,6 +15162,7 @@ function apply(ctx, config) {
14958
15162
  registerBootstrap(ctx);
14959
15163
  registerSkiff(ctx);
14960
15164
  registerAcp(ctx);
15165
+ registerCroTurnTracking(ctx);
14961
15166
  registerWakeScheduler(ctx);
14962
15167
  registerWeixinBridge(ctx);
14963
15168
  registerWeixinSendApi(ctx);
@@ -4,7 +4,7 @@
4
4
  * v1.33(S142 §32 用户裁决):由 `logbook` **更名并收敛为 `trajectory`**(v1.34:工具名再硬切为
5
5
  * `container_trajectory`,无别名)——trajectory 是一等概念
6
6
  * (SESSION.md 是它的持久身体),本工具管它的**载体生命周期 + 一次性时间安排**。
7
- * 动作面现行 **7 个**:list / show / create / use / rebuild / **`send-now`** / **`send-later`**。
7
+ * 动作面现行 **8 个**:list / show / create / use / rebuild / **`send-now`** / **`send-later`** / **`cro-guide`**。
8
8
  * 🔴 2026-09-16(所有者裁决):**第 7 个动作 `send-message`(即时投递)**
9
9
  * ——与 `wake-later` 共用取用通路,差别只在**时刻**(现在 vs 未来)与**回执**(有 vs 无);
10
10
  * 实现落在 `wake-scheduler.ts` 的 `sendToTrajectory()`("怎么把一句话送到一条轨迹"是调度器的知识)。
@@ -27,6 +27,9 @@
27
27
  * `systemPrompt.section` 注入,见 `docs/trajectory-skill-injection.md`)
28
28
  * · autopilot 面(all/init/random/diag/doc/check/status/guide)→ `container_admin` 的 autopilot 域
29
29
  * · `wake-add`/`wake-list`/`wake-rm` → **`wake-later`**(v1.33 收敛;**2026-09-17 更名 `send-later`**)
30
+ * · 2026-09-20(CRO 落地):新增 **`cro-guide`** —— CRO 编写指南的出口(纯读)。
31
+ * 判据(R↓,为何在此而不新增域):CRO 程序放在**轨迹自己的目录**里 ⇒ "怎么写它"是
32
+ * **逐轨迹**的知识,而管轨迹的人正是用本工具的人(设计 §9-5「既有 guide 位置,不新增域」)。
30
33
  *
31
34
  * 保留 osp 对齐语义的部分:create 的 `--desc`/`--issue` 二选一、use 激活即重命名 dsh 会话标题(F3)。
32
35
  * 活跃会话跟踪:内存 Map(按 dsh 会话 id 隔离)+ 从 events 恢复(S134)。
@@ -94,7 +94,7 @@ function localIdStamp(value = Date.now()) {
94
94
  * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec。
95
95
  *
96
96
  * v1.33 收敛(S142 §32):本文件只服务 `container_trajectory` 的动作面
97
- * (现行 **7 个**:list / show / create / use / rebuild / **send-now** / **send-later**)。旧 `logbook` 面里
97
+ * (现行 **8 个**:list / show / create / use / rebuild / **send-now** / **send-later** / **cro-guide**)。旧 `logbook` 面里
98
98
  * **close / archive / health / qa 四个动作已删**(用户裁决「功能上废弃,实际上没用」),
99
99
  * 其函数(closeSession / archiveSessions / healthCheck / qaCheck)**同批删除**——
100
100
  * 保留下来的只有:create(--desc / --issue 二选一、dry-run 预览)、
@@ -108,7 +108,8 @@ const TRAJECTORY_ACTIONS = [
108
108
  "use",
109
109
  "rebuild",
110
110
  "send-now",
111
- "send-later"
111
+ "send-later",
112
+ "cro-guide"
112
113
  ];
113
114
  /**
114
115
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
@@ -4,7 +4,7 @@
4
4
  * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec。
5
5
  *
6
6
  * v1.33 收敛(S142 §32):本文件只服务 `container_trajectory` 的动作面
7
- * (现行 **7 个**:list / show / create / use / rebuild / **send-now** / **send-later**)。旧 `logbook` 面里
7
+ * (现行 **8 个**:list / show / create / use / rebuild / **send-now** / **send-later** / **cro-guide**)。旧 `logbook` 面里
8
8
  * **close / archive / health / qa 四个动作已删**(用户裁决「功能上废弃,实际上没用」),
9
9
  * 其函数(closeSession / archiveSessions / healthCheck / qaCheck)**同批删除**——
10
10
  * 保留下来的只有:create(--desc / --issue 二选一、dry-run 预览)、
@@ -29,8 +29,14 @@
29
29
  * 同落点语义),只差**时刻**;而「唤醒(冷载入)」是**两条路径共有**的属性,不配做区分
30
30
  * ⇒ 族名取共享词干 **`send-`**、轴取 **`-now` / `-later`**(同构)。**硬切无别名**;
31
31
  * 机制层词汇(`wake-registry.json` / `w-*` id / `WakeEntry` / 调度器名)**一律不动**(分层命名)。
32
+ * 2026-09-20(CRO 落地,owner 令「搞定了发一版」):新增 **`cro-guide`** —— CRO
33
+ * (Continuous Re-Occurrence,`docs/cro-design.md`)的**编写指南**出口。
34
+ * 判据(R↓,为何挂在本工具而不新增域):CRO 程序**放在轨迹自己的目录里**
35
+ * (`<轨迹目录>/continuous-re-occurrence.ts`)⇒ 「怎么写它」是**逐轨迹**的知识,
36
+ * 而**管轨迹的人正是用本工具的人**;挂这儿 = 设计 §9-5 的"**既有 guide 位置、不新增域**"。
37
+ * ⚠️ 本动作**纯读**(输出指南正文,不碰 fs、不碰注册表)。
32
38
  */
33
- type TrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'send-now' | 'send-later';
39
+ type TrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'send-now' | 'send-later' | 'cro-guide';
34
40
  export declare const TRAJECTORY_ACTIONS: readonly TrajectoryAction[];
35
41
  /**
36
42
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类