@shgroup/dsh-serenity-hooks 1.111.0 → 1.113.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.
@@ -1,10 +1,10 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
2
- import { c as hostAgents, o as listCccs, u as hostService } from "./ccc-roots-DPMwBywc.js";
3
- import { g as resolveInside } from "./ccc-BmpE3cQz.js";
2
+ import { c as hostAgents, o as listCccs, u as hostService } from "./ccc-roots-CsSSQjSS.js";
3
+ import { _ as resolveInside } from "./ccc-x94FCzOv.js";
4
4
  import { F as isoLocal, L as localHuman, P as readTrajectoryFile, R as localIdStamp, T as sessionsRoot, b as parseTrajectoryCode, j as TRAJECTORY_FILENAME, k as trajectoryDescOf, p as findSession, v as namingTitleFor } from "./bind-file-B0TuOP89.js";
5
- import { a as listBoundSessionIds, i as carrierState, n as PLUGIN_SOURCE, r as appendBound } from "./message-source-BTIe2cVO.js";
5
+ import { i as carrierState, n as PLUGIN_SOURCE, o as listBoundSessionIds, r as appendBound } from "./message-source-DLei3MqR.js";
6
6
  import { i as sessionsRootDir, n as findSessionLog, r as hasSessionLogById } from "./cleanup-CPl1SSaK.js";
7
- import { n as readSimpleSettings } from "./settings-DY4_DYYY.js";
7
+ import { n as readSimpleSettings } from "./settings-DibHCfEU.js";
8
8
  import { basename, dirname, join } from "node:path";
9
9
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
10
10
  import { spawn } from "node:child_process";
@@ -438,11 +438,24 @@ const CARRIER_OPENING_MARK = "[ACC 代用户开场]";
438
438
  */
439
439
  function buildCarrierOpening(code, desc) {
440
440
  const label = desc.trim() === "" ? code : `${code}(${desc})`;
441
+ /**
442
+ * 🔴 2026-11-02 §D5(owner Q3「全砍」):**166 → 93 码点(−44%)**。
443
+ *
444
+ * 砍掉的只有一句:`之所以代发,是为了让程序性会话与人工会话在宿主侧具有相同投影
445
+ * (有标题、有首轮对齐声明)` —— 那是**设计理由**,读者(这条轨迹自己)既无法据此行动、
446
+ * 也无法据此判断任何事。
447
+ *
448
+ * 🔴 **首句一字不动**:它是**身份与动作声明**(我是谁、我要接着做什么),砍了目标就不知道
449
+ * 自己该干嘛。⇒ 这也是本项只降 44%、降不到 70% 的**诚实原因**(不吹大)。
450
+ *
451
+ * 🔴🔴 **`CARRIER_OPENING_MARK` 一字不动** —— 它是 `session-corpus` **排除语料**的判据
452
+ * (动了它 ⇒ 假开场白会被当成所有者发言,污染全部语料统计)。
453
+ * ⚠️ **"它不是任何人的发言"这句必须留**:否则这条假开场白会被当成人类指令执行。
454
+ */
441
455
  return [
442
456
  `${CARRIER_OPENING_MARK} 激活认知轨迹 ${label},接着它 SESSION.md 里的工作往下做。`,
443
457
  "",
444
- "(这条开场白由 ACC 代为发出。如此做的目的只有一个:让程序性创建的会话与用户在界面里",
445
- "人工创建的会话,在宿主侧具有相同的投影 —— 有标题、有首轮对齐声明。它不是任何人的发言。)"
458
+ "(这条开场白由 ACC 代为发出,它不是任何人的发言。)"
446
459
  ].join("\n");
447
460
  }
448
461
  /**
@@ -2478,16 +2491,25 @@ function createResumeOne(deps) {
2478
2491
  * 即**动两条正在跑的时钟的骨架**;**不值当**(裁决原文见 SESSION §12.8②)。
2479
2492
  */
2480
2493
  /**
2481
- * tick 周期(**5 分钟**)。
2494
+ * tick 周期(**60 秒**)。
2495
+ *
2496
+ * 🔴 2026-11-02 owner 令:「整体都是 60 秒…**能不做轮询就不做,如果做,就一定要少,
2497
+ * 所以 ACC 全局提供一个轮询,60 秒一次**」⇒ 由 `5 * 60 * 1000` 改为 `60 * 1000`。
2482
2498
  *
2483
- * 2026-09-15 S142「ACC 侧 autopilot 退场」:本值原从 `autopilot-core.ts` 导入(`TICK_MS`),
2484
- * 但该模块随 autopilot 退场,而**本模块的唯一消费者是唤醒调度器**(`wake-scheduler`)——
2485
- * 值本身与 autopilot 无关 ⇒ 随消费者归位到本模块(不再依赖 autopilot 判据层)。
2499
+ * **为什么可以降到 60s(本批的硬前提,⛔ 不是顺手的调参)**:
2500
+ * 降频到 60s 意味着 CRO 进程量涨约 5 倍,而 CRO **每条 spawn 一个子进程、单条硬超时 60s**。
2501
+ * 若阶段仍串行,一拍就 > 60s ⇒ 拍子排队只积不丢 ⇒ **调度器静默永久追不上**。
2502
+ * ⇒ 必须先有 `wake/scheduler.ts` 的**受控并发**(上限 4)与 `tick()` 的**跳拍而非排队**。
2503
+ * 这两件在 `续 373` 已落地并做了双变异检验(M1/M2 都能真红),故此处才允许改这个值。
2486
2504
  *
2487
- * ⚠️ 语义不得变:该值同时是**报告文案的来源**("等下个 Nmin tick"),历史上曾因文案写死
2488
- * 10min 与实现 5min 不符而误导排查(§12.7 文案纠错)。
2505
+ * **owner 的架构原则一并记在这里**:**全局只允许一条轮询**。
2506
+ * 实测 `createClock()` 全仓只有一处调用(`wake/scheduler.ts`),autopilot 钟已于
2507
+ * 2026-09-15 整体删除 ⇒ 现状本来就只有一条。⇒ 本批**不新增任何定时器、不新增"每 N 拍"开关**。
2508
+ *
2509
+ * ⚠️ 语义不得变:该值同时是**报告文案的来源**("等下个 Nmin tick")—— 文案已随 60s 改为分钟/秒自适应,
2510
+ * 历史上曾因文案写死 10min 与实现 5min 不符而误导排查(§12.7 文案纠错)。
2489
2511
  */
2490
- const TICK_MS = 3e5;
2512
+ const TICK_MS = 6e4;
2491
2513
  /**
2492
2514
  * 挂事件 → 触发 `start()`(**每个事件一次 try/catch 吞异常**:事件通道缺失不阻断时钟)。
2493
2515
  *
@@ -2527,6 +2549,8 @@ function createClock(opts) {
2527
2549
  chain: Promise.resolve(),
2528
2550
  runtime,
2529
2551
  wired: false,
2552
+ tickPending: false,
2553
+ tickStartedAt: null,
2530
2554
  opts
2531
2555
  };
2532
2556
  /** 记一次 tick(工厂内部与 body 共用同一实现——只有一处会计逻辑) */
@@ -2534,12 +2558,59 @@ function createClock(opts) {
2534
2558
  runtime.lastTickAt = Date.now();
2535
2559
  runtime.ticks += 1;
2536
2560
  };
2561
+ /**
2562
+ * 本钟累计跳过几拍(§A3)。
2563
+ *
2564
+ * ⚠️ **刻意不进 `ClockRuntime`**:`ClockRuntime` 的字段是**对外契约**
2565
+ * (`acc-diag` / `containerClocks()` / 面板在读,见文件头"对外可观测面零变化"),
2566
+ * 加字段等于改契约。跳过次数目前只出现在**日志行**里 —— 那已经够判"这个钟在追赶还是空转"。
2567
+ * 若日后要进诊断面,须按改契约走(同批改消费方),⛔ 不许顺手塞。
2568
+ */
2569
+ let skipCount = 0;
2537
2570
  /** 逐行打印(`logFrom` 缺省 ⇒ 本钟无 tick 日志,整段为死代码路径) */
2538
2571
  const emit = (lines) => {
2539
2572
  if (!opts.logFrom) return;
2540
2573
  for (const line of lines) console.log(`${opts.logFrom.prefix}${line}`);
2541
2574
  };
2542
- const tick = () => {
2575
+ /**
2576
+ * 跳拍判定(2026-11-02 §A3):上一拍**还没跑完** ⇒ 本拍**直接丢弃**,不入链。
2577
+ *
2578
+ * 🔴 为什么必须跳、不能排队(owner 令「整体节律 60 秒」的硬前提):
2579
+ * · 排队语义下,一拍耗时 > 节拍 ⇒ 积压**只增不减**,且呈现为"投递越来越晚"而非任何报错;
2580
+ * · CRO 每拍要 spawn N 条子进程(单条硬超时 60s),N ≥ 8 时最坏 480s ⇒ 60s 节拍下
2581
+ * 必然积压 ⇒ **调度器静默永久追不上**;
2582
+ * · 而"跳掉一拍"的代价是**迟一拍拍到**,与"排队后跑到 8 拍之前的内容"相比,
2583
+ * 后者的输出在语义上已经过期(唤醒"看着情况叫",看的是**当时**的情况)。
2584
+ * ⇒ 跳拍是**正确性**要求,不是性能优化。
2585
+ *
2586
+ * 🔴 跳拍**不记账**(不调 `countTick`):`ticks` 是**所有 CRO 判据的时间基准**
2587
+ * (`cro/core.ts` 快照里就是 `scheduler.ticks`,`guard` 的"刚启动窗口 = 第 2~3 拍"直接依赖它)
2588
+ * ⇒ 跳掉的那一拍**不是一拍已完成的钟**,给它 +1 会**静默改变所有下游的时间语义**。
2589
+ *
2590
+ * 🔴 跳拍**必须出声**(D186/D209:可以拒绝,但不许不出声):写一行带读数的 warn ——
2591
+ * "跳了几拍、在飞的那拍已经跑了多久"。否则"钟在跑但什么都没发生"与"钟根本没跑"
2592
+ * 在读数上不可分(A106 同族)。
2593
+ */
2594
+ const skipOrRun = () => {
2595
+ if (st.tickPending) {
2596
+ const runningFor = st.tickStartedAt === null ? 0 : Date.now() - st.tickStartedAt;
2597
+ skipCount += 1;
2598
+ const msg = `⏭ 跳拍(上一拍仍在飞,已跑 ${Math.round(runningFor / 1e3)}s;本钟累计跳过 ${skipCount} 拍,节拍 ${Math.round(TICK_MS / 1e3)}s)`;
2599
+ runtime.lastSkipReason = msg;
2600
+ if (opts.logFrom) runtime.lastTickLog = [msg];
2601
+ console.warn(`[serenity-hooks] ${msg}(${opts.label})`);
2602
+ return;
2603
+ }
2604
+ runTick();
2605
+ };
2606
+ /**
2607
+ * 跑一拍(进入本钟私有串行链)。
2608
+ *
2609
+ * ⚠️ `tickPending` 在**入链之前**置位、在 body 完成(或异常)后的 `finally` 里清位 ——
2610
+ * 置位必须同步、早于 `st.chain = st.chain.then(...)` 真正执行回调,
2611
+ * 否则同一 tick 周期内的两次调用会都判"无在飞"而双双入队。
2612
+ */
2613
+ const runTick = () => {
2543
2614
  if (opts.gate !== void 0 && !opts.gate()) {
2544
2615
  runtime.lastSkipReason = opts.gateOffReason ?? null;
2545
2616
  return;
@@ -2550,6 +2621,8 @@ function createClock(opts) {
2550
2621
  console.warn(`[serenity-hooks] ✗ tick 前置异常: ${String(err?.message ?? err)}(${opts.label})`);
2551
2622
  return;
2552
2623
  }
2624
+ st.tickPending = true;
2625
+ st.tickStartedAt = Date.now();
2553
2626
  st.chain = st.chain.then(async () => {
2554
2627
  try {
2555
2628
  const value = await opts.body();
@@ -2562,6 +2635,9 @@ function createClock(opts) {
2562
2635
  const msg = `✗ tick 异常: ${String(err?.message ?? err)}`;
2563
2636
  if (opts.logFrom) runtime.lastTickLog = [msg];
2564
2637
  console.warn(`[serenity-hooks] ${msg}(${opts.label})`);
2638
+ } finally {
2639
+ st.tickPending = false;
2640
+ st.tickStartedAt = null;
2565
2641
  }
2566
2642
  });
2567
2643
  };
@@ -2576,12 +2652,12 @@ function createClock(opts) {
2576
2652
  attachClockEvents(opts.ctx, api, opts.events);
2577
2653
  }
2578
2654
  if (opts.gate !== void 0 && !opts.gate()) return;
2579
- st.timer = setInterval(tick, TICK_MS);
2655
+ st.timer = setInterval(skipOrRun, TICK_MS);
2580
2656
  st.timer.unref();
2581
2657
  runtime.armed = true;
2582
2658
  runtime.armedAt = Date.now();
2583
2659
  console.log(opts.startLog());
2584
- if (opts.immediate !== false) tick();
2660
+ if (opts.immediate !== false) skipOrRun();
2585
2661
  };
2586
2662
  const dispose = () => {
2587
2663
  if (st.timer) {
@@ -2621,6 +2697,9 @@ function createClock(opts) {
2621
2697
  runtime.lastSkipReason = null;
2622
2698
  if (opts.logFrom) runtime.lastTickLog = [];
2623
2699
  st.wired = false;
2700
+ st.tickPending = false;
2701
+ st.tickStartedAt = null;
2702
+ skipCount = 0;
2624
2703
  opts.onReset?.();
2625
2704
  }
2626
2705
  };
@@ -2631,7 +2710,7 @@ function createClock(opts) {
2631
2710
  /**
2632
2711
  * wake/scheduler.ts — 认知轨迹唤醒调度器(D58/D59/D60;S142 2026-09-13)
2633
2712
  *
2634
- * 一个**中心调度器**(5min tick,复用 autopilot 的节律常量),处理 CCC 唤醒注册表里
2713
+ * 一个**中心调度器**(60s tick,2026-11-02 owner 令「整体都是 60 秒」),处理 CCC 唤醒注册表里
2635
2714
  * 到期的条目:把「未来时刻 + 一条 message」投递给目标认知轨迹,**fire-and-forget**
2636
2715
  * (无阻塞、无等待、无回执——发起方不 await,调度器不替模型结果负责)。
2637
2716
  *
@@ -2716,7 +2795,7 @@ const clockOpts = {
2716
2795
  prefix: "[serenity-hooks] 认知轨迹唤醒 ",
2717
2796
  lines: (lines) => lines
2718
2797
  },
2719
- startLog: () => "[serenity-hooks] ✓ 认知轨迹唤醒调度器启动(5min tick)"
2798
+ startLog: () => "[serenity-hooks] ✓ 认知轨迹唤醒调度器启动(60s tick)"
2720
2799
  };
2721
2800
  const clock = createClock(clockOpts);
2722
2801
  /** 调度器进程态快照(只读)。
@@ -2785,16 +2864,27 @@ async function acquireWakeAgent(ctx, root, dirName) {
2785
2864
  }
2786
2865
  /** 唤醒消息(唤起即投递正文:身份锚定 + 唤醒信息 + 任务) */
2787
2866
  function buildWakeText(entry, target) {
2867
+ /**
2868
+ * 🔴 2026-11-02 §D1(owner 令「精简注入提示词模板尺寸」+ Q3「全砍」):**356 → 89 码点**。
2869
+ *
2870
+ * 砍掉的四类(判据 = 「这条信息能不能帮**目标**决定下一步怎么做」,D150):
2871
+ * ① **审计信息**(`登记于`/`id`)—— 那是给人回溯注册表用的,目标拿到它无从行动;
2872
+ * ② **身份锚定整句**(`继续 <目录名> 的认知轨迹(SESSION.md: <绝对路径>)`)——
2873
+ * 目标**本来就知道**自己在哪条轨迹(它就是这个会话),重复一遍是纯噪声;
2874
+ * ③ 一节空行+`唤醒信息:`标签 —— 标签本身不含信息,正文紧接其上即可;
2875
+ * ④ 末尾`任务:按上述唤醒信息继续…` —— 与正文同义反复。
2876
+ *
2877
+ * 🔴 **必须保留的三件**(每一件都有过代价):
2878
+ * · **`[认知轨迹唤醒]` 标记** —— 与另外两种来源区分,缺了目标会把注入当成人类发言;
2879
+ * · **当前时间**(v1.39.2 owner 令)—— 冷载入的目标上下文里**没有任何近期时间锚**;
2880
+ * · **发起者** —— 目标要能判断"这是谁叫我",且测试反向钉住"不得冒充其他来源"。
2881
+ *
2882
+ * ⚠️ `entry.createdAt` / `entry.id` 不再进正文(仍完整保存在注册表里,回溯走那里)。
2883
+ */
2788
2884
  return [
2789
- `[认知轨迹唤醒] 到点(登记于 ${entry.createdAt},发起者 ${entry.createdBy || "未知"},id ${entry.id})。`,
2790
- `当前时间:${localHuman()}(当地时区)。`,
2791
- "",
2792
- `身份锚定:继续 ${target.dirName} 的认知轨迹(SESSION.md: ${target.mdPath})。`,
2793
- "",
2794
- "唤醒信息:",
2795
- entry.message,
2885
+ `[认知轨迹唤醒] 到点(来自 ${entry.createdBy || "未知"})。当前时间:${localHuman()}(当地时区)。`,
2796
2886
  "",
2797
- "任务:按上述唤醒信息继续本轨迹的工作;完成后把进展写入 SESSION.md。"
2887
+ entry.message
2798
2888
  ].join("\n");
2799
2889
  }
2800
2890
  /**
@@ -2851,12 +2941,7 @@ function buildSendText(target, message, sender) {
2851
2941
  return [
2852
2942
  `[即时消息] 来自 ${sender || "未知轨迹"}。当前时间:${localHuman()}(当地时区)。`,
2853
2943
  "",
2854
- `身份锚定:继续 ${target.dirName} 的认知轨迹(SESSION.md: ${target.mdPath})。`,
2855
- "",
2856
- "消息:",
2857
- message,
2858
- "",
2859
- "说明:这是**即时投递**(不是到点唤醒)——它**不排队**:目标正在跑轮次就**当场注入当前轮**,目标空闲则立即起一轮。处理完照常把进展写入 SESSION.md。"
2944
+ message
2860
2945
  ].join("\n");
2861
2946
  }
2862
2947
  /**
@@ -3219,17 +3304,11 @@ async function collectWakeCccs(ctx) {
3219
3304
  */
3220
3305
  function buildCroWakeText(dirName, mdPath, prompt, reason) {
3221
3306
  return [
3222
- `[CRO 唤起] ${dirName} 自带的 continuous-re-occurrence.ts 判定:现在该唤起。`,
3223
- `当前时间:${localHuman()}(当地时区)。`,
3224
- "",
3225
- `身份锚定:继续 ${dirName} 的认知轨迹(SESSION.md: ${mdPath})。`,
3307
+ `[CRO 唤起] 本轨迹自带的 CRO 程序判定:现在该唤起。当前时间:${localHuman()}(当地时区)。`,
3226
3308
  "",
3227
3309
  `判定理由:${reason ?? "(程序未提供 reason —— 见 CRO 编写指南 §7 坑 3)"}`,
3228
3310
  "",
3229
- "唤起提示词:",
3230
- prompt,
3231
- "",
3232
- "说明:这是由**本轨迹自己的 CRO 程序**按当时情况做的判定(**不是**定时唤醒,**也不是**别人发的消息)。处理完照常把进展写入 SESSION.md。"
3311
+ prompt
3233
3312
  ].join("\n");
3234
3313
  }
3235
3314
  /**
@@ -3323,6 +3402,45 @@ async function deliverCroWake(ctx, root, dirName, prompt, reason) {
3323
3402
  };
3324
3403
  }
3325
3404
  /**
3405
+ * CRO 阶段**受控并发**上限(2026-11-02 owner 令「整体节律 60 秒」的准入条件)。
3406
+ *
3407
+ * 🔴 为什么必须并发:CRO 每条 **spawn 一个子进程**,单条硬超时 60s(`cro/core.ts:68`)。
3408
+ * 修前 `for … await` 串行 ⇒ 最坏一拍 = N × 60s。实测 N ≥ 8(本机各 CCC 的并集,
3409
+ * 枚举走全机 CCC 并集)⇒ **最坏 480s**。
3410
+ * 节拍降到 60s 后,480s 一拍 = 积 8 拍,而拍子**排队不丢只积** ⇒ 调度器**静默永久追不上**。
3411
+ * 并发化把墙上时间从 `Σ` 降到 `max`(≈60s)。
3412
+ *
3413
+ * 🔴 为什么**不设成 8(全并发)**:
3414
+ * · 每条是完整 `bun`/`node` 运行时(实测 `bun` 二进制 92 MB)⇒ 8 条同时起是几百 MB 尖峰;
3415
+ * · 更危险的是**行为挤兑**:网络一恢复,8 条可能**同时**判 `wake` ⇒ 同时唤醒 8 条轨迹
3416
+ * ⇒ 挤兑宿主模型配额。上限 4 把两者压住,仍足以把 480s 压到 2 轮 ≈120s。
3417
+ *
3418
+ * ⚠️ 调此值的判据:**保持 `ceil(N / 上限) × 单条超时 < 节拍`** 才叫"跑得完"。
3419
+ * 60s 节拍、N=8、上限 4 ⇒ 2 × 60 = 120s **仍大于 60s** ⇒ ⛔ 别以为并发调大就不需要跳拍。
3420
+ */
3421
+ const CRO_CONCURRENCY = 4;
3422
+ /**
3423
+ * 受控并发跑一组异步任务(极小实现,**不引入依赖**)。
3424
+ *
3425
+ * 语义对齐 `Promise.allSettled`:**永不抛**,单条失败不影响其余(CRO 旁路容忍铁律)。
3426
+ * ⚠️ 结果按**原索引**回填 ⇒ 调用方按 `dirs` 顺序读时不会错配。
3427
+ */
3428
+ async function mapWithConcurrency(items, limit, worker) {
3429
+ const results = new Array(items.length);
3430
+ let cursor = 0;
3431
+ const width = Math.max(1, Math.min(limit, items.length));
3432
+ const runners = Array.from({ length: width }, async () => {
3433
+ for (;;) {
3434
+ const i = cursor;
3435
+ cursor += 1;
3436
+ if (i >= items.length) return;
3437
+ results[i] = await worker(items[i], i);
3438
+ }
3439
+ });
3440
+ await Promise.all(runners);
3441
+ return results;
3442
+ }
3443
+ /**
3326
3444
  * CRO 阶段:本 tick 对**每条启用了 CRO 的轨迹**跑一次它自带的程序,按判定投递。
3327
3445
  *
3328
3446
  * ## 为什么放在既有投递**之后**(R↓)
@@ -3364,80 +3482,84 @@ async function runCroPhase(ctx, root, registry, log) {
3364
3482
  };
3365
3483
  const agents = hostAgents(ctx);
3366
3484
  const selfHost = safeHostname();
3367
- let hostSkips = 0;
3368
- let wakes = 0;
3369
- let quiet = 0;
3370
- let skips = 0;
3371
- for (const dirName of dirs) try {
3372
- const verdict = resolveCroHostBinding(root, dirName, selfHost);
3373
- if (!verdict.allowed) {
3374
- hostSkips += 1;
3375
- log.push(`· ${root}: ${dirName}: CRO 机器绑定未通过(${verdict.code}):${verdict.detail}`);
3376
- continue;
3377
- }
3378
- const bound = listBoundSessionIds(root, dirName, hostAliveProbe(ctx));
3379
- const running = runningCarriersOf(bound, nowMs);
3380
- const outcome = await evaluateCro(root, dirName, readCroSnapshotInput(root, dirName, nowMs, {
3381
- boundSessionIds: bound,
3382
- liveSessionIds: bound.filter((id) => Boolean(agents?.get?.(id))),
3383
- runningSessionIds: running,
3384
- pendingWakes: registry.filter((e) => e.state === "pending" && resolveWakeTarget(root, e.target)?.dirName === dirName).map((e) => ({
3485
+ const outcomes = await mapWithConcurrency(dirs, CRO_CONCURRENCY, async (dirName) => {
3486
+ try {
3487
+ const verdict = resolveCroHostBinding(root, dirName, selfHost);
3488
+ if (!verdict.allowed) {
3489
+ log.push(`· ${root}: ${dirName}: CRO 机器绑定未通过(${verdict.code}):${verdict.detail}`);
3490
+ return "host-skip";
3491
+ }
3492
+ const bound = listBoundSessionIds(root, dirName, hostAliveProbe(ctx));
3493
+ const running = runningCarriersOf(bound, nowMs);
3494
+ const live = bound.filter((id) => Boolean(agents?.get?.(id)));
3495
+ const pendingWakes = registry.filter((e) => e.state === "pending" && resolveWakeTarget(root, e.target)?.dirName === dirName).map((e) => ({
3385
3496
  id: e.id,
3386
3497
  at: e.at,
3387
3498
  createdAt: e.createdAt,
3388
3499
  createdBy: e.createdBy
3389
- })),
3390
- scheduler
3391
- }));
3392
- if (outcome.status === "wake") {
3393
- wakes += 1;
3394
- const res = await deliverCroWake(ctx, root, dirName, outcome.prompt, outcome.decision.reason);
3395
- log.push(`· ${root}: ${renderCroOutcome(dirName, outcome)} → ${res.ok ? "已投递" : `投递未成功:${res.detail}`}`);
3396
- {
3397
- const rec = appendCroWakeLog(root, dirName, {
3398
- ok: res.ok,
3399
- ...res.notReady === true ? { notReady: true } : {},
3400
- detail: res.detail,
3401
- tick: s.ticks,
3402
- reason: outcome.decision.reason ?? null,
3403
- prompt: outcome.prompt
3404
- }, nowMs);
3405
- if (!rec.ok) log.push(`· ${root}: ${dirName}: CRO 流水写入失败(已忽略,不影响投递): ${rec.error}`);
3406
- }
3407
- } else if (outcome.status === "skipped") {
3408
- skips += 1;
3409
- log.push(`· ${root}: ${renderCroOutcome(dirName, outcome)}`);
3410
- } else if (outcome.status === "no-wake") {
3411
- quiet += 1;
3412
- /**
3413
- * 🔴 **2026-10-23(A102):`no-wake` 也落盘。**
3414
- *
3415
- * 修前这里**只累加计数**、一个字都不写该轨迹的流水 ⇒ 流水**永久停在上一次真唤起处**。
3416
- * 实测后果(guard 轨迹,真机):它的 `cro-wake-log.log` 停在 `01:40:55`,
3417
- * owner 据此认为"守卫从那以后就没工作过"——而真相是它**此后每个 tick 都在被评估**,
3418
- * 只是判定为"不打扰"。⇒ **「我判了、只是不叫」与「我根本没被评估」在读数上完全一样。**
3419
- *
3420
- * 判据同 D209:**可以不出声地判"不打扰",但"判过"本身要留痕**。
3421
- * 四态:`ok` / `fail` / `not-ready` / `no-wake`。
3422
- *
3423
- * ⚠️ 与 `wake` 分支同一条硬约束:**写流水失败绝不影响投递与既有链路**(设计 §5 铁律)。
3424
- */
3425
- {
3426
- const rec = appendCroWakeLog(root, dirName, {
3427
- ok: false,
3428
- noWake: true,
3429
- detail: outcome.detail,
3430
- tick: s.ticks,
3431
- reason: outcome.decision.reason ?? null
3432
- }, nowMs);
3433
- if (!rec.ok) log.push(`· ${root}: ${dirName}: CRO 流水写入失败(已忽略,不影响既有链路): ${rec.error}`);
3500
+ }));
3501
+ const outcome = await evaluateCro(root, dirName, readCroSnapshotInput(root, dirName, nowMs, {
3502
+ boundSessionIds: bound,
3503
+ liveSessionIds: live,
3504
+ runningSessionIds: running,
3505
+ pendingWakes,
3506
+ scheduler
3507
+ }));
3508
+ if (outcome.status === "wake") {
3509
+ const res = await deliverCroWake(ctx, root, dirName, outcome.prompt, outcome.decision.reason);
3510
+ log.push(`· ${root}: ${renderCroOutcome(dirName, outcome)} → ${res.ok ? "已投递" : `投递未成功:${res.detail}`}`);
3511
+ {
3512
+ const rec = appendCroWakeLog(root, dirName, {
3513
+ ok: res.ok,
3514
+ ...res.notReady === true ? { notReady: true } : {},
3515
+ detail: res.detail,
3516
+ tick: s.ticks,
3517
+ reason: outcome.decision.reason ?? null,
3518
+ prompt: outcome.prompt
3519
+ }, nowMs);
3520
+ if (!rec.ok) log.push(`· ${root}: ${dirName}: CRO 流水写入失败(已忽略,不影响投递): ${rec.error}`);
3521
+ }
3522
+ return "wake";
3523
+ } else if (outcome.status === "skipped") {
3524
+ log.push(`· ${root}: ${renderCroOutcome(dirName, outcome)}`);
3525
+ return "skip";
3526
+ } else if (outcome.status === "no-wake") {
3527
+ /**
3528
+ * 🔴 **2026-10-23(A102):`no-wake` 也落盘。**
3529
+ *
3530
+ * 修前这里**只累加计数**、一个字都不写该轨迹的流水 ⇒ 流水**永久停在上一次真唤起处**。
3531
+ * 实测后果(guard 轨迹,真机):它的 `cro-wake-log.log` 停在 `01:40:55`,
3532
+ * owner 据此认为"守卫从那以后就没工作过"——而真相是它**此后每个 tick 都在被评估**,
3533
+ * 只是判定为"不打扰"。⇒ **「我判了、只是不叫」与「我根本没被评估」在读数上完全一样。**
3534
+ *
3535
+ * 判据同 D209:**可以不出声地判"不打扰",但"判过"本身要留痕**。
3536
+ * 四态:`ok` / `fail` / `not-ready` / `no-wake`。
3537
+ *
3538
+ * ⚠️ 与 `wake` 分支同一条硬约束:**写流水失败绝不影响投递与既有链路**(设计 §5 铁律)。
3539
+ */
3540
+ {
3541
+ const rec = appendCroWakeLog(root, dirName, {
3542
+ ok: false,
3543
+ noWake: true,
3544
+ detail: outcome.detail,
3545
+ tick: s.ticks,
3546
+ reason: outcome.decision.reason ?? null
3547
+ }, nowMs);
3548
+ if (!rec.ok) log.push(`· ${root}: ${dirName}: CRO 流水写入失败(已忽略,不影响既有链路): ${rec.error}`);
3549
+ }
3550
+ return "quiet";
3434
3551
  }
3552
+ return "skip";
3553
+ } catch (err) {
3554
+ log.push(`· ${root}: ${dirName}: CRO 内部异常(已忽略,不影响既有链路): ${String(err?.message ?? err)}`);
3555
+ return "skip";
3435
3556
  }
3436
- } catch (err) {
3437
- skips += 1;
3438
- log.push(`· ${root}: ${dirName}: CRO 内部异常(已忽略,不影响既有链路): ${String(err?.message ?? err)}`);
3439
- }
3440
- log.push(`· ${root}: CRO 评估 ${dirs.length} 条(唤起 ${wakes},不唤起 ${quiet},跳过 ${skips}${hostSkips > 0 ? `,非本机绑定 ${hostSkips}` : ""})`);
3557
+ });
3558
+ const hostSkips = outcomes.filter((o) => o === "host-skip").length;
3559
+ const wakes = outcomes.filter((o) => o === "wake").length;
3560
+ const quiet = outcomes.filter((o) => o === "quiet").length;
3561
+ const skips = outcomes.filter((o) => o === "skip").length;
3562
+ log.push(`· ${root}: CRO 评估 ${dirs.length} 条(唤起 ${wakes},不唤起 ${quiet},跳过 ${skips}${hostSkips > 0 ? `,非本机绑定 ${hostSkips}` : ""};并发上限 ${CRO_CONCURRENCY})`);
3441
3563
  }
3442
3564
  /**
3443
3565
  * 取本机机器名(**永不抛**)。
@@ -3600,4 +3722,4 @@ function registerWakeScheduler(ctx) {
3600
3722
  registerDisposer(ctx, "认知轨迹唤醒调度器", () => clock.dispose());
3601
3723
  }
3602
3724
  //#endregion
3603
- export { DEFAULT_LOOKBACK_MS as a, scanInterruptedSessions as c, registerDisposer as d, buildCroSnapshot as f, listWakes as g, addWake as h, wakeSchedulerState as i, listRunningSessionIds as l, WAKE_CATCH_UP_MS as m, scheduler_exports as n, createResumeOne as o, listCroCognitiveTrajectories as p, sendToCognitiveTrajectory as r, projectDirNameForCwd as s, registerWakeScheduler as t, registerCroTurnTracking as u };
3725
+ export { listWakes as _, DEFAULT_LOOKBACK_MS as a, scanInterruptedSessions as c, registerDisposer as d, buildCroSnapshot as f, addWake as g, WAKE_CATCH_UP_MS as h, wakeSchedulerState as i, listRunningSessionIds as l, CARRIER_OPENING_MARK as m, scheduler_exports as n, createResumeOne as o, listCroCognitiveTrajectories as p, sendToCognitiveTrajectory as r, projectDirNameForCwd as s, registerWakeScheduler as t, registerCroTurnTracking as u };
@@ -1,10 +1,10 @@
1
- import { d as hostSessions, r as cccRootForCwd } from "./ccc-roots-DPMwBywc.js";
2
- import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.js";
1
+ import { d as hostSessions, r as cccRootForCwd } from "./ccc-roots-CsSSQjSS.js";
2
+ import { m as readTrajectorySubscriptions } from "./ccc-x94FCzOv.js";
3
3
  import { F as isoLocal, w as sessionEvents } from "./bind-file-B0TuOP89.js";
4
- import { m as WAKE_CATCH_UP_MS, p as listCroCognitiveTrajectories } from "./scheduler-B0pB9mxI.js";
5
- import { n as readSimpleSettings } from "./settings-DY4_DYYY.js";
6
- import { i as subscriptionStats, r as subscriptionEval } from "./subscriptions-DBR99OVm.js";
7
- import { containerClocks, containerWakes } from "./observation-BWpkA865.js";
4
+ import { h as WAKE_CATCH_UP_MS, p as listCroCognitiveTrajectories } from "./scheduler-CB06u0Qc.js";
5
+ import { n as readSimpleSettings } from "./settings-DibHCfEU.js";
6
+ import { i as subscriptionStats, r as subscriptionEval } from "./subscriptions-D05XffxT.js";
7
+ import { containerClocks, containerWakes } from "./observation-BKsS1Qke.js";
8
8
  //#region src/trajectory/live.ts
9
9
  /**
10
10
  * trajectory/live.ts — 进程内 live 会话取数 + 精简诊断
@@ -1,4 +1,4 @@
1
- import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-BmpE3cQz.js";
1
+ import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-x94FCzOv.js";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
4
4
  //#region src/tools/localstore/service.ts
@@ -1,10 +1,10 @@
1
- import { c as hostAgents, n as agentCwdFor, r as cccRootForCwd, s as hostAgentDefaultModel } from "./ccc-roots-DPMwBywc.js";
2
- import { f as readCognitiveTrajectorySkills, h as readUtf8, o as isSafeModeOn, u as readBlacklist } from "./ccc-BmpE3cQz.js";
1
+ import { c as hostAgents, n as agentCwdFor, r as cccRootForCwd, s as hostAgentDefaultModel } from "./ccc-roots-CsSSQjSS.js";
2
+ import { f as readCognitiveTrajectorySkills, g as readUtf8, o as isSafeModeOn, u as readBlacklist } from "./ccc-x94FCzOv.js";
3
3
  import { F as isoLocal, T as sessionsRoot, s as DEFAULT_SESSION_SCOPE, x as readActiveSessionMd } from "./bind-file-B0TuOP89.js";
4
- import { a as readGitTrack, i as localstorePath } from "./service-Z3aSR1cn.js";
5
- import { a as createProfilePromptReader, n as buildTrajectoryBasePrompt, o as profileMsmWhitelist, r as constraintCognitiveTrajectory, u as ACC_VERSION } from "./rules-BLkYTPUy.js";
6
- import { d as registerTrajectorySession$1, f as trajectoryDirNameForSession, o as readTrajectoryConstraintAt, p as unregisterTrajectorySession$1, u as trajectoryConstraintForSession } from "./profile-BjBn_-be.js";
7
- import { n as PLUGIN_SOURCE, o as readLastBound } from "./message-source-BTIe2cVO.js";
4
+ import { a as readGitTrack, i as localstorePath } from "./service-Dv-8E2bI.js";
5
+ import { a as createProfilePromptReader, n as buildTrajectoryBasePrompt, o as profileMsmWhitelist, r as constraintCognitiveTrajectory, u as ACC_VERSION } from "./rules-DKlpuFN_.js";
6
+ import { d as registerTrajectorySession$1, f as trajectoryDirNameForSession, o as readTrajectoryConstraintAt, p as unregisterTrajectorySession$1, u as trajectoryConstraintForSession } from "./profile-Djqz4Noy.js";
7
+ import { n as PLUGIN_SOURCE, s as readLastBound } from "./message-source-DLei3MqR.js";
8
8
  import { basename, dirname, join, resolve } from "node:path";
9
9
  import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
10
10
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
@@ -1504,7 +1504,7 @@ function toolsBlock() {
1504
1504
  "",
1505
1505
  " container_fs — container filesystem operations (14 subcommands: root/resolve/exists/list/tree/relative/mkdir/rm/mv/cp/touch/reveal/info/find)",
1506
1506
  " cognitive_trajectory — one cognitive 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 cognitive trajectory; fire-and-forget — no receipt, no recall) / cro-guide (the CRO programming guide: how to give THIS cognitive trajectory its own program that decides when it should be woken)",
1507
- " dashboard — always-on container instruments: health (CCC three-principle check + registry integrity) / time (now) / wait (N seconds)",
1507
+ " dashboard — always-on container instruments: health (CCC three-principle check + registry integrity) / time (now) / diag (runtime diagnosis)",
1508
1508
  " container_git— git operations (status/commit/push/log/pull/diff)",
1509
1509
  " msm — execute a registered CCC MSM: msm(name, args); partial name returns candidates; inspect=true shows usage",
1510
1510
  " praxis — actionable theory injection: praxis (index) / praxis eap / praxis neat / praxis cce / praxis ontology",
@@ -1,4 +1,4 @@
1
- import { f as hostSettings } from "./ccc-roots-DPMwBywc.js";
1
+ import { f as hostSettings } from "./ccc-roots-CsSSQjSS.js";
2
2
  //#region src/surface/settings.ts
3
3
  /**
4
4
  * 设置面板命名空间 = **profile 条目 id**(v0.1.7 起;与旧 `settings.yaml` 段名逐字相同)。
@@ -1,7 +1,7 @@
1
- import { r as cccRootForCwd } from "./ccc-roots-DPMwBywc.js";
2
- import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.js";
1
+ import { r as cccRootForCwd } from "./ccc-roots-CsSSQjSS.js";
2
+ import { m as readTrajectorySubscriptions } from "./ccc-x94FCzOv.js";
3
3
  import { L as localHuman, n as findTrajectoryHolding } from "./bind-file-B0TuOP89.js";
4
- import { d as registerDisposer } from "./scheduler-B0pB9mxI.js";
4
+ import { d as registerDisposer } from "./scheduler-CB06u0Qc.js";
5
5
  //#region src/trajectory/subscriptions.ts
6
6
  /**
7
7
  * trajectory/subscriptions.ts — 轨迹消息订阅(v1.107.0,owner 2026-11-01 令)
@@ -306,7 +306,7 @@ function defaultSubscriptionDeps(ctx) {
306
306
  readSubs: (root) => readTrajectorySubscriptions(root),
307
307
  dirForSession: (root, sessionId) => findTrajectoryHolding(`${root}/AGENT_SESSIONS`, sessionId),
308
308
  deliver: async (root, target, message) => {
309
- const { sendToCognitiveTrajectory } = await import("./scheduler-B0pB9mxI.js").then((n) => n.n);
309
+ const { sendToCognitiveTrajectory } = await import("./scheduler-CB06u0Qc.js").then((n) => n.n);
310
310
  const res = await sendToCognitiveTrajectory(ctx, root, target, message, "trajectory-subscription");
311
311
  return {
312
312
  ok: res.ok,
@@ -4,12 +4,17 @@
4
4
  * 行为对齐 osp(opencode-serenity-plugin/src/acc-kit.ts)——osp 是 ACC 工具 spec:
5
5
  * - health:{ccc, root, version, status: healthy|degraded, principles: {P1_rooted, P2_git_managed, P3_binary_permissions}}
6
6
  * - time:{now_iso, now_local, epoch_ms}
7
- * - wait:缺省 1s(正整数秒),返回 'waited Ns' 文本
8
7
  * 平台适配:P3 在 osp 检查 opencode.json,DSH 无 opencode.json → 检查 DSH/opencode 配置路径
9
8
  * (.opencode/serenity.json / .dsh/serenity.json 等,见 DEFAULT_SERENITY_CONFIG_PATHS)。
10
9
  * CCC 缺失时返回 degraded 报告而非抛错(对齐 osp 未激活语义)。
11
10
  * 保留 dsp 增强:accVersion/dshVersion 版本自省字段。
12
- * wait 用纯 Node setTimeout——不依赖外部 sleep 可执行文件(Windows 无 GNU coreutils sleep)。
11
+ *
12
+ * 🔴 `wait` 已于 2026-11-02 按 owner 令**整条砍掉**(原「砍掉 wait」令第一条)。
13
+ * 理由:它唯一的用途是"循环睡等长任务",而那正是 owner 反感的形态
14
+ * ——把一次等待摊成一串轮询,且**每睡一次都要占一轮模型上下文**。
15
+ * 替代表达:短延迟用 `send-later +0.5m`(`wake/registry.ts` 正则认小数分钟),
16
+ * 长任务用 `send-later` 排到点。⛔ 不要再把它加回来。
17
+ * ⚠️ ACC 自己的 `dashboard` 是"时钟",⛔ 不是"可用 sleep" —— 两者别混。
13
18
  *
14
19
  * C5「观察面归一」(S142 2026-09-15):本文件的 health **不再自己取数**——三原则、注册表结构判据、
15
20
  * 配置、宿主契约一律经 `surface/observation.ts` 取(唯一取数出口),本文件只把事实**渲染**成 osp
@@ -20,11 +25,10 @@
20
25
  * ⚠️ wire 形状**逐字不变**(字段名/取值/出现条件都不许动)——C5 是取数归一,不是文案改版。
21
26
  */
22
27
  import type { JsonValue } from '../../kernel/json.js';
23
- type KitAction = 'health' | 'time' | 'wait' | 'diag';
28
+ type KitAction = 'health' | 'time' | 'diag';
24
29
  export declare const KIT_ACTIONS: readonly KitAction[];
25
30
  interface KitArgs {
26
31
  action: KitAction;
27
- seconds?: number;
28
32
  }
29
33
  export declare function runKit(root: string | null, args: KitArgs, hostCtx?: unknown): Promise<JsonValue>;
30
34
  export {};