@shgroup/dsh-serenity-hooks 1.44.0 → 1.45.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.
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.1",
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
  }) })
@@ -24,10 +24,12 @@
24
24
  * **时钟永久不武装**(实测 6.6h 零 tick)。⇒ 现在「**全局闸开即武装**」,"有无目标"降级为
25
25
  * tick 内的廉价判定。**武装与"本次有无目标"是两件事,本工厂不得把二者耦合。**
26
26
  *
27
- * 🔴 硬约束三:**两条闸必须继续分开传**(v1.34 S-1 解耦)
27
+ * 🔴 硬约束三:**闸是可选能力,工厂不得替调用方假设"必须有闸"**(v1.34 S-1 解耦 → 2026-09-21 收窄)
28
28
  *
29
- * 唤醒调度器 `wakeSchedulerEnabled`(**缺省开**)|autopilot `autopilotWakeEnabled`
30
- * (**缺省关**)——取值方向相反。工厂取 `gate` **回调**(每次现读),**不做**任何合并或缓存。
29
+ * 现只余 **autopilot `autopilotWakeEnabled`**(**缺省关**)一条;**唤醒调度器已无闸**
30
+ * (原 `wakeSchedulerEnabled` 于 2026-09-21 所有者令砍掉 ⇒ 调用方**不传** `gate`
31
+ * = 恒武装、永不因闸跳过、`enabled` 恒 `true`)。工厂取 `gate` **回调**(每次现读),
32
+ * **不做**任何合并或缓存;**缺省无闸是合法形态,不是漏配**。
31
33
  *
32
34
  * ───────────────────────────────────────────────────────────────────────────
33
35
  * 两条时钟**逐项语义差**(`ClockOptions` 的每个可配项都对应下表一行,不是随意的灵活性):
@@ -129,10 +131,16 @@ export interface ClockOptions<T> {
129
131
  ctx: unknown;
130
132
  /** 热启动触发面事件名(回调恒为 `() => start()`——两条钟的触发面同形,不开放自定义回调) */
131
133
  events?: string[];
132
- /** 全局闸:**每次现读**(不缓存——面板改开关后要能立刻反映)+ 武装门**只**判它 */
133
- gate: () => boolean;
134
- /** body 被**闸**跳过时写入 `lastSkipReason` 的文案(文案归各钟,工厂不编) */
135
- gateOffReason: string;
134
+ /**
135
+ * 闸(**可选**):**每次现读**(不缓存——面板改开关后要能立刻反映)+ 武装门**只**判它。
136
+ *
137
+ * ⚠️ **2026-09-21(所有者令)起可为缺省**:唤醒调度器的闸已被**砍掉**(原话「send-later 的开关
138
+ * 不再重要了,砍掉」)⇒ 「**本钟没有闸**」必须能被表达。**缺省 = 无闸**:恒武装、永不因闸跳过、
139
+ * `snapshot().enabled` 恒 `true`。(工厂**能力**保留——将来任何钟仍可自带闸。)
140
+ */
141
+ gate?: () => boolean;
142
+ /** body 被**闸**跳过时写入 `lastSkipReason` 的文案(文案归各钟,工厂不编;**无闸时无意义**) */
143
+ gateOffReason?: string;
136
144
  /**
137
145
  * **同步前置阶段**(在 body 被调用**之前**、同一个 tick 内同步执行)。
138
146
  *
package/lib/index.js CHANGED
@@ -2,13 +2,13 @@ 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, g as resolveInside, i as findGitRoot, l as pathInside, m as readTrajectorySkills, 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-DG4Oc7I1.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-FxWXuZPw.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-BzdzsDPI.js";
5
+ import { C as useSession, S as summarize, T as localFileStamp, _ as resolveSessionByTitle, a as resolveSessionTrajectoryLabel, b as setActiveSessionInfo, c as TRAJECTORY_ACTIONS, d as extractSessionMdPathFromText, f as findSession, g as readActiveSessionMd, h as parseSessionContextFromEvents, i as readLastBound, l as clearActiveSessionInfo, m as listSessions, o as setBindingStore, p as getActiveSessionInfo, r as pruneMissingBindings, s as DEFAULT_SESSION_SCOPE, t as appendBound, u as createSession, v as sessionEvents$1, w as isoLocal, x as showSession, y as sessionsRoot } from "./trajectory-bound-BPWKkzJC.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-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-DF-YWcX5.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),可以放心留一半
@@ -4490,6 +4497,9 @@ ${renderCroSampleSnapshot()}
4490
4497
  * ⇒ 族名取共享词干 **`send-`**、轴取 **`-now` / `-later`**(同构)。**硬切无别名**(D46/D61 先例);
4491
4498
  * 机制层词汇(`wake-registry.json` / `w-*` id / `WakeEntry` / 调度器名 / 配置键 `wakeSchedulerEnabled`)
4492
4499
  * **一律不动** —— 接受"机制叫 wake、动作叫 send-later"的**分层命名**(二者本是两层)。
4500
+ * 🔴 **2026-09-21 补注(不改写历史,只标失效时点)**:上句里那个**配置键 `wakeSchedulerEnabled`
4501
+ * 已随后续所有者令被砍**(唤醒调度器无闸、恒武装)⇒ 该词从"机制层词汇"里**自然减员**;
4502
+ * 现行总闸键是 CRO 阶段的 **`croEnabled`**。
4493
4503
  *
4494
4504
  * 与旧面(logbook 11 动作 + trajectory 12 动作)的对应(用户逐条裁决,R↓):
4495
4505
  * · `summary` → 并入 `list`(全库统计随清单一起给)
@@ -4513,10 +4523,21 @@ ${renderCroSampleSnapshot()}
4513
4523
  function agentScope$1(exec) {
4514
4524
  return exec.agent?.session?.id ?? "default";
4515
4525
  }
4516
- /** 当前 dsh 会话对象(append bound 用);无 → null */
4526
+ /**
4527
+ * 当前 dsh 会话对象(绑定的读写都要用它);无 `append` → null。
4528
+ *
4529
+ * 🔴 **2026-09-21 修 F3(原实现是 F1 的上游成因)**:本函数原先把会话**削成只带 `append` 的包装对象**。
4530
+ * 但 `appendBound` / `readLastBound` 定位"这是哪条会话、哪个 CCC 根"靠的是
4531
+ * `session.header.id` 与 `session.header.cwd`(见 `trajectory-bound.ts` 的 `sessionHeader`)——
4532
+ * **包装对象没有 header** ⇒ ① `appendBound` **在读 id 处直接 `return false`**(静默 no-op)
4533
+ * ⇒ **`use` 这条路从来不写当前载体的绑定**(实证吻合:S142 §7.4 记录"当前载体的绑定**直到
4534
+ * 17:05 那次 rebuild 才写入**")② `readLastBound` 同样恒 null ⇒ G1 切换守卫只能靠内存回退。
4535
+ * ⇒ 改为**返回原会话对象**(只增字段、不削字段):只用 `append` 的调用点行为不变,
4536
+ * 而绑定读写从此拿得到 header。
4537
+ */
4517
4538
  function agentDshSession(exec) {
4518
4539
  const s = exec.agent?.session;
4519
- return s && typeof s.append === "function" ? { append: s.append } : null;
4540
+ return s && typeof s.append === "function" ? s : null;
4520
4541
  }
4521
4542
  /**
4522
4543
  * 当前绑定的权威 dirName(优先持久化 bound——防内存被误 use 污染;无 bound 回退内存 active)。
@@ -4752,9 +4773,6 @@ function createTrajectoryTool(ctx) {
4752
4773
  };
4753
4774
  if (advisory) out.advisory = advisory;
4754
4775
  if (dsh) {
4755
- const selfId = String(dsh.header?.id ?? "");
4756
- const superseded = supersedeOtherBindings(root, info?.dirName ?? targetDirName, selfId === "" ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([selfId]));
4757
- if (superseded.length > 0) out.supersededBindings = superseded;
4758
4776
  const pruned = pruneMissingBindings(root, (id) => !hasSessionLogById(sessionsRootDir(), id));
4759
4777
  if (pruned.length > 0) out.prunedBindings = pruned;
4760
4778
  }
@@ -7057,7 +7075,7 @@ function registerStatusApi(ctx, opts = {}) {
7057
7075
  return;
7058
7076
  }
7059
7077
  const settings = readAdvancedSettings();
7060
- const { readSimpleSettings } = await import("./settings-section-DMDUoQum.js").then((n) => n.r);
7078
+ const { readSimpleSettings } = await import("./settings-section-CIuyoSOX.js").then((n) => n.r);
7061
7079
  const simple = readSimpleSettings();
7062
7080
  const allowed = settings.publicAsk.allowed;
7063
7081
  const port = simple.acpHttpPort ?? ACP_HTTP_PORT;
@@ -14829,7 +14847,7 @@ function renderClock(label, s) {
14829
14847
  const ts = (ms) => ms === null ? "(从未)" : isoLocal(ms);
14830
14848
  const parts = [
14831
14849
  `armed=${s.armed}`,
14832
- `全局闸=${s.enabled}`,
14850
+ `CRO 闸=${readSimpleSettings().croEnabled !== false}`,
14833
14851
  `tick 次数=${s.ticks}`,
14834
14852
  `上次 tick=${ts(s.lastTickAt)}`
14835
14853
  ];
@@ -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;
@@ -15,6 +15,9 @@
15
15
  * ⇒ 族名取共享词干 **`send-`**、轴取 **`-now` / `-later`**(同构)。**硬切无别名**(D46/D61 先例);
16
16
  * 机制层词汇(`wake-registry.json` / `w-*` id / `WakeEntry` / 调度器名 / 配置键 `wakeSchedulerEnabled`)
17
17
  * **一律不动** —— 接受"机制叫 wake、动作叫 send-later"的**分层命名**(二者本是两层)。
18
+ * 🔴 **2026-09-21 补注(不改写历史,只标失效时点)**:上句里那个**配置键 `wakeSchedulerEnabled`
19
+ * 已随后续所有者令被砍**(唤醒调度器无闸、恒武装)⇒ 该词从"机制层词汇"里**自然减员**;
20
+ * 现行总闸键是 CRO 阶段的 **`croEnabled`**。
18
21
  *
19
22
  * 与旧面(logbook 11 动作 + trajectory 12 动作)的对应(用户逐条裁决,R↓):
20
23
  * · `summary` → 并入 `list`(全库统计随清单一起给)
@@ -801,66 +801,30 @@ function listBoundSessionIds(root, dirName) {
801
801
  return hits.sort((a, b) => b.at - a.at).map((h) => h.id);
802
802
  }
803
803
  /**
804
- * **(b) 同一 trajectory 多 live 会话的机械守卫**(S142 §0y,所有者 2026-09-18 裁「b 做」)。
804
+ * 🔴 **「只留一条」的唯一判据**(2026-09-21 收进单一实现;此前同一判据在域侧/文件侧各写一遍)。
805
805
  *
806
- * 把绑定到 `dirName` 的**其它**会话 id 标记为 `supersededAt` —— **保留记录**(沿革/正向查询不丢),
807
- * 只切断"**唤醒还会找到它**"这条路。语义上即"解绑",且**不动那个会话本身**(它仍可被人工使用)。
806
+ * 判据:同 `dirName` **不是** `keepIds` 里的 ∧ **尚未** `supersededAt`。
807
+ * 域侧与文件侧**同判据**——历史缺陷(2026-09-19)正是"只在一侧收集 ⇒ 返回值恒空"
808
+ * 见 {@link supersedeOtherBindings} 的注释。
808
809
  *
809
- * 为什么必须有机制(R↓):`.bindings.json` 的语义是"latest-wins 覆盖**本条会话记录**",
810
- * 对**同一 trajectory 的其它会话**没有任何约束 多代会话自然堆积(实测 S142 4 代 / S185 2 代),
811
- * 而 `acquireWakeAgent` 是"遍历全部绑定 id、任一条 live 就用它"——**两条 live 都能被选中**。
812
- *
813
- * @param root CCC 根
814
- * @param dirName 目标 trajectory 目录名
815
- * @param keepIds 保留(不标记)的会话 id 集合——通常是"当前正在 use 的这条"
816
- * @returns **实际被标记**的会话 id(升序稳定;供调用方如实报告,未标记任何一条 → `[]`)
810
+ * @param fileSessions 旧文件表的记录集
811
+ * @param domainEntries 域侧条目(域不可用时传 `undefined` = 不参与判定)
817
812
  */
818
- function supersedeOtherBindings(root, dirName, keepIds) {
819
- const path = join(root, BINDINGS_REL_PATH);
820
- const file = readBindingsFile(path);
821
- const at = Date.now();
822
- /**
823
- * 需要退休的会话 id 集合。
824
- *
825
- * 🔴 必须取**域 ∪ 文件的并集**(实测缺陷,2026-09-19):
826
- * 首版实现只在**文件循环**里 `marked.push(id)`,于是"记录只在域里"时
827
- * 返回值恒为 `[]` —— 而调用方(`tools/trajectory.ts` 的 `use`)**靠这个返回值**决定
828
- * 是否回报 `supersededBindings`,并且早先用 `marked.length === 0` 短路**跳过了写盘**。
829
- * ⇒ 症状是"D69 只留一条**静默不生效**"(记录没被标记,返回也看不出异常)。
830
- * 由 `tests/trajectory-bound.test.ts` 的 D69 域路径用例抓到。
831
- */
813
+ function collectSupersedeTargets(dirName, keepIds, fileSessions, domainEntries) {
832
814
  const toMark = /* @__PURE__ */ new Set();
833
- if (domainStore?.available) for (const [id, raw] of domainStore.entries()) {
815
+ if (domainEntries) for (const [id, raw] of domainEntries) {
834
816
  const rec = fromDomainRecord(raw);
835
817
  if (rec.dirName !== dirName) continue;
836
818
  if (keepIds.has(id) || rec.supersededAt !== void 0) continue;
837
819
  toMark.add(id);
838
820
  }
839
- for (const [id, raw] of Object.entries(file.sessions)) {
821
+ for (const [id, raw] of Object.entries(fileSessions)) {
840
822
  const rec = asBoundRecord(raw);
841
823
  if (!rec || rec.dirName !== dirName) continue;
842
824
  if (keepIds.has(id) || rec.supersededAt !== void 0) continue;
843
825
  toMark.add(id);
844
826
  }
845
- if (toMark.size === 0) return [];
846
- if (domainStore?.available) for (const id of toMark) {
847
- const raw = domainStore.get(id);
848
- if (!raw) continue;
849
- domainStore.put(id, toDomainRecord({
850
- ...fromDomainRecord(raw),
851
- supersededAt: at
852
- })).catch(() => {});
853
- }
854
- for (const id of toMark) {
855
- const rec = asBoundRecord(file.sessions[id]);
856
- if (!rec) continue;
857
- rec.supersededAt = at;
858
- file.sessions[id] = rec;
859
- }
860
- try {
861
- writeBindingsFile(path, file);
862
- } catch {}
863
- return [...toMark].sort();
827
+ return toMark;
864
828
  }
865
829
  /**
866
830
  * **(c) 绑定一致性兜底**(S142 §0y,所有者 2026-09-18 裁「c 也算个兜底」):
@@ -906,6 +870,11 @@ function pruneMissingBindings(root, isMissing) {
906
870
  * 写入绑定(latest-wins 覆盖该会话记录)。
907
871
  *
908
872
  * 绑定持久化尽力而为:无法定位 CCC 根 / 无会话 id / 写盘失败 → 返回 false,不阻断主流程。
873
+ *
874
+ * 🔴 **同时是「只留一条」(D69)的唯一写入口**(2026-09-21 起):每写一条,就在**同一次 RMW** 里
875
+ * 把同轨迹的**其它**条标 `supersededAt`(自己除外)。⇒ 任何调用路径(`create`/`activate`/`switch`/
876
+ * `rebuild`/`reconcile`)**都自动满足"只留一条"**,调用方**不需要**(也**不应当**)自己算 selfId。
877
+ *
909
878
  * @param session 目标 dsh 会话(需 `header.id` + `header.cwd` 可定位 CCC 根)
910
879
  * @param action 绑定动作
911
880
  * @param rec 绑定记录(dirName + mdPath 必填;sessionId 可选展示码)
@@ -927,11 +896,26 @@ function appendBound(session, action, rec) {
927
896
  try {
928
897
  const file = readBindingsFile(path);
929
898
  file.sessions[id] = record;
899
+ const targets = collectSupersedeTargets(rec.dirName, /* @__PURE__ */ new Set([id]), file.sessions, domainStore?.available ? domainStore.entries() : void 0);
900
+ for (const other of targets) {
901
+ const otherRec = asBoundRecord(file.sessions[other]);
902
+ if (!otherRec) continue;
903
+ otherRec.supersededAt = record.at;
904
+ file.sessions[other] = otherRec;
905
+ }
930
906
  writeBindingsFile(path, file);
907
+ if (domainStore?.available) for (const other of targets) {
908
+ const raw = domainStore.get(other);
909
+ if (!raw) continue;
910
+ domainStore.put(other, toDomainRecord({
911
+ ...fromDomainRecord(raw),
912
+ supersededAt: record.at
913
+ })).catch(() => {});
914
+ }
931
915
  return true;
932
916
  } catch {
933
917
  return domainStore?.available === true;
934
918
  }
935
919
  }
936
920
  //#endregion
937
- export { summarize as C, localHuman as D, localFileStamp as E, localIdStamp as O, showSession as S, isoLocal as T, readActiveSessionMd as _, resolveSessionTrajectoryLabel as a, sessionsRoot as b, DEFAULT_SESSION_SCOPE as c, createSession as d, extractSessionMdPathFromText as f, parseSessionContextFromEvents as g, listSessions as h, readLastBound as i, TRAJECTORY_ACTIONS as l, getActiveSessionInfo as m, listBoundSessionIds as n, setBindingStore as o, findSession as p, pruneMissingBindings as r, supersedeOtherBindings as s, appendBound as t, clearActiveSessionInfo as u, resolveSessionByTitle as v, useSession as w, setActiveSessionInfo as x, sessionEvents as y };
921
+ export { useSession as C, localIdStamp as D, localHuman as E, summarize as S, localFileStamp as T, resolveSessionByTitle as _, resolveSessionTrajectoryLabel as a, setActiveSessionInfo as b, TRAJECTORY_ACTIONS as c, extractSessionMdPathFromText as d, findSession as f, readActiveSessionMd as g, parseSessionContextFromEvents as h, readLastBound as i, clearActiveSessionInfo as l, listSessions as m, listBoundSessionIds as n, setBindingStore as o, getActiveSessionInfo as p, pruneMissingBindings as r, DEFAULT_SESSION_SCOPE as s, appendBound as t, createSession as u, sessionEvents as v, isoLocal as w, showSession as x, sessionsRoot as y };
@@ -169,6 +169,11 @@ export declare function pruneMissingBindings(root: string, isMissing: (sessionId
169
169
  * 写入绑定(latest-wins 覆盖该会话记录)。
170
170
  *
171
171
  * 绑定持久化尽力而为:无法定位 CCC 根 / 无会话 id / 写盘失败 → 返回 false,不阻断主流程。
172
+ *
173
+ * 🔴 **同时是「只留一条」(D69)的唯一写入口**(2026-09-21 起):每写一条,就在**同一次 RMW** 里
174
+ * 把同轨迹的**其它**条标 `supersededAt`(自己除外)。⇒ 任何调用路径(`create`/`activate`/`switch`/
175
+ * `rebuild`/`reconcile`)**都自动满足"只留一条"**,调用方**不需要**(也**不应当**)自己算 selfId。
176
+ *
172
177
  * @param session 目标 dsh 会话(需 `header.id` + `header.cwd` 可定位 CCC 根)
173
178
  * @param action 绑定动作
174
179
  * @param rec 绑定记录(dirName + mdPath 必填;sessionId 可选展示码)
@@ -1,8 +1,8 @@
1
1
  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
- 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";
4
+ import { D as localIdStamp, E as localHuman, f as findSession, n as listBoundSessionIds, w as isoLocal, y as sessionsRoot } from "./trajectory-bound-BPWKkzJC.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";
@@ -1190,10 +1190,12 @@ function appendCroWakeLog(root, dirName, input, nowMs = Date.now()) {
1190
1190
  * **时钟永久不武装**(实测 6.6h 零 tick)。⇒ 现在「**全局闸开即武装**」,"有无目标"降级为
1191
1191
  * tick 内的廉价判定。**武装与"本次有无目标"是两件事,本工厂不得把二者耦合。**
1192
1192
  *
1193
- * 🔴 硬约束三:**两条闸必须继续分开传**(v1.34 S-1 解耦)
1193
+ * 🔴 硬约束三:**闸是可选能力,工厂不得替调用方假设"必须有闸"**(v1.34 S-1 解耦 → 2026-09-21 收窄)
1194
1194
  *
1195
- * 唤醒调度器 `wakeSchedulerEnabled`(**缺省开**)|autopilot `autopilotWakeEnabled`
1196
- * (**缺省关**)——取值方向相反。工厂取 `gate` **回调**(每次现读),**不做**任何合并或缓存。
1195
+ * 现只余 **autopilot `autopilotWakeEnabled`**(**缺省关**)一条;**唤醒调度器已无闸**
1196
+ * (原 `wakeSchedulerEnabled` 于 2026-09-21 所有者令砍掉 ⇒ 调用方**不传** `gate`
1197
+ * = 恒武装、永不因闸跳过、`enabled` 恒 `true`)。工厂取 `gate` **回调**(每次现读),
1198
+ * **不做**任何合并或缓存;**缺省无闸是合法形态,不是漏配**。
1197
1199
  *
1198
1200
  * ───────────────────────────────────────────────────────────────────────────
1199
1201
  * 两条时钟**逐项语义差**(`ClockOptions` 的每个可配项都对应下表一行,不是随意的灵活性):
@@ -1280,8 +1282,8 @@ function createClock(opts) {
1280
1282
  for (const line of lines) console.log(`${opts.logFrom.prefix}${line}`);
1281
1283
  };
1282
1284
  const tick = () => {
1283
- if (!opts.gate()) {
1284
- runtime.lastSkipReason = opts.gateOffReason;
1285
+ if (opts.gate !== void 0 && !opts.gate()) {
1286
+ runtime.lastSkipReason = opts.gateOffReason ?? null;
1285
1287
  return;
1286
1288
  }
1287
1289
  if (opts.begin) try {
@@ -1315,7 +1317,7 @@ function createClock(opts) {
1315
1317
  st.wired = true;
1316
1318
  attachClockEvents(opts.ctx, api, opts.events);
1317
1319
  }
1318
- if (!opts.gate()) return;
1320
+ if (opts.gate !== void 0 && !opts.gate()) return;
1319
1321
  st.timer = setInterval(tick, TICK_MS);
1320
1322
  st.timer.unref();
1321
1323
  runtime.armed = true;
@@ -1336,7 +1338,7 @@ function createClock(opts) {
1336
1338
  start,
1337
1339
  dispose,
1338
1340
  snapshot: () => ({
1339
- enabled: opts.gate(),
1341
+ enabled: opts.gate === void 0 ? true : opts.gate(),
1340
1342
  ...runtime,
1341
1343
  ...runtime.lastTickLog ? { lastTickLog: [...runtime.lastTickLog] } : {}
1342
1344
  }),
@@ -1389,24 +1391,20 @@ function resolveWakeTarget(root, target) {
1389
1391
  };
1390
1392
  }
1391
1393
  /**
1392
- * 全局闸:**只看 `wakeSchedulerEnabled`**(缺省**开**;显式 `false` 才关)。
1394
+ * 🔴 **本钟的全局闸已于 2026-09-21 砍掉**(所有者令逐字:「**send-later 的开关不再重要了,砍掉**」)。
1393
1395
  *
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 空检查。
1396
+ * **为什么砍**(R↓):唤醒已从"可选实验能力"长成**全容器的续接绳**——S142/S151/S185 的链、
1397
+ * 跨轨迹投递、`send-now`/`send-later` 都走它。留一个"能被误关的开关"的**代价**是
1398
+ * "整条链静默停摆且无人告警"(本仓已实测过同族事故:闸关 6.6h tick、断链 1 14 小时);
1399
+ * 而**收益**只剩"关掉一个 5min unref 空检查"。⇒ **收益 < 代价,故删闸**(不是改为缺省开——是**没有这个键了**)。
1400
1400
  *
1401
- * 设置服务不可用 关(保守;异常由日志与 `dashboard health` 响亮暴露,不静默)。
1401
+ * ⚠️ **兼容**:旧配置文件里残留的 `wakeSchedulerEnabled` **静默忽略**(无回退键、无告警噪声;
1402
+ * 与旧 `bootstrap` 段的处置先例一致)。**机制本身一行未动**(所有者:"我说的只是开关")。
1403
+ *
1404
+ * 历史(勿误读):v1.34 S-1 曾把两闸解耦(周期自唤醒 `autopilotWakeEnabled` / 本钟 `wakeSchedulerEnabled`),
1405
+ * 理由是"关 auto-trajectory 不得连带关一次性唤醒";随 ACC 侧 autopilot 于 v1.35.0 整段退场,
1406
+ * 两闸只剩本钟一座 ⇒ 现已整座移除。详见 `docs/trajectory-scheduling.md` §S-1 与 v1.44 CHANGELOG。
1402
1407
  */
1403
- function wakeSchedulerEnabled() {
1404
- try {
1405
- return readSimpleSettings().wakeSchedulerEnabled !== false;
1406
- } catch {
1407
- return false;
1408
- }
1409
- }
1410
1408
  /**
1411
1409
  * 🔴 **本钟的串行域**(C6b 硬约束):`clock.chain` 是**本实例私有**的——
1412
1410
  * 与 autopilot 的串行链**零共享**。autopilot 每轮跑 CCC 偏见脚本可能阻塞数十秒,
@@ -1422,8 +1420,6 @@ const clockOpts = {
1422
1420
  label: "trajectory 唤醒调度器",
1423
1421
  ctx: void 0,
1424
1422
  events: ["session/created", "serenity/settings-changed"],
1425
- gate: wakeSchedulerEnabled,
1426
- gateOffReason: "唤醒调度器闸关闭(wakeSchedulerEnabled=false)",
1427
1423
  body: () => runWakeTick(clockOpts.ctx),
1428
1424
  logFrom: {
1429
1425
  prefix: "[serenity-hooks] trajectory 唤醒 ",
@@ -1432,7 +1428,9 @@ const clockOpts = {
1432
1428
  startLog: () => "[serenity-hooks] ✓ trajectory 唤醒调度器启动(5min tick)"
1433
1429
  };
1434
1430
  const clock = createClock(clockOpts);
1435
- /** 调度器进程态快照(只读;`enabled` = 全局闸**当前**值,便于区分"未武装"与"闸关") */
1431
+ /** 调度器进程态快照(只读)。
1432
+ * ⚠️ `enabled` 对**本钟已无意义**(2026-09-21 起无闸 ⇒ 恒 `true`);保留字段只为沿用工厂快照形状。
1433
+ * "这轮为什么没被唤起"现在看 `armed` / `lastSkipReason`(tick 内真实原因)+ **CRO 闸**(见 `croEnabled`)。 */
1436
1434
  function wakeSchedulerState() {
1437
1435
  return clock.snapshot();
1438
1436
  }
@@ -1443,6 +1441,17 @@ function wakeSchedulerState() {
1443
1441
  * @param dirName 目标 trajectory 目录名
1444
1442
  * @returns 命中返回 agent 与取得方式(how 进 lastResult,便于诊断);未命中返回原因
1445
1443
  * (原因带 `notReady` = **环境未就绪**而非投递失败,调用方**不得**据此记一次失败)
1444
+ *
1445
+ * 🔴 **前置条件:本轨迹名下必须有一条「未取代」的绑定记录**(2026-09-20 回源码答复 S151 实测):
1446
+ * 选人是**遍历 `listBoundSessionIds(root, dirName)` 给出的 id**(按绑定时间倒序),**live 只是这条
1447
+ * 记录的一个加分项**——「绑定里的那条恰好 live ⇒ 直接注入」,否则走冷载入。
1448
+ * ⇒ **「有 live 会话」≠「有绑定」**:会话活着但该轨迹**零条未取代绑定**时,本函数**直接返回
1449
+ * `无绑定会话记录…`**(`send-now` / `send-later` 到点投递同此判据)。
1450
+ * 实证(2026-09-20):S142 三条旧绑定于 **08:03** 被 `supersededAt` 取代(D69「同轨迹只留一条」),
1451
+ * 而当前载体的绑定**直到 17:05 那次 rebuild 才写入**(`queueRebuild` 内的 `appendBound(action:'rebuild')`)
1452
+ * ⇒ **10:42 的 `send-now` 落在这个窗口里** ⇒ 报"无绑定会话记录"(当时确有 live 会话)。
1453
+ * ⚠️ 已知**注释漂移**:本行上方"→ 标题回退"在函数体内**没有对应分支**(标题回退属 v1.29.2 R2,
1454
+ * 现行实现已只认绑定);**仅登记,未改**(改它属 ACC 代码改动,须具名令)。
1446
1455
  */
1447
1456
  async function acquireWakeAgent(ctx, root, dirName) {
1448
1457
  const agents = hostAgents(ctx);
@@ -1760,6 +1769,10 @@ async function deliverCroWake(ctx, root, dirName, prompt, reason) {
1760
1769
  * @param log 本 tick 的人读摘要(就地追加)
1761
1770
  */
1762
1771
  async function runCroPhase(ctx, root, registry, log) {
1772
+ if (readSimpleSettings().croEnabled === false) {
1773
+ log.push("CRO 阶段:已关闭(croEnabled=false)——既有唤醒投递不受影响");
1774
+ return;
1775
+ }
1763
1776
  let dirs;
1764
1777
  try {
1765
1778
  dirs = listCroTrajectories(root);
@@ -18,8 +18,9 @@
18
18
  * 而非"投递失败",见 `WakeDeliveryResult.notReady` —— 启动那一拍早于懒服务就绪是常态)
19
19
  * 4. 投递:`agent.followup(...)`("Queue an ordinary follow-up turn and wake the driver")
20
20
  *
21
- * 守卫(I-4 默认 + v1.34 S-1 解耦):全局 `wakeSchedulerEnabled`(**缺省开**;**不再**回退旧键
22
- * `autopilotEnabled`——关周期自唤醒不得连带关一次性唤醒)|
21
+ * 守卫(2026-09-21 起**本钟无闸**):🔴 **恒武装**——原 `wakeSchedulerEnabled` 已砍,
22
+ * 本钟不再有「可被误关的开关」;旧配置残留该键**静默忽略**,且**不**回退 `autopilotEnabled`|
23
+ * CRO 阶段另有**独立**总闸 `croEnabled`(只停 CRO,**不影响**本注册表投递)|
23
24
  * 补跑窗口 2h(超窗置 missed 留痕)|同 tick 串行|唤起后维持 live(人类可介入)。
24
25
  */
25
26
  import type { Context } from 'cordis';
@@ -68,7 +69,9 @@ interface WakeTarget {
68
69
  * @returns 命中返回目录信息,未命中 null
69
70
  */
70
71
  export declare function resolveWakeTarget(root: string, target: string): WakeTarget | null;
71
- /** 调度器进程态快照(只读;`enabled` = 全局闸**当前**值,便于区分"未武装"与"闸关") */
72
+ /** 调度器进程态快照(只读)。
73
+ * ⚠️ `enabled` 对**本钟已无意义**(2026-09-21 起无闸 ⇒ 恒 `true`);保留字段只为沿用工厂快照形状。
74
+ * "这轮为什么没被唤起"现在看 `armed` / `lastSkipReason`(tick 内真实原因)+ **CRO 闸**(见 `croEnabled`)。 */
72
75
  export declare function wakeSchedulerState(): WakeSchedulerRuntime & {
73
76
  enabled: boolean;
74
77
  };
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.1",
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": {