@shgroup/dsh-serenity-hooks 1.111.0 → 1.112.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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.111.0",
3
+ "version": "1.112.0",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——12 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/localstore/container_admin;另两个 im-bridge/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -185,7 +185,7 @@ Directory of ACC capabilities — each area lists where to go for details (guide
185
185
  ② 认知质量框架 → praxis(eap/neat/cce/ontology 四合一——可实践理论注入,section 渐进披露,无参即目录)
186
186
  ontology(v1.52 D121:本体工程**引擎**——init/check/explain/verify/review/compliance;
187
187
  与 praxis ontology 的分工 = 那个是**方法文本**、这个是**能跑的那个**)
188
- ③ 工具与执行 → container_fs(容器文件系统 15 子命令)/ container_git(git)/ dashboard(health 含注册表检查/time/wait)
188
+ ③ 工具与执行 → container_fs(容器文件系统 15 子命令)/ container_git(git)/ dashboard(health 含注册表检查/time/diag)
189
189
  acc_msm 已并入 msm(执行+发现)与 container_admin(管理)——msm("<name>", ["<args>"]);inspect=true 查用法
190
190
  (v1.106.0 已删 exclusiveTools 机制:原专属工具 acc-diag **已并入 dashboard diag**)
191
191
  ④ 轨迹约束与对外面 → container_admin config(轨迹约束四动作 guide/validate/apply/list——**原 role 域已并入 config**,旧名作过渡别名仍可用;说明类配置走**两层菜单** config docs 目录 / config docs <章节> 详情)
package/lib/index.js CHANGED
@@ -4,16 +4,16 @@ import { a as findSerenityRoot$1, d as readCccName, g as resolveInside, l as pat
4
4
  import { A as useSession, C as resolveSessionByTitle, D as showSession, E as setActiveSessionInfo, F as isoLocal, I as localFileStamp, M as TRAJECTORY_LEGACY_FILENAMES, O as summarize, S as readTrajectoryUid, T as sessionsRoot, _ as listSessions, b as parseTrajectoryCode, c as UID_FILENAME, d as createSession, f as extractSessionMdPathFromText, j as TRAJECTORY_FILENAME, k as trajectoryDescOf, l as archiveSession, m as getActiveSessionInfo, o as COGNITIVE_TRAJECTORY_ACTIONS, p as findSession, u as clearActiveSessionInfo, v as namingTitleFor, w as sessionEvents, y as parseSessionContextFromEvents } from "./bind-file-B0TuOP89.js";
5
5
  import { n as checkLocalstoreGitCompliance, o as readStore, s as runLocalStore, t as LOCALSTORE_SCOPES } from "./service-Z3aSR1cn.js";
6
6
  import { d as findPackageRoot, i as constraintSystemPromptSource, l as resolveConstraintSystemPrompt, r as constraintCognitiveTrajectory, t as TRAJECTORY_CONSTRAINT_HINT, u as ACC_VERSION } from "./rules-BLkYTPUy.js";
7
- import { C as docsPointer, E as setWeixinSendEndpoint, S as runMsmAsync, T as renderDocsIndex, _ as CCC_CONFIG_REFERENCE, a as setSafeMode, b as loadMsmEntries, d as forgetNonCccToolVisibility, g as ACC_CATALOG, h as forgetToolVisibility, i as readDshVersion, m as syncToolVisibility, n as summarizeHostContract, o as listOpencodeSkillDirs, p as registerGuards, r as getStatus, s as loadOpencodeSkill, t as hostContractReport, w as findDocsChapter, x as runMsm, y as findEntry } from "./contract-BiNzzd77.js";
7
+ import { C as docsPointer, E as setWeixinSendEndpoint, S as runMsmAsync, T as renderDocsIndex, _ as CCC_CONFIG_REFERENCE, a as setSafeMode, b as loadMsmEntries, d as forgetNonCccToolVisibility, g as ACC_CATALOG, h as forgetToolVisibility, i as readDshVersion, m as syncToolVisibility, n as summarizeHostContract, o as listOpencodeSkillDirs, p as registerGuards, r as getStatus, s as loadOpencodeSkill, t as hostContractReport, w as findDocsChapter, x as runMsm, y as findEntry } from "./contract-DtFUPbPg.js";
8
8
  import { c as replacesDefaultIdentity, i as listTrajectoryConstraints, l as trajectoryCodeForSession, n as findDirNameByCode, o as readTrajectoryConstraintAt, r as isTrajectoryConstrained, s as readTrajectoryConstraintByCode, t as TRAJECTORY_CONSTRAINT_FILENAME } from "./profile-BjBn_-be.js";
9
- import { A as truncateContent, C as verifyTotpCode, D as buildResourceIndex, E as SKILL_ONTOLOGY_FILE, M as hasTrajectoryPrompt, O as buildResourceNameSuffix, S as MECHANISM_PORTS, T as REFERENCE_DIR, _ as projectKnownWorkspaces, a as trajectoryConstraintFor, b as verifyPassword, c as trajectoryWorkspaceMdPath, d as splitModel, f as registerCognitiveTrajectorySkillSection, g as migrateLegacyLocalstore, h as applyWirePatch, i as getTrajectoryAgent, j as TRAJECTORY_PROMPT_FILENAME, k as isSafeSkillName, l as unregisterTrajectorySession, m as registerEntrySkillSectionGlobal, n as deliverToTrajectory, o as trajectoryConstraintMsmGate, p as registerEntrySkillSection, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as createTrajectoryAgent, u as workspaceCognitiveTrajectoryLine, v as readAdvancedSettings, w as recordToolUsage, x as FACE_PORTS, y as toWire } from "./session-BlgUdKH4.js";
9
+ import { A as truncateContent, C as verifyTotpCode, D as buildResourceIndex, E as SKILL_ONTOLOGY_FILE, M as hasTrajectoryPrompt, O as buildResourceNameSuffix, S as MECHANISM_PORTS, T as REFERENCE_DIR, _ as projectKnownWorkspaces, a as trajectoryConstraintFor, b as verifyPassword, c as trajectoryWorkspaceMdPath, d as splitModel, f as registerCognitiveTrajectorySkillSection, g as migrateLegacyLocalstore, h as applyWirePatch, i as getTrajectoryAgent, j as TRAJECTORY_PROMPT_FILENAME, k as isSafeSkillName, l as unregisterTrajectorySession, m as registerEntrySkillSectionGlobal, n as deliverToTrajectory, o as trajectoryConstraintMsmGate, p as registerEntrySkillSection, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as createTrajectoryAgent, u as workspaceCognitiveTrajectoryLine, v as readAdvancedSettings, w as recordToolUsage, x as FACE_PORTS, y as toWire } from "./session-DVvYS7z0.js";
10
10
  import { n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND } from "./message-source-BTIe2cVO.js";
11
- import { a as DEFAULT_LOOKBACK_MS, c as scanInterruptedSessions, d as registerDisposer, f as buildCroSnapshot, h as addWake, l as listRunningSessionIds, m as WAKE_CATCH_UP_MS, o as createResumeOne, r as sendToCognitiveTrajectory, s as projectDirNameForCwd, t as registerWakeScheduler, u as registerCroTurnTracking } from "./scheduler-B0pB9mxI.js";
11
+ import { a as DEFAULT_LOOKBACK_MS, c as scanInterruptedSessions, d as registerDisposer, f as buildCroSnapshot, h as addWake, l as listRunningSessionIds, m as WAKE_CATCH_UP_MS, o as createResumeOne, r as sendToCognitiveTrajectory, s as projectDirNameForCwd, t as registerWakeScheduler, u as registerCroTurnTracking } from "./scheduler-B-JpixMD.js";
12
12
  import { i as sessionsRootDir } from "./cleanup-CPl1SSaK.js";
13
13
  import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-DY4_DYYY.js";
14
14
  import { a as readFeishuCredential, c as readWeixinSettings, d as weixinInboundDir, f as weixinSessionIdForTrajectory, i as matchWeixinRoute, n as extractWeixinText, r as hasVoiceItem, s as readWeixinCredential, t as extractWeixinMedia, u as sanitizeFileName$1 } from "./route-reyv8qcB.js";
15
15
  import { i as runImBridge, n as isImWiredTrajectory, r as registerImChannel, t as imChannelIds } from "./channels-Dty_NIl_.js";
16
- import { i as subscriptionStats, n as registerTrajectorySubscriptions, r as subscriptionEval, t as defaultSubscriptionDeps } from "./subscriptions-DBR99OVm.js";
16
+ import { i as subscriptionStats, n as registerTrajectorySubscriptions, r as subscriptionEval, t as defaultSubscriptionDeps } from "./subscriptions-BMWAwpCn.js";
17
17
  import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-CsZ-f64q.js";
18
18
  import { a as registerImAccountImpl, i as normalizeAccountChannel, n as getImAccountImpl, r as imAccountChannels } from "./accounts-BHQbakUh.js";
19
19
  import { createRequire } from "node:module";
@@ -511,13 +511,12 @@ const ccFsTool = defineTool({
511
511
  const KIT_ACTIONS = [
512
512
  "health",
513
513
  "time",
514
- "wait",
515
514
  "diag"
516
515
  ];
517
516
  async function runKit(root, args, hostCtx) {
518
517
  switch (args.action) {
519
518
  case "health": {
520
- const { containerStatus } = await import("./observation-BWpkA865.js");
519
+ const { containerStatus } = await import("./observation-DzvyOI-A.js");
521
520
  const s = containerStatus({
522
521
  root,
523
522
  hostCtx
@@ -561,15 +560,9 @@ async function runKit(root, args, hostCtx) {
561
560
  epoch_ms: now.getTime()
562
561
  };
563
562
  }
564
- case "wait": {
565
- const seconds = args.seconds ?? 1;
566
- if (!Number.isInteger(seconds) || seconds <= 0) throw new Error("wait requires a positive integer number of seconds (default 1)");
567
- await new Promise((r) => setTimeout(r, seconds * 1e3));
568
- return `waited ${seconds}s`;
569
- }
570
563
  case "diag": {
571
564
  if (hostCtx === void 0) throw new Error("diag requires the plugin context (live session data unavailable without it)");
572
- const { runDiag, renderDiag } = await import("./service-CCzsVeN_.js");
565
+ const { runDiag, renderDiag } = await import("./service-CNzT-5Du.js");
573
566
  return renderDiag(await runDiag(hostCtx, root ?? ""));
574
567
  }
575
568
  default: throw new Error(`Unknown action: ${args.action}`);
@@ -593,19 +586,13 @@ function renderText$9(value) {
593
586
  function createKitTool(ctx) {
594
587
  return defineTool({
595
588
  name: "dashboard",
596
- description: "Dashboard — always-on container instruments (works any time, no side effects): health (CCC three-principle check P1/P2/config + MSM registry integrity + host-contract probe, healthy/degraded) / time (now_iso/now_local/epoch_ms) / wait (wait N seconds, default 1) / diag (ACC runtime diagnosis, read-only: live sessions across all CCCs / wake scheduler clock / CRO-enabled trajectories / wake registry split into future vs overdue / trajectory-subscription delivery readings). Routine self-check before entering a CCC.",
597
- parameters: {
598
- action: {
599
- type: "string",
600
- enum: [...KIT_ACTIONS],
601
- required: true,
602
- description: "Subcommand"
603
- },
604
- seconds: {
605
- type: "integer",
606
- description: "Seconds to wait (positive integer, default 1)"
607
- }
608
- },
589
+ description: "Dashboard — always-on container instruments (works any time, no side effects): health (CCC three-principle check P1/P2/config + MSM registry integrity + host-contract probe, healthy/degraded) / time (now_iso/now_local/epoch_ms) / diag (ACC runtime diagnosis, read-only: live sessions across all CCCs / wake scheduler clock / CRO-enabled trajectories / wake registry split into future vs overdue / trajectory-subscription delivery readings). Routine self-check before entering a CCC.",
590
+ parameters: { action: {
591
+ type: "string",
592
+ enum: [...KIT_ACTIONS],
593
+ required: true,
594
+ description: "Subcommand"
595
+ } },
609
596
  output: {
610
597
  schema: { type: "json" },
611
598
  render: (args, value) => renderText$9(value)
@@ -1,7 +1,7 @@
1
1
  import { d as readCccName, i as findGitRoot, l as pathInside, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-BmpE3cQz.js";
2
2
  import { u as ACC_VERSION } from "./rules-BLkYTPUy.js";
3
- import { i as readDshVersion, t as hostContractReport, v as checkRegistryQuality } from "./contract-BiNzzd77.js";
4
- import { g as listWakes, i as wakeSchedulerState } from "./scheduler-B0pB9mxI.js";
3
+ import { i as readDshVersion, t as hostContractReport, v as checkRegistryQuality } from "./contract-DtFUPbPg.js";
4
+ import { g as listWakes, i as wakeSchedulerState } from "./scheduler-B-JpixMD.js";
5
5
  import { resolve } from "node:path";
6
6
  import { existsSync, readFileSync, statSync } from "node:fs";
7
7
  //#region src/surface/observation.ts
@@ -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
  * 取本机机器名(**永不抛**)。
@@ -1,10 +1,10 @@
1
1
  import { d as hostSessions, r as cccRootForCwd } from "./ccc-roots-DPMwBywc.js";
2
2
  import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.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";
4
+ import { m as WAKE_CATCH_UP_MS, p as listCroCognitiveTrajectories } from "./scheduler-B-JpixMD.js";
5
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";
6
+ import { i as subscriptionStats, r as subscriptionEval } from "./subscriptions-BMWAwpCn.js";
7
+ import { containerClocks, containerWakes } from "./observation-DzvyOI-A.js";
8
8
  //#region src/trajectory/live.ts
9
9
  /**
10
10
  * trajectory/live.ts — 进程内 live 会话取数 + 精简诊断
@@ -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,7 +1,7 @@
1
1
  import { r as cccRootForCwd } from "./ccc-roots-DPMwBywc.js";
2
2
  import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.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-B-JpixMD.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-B-JpixMD.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 {};
@@ -17,7 +17,7 @@ export declare const MSM_ACTIONS: readonly MsmAction[];
17
17
  * `msm catalog` 动作**降为指针**(只指路,不再返回本常量)—— 否则同一份正文会有两个入口,
18
18
  * 而"两个入口返回同一份内容"正是本目录自己反对的形态。
19
19
  */
20
- export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u8F68\u8FF9\u672C\u4F53 \u2192 cognitive_trajectory\uFF08list/show/create/use + rebuild \u8D85\u9650\u91CD\u5EFA + send-now \u5373\u65F6\u6295\u9012 + send-later \u672A\u6765\u4E00\u6B21\u6027\u5524\u9192\n + cro-guide CRO \u7F16\u5199\u6307\u5357\uFF09\n \u539F logbook \u5DF2\u5E76\u5165\uFF08v1.33 \u7528\u6237\u88C1\u51B3\uFF1A\u5E9F\u9664 logbook \u8BCD\uFF09\uFF1Bclose/archive \u5220\uFF08\u5F52\u6863\u8D70 container_fs mv\uFF09\uFF0C\n health/qa/summary \u5206\u522B\u5E76\u5165 use / list\uFF0Chook-develop-guide \u5E76\u8FDB container_admin msm guide\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 praxis\uFF08eap/neat/cce/ontology \u56DB\u5408\u4E00\u2014\u2014\u53EF\u5B9E\u8DF5\u7406\u8BBA\u6CE8\u5165\uFF0Csection \u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u76EE\u5F55\uFF09\n ontology\uFF08v1.52 D121\uFF1A\u672C\u4F53\u5DE5\u7A0B**\u5F15\u64CE**\u2014\u2014init/check/explain/verify/review/compliance\uFF1B\n \u4E0E praxis ontology \u7684\u5206\u5DE5 = \u90A3\u4E2A\u662F**\u65B9\u6CD5\u6587\u672C**\u3001\u8FD9\u4E2A\u662F**\u80FD\u8DD1\u7684\u90A3\u4E2A**\uFF09\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 container_fs\uFF08\u5BB9\u5668\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ container_git\uFF08git\uFF09/ dashboard\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/wait\uFF09\n acc_msm \u5DF2\u5E76\u5165 msm\uFF08\u6267\u884C+\u53D1\u73B0\uFF09\u4E0E container_admin\uFF08\u7BA1\u7406\uFF09\u2014\u2014msm(\"<name>\", [\"<args>\"])\uFF1Binspect=true \u67E5\u7528\u6CD5\n \uFF08v1.106.0 \u5DF2\u5220 exclusiveTools \u673A\u5236\uFF1A\u539F\u4E13\u5C5E\u5DE5\u5177 acc-diag **\u5DF2\u5E76\u5165 dashboard diag**\uFF09\n \u2463 \u8F68\u8FF9\u7EA6\u675F\u4E0E\u5BF9\u5916\u9762 \u2192 container_admin config\uFF08\u8F68\u8FF9\u7EA6\u675F\u56DB\u52A8\u4F5C guide/validate/apply/list\u2014\u2014**\u539F role \u57DF\u5DF2\u5E76\u5165 config**\uFF0C\u65E7\u540D\u4F5C\u8FC7\u6E21\u522B\u540D\u4ECD\u53EF\u7528\uFF1B\u8BF4\u660E\u7C7B\u914D\u7F6E\u8D70**\u4E24\u5C42\u83DC\u5355** config docs \u76EE\u5F55 \uFF0F config docs <\u7AE0\u8282> \u8BE6\u60C5\uFF09\n \u5916\u90E8\u7A0B\u5E8F\u5316\u63A5\u5165\u7528\u5B98\u65B9 dsh --profile acp\n \uFF0B \u73B0\u6210 ACP \u5BA2\u6237\u7AEF\uFF1B\u672C\u63D2\u4EF6\u4E0D\u63D0\u4F9B ACP \u9762\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 cognitive_trajectory send-now\uFF08\u8DE8\u8F68\u8FF9\u7684**\u5373\u65F6**\u9012\u9001\uFF0C**\u4E0D\u6392\u961F**\uFF1Alive \u76EE\u6807\u5728\u8DD1\u5C31\u5F53\u573A\u6CE8\u5165\u5F53\u524D\u8F6E\u3001\u7A7A\u95F2\u5219\u7ACB\u5373\u8D77\u8F6E\uFF1B\u975E live \u51B7\u8F7D\u5165\u2014\u2014\u7B49\u6548\u4E8E\u76F4\u63A5 wake\uFF1B**\u6709\u540C\u6B65\u56DE\u6267**\uFF09\n cognitive_trajectory send-later\uFF08\u8DE8\u8F68\u8FF9\u7684\"\u672A\u6765\u65F6\u523B + \u4E00\u6761 message\"\uFF1Bfire-and-forget\uFF0C\u65E0\u56DE\u6267\u65E0\u56DE\u6536\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Amsm(\"weixin-doctor\", [\"guide\"])\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 container_admin config docs config\uFF08\u6309\u7AE0\u8BE6\u60C5\u2014\u20148 \u6BB5\u5168\u8868\uFF09\n \u6216 container_admin msm ccc-config\uFF08\u540C\u4E00\u4EFD\u6B63\u6587\u7684\u65E7\u5165\u53E3\uFF0C\u4FDD\u7559\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 container_admin msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n dashboard health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n CCC \u7EA7\u5F00\u5173\uFF1AsafeMode.blacklist\uFF08\u5199\u8DEF\u5F84\u9ED1\u540D\u5355\uFF09\n / safeMode.hiddenTools\uFF08**\u5B89\u5168\u6A21\u5F0F\u5F00\u542F\u671F\u95F4**\u989D\u5916\u9690\u85CF\u7684\u5DE5\u5177\uFF0Cv1.51.4\uFF09\n CCC \u7EA7 skill \u4F9B\u7ED9\uFF1AcognitiveTrajectory.skills\uFF08v1.44.0\u2014\u2014**\u672C CCC \u6BCF\u6761\u8F68\u8FF9\u90FD\u5E26**\uFF0C\u542B \u8F68\u8FF9\u7EA6\u675F\u4F1A\u8BDD\uFF1B\u4E0E\u8F68\u8FF9\u81EA\u5DF1\u7684 frontmatter \u58F0\u660E\u53D6\u5E76\u96C6\uFF09\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
20
+ export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u8F68\u8FF9\u672C\u4F53 \u2192 cognitive_trajectory\uFF08list/show/create/use + rebuild \u8D85\u9650\u91CD\u5EFA + send-now \u5373\u65F6\u6295\u9012 + send-later \u672A\u6765\u4E00\u6B21\u6027\u5524\u9192\n + cro-guide CRO \u7F16\u5199\u6307\u5357\uFF09\n \u539F logbook \u5DF2\u5E76\u5165\uFF08v1.33 \u7528\u6237\u88C1\u51B3\uFF1A\u5E9F\u9664 logbook \u8BCD\uFF09\uFF1Bclose/archive \u5220\uFF08\u5F52\u6863\u8D70 container_fs mv\uFF09\uFF0C\n health/qa/summary \u5206\u522B\u5E76\u5165 use / list\uFF0Chook-develop-guide \u5E76\u8FDB container_admin msm guide\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 praxis\uFF08eap/neat/cce/ontology \u56DB\u5408\u4E00\u2014\u2014\u53EF\u5B9E\u8DF5\u7406\u8BBA\u6CE8\u5165\uFF0Csection \u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u76EE\u5F55\uFF09\n ontology\uFF08v1.52 D121\uFF1A\u672C\u4F53\u5DE5\u7A0B**\u5F15\u64CE**\u2014\u2014init/check/explain/verify/review/compliance\uFF1B\n \u4E0E praxis ontology \u7684\u5206\u5DE5 = \u90A3\u4E2A\u662F**\u65B9\u6CD5\u6587\u672C**\u3001\u8FD9\u4E2A\u662F**\u80FD\u8DD1\u7684\u90A3\u4E2A**\uFF09\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 container_fs\uFF08\u5BB9\u5668\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ container_git\uFF08git\uFF09/ dashboard\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/diag\uFF09\n acc_msm \u5DF2\u5E76\u5165 msm\uFF08\u6267\u884C+\u53D1\u73B0\uFF09\u4E0E container_admin\uFF08\u7BA1\u7406\uFF09\u2014\u2014msm(\"<name>\", [\"<args>\"])\uFF1Binspect=true \u67E5\u7528\u6CD5\n \uFF08v1.106.0 \u5DF2\u5220 exclusiveTools \u673A\u5236\uFF1A\u539F\u4E13\u5C5E\u5DE5\u5177 acc-diag **\u5DF2\u5E76\u5165 dashboard diag**\uFF09\n \u2463 \u8F68\u8FF9\u7EA6\u675F\u4E0E\u5BF9\u5916\u9762 \u2192 container_admin config\uFF08\u8F68\u8FF9\u7EA6\u675F\u56DB\u52A8\u4F5C guide/validate/apply/list\u2014\u2014**\u539F role \u57DF\u5DF2\u5E76\u5165 config**\uFF0C\u65E7\u540D\u4F5C\u8FC7\u6E21\u522B\u540D\u4ECD\u53EF\u7528\uFF1B\u8BF4\u660E\u7C7B\u914D\u7F6E\u8D70**\u4E24\u5C42\u83DC\u5355** config docs \u76EE\u5F55 \uFF0F config docs <\u7AE0\u8282> \u8BE6\u60C5\uFF09\n \u5916\u90E8\u7A0B\u5E8F\u5316\u63A5\u5165\u7528\u5B98\u65B9 dsh --profile acp\n \uFF0B \u73B0\u6210 ACP \u5BA2\u6237\u7AEF\uFF1B\u672C\u63D2\u4EF6\u4E0D\u63D0\u4F9B ACP \u9762\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 cognitive_trajectory send-now\uFF08\u8DE8\u8F68\u8FF9\u7684**\u5373\u65F6**\u9012\u9001\uFF0C**\u4E0D\u6392\u961F**\uFF1Alive \u76EE\u6807\u5728\u8DD1\u5C31\u5F53\u573A\u6CE8\u5165\u5F53\u524D\u8F6E\u3001\u7A7A\u95F2\u5219\u7ACB\u5373\u8D77\u8F6E\uFF1B\u975E live \u51B7\u8F7D\u5165\u2014\u2014\u7B49\u6548\u4E8E\u76F4\u63A5 wake\uFF1B**\u6709\u540C\u6B65\u56DE\u6267**\uFF09\n cognitive_trajectory send-later\uFF08\u8DE8\u8F68\u8FF9\u7684\"\u672A\u6765\u65F6\u523B + \u4E00\u6761 message\"\uFF1Bfire-and-forget\uFF0C\u65E0\u56DE\u6267\u65E0\u56DE\u6536\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Amsm(\"weixin-doctor\", [\"guide\"])\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 container_admin config docs config\uFF08\u6309\u7AE0\u8BE6\u60C5\u2014\u20148 \u6BB5\u5168\u8868\uFF09\n \u6216 container_admin msm ccc-config\uFF08\u540C\u4E00\u4EFD\u6B63\u6587\u7684\u65E7\u5165\u53E3\uFF0C\u4FDD\u7559\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 container_admin msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n dashboard health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n CCC \u7EA7\u5F00\u5173\uFF1AsafeMode.blacklist\uFF08\u5199\u8DEF\u5F84\u9ED1\u540D\u5355\uFF09\n / safeMode.hiddenTools\uFF08**\u5B89\u5168\u6A21\u5F0F\u5F00\u542F\u671F\u95F4**\u989D\u5916\u9690\u85CF\u7684\u5DE5\u5177\uFF0Cv1.51.4\uFF09\n CCC \u7EA7 skill \u4F9B\u7ED9\uFF1AcognitiveTrajectory.skills\uFF08v1.44.0\u2014\u2014**\u672C CCC \u6BCF\u6761\u8F68\u8FF9\u90FD\u5E26**\uFF0C\u542B \u8F68\u8FF9\u7EA6\u675F\u4F1A\u8BDD\uFF1B\u4E0E\u8F68\u8FF9\u81EA\u5DF1\u7684 frontmatter \u58F0\u660E\u53D6\u5E76\u96C6\uFF09\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
21
21
  export declare const MSM_GUIDE = "MSM Development Manual (Mech & Semi-Mech framework)\n\n## What it is\nMSM = the executable-unit layer. Mech is pure TS with zero LLM reasoning; Semi-Mech is a TS framework + LLM decision points.\nMSM is ACC's deterministic executable-unit layer \u2014 all shell/exec operations go through MSM and cannot be bypassed.\n\n## Registering a new MSM (container_admin msm register)\n1. Write the script under <skill>/scripts/ (runnable via tsx; must include a main() CLI guard with an import.meta.url check)\n2. container_admin msm register --domain msm --action register <name> --skill <s> --path <script path relative to root> --category <mech|semi-mech> --description <desc>\n3. Auto-writes mech-registry.json (preserving the original format) + git commit (commits only the registry file)\n4. Validation: path must be inside root, script must exist, name must be globally unique\n\n## flag schema (v1)\nflags is a new-style object array for parameter validation and path-escape guarding:\n [{\"name\":\"output\",\"type\":\"string\",\"description\":\"output path\"},\n {\"name\":\"target\",\"type\":\"path\",\"description\":\"operation target (type:path enables in-root validation + symlink defense)\"},\n {\"name\":\"force\",\"type\":\"boolean\",\"description\":\"force mode\",\"default\":false}]\n- {name, type} format \u2014 new style, type:\"path\" enables the path-escape guard\n- {flag, description} format \u2014 old style, CLI flag description string\n- On registration, flags are passed via container_admin msm register --flags '<json>'\n\n## Script conventions\n- Top-of-file documentation: purpose / usage / exit codes\n- Exit codes: 0 success / 1 user / 2 system / 3 operator (per ACC protocol classification)\n- main() CLI guard (DC-M2): the script must start with\n if (import.meta.url === `file://${process.argv[1]}`) { main() }\n or an equivalent isMain / require.main === check \u2014 so vitest imports never trigger top-level code\n- A paired .test.ts or .spec.ts (DC-M1, vitest)\n- Business subprocess environment: SERENITY_ROOT / SERENITY_CCC / SERENITY_VERSION injected\n\n## Interaction & confirmation conventions (no blocking confirmation)\n- MSMs run in **user-less subprocesses** (spawn/execFile, 600s timeout) \u2014 **never** use\n readline / prompt / process.stdin etc. to block waiting for user input (it would hang until killed by the timeout)\n- When a second confirmation is needed: **directly return the confirmation request** (list the operation to perform and its impact + how to retry with the confirmation flag),\n returning a non-zero exit code (or an explicit hint)\n- After the agent confirms, **re-invoke the MSM with the confirmation flag** (e.g. --confirm / --yes / --force) to retry\n- Standard mode (two-phase):\n 1. First call: destructive/confirmation-requiring operation detected and no confirmation flag present \u2192 output the confirmation request (list operation/impact/rollback),\n exit non-zero (e.g. 1 user), **perform no changes**\n 2. After the agent evaluates, re-invoke: with the confirmation flag \u2192 execute and output the result\n- Applies to: delete/overwrite/push/batch operations and other irreversible or wide-impact operations\n- Anti-example (forbidden): readline waiting for user input, process.stdin.on('data') blocking waits\n (MSMs have no stdin interaction channel \u2014 they hang until the 600s timeout)\n\n## Quality checks (container_admin msm check, DC-M1~M4)\nDC-M1 has .test.ts/.spec.ts; DC-M2 has a main() guard (function main( / isMain / require.main === / import.meta.url);\nDC-M3 bidirectional: scripts unregistered + registry references missing scripts; DC-M4 path-type flags marked type:\"path\"\n\n## Self-description (protocol flags, first argument only)\nmsm(\"<name>\", [\"--list\"]) \u2014 list all MSMs\nmsm(\"<name>\", [\"--schema\", \"<n>\"]) \u2014 view a specific MSM's parameter schema\nmsm(\"<name>\", [\"--format=json\"]) \u2014 JSON output mode (remaining args passed through losslessly)\n";
22
22
  /**
23
23
  * CCC 配置参考(对齐 osp ccc-config action)。
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * wake/scheduler.ts — 认知轨迹唤醒调度器(D58/D59/D60;S142 2026-09-13)
3
3
  *
4
- * 一个**中心调度器**(5min tick,复用 autopilot 的节律常量),处理 CCC 唤醒注册表里
4
+ * 一个**中心调度器**(60s tick,2026-11-02 owner 令「整体都是 60 秒」),处理 CCC 唤醒注册表里
5
5
  * 到期的条目:把「未来时刻 + 一条 message」投递给目标认知轨迹,**fire-and-forget**
6
6
  * (无阻塞、无等待、无回执——发起方不 await,调度器不替模型结果负责)。
7
7
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.111.0",
3
+ "version": "1.112.0",
4
4
  "description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:12 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/localstore/container_admin;另两个 im-bridge/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
5
5
  "license": "MIT",
6
6
  "repository": {