@shgroup/dsh-serenity-hooks 1.20.5 → 1.20.6

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.20.5",
3
+ "version": "1.20.6",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/loop + 拦截缝机械约束(safe-mode/路径守卫)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。私有(dsh-external 组织)。",
6
6
  "engines": {
package/lib/client.js CHANGED
@@ -8,11 +8,11 @@ window.__ModuleLoader__.load({
8
8
  let react = require("react");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
10
  //#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SafeModePanel
11
- const css$1 = "/* SafeModePanel — 会话头部 Serenity 状态徽章(点击展开详情卡)。\n * 遵循 web-styling.md:颜色只用 --dsw-alias-* 语义 token(明暗自适应);\n * 尺寸与官方 header 标签一致;前缀 sp- 防冲突。 */\n\n.sp-root {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 4px 0 4px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 24px;\n white-space: nowrap;\n}\n\n.sp-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 22px;\n padding: 0 6px;\n border: none;\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font-size: 12px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-badge:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sp-badge:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n}\n\n.sp-dotOn {\n background: var(--dsw-alias-state-success-primary);\n}\n\n.sp-dotOff {\n background: var(--dsw-alias-label-dimmed);\n}\n\n.sp-brand {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n.sp-toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 18px;\n padding: 0 8px;\n border: none;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-toggle:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-toggle:disabled {\n opacity: 0.55;\n cursor: default;\n}\n\n.sp-toggleOn {\n background: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n.sp-toggleOn:hover:not(:disabled) {\n background: var(--dsw-alias-state-error-secondary);\n}\n\n.sp-toggleOff {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-toggleOff:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n.sp-toggleIcon {\n flex: none;\n}\n\n.sp-toggleLg {\n height: 26px;\n padding: 0 14px;\n font-size: 13px;\n line-height: 26px;\n border-radius: 6px;\n}\n\n/* 详情卡:相对徽章绝对定位(右对齐),卡片 token */\n.sp-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 20;\n width: 300px;\n box-sizing: border-box;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 12px;\n background: var(--dsw-specific-tip);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sp-popRow {\n display: flex;\n align-items: baseline;\n gap: 10px;\n min-width: 0;\n}\n\n.sp-popLabel {\n flex: none;\n width: 34px;\n font-size: 12px;\n color: var(--dsw-alias-label-caption);\n}\n\n.sp-popValue {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n.sp-popActions {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 2px;\n}\n\n/* loop 运行状态区块(WebUI 等待界面;并行任务各自一行) */\n.sp-popSection {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 2px;\n}\n\n.sp-loopItem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 2px 0 2px 44px;\n min-width: 0;\n}\n\n.sp-loopHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n}\n\n.sp-loopLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.sp-loopRound {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-state-info-primary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n.sp-loopTime {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-caption);\n}\n\n.sp-loopResp {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sp-toggle,\n .sp-badge {\n transition: none;\n }\n}\n";
11
+ const css = "/* SafeModePanel — 会话头部 Serenity 状态徽章(点击展开详情卡)。\n * 遵循 web-styling.md:颜色只用 --dsw-alias-* 语义 token(明暗自适应);\n * 尺寸与官方 header 标签一致;前缀 sp- 防冲突。 */\n\n.sp-root {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 4px 0 4px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 24px;\n white-space: nowrap;\n}\n\n.sp-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 22px;\n padding: 0 6px;\n border: none;\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font-size: 12px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-badge:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sp-badge:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n}\n\n.sp-dotOn {\n background: var(--dsw-alias-state-success-primary);\n}\n\n.sp-dotOff {\n background: var(--dsw-alias-label-dimmed);\n}\n\n.sp-brand {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n.sp-toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 18px;\n padding: 0 8px;\n border: none;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-toggle:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-toggle:disabled {\n opacity: 0.55;\n cursor: default;\n}\n\n.sp-toggleOn {\n background: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n.sp-toggleOn:hover:not(:disabled) {\n background: var(--dsw-alias-state-error-secondary);\n}\n\n.sp-toggleOff {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-toggleOff:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n.sp-toggleIcon {\n flex: none;\n}\n\n.sp-toggleLg {\n height: 26px;\n padding: 0 14px;\n font-size: 13px;\n line-height: 26px;\n border-radius: 6px;\n}\n\n/* 详情卡:相对徽章绝对定位(右对齐),卡片 token */\n.sp-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 20;\n width: 300px;\n box-sizing: border-box;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 12px;\n background: var(--dsw-specific-tip);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sp-popRow {\n display: flex;\n align-items: baseline;\n gap: 10px;\n min-width: 0;\n}\n\n.sp-popLabel {\n flex: none;\n width: 34px;\n font-size: 12px;\n color: var(--dsw-alias-label-caption);\n}\n\n.sp-popValue {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n.sp-popActions {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 2px;\n}\n\n/* loop 运行状态区块(WebUI 等待界面;并行任务各自一行) */\n.sp-popSection {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 2px;\n}\n\n.sp-loopItem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 2px 0 2px 44px;\n min-width: 0;\n}\n\n.sp-loopHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n}\n\n.sp-loopLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.sp-loopRound {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-state-info-primary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n.sp-loopTime {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-caption);\n}\n\n.sp-loopResp {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-family: var(--ds-font-family-code, monospace);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sp-toggle,\n .sp-badge {\n transition: none;\n }\n}\n";
12
12
  if (typeof document !== "undefined" && document.querySelector("style[data-sp-css]") === null) {
13
13
  const tag = document.createElement("style");
14
14
  tag.setAttribute("data-sp-css", "1");
15
- tag.textContent = css$1;
15
+ tag.textContent = css;
16
16
  document.head.appendChild(tag);
17
17
  }
18
18
  //#endregion
@@ -244,11 +244,15 @@ window.__ModuleLoader__.load({
244
244
  /** 图片落盘接口路径(node half api.ts,client 专属 x-serenity-ui 头) */
245
245
  const UPLOAD_PATH = "/serenity/image-upload";
246
246
  /**
247
- * 识别结果消息模板(协议固有,S142 用户迭代:v1.20.5 去掉具体文件路径——UI 突兀,
248
- * 改为目录级自然提示;agent 自行查 _tmp/images_from_user/ 找图片 → 调 CCC vlm MSM 识别)
247
+ * 图片提示消息模板(协议固有,S142 用户迭代):
248
+ * - v1.20.5 目录级提示(无文件名)→ 用户反馈 agent 还要猜
249
+ * - v1.20.6 恢复具体路径(对话里一定写名图片路径,agent 直接可用,无需猜)
250
+ * 单图:用户提供了一张图片(路径:...);多图:每张一行路径
249
251
  */
250
- const IMAGE_NOTE_TEMPLATE_SINGLE = "用户提供了一张图片(已保存到 _tmp/images_from_user/),请查看该目录下的图片并处理";
251
- const IMAGE_NOTE_TEMPLATE_MULTI = (count) => `用户提供了 ${count} 张图片(已保存到 _tmp/images_from_user/),请查看该目录下的图片并处理`;
252
+ function imageNoteTemplate(paths) {
253
+ if (paths.length === 1) return `用户提供了一张图片(路径:${paths[0]})`;
254
+ return `用户提供了 ${paths.length} 张图片:\n${paths.map((p) => `- ${p}`).join("\n")}`;
255
+ }
252
256
  /** 浏览器 File → base64(与 ui-conversation serializeImages 等价的最小实现) */
253
257
  function fileToBase64(file) {
254
258
  return file.arrayBuffer().then((buffer) => {
@@ -309,17 +313,8 @@ window.__ModuleLoader__.load({
309
313
  if (!result.ok) throw new Error(`serenity image fallback resend failed: ${result.error?.code}: ${result.error?.message}`);
310
314
  }
311
315
  //#endregion
312
- //#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/ImageFallbackDock
313
- const css = "/* ImageFallbackDock — 图片自动落盘兜底状态条(S142) */\n\n.serenity-image-fallback {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n line-height: 1.5;\n padding: 2px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-surface-muted, rgba(127, 127, 127, 0.1));\n color: var(--dsw-alias-text-secondary, currentColor);\n}\n\n.serenity-image-fallback[data-state='busy'] {\n color: var(--dsw-alias-text-secondary, currentColor);\n}\n\n.serenity-image-fallback[data-state='done'] {\n color: var(--dsw-alias-text-success, currentColor);\n}\n\n.serenity-image-fallback[data-state='error'] {\n color: var(--dsw-alias-text-danger, currentColor);\n}\n\n.serenity-image-fallback code {\n font-family: var(--dsw-alias-font-mono, monospace);\n font-size: 11px;\n background: var(--dsw-alias-surface-muted, rgba(127, 127, 127, 0.12));\n border-radius: 4px;\n padding: 0 4px;\n}\n";
314
- if (typeof document !== "undefined" && document.querySelector("style[data-sp-css]") === null) {
315
- const tag = document.createElement("style");
316
- tag.setAttribute("data-sp-css", "1");
317
- tag.textContent = css;
318
- document.head.appendChild(tag);
319
- }
320
- //#endregion
321
316
  //#region src/client/ImageFallbackDock.tsx
322
- /** input.dock 条目:图片发送失败自动落盘 + 文本重发(补救后自动清空输入框 rail 图片) */
317
+ /** input.dock 条目(静默):图片发送失败自动落盘 + 文本重发,无 UI */
323
318
  function ImageFallbackDock(props) {
324
319
  const zone = props;
325
320
  const session = zone.session;
@@ -327,9 +322,6 @@ window.__ModuleLoader__.load({
327
322
  const sessionId = props.sessionId;
328
323
  const { uploadImage, getDraftFiles, resendText } = props;
329
324
  const inputActions = props.inputActions;
330
- const [state, setState] = (0, react.useState)("idle");
331
- const [paths, setPaths] = (0, react.useState)([]);
332
- const [errorText, setErrorText] = (0, react.useState)(null);
333
325
  const handlingRef = (0, react.useRef)(false);
334
326
  const promptError = session?.promptError?.error;
335
327
  const imageIds = input?.imageIds ?? [];
@@ -338,14 +330,13 @@ window.__ModuleLoader__.load({
338
330
  if (promptError.details?.reason !== "MODEL_DOES_NOT_SUPPORT_IMAGES") return;
339
331
  if (handlingRef.current || imageIds.length === 0) return;
340
332
  handlingRef.current = true;
341
- setState("uploading");
342
333
  (async () => {
343
334
  try {
344
335
  const files = await getDraftFiles(String(sessionId), imageIds);
345
336
  if (files.length === 0) throw new Error("no draft image files");
346
337
  const saved = [];
347
338
  for (const file of files) saved.push(await uploadImage(file, String(sessionId)));
348
- const note = saved.length === 1 ? IMAGE_NOTE_TEMPLATE_SINGLE : IMAGE_NOTE_TEMPLATE_MULTI(saved.length);
339
+ const note = imageNoteTemplate(saved);
349
340
  const draft = input?.draft ?? "";
350
341
  const text = draft === "" ? note : `${draft}\n${note}`;
351
342
  if (inputActions?.removeImage !== void 0 && inputActions.setDraft !== void 0 && inputActions.submit !== void 0) {
@@ -353,13 +344,8 @@ window.__ModuleLoader__.load({
353
344
  inputActions.setDraft(text);
354
345
  inputActions.submit();
355
346
  } else await resendText(String(sessionId), text);
356
- setPaths(saved);
357
- setState("done");
358
347
  } catch (err) {
359
- const message = String(err?.message ?? err);
360
- console.warn(`[serenity] image fallback failed: ${message}`);
361
- setErrorText(message);
362
- setState("error");
348
+ console.warn(`[serenity] image fallback failed: ${String(err?.message ?? err)}`);
363
349
  } finally {
364
350
  handlingRef.current = false;
365
351
  }
@@ -374,25 +360,7 @@ window.__ModuleLoader__.load({
374
360
  input?.draft,
375
361
  inputActions
376
362
  ]);
377
- if (state === "idle") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
378
- className: "serenity-image-fallback",
379
- "data-state": "idle"
380
- });
381
- if (state === "uploading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
382
- className: "serenity-image-fallback",
383
- "data-state": "busy",
384
- children: "图片已保存中…"
385
- });
386
- if (state === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
387
- className: "serenity-image-fallback",
388
- "data-state": "done",
389
- children: paths.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: p }, p))
390
- });
391
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
392
- className: "serenity-image-fallback",
393
- "data-state": "error",
394
- children: ["图片保存失败:", errorText ?? "未知错误"]
395
- });
363
+ return null;
396
364
  }
397
365
  //#endregion
398
366
  //#region src/client/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.20.5",
3
+ "version": "1.20.6",
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": {