@shgroup/dsh-serenity-hooks 1.30.3 → 1.30.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.30.3",
3
+ "version": "1.30.5",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
package/lib/client.js CHANGED
@@ -358,6 +358,23 @@ window.__ModuleLoader__.load({
358
358
  /** 图片落盘接口路径(node half api.ts,client 专属 x-serenity-ui 头) */
359
359
  const UPLOAD_PATH = "/serenity/image-upload";
360
360
  /**
361
+ * 判断是否触发图片落盘补救(纯函数,可单测)。
362
+ *
363
+ * ⚠️ v1.30.5 错误码契约修复(2026-09-08 用户实测"图片能进 rail 但发送被拒、无落盘"):
364
+ * DSH 0.1.1-rc.2 → 0.1.2-rc.1 升级后,host session-controller 把图片被拒错误码从
365
+ * `attachment-error` 改为 `session/attachment-invalid`(主会话)/ `subagent/attachment-invalid`
366
+ * (子代理),reason 仍为 `MODEL_DOES_NOT_SUPPORT_IMAGES`(rc.1 commands.ts:321 实证)。
367
+ * 旧实现只匹配 `attachment-error` → rc.1 下补救永不触发。兼容三码 + reason 双条件判定。
368
+ *
369
+ * @param code - promptError.error.code(host 投影)
370
+ * @param reason - promptError.error.details.reason
371
+ * @returns true = 应触发自动落盘补救
372
+ */
373
+ function isImageFallbackTrigger(code, reason) {
374
+ if (code !== "attachment-error" && code !== "session/attachment-invalid" && code !== "subagent/attachment-invalid") return false;
375
+ return reason === "MODEL_DOES_NOT_SUPPORT_IMAGES";
376
+ }
377
+ /**
361
378
  * 图片提示消息模板(协议固有,S142 用户迭代):
362
379
  * - v1.20.5 目录级提示(无文件名)→ 用户反馈 agent 还要猜
363
380
  * - v1.20.6 恢复具体路径(对话里一定写名图片路径,agent 直接可用,无需猜)
@@ -440,9 +457,8 @@ window.__ModuleLoader__.load({
440
457
  const promptError = session?.promptError?.error;
441
458
  const imageIds = input?.imageIds ?? [];
442
459
  (0, react.useEffect)(() => {
443
- if (promptError?.code !== "attachment-error") return;
444
- if (promptError.details?.reason !== "MODEL_DOES_NOT_SUPPORT_IMAGES") return;
445
- if (handlingRef.current || imageIds.length === 0) return;
460
+ if (handlingRef.current || !isImageFallbackTrigger(promptError?.code, promptError?.details?.reason)) return;
461
+ if (imageIds.length === 0) return;
446
462
  handlingRef.current = true;
447
463
  (async () => {
448
464
  try {
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { a as findSerenityRoot, c as matchBlacklist, d as readCccName$2, f as readHandymanConfig, i as findGitRoot, l as pathInside, m as resolveInside, n as SAFE_MODE_MARKER, o as isSafeModeOn, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-CX48YNUL.js";
3
3
  import { a as resolveRoleSystemPrompt, i as readSkiffRoles, l as systemPromptSource, r as isSkiffSessionId, s as roleToolWhitelist } from "./skiff-role-LW4tjF9L.js";
4
- import { C as splitModel, E as skiffRoleFor, S as requireWhitelistedModel, T as writeProgress, _ as buildRoundPrompt, a as startSkiffDebugServer, b as newStopToken, c as askSkiff, d as skiffMsmGate, f as skiffSessionInfo, g as HANDYMAN_GUIDE, h as unregisterSkiffSession, l as createSkiffAgent, m as skiffTrajectoryEnabled, n as jscSafeJsonText, o as stopSkiffDebugServer, p as skiffSessionSnapshot, r as renderSkiffMarkdown, s as stripThink, t as discoverCccs, u as getSkiffAgent, v as handymanProgressPaths, w as writeFailedStatus, x as readProgress, y as listActiveHandymen } from "./skiff-debug-CjV1g6T7.js";
4
+ import { C as readProgress, D as writeProgress, E as writeFailedStatus, O as skiffRoleFor, S as newStopToken, T as splitModel, _ as workspaceTrajectoryLine, a as startSkiffDebugServer, b as handymanProgressPaths, c as askSkiff, d as getSkiffAgent, f as skiffMsmGate, g as unregisterSkiffSession, h as skiffTrajectoryEnabled, l as createSkiffAgent, m as skiffSessionSnapshot, n as jscSafeJsonText, o as stopSkiffDebugServer, p as skiffSessionInfo, r as renderSkiffMarkdown, s as stripThink, t as discoverCccs, u as ensureSkiffSession, v as HANDYMAN_GUIDE, w as requireWhitelistedModel, x as listActiveHandymen, y as buildRoundPrompt } from "./skiff-debug-gYigSgl_.js";
5
5
  import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, h as runLocalStore, 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-jA0qENOf.js";
6
6
  import { C as useSession, S as summarize, _ as resolveSessionByTitle, a as archiveSessions, b as setActiveSessionInfo, c as extractSessionMdPathFromText, d as getActiveSessionInfo, f as healthCheck, g as readActiveSessionMd, h as qaCheck, i as SESSION_ACTIONS, l as findLatestActiveSessionMd, m as parseSessionContextFromEvents, n as readLastBound, o as closeSession, p as listSessions, r as DEFAULT_SESSION_SCOPE, s as createSession, t as appendBound, u as findSession, v as sessionEvents, x as showSession, y as sessionsRoot } from "./session-bound-p9oR9dj9.js";
7
7
  import { n as registerSettingsSection, t as readSimpleSettings } from "./settings-section-BfVxgCZy.js";
@@ -6071,7 +6071,7 @@ function registerStatusApi(ctx, opts = {}) {
6071
6071
  workspace: url.searchParams.get("workspace") ?? void 0
6072
6072
  });
6073
6073
  const root = findSerenityRoot(workspace) ?? "";
6074
- const { discoverCccs } = await import("./skiff-debug-CjV1g6T7.js").then((n) => n.i);
6074
+ const { discoverCccs } = await import("./skiff-debug-gYigSgl_.js").then((n) => n.i);
6075
6075
  sendJson$1(res, 200, { cccs: await discoverCccs(ctx, root) });
6076
6076
  } catch (err) {
6077
6077
  sendJson$1(res, 400, { error: err.message ?? String(err) });
@@ -9036,6 +9036,11 @@ async function handleIncoming(ctx, root, accountId, cred, msg) {
9036
9036
  const sessionId = weixinSessionIdFor(fromUserId);
9037
9037
  const existing = getSkiffAgent(sessionId);
9038
9038
  const hc = readHandymanConfig(root);
9039
+ if (existing) try {
9040
+ ensureSkiffSession(root, existing, roleName, role);
9041
+ } catch (err) {
9042
+ console.warn(`[serenity-hooks] weixin-bridge ensure 失败(不影响处理): ${String(err?.message ?? err)}`);
9043
+ }
9039
9044
  const ref = existing ? {
9040
9045
  agent: existing,
9041
9046
  sessionId,
@@ -9097,6 +9102,8 @@ async function handleIncoming(ctx, root, accountId, cred, msg) {
9097
9102
  }
9098
9103
  }
9099
9104
  const parts = [];
9105
+ const activeWorkspace = getActiveSessionInfo(sessionId);
9106
+ if (activeWorkspace?.mdPath) parts.push(workspaceTrajectoryLine(activeWorkspace.mdPath));
9100
9107
  if (text) parts.push(text);
9101
9108
  parts.push(...mediaNotes, ...degradedNotes);
9102
9109
  const question = parts.join("\n");
@@ -1,5 +1,10 @@
1
1
  /**
2
- * system-prompt.ts — 顶层入口 skill 全文 + ACC/CCE/Constraints/Session 系统提示词注入
2
+ * system-prompt.ts — Induction(成员装配机制,specs v1.5.0 命名)装配文本构造
3
+ *
4
+ * 机制:把新实例(新会话 / rebuild 重建 / 新 agent)引入为轨迹成员的装配机制——本文件装配的文本
5
+ * 即 Induction 骨架(8 块五层,specs README §5):A 主体定义(ACC/Principles/CCE)→ B 质量规范(EAP)
6
+ * → C 状态调节(状态块)→ D 工作供给(SKILL/Tools)→ E 任务指示(Session),稳定→易变装配序;
7
+ * Metaphor 为 A 层世界模型记忆钩渲染层(不计入 8 块骨架)。
3
8
  *
4
9
  * **完全对齐 opencode-serenity-plugin 的 system.transform 注入内容**(compacting.ts):
5
10
  * 结构(v1.19.8 精简,S142 重建视角 R↓):
@@ -28,8 +28,11 @@ export declare function skiffSessionSnapshot(): ReadonlyMap<string, {
28
28
  ccc: string;
29
29
  }>;
30
30
  /**
31
- * 系统提示词中的工作台指引段(agent 上下文,用户对话面不可见)。
32
- * SESSION = 工作台——skiff 与主舱同一套机制:write/edit 记进度,logbook rebuild 续接。
31
+ * 系统提示词中的**工作台纪律块**(v1.30.4 升级:从单行路径 → 完整 ACC 层约束)。
32
+ * 用户点破(S142):只给路径 LLM 不会主动用——需注入「已绑定 + 使用纪律 + 动作指引」。
33
+ * SESSION = 工作台——skiff 与主舱同一套机制(零特调,用户拍板):
34
+ * 自动绑定已生效(无需 logbook use)、SESSION.md 是持久记忆载体(write/edit 维护)、
35
+ * rebuild 自动从本 SESSION 续接。注入 agent 系统提示词(用户对话面不可见)。
33
36
  */
34
37
  export declare function workspaceTrajectoryLine(mdPath: string): string;
35
38
  /**
@@ -248,12 +248,29 @@ function skiffSessionSnapshot() {
248
248
  /** 自动创建的 bound 标记(readLastBound 恢复判定——只恢复本机制建的;手工 use 的旧 bound 不认) */
249
249
  const AUTO_BOUND_NOTE_PREFIX = "auto-created for skiff role";
250
250
  /**
251
- * 系统提示词中的工作台指引段(agent 上下文,用户对话面不可见)。
252
- * SESSION = 工作台——skiff 与主舱同一套机制:write/edit 记进度,logbook rebuild 续接。
251
+ * 系统提示词中的**工作台纪律块**(v1.30.4 升级:从单行路径 → 完整 ACC 层约束)。
252
+ * 用户点破(S142):只给路径 LLM 不会主动用——需注入「已绑定 + 使用纪律 + 动作指引」。
253
+ * SESSION = 工作台——skiff 与主舱同一套机制(零特调,用户拍板):
254
+ * 自动绑定已生效(无需 logbook use)、SESSION.md 是持久记忆载体(write/edit 维护)、
255
+ * rebuild 自动从本 SESSION 续接。注入 agent 系统提示词(用户对话面不可见)。
253
256
  */
254
257
  function workspaceTrajectoryLine(mdPath) {
255
- return `Your trajectory workspace (auto-assigned SESSION):
256
- SESSION.md: ${mdPath}\n Record progress/decisions here with write/edit; logbook rebuild resumes from this SESSION.`;
258
+ return [
259
+ "── Serenity Session Workspace ──",
260
+ "This role session is AUTO-BOUND to a trajectory workspace SESSION (no logbook use needed):",
261
+ ` SESSION.md: ${mdPath}`,
262
+ "",
263
+ "Rules of the workspace:",
264
+ " 1. This SESSION.md is your persistent memory carrier (like the main cabin SESSION) — ",
265
+ " read it first when context feels thin or work spans turns.",
266
+ " 2. Record key decisions/progress/unresolved items INTO this SESSION.md with write/edit",
267
+ " (sections: 目标 / 状态 / 关键决策 / 进度记录 / 未解决的问题). Keep it current — it is",
268
+ " what a rebuild resumes from.",
269
+ " 3. When context pressure is high, run logbook rebuild — it auto-resumes from THIS SESSION.md",
270
+ " (no manual use; do not switch to or read other SESSIONs unless the user explicitly asks).",
271
+ " 4. Never expose this internal path in user-facing replies (chat stays clean).",
272
+ "── ──"
273
+ ].join("\n");
257
274
  }
258
275
  /**
259
276
  * 确保启用 session 能力的 skiff 会话拥有**专属 SESSION**(工作台):
@@ -2731,4 +2748,4 @@ async function handle(ctx, defaultRoot, webPort, req, res) {
2731
2748
  }
2732
2749
  }
2733
2750
  //#endregion
2734
- export { splitModel as C, skiffRoleFor$1 as E, requireWhitelistedModel as S, writeProgress as T, buildRoundPrompt as _, startSkiffDebugServer as a, newStopToken as b, askSkiff as c, skiffMsmGate as d, skiffSessionInfo as f, HANDYMAN_GUIDE as g, unregisterSkiffSession as h, skiff_debug_exports as i, createSkiffAgent as l, skiffTrajectoryEnabled as m, jscSafeJsonText as n, stopSkiffDebugServer as o, skiffSessionSnapshot as p, renderSkiffMarkdown as r, stripThink as s, discoverCccs as t, getSkiffAgent as u, handymanProgressPaths as v, writeFailedStatus as w, readProgress as x, listActiveHandymen as y };
2751
+ export { readProgress as C, writeProgress as D, writeFailedStatus as E, skiffRoleFor$1 as O, newStopToken as S, splitModel as T, workspaceTrajectoryLine as _, startSkiffDebugServer as a, handymanProgressPaths as b, askSkiff as c, getSkiffAgent as d, skiffMsmGate as f, unregisterSkiffSession as g, skiffTrajectoryEnabled as h, skiff_debug_exports as i, createSkiffAgent as l, skiffSessionSnapshot as m, jscSafeJsonText as n, stopSkiffDebugServer as o, skiffSessionInfo as p, renderSkiffMarkdown as r, stripThink as s, discoverCccs as t, ensureSkiffSession as u, HANDYMAN_GUIDE as v, requireWhitelistedModel as w, listActiveHandymen as x, buildRoundPrompt as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.30.3",
3
+ "version": "1.30.5",
4
4
  "description": "宁静号 ACC harness — Native Cordis 插件(DeepSeek Harness 运行时)。真实 DSH 工具注册(cc_fs/session/acc_msm 等 9 工具)+ 拦截缝机械约束(safe-mode/路径守卫/会话落盘)+ 系统提示词注入(ACC/CCE/Constraints/SKILL/Session 五块)。适配 DSH 公开版(deepseek-ai/deepseek-harness 0.1.0-rc)。",
5
5
  "license": "MIT",
6
6
  "repository": {