@shgroup/dsh-serenity-hooks 1.44.0 → 1.45.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/README.md CHANGED
@@ -289,7 +289,7 @@ DSH 一个进程可以同时带多个工作区,每个工作区各自对接自
289
289
  | | 内容 |
290
290
  |---|---|
291
291
  | **程序放哪** | `<CCC 根>/AGENT_SESSIONS/<轨迹目录>/continuous-re-occurrence.ts`(放**轨迹自己目录**里 ⇒ 跟随轨迹跨载体存活、天然进 git) |
292
- | **开关** | 🔴 **没有开关**——**文件在 = 启用,文件不在 = 禁用**(无 enabled 字段、无注册表) |
292
+ | **开关** | **逐轨迹**:**文件在 = 启用,文件不在 = 禁用**(无 enabled 字段、无注册表)② 🔴 **总闸**:设置面板「**CRO(轨迹自编程唤起)**」(`croEnabled`,缺省**开**)——关掉**只停 CRO 阶段**,`send-later` / `send-now` / 唤醒表投递**照常工作** |
293
293
  | **谁跑它** | ACC 的唤醒调度器(既有 **5 分钟** tick) |
294
294
  | **给它什么** | 一条 stdin 进来的 **JSON 快照**:身份 / 时间 / 轨迹身体(SESSION.md 体积与 mtime、`references/` 清单)/ 绑定与载体(绑定的、live 的、🔴 **正在跑轮次的**)/ 调度面(本轨迹在办唤醒、调度器状态) |
295
295
  | **它给我什么** | stdout **一行 JSON**:`{"wake":true,"prompt":"…","reason":"…"}` 或 `{"wake":false}`(**缺省 = 不打扰**) |
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.44.0",
3
+ "version": "1.45.0",
4
4
  "main": "lib/index.js",
5
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": {
package/lib/client.js CHANGED
@@ -4825,13 +4825,13 @@ Instruction-following style:
4825
4825
  const acpOn = value?.acpEnabled ?? false;
4826
4826
  const acpPort = value?.acpHttpPort ?? 3100;
4827
4827
  const publicAskOn = value?.publicAskEnabled ?? false;
4828
- const wakeSchedOn = value?.wakeSchedulerEnabled ?? true;
4828
+ const croOn = value?.croEnabled ?? true;
4829
4829
  const [openGateway, setOpenGateway] = (0, react.useState)(false);
4830
4830
  const [openRebuild, setOpenRebuild] = (0, react.useState)(false);
4831
4831
  const [openSkiff, setOpenSkiff] = (0, react.useState)(false);
4832
4832
  const [openAcp, setOpenAcp] = (0, react.useState)(false);
4833
4833
  const [openPublicAsk, setOpenPublicAsk] = (0, react.useState)(false);
4834
- const [openWakeSched, setOpenWakeSched] = (0, react.useState)(false);
4834
+ const [openCro, setOpenCro] = (0, react.useState)(false);
4835
4835
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4836
4836
  className: "ss-section",
4837
4837
  children: [
@@ -4978,20 +4978,20 @@ Instruction-following style:
4978
4978
  })
4979
4979
  }) }),
4980
4980
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4981
- title: "唤醒调度器(条目来源:send-later)",
4982
- desc: "投递已登记的“未来时刻 + 一条 message”(全局开关,默认开)",
4981
+ title: "CRO(轨迹自编程唤起)",
4982
+ desc: "让轨迹用自己的一段程序决定何时唤起(全局开关,默认开)",
4983
4983
  expandable: true,
4984
- open: openWakeSched,
4985
- onToggle: setOpenWakeSched,
4984
+ open: openCro,
4985
+ onToggle: setOpenCro,
4986
4986
  control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
4987
- checked: wakeSchedOn,
4988
- onChange: (on) => toggle("wakeSchedulerEnabled", on)
4987
+ checked: croOn,
4988
+ onChange: (on) => toggle("croEnabled", on)
4989
4989
  }),
4990
4990
  detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4991
4991
  className: "ss-detailStack",
4992
4992
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4993
4993
  className: "ss-detailIntro",
4994
- children: "唤醒调度器全局闸(v1.34 独立开关):\n· 作用:把 CCC 唤醒注册表(AGENT_SESSIONS/wake-registry.json)里到点的条目投递给目标轨迹\条目来源:`container_trajectory send-later`(对自己或别的 trajectory 预约未来时刻 + 一条 message)\默认开:条目全部由人类/agent 显式登记,无环境自主性 ⇒ 不需要“默认关”的实验保护\唯一性:ACC 现存的**唯一**轨迹调度时钟(原并列的周期自唤醒闸已随 ACC autopilot 退场删除)\精度:5min tick;补跑窗口 2h(超窗判 missed 留痕);fire-and-forget 无回执"
4994
+ children: "CRO = Continuous Re-Occurrence(轨迹自编程唤起)。\作用:轨迹目录下放一个 continuous-re-occurrence.ts,ACC 5min tick spawn 它,\n 由这段程序自己决定“要不要唤、何时唤、唤起时说什么”\n· 怎么启用:程序文件在即启用(无需在此配置);本开关是**总闸**\关掉它的后果:**只有 CRO 阶段停跑** —— 定时唤醒(send-later)、即时投递(send-now)\n 与唤醒表投递**照常工作**\n· 默认开:已在生产稳定运行,且“没有程序文件的轨迹”本来就不参与(默认存在感为零)\与它同时废止的开关:原“唤醒调度器”闸(2026-09-21 所有者令砍掉)——\n 唤醒调度器现**恒开**,不再有可被误关的开关"
4995
4995
  })
4996
4996
  })
4997
4997
  }) })
@@ -129,10 +129,16 @@ export interface ClockOptions<T> {
129
129
  ctx: unknown;
130
130
  /** 热启动触发面事件名(回调恒为 `() => start()`——两条钟的触发面同形,不开放自定义回调) */
131
131
  events?: string[];
132
- /** 全局闸:**每次现读**(不缓存——面板改开关后要能立刻反映)+ 武装门**只**判它 */
133
- gate: () => boolean;
134
- /** body 被**闸**跳过时写入 `lastSkipReason` 的文案(文案归各钟,工厂不编) */
135
- gateOffReason: string;
132
+ /**
133
+ * 闸(**可选**):**每次现读**(不缓存——面板改开关后要能立刻反映)+ 武装门**只**判它。
134
+ *
135
+ * ⚠️ **2026-09-21(所有者令)起可为缺省**:唤醒调度器的闸已被**砍掉**(原话「send-later 的开关
136
+ * 不再重要了,砍掉」)⇒ 「**本钟没有闸**」必须能被表达。**缺省 = 无闸**:恒武装、永不因闸跳过、
137
+ * `snapshot().enabled` 恒 `true`。(工厂**能力**保留——将来任何钟仍可自带闸。)
138
+ */
139
+ gate?: () => boolean;
140
+ /** body 被**闸**跳过时写入 `lastSkipReason` 的文案(文案归各钟,工厂不编;**无闸时无意义**) */
141
+ gateOffReason?: string;
136
142
  /**
137
143
  * **同步前置阶段**(在 body 被调用**之前**、同一个 tick 内同步执行)。
138
144
  *
package/lib/index.js CHANGED
@@ -6,9 +6,9 @@ import { C as summarize, E as localFileStamp, S as showSession, T as isoLocal, _
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-CWMRa36W.js";
7
7
  import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, o as ACC_VERSION, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-BjIX_KD1.js";
8
8
  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-KqQA6pkr.js";
9
- 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";
9
+ 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-CIuyoSOX.js";
10
10
  import { r as sessionsRootDir, t as hasSessionLogById } from "./session-cleanup-BtkSmry8.js";
11
- 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-C2GwdriD.js";
11
+ 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-fVe71jkg.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";
14
14
  import { defineTool } from "@deepseek-ai/dsh-tools";
@@ -4365,7 +4365,13 @@ const CRO_GUIDE = `CRO(Continuous Re-Occurrence · 持续再发生)编写指
4365
4365
 
4366
4366
  🔴 **文件名必须全写**(不许用缩写)。
4367
4367
  🔴 **程序只有一个**:**文件在 = 启用;文件不在 = 禁用**。
4368
- —— 没有开关、没有注册表、没有 enabled 字段。
4368
+ —— 没有**逐条**开关、没有注册表、没有 enabled 字段。
4369
+ 🔴 **但上面那条只管"这一条"** —— 另有一个**全局总闸** \`croEnabled\`
4370
+ (设置面板「**CRO(轨迹自编程唤起)**」,缺省**开**):
4371
+ 关掉**只停 CRO 阶段** —— \`send-later\` / \`send-now\` / 唤醒表投递**照常工作**。
4372
+ ⚠️ 所以「**文件在**」**不等于**「**一定会跑**」:总闸关掉时 ACC **根本不调用**你的程序
4373
+ (tick 日志里会记一行跳过理由 —— 这是为了让你事后能分辨
4374
+ 「**总闸关着没跑**」和「**跑了、程序自己判了不叫**」这两件完全不同的事)。
4369
4375
 
4370
4376
  ## 3. 我给你什么(输入)
4371
4377
  ACC 把这条轨迹的状态做成一个 **JSON 快照**,从 **stdin** 喂给你的程序。
@@ -4427,7 +4433,8 @@ CRO 程序**是可以自测的** —— 因为它只做一件事:**吃一份
4427
4433
  (纯函数式的边界 ⇒ 不需要真机、不需要等 5 分钟 tick、不需要调度器。)
4428
4434
 
4429
4435
  ### 8.1 推荐流程:**用开发名写,绿了再改名**
4430
- 因为「**文件在 = 启用**」没有开关,**改名这个动作本身就是上线动作**:
4436
+ 因为「**文件在 = 启用**」**没有逐条开关**(总闸是全局的,管不了单条),
4437
+ **改名这个动作本身就是上线动作**:
4431
4438
 
4432
4439
  1. 先用**开发名**写(如 \`continuous-re-occurrence.dev.ts\`)
4433
4440
  —— 开发名**不会**被 ACC 启用(启用只认正式名 exact match),可以放心留一半
@@ -7057,7 +7064,7 @@ function registerStatusApi(ctx, opts = {}) {
7057
7064
  return;
7058
7065
  }
7059
7066
  const settings = readAdvancedSettings();
7060
- const { readSimpleSettings } = await import("./settings-section-DMDUoQum.js").then((n) => n.r);
7067
+ const { readSimpleSettings } = await import("./settings-section-CIuyoSOX.js").then((n) => n.r);
7061
7068
  const simple = readSimpleSettings();
7062
7069
  const allowed = settings.publicAsk.allowed;
7063
7070
  const port = simple.acpHttpPort ?? ACP_HTTP_PORT;
@@ -14829,7 +14836,7 @@ function renderClock(label, s) {
14829
14836
  const ts = (ms) => ms === null ? "(从未)" : isoLocal(ms);
14830
14837
  const parts = [
14831
14838
  `armed=${s.armed}`,
14832
- `全局闸=${s.enabled}`,
14839
+ `CRO 闸=${readSimpleSettings().croEnabled !== false}`,
14833
14840
  `tick 次数=${s.ticks}`,
14834
14841
  `上次 tick=${ts(s.lastTickAt)}`
14835
14842
  ];
@@ -78,7 +78,7 @@ const simpleSettingsSchema = z.object({
78
78
  acpEnabled: z.boolean().default(false),
79
79
  acpHttpPort: z.number().min(1024).max(65535).default(ACP_HTTP_PORT),
80
80
  publicAskEnabled: z.boolean().default(false),
81
- wakeSchedulerEnabled: z.boolean().default(true)
81
+ croEnabled: z.boolean().default(true)
82
82
  });
83
83
  /** 从插件 Config 提取 entry 默认(settings base 层) */
84
84
  function entryDefaults(config) {
@@ -91,7 +91,7 @@ function entryDefaults(config) {
91
91
  acpEnabled: config.acp?.enabled ?? false,
92
92
  acpHttpPort: config.acp?.httpPort ?? ACP_HTTP_PORT,
93
93
  publicAskEnabled: config.publicAsk?.enabled ?? false,
94
- wakeSchedulerEnabled: true
94
+ croEnabled: true
95
95
  };
96
96
  }
97
97
  /** 运行时源(installSettingsSection 注入:settings scope 或 entry fallback) */
@@ -109,7 +109,7 @@ function defaultSimpleSettings() {
109
109
  acpEnabled: false,
110
110
  acpHttpPort: ACP_HTTP_PORT,
111
111
  publicAskEnabled: false,
112
- wakeSchedulerEnabled: true
112
+ croEnabled: true
113
113
  };
114
114
  }
115
115
  /**
@@ -63,12 +63,18 @@ interface SerenitySimpleSettings {
63
63
  acpHttpPort: number;
64
64
  /** F4d 建议问答页总开关(实验性;默认关——按认知容器暴露问答页,key 认证) */
65
65
  publicAskEnabled: boolean;
66
- /** **唤醒调度器全局闸** —— v1.34 更名(原 `trajectoryEnabled`):投递已登记的"未来时刻 + 一条 message"。
67
- * **缺省开**:它是 trajectory 的基础能力(D58),且**不得**被"关掉周期自唤醒"连带关掉
68
- * ——用户 2026-09-15 裁决:「auto-trajectory 的开关只关闭 auto-trajectory 唤醒」。
69
- * (原并列的周期自唤醒闸 `autopilotWakeEnabled` / 旧键 `autopilotEnabled` 已随 ACC 侧
70
- * autopilot 于 2026-09-15 整段退场删除——现只剩这一座闸。) */
71
- wakeSchedulerEnabled: boolean;
66
+ /** **CRO(轨迹自编程唤起)总开关** —— 2026-09-21 所有者令新增。
67
+ *
68
+ * CRO = 轨迹目录下放一个 `continuous-re-occurrence.ts`,由 ACC 5min tick spawn,
69
+ * 由**程序**决定"要不要唤、何时唤、唤起的提示词是什么"。
70
+ *
71
+ * **缺省开**:① 它已在生产上稳定运行(S151 / S185 各有程序在跑);② 它的**默认存在感为零**
72
+ * ——没有程序文件的轨迹本来就不参与;③ 缺省关会让"已上线的程序突然不跑"(等于静默回退)。
73
+ * **只关 CRO 阶段**:`send-later` / `send-now` / 唤醒表投递**照常**(见 `cro.ts` 头注的承诺)。
74
+ *
75
+ * ⚠️ 与它**同时废止**的键:`wakeSchedulerEnabled`(所有者 2026-09-21 令「send-later 的开关
76
+ * 不再重要了,砍掉」)——唤醒调度器**不再有任何闸**(恒开);旧配置里的该键**静默忽略**。 */
77
+ croEnabled: boolean;
72
78
  }
73
79
  /** 从插件 Config 提取 entry 默认(settings base 层) */
74
80
  export declare function entryDefaults(config: SimpleConfigFragment): SerenitySimpleSettings;
@@ -2,7 +2,7 @@ import { r as hostService, t as hostAgents } from "./access-fiehjxV6.js";
2
2
  import { g as resolveInside } from "./ccc-DG4Oc7I1.js";
3
3
  import { o as listCccs } from "./ccc-roots-FxWXuZPw.js";
4
4
  import { D as localHuman, O as localIdStamp, T as isoLocal, b as sessionsRoot, n as listBoundSessionIds, p as findSession } from "./trajectory-bound-BzdzsDPI.js";
5
- import { t as readSimpleSettings } from "./settings-section-DMDUoQum.js";
5
+ import { t as readSimpleSettings } from "./settings-section-CIuyoSOX.js";
6
6
  import { basename, dirname, join } from "node:path";
7
7
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
8
8
  import { spawn } from "node:child_process";
@@ -1280,8 +1280,8 @@ function createClock(opts) {
1280
1280
  for (const line of lines) console.log(`${opts.logFrom.prefix}${line}`);
1281
1281
  };
1282
1282
  const tick = () => {
1283
- if (!opts.gate()) {
1284
- runtime.lastSkipReason = opts.gateOffReason;
1283
+ if (opts.gate !== void 0 && !opts.gate()) {
1284
+ runtime.lastSkipReason = opts.gateOffReason ?? null;
1285
1285
  return;
1286
1286
  }
1287
1287
  if (opts.begin) try {
@@ -1315,7 +1315,7 @@ function createClock(opts) {
1315
1315
  st.wired = true;
1316
1316
  attachClockEvents(opts.ctx, api, opts.events);
1317
1317
  }
1318
- if (!opts.gate()) return;
1318
+ if (opts.gate !== void 0 && !opts.gate()) return;
1319
1319
  st.timer = setInterval(tick, TICK_MS);
1320
1320
  st.timer.unref();
1321
1321
  runtime.armed = true;
@@ -1336,7 +1336,7 @@ function createClock(opts) {
1336
1336
  start,
1337
1337
  dispose,
1338
1338
  snapshot: () => ({
1339
- enabled: opts.gate(),
1339
+ enabled: opts.gate === void 0 ? true : opts.gate(),
1340
1340
  ...runtime,
1341
1341
  ...runtime.lastTickLog ? { lastTickLog: [...runtime.lastTickLog] } : {}
1342
1342
  }),
@@ -1389,24 +1389,20 @@ function resolveWakeTarget(root, target) {
1389
1389
  };
1390
1390
  }
1391
1391
  /**
1392
- * 全局闸:**只看 `wakeSchedulerEnabled`**(缺省**开**;显式 `false` 才关)。
1392
+ * 🔴 **本钟的全局闸已于 2026-09-21 砍掉**(所有者令逐字:「**send-later 的开关不再重要了,砍掉**」)。
1393
1393
  *
1394
- * ⚠️ 2026-09-15 用户裁决(S-1 **解耦**):「auto-trajectory 的开关**只关闭 auto-trajectory 唤醒**」。
1395
- * ⇒ 本函数**不得**再把 `autopilotEnabled`(周期自唤醒闸)作为回退键 —— 旧实现是
1396
- * `trajectoryEnabled === true || autopilotEnabled === true`,后果实测:所有者关掉 auto-trajectory 后,
1397
- * **一次性唤醒 `wake-later`(今 `send-later`)被连带关掉**,注册表条目静默滞留(当日 6.6h tick)。
1398
- * 缺省由 false 改 true 的理由:唤醒注册表已是一等机制(D58),条目**全部由人类/agent 显式登记**
1399
- * 未来时刻(无环境自主性),不需要"默认关"的实验保护;代价 = 一个 unref 的 5min 空检查。
1394
+ * **为什么砍**(R↓):唤醒已从"可选实验能力"长成**全容器的续接绳**——S142/S151/S185 的链、
1395
+ * 跨轨迹投递、`send-now`/`send-later` 都走它。留一个"能被误关的开关"的**代价**是
1396
+ * "整条链静默停摆且无人告警"(本仓已实测过同族事故:闸关 6.6h tick、断链 1 14 小时);
1397
+ * 而**收益**只剩"关掉一个 5min unref 空检查"。⇒ **收益 < 代价,故删闸**(不是改为缺省开——是**没有这个键了**)。
1400
1398
  *
1401
- * 设置服务不可用 关(保守;异常由日志与 `dashboard health` 响亮暴露,不静默)。
1399
+ * ⚠️ **兼容**:旧配置文件里残留的 `wakeSchedulerEnabled` **静默忽略**(无回退键、无告警噪声;
1400
+ * 与旧 `bootstrap` 段的处置先例一致)。**机制本身一行未动**(所有者:"我说的只是开关")。
1401
+ *
1402
+ * 历史(勿误读):v1.34 S-1 曾把两闸解耦(周期自唤醒 `autopilotWakeEnabled` / 本钟 `wakeSchedulerEnabled`),
1403
+ * 理由是"关 auto-trajectory 不得连带关一次性唤醒";随 ACC 侧 autopilot 于 v1.35.0 整段退场,
1404
+ * 两闸只剩本钟一座 ⇒ 现已整座移除。详见 `docs/trajectory-scheduling.md` §S-1 与 v1.44 CHANGELOG。
1402
1405
  */
1403
- function wakeSchedulerEnabled() {
1404
- try {
1405
- return readSimpleSettings().wakeSchedulerEnabled !== false;
1406
- } catch {
1407
- return false;
1408
- }
1409
- }
1410
1406
  /**
1411
1407
  * 🔴 **本钟的串行域**(C6b 硬约束):`clock.chain` 是**本实例私有**的——
1412
1408
  * 与 autopilot 的串行链**零共享**。autopilot 每轮跑 CCC 偏见脚本可能阻塞数十秒,
@@ -1422,8 +1418,6 @@ const clockOpts = {
1422
1418
  label: "trajectory 唤醒调度器",
1423
1419
  ctx: void 0,
1424
1420
  events: ["session/created", "serenity/settings-changed"],
1425
- gate: wakeSchedulerEnabled,
1426
- gateOffReason: "唤醒调度器闸关闭(wakeSchedulerEnabled=false)",
1427
1421
  body: () => runWakeTick(clockOpts.ctx),
1428
1422
  logFrom: {
1429
1423
  prefix: "[serenity-hooks] trajectory 唤醒 ",
@@ -1432,7 +1426,9 @@ const clockOpts = {
1432
1426
  startLog: () => "[serenity-hooks] ✓ trajectory 唤醒调度器启动(5min tick)"
1433
1427
  };
1434
1428
  const clock = createClock(clockOpts);
1435
- /** 调度器进程态快照(只读;`enabled` = 全局闸**当前**值,便于区分"未武装"与"闸关") */
1429
+ /** 调度器进程态快照(只读)。
1430
+ * ⚠️ `enabled` 对**本钟已无意义**(2026-09-21 起无闸 ⇒ 恒 `true`);保留字段只为沿用工厂快照形状。
1431
+ * "这轮为什么没被唤起"现在看 `armed` / `lastSkipReason`(tick 内真实原因)+ **CRO 闸**(见 `croEnabled`)。 */
1436
1432
  function wakeSchedulerState() {
1437
1433
  return clock.snapshot();
1438
1434
  }
@@ -1443,6 +1439,17 @@ function wakeSchedulerState() {
1443
1439
  * @param dirName 目标 trajectory 目录名
1444
1440
  * @returns 命中返回 agent 与取得方式(how 进 lastResult,便于诊断);未命中返回原因
1445
1441
  * (原因带 `notReady` = **环境未就绪**而非投递失败,调用方**不得**据此记一次失败)
1442
+ *
1443
+ * 🔴 **前置条件:本轨迹名下必须有一条「未取代」的绑定记录**(2026-09-20 回源码答复 S151 实测):
1444
+ * 选人是**遍历 `listBoundSessionIds(root, dirName)` 给出的 id**(按绑定时间倒序),**live 只是这条
1445
+ * 记录的一个加分项**——「绑定里的那条恰好 live ⇒ 直接注入」,否则走冷载入。
1446
+ * ⇒ **「有 live 会话」≠「有绑定」**:会话活着但该轨迹**零条未取代绑定**时,本函数**直接返回
1447
+ * `无绑定会话记录…`**(`send-now` / `send-later` 到点投递同此判据)。
1448
+ * 实证(2026-09-20):S142 三条旧绑定于 **08:03** 被 `supersededAt` 取代(D69「同轨迹只留一条」),
1449
+ * 而当前载体的绑定**直到 17:05 那次 rebuild 才写入**(`queueRebuild` 内的 `appendBound(action:'rebuild')`)
1450
+ * ⇒ **10:42 的 `send-now` 落在这个窗口里** ⇒ 报"无绑定会话记录"(当时确有 live 会话)。
1451
+ * ⚠️ 已知**注释漂移**:本行上方"→ 标题回退"在函数体内**没有对应分支**(标题回退属 v1.29.2 R2,
1452
+ * 现行实现已只认绑定);**仅登记,未改**(改它属 ACC 代码改动,须具名令)。
1446
1453
  */
1447
1454
  async function acquireWakeAgent(ctx, root, dirName) {
1448
1455
  const agents = hostAgents(ctx);
@@ -1760,6 +1767,10 @@ async function deliverCroWake(ctx, root, dirName, prompt, reason) {
1760
1767
  * @param log 本 tick 的人读摘要(就地追加)
1761
1768
  */
1762
1769
  async function runCroPhase(ctx, root, registry, log) {
1770
+ if (readSimpleSettings().croEnabled === false) {
1771
+ log.push("CRO 阶段:已关闭(croEnabled=false)——既有唤醒投递不受影响");
1772
+ return;
1773
+ }
1763
1774
  let dirs;
1764
1775
  try {
1765
1776
  dirs = listCroTrajectories(root);
@@ -68,7 +68,9 @@ interface WakeTarget {
68
68
  * @returns 命中返回目录信息,未命中 null
69
69
  */
70
70
  export declare function resolveWakeTarget(root: string, target: string): WakeTarget | null;
71
- /** 调度器进程态快照(只读;`enabled` = 全局闸**当前**值,便于区分"未武装"与"闸关") */
71
+ /** 调度器进程态快照(只读)。
72
+ * ⚠️ `enabled` 对**本钟已无意义**(2026-09-21 起无闸 ⇒ 恒 `true`);保留字段只为沿用工厂快照形状。
73
+ * "这轮为什么没被唤起"现在看 `armed` / `lastSkipReason`(tick 内真实原因)+ **CRO 闸**(见 `croEnabled`)。 */
72
74
  export declare function wakeSchedulerState(): WakeSchedulerRuntime & {
73
75
  enabled: boolean;
74
76
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.44.0",
3
+ "version": "1.45.0",
4
4
  "description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「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。",
5
5
  "license": "MIT",
6
6
  "repository": {