@shgroup/dsh-serenity-hooks 1.73.0 → 1.74.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.
Files changed (46) hide show
  1. package/README.md +12 -11
  2. package/dsh.plugin.json +2 -2
  3. package/lib/accounts-BHQbakUh.js +33 -0
  4. package/lib/{ccc-CZUOq3NY.js → ccc-CyYJL4F2.js} +9 -9
  5. package/lib/{ccc-roots-BhoA7G-0.js → ccc-roots-B2t_aM8L.js} +4 -4
  6. package/lib/client.js +116 -1
  7. package/lib/cro/core.d.ts +1 -1
  8. package/lib/guard/seam.d.ts +4 -4
  9. package/lib/host/effect.d.ts +1 -1
  10. package/lib/im/bridge.d.ts +3 -3
  11. package/lib/im/endpoint.d.ts +2 -2
  12. package/lib/im/guard.d.ts +1 -1
  13. package/lib/im/hook.d.ts +1 -1
  14. package/lib/im/inbound-event.d.ts +6 -6
  15. package/lib/im/route.d.ts +25 -3
  16. package/lib/index.d.ts +5 -5
  17. package/lib/index.js +360 -265
  18. package/lib/kernel/ccc-roots.d.ts +4 -4
  19. package/lib/kernel/ccc.d.ts +19 -19
  20. package/lib/kernel/ports.d.ts +1 -1
  21. package/lib/{message-source-ChyVfev9.js → message-source-DCpoRHP3.js} +2 -2
  22. package/lib/patches/opencode-provider.d.ts +1 -1
  23. package/lib/{profile-BIQ2widI.js → profile-BVt84mbi.js} +59 -59
  24. package/lib/{route-ItCgAsnz.js → route-COOFLTpU.js} +44 -6
  25. package/lib/seams/guards.d.ts +14 -14
  26. package/lib/seams/keeper.d.ts +1 -1
  27. package/lib/seams/lifecycle.d.ts +2 -2
  28. package/lib/{settings-UcwIPJhM.js → settings-D8hlqxua.js} +40 -26
  29. package/lib/surface/faces.d.ts +1 -1
  30. package/lib/surface/http.d.ts +1 -1
  31. package/lib/surface/settings.d.ts +7 -7
  32. package/lib/surface/text.d.ts +3 -3
  33. package/lib/tools/config-docs.d.ts +53 -0
  34. package/lib/tools/container-admin.d.ts +19 -12
  35. package/lib/tools/msm/service.d.ts +7 -0
  36. package/lib/tools/trajectory-constraint-admin.d.ts +30 -0
  37. package/lib/trajectory/carrier.d.ts +1 -1
  38. package/lib/trajectory/core.d.ts +1 -1
  39. package/lib/trajectory/policy/profile.d.ts +36 -36
  40. package/lib/trajectory/policy/rules.d.ts +33 -20
  41. package/lib/trajectory/policy/window.d.ts +13 -13
  42. package/lib/trajectory/prompt.d.ts +12 -12
  43. package/lib/trajectory/rebuild.d.ts +2 -2
  44. package/lib/trajectory/session.d.ts +49 -49
  45. package/package.json +2 -2
  46. package/lib/tools/skiff-admin.d.ts +0 -30
@@ -83,9 +83,9 @@ export interface CccEntry {
83
83
  /** 目录名(展示用) */
84
84
  name: string;
85
85
  /**
86
- * 该 CCC 的 skiff 列表(**轨迹编码**;新模型里编码即身份)。
86
+ * 该 CCC 的 轨迹约束 列表(**轨迹编码**;新模型里编码即身份)。
87
87
  * ⚠️ **仅 `withRoles: true` 时非空**;缺省 `false` ⇒ 恒为 `[]` 且**不扫
88
- * `AGENT_SESSIONS/`**(唤醒调度器每 tick 都要枚举,不该为 skiff 付 IO)。
88
+ * `AGENT_SESSIONS/`**(唤醒调度器每 tick 都要枚举,不该为 轨迹约束 付 IO)。
89
89
  */
90
90
  roles: string[];
91
91
  }
@@ -95,7 +95,7 @@ export interface ListCccsOptions {
95
95
  * 传 `undefined`/`''` 表示没有默认根。
96
96
  */
97
97
  defaultRoot?: string;
98
- /** 是否实时扫各 CCC 的 skiff 轨迹(缺省 false)。 */
98
+ /** 是否实时扫各 CCC 的 轨迹约束轨迹(缺省 false)。 */
99
99
  withRoles?: boolean;
100
100
  }
101
101
  /**
@@ -110,7 +110,7 @@ export interface ListCccsOptions {
110
110
  * **整个列表都不含后者**("名单不全")。并集修正它,且**不改**任何消费方的输入契约。
111
111
  *
112
112
  * @param ctx 插件上下文
113
- * @param opts.defaultRoot 默认根(不在列表 → 置首);opts.withRoles 是否读 `skiff.roles`
113
+ * @param opts.defaultRoot 默认根(不在列表 → 置首);opts.withRoles 是否读 `轨迹约束.roles`
114
114
  * @returns 按上述顺序去重的 CCC 条目(无任何来源 → 空数组 + 可选默认根)
115
115
  */
116
116
  export declare function listCccs(ctx: unknown, opts?: ListCccsOptions): Promise<CccEntry[]>;
@@ -87,14 +87,14 @@ interface SerenityConfig {
87
87
  autoRestoreSession?: boolean;
88
88
  };
89
89
  /**
90
- * 🔴 **`skiff` 段已于 2026-10-19 退役**(owner 重做令)。
90
+ * 🔴 **`轨迹约束` 段已于 2026-10-19 退役**(owner 重做令)。
91
91
  *
92
- * skiff 不再是 `serenity.json` 里的一组角色定义,而是**带 `skiff.json` 的认知轨迹**
93
- * (约束面住在轨迹目录里)。⇒ 本段**不再被读取**:存量配置里残留的 `skiff.roles` ⇒
94
- * **静默忽略**(schemastery 非 strict,不报错;也不会被误当成"没有 skiff")。
92
+ * 轨迹约束 不再是 `serenity.json` 里的一组角色定义,而是**带 `trajectory-constraint.json` 的认知轨迹**
93
+ * (约束面住在轨迹目录里)。⇒ 本段**不再被读取**:存量配置里残留的 `轨迹约束.roles` ⇒
94
+ * **静默忽略**(schemastery 非 strict,不报错;也不会被误当成"没有 轨迹约束")。
95
95
  *
96
- * 迁移路径 = 把 `skiff.roles.<name>` 的内容原样搬进对应轨迹目录的 `skiff.json`
97
- * (判据与步骤见 `trajectory/policy/profile.ts` 头注释与 `docs/skiff-as-trajectory-redesign.md` §5)。
96
+ * 迁移路径 = 把 `轨迹约束.roles.<name>` 的内容原样搬进对应轨迹目录的 `trajectory-constraint.json`
97
+ * (判据与步骤见 `trajectory/policy/profile.ts` 头注释与 `docs/trajectory-constraint-redesign.md` §5)。
98
98
  */
99
99
  /**
100
100
  * 认知轨迹族配置(D58,S142 2026-09-13;2026-10-18 更名 `cognitiveTrajectory`)。
@@ -109,7 +109,7 @@ interface SerenityConfig {
109
109
  */
110
110
  cognitiveTrajectory?: {
111
111
  /**
112
- * **CCC 级 skill 供给**(v1.44.0;owner 令 2026-09-20:「要求实现我的诉求……skiff 也支持」)。
112
+ * **CCC 级 skill 供给**(v1.44.0;owner 令 2026-09-20:「要求实现我的诉求……轨迹约束也支持」)。
113
113
  *
114
114
  * 语义:**本 CCC 的每条轨迹都带这些 skill**——声明的 skill 全文在该轨迹**被绑定期间**
115
115
  * 动态注入系统提示词(每请求重新求值,不缓存)。与轨迹自己在 `SESSION.md` frontmatter
@@ -124,7 +124,7 @@ interface SerenityConfig {
124
124
  * 配置损坏本身已由 `loadSerenityConfig` 响亮告警(不静默)。
125
125
  *
126
126
  * ⚠️ 与 `create` 的关系:**不触发**——`create` 刻意不夺绑定(U6),注入的门是"存在绑定"。
127
- * ⚠️ 作用面:**含 skiff 角色会话**(它们同样绑定工作台轨迹)。
127
+ * ⚠️ 作用面:**含 轨迹约束角色会话**(它们同样绑定工作台轨迹)。
128
128
  */
129
129
  skills?: string[];
130
130
  };
@@ -223,7 +223,7 @@ export interface ImRouteConfig {
223
223
  * - 结构/路由/开关在 .opencode/serenity.json(git 管可重建)
224
224
  * - **bot_token 凭据在 CCC localstore**(weixin.accounts.<accountId>.token/.baseUrl/.userId)——
225
225
  * 扫码登录后插件自动写入(面板只显示"已绑定"),永不进 git 明文面
226
- * - 路由 user → role:exact 匹配优先,通配 `*` 兜底;role 必须是该 CCC skiff.roles 之一
226
+ * - 路由 user → role:exact 匹配优先,通配 `*` 兜底;role 必须是该 CCC 轨迹约束.roles 之一
227
227
  * - 多账号:accounts[] 每项 { accountId, name?, enabled }(本地唯一键,如 wechat-1)
228
228
  *
229
229
  * 🔴 2026-10-19:**本段已被统一 `im` 段取代**(见上方 `ImSettings`)。此处保留是因为
@@ -236,7 +236,7 @@ export interface WeixinSettings {
236
236
  botType?: string;
237
237
  /** 账号表(本地键 accountId;凭据在 localstore) */
238
238
  accounts?: WeixinAccountConfig[];
239
- /** 消息路由:微信用户 → 该 CCC 的 skiff role(不绑定具体 role——用户自选) */
239
+ /** 消息路由:微信用户 → 该 CCC 的 轨迹约束 role(不绑定具体 role——用户自选) */
240
240
  routes?: WeixinRouteConfig[];
241
241
  /**
242
242
  * 用户别名表(v1.56.10):`{ "<别名>": "<localstore 凭据键>" }`。
@@ -298,8 +298,8 @@ export interface WeixinAccountConfig {
298
298
  * 微信桥路由配置:微信用户 → 该 CCC 的**认知轨迹编码**
299
299
  *
300
300
  * 🔴 2026-10-19(owner 重做令):「微信桥的路由表修改为 **user → 认知轨迹的映射**」。
301
- * 旧形态指向 `skiff.roles` 里的**角色名**;新形态直接指向**轨迹编码**
302
- * (= 目录名固定位置那一段;该轨迹目录里有 `skiff.json` 时它就是 skiff)。
301
+ * 旧形态指向 `轨迹约束.roles` 里的**角色名**;新形态直接指向**轨迹编码**
302
+ * (= 目录名固定位置那一段;该轨迹目录里有 `trajectory-constraint.json` 时它就是 轨迹约束)。
303
303
  */
304
304
  export interface WeixinRouteConfig {
305
305
  /** 微信用户标识(from_user_id,形如 userA@im.wechat);`*` = 通配兜底 */
@@ -314,18 +314,18 @@ export interface WeixinRouteConfig {
314
314
  role?: string;
315
315
  }
316
316
  /**
317
- * 🔴 **`SkiffRoleConfig` 已于 2026-10-19 退役**(owner 重做令)。
317
+ * 🔴 **`TrajectoryConstraintConfig` 已于 2026-10-19 退役**(owner 重做令)。
318
318
  *
319
- * 它的语义整体搬进**轨迹目录下的 `skiff.json`**,类型现在是
320
- * `trajectory/policy/profile.ts` 的 `SkiffProfile`(在那里还多了 `code`/`dirName`/`path`
319
+ * 它的语义整体搬进**轨迹目录下的 `trajectory-constraint.json`**,类型现在是
320
+ * `trajectory/policy/profile.ts` 的 `TrajectoryConstraint`(在那里还多了 `code`/`dirName`/`path`
321
321
  * 三个与轨迹身份相关的字段)。
322
322
  *
323
- * 退役理由(一句话):skiff 的约束面是**某一条轨迹的属性**,不是容器级配置表里的一个 entry。
324
- * 放进 `serenity.json` 会让"这条轨迹是不是 skiff"分散在**两个文件**里,而 owner 要的是
325
- * 一条判据(「目录下拥有 `skiff.json` 的认知轨迹自动是一个 skiff」)。
323
+ * 退役理由(一句话):轨迹约束的约束面是**某一条轨迹的属性**,不是容器级配置表里的一个 entry。
324
+ * 放进 `serenity.json` 会让"这条轨迹是不是 轨迹约束"分散在**两个文件**里,而 owner 要的是
325
+ * 一条判据(「目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束」)。
326
326
  *
327
327
  * ⚠️ 旧字段里 `kind: temporary|persistent` **整件无对应物**:它区分"有没有工作台",
328
- * 而新模型里 skiff 恒等于一条轨迹 ⇒ 恒有 SESSION.md ⇒ 该区分没有指称对象(静默忽略)。
328
+ * 而新模型里 轨迹约束恒等于一条轨迹 ⇒ 恒有 SESSION.md ⇒ 该区分没有指称对象(静默忽略)。
329
329
  */
330
330
  /**
331
331
  * 解析 cheap-worker 配置。
@@ -36,7 +36,7 @@ export interface PortSpec {
36
36
  /**
37
37
  * 集中端口表。
38
38
  * A=宿主主面(插件不监听)/ B=网关(可配,默认关)/ C=微信发送(默认开,仅 loopback)
39
- * / D=Skiff 调试(默认关)。
39
+ * / D=轨迹约束调试(默认关)。
40
40
  */
41
41
  export declare const FACE_PORTS: Readonly<Record<FaceId, PortSpec>>;
42
42
  /** 宿主主 WebUI 端口(面 A:插件**不监听**,只读取;`readWebPort` 的回退值) */
@@ -1,5 +1,5 @@
1
- import { r as cccRootForCwd } from "./ccc-roots-BhoA7G-0.js";
2
- import { T as parseTrajectoryCode, b as getLastActiveSessionInfo, k as sessionEvents, y as getActiveSessionInfo } from "./profile-BIQ2widI.js";
1
+ import { r as cccRootForCwd } from "./ccc-roots-B2t_aM8L.js";
2
+ import { T as parseTrajectoryCode, b as getLastActiveSessionInfo, k as sessionEvents, y as getActiveSessionInfo } from "./profile-BVt84mbi.js";
3
3
  import { dirname, join } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
5
  //#region src/trajectory/bound.ts
@@ -191,7 +191,7 @@ export declare function applyOpencodeAutoConfigOnce(ctx: Context, env?: Readonly
191
191
  /**
192
192
  * 装配 opencode 路由自动配置。
193
193
  *
194
- * 触发面(三层,与 skiff 同款;R↓:单点触发在同装载竞态下必然漏):
194
+ * 触发面(三层,与 轨迹约束 同款;R↓:单点触发在同装载竞态下必然漏):
195
195
  * ① apply 时立即试一次
196
196
  * ② 命名空间尚未注册 → 退避重试(1s/3s/8s/20s/40s)
197
197
  * ③ `settings/updated` → 再试(用户热改 settings.yaml 加路由时自愈;自身写入触发的复评是幂等空转)
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
2
- import { _ as resolveInside, g as readUtf8 } from "./ccc-CZUOq3NY.js";
2
+ import { _ as resolveInside, g as readUtf8 } from "./ccc-CyYJL4F2.js";
3
3
  import { basename, dirname, join } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
5
5
  //#region src/kernel/time.ts
@@ -123,7 +123,7 @@ function localIdStamp(value = Date.now()) {
123
123
  *
124
124
  * ⚠️ 由此产生一条**必须成立**的配套:`readAllSessions` **跳过 `_` 前缀目录**。
125
125
  * 否则归档后的轨迹会继续出现在清单里,"归档"就不是归档了(历史 bug:`_weixin-logs` /
126
- * `_skiff-logs` / `_corpus` 曾被当成轨迹列出来)。
126
+ * `_轨迹约束-logs` / `_corpus` 曾被当成轨迹列出来)。
127
127
  */
128
128
  const COGNITIVE_TRAJECTORY_ACTIONS = [
129
129
  "list",
@@ -199,7 +199,7 @@ function readSessionEntry(dirPath) {
199
199
  * 读取 AGENT_SESSIONS 中所有**活跃**轨迹,按 mtime 降序。
200
200
  *
201
201
  * 🔴 **跳过 `_` 前缀目录**(2026-10-18 新增,与归档配套):
202
- * `_archived` 是归档区,`_skiff-logs` / `_weixin-logs` / `_corpus` 是**日志与数据区**——
202
+ * `_archived` 是归档区,`_轨迹约束-logs` / `_weixin-logs` / `_corpus` 是**日志与数据区**——
203
203
  * 它们**都不是轨迹**。旧实现会把它们当轨迹列出来(历史 bug)。
204
204
  * 没有这条,归档后的轨迹仍会出现在清单里 ⇒ **"归档"名不副实**。
205
205
  *
@@ -751,74 +751,74 @@ function archiveSession(root, key, dryRun = false) {
751
751
  }
752
752
  //#endregion
753
753
  //#region src/trajectory/policy/window.ts
754
- const skiffSessions = /* @__PURE__ */ new Map();
754
+ const 轨迹约束Sessions = /* @__PURE__ */ new Map();
755
755
  /** 登记/更新一个会话 → 轨迹的映射 */
756
- function registerSkiffSession(sessionId, trajectoryDirName, ccc) {
757
- skiffSessions.set(sessionId, {
756
+ function registerTrajectorySession(sessionId, trajectoryDirName, ccc) {
757
+ 轨迹约束Sessions.set(sessionId, {
758
758
  trajectoryDirName,
759
759
  ccc
760
760
  });
761
761
  }
762
762
  /** 解绑(会话销毁 / 轨迹失效 ⇒ 换身份) */
763
- function unregisterSkiffSession(sessionId) {
764
- skiffSessions.delete(sessionId);
763
+ function unregisterTrajectorySession(sessionId) {
764
+ 轨迹约束Sessions.delete(sessionId);
765
765
  }
766
766
  /** 查会话承载的轨迹目录名(无 → null);`guards`/`system-prompt` 的同步热路径用 */
767
- function skiffTrajectoryDirNameFor(sessionId) {
768
- const b = skiffSessions.get(sessionId);
767
+ function trajectoryDirNameForSession(sessionId) {
768
+ const b = 轨迹约束Sessions.get(sessionId);
769
769
  return b === void 0 || b.trajectoryDirName === "" ? null : b.trajectoryDirName;
770
770
  }
771
771
  //#endregion
772
772
  //#region src/trajectory/policy/profile.ts
773
773
  /**
774
- * trajectory/policy/profile.ts — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
774
+ * trajectory/policy/profile.ts — **轨迹约束的唯一判据**:目录下有 `trajectory-constraint.json` 的认知轨迹(零 DSH 依赖,可独立单测)
775
775
  *
776
776
  * ## 🔴 owner 2026-10-19 重做令(逐字,本文件存在的全部理由)
777
777
  *
778
- * > 「skiff 复杂的约束和提示词体系都干掉,改为这样的实现:
779
- * > **skiff 本身是认知轨迹的一个特殊情况,即目录下拥有 `skiff.json` 的认知轨迹自动是一个 skiff**
780
- * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `skiff.json`,则运行时实现各类约束**」
778
+ * > 「轨迹约束 复杂的约束和提示词体系都干掉,改为这样的实现:
779
+ * > **轨迹约束本身是认知轨迹的一个特殊情况,即目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束**
780
+ * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `trajectory-constraint.json`,则运行时实现各类约束**」
781
781
  *
782
782
  * ## 旧模型 → 新模型(**一条判据取代四条**)
783
783
  *
784
784
  * | 项 | 旧 | 新 |
785
785
  * |---|---|---|
786
- * | skiff 是什么 | `serenity.json` 的 `skiff.roles.<name>` 一条配置 | **轨迹目录里有 `skiff.json`** |
787
- * | 怎么认出 skiff 会话 | dsh sessionId 前缀 `skiff-` | **它绑定的轨迹有 `skiff.json`** |
788
- * | 工作台从哪来 | `ensureSkiffSession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
786
+ * | 轨迹约束是什么 | `serenity.json` 的 `轨迹约束.roles.<name>` 一条配置 | **轨迹目录里有 `trajectory-constraint.json`** |
787
+ * | 怎么认出 轨迹约束会话 | dsh sessionId 前缀 `轨迹约束-` | **它绑定的轨迹有 `trajectory-constraint.json`** |
788
+ * | 工作台从哪来 | `ensureTrajectorySession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
789
789
  * | 身份 | 角色名 | **轨迹编码**(`trajectory/core.ts` 的 `parseTrajectoryCode`) |
790
790
  *
791
791
  * ⇒ 收益(owner:「理解难度大幅下降」的实际内容):四个各自会漂的机制收敛为**一条文件存在性判据**。
792
- * 删掉 `skiff.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
792
+ * 删掉 `trajectory-constraint.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
793
793
  *
794
794
  * ## 归属(D23)
795
795
  * **机制在 ACC**(文件叫什么、怎么读、怎么判、缺省值、如何施加约束);
796
- * **内容在 CCC**(`skiff.json` 里填什么:模型、白名单、提示词路径)。
797
- * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 skiff 段(该段已退役)。
796
+ * **内容在 CCC**(`trajectory-constraint.json` 里填什么:模型、白名单、提示词路径)。
797
+ * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 轨迹约束段(该段已退役)。
798
798
  *
799
- * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/skiff/` 下(该目录已随本重构消失)
799
+ * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/轨迹约束/` 下(该目录已随本重构消失)
800
800
  *
801
801
  * 落点 = `trajectory/policy/`。判据(判读表 §3.1):本文件判的是**某条轨迹的约束面**,
802
802
  * 主语是轨迹 ⇒ 它一直就是轨迹切面,只是旧目录把它挂在"角色"这个**平行概念**下。
803
- * ⚠️ **文件名 `profile` 与 `skiff.json` / `SkiffProfile` 等符号名一律不动**:
803
+ * ⚠️ **文件名 `profile` 与 `trajectory-constraint.json` / `TrajectoryConstraint` 等符号名一律不动**:
804
804
  * 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
805
805
  */
806
806
  var profile_exports = /* @__PURE__ */ __exportAll({
807
- SKIFF_PROFILE_FILENAME: () => SKIFF_PROFILE_FILENAME,
807
+ TRAJECTORY_CONSTRAINT_FILENAME: () => TRAJECTORY_CONSTRAINT_FILENAME,
808
808
  findDirNameByCode: () => findDirNameByCode,
809
- isSkiffSession: () => isSkiffSession,
810
- listSkiffProfiles: () => listSkiffProfiles,
811
- readSkiffProfileAt: () => readSkiffProfileAt,
812
- readSkiffProfileByCode: () => readSkiffProfileByCode,
813
- skiffProfileForSession: () => skiffProfileForSession
809
+ isTrajectoryConstrained: () => isTrajectoryConstrained,
810
+ listTrajectoryConstraints: () => listTrajectoryConstraints,
811
+ readTrajectoryConstraintAt: () => readTrajectoryConstraintAt,
812
+ readTrajectoryConstraintByCode: () => readTrajectoryConstraintByCode,
813
+ trajectoryConstraintForSession: () => trajectoryConstraintForSession
814
814
  });
815
- /** `skiff.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
816
- const SKIFF_PROFILE_FILENAME = "skiff.json";
815
+ /** `trajectory-constraint.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
816
+ const TRAJECTORY_CONSTRAINT_FILENAME = "trajectory-constraint.json";
817
817
  /**
818
- * 已告警过的坏 `skiff.json`(进程级去重:同一坏文件不刷屏,但**绝不静默**)。
818
+ * 已告警过的坏 `trajectory-constraint.json`(进程级去重:同一坏文件不刷屏,但**绝不静默**)。
819
819
  *
820
820
  * 🔴 为什么必须响亮(同源先例 = `loadSerenityConfig` 的 F-07):一份坏 JSON 会让
821
- * **工具白名单静默失效**——而白名单正是 skiff 的权限边界 ⇒ 静默 = 权限面悄悄放开或收死,
821
+ * **工具白名单静默失效**——而白名单正是 轨迹约束的权限边界 ⇒ 静默 = 权限面悄悄放开或收死,
822
822
  * 两种都查不到原因。
823
823
  */
824
824
  const warnedBrokenProfiles = /* @__PURE__ */ new Set();
@@ -831,22 +831,22 @@ function activeTrajectoryDirNames(root) {
831
831
  }
832
832
  }
833
833
  /**
834
- * 读一个目录下的 `skiff.json`(**纯读,不施加约束**)。
834
+ * 读一个目录下的 `trajectory-constraint.json`(**纯读,不施加约束**)。
835
835
  *
836
836
  * @param trajectoryDir 轨迹目录绝对路径
837
837
  * @param root CCC 根(仅用于 `systemPromptFile` 的逃逸拒绝)
838
- * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 skiff,常态,不是错误)**
838
+ * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 轨迹约束,常态,不是错误)**
839
839
  *
840
840
  * ⚠️ **形态容错**:数组元素非字符串 → 丢弃该项(不整份作废);`cognitiveTrajectory`
841
841
  * 缺项 → 各自取 **true**(见 R↓);`model` 空白 → undefined(回退缺省)。
842
- * 坏 JSON ⇒ 告警 + `null`(**按"不是 skiff"处理**:宁可让它退回普通轨迹,也不要带着
842
+ * 坏 JSON ⇒ 告警 + `null`(**按"不是 轨迹约束"处理**:宁可让它退回普通轨迹,也不要带着
843
843
  * 半份读不懂的权限面运行)。
844
844
  */
845
- function readSkiffProfileAt(trajectoryDir, root) {
845
+ function readTrajectoryConstraintAt(trajectoryDir, root) {
846
846
  const dirName = trajectoryDir.split("/").filter(Boolean).pop() ?? "";
847
847
  const code = parseTrajectoryCode(dirName);
848
848
  if (code === null) return null;
849
- const file = join(trajectoryDir, SKIFF_PROFILE_FILENAME);
849
+ const file = join(trajectoryDir, TRAJECTORY_CONSTRAINT_FILENAME);
850
850
  if (!existsSync(file)) return null;
851
851
  let raw;
852
852
  try {
@@ -854,14 +854,14 @@ function readSkiffProfileAt(trajectoryDir, root) {
854
854
  } catch (err) {
855
855
  if (!warnedBrokenProfiles.has(file)) {
856
856
  warnedBrokenProfiles.add(file);
857
- console.warn(`[serenity-hooks] ✗ ${SKIFF_PROFILE_FILENAME} 解析失败 ⇒ 该轨迹**按普通轨迹处理**(工具白名单与提示词约束全部不施加)。请修 JSON: ${file} — ${String(err?.message ?? err)}`);
857
+ console.warn(`[serenity-hooks] ✗ ${TRAJECTORY_CONSTRAINT_FILENAME} 解析失败 ⇒ 该轨迹**按普通轨迹处理**(工具白名单与提示词约束全部不施加)。请修 JSON: ${file} — ${String(err?.message ?? err)}`);
858
858
  }
859
859
  return null;
860
860
  }
861
861
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
862
862
  if (!warnedBrokenProfiles.has(file)) {
863
863
  warnedBrokenProfiles.add(file);
864
- console.warn(`[serenity-hooks] ✗ ${SKIFF_PROFILE_FILENAME} 顶层不是对象 ⇒ 按普通轨迹处理: ${file}`);
864
+ console.warn(`[serenity-hooks] ✗ ${TRAJECTORY_CONSTRAINT_FILENAME} 顶层不是对象 ⇒ 按普通轨迹处理: ${file}`);
865
865
  }
866
866
  return null;
867
867
  }
@@ -878,7 +878,7 @@ function readSkiffProfileAt(trajectoryDir, root) {
878
878
  resolveInside(root, rawFile);
879
879
  systemPromptFile = rawFile;
880
880
  } catch (err) {
881
- console.warn(`[serenity-hooks] ✗ ${SKIFF_PROFILE_FILENAME} 的 systemPromptFile 越界,已忽略(其余约束仍生效): ${file} — ${String(err?.message ?? err)}`);
881
+ console.warn(`[serenity-hooks] ✗ ${TRAJECTORY_CONSTRAINT_FILENAME} 的 systemPromptFile 越界,已忽略(其余约束仍生效): ${file} — ${String(err?.message ?? err)}`);
882
882
  }
883
883
  return {
884
884
  dirName,
@@ -897,20 +897,20 @@ function readSkiffProfileAt(trajectoryDir, root) {
897
897
  };
898
898
  }
899
899
  /**
900
- * 按**轨迹编码**解析 skiff 约束面(`list`/`admin`/调试页/路由解析用)。
900
+ * 按**轨迹编码**解析 轨迹约束面(`list`/`admin`/调试页/路由解析用)。
901
901
  *
902
- * @returns 约束面;轨迹不存在 / 无 `skiff.json` → `null`
902
+ * @returns 约束面;轨迹不存在 / 无 `trajectory-constraint.json` → `null`
903
903
  */
904
- function readSkiffProfileByCode(root, code) {
904
+ function readTrajectoryConstraintByCode(root, code) {
905
905
  const dirName = findDirNameByCode(root, code);
906
906
  if (dirName === null) return null;
907
- return readSkiffProfileAt(join(sessionsRoot(root), dirName), root);
907
+ return readTrajectoryConstraintAt(join(sessionsRoot(root), dirName), root);
908
908
  }
909
- /** 扫全部活跃轨迹,返回全部 skiff。**顺序按目录名**(确定性,便于对读)。 */
910
- function listSkiffProfiles(root) {
909
+ /** 扫全部活跃轨迹,返回全部 轨迹约束。**顺序按目录名**(确定性,便于对读)。 */
910
+ function listTrajectoryConstraints(root) {
911
911
  const out = [];
912
912
  for (const name of activeTrajectoryDirNames(root)) {
913
- const p = readSkiffProfileAt(join(sessionsRoot(root), name), root);
913
+ const p = readTrajectoryConstraintAt(join(sessionsRoot(root), name), root);
914
914
  if (p) out.push(p);
915
915
  }
916
916
  return out;
@@ -927,40 +927,40 @@ function findDirNameByCode(root, code) {
927
927
  return null;
928
928
  }
929
929
  /**
930
- * **会话级**判据(J2):这个 dsh 会话是不是 skiff 会话 —— 唯一入口。
930
+ * **会话级**判据(J2):这个 dsh 会话是不是 轨迹约束会话 —— 唯一入口。
931
931
  *
932
- * 判据 = **它绑定的轨迹有 `skiff.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
932
+ * 判据 = **它绑定的轨迹有 `trajectory-constraint.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
933
933
  *
934
934
  * ## 为什么"绑定的轨迹"从两个来源取(R↓,一个失败模式)
935
935
  * ① **持久绑定**(`readLastBound`,宿主存储域/`.bindings.json`)—— 权威,跨重启成立;
936
936
  * ② **内存注册表**(`trajectory/policy/window`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
937
- * ⇒ 只取 ① 会在建会话的第一轮判成"不是 skiff"(工具面不收窄,模型看见不该有的工具);
938
- * 只取 ② 会在进程重启后全判成"不是"(skiff 失去约束,**权限面静默放开**)。
937
+ * ⇒ 只取 ① 会在建会话的第一轮判成"不是 轨迹约束"(工具面不收窄,模型看见不该有的工具);
938
+ * 只取 ② 会在进程重启后全判成"不是"(轨迹约束 失去约束,**权限面静默放开**)。
939
939
  * ⇒ **两来源并取**,都不中才 `null`。
940
940
  *
941
941
  * @param root CCC 根
942
942
  * @param sessionId dsh 会话 id
943
943
  * @param boundDirName 调用方已解析的绑定目录名(可选;给了就省一次读绑定)
944
- * @returns 约束面;不是 skiff 会话 → `null`
944
+ * @returns 约束面;不是 轨迹约束会话 → `null`
945
945
  */
946
- function skiffProfileForSession(root, sessionId, boundDirName) {
946
+ function trajectoryConstraintForSession(root, sessionId, boundDirName) {
947
947
  const dirName = boundDirName ?? registeredDirName(sessionId);
948
948
  if (dirName === null || dirName === "") return null;
949
- return readSkiffProfileAt(join(sessionsRoot(root), dirName), root);
949
+ return readTrajectoryConstraintAt(join(sessionsRoot(root), dirName), root);
950
950
  }
951
951
  /** 内存登记的轨迹目录名(注册表单一真相源在 `./registry.ts`;此处只做一次转发) */
952
952
  function registeredDirName(sessionId) {
953
953
  if (typeof sessionId !== "string" || sessionId === "") return null;
954
- return skiffTrajectoryDirNameFor(sessionId);
954
+ return trajectoryDirNameForSession(sessionId);
955
955
  }
956
956
  /**
957
- * 该 dsh 会话**是不是** skiff 会话(布尔形态的 `skiffProfileForSession`)。
957
+ * 该 dsh 会话**是不是** 轨迹约束会话(布尔形态的 `trajectoryConstraintForSession`)。
958
958
  *
959
959
  * 存在的理由:调用点很多只要一个"是/不是"(seams 的旁路判定),
960
960
  * 让它们各自写 `!== null` 会把判据散开;**判据只能有一个入口**。
961
961
  */
962
- function isSkiffSession(root, sessionId) {
963
- return skiffProfileForSession(root, sessionId) !== null;
962
+ function isTrajectoryConstrained(root, sessionId) {
963
+ return trajectoryConstraintForSession(root, sessionId) !== null;
964
964
  }
965
965
  //#endregion
966
- export { sessionsRoot as A, namingTitleFor as C, readTrajectoryUid as D, readActiveSessionMd as E, isoLocal as F, localFileStamp as I, localHuman as L, showSession as M, summarize as N, resolveSessionByTitle as O, useSession as P, localIdStamp as R, listSessions as S, parseTrajectoryCode as T, extractSessionMdPathFromText as _, readSkiffProfileAt as a, getLastActiveSessionInfo as b, registerSkiffSession as c, COGNITIVE_TRAJECTORY_ACTIONS as d, DEFAULT_SESSION_SCOPE as f, createSession as g, clearActiveSessionInfo as h, profile_exports as i, setActiveSessionInfo as j, sessionEvents as k, skiffTrajectoryDirNameFor as l, archiveSession as m, isSkiffSession as n, readSkiffProfileByCode as o, UID_FILENAME as p, listSkiffProfiles as r, skiffProfileForSession as s, SKIFF_PROFILE_FILENAME as t, unregisterSkiffSession as u, findSession as v, parseSessionContextFromEvents as w, listActiveTrajectories as x, getActiveSessionInfo as y };
966
+ export { sessionsRoot as A, namingTitleFor as C, readTrajectoryUid as D, readActiveSessionMd as E, isoLocal as F, localFileStamp as I, localHuman as L, showSession as M, summarize as N, resolveSessionByTitle as O, useSession as P, localIdStamp as R, listSessions as S, parseTrajectoryCode as T, extractSessionMdPathFromText as _, readTrajectoryConstraintAt as a, getLastActiveSessionInfo as b, registerTrajectorySession as c, COGNITIVE_TRAJECTORY_ACTIONS as d, DEFAULT_SESSION_SCOPE as f, createSession as g, clearActiveSessionInfo as h, profile_exports as i, setActiveSessionInfo as j, sessionEvents as k, trajectoryDirNameForSession as l, archiveSession as m, isTrajectoryConstrained as n, readTrajectoryConstraintByCode as o, UID_FILENAME as p, listTrajectoryConstraints as r, trajectoryConstraintForSession as s, TRAJECTORY_CONSTRAINT_FILENAME as t, unregisterTrajectorySession as u, findSession as v, parseSessionContextFromEvents as w, listActiveTrajectories as x, getActiveSessionInfo as y };
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
2
- import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-CZUOq3NY.js";
2
+ import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-CyYJL4F2.js";
3
3
  import { join, resolve } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import { createHash } from "node:crypto";
@@ -288,7 +288,7 @@ function runLocalStore(root, args) {
288
288
  * 职责(零 DSH 依赖,可独立单测):
289
289
  * - 读取 CCC 的 weixin 配置(.opencode/serenity.json weixin 段——结构/路由/开关)
290
290
  * - 读取/写入 CCC localstore 的账号凭据(weixin.accounts.<accountId>.token/.baseUrl/.userId)
291
- * - 微信用户 → skiff 会话 id 映射(固定可重建:skiff-weixin-<sha256(userid)>.slice(1, 17);
291
+ * - 微信用户 → 轨迹约束会话 id 映射(固定可重建:skiff-weixin-<sha256(userid)>.slice(1, 17);
292
292
  * v1.27.3 错位一位避开损坏 log)
293
293
  * - 路由匹配(exact user → 通配 * 兜底)
294
294
  *
@@ -300,7 +300,9 @@ var route_exports = /* @__PURE__ */ __exportAll({
300
300
  extractWeixinMedia: () => extractWeixinMedia,
301
301
  extractWeixinText: () => extractWeixinText,
302
302
  hasVoiceItem: () => hasVoiceItem,
303
+ imCredentialBound: () => imCredentialBound,
303
304
  matchWeixinRoute: () => matchWeixinRoute,
305
+ nextFeishuAccountId: () => nextFeishuAccountId,
304
306
  nextWeixinAccountId: () => nextWeixinAccountId,
305
307
  readFeishuCredential: () => readFeishuCredential,
306
308
  readImSettings: () => readImSettings,
@@ -313,6 +315,7 @@ var route_exports = /* @__PURE__ */ __exportAll({
313
315
  upsertWeixinAccount: () => upsertWeixinAccount,
314
316
  weixinInboundDir: () => weixinInboundDir,
315
317
  weixinSessionIdForTrajectory: () => weixinSessionIdForTrajectory,
318
+ writeFeishuCredential: () => writeFeishuCredential,
316
319
  writeWeixinCredential: () => writeWeixinCredential
317
320
  });
318
321
  /** localstore 凭据键前缀(**credential scope**——token 是凭据,走 UPPER_SNAKE 键;
@@ -323,10 +326,10 @@ function accountKeyPart(accountId) {
323
326
  return accountId.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
324
327
  }
325
328
  /**
326
- * 微信桥 skiff 会话 id 前缀(守卫识别"外部面"用)。
329
+ * 微信桥 轨迹约束会话 id 前缀(守卫识别"外部面"用)。
327
330
  *
328
- * ⚠️ **2026-10-19 起它只是命名习惯,不再是判据** —— skiff 的身份是**轨迹**,
329
- * 判据 = 「绑定的轨迹有 `skiff.json`」(`trajectory/policy/profile.ts` 的 `isSkiffSession`)。
331
+ * ⚠️ **2026-10-19 起它只是命名习惯,不再是判据** —— 轨迹约束的身份是**轨迹**,
332
+ * 判据 = 「绑定的轨迹有 `trajectory-constraint.json`」(`trajectory/policy/profile.ts` 的 `isTrajectoryConstrained`)。
330
333
  * 保留前缀只为:① 日志/会话列表里一眼认出这是外部面;② 存量会话目录名不变。
331
334
  */
332
335
  const WEIXIN_SESSION_PREFIX = "skiff-weixin-";
@@ -340,7 +343,7 @@ const WEIXIN_SESSION_PREFIX = "skiff-weixin-";
340
343
  * 对不上旧会话的历史工具清单)。⇒ 那不是"轨迹是一等公民",那是"用户是一等公民"。
341
344
  *
342
345
  * 新派生 = **由轨迹编码决定**:同一条轨迹 ⇒ 恒同一条 dsh 会话(无论谁在跟它说话);
343
- * 换轨迹 ⇒ 新会话。这正是"skiff 是认知轨迹的一种"。
346
+ * 换轨迹 ⇒ 新会话。这正是"轨迹约束是认知轨迹的一种"。
344
347
  *
345
348
  * ## 连带删掉的东西
346
349
  *
@@ -507,6 +510,28 @@ function readFeishuCredential(root, accountId) {
507
510
  appSecret
508
511
  };
509
512
  }
513
+ /** 写入飞书账号凭据(面板保存后;两者都必写——只写一半等于没绑) */
514
+ function writeFeishuCredential(root, accountId, cred) {
515
+ writeEntry(root, "credential", feishuLsKey(accountId, "APPID"), cred.appId);
516
+ writeEntry(root, "credential", feishuLsKey(accountId, "SECRET"), cred.appSecret);
517
+ }
518
+ /**
519
+ * **按渠道判「该账号是否已绑定凭据」**(面板读数用;单一处)。
520
+ *
521
+ * 🔴 为什么需要它(2026-10-19 P2 面板实测缺陷):面板原先对所有账号都调
522
+ * `readWeixinCredential`(只看 `WEIXIN_<A>_TOKEN`)。一个**飞书**账号的凭据在
523
+ * `FEISHU_<A>_APPID|SECRET`,走那条读法**必然读到 null** ⇒ 面板把一个配好的飞书账号
524
+ * 显示成「未绑定凭据」,用户据此以为没配上。
525
+ *
526
+ * 判据与装配处**同源**(`im/bridge.ts` 的 `readImCredentialByChannel`):飞书要 appId **且**
527
+ * appSecret,微信只要有 token。两处若各写一份判据,就会重演"两个读数器给出不同答案"。
528
+ *
529
+ * ⚠️ 只回**布尔**,不回任何凭据值 —— 这是 wire 面。
530
+ */
531
+ function imCredentialBound(root, accountId, channel) {
532
+ if ((channel ?? "").trim() === "feishu") return readFeishuCredential(root, accountId) !== null;
533
+ return readWeixinCredential(root, accountId) !== null;
534
+ }
510
535
  /**
511
536
  * 路由匹配:exact user 优先,通配 `*` 兜底。
512
537
  * @returns 命中的**轨迹编码**;未命中 → null(无路由 → 消息不回复/忽略)
@@ -645,6 +670,19 @@ function nextWeixinAccountId(settings) {
645
670
  while (used.has(`wechat-${n}`)) n++;
646
671
  return `wechat-${n}`;
647
672
  }
673
+ /**
674
+ * 生成下一个可用飞书账号 id(`feishu-N`,N 取**最小未占用**)。
675
+ *
676
+ * 与 {@link nextWeixinAccountId} 分开而不是加参数:两者的**前缀不同**,
677
+ * 而前缀是给人看的(面板上一眼分清哪些账号来自哪个渠道)。
678
+ * 判据相同(最小未占用,删中间不跳号)。
679
+ */
680
+ function nextFeishuAccountId(settings) {
681
+ const used = new Set((settings.accounts ?? []).map((a) => a.accountId));
682
+ let n = 1;
683
+ while (used.has(`feishu-${n}`)) n++;
684
+ return `feishu-${n}`;
685
+ }
648
686
  /** 切换总开关 */
649
687
  function setWeixinEnabled(root, enabled) {
650
688
  const next = {
@@ -9,7 +9,7 @@
9
9
  import type { Context } from 'cordis';
10
10
  import type { Agent } from '@deepseek-ai/dsh-agent';
11
11
  import { type BlacklistRule } from '../kernel/ccc.js';
12
- import { type SkiffProfile } from '../trajectory/policy/profile.js';
12
+ import { type TrajectoryConstraint } from '../trajectory/policy/profile.js';
13
13
  export interface GuardInput {
14
14
  root: string;
15
15
  toolName: string;
@@ -20,13 +20,13 @@ export interface GuardInput {
20
20
  /** container_fs 等复合工具的子命令 action(只读子命令不查黑名单) */
21
21
  action?: string;
22
22
  /**
23
- * 该会话的 skiff 约束面(`null`/`undefined` = 不是 skiff 会话 ⇒ 不判定)。
23
+ * 该会话的 轨迹约束面(`null`/`undefined` = 不是 轨迹约束会话 ⇒ 不判定)。
24
24
  *
25
25
  * 🔴 2026-10-19 起传**已解析好的约束面**,不传 sessionId:解判据("这条轨迹有没有
26
- * `skiff.json`")留在唯一入口 `profile.ts`,守卫只消费结果 ⇒ 纯函数里不再做 IO,
26
+ * `trajectory-constraint.json`")留在唯一入口 `profile.ts`,守卫只消费结果 ⇒ 纯函数里不再做 IO,
27
27
  * 也不可能出现"守卫的判据与 schema 收窄的判据不一致"。
28
28
  */
29
- skiffProfile?: SkiffProfile | null;
29
+ trajectoryConstraint?: TrajectoryConstraint | null;
30
30
  }
31
31
  interface GuardDecisionResult {
32
32
  deny?: string;
@@ -102,21 +102,21 @@ export declare function forgetHostScheduleToolHiding(sessionId: string): void;
102
102
  export declare function getExclusiveToolsDiagnostics(): {
103
103
  hidden: string[];
104
104
  };
105
- /** Skiff 角色工具面诊断(排查"某工具为什么不在 skiff 的清单里") */
106
- export declare function getSkiffRoleVisibilityDiagnostics(): {
105
+ /** 轨迹约束工具面诊断(排查"某工具为什么不在 轨迹约束的清单里") */
106
+ export declare function getTrajectoryConstraintVisibilityDiagnostics(): {
107
107
  keys: string[];
108
108
  denyByKey: Record<string, string[]>;
109
109
  };
110
110
  /**
111
- * 同步 **skiff 会话的工具面**:把白名单之外的工具**从 schema 移除**(不是"看得到但被拒")。
111
+ * 同步 **轨迹约束会话的工具面**:把白名单之外的工具**从 schema 移除**(不是"看得到但被拒")。
112
112
  *
113
113
  * ## 为什么必须有这条(owner 2026-10-19:「工具清单也要热加载」)
114
114
  *
115
- * 在它之前,skiff 白名单**只由运行时守卫拦截**(`decideGuard` 的 skiff 分支):
115
+ * 在它之前,轨迹约束白名单**只由运行时守卫拦截**(`decideGuard` 的 轨迹约束 分支):
116
116
  * 工具全部出现在模型 schema 里,调用时才被打回。⇒ 两个真实后果:
117
117
  * ① **模型看得见它不该有的工具** —— 它会去试,试了才撞墙(一轮白烧,且错误文案泛化,
118
118
  * 看不出"是不在清单里"还是"临时性拒绝");
119
- * ② **配置变动在 schema 上永远不生效** —— 改 `skiff.json` 的 `tools` 只影响"调用是否放行"。
119
+ * ② **配置变动在 schema 上永远不生效** —— 改 `trajectory-constraint.json` 的 `tools` 只影响"调用是否放行"。
120
120
  *
121
121
  * ## 判据与降级
122
122
  *
@@ -124,17 +124,17 @@ export declare function getSkiffRoleVisibilityDiagnostics(): {
124
124
  * 不去动宿主的工具 —— 宿主的工具由各自的条件同步管)。
125
125
  * - ⚠️ **未注册的名字会让整次 restrict 失败**(宿主契约逐字 "unknown names … fail"),
126
126
  * 而 `diagram` 是按开关注册的 ⇒ 与 `hideAllFor` 同款**两档尝试**(先全覆盖,失败退常驻段)。
127
- * - 读不到约束面(不是 skiff / 配置删了)⇒ **撤销既有隐藏**(回到"无约束"):
128
- * ⛔ 不能只是 `return` —— 那会把上一步的隐藏**永久留在**一个已不再是 skiff 的会话上
129
- * (这正是 owner 说的"删掉 `skiff.json` 就该立刻恢复")。
127
+ * - 读不到约束面(不是 轨迹约束 / 配置删了)⇒ **撤销既有隐藏**(回到"无约束"):
128
+ * ⛔ 不能只是 `return` —— 那会把上一步的隐藏**永久留在**一个已不再是 轨迹约束的会话上
129
+ * (这正是 owner 说的"删掉 `trajectory-constraint.json` 就该立刻恢复")。
130
130
  * - 幂等:算出来的 deny 签名不变就跳过(不每步重建 schema)。
131
131
  *
132
132
  * @param agent 目标会话
133
133
  * @param root CCC 根
134
134
  */
135
- export declare function syncSkiffRoleToolVisibility(agent: Agent, root: string): void;
135
+ export declare function syncTrajectoryConstraintToolVisibility(agent: Agent, root: string): void;
136
136
  /** 会话销毁清理(lifecycle 调用) */
137
- export declare function forgetSkiffRoleToolVisibility(sessionId: string): void;
137
+ export declare function forgetTrajectoryConstraintToolVisibility(sessionId: string): void;
138
138
  /**
139
139
  * 同步专属工具可见性(v1.33)。
140
140
  *
@@ -85,7 +85,7 @@ export declare function __resetLogbookCompactionForTest(): void;
85
85
  * 解析**活跃** SESSION.md 绝对路径(缓存 60s)。
86
86
  *
87
87
  * 候选链(刻意比 rebuild 的完整链短——这里每个工具调用都要跑,贵候选不划算):
88
- * ① `getActiveSessionInfo(scope).mdPath`(`cognitive_trajectory use` / skiff 绑定 / 重启恢复都会写)
88
+ * ① `getActiveSessionInfo(scope).mdPath`(`cognitive_trajectory use` / 轨迹约束 绑定 / 重启恢复都会写)
89
89
  * ② `readLastBound(session).mdPath`(`.bindings.json` 权威绑定——重启后内存空时兜底)
90
90
  * 两者都拿不到 → null(**不猜**:宁可不提醒,也不去猜别的轨迹——对齐 v1.30.13 D4 的教训)。
91
91
  */
@@ -4,13 +4,13 @@
4
4
  * 两个此前缺失的收尾面:
5
5
  *
6
6
  * ① **会话/agent 销毁 → 清理 per-会话内存态**。dsp 有约 10 处 per-会话 Map
7
- * (活跃 SESSION 作用域、skiff 注册表、keeper 计分、guard 白名单缓存、bootstrap
7
+ * (活跃 SESSION 作用域、轨迹约束 注册表、keeper 计分、guard 白名单缓存、bootstrap
8
8
  * 晋升状态、输出守卫状态…)。此前无人订阅 `agent/disposed` / `session/disposed`
9
9
  * (宿主 0.1.2-rc.1 真实存在:`core/agent/src/runtime-types.ts:175`、
10
10
  * `core/session/src/index.ts:62`),长跑进程里这些 Map 只增不减——且 `waitIdle`
11
11
  * 在 agent 先被销毁时永不结算。
12
12
  *
13
- * ② **插件卸载/HMR/profile 重载 → 停掉自起的监听器与轮询器**。skiff 调试页、微信桥轮询
13
+ * ② **插件卸载/HMR/profile 重载 → 停掉自起的监听器与轮询器**。轨迹约束调试页、微信桥轮询
14
14
  * 都是 dsp 自己起的资源(⚠️ 2026-10-15:原同批还有 ACP HTTP 端点,该面已退役);
15
15
  * 此前没有 `ctx.effect` 拆卸,卸载后端口仍被占用(EADDRINUSE)、轮询器重复启动。
16
16
  *