@shgroup/dsh-serenity-hooks 1.69.1 → 1.69.2

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 CHANGED
@@ -275,7 +275,8 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
275
275
 
276
276
  ### 6.4 对外接入(官方 ACP)
277
277
 
278
- 本插件**不自造** ACP 面。要程序化或远程使用,用宿主自带的官方 ACP server:
278
+ **本插件不提供 ACP 面** —— 既不提供当年那种自造 HTTP 面,也不提供跑在 `dsh web` 进程内的
279
+ 那一版(后者已在 v1.69.1 整面删除)。要程序化或远程使用,用宿主自带的官方 ACP server:
279
280
 
280
281
  | 步 | 做什么 |
281
282
  |---|---|
@@ -283,8 +284,10 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
283
284
  | 2 | 用任一 ACP 客户端连它(编辑器内直接起子进程;手机/远程经桥 + 隧道) |
284
285
  | 3 | **认证放在接入层**(隧道 / 反代 / Cloudflare Access)——官方 server 自身不做认证 |
285
286
 
286
- > **为什么不再自造**:原 3100 面是一个**没有客户端生态**的私有外壳,而官方件已发布并随宿主同版本演进。
287
- > 详细接法与手机端配置见宁静号 CCC 的接入指南。
287
+ > **为什么不自造**:原 3100 面是一个**没有客户端生态**的私有外壳,而官方件已发布并随宿主同版本演进。
288
+ > **为什么连进程内那版也删掉**:`dsh-acp` 没有 `session/load`,且 `session/resume` 不回放历史
289
+ > ⇒ 客户端每次连上只能新建会话、看不到既有对话。对一个以「长期认知轨迹」为核心的系统,
290
+ > 那是结构性障碍,不是体验问题。⇒ 详见 CHANGELOG 的 v1.69.1。
288
291
 
289
292
  ### 6.5 认知轨迹与定时唤醒(cognitive trajectory)
290
293
 
@@ -345,7 +348,7 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
345
348
 
346
349
  | 层 | 位置 | 放什么 |
347
350
  |---|---|---|
348
- | DSH 原生设置 | DSH 的 settings.yaml(即设置面板那几项) | 开关与阈值:网关总开关、重建阈值、子角色开关与调试端口、**CRO 总闸(`croEnabled`,默认为开)**、**图工具总闸(默认关)**、**官方 ACP 面(`acpFaceEnabled`,默认关)** |
351
+ | DSH 原生设置 | DSH 的 settings.yaml(即设置面板那几项) | 开关与阈值:网关总开关、重建阈值、子角色开关与调试端口、**CRO 总闸(`croEnabled`,默认为开)**、**图工具总闸(默认关)** |
349
352
  | 插件全局文件 | `~/.dsh/serenity-hooks.json`(权限 0600) | 网关账号(scrypt + TOTP)、监听地址与端口、工作区白名单、cookie 安全开关 |
350
353
  | 工作区配置 | `.opencode/serenity.json` | 助手模型白名单、日志阈值、安全模式黑名单、子角色、**认知轨迹级 skill 供给(`cognitiveTrajectory.skills`)**、微信(账号/路由/开关) |
351
354
  | 工作区凭据 | `localstore.json` | 密钥与本地偏好;微信机器人 token 也在这一层 |
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.69.1",
3
+ "version": "1.69.2",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/官方 ACP 面/认知轨迹唤醒注册表。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -227,7 +227,7 @@ async function listCccs(ctx, opts = {}) {
227
227
  if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
228
228
  let rolesOf = null;
229
229
  if (opts.withRoles === true) {
230
- const { readSkiffRoles } = await import("./skiff-role-Boc4SKct.js").then((n) => n.d);
230
+ const { readSkiffRoles } = await import("./skiff-role-cwxAt0gE.js").then((n) => n.d);
231
231
  rolesOf = (root) => [...readSkiffRoles(root).keys()];
232
232
  }
233
233
  return c.roots.map((root) => ({
package/lib/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-RMzGU-CJ.js";
2
+ import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-RzasspMr.js";
3
3
  import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readCheapWorkerConfig, h as readSafeModeHiddenTools, i as findGitRoot, l as pathInside, m as readExclusiveTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readCognitiveTrajectorySkills, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-C33QWoWZ.js";
4
- import { A as summarize, C as readTrajectoryUid, D as setActiveSessionInfo, E as sessionsRoot, F as localIdStamp, M as isoLocal, N as localFileStamp, O as setTrajectoryUid, P as localHuman, S as readActiveSessionMd, T as sessionEvents$1, _ as getActiveSessionInfo, a as pruneMissingBindings, b as namingTitleFor, c as setBindingStore, d as UID_FILENAME, f as archiveSession, g as findSession, h as extractSessionMdPathFromText, i as listBoundSessionIds, j as useSession, k as showSession, l as COGNITIVE_TRAJECTORY_ACTIONS, m as createSession, n as PLUGIN_SOURCE, o as readLastBound, p as clearActiveSessionInfo, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, u as DEFAULT_SESSION_SCOPE, v as listActiveTrajectories, w as resolveSessionByTitle, x as parseSessionContextFromEvents, y as listSessions } from "./message-source-Catc7q1z.js";
4
+ import { A as summarize, C as readTrajectoryUid, D as setActiveSessionInfo, E as sessionsRoot, F as localIdStamp, M as isoLocal, N as localFileStamp, O as setTrajectoryUid, P as localHuman, S as readActiveSessionMd, T as sessionEvents$1, _ as getActiveSessionInfo, a as pruneMissingBindings, b as namingTitleFor, c as setBindingStore, d as UID_FILENAME, f as archiveSession, g as findSession, h as extractSessionMdPathFromText, i as listBoundSessionIds, j as useSession, k as showSession, l as COGNITIVE_TRAJECTORY_ACTIONS, m as createSession, n as PLUGIN_SOURCE, o as readLastBound, p as clearActiveSessionInfo, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, u as DEFAULT_SESSION_SCOPE, v as listActiveTrajectories, w as resolveSessionByTitle, x as parseSessionContextFromEvents, y as listSessions } from "./message-source-DWWECjGB.js";
5
5
  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-D_DvgPqy.js";
6
- import { a as GATEWAY_PORT, c as SKIFF_DEBUG_PORT, d as skiffRoleFor$1, f as skiffSessionInfo$1, i as FACE_PORTS, l as WEIXIN_SEND_PORT, m as ACC_VERSION, n as readSimpleSettings, o as MAIN_WEB_PORT, p as unregisterSkiffSession$1, r as registerSettingsSection, s as MECHANISM_PORTS, u as registerSkiffSession$1 } from "./settings-section-DcZPcWPv.js";
7
- import { a as isSkiffSessionId, c as resolveSkiffKind, f as systemPromptSource, i as createRolePromptReader, l as roleMsmWhitelist, n as buildSkiffBasePrompt, o as readSkiffRoles, r as cognitiveTrajectorySubset, s as resolveRoleSystemPrompt, u as roleToolWhitelist } from "./skiff-role-Boc4SKct.js";
6
+ import { a as GATEWAY_PORT, c as SKIFF_DEBUG_PORT, d as skiffRoleFor$1, f as skiffSessionInfo$1, i as FACE_PORTS, l as WEIXIN_SEND_PORT, m as ACC_VERSION, n as readSimpleSettings, o as MAIN_WEB_PORT, p as unregisterSkiffSession$1, r as registerSettingsSection, s as MECHANISM_PORTS, u as registerSkiffSession$1 } from "./settings-section-0TPYWug9.js";
7
+ import { a as isSkiffSessionId, c as resolveSkiffKind, f as systemPromptSource, i as createRolePromptReader, l as roleMsmWhitelist, n as buildSkiffBasePrompt, o as readSkiffRoles, r as cognitiveTrajectorySubset, s as resolveRoleSystemPrompt, u as roleToolWhitelist } from "./skiff-role-cwxAt0gE.js";
8
8
  import { REGISTERED_TOOLS } from "./invariant.js";
9
9
  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-BrRcPiQs.js";
10
10
  import { createRequire } from "node:module";
@@ -3968,10 +3968,31 @@ async function createSkiffAgent(ctx, root, roleName, role, defaultModel, session
3968
3968
  console.warn(`[serenity-hooks] skiff 角色 "${roleName}" 专属 SESSION 处理失败(不影响 agent 创建): ${String(err?.message ?? err)}`);
3969
3969
  }
3970
3970
  try {
3971
+ let readerPath = role?.systemPromptFile?.trim();
3972
+ let reader = rolePrompt;
3973
+ const liveRolePrompt = () => {
3974
+ let live = role;
3975
+ try {
3976
+ const fresh = readSkiffRoles(root).get(roleName);
3977
+ if (fresh) live = fresh;
3978
+ } catch {}
3979
+ const wantPath = live?.systemPromptFile?.trim();
3980
+ if (wantPath !== readerPath) {
3981
+ reader = kind === "persistent" ? createRolePromptReader(root, live) : (() => {
3982
+ let snapshot = "";
3983
+ try {
3984
+ snapshot = resolveRoleSystemPrompt(root, live);
3985
+ } catch {}
3986
+ return () => snapshot;
3987
+ })();
3988
+ readerPath = wantPath;
3989
+ }
3990
+ return reader();
3991
+ };
3971
3992
  agent.ctx.systemPrompt.section({
3972
3993
  name: "serenity-skiff",
3973
3994
  order: -60,
3974
- text: () => [buildSkiffBasePrompt(roleName, role), rolePrompt()].filter(Boolean).join("\n")
3995
+ text: () => [buildSkiffBasePrompt(roleName), liveRolePrompt()].filter(Boolean).join("\n")
3975
3996
  });
3976
3997
  } catch (err) {
3977
3998
  console.warn(`[serenity-hooks] skiff 系统提示词注册失败: ${String(err?.message ?? err)}`);
@@ -15404,7 +15425,7 @@ function registerStatusApi(ctx, opts = {}) {
15404
15425
  return;
15405
15426
  }
15406
15427
  const { saveWeixinRoutes } = await import("./weixin-route-D_DvgPqy.js").then((n) => n.u);
15407
- const { readSkiffRoles } = await import("./skiff-role-Boc4SKct.js").then((n) => n.d);
15428
+ const { readSkiffRoles } = await import("./skiff-role-cwxAt0gE.js").then((n) => n.d);
15408
15429
  const roles = readSkiffRoles(root);
15409
15430
  for (const r of routes) if (!roles.has(r.role)) {
15410
15431
  sendJson$3(res, 400, { error: `unknown role: ${r.role} (not in ${root} skiff.roles)` });
@@ -20763,7 +20784,7 @@ function manualOutputFallbackNeeded(input) {
20763
20784
  */
20764
20785
  async function resolveCccRootByAlias(ctx, alias) {
20765
20786
  try {
20766
- const { listCccs } = await import("./ccc-roots-RMzGU-CJ.js").then((n) => n.a);
20787
+ const { listCccs } = await import("./ccc-roots-RzasspMr.js").then((n) => n.a);
20767
20788
  const entries = await listCccs(ctx);
20768
20789
  const byName = entries.find((e) => e.name === alias);
20769
20790
  if (byName) return byName.root;
@@ -21262,7 +21283,7 @@ function syncHumanChannel(ctx) {
21262
21283
  (async () => {
21263
21284
  try {
21264
21285
  stopMachineLoops();
21265
- const { listCccs } = await import("./ccc-roots-RMzGU-CJ.js").then((n) => n.a);
21286
+ const { listCccs } = await import("./ccc-roots-RzasspMr.js").then((n) => n.a);
21266
21287
  for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
21267
21288
  } catch {}
21268
21289
  })();
@@ -21498,7 +21519,7 @@ function matchCcc(input, candidates) {
21498
21519
  }
21499
21520
  /** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
21500
21521
  async function collectCandidates(ctx) {
21501
- const { listCccs } = await import("./ccc-roots-RMzGU-CJ.js").then((n) => n.a);
21522
+ const { listCccs } = await import("./ccc-roots-RzasspMr.js").then((n) => n.a);
21502
21523
  const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
21503
21524
  const seen = /* @__PURE__ */ new Set();
21504
21525
  const out = [];
@@ -1,4 +1,4 @@
1
- import { r as cccRootForCwd } from "./ccc-roots-RMzGU-CJ.js";
1
+ import { r as cccRootForCwd } from "./ccc-roots-RzasspMr.js";
2
2
  import { basename, dirname, join } from "node:path";
3
3
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  //#region src/time.ts
@@ -1,4 +1,4 @@
1
- import { f as hostSettings } from "./ccc-roots-RMzGU-CJ.js";
1
+ import { f as hostSettings } from "./ccc-roots-RzasspMr.js";
2
2
  import { dirname, join } from "node:path";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
@@ -166,25 +166,38 @@ function createRolePromptReader(root, role) {
166
166
  };
167
167
  }
168
168
  /**
169
- * Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接):
170
- * 身份 + 可用 MSM/工具清单 + 调用协议 + 边界声明。动态生成(清单来自角色白名单)。
169
+ * Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接)。
170
+ *
171
+ * ## 🔴 为什么**不再枚举**清单(owner 2026-10-19 令)
172
+ *
173
+ * 旧版在这里抄了两份清单(`MSMs: a, b, c` / `Tools: read, grep, …`)。那是**第二真相源**,
174
+ * 而真相源本来就在模型自己手里:
175
+ * · **工具清单** = 这一轮实际注册给它的 tool schema —— 模型已经看得见,抄一遍只会漂
176
+ * · **MSM 清单** = `msm()` 无参调用返回的目录 —— 已按角色白名单过滤,且**每次实时读配置**
177
+ *
178
+ * ⚠️ **漂移不是理论风险,是已发生的缺陷**(2026-10-19):角色配置早就长到 8 个工具,
179
+ * 而这个函数是从**创建时冻结的 role 快照**求值的 ⇒ 提示词里一直写着旧的 4 个
180
+ * ⇒ 模型照着提示词办事,**它自己以为没有的能力就不去调** ⇒ 症状是"工具用不了",
181
+ * 而守卫那边(每调用实时读配置)其实是放行的。两个真相源打架,输的总是提示词。
182
+ *
183
+ * ⇒ 现在只声明**边界与发现路径**,不抄内容:清单在哪,怎么取,越界会怎样。
184
+ *
185
+ * @param roleName 角色名(CCC 定义;用于身份声明)
171
186
  */
172
- function buildSkiffBasePrompt(roleName, role) {
173
- const msms = role?.msms ?? [];
174
- const tools = role?.tools ?? [];
175
- const lines = [
187
+ function buildSkiffBasePrompt(roleName) {
188
+ return [
176
189
  "=== Serenity Skiff ===",
177
190
  `Role: ${roleName} (defined by this CCC)`,
178
- "You interact with this CCC ONLY through the exposed surface below:"
179
- ];
180
- if (msms.length > 0) lines.push(` MSMs: ${msms.join(", ")} (call msm("<name>", ["<args>"]) ; pass inspect=true or "--help" as first arg for usage)`);
181
- else lines.push(" MSMs: (none)");
182
- lines.push(` Tools: ${tools.length > 0 ? tools.join(", ") : "(none)"}`);
183
- lines.push("No other tools are available. Your capability boundary is this surface.");
184
- lines.push("");
185
- lines.push("---");
186
- lines.push("");
187
- return lines.join("\n");
191
+ "Your capability boundary is enforced mechanically by this CCC — anything outside it is rejected at the call site, not by your judgment.",
192
+ "Discover your surface, do not memorize it (both are generated from the live config on every turn):",
193
+ " · Your tools are exactly the tool schemas you see in this session — if a tool is not in your schema, it is not available.",
194
+ " · Your MSMs are listed by calling msm() with no arguments — that directory is already filtered to this role.",
195
+ " · Usage for any MSM: msm(\"<name>\", [], inspect=true) or pass \"--help\" as the first argument.",
196
+ "Do not infer unavailability from anything you remember or from an earlier list: this surface changes when the CCC configuration changes, and it takes effect without restarting.",
197
+ "",
198
+ "---",
199
+ ""
200
+ ].join("\n");
188
201
  }
189
202
  //#endregion
190
203
  export { isSkiffSessionId as a, resolveSkiffKind as c, skiff_role_exports as d, systemPromptSource as f, createRolePromptReader as i, roleMsmWhitelist as l, buildSkiffBasePrompt as n, readSkiffRoles as o, cognitiveTrajectorySubset as r, resolveRoleSystemPrompt as s, SKIFF_SESSION_PREFIX as t, roleToolWhitelist as u };
@@ -68,7 +68,22 @@ export declare function resolveSkiffKind(role: SkiffRoleConfig | undefined, hasS
68
68
  */
69
69
  export declare function createRolePromptReader(root: string, role: SkiffRoleConfig | undefined): () => string;
70
70
  /**
71
- * Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接):
72
- * 身份 + 可用 MSM/工具清单 + 调用协议 + 边界声明。动态生成(清单来自角色白名单)。
71
+ * Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接)。
72
+ *
73
+ * ## 🔴 为什么**不再枚举**清单(owner 2026-10-19 令)
74
+ *
75
+ * 旧版在这里抄了两份清单(`MSMs: a, b, c` / `Tools: read, grep, …`)。那是**第二真相源**,
76
+ * 而真相源本来就在模型自己手里:
77
+ * · **工具清单** = 这一轮实际注册给它的 tool schema —— 模型已经看得见,抄一遍只会漂
78
+ * · **MSM 清单** = `msm()` 无参调用返回的目录 —— 已按角色白名单过滤,且**每次实时读配置**
79
+ *
80
+ * ⚠️ **漂移不是理论风险,是已发生的缺陷**(2026-10-19):角色配置早就长到 8 个工具,
81
+ * 而这个函数是从**创建时冻结的 role 快照**求值的 ⇒ 提示词里一直写着旧的 4 个
82
+ * ⇒ 模型照着提示词办事,**它自己以为没有的能力就不去调** ⇒ 症状是"工具用不了",
83
+ * 而守卫那边(每调用实时读配置)其实是放行的。两个真相源打架,输的总是提示词。
84
+ *
85
+ * ⇒ 现在只声明**边界与发现路径**,不抄内容:清单在哪,怎么取,越界会怎样。
86
+ *
87
+ * @param roleName 角色名(CCC 定义;用于身份声明)
73
88
  */
74
- export declare function buildSkiffBasePrompt(roleName: string, role: SkiffRoleConfig | undefined): string;
89
+ export declare function buildSkiffBasePrompt(roleName: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.69.1",
3
+ "version": "1.69.2",
4
4
  "description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/官方 ACP 面/认知轨迹唤醒注册表。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
5
5
  "license": "MIT",
6
6
  "repository": {