@shgroup/dsh-serenity-hooks 1.72.0 → 1.73.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 (41) hide show
  1. package/dsh.plugin.json +1 -1
  2. package/lib/{ccc-Dkoa2oW3.js → ccc-CZUOq3NY.js} +1 -1
  3. package/lib/{ccc-roots-jZYR2GVE.js → ccc-roots-BhoA7G-0.js} +3 -3
  4. package/lib/client.js +50 -58
  5. package/lib/{wake/cro.d.ts → cro/core.d.ts} +2 -2
  6. package/lib/{wake/cro-guide.d.ts → cro/guide.d.ts} +3 -3
  7. package/lib/{wake/cro-log.d.ts → cro/log.d.ts} +2 -2
  8. package/lib/{wake/cro-turns.d.ts → cro/turns.d.ts} +2 -2
  9. package/lib/guard/seam.d.ts +1 -1
  10. package/lib/{ilink-DEpmE3yi.js → ilink-BMk2w2KY.js} +1 -1
  11. package/lib/im/bridge.d.ts +33 -62
  12. package/lib/im/endpoint.d.ts +1 -1
  13. package/lib/im/feishu-account.d.ts +92 -0
  14. package/lib/im/inbound-event.d.ts +162 -0
  15. package/lib/im/route.d.ts +13 -0
  16. package/lib/index.d.ts +0 -22
  17. package/lib/index.js +700 -914
  18. package/lib/kernel/ccc.d.ts +2 -2
  19. package/lib/kernel/ports.d.ts +2 -4
  20. package/lib/lib-TxscFKeo.js +119355 -0
  21. package/lib/{message-source-kVoNK0C5.js → message-source-ChyVfev9.js} +2 -2
  22. package/lib/{profile-DyMJ_bfr.js → profile-BIQ2widI.js} +14 -11
  23. package/lib/rolldown-runtime-B4iAMlE-.js +35 -0
  24. package/lib/{route-f7JlinIt.js → route-ItCgAsnz.js} +19 -4
  25. package/lib/seams/guards.d.ts +1 -1
  26. package/lib/{settings-lt1i3OZv.js → settings-UcwIPJhM.js} +13 -62
  27. package/lib/skills/resource-index.d.ts +1 -1
  28. package/lib/surface/settings.d.ts +0 -6
  29. package/lib/surface/text.d.ts +72 -0
  30. package/lib/surface/usage.d.ts +2 -2
  31. package/lib/{role/worker/idle.d.ts → trajectory/carrier.d.ts} +12 -2
  32. package/lib/{role/worker → trajectory/delegate}/core.d.ts +7 -1
  33. package/lib/{role/worker → trajectory/delegate}/preset.d.ts +9 -2
  34. package/lib/{role/skiff → trajectory/policy}/profile.d.ts +9 -2
  35. package/lib/{role/skiff/config.d.ts → trajectory/policy/rules.d.ts} +9 -3
  36. package/lib/{role/skiff/registry.d.ts → trajectory/policy/window.d.ts} +7 -1
  37. package/lib/trajectory/prompt.d.ts +1 -1
  38. package/lib/{role/skiff/core.d.ts → trajectory/session.d.ts} +13 -4
  39. package/package.json +2 -1
  40. package/lib/role/skiff/debug.d.ts +0 -88
  41. package/lib/rolldown-runtime-8H4AJuhK.js +0 -14
@@ -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-BhoA7G-0.js";
2
+ import { T as parseTrajectoryCode, b as getLastActiveSessionInfo, k as sessionEvents, y as getActiveSessionInfo } from "./profile-BIQ2widI.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
@@ -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-CZUOq3NY.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
@@ -750,7 +750,7 @@ function archiveSession(root, key, dryRun = false) {
750
750
  };
751
751
  }
752
752
  //#endregion
753
- //#region src/role/skiff/registry.ts
753
+ //#region src/trajectory/policy/window.ts
754
754
  const skiffSessions = /* @__PURE__ */ new Map();
755
755
  /** 登记/更新一个会话 → 轨迹的映射 */
756
756
  function registerSkiffSession(sessionId, trajectoryDirName, ccc) {
@@ -768,14 +768,10 @@ function skiffTrajectoryDirNameFor(sessionId) {
768
768
  const b = skiffSessions.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 — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
779
775
  *
780
776
  * ## 🔴 owner 2026-10-19 重做令(逐字,本文件存在的全部理由)
781
777
  *
@@ -799,6 +795,13 @@ function skiffSessionInfo(sessionId) {
799
795
  * **机制在 ACC**(文件叫什么、怎么读、怎么判、缺省值、如何施加约束);
800
796
  * **内容在 CCC**(`skiff.json` 里填什么:模型、白名单、提示词路径)。
801
797
  * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 skiff 段(该段已退役)。
798
+ *
799
+ * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/skiff/` 下(该目录已随本重构消失)
800
+ *
801
+ * 落点 = `trajectory/policy/`。判据(判读表 §3.1):本文件判的是**某条轨迹的约束面**,
802
+ * 主语是轨迹 ⇒ 它一直就是轨迹切面,只是旧目录把它挂在"角色"这个**平行概念**下。
803
+ * ⚠️ **文件名 `profile` 与 `skiff.json` / `SkiffProfile` 等符号名一律不动**:
804
+ * 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
802
805
  */
803
806
  var profile_exports = /* @__PURE__ */ __exportAll({
804
807
  SKIFF_PROFILE_FILENAME: () => SKIFF_PROFILE_FILENAME,
@@ -930,7 +933,7 @@ function findDirNameByCode(root, code) {
930
933
  *
931
934
  * ## 为什么"绑定的轨迹"从两个来源取(R↓,一个失败模式)
932
935
  * ① **持久绑定**(`readLastBound`,宿主存储域/`.bindings.json`)—— 权威,跨重启成立;
933
- * ② **内存注册表**(`skiff/registry`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
936
+ * ② **内存注册表**(`trajectory/policy/window`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
934
937
  * ⇒ 只取 ① 会在建会话的第一轮判成"不是 skiff"(工具面不收窄,模型看见不该有的工具);
935
938
  * 只取 ② 会在进程重启后全判成"不是"(skiff 失去约束,**权限面静默放开**)。
936
939
  * ⇒ **两来源并取**,都不中才 `null`。
@@ -960,4 +963,4 @@ function isSkiffSession(root, sessionId) {
960
963
  return skiffProfileForSession(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 _, 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 };
@@ -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-CZUOq3NY.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";
@@ -302,6 +302,7 @@ var route_exports = /* @__PURE__ */ __exportAll({
302
302
  hasVoiceItem: () => hasVoiceItem,
303
303
  matchWeixinRoute: () => matchWeixinRoute,
304
304
  nextWeixinAccountId: () => nextWeixinAccountId,
305
+ readFeishuCredential: () => readFeishuCredential,
305
306
  readImSettings: () => readImSettings,
306
307
  readWeixinCredential: () => readWeixinCredential,
307
308
  readWeixinSettings: () => readWeixinSettings,
@@ -325,7 +326,7 @@ function accountKeyPart(accountId) {
325
326
  * 微信桥 skiff 会话 id 前缀(守卫识别"外部面"用)。
326
327
  *
327
328
  * ⚠️ **2026-10-19 起它只是命名习惯,不再是判据** —— skiff 的身份是**轨迹**,
328
- * 判据 = 「绑定的轨迹有 `skiff.json`」(`role/skiff/profile.ts` 的 `isSkiffSession`)。
329
+ * 判据 = 「绑定的轨迹有 `skiff.json`」(`trajectory/policy/profile.ts` 的 `isSkiffSession`)。
329
330
  * 保留前缀只为:① 日志/会话列表里一眼认出这是外部面;② 存量会话目录名不变。
330
331
  */
331
332
  const WEIXIN_SESSION_PREFIX = "skiff-weixin-";
@@ -492,6 +493,20 @@ function clearWeixinCredential(root, accountId) {
492
493
  unsetEntry(root, "credential", lsKey(accountId, "BASEURL"));
493
494
  unsetEntry(root, "credential", lsKey(accountId, "USERID"));
494
495
  }
496
+ /** 飞书凭据键(credential scope: FEISHU_<ACCOUNT_ID>_<FIELD>) */
497
+ function feishuLsKey(accountId, field) {
498
+ return `FEISHU_${accountKeyPart(accountId)}_${field}`;
499
+ }
500
+ /** 读取飞书账号凭据(appId 或 appSecret 缺失 → null——账号未绑定) */
501
+ function readFeishuCredential(root, accountId) {
502
+ const appId = getEntry(root, "credential", feishuLsKey(accountId, "APPID"));
503
+ const appSecret = getEntry(root, "credential", feishuLsKey(accountId, "SECRET"));
504
+ if (!appId || !appSecret) return null;
505
+ return {
506
+ appId,
507
+ appSecret
508
+ };
509
+ }
495
510
  /**
496
511
  * 路由匹配:exact user 优先,通配 `*` 兜底。
497
512
  * @returns 命中的**轨迹编码**;未命中 → null(无路由 → 消息不回复/忽略)
@@ -640,4 +655,4 @@ function setWeixinEnabled(root, enabled) {
640
655
  return next;
641
656
  }
642
657
  //#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 };
658
+ 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 SkiffProfile } from '../trajectory/policy/profile.js';
13
13
  export interface GuardInput {
14
14
  root: string;
15
15
  toolName: string;
@@ -1,5 +1,5 @@
1
- import { f as hostSettings } from "./ccc-roots-jZYR2GVE.js";
2
- import { _ as resolveInside, g as readUtf8 } from "./ccc-Dkoa2oW3.js";
1
+ import { f as hostSettings } from "./ccc-roots-BhoA7G-0.js";
2
+ import { _ as resolveInside, g as readUtf8 } from "./ccc-CZUOq3NY.js";
3
3
  import { dirname, join } from "node:path";
4
4
  import { existsSync, readFileSync, statSync } from "node:fs";
5
5
  import { fileURLToPath } from "node:url";
@@ -48,20 +48,26 @@ const ACC_VERSION = (() => {
48
48
  }
49
49
  })();
50
50
  //#endregion
51
- //#region src/role/skiff/config.ts
51
+ //#region src/trajectory/policy/rules.ts
52
52
  /**
53
- * role/skiff/config.ts — skiff 约束面的**纯逻辑助手**(零 DSH 依赖,可独立单测)
53
+ * trajectory/policy/rules.ts — 轨迹约束面的**纯逻辑助手**(零 DSH 依赖,可独立单测)
54
54
  *
55
55
  * ## 2026-10-19 重做后的职责边界(R↓,别再混起来)
56
56
  *
57
57
  * | 模块 | 管什么 |
58
58
  * |---|---|
59
59
  * | `./profile.ts` | **判据 + 读盘**("这是不是 skiff"、"约束面是什么") |
60
- * | `./config.ts`(本文件) | **从约束面派生出的纯函数**(白名单集合、提示词读取器、基础提示词文本) |
61
- * | `./core.ts` | 会话创建/复用、提问、守门查询 |
60
+ * | `./rules.ts`(本文件) | **从约束面派生出的纯函数**(白名单集合、提示词读取器、基础提示词文本) |
61
+ * | `../session-create.ts` | 会话创建/复用、提问、守门查询 |
62
62
  *
63
63
  * ⇒ 本文件**不再读 `serenity.json`**:`skiff.roles` 整段已退役(owner 2026-10-19 重做)。
64
64
  * 它只接收一个已解析好的 `SkiffProfile`,因此**不涉及任何 IO**(除提示词文件,那是刻意懒读的)。
65
+ *
66
+ * ## S12(2026-10-19,轨迹中心重构)
67
+ *
68
+ * 原名 `role/skiff/config.ts`。改名理由(框架 §6.3「角色不是一个概念,是一段历史」):
69
+ * 它派生的是**某条轨迹的约束面**,与"配置读取"无关(本文件零配置读取,见上一段)
70
+ * ⇒ `config` 这个名字描述的是**它曾经的样子**,`rules` 描述它**现在做的事**。
65
71
  */
66
72
  /** 白名单推导 ────────────────────────────────────────────────────────────── */
67
73
  /** 提示词来源提示串(`apply` 回执与面板共用;避免两处措辞漂) */
@@ -202,57 +208,6 @@ function buildSkiffBasePrompt(code) {
202
208
  ].join("\n");
203
209
  }
204
210
  //#endregion
205
- //#region src/kernel/ports.ts
206
- /**
207
- * 集中端口表。
208
- * A=宿主主面(插件不监听)/ B=网关(可配,默认关)/ C=微信发送(默认开,仅 loopback)
209
- * / D=Skiff 调试(默认关)。
210
- */
211
- const FACE_PORTS = {
212
- main: {
213
- port: 3080,
214
- host: null,
215
- defaultEnabled: true,
216
- meaning: "宿主 DSH 主 WebUI + 插件 /serenity/* 路由面(**插件不起此 listener**,端口自宿主读)"
217
- },
218
- gateway: {
219
- port: 3081,
220
- host: "0.0.0.0",
221
- defaultEnabled: false,
222
- meaning: "双端口网关(外部登录 + 全量反代宿主主面;host/port 走 plugin 全局配置)"
223
- },
224
- weixinSend: {
225
- port: 3082,
226
- host: "127.0.0.1",
227
- defaultEnabled: true,
228
- meaning: "微信主动发送面(容器外进程 → POST /send;与 3080 显式解耦,不经网关)"
229
- },
230
- skiffDebug: {
231
- port: 3099,
232
- host: "127.0.0.1",
233
- defaultEnabled: false,
234
- meaning: "Skiff 调试问答面(人工调试子角色;无认证,仅靠 loopback)"
235
- }
236
- };
237
- /** 宿主主 WebUI 端口(面 A:插件**不监听**,只读取;`readWebPort` 的回退值) */
238
- const MAIN_WEB_PORT = FACE_PORTS.main.port;
239
- /** 网关端口默认值(面 B) */
240
- const GATEWAY_PORT = FACE_PORTS.gateway.port;
241
- /** 微信主动发送端口默认值(面 C) */
242
- const WEIXIN_SEND_PORT = FACE_PORTS.weixinSend.port;
243
- /** Skiff 调试页端口默认值(面 D) */
244
- const SKIFF_DEBUG_PORT = FACE_PORTS.skiffDebug.port;
245
- /**
246
- * **机制端口**词表(output-guard 用:agent 在**用户可见输出**里提及内部端口即打回)。
247
- *
248
- * 由 {@link FACE_PORTS} 机械派生 ⇒ 与面清单**永不漂移**。
249
- * ⚠️ 修复记录(C4 块 B,2026-09-15):旧常量硬写 `['3080','3081','3099','3100']`
250
- * ——**漏 3082**(微信发送面,默认开)⇒ 守卫拦不住"3082"这类提及。现由表派生,四面齐全。
251
- * ⚠️ 面变更记录(2026-10-15):**面 E(3100 ACP/问答)已整体退役**(owner 裁「砍掉外部问答」)
252
- * ⇒ 本词表随之少一项,**无需另改**(这正是"派生而非手抄"的收益)。
253
- */
254
- const MECHANISM_PORTS = Object.keys(FACE_PORTS).map((id) => String(FACE_PORTS[id].port));
255
- //#endregion
256
211
  //#region src/surface/settings.ts
257
212
  /**
258
213
  * 设置面板命名空间 = **profile 条目 id**(v0.1.7 起;与旧 `settings.yaml` 段名逐字相同)。
@@ -263,8 +218,6 @@ function defaultSimpleSettings() {
263
218
  return {
264
219
  gatewayEnabled: false,
265
220
  rebuildThresholdK: 400,
266
- skiffEnabled: false,
267
- skiffDebugPort: SKIFF_DEBUG_PORT,
268
221
  croEnabled: true,
269
222
  diagramEnabled: false,
270
223
  humanChannel: defaultHumanChannelSettings()
@@ -358,8 +311,6 @@ function simpleSettingsFromConfig(config) {
358
311
  return {
359
312
  gatewayEnabled: unwrapVolatile(config.gatewayEnabled) ?? config.gateway?.enabled ?? d.gatewayEnabled,
360
313
  rebuildThresholdK: unwrapVolatile(config.rebuildThresholdK) ?? config.rebuild?.thresholdK ?? d.rebuildThresholdK,
361
- skiffEnabled: unwrapVolatile(config.skiffEnabled) ?? config.skiff?.enabled ?? d.skiffEnabled,
362
- skiffDebugPort: unwrapVolatile(config.skiffDebugPort) ?? config.skiff?.debugPort ?? d.skiffDebugPort,
363
314
  croEnabled: unwrapVolatile(config.croEnabled) ?? d.croEnabled,
364
315
  diagramEnabled: unwrapVolatile(config.diagramEnabled) ?? config.diagram?.enabled ?? d.diagramEnabled,
365
316
  humanChannel: humanChannelSettingsFromConfig(config.humanChannel)
@@ -400,4 +351,4 @@ function registerSettingsSection(ctx, config) {
400
351
  } catch {}
401
352
  }
402
353
  //#endregion
403
- export { resolveProfileSystemPrompt as _, GATEWAY_PORT as a, SKIFF_DEBUG_PORT as c, buildSkiffBasePrompt as d, createProfilePromptReader as f, profileToolWhitelist as g, profileSystemPromptSource as h, FACE_PORTS as i, WEIXIN_SEND_PORT as l, profileMsmWhitelist as m, readSimpleSettings as n, MAIN_WEB_PORT as o, profileCognitiveTrajectory as p, registerSettingsSection as r, MECHANISM_PORTS as s, SERENITY_SETTINGS_NS as t, SKIFF_PROFILE_HINT as u, ACC_VERSION as v, findPackageRoot as y };
354
+ export { buildSkiffBasePrompt as a, profileMsmWhitelist as c, resolveProfileSystemPrompt as d, ACC_VERSION as f, SKIFF_PROFILE_HINT as i, profileSystemPromptSource as l, readSimpleSettings as n, createProfilePromptReader as o, findPackageRoot as p, registerSettingsSection as r, profileCognitiveTrajectory as s, SERENITY_SETTINGS_NS as t, profileToolWhitelist as u };
@@ -14,7 +14,7 @@
14
14
  * 六条硬性规则(逐条对应设计 §4.2,改这里先改那里):
15
15
  * ① **只枚举,不注入正文** —— 索引里**绝不**出现任何参考文件的正文;
16
16
  * ② **确定性排序** = 相对路径的 **UTF-8 字节序**(🔴 **不用 mtime**:mtime 随检出漂移,
17
- * 会让每请求的注入文本抖动;对照 `src/wake/cro.ts:101` 那份**落盘快照**用 {name,bytes,mtime} ——
17
+ * 会让每请求的注入文本抖动;对照 `src/cro/core.ts:101` 那份**落盘快照**用 {name,bytes,mtime} ——
18
18
  * **同一件事两处的取舍相反,那个差异是判据不是巧合**);
19
19
  * ③ **有界 + 响亮** —— 条数/字符各有上限,超出**必须显式写出还剩多少项**,**绝不静默截断**;
20
20
  * ④ **摘要可复现** —— 取该文件首个 `#` 标题(剥 markdown 记号);取不到 ⇒ 留空,**不编**;
@@ -73,8 +73,6 @@ interface SimpleConfigFragment {
73
73
  humanChannel?: HumanChannelConfigFragment;
74
74
  gatewayEnabled?: PanelBoolean;
75
75
  rebuildThresholdK?: PanelNumber;
76
- skiffEnabled?: PanelBoolean;
77
- skiffDebugPort?: PanelNumber;
78
76
  croEnabled?: PanelBoolean;
79
77
  diagramEnabled?: PanelBoolean;
80
78
  }
@@ -90,10 +88,6 @@ interface SerenitySimpleSettings {
90
88
  gatewayEnabled: boolean;
91
89
  /** F2 触发阈值(需求① S142 用户拍板:百分比比例 → K 数值;projectedTokens ≥ thresholdK*1000 触发) */
92
90
  rebuildThresholdK: number;
93
- /** F4 Skiff 调试服务总开关(实验性;默认关——不随插件加载自动启动,人工开启) */
94
- skiffEnabled: boolean;
95
- /** F4 Skiff 调试端口(默认 3099,仅 127.0.0.1) */
96
- skiffDebugPort: number;
97
91
  /** **CRO(轨迹自编程唤起)总开关**(2026-09-21 所有者令新增;**缺省开**)。
98
92
  *
99
93
  * CRO = 轨迹目录下放一个 `continuous-re-occurrence.ts`,由 ACC 的 5min tick spawn,
@@ -0,0 +1,72 @@
1
+ /**
2
+ * surface/text.ts — 输出文本的清洗原语(**纯函数,零 listener、零宿主依赖**,可独立单测)
3
+ *
4
+ * ## 为什么它从调试面里拆出来(S11,2026-10-19,轨迹中心重构)
5
+ *
6
+ * 拆之前它是 `role/skiff/debug.ts` 的**后半段**,而那份文件是**混装件**:
7
+ * · 前半段 = **面 D** 的 HTTP 调试页(自起 listener,端口见 `kernel/ports.ts`)
8
+ * · 后半段 = **通用文本清洗**(本文件,已随重构搬到 `surface/text.ts`)
9
+ *
10
+ * 判据(实测,不是猜):本文件的导出被**两个与 skiff 无关的模块**直接使用 ——
11
+ * `im/bridge.ts`(微信桥:回复前剥 think)与 `guard/seam.ts`(输出守卫:检测前剥 think)。
12
+ * ⇒ 它不属于"某一条轨迹的调试面",它是**任何输出面都会用的清洗**。
13
+ *
14
+ * ## 与面的关系(单向)
15
+ *
16
+ * `surface/debug.ts`(面 D)──► 本文件
17
+ * 本文件 ──► 无(不 import 任何面)
18
+ *
19
+ * ⛔ **反向依赖会立刻建立环**:本文件若为了"方便"去 import 面 D 的 sendJson 之类,
20
+ * 就把纯函数拖进了 HTTP 生命周期。
21
+ */
22
+ /**
23
+ * Markdown 渲染(v1.25.9,正经库 marked 服务端渲染——替代手写正则渲染器,S142 用户要求):
24
+ * ① 提取 `<think>…</think>` 块(v1.26.8 状态机扫描,占位符 \u0001T<idx>\u0001)
25
+ * ② 正文与 think 内容**先 escapeHtml 再 marked.parse**(GFM + breaks)——markdown 语法不受
26
+ * 转义影响,原始 HTML 注入被消除(安全);代码块内 `<` 显示为实体(可接受)
27
+ * ③ think 占位符:默认还原为 `<details class="think">` 折叠卡(🧠 思考过程,默认收起);
28
+ * **hideThink=true(v1.26.4,public 口)→ 直接移除**(思考过程对普通用户不展示)
29
+ * @param hideThink 为 true 时 `<think>` 内容完全不渲染(public 问答页体验)
30
+ */
31
+ export declare function renderSkiffMarkdown(raw: string, hideThink?: boolean): string;
32
+ /**
33
+ * 剥离 `<think>…</think>` 块(v1.27.1,微信桥用户反馈:"过微信桥回复给用户的消息,
34
+ * 要去掉 think 标签,用户不应看到")。复用 extractThinkBlocks 状态机(v1.26.8,
35
+ * 弃正则)——提取后**只保留正文**(占位符替换为空,think 内容丢弃),
36
+ * 未闭合 think 优雅截断。适用于纯文本输出面(微信等不支持 think 折叠的通道)。
37
+ */
38
+ export declare function stripThink(raw: string): string;
39
+ /**
40
+ * JSC (Safari/iOS) JSON.parse 快速路径正则兼容化(v1.26.9,S142 调研定稿)。
41
+ *
42
+ * 背景:WebKit bug 200190「JavaScriptCore's Regex can't match the content」——JSC 的
43
+ * JSON.parse 用**内部正则**预校验字符串;内容含**原始** `\u2028`(行分隔符)/`\u2029`
44
+ * (段分隔符)时正则无法匹配 → 对**合法 JSON** 也抛
45
+ * `SyntaxError: The string did not match the expected pattern`(sentry-javascript #2487 同源)。
46
+ * JSON.stringify **不转义** `\u2028`/`\u2029`/`\uFEFF`(它们都是合法 JSON 字符串字符)→
47
+ * 在 JSON **文本层**把它们替换为 `\uXXXX` 转义序列:JSON.parse 后语义完全一致(还原原字符),
48
+ * 且 JSC 正则看到的是常规 ASCII 转义(与 JSON.stringify 对控制字符的输出同形态,安全)。
49
+ *
50
+ * 3099 调试页客户端 `await res.json()` 与页面内嵌 JSON 均需此兼容层
51
+ * ——iOS Safari 用户实测"复杂回答"触发。(原同批还列了 3100 问答页,该面已退役,2026-10-15)
52
+ *
53
+ * @param jsonText JSON.stringify 的输出文本;原地等价替换,返回 JSC 安全文本
54
+ */
55
+ export declare function jscSafeJsonText(jsonText: string): string;
56
+ /** HTML 文本/属性转义(本文件的唯一转义口径;面 D 渲染时也用这一个,不另写) */
57
+ export declare function escapeHtml(s: string): string;
58
+ /**
59
+ * 提取 `<think>…</think>` 块(v1.26.8:**状态机扫描,弃正则**——用户批评"老用正则不是个办法")。
60
+ *
61
+ * 逐字符扫描识别开/闭标签(大小写不敏感;`<think ...>` 允许属性变体;`</think >` 允许尾随空格),
62
+ * 不依赖正则回溯,天然处理:
63
+ * - **嵌套 `<think>`**(内层按内容处理,不递归——DeepSeek think 不会嵌套)
64
+ * - **未闭合 `<think>`**(优雅截断:剩余全部作为 think 内容,不泄漏标记)
65
+ * - **占位符冲突**(用 \u0001T<idx>\u0001——ASCII 控制字符,正文几乎不可能出现)
66
+ *
67
+ * @returns body(占位符替换后的正文)+ thinks(提取的 think 内容数组,保序)
68
+ */
69
+ export declare function extractThinkBlocks(raw: string): {
70
+ body: string;
71
+ thinks: string[];
72
+ };
@@ -15,7 +15,7 @@
15
15
  * ⇒ 本模块让每个 CCC 留下一份**纯计数**账本:**用了哪个、多少次、第一次和最近一次是什么时候**。
16
16
  * 用途 = 清理/精简的**依据**(没有人用的东西与天天在用的东西,不再靠猜)。
17
17
  *
18
- * ## 🔴 铁律(与 `wake/cro-log.ts` 同族)
18
+ * ## 🔴 铁律(与 `cro/log.ts` 同族)
19
19
  *
20
20
  * **本模块每个导出函数都不抛错**:读盘 / 解析 / 写盘失败一律返回结构化失败,
21
21
  * 由调用方只记一行日志(或什么都不做)⇒ **统计的问题绝不影响工具执行与既有链路**。
@@ -31,7 +31,7 @@
31
31
  *
32
32
  * 宿主会被重启(本容器实测 24h 内 3 次)⇒ 计数**不能只活在内存里**:
33
33
  * 每次写盘 = **读旧文件 → 在旧值上自增 → 原子写**(`tmp + rename`,与 `wake/registry.ts` /
34
- * `wake/cro-log.ts` 同款形态)⇒ **进程重启后计数自然延续**,无需额外的 flush/落盘时机。
34
+ * `cro/log.ts` 同款形态)⇒ **进程重启后计数自然延续**,无需额外的 flush/落盘时机。
35
35
  *
36
36
  * ## 口径(两个字段,勿合并)
37
37
  *
@@ -1,7 +1,17 @@
1
1
  /**
2
- * role/worker/idle.ts — 等待 agent 空闲(含销毁竞速,S142 review F-08)
2
+ * trajectory/carrier.ts — 等待 agent 空闲(含销毁竞速,S142 review F-08)
3
3
  *
4
- * 为什么单独成模块:`askSkiff`(skiff 问答)与 `cheap-worker`(杂工循环)都要"等这一轮做完",
4
+ * ## 为什么在 `trajectory/` 而不是某个委派子域(S14,2026-10-19,轨迹中心重构)
5
+ *
6
+ * 它的两个消费者分属**不同的层**:`trajectory/session.ts`(轨迹的载体管理)与
7
+ * `cheap-worker`(轨迹 × 轨迹的委派)。⇒ 它**不是哪一家的私有件**,
8
+ * 而是"载体这一轮跑完没有"这个问题的**公共原语**——凡与载体打交道的地方都可能在用。
9
+ *
10
+ * 🔴 名字从 `idle` 改为 `carrier`:`idle` 描述的是**状态**(宿主 agent 空闲),
11
+ * 而本模块回答的是**关于载体的问题**(它空闲了/它被销毁了/会话先没了)。
12
+ * 三个结算条件(见下)里有两条与"空闲"无关 —— 名字取窄了会误导调用方以为只需等 idle。
13
+ *
14
+ * 为什么单独成模块:`askSkiff`(问答)与 `cheap-worker`(杂工循环)都要"等这一轮做完",
5
15
  * 此前各自复制了一份只监听 `agent/status → idle` 的实现。该实现有一个静默挂死:
6
16
  * **agent 先被销毁(会话关闭/进程回收/显式 dispose)就永远不会再发 idle 事件**,
7
17
  * 等待方 Promise 永不结算 → 问答/杂工永久卡住(宿主的 disposal 语义:
@@ -1,9 +1,15 @@
1
1
  /**
2
- * role/worker/core.ts — cheap-worker(杂工)纯逻辑层(零 DSH 依赖,可独立单测)
2
+ * trajectory/delegate/core.ts — cheap-worker(杂工)纯逻辑层(零 DSH 依赖,可独立单测)
3
3
  *
4
4
  * 🆕 2026-10-14(owner 令「删除后台运行能力」):**进度文件 / stop token / 轮次循环**整族已退场 ——
5
5
  * 它们**只**服务于 background 模式。本模块现存 = 前台委派真正需要的三件:
6
6
  * 模型串解析 / 白名单校验 / provider 可用性判读(+ 使用指引文本)。
7
+ *
8
+ * ## S14(2026-10-19,轨迹中心重构):此前位于 `role/worker/` 下(该目录已消失)
9
+ *
10
+ * 落点 = `trajectory/delegate/`。判据(判读表 §3.1):它是**轨迹 × 轨迹**那种合法形态 ——
11
+ * 主语是「主轨迹把活交给子 agent」,既不是某一条轨迹的切面,也不是容器宪法。
12
+ * ⚠️ 它**不属于** `policy/`:policy 管"这条轨迹允许什么",本模块管"一条轨迹怎么把活派出去"。
7
13
  */
8
14
  /** 解析 model 字符串(provider/model)→ {provider, model};无 / 视为 model-only */
9
15
  export declare function splitModel(model: string): {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * role/worker/preset.ts — cheap-worker worker 的 preset 继承 + 工具面收窄(纯函数,可单测)
2
+ * trajectory/delegate/preset.ts — cheap-worker worker 的 preset 继承 + 工具面收窄(纯函数,可单测)
3
3
  *
4
4
  * v1.24.0:loop → cheap-worker 重命名。对齐 subagent 先例(applyChildComposition →
5
5
  * agentPresets.composeFrom):cheap-worker worker 在创建窗口内 join 发起方 agent 的 standing
@@ -16,7 +16,14 @@
16
16
  * (在 agent 未发布前执行 composeFrom + restrict,失败由创建事务回滚)。
17
17
  *
18
18
  * 仅依赖 cordis 的 Context 类型(type-only,运行时擦除)——保持可被 vitest
19
- * 直接加载(与 kernel/ccc.ts / role/worker/core.ts 同级的纯模块约定)。
19
+ * 直接加载(与 kernel/ccc.ts / trajectory/delegate/core.ts 同级的纯模块约定)。
20
+ *
21
+ * ## S14(2026-10-19,轨迹中心重构):此前位于 `role/worker/` 下(该目录已消失)
22
+ *
23
+ * 落点 = `trajectory/delegate/`,与 `./core.ts` 同域。这里的"preset 继承"是**委派关系**的
24
+ * 一部分(子 agent join 父的 standing preset),主语仍是"主轨迹怎么把活派出去"。
25
+ * 🔴 递归防护(`deny: ['cheap-worker']`)也住在这里 —— 它是委派**方向的守卫**,不是容器宪法:
26
+ * 换一条轨迹,它照样生效,但它约束的是"派出去之后再派"这件事。
20
27
  */
21
28
  import type { Context } from 'cordis';
22
29
  /** 从父 agent ctx 解析 preset 继承的创建期组合。 */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * role/skiff/profile.ts — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
2
+ * trajectory/policy/profile.ts — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
3
3
  *
4
4
  * ## 🔴 owner 2026-10-19 重做令(逐字,本文件存在的全部理由)
5
5
  *
@@ -23,6 +23,13 @@
23
23
  * **机制在 ACC**(文件叫什么、怎么读、怎么判、缺省值、如何施加约束);
24
24
  * **内容在 CCC**(`skiff.json` 里填什么:模型、白名单、提示词路径)。
25
25
  * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 skiff 段(该段已退役)。
26
+ *
27
+ * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/skiff/` 下(该目录已随本重构消失)
28
+ *
29
+ * 落点 = `trajectory/policy/`。判据(判读表 §3.1):本文件判的是**某条轨迹的约束面**,
30
+ * 主语是轨迹 ⇒ 它一直就是轨迹切面,只是旧目录把它挂在"角色"这个**平行概念**下。
31
+ * ⚠️ **文件名 `profile` 与 `skiff.json` / `SkiffProfile` 等符号名一律不动**:
32
+ * 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
26
33
  */
27
34
  /** `skiff.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
28
35
  export declare const SKIFF_PROFILE_FILENAME = "skiff.json";
@@ -95,7 +102,7 @@ export declare function findDirNameByCode(root: string, code: string): string |
95
102
  *
96
103
  * ## 为什么"绑定的轨迹"从两个来源取(R↓,一个失败模式)
97
104
  * ① **持久绑定**(`readLastBound`,宿主存储域/`.bindings.json`)—— 权威,跨重启成立;
98
- * ② **内存注册表**(`skiff/registry`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
105
+ * ② **内存注册表**(`trajectory/policy/window`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
99
106
  * ⇒ 只取 ① 会在建会话的第一轮判成"不是 skiff"(工具面不收窄,模型看见不该有的工具);
100
107
  * 只取 ② 会在进程重启后全判成"不是"(skiff 失去约束,**权限面静默放开**)。
101
108
  * ⇒ **两来源并取**,都不中才 `null`。
@@ -1,16 +1,22 @@
1
1
  /**
2
- * role/skiff/config.ts — skiff 约束面的**纯逻辑助手**(零 DSH 依赖,可独立单测)
2
+ * trajectory/policy/rules.ts — 轨迹约束面的**纯逻辑助手**(零 DSH 依赖,可独立单测)
3
3
  *
4
4
  * ## 2026-10-19 重做后的职责边界(R↓,别再混起来)
5
5
  *
6
6
  * | 模块 | 管什么 |
7
7
  * |---|---|
8
8
  * | `./profile.ts` | **判据 + 读盘**("这是不是 skiff"、"约束面是什么") |
9
- * | `./config.ts`(本文件) | **从约束面派生出的纯函数**(白名单集合、提示词读取器、基础提示词文本) |
10
- * | `./core.ts` | 会话创建/复用、提问、守门查询 |
9
+ * | `./rules.ts`(本文件) | **从约束面派生出的纯函数**(白名单集合、提示词读取器、基础提示词文本) |
10
+ * | `../session-create.ts` | 会话创建/复用、提问、守门查询 |
11
11
  *
12
12
  * ⇒ 本文件**不再读 `serenity.json`**:`skiff.roles` 整段已退役(owner 2026-10-19 重做)。
13
13
  * 它只接收一个已解析好的 `SkiffProfile`,因此**不涉及任何 IO**(除提示词文件,那是刻意懒读的)。
14
+ *
15
+ * ## S12(2026-10-19,轨迹中心重构)
16
+ *
17
+ * 原名 `role/skiff/config.ts`。改名理由(框架 §6.3「角色不是一个概念,是一段历史」):
18
+ * 它派生的是**某条轨迹的约束面**,与"配置读取"无关(本文件零配置读取,见上一段)
19
+ * ⇒ `config` 这个名字描述的是**它曾经的样子**,`rules` 描述它**现在做的事**。
14
20
  */
15
21
  import type { SkiffProfile } from './profile.js';
16
22
  /** 白名单推导 ────────────────────────────────────────────────────────────── */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * role/skiff/registry.ts — skiff 会话注册表(sessionId → {trajectory, ccc};零 DSH 依赖)
2
+ * trajectory/policy/window.ts — 会话 → 轨迹 的内存映射(零 DSH 依赖)
3
3
  *
4
4
  * ## 它现在只做一件事:**把「会话」映到「轨迹」**
5
5
  *
@@ -8,6 +8,12 @@
8
8
  * ⇒ 本表退化为一张**会话 → 轨迹目录名**的内存映射,供**同步**热路径(guards / system-prompt)查询;
9
9
  * 权威来源仍是持久绑定(`trajectory/bound.ts` 的 `readLastBound`)。
10
10
  *
11
+ * ## S12(2026-10-19,轨迹中心重构):原名 `role/skiff/registry.ts`
12
+ *
13
+ * 改名理由:它**不是**一张"注册表"(注册表的语义是权威名单),它是**权威来源之外的一个窗口**——
14
+ * 覆盖「轨迹已定、绑定还没落盘」那一段(见下方「为什么还需要这张内存表」)。
15
+ * `registry` 这个名字会让下一个人以为它是权威,而权威在 `bound.ts` ⇒ 改叫 `window`。
16
+ *
11
17
  * ## 为什么还需要这张内存表(R↓,一个窗口期)
12
18
  *
13
19
  * 持久绑定是**异步落盘**的(宿主存储域写入)。会话刚建立、`skiff.json` 已生效、绑定的记录
@@ -32,7 +32,7 @@
32
32
  * `PROMPT.md` 不存在时**不报错**(普通轨迹常态)。skiff 的旧字段 `systemPromptFile`
33
33
  * 在兼容期仍被读取——优先级见 {@link resolveTrajectoryPrompt}。
34
34
  */
35
- import type { SkiffProfile } from '../role/skiff/profile.js';
35
+ import type { SkiffProfile } from './policy/profile.js';
36
36
  /** 轨迹提示词的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
37
37
  export declare const TRAJECTORY_PROMPT_FILENAME = "PROMPT.md";
38
38
  /** 一次解析的结果(`source` 说明正文**从哪来**,便于诊断与「为什么我改的不生效」) */
@@ -1,7 +1,7 @@
1
1
  /**
2
- * role/skiff/core.ts — skiff 会话核心(**2026-10-19 重做**:skiff = 带 `skiff.json` 的认知轨迹)
2
+ * trajectory/session.ts — 轨迹的**会话(载体)管理**(**2026-10-19 重做**:skiff = 带 `skiff.json` 的认知轨迹)
3
3
  *
4
- * ## 与旧版的根本差别(R↓,这是本次重做的全部内容)
4
+ * ## 与旧版的根本差别(R↓,这是那次重做的全部内容)
5
5
  *
6
6
  * 旧版:skiff 是**一个角色**(`serenity.json` 的 `skiff.roles.<name>`),会话身份由
7
7
  * dsh sessionId 前缀 `skiff-` 判定,工作台由 `ensureSkiffSession` **另建一个 SESSION**。
@@ -9,7 +9,7 @@
9
9
  * 新版:skiff 是**一条认知轨迹**(目录里有 `skiff.json`)——
10
10
  * · **身份 = 轨迹编码**(不是角色名,不是 sessionId 前缀);
11
11
  * · **工作台 = 该轨迹自己的 SESSION.md**(不再另建,`ensureSkiffSession` 已删除);
12
- * · **判据 = 绑定的轨迹有没有 `skiff.json`**(唯一入口 `profile.ts` 的 `skiffProfileForSession`)。
12
+ * · **判据 = 绑定的轨迹有没有 `skiff.json`**(唯一入口 `policy/profile.ts` 的 `skiffProfileForSession`)。
13
13
  *
14
14
  * ⇒ 删掉的东西(它们只是旧模型的补丁,不是通用机制):
15
15
  * `SKIFF_SESSION_PREFIX` 判定 / `ensureSkiffSession` 自动建工作台 /
@@ -17,10 +17,19 @@
17
17
  *
18
18
  * ## 本文件仍负责
19
19
  * agent 创建/复用(resume-or-create)/系统提示词段注册/提问与等本轮回答/守门查询。
20
+ *
21
+ * ## S13(2026-10-19,轨迹中心重构):此前位于 `role/skiff/` 下(该目录已随本重构消失)
22
+ *
23
+ * 文件名从 `core` 改为 `session`:它管的是**轨迹的会话(载体)**——
24
+ * 与同目录 `live.ts`(活载体查询)/`rebuild.ts`(换船板)/`cleanup.ts`(清理)同族。
25
+ * `core` 描述的是"它在角色目录里居中",而那层含义随目录一起消失了。
26
+ *
27
+ * 🔴 **不拆**(S13 判据):26 KB 未过 30 KB 阈值 ⇒ 按计划 R-d 的候选 ②,
28
+ * 本期是**零语义改动**,拆函数体属另一件事。
20
29
  */
21
30
  import type { Context } from 'cordis';
22
31
  import type { Agent, AgentHandle } from '@deepseek-ai/dsh-agent';
23
- import { type SkiffProfile } from './profile.js';
32
+ import { type SkiffProfile } from './policy/profile.js';
24
33
  export type { SkiffProfile };
25
34
  /** 查 sessionId 承载的轨迹目录名(无 → null) */
26
35
  export declare function skiffTrajectoryDirNameFor(sessionId: string): string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.72.0",
3
+ "version": "1.73.0",
4
4
  "description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/微信桥/认知轨迹唤醒注册表。skiff = 目录下有 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": {
@@ -150,6 +150,7 @@
150
150
  "@deepseek-ai/dsh-web-fetch-http": "0.1.7-rc.1",
151
151
  "@deepseek-ai/dsh-workspace": "0.1.7-rc.1",
152
152
  "@deepseek-ai/schemastery": "^3.18.4",
153
+ "@larksuiteoapi/node-sdk": "^1.76.0",
153
154
  "@types/node": "^20.0.0",
154
155
  "@types/qrcode-generator": "^1.0.6",
155
156
  "@types/react": "^18.2.0",