@shgroup/dsh-serenity-hooks 1.72.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 (61) 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-Dkoa2oW3.js → ccc-CyYJL4F2.js} +9 -9
  5. package/lib/{ccc-roots-jZYR2GVE.js → ccc-roots-B2t_aM8L.js} +5 -5
  6. package/lib/client.js +165 -58
  7. package/lib/{wake/cro.d.ts → cro/core.d.ts} +3 -3
  8. package/lib/{wake/cro-guide.d.ts → cro/guide.d.ts} +3 -3
  9. package/lib/{wake/cro-log.d.ts → cro/log.d.ts} +2 -2
  10. package/lib/{wake/cro-turns.d.ts → cro/turns.d.ts} +2 -2
  11. package/lib/guard/seam.d.ts +4 -4
  12. package/lib/host/effect.d.ts +1 -1
  13. package/lib/{ilink-DEpmE3yi.js → ilink-BMk2w2KY.js} +1 -1
  14. package/lib/im/bridge.d.ts +36 -65
  15. package/lib/im/endpoint.d.ts +3 -3
  16. package/lib/im/feishu-account.d.ts +92 -0
  17. package/lib/im/guard.d.ts +1 -1
  18. package/lib/im/hook.d.ts +1 -1
  19. package/lib/im/inbound-event.d.ts +162 -0
  20. package/lib/im/route.d.ts +38 -3
  21. package/lib/index.d.ts +5 -27
  22. package/lib/index.js +1089 -1208
  23. package/lib/kernel/ccc-roots.d.ts +4 -4
  24. package/lib/kernel/ccc.d.ts +19 -19
  25. package/lib/kernel/ports.d.ts +3 -5
  26. package/lib/lib-TxscFKeo.js +119355 -0
  27. package/lib/{message-source-kVoNK0C5.js → message-source-DCpoRHP3.js} +2 -2
  28. package/lib/patches/opencode-provider.d.ts +1 -1
  29. package/lib/{profile-DyMJ_bfr.js → profile-BVt84mbi.js} +68 -65
  30. package/lib/rolldown-runtime-B4iAMlE-.js +35 -0
  31. package/lib/{route-f7JlinIt.js → route-COOFLTpU.js} +61 -8
  32. package/lib/seams/guards.d.ts +14 -14
  33. package/lib/seams/keeper.d.ts +1 -1
  34. package/lib/seams/lifecycle.d.ts +2 -2
  35. package/lib/{settings-lt1i3OZv.js → settings-D8hlqxua.js} +49 -84
  36. package/lib/skills/resource-index.d.ts +1 -1
  37. package/lib/surface/faces.d.ts +1 -1
  38. package/lib/surface/http.d.ts +1 -1
  39. package/lib/surface/settings.d.ts +7 -13
  40. package/lib/surface/text.d.ts +72 -0
  41. package/lib/surface/usage.d.ts +2 -2
  42. package/lib/tools/config-docs.d.ts +53 -0
  43. package/lib/tools/container-admin.d.ts +19 -12
  44. package/lib/tools/msm/service.d.ts +7 -0
  45. package/lib/tools/trajectory-constraint-admin.d.ts +30 -0
  46. package/lib/{role/worker/idle.d.ts → trajectory/carrier.d.ts} +12 -2
  47. package/lib/trajectory/core.d.ts +1 -1
  48. package/lib/{role/worker → trajectory/delegate}/core.d.ts +7 -1
  49. package/lib/{role/worker → trajectory/delegate}/preset.d.ts +9 -2
  50. package/lib/trajectory/policy/profile.d.ts +122 -0
  51. package/lib/trajectory/policy/rules.d.ts +98 -0
  52. package/lib/{role/skiff/registry.d.ts → trajectory/policy/window.d.ts} +19 -13
  53. package/lib/trajectory/prompt.d.ts +12 -12
  54. package/lib/trajectory/rebuild.d.ts +2 -2
  55. package/lib/{role/skiff/core.d.ts → trajectory/session.d.ts} +58 -49
  56. package/package.json +3 -2
  57. package/lib/role/skiff/config.d.ts +0 -79
  58. package/lib/role/skiff/debug.d.ts +0 -88
  59. package/lib/role/skiff/profile.d.ts +0 -115
  60. package/lib/rolldown-runtime-8H4AJuhK.js +0 -14
  61. package/lib/tools/skiff-admin.d.ts +0 -30
@@ -1,5 +1,5 @@
1
- import { r as cccRootForCwd } from "./ccc-roots-jZYR2GVE.js";
2
- import { A as sessionEvents, E as parseTrajectoryCode, b as getActiveSessionInfo, x as getLastActiveSessionInfo } from "./profile-DyMJ_bfr.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
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { _ as resolveInside, g as readUtf8 } from "./ccc-Dkoa2oW3.js";
1
+ import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.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
  *
@@ -750,72 +750,75 @@ function archiveSession(root, key, dryRun = false) {
750
750
  };
751
751
  }
752
752
  //#endregion
753
- //#region src/role/skiff/registry.ts
754
- const skiffSessions = /* @__PURE__ */ new Map();
753
+ //#region src/trajectory/policy/window.ts
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
- /** 查会话的完整绑定(轨迹 + CCC;无 → null)——追问延续时校验 (轨迹, CCC) 未串味 */
772
- function skiffSessionInfo(sessionId) {
773
- return skiffSessions.get(sessionId) ?? null;
774
- }
775
771
  //#endregion
776
- //#region src/role/skiff/profile.ts
772
+ //#region src/trajectory/policy/profile.ts
777
773
  /**
778
- * role/skiff/profile.ts — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
774
+ * trajectory/policy/profile.ts — **轨迹约束的唯一判据**:目录下有 `trajectory-constraint.json` 的认知轨迹(零 DSH 依赖,可独立单测)
779
775
  *
780
776
  * ## 🔴 owner 2026-10-19 重做令(逐字,本文件存在的全部理由)
781
777
  *
782
- * > 「skiff 复杂的约束和提示词体系都干掉,改为这样的实现:
783
- * > **skiff 本身是认知轨迹的一个特殊情况,即目录下拥有 `skiff.json` 的认知轨迹自动是一个 skiff**
784
- * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `skiff.json`,则运行时实现各类约束**」
778
+ * > 「轨迹约束 复杂的约束和提示词体系都干掉,改为这样的实现:
779
+ * > **轨迹约束本身是认知轨迹的一个特殊情况,即目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束**
780
+ * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `trajectory-constraint.json`,则运行时实现各类约束**」
785
781
  *
786
782
  * ## 旧模型 → 新模型(**一条判据取代四条**)
787
783
  *
788
784
  * | 项 | 旧 | 新 |
789
785
  * |---|---|---|
790
- * | skiff 是什么 | `serenity.json` 的 `skiff.roles.<name>` 一条配置 | **轨迹目录里有 `skiff.json`** |
791
- * | 怎么认出 skiff 会话 | dsh sessionId 前缀 `skiff-` | **它绑定的轨迹有 `skiff.json`** |
792
- * | 工作台从哪来 | `ensureSkiffSession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
786
+ * | 轨迹约束是什么 | `serenity.json` 的 `轨迹约束.roles.<name>` 一条配置 | **轨迹目录里有 `trajectory-constraint.json`** |
787
+ * | 怎么认出 轨迹约束会话 | dsh sessionId 前缀 `轨迹约束-` | **它绑定的轨迹有 `trajectory-constraint.json`** |
788
+ * | 工作台从哪来 | `ensureTrajectorySession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
793
789
  * | 身份 | 角色名 | **轨迹编码**(`trajectory/core.ts` 的 `parseTrajectoryCode`) |
794
790
  *
795
791
  * ⇒ 收益(owner:「理解难度大幅下降」的实际内容):四个各自会漂的机制收敛为**一条文件存在性判据**。
796
- * 删掉 `skiff.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
792
+ * 删掉 `trajectory-constraint.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
797
793
  *
798
794
  * ## 归属(D23)
799
795
  * **机制在 ACC**(文件叫什么、怎么读、怎么判、缺省值、如何施加约束);
800
- * **内容在 CCC**(`skiff.json` 里填什么:模型、白名单、提示词路径)。
801
- * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 skiff 段(该段已退役)。
796
+ * **内容在 CCC**(`trajectory-constraint.json` 里填什么:模型、白名单、提示词路径)。
797
+ * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 轨迹约束段(该段已退役)。
798
+ *
799
+ * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/轨迹约束/` 下(该目录已随本重构消失)
800
+ *
801
+ * 落点 = `trajectory/policy/`。判据(判读表 §3.1):本文件判的是**某条轨迹的约束面**,
802
+ * 主语是轨迹 ⇒ 它一直就是轨迹切面,只是旧目录把它挂在"角色"这个**平行概念**下。
803
+ * ⚠️ **文件名 `profile` 与 `trajectory-constraint.json` / `TrajectoryConstraint` 等符号名一律不动**:
804
+ * 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
802
805
  */
803
806
  var profile_exports = /* @__PURE__ */ __exportAll({
804
- SKIFF_PROFILE_FILENAME: () => SKIFF_PROFILE_FILENAME,
807
+ TRAJECTORY_CONSTRAINT_FILENAME: () => TRAJECTORY_CONSTRAINT_FILENAME,
805
808
  findDirNameByCode: () => findDirNameByCode,
806
- isSkiffSession: () => isSkiffSession,
807
- listSkiffProfiles: () => listSkiffProfiles,
808
- readSkiffProfileAt: () => readSkiffProfileAt,
809
- readSkiffProfileByCode: () => readSkiffProfileByCode,
810
- skiffProfileForSession: () => skiffProfileForSession
809
+ isTrajectoryConstrained: () => isTrajectoryConstrained,
810
+ listTrajectoryConstraints: () => listTrajectoryConstraints,
811
+ readTrajectoryConstraintAt: () => readTrajectoryConstraintAt,
812
+ readTrajectoryConstraintByCode: () => readTrajectoryConstraintByCode,
813
+ trajectoryConstraintForSession: () => trajectoryConstraintForSession
811
814
  });
812
- /** `skiff.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
813
- const SKIFF_PROFILE_FILENAME = "skiff.json";
815
+ /** `trajectory-constraint.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
816
+ const TRAJECTORY_CONSTRAINT_FILENAME = "trajectory-constraint.json";
814
817
  /**
815
- * 已告警过的坏 `skiff.json`(进程级去重:同一坏文件不刷屏,但**绝不静默**)。
818
+ * 已告警过的坏 `trajectory-constraint.json`(进程级去重:同一坏文件不刷屏,但**绝不静默**)。
816
819
  *
817
820
  * 🔴 为什么必须响亮(同源先例 = `loadSerenityConfig` 的 F-07):一份坏 JSON 会让
818
- * **工具白名单静默失效**——而白名单正是 skiff 的权限边界 ⇒ 静默 = 权限面悄悄放开或收死,
821
+ * **工具白名单静默失效**——而白名单正是 轨迹约束的权限边界 ⇒ 静默 = 权限面悄悄放开或收死,
819
822
  * 两种都查不到原因。
820
823
  */
821
824
  const warnedBrokenProfiles = /* @__PURE__ */ new Set();
@@ -828,22 +831,22 @@ function activeTrajectoryDirNames(root) {
828
831
  }
829
832
  }
830
833
  /**
831
- * 读一个目录下的 `skiff.json`(**纯读,不施加约束**)。
834
+ * 读一个目录下的 `trajectory-constraint.json`(**纯读,不施加约束**)。
832
835
  *
833
836
  * @param trajectoryDir 轨迹目录绝对路径
834
837
  * @param root CCC 根(仅用于 `systemPromptFile` 的逃逸拒绝)
835
- * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 skiff,常态,不是错误)**
838
+ * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 轨迹约束,常态,不是错误)**
836
839
  *
837
840
  * ⚠️ **形态容错**:数组元素非字符串 → 丢弃该项(不整份作废);`cognitiveTrajectory`
838
841
  * 缺项 → 各自取 **true**(见 R↓);`model` 空白 → undefined(回退缺省)。
839
- * 坏 JSON ⇒ 告警 + `null`(**按"不是 skiff"处理**:宁可让它退回普通轨迹,也不要带着
842
+ * 坏 JSON ⇒ 告警 + `null`(**按"不是 轨迹约束"处理**:宁可让它退回普通轨迹,也不要带着
840
843
  * 半份读不懂的权限面运行)。
841
844
  */
842
- function readSkiffProfileAt(trajectoryDir, root) {
845
+ function readTrajectoryConstraintAt(trajectoryDir, root) {
843
846
  const dirName = trajectoryDir.split("/").filter(Boolean).pop() ?? "";
844
847
  const code = parseTrajectoryCode(dirName);
845
848
  if (code === null) return null;
846
- const file = join(trajectoryDir, SKIFF_PROFILE_FILENAME);
849
+ const file = join(trajectoryDir, TRAJECTORY_CONSTRAINT_FILENAME);
847
850
  if (!existsSync(file)) return null;
848
851
  let raw;
849
852
  try {
@@ -851,14 +854,14 @@ function readSkiffProfileAt(trajectoryDir, root) {
851
854
  } catch (err) {
852
855
  if (!warnedBrokenProfiles.has(file)) {
853
856
  warnedBrokenProfiles.add(file);
854
- 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)}`);
855
858
  }
856
859
  return null;
857
860
  }
858
861
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
859
862
  if (!warnedBrokenProfiles.has(file)) {
860
863
  warnedBrokenProfiles.add(file);
861
- console.warn(`[serenity-hooks] ✗ ${SKIFF_PROFILE_FILENAME} 顶层不是对象 ⇒ 按普通轨迹处理: ${file}`);
864
+ console.warn(`[serenity-hooks] ✗ ${TRAJECTORY_CONSTRAINT_FILENAME} 顶层不是对象 ⇒ 按普通轨迹处理: ${file}`);
862
865
  }
863
866
  return null;
864
867
  }
@@ -875,7 +878,7 @@ function readSkiffProfileAt(trajectoryDir, root) {
875
878
  resolveInside(root, rawFile);
876
879
  systemPromptFile = rawFile;
877
880
  } catch (err) {
878
- 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)}`);
879
882
  }
880
883
  return {
881
884
  dirName,
@@ -894,20 +897,20 @@ function readSkiffProfileAt(trajectoryDir, root) {
894
897
  };
895
898
  }
896
899
  /**
897
- * 按**轨迹编码**解析 skiff 约束面(`list`/`admin`/调试页/路由解析用)。
900
+ * 按**轨迹编码**解析 轨迹约束面(`list`/`admin`/调试页/路由解析用)。
898
901
  *
899
- * @returns 约束面;轨迹不存在 / 无 `skiff.json` → `null`
902
+ * @returns 约束面;轨迹不存在 / 无 `trajectory-constraint.json` → `null`
900
903
  */
901
- function readSkiffProfileByCode(root, code) {
904
+ function readTrajectoryConstraintByCode(root, code) {
902
905
  const dirName = findDirNameByCode(root, code);
903
906
  if (dirName === null) return null;
904
- return readSkiffProfileAt(join(sessionsRoot(root), dirName), root);
907
+ return readTrajectoryConstraintAt(join(sessionsRoot(root), dirName), root);
905
908
  }
906
- /** 扫全部活跃轨迹,返回全部 skiff。**顺序按目录名**(确定性,便于对读)。 */
907
- function listSkiffProfiles(root) {
909
+ /** 扫全部活跃轨迹,返回全部 轨迹约束。**顺序按目录名**(确定性,便于对读)。 */
910
+ function listTrajectoryConstraints(root) {
908
911
  const out = [];
909
912
  for (const name of activeTrajectoryDirNames(root)) {
910
- const p = readSkiffProfileAt(join(sessionsRoot(root), name), root);
913
+ const p = readTrajectoryConstraintAt(join(sessionsRoot(root), name), root);
911
914
  if (p) out.push(p);
912
915
  }
913
916
  return out;
@@ -924,40 +927,40 @@ function findDirNameByCode(root, code) {
924
927
  return null;
925
928
  }
926
929
  /**
927
- * **会话级**判据(J2):这个 dsh 会话是不是 skiff 会话 —— 唯一入口。
930
+ * **会话级**判据(J2):这个 dsh 会话是不是 轨迹约束会话 —— 唯一入口。
928
931
  *
929
- * 判据 = **它绑定的轨迹有 `skiff.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
932
+ * 判据 = **它绑定的轨迹有 `trajectory-constraint.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
930
933
  *
931
934
  * ## 为什么"绑定的轨迹"从两个来源取(R↓,一个失败模式)
932
935
  * ① **持久绑定**(`readLastBound`,宿主存储域/`.bindings.json`)—— 权威,跨重启成立;
933
- * ② **内存注册表**(`skiff/registry`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
934
- * ⇒ 只取 ① 会在建会话的第一轮判成"不是 skiff"(工具面不收窄,模型看见不该有的工具);
935
- * 只取 ② 会在进程重启后全判成"不是"(skiff 失去约束,**权限面静默放开**)。
936
+ * ② **内存注册表**(`trajectory/policy/window`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
937
+ * ⇒ 只取 ① 会在建会话的第一轮判成"不是 轨迹约束"(工具面不收窄,模型看见不该有的工具);
938
+ * 只取 ② 会在进程重启后全判成"不是"(轨迹约束 失去约束,**权限面静默放开**)。
936
939
  * ⇒ **两来源并取**,都不中才 `null`。
937
940
  *
938
941
  * @param root CCC 根
939
942
  * @param sessionId dsh 会话 id
940
943
  * @param boundDirName 调用方已解析的绑定目录名(可选;给了就省一次读绑定)
941
- * @returns 约束面;不是 skiff 会话 → `null`
944
+ * @returns 约束面;不是 轨迹约束会话 → `null`
942
945
  */
943
- function skiffProfileForSession(root, sessionId, boundDirName) {
946
+ function trajectoryConstraintForSession(root, sessionId, boundDirName) {
944
947
  const dirName = boundDirName ?? registeredDirName(sessionId);
945
948
  if (dirName === null || dirName === "") return null;
946
- return readSkiffProfileAt(join(sessionsRoot(root), dirName), root);
949
+ return readTrajectoryConstraintAt(join(sessionsRoot(root), dirName), root);
947
950
  }
948
951
  /** 内存登记的轨迹目录名(注册表单一真相源在 `./registry.ts`;此处只做一次转发) */
949
952
  function registeredDirName(sessionId) {
950
953
  if (typeof sessionId !== "string" || sessionId === "") return null;
951
- return skiffTrajectoryDirNameFor(sessionId);
954
+ return trajectoryDirNameForSession(sessionId);
952
955
  }
953
956
  /**
954
- * 该 dsh 会话**是不是** skiff 会话(布尔形态的 `skiffProfileForSession`)。
957
+ * 该 dsh 会话**是不是** 轨迹约束会话(布尔形态的 `trajectoryConstraintForSession`)。
955
958
  *
956
959
  * 存在的理由:调用点很多只要一个"是/不是"(seams 的旁路判定),
957
960
  * 让它们各自写 `!== null` 会把判据散开;**判据只能有一个入口**。
958
961
  */
959
- function isSkiffSession(root, sessionId) {
960
- return skiffProfileForSession(root, sessionId) !== null;
962
+ function isTrajectoryConstrained(root, sessionId) {
963
+ return trajectoryConstraintForSession(root, sessionId) !== null;
961
964
  }
962
965
  //#endregion
963
- export { sessionEvents as A, listSessions as C, readActiveSessionMd as D, parseTrajectoryCode as E, useSession as F, isoLocal as I, localFileStamp as L, setActiveSessionInfo as M, showSession as N, readTrajectoryUid as O, summarize as P, localHuman as R, listActiveTrajectories as S, parseSessionContextFromEvents as T, createSession as _, readSkiffProfileAt as a, getActiveSessionInfo as b, registerSkiffSession as c, unregisterSkiffSession as d, COGNITIVE_TRAJECTORY_ACTIONS as f, clearActiveSessionInfo as g, archiveSession as h, profile_exports as i, sessionsRoot as j, resolveSessionByTitle as k, skiffSessionInfo as l, UID_FILENAME as m, isSkiffSession as n, readSkiffProfileByCode as o, DEFAULT_SESSION_SCOPE as p, listSkiffProfiles as r, skiffProfileForSession as s, SKIFF_PROFILE_FILENAME as t, skiffTrajectoryDirNameFor as u, extractSessionMdPathFromText as v, namingTitleFor as w, getLastActiveSessionInfo as x, findSession as y, localIdStamp as z };
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 };
@@ -0,0 +1,35 @@
1
+ import { createRequire } from "node:module";
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
10
+ var __exportAll = (all, no_symbols) => {
11
+ let target = {};
12
+ for (var name in all) __defProp(target, name, {
13
+ get: all[name],
14
+ enumerable: true
15
+ });
16
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
17
+ return target;
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
21
+ key = keys[i];
22
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
23
+ get: ((k) => from[k]).bind(null, key),
24
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
25
+ });
26
+ }
27
+ return to;
28
+ };
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
30
+ value: mod,
31
+ enumerable: true
32
+ }) : target, mod));
33
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
34
+ //#endregion
35
+ export { __toESM as i, __exportAll as n, __require as r, __commonJSMin as t };
@@ -1,5 +1,5 @@
1
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-Dkoa2oW3.js";
1
+ import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.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,8 +300,11 @@ 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,
307
+ readFeishuCredential: () => readFeishuCredential,
305
308
  readImSettings: () => readImSettings,
306
309
  readWeixinCredential: () => readWeixinCredential,
307
310
  readWeixinSettings: () => readWeixinSettings,
@@ -312,6 +315,7 @@ var route_exports = /* @__PURE__ */ __exportAll({
312
315
  upsertWeixinAccount: () => upsertWeixinAccount,
313
316
  weixinInboundDir: () => weixinInboundDir,
314
317
  weixinSessionIdForTrajectory: () => weixinSessionIdForTrajectory,
318
+ writeFeishuCredential: () => writeFeishuCredential,
315
319
  writeWeixinCredential: () => writeWeixinCredential
316
320
  });
317
321
  /** localstore 凭据键前缀(**credential scope**——token 是凭据,走 UPPER_SNAKE 键;
@@ -322,10 +326,10 @@ function accountKeyPart(accountId) {
322
326
  return accountId.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
323
327
  }
324
328
  /**
325
- * 微信桥 skiff 会话 id 前缀(守卫识别"外部面"用)。
329
+ * 微信桥 轨迹约束会话 id 前缀(守卫识别"外部面"用)。
326
330
  *
327
- * ⚠️ **2026-10-19 起它只是命名习惯,不再是判据** —— skiff 的身份是**轨迹**,
328
- * 判据 = 「绑定的轨迹有 `skiff.json`」(`role/skiff/profile.ts` 的 `isSkiffSession`)。
331
+ * ⚠️ **2026-10-19 起它只是命名习惯,不再是判据** —— 轨迹约束的身份是**轨迹**,
332
+ * 判据 = 「绑定的轨迹有 `trajectory-constraint.json`」(`trajectory/policy/profile.ts` 的 `isTrajectoryConstrained`)。
329
333
  * 保留前缀只为:① 日志/会话列表里一眼认出这是外部面;② 存量会话目录名不变。
330
334
  */
331
335
  const WEIXIN_SESSION_PREFIX = "skiff-weixin-";
@@ -339,7 +343,7 @@ const WEIXIN_SESSION_PREFIX = "skiff-weixin-";
339
343
  * 对不上旧会话的历史工具清单)。⇒ 那不是"轨迹是一等公民",那是"用户是一等公民"。
340
344
  *
341
345
  * 新派生 = **由轨迹编码决定**:同一条轨迹 ⇒ 恒同一条 dsh 会话(无论谁在跟它说话);
342
- * 换轨迹 ⇒ 新会话。这正是"skiff 是认知轨迹的一种"。
346
+ * 换轨迹 ⇒ 新会话。这正是"轨迹约束是认知轨迹的一种"。
343
347
  *
344
348
  * ## 连带删掉的东西
345
349
  *
@@ -492,6 +496,42 @@ function clearWeixinCredential(root, accountId) {
492
496
  unsetEntry(root, "credential", lsKey(accountId, "BASEURL"));
493
497
  unsetEntry(root, "credential", lsKey(accountId, "USERID"));
494
498
  }
499
+ /** 飞书凭据键(credential scope: FEISHU_<ACCOUNT_ID>_<FIELD>) */
500
+ function feishuLsKey(accountId, field) {
501
+ return `FEISHU_${accountKeyPart(accountId)}_${field}`;
502
+ }
503
+ /** 读取飞书账号凭据(appId 或 appSecret 缺失 → null——账号未绑定) */
504
+ function readFeishuCredential(root, accountId) {
505
+ const appId = getEntry(root, "credential", feishuLsKey(accountId, "APPID"));
506
+ const appSecret = getEntry(root, "credential", feishuLsKey(accountId, "SECRET"));
507
+ if (!appId || !appSecret) return null;
508
+ return {
509
+ appId,
510
+ appSecret
511
+ };
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
+ }
495
535
  /**
496
536
  * 路由匹配:exact user 优先,通配 `*` 兜底。
497
537
  * @returns 命中的**轨迹编码**;未命中 → null(无路由 → 消息不回复/忽略)
@@ -630,6 +670,19 @@ function nextWeixinAccountId(settings) {
630
670
  while (used.has(`wechat-${n}`)) n++;
631
671
  return `wechat-${n}`;
632
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
+ }
633
686
  /** 切换总开关 */
634
687
  function setWeixinEnabled(root, enabled) {
635
688
  const next = {
@@ -640,4 +693,4 @@ function setWeixinEnabled(root, enabled) {
640
693
  return next;
641
694
  }
642
695
  //#endregion
643
- export { readWeixinCredential as a, sanitizeFileName as c, LOCALSTORE_SCOPES as d, checkLocalstoreGitCompliance as f, runLocalStore as g, readStore as h, matchWeixinRoute as i, weixinInboundDir as l, readGitTrack as m, extractWeixinText as n, readWeixinSettings as o, localstorePath as p, hasVoiceItem as r, route_exports as s, extractWeixinMedia as t, weixinSessionIdForTrajectory as u };
696
+ export { runLocalStore as _, readFeishuCredential as a, route_exports as c, weixinSessionIdForTrajectory as d, LOCALSTORE_SCOPES as f, readStore as g, readGitTrack as h, matchWeixinRoute as i, sanitizeFileName as l, localstorePath as m, extractWeixinText as n, readWeixinCredential as o, checkLocalstoreGitCompliance as p, hasVoiceItem as r, readWeixinSettings as s, extractWeixinMedia as t, weixinInboundDir as u };
@@ -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 '../role/skiff/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
  *