@shgroup/dsh-serenity-hooks 1.25.0 → 1.25.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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.25.0",
3
+ "version": "1.25.2",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/handyman/session_rebuild/skiff_admin + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
package/lib/client.js CHANGED
@@ -3819,7 +3819,7 @@ Instruction-following style:
3819
3819
  }
3820
3820
  //#endregion
3821
3821
  //#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SettingsSection
3822
- const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n";
3822
+ const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n";
3823
3823
  if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
3824
3824
  const tag = document.createElement("style");
3825
3825
  tag.setAttribute("data-sp-css", "SettingsSection");
@@ -3892,6 +3892,9 @@ Instruction-following style:
3892
3892
  const setThreshold = (v) => {
3893
3893
  scope.set("rebuildThreshold", Math.min(1, Math.max(.01, v)));
3894
3894
  };
3895
+ const setSkiffPort = (v) => {
3896
+ scope.set("skiffDebugPort", Math.min(65535, Math.max(1024, Math.round(v))));
3897
+ };
3895
3898
  if (!ready) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3896
3899
  className: "ss-section",
3897
3900
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -3903,6 +3906,8 @@ Instruction-following style:
3903
3906
  const rebuildOn = value?.rebuildEnabled ?? true;
3904
3907
  const threshold = value?.rebuildThreshold ?? .9;
3905
3908
  const namingOn = value?.namingEnabled ?? true;
3909
+ const skiffOn = value?.skiffEnabled ?? false;
3910
+ const skiffPort = value?.skiffDebugPort ?? 3099;
3906
3911
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3907
3912
  className: "ss-section",
3908
3913
  children: [
@@ -3965,6 +3970,32 @@ Instruction-following style:
3965
3970
  })
3966
3971
  }) })
3967
3972
  }),
3973
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Group, {
3974
+ title: "Skiff",
3975
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
3976
+ title: "认知子集调试服务",
3977
+ desc: "Skiff 角色问答页(实验性;启停人工控制,仅监听 127.0.0.1)",
3978
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
3979
+ checked: skiffOn,
3980
+ onChange: (on) => toggle("skiffEnabled", on)
3981
+ })
3982
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
3983
+ title: "调试端口",
3984
+ desc: "Skiff 问答页端口(1024 ~ 65535,默认 3099)",
3985
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3986
+ className: "ss-threshold",
3987
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3988
+ className: "ss-portInput",
3989
+ type: "number",
3990
+ min: 1024,
3991
+ max: 65535,
3992
+ value: skiffPort,
3993
+ disabled: !skiffOn,
3994
+ onChange: (e) => setSkiffPort(Number(e.target.value))
3995
+ })
3996
+ })
3997
+ }) })]
3998
+ }),
3968
3999
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3969
4000
  className: "ss-group",
3970
4001
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
package/lib/index.js CHANGED
@@ -9333,8 +9333,8 @@ function sendHtml(res, html) {
9333
9333
  });
9334
9334
  res.end(html);
9335
9335
  }
9336
- /** 问答页 HTML:角色下拉 + 输入 + 答案区 + 轨迹区(JS 渲染)+ WebUI 链接 */
9337
- function skiffDebugPage(roles, webPort) {
9336
+ /** 问答页 HTML:角色下拉 + 输入 + 答案区 + 轨迹区(JS 渲染)+ 绑定的 CCC + WebUI 链接 */
9337
+ function skiffDebugPage(roles, cccRoot, webPort) {
9338
9338
  const roleOptions = [...roles.entries()].map(([name, r]) => `<option value="${escapeHtml(name)}">${escapeHtml(name)}${r.model ? ` (${escapeHtml(r.model)})` : ""}</option>`).join("\n");
9339
9339
  const webUrl = `http://127.0.0.1:${webPort}`;
9340
9340
  return `<!DOCTYPE html>
@@ -9350,6 +9350,8 @@ function skiffDebugPage(roles, webPort) {
9350
9350
  main { max-width: 720px; margin: 0 auto; }
9351
9351
  h1 { font-size: 18px; margin: 0 0 4px; }
9352
9352
  .sub { opacity: .65; font-size: 13px; margin-bottom: 16px; }
9353
+ .ccc { display: inline-block; padding: 3px 10px; border-radius: 999px; background: rgba(11,168,117,.12); color: #0ba875; font-size: 12px; font-weight: 600; margin-bottom: 12px; word-break: break-all; }
9354
+ @media (prefers-color-scheme: dark) { .ccc { color: #3ddc9a; } }
9353
9355
  label { font-size: 13px; font-weight: 600; display: block; margin: 12px 0 4px; }
9354
9356
  select, textarea { width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 8px; border: 1px solid #d0d7de; background: #fff; color: inherit; font-size: 14px; }
9355
9357
  @media (prefers-color-scheme: dark) { select, textarea { background: #26282c; border-color: #3a3d42; } }
@@ -9371,7 +9373,8 @@ function skiffDebugPage(roles, webPort) {
9371
9373
  <body>
9372
9374
  <main>
9373
9375
  <h1>Skiff Debug</h1>
9374
- <div class="sub">宁静号 trajectory 子集角色问答页(v1.25.0 实验性)— 走 DSH agent-loop 会话核心,轨迹与 WebUI 同源</div>
9376
+ <div class="sub">宁静号 trajectory 子集角色问答页(v1.25.2 实验性)— 走 DSH agent-loop 会话核心,轨迹与 WebUI 同源</div>
9377
+ <div class="ccc">CCC: ${escapeHtml(cccRoot)}</div>
9375
9378
  <label for="role">角色</label>
9376
9379
  <select id="role">${roleOptions || "<option value=\"\">(未配置角色)</option>"}</select>
9377
9380
  <label for="q">问题</label>
@@ -9431,15 +9434,20 @@ function escapeHtml(s) {
9431
9434
  }
9432
9435
  /**
9433
9436
  * 启动调试问答服务(单实例;重复启动幂等返回既有实例)。
9434
- * @param root 当前 CCC 根(角色配置读取 + skiff agent cwd)
9437
+ *
9438
+ * **CCC 绑定(v1.25.2 用户指出)**:服务绑定一个 CCC root(调用方 resolveSkiffRoot
9439
+ * 解析:live 会话中**含 skiff.roles 的 CCC 优先**);角色配置**每次请求实时读取**
9440
+ * (不缓存快照)——改 .opencode/serenity.json 后刷新页面即生效,无需重启服务。
9441
+ * 页面顶部显示绑定的 CCC root,绑定可核对。
9442
+ *
9443
+ * @param root 绑定的 CCC 根(角色配置读取 + skiff agent cwd)
9435
9444
  * @param port 调试端口(仅 127.0.0.1)
9436
9445
  * @param webPort 主 WebUI 端口(WebUI 链接)
9437
9446
  */
9438
9447
  async function startSkiffDebugServer(ctx, root, port, webPort) {
9439
9448
  if (active) return;
9440
- const roles = readSkiffRoles(root);
9441
9449
  const server = createServer((req, res) => {
9442
- handle(ctx, root, roles, webPort, req, res);
9450
+ handle(ctx, root, webPort, req, res);
9443
9451
  });
9444
9452
  await new Promise((resolve, reject) => {
9445
9453
  server.once("error", reject);
@@ -9449,7 +9457,7 @@ async function startSkiffDebugServer(ctx, root, port, webPort) {
9449
9457
  server,
9450
9458
  port
9451
9459
  };
9452
- console.log(`[serenity-hooks] ✓ Skiff 调试问答页: http://127.0.0.1:${port}(角色: ${roles.size},WebUI: ${webPort})`);
9460
+ console.log(`[serenity-hooks] ✓ Skiff 调试问答页: http://127.0.0.1:${port}(CCC: ${root},WebUI: ${webPort})`);
9453
9461
  }
9454
9462
  function stopSkiffDebugServer() {
9455
9463
  if (!active) return;
@@ -9458,11 +9466,11 @@ function stopSkiffDebugServer() {
9458
9466
  } catch {}
9459
9467
  active = null;
9460
9468
  }
9461
- async function handle(ctx, root, roles, webPort, req, res) {
9469
+ async function handle(ctx, root, webPort, req, res) {
9462
9470
  try {
9463
9471
  const url = (req.url ?? "/").split("?")[0] ?? "/";
9464
9472
  if (req.method === "GET" && url === "/") {
9465
- sendHtml(res, skiffDebugPage(roles, webPort));
9473
+ sendHtml(res, skiffDebugPage(readSkiffRoles(root), root, webPort));
9466
9474
  return;
9467
9475
  }
9468
9476
  if (req.method === "POST" && url === "/ask") {
@@ -9477,7 +9485,7 @@ async function handle(ctx, root, roles, webPort, req, res) {
9477
9485
  }
9478
9486
  const roleName = typeof body.role === "string" ? body.role : "";
9479
9487
  const question = typeof body.question === "string" ? body.question : "";
9480
- const role = roles.get(roleName);
9488
+ const role = readSkiffRoles(root).get(roleName);
9481
9489
  if (!roleName || !role) {
9482
9490
  sendJson(res, 400, { error: `unknown role: ${roleName}` });
9483
9491
  return;
@@ -9606,21 +9614,28 @@ function registerSkiff(ctx) {
9606
9614
  } catch {}
9607
9615
  sync();
9608
9616
  }
9609
- /** 解析当前 CCC 根:进程 cwd 上溯 .serenity 优先,live 会话 cwd 兜底 */
9617
+ /**
9618
+ * 解析 Skiff 调试服务绑定的 CCC 根(v1.25.2 用户指出:skiff 必须绑定 CCC):
9619
+ * ① live 会话中**配置了 skiff.roles 的 CCC 优先**(用户认知中的绑定目标)
9620
+ * ② 回退进程 cwd 上溯 .serenity
9621
+ * ③ 再回退任一 live 会话的 CCC
9622
+ */
9610
9623
  function resolveSkiffRoot(ctx) {
9611
- const fromCwd = findSerenityRoot(process.cwd());
9612
- if (fromCwd) return fromCwd;
9624
+ const liveRoots = [];
9613
9625
  try {
9614
9626
  const sessions = ctx.sessions;
9615
9627
  for (const s of sessions?.list?.() ?? []) {
9616
9628
  const cwd = s?.header?.cwd;
9617
9629
  if (typeof cwd === "string") {
9618
9630
  const r = findSerenityRoot(cwd);
9619
- if (r) return r;
9631
+ if (r && !liveRoots.includes(r)) liveRoots.push(r);
9620
9632
  }
9621
9633
  }
9622
9634
  } catch {}
9623
- return null;
9635
+ for (const r of liveRoots) if (readSkiffRoles(r).size > 0) return r;
9636
+ const fromCwd = findSerenityRoot(process.cwd());
9637
+ if (fromCwd) return fromCwd;
9638
+ return liveRoots[0] ?? null;
9624
9639
  }
9625
9640
  /** 主 WebUI 端口(WebUI 链接;webServer 未装配回退 3080) */
9626
9641
  function readWebPort(ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.25.0",
3
+ "version": "1.25.2",
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": {