@shgroup/dsh-serenity-hooks 1.108.0 → 1.109.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/dsh.plugin.json +1 -1
- package/lib/client.js +26 -0
- package/lib/index.js +4 -3
- package/lib/{service-xvjwsX3p.js → service-CCzsVeN_.js} +12 -2
- package/lib/{subscriptions-CyrfNpcG.js → subscriptions-DBR99OVm.js} +70 -22
- package/lib/tools/diag/service.d.ts +11 -0
- package/lib/trajectory/subscriptions.d.ts +27 -0
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.109.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——12 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/localstore/container_admin;另两个 im-bridge/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/client.js
CHANGED
|
@@ -4862,6 +4862,32 @@ Instruction-following style:
|
|
|
4862
4862
|
style: { margin: "12px 0 4px" },
|
|
4863
4863
|
children: "投递(实际:发生了没有)"
|
|
4864
4864
|
}),
|
|
4865
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4866
|
+
style: {
|
|
4867
|
+
opacity: .75,
|
|
4868
|
+
fontSize: 12,
|
|
4869
|
+
marginBottom: 4
|
|
4870
|
+
},
|
|
4871
|
+
children: [
|
|
4872
|
+
"机制计数:收到 agent/status ",
|
|
4873
|
+
data.eval.statusEvents,
|
|
4874
|
+
" 次 | running ",
|
|
4875
|
+
data.eval.runningSeen,
|
|
4876
|
+
" / idle",
|
|
4877
|
+
" ",
|
|
4878
|
+
data.eval.idleSeen,
|
|
4879
|
+
" | 判成一轮结束 ",
|
|
4880
|
+
data.eval.turnFinished,
|
|
4881
|
+
Object.keys(data.eval.skips).length > 0 && ` | 跳过 ${Object.entries(data.eval.skips).map(([k, v]) => `${k}=${v}`).join("、")}`
|
|
4882
|
+
]
|
|
4883
|
+
}),
|
|
4884
|
+
data.eval.statusEvents === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4885
|
+
style: {
|
|
4886
|
+
opacity: .7,
|
|
4887
|
+
fontSize: 12
|
|
4888
|
+
},
|
|
4889
|
+
children: "⚠ 一次 agent/status 都没收到 —— 可能此刻没人跑轮次,也可能订阅未装配;两者在读数上同形。"
|
|
4890
|
+
}),
|
|
4865
4891
|
data.deliveries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4866
4892
|
style: { opacity: .7 },
|
|
4867
4893
|
children: "(本进程内还没有任何投递发生 —— 配了但没出现 = 还没触发过,不等于在工作)"
|
package/lib/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { i as sessionsRootDir } from "./cleanup-CPl1SSaK.js";
|
|
|
13
13
|
import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-DY4_DYYY.js";
|
|
14
14
|
import { a as readFeishuCredential, c as readWeixinSettings, d as weixinInboundDir, f as weixinSessionIdForTrajectory, i as matchWeixinRoute, n as extractWeixinText, r as hasVoiceItem, s as readWeixinCredential, t as extractWeixinMedia, u as sanitizeFileName$1 } from "./route-reyv8qcB.js";
|
|
15
15
|
import { i as runImBridge, n as isImWiredTrajectory, r as registerImChannel, t as imChannelIds } from "./channels-Dty_NIl_.js";
|
|
16
|
-
import { n as registerTrajectorySubscriptions, r as
|
|
16
|
+
import { i as subscriptionStats, n as registerTrajectorySubscriptions, r as subscriptionEval, t as defaultSubscriptionDeps } from "./subscriptions-DBR99OVm.js";
|
|
17
17
|
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-CsZ-f64q.js";
|
|
18
18
|
import { a as registerImAccountImpl, i as normalizeAccountChannel, n as getImAccountImpl, r as imAccountChannels } from "./accounts-BHQbakUh.js";
|
|
19
19
|
import { createRequire } from "node:module";
|
|
@@ -569,7 +569,7 @@ async function runKit(root, args, hostCtx) {
|
|
|
569
569
|
}
|
|
570
570
|
case "diag": {
|
|
571
571
|
if (hostCtx === void 0) throw new Error("diag requires the plugin context (live session data unavailable without it)");
|
|
572
|
-
const { runDiag, renderDiag } = await import("./service-
|
|
572
|
+
const { runDiag, renderDiag } = await import("./service-CCzsVeN_.js");
|
|
573
573
|
return renderDiag(await runDiag(hostCtx, root ?? ""));
|
|
574
574
|
}
|
|
575
575
|
default: throw new Error(`Unknown action: ${args.action}`);
|
|
@@ -9547,7 +9547,8 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
9547
9547
|
note: s.note ?? null
|
|
9548
9548
|
})),
|
|
9549
9549
|
problems,
|
|
9550
|
-
deliveries: subscriptionStats()
|
|
9550
|
+
deliveries: subscriptionStats(),
|
|
9551
|
+
eval: subscriptionEval()
|
|
9551
9552
|
});
|
|
9552
9553
|
} catch (err) {
|
|
9553
9554
|
sendJson$2(res, 400, { error: err.message ?? String(err) });
|
|
@@ -3,7 +3,7 @@ import { m as readTrajectorySubscriptions } from "./ccc-BmpE3cQz.js";
|
|
|
3
3
|
import { F as isoLocal, w as sessionEvents } from "./bind-file-B0TuOP89.js";
|
|
4
4
|
import { m as WAKE_CATCH_UP_MS, p as listCroCognitiveTrajectories } from "./scheduler-B0pB9mxI.js";
|
|
5
5
|
import { n as readSimpleSettings } from "./settings-DY4_DYYY.js";
|
|
6
|
-
import {
|
|
6
|
+
import { i as subscriptionStats, r as subscriptionEval } from "./subscriptions-DBR99OVm.js";
|
|
7
7
|
import { containerClocks, containerWakes } from "./observation-BWpkA865.js";
|
|
8
8
|
//#region src/trajectory/live.ts
|
|
9
9
|
/**
|
|
@@ -187,7 +187,8 @@ async function runDiag(ctx, root, nowMs = Date.now()) {
|
|
|
187
187
|
},
|
|
188
188
|
nowMs,
|
|
189
189
|
subscriptions: subscriptionStats(),
|
|
190
|
-
subscriptionProblems: readTrajectorySubscriptions(root).problems
|
|
190
|
+
subscriptionProblems: readTrajectorySubscriptions(root).problems,
|
|
191
|
+
subscriptionEval: subscriptionEval()
|
|
191
192
|
};
|
|
192
193
|
}
|
|
193
194
|
/** 人读渲染一行唤醒条目 */
|
|
@@ -234,6 +235,15 @@ function renderDiag(r) {
|
|
|
234
235
|
}
|
|
235
236
|
lines.push("");
|
|
236
237
|
lines.push(`── ⑤ 轨迹消息订阅(投递读数;只列发生过的投递,配置全表见 serenity.json)──`);
|
|
238
|
+
{
|
|
239
|
+
const e = r.subscriptionEval;
|
|
240
|
+
const skipText = Object.keys(e.skips).length === 0 ? "无" : Object.entries(e.skips).map(([k, v]) => `${k}=${v}`).join(" / ");
|
|
241
|
+
lines.push(`机制计数: 收到 agent/status ${e.statusEvents} 次|running ${e.runningSeen}|idle ${e.idleSeen}|判成一轮结束 ${e.turnFinished}|跳过: ${skipText}`);
|
|
242
|
+
if (e.statusEvents === 0) {
|
|
243
|
+
lines.push(" ⚠ 一次 agent/status 都没收到 ⇒ 要么此刻真的没人在跑轮次,要么订阅未装配。");
|
|
244
|
+
lines.push(" 两者在读数上同形 —— 判\"未装配\"要看宿主日志里有没有「轨迹消息订阅未装配」。");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
237
247
|
if (r.subscriptionProblems.length > 0) {
|
|
238
248
|
lines.push(`⚠ 配置坏项 ${r.subscriptionProblems.length} 条(**配了但不生效**):`);
|
|
239
249
|
for (const p of r.subscriptionProblems) lines.push(` · ${p}`);
|
|
@@ -57,6 +57,34 @@ import { d as registerDisposer } from "./scheduler-B0pB9mxI.js";
|
|
|
57
57
|
* 它有上界(键 = 订阅数),且随插件卸载清空({@link registerTrajectorySubscriptions} 的拆卸)。
|
|
58
58
|
*/
|
|
59
59
|
const stats = /* @__PURE__ */ new Map();
|
|
60
|
+
const evalStats = {
|
|
61
|
+
statusEvents: 0,
|
|
62
|
+
runningSeen: 0,
|
|
63
|
+
idleSeen: 0,
|
|
64
|
+
turnFinished: 0,
|
|
65
|
+
skips: {}
|
|
66
|
+
};
|
|
67
|
+
/** 评估计数快照(诊断/面板读) */
|
|
68
|
+
function subscriptionEval() {
|
|
69
|
+
return {
|
|
70
|
+
...evalStats,
|
|
71
|
+
skips: { ...evalStats.skips }
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function bump(key) {
|
|
75
|
+
evalStats[key] += 1;
|
|
76
|
+
}
|
|
77
|
+
function bumpSkip(reason) {
|
|
78
|
+
evalStats.skips[reason] = (evalStats.skips[reason] ?? 0) + 1;
|
|
79
|
+
}
|
|
80
|
+
/** 测试用:评估计数复位 */
|
|
81
|
+
function __resetSubscriptionEvalForTest() {
|
|
82
|
+
evalStats.statusEvents = 0;
|
|
83
|
+
evalStats.runningSeen = 0;
|
|
84
|
+
evalStats.idleSeen = 0;
|
|
85
|
+
evalStats.turnFinished = 0;
|
|
86
|
+
evalStats.skips = {};
|
|
87
|
+
}
|
|
60
88
|
function statOf(key) {
|
|
61
89
|
const cur = stats.get(key);
|
|
62
90
|
if (cur) return cur;
|
|
@@ -120,30 +148,42 @@ function buildSubscriptionText(memberDir, sub, atMs, iso) {
|
|
|
120
148
|
*/
|
|
121
149
|
async function onTurnFinished(deps, sessionId, nowMs) {
|
|
122
150
|
const root = deps.rootForSession(sessionId);
|
|
123
|
-
if (root === null)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
151
|
+
if (root === null) {
|
|
152
|
+
bumpSkip("no-ccc");
|
|
153
|
+
return {
|
|
154
|
+
skipped: "no-ccc",
|
|
155
|
+
delivered: 0,
|
|
156
|
+
failed: 0
|
|
157
|
+
};
|
|
158
|
+
}
|
|
128
159
|
const { subs, problems } = deps.readSubs(root);
|
|
129
160
|
for (const p of problems) deps.warn(`[serenity-hooks] ✗ 轨迹订阅配置有坏项(${root}):${p}`);
|
|
130
|
-
if (subs.length === 0)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
161
|
+
if (subs.length === 0) {
|
|
162
|
+
bumpSkip("no-subscriptions");
|
|
163
|
+
return {
|
|
164
|
+
skipped: "no-subscriptions",
|
|
165
|
+
delivered: 0,
|
|
166
|
+
failed: 0
|
|
167
|
+
};
|
|
168
|
+
}
|
|
135
169
|
const memberDir = deps.dirForSession(root, sessionId);
|
|
136
|
-
if (memberDir === null)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
170
|
+
if (memberDir === null) {
|
|
171
|
+
bumpSkip("unbound-member");
|
|
172
|
+
return {
|
|
173
|
+
skipped: "unbound-member",
|
|
174
|
+
delivered: 0,
|
|
175
|
+
failed: 0
|
|
176
|
+
};
|
|
177
|
+
}
|
|
141
178
|
const hits = pickSubscriptionsFor(subs, memberDir);
|
|
142
|
-
if (hits.length === 0)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
179
|
+
if (hits.length === 0) {
|
|
180
|
+
bumpSkip("not-in-any-members");
|
|
181
|
+
return {
|
|
182
|
+
skipped: "unbound-member",
|
|
183
|
+
delivered: 0,
|
|
184
|
+
failed: 0
|
|
185
|
+
};
|
|
186
|
+
}
|
|
147
187
|
let delivered = 0;
|
|
148
188
|
let failed = 0;
|
|
149
189
|
for (const sub of hits) {
|
|
@@ -192,11 +232,13 @@ function registerTrajectorySubscriptions(ctx, deps) {
|
|
|
192
232
|
const lastStatus = /* @__PURE__ */ new Map();
|
|
193
233
|
try {
|
|
194
234
|
ctx.on("agent/status", (payload) => {
|
|
235
|
+
bump("statusEvents");
|
|
195
236
|
const p = payload;
|
|
196
237
|
const sessionId = (p?.agent)?.session?.id;
|
|
197
238
|
if (typeof sessionId !== "string" || sessionId === "") return;
|
|
198
239
|
const status = typeof p.status === "string" ? p.status : "";
|
|
199
240
|
if (status === "running") {
|
|
241
|
+
bump("runningSeen");
|
|
200
242
|
lastStatus.set(sessionId, "running");
|
|
201
243
|
return;
|
|
202
244
|
}
|
|
@@ -204,9 +246,14 @@ function registerTrajectorySubscriptions(ctx, deps) {
|
|
|
204
246
|
lastStatus.delete(sessionId);
|
|
205
247
|
return;
|
|
206
248
|
}
|
|
249
|
+
bump("idleSeen");
|
|
207
250
|
const prev = lastStatus.get(sessionId);
|
|
208
251
|
lastStatus.delete(sessionId);
|
|
209
|
-
if (prev !== "running")
|
|
252
|
+
if (prev !== "running") {
|
|
253
|
+
bumpSkip("idle-without-running");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
bump("turnFinished");
|
|
210
257
|
onTurnFinished(deps, sessionId, Date.now()).catch((err) => {
|
|
211
258
|
deps.warn(`[serenity-hooks] ✗ 轨迹订阅处理异常(会话 ${sessionId}):${String(err?.message ?? err)}`);
|
|
212
259
|
});
|
|
@@ -217,6 +264,7 @@ function registerTrajectorySubscriptions(ctx, deps) {
|
|
|
217
264
|
registerDisposer(ctx, "trajectory subscriptions", () => {
|
|
218
265
|
lastStatus.clear();
|
|
219
266
|
stats.clear();
|
|
267
|
+
__resetSubscriptionEvalForTest();
|
|
220
268
|
});
|
|
221
269
|
}
|
|
222
270
|
/**
|
|
@@ -270,4 +318,4 @@ function defaultSubscriptionDeps(ctx) {
|
|
|
270
318
|
};
|
|
271
319
|
}
|
|
272
320
|
//#endregion
|
|
273
|
-
export { registerTrajectorySubscriptions as n,
|
|
321
|
+
export { subscriptionStats as i, registerTrajectorySubscriptions as n, subscriptionEval as r, defaultSubscriptionDeps as t };
|
|
@@ -112,6 +112,17 @@ export interface DiagReport {
|
|
|
112
112
|
}>;
|
|
113
113
|
/** 订阅配置本身的**坏项**(配了但不生效的条目 —— 必须显形,否则用户以为它在工作) */
|
|
114
114
|
subscriptionProblems: string[];
|
|
115
|
+
/**
|
|
116
|
+
* 订阅机制的**评估计数**(v1.108.0):收到多少 `agent/status`、认出多少次一轮结束、各因何跳过。
|
|
117
|
+
* 🔴 它回答的是「**机制在跑吗**」—— 与「送出过东西吗」是两个问题;缺了它两者同形(都是空)。
|
|
118
|
+
*/
|
|
119
|
+
subscriptionEval: {
|
|
120
|
+
statusEvents: number;
|
|
121
|
+
runningSeen: number;
|
|
122
|
+
idleSeen: number;
|
|
123
|
+
turnFinished: number;
|
|
124
|
+
skips: Record<string, number>;
|
|
125
|
+
};
|
|
115
126
|
}
|
|
116
127
|
/**
|
|
117
128
|
* 装配报告(一次调用即全报告)。
|
|
@@ -63,6 +63,33 @@ interface DeliveryStat {
|
|
|
63
63
|
/** 最后一次投递尝试的时刻 */
|
|
64
64
|
lastAt: number | null;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* 评估计数(**"这个机制到底有没有在跑"的唯一读数**,v1.108.0)。
|
|
68
|
+
*
|
|
69
|
+
* 🔴 **为什么必须有它**(我自己在第一版里漏掉了):只有 `stats`(投递计数)时,
|
|
70
|
+
* **「机制没装配」与「装配了但从未命中」在面板上完全同形** —— 两者都是空表。
|
|
71
|
+
* 而那正是本文件头批评过的失败形态("配了但不生效"与"没人干活"分不开)。
|
|
72
|
+
* ⇒ 本计数把**事件流**也记下来:收到多少 `agent/status`、认出多少次 running→idle、
|
|
73
|
+
* 每次因何跳过。有它才能回答「它在跑吗」,而不只是「它送出过东西吗」。
|
|
74
|
+
*
|
|
75
|
+
* ⚠️ 上界:固定字段(不是无界 Map)⇒ 结构上不可能"只增不清"。
|
|
76
|
+
*/
|
|
77
|
+
export interface EvalStats {
|
|
78
|
+
/** 收到的 `agent/status` 事件数(含非 running/idle 的) */
|
|
79
|
+
statusEvents: number;
|
|
80
|
+
/** 其中被认成 running 的 */
|
|
81
|
+
runningSeen: number;
|
|
82
|
+
/** 其中被认成 idle 的 */
|
|
83
|
+
idleSeen: number;
|
|
84
|
+
/** 真被判成「一轮结束」(= 有前置 running 的 idle)的次数 */
|
|
85
|
+
turnFinished: number;
|
|
86
|
+
/** 跳过原因计数(键 = `no-ccc` / `no-subscriptions` / `unbound-member`) */
|
|
87
|
+
skips: Record<string, number>;
|
|
88
|
+
}
|
|
89
|
+
/** 评估计数快照(诊断/面板读) */
|
|
90
|
+
export declare function subscriptionEval(): EvalStats;
|
|
91
|
+
/** 测试用:评估计数复位 */
|
|
92
|
+
export declare function __resetSubscriptionEvalForTest(): void;
|
|
66
93
|
/** 投递统计快照(`dashboard diag` 与测试读;空 = 从未有投递尝试) */
|
|
67
94
|
export declare function subscriptionStats(): Array<{
|
|
68
95
|
key: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.109.0",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:12 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/localstore/container_admin;另两个 im-bridge/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|