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