@shgroup/dsh-serenity-hooks 1.31.0 → 1.31.1
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 -2
- package/dsh.plugin.json +4 -3
- package/lib/ccc.d.ts +9 -0
- package/lib/index.js +150 -5
- package/lib/invariant.d.ts +8 -2
- package/lib/invariant.js +9 -2
- package/lib/msm-ops.d.ts +1 -1
- package/lib/seams/keeper.d.ts +52 -0
- package/lib/trajectory-assistant.d.ts +13 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -95,6 +95,8 @@ dsh plugin --profile web add link:$(pwd)/hooks/dsh-serenity-hooks
|
|
|
95
95
|
| **密钥文件守卫** | `localstore.json` 对**所有**工具拒绝(包括 read/grep/glob) | 密钥值在结构上就出不来 |
|
|
96
96
|
| **对外输出守卫** | 对外面的会话(子角色 / ACP / 重建会话)如果答出敏感词,会被打回重答,并告诉它命中了哪个词、该怎么改 | 外面的人不该看到内部机制 |
|
|
97
97
|
| **轨迹提醒** | 做久了会提醒 AI"把进度写回工作日志",并要求它回一个确认码 | 提醒是机制,不是靠自觉 |
|
|
98
|
+
| **工作日志体积提醒** | 工作日志(SESSION.md)超过 100KB 时提醒 AI"停下来重写一遍",并附四条重写原则(保留骨架 / 细节挪到附件文件 / 该合并的合并 / 其余你自己判断) | 日志越写越厚就没人读得完;重写比堆积便宜。阈值按工作区可调(`sessionKeeper.sessionMdMaxKB`,0 = 关) |
|
|
99
|
+
| **重建前交接** | 要重建上下文时,会要求 AI 先把"手头做到哪了 / 还差什么 / 下一步做什么"写进工作日志**末尾**的固定小标题下;重建后的它第一件事就是去读那一段接着干 | 上下文被清空,但手头的事不能丢——写侧与读侧用同一个标题,读的时候才找得到 |
|
|
98
100
|
|
|
99
101
|
### 3.3 对外的入口
|
|
100
102
|
|
|
@@ -294,7 +296,7 @@ AI 一次能"记住"的内容有上限。满了不用你手动开新会话:
|
|
|
294
296
|
|
|
295
297
|
```bash
|
|
296
298
|
pnpm typecheck # 类型检查(node + 浏览器端两套)
|
|
297
|
-
pnpm test # 全量测试(当前 75 个文件 /
|
|
299
|
+
pnpm test # 全量测试(当前 75 个文件 / 1110 个用例)
|
|
298
300
|
pnpm build # 打包(lib/index.js + client.js)
|
|
299
301
|
```
|
|
300
302
|
|
|
@@ -358,4 +360,4 @@ pnpm build # 打包(lib/index.js + client.js)
|
|
|
358
360
|
|
|
359
361
|
MIT(见 [LICENSE](https://github.com/tellmewhattodo/dsh-serenity-plugin/blob/master/LICENSE))
|
|
360
362
|
|
|
361
|
-
> **版本**:v1.31.
|
|
363
|
+
> **版本**:v1.31.1 | **前置**:DSH 0.1.2-rc.1+ / Node ≥ 20 或 bun | **测试**:75 个文件 / 1110 个用例
|
package/dsh.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.1",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
|
-
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——
|
|
5
|
+
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory/im-bridge)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.2-rc.1(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
7
7
|
"dsh": ">=0.1.2-rc.1"
|
|
8
8
|
},
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"handyman",
|
|
18
18
|
"localstore",
|
|
19
19
|
"container_admin",
|
|
20
|
-
"autopilot-trajectory"
|
|
20
|
+
"autopilot-trajectory",
|
|
21
|
+
"im-bridge"
|
|
21
22
|
],
|
|
22
23
|
"skills": []
|
|
23
24
|
}
|
package/lib/ccc.d.ts
CHANGED
|
@@ -44,7 +44,16 @@ export interface SerenityConfig {
|
|
|
44
44
|
maxParallel?: number;
|
|
45
45
|
};
|
|
46
46
|
sessionKeeper?: {
|
|
47
|
+
/** 计分提醒阈值(缺省 150) */
|
|
47
48
|
threshold?: number;
|
|
49
|
+
/**
|
|
50
|
+
* 活跃 SESSION.md 体积上限(KB,缺省 100——v1.31.1,S142 用户需求)。
|
|
51
|
+
*
|
|
52
|
+
* 超过 → trajectory-assistant 注入 LOGBOOK COMPACTION 提醒(暂停工作 → 加载 eap →
|
|
53
|
+
* 按 EAP 分层骨架重写 SESSION.md;内容可外移到 references 文件、可整合不重要事项、
|
|
54
|
+
* 自主裁量权充分允许)。设 0 = 关闭该提醒。
|
|
55
|
+
*/
|
|
56
|
+
sessionMdMaxKB?: number;
|
|
48
57
|
};
|
|
49
58
|
safeMode?: {
|
|
50
59
|
blacklist?: string[];
|
package/lib/index.js
CHANGED
|
@@ -2027,16 +2027,25 @@ handyman(杂工)工具可用模型白名单(provider/model 列表);未
|
|
|
2027
2027
|
Example:
|
|
2028
2028
|
{ "handyman": { "models": ["minimax-cn-coding-plan/MiniMax-M3"], "defaultModel": "minimax-cn-coding-plan/MiniMax-M3", "maxRounds": 100, "maxParallel": 10 } }
|
|
2029
2029
|
|
|
2030
|
-
── 2. sessionKeeper.threshold ──
|
|
2030
|
+
── 2. sessionKeeper.threshold / sessionKeeper.sessionMdMaxKB ──
|
|
2031
2031
|
trajectory-assistant(TRAJECTORY-ASSISTANT · CHECKPOINT)提醒机制的积分阈值(非 headless 主 agent)。
|
|
2032
2032
|
按工具调用加权 + 耗时计分;达到阈值注入提醒,要求模型回复 ACK 码。
|
|
2033
2033
|
|
|
2034
2034
|
Config:
|
|
2035
|
-
{ "sessionKeeper": { "threshold": 150 } }
|
|
2035
|
+
{ "sessionKeeper": { "threshold": 150, "sessionMdMaxKB": 100 } }
|
|
2036
2036
|
|
|
2037
2037
|
计分:write/edit = 3,task = 10,read/grep/glob/msm 等 = 1,时间 = 1/分钟
|
|
2038
2038
|
默认:150
|
|
2039
2039
|
|
|
2040
|
+
▸ sessionMdMaxKB(v1.31.1):**活跃 SESSION.md 体积上限(KB,缺省 100;0 = 关闭)**。
|
|
2041
|
+
超过 → 注入 [TRAJECTORY-ASSISTANT · LOGBOOK COMPACTION] 提醒:暂停当前工作 →
|
|
2042
|
+
加载 eap(praxis eap)→ 按 EAP 分层骨架重写 SESSION.md。四条原则(ACC 内嵌,随提醒给出):
|
|
2043
|
+
① 保留 EAP 分层骨架(不压成时间流水账)② 内容可外移到 references 文件
|
|
2044
|
+
(AGENT_SESSIONS/<会话>/references/*.md,SESSION.md 留链接)③ 允许整合/删除不重要事项
|
|
2045
|
+
(被取代的决策、已解决问题、中间态)④ 自主裁量权充分允许(唯一硬要求 = 骨架 +
|
|
2046
|
+
未决项/决策理由/下一步仍可重建)。超限每轮提醒;连续 3 轮未重写 → 升级强制语气;
|
|
2047
|
+
文件回到限内 → 自动停止(自愈)。轨迹提醒**不机械阻断工作**(与 rebuild 提醒同族)。
|
|
2048
|
+
|
|
2040
2049
|
── 3. localstore.gitTrack ──
|
|
2041
2050
|
localstore.json 的 git 策略:allow 可提交 / deny 禁提交(默认 deny)。
|
|
2042
2051
|
deny 时写入自动确保 .gitignore 含该文件(物理保证),container_git commit 会检查拒绝。
|
|
@@ -5045,7 +5054,9 @@ const EVENT_LABEL = {
|
|
|
5045
5054
|
/** 重建锚点头部(原 TRAJECTORY-REBUILD) */
|
|
5046
5055
|
rebuild: "REBUILD",
|
|
5047
5056
|
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
5048
|
-
guard: "BOUNDARY GUARD"
|
|
5057
|
+
guard: "BOUNDARY GUARD",
|
|
5058
|
+
/** SESSION.md 体积超限重写提醒(v1.31.1,S142 用户需求) */
|
|
5059
|
+
compaction: "LOGBOOK COMPACTION"
|
|
5049
5060
|
};
|
|
5050
5061
|
/** 家族标识(所有动态注入统一前缀) */
|
|
5051
5062
|
const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
@@ -5055,6 +5066,17 @@ function eventToken(event) {
|
|
|
5055
5066
|
}
|
|
5056
5067
|
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
5057
5068
|
const ACK_PREFIX = `${ASSISTANT_PREFIX}-recorded`;
|
|
5069
|
+
/**
|
|
5070
|
+
* rebuild 交接区块标题(v1.31.1,S142 用户需求)。
|
|
5071
|
+
*
|
|
5072
|
+
* 用途:rebuild 提醒要求模型把**当前手头事项**写到 SESSION.md **末尾**的这个小标题之下;
|
|
5073
|
+
* rebuild 锚点随后要求重建后的自己去读这一段并处理。两侧引用**同一个常量**——
|
|
5074
|
+
* 标题一旦漂移,读侧就找不到写侧写的东西(单一真相源)。
|
|
5075
|
+
*
|
|
5076
|
+
* 形态(用户拍板 Q2):**固定英文标题行**(不是 HTML 注释锚)——人读友好;ACC 写死英文,
|
|
5077
|
+
* 因为 SESSION.md 的正文语言归 CCC,但两侧的**机械锚点**必须逐字一致。
|
|
5078
|
+
*/
|
|
5079
|
+
const IN_FLIGHT_HEADING = "## In-flight (rebuild handover)";
|
|
5058
5080
|
//#endregion
|
|
5059
5081
|
//#region src/seams/keeper.ts
|
|
5060
5082
|
const SCORES = {
|
|
@@ -5119,10 +5141,16 @@ function reminderText(code, score) {
|
|
|
5119
5141
|
*
|
|
5120
5142
|
* 需求①(S142 用户拍板):百分比比例 → K 数值——tokensK = 实际占用(千 token),
|
|
5121
5143
|
* thresholdK = 配置阈值(千 token);文案 `Context usage at NNNK (threshold NNNK)`。
|
|
5144
|
+
*
|
|
5145
|
+
* v1.31.1 交接协议(S142 用户需求"要求 LLM 将当前手头事项写在 SESSION.md 尾部,并要求
|
|
5146
|
+
* rebuild 后去读并处理"):**写侧** = 这里(两条文案都要求把 in-flight 事项写在
|
|
5147
|
+
* SESSION.md 末尾的 `IN_FLIGHT_HEADING` 之下);**读侧** = rebuild 锚点(rebuild.ts)。
|
|
5148
|
+
* 两侧共用 trajectory-assistant 的标题常量(单一真相源)。
|
|
5122
5149
|
*/
|
|
5123
5150
|
function rebuildReminderText(tokensK, thresholdK, escalated = false) {
|
|
5124
|
-
|
|
5125
|
-
return `${eventToken("
|
|
5151
|
+
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) at the very end of SESSION.md under the heading "${IN_FLIGHT_HEADING}" — the rebuilt conversation reads that section first and continues from it.`;
|
|
5152
|
+
if (escalated) return `${eventToken("limitMandatory")} Context usage at ${Math.round(tokensK)}K (threshold ${Math.round(thresholdK)}K) — you have been reminded repeatedly and have NOT called the logbook 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 logbook 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 logbook rebuild.`;
|
|
5153
|
+
return `${eventToken("limit")} Context usage at ${Math.round(tokensK)}K (threshold ${Math.round(thresholdK)}K). 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 logbook 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.`;
|
|
5126
5154
|
}
|
|
5127
5155
|
/** 读取会话 contextPressure 投影(sessionProjections 可选服务;未装配返回 null) */
|
|
5128
5156
|
function readContextPressure(ctx, session) {
|
|
@@ -5139,6 +5167,96 @@ function readContextPressure(ctx, session) {
|
|
|
5139
5167
|
return null;
|
|
5140
5168
|
}
|
|
5141
5169
|
}
|
|
5170
|
+
/** 连续超限轮数达此值 → 升级强制语气(对齐 rebuild 提醒的 REBUILD_ESCALATE_AFTER) */
|
|
5171
|
+
const COMPACTION_ESCALATE_AFTER = 3;
|
|
5172
|
+
/** 路径/配置缓存 TTL(避免每次工具调用都解析路径与读配置;stat 每次都做,很便宜) */
|
|
5173
|
+
const MD_CACHE_TTL_MS = 6e4;
|
|
5174
|
+
const mdPathCache = /* @__PURE__ */ new Map();
|
|
5175
|
+
const mdLimitCache = /* @__PURE__ */ new Map();
|
|
5176
|
+
const compactionStates = /* @__PURE__ */ new Map();
|
|
5177
|
+
/** 会话销毁/测试重置:清理路径缓存与超限计数(防 per-会话 Map 无界增长,review F-08 同族) */
|
|
5178
|
+
function forgetLogbookCompactionState(scope) {
|
|
5179
|
+
mdPathCache.delete(scope);
|
|
5180
|
+
compactionStates.delete(scope);
|
|
5181
|
+
}
|
|
5182
|
+
/**
|
|
5183
|
+
* 解析**活跃** SESSION.md 绝对路径(缓存 60s)。
|
|
5184
|
+
*
|
|
5185
|
+
* 候选链(刻意比 rebuild 的完整链短——这里每个工具调用都要跑,贵候选不划算):
|
|
5186
|
+
* ① `getActiveSessionInfo(scope).mdPath`(`logbook use` / skiff 绑定 / 重启恢复都会写)
|
|
5187
|
+
* ② `readLastBound(session).mdPath`(`.bindings.json` 权威绑定——重启后内存空时兜底)
|
|
5188
|
+
* 两者都拿不到 → null(**不猜**:宁可不提醒,也不去猜别的轨迹——对齐 v1.30.13 D4 的教训)。
|
|
5189
|
+
*/
|
|
5190
|
+
function resolveActiveSessionMdPath(root, scope, session, now = Date.now) {
|
|
5191
|
+
const t = now();
|
|
5192
|
+
const cached = mdPathCache.get(scope);
|
|
5193
|
+
if (cached && t - cached.at < MD_CACHE_TTL_MS) return cached.mdPath;
|
|
5194
|
+
let candidate = null;
|
|
5195
|
+
try {
|
|
5196
|
+
candidate = getActiveSessionInfo(scope)?.mdPath ?? null;
|
|
5197
|
+
} catch {
|
|
5198
|
+
candidate = null;
|
|
5199
|
+
}
|
|
5200
|
+
if (!candidate) try {
|
|
5201
|
+
candidate = readLastBound(session)?.mdPath ?? null;
|
|
5202
|
+
} catch {
|
|
5203
|
+
candidate = null;
|
|
5204
|
+
}
|
|
5205
|
+
let abs = null;
|
|
5206
|
+
if (candidate) {
|
|
5207
|
+
const p = candidate.startsWith(root) ? candidate : resolve(root, candidate);
|
|
5208
|
+
abs = existsSync(p) ? p : null;
|
|
5209
|
+
}
|
|
5210
|
+
mdPathCache.set(scope, {
|
|
5211
|
+
mdPath: abs,
|
|
5212
|
+
at: t
|
|
5213
|
+
});
|
|
5214
|
+
return abs;
|
|
5215
|
+
}
|
|
5216
|
+
/** 读文件字节数(读不到 → null,不抛错) */
|
|
5217
|
+
function readFileSize(absPath) {
|
|
5218
|
+
try {
|
|
5219
|
+
return statSync(absPath).size;
|
|
5220
|
+
} catch {
|
|
5221
|
+
return null;
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
/** 读该 CCC 的 SESSION.md 体积上限(KB;缓存 60s;0 = 关闭提醒) */
|
|
5225
|
+
function readSessionMdMaxKB(root, configPaths, now = Date.now) {
|
|
5226
|
+
const t = now();
|
|
5227
|
+
const cached = mdLimitCache.get(root);
|
|
5228
|
+
if (cached && t - cached.at < MD_CACHE_TTL_MS) return cached.limitKB;
|
|
5229
|
+
let limitKB = 100;
|
|
5230
|
+
try {
|
|
5231
|
+
const configured = loadSerenityConfig(root, configPaths).sessionKeeper?.sessionMdMaxKB;
|
|
5232
|
+
if (typeof configured === "number" && Number.isFinite(configured) && configured >= 0) limitKB = configured;
|
|
5233
|
+
} catch {}
|
|
5234
|
+
mdLimitCache.set(root, {
|
|
5235
|
+
limitKB,
|
|
5236
|
+
at: t
|
|
5237
|
+
});
|
|
5238
|
+
return limitKB;
|
|
5239
|
+
}
|
|
5240
|
+
/**
|
|
5241
|
+
* LOGBOOK COMPACTION 提醒文案(v1.31.1)。
|
|
5242
|
+
*
|
|
5243
|
+
* 归属(D23 + 用户 2026-09-09 拍板):**ACC 内嵌机制事实 + 4 条重写原则**——理由:这 4 条是
|
|
5244
|
+
* 认知质量规范(与 EAP 同层,不是会随角色迭代的措辞),且未配置任何 CCC 文档的容器也要立刻可用。
|
|
5245
|
+
*
|
|
5246
|
+
* 四条原则(用户原话逐条落成可执行判据):
|
|
5247
|
+
* ① 保留 EAP 分层骨架(不许压成时间流水账)
|
|
5248
|
+
* ② 内容可外移到 references 文件(证据链/日志/参考资料 → `AGENT_SESSIONS/<会话>/references/*.md`,
|
|
5249
|
+
* 在 SESSION.md 里留链接)
|
|
5250
|
+
* ③ 允许整合不重要事项(被取代的决策 / 已解决问题 / 中间态)
|
|
5251
|
+
* ④ 自主裁量权充分允许(唯一硬要求 = 骨架 + 未决项/决策理由/下一步仍可重建)
|
|
5252
|
+
*/
|
|
5253
|
+
function logbookCompactionReminderText(input) {
|
|
5254
|
+
const { sizeKB, limitKB, mdPath, escalated = false } = input;
|
|
5255
|
+
const facts = `SESSION.md is ${sizeKB} KB (limit ${limitKB} KB): ${mdPath}`;
|
|
5256
|
+
const principles = "Load eap (praxis eap) first, then rewrite SESSION.md under these principles: (1) keep the EAP layered skeleton — a stable section structure, not a chronological dump; (2) move detail out — long evidence chains, logs and reference material belong in separate files (e.g. AGENT_SESSIONS/<session>/references/*.md) linked from SESSION.md; (3) merge or drop what no longer matters — superseded decisions, resolved issues, intermediate states; (4) you have full discretion on how far to go: the only hard requirements are the skeleton and that every still-open item, decision rationale and next step stays recoverable (reconstruction over preservation).";
|
|
5257
|
+
if (escalated) return `${eventToken("compaction")} ${facts} — you have been reminded repeatedly and have NOT compacted the logbook. This is now mandatory: STOP the current task step, load eap (praxis eap), rewrite SESSION.md, then resume. ${principles} This reminder persists until the file is under the limit.`;
|
|
5258
|
+
return `${eventToken("compaction")} ${facts}. Pause the current work and compact the trajectory logbook before continuing — the logbook is the persistent body of this trajectory, and its size is operational entropy (H_op) the container pays on every read. ${principles} After rewriting, resume the paused work; this reminder stops once the file is under the limit.`;
|
|
5259
|
+
}
|
|
5142
5260
|
const PLUGIN_SOURCE$4 = {
|
|
5143
5261
|
kind: "plugin",
|
|
5144
5262
|
plugin: "dsh-serenity-hooks"
|
|
@@ -5200,6 +5318,29 @@ function registerKeeper(ctx, opts = {}) {
|
|
|
5200
5318
|
}
|
|
5201
5319
|
}
|
|
5202
5320
|
}
|
|
5321
|
+
if (skiffTrajectoryEnabled(root, sessionId, "session")) {
|
|
5322
|
+
const limitKB = readSessionMdMaxKB(root, opts.configPaths);
|
|
5323
|
+
if (limitKB > 0) {
|
|
5324
|
+
const scope = sessionId ?? "global";
|
|
5325
|
+
const session = exec.agent?.session;
|
|
5326
|
+
const mdPath = resolveActiveSessionMdPath(root, scope, session);
|
|
5327
|
+
const size = mdPath ? readFileSize(mdPath) : null;
|
|
5328
|
+
if (mdPath && size !== null && size > limitKB * 1024) {
|
|
5329
|
+
const st = compactionStates.get(scope) ?? { consecutive: 0 };
|
|
5330
|
+
st.consecutive += 1;
|
|
5331
|
+
blocks.push({
|
|
5332
|
+
type: "text",
|
|
5333
|
+
text: logbookCompactionReminderText({
|
|
5334
|
+
sizeKB: Math.round(size / 1024),
|
|
5335
|
+
limitKB,
|
|
5336
|
+
mdPath,
|
|
5337
|
+
escalated: st.consecutive >= COMPACTION_ESCALATE_AFTER
|
|
5338
|
+
})
|
|
5339
|
+
});
|
|
5340
|
+
compactionStates.set(scope, st);
|
|
5341
|
+
} else compactionStates.delete(scope);
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5203
5344
|
if (blocks.length === 0) return downstream;
|
|
5204
5345
|
const reminderAll = createUserMessage({
|
|
5205
5346
|
content: blocks,
|
|
@@ -8202,6 +8343,7 @@ function buildRebuildAnchor(root, sessionName, activeMdPath, anchorMessages = DE
|
|
|
8202
8343
|
`- Persistent trajectory — SESSION.md path: ${rel}`,
|
|
8203
8344
|
` (the trajectory's persistent body — stays in place through rebuilds)`,
|
|
8204
8345
|
`- Read that SESSION.md first (goal/decisions/progress/unresolved), then continue from the last checkpoint.`,
|
|
8346
|
+
`- Then read the "${IN_FLIGHT_HEADING}" section at the very end of SESSION.md and work through those in-flight items (the previous self paused mid-task and handed them over). If that section is missing, infer the in-flight items from the latest progress entries.`,
|
|
8205
8347
|
...focusLine ? [`- Task focus: ${focusLine}`] : []
|
|
8206
8348
|
].join("\n");
|
|
8207
8349
|
}
|
|
@@ -10610,6 +10752,9 @@ function cleanupSessionState(sessionId) {
|
|
|
10610
10752
|
try {
|
|
10611
10753
|
forgetImBridgeVisibility(sessionId);
|
|
10612
10754
|
} catch {}
|
|
10755
|
+
try {
|
|
10756
|
+
forgetLogbookCompactionState(sessionId);
|
|
10757
|
+
} catch {}
|
|
10613
10758
|
}
|
|
10614
10759
|
/**
|
|
10615
10760
|
* 装配生命周期订阅与资源拆卸。
|
package/lib/invariant.d.ts
CHANGED
|
@@ -25,5 +25,11 @@ export declare function readPluginManifest(manifestPath: string): PluginManifest
|
|
|
25
25
|
* 返回不一致项列表(空 = 通过)。
|
|
26
26
|
*/
|
|
27
27
|
export declare function verifyToolConsistency(manifestPath: string, registeredTools: readonly string[]): string[];
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* 包级不变量:本插件注册的工具集合(与 dsh.plugin.json contributes.tools 一致)。
|
|
30
|
+
*
|
|
31
|
+
* v1.31.1 修正:v1.31.0 新增 `im-bridge`(条件可见)时**漏改此处与清单**——两侧同错 →
|
|
32
|
+
* `verifyToolConsistency` 零问题(**陈旧的双侧一致 = 静默通过**),而代码实际注册 11 个。
|
|
33
|
+
* 教训:工具面变更必须同时改三处(tools/*.ts 注册 / 本常量 / dsh.plugin.json)。
|
|
34
|
+
*/
|
|
35
|
+
export declare const REGISTERED_TOOLS: readonly ["container_fs", "logbook", "dashboard", "container_git", "msm", "praxis", "handyman", "localstore", "container_admin", "autopilot-trajectory", "im-bridge"];
|
package/lib/invariant.js
CHANGED
|
@@ -31,7 +31,13 @@ function verifyToolConsistency(manifestPath, registeredTools) {
|
|
|
31
31
|
if (undeclared.length) issues.push(`registered tools not declared in manifest: ${undeclared.join(", ")}`);
|
|
32
32
|
return issues;
|
|
33
33
|
}
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* 包级不变量:本插件注册的工具集合(与 dsh.plugin.json contributes.tools 一致)。
|
|
36
|
+
*
|
|
37
|
+
* v1.31.1 修正:v1.31.0 新增 `im-bridge`(条件可见)时**漏改此处与清单**——两侧同错 →
|
|
38
|
+
* `verifyToolConsistency` 零问题(**陈旧的双侧一致 = 静默通过**),而代码实际注册 11 个。
|
|
39
|
+
* 教训:工具面变更必须同时改三处(tools/*.ts 注册 / 本常量 / dsh.plugin.json)。
|
|
40
|
+
*/
|
|
35
41
|
const REGISTERED_TOOLS = [
|
|
36
42
|
"container_fs",
|
|
37
43
|
"logbook",
|
|
@@ -42,7 +48,8 @@ const REGISTERED_TOOLS = [
|
|
|
42
48
|
"handyman",
|
|
43
49
|
"localstore",
|
|
44
50
|
"container_admin",
|
|
45
|
-
"autopilot-trajectory"
|
|
51
|
+
"autopilot-trajectory",
|
|
52
|
+
"im-bridge"
|
|
46
53
|
];
|
|
47
54
|
//#endregion
|
|
48
55
|
export { REGISTERED_TOOLS, readPluginManifest, verifyToolConsistency };
|
package/lib/msm-ops.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const MSM_ACTIONS: readonly MsmAction[];
|
|
|
19
19
|
export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u4F1A\u8BDD\u4E0E\u8F68\u8FF9 \u2192 logbook\uFF08list/show/create/use/close/health/qa/archive/summary/hook-develop-guide + rebuild \u8D85\u9650\u91CD\u5EFA\uFF09\n session_rebuild \u5DF2\u5E76\u5165 logbook rebuild\uFF08\u8D85\u9650\u91CD\u5EFA\uFF1B\u9608\u503C K \u89C1 container_admin ccc-config / \u8BBE\u7F6E\u9762\u677F\u91CD\u5EFA\u9608\u503CK\uFF09\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 praxis\uFF08eap/neat/cce \u4E09\u5408\u4E00\u2014\u2014\u53EF\u5B9E\u8DF5\u7406\u8BBA\u6CE8\u5165\uFF0Csection \u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u76EE\u5F55\uFF09\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 container_fs\uFF08\u5BB9\u5668\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ container_git\uFF08git\uFF09/ dashboard\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/wait\uFF09\n acc_msm \u5DF2\u5E76\u5165 msm\uFF08\u6267\u884C+\u53D1\u73B0\uFF09\u4E0E container_admin\uFF08\u7BA1\u7406\uFF09\u2014\u2014msm(\"<name>\", [\"<args>\"])\uFF1Binspect=true \u67E5\u7528\u6CD5\n handyman\uFF08\u6742\u5DE5 agent \u7F16\u6392\u2014\u2014guide \u5B50\u547D\u4EE4\uFF1Ahandyman guide\uFF09\n \u2463 \u89D2\u8272\u4E0E\u5BF9\u5916\u9762 \u2192 container_admin role\uFF08Skiff \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF1Aguide/validate/apply/list\u2014\u2014skiff_admin \u5DF2\u5E76\u5165\uFF09\n ACP\uFF08\u7A0B\u5E8F\u5316 JSON-RPC 3100\uFF09/ Skiff \u95EE\u7B54\u9875\uFF08\u516C\u7F51 ask\uFF09\u2014\u2014\u9762\u677F\u300C\u5916\u90E8\u80FD\u529B\u300D\u7EC4\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 autopilot-trajectory\uFF08Autopilot \u4E00\u7AD9\u5F0F\uFF1Aall/init/random/diag/doc/check/status/guide\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Amsm(\"weixin-doctor\", [\"guide\"])\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 container_admin msm ccc-config\uFF088 \u6BB5\uFF1Ahandyman/sessionKeeper/localstore/hooks/safeMode/skiff/autopilotTrajectory/weixin\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 container_admin msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n dashboard health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
|
|
20
20
|
export declare const MSM_GUIDE = "MSM Development Manual (Mech & Semi-Mech framework)\n\n## What it is\nMSM = the executable-unit layer. Mech is pure TS with zero LLM reasoning; Semi-Mech is a TS framework + LLM decision points.\nMSM is ACC's deterministic executable-unit layer \u2014 all shell/exec operations go through MSM and cannot be bypassed.\n\n## Registering a new MSM (container_admin msm register)\n1. Write the script under <skill>/scripts/ (runnable via tsx; must include a main() CLI guard with an import.meta.url check)\n2. container_admin msm register --domain msm --action register <name> --skill <s> --path <script path relative to root> --category <mech|semi-mech> --description <desc>\n3. Auto-writes mech-registry.json (preserving the original format) + git commit (commits only the registry file)\n4. Validation: path must be inside root, script must exist, name must be globally unique\n\n## flag schema (v1)\nflags is a new-style object array for parameter validation and path-escape guarding:\n [{\"name\":\"output\",\"type\":\"string\",\"description\":\"output path\"},\n {\"name\":\"target\",\"type\":\"path\",\"description\":\"operation target (type:path enables in-root validation + symlink defense)\"},\n {\"name\":\"force\",\"type\":\"boolean\",\"description\":\"force mode\",\"default\":false}]\n- {name, type} format \u2014 new style, type:\"path\" enables the path-escape guard\n- {flag, description} format \u2014 old style, CLI flag description string\n- On registration, flags are passed via container_admin msm register --flags '<json>'\n\n## Script conventions\n- Top-of-file documentation: purpose / usage / exit codes\n- Exit codes: 0 success / 1 user / 2 system / 3 operator (per ACC protocol classification)\n- main() CLI guard (DC-M2): the script must start with\n if (import.meta.url === `file://${process.argv[1]}`) { main() }\n or an equivalent isMain / require.main === check \u2014 so vitest imports never trigger top-level code\n- A paired .test.ts or .spec.ts (DC-M1, vitest)\n- Business subprocess environment: SERENITY_ROOT / SERENITY_CCC / SERENITY_VERSION injected\n\n## Interaction & confirmation conventions (no blocking confirmation)\n- MSMs run in **user-less subprocesses** (spawn/execFile, 600s timeout) \u2014 **never** use\n readline / prompt / process.stdin etc. to block waiting for user input (it would hang until killed by the timeout)\n- When a second confirmation is needed: **directly return the confirmation request** (list the operation to perform and its impact + how to retry with the confirmation flag),\n returning a non-zero exit code (or an explicit hint)\n- After the agent confirms, **re-invoke the MSM with the confirmation flag** (e.g. --confirm / --yes / --force) to retry\n- Standard mode (two-phase):\n 1. First call: destructive/confirmation-requiring operation detected and no confirmation flag present \u2192 output the confirmation request (list operation/impact/rollback),\n exit non-zero (e.g. 1 user), **perform no changes**\n 2. After the agent evaluates, re-invoke: with the confirmation flag \u2192 execute and output the result\n- Applies to: delete/overwrite/push/batch operations and other irreversible or wide-impact operations\n- Anti-example (forbidden): readline waiting for user input, process.stdin.on('data') blocking waits\n (MSMs have no stdin interaction channel \u2014 they hang until the 600s timeout)\n\n## Quality checks (container_admin msm check, DC-M1~M4)\nDC-M1 has .test.ts/.spec.ts; DC-M2 has a main() guard (function main( / isMain / require.main === / import.meta.url);\nDC-M3 bidirectional: scripts unregistered + registry references missing scripts; DC-M4 path-type flags marked type:\"path\"\n\n## Self-description (protocol flags, first argument only)\nmsm(\"<name>\", [\"--list\"]) \u2014 list all MSMs\nmsm(\"<name>\", [\"--schema\", \"<n>\"]) \u2014 view a specific MSM's parameter schema\nmsm(\"<name>\", [\"--format=json\"]) \u2014 JSON output mode (remaining args passed through losslessly)\n";
|
|
21
21
|
/** CCC 配置参考(对齐 osp ccc-config action) */
|
|
22
|
-
export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. handyman.models \u2500\u2500\nhandyman\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 handyman \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 handyman.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n\n Config:\n { \"handyman\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"handyman\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\", \"maxRounds\": 100, \"maxParallel\": 10 } }\n\n\u2500\u2500 2. sessionKeeper.threshold \u2500\u2500\ntrajectory-assistant\uFF08TRAJECTORY-ASSISTANT \u00B7 CHECKPOINT\uFF09\u63D0\u9192\u673A\u5236\u7684\u79EF\u5206\u9608\u503C\uFF08\u975E headless \u4E3B agent\uFF09\u3002\n\u6309\u5DE5\u5177\u8C03\u7528\u52A0\u6743 + \u8017\u65F6\u8BA1\u5206\uFF1B\u8FBE\u5230\u9608\u503C\u6CE8\u5165\u63D0\u9192\uFF0C\u8981\u6C42\u6A21\u578B\u56DE\u590D ACK \u7801\u3002\n\n Config:\n { \"sessionKeeper\": { \"threshold\": 150 } }\n\n \u8BA1\u5206\uFF1Awrite/edit = 3\uFF0Ctask = 10\uFF0Cread/grep/glob/msm \u7B49 = 1\uFF0C\u65F6\u95F4 = 1/\u5206\u949F\n \u9ED8\u8BA4\uFF1A150\n\n\u2500\u2500 3. localstore.gitTrack \u2500\u2500\nlocalstore.json \u7684 git \u7B56\u7565\uFF1Aallow \u53EF\u63D0\u4EA4 / deny \u7981\u63D0\u4EA4\uFF08\u9ED8\u8BA4 deny\uFF09\u3002\ndeny \u65F6\u5199\u5165\u81EA\u52A8\u786E\u4FDD .gitignore \u542B\u8BE5\u6587\u4EF6\uFF08\u7269\u7406\u4FDD\u8BC1\uFF09\uFF0Ccontainer_git commit \u4F1A\u68C0\u67E5\u62D2\u7EDD\u3002\n\n Config:\n { \"localstore\": { \"gitTrack\": \"allow\" } }\n\n\u2500\u2500 4. hooks.autoRestoreSession \u2500\u2500\n\u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\uFF08\u9ED8\u8BA4 true\uFF1B\u53D7 events \u95E8\u63A7\u2014\u2014\u4EC5\u6839\u4F1A\u8BDD + \u5DF2\u6709\u5BF9\u8BDD\u5386\u53F2\u624D\u6062\u590D\uFF09\u3002\n\n Config:\n { \"hooks\": { \"autoRestoreSession\": false } }\n\n\u2500\u2500 5. safeMode / blacklist \u2500\u2500\nsafe-mode \u7531 WebUI \u5F00\u5173\u63A7\u5236\uFF08\u5199 .serenity-safe-on \u6807\u8BB0\uFF09\uFF1B\u9ED1\u540D\u5355\u8DEF\u5F84\u53D7 guards seam \u62E6\u622A\u3002\n\n Config:\n { \"safeMode\": { \"blacklist\": [\".secrets/\"] } }\n\n\u2500\u2500 6. skiff.roles\uFF08F4 \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF09\u2500\u2500\nSkiff \u89D2\u8272 = \u5168\u77E5\u5168\u80FD trajectory \u7684\u4EFB\u610F\u5B50\u96C6\uFF08CCC \u5B9A\u4E49\uFF09\u3002\u6BCF\u89D2\u8272\u72EC\u7ACB\u6A21\u578B + \u53CC\u767D\u540D\u5355\n\uFF08MSM \u767D\u540D\u5355 msms[] \u4E0E\u975E MSM \u5DE5\u5177\u767D\u540D\u5355 tools[]\uFF0C\u767D\u540D\u5355\u5916\u5168\u9690\u85CF\uFF1Bskill \u52A0\u8F7D\u6052\u53EF\u7528\uFF09\u3002\ntrajectory \u7EAA\u5F8B\u5B50\u96C6\uFF08session/keeper/rebuild \u53C2\u4E0E\u9879\uFF09\u9ED8\u8BA4\u5168\u5173 = \u5B8C\u5168\u72EC\u7ACB\u3002\nsystemPrompt \u5185\u8054 \u6216 systemPromptFile\uFF08.md \u5F15\u7528\uFF0C\u63A8\u8350\uFF09\u2014\u2014\u89D2\u8272\u4F1A\u8BDD\u7684\u5B8C\u6574\u4EBA\u683C/\u8FB9\u754C\u63D0\u793A\u8BCD\u3002\nvalidate \u6821\u9A8C / apply \u751F\u6548 / list \u67E5\u770B\uFF1Acontainer_admin role <guide|validate|apply|list>\uFF08skiff_admin \u5DF2\u5E76\u5165\uFF09\u3002\n\n Config:\n { \"skiff\": { \"roles\": {\n \"qa\": {\n \"model\": \"provider/model\",\n \"msms\": [\"web-search\", \"vlm-describe\"],\n \"tools\": [\"read\", \"grep\", \"glob\"],\n \"systemPromptFile\": \".opencode/skiff/qa.md\"\n } } } }\n\n\u2500\u2500 7. autopilotTrajectory\uFF08\u81EA\u52A8\u5DE1\u822A\u8F68\u8FF9\uFF09\u2500\u2500\nCCC \u5B9A\u4E49\u7684\u4E00\u6761\u81EA\u4E3B trajectory\u2014\u2014\u65F6\u949F\u5230\u70B9\u81EA\u52A8\u5524\u8D77\uFF08\u524D\u53F0\u6CE8\u5165\uFF0C\u7528\u6237\u53EF\u89C1\u53EF\u4ECB\u5165\uFF09\u3002\n\u672A\u914D\u7F6E\u6216 enabled=false \u2192 \u5B8C\u5168\u4E0D\u542F\u52A8\uFF08\u96F6\u8D44\u6E90\u5360\u7528\uFF09\u3002\u591A CCC \u72EC\u7ACB\uFF1A\u6BCF CCC \u81EA\u5DF1\u7684\u914D\u7F6E\u3002\n\u5524\u8D77\u6D88\u606F\u56DB\u6BB5\u5F0F\uFF1A\u8F68\u8FF9\u7126\u70B9 topPrompt\uFF08\u6700\u5148\u6CE8\u5165\uFF0C\u7A33\u5B9A\u951A\uFF09\u2192 \u8EAB\u4EFD\u951A\u5B9A \u2192 \u5148\u9A8C\u504F\u89C1\n\uFF08CCC \u6839\u811A\u672C biasProvider \u8F93\u51FA\uFF09\u2192 \u4EFB\u52A1\u3002\u76EE\u6807\u4F1A\u8BDD session \u5FC5\u586B\uFF08\u76EE\u5F55\u987B\u5E26 --auto \u540E\u7F00\uFF09\u3002\n\u8BCA\u65AD/\u72B6\u6001/\u7ACB\u5373\u5524\u8D77\uFF1Aautopilot-trajectory <all|check|status|diag>\uFF08msm(\"autopilot-trajectory\", [\"all\"])\uFF09\u3002\n\n Config:\n { \"autopilotTrajectory\": {\n \"enabled\": true,\n \"intervalHours\": 2,\n \"session\": \"S151\",\n \"biasProvider\": \"autopilot-bias.ts\",\n \"topPrompt\": \"\u672C\u8F68\u8FF9\u6838\u5FC3\u76EE\u6807/\u7EAA\u5F8B/\u8D28\u91CF\u8981\u6C42\uFF08CCC \u81EA\u586B\uFF0C\u9632\u6F02\u79FB\uFF09\",\n \"avoidWakeHours\": { \"start\": 8, \"end\": 18 }\n } }\n\n\u2500\u2500 8. weixin\uFF08\u5FAE\u4FE1\u6865 F4c-3\uFF0C\u542B\u6D88\u606F\u8BB0\u5F55 hook\uFF09\u2500\u2500\nCCC \u7EA7\u5FAE\u4FE1\u4E2A\u4EBA\u53F7\u63A5\u5165\uFF08iLink \u534F\u8BAE\uFF09\uFF1Adsh \u4E00\u8FDB\u7A0B\u591A CCC\uFF0C\u6BCF CCC \u72EC\u7ACB\u5BF9\u63A5\u5FAE\u4FE1\u6865\u3002\n\u8D26\u53F7/\u8DEF\u7531/\u5F00\u5173\u5728\u6B64\u6587\u4EF6\uFF1B**bot_token \u51ED\u636E\u5728 CCC localstore credential scope**\n\uFF08\u626B\u7801\u7ED1\u5B9A\u540E\u81EA\u52A8\u5199\u5165\uFF0C\u6C38\u4E0D\u8FDB git \u660E\u6587\u9762\uFF09\u3002\n\u8DEF\u7531 user \u2192 role\uFF1Aexact \u4F18\u5148\uFF0C* \u901A\u914D\u515C\u5E95\uFF1Brole \u5FC5\u987B \u2208 \u8BE5 CCC skiff.roles\u3002\n\u9762\u677F\uFF08WebUI \u8BBE\u7F6E \u2192 \u5FAE\u4FE1\u6865\uFF09\u53EF\u626B\u7801\u7ED1\u5B9A/\u79FB\u9664\u8D26\u53F7/\u7F16\u8F91\u8DEF\u7531\uFF1Bmsm(\"weixin-doctor\", [\"status\"|\"diag\"|\"verify\"|\"guide\"]) \u6392\u67E5 + \u5927\u800C\u5168\u6307\u5357\u3002\u51ED\u636E\u4E3B\u52A8\u67E5\u770B\uFF1Alocalstore get WEIXIN_<ACCOUNT>_TOKEN\u3002\n \u25B8 \u4E3B\u52A8\u53D1\u9001\uFF08v1.31.0\uFF1A**ACC \u5DE5\u5177 im-bridge**\uFF09\uFF1A\u8C03\n im-bridge({channel:\"weixin\", action:\"send\", user:\"<\u522B\u540D|id>\", text:\"<\u6587\u672C>\"}) \u7ED9\u7528\u6237\u53D1\u6D88\u606F\u2014\u2014\n **\u5DE5\u5177\u53EA\u80FD\u64CD\u4F5C\u672C\u4F1A\u8BDD CCC**\uFF08\u65E0 ccc \u53C2\u6570\uFF0C\u9632\u8BEF\u53D1\u4ED6\u5BB9\u5668\uFF09\u2192 weixin-bridge.sendProactiveText \u2192\n \u6210\u529F\u540E\u89E6\u53D1 outgoing hook\uFF08source=\"proactive\"\uFF09\u3002\u6587\u4EF6\u7528 action:\"send-file\" + file:\"<CCC \u5185\u8DEF\u5F84>\"\n \uFF08\u9003\u9038/\u7F3A\u5931/\u8D85 20MB \u62D2\u7EDD\uFF09+ \u53EF\u9009 caption\u3002**\u53EF\u89C1\u6027**\uFF1A\u672C CCC \u914D\u7F6E\u4E86 IM \u901A\u9053\n \uFF08weixin.enabled=true\uFF09\u624D\u51FA\u73B0\u5728\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u91CC\uFF1B\u672A\u914D\u7F6E \u2192 \u7531 guards \u9010 agent\n tools.restrict({deny:['im-bridge']}) \u79FB\u9664\uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002skiff \u89D2\u8272\u53E6\u9700\u5728\n roles.<role>.tools \u767D\u540D\u5355\u5217\u51FA im-bridge\u3002\n \u5386\u53F2\uFF08v1.30.9~v1.30.x\uFF09\uFF1ACCC \u4FA7 MSM weixin-send\uFF08\u8D70 loopback HTTP \u5165\u53E3 3082\uFF09\u2014\u2014\n v1.31.0 \u5DF2\u9000\u5F79\uFF08\u811A\u672C\u5220\u9664 + \u6CE8\u518C\u8868\u6CE8\u9500\uFF09\uFF1B3082 \u5165\u53E3\u4FDD\u7559\u7ED9**\u975E agent \u8C03\u7528\u8005**\u3002\n\n \u25B8 weixin.autoReplyWithLastMessage\uFF08v1.30.10\uFF0C\u5173\u95ED\u6865\u7684\u81EA\u52A8\u8F93\u51FA\uFF09\uFF1A\n \u7F3A\u7701 true = \u73B0\u72B6\uFF1A\u6865\u5728 agent \u4E00\u8F6E\u7ED3\u675F\u540E\u628A**\u6700\u7EC8 assistant \u6587\u672C**\u81EA\u52A8\u56DE\u53D1\u7528\u6237\uFF08source=\"reply\"\uFF09\u3002\n \u663E\u5F0F false = \u5173\u95ED\uFF1A\u6865**\u4E0D\u518D\u8F6C\u53D1\u6700\u7EC8\u6587\u672C**\uFF0C\u8F93\u51FA\u6743\u4EA4\u7ED9 agent\u2014\u2014\u6BCF\u8F6E\u5728\u7528\u6237\u6D88\u606F**\u672B\u5C3E**\u8FFD\u52A0\n **\u673A\u5236\u6807\u8BB0** [serenity:weixin-manual-output] + \u4E00\u884C\u5DF2\u586B\u597D\u53C2\u6570\u7684 im-bridge \u8C03\u7528\n \uFF08\u8D26\u53F7/\u7528\u6237 id\uFF09\uFF0Cagent \u81EA\u5DF1\u51B3\u5B9A\u53D1\u4EC0\u4E48\u3001\u53D1\u51E0\u6761\uFF08\u5168\u90E8\u8BB0 source=\"proactive\"\uFF09\u3002\n **ACC \u53EA\u7ED9\u673A\u5236\u4E0E\u6570\u636E\uFF0C\u7EAA\u5F8B\u63AA\u8F9E\u5F52 CCC**\uFF08v1.30.16\uFF09\uFF1A\u600E\u4E48\u5199/\u5FC5\u987B\u600E\u4E48\u505A/\u540E\u679C\u662F\u4EC0\u4E48\u5199\u5728\n CCC \u89D2\u8272\u63D0\u793A\u8BCD\u6587\u4EF6\u91CC\uFF08\u5982 .opencode/skiff/<role>.md\uFF09\uFF0C\u53EF\u70ED\u6539\uFF08v1.30.15 \u8D77\u89D2\u8272\u63D0\u793A\u8BCD\u70ED\u91CD\u8F7D\uFF09\u3002\n \u673A\u68B0\u95F8\u95E8\uFF08v1.30.16\uFF09\uFF1A\u672C\u8F6E turn \u7ED3\u675F\u4ECD\u672A\u6210\u529F\u8C03\u7528 im-bridge\uFF08send / send-file\uFF1B\u517C\u5BB9\u65E7\n msm(\"weixin-send\") \u5F62\u6001\uFF09\u2192 agent \u88AB\u6253\u56DE\uFF08\u22642 \u6B21\uFF0C\u63D0\u793A = \u6807\u8BB0 + \u4E8B\u5B9E\uFF09\uFF1B\u8FBE\u4E0A\u9650\u653E\u5F03\u5E76\u54CD\u4EAE\u544A\u8B66\u3002\n \u5931\u8D25\u8C03\u7528\u4E0D\u7B97\u5DF2\u9001\u8FBE\u3002\n \u8BED\u4E49\u8FB9\u754C\uFF08\u7528\u6237\u62CD\u677F\uFF09\uFF1A\u53EA\u5173\u6700\u7EC8\u6587\u672C\uFF1B\u7CFB\u7EDF\u7C7B\u6D88\u606F\uFF08\u65B0\u5BF9\u8BDD\u901A\u77E5 / \u8BED\u97F3\u65E0\u6CD5\u89E3\u6790\u63D0\u793A\uFF09\u4FDD\u7559\uFF1B\n typing \u6307\u793A\u4E0E incoming hook \u4E0D\u53D7\u5F71\u54CD\u3002\n\n \u25B8 weixin.fallbackOnNoSend\uFF08v1.30.17\uFF0C\u624B\u52A8\u6A21\u5F0F\u7684**\u515C\u5E95**\uFF1B\u7F3A\u7701 false\uFF09\uFF1A\n \u4EC5\u5728 autoReplyWithLastMessage=false \u65F6\u751F\u6548\u3002true \u2192 \u4E00\u8F6E\u7ED3\u675F\u65F6\u82E5 agent **\u4E00\u6B21\u90FD\u6CA1\u6210\u529F**\n \u8C03\u7528\u8F93\u51FA\u5DE5\u5177\uFF08\u95F8\u95E8\u6253\u56DE\u7528\u5C3D\uFF09\uFF0C\u6865\u628A\u8BE5\u8F6E\u6700\u7EC8\u6587\u672C\u8F6C\u53D1\u7ED9\u7528\u6237\uFF08\u8BB0\u5F55 source=\"reply-fallback\"\uFF0C\n \u65E5\u5FD7\u7559\u54CD\u4EAE\u544A\u8B66\uFF09\u2014\u2014\u4FDD\u8BC1\"\u4E0D\u4E22\u6D88\u606F\"\u3002agent \u81EA\u5DF1\u53D1\u8FC7 \u2192 \u4E0D\u515C\u5E95\uFF08\u8F93\u51FA\u6743\u4ECD\u5728 agent\uFF09\u3002\n \u4E3A\u4EC0\u4E48\u9700\u8981\uFF08\u5B9E\u8BC1\uFF09\uFF1Av1.30.16 \u95F8\u95E8\u4F1A\u6253\u56DE \u22642 \u6B21\uFF0C\u4F46\u5B9E\u6D4B\u67D0\u6A21\u578B\u5728**\u5BD2\u6684\u7C7B\u6D88\u606F**\u4E0A\u8FDE\u7EED 4 \u8F6E\u3001\n \u8DE8 3 \u7248 CCC \u63D0\u793A\u8BCD\u4ECD\u4E0D\u8C03\u5DE5\u5177 \u2192 \u6253\u56DE\u7528\u5C3D\u540E\u7528\u6237\u4EC0\u4E48\u90FD\u6536\u4E0D\u5230\uFF1B\u63D0\u793A\u8BCD\u4E0E\u95F8\u95E8\u5747\u5DF2\u6392\u9664\u3002\n \u4EE3\u4EF7\uFF08\u663E\u5F0F\uFF09\uFF1A\u89D2\u8272\u5931\u53BB\"\u6545\u610F\u9759\u9ED8\"\u80FD\u529B\uFF08\u5B83\u603B\u4F1A\u4EA7\u51FA\u4E00\u6BB5\u6700\u7EC8\u6587\u672C\uFF09\u2192 \u9700\u4E25\u683C\u9759\u9ED8\u7684\u89D2\u8272\u4FDD\u6301\u7F3A\u7701\u3002\n \u4E09\u6001\uFF1A\u2460 autoReplyWithLastMessage=true\uFF08\u7F3A\u7701\uFF09\u6865\u603B\u662F\u56DE\u53D1\uFF1B\u2461 =false + fallbackOnNoSend=true\n = agent \u4F18\u5148\u3001\u6865\u515C\u5E95\uFF08\u63A8\u8350\uFF09\uFF1B\u2462 \u4E24\u8005\u7686 false\uFF08\u7F3A\u7701\uFF09= \u4E25\u683C\u9759\u9ED8\uFF08v1.30.10 \u8BED\u4E49\uFF09\u3002\n \u26A0\uFE0F \u515C\u5E95\u53EA\u5728**\u95F8\u95E8\u88C5\u914D\u6210\u529F**\u65F6\u751F\u6548\uFF08\u672A\u88C5\u914D\u5219\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u53D1\u9001\u8FC7 \u2192 \u4E0D\u5192\u91CD\u590D\u53D1\u9001\u98CE\u9669\uFF09\u3002\n\n Config:\n { \"weixin\": {\n \"enabled\": true,\n \"hook\": \"scripts/weixin-message-hook.ts\",\n \"autoReplyWithLastMessage\": true,\n \"fallbackOnNoSend\": false,\n \"accounts\": [{ \"accountId\": \"wechat-1\", \"name\": \"\u5BB6\u5EAD\u52A9\u624B\", \"enabled\": true }],\n \"routes\": [{ \"user\": \"*\", \"role\": \"zhaocai\" }]\n } }\n\n \u25B8 weixin.hook\uFF08\u6D88\u606F\u8BB0\u5F55 hook\uFF0Cv1.27.13\uFF09\uFF1A\n \u5FAE\u4FE1\u6865\u6BCF\u6536/\u53D1\u4E00\u6761\u6D88\u606F\u89E6\u53D1\u4E00\u6B21 CCC \u81EA\u5199\u811A\u672C\uFF0C\u7531 CCC \u81EA\u884C\u6301\u4E45\u5316\u4FDD\u5B58\uFF08\u5B58\u54EA/\u5B58\u6210\u4EC0\u4E48\n /\u662F\u5426\u5165\u5E93\u5168\u5F52 CCC\u2014\u2014ACC \u4E0D\u7ED1\u5B9A\u5B58\u50A8\uFF09\u3002\u672A\u914D\u7F6E hook \u2192 \u96F6\u53D8\u5316\uFF08\u4E0D\u89E6\u53D1\uFF09\u3002\n\n \u89E6\u53D1\uFF08\u53CC\u5411\uFF09\uFF1A\n incoming = \u7528\u6237 \u2192 bot\uFF1A\u8DEF\u7531\u547D\u4E2D\u540E\u3001\u5A92\u4F53\u843D\u76D8\u540E\u89E6\u53D1\uFF08\u6587\u672C\u542B\u8BED\u97F3\u8F6C\u5199\uFF1B\u5A92\u4F53\u5E26\u843D\u76D8 relPath\uFF09\n outgoing = bot \u2192 \u7528\u6237\uFF1A\u53D1\u9001\u6210\u529F\u540E\u89E6\u53D1\uFF08reply = \u7528\u6237\u5B9E\u9645\u6536\u5230\u7684\u7EAF\u6587\u672C\uFF0C\u5DF2\u5265\u79BB think\uFF09\n \u00B7 source=\"reply\"\uFF08\u7F3A\u7701\uFF09= \u56DE\u590D\u7528\u6237\u6D88\u606F\uFF1Bsource=\"proactive\"\uFF08v1.30.9\uFF09= bot \u4E3B\u52A8\u53D1\u8D77\n \uFF08CCC \u7ECF im-bridge \u5DE5\u5177\uFF08v1.31.0\uFF1B\u65E7 weixin-send MSM \u5DF2\u9000\u5F79\uFF09\u2192 sendProactiveText\uFF09\uFF1B\n source=\"reply-fallback\"\uFF08v1.30.17\uFF09= \u624B\u52A8\u6A21\u5F0F\u4E0B agent \u672C\u8F6E\u672A\u53D1\u9001 \u2192 \u6865\u515C\u5E95\u8F6C\u53D1\u6700\u7EC8\u6587\u672C\n \u00B7 file\uFF08\u4EC5 send-file \u8865\u8BB0\uFF09\uFF1A{ \"name\": \"\u62A5\u544A.pdf\", \"size\": 12345, \"caption\": \"\u53EF\u9009\" }\n\n \u811A\u672C\u7EA6\u5B9A\uFF08\u4E8B\u4EF6 JSON \u5355\u884C\u7ECF stdin \u4F20\u5165\uFF1Bbun \u4F18\u5148 node \u515C\u5E95\uFF09\uFF1A\n #!/usr/bin/env bun \u6216 node script.js \u2014\u2014 \u8BFB process.stdin \u6574\u6BB5 JSON.parse\n const ev = JSON.parse(await new Response(process.stdin).text())\n ev.event === 'incoming' | 'outgoing'\n\n \u4E8B\u4EF6 schema\uFF08**\u4E0D\u542B\u4EFB\u4F55\u4F1A\u8BDD\u51ED\u636E**\u2014\u2014context_token/bot_token/token/aes_key \u5747\u4E0D\u51FA\u73B0\uFF09\uFF1A\n { \"event\": \"incoming\", \"ts\": 1788359941488, \"cccRoot\": \"/path/ccc\",\n \"accountId\": \"wechat-1\", \"userId\": \"u1@im.wechat\",\n \"sessionId\": \"skiff-weixin-xxx\", \"role\": \"zhaocai\",\n \"message\": { \"text\": \"\u4F60\u597D\", \"media\": [{ \"kind\": \"image\", \"relPath\": \"_tmp/weixin-inbound/<hash>/img_x.jpg\" }] } }\n { \"event\": \"outgoing\", \"ts\": ..., \"cccRoot\": ..., \"accountId\": ...,\n \"userId\": ..., \"sessionId\": ..., \"role\": ...,\n \"reply\": \"\u5DF2\u8BB0\u5F55\uFF08\u7EAF\u6587\u672C\uFF09\", \"source\": \"reply\" | \"proactive\" | \"reply-fallback\" }\n\n \u793A\u4F8B\u811A\u672C\uFF08\u8FFD\u52A0\u5230\u6309\u65E5\u6587\u4EF6\u2014\u2014\u6301\u4E45\u5316\u5F52 CCC \u81EA\u9009\uFF1A\u6587\u4EF6/DB/\u8FDC\u7AEF\u5747\u53EF\uFF09\uFF1A\n const fs = require('node:fs'); const p = '/path/ccc/AGENT_SESSIONS/_weixin-log.jsonl';\n fs.appendFileSync(p, JSON.stringify(ev) + '\\n');\n\n \u6267\u884C\u8BED\u4E49\uFF08\u65C1\u8DEF\u5BB9\u5FCD\uFF09\uFF1A\u5F02\u6B65 fire-and-forget + 15s \u8D85\u65F6 kill + \u5931\u8D25\u4EC5\u65E5\u5FD7\u2014\u2014\n \u5FAE\u4FE1\u6865\u6D88\u606F\u5904\u7406/\u56DE\u590D\u4E0D\u53D7 hook \u5F71\u54CD\uFF1B\u811A\u672C\u987B\u5728 CCC \u6839\u5185\uFF08\u8DEF\u5F84\u9003\u9038\u62D2\u7EDD\uFF09\u3002\n \u5A92\u4F53 relPath \u6307\u5411 _tmp/weixin-inbound/\uFF08\u4E34\u65F6\u76EE\u5F55\uFF09\u2014\u2014\u9700\u6301\u4E45\u4FDD\u5B58\u5A92\u4F53\u6587\u4EF6\u8BF7\u81EA\u884C copy\u3002\n";
|
|
22
|
+
export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. handyman.models \u2500\u2500\nhandyman\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 handyman \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 handyman.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n\n Config:\n { \"handyman\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"handyman\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\", \"maxRounds\": 100, \"maxParallel\": 10 } }\n\n\u2500\u2500 2. sessionKeeper.threshold / sessionKeeper.sessionMdMaxKB \u2500\u2500\ntrajectory-assistant\uFF08TRAJECTORY-ASSISTANT \u00B7 CHECKPOINT\uFF09\u63D0\u9192\u673A\u5236\u7684\u79EF\u5206\u9608\u503C\uFF08\u975E headless \u4E3B agent\uFF09\u3002\n\u6309\u5DE5\u5177\u8C03\u7528\u52A0\u6743 + \u8017\u65F6\u8BA1\u5206\uFF1B\u8FBE\u5230\u9608\u503C\u6CE8\u5165\u63D0\u9192\uFF0C\u8981\u6C42\u6A21\u578B\u56DE\u590D ACK \u7801\u3002\n\n Config:\n { \"sessionKeeper\": { \"threshold\": 150, \"sessionMdMaxKB\": 100 } }\n\n \u8BA1\u5206\uFF1Awrite/edit = 3\uFF0Ctask = 10\uFF0Cread/grep/glob/msm \u7B49 = 1\uFF0C\u65F6\u95F4 = 1/\u5206\u949F\n \u9ED8\u8BA4\uFF1A150\n\n \u25B8 sessionMdMaxKB\uFF08v1.31.1\uFF09\uFF1A**\u6D3B\u8DC3 SESSION.md \u4F53\u79EF\u4E0A\u9650\uFF08KB\uFF0C\u7F3A\u7701 100\uFF1B0 = \u5173\u95ED\uFF09**\u3002\n \u8D85\u8FC7 \u2192 \u6CE8\u5165 [TRAJECTORY-ASSISTANT \u00B7 LOGBOOK COMPACTION] \u63D0\u9192\uFF1A\u6682\u505C\u5F53\u524D\u5DE5\u4F5C \u2192\n \u52A0\u8F7D eap\uFF08praxis eap\uFF09\u2192 \u6309 EAP \u5206\u5C42\u9AA8\u67B6\u91CD\u5199 SESSION.md\u3002\u56DB\u6761\u539F\u5219\uFF08ACC \u5185\u5D4C\uFF0C\u968F\u63D0\u9192\u7ED9\u51FA\uFF09\uFF1A\n \u2460 \u4FDD\u7559 EAP \u5206\u5C42\u9AA8\u67B6\uFF08\u4E0D\u538B\u6210\u65F6\u95F4\u6D41\u6C34\u8D26\uFF09\u2461 \u5185\u5BB9\u53EF\u5916\u79FB\u5230 references \u6587\u4EF6\n \uFF08AGENT_SESSIONS/<\u4F1A\u8BDD>/references/*.md\uFF0CSESSION.md \u7559\u94FE\u63A5\uFF09\u2462 \u5141\u8BB8\u6574\u5408/\u5220\u9664\u4E0D\u91CD\u8981\u4E8B\u9879\n \uFF08\u88AB\u53D6\u4EE3\u7684\u51B3\u7B56\u3001\u5DF2\u89E3\u51B3\u95EE\u9898\u3001\u4E2D\u95F4\u6001\uFF09\u2463 \u81EA\u4E3B\u88C1\u91CF\u6743\u5145\u5206\u5141\u8BB8\uFF08\u552F\u4E00\u786C\u8981\u6C42 = \u9AA8\u67B6 +\n \u672A\u51B3\u9879/\u51B3\u7B56\u7406\u7531/\u4E0B\u4E00\u6B65\u4ECD\u53EF\u91CD\u5EFA\uFF09\u3002\u8D85\u9650\u6BCF\u8F6E\u63D0\u9192\uFF1B\u8FDE\u7EED 3 \u8F6E\u672A\u91CD\u5199 \u2192 \u5347\u7EA7\u5F3A\u5236\u8BED\u6C14\uFF1B\n \u6587\u4EF6\u56DE\u5230\u9650\u5185 \u2192 \u81EA\u52A8\u505C\u6B62\uFF08\u81EA\u6108\uFF09\u3002\u8F68\u8FF9\u63D0\u9192**\u4E0D\u673A\u68B0\u963B\u65AD\u5DE5\u4F5C**\uFF08\u4E0E rebuild \u63D0\u9192\u540C\u65CF\uFF09\u3002\n\n\u2500\u2500 3. localstore.gitTrack \u2500\u2500\nlocalstore.json \u7684 git \u7B56\u7565\uFF1Aallow \u53EF\u63D0\u4EA4 / deny \u7981\u63D0\u4EA4\uFF08\u9ED8\u8BA4 deny\uFF09\u3002\ndeny \u65F6\u5199\u5165\u81EA\u52A8\u786E\u4FDD .gitignore \u542B\u8BE5\u6587\u4EF6\uFF08\u7269\u7406\u4FDD\u8BC1\uFF09\uFF0Ccontainer_git commit \u4F1A\u68C0\u67E5\u62D2\u7EDD\u3002\n\n Config:\n { \"localstore\": { \"gitTrack\": \"allow\" } }\n\n\u2500\u2500 4. hooks.autoRestoreSession \u2500\u2500\n\u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\uFF08\u9ED8\u8BA4 true\uFF1B\u53D7 events \u95E8\u63A7\u2014\u2014\u4EC5\u6839\u4F1A\u8BDD + \u5DF2\u6709\u5BF9\u8BDD\u5386\u53F2\u624D\u6062\u590D\uFF09\u3002\n\n Config:\n { \"hooks\": { \"autoRestoreSession\": false } }\n\n\u2500\u2500 5. safeMode / blacklist \u2500\u2500\nsafe-mode \u7531 WebUI \u5F00\u5173\u63A7\u5236\uFF08\u5199 .serenity-safe-on \u6807\u8BB0\uFF09\uFF1B\u9ED1\u540D\u5355\u8DEF\u5F84\u53D7 guards seam \u62E6\u622A\u3002\n\n Config:\n { \"safeMode\": { \"blacklist\": [\".secrets/\"] } }\n\n\u2500\u2500 6. skiff.roles\uFF08F4 \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF09\u2500\u2500\nSkiff \u89D2\u8272 = \u5168\u77E5\u5168\u80FD trajectory \u7684\u4EFB\u610F\u5B50\u96C6\uFF08CCC \u5B9A\u4E49\uFF09\u3002\u6BCF\u89D2\u8272\u72EC\u7ACB\u6A21\u578B + \u53CC\u767D\u540D\u5355\n\uFF08MSM \u767D\u540D\u5355 msms[] \u4E0E\u975E MSM \u5DE5\u5177\u767D\u540D\u5355 tools[]\uFF0C\u767D\u540D\u5355\u5916\u5168\u9690\u85CF\uFF1Bskill \u52A0\u8F7D\u6052\u53EF\u7528\uFF09\u3002\ntrajectory \u7EAA\u5F8B\u5B50\u96C6\uFF08session/keeper/rebuild \u53C2\u4E0E\u9879\uFF09\u9ED8\u8BA4\u5168\u5173 = \u5B8C\u5168\u72EC\u7ACB\u3002\nsystemPrompt \u5185\u8054 \u6216 systemPromptFile\uFF08.md \u5F15\u7528\uFF0C\u63A8\u8350\uFF09\u2014\u2014\u89D2\u8272\u4F1A\u8BDD\u7684\u5B8C\u6574\u4EBA\u683C/\u8FB9\u754C\u63D0\u793A\u8BCD\u3002\nvalidate \u6821\u9A8C / apply \u751F\u6548 / list \u67E5\u770B\uFF1Acontainer_admin role <guide|validate|apply|list>\uFF08skiff_admin \u5DF2\u5E76\u5165\uFF09\u3002\n\n Config:\n { \"skiff\": { \"roles\": {\n \"qa\": {\n \"model\": \"provider/model\",\n \"msms\": [\"web-search\", \"vlm-describe\"],\n \"tools\": [\"read\", \"grep\", \"glob\"],\n \"systemPromptFile\": \".opencode/skiff/qa.md\"\n } } } }\n\n\u2500\u2500 7. autopilotTrajectory\uFF08\u81EA\u52A8\u5DE1\u822A\u8F68\u8FF9\uFF09\u2500\u2500\nCCC \u5B9A\u4E49\u7684\u4E00\u6761\u81EA\u4E3B trajectory\u2014\u2014\u65F6\u949F\u5230\u70B9\u81EA\u52A8\u5524\u8D77\uFF08\u524D\u53F0\u6CE8\u5165\uFF0C\u7528\u6237\u53EF\u89C1\u53EF\u4ECB\u5165\uFF09\u3002\n\u672A\u914D\u7F6E\u6216 enabled=false \u2192 \u5B8C\u5168\u4E0D\u542F\u52A8\uFF08\u96F6\u8D44\u6E90\u5360\u7528\uFF09\u3002\u591A CCC \u72EC\u7ACB\uFF1A\u6BCF CCC \u81EA\u5DF1\u7684\u914D\u7F6E\u3002\n\u5524\u8D77\u6D88\u606F\u56DB\u6BB5\u5F0F\uFF1A\u8F68\u8FF9\u7126\u70B9 topPrompt\uFF08\u6700\u5148\u6CE8\u5165\uFF0C\u7A33\u5B9A\u951A\uFF09\u2192 \u8EAB\u4EFD\u951A\u5B9A \u2192 \u5148\u9A8C\u504F\u89C1\n\uFF08CCC \u6839\u811A\u672C biasProvider \u8F93\u51FA\uFF09\u2192 \u4EFB\u52A1\u3002\u76EE\u6807\u4F1A\u8BDD session \u5FC5\u586B\uFF08\u76EE\u5F55\u987B\u5E26 --auto \u540E\u7F00\uFF09\u3002\n\u8BCA\u65AD/\u72B6\u6001/\u7ACB\u5373\u5524\u8D77\uFF1Aautopilot-trajectory <all|check|status|diag>\uFF08msm(\"autopilot-trajectory\", [\"all\"])\uFF09\u3002\n\n Config:\n { \"autopilotTrajectory\": {\n \"enabled\": true,\n \"intervalHours\": 2,\n \"session\": \"S151\",\n \"biasProvider\": \"autopilot-bias.ts\",\n \"topPrompt\": \"\u672C\u8F68\u8FF9\u6838\u5FC3\u76EE\u6807/\u7EAA\u5F8B/\u8D28\u91CF\u8981\u6C42\uFF08CCC \u81EA\u586B\uFF0C\u9632\u6F02\u79FB\uFF09\",\n \"avoidWakeHours\": { \"start\": 8, \"end\": 18 }\n } }\n\n\u2500\u2500 8. weixin\uFF08\u5FAE\u4FE1\u6865 F4c-3\uFF0C\u542B\u6D88\u606F\u8BB0\u5F55 hook\uFF09\u2500\u2500\nCCC \u7EA7\u5FAE\u4FE1\u4E2A\u4EBA\u53F7\u63A5\u5165\uFF08iLink \u534F\u8BAE\uFF09\uFF1Adsh \u4E00\u8FDB\u7A0B\u591A CCC\uFF0C\u6BCF CCC \u72EC\u7ACB\u5BF9\u63A5\u5FAE\u4FE1\u6865\u3002\n\u8D26\u53F7/\u8DEF\u7531/\u5F00\u5173\u5728\u6B64\u6587\u4EF6\uFF1B**bot_token \u51ED\u636E\u5728 CCC localstore credential scope**\n\uFF08\u626B\u7801\u7ED1\u5B9A\u540E\u81EA\u52A8\u5199\u5165\uFF0C\u6C38\u4E0D\u8FDB git \u660E\u6587\u9762\uFF09\u3002\n\u8DEF\u7531 user \u2192 role\uFF1Aexact \u4F18\u5148\uFF0C* \u901A\u914D\u515C\u5E95\uFF1Brole \u5FC5\u987B \u2208 \u8BE5 CCC skiff.roles\u3002\n\u9762\u677F\uFF08WebUI \u8BBE\u7F6E \u2192 \u5FAE\u4FE1\u6865\uFF09\u53EF\u626B\u7801\u7ED1\u5B9A/\u79FB\u9664\u8D26\u53F7/\u7F16\u8F91\u8DEF\u7531\uFF1Bmsm(\"weixin-doctor\", [\"status\"|\"diag\"|\"verify\"|\"guide\"]) \u6392\u67E5 + \u5927\u800C\u5168\u6307\u5357\u3002\u51ED\u636E\u4E3B\u52A8\u67E5\u770B\uFF1Alocalstore get WEIXIN_<ACCOUNT>_TOKEN\u3002\n \u25B8 \u4E3B\u52A8\u53D1\u9001\uFF08v1.31.0\uFF1A**ACC \u5DE5\u5177 im-bridge**\uFF09\uFF1A\u8C03\n im-bridge({channel:\"weixin\", action:\"send\", user:\"<\u522B\u540D|id>\", text:\"<\u6587\u672C>\"}) \u7ED9\u7528\u6237\u53D1\u6D88\u606F\u2014\u2014\n **\u5DE5\u5177\u53EA\u80FD\u64CD\u4F5C\u672C\u4F1A\u8BDD CCC**\uFF08\u65E0 ccc \u53C2\u6570\uFF0C\u9632\u8BEF\u53D1\u4ED6\u5BB9\u5668\uFF09\u2192 weixin-bridge.sendProactiveText \u2192\n \u6210\u529F\u540E\u89E6\u53D1 outgoing hook\uFF08source=\"proactive\"\uFF09\u3002\u6587\u4EF6\u7528 action:\"send-file\" + file:\"<CCC \u5185\u8DEF\u5F84>\"\n \uFF08\u9003\u9038/\u7F3A\u5931/\u8D85 20MB \u62D2\u7EDD\uFF09+ \u53EF\u9009 caption\u3002**\u53EF\u89C1\u6027**\uFF1A\u672C CCC \u914D\u7F6E\u4E86 IM \u901A\u9053\n \uFF08weixin.enabled=true\uFF09\u624D\u51FA\u73B0\u5728\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u91CC\uFF1B\u672A\u914D\u7F6E \u2192 \u7531 guards \u9010 agent\n tools.restrict({deny:['im-bridge']}) \u79FB\u9664\uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002skiff \u89D2\u8272\u53E6\u9700\u5728\n roles.<role>.tools \u767D\u540D\u5355\u5217\u51FA im-bridge\u3002\n \u5386\u53F2\uFF08v1.30.9~v1.30.x\uFF09\uFF1ACCC \u4FA7 MSM weixin-send\uFF08\u8D70 loopback HTTP \u5165\u53E3 3082\uFF09\u2014\u2014\n v1.31.0 \u5DF2\u9000\u5F79\uFF08\u811A\u672C\u5220\u9664 + \u6CE8\u518C\u8868\u6CE8\u9500\uFF09\uFF1B3082 \u5165\u53E3\u4FDD\u7559\u7ED9**\u975E agent \u8C03\u7528\u8005**\u3002\n\n \u25B8 weixin.autoReplyWithLastMessage\uFF08v1.30.10\uFF0C\u5173\u95ED\u6865\u7684\u81EA\u52A8\u8F93\u51FA\uFF09\uFF1A\n \u7F3A\u7701 true = \u73B0\u72B6\uFF1A\u6865\u5728 agent \u4E00\u8F6E\u7ED3\u675F\u540E\u628A**\u6700\u7EC8 assistant \u6587\u672C**\u81EA\u52A8\u56DE\u53D1\u7528\u6237\uFF08source=\"reply\"\uFF09\u3002\n \u663E\u5F0F false = \u5173\u95ED\uFF1A\u6865**\u4E0D\u518D\u8F6C\u53D1\u6700\u7EC8\u6587\u672C**\uFF0C\u8F93\u51FA\u6743\u4EA4\u7ED9 agent\u2014\u2014\u6BCF\u8F6E\u5728\u7528\u6237\u6D88\u606F**\u672B\u5C3E**\u8FFD\u52A0\n **\u673A\u5236\u6807\u8BB0** [serenity:weixin-manual-output] + \u4E00\u884C\u5DF2\u586B\u597D\u53C2\u6570\u7684 im-bridge \u8C03\u7528\n \uFF08\u8D26\u53F7/\u7528\u6237 id\uFF09\uFF0Cagent \u81EA\u5DF1\u51B3\u5B9A\u53D1\u4EC0\u4E48\u3001\u53D1\u51E0\u6761\uFF08\u5168\u90E8\u8BB0 source=\"proactive\"\uFF09\u3002\n **ACC \u53EA\u7ED9\u673A\u5236\u4E0E\u6570\u636E\uFF0C\u7EAA\u5F8B\u63AA\u8F9E\u5F52 CCC**\uFF08v1.30.16\uFF09\uFF1A\u600E\u4E48\u5199/\u5FC5\u987B\u600E\u4E48\u505A/\u540E\u679C\u662F\u4EC0\u4E48\u5199\u5728\n CCC \u89D2\u8272\u63D0\u793A\u8BCD\u6587\u4EF6\u91CC\uFF08\u5982 .opencode/skiff/<role>.md\uFF09\uFF0C\u53EF\u70ED\u6539\uFF08v1.30.15 \u8D77\u89D2\u8272\u63D0\u793A\u8BCD\u70ED\u91CD\u8F7D\uFF09\u3002\n \u673A\u68B0\u95F8\u95E8\uFF08v1.30.16\uFF09\uFF1A\u672C\u8F6E turn \u7ED3\u675F\u4ECD\u672A\u6210\u529F\u8C03\u7528 im-bridge\uFF08send / send-file\uFF1B\u517C\u5BB9\u65E7\n msm(\"weixin-send\") \u5F62\u6001\uFF09\u2192 agent \u88AB\u6253\u56DE\uFF08\u22642 \u6B21\uFF0C\u63D0\u793A = \u6807\u8BB0 + \u4E8B\u5B9E\uFF09\uFF1B\u8FBE\u4E0A\u9650\u653E\u5F03\u5E76\u54CD\u4EAE\u544A\u8B66\u3002\n \u5931\u8D25\u8C03\u7528\u4E0D\u7B97\u5DF2\u9001\u8FBE\u3002\n \u8BED\u4E49\u8FB9\u754C\uFF08\u7528\u6237\u62CD\u677F\uFF09\uFF1A\u53EA\u5173\u6700\u7EC8\u6587\u672C\uFF1B\u7CFB\u7EDF\u7C7B\u6D88\u606F\uFF08\u65B0\u5BF9\u8BDD\u901A\u77E5 / \u8BED\u97F3\u65E0\u6CD5\u89E3\u6790\u63D0\u793A\uFF09\u4FDD\u7559\uFF1B\n typing \u6307\u793A\u4E0E incoming hook \u4E0D\u53D7\u5F71\u54CD\u3002\n\n \u25B8 weixin.fallbackOnNoSend\uFF08v1.30.17\uFF0C\u624B\u52A8\u6A21\u5F0F\u7684**\u515C\u5E95**\uFF1B\u7F3A\u7701 false\uFF09\uFF1A\n \u4EC5\u5728 autoReplyWithLastMessage=false \u65F6\u751F\u6548\u3002true \u2192 \u4E00\u8F6E\u7ED3\u675F\u65F6\u82E5 agent **\u4E00\u6B21\u90FD\u6CA1\u6210\u529F**\n \u8C03\u7528\u8F93\u51FA\u5DE5\u5177\uFF08\u95F8\u95E8\u6253\u56DE\u7528\u5C3D\uFF09\uFF0C\u6865\u628A\u8BE5\u8F6E\u6700\u7EC8\u6587\u672C\u8F6C\u53D1\u7ED9\u7528\u6237\uFF08\u8BB0\u5F55 source=\"reply-fallback\"\uFF0C\n \u65E5\u5FD7\u7559\u54CD\u4EAE\u544A\u8B66\uFF09\u2014\u2014\u4FDD\u8BC1\"\u4E0D\u4E22\u6D88\u606F\"\u3002agent \u81EA\u5DF1\u53D1\u8FC7 \u2192 \u4E0D\u515C\u5E95\uFF08\u8F93\u51FA\u6743\u4ECD\u5728 agent\uFF09\u3002\n \u4E3A\u4EC0\u4E48\u9700\u8981\uFF08\u5B9E\u8BC1\uFF09\uFF1Av1.30.16 \u95F8\u95E8\u4F1A\u6253\u56DE \u22642 \u6B21\uFF0C\u4F46\u5B9E\u6D4B\u67D0\u6A21\u578B\u5728**\u5BD2\u6684\u7C7B\u6D88\u606F**\u4E0A\u8FDE\u7EED 4 \u8F6E\u3001\n \u8DE8 3 \u7248 CCC \u63D0\u793A\u8BCD\u4ECD\u4E0D\u8C03\u5DE5\u5177 \u2192 \u6253\u56DE\u7528\u5C3D\u540E\u7528\u6237\u4EC0\u4E48\u90FD\u6536\u4E0D\u5230\uFF1B\u63D0\u793A\u8BCD\u4E0E\u95F8\u95E8\u5747\u5DF2\u6392\u9664\u3002\n \u4EE3\u4EF7\uFF08\u663E\u5F0F\uFF09\uFF1A\u89D2\u8272\u5931\u53BB\"\u6545\u610F\u9759\u9ED8\"\u80FD\u529B\uFF08\u5B83\u603B\u4F1A\u4EA7\u51FA\u4E00\u6BB5\u6700\u7EC8\u6587\u672C\uFF09\u2192 \u9700\u4E25\u683C\u9759\u9ED8\u7684\u89D2\u8272\u4FDD\u6301\u7F3A\u7701\u3002\n \u4E09\u6001\uFF1A\u2460 autoReplyWithLastMessage=true\uFF08\u7F3A\u7701\uFF09\u6865\u603B\u662F\u56DE\u53D1\uFF1B\u2461 =false + fallbackOnNoSend=true\n = agent \u4F18\u5148\u3001\u6865\u515C\u5E95\uFF08\u63A8\u8350\uFF09\uFF1B\u2462 \u4E24\u8005\u7686 false\uFF08\u7F3A\u7701\uFF09= \u4E25\u683C\u9759\u9ED8\uFF08v1.30.10 \u8BED\u4E49\uFF09\u3002\n \u26A0\uFE0F \u515C\u5E95\u53EA\u5728**\u95F8\u95E8\u88C5\u914D\u6210\u529F**\u65F6\u751F\u6548\uFF08\u672A\u88C5\u914D\u5219\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u53D1\u9001\u8FC7 \u2192 \u4E0D\u5192\u91CD\u590D\u53D1\u9001\u98CE\u9669\uFF09\u3002\n\n Config:\n { \"weixin\": {\n \"enabled\": true,\n \"hook\": \"scripts/weixin-message-hook.ts\",\n \"autoReplyWithLastMessage\": true,\n \"fallbackOnNoSend\": false,\n \"accounts\": [{ \"accountId\": \"wechat-1\", \"name\": \"\u5BB6\u5EAD\u52A9\u624B\", \"enabled\": true }],\n \"routes\": [{ \"user\": \"*\", \"role\": \"zhaocai\" }]\n } }\n\n \u25B8 weixin.hook\uFF08\u6D88\u606F\u8BB0\u5F55 hook\uFF0Cv1.27.13\uFF09\uFF1A\n \u5FAE\u4FE1\u6865\u6BCF\u6536/\u53D1\u4E00\u6761\u6D88\u606F\u89E6\u53D1\u4E00\u6B21 CCC \u81EA\u5199\u811A\u672C\uFF0C\u7531 CCC \u81EA\u884C\u6301\u4E45\u5316\u4FDD\u5B58\uFF08\u5B58\u54EA/\u5B58\u6210\u4EC0\u4E48\n /\u662F\u5426\u5165\u5E93\u5168\u5F52 CCC\u2014\u2014ACC \u4E0D\u7ED1\u5B9A\u5B58\u50A8\uFF09\u3002\u672A\u914D\u7F6E hook \u2192 \u96F6\u53D8\u5316\uFF08\u4E0D\u89E6\u53D1\uFF09\u3002\n\n \u89E6\u53D1\uFF08\u53CC\u5411\uFF09\uFF1A\n incoming = \u7528\u6237 \u2192 bot\uFF1A\u8DEF\u7531\u547D\u4E2D\u540E\u3001\u5A92\u4F53\u843D\u76D8\u540E\u89E6\u53D1\uFF08\u6587\u672C\u542B\u8BED\u97F3\u8F6C\u5199\uFF1B\u5A92\u4F53\u5E26\u843D\u76D8 relPath\uFF09\n outgoing = bot \u2192 \u7528\u6237\uFF1A\u53D1\u9001\u6210\u529F\u540E\u89E6\u53D1\uFF08reply = \u7528\u6237\u5B9E\u9645\u6536\u5230\u7684\u7EAF\u6587\u672C\uFF0C\u5DF2\u5265\u79BB think\uFF09\n \u00B7 source=\"reply\"\uFF08\u7F3A\u7701\uFF09= \u56DE\u590D\u7528\u6237\u6D88\u606F\uFF1Bsource=\"proactive\"\uFF08v1.30.9\uFF09= bot \u4E3B\u52A8\u53D1\u8D77\n \uFF08CCC \u7ECF im-bridge \u5DE5\u5177\uFF08v1.31.0\uFF1B\u65E7 weixin-send MSM \u5DF2\u9000\u5F79\uFF09\u2192 sendProactiveText\uFF09\uFF1B\n source=\"reply-fallback\"\uFF08v1.30.17\uFF09= \u624B\u52A8\u6A21\u5F0F\u4E0B agent \u672C\u8F6E\u672A\u53D1\u9001 \u2192 \u6865\u515C\u5E95\u8F6C\u53D1\u6700\u7EC8\u6587\u672C\n \u00B7 file\uFF08\u4EC5 send-file \u8865\u8BB0\uFF09\uFF1A{ \"name\": \"\u62A5\u544A.pdf\", \"size\": 12345, \"caption\": \"\u53EF\u9009\" }\n\n \u811A\u672C\u7EA6\u5B9A\uFF08\u4E8B\u4EF6 JSON \u5355\u884C\u7ECF stdin \u4F20\u5165\uFF1Bbun \u4F18\u5148 node \u515C\u5E95\uFF09\uFF1A\n #!/usr/bin/env bun \u6216 node script.js \u2014\u2014 \u8BFB process.stdin \u6574\u6BB5 JSON.parse\n const ev = JSON.parse(await new Response(process.stdin).text())\n ev.event === 'incoming' | 'outgoing'\n\n \u4E8B\u4EF6 schema\uFF08**\u4E0D\u542B\u4EFB\u4F55\u4F1A\u8BDD\u51ED\u636E**\u2014\u2014context_token/bot_token/token/aes_key \u5747\u4E0D\u51FA\u73B0\uFF09\uFF1A\n { \"event\": \"incoming\", \"ts\": 1788359941488, \"cccRoot\": \"/path/ccc\",\n \"accountId\": \"wechat-1\", \"userId\": \"u1@im.wechat\",\n \"sessionId\": \"skiff-weixin-xxx\", \"role\": \"zhaocai\",\n \"message\": { \"text\": \"\u4F60\u597D\", \"media\": [{ \"kind\": \"image\", \"relPath\": \"_tmp/weixin-inbound/<hash>/img_x.jpg\" }] } }\n { \"event\": \"outgoing\", \"ts\": ..., \"cccRoot\": ..., \"accountId\": ...,\n \"userId\": ..., \"sessionId\": ..., \"role\": ...,\n \"reply\": \"\u5DF2\u8BB0\u5F55\uFF08\u7EAF\u6587\u672C\uFF09\", \"source\": \"reply\" | \"proactive\" | \"reply-fallback\" }\n\n \u793A\u4F8B\u811A\u672C\uFF08\u8FFD\u52A0\u5230\u6309\u65E5\u6587\u4EF6\u2014\u2014\u6301\u4E45\u5316\u5F52 CCC \u81EA\u9009\uFF1A\u6587\u4EF6/DB/\u8FDC\u7AEF\u5747\u53EF\uFF09\uFF1A\n const fs = require('node:fs'); const p = '/path/ccc/AGENT_SESSIONS/_weixin-log.jsonl';\n fs.appendFileSync(p, JSON.stringify(ev) + '\\n');\n\n \u6267\u884C\u8BED\u4E49\uFF08\u65C1\u8DEF\u5BB9\u5FCD\uFF09\uFF1A\u5F02\u6B65 fire-and-forget + 15s \u8D85\u65F6 kill + \u5931\u8D25\u4EC5\u65E5\u5FD7\u2014\u2014\n \u5FAE\u4FE1\u6865\u6D88\u606F\u5904\u7406/\u56DE\u590D\u4E0D\u53D7 hook \u5F71\u54CD\uFF1B\u811A\u672C\u987B\u5728 CCC \u6839\u5185\uFF08\u8DEF\u5F84\u9003\u9038\u62D2\u7EDD\uFF09\u3002\n \u5A92\u4F53 relPath \u6307\u5411 _tmp/weixin-inbound/\uFF08\u4E34\u65F6\u76EE\u5F55\uFF09\u2014\u2014\u9700\u6301\u4E45\u4FDD\u5B58\u5A92\u4F53\u6587\u4EF6\u8BF7\u81EA\u884C copy\u3002\n";
|
|
23
23
|
export interface MsmFlag {
|
|
24
24
|
name: string;
|
|
25
25
|
type?: string;
|
package/lib/seams/keeper.d.ts
CHANGED
|
@@ -40,6 +40,11 @@ export declare function reminderText(code: string, score: number): string;
|
|
|
40
40
|
*
|
|
41
41
|
* 需求①(S142 用户拍板):百分比比例 → K 数值——tokensK = 实际占用(千 token),
|
|
42
42
|
* thresholdK = 配置阈值(千 token);文案 `Context usage at NNNK (threshold NNNK)`。
|
|
43
|
+
*
|
|
44
|
+
* v1.31.1 交接协议(S142 用户需求"要求 LLM 将当前手头事项写在 SESSION.md 尾部,并要求
|
|
45
|
+
* rebuild 后去读并处理"):**写侧** = 这里(两条文案都要求把 in-flight 事项写在
|
|
46
|
+
* SESSION.md 末尾的 `IN_FLIGHT_HEADING` 之下);**读侧** = rebuild 锚点(rebuild.ts)。
|
|
47
|
+
* 两侧共用 trajectory-assistant 的标题常量(单一真相源)。
|
|
43
48
|
*/
|
|
44
49
|
export declare function rebuildReminderText(tokensK: number, thresholdK: number, escalated?: boolean): string;
|
|
45
50
|
/** 读取会话 contextPressure 投影(sessionProjections 可选服务;未装配返回 null) */
|
|
@@ -47,6 +52,53 @@ export declare function readContextPressure(ctx: Context, session: unknown): {
|
|
|
47
52
|
projectedTokens: number;
|
|
48
53
|
contextWindow: number | undefined;
|
|
49
54
|
} | null;
|
|
55
|
+
/**
|
|
56
|
+
* 活跃 SESSION.md 体积上限缺省值(KB)。
|
|
57
|
+
* CCC 级可覆盖:`.opencode/serenity.json` → `sessionKeeper.sessionMdMaxKB`(0 = 关闭)。
|
|
58
|
+
*/
|
|
59
|
+
export declare const DEFAULT_SESSION_MD_MAX_KB = 100;
|
|
60
|
+
interface CompactionState {
|
|
61
|
+
/** 连续超限轮数(文件降回限内即清零 → 重写完成后自动停止提醒) */
|
|
62
|
+
consecutive: number;
|
|
63
|
+
}
|
|
64
|
+
/** 测试/调试:查看超限提醒状态 */
|
|
65
|
+
export declare function compactionStateSnapshot(): ReadonlyMap<string, CompactionState>;
|
|
66
|
+
/** 会话销毁/测试重置:清理路径缓存与超限计数(防 per-会话 Map 无界增长,review F-08 同族) */
|
|
67
|
+
export declare function forgetLogbookCompactionState(scope: string): void;
|
|
68
|
+
/** 测试辅助:清空全部缓存(含 root 维度的阈值缓存) */
|
|
69
|
+
export declare function __resetLogbookCompactionForTest(): void;
|
|
70
|
+
/**
|
|
71
|
+
* 解析**活跃** SESSION.md 绝对路径(缓存 60s)。
|
|
72
|
+
*
|
|
73
|
+
* 候选链(刻意比 rebuild 的完整链短——这里每个工具调用都要跑,贵候选不划算):
|
|
74
|
+
* ① `getActiveSessionInfo(scope).mdPath`(`logbook use` / skiff 绑定 / 重启恢复都会写)
|
|
75
|
+
* ② `readLastBound(session).mdPath`(`.bindings.json` 权威绑定——重启后内存空时兜底)
|
|
76
|
+
* 两者都拿不到 → null(**不猜**:宁可不提醒,也不去猜别的轨迹——对齐 v1.30.13 D4 的教训)。
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveActiveSessionMdPath(root: string, scope: string, session: unknown, now?: () => number): string | null;
|
|
79
|
+
/** 读文件字节数(读不到 → null,不抛错) */
|
|
80
|
+
export declare function readFileSize(absPath: string): number | null;
|
|
81
|
+
/** 读该 CCC 的 SESSION.md 体积上限(KB;缓存 60s;0 = 关闭提醒) */
|
|
82
|
+
export declare function readSessionMdMaxKB(root: string, configPaths?: string[], now?: () => number): number;
|
|
83
|
+
/**
|
|
84
|
+
* LOGBOOK COMPACTION 提醒文案(v1.31.1)。
|
|
85
|
+
*
|
|
86
|
+
* 归属(D23 + 用户 2026-09-09 拍板):**ACC 内嵌机制事实 + 4 条重写原则**——理由:这 4 条是
|
|
87
|
+
* 认知质量规范(与 EAP 同层,不是会随角色迭代的措辞),且未配置任何 CCC 文档的容器也要立刻可用。
|
|
88
|
+
*
|
|
89
|
+
* 四条原则(用户原话逐条落成可执行判据):
|
|
90
|
+
* ① 保留 EAP 分层骨架(不许压成时间流水账)
|
|
91
|
+
* ② 内容可外移到 references 文件(证据链/日志/参考资料 → `AGENT_SESSIONS/<会话>/references/*.md`,
|
|
92
|
+
* 在 SESSION.md 里留链接)
|
|
93
|
+
* ③ 允许整合不重要事项(被取代的决策 / 已解决问题 / 中间态)
|
|
94
|
+
* ④ 自主裁量权充分允许(唯一硬要求 = 骨架 + 未决项/决策理由/下一步仍可重建)
|
|
95
|
+
*/
|
|
96
|
+
export declare function logbookCompactionReminderText(input: {
|
|
97
|
+
sizeKB: number;
|
|
98
|
+
limitKB: number;
|
|
99
|
+
mdPath: string;
|
|
100
|
+
escalated?: boolean;
|
|
101
|
+
}): string;
|
|
50
102
|
export interface KeeperRegistration {
|
|
51
103
|
/** 缺省阈值(serenity.json sessionKeeper.threshold 优先,其次此值) */
|
|
52
104
|
defaultThreshold?: number;
|
|
@@ -30,6 +30,8 @@ export declare const EVENT_LABEL: {
|
|
|
30
30
|
readonly rebuild: "REBUILD";
|
|
31
31
|
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
32
32
|
readonly guard: "BOUNDARY GUARD";
|
|
33
|
+
/** SESSION.md 体积超限重写提醒(v1.31.1,S142 用户需求) */
|
|
34
|
+
readonly compaction: "LOGBOOK COMPACTION";
|
|
33
35
|
};
|
|
34
36
|
/** 家族标识(所有动态注入统一前缀) */
|
|
35
37
|
export declare const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
@@ -38,6 +40,17 @@ export declare function eventToken(event: keyof typeof EVENT_LABEL): string;
|
|
|
38
40
|
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
39
41
|
export declare const ACK_PREFIX = "TRAJECTORY-ASSISTANT-recorded";
|
|
40
42
|
export declare const ACK_SKIP_PREFIX = "TRAJECTORY-ASSISTANT-skipped";
|
|
43
|
+
/**
|
|
44
|
+
* rebuild 交接区块标题(v1.31.1,S142 用户需求)。
|
|
45
|
+
*
|
|
46
|
+
* 用途:rebuild 提醒要求模型把**当前手头事项**写到 SESSION.md **末尾**的这个小标题之下;
|
|
47
|
+
* rebuild 锚点随后要求重建后的自己去读这一段并处理。两侧引用**同一个常量**——
|
|
48
|
+
* 标题一旦漂移,读侧就找不到写侧写的东西(单一真相源)。
|
|
49
|
+
*
|
|
50
|
+
* 形态(用户拍板 Q2):**固定英文标题行**(不是 HTML 注释锚)——人读友好;ACC 写死英文,
|
|
51
|
+
* 因为 SESSION.md 的正文语言归 CCC,但两侧的**机械锚点**必须逐字一致。
|
|
52
|
+
*/
|
|
53
|
+
export declare const IN_FLIGHT_HEADING = "## In-flight (rebuild handover)";
|
|
41
54
|
/** 风格档位:plain(默认,精确文本)/ metaphor(借星舰词——产品隐喻非游戏词) */
|
|
42
55
|
export type TrajectoryStyle = 'plain' | 'metaphor';
|
|
43
56
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.31.
|
|
4
|
-
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:
|
|
3
|
+
"version": "1.31.1",
|
|
4
|
+
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:11 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory/im-bridge)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.2-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|