@shgroup/dsh-serenity-hooks 1.41.0 → 1.42.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag;后两个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/diag-ops.d.ts
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* ① live 运行态 —— 插件进程内 `diagLive(ctx)`(进程 cwd/CCC + live 会话清单)
|
|
12
12
|
* ——**独立进程看不到运行时**,这正是本工具存在的理由
|
|
13
13
|
* ①b 唤醒时钟 —— `containerClocks().wake`(唤醒调度器进程内快照:武装态/计数/上次跳过原因)
|
|
14
|
-
* ③ 唤醒注册表 —— `wake-registry.json`
|
|
14
|
+
* ③ 唤醒注册表 —— `wake-registry.json` 的**在办条目**(state / at / target / lastResult)+ 补跑窗口
|
|
15
|
+
* (🔴 2026-09-19 §0Q 甲案:终态条目**结案即清除** ⇒ 本段只列在办项,不再是"历史全量";
|
|
16
|
+
* 历史由 SESSION.md / 工具输出承担——该承诺原本就写在 `wake-registry.ts` 注释里,本次做实)
|
|
15
17
|
*
|
|
16
18
|
* ── 2026-09-15:段数由四降为三(S142「ACC 侧 autopilot 退场」§1 二阶裁定)─────────────
|
|
17
19
|
* ACC 侧 autopilot 整段退场后,报告里两段的**主语消失**,故删除(不是"暂时关掉"):
|
package/lib/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPE
|
|
|
7
7
|
import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-CEHL5cek.js";
|
|
8
8
|
import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-FTjoWQTQ.js";
|
|
9
9
|
import { r as sessionsRootDir, t as hasSessionLogById } from "./session-cleanup-BtkSmry8.js";
|
|
10
|
-
import { a as WAKE_CATCH_UP_MS, i as registerDisposer, n as sendToTrajectory, o as addWake, r as wakeSchedulerState, s as listWakes, t as registerWakeScheduler } from "./wake-scheduler-
|
|
10
|
+
import { a as WAKE_CATCH_UP_MS, i as registerDisposer, n as sendToTrajectory, o as addWake, r as wakeSchedulerState, s as listWakes, t as registerWakeScheduler } from "./wake-scheduler-1AsvNQPW.js";
|
|
11
11
|
import { a as FACE_PORTS, c as MECHANISM_PORTS, i as ACP_HTTP_PORT, l as SKIFF_DEBUG_PORT, n as registerSettingsSection, o as GATEWAY_PORT, s as MAIN_WEB_PORT, t as readSimpleSettings, u as WEIXIN_SEND_PORT } from "./settings-section-DMDUoQum.js";
|
|
12
12
|
import { a as markdownToPlainText, c as sendTyping, i as getUpdates, l as sniffImageExt, n as downloadMedia, o as sendFileMessage, r as getConfig, s as sendTextMessage, t as TypingStatus } from "./weixin-api-CtFYm53S.js";
|
|
13
13
|
import z from "@deepseek-ai/schemastery";
|
|
@@ -14557,7 +14557,9 @@ function containerStatus(opts = {}) {
|
|
|
14557
14557
|
* ① live 运行态 —— 插件进程内 `diagLive(ctx)`(进程 cwd/CCC + live 会话清单)
|
|
14558
14558
|
* ——**独立进程看不到运行时**,这正是本工具存在的理由
|
|
14559
14559
|
* ①b 唤醒时钟 —— `containerClocks().wake`(唤醒调度器进程内快照:武装态/计数/上次跳过原因)
|
|
14560
|
-
* ③ 唤醒注册表 —— `wake-registry.json`
|
|
14560
|
+
* ③ 唤醒注册表 —— `wake-registry.json` 的**在办条目**(state / at / target / lastResult)+ 补跑窗口
|
|
14561
|
+
* (🔴 2026-09-19 §0Q 甲案:终态条目**结案即清除** ⇒ 本段只列在办项,不再是"历史全量";
|
|
14562
|
+
* 历史由 SESSION.md / 工具输出承担——该承诺原本就写在 `wake-registry.ts` 注释里,本次做实)
|
|
14561
14563
|
*
|
|
14562
14564
|
* ── 2026-09-15:段数由四降为三(S142「ACC 侧 autopilot 退场」§1 二阶裁定)─────────────
|
|
14563
14565
|
* ACC 侧 autopilot 整段退场后,报告里两段的**主语消失**,故删除(不是"暂时关掉"):
|
|
@@ -14632,10 +14634,11 @@ function renderAccDiag(r) {
|
|
|
14632
14634
|
lines.push("");
|
|
14633
14635
|
lines.push(renderClock("唤醒调度器(wake-registry tick)", r.clocks.wake));
|
|
14634
14636
|
lines.push("");
|
|
14635
|
-
lines.push(`── ③
|
|
14637
|
+
lines.push(`── ③ 唤醒注册表(在办项;已结案条目即时清除,历史见 SESSION.md)──`);
|
|
14638
|
+
lines.push(` (${r.ccc}/AGENT_SESSIONS/wake-registry.json)`);
|
|
14636
14639
|
if (r.wakes.error) lines.push(`⚠ 注册表读取问题: ${r.wakes.error}`);
|
|
14637
14640
|
lines.push(`条目: ${r.wakes.entries.length} 条(在办 ${r.wakes.pending})|补跑窗口 ${WAKE_CATCH_UP_MS / 36e5}h`);
|
|
14638
|
-
if (r.wakes.entries.length === 0) lines.push("
|
|
14641
|
+
if (r.wakes.entries.length === 0) lines.push("(无在办条目)");
|
|
14639
14642
|
for (const w of r.wakes.entries) {
|
|
14640
14643
|
lines.push(` · ${w.id} [${w.state}] at=${w.at} → ${w.target} by=${w.createdBy} attempts=${w.attempts}`);
|
|
14641
14644
|
if (w.lastResult) lines.push(` lastResult: ${w.lastResult}`);
|
package/lib/wake-registry.d.ts
CHANGED
|
@@ -118,8 +118,61 @@ export declare function splitDueWakes(registry: WakeRegistry, nowMs: number, cat
|
|
|
118
118
|
due: WakeEntry[];
|
|
119
119
|
expired: WakeEntry[];
|
|
120
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* 🔴 结案并**移除**一条(owner 2026-09-19 裁定「**直接删**」,S142 §0Q 甲案)。
|
|
123
|
+
*
|
|
124
|
+
* ## 为什么删(R↓)
|
|
125
|
+
*
|
|
126
|
+
* 本模块原本是「`pending` → 终态」但**终态条目永不移除** ⇒ 文件**只增**(实测 308 KB / 143+ 条)。
|
|
127
|
+
* owner 明令「应当**唤醒后就清理**的」⇒ 终态即删。
|
|
128
|
+
*
|
|
129
|
+
* **审计不丢**:由 **SESSION.md 与工具输出**承担——这正是本文件 `removeWake` 的既有注释承诺
|
|
130
|
+
* (*"审计由 SESSION.md 与工具输出承担——注册表只保留在办项"*)。
|
|
131
|
+
* ⚠️ 此前该承诺**并未兑现**(`updateWake` 只改 state 从不删行)⇒ 本次是**把承诺做实**。
|
|
132
|
+
*
|
|
133
|
+
* ## 与 `updateWake` 的分工(**别混用**)
|
|
134
|
+
*
|
|
135
|
+
* - `updateWake`:**仍在办**的推进(失败重试 `state:'pending'` + `attempts+1`)⇒ **保留行**;
|
|
136
|
+
* - `finalizeWake`:**不再办**的归宿(投递成功 / 超窗 missed)⇒ 写终态后**同一笔事务里删掉**。
|
|
137
|
+
*
|
|
138
|
+
* 🔴 **为什么两个动作要同一次写盘**:若先 `updateWake(delivered)` 再 `removeWake`,
|
|
139
|
+
* 中间被打断会留下一条"已终结但没删"的条目 ⇒ 又回到只增。
|
|
140
|
+
* 故本函数**读一次、改一次、删一次、写一次**(单次原子落盘)。
|
|
141
|
+
*
|
|
142
|
+
* @param root CCC 根
|
|
143
|
+
* @param id 条目 id
|
|
144
|
+
* @param terminal 终态(`delivered` / `missed` / `cancelled`)——写入仅用于**日志文案**,
|
|
145
|
+
* 随即整行移除;保留该参数是为了让调用点语义自明("它归到哪一档了")。
|
|
146
|
+
* @param result 人读结果(进日志,不进表)
|
|
147
|
+
* @returns `removed` = 被移除的条目(供调用方打印"它是什么");不存在 → 稳定错误码
|
|
148
|
+
*/
|
|
149
|
+
export declare function finalizeWake(root: string, id: string, terminal: 'delivered' | 'missed' | 'cancelled', result: string): {
|
|
150
|
+
ok: boolean;
|
|
151
|
+
error: string | null;
|
|
152
|
+
removed: WakeEntry | null;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* 一次性清除**存量终态条目**(`delivered` / `missed` / `cancelled`)。
|
|
156
|
+
*
|
|
157
|
+
* ## 为什么需要(不是可选)
|
|
158
|
+
*
|
|
159
|
+
* 本函数上线前,表里已积压 143+ 条终态记录(308 KB)⇒ **只改行为不改存量 = 文件不再涨但仍很大**。
|
|
160
|
+
* 故首次运行须清一次。**幂等**(无终态条目时空转,不写盘)。
|
|
161
|
+
*
|
|
162
|
+
* 审计不丢:与 `finalizeWake` 同理(终态本就属性"已结案",其史由 SESSION.md 承担)。
|
|
163
|
+
* @param root CCC 根
|
|
164
|
+
* @returns 清掉几条(0 = 本来就没有)
|
|
165
|
+
*/
|
|
166
|
+
export declare function purgeFinalizedWakes(root: string): {
|
|
167
|
+
ok: boolean;
|
|
168
|
+
error: string | null;
|
|
169
|
+
purged: number;
|
|
170
|
+
};
|
|
121
171
|
/**
|
|
122
172
|
* 更新一条(状态推进;调用方给最终状态与结果文案)。
|
|
173
|
+
*
|
|
174
|
+
* ⚠️ **只用于"仍在办"的推进**(主要是失败重试)。**终态请用 `finalizeWake`**——
|
|
175
|
+
* 否则该行会永远留下(这正是本表过去只增的根因,见 `finalizeWake` 注释)。
|
|
123
176
|
* @param root CCC 根
|
|
124
177
|
* @param id 条目 id
|
|
125
178
|
* @param patch 要写入的字段
|
|
@@ -230,7 +230,109 @@ function splitDueWakes(registry, nowMs, catchUpMs = WAKE_CATCH_UP_MS) {
|
|
|
230
230
|
};
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
|
+
* 🔴 结案并**移除**一条(owner 2026-09-19 裁定「**直接删**」,S142 §0Q 甲案)。
|
|
234
|
+
*
|
|
235
|
+
* ## 为什么删(R↓)
|
|
236
|
+
*
|
|
237
|
+
* 本模块原本是「`pending` → 终态」但**终态条目永不移除** ⇒ 文件**只增**(实测 308 KB / 143+ 条)。
|
|
238
|
+
* owner 明令「应当**唤醒后就清理**的」⇒ 终态即删。
|
|
239
|
+
*
|
|
240
|
+
* **审计不丢**:由 **SESSION.md 与工具输出**承担——这正是本文件 `removeWake` 的既有注释承诺
|
|
241
|
+
* (*"审计由 SESSION.md 与工具输出承担——注册表只保留在办项"*)。
|
|
242
|
+
* ⚠️ 此前该承诺**并未兑现**(`updateWake` 只改 state 从不删行)⇒ 本次是**把承诺做实**。
|
|
243
|
+
*
|
|
244
|
+
* ## 与 `updateWake` 的分工(**别混用**)
|
|
245
|
+
*
|
|
246
|
+
* - `updateWake`:**仍在办**的推进(失败重试 `state:'pending'` + `attempts+1`)⇒ **保留行**;
|
|
247
|
+
* - `finalizeWake`:**不再办**的归宿(投递成功 / 超窗 missed)⇒ 写终态后**同一笔事务里删掉**。
|
|
248
|
+
*
|
|
249
|
+
* 🔴 **为什么两个动作要同一次写盘**:若先 `updateWake(delivered)` 再 `removeWake`,
|
|
250
|
+
* 中间被打断会留下一条"已终结但没删"的条目 ⇒ 又回到只增。
|
|
251
|
+
* 故本函数**读一次、改一次、删一次、写一次**(单次原子落盘)。
|
|
252
|
+
*
|
|
253
|
+
* @param root CCC 根
|
|
254
|
+
* @param id 条目 id
|
|
255
|
+
* @param terminal 终态(`delivered` / `missed` / `cancelled`)——写入仅用于**日志文案**,
|
|
256
|
+
* 随即整行移除;保留该参数是为了让调用点语义自明("它归到哪一档了")。
|
|
257
|
+
* @param result 人读结果(进日志,不进表)
|
|
258
|
+
* @returns `removed` = 被移除的条目(供调用方打印"它是什么");不存在 → 稳定错误码
|
|
259
|
+
*/
|
|
260
|
+
function finalizeWake(root, id, terminal, result) {
|
|
261
|
+
const { registry, error } = loadWakeRegistry(root);
|
|
262
|
+
if (error) return {
|
|
263
|
+
ok: false,
|
|
264
|
+
error,
|
|
265
|
+
removed: null
|
|
266
|
+
};
|
|
267
|
+
const idx = registry.entries.findIndex((e) => e.id === id);
|
|
268
|
+
if (idx < 0) return {
|
|
269
|
+
ok: false,
|
|
270
|
+
error: `wake_not_found: ${id}`,
|
|
271
|
+
removed: null
|
|
272
|
+
};
|
|
273
|
+
const [removed] = registry.entries.splice(idx, 1);
|
|
274
|
+
const saved = saveWakeRegistry(root, registry);
|
|
275
|
+
if (!saved.ok) return {
|
|
276
|
+
ok: false,
|
|
277
|
+
error: saved.error,
|
|
278
|
+
removed: null
|
|
279
|
+
};
|
|
280
|
+
return {
|
|
281
|
+
ok: true,
|
|
282
|
+
error: null,
|
|
283
|
+
removed: {
|
|
284
|
+
...removed,
|
|
285
|
+
state: terminal,
|
|
286
|
+
lastResult: result
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 一次性清除**存量终态条目**(`delivered` / `missed` / `cancelled`)。
|
|
292
|
+
*
|
|
293
|
+
* ## 为什么需要(不是可选)
|
|
294
|
+
*
|
|
295
|
+
* 本函数上线前,表里已积压 143+ 条终态记录(308 KB)⇒ **只改行为不改存量 = 文件不再涨但仍很大**。
|
|
296
|
+
* 故首次运行须清一次。**幂等**(无终态条目时空转,不写盘)。
|
|
297
|
+
*
|
|
298
|
+
* 审计不丢:与 `finalizeWake` 同理(终态本就属性"已结案",其史由 SESSION.md 承担)。
|
|
299
|
+
* @param root CCC 根
|
|
300
|
+
* @returns 清掉几条(0 = 本来就没有)
|
|
301
|
+
*/
|
|
302
|
+
function purgeFinalizedWakes(root) {
|
|
303
|
+
const { registry, error } = loadWakeRegistry(root);
|
|
304
|
+
if (error) return {
|
|
305
|
+
ok: false,
|
|
306
|
+
error,
|
|
307
|
+
purged: 0
|
|
308
|
+
};
|
|
309
|
+
const kept = registry.entries.filter((e) => e.state === "pending");
|
|
310
|
+
const purged = registry.entries.length - kept.length;
|
|
311
|
+
if (purged === 0) return {
|
|
312
|
+
ok: true,
|
|
313
|
+
error: null,
|
|
314
|
+
purged: 0
|
|
315
|
+
};
|
|
316
|
+
const saved = saveWakeRegistry(root, {
|
|
317
|
+
...registry,
|
|
318
|
+
entries: kept
|
|
319
|
+
});
|
|
320
|
+
if (!saved.ok) return {
|
|
321
|
+
ok: false,
|
|
322
|
+
error: saved.error,
|
|
323
|
+
purged: 0
|
|
324
|
+
};
|
|
325
|
+
return {
|
|
326
|
+
ok: true,
|
|
327
|
+
error: null,
|
|
328
|
+
purged
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
233
332
|
* 更新一条(状态推进;调用方给最终状态与结果文案)。
|
|
333
|
+
*
|
|
334
|
+
* ⚠️ **只用于"仍在办"的推进**(主要是失败重试)。**终态请用 `finalizeWake`**——
|
|
335
|
+
* 否则该行会永远留下(这正是本表过去只增的根因,见 `finalizeWake` 注释)。
|
|
234
336
|
* @param root CCC 根
|
|
235
337
|
* @param id 条目 id
|
|
236
338
|
* @param patch 要写入的字段
|
|
@@ -801,6 +903,8 @@ async function runWakeTick(ctx) {
|
|
|
801
903
|
}
|
|
802
904
|
clock.noteSkipReason(null);
|
|
803
905
|
for (const root of roots) {
|
|
906
|
+
const purged = purgeFinalizedWakes(root);
|
|
907
|
+
if (purged.ok && purged.purged > 0) log.push(`· ${root}: 清除 ${purged.purged} 条已结案记录(存量首清)`);
|
|
804
908
|
const { registry, error } = loadWakeRegistry(root);
|
|
805
909
|
if (error) {
|
|
806
910
|
log.push(`✗ ${root}: ${error}`);
|
|
@@ -808,11 +912,8 @@ async function runWakeTick(ctx) {
|
|
|
808
912
|
}
|
|
809
913
|
const { due, expired } = splitDueWakes(registry, Date.now(), WAKE_CATCH_UP_MS);
|
|
810
914
|
for (const e of expired) {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
lastResult: `超过补跑窗口(${WAKE_CATCH_UP_MS / 36e5}h)未投递`
|
|
814
|
-
});
|
|
815
|
-
log.push(`· ${root}: ${e.id} → missed(超补跑窗口)`);
|
|
915
|
+
finalizeWake(root, e.id, "missed", `超过补跑窗口(${WAKE_CATCH_UP_MS / 36e5}h)未投递`);
|
|
916
|
+
log.push(`· ${root}: ${e.id} → missed(超补跑窗口,已清除)`);
|
|
816
917
|
}
|
|
817
918
|
for (const e of due) {
|
|
818
919
|
const res = await deliverWake(ctx, root, e);
|
|
@@ -820,13 +921,17 @@ async function runWakeTick(ctx) {
|
|
|
820
921
|
log.push(`· ${root}: ${e.id} → 跳过(宿主服务未就绪,下个 tick 再试;不计失败)`);
|
|
821
922
|
continue;
|
|
822
923
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
924
|
+
if (res.ok) {
|
|
925
|
+
finalizeWake(root, e.id, "delivered", res.detail);
|
|
926
|
+
log.push(`· ${root}: ${e.id} → delivered(已清除)`);
|
|
927
|
+
} else {
|
|
928
|
+
updateWake(root, e.id, {
|
|
929
|
+
state: "pending",
|
|
930
|
+
attempts: e.attempts + 1,
|
|
931
|
+
lastResult: res.detail
|
|
932
|
+
});
|
|
933
|
+
log.push(`· ${root}: ${e.id} → 重试(${res.detail})`);
|
|
934
|
+
}
|
|
830
935
|
}
|
|
831
936
|
}
|
|
832
937
|
return log;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.0",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|