@shgroup/dsh-serenity-hooks 1.48.2 → 1.49.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 +3 -9
- package/lib/index.d.ts +0 -6
- package/lib/index.js +87 -22
- package/lib/seams/keeper.d.ts +51 -3
- package/lib/{settings-section-DxMwlCv9.js → settings-section-B-KOyOYn.js} +0 -2
- package/lib/settings-section.d.ts +0 -4
- package/lib/trajectory-assistant.d.ts +20 -7
- 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.49.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/client.js
CHANGED
|
@@ -4741,7 +4741,7 @@ Instruction-following style:
|
|
|
4741
4741
|
})
|
|
4742
4742
|
]
|
|
4743
4743
|
}),
|
|
4744
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4744
|
+
control !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4745
4745
|
className: "ss-rowControl",
|
|
4746
4746
|
children: control
|
|
4747
4747
|
}),
|
|
@@ -4804,7 +4804,6 @@ Instruction-following style:
|
|
|
4804
4804
|
set("acpHttpPort", Math.min(65535, Math.max(1024, Math.round(v))));
|
|
4805
4805
|
};
|
|
4806
4806
|
const gatewayOn = value?.gatewayEnabled ?? false;
|
|
4807
|
-
const rebuildOn = value?.rebuildEnabled ?? true;
|
|
4808
4807
|
const thresholdK = value?.rebuildThresholdK ?? 400;
|
|
4809
4808
|
const skiffOn = value?.skiffEnabled ?? false;
|
|
4810
4809
|
const skiffPort = value?.skiffDebugPort ?? 3099;
|
|
@@ -4862,19 +4861,15 @@ Instruction-following style:
|
|
|
4862
4861
|
open: openRebuild,
|
|
4863
4862
|
onToggle: setOpenRebuild,
|
|
4864
4863
|
expandHint: "配置",
|
|
4865
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4866
|
-
checked: rebuildOn,
|
|
4867
|
-
onChange: (on) => toggle("rebuildEnabled", on)
|
|
4868
|
-
}),
|
|
4869
4864
|
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4870
4865
|
className: "ss-detailStack",
|
|
4871
4866
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4872
4867
|
className: "ss-detailIntro",
|
|
4873
|
-
children: "上下文超限自动重建(container_trajectory rebuild,v1.33 起 logbook 并入 trajectory):\n· 机制:agent 上下文占用达到阈值时,由 LLM 主动调用重建\n· 语义:完全丢弃当前 dsh 会话 + 自动新建 + 注入「继续原 SESSION 的工作」\n· 效果:SESSION.md 原位不动,认知轨迹延续,上下文归零\n·
|
|
4868
|
+
children: "上下文超限自动重建(container_trajectory rebuild,v1.33 起 logbook 并入 trajectory):\n· 机制:agent 上下文占用达到阈值时,由 LLM 主动调用重建\n· 语义:完全丢弃当前 dsh 会话 + 自动新建 + 注入「继续原 SESSION 的工作」\n· 效果:SESSION.md 原位不动,认知轨迹延续,上下文归零\n· 无总开关(v1.49.0 砍掉):长期验证下它已能很好地代替上下文压缩;\n 要调敏感度就改下面的阈值"
|
|
4874
4869
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4875
4870
|
title: "重建阈值",
|
|
4876
4871
|
desc: "上下文占用达到该 K 数值时提示(单位 K token,默认 400)",
|
|
4877
|
-
help: "重建触发阈值(需求①:K 数值,默认 400K,范围 50~4000K):\n· 含义:上下文 projected tokens 达到 thresholdK × 1000 时触发提醒\n· 纯绝对数值(不再依赖窗口比例)\n· 迁移:旧版 0~1 比例(settings.yaml rebuildThreshold)已废弃被忽略\n· 调低更早触发 /
|
|
4872
|
+
help: "重建触发阈值(需求①:K 数值,默认 400K,范围 50~4000K):\n· 含义:上下文 projected tokens 达到 thresholdK × 1000 时触发提醒\n· 纯绝对数值(不再依赖窗口比例)\n· 迁移:旧版 0~1 比例(settings.yaml rebuildThreshold)已废弃被忽略\n· 调低更早触发 / 调高更晚触发(v1.49.0 起无总开关,它恒生效)",
|
|
4878
4873
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4879
4874
|
className: "ss-portInput",
|
|
4880
4875
|
type: "number",
|
|
@@ -4882,7 +4877,6 @@ Instruction-following style:
|
|
|
4882
4877
|
max: 4e3,
|
|
4883
4878
|
step: 50,
|
|
4884
4879
|
value: thresholdK,
|
|
4885
|
-
disabled: !rebuildOn,
|
|
4886
4880
|
title: "重建阈值(K token,默认 400)",
|
|
4887
4881
|
onChange: (e) => setThreshold(Number(e.target.value))
|
|
4888
4882
|
})
|
package/lib/index.d.ts
CHANGED
|
@@ -121,10 +121,8 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
121
121
|
enabled: z<boolean, boolean, "defined">;
|
|
122
122
|
}>>, "plain">;
|
|
123
123
|
rebuild: z<Schemastery.ObjectS<NoInfer<{
|
|
124
|
-
enabled: z<boolean, boolean, "defined">;
|
|
125
124
|
thresholdK: z<number, number, "defined">;
|
|
126
125
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
127
|
-
enabled: z<boolean, boolean, "defined">;
|
|
128
126
|
thresholdK: z<number, number, "defined">;
|
|
129
127
|
}>>, "plain">;
|
|
130
128
|
skiff: z<Schemastery.ObjectS<NoInfer<{
|
|
@@ -157,7 +155,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
157
155
|
enabled: z<boolean, boolean, "defined">;
|
|
158
156
|
}>>, "plain">;
|
|
159
157
|
gatewayEnabled: z<boolean, boolean, "volatile">;
|
|
160
|
-
rebuildEnabled: z<boolean, boolean, "volatile">;
|
|
161
158
|
rebuildThresholdK: z<number, number, "volatile">;
|
|
162
159
|
skiffEnabled: z<boolean, boolean, "volatile">;
|
|
163
160
|
skiffDebugPort: z<number, number, "volatile">;
|
|
@@ -184,10 +181,8 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
184
181
|
enabled: z<boolean, boolean, "defined">;
|
|
185
182
|
}>>, "plain">;
|
|
186
183
|
rebuild: z<Schemastery.ObjectS<NoInfer<{
|
|
187
|
-
enabled: z<boolean, boolean, "defined">;
|
|
188
184
|
thresholdK: z<number, number, "defined">;
|
|
189
185
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
190
|
-
enabled: z<boolean, boolean, "defined">;
|
|
191
186
|
thresholdK: z<number, number, "defined">;
|
|
192
187
|
}>>, "plain">;
|
|
193
188
|
skiff: z<Schemastery.ObjectS<NoInfer<{
|
|
@@ -220,7 +215,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
220
215
|
enabled: z<boolean, boolean, "defined">;
|
|
221
216
|
}>>, "plain">;
|
|
222
217
|
gatewayEnabled: z<boolean, boolean, "volatile">;
|
|
223
|
-
rebuildEnabled: z<boolean, boolean, "volatile">;
|
|
224
218
|
rebuildThresholdK: z<number, number, "volatile">;
|
|
225
219
|
skiffEnabled: z<boolean, boolean, "volatile">;
|
|
226
220
|
skiffDebugPort: z<number, number, "volatile">;
|
package/lib/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { A as localIdStamp, C as setActiveSessionInfo, D as isoLocal, E as useSe
|
|
|
6
6
|
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-CWMRa36W.js";
|
|
7
7
|
import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, o as ACC_VERSION, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-BjIX_KD1.js";
|
|
8
8
|
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-KqQA6pkr.js";
|
|
9
|
-
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-
|
|
9
|
+
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-B-KOyOYn.js";
|
|
10
10
|
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";
|
|
11
11
|
import z from "@deepseek-ai/schemastery";
|
|
12
12
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
@@ -9235,7 +9235,12 @@ const EVENT_LABEL = {
|
|
|
9235
9235
|
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
9236
9236
|
guard: "BOUNDARY GUARD",
|
|
9237
9237
|
/** SESSION.md 体积超限重写提醒(v1.31.1,S142 用户需求) */
|
|
9238
|
-
compaction: "LOGBOOK COMPACTION"
|
|
9238
|
+
compaction: "LOGBOOK COMPACTION",
|
|
9239
|
+
/** **交界便签(REBUILD-TODO.md)体积超限清理提醒**(v1.49.0,owner 2026-09-26 需求)。
|
|
9240
|
+
*
|
|
9241
|
+
* 🔴 **刻意与 `compaction` 分开**:那条要求"**重写 SESSION.md 并保留 EAP 骨架**",
|
|
9242
|
+
* 本条只要求"**清理便签**"——共用一个 token 会让模型误以为要动 SESSION.md。 */
|
|
9243
|
+
scratchPrune: "SCRATCH PRUNE"
|
|
9239
9244
|
};
|
|
9240
9245
|
/** 家族标识(所有动态注入统一前缀) */
|
|
9241
9246
|
const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
@@ -9246,16 +9251,24 @@ function eventToken(event) {
|
|
|
9246
9251
|
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
9247
9252
|
const ACK_PREFIX = `${ASSISTANT_PREFIX}-recorded`;
|
|
9248
9253
|
/**
|
|
9249
|
-
* rebuild
|
|
9254
|
+
* rebuild 交界便签的**文件名**(v1.49.0;owner 2026-09-26 需求)。
|
|
9255
|
+
*
|
|
9256
|
+
* ## 它取代了什么(owner 原话:*"砍掉 in-flight,这正是目的"*)
|
|
9257
|
+
* v1.31.1 的交界协议要求把手头事项写进 **SESSION.md 末尾**的 `## In-flight (rebuild handover)` 段。
|
|
9258
|
+
* 实测的代价(S142 自身取证):In-flight 段曾积 **12 块**(含多份**已被取代**的交接),
|
|
9259
|
+
* 而 SESSION.md 是**有格式义务**的持久文件(7 段固定 + 粒度受 EAP 约束)⇒
|
|
9260
|
+
* ① 持久文件被临时物污染 ② 每次整理都要付"压缩+归档+保真"三件套(该文件曾达 292 KB)。
|
|
9261
|
+
*
|
|
9262
|
+
* ⇒ 分家:**只用一次的交界材料**写进这份**临时便签**(无格式义务、无留档义务、可随时丢弃)。
|
|
9250
9263
|
*
|
|
9251
|
-
*
|
|
9252
|
-
* rebuild
|
|
9253
|
-
*
|
|
9264
|
+
* ## 🔴 三处引用同一常量(单一真相源)
|
|
9265
|
+
* **写侧** = `seams/keeper.ts` 的 `rebuildReminderText()`|**读侧** = `rebuild.ts` 的重建锚点|
|
|
9266
|
+
* **体积提醒** = `seams/keeper.ts` 的 `rebuildTodoReminderText()`。
|
|
9267
|
+
* 文件名一旦漂移,写侧写的东西读侧就找不到 —— **且没有任何机械信号会报警**。
|
|
9254
9268
|
*
|
|
9255
|
-
*
|
|
9256
|
-
* 因为 SESSION.md 的正文语言归 CCC,但两侧的**机械锚点**必须逐字一致。
|
|
9269
|
+
* 🔴 **不得改名**(owner 已具名)。形态 = **固定文件名**(人读友好;比照旧 IN_FLIGHT_HEADING 的取舍)。
|
|
9257
9270
|
*/
|
|
9258
|
-
const
|
|
9271
|
+
const REBUILD_TODO_FILENAME = "REBUILD-TODO.md";
|
|
9259
9272
|
//#endregion
|
|
9260
9273
|
//#region src/seams/keeper.ts
|
|
9261
9274
|
const SCORES = {
|
|
@@ -9328,12 +9341,15 @@ function reminderText(code) {
|
|
|
9328
9341
|
* 使用者若要查看当前占用/阈值:看面板(`rebuildThresholdK` 滑块 + 状态显示)——那是给人看的。
|
|
9329
9342
|
*
|
|
9330
9343
|
* v1.31.1 交接协议(S142 用户需求"要求 LLM 将当前手头事项写在 SESSION.md 尾部,并要求
|
|
9331
|
-
* rebuild 后去读并处理"):**写侧** =
|
|
9332
|
-
*
|
|
9333
|
-
*
|
|
9344
|
+
* rebuild 后去读并处理"):**写侧** = 这里;**读侧** = rebuild 锚点(rebuild.ts)。
|
|
9345
|
+
* 两侧共用 trajectory-assistant 的常量(单一真相源)。
|
|
9346
|
+
*
|
|
9347
|
+
* 🔴 **v1.49.0(owner 2026-09-26 裁决:"砍掉 in-flight,这正是目的")**:写侧**不再**指向
|
|
9348
|
+
* SESSION.md 末尾的段,改指**独立便签文件** `REBUILD-TODO_FILENAME`(轨迹目录下)——
|
|
9349
|
+
* 理由见该常量的头注(持久文件 vs 只用一次的交界材料必须分家)。
|
|
9334
9350
|
*/
|
|
9335
9351
|
function rebuildReminderText(escalated = false) {
|
|
9336
|
-
const handover = ` Before rebuilding, write your current in-flight items (the exact step you are in the middle of, what is not finished yet, and what the next action is)
|
|
9352
|
+
const handover = ` Before rebuilding, write your current in-flight items (the exact step you are in the middle of, what is not finished yet, and what the next action is) into "${REBUILD_TODO_FILENAME}" in this trajectory's directory — create it if it does not exist. That file is a scratch note for the handover only: no format obligation, no archival duty, safe to discard at any time. The rebuilt conversation reads it first and continues from it.`;
|
|
9337
9353
|
if (escalated) return `${eventToken("limitMandatory")} Context usage has reached the configured rebuild threshold — you have been reminded repeatedly and have NOT called the container_trajectory rebuild action. This is now mandatory: STOP at the current task step, preserve valuable cognition into the CCC skills (or write a new-skill proposal into SESSION.md), then call container_trajectory rebuild immediately, passing --summary "<content summary ≤20 chars>" (required; the dsh session title is renamed to S###-YYYY-MM-DD-<summary> after rebuild).${handover} The conversation will be cleared and rebuilt in place; SESSION.md is the persistent trajectory and stays in place — identity continues from it. Do not continue working without rebuilding; this reminder persists until you call container_trajectory rebuild.`;
|
|
9338
9354
|
return `${eventToken("limit")} Context usage has reached the configured rebuild threshold. This session is the rebuildable carrier of the trajectory: SESSION.md is the persistent body, this conversation is only a temporary work copy. Before rebuilding: if this conversation produced valuable cognition, revise the relevant existing skill of this CCC (structure it with eap); if a new skill is warranted, write a short proposal into SESSION.md for the user to review — do not create it yourself.${handover} ACT NOW: at the next natural pause (end of the current task step), call the container_trajectory rebuild action — passing --summary "<content summary ≤20 chars>" describing the next work phase (required; the dsh session title is renamed to S###-YYYY-MM-DD-<summary> after rebuild) — to clear and rebuild this conversation: the current copy is discarded, identity continues from SESSION.md. If you are in the middle of an unbreakable step, continue it, then rebuild at its end. Do not ignore this; rebuild is the expected action, not an option.`;
|
|
9339
9355
|
}
|
|
@@ -9443,6 +9459,37 @@ function trajectoryCompactionReminderText(input) {
|
|
|
9443
9459
|
if (escalated) return `${eventToken("compaction")} ${facts} — you have been reminded repeatedly and have NOT compacted SESSION.md. This is now mandatory: STOP the current task step, load eap (praxis eap), rewrite SESSION.md, then resume. ${principles} ${frontmatterGuard} This reminder persists until the file is under the limit.`;
|
|
9444
9460
|
return `${eventToken("compaction")} ${facts}. Pause the current work and compact this trajectory's log (SESSION.md) before continuing — that log is the persistent body of this trajectory, and its size is operational entropy (H_op) the container pays on every read. ${principles} ${frontmatterGuard} After rewriting, resume the paused work; this reminder stops once the file is under the limit.`;
|
|
9445
9461
|
}
|
|
9462
|
+
/** 连续超限轮数达此值 → 语气升级(对齐 COMPACTION_ESCALATE_AFTER / REBUILD_ESCALATE_AFTER) */
|
|
9463
|
+
const REBUILD_TODO_ESCALATE_AFTER = 3;
|
|
9464
|
+
const rebuildTodoStates = /* @__PURE__ */ new Map();
|
|
9465
|
+
/**
|
|
9466
|
+
* 交界便签超限提醒文案(v1.49.0)。
|
|
9467
|
+
*
|
|
9468
|
+
* ## 与 SESSION.md 档的**语义差别**(刻意,不是疏漏)
|
|
9469
|
+
*
|
|
9470
|
+
* | | SESSION.md 超限(`trajectoryCompactionReminderText`) | 便签超限(本条) |
|
|
9471
|
+
* |---|---|---|
|
|
9472
|
+
* | 动作 | **重写**(compaction) | **清理/丢弃**(prune) |
|
|
9473
|
+
* | 结构义务 | 保 EAP 骨架 + 4 条重写原则 + frontmatter 护栏 | **无** |
|
|
9474
|
+
* | 强度 | 升级后**强制**("STOP…必须先重写") | 升级后**语气加重,但动作仍只是"清理"** |
|
|
9475
|
+
* | 授权 | — | 🔴 **明确授权整份删除** |
|
|
9476
|
+
*
|
|
9477
|
+
* ## 归属(D23)
|
|
9478
|
+
* 机制(文件名 / 上限 / 注入时机)归 **ACC**;**写什么、怎么组织、何时丢**归 **CCC**。
|
|
9479
|
+
* 🔴 owner 裁决(逐字):*"rebuild 提示 Agent 去写,清空我们就不干涉了,只管最大量"* ⇒
|
|
9480
|
+
* **ACC 只提醒,不做任何写/删/归档操作**(自动删 = 数据丢失风险:rebuild 时序上新我还没读就被删)。
|
|
9481
|
+
*
|
|
9482
|
+
* ## 为什么要求"参照 eap"
|
|
9483
|
+
* owner 裁决(逐字):*"不规定,但要求参照 eap 来编写(这样质量会好点)"* ⇒
|
|
9484
|
+
* **不规定内部结构**(不给骨架),但**要求按 EAP 写**(显式 / 可重建 / 稳定)。
|
|
9485
|
+
*/
|
|
9486
|
+
function rebuildTodoReminderText(input) {
|
|
9487
|
+
const { sizeKB, limitKB, mdPath, escalated = false } = input;
|
|
9488
|
+
const facts = `${REBUILD_TODO_FILENAME} is ${sizeKB} KB (limit ${limitKB} KB): ${mdPath}`;
|
|
9489
|
+
const action = "This file is a scratch note for the rebuild handover — it carries no archival duty and you may discard it wholesale at any time. Prune it now, writing in the spirit of eap (praxis eap): (1) delete what is already done; (2) delete what has been superseded; (3) delete what is already recorded in SESSION.md — that file is the trajectory's persistent body, this one only carries what the next self needs once. Do not restructure it into a formal document: the only mechanical constraint on this file is its size.";
|
|
9490
|
+
if (escalated) return `${eventToken("scratchPrune")} ${facts} — you have been reminded repeatedly and have NOT pruned it. Prune it now. ${action} This reminder persists until the file is under the limit.`;
|
|
9491
|
+
return `${eventToken("scratchPrune")} ${facts}. ${action} This reminder stops once the file is under the limit.`;
|
|
9492
|
+
}
|
|
9446
9493
|
/** 每 agent 一个跟踪器(进程内存态,agent token 维度) */
|
|
9447
9494
|
const trackers = /* @__PURE__ */ new Map();
|
|
9448
9495
|
/** 连续超阈值轮数达此值 → 升级为 [TRAJECTORY-ESCALATED] 强制语气(此后持续升级催,直到 rebuild) */
|
|
@@ -9482,7 +9529,7 @@ function registerKeeper(ctx, opts = {}) {
|
|
|
9482
9529
|
text: reminderText(code)
|
|
9483
9530
|
});
|
|
9484
9531
|
}
|
|
9485
|
-
if (skiffRebuild
|
|
9532
|
+
if (skiffRebuild) {
|
|
9486
9533
|
const session = exec.agent?.session;
|
|
9487
9534
|
if (session) {
|
|
9488
9535
|
const pressure = readContextPressure(ctx, session);
|
|
@@ -9525,6 +9572,27 @@ function registerKeeper(ctx, opts = {}) {
|
|
|
9525
9572
|
} else compactionStates.delete(scope);
|
|
9526
9573
|
}
|
|
9527
9574
|
}
|
|
9575
|
+
if (skiffTrajectoryEnabled(root, sessionId, "session")) {
|
|
9576
|
+
const scope = sessionId ?? "global";
|
|
9577
|
+
const session = exec.agent?.session;
|
|
9578
|
+
const mdPath = resolveActiveSessionMdPath(root, scope, session);
|
|
9579
|
+
const todoPath = mdPath ? join(dirname(mdPath), REBUILD_TODO_FILENAME) : null;
|
|
9580
|
+
const size = todoPath ? readFileSize(todoPath) : null;
|
|
9581
|
+
if (todoPath && size !== null && size > 10240) {
|
|
9582
|
+
const st = rebuildTodoStates.get(scope) ?? { consecutive: 0 };
|
|
9583
|
+
st.consecutive += 1;
|
|
9584
|
+
blocks.push({
|
|
9585
|
+
type: "text",
|
|
9586
|
+
text: rebuildTodoReminderText({
|
|
9587
|
+
sizeKB: Math.round(size / 1024),
|
|
9588
|
+
limitKB: 10,
|
|
9589
|
+
mdPath: todoPath,
|
|
9590
|
+
escalated: st.consecutive >= REBUILD_TODO_ESCALATE_AFTER
|
|
9591
|
+
})
|
|
9592
|
+
});
|
|
9593
|
+
rebuildTodoStates.set(scope, st);
|
|
9594
|
+
} else rebuildTodoStates.delete(scope);
|
|
9595
|
+
}
|
|
9528
9596
|
if (blocks.length === 0) return downstream;
|
|
9529
9597
|
const reminderAll = createUserMessage({
|
|
9530
9598
|
content: blocks,
|
|
@@ -10181,7 +10249,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10181
10249
|
return;
|
|
10182
10250
|
}
|
|
10183
10251
|
const settings = readAdvancedSettings();
|
|
10184
|
-
const { readSimpleSettings } = await import("./settings-section-
|
|
10252
|
+
const { readSimpleSettings } = await import("./settings-section-B-KOyOYn.js").then((n) => n.r);
|
|
10185
10253
|
const simple = readSimpleSettings();
|
|
10186
10254
|
const allowed = settings.publicAsk.allowed;
|
|
10187
10255
|
const port = simple.acpHttpPort ?? ACP_HTTP_PORT;
|
|
@@ -12172,6 +12240,8 @@ function stripAckSuffix(text) {
|
|
|
12172
12240
|
*/
|
|
12173
12241
|
function buildRebuildAnchor(root, sessionName, activeMdPath, anchorMessages = DEFAULT_ANCHOR_MESSAGES, focus) {
|
|
12174
12242
|
const rel = activeMdPath.startsWith(root) ? activeMdPath.slice(root.length + 1) : activeMdPath;
|
|
12243
|
+
const todoAbs = join(dirname(activeMdPath), REBUILD_TODO_FILENAME);
|
|
12244
|
+
const todoRel = todoAbs.startsWith(root) ? todoAbs.slice(root.length + 1) : todoAbs;
|
|
12175
12245
|
const sessionDir = basename(dirname(activeMdPath));
|
|
12176
12246
|
const sessionLine = sessionDir !== "AGENT_SESSIONS" ? `- Serenity session: ${sessionName !== "" ? `${sessionName} (${sessionDir})` : sessionDir}` : null;
|
|
12177
12247
|
const focusLine = sanitizeFocusLine(focus);
|
|
@@ -12184,7 +12254,7 @@ function buildRebuildAnchor(root, sessionName, activeMdPath, anchorMessages = DE
|
|
|
12184
12254
|
`- Persistent trajectory — SESSION.md path: ${rel}`,
|
|
12185
12255
|
` (the trajectory's persistent body — stays in place through rebuilds)`,
|
|
12186
12256
|
`- Read that SESSION.md first (goal/decisions/progress/unresolved), then continue from the last checkpoint.`,
|
|
12187
|
-
`- Then read the
|
|
12257
|
+
`- Then read the handover scratch note: ${todoRel} (path: ${todoAbs}) — the previous self paused mid-task and left its in-flight items there. That file carries no format obligation and may be discarded at any time; it is NOT the authoritative state. If it is missing, infer the in-flight items from SESSION.md's latest progress entries.`,
|
|
12188
12258
|
...focusLine ? [`- Task focus: ${focusLine}`] : []
|
|
12189
12259
|
].join("\n");
|
|
12190
12260
|
}
|
|
@@ -12290,7 +12360,6 @@ function writeRebuildDiag(root, entry) {
|
|
|
12290
12360
|
* @returns 排队结果;rebuild.enabled=false 或非 CCC 抛错
|
|
12291
12361
|
*/
|
|
12292
12362
|
async function queueRebuild(ctx, opts) {
|
|
12293
|
-
if (!readSimpleSettings().rebuildEnabled) throw new Error("container_trajectory rebuild is disabled (rebuild.enabled=false — enable it in the dsh settings panel)");
|
|
12294
12363
|
const { root, note, summary, dshSessionId } = opts;
|
|
12295
12364
|
const session = ctx.sessions?.get?.(dshSessionId);
|
|
12296
12365
|
if (!session) throw new Error(`Unable to locate dsh session ${dshSessionId} (session may be closed)`);
|
|
@@ -18699,10 +18768,7 @@ const Config = z.object({
|
|
|
18699
18768
|
env: z.boolean().default(true),
|
|
18700
18769
|
opencodeSkills: z.boolean().default(true),
|
|
18701
18770
|
gateway: z.object({ enabled: z.boolean().default(false) }),
|
|
18702
|
-
rebuild: z.object({
|
|
18703
|
-
enabled: z.boolean().default(true),
|
|
18704
|
-
thresholdK: z.number().min(50).max(4e3).default(400)
|
|
18705
|
-
}),
|
|
18771
|
+
rebuild: z.object({ thresholdK: z.number().min(50).max(4e3).default(400) }),
|
|
18706
18772
|
skiff: z.object({
|
|
18707
18773
|
enabled: z.boolean().default(false),
|
|
18708
18774
|
debugPort: z.number().min(1024).max(65535).default(SKIFF_DEBUG_PORT)
|
|
@@ -18715,7 +18781,6 @@ const Config = z.object({
|
|
|
18715
18781
|
opencodeProvider: z.object({ autoConfigure: z.boolean().default(true) }),
|
|
18716
18782
|
visionPatch: z.object({ enabled: z.boolean().default(true) }),
|
|
18717
18783
|
gatewayEnabled: z.boolean().volatile(),
|
|
18718
|
-
rebuildEnabled: z.boolean().volatile(),
|
|
18719
18784
|
rebuildThresholdK: z.number().min(50).max(4e3).volatile(),
|
|
18720
18785
|
skiffEnabled: z.boolean().volatile(),
|
|
18721
18786
|
skiffDebugPort: z.number().min(1024).max(65535).volatile(),
|
package/lib/seams/keeper.d.ts
CHANGED
|
@@ -48,9 +48,12 @@ export declare function reminderText(code: string): string;
|
|
|
48
48
|
* 使用者若要查看当前占用/阈值:看面板(`rebuildThresholdK` 滑块 + 状态显示)——那是给人看的。
|
|
49
49
|
*
|
|
50
50
|
* v1.31.1 交接协议(S142 用户需求"要求 LLM 将当前手头事项写在 SESSION.md 尾部,并要求
|
|
51
|
-
* rebuild 后去读并处理"):**写侧** =
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* rebuild 后去读并处理"):**写侧** = 这里;**读侧** = rebuild 锚点(rebuild.ts)。
|
|
52
|
+
* 两侧共用 trajectory-assistant 的常量(单一真相源)。
|
|
53
|
+
*
|
|
54
|
+
* 🔴 **v1.49.0(owner 2026-09-26 裁决:"砍掉 in-flight,这正是目的")**:写侧**不再**指向
|
|
55
|
+
* SESSION.md 末尾的段,改指**独立便签文件** `REBUILD-TODO_FILENAME`(轨迹目录下)——
|
|
56
|
+
* 理由见该常量的头注(持久文件 vs 只用一次的交界材料必须分家)。
|
|
54
57
|
*/
|
|
55
58
|
export declare function rebuildReminderText(escalated?: boolean): string;
|
|
56
59
|
/** 读取会话 contextPressure 投影(sessionProjections 可选服务;未装配返回 null) */
|
|
@@ -110,6 +113,51 @@ export declare function trajectoryCompactionReminderText(input: {
|
|
|
110
113
|
mdPath: string;
|
|
111
114
|
escalated?: boolean;
|
|
112
115
|
}): string;
|
|
116
|
+
/**
|
|
117
|
+
* 交界便签体积上限(KB)—— **硬编码,刻意不设配置键**。
|
|
118
|
+
*
|
|
119
|
+
* 🔴 owner 2026-09-26 裁决(逐字):*"不需要设定,很多设定项我想砍掉了,好的功能用久了就发现
|
|
120
|
+
* 离不开,就不需要了"* ⇒ **不提供 `sessionKeeper.rebuildTodoMaxKB`**(设计件 Q4 的原倾向被否)。
|
|
121
|
+
* 对照:SESSION.md 的上限**保留可配置**(既有面,本版不动)。
|
|
122
|
+
*/
|
|
123
|
+
export declare const DEFAULT_REBUILD_TODO_MAX_KB = 10;
|
|
124
|
+
interface RebuildTodoState {
|
|
125
|
+
/** 连续超限轮数(文件降回限内即清零 → 清理完成后提醒自动停止) */
|
|
126
|
+
consecutive: number;
|
|
127
|
+
}
|
|
128
|
+
/** 测试/调试:查看交界便签超限提醒状态 */
|
|
129
|
+
export declare function rebuildTodoStateSnapshot(): ReadonlyMap<string, RebuildTodoState>;
|
|
130
|
+
/** 会话销毁/测试重置:清理超限计数(防 per-会话 Map 无界增长) */
|
|
131
|
+
export declare function forgetRebuildTodoState(scope: string): void;
|
|
132
|
+
/** 测试辅助:清空交界便签提醒状态 */
|
|
133
|
+
export declare function __resetRebuildTodoForTest(): void;
|
|
134
|
+
/**
|
|
135
|
+
* 交界便签超限提醒文案(v1.49.0)。
|
|
136
|
+
*
|
|
137
|
+
* ## 与 SESSION.md 档的**语义差别**(刻意,不是疏漏)
|
|
138
|
+
*
|
|
139
|
+
* | | SESSION.md 超限(`trajectoryCompactionReminderText`) | 便签超限(本条) |
|
|
140
|
+
* |---|---|---|
|
|
141
|
+
* | 动作 | **重写**(compaction) | **清理/丢弃**(prune) |
|
|
142
|
+
* | 结构义务 | 保 EAP 骨架 + 4 条重写原则 + frontmatter 护栏 | **无** |
|
|
143
|
+
* | 强度 | 升级后**强制**("STOP…必须先重写") | 升级后**语气加重,但动作仍只是"清理"** |
|
|
144
|
+
* | 授权 | — | 🔴 **明确授权整份删除** |
|
|
145
|
+
*
|
|
146
|
+
* ## 归属(D23)
|
|
147
|
+
* 机制(文件名 / 上限 / 注入时机)归 **ACC**;**写什么、怎么组织、何时丢**归 **CCC**。
|
|
148
|
+
* 🔴 owner 裁决(逐字):*"rebuild 提示 Agent 去写,清空我们就不干涉了,只管最大量"* ⇒
|
|
149
|
+
* **ACC 只提醒,不做任何写/删/归档操作**(自动删 = 数据丢失风险:rebuild 时序上新我还没读就被删)。
|
|
150
|
+
*
|
|
151
|
+
* ## 为什么要求"参照 eap"
|
|
152
|
+
* owner 裁决(逐字):*"不规定,但要求参照 eap 来编写(这样质量会好点)"* ⇒
|
|
153
|
+
* **不规定内部结构**(不给骨架),但**要求按 EAP 写**(显式 / 可重建 / 稳定)。
|
|
154
|
+
*/
|
|
155
|
+
export declare function rebuildTodoReminderText(input: {
|
|
156
|
+
sizeKB: number;
|
|
157
|
+
limitKB: number;
|
|
158
|
+
mdPath: string;
|
|
159
|
+
escalated?: boolean;
|
|
160
|
+
}): string;
|
|
113
161
|
interface KeeperRegistration {
|
|
114
162
|
/** 缺省阈值(serenity.json sessionKeeper.threshold 优先,其次此值) */
|
|
115
163
|
defaultThreshold?: number;
|
|
@@ -70,7 +70,6 @@ var settings_section_exports = /* @__PURE__ */ __exportAll({
|
|
|
70
70
|
function defaultSimpleSettings() {
|
|
71
71
|
return {
|
|
72
72
|
gatewayEnabled: false,
|
|
73
|
-
rebuildEnabled: true,
|
|
74
73
|
rebuildThresholdK: 400,
|
|
75
74
|
skiffEnabled: false,
|
|
76
75
|
skiffDebugPort: SKIFF_DEBUG_PORT,
|
|
@@ -116,7 +115,6 @@ function simpleSettingsFromConfig(config) {
|
|
|
116
115
|
const d = defaultSimpleSettings();
|
|
117
116
|
return {
|
|
118
117
|
gatewayEnabled: unwrapVolatile(config.gatewayEnabled) ?? config.gateway?.enabled ?? d.gatewayEnabled,
|
|
119
|
-
rebuildEnabled: unwrapVolatile(config.rebuildEnabled) ?? config.rebuild?.enabled ?? d.rebuildEnabled,
|
|
120
118
|
rebuildThresholdK: unwrapVolatile(config.rebuildThresholdK) ?? config.rebuild?.thresholdK ?? d.rebuildThresholdK,
|
|
121
119
|
skiffEnabled: unwrapVolatile(config.skiffEnabled) ?? config.skiff?.enabled ?? d.skiffEnabled,
|
|
122
120
|
skiffDebugPort: unwrapVolatile(config.skiffDebugPort) ?? config.skiff?.debugPort ?? d.skiffDebugPort,
|
|
@@ -49,7 +49,6 @@ interface SimpleConfigFragment {
|
|
|
49
49
|
enabled?: boolean;
|
|
50
50
|
};
|
|
51
51
|
rebuild?: {
|
|
52
|
-
enabled?: boolean;
|
|
53
52
|
thresholdK?: number;
|
|
54
53
|
};
|
|
55
54
|
/** F4 Skiff(实验性):调试服务启停(人工) */
|
|
@@ -63,7 +62,6 @@ interface SimpleConfigFragment {
|
|
|
63
62
|
httpPort?: number;
|
|
64
63
|
};
|
|
65
64
|
gatewayEnabled?: PanelBoolean;
|
|
66
|
-
rebuildEnabled?: PanelBoolean;
|
|
67
65
|
rebuildThresholdK?: PanelNumber;
|
|
68
66
|
skiffEnabled?: PanelBoolean;
|
|
69
67
|
skiffDebugPort?: PanelNumber;
|
|
@@ -81,8 +79,6 @@ export declare const SERENITY_SETTINGS_NS = "serenity-hooks";
|
|
|
81
79
|
interface SerenitySimpleSettings {
|
|
82
80
|
/** F1 双端口网关总开关 */
|
|
83
81
|
gatewayEnabled: boolean;
|
|
84
|
-
/** F2 超限重建总开关 */
|
|
85
|
-
rebuildEnabled: boolean;
|
|
86
82
|
/** F2 触发阈值(需求① S142 用户拍板:百分比比例 → K 数值;projectedTokens ≥ thresholdK*1000 触发) */
|
|
87
83
|
rebuildThresholdK: number;
|
|
88
84
|
/** F4 Skiff 调试服务总开关(实验性;默认关——不随插件加载自动启动,人工开启) */
|
|
@@ -33,6 +33,11 @@ export declare const EVENT_LABEL: {
|
|
|
33
33
|
readonly guard: "BOUNDARY GUARD";
|
|
34
34
|
/** SESSION.md 体积超限重写提醒(v1.31.1,S142 用户需求) */
|
|
35
35
|
readonly compaction: "LOGBOOK COMPACTION";
|
|
36
|
+
/** **交界便签(REBUILD-TODO.md)体积超限清理提醒**(v1.49.0,owner 2026-09-26 需求)。
|
|
37
|
+
*
|
|
38
|
+
* 🔴 **刻意与 `compaction` 分开**:那条要求"**重写 SESSION.md 并保留 EAP 骨架**",
|
|
39
|
+
* 本条只要求"**清理便签**"——共用一个 token 会让模型误以为要动 SESSION.md。 */
|
|
40
|
+
readonly scratchPrune: "SCRATCH PRUNE";
|
|
36
41
|
};
|
|
37
42
|
/** 家族标识(所有动态注入统一前缀) */
|
|
38
43
|
export declare const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
@@ -42,16 +47,24 @@ export declare function eventToken(event: keyof typeof EVENT_LABEL): string;
|
|
|
42
47
|
export declare const ACK_PREFIX = "TRAJECTORY-ASSISTANT-recorded";
|
|
43
48
|
export declare const ACK_SKIP_PREFIX = "TRAJECTORY-ASSISTANT-skipped";
|
|
44
49
|
/**
|
|
45
|
-
* rebuild
|
|
50
|
+
* rebuild 交界便签的**文件名**(v1.49.0;owner 2026-09-26 需求)。
|
|
46
51
|
*
|
|
47
|
-
*
|
|
48
|
-
* rebuild
|
|
49
|
-
*
|
|
52
|
+
* ## 它取代了什么(owner 原话:*"砍掉 in-flight,这正是目的"*)
|
|
53
|
+
* v1.31.1 的交界协议要求把手头事项写进 **SESSION.md 末尾**的 `## In-flight (rebuild handover)` 段。
|
|
54
|
+
* 实测的代价(S142 自身取证):In-flight 段曾积 **12 块**(含多份**已被取代**的交接),
|
|
55
|
+
* 而 SESSION.md 是**有格式义务**的持久文件(7 段固定 + 粒度受 EAP 约束)⇒
|
|
56
|
+
* ① 持久文件被临时物污染 ② 每次整理都要付"压缩+归档+保真"三件套(该文件曾达 292 KB)。
|
|
50
57
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
58
|
+
* ⇒ 分家:**只用一次的交界材料**写进这份**临时便签**(无格式义务、无留档义务、可随时丢弃)。
|
|
59
|
+
*
|
|
60
|
+
* ## 🔴 三处引用同一常量(单一真相源)
|
|
61
|
+
* **写侧** = `seams/keeper.ts` 的 `rebuildReminderText()`|**读侧** = `rebuild.ts` 的重建锚点|
|
|
62
|
+
* **体积提醒** = `seams/keeper.ts` 的 `rebuildTodoReminderText()`。
|
|
63
|
+
* 文件名一旦漂移,写侧写的东西读侧就找不到 —— **且没有任何机械信号会报警**。
|
|
64
|
+
*
|
|
65
|
+
* 🔴 **不得改名**(owner 已具名)。形态 = **固定文件名**(人读友好;比照旧 IN_FLIGHT_HEADING 的取舍)。
|
|
53
66
|
*/
|
|
54
|
-
export declare const
|
|
67
|
+
export declare const REBUILD_TODO_FILENAME = "REBUILD-TODO.md";
|
|
55
68
|
/** 风格档位:plain(默认,精确文本)/ metaphor(借星舰词——产品隐喻非游戏词) */
|
|
56
69
|
type TrajectoryStyle = 'plain' | 'metaphor';
|
|
57
70
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.49.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.7-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|