@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
package/lib/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { i as __toESM, n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
2
- import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-BhoA7G-0.js";
3
- import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readCheapWorkerConfig, g as readUtf8, h as readSafeModeHiddenTools, i as findGitRoot, l as pathInside, m as readExclusiveTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readCognitiveTrajectorySkills, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-CZUOq3NY.js";
4
- import { A as sessionsRoot, C as namingTitleFor, D as readTrajectoryUid, E as readActiveSessionMd, F as isoLocal, I as localFileStamp, L as localHuman, M as showSession, N as summarize, O as resolveSessionByTitle, P as useSession, R as localIdStamp, S as listSessions, T as parseTrajectoryCode, _ as extractSessionMdPathFromText, a as readSkiffProfileAt, c as registerSkiffSession$1, d as COGNITIVE_TRAJECTORY_ACTIONS, f as DEFAULT_SESSION_SCOPE, g as createSession, h as clearActiveSessionInfo, j as setActiveSessionInfo, k as sessionEvents$1, l as skiffTrajectoryDirNameFor, m as archiveSession, n as isSkiffSession, o as readSkiffProfileByCode, p as UID_FILENAME, r as listSkiffProfiles, s as skiffProfileForSession, t as SKIFF_PROFILE_FILENAME, u as unregisterSkiffSession$1, v as findSession, w as parseSessionContextFromEvents, x as listActiveTrajectories, y as getActiveSessionInfo } from "./profile-BIQ2widI.js";
5
- import { _ as runLocalStore, a as readFeishuCredential, d as weixinSessionIdForTrajectory, f as LOCALSTORE_SCOPES, g as readStore, h as readGitTrack, i as matchWeixinRoute, l as sanitizeFileName$1, m as localstorePath, n as extractWeixinText, o as readWeixinCredential, p as checkLocalstoreGitCompliance, r as hasVoiceItem, s as readWeixinSettings, t as extractWeixinMedia, u as weixinInboundDir } from "./route-ItCgAsnz.js";
6
- import { a as buildSkiffBasePrompt, c as profileMsmWhitelist, d as resolveProfileSystemPrompt, f as ACC_VERSION, i as SKIFF_PROFILE_HINT, l as profileSystemPromptSource, n as readSimpleSettings, o as createProfilePromptReader, p as findPackageRoot, r as registerSettingsSection, s as profileCognitiveTrajectory, u as profileToolWhitelist } from "./settings-UcwIPJhM.js";
7
- import { a as pruneMissingBindings, c as setBindingStore, i as listBoundSessionIds, n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND } from "./message-source-ChyVfev9.js";
2
+ import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-B2t_aM8L.js";
3
+ import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readCheapWorkerConfig, g as readUtf8, h as readSafeModeHiddenTools, i as findGitRoot, l as pathInside, m as readExclusiveTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readCognitiveTrajectorySkills, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-CyYJL4F2.js";
4
+ import { A as sessionsRoot, C as namingTitleFor, D as readTrajectoryUid, E as readActiveSessionMd, F as isoLocal, I as localFileStamp, L as localHuman, M as showSession, N as summarize, O as resolveSessionByTitle, P as useSession, R as localIdStamp, S as listSessions, T as parseTrajectoryCode, _ as extractSessionMdPathFromText, a as readTrajectoryConstraintAt, c as registerTrajectorySession$1, d as COGNITIVE_TRAJECTORY_ACTIONS, f as DEFAULT_SESSION_SCOPE, g as createSession, h as clearActiveSessionInfo, j as setActiveSessionInfo, k as sessionEvents$1, l as trajectoryDirNameForSession, m as archiveSession, n as isTrajectoryConstrained, o as readTrajectoryConstraintByCode, p as UID_FILENAME, r as listTrajectoryConstraints, s as trajectoryConstraintForSession, t as TRAJECTORY_CONSTRAINT_FILENAME, u as unregisterTrajectorySession$1, v as findSession, w as parseSessionContextFromEvents, x as listActiveTrajectories, y as getActiveSessionInfo } from "./profile-BVt84mbi.js";
5
+ import { _ as runLocalStore, a as readFeishuCredential, d as weixinSessionIdForTrajectory, f as LOCALSTORE_SCOPES, g as readStore, h as readGitTrack, i as matchWeixinRoute, l as sanitizeFileName$1, m as localstorePath, n as extractWeixinText, o as readWeixinCredential, p as checkLocalstoreGitCompliance, r as hasVoiceItem, s as readWeixinSettings, t as extractWeixinMedia, u as weixinInboundDir } from "./route-COOFLTpU.js";
6
+ import { a as buildTrajectoryBasePrompt, c as createProfilePromptReader, d as resolveConstraintSystemPrompt, f as ACC_VERSION, i as TRAJECTORY_CONSTRAINT_HINT, l as profileMsmWhitelist, n as readSimpleSettings, o as constraintCognitiveTrajectory, p as findPackageRoot, r as registerSettingsSection, s as constraintSystemPromptSource, u as profileToolWhitelist } from "./settings-D8hlqxua.js";
7
+ import { a as pruneMissingBindings, c as setBindingStore, i as listBoundSessionIds, n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND } from "./message-source-DCpoRHP3.js";
8
8
  import { REGISTERED_TOOLS } from "./invariant.js";
9
9
  import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-BMk2w2KY.js";
10
+ import { a as registerImAccountImpl, i as normalizeAccountChannel, n as getImAccountImpl, r as imAccountChannels } from "./accounts-BHQbakUh.js";
10
11
  import { createRequire } from "node:module";
11
12
  import z from "@deepseek-ai/schemastery";
12
13
  import { defineTool } from "@deepseek-ai/dsh-tools";
@@ -977,8 +978,8 @@ const gitTool = defineTool({
977
978
  *
978
979
  * 为什么单独一个模块(R↓):地址的读者是 `msm-ops.buildMsmEnv`(把地址注入 MSM 子进程 env),
979
980
  * 写者才是 `weixin-send-api`(监听器启停)。若 msm-ops 直接 import weixin-send-api,
980
- * 静态依赖链会拖进整条微信桥栈(weixin-bridge → skiff-core → `@deepseek-ai/dsh-llm`)——
981
- * 后果实测:`acc-extras` / `ops` / `skiff-admin` 三个测试套件因解析不到宿主包而**整文件加载失败**
981
+ * 静态依赖链会拖进整条微信桥栈(weixin-bridge → trajectory-session → `@deepseek-ai/dsh-llm`)——
982
+ * 后果实测:`acc-extras` / `ops` / `trajectory-constraint-admin` 三个测试套件因解析不到宿主包而**整文件加载失败**
982
983
  * (它们只用到 MSM 注册表逻辑)。叶模块把「读」与「写」解耦:读者零依赖,写者自己承担重量。
983
984
  *
984
985
  * 同款先例:`host/effect.ts`(拆卸登记)、`trajectory/carrier.ts`(等待结算)。
@@ -1083,18 +1084,19 @@ Directory of ACC capabilities — each area lists where to go for details (guide
1083
1084
  acc_msm 已并入 msm(执行+发现)与 container_admin(管理)——msm("<name>", ["<args>"]);inspect=true 查用法
1084
1085
  cheap-worker(杂工 agent 编排——guide 子命令:cheap-worker guide)
1085
1086
  专属工具(**默认对所有 CCC 隐藏**,只有在自己 exclusiveTools 里点名的 CCC 可见)→ acc-diag(运行态诊断)
1086
- ④ 角色与对外面 → container_admin role(Skiff 认知子集角色:guide/validate/apply/list——skiff_admin 已并入)
1087
- 3099 Skiff 调试问答页(人工调试面)。外部程序化接入用官方 dsh --profile acp
1087
+ ④ 轨迹约束与对外面 → container_admin config(轨迹约束四动作 guide/validate/apply/list——**原 role 域已并入 config**,旧名作过渡别名仍可用;说明类配置走**两层菜单** config docs 目录 / config docs <章节> 详情)
1088
+ 外部程序化接入用官方 dsh --profile acp
1088
1089
  + 现成 ACP 客户端;本插件不提供 ACP 面
1089
1090
  ⑤ 自主与接入 → cognitive_trajectory send-now(跨轨迹的**即时**递送,**不排队**:live 目标在跑就当场注入当前轮、空闲则立即起轮;非 live 冷载入——等效于直接 wake;**有同步回执**)
1090
1091
  cognitive_trajectory send-later(跨轨迹的"未来时刻 + 一条 message";fire-and-forget,无回执无回收)
1091
1092
  weixin 微信桥(配置/扫码/路由/消息 hook——CCC 侧 weixin-doctor MSM:msm("weixin-doctor", ["guide"]))
1092
- ⑥ CCC 配置总览 → container_admin msm ccc-config(9 段:cheap-worker/sessionKeeper/localstore/hooks/safeMode/skiff/cognitiveTrajectory/weixin/**exclusiveTools**)
1093
+ ⑥ CCC 配置总览 → container_admin config docs config(按章详情——9 段全表)
1094
+ 或 container_admin msm ccc-config(同一份正文的旧入口,保留)
1093
1095
  ⑦ 注册表与安全 → mech-registry.json 由 container_admin msm register/deregister 管理(写保护——不可直接编辑)
1094
1096
  dashboard health 输出 registry 完整性检查;损坏恢复指引见 health registry.issues
1095
1097
  CCC 级开关:exclusiveTools(声明专属工具)/ safeMode.blacklist(写路径黑名单)
1096
1098
  / safeMode.hiddenTools(**安全模式开启期间**额外隐藏的工具,v1.51.4)
1097
- CCC 级 skill 供给:cognitiveTrajectory.skills(v1.44.0——**本 CCC 每条轨迹都带**,含 skiff 会话;与轨迹自己的 frontmatter 声明取并集)
1099
+ CCC 级 skill 供给:cognitiveTrajectory.skills(v1.44.0——**本 CCC 每条轨迹都带**,含 轨迹约束会话;与轨迹自己的 frontmatter 声明取并集)
1098
1100
 
1099
1101
  每区:一句话定位 + 详细入口(工具名 / guide 子命令)。详情永远以对应工具的 guide/ccc-config 为单一真相源。
1100
1102
  `;
@@ -1151,7 +1153,12 @@ msm("<name>", ["--list"]) — list all MSMs
1151
1153
  msm("<name>", ["--schema", "<n>"]) — view a specific MSM's parameter schema
1152
1154
  msm("<name>", ["--format=json"]) — JSON output mode (remaining args passed through losslessly)
1153
1155
  `;
1154
- /** CCC 配置参考(对齐 osp ccc-config action) */
1156
+ /**
1157
+ * CCC 配置参考(对齐 osp ccc-config action)。
1158
+ *
1159
+ * 🔴 **2026-10-19 起导出**:`container_admin config docs config` 的两层菜单把它作为
1160
+ * 「config」章正文返回。**不另写一份**——同一段说明有第二份副本就会漂(本轨反复踩过)。
1161
+ */
1155
1162
  const CCC_CONFIG_REFERENCE = `═══ CCC Configuration Reference ═══
1156
1163
 
1157
1164
  CCC-level features are configured in .opencode/serenity.json.
@@ -1227,15 +1234,15 @@ safe-mode 由 WebUI 开关控制(写 .serenity-safe-on 标记);黑名单
1227
1234
  Config:
1228
1235
  { "safeMode": { "blacklist": [".secrets/"], "hiddenTools": ["workflow", "job_kill"] } }
1229
1236
 
1230
- ── 6. skiff.roles(F4 认知子集角色)──
1231
- Skiff 角色 = 全知全能 cognitive trajectory 的任意子集(CCC 定义)。每角色独立模型 + 双白名单
1237
+ ── 6. 轨迹约束.roles(F4 认知子集角色)──
1238
+ 轨迹约束角色 = 全知全能 cognitive trajectory 的任意子集(CCC 定义)。每角色独立模型 + 双白名单
1232
1239
  (MSM 白名单 msms[] 与非 MSM 工具白名单 tools[],白名单外全隐藏;skill 加载恒可用)。
1233
1240
  cognitive trajectory 纪律子集(session/keeper/rebuild 参与项)默认全关 = 完全独立。
1234
1241
  systemPrompt 内联 或 systemPromptFile(.md 引用,推荐)——角色会话的完整人格/边界提示词。
1235
- validate 校验 / apply 生效 / list 查看:container_admin role <guide|validate|apply|list>(skiff_admin 已并入)。
1242
+ validate 校验 / apply 生效 / list 查看:container_admin config <guide|validate|apply|list>(原 role 域已并入 config,旧名作过渡别名仍可用)。
1236
1243
 
1237
1244
  Config:
1238
- { "skiff": { "roles": {
1245
+ { "轨迹约束": { "roles": {
1239
1246
  "qa": {
1240
1247
  "model": "provider/model",
1241
1248
  "msms": ["web-search", "vlm-describe"],
@@ -1255,12 +1262,12 @@ CCC 的一条 cognitive trajectory = 持久身体(SESSION.md)+ 时间轴(A
1255
1262
  运行态诊断(ACC 负责人专用):acc-diag(① live 运行态 / ①b 唤醒时钟 / ③ 唤醒注册表)。
1256
1263
 
1257
1264
  ▸ cognitiveTrajectory.skills(v1.44.0,**CCC 级 skill 供给**;owner 令 2026-09-20「要求实现我的诉求……
1258
- 注入是动态注入就行;create 先不触发吧;**skiff 也支持**」):
1265
+ 注入是动态注入就行;create 先不触发吧;**轨迹约束也支持**」):
1259
1266
  **本 CCC 的每条轨迹都带这些 skill**——声明的 skill 全文在该轨迹**被绑定期间**注入系统提示词
1260
1267
  (**动态注入**:每请求重新求值、不缓存 ⇒ 改配置或改 frontmatter **即时生效**,无需重新 use、无需重启)。
1261
1268
  两条声明来源**并集**(不是二选一):本键 **cognitiveTrajectory.skills**(容器给的底座,**在前**)
1262
1269
  + 轨迹自己 SESSION.md 顶部 frontmatter 的 skills:(这条轨迹额外的,**追加**;同名去重)。
1263
- ✅ **含 skiff 角色会话**(旁路的是 ACC 身份与纪律;skill 是"工作资料",照给)。
1270
+ ✅ **含 轨迹约束角色会话**(旁路的是 ACC 身份与纪律;skill 是"工作资料",照给)。
1264
1271
  守卫:名字先过安全校验才用于拼路径(防穿越)|**合并后**统一 32 KB 上限截断|找不到响亮写 [缺失]。
1265
1272
  ⚠️ 与 create **无关**(create 刻意不夺绑定,U6)⇒ 注入的门是"**存在绑定**"(cognitive_trajectory use)。
1266
1273
  失败语义:未配置 / 字段缺失 / 配置损坏 ⇒ **空数组**(= 无 CCC 级供给;轨迹级声明照旧生效)。
@@ -1268,7 +1275,7 @@ CCC 的一条 cognitive trajectory = 持久身体(SESSION.md)+ 时间轴(A
1268
1275
 
1269
1276
  Config:
1270
1277
  { "cognitiveTrajectory": {
1271
- "skills": ["acc-session", "cce"], // v1.44.0:本 CCC 的每条轨迹都带(含 skiff 会话)
1278
+ "skills": ["acc-session", "cce"], // v1.44.0:本 CCC 的每条轨迹都带(含 轨迹约束会话)
1272
1279
  "autopilot": { // 原 autopilotTrajectory 段,字段不变(旧键仍回退读)
1273
1280
  "enabled": true,
1274
1281
  "intervalHours": 2,
@@ -1282,7 +1289,7 @@ CCC 的一条 cognitive trajectory = 持久身体(SESSION.md)+ 时间轴(A
1282
1289
  CCC 级微信个人号接入(iLink 协议):dsh 一进程多 CCC,每 CCC 独立对接微信桥。
1283
1290
  账号/路由/开关在此文件;**bot_token 凭据在 CCC localstore credential scope**
1284
1291
  (扫码绑定后自动写入,永不进 git 明文面)。
1285
- 路由 user → role:exact 优先,* 通配兜底;role 必须 ∈ 该 CCC skiff.roles。
1292
+ 路由 user → role:exact 优先,* 通配兜底;role 必须 ∈ 该 CCC 轨迹约束.roles。
1286
1293
  面板(WebUI 设置 → 微信桥)可扫码绑定/移除账号/编辑路由;msm("weixin-doctor", ["status"|"diag"|"verify"|"guide"]) 排查 + 大而全指南。凭据主动查看:localstore get WEIXIN_<ACCOUNT>_TOKEN。
1287
1294
  ▸ 主动发送(v1.31.0:**ACC 工具 im-bridge**):调
1288
1295
  im-bridge({channel:"weixin", action:"send", user:"<别名|id>", text:"<文本>"}) 给用户发消息——
@@ -1290,7 +1297,7 @@ CCC 级微信个人号接入(iLink 协议):dsh 一进程多 CCC,每 CCC
1290
1297
  成功后触发 outgoing hook(source="proactive")。文件用 action:"send-file" + file:"<CCC 内路径>"
1291
1298
  (逃逸/缺失/超 20MB 拒绝)+ 可选 caption。**可见性**:本 CCC 配置了 IM 通道
1292
1299
  (weixin.enabled=true)才出现在模型工具清单里;未配置 → 由 guards 逐 agent
1293
- tools.restrict({deny:['im-bridge']}) 移除(不是"看得到但被拒")。skiff 角色另需在
1300
+ tools.restrict({deny:['im-bridge']}) 移除(不是"看得到但被拒")。轨迹约束角色另需在
1294
1301
  roles.<role>.tools 白名单列出 im-bridge。
1295
1302
  历史(v1.30.9~v1.30.x):CCC 侧 MSM weixin-send(走 loopback HTTP 入口 3082)——
1296
1303
  v1.31.0 已退役(脚本删除 + 注册表注销);3082 入口保留给**非 agent 调用者**。
@@ -1834,7 +1841,7 @@ async function runMsmAsync(root, args) {
1834
1841
  * **轨迹提示词** = 一条认知轨迹的**可编辑章程声明**,由 ACC 按固定顺序装配进系统提示词。
1835
1842
  * 三个关键词各是一条判据:
1836
1843
  * - **可编辑**:住在 CCC(盘上),改它**不发版**(D23 归属判据的直接推论)
1837
- * - **声明**:它声明**身份/章程/方法论**,**不声明能力**(能力面归 `skiff.json` 白名单与工具 schema)
1844
+ * - **声明**:它声明**身份/章程/方法论**,**不声明能力**(能力面归 `trajectory-constraint.json` 白名单与工具 schema)
1838
1845
  * - **固定顺序**:装配顺序由 ACC 定死(见 `seams/system-prompt.ts` 的 ⑧ 位)
1839
1846
  *
1840
1847
  * ## 为什么取代「人格」
@@ -1849,13 +1856,13 @@ async function runMsmAsync(root, args) {
1849
1856
  *
1850
1857
  * - **跟着轨迹走**:`archive` 时整个目录搬走,章程不会掉队(旧形态 `.opencode/skiff/<name>.md`
1851
1858
  * 与轨迹**分居两处** —— 多条轨迹共用一份文件正是那个后果)。
1852
- * - **每条轨迹都能有**:不只是 skiff。普通轨迹同样需要"我是谁、按什么章程"。
1853
- * - 与 `SESSION.md`(身体:延续/日志)、`skiff.json`(约束面:能力)三件并列,
1859
+ * - **每条轨迹都能有**:不只是 轨迹约束。普通轨迹同样需要"我是谁、按什么章程"。
1860
+ * - 与 `SESSION.md`(身体:延续/日志)、`trajectory-constraint.json`(约束面:能力)三件并列,
1854
1861
  * 各管一件事,不合并(合并会让"改能力"与"改身份"互相牵连)。
1855
1862
  *
1856
1863
  * ## 兼容(不静默坏)
1857
1864
  *
1858
- * `PROMPT.md` 不存在时**不报错**(普通轨迹常态)。skiff 的旧字段 `systemPromptFile`
1865
+ * `PROMPT.md` 不存在时**不报错**(普通轨迹常态)。轨迹约束的旧字段 `systemPromptFile`
1859
1866
  * 在兼容期仍被读取——优先级见 {@link resolveTrajectoryPrompt}。
1860
1867
  */
1861
1868
  /** 轨迹提示词的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
@@ -1867,9 +1874,9 @@ function trajectoryPromptPath(root, dirName) {
1867
1874
  /**
1868
1875
  * 该轨迹**有没有**轨迹提示词(单一判据)。
1869
1876
  *
1870
- * 用途:兼容期的"让位"判定 —— 若已有 `PROMPT.md`,skiff 旧字段 `systemPromptFile`
1871
- * 必须**让位**,否则同一份章程会在两处各注入一遍(第 ⑧ 段 + `serenity-skiff` 段)。
1872
- * 🔴 判据只有这一处:别在 skiff 那边自己拼路径再判(两处会漂)。
1877
+ * 用途:兼容期的"让位"判定 —— 若已有 `PROMPT.md`,轨迹约束 旧字段 `systemPromptFile`
1878
+ * 必须**让位**,否则同一份章程会在两处各注入一遍(第 ⑧ 段 + `serenity-轨迹约束` 段)。
1879
+ * 🔴 判据只有这一处:别在 轨迹约束那边自己拼路径再判(两处会漂)。
1873
1880
  */
1874
1881
  function hasTrajectoryPrompt(root, dirName) {
1875
1882
  try {
@@ -2903,7 +2910,7 @@ function verifyTotpCode(secretBase32, code, nowSeconds = nowEpochSeconds()) {
2903
2910
  /**
2904
2911
  * 集中端口表。
2905
2912
  * A=宿主主面(插件不监听)/ B=网关(可配,默认关)/ C=微信发送(默认开,仅 loopback)
2906
- * / D=Skiff 调试(默认关)。
2913
+ * / D=轨迹约束调试(默认关)。
2907
2914
  */
2908
2915
  const FACE_PORTS = {
2909
2916
  main: {
@@ -3263,7 +3270,7 @@ function toolsBlock() {
3263
3270
  " cheap-worker — delegate work to a worker agent on the CCC-configured model; one serial child per task, returns its final text. `jobs=[...]` fans out in parallel (cap 10, results keep your order). No loop, no completion code, no progress file. The model is NOT selectable per call (read from the CCC config); a worker's tool set excludes cheap-worker itself",
3264
3271
  " serenity-skill-creator — creator for serenity-skills (this container's enhanced skill standard): guide (authoring/optimization method — read first) / create <name> (scaffold SKILL.md + skill.ttl + references/, base-chain import path computed) / check <name> (A1 structural + A2 base-chain; three states: modeled-ok / plain-skill / modeled-but-check-could-not-run) / review <name> (C tier: axiom-vs-text compliance question list, half-mechanical) / index <name> (preview the second-layer resource list the model will see) / status (which skills are modeled). A skill is \"modeled\" iff it has a file named exactly skill.ttl next to SKILL.md; a plain skill is NOT an anomaly. Only `create` writes, and it refuses an existing directory",
3265
3272
  " localstore — ACC local credential/config storage (CCC-root localstore.json; git policy localstore.gitTrack default deny)",
3266
- " container_admin — container administration (the maintenance bay): role (Skiff roles: guide/validate/apply/list) / msm (register/deregister/check/guide/catalog/ccc-config) / config (view)",
3273
+ " container_admin — container administration (the maintenance bay): role (轨迹约束 roles: guide/validate/apply/list) / msm (register/deregister/check/guide/catalog/ccc-config) / config (view)",
3267
3274
  "",
3268
3275
  "MSM call (registered CCC MSMs, deterministic Mech & Semi-Mech):",
3269
3276
  " Execute: msm(\"<name>\", [\"<arg1>\", \"<arg2>\"]) — run a registered MSM directly (partial name returns matching candidates)",
@@ -3763,7 +3770,7 @@ function registerEntrySkillSection(agent, root) {
3763
3770
  *
3764
3771
  * **声明来源(两条,并集)**:
3765
3772
  * · **CCC 级**(v1.44.0,owner 令)= `.opencode/serenity.json` 的 `cognitiveTrajectory.skills`
3766
- * ——**本 CCC 的每条轨迹都带**(含 skiff 角色会话),是容器给的底座;
3773
+ * ——**本 CCC 的每条轨迹都带**(含 轨迹约束角色会话),是容器给的底座;
3767
3774
  * · **轨迹级** = 该会话绑定的轨迹(`readLastBound(session).mdPath` = 它的 `SESSION.md`)
3768
3775
  * 顶部 frontmatter 的 `skills:`——这条轨迹额外的。
3769
3776
  * 合并规则与顺序见 `cognitive-trajectory-skills.mergeSkillNames`(CCC 级在前,同名去重)。
@@ -3960,36 +3967,36 @@ Before calling cheap-worker, load eap (acc-eap skill) and design the "scale-up c
3960
3967
  //#endregion
3961
3968
  //#region src/trajectory/session.ts
3962
3969
  /** `provider/model` → agentOptions(由 delegate/core 提供,保持单一实现) */
3963
- const skiffAgents = /* @__PURE__ */ new Map();
3970
+ const trajectoryAgents = /* @__PURE__ */ new Map();
3964
3971
  /** 查 sessionId 的活体 agent(进程内会话延续用;未注册/已清理 → undefined) */
3965
- function getSkiffAgent(sessionId) {
3966
- return skiffAgents.get(sessionId);
3972
+ function getTrajectoryAgent(sessionId) {
3973
+ return trajectoryAgents.get(sessionId);
3967
3974
  }
3968
- /** 该会话当前绑定的 skiff 约束面(不是 skiff → null)。**守门与提示词的唯一查询入口。** */
3969
- function skiffProfileFor(root, sessionId) {
3975
+ /** 该会话当前绑定的 轨迹约束面(不是 轨迹约束 → null)。**守门与提示词的唯一查询入口。** */
3976
+ function trajectoryConstraintFor(root, sessionId) {
3970
3977
  if (sessionId === void 0) return null;
3971
- return skiffProfileForSession(root, sessionId, skiffTrajectoryDirNameFor(sessionId));
3978
+ return trajectoryConstraintForSession(root, sessionId, trajectoryDirNameForSession(sessionId));
3972
3979
  }
3973
- function registerSkiffSession(sessionId, trajectoryDirName, ccc, agent) {
3974
- skiffAgents.set(sessionId, agent);
3975
- registerSkiffSession$1(sessionId, trajectoryDirName, ccc);
3980
+ function registerTrajectorySession(sessionId, trajectoryDirName, ccc, agent) {
3981
+ trajectoryAgents.set(sessionId, agent);
3982
+ registerTrajectorySession$1(sessionId, trajectoryDirName, ccc);
3976
3983
  }
3977
- function unregisterSkiffSession(sessionId) {
3978
- skiffAgents.delete(sessionId);
3979
- unregisterSkiffSession$1(sessionId);
3984
+ function unregisterTrajectorySession(sessionId) {
3985
+ trajectoryAgents.delete(sessionId);
3986
+ unregisterTrajectorySession$1(sessionId);
3980
3987
  }
3981
3988
  /**
3982
- * 该 skiff 会话的**工作台路径** = 它自己轨迹的 SESSION.md。
3989
+ * 该 轨迹约束会话的**工作台路径** = 它自己轨迹的 SESSION.md。
3983
3990
  *
3984
- * 🔴 与旧版的差别:旧版会在这里**自动新建**一个 SESSION(`ensureSkiffSession`);
3985
- * 新版**没有新建这个动作** —— 轨迹就是工作台,`skiff.json` 与 `SESSION.md` 同处一个目录。
3991
+ * 🔴 与旧版的差别:旧版会在这里**自动新建**一个 SESSION(`ensureTrajectorySession`);
3992
+ * 新版**没有新建这个动作** —— 轨迹就是工作台,`trajectory-constraint.json` 与 `SESSION.md` 同处一个目录。
3986
3993
  * ⇒ 语义变成纯粹的"查询:我自己的身体在哪"。
3987
3994
  *
3988
- * @returns SESSION.md 绝对路径;不是 skiff / 文件不在 → null
3995
+ * @returns SESSION.md 绝对路径;不是 轨迹约束 / 文件不在 → null
3989
3996
  */
3990
- function skiffWorkspaceMdPath(root, sessionId) {
3997
+ function trajectoryWorkspaceMdPath(root, sessionId) {
3991
3998
  if (sessionId === void 0) return null;
3992
- const dirName = skiffTrajectoryDirNameFor(sessionId);
3999
+ const dirName = trajectoryDirNameForSession(sessionId);
3993
4000
  if (dirName === null) return null;
3994
4001
  const md = join(sessionsRoot(root), dirName, "SESSION.md");
3995
4002
  return existsSync(md) ? md : null;
@@ -3997,12 +4004,12 @@ function skiffWorkspaceMdPath(root, sessionId) {
3997
4004
  /**
3998
4005
  * 系统提示词中的**工作台纪律块**(S142 用户:只给路径 LLM 不会主动用)。
3999
4006
  *
4000
- * SESSION = 工作台 —— skiff 与主舱同一套机制(**零特调**,用户拍板):
4007
+ * SESSION = 工作台 —— 轨迹约束与主舱同一套机制(**零特调**,用户拍板):
4001
4008
  * SESSION.md 是持久记忆载体、rebuild 自动从本 SESSION 续接。
4002
4009
  * 注入 agent 系统提示词(用户对话面不可见)。
4003
4010
  *
4004
4011
  * v1.30.13(S142 诊断 D5):写入纪律**不点名具体工具** —— 旧文案写死 "with write/edit",
4005
- * 而某个 skiff 的工具白名单里根本没有 write/edit ⇒ 指令指向它没有的工具
4012
+ * 而某个 轨迹约束的工具白名单里根本没有 write/edit ⇒ 指令指向它没有的工具
4006
4013
  * (注入纪律与能力面矛盾,模型只能猜)。现文案改为「用本轨迹被授权的写入通道」。
4007
4014
  */
4008
4015
  function workspaceCognitiveTrajectoryLine(mdPath) {
@@ -4030,10 +4037,10 @@ const workspaceSectionAgents = /* @__PURE__ */ new WeakSet();
4030
4037
  /**
4031
4038
  * 把**工作台纪律块**挂到 agent 的系统提示词段(单一注入点)。
4032
4039
  *
4033
- * 用户原话(S142,2026-09-08):"微信桥的注入机制,每个用户消息都会注入,skiff 本身也会注入,
4034
- * 这样就重复,能否微信桥情况下,注入内容直接取 skiff 的,这样不用配两遍"。
4040
+ * 用户原话(S142,2026-09-08):"微信桥的注入机制,每个用户消息都会注入,轨迹约束本身也会注入,
4041
+ * 这样就重复,能否微信桥情况下,注入内容直接取 轨迹约束的,这样不用配两遍"。
4035
4042
  *
4036
- * 现形态:工作台行**只**经本函数挂系统提示词段(name `serenity-skiff-workspace`,
4043
+ * 现形态:工作台行**只**经本函数挂系统提示词段(name `serenity-轨迹约束-workspace`,
4037
4044
  * 动态 `text()` 每轮按 scope 读当前活跃 mdPath)。
4038
4045
  *
4039
4046
  * @returns true = 段已在位;false = 该 agent 挂不上(调用方降级为 question 前缀注入)
@@ -4045,39 +4052,39 @@ function ensureWorkspacePromptSection(agent, scope, root) {
4045
4052
  if (typeof api?.section !== "function") return false;
4046
4053
  try {
4047
4054
  api.section({
4048
- name: "serenity-skiff-workspace",
4055
+ name: "serenity-轨迹约束-workspace",
4049
4056
  order: -55,
4050
4057
  text: () => {
4051
- const mdPath = skiffWorkspaceMdPath(root, scope);
4058
+ const mdPath = trajectoryWorkspaceMdPath(root, scope);
4052
4059
  return mdPath ? workspaceCognitiveTrajectoryLine(mdPath) : "";
4053
4060
  }
4054
4061
  });
4055
4062
  workspaceSectionAgents.add(agent);
4056
4063
  return true;
4057
4064
  } catch (err) {
4058
- console.warn(`[serenity-hooks] skiff 工作台提示词段注册失败(回退 question 注入): ${String(err?.message ?? err)}`);
4065
+ console.warn(`[serenity-hooks] 轨迹约束 工作台提示词段注册失败(回退 question 注入): ${String(err?.message ?? err)}`);
4059
4066
  return false;
4060
4067
  }
4061
4068
  }
4062
- /** skiff agent 挂载的 DSH preset(平台工具面由 preset 决定;白名单再按轨迹过滤) */
4063
- const SKIFF_PRESET = "standard";
4069
+ /** 轨迹约束 agent 挂载的 DSH preset(平台工具面由 preset 决定;白名单再按轨迹过滤) */
4070
+ const TRAJECTORY_PRESET = "standard";
4064
4071
  /**
4065
- * 创建(或复用)一个 skiff 会话。
4072
+ * 创建(或复用)一个 轨迹约束会话。
4066
4073
  *
4067
4074
  * **固定 sessionId 的 resume-or-create**(v1.27.2):指定 sessionId 且磁盘已有持久化 log →
4068
4075
  * `ctx.agents.resume`(DSH 持久化语义:sessionId 即身份,历史 + turn 续号延续);
4069
4076
  * 无 log(首次)→ `ctx.agents.create`。不指定 → 随机 id 恒 create(调试页路径)。
4070
4077
  *
4071
- * @param profile 该 skiff 的约束面(来自 `skiff.json`)
4078
+ * @param profile 该 轨迹约束的约束面(来自 `trajectory-constraint.json`)
4072
4079
  * @param sessionId 指定会话 id(可选;微信桥等外部面用固定 id 实现"轨迹 ↔ 会话"长期映射)
4073
4080
  */
4074
- async function createSkiffAgent(ctx, root, profile, defaultModel, sessionId) {
4075
- if (!ctx.agents) throw new Error("skiff: ctx.agents unavailable");
4081
+ async function createTrajectoryAgent(ctx, root, profile, defaultModel, sessionId) {
4082
+ if (!ctx.agents) throw new Error("轨迹约束: ctx.agents unavailable");
4076
4083
  const model = profile.model?.trim() || defaultModel || "";
4077
- const id = sessionId ?? `skiff-${profile.code}-${randomUUID()}`;
4084
+ const id = sessionId ?? `轨迹约束-${profile.code}-${randomUUID()}`;
4078
4085
  const setup = async (agentCtx) => {
4079
4086
  try {
4080
- await agentCtx.get("agentPresets")?.mount?.(agentCtx, SKIFF_PRESET);
4087
+ await agentCtx.get("agentPresets")?.mount?.(agentCtx, TRAJECTORY_PRESET);
4081
4088
  } catch {}
4082
4089
  };
4083
4090
  const handle = await createOrResumeAgent(ctx, id, root, model, setup, sessionId !== void 0);
@@ -4087,7 +4094,7 @@ async function createSkiffAgent(ctx, root, profile, defaultModel, sessionId) {
4087
4094
  const livePrompt = () => {
4088
4095
  let live = profile;
4089
4096
  try {
4090
- const fresh = readSkiffProfileAt(join(sessionsRoot(root), profile.dirName), root);
4097
+ const fresh = readTrajectoryConstraintAt(join(sessionsRoot(root), profile.dirName), root);
4091
4098
  if (fresh) live = fresh;
4092
4099
  } catch {}
4093
4100
  const wantPath = live.systemPromptFile?.trim();
@@ -4100,23 +4107,23 @@ async function createSkiffAgent(ctx, root, profile, defaultModel, sessionId) {
4100
4107
  livePrompt();
4101
4108
  try {
4102
4109
  agent.ctx.systemPrompt.section({
4103
- name: "serenity-skiff",
4110
+ name: "serenity-轨迹约束",
4104
4111
  order: -60,
4105
4112
  text: () => {
4106
4113
  const legacy = hasTrajectoryPrompt(root, profile.dirName) ? "" : livePrompt();
4107
- return [buildSkiffBasePrompt(profile.code), legacy].filter(Boolean).join("\n");
4114
+ return [buildTrajectoryBasePrompt(profile.code), legacy].filter(Boolean).join("\n");
4108
4115
  }
4109
4116
  });
4110
4117
  } catch (err) {
4111
- console.warn(`[serenity-hooks] skiff 系统提示词注册失败: ${String(err?.message ?? err)}`);
4118
+ console.warn(`[serenity-hooks] 轨迹约束 系统提示词注册失败: ${String(err?.message ?? err)}`);
4112
4119
  }
4113
4120
  if (agent?.session) try {
4114
4121
  registerCognitiveTrajectorySkillSection(agent, root);
4115
4122
  } catch (err) {
4116
- console.warn(`[serenity-hooks] skiff 轨迹 skill 注入注册失败(不影响 agent 创建): ${String(err?.message ?? err)}`);
4123
+ console.warn(`[serenity-hooks] 轨迹约束轨迹 skill 注入注册失败(不影响 agent 创建): ${String(err?.message ?? err)}`);
4117
4124
  }
4118
- if (skiffWorkspaceMdPath(root, id) !== null) ensureWorkspacePromptSection(agent, id, root);
4119
- registerSkiffSession(id, profile.dirName, root, agent);
4125
+ if (trajectoryWorkspaceMdPath(root, id) !== null) ensureWorkspacePromptSection(agent, id, root);
4126
+ registerTrajectorySession(id, profile.dirName, root, agent);
4120
4127
  return {
4121
4128
  handle,
4122
4129
  agent,
@@ -4155,7 +4162,7 @@ async function createOrResumeAgent(ctx, id, root, model, setup, fixedId) {
4155
4162
  sessionId: id,
4156
4163
  meta: {
4157
4164
  cwd: root,
4158
- agentPreset: SKIFF_PRESET
4165
+ agentPreset: TRAJECTORY_PRESET
4159
4166
  },
4160
4167
  setup,
4161
4168
  ...model ? { agentOptions: splitModel(model) } : {}
@@ -4170,7 +4177,7 @@ async function createOrResumeAgent(ctx, id, root, model, setup, fixedId) {
4170
4177
  sessionId: id,
4171
4178
  meta: {
4172
4179
  cwd: root,
4173
- agentPreset: SKIFF_PRESET
4180
+ agentPreset: TRAJECTORY_PRESET
4174
4181
  },
4175
4182
  setup,
4176
4183
  ...model ? { agentOptions: splitModel(model) } : {}
@@ -4191,14 +4198,14 @@ async function createOrResumeAgent(ctx, id, root, model, setup, fixedId) {
4191
4198
  if (liveNow) return liveReuseRef(liveNow, setup);
4192
4199
  const msg = err instanceof Error ? err.message : String(err);
4193
4200
  const stack = err instanceof Error ? err.stack ?? "" : "";
4194
- console.log(`[serenity-hooks] skiff resume 失败降级 create (id=${id}): ${msg}`);
4195
- if (stack) console.log(`[serenity-hooks] skiff resume stack:\n${stack.slice(0, 1200)}`);
4201
+ console.log(`[serenity-hooks] 轨迹约束 resume 失败降级 create (id=${id}): ${msg}`);
4202
+ if (stack) console.log(`[serenity-hooks] 轨迹约束 resume stack:\n${stack.slice(0, 1200)}`);
4196
4203
  return {
4197
4204
  ...await ctx.agents.create({
4198
4205
  sessionId: id,
4199
4206
  meta: {
4200
4207
  cwd: root,
4201
- agentPreset: SKIFF_PRESET
4208
+ agentPreset: TRAJECTORY_PRESET
4202
4209
  },
4203
4210
  setup,
4204
4211
  ...model ? { agentOptions: splitModel(model) } : {}
@@ -4262,7 +4269,7 @@ async function waitForTurnAssistant(ctx, agent, beforeAssistantCount, opts = {})
4262
4269
  *
4263
4270
  * @param options.timeoutMs 本轮等待上限(测试注入;生产用缺省)
4264
4271
  */
4265
- async function askSkiff(ctx, agent, question, options) {
4272
+ async function askTrajectory(ctx, agent, question, options) {
4266
4273
  const beforeAssistant = countAssistantMessages(agent.session);
4267
4274
  agent.followup(createUserMessage({
4268
4275
  content: [{
@@ -4277,29 +4284,29 @@ async function askSkiff(ctx, agent, question, options) {
4277
4284
  };
4278
4285
  }
4279
4286
  /**
4280
- * skiff 会话的轨迹纪律参与判定:**不是 skiff 恒 true**(正常参与);
4281
- * skiff 按 `skiff.json` 的 `cognitiveTrajectory` 子集决定。
4287
+ * 轨迹约束会话的轨迹纪律参与判定:**不是 轨迹约束恒 true**(正常参与);
4288
+ * 轨迹约束 按 `trajectory-constraint.json` 的 `cognitiveTrajectory` 子集决定。
4282
4289
  *
4283
- * 注册表缺失(进程刚重启、绑定还没读)⇒ 由 `skiffProfileForSession` 回落持久绑定;
4284
- * 两者都不中 ⇒ 判"不是 skiff" ⇒ 恒 true(正常参与)。**fail-open 是有意的**:
4290
+ * 注册表缺失(进程刚重启、绑定还没读)⇒ 由 `trajectoryConstraintForSession` 回落持久绑定;
4291
+ * 两者都不中 ⇒ 判"不是 轨迹约束" ⇒ 恒 true(正常参与)。**fail-open 是有意的**:
4285
4292
  * 纪律参与项的失败不该让会话失去 keeper/rebuild(那是能力倒退,比多跑一次更糟)。
4286
4293
  */
4287
- function skiffCognitiveTrajectoryEnabled(root, sessionId, key) {
4294
+ function trajectoryConstraintParticipates(root, sessionId, key) {
4288
4295
  if (sessionId === void 0) return true;
4289
- const profile = skiffProfileFor(root, sessionId);
4296
+ const profile = trajectoryConstraintFor(root, sessionId);
4290
4297
  if (profile === null) return true;
4291
- return profileCognitiveTrajectory(profile)[key];
4298
+ return constraintCognitiveTrajectory(profile)[key];
4292
4299
  }
4293
4300
  /**
4294
- * `msm` 工具的 skiff 门控:非 skiff 恒放行;skiff 会话——
4301
+ * `msm` 工具的 轨迹约束门控:非 轨迹约束恒放行;轨迹约束会话——
4295
4302
  * exec 非白名单 MSM 拒绝(**不列名单**)、register/deregister 必拒、
4296
4303
  * list 白名单过滤、check/guide/ccc-config 只读放行。
4297
4304
  */
4298
- function skiffMsmGate(root, sessionId, action, name) {
4305
+ function trajectoryConstraintMsmGate(root, sessionId, action, name) {
4299
4306
  if (sessionId === void 0) return {};
4300
- const profile = skiffProfileFor(root, sessionId);
4307
+ const profile = trajectoryConstraintFor(root, sessionId);
4301
4308
  if (profile === null) return {};
4302
- if (action === "register" || action === "deregister") return { reject: "register/deregister is not allowed in skiff sessions" };
4309
+ if (action === "register" || action === "deregister") return { reject: "register/deregister is not allowed in 轨迹约束 sessions" };
4303
4310
  if (action === "exec") {
4304
4311
  if (!name || !profile.msms.includes(name)) return { reject: "MSM not allowed" };
4305
4312
  return {};
@@ -4386,7 +4393,7 @@ const msmTool = defineTool({
4386
4393
  if (!root) throw new Error(NO_CCC_FROM_AGENT_CWD);
4387
4394
  const sessionId = agentSessionId$1(exec);
4388
4395
  const name = args.name;
4389
- const gate = skiffMsmGate(root, sessionId, name ? "exec" : "list", name);
4396
+ const gate = trajectoryConstraintMsmGate(root, sessionId, name ? "exec" : "list", name);
4390
4397
  if (gate.reject) throw new Error(gate.reject);
4391
4398
  if (!name || name.trim() === "") return gate.whitelist ? "MSMs allowed in this role:\n" + [...gate.whitelist].join("\n") : buildMsmIndex(root);
4392
4399
  const clean = name.trim();
@@ -10419,7 +10426,7 @@ function parseCroHostBinding(raw) {
10419
10426
  * `AGENT_SESSIONS/` 下每个目录查一次 `<目录>/continuous-re-occurrence.ts`。
10420
10427
  * · **一次 readdir + 每个目录一次 existsSync**:N 条轨迹的代价是 O(N) 次 `stat`,
10421
10428
  * 每 5min 一次 —— 与既有 `listSessions` 同量级,可接受。
10422
- * · 跳过 **`_` 前缀**(`_archived` / `_skiff-logs` / `_weixin-logs` = 系统与日志目录)
10429
+ * · 跳过 **`_` 前缀**(`_archived` / `_轨迹约束-logs` / `_weixin-logs` = 系统与日志目录)
10423
10430
  * 与 **`.` 前缀**(隐藏)——它们**不是轨迹**,且扫它们纯属浪费。
10424
10431
  * · 🔴 **本函数绝不抛错**(返回 `[]`)——它跑在调度器 tick 内,任何异常都可能影响既有链路
10425
10432
  * (设计 §5 铁律)。目录读不到(不存在 / 权限)⇒ `[]` = "没有轨迹启用 CRO",语义正确。
@@ -12815,20 +12822,20 @@ const localstoreTool = defineTool({
12815
12822
  }
12816
12823
  });
12817
12824
  //#endregion
12818
- //#region src/tools/skiff-admin.ts
12819
- /** Skiff 定义教程:概念 / `skiff.json` schema / 双白名单 / 轨迹纪律 / 微信路由 */
12820
- const SKIFF_GUIDE = `═══ Skiff Guide (2026-10-19 redesigned) ═══
12825
+ //#region src/tools/trajectory-constraint-admin.ts
12826
+ /** 轨迹约束 定义教程:概念 / `trajectory-constraint.json` schema / 双白名单 / 轨迹纪律 / 微信路由 */
12827
+ const TRAJECTORY_CONSTRAINT_GUIDE = `═══ 轨迹约束 Guide (2026-10-19 redesigned) ═══
12821
12828
 
12822
- **A skiff IS a cognitive trajectory — the one whose directory contains \`${SKIFF_PROFILE_FILENAME}\`.**
12829
+ **A 轨迹约束 IS a cognitive trajectory — the one whose directory contains \`${TRAJECTORY_CONSTRAINT_FILENAME}\`.**
12823
12830
  That is the whole rule. No role table, no name registry: put the file there and the trajectory
12824
- becomes a skiff; delete it and it goes back to being an ordinary trajectory (takes effect at once).
12831
+ becomes a 轨迹约束; delete it and it goes back to being an ordinary trajectory (takes effect at once).
12825
12832
 
12826
12833
  AGENT_SESSIONS/<YYYY-MM-DD--<code>--<desc>>/
12827
12834
  ├─ SESSION.md ← its persistent body (this IS the workspace — nothing is auto-created)
12828
- ├─ ${SKIFF_PROFILE_FILENAME} ← its constraints (this file is what makes it a skiff)
12835
+ ├─ ${TRAJECTORY_CONSTRAINT_FILENAME} ← its constraints (this file is what makes it a 轨迹约束)
12829
12836
  └─ TRAJECTORY-UID ← legacy, read-only (superseded by the code)
12830
12837
 
12831
- ── ${SKIFF_PROFILE_FILENAME} schema ──
12838
+ ── ${TRAJECTORY_CONSTRAINT_FILENAME} schema ──
12832
12839
  {
12833
12840
  "model": "provider/model", // optional; falls back to cheap-worker.defaultModel
12834
12841
  "tools": ["read","grep","msm",...], // non-MSM toolbar whitelist — anything not listed is REMOVED from the schema
@@ -12839,35 +12846,34 @@ becomes a skiff; delete it and it goes back to being an ordinary trajectory (tak
12839
12846
  }
12840
12847
 
12841
12848
  ── Two whitelists, both default-deny ──
12842
- - \`tools: []\` + non-empty \`msms\` = pure-MSM skiff (the usual knowledge-QA shape)
12849
+ - \`tools: []\` + non-empty \`msms\` = pure-MSM 轨迹约束 (the usual knowledge-QA shape)
12843
12850
  - non-empty \`msms\` ⇒ the \`msm\` tool is added automatically (the only entry point for MSMs)
12844
12851
  - anything outside both lists is invisible in the schema, not merely rejected at call time
12845
12852
 
12846
12853
  ── cognitiveTrajectory: why the defaults are TRUE ──
12847
- The workspace of a skiff is its own SESSION.md. Setting these to false would cut it off from
12854
+ The workspace of a 轨迹约束 is its own SESSION.md. Setting these to false would cut it off from
12848
12855
  its own body, so \`session\`/\`keeper\`/\`rebuild\` all default to true. Set false explicitly only
12849
12856
  when you deliberately want that participation off.
12850
12857
 
12851
12858
  ── WeChat routing: user → trajectory code ──
12852
12859
  \`weixin.routes\`: \`[{ "user": "<wx id or *>", "trajectory": "<code>" }]\`
12853
12860
  A route pointing at a code with no such trajectory is a hard error (the message is NOT delivered).
12854
- A trajectory WITHOUT \`${SKIFF_PROFILE_FILENAME}\` is still a legal target — it is just an ordinary trajectory.
12861
+ A trajectory WITHOUT \`${TRAJECTORY_CONSTRAINT_FILENAME}\` is still a legal target — it is just an ordinary trajectory.
12855
12862
 
12856
12863
  ── Operating it ──
12857
- Debug page: Settings → Serenity → enable the Skiff block → http://127.0.0.1:<debugPort>
12858
- Everything is read live: saving \`${SKIFF_PROFILE_FILENAME}\` takes effect on the next turn, no restart.
12864
+ Everything is read live: saving \`${TRAJECTORY_CONSTRAINT_FILENAME}\` takes effect on the next turn, no restart.
12859
12865
  (The prompt FILE hot-reloads by mtime; the JSON itself is re-read every turn.)
12860
- After editing, run container_admin role apply for an explicit validation + confirmation pass.
12861
- Skill loading is always available to skiff sessions (skills are not whitelisted — they are read-only knowledge).`;
12862
- /** 校验当前 CCC 的 skiff 约束面:msms 均已注册 / model ∈ cheap-worker.models / 提示词非空 */
12863
- function validateSkiffConfig(root) {
12864
- const profiles = listSkiffProfiles(root);
12866
+ After editing, run container_admin config apply for an explicit validation + confirmation pass.
12867
+ Skill loading is always available to 轨迹约束 sessions (skills are not whitelisted — they are read-only knowledge).`;
12868
+ /** 校验当前 CCC 的 轨迹约束面:msms 均已注册 / model ∈ cheap-worker.models / 提示词非空 */
12869
+ function validateTrajectoryConstraint(root) {
12870
+ const profiles = listTrajectoryConstraints(root);
12865
12871
  const issues = [];
12866
12872
  if (profiles.length === 0) return {
12867
12873
  ok: true,
12868
12874
  issues: [],
12869
- roleCount: 0,
12870
- note: `no skiff trajectories in this CCC (no trajectory has ${SKIFF_PROFILE_FILENAME} — zero impact)`
12875
+ constraintCount: 0,
12876
+ note: `no 轨迹约束 trajectories in this CCC (no trajectory has ${TRAJECTORY_CONSTRAINT_FILENAME} — zero impact)`
12871
12877
  };
12872
12878
  const registered = new Set(loadMsmEntries(root).map((e) => e.name));
12873
12879
  const hc = readCheapWorkerConfig(root);
@@ -12875,7 +12881,7 @@ function validateSkiffConfig(root) {
12875
12881
  for (const p of profiles) {
12876
12882
  if (!(hasTrajectoryPrompt(root, p.dirName) || (() => {
12877
12883
  try {
12878
- return resolveProfileSystemPrompt(root, p).trim() !== "";
12884
+ return resolveConstraintSystemPrompt(root, p).trim() !== "";
12879
12885
  } catch (err) {
12880
12886
  issues.push(`trajectory "${p.code}": ${String(err?.message ?? err)}`);
12881
12887
  return true;
@@ -12887,15 +12893,15 @@ function validateSkiffConfig(root) {
12887
12893
  return {
12888
12894
  ok: issues.length === 0,
12889
12895
  issues,
12890
- roleCount: profiles.length
12896
+ constraintCount: profiles.length
12891
12897
  };
12892
12898
  }
12893
- /** 列出当前 CCC 的 skiff 轨迹(编码 / 模型 / msms / tools / 纪律摘要 / 提示词来源) */
12894
- function listSkiffRoles(root) {
12895
- const profiles = listSkiffProfiles(root);
12899
+ /** 列出当前 CCC 的轨迹约束(编码 / 模型 / msms / tools / 纪律摘要 / 提示词来源) */
12900
+ function listTrajectoryConstraintSummary(root) {
12901
+ const profiles = listTrajectoryConstraints(root);
12896
12902
  if (profiles.length === 0) return {
12897
12903
  roles: [],
12898
- note: `no skiff trajectories in this CCC (no trajectory has ${SKIFF_PROFILE_FILENAME})`
12904
+ note: `no 轨迹约束 trajectories in this CCC (no trajectory has ${TRAJECTORY_CONSTRAINT_FILENAME})`
12899
12905
  };
12900
12906
  const items = profiles.map((p) => ({
12901
12907
  name: p.code,
@@ -12903,8 +12909,8 @@ function listSkiffRoles(root) {
12903
12909
  model: p.model ?? "(cheap-worker default)",
12904
12910
  msms: p.msms,
12905
12911
  tools: p.tools,
12906
- cognitiveTrajectory: profileCognitiveTrajectory(p),
12907
- promptSource: profileSystemPromptSource(p),
12912
+ cognitiveTrajectory: constraintCognitiveTrajectory(p),
12913
+ promptSource: constraintSystemPromptSource(p, hasTrajectoryPrompt(root, p.dirName)),
12908
12914
  ...p.systemPromptFile ? { systemPromptFile: p.systemPromptFile } : {}
12909
12915
  }));
12910
12916
  return {
@@ -12913,51 +12919,91 @@ function listSkiffRoles(root) {
12913
12919
  };
12914
12920
  }
12915
12921
  /**
12916
- * 应用当前 skiff 配置(S142 用户:改了 json 应该有个生效机制)。
12922
+ * 应用当前 轨迹约束 配置(S142 用户:改了 json 应该有个生效机制)。
12917
12923
  *
12918
12924
  * 语义:约束面是**每轮实时读取**的 ⇒ apply 不是"推送",而是**显式校验 + 应用确认**:
12919
12925
  * ① 校验合法(复用 validate:msms 注册 / model 白名单 / 提示词非空)
12920
12926
  * ② 非法 → 报告问题清单,不应用(提示修复后重跑 apply)
12921
12927
  * ③ 合法 → 应用确认:绑定 CCC + 轨迹清单 + 说明(下一轮即生效)
12922
12928
  */
12923
- function applySkiffConfig(root) {
12924
- const validation = validateSkiffConfig(root);
12925
- const profiles = listSkiffProfiles(root);
12929
+ function applyTrajectoryConstraint(root) {
12930
+ const validation = validateTrajectoryConstraint(root);
12931
+ const profiles = listTrajectoryConstraints(root);
12926
12932
  if (!validation.ok) return {
12927
12933
  applied: false,
12928
12934
  cccRoot: root,
12929
- roleCount: profiles.length,
12935
+ constraintCount: profiles.length,
12930
12936
  issues: validation.issues,
12931
- hint: "fix the issues above, then run container_admin role apply again"
12937
+ hint: "fix the issues above, then run container_admin config apply again"
12932
12938
  };
12933
12939
  return {
12934
12940
  applied: true,
12935
12941
  cccRoot: root,
12936
- roleCount: profiles.length,
12942
+ constraintCount: profiles.length,
12937
12943
  roles: profiles.map((p) => p.code),
12938
- note: `constraints are read live from each trajectory's ${SKIFF_PROFILE_FILENAME} — they take effect on the next turn (no restart); ${SKIFF_PROFILE_HINT}`
12944
+ note: `constraints are read live from each trajectory's ${TRAJECTORY_CONSTRAINT_FILENAME} — they take effect on the next turn (no restart); ${TRAJECTORY_CONSTRAINT_HINT}`
12939
12945
  };
12940
12946
  }
12941
12947
  //#endregion
12948
+ //#region src/tools/config-docs.ts
12949
+ /**
12950
+ * 渲染**目录**(第一层)。
12951
+ *
12952
+ * 🔴 只调 `summary`,**绝不调 `render`** —— 目录若触发正文,就退化成"整份长文"。
12953
+ * 这条不是性能优化,是**判据**:它保证 `docs` 的输出大小与章数成正比,与正文长度无关。
12954
+ */
12955
+ function renderDocsIndex(chapters) {
12956
+ const lines = [
12957
+ "═══ CCC 配置说明 · 目录 ═══",
12958
+ "",
12959
+ "说明类内容已超过单次返回的合适篇幅 ⇒ 先读目录,再按章取详情。",
12960
+ "",
12961
+ "用法:container_admin config docs <章节>",
12962
+ ""
12963
+ ];
12964
+ for (const ch of chapters) lines.push(` ${ch.id.padEnd(14)}${ch.summary}`);
12965
+ lines.push("");
12966
+ lines.push("相关:container_admin msm catalog(工具/能力目录——与本章录互指,不互相复制)");
12967
+ return lines.join("\n");
12968
+ }
12969
+ /**
12970
+ * 解析一个章节参数(第二层)。
12971
+ *
12972
+ * 不存在 ⇒ 返回 `null`,由调用方给出**带候选清单**的拒绝 ——
12973
+ * "不知道这个章节" 与 "这一章是空的" 必须可区分(否则用户以为功能没有)。
12974
+ */
12975
+ function findDocsChapter(chapters, id) {
12976
+ const want = id.trim().toLowerCase();
12977
+ if (want === "") return null;
12978
+ return chapters.find((c) => c.id.toLowerCase() === want) ?? null;
12979
+ }
12980
+ //#endregion
12942
12981
  //#region src/tools/container-admin.ts
12943
12982
  /**
12944
12983
  * container-admin.ts — container_admin(v1.30:机务舱——容器管理面统一入口)
12945
12984
  *
12946
- * 合并自:
12947
- * · skiff_admin(F4 Skiff 认知子集角色:guide/validate/apply/list)
12948
- * · acc_msm 管理面(register/deregister/check/guide/catalog/ccc-config)
12949
- * —— msm 工具只管执行+发现;一切「管理容器」的操作归本工具
12985
+ * ## 域结构(2026-10-19 owner 两条令后:**两域**)
12950
12986
  *
12951
- * 语义(用户拍板"skiff_admin 及系列 admin 合并成 container_admin"):
12987
+ * | 域 | 管什么 |
12988
+ * |---|---|
12989
+ * | `config` | **本 CCC 的全部配置面**:说明目录/按章详情 + 轨迹约束(原 `role` 域,已并入) |
12990
+ * | `msm` | MSM 注册表管理 + 手册(register/deregister/check/guide/catalog/ccc-config) |
12991
+ *
12992
+ * 🔴 **`role` 域已并入 `config`**(owner 2026-10-19 裁「1 并入」)。为什么不是三个平行域:
12993
+ * `role` 管的本来就是"某条轨迹的约束面"——**一组配置**,与 `config` 是同一抽象层的两半。
12994
+ * 分着放的代价是:用户在 `config` 里看不到"轨迹怎么约束",得先知道 `role` 这个词存在。
12995
+ * ⚠️ **旧 `role` 域仍被接受**(过渡别名,指向同一实现)——存量 CCC 的文档/脚本里到处是
12996
+ * `container_admin role validate`(实测本仓 30 处),硬切会让它们全部变成"未知域"。
12997
+ * 别名**只保留读取路径**:schema 的 `enum` 只列新名,文案只教新名。
12998
+ *
12999
+ * ## 三个动作名为什么是这三个(P3 的实现形态)
13000
+ * - `config docs`(无参)→ **使用说明目录**(第一层;只索引不复制)
13001
+ * - `config docs <chapter>` → **使用说明详情**(第二层;按章获得)
13002
+ * - `config view` → 配置**现值**(原来是唯一动作;现在是"看当前填了什么")
13003
+ *
13004
+ * 归属(D23):**机制在 ACC**(有哪几章、怎么路由、怎么校验),**内容在 CCC**(填什么)。
13005
+ * 语义(用户拍板"轨迹约束_admin 及系列 admin 合并成 container_admin"):
12952
13006
  * container = CCC(具体认知容器);admin = 管理操作。
12953
- * 类比 The Manifest(清单维护——工具注册表)+ Crew(角色管理)+ 机务(配置/手册)。
12954
- *
12955
- * 参数极简(LLM 直觉):domain(管理域)+ action(该域子命令)+ 少量业务参数。
12956
- *
12957
- * v1.34.1(⑥ C6a):由 `export const containerAdminTool` 改为**工厂**
12958
- * `createContainerAdminTool(ctx)`——原为 autopilot 域传进程内运行态事实(全局闸 / live 会话 /
12959
- * agent 可解析性)。该域已于 2026-09-15 随 ACC 侧 autopilot 整段退场删除(所有者裁决 (a)):
12960
- * `ctx` 现**无消费者**,工厂形态保留只是为了让装配点签名不再变动(见 index.ts 注册处)。
12961
13007
  */
12962
13008
  function agentSessionId(exec) {
12963
13009
  return exec.agent?.session?.id ?? "";
@@ -12968,9 +13014,13 @@ function renderText$1(value) {
12968
13014
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
12969
13015
  }];
12970
13016
  }
13017
+ /** 过渡别名表:旧域 → 新域(只读兼容;文案不教它) */
13018
+ const DOMAIN_ALIASES = { role: "config" };
12971
13019
  /** 合法 domain 名(拒绝文案与 schema enum 同源——不得各写一份) */
12972
13020
  const DOMAIN_NAMES = Object.keys({
12973
- role: [
13021
+ config: [
13022
+ "docs",
13023
+ "view",
12974
13024
  "guide",
12975
13025
  "validate",
12976
13026
  "apply",
@@ -12983,23 +13033,43 @@ const DOMAIN_NAMES = Object.keys({
12983
13033
  "guide",
12984
13034
  "catalog",
12985
13035
  "ccc-config"
12986
- ],
12987
- config: ["view"]
13036
+ ]
12988
13037
  });
13038
+ /**
13039
+ * 说明目录的章节(P3 两层菜单的**唯一注册处**)。
13040
+ *
13041
+ * 🔴 加一章 = 在这里加一项(`render` 惰性求值)。**正文不复制**:
13042
+ * 每章的真相源就在它自己的函数里(`CCC_CONFIG_REFERENCE` / `TRAJECTORY_CONSTRAINT_GUIDE`)——
13043
+ * 本表只做**切分与路由**,避免"同一段说明有第二份会漂的副本"。
13044
+ */
13045
+ const DOCS_CHAPTERS = [{
13046
+ id: "config",
13047
+ summary: "CCC 配置全表——9 段各是什么、怎么填、填错会怎样(.opencode/serenity.json)",
13048
+ render: () => CCC_CONFIG_REFERENCE
13049
+ }, {
13050
+ id: "trajectory-constraint",
13051
+ summary: "轨迹约束:一条轨迹怎么被约束(trajectory-constraint.json 的 schema + 双白名单)",
13052
+ render: () => TRAJECTORY_CONSTRAINT_GUIDE
13053
+ }];
12989
13054
  function createContainerAdminTool(ctx) {
12990
13055
  return defineTool({
12991
13056
  name: "container_admin",
12992
- description: "Container administration (the ship's maintenance bay — one entry for managing the CCC): role — Skiff cognitive-subset roles (guide/validate/apply/list); msm — MSM registry management (register/deregister/check quality DC-M1~M4) + manuals (guide dev manual / catalog ACC capability directory / ccc-config CCC configuration reference); config — view CCC configuration. Execution of registered MSMs belongs to the msm tool; this tool manages the container.",
13057
+ description: "Container administration (the ship's maintenance bay — one entry for managing the CCC): config — CCC configuration: docs (usage-manual index) / docs <chapter> (one chapter in full) / view (current values) + 轨迹约束 (guide/validate/apply/list); msm — MSM registry management (register/deregister/check quality DC-M1~M4) + manuals (guide dev manual / catalog ACC capability directory / ccc-config CCC configuration reference). Execution of registered MSMs belongs to the msm tool; this tool manages the container.",
12993
13058
  parameters: {
12994
13059
  domain: {
12995
13060
  type: "string",
12996
13061
  enum: DOMAIN_NAMES,
12997
13062
  required: true,
12998
- description: "Management domain: role (Skiff roles) / msm (MSM registry + manuals) / config (CCC config view)"
13063
+ description: "Management domain: config (CCC configuration + 轨迹约束) / msm (MSM registry + manuals)"
12999
13064
  },
13000
13065
  action: {
13001
13066
  type: "string",
13002
- description: "Domain subcommand (see domain descriptions; e.g. role: validate/apply/list/guide; msm: register/deregister/check/guide/catalog/ccc-config)"
13067
+ description: "Domain subcommand. config: docs / view / guide / validate / apply / list; msm: register / deregister / check / guide / catalog / ccc-config"
13068
+ },
13069
+ /** 第二层菜单参数:`config docs <chapter>`(缺省 = 目录) */
13070
+ chapter: {
13071
+ type: "string",
13072
+ description: "config docs only: chapter id (omit for the index; e.g. config / trajectory-constraint)"
13003
13073
  },
13004
13074
  name: {
13005
13075
  type: "string",
@@ -13038,18 +13108,35 @@ function createContainerAdminTool(ctx) {
13038
13108
  const root = cccRootForExec(exec);
13039
13109
  if (!root) throw new Error(NO_CCC_FROM_AGENT_CWD);
13040
13110
  const sessionId = agentSessionId(exec);
13041
- const domain = args.domain;
13111
+ const rawDomain = String(args.domain ?? "");
13112
+ const domain = DOMAIN_ALIASES[rawDomain] ?? rawDomain;
13042
13113
  const action = args.action ?? "";
13114
+ if (!DOMAIN_NAMES.includes(domain)) throw new Error(`container_admin requires domain: ${DOMAIN_NAMES.join(" | ")}`);
13043
13115
  if (domain === "msm" && (action === "register" || action === "deregister")) {
13044
- const gate = skiffMsmGate(root, sessionId, action, args.name);
13116
+ const gate = trajectoryConstraintMsmGate(root, sessionId, action, args.name);
13045
13117
  if (gate.reject) throw new Error(gate.reject);
13046
13118
  }
13047
- if (domain === "role") switch (action) {
13048
- case "guide": return { guide: SKIFF_GUIDE };
13049
- case "validate": return validateSkiffConfig(root);
13050
- case "apply": return applySkiffConfig(root);
13051
- case "list": return listSkiffRoles(root);
13052
- default: throw new Error(`container_admin role requires action: guide | validate | apply | list`);
13119
+ if (domain === "config") switch (action) {
13120
+ case "docs": {
13121
+ const chapter = args.chapter?.trim() ?? "";
13122
+ if (chapter === "") return {
13123
+ docs: renderDocsIndex(DOCS_CHAPTERS),
13124
+ chapters: DOCS_CHAPTERS.map((c) => c.id)
13125
+ };
13126
+ const found = findDocsChapter(DOCS_CHAPTERS, chapter);
13127
+ if (found === null) throw new Error(`container_admin config docs: unknown chapter "${chapter}". Available: ${DOCS_CHAPTERS.map((c) => c.id).join(" | ")} (omit the chapter for the index)`);
13128
+ return {
13129
+ chapter: found.id,
13130
+ docs: found.render()
13131
+ };
13132
+ }
13133
+ case "view":
13134
+ case "": return { config: runMsm(root, { action: "ccc-config" }) };
13135
+ case "guide": return { guide: TRAJECTORY_CONSTRAINT_GUIDE };
13136
+ case "validate": return validateTrajectoryConstraint(root);
13137
+ case "apply": return applyTrajectoryConstraint(root);
13138
+ case "list": return listTrajectoryConstraintSummary(root);
13139
+ default: throw new Error(`container_admin config requires action: docs | view | guide | validate | apply | list`);
13053
13140
  }
13054
13141
  if (domain === "msm") {
13055
13142
  const mgmtActions = [
@@ -13072,7 +13159,6 @@ function createContainerAdminTool(ctx) {
13072
13159
  usage: args.usage
13073
13160
  });
13074
13161
  }
13075
- if (domain === "config") return { config: runMsm(root, { action: "ccc-config" }) };
13076
13162
  throw new Error(`container_admin requires domain: ${DOMAIN_NAMES.join(" | ")}`);
13077
13163
  }
13078
13164
  });
@@ -13324,7 +13410,7 @@ const SENSITIVE_CREDENTIAL_FILES = /* @__PURE__ */ new Set(["localstore.json"]);
13324
13410
  * MSM 注册表写保护(需求⑤b S142 用户拍板:"msm注册的文件需要写保护起来,避免CCC意外写坏搞崩自己"):
13325
13411
  * mech-registry.json 是 CCC 执行层地基(坏 → loadMsmEntries 抛 → container_admin/output-guard 全崩,
13326
13412
  * register 也崩 → 自锁)。**写 deny、读 allow**(与 localstore 读 deny 语义区分 R6——注册表是
13327
- * 结构核心不是秘密,需被 output-guard/skiff-admin 读取建 MSM 词表)。
13413
+ * 结构核心不是秘密,需被 output-guard/trajectory-constraint-admin 读取建 MSM 词表)。
13328
13414
  *
13329
13415
  * 单级化(需求⑤a)后**唯一合法注册表 = cccName 聚合档**
13330
13416
  * `.opencode/skills/<cccName>/references/mech-registry.json`(cccName = .serenity 首行)。
@@ -13362,15 +13448,15 @@ function isWriteTool(toolName, action) {
13362
13448
  */
13363
13449
  function decideGuard(input) {
13364
13450
  const { root, toolName, safeModeOn, blacklist, pathArg, action } = input;
13365
- if (input.skiffProfile !== void 0 && input.skiffProfile !== null) {
13366
- const profile = input.skiffProfile;
13451
+ if (input.trajectoryConstraint !== void 0 && input.trajectoryConstraint !== null) {
13452
+ const profile = input.trajectoryConstraint;
13367
13453
  if (toolName === "skill") return { kind: "allow" };
13368
13454
  if (profile.msms.includes(toolName)) return {
13369
13455
  deny: `"${toolName}" is a registered MSM, not a direct tool in this trajectory — call it through the msm tool: msm("${toolName}", ["<args>"]) (pass "--help" or inspect=true for usage)`,
13370
13456
  kind: "deny"
13371
13457
  };
13372
13458
  if (!profileToolWhitelist(profile).has(toolName)) return {
13373
- deny: "tool not allowed in this skiff trajectory",
13459
+ deny: "tool not allowed in this 轨迹约束 trajectory",
13374
13460
  kind: "deny"
13375
13461
  };
13376
13462
  }
@@ -13655,17 +13741,17 @@ const exclusiveRestrictions = /* @__PURE__ */ new Map();
13655
13741
  * 每次 pre-step 都重算白名单,只有**算出来的结果变了**才重新发 restrict
13656
13742
  * —— 配置不变就不重复发(restrict 会重建 schema,没必要每步都做)。
13657
13743
  */
13658
- const skiffRoleRestrictions = /* @__PURE__ */ new Map();
13744
+ const trajectoryConstraintRestrictions = /* @__PURE__ */ new Map();
13659
13745
  /**
13660
- * 同步 **skiff 会话的工具面**:把白名单之外的工具**从 schema 移除**(不是"看得到但被拒")。
13746
+ * 同步 **轨迹约束会话的工具面**:把白名单之外的工具**从 schema 移除**(不是"看得到但被拒")。
13661
13747
  *
13662
13748
  * ## 为什么必须有这条(owner 2026-10-19:「工具清单也要热加载」)
13663
13749
  *
13664
- * 在它之前,skiff 白名单**只由运行时守卫拦截**(`decideGuard` 的 skiff 分支):
13750
+ * 在它之前,轨迹约束白名单**只由运行时守卫拦截**(`decideGuard` 的 轨迹约束 分支):
13665
13751
  * 工具全部出现在模型 schema 里,调用时才被打回。⇒ 两个真实后果:
13666
13752
  * ① **模型看得见它不该有的工具** —— 它会去试,试了才撞墙(一轮白烧,且错误文案泛化,
13667
13753
  * 看不出"是不在清单里"还是"临时性拒绝");
13668
- * ② **配置变动在 schema 上永远不生效** —— 改 `skiff.json` 的 `tools` 只影响"调用是否放行"。
13754
+ * ② **配置变动在 schema 上永远不生效** —— 改 `trajectory-constraint.json` 的 `tools` 只影响"调用是否放行"。
13669
13755
  *
13670
13756
  * ## 判据与降级
13671
13757
  *
@@ -13673,24 +13759,24 @@ const skiffRoleRestrictions = /* @__PURE__ */ new Map();
13673
13759
  * 不去动宿主的工具 —— 宿主的工具由各自的条件同步管)。
13674
13760
  * - ⚠️ **未注册的名字会让整次 restrict 失败**(宿主契约逐字 "unknown names … fail"),
13675
13761
  * 而 `diagram` 是按开关注册的 ⇒ 与 `hideAllFor` 同款**两档尝试**(先全覆盖,失败退常驻段)。
13676
- * - 读不到约束面(不是 skiff / 配置删了)⇒ **撤销既有隐藏**(回到"无约束"):
13677
- * ⛔ 不能只是 `return` —— 那会把上一步的隐藏**永久留在**一个已不再是 skiff 的会话上
13678
- * (这正是 owner 说的"删掉 `skiff.json` 就该立刻恢复")。
13762
+ * - 读不到约束面(不是 轨迹约束 / 配置删了)⇒ **撤销既有隐藏**(回到"无约束"):
13763
+ * ⛔ 不能只是 `return` —— 那会把上一步的隐藏**永久留在**一个已不再是 轨迹约束的会话上
13764
+ * (这正是 owner 说的"删掉 `trajectory-constraint.json` 就该立刻恢复")。
13679
13765
  * - 幂等:算出来的 deny 签名不变就跳过(不每步重建 schema)。
13680
13766
  *
13681
13767
  * @param agent 目标会话
13682
13768
  * @param root CCC 根
13683
13769
  */
13684
- function syncSkiffRoleToolVisibility(agent, root) {
13770
+ function syncTrajectoryConstraintToolVisibility(agent, root) {
13685
13771
  const sessionId = agent.session.id ?? "global";
13686
- const profile = skiffProfileForSession(root, sessionId);
13687
- const existing = skiffRoleRestrictions.get(sessionId);
13772
+ const profile = trajectoryConstraintForSession(root, sessionId);
13773
+ const existing = trajectoryConstraintRestrictions.get(sessionId);
13688
13774
  if (profile === null) {
13689
13775
  if (existing !== void 0) {
13690
13776
  try {
13691
13777
  existing.dispose();
13692
13778
  } catch {}
13693
- skiffRoleRestrictions.delete(sessionId);
13779
+ trajectoryConstraintRestrictions.delete(sessionId);
13694
13780
  }
13695
13781
  return;
13696
13782
  }
@@ -13706,7 +13792,7 @@ function syncSkiffRoleToolVisibility(agent, root) {
13706
13792
  try {
13707
13793
  existing.dispose();
13708
13794
  } catch {}
13709
- skiffRoleRestrictions.delete(sessionId);
13795
+ trajectoryConstraintRestrictions.delete(sessionId);
13710
13796
  }
13711
13797
  return;
13712
13798
  }
@@ -13715,10 +13801,10 @@ function syncSkiffRoleToolVisibility(agent, root) {
13715
13801
  try {
13716
13802
  existing.dispose();
13717
13803
  } catch {}
13718
- skiffRoleRestrictions.delete(sessionId);
13804
+ trajectoryConstraintRestrictions.delete(sessionId);
13719
13805
  }
13720
13806
  const dispose = agent.ctx.tools.restrict({ deny: [...deny] });
13721
- skiffRoleRestrictions.set(sessionId, {
13807
+ trajectoryConstraintRestrictions.set(sessionId, {
13722
13808
  signature,
13723
13809
  deny,
13724
13810
  dispose
@@ -13730,13 +13816,13 @@ function syncSkiffRoleToolVisibility(agent, root) {
13730
13816
  }
13731
13817
  }
13732
13818
  /** 会话销毁清理(lifecycle 调用) */
13733
- function forgetSkiffRoleToolVisibility(sessionId) {
13734
- const existing = skiffRoleRestrictions.get(sessionId);
13819
+ function forgetTrajectoryConstraintToolVisibility(sessionId) {
13820
+ const existing = trajectoryConstraintRestrictions.get(sessionId);
13735
13821
  if (!existing) return;
13736
13822
  try {
13737
13823
  existing.dispose();
13738
13824
  } catch {}
13739
- skiffRoleRestrictions.delete(sessionId);
13825
+ trajectoryConstraintRestrictions.delete(sessionId);
13740
13826
  }
13741
13827
  /**
13742
13828
  * 同步专属工具可见性(v1.33)。
@@ -13931,7 +14017,7 @@ function registerGuards(ctx, opts = {}) {
13931
14017
  const pathArg = extractPathArg(exec);
13932
14018
  const action = extractAction(exec);
13933
14019
  const sessionId = exec?.agent?.session?.id;
13934
- const skiffProfile = skiffProfileForSession(root, sessionId);
14020
+ const trajectoryConstraint = trajectoryConstraintForSession(root, sessionId);
13935
14021
  return decideGuard({
13936
14022
  root,
13937
14023
  toolName: exec.name,
@@ -13939,7 +14025,7 @@ function registerGuards(ctx, opts = {}) {
13939
14025
  blacklist,
13940
14026
  pathArg,
13941
14027
  action,
13942
- skiffProfile
14028
+ trajectoryConstraint
13943
14029
  });
13944
14030
  };
13945
14031
  ctx.on("tools/pre-execute", async (exec, next) => {
@@ -14176,7 +14262,7 @@ function createEpochPromotion(promoteEvents, requiredSignals = 1, maxRoundsFallb
14176
14262
  const loopSid = session.id;
14177
14263
  const loopCwd = session.header?.cwd ?? process.cwd();
14178
14264
  const loopRoot = cccRootForCwd(loopCwd);
14179
- if (typeof loopSid === "string" && (loopSid.startsWith("cheap-worker-") || loopRoot !== null && isSkiffSession(loopRoot, loopSid))) return {
14265
+ if (typeof loopSid === "string" && (loopSid.startsWith("cheap-worker-") || loopRoot !== null && isTrajectoryConstrained(loopRoot, loopSid))) return {
14180
14266
  boundary: -1,
14181
14267
  promoted: true
14182
14268
  };
@@ -14295,7 +14381,7 @@ function registerBootstrap(ctx) {
14295
14381
  const depth = session?.header?.delegationDepth ?? 0;
14296
14382
  const sid = typeof session?.id === "string" ? session.id : void 0;
14297
14383
  if (sid === void 0) return;
14298
- if (sid.startsWith("cheap-worker-") || isSkiffSession(root, sid)) return;
14384
+ if (sid.startsWith("cheap-worker-") || isTrajectoryConstrained(root, sid)) return;
14299
14385
  if (depth === 0) {
14300
14386
  if (hasUserMessageHistory(session)) return;
14301
14387
  } else if (anchoredSessions.has(sid)) return;
@@ -14609,7 +14695,7 @@ function forgetLogbookCompactionState(scope) {
14609
14695
  * 解析**活跃** SESSION.md 绝对路径(缓存 60s)。
14610
14696
  *
14611
14697
  * 候选链(刻意比 rebuild 的完整链短——这里每个工具调用都要跑,贵候选不划算):
14612
- * ① `getActiveSessionInfo(scope).mdPath`(`cognitive_trajectory use` / skiff 绑定 / 重启恢复都会写)
14698
+ * ① `getActiveSessionInfo(scope).mdPath`(`cognitive_trajectory use` / 轨迹约束 绑定 / 重启恢复都会写)
14613
14699
  * ② `readLastBound(session).mdPath`(`.bindings.json` 权威绑定——重启后内存空时兜底)
14614
14700
  * 两者都拿不到 → null(**不猜**:宁可不提醒,也不去猜别的轨迹——对齐 v1.30.13 D4 的教训)。
14615
14701
  */
@@ -14738,10 +14824,10 @@ function registerKeeper(ctx, opts = {}) {
14738
14824
  const root = cccRootForCwd(cwd);
14739
14825
  if (!root) return next();
14740
14826
  const sessionId = exec.agent?.session?.id;
14741
- const skiffKeeper = skiffCognitiveTrajectoryEnabled(root, sessionId, "keeper");
14742
- const skiffRebuild = skiffCognitiveTrajectoryEnabled(root, sessionId, "rebuild");
14827
+ const 轨迹约束Keeper = trajectoryConstraintParticipates(root, sessionId, "keeper");
14828
+ const 轨迹约束Rebuild = trajectoryConstraintParticipates(root, sessionId, "rebuild");
14743
14829
  const tracker = trackerFor(exec);
14744
- const shouldRemind = skiffKeeper ? tracker.step(exec.name) : false;
14830
+ const shouldRemind = 轨迹约束Keeper ? tracker.step(exec.name) : false;
14745
14831
  const downstream = await next();
14746
14832
  try {
14747
14833
  recordToolUsage(root, exec.name, exec.arguments);
@@ -14754,7 +14840,7 @@ function registerKeeper(ctx, opts = {}) {
14754
14840
  text: reminderText(code)
14755
14841
  });
14756
14842
  }
14757
- if (skiffRebuild) {
14843
+ if (轨迹约束Rebuild) {
14758
14844
  const session = exec.agent?.session;
14759
14845
  if (session) {
14760
14846
  const pressure = readContextPressure(ctx, session);
@@ -14774,7 +14860,7 @@ function registerKeeper(ctx, opts = {}) {
14774
14860
  }
14775
14861
  }
14776
14862
  }
14777
- if (skiffCognitiveTrajectoryEnabled(root, sessionId, "session")) {
14863
+ if (trajectoryConstraintParticipates(root, sessionId, "session")) {
14778
14864
  const limitKB = readSessionMdMaxKB(root, opts.configPaths);
14779
14865
  if (limitKB > 0) {
14780
14866
  const scope = sessionId ?? "global";
@@ -14797,7 +14883,7 @@ function registerKeeper(ctx, opts = {}) {
14797
14883
  } else compactionStates.delete(scope);
14798
14884
  }
14799
14885
  }
14800
- if (skiffCognitiveTrajectoryEnabled(root, sessionId, "session")) {
14886
+ if (trajectoryConstraintParticipates(root, sessionId, "session")) {
14801
14887
  const scope = sessionId ?? "global";
14802
14888
  const session = exec.agent?.session;
14803
14889
  const mdPath = resolveActiveSessionMdPath(root, scope, session);
@@ -14905,7 +14991,7 @@ function shouldAutoRestore(agent, root) {
14905
14991
  if (session.header?.parentSession) return false;
14906
14992
  if (session.id?.startsWith("cheap-worker-")) return false;
14907
14993
  const cccRoot = root !== void 0 ? root : cccRootForCwd(session.header?.cwd ?? process.cwd());
14908
- if (cccRoot && isSkiffSession(cccRoot, session.id)) return false;
14994
+ if (cccRoot && isTrajectoryConstrained(cccRoot, session.id)) return false;
14909
14995
  return true;
14910
14996
  }
14911
14997
  /**
@@ -14928,7 +15014,7 @@ function registerContext(ctx, opts = {}) {
14928
15014
  } catch {}
14929
15015
  if (!root) return;
14930
15016
  const key = agentKey(agent);
14931
- if (isSkiffSession(root, key)) return;
15017
+ if (isTrajectoryConstrained(root, key)) return;
14932
15018
  registerEntrySkillSection(agent, root);
14933
15019
  registerCognitiveTrajectorySkillSection(agent, root);
14934
15020
  const scope = agentScope(agent);
@@ -15012,9 +15098,9 @@ function registerContext(ctx, opts = {}) {
15012
15098
  const key = agentKey(agent);
15013
15099
  const downstream = await next();
15014
15100
  if (root) try {
15015
- syncSkiffRoleToolVisibility(agent, root);
15101
+ syncTrajectoryConstraintToolVisibility(agent, root);
15016
15102
  } catch {}
15017
- if (root && isSkiffSession(root, key)) return downstream;
15103
+ if (root && isTrajectoryConstrained(root, key)) return downstream;
15018
15104
  try {
15019
15105
  syncCccToolVisibility(agent, root);
15020
15106
  } catch {}
@@ -15063,7 +15149,7 @@ function registerCompactRetention(ctx, opts = {}) {
15063
15149
  const cwd = agent.session?.header?.cwd ?? process.cwd();
15064
15150
  const root = cccRootForCwd(cwd);
15065
15151
  if (!root) return;
15066
- if (isSkiffSession(root, String(session.id ?? ""))) return;
15152
+ if (isTrajectoryConstrained(root, String(session.id ?? ""))) return;
15067
15153
  try {
15068
15154
  agent.inject(accMessage(root, configPaths, entrySkillMaxChars));
15069
15155
  } catch {}
@@ -15404,7 +15490,7 @@ function requireWebUi(req, res, message) {
15404
15490
  *
15405
15491
  * 🔴🔴 **2026-10-18 修缺陷(owner 报「在别的 CCC 点开显示的还是 home-serenity 的信息」)**:
15406
15492
  * 旧实现第 ③ 步是「**遍历 live sessions 找第一个 CCC 会话的 cwd**」—— 那是**跨工作区猜测**:
15407
- * 只要 sessionId 缺失或那条会话查不到(ACP/skiff 会话、尚未 materialize 的会话、远程访问),
15493
+ * 只要 sessionId 缺失或那条会话查不到(ACP/轨迹约束会话、尚未 materialize 的会话、远程访问),
15408
15494
  * 它就会**静默返回另一个 CCC 的路径**,于是面板把**别人的轨迹/技能/安全模式**当成你的显示出来。
15409
15495
  * 这比"显示未激活"危险得多 —— 用户会据此做判断(以为自己的 safe-mode 开着、以为那是自己的轨迹)。
15410
15496
  *
@@ -15618,17 +15704,22 @@ function registerStatusApi(ctx, opts = {}) {
15618
15704
  sendJson$2(res, 400, { error: chk.error });
15619
15705
  return;
15620
15706
  }
15621
- const { readWeixinSettings } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15707
+ const { readWeixinSettings } = await import("./route-COOFLTpU.js").then((n) => n.c);
15622
15708
  const { weixinBridgeStatus } = await Promise.resolve().then(() => bridge_exports);
15623
15709
  const settings = readWeixinSettings(chk.root);
15624
15710
  const bridge = weixinBridgeStatus().find((b) => b.ccc === chk.root);
15625
- const { readWeixinCredential } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15626
- const accounts = (settings.accounts ?? []).map((a) => ({
15627
- accountId: a.accountId,
15628
- name: a.name ?? void 0,
15629
- enabled: a.enabled !== false,
15630
- bound: readWeixinCredential(chk.root, a.accountId) !== null
15631
- }));
15711
+ const { imCredentialBound } = await import("./route-COOFLTpU.js").then((n) => n.c);
15712
+ const { normalizeAccountChannel } = await import("./accounts-BHQbakUh.js").then((n) => n.t);
15713
+ const accounts = (settings.accounts ?? []).map((a) => {
15714
+ const channel = normalizeAccountChannel(a.channel);
15715
+ return {
15716
+ accountId: a.accountId,
15717
+ name: a.name ?? void 0,
15718
+ enabled: a.enabled !== false,
15719
+ channel,
15720
+ bound: imCredentialBound(chk.root, a.accountId, channel)
15721
+ };
15722
+ });
15632
15723
  sendJson$2(res, 200, {
15633
15724
  enabled: settings.enabled === true,
15634
15725
  botType: settings.botType ?? void 0,
@@ -15654,7 +15745,7 @@ function registerStatusApi(ctx, opts = {}) {
15654
15745
  const { fetchQRCode } = await import("./ilink-BMk2w2KY.js").then((n) => n.a);
15655
15746
  const { randomUUID } = await import("node:crypto");
15656
15747
  for (const [key, v] of weixinLogins) if (Date.now() - v.startedAt > WEIXIN_LOGIN_TTL_MS) weixinLogins.delete(key);
15657
- const { readWeixinSettings } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15748
+ const { readWeixinSettings } = await import("./route-COOFLTpU.js").then((n) => n.c);
15658
15749
  const qr = await fetchQRCode({ botType: readWeixinSettings(root).botType ?? void 0 });
15659
15750
  const loginKey = randomUUID();
15660
15751
  weixinLogins.set(loginKey, {
@@ -15675,7 +15766,7 @@ function registerStatusApi(ctx, opts = {}) {
15675
15766
  sendJson$2(res, 400, { error: "missing accountId" });
15676
15767
  return;
15677
15768
  }
15678
- const { removeWeixinAccount } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15769
+ const { removeWeixinAccount } = await import("./route-COOFLTpU.js").then((n) => n.c);
15679
15770
  const { syncCccBridge } = await Promise.resolve().then(() => bridge_exports);
15680
15771
  removeWeixinAccount(root, body.accountId);
15681
15772
  syncCccBridge(ctx, root);
@@ -15701,8 +15792,8 @@ function registerStatusApi(ctx, opts = {}) {
15701
15792
  trajectory: code
15702
15793
  });
15703
15794
  }
15704
- const { saveWeixinRoutes } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15705
- const { findDirNameByCode } = await import("./profile-BIQ2widI.js").then((n) => n.i);
15795
+ const { saveWeixinRoutes } = await import("./route-COOFLTpU.js").then((n) => n.c);
15796
+ const { findDirNameByCode } = await import("./profile-BVt84mbi.js").then((n) => n.i);
15706
15797
  for (const r of routes) if (findDirNameByCode(root, r.trajectory) === null) {
15707
15798
  sendJson$2(res, 400, { error: `unknown trajectory: ${r.trajectory} (no such trajectory code in ${root})` });
15708
15799
  return;
@@ -15713,7 +15804,7 @@ function registerStatusApi(ctx, opts = {}) {
15713
15804
  }
15714
15805
  if (body.action === "set-enabled") {
15715
15806
  const enabled = body.enabled === true;
15716
- const { readWeixinSettings, setWeixinEnabled } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15807
+ const { readWeixinSettings, setWeixinEnabled } = await import("./route-COOFLTpU.js").then((n) => n.c);
15717
15808
  const { syncCccBridge } = await Promise.resolve().then(() => bridge_exports);
15718
15809
  const settings = readWeixinSettings(root);
15719
15810
  if (enabled && (settings.accounts ?? []).length === 0) {
@@ -15729,6 +15820,35 @@ function registerStatusApi(ctx, opts = {}) {
15729
15820
  sendJson$2(res, 200, { enabled });
15730
15821
  return;
15731
15822
  }
15823
+ if (body.action === "add-feishu-account") {
15824
+ const appId = (body.appId ?? "").trim();
15825
+ const appSecret = (body.appSecret ?? "").trim();
15826
+ if (appId === "" || appSecret === "") {
15827
+ sendJson$2(res, 400, { error: "appId 与 appSecret 都必须填(只填一个等于没绑)" });
15828
+ return;
15829
+ }
15830
+ const { readWeixinSettings, upsertWeixinAccount, writeFeishuCredential, nextFeishuAccountId } = await import("./route-COOFLTpU.js").then((n) => n.c);
15831
+ const { syncCccBridge } = await Promise.resolve().then(() => bridge_exports);
15832
+ const before = readWeixinSettings(root);
15833
+ const accountId = (body.accountId ?? "").trim() !== "" ? body.accountId.trim() : nextFeishuAccountId(before);
15834
+ upsertWeixinAccount(root, {
15835
+ accountId,
15836
+ name: (body.name ?? "").trim() !== "" ? body.name.trim() : void 0,
15837
+ channel: "feishu",
15838
+ enabled: true
15839
+ });
15840
+ writeFeishuCredential(root, accountId, {
15841
+ appId,
15842
+ appSecret
15843
+ });
15844
+ if (before.enabled) syncCccBridge(ctx, root);
15845
+ sendJson$2(res, 200, {
15846
+ accountId,
15847
+ channel: "feishu",
15848
+ saved: true
15849
+ });
15850
+ return;
15851
+ }
15732
15852
  sendJson$2(res, 400, { error: `unsupported action: ${body.action ?? ""}` });
15733
15853
  } catch (err) {
15734
15854
  sendJson$2(res, 400, { error: err.message ?? String(err) });
@@ -15757,7 +15877,7 @@ function registerStatusApi(ctx, opts = {}) {
15757
15877
  return;
15758
15878
  }
15759
15879
  const { pollQRStatus } = await import("./ilink-BMk2w2KY.js").then((n) => n.a);
15760
- const { readWeixinSettings } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15880
+ const { readWeixinSettings } = await import("./route-COOFLTpU.js").then((n) => n.c);
15761
15881
  const settings = readWeixinSettings(login.root);
15762
15882
  const status = await pollQRStatus({
15763
15883
  baseUrl: void 0,
@@ -15772,7 +15892,7 @@ function registerStatusApi(ctx, opts = {}) {
15772
15892
  });
15773
15893
  return;
15774
15894
  }
15775
- const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./route-ItCgAsnz.js").then((n) => n.c);
15895
+ const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./route-COOFLTpU.js").then((n) => n.c);
15776
15896
  const { syncCccBridge } = await Promise.resolve().then(() => bridge_exports);
15777
15897
  const accountId = nextWeixinAccountId(settings);
15778
15898
  upsertWeixinAccount(login.root, {
@@ -16214,7 +16334,7 @@ const HOST_SERVICES = [
16214
16334
  name: "get",
16215
16335
  kind: "function"
16216
16336
  }],
16217
- impact: "skiff/cheap-worker 无法创建或复用 agent",
16337
+ impact: "轨迹约束/cheap-worker 无法创建或复用 agent",
16218
16338
  required: true
16219
16339
  },
16220
16340
  {
@@ -16637,7 +16757,7 @@ function summarizeHostContract(report) {
16637
16757
  *
16638
16758
  * ## 现状 → 本模块要收掉什么(取证:`…/acc-c4c5-current-state.md` §①/§③ 3.1)
16639
16759
  *
16640
- * 插件自己 spawn 了**三个** node:http 监听器(B 3081 网关 / C 3082 微信发送 / D 3099 Skiff 调试)。
16760
+ * 插件自己 spawn 了**三个** node:http 监听器(B 3081 网关 / C 3082 微信发送 / D 3099 轨迹约束调试)。
16641
16761
  * ⚠️ **2026-10-15 变更**:原为四个(含 **E 3100 ACP+问答**),E 已随 owner「砍掉外部问答」令**整面退役**
16642
16762
  * ⇒ 仍保有面 B/C/D 三个;本段保留"当年是四个"的记述,因为下方"两套拆卸"的病史由它解释。
16643
16763
  * 此前四处各写一份同款样板:`createServer` + `server.once('error')` +
@@ -17808,9 +17928,9 @@ function sessionNameFromMdPath(mdPath) {
17808
17928
  * → ②b **权威绑定**(`AGENT_SESSIONS/.bindings.json`,本会话持久绑定)→ ③ surface 首条锚点
17809
17929
  * (events 异常时兜底)。
17810
17930
  *
17811
- * v1.30.13(S142 用户"微信桥 + skiff 会话锚定要准确",诊断 D4):**移除**原 ④「全局最新未完成
17931
+ * v1.30.13(S142 用户"微信桥 + 轨迹约束会话锚定要准确",诊断 D4):**移除**原 ④「全局最新未完成
17812
17932
  * 会话」(`findLatestActiveSessionMd`)。理由(R↓):④ 是**跨轨迹**猜测——候选①②③全空时,
17813
- * 它会把 rebuild 静默接到 AGENT_SESSIONS 里最新的另一个会话(临时 skiff 会话 persistent=false、
17933
+ * 它会把 rebuild 静默接到 AGENT_SESSIONS 里最新的另一个会话(临时 轨迹约束会话 persistent=false、
17814
17934
  * 重启后首条消息前、新会话首条消息都命中该形态),而"接错轨迹"比重建失败危险得多
17815
17935
  * (错误轨迹被继续写入 + 正确轨迹静默丢失)。现在全部候选失败 → 返回 null → 调用方
17816
17936
  * 报错引导用户显式 `cognitive_trajectory use`(响亮失败优于静默接错)。
@@ -19856,9 +19976,9 @@ const MECHANISM_WORDS = [
19856
19976
  "拦截缝",
19857
19977
  "装配层",
19858
19978
  "acp-core",
19859
- "skiff-core",
19860
- "skiff-registry",
19861
- "skiff-role",
19979
+ "trajectory-session",
19980
+ "trajectory-window",
19981
+ "trajectory-constraint",
19862
19982
  "output-guard"
19863
19983
  ];
19864
19984
  /**
@@ -19958,20 +20078,20 @@ const rebukeStates = /* @__PURE__ */ new Map();
19958
20078
  /**
19959
20079
  * 外部面会话判定(v1.26.3 用户拍板:仅外部面检测,本地维护会话豁免)。
19960
20080
  *
19961
- * 🔴 **2026-10-19 判据更换**:skiff 那一条从「sessionId 前缀 `skiff-`」改为
19962
- * **「该会话绑定的轨迹有 `skiff.json`」**(owner 重做令)。前缀判据在新模型下是
19963
- * **错的**——skiff 的身份是轨迹,不再由 id 前缀表达;继续用前缀会漏掉所有
19964
- * "挂在 skiff 轨迹上、但 id 不带前缀"的会话(典型 = 微信桥按轨迹派生的会话 id)。
20081
+ * 🔴 **2026-10-19 判据更换**:轨迹约束那一条从「sessionId 前缀 `轨迹约束-`」改为
20082
+ * **「该会话绑定的轨迹有 `trajectory-constraint.json`」**(owner 重做令)。前缀判据在新模型下是
20083
+ * **错的**——轨迹约束的身份是轨迹,不再由 id 前缀表达;继续用前缀会漏掉所有
20084
+ * "挂在 轨迹约束轨迹上、但 id 不带前缀"的会话(典型 = 微信桥按轨迹派生的会话 id)。
19965
20085
  *
19966
- * ⚠️ `rebuild-` 前缀保留(那是另一件事:重建会话同属对外面,与 skiff 无关);
20086
+ * ⚠️ `rebuild-` 前缀保留(那是另一件事:重建会话同属对外面,与 轨迹约束 无关);
19967
20087
  * `acp-` 分支保留但**已是死判据**(无生产者;面 E 已于 2026-10-15 退役)——
19968
20088
  * 理由与"为何不擅自删"见文件头注释。
19969
20089
  */
19970
20090
  function isExternalFaceSession(sessionId, root) {
19971
20091
  if (!sessionId) return false;
19972
- return isSkiffSession(root, sessionId) || sessionId.startsWith("acp-") || sessionId.startsWith("rebuild-");
20092
+ return isTrajectoryConstrained(root, sessionId) || sessionId.startsWith("acp-") || sessionId.startsWith("rebuild-");
19973
20093
  }
19974
- /** 读会话最后一个 assistant/message 文本(skiff-core 同款)
20094
+ /** 读会话最后一个 assistant/message 文本(trajectory-session 同款)
19975
20095
  * **v1.63.3 起唯一的导出理由消失**:原导出是给 `unattended-seam.ts` 复用的(D77),
19976
20096
  * 该文件已随无人值守功能整条退役 ⇒ 现只有本模块自己用(`isLeak` 的调用点)。
19977
20097
  * ⚠️ 保持 `export` 无害(它有测试覆盖,且将来"同一读法只留一份"的纪律仍成立),
@@ -20445,31 +20565,6 @@ function invokeWeixinHook(root, hookRel, event) {
20445
20565
  return activeRunner(root, hookRel, event);
20446
20566
  }
20447
20567
  //#endregion
20448
- //#region src/im/accounts.ts
20449
- const impls = /* @__PURE__ */ new Map();
20450
- /** 注册账号实现(`index.ts` 装配时调用;重复 channel 覆盖——测试与热重载友好) */
20451
- function registerImAccountImpl(impl) {
20452
- impls.set(impl.channel, impl);
20453
- }
20454
- /** 取实现(未注册 ⇒ `null`,由调用方**响亮出声**,不要静默跳过) */
20455
- function getImAccountImpl(channel) {
20456
- return impls.get(channel) ?? null;
20457
- }
20458
- /** 已注册的实现名(诊断与错误文案用;顺序 = 注册顺序) */
20459
- function imAccountChannels() {
20460
- return [...impls.keys()];
20461
- }
20462
- /**
20463
- * 账号行的渠道归一(**单一处**)。
20464
- *
20465
- * 缺省 `weixin`:老配置平移到 `im` 段时不必补这个字段——owner 的"统一配置"
20466
- * 要能直接吃旧数据(与 `route.ts` 的 `normalizeImSection` 保持同一口径)。
20467
- */
20468
- function normalizeAccountChannel(channel) {
20469
- const v = (channel ?? "").trim();
20470
- return v === "" ? "weixin" : v;
20471
- }
20472
- //#endregion
20473
20568
  //#region src/im/weixin-account.ts
20474
20569
  /** 轮询间隔(getupdates 失败后重试;成功 = 立即续,长轮询本身 hold 35s) */
20475
20570
  const POLL_RETRY_MS = 3e3;
@@ -20546,7 +20641,7 @@ function installWeixinAccountImpl(d) {
20546
20641
  const manualSessions = /* @__PURE__ */ new Map();
20547
20642
  /**
20548
20643
  * 本轮是否已成功发送(**由桥在每轮开始时清空** `clearSentThisTurn`;闸门只置位不清空——
20549
- * v1.30.17 起桥要在 `askSkiff` 返回后读它决定是否兜底,故 turn-stopping 不再结算清空)。
20644
+ * v1.30.17 起桥要在 `askTrajectory` 返回后读它决定是否兜底,故 turn-stopping 不再结算清空)。
20550
20645
  */
20551
20646
  const sentThisTurn = /* @__PURE__ */ new Set();
20552
20647
  /** 连续打回计数(成功发送即清零) */
@@ -20614,7 +20709,7 @@ function buildManualOutputRebuke(session) {
20614
20709
  }
20615
20710
  /**
20616
20711
  * 装配闸门(index.ts apply 调用)。
20617
- * 只对**已登记的手动模式会话**生效——其他会话(主舱/其他 skiff 会话)零干预。
20712
+ * 只对**已登记的手动模式会话**生效——其他会话(主舱/其他 轨迹约束会话)零干预。
20618
20713
  */
20619
20714
  function registerWeixinOutputGuard(ctx) {
20620
20715
  try {
@@ -20681,7 +20776,7 @@ const MEDIA_MAX_BYTES = 20971520;
20681
20776
  */
20682
20777
  async function resolveCccRootByAlias(ctx, alias) {
20683
20778
  try {
20684
- const { listCccs } = await import("./ccc-roots-BhoA7G-0.js").then((n) => n.a);
20779
+ const { listCccs } = await import("./ccc-roots-B2t_aM8L.js").then((n) => n.a);
20685
20780
  const entries = await listCccs(ctx);
20686
20781
  const byName = entries.find((e) => e.name === alias);
20687
20782
  if (byName) return byName.root;
@@ -20749,7 +20844,7 @@ async function resolveInboundTarget(ctx, input) {
20749
20844
  });
20750
20845
  return null;
20751
20846
  }
20752
- const { findDirNameByCode } = await import("./profile-BIQ2widI.js").then((n) => n.i);
20847
+ const { findDirNameByCode } = await import("./profile-BVt84mbi.js").then((n) => n.i);
20753
20848
  if (findDirNameByCode(root, target.role) === null) {
20754
20849
  const detail = `目标 CCC "${target.ccc}" 内没有编码为 "${target.role}" 的认知轨迹`;
20755
20850
  console.error(`[serenity-hooks] ✗ human-channel: ${detail}(account=${input.account} user=${input.user})—— 该消息**未投递**,请改订阅表里的目标编码`);
@@ -20763,7 +20858,7 @@ async function resolveInboundTarget(ctx, input) {
20763
20858
  });
20764
20859
  return null;
20765
20860
  }
20766
- const profile = readSkiffProfileByCode(root, target.role);
20861
+ const profile = readTrajectoryConstraintByCode(root, target.role);
20767
20862
  return {
20768
20863
  root,
20769
20864
  trajectory: target.role,
@@ -20814,13 +20909,13 @@ async function handleInboundEvent(ctx, root, accountId, io, event, preset) {
20814
20909
  }
20815
20910
  try {
20816
20911
  const sessionId = weixinSessionIdForTrajectory(trajectory);
20817
- const existing = getSkiffAgent(sessionId);
20912
+ const existing = getTrajectoryAgent(sessionId);
20818
20913
  const hc = readCheapWorkerConfig(root);
20819
20914
  const ref = existing ? {
20820
20915
  agent: existing,
20821
20916
  sessionId,
20822
20917
  resumed: true
20823
- } : await createSkiffAgent(ctx, root, profile ?? {
20918
+ } : await createTrajectoryAgent(ctx, root, profile ?? {
20824
20919
  dirName: trajectory,
20825
20920
  code: trajectory,
20826
20921
  path: "",
@@ -20885,7 +20980,7 @@ async function handleInboundEvent(ctx, root, accountId, io, event, preset) {
20885
20980
  }
20886
20981
  }
20887
20982
  const parts = [];
20888
- const workspaceMd = skiffWorkspaceMdPath(root, sessionId) ?? getActiveSessionInfo(sessionId)?.mdPath ?? null;
20983
+ const workspaceMd = trajectoryWorkspaceMdPath(root, sessionId) ?? getActiveSessionInfo(sessionId)?.mdPath ?? null;
20889
20984
  if (workspaceMd) {
20890
20985
  if (!ensureWorkspacePromptSection(ref.agent, sessionId, root)) parts.push(workspaceCognitiveTrajectoryLine(workspaceMd));
20891
20986
  }
@@ -20915,7 +21010,7 @@ async function handleInboundEvent(ctx, root, accountId, io, event, preset) {
20915
21010
  })).catch((err) => {
20916
21011
  console.log(`[serenity-hooks] im hook incoming error: ${err instanceof Error ? err.message : String(err)}`);
20917
21012
  });
20918
- const answer = (await askSkiff(ctx, ref.agent, question)).answer ?? "";
21013
+ const answer = (await askTrajectory(ctx, ref.agent, question)).answer ?? "";
20919
21014
  if (manualOutput) {
20920
21015
  if (!manualOutputFallbackNeeded({
20921
21016
  fallbackOnNoSend: settings.fallbackOnNoSend,
@@ -21561,7 +21656,7 @@ function syncHumanChannel(ctx) {
21561
21656
  (async () => {
21562
21657
  try {
21563
21658
  stopMachineLoops();
21564
- const { listCccs } = await import("./ccc-roots-BhoA7G-0.js").then((n) => n.a);
21659
+ const { listCccs } = await import("./ccc-roots-B2t_aM8L.js").then((n) => n.a);
21565
21660
  for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
21566
21661
  } catch {}
21567
21662
  })();
@@ -21825,7 +21920,7 @@ function matchCcc(input, candidates) {
21825
21920
  }
21826
21921
  /** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
21827
21922
  async function collectCandidates(ctx) {
21828
- const { listCccs } = await import("./ccc-roots-BhoA7G-0.js").then((n) => n.a);
21923
+ const { listCccs } = await import("./ccc-roots-B2t_aM8L.js").then((n) => n.a);
21829
21924
  const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
21830
21925
  const seen = /* @__PURE__ */ new Set();
21831
21926
  const out = [];
@@ -22045,7 +22140,7 @@ function sessionIdOf(value) {
22045
22140
  /** 单会话内存态清理(幂等;无对应状态即 no-op) */
22046
22141
  function cleanupSessionState(sessionId) {
22047
22142
  try {
22048
- unregisterSkiffSession(sessionId);
22143
+ unregisterTrajectorySession(sessionId);
22049
22144
  } catch {}
22050
22145
  try {
22051
22146
  clearActiveSessionInfo(sessionId);
@@ -22066,7 +22161,7 @@ function cleanupSessionState(sessionId) {
22066
22161
  forgetHostScheduleToolHiding(sessionId);
22067
22162
  } catch {}
22068
22163
  try {
22069
- forgetSkiffRoleToolVisibility(sessionId);
22164
+ forgetTrajectoryConstraintToolVisibility(sessionId);
22070
22165
  } catch {}
22071
22166
  try {
22072
22167
  forgetLogbookCompactionState(sessionId);
@@ -22097,7 +22192,7 @@ function registerLifecycle(ctx) {
22097
22192
  stopAllBridges();
22098
22193
  } catch {}
22099
22194
  };
22100
- registerDisposer(ctx, "self-started resources (gateway/weixin/skiff-debug faces + weixin bridges)", disposeAll);
22195
+ registerDisposer(ctx, "self-started resources (gateway/weixin/trajectory-debug faces + weixin bridges)", disposeAll);
22101
22196
  }
22102
22197
  //#endregion
22103
22198
  //#region src/patches/web-fetch.ts
@@ -22691,7 +22786,7 @@ async function applyOpencodeAutoConfigOnce(ctx, env) {
22691
22786
  *
22692
22787
  * 为什么要重试:`llm-pi-ai` 只在**它自己的** `ctx.inject(['settings'])` 回调里注册命名空间,
22693
22788
  * 与本插件 apply **无先后保证**(两者都依赖 settings 服务)。首次读取拿到 undefined 是常态而非错误
22694
- * (与 skiff 的 CCC root 重试同款问题、同款处置:v1.30.13 实证"只在 apply 时试一次 → 永不重试")。
22789
+ * (与 轨迹约束的 CCC root 重试同款问题、同款处置:v1.30.13 实证"只在 apply 时试一次 → 永不重试")。
22695
22790
  */
22696
22791
  const NAMESPACE_RETRY_DELAYS_MS$1 = [
22697
22792
  1e3,
@@ -22703,7 +22798,7 @@ const NAMESPACE_RETRY_DELAYS_MS$1 = [
22703
22798
  /**
22704
22799
  * 装配 opencode 路由自动配置。
22705
22800
  *
22706
- * 触发面(三层,与 skiff 同款;R↓:单点触发在同装载竞态下必然漏):
22801
+ * 触发面(三层,与 轨迹约束 同款;R↓:单点触发在同装载竞态下必然漏):
22707
22802
  * ① apply 时立即试一次
22708
22803
  * ② 命名空间尚未注册 → 退避重试(1s/3s/8s/20s/40s)
22709
22804
  * ③ `settings/updated` → 再试(用户热改 settings.yaml 加路由时自愈;自身写入触发的复评是幂等空转)
@@ -24298,7 +24393,7 @@ function renderDsl(model) {
24298
24393
  * 🔴 **为什么 PNG 是必需的**:宿主的对话内图片通路**白名单只有光栅格式**
24299
24394
  * (`image/png|jpeg|webp|gif`,见 `dsh-attachment/types.d.ts`)⇒ **SVG 进不去**。
24300
24395
  *
24301
- * 🔴 **开关**:由 `index.ts` 门控(**关时不注册** ⇒ 工具根本不进模型工具清单),同 skiff 口径。
24396
+ * 🔴 **开关**:由 `index.ts` 门控(**关时不注册** ⇒ 工具根本不进模型工具清单),同 轨迹约束 口径。
24302
24397
  *
24303
24398
  * ## 🔴 两条**宿主契约**(2026-09-29 现场取证;第 ① 条是本文件第一版写错的地方)
24304
24399
  *
@@ -24769,7 +24864,7 @@ function apply(ctx, config) {
24769
24864
  * ① 听宿主的**真事件** `settings/document-updated`(ns = 我们那张设置页)——顺带说明为什么不用
24770
24865
  * 我们自己的 `serenity/settings-changed`:那个事件**全仓没有任何 `emit` 点**(只有 `ctx.on` 侧
24771
24866
  * 在用)=**死通道**,照着它接线等于接了个永远不响的铃;
24772
- * ② 兜底再挂 `agent/created` / `session/created`(与 skiff 同款做法,那两条在实测里确实会 fire)
24867
+ * ② 兜底再挂 `agent/created` / `session/created`(与 轨迹约束 同款做法,那两条在实测里确实会 fire)
24773
24868
  * —— 宿主事件面若换名,至少还有这一条能自愈;
24774
24869
  * ③ 启动时同步一次(apply 时按当前配置定初始态)。
24775
24870
  * 🔴 **关的时候要注销**(不是"留着但不响应"):与"关时不注册"同一口径 —— 工具不出现在模型清单里。