@shgroup/dsh-serenity-hooks 1.105.0 → 1.108.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 +4 -3
- package/dsh.plugin.json +2 -3
- package/lib/{profile-Dpg3wYO5.js → bind-file-B0TuOP89.js} +1 -333
- package/lib/{ccc-B-h_A7uc.js → ccc-BmpE3cQz.js} +64 -12
- package/lib/{ccc-roots-BPicjCsj.js → ccc-roots-DPMwBywc.js} +2 -2
- package/lib/{channels-bAiZlY07.js → channels-Dty_NIl_.js} +2 -146
- package/lib/client.js +125 -0
- package/lib/contract-BiNzzd77.js +2197 -0
- package/lib/index.js +217 -6361
- package/lib/invariant.js +1 -2
- package/lib/kernel/ccc.d.ts +60 -13
- package/lib/kernel/invariant.d.ts +2 -2
- package/lib/message-source-BTIe2cVO.js +254 -0
- package/lib/observation-BWpkA865.js +210 -0
- package/lib/profile-BjBn_-be.js +336 -0
- package/lib/{route-CmEoKp9w.js → route-reyv8qcB.js} +2 -2
- package/lib/rules-BLkYTPUy.js +261 -0
- package/lib/scheduler-B0pB9mxI.js +3603 -0
- package/lib/seams/guards.d.ts +0 -4
- package/lib/{service-Cndtf7q4.js → service-Z3aSR1cn.js} +1 -1
- package/lib/service-xvjwsX3p.js +249 -0
- package/lib/{session-CYqyod3z.js → session-BlgUdKH4.js} +7 -5
- package/lib/settings-DY4_DYYY.js +145 -0
- package/lib/subscriptions-CyrfNpcG.js +273 -0
- package/lib/tools/diag/service.d.ts +74 -24
- package/lib/tools/kit/service.d.ts +1 -1
- package/lib/tools/msm/service.d.ts +2 -2
- package/lib/trajectory/subscriptions.d.ts +170 -0
- package/package.json +2 -2
- package/lib/message-source-DoVtXnoe.js +0 -513
- package/lib/tools/diag/index.d.ts +0 -25
package/lib/seams/guards.d.ts
CHANGED
|
@@ -107,10 +107,6 @@ export declare function getHostScheduleHiddenDiagnostics(): {
|
|
|
107
107
|
};
|
|
108
108
|
/** 会话销毁清理(lifecycle 调用)——方案 C 后由统一清理撤销,这里保留语义占位。 */
|
|
109
109
|
export declare function forgetHostScheduleToolHiding(_sessionId: string): void;
|
|
110
|
-
/** 专属工具隐藏诊断(排查"工具为什么不在清单里") */
|
|
111
|
-
export declare function getExclusiveToolsDiagnostics(): {
|
|
112
|
-
hidden: string[];
|
|
113
|
-
};
|
|
114
110
|
/** 轨迹约束工具面诊断(排查"某工具为什么不在 轨迹约束的清单里") */
|
|
115
111
|
export declare function getTrajectoryConstraintVisibilityDiagnostics(): {
|
|
116
112
|
keys: string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-
|
|
1
|
+
import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-BmpE3cQz.js";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/tools/localstore/service.ts
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { d as hostSessions, r as cccRootForCwd } from "./ccc-roots-DPMwBywc.js";
|
|
2
|
+
import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.js";
|
|
3
|
+
import { F as isoLocal, w as sessionEvents } from "./bind-file-B0TuOP89.js";
|
|
4
|
+
import { m as WAKE_CATCH_UP_MS, p as listCroCognitiveTrajectories } from "./scheduler-B0pB9mxI.js";
|
|
5
|
+
import { n as readSimpleSettings } from "./settings-DY4_DYYY.js";
|
|
6
|
+
import { r as subscriptionStats } from "./subscriptions-CyrfNpcG.js";
|
|
7
|
+
import { containerClocks, containerWakes } from "./observation-BWpkA865.js";
|
|
8
|
+
//#region src/trajectory/live.ts
|
|
9
|
+
/**
|
|
10
|
+
* trajectory/live.ts — 进程内 live 会话取数 + 精简诊断
|
|
11
|
+
*
|
|
12
|
+
* ── 为什么单独成模块(R↓,2026-09-15 S142「ACC 侧 autopilot 退场」S1 搬迁)──
|
|
13
|
+
* 这两个函数原先住在 `autopilot-trajectory.ts`,但它们的**主语不是 autopilot**:
|
|
14
|
+
* `listLiveSessions` 服务 `acc-diag` ① 段的"**哪个会话属于哪个 CCC**"(会话维度,
|
|
15
|
+
* 不是 CCC 维度),而"**独立进程看不到运行时**"正是 `acc-diag` 存在的理由。
|
|
16
|
+
* autopilot 退场后它们必须活下去 ⇒ 独立成模块,不再挂着已死机制的名字。
|
|
17
|
+
*
|
|
18
|
+
* ── 迁移边界(不搬什么,以及为什么)──────────────────────────────────────
|
|
19
|
+
* 原 `diagLive` 还含两段,**均不搬**(其主语是 autopilot,随机制退场):
|
|
20
|
+
* · `autopilotCccs`(逐 CCC 目标命中 / agent 定位诊断)—— 依赖 `readAutopilotSettings` /
|
|
21
|
+
* `getAutopilotStatus` / `resolveTargetAgent`
|
|
22
|
+
* · `panelResolved`(无参面板请求落到哪个 CCC)—— 面板区块随机制退场
|
|
23
|
+
* 留下的 = **进程 cwd/CCC + live 会话清单**(`acc-diag` ① 段仍需要)。
|
|
24
|
+
*
|
|
25
|
+
* 判据纪律:本模块**不得**反向依赖 autopilot 判据层(那会让退场半途而废)。
|
|
26
|
+
*
|
|
27
|
+
* ── 🔴 2026-09-25 I2 收敛(约束文档 §2.7 违反清单,L1 违反之一)────────────────
|
|
28
|
+
* **本模块的 `ctx` 参数类型从 `Context` 改为 `unknown`** —— 消除本文件唯一的 `W2` 接触
|
|
29
|
+
* (直接 import 宿主 `cordis` 的类型)。
|
|
30
|
+
*
|
|
31
|
+
* **为什么这是"真解耦"而不是"把类型藏起来"(判据):** `ctx` 在本模块**从不被解引用** ——
|
|
32
|
+
* 它只被**原样透传**给 `hostSessions(ctx)`,而后者(`host/access.ts`,**L0**)的参数
|
|
33
|
+
* 本就声明为 `ctx: unknown` ⇒ `Context` 这个 import **在语义上是多余的**,
|
|
34
|
+
* 它没有参与任何类型检查,只贡献了一处 L1→宿主 的接触点。
|
|
35
|
+
* 🔵 **证据**:grep 本文件 `ctx` 全部 5 处命中 —— 3 处在参数/调用位、2 处在注释,
|
|
36
|
+
* **零处**属性访问(`ctx.xxx`)。
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* 从 dsh 会话 log 读取标题(latest-wins `session/title` 事件)——
|
|
40
|
+
* **标题不在 `sessions.list()` 条目上**(wire/对象均无 title 字段;F3 命名经
|
|
41
|
+
* `sessionTitle.rename` 写进 session log),必须从 events 提取(rebuild 同款读取模式)。
|
|
42
|
+
*/
|
|
43
|
+
function readSessionTitle(session) {
|
|
44
|
+
try {
|
|
45
|
+
const events = sessionEvents(session);
|
|
46
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
47
|
+
const e = events[i];
|
|
48
|
+
if (e?.type === "session/title" && typeof e.data?.title === "string" && e.data.title.trim() !== "") return e.data.title.trim();
|
|
49
|
+
}
|
|
50
|
+
} catch {}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 逐条 live 会话(`cccRoot` = 该会话 cwd 的 CCC 归属,无 → null)。
|
|
55
|
+
*
|
|
56
|
+
* CCC 枚举("本机有哪些 CCC")**不在这里**,归 `ccc-roots.listCccs`(并集语义);
|
|
57
|
+
* 本函数保留的是它**独有**的那部分:会话维度 + cwd 归属 + 标题 + id。
|
|
58
|
+
*
|
|
59
|
+
* @param ctx 插件上下文(**只透传**给 L0 取数口,本模块不解引用 ⇒ 类型为 `unknown`)
|
|
60
|
+
* @returns 逐条 live 会话
|
|
61
|
+
*/
|
|
62
|
+
function listLiveSessions(ctx) {
|
|
63
|
+
const out = [];
|
|
64
|
+
try {
|
|
65
|
+
const sessions = hostSessions(ctx);
|
|
66
|
+
for (const s of sessions?.list?.() ?? []) {
|
|
67
|
+
const cwd = s?.header?.cwd ?? null;
|
|
68
|
+
out.push({
|
|
69
|
+
id: s?.id ?? "",
|
|
70
|
+
cwd,
|
|
71
|
+
cccRoot: cwd ? cccRootForCwd(cwd) : null,
|
|
72
|
+
title: readSessionTitle(s)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
} catch {}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
function diagLive(ctx) {
|
|
79
|
+
const processCwd = process.cwd();
|
|
80
|
+
return {
|
|
81
|
+
processCwd,
|
|
82
|
+
processCcc: cccRootForCwd(processCwd),
|
|
83
|
+
liveSessions: listLiveSessions(ctx)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/tools/diag/service.ts
|
|
88
|
+
/**
|
|
89
|
+
* tools/diag/service.ts — 运行态诊断报告装配(原 `acc-diag` 工具;v1.106.0 并入 `dashboard diag`)
|
|
90
|
+
*
|
|
91
|
+
* ## 为什么并进 dashboard(owner 2026-11-01 裁「方案 C」)
|
|
92
|
+
*
|
|
93
|
+
* 原 `acc-diag` 是**专属工具**(要 CCC 在 `exclusiveTools` 里逐字点名才可见)。
|
|
94
|
+
* owner 要的是「诊断入口随时可用」,而专属机制让入口本身成了特权的副产品:
|
|
95
|
+
* 换个 CCC 就看不见,且"看不见"与"坏了"在现象上同形。⇒ 并入常驻的 `dashboard`,
|
|
96
|
+
* 并**整体删除 `exclusiveTools` 机制**(那一版永远只有一个成员,机制成本高于收益)。
|
|
97
|
+
*
|
|
98
|
+
* ⚠️ **代价(owner 已知并确认)**:`dashboard` 常驻 ⇒ 本节对**所有轨迹**可见,
|
|
99
|
+
* 而 ① 段的 live 会话清单是**全部 CCC** 的(跨容器)。这是方案 C 的既定后果,不是缺陷。
|
|
100
|
+
*
|
|
101
|
+
* 为什么单独成模块(R↓):工具面(`tools/kit/index.ts`)只做"取 CCC 根 + 渲染",
|
|
102
|
+
* 装配逻辑放这里 ⇒ 纯函数可单测、不依赖 DSH 工具注册。
|
|
103
|
+
*
|
|
104
|
+
* 四段内容(数据来源各自单一真相源,本模块只聚合不复制语义):
|
|
105
|
+
* ① live 运行态 —— 插件进程内 `diagLive(ctx)`(进程 cwd/CCC + live 会话清单)
|
|
106
|
+
* ——**独立进程看不到运行时**,这正是本段存在的理由
|
|
107
|
+
* ①b 唤醒时钟 —— `containerClocks().wake`(唤醒调度器进程内快照:武装态/计数/上次跳过原因)
|
|
108
|
+
* ② CRO 已注册清单 —— `listCroCognitiveTrajectories(root)`(v1.106.0 新增,owner 要求)
|
|
109
|
+
* **CRO 没有注册表**(见 `cro/core.ts` 文件头):`continuous-re-occurrence.ts` 文件存在即启用
|
|
110
|
+
* ⇒ 本段是那个"隐式事实"的**唯一可见出口**。运维看不到它,就只能靠翻目录猜。
|
|
111
|
+
* ③ 唤醒注册表 —— `wake-registry.json` 的**在办条目** + **未来与已过期分开列**(v1.106.0)
|
|
112
|
+
* 🔴 2026-09-19 §0Q 甲案:终态条目**结案即清除** ⇒ 本段只列在办项,不再是"历史全量"。
|
|
113
|
+
* 🔴 v1.106.0 补一条判据(owner 2026-11-01 要"看未来会被唤起的"):
|
|
114
|
+
* **过去的不看** ⇒ `at > now` 单独成组;**已过期但仍在办**的另列一组。
|
|
115
|
+
* 两者必须分开,因为它们的**病情不同**:未来项 = 正常排队;过期项 = 补跑窗口里卡着
|
|
116
|
+
* (调度器没跑 / 目标不可解析),混在一起读会以为"排了好多活儿"。
|
|
117
|
+
*
|
|
118
|
+
* ── 2026-09-15:段数由四降为三(S142「ACC 侧 autopilot 退场」§1 二阶裁定)─────────────
|
|
119
|
+
* ACC 侧 autopilot 整段退场后,报告里两段的**主语消失**,故删除(不是"暂时关掉"):
|
|
120
|
+
* · 原 ② 面板解析 —— `diagLive.panelResolved` 的来源是"哪个 CCC 配了 autopilot",
|
|
121
|
+
* 面板区块同批删除 ⇒ 主语不存在。
|
|
122
|
+
* · 原 ④ 唤起条件链 —— 整段都是 ACC autopilot 的唤起条件(`buildWakeChain` +
|
|
123
|
+
* `autopilotRuntimeFacts`),实现模块已删 ⇒ 不留第二份条件链、也不留半死的手写版。
|
|
124
|
+
* · 原 ① 段的 autopilot CCC 渲染(逐 CCC 目标命中 / agent 定位)同批删除。
|
|
125
|
+
*
|
|
126
|
+
* 🔴 **已知缺口(登记,不静默丢弃)**:④「为什么这轮没唤起」的诊断在 **CCC 自管理链**上归零。
|
|
127
|
+
* 新链的失败形态是"S151 漏了自排下一轮"或"调度器闸关/未 tick",而删掉 ④ 后这两种病因都不可见。
|
|
128
|
+
* 按所有者裁决本次**不补**(一句话可补,代价 = 一条新条件链:调度器 armed / 闸 / tick 在跑 /
|
|
129
|
+
* 条目到期 / 补跑窗口 / 目标可解析 / CCC 闸)。**不得**以"顺手保留 ④"的方式把它偷偷带回。
|
|
130
|
+
* ⚠️ v1.106.0 的 ③ 两分组**不是**这条缺口的补丁:分组只把"已过期在办"显形,
|
|
131
|
+
* 没有回答"为什么没 tick"——那是 ①b 的 lastSkipReason 与 tick 次数的事,别混为一谈。
|
|
132
|
+
*
|
|
133
|
+
* C5「观察面归一」(2026-09-15):① 走 `diagLive`(那是**live 运行态**的独有取数,没有第二个
|
|
134
|
+
* 来源);①b 时钟与 ③ 注册表经 `surface/observation.ts` 取(唯一取数出口)——**投影仍在本文件**
|
|
135
|
+
* (诊断段不含 `message`,面板含;这是渲染差异,不是取数差异)。
|
|
136
|
+
*/
|
|
137
|
+
/** 人读渲染一行时钟状态("为何没有 tick" 的第一手判据) */
|
|
138
|
+
function renderClock(label, s) {
|
|
139
|
+
const ts = (ms) => ms === null ? "(从未)" : isoLocal(ms);
|
|
140
|
+
const parts = [
|
|
141
|
+
`armed=${s.armed}`,
|
|
142
|
+
`CRO 闸=${readSimpleSettings().croEnabled !== false}`,
|
|
143
|
+
`tick 次数=${s.ticks}`,
|
|
144
|
+
`上次 tick=${ts(s.lastTickAt)}`
|
|
145
|
+
];
|
|
146
|
+
if (s.armedAt !== null) parts.push(`武装于=${ts(s.armedAt)}`);
|
|
147
|
+
if (s.lastSkipReason) parts.push(`上次跳过: ${s.lastSkipReason}`);
|
|
148
|
+
return `${label}: ${parts.join(" | ")}`;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 装配报告(一次调用即全报告)。
|
|
152
|
+
* @param ctx 插件上下文(进程内读 sessions/agents)
|
|
153
|
+
* @param root 调用方 CCC 根(唤醒注册表取数目标)
|
|
154
|
+
* @param nowMs 判"未来 / 已过期"的基准时刻(可注入 ⇒ 可单测,不依赖挂钟)
|
|
155
|
+
* @returns 结构化报告(渲染由 {@link renderDiag} 负责)
|
|
156
|
+
*/
|
|
157
|
+
async function runDiag(ctx, root, nowMs = Date.now()) {
|
|
158
|
+
const live = diagLive(ctx);
|
|
159
|
+
const clocks = containerClocks();
|
|
160
|
+
const wakes = containerWakes(root);
|
|
161
|
+
const project = (e) => ({
|
|
162
|
+
id: e.id,
|
|
163
|
+
target: e.target,
|
|
164
|
+
at: e.at,
|
|
165
|
+
state: e.state,
|
|
166
|
+
createdBy: e.createdBy,
|
|
167
|
+
attempts: e.attempts ?? 0,
|
|
168
|
+
lastResult: e.lastResult ?? null
|
|
169
|
+
});
|
|
170
|
+
const future = [];
|
|
171
|
+
const overdue = [];
|
|
172
|
+
for (const e of wakes.entries) {
|
|
173
|
+
const at = Date.parse(e.at);
|
|
174
|
+
if (Number.isFinite(at) && at > nowMs) future.push(project(e));
|
|
175
|
+
else overdue.push(project(e));
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
ccc: root,
|
|
179
|
+
live,
|
|
180
|
+
clocks: { wake: clocks.wake },
|
|
181
|
+
cro: listCroCognitiveTrajectories(root),
|
|
182
|
+
wakes: {
|
|
183
|
+
error: wakes.error,
|
|
184
|
+
future,
|
|
185
|
+
overdue,
|
|
186
|
+
pending: wakes.pending
|
|
187
|
+
},
|
|
188
|
+
nowMs,
|
|
189
|
+
subscriptions: subscriptionStats(),
|
|
190
|
+
subscriptionProblems: readTrajectorySubscriptions(root).problems
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/** 人读渲染一行唤醒条目 */
|
|
194
|
+
function renderWake(w) {
|
|
195
|
+
return ` · ${w.id} [${w.state}] at=${w.at} → ${w.target} by=${w.createdBy} attempts=${w.attempts}`;
|
|
196
|
+
}
|
|
197
|
+
/** 人读渲染(四段;空段也要显式说明"无",避免"沉默 = 一切正常"的误读) */
|
|
198
|
+
function renderDiag(r) {
|
|
199
|
+
const lines = [];
|
|
200
|
+
lines.push(`═══ ACC 运行态诊断(dashboard diag)═══`);
|
|
201
|
+
lines.push(`调用方 CCC: ${r.ccc}`);
|
|
202
|
+
lines.push(`报告时刻: ${isoLocal(r.nowMs)}`);
|
|
203
|
+
lines.push("");
|
|
204
|
+
lines.push(`── ① live 运行态(插件进程内)──`);
|
|
205
|
+
lines.push(`进程 cwd: ${r.live.processCwd}`);
|
|
206
|
+
lines.push(`进程 CCC: ${r.live.processCcc ?? "(无——进程 cwd 不在任何 CCC 内)"}`);
|
|
207
|
+
lines.push(`live 会话: ${r.live.liveSessions.length} 个`);
|
|
208
|
+
for (const s of r.live.liveSessions) lines.push(` · ${s.id}${s.title ? `「${s.title}」` : ""} — ccc=${s.cccRoot ?? "(非 CCC)"} cwd=${s.cwd ?? "(无)"}`);
|
|
209
|
+
lines.push("");
|
|
210
|
+
lines.push(renderClock("唤醒调度器(wake-registry tick)", r.clocks.wake));
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push(`── ② CRO 已启用轨迹(判据:目录下有 continuous-re-occurrence.ts;无注册表)──`);
|
|
213
|
+
if (r.cro.length === 0) lines.push("(无——本 CCC 没有轨迹启用 CRO)");
|
|
214
|
+
else {
|
|
215
|
+
lines.push(`共 ${r.cro.length} 条:`);
|
|
216
|
+
for (const d of r.cro) lines.push(` · ${d}`);
|
|
217
|
+
}
|
|
218
|
+
lines.push("");
|
|
219
|
+
lines.push(`── ③ 唤醒注册表(在办项;已结案条目即时清除,历史见 SESSION.md)──`);
|
|
220
|
+
lines.push(` (${r.ccc}/AGENT_SESSIONS/wake-registry.json)`);
|
|
221
|
+
if (r.wakes.error) lines.push(`⚠ 注册表读取问题: ${r.wakes.error}`);
|
|
222
|
+
lines.push(`在办 ${r.wakes.pending} 条 = 未来 ${r.wakes.future.length} + 已过期 ${r.wakes.overdue.length}|补跑窗口 ${WAKE_CATCH_UP_MS / 36e5}h`);
|
|
223
|
+
lines.push(`· 未来(at > 报告时刻;正常排队): ${r.wakes.future.length} 条`);
|
|
224
|
+
if (r.wakes.future.length === 0) lines.push(" (无)");
|
|
225
|
+
for (const w of r.wakes.future) {
|
|
226
|
+
lines.push(renderWake(w));
|
|
227
|
+
if (w.lastResult) lines.push(` lastResult: ${w.lastResult}`);
|
|
228
|
+
}
|
|
229
|
+
lines.push(`· 已过期但仍在办(at ≤ 报告时刻;卡在补跑窗口,多半是调度器没 tick 或目标不可解析): ${r.wakes.overdue.length} 条`);
|
|
230
|
+
if (r.wakes.overdue.length === 0) lines.push(" (无)");
|
|
231
|
+
for (const w of r.wakes.overdue) {
|
|
232
|
+
lines.push(renderWake(w));
|
|
233
|
+
if (w.lastResult) lines.push(` lastResult: ${w.lastResult}`);
|
|
234
|
+
}
|
|
235
|
+
lines.push("");
|
|
236
|
+
lines.push(`── ⑤ 轨迹消息订阅(投递读数;只列发生过的投递,配置全表见 serenity.json)──`);
|
|
237
|
+
if (r.subscriptionProblems.length > 0) {
|
|
238
|
+
lines.push(`⚠ 配置坏项 ${r.subscriptionProblems.length} 条(**配了但不生效**):`);
|
|
239
|
+
for (const p of r.subscriptionProblems) lines.push(` · ${p}`);
|
|
240
|
+
}
|
|
241
|
+
if (r.subscriptions.length === 0) lines.push("(本进程内还没有任何订阅投递发生)");
|
|
242
|
+
else for (const s of r.subscriptions) {
|
|
243
|
+
const tail = s.failed > 0 ? ` ⚠ 最近失败:${s.lastError ?? "(无说明)"}` : "";
|
|
244
|
+
lines.push(` · ${s.key} 成功 ${s.ok} / 失败 ${s.failed}${s.lastAt ? ` | 最后 ${isoLocal(s.lastAt)}` : ""}${tail}`);
|
|
245
|
+
}
|
|
246
|
+
return lines.join("\n");
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
export { renderDiag, runDiag };
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { c as hostAgents, n as agentCwdFor, r as cccRootForCwd, s as hostAgentDefaultModel } from "./ccc-roots-
|
|
2
|
-
import { f as readCognitiveTrajectorySkills, h as readUtf8, o as isSafeModeOn, u as readBlacklist } from "./ccc-
|
|
3
|
-
import {
|
|
4
|
-
import { a as readGitTrack, i as localstorePath } from "./service-
|
|
5
|
-
import {
|
|
1
|
+
import { c as hostAgents, n as agentCwdFor, r as cccRootForCwd, s as hostAgentDefaultModel } from "./ccc-roots-DPMwBywc.js";
|
|
2
|
+
import { f as readCognitiveTrajectorySkills, h as readUtf8, o as isSafeModeOn, u as readBlacklist } from "./ccc-BmpE3cQz.js";
|
|
3
|
+
import { F as isoLocal, T as sessionsRoot, s as DEFAULT_SESSION_SCOPE, x as readActiveSessionMd } from "./bind-file-B0TuOP89.js";
|
|
4
|
+
import { a as readGitTrack, i as localstorePath } from "./service-Z3aSR1cn.js";
|
|
5
|
+
import { a as createProfilePromptReader, n as buildTrajectoryBasePrompt, o as profileMsmWhitelist, r as constraintCognitiveTrajectory, u as ACC_VERSION } from "./rules-BLkYTPUy.js";
|
|
6
|
+
import { d as registerTrajectorySession$1, f as trajectoryDirNameForSession, o as readTrajectoryConstraintAt, p as unregisterTrajectorySession$1, u as trajectoryConstraintForSession } from "./profile-BjBn_-be.js";
|
|
7
|
+
import { n as PLUGIN_SOURCE, o as readLastBound } from "./message-source-BTIe2cVO.js";
|
|
6
8
|
import { basename, dirname, join, resolve } from "node:path";
|
|
7
9
|
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
8
10
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { f as hostSettings } from "./ccc-roots-DPMwBywc.js";
|
|
2
|
+
//#region src/surface/settings.ts
|
|
3
|
+
/**
|
|
4
|
+
* 设置面板命名空间 = **profile 条目 id**(v0.1.7 起;与旧 `settings.yaml` 段名逐字相同)。
|
|
5
|
+
*/
|
|
6
|
+
const SERENITY_SETTINGS_NS = "serenity-hooks";
|
|
7
|
+
/** 进程级默认(无 Config 可读时的兜底;与 Config 各字段的缺省一致) */
|
|
8
|
+
function defaultSimpleSettings() {
|
|
9
|
+
return {
|
|
10
|
+
gatewayEnabled: false,
|
|
11
|
+
rebuildThresholdK: 400,
|
|
12
|
+
croEnabled: true,
|
|
13
|
+
diagramEnabled: false,
|
|
14
|
+
humanChannel: defaultHumanChannelSettings()
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* volatile 字段的**结构化解包**(v1.47.2;本文件读取语义的第一道)。
|
|
19
|
+
*
|
|
20
|
+
* ## 为什么必须有它(两个事实的合成,缺一即错)
|
|
21
|
+
* ① **0.1.7 的面板层字段必须标 `.volatile()`** —— 否则本插件命名空间整个不进宿主的
|
|
22
|
+
* `settings.describe()`(`volatileForm()` 只认 `meta.volatile`)⇒ **设置面板那一节消失**。
|
|
23
|
+
* ② **标了之后,运行期拿到的是引用包装,不是裸值** —— schemastery 的 `Schema.resolve()` 对
|
|
24
|
+
* `meta.volatile` **无条件**包 `createVolatile(value)`,且该分支排在"缺省值回退"那一段
|
|
25
|
+
* **之前** ⇒ **"用户没设过"的字段也是恒真对象**(`.get()` 返回 `undefined`),**不是 `undefined`**。
|
|
26
|
+
*
|
|
27
|
+
* ⇒ 若这里不解包,下面十行的 `??` 链会**短路在这层包装上** ⇒ 网关 / 轨迹约束 会被
|
|
28
|
+
* **无意打开**(比"面板不显示"更坏:静默改变对外暴露面)。
|
|
29
|
+
*
|
|
30
|
+
* ## 为什么用结构判定
|
|
31
|
+
* 可观察形状就是"有 `get()`"(cosmokit 的 `isVolatile` 也这么判);本模块不引它的运行时依赖。
|
|
32
|
+
*
|
|
33
|
+
* @param value - volatile 引用 | 裸值 | undefined
|
|
34
|
+
* @returns 解包后的裸值(引用 ⇒ `.get()`;裸值原样;缺省 ⇒ `undefined`)
|
|
35
|
+
*/
|
|
36
|
+
function unwrapVolatile(value) {
|
|
37
|
+
if (value === void 0 || value === null) return void 0;
|
|
38
|
+
if (typeof value.get === "function") return value.get();
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/** human-channel 的内建缺省(与 `Config` 的 schema 缺省**同源**:这里是读取面,那里是解析面) */
|
|
42
|
+
function defaultHumanChannelSettings() {
|
|
43
|
+
return {
|
|
44
|
+
accounts: [],
|
|
45
|
+
subscriptions: [],
|
|
46
|
+
relayCcc: null,
|
|
47
|
+
sendingAllow: ["*"]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** 取"有内容的字符串"(首尾空白剥掉;空白串 ⇒ `undefined`)—— 面板空文本框会写 `''`,那是"没填"不是"填了个空名" */
|
|
51
|
+
function nonEmptyText(value) {
|
|
52
|
+
if (typeof value !== "string") return void 0;
|
|
53
|
+
const trimmed = value.trim();
|
|
54
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `humanChannel` 片段 → 运行时归一形态。**优先级:显式值 > 内建缺省**(与 `simpleSettingsFromConfig` 同族)。
|
|
58
|
+
*
|
|
59
|
+
* 🔴 三处"缺省 vs 显式"的语义差别,别写反:
|
|
60
|
+
* ① `sending.allow: []` ⇒ **`[]`**("谁都不许"),**不是**回退到 `['*']` —— 故用 `??`
|
|
61
|
+
* (只对 `undefined`/`null` 回退)。⚠️ **别拿 `??`→`||` 当变异探针**:空数组在 JS 里是
|
|
62
|
+
* **真值** ⇒ 两种写法在这个输入上**恰好同效**,那是**非变异**(会得出"测试不承重"的假结论)。
|
|
63
|
+
* ② `relay.ccc` 空白 ⇒ `null`("没填"与"没这一项"同义),**不是**把空白当 CCC 名;
|
|
64
|
+
* ③ 账号 `enabled` 缺省 **true**(老账号表里 `enabled` 不写就是开)。
|
|
65
|
+
*
|
|
66
|
+
* 🔴 **旧 CCC 侧 `weixin.*` 不在这里、也不该在这里**:机器级面**只**认 `humanChannel`
|
|
67
|
+
* (硬切无别名,同 D61 先例)⇒ 传进来的旧键**一律不进结构**(回归钉见
|
|
68
|
+
* `tests/human-channel-config.test.ts`;CCC 侧旧读取面的退役在 P0-2~P0-4)。
|
|
69
|
+
* @param fragment - `Config.humanChannel`(可能整个不存在 —— 那是**合法**初始态)
|
|
70
|
+
* @returns 归一形态(永不 `undefined`)
|
|
71
|
+
*/
|
|
72
|
+
function humanChannelSettingsFromConfig(fragment) {
|
|
73
|
+
const d = defaultHumanChannelSettings();
|
|
74
|
+
if (!fragment) return d;
|
|
75
|
+
return {
|
|
76
|
+
accounts: (fragment.accounts ?? []).map((a) => ({
|
|
77
|
+
id: nonEmptyText(a?.id),
|
|
78
|
+
channel: nonEmptyText(a?.channel),
|
|
79
|
+
enabled: a?.enabled !== false,
|
|
80
|
+
token: a?.token,
|
|
81
|
+
userId: a?.userId
|
|
82
|
+
})),
|
|
83
|
+
subscriptions: (fragment.subscriptions ?? []).map((s) => ({
|
|
84
|
+
account: nonEmptyText(s?.account),
|
|
85
|
+
user: nonEmptyText(s?.user),
|
|
86
|
+
ccc: nonEmptyText(s?.ccc),
|
|
87
|
+
role: nonEmptyText(s?.role)
|
|
88
|
+
})),
|
|
89
|
+
relayCcc: nonEmptyText(fragment.relay?.ccc) ?? d.relayCcc,
|
|
90
|
+
sendingAllow: fragment.sending?.allow ?? d.sendingAllow
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Config(宿主 Loader 校验后的解析值)→ 扁平简单配置。**本文件唯一的读取语义**。
|
|
95
|
+
*
|
|
96
|
+
* 优先级:**面板层(扁平键)> 部署层(嵌套段)> 内建缺省**。
|
|
97
|
+
* @param config - 插件 Config(`fiber.config` 或 apply 收到的 config)
|
|
98
|
+
* @returns 扁平开关集合
|
|
99
|
+
*/
|
|
100
|
+
function simpleSettingsFromConfig(config) {
|
|
101
|
+
const d = defaultSimpleSettings();
|
|
102
|
+
return {
|
|
103
|
+
gatewayEnabled: unwrapVolatile(config.gatewayEnabled) ?? config.gateway?.enabled ?? d.gatewayEnabled,
|
|
104
|
+
rebuildThresholdK: unwrapVolatile(config.rebuildThresholdK) ?? config.rebuild?.thresholdK ?? d.rebuildThresholdK,
|
|
105
|
+
croEnabled: unwrapVolatile(config.croEnabled) ?? d.croEnabled,
|
|
106
|
+
diagramEnabled: unwrapVolatile(config.diagramEnabled) ?? config.diagram?.enabled ?? d.diagramEnabled,
|
|
107
|
+
humanChannel: humanChannelSettingsFromConfig(config.humanChannel)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** 运行时源(`registerSettingsSection` 装配:读本插件 fiber 的**当前** Config) */
|
|
111
|
+
let simpleSource = null;
|
|
112
|
+
/**
|
|
113
|
+
* 读取当前简单配置(各功能 gateway/rebuild/轨迹约束/… 的启动与运行时判断都经此)。
|
|
114
|
+
*
|
|
115
|
+
* 源 = 本插件 fiber 的 `config`(宿主在配置变更时走 `fiber.update()` ⇒ `config` 始终最新,
|
|
116
|
+
* **不必**依赖 apply 重跑,也不必缓存)。
|
|
117
|
+
* @returns 扁平开关集合
|
|
118
|
+
*/
|
|
119
|
+
function readSimpleSettings() {
|
|
120
|
+
return simpleSource ? simpleSource() : defaultSimpleSettings();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 装配简单配置读取面(v1.21 分层;**v0.1.7 起不再注册任何 section**)。
|
|
124
|
+
*
|
|
125
|
+
* 两件事:
|
|
126
|
+
* 1. 把"本插件自己的 Config"接成简单配置源 —— 读 `ctx.fiber.config`(宿主 `fiber.update()`
|
|
127
|
+
* 保证最新),拿不到 fiber 时退回 apply 收到的 `config`。
|
|
128
|
+
* 2. 关掉宿主按 Config schema **自动生成**的通用页(`settings.configure({ auto: false })`)——
|
|
129
|
+
* 门面是我们的自定义页 `client/SettingsSection.tsx`(同一个命名空间,同一份数据)。
|
|
130
|
+
*
|
|
131
|
+
* ⚠️ 两个失败都不阻断插件装载(面板是附属能力,绝不能成为启动单点)。
|
|
132
|
+
* @param ctx - 插件上下文
|
|
133
|
+
* @param config - apply 收到的 Config(fiber.config 不可用时的兜底)
|
|
134
|
+
*/
|
|
135
|
+
function registerSettingsSection(ctx, config) {
|
|
136
|
+
const fiber = ctx.fiber;
|
|
137
|
+
const readConfig = () => fiber?.config ?? config;
|
|
138
|
+
simpleSource = () => simpleSettingsFromConfig(readConfig());
|
|
139
|
+
const settings = hostSettings(ctx);
|
|
140
|
+
try {
|
|
141
|
+
settings?.configure?.({ auto: false }, fiber);
|
|
142
|
+
} catch {}
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { readSimpleSettings as n, registerSettingsSection as r, SERENITY_SETTINGS_NS as t };
|