@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 +1 -1
- package/lib/client.js +14 -46
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.20.
|
|
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
|
|
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
|
|
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
|
-
*
|
|
248
|
-
*
|
|
247
|
+
* 图片提示消息模板(协议固有,S142 用户迭代):
|
|
248
|
+
* - v1.20.5 目录级提示(无文件名)→ 用户反馈 agent 还要猜
|
|
249
|
+
* - v1.20.6 恢复具体路径(对话里一定写名图片路径,agent 直接可用,无需猜)
|
|
250
|
+
* 单图:用户提供了一张图片(路径:...);多图:每张一行路径
|
|
249
251
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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": {
|