@shgroup/dsh-serenity-hooks 1.26.7 → 1.26.8

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.26.7",
3
+ "version": "1.26.8",
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/index.js CHANGED
@@ -11724,8 +11724,84 @@ function escapeHtml(s) {
11724
11724
  })[c] ?? c);
11725
11725
  }
11726
11726
  /**
11727
+ * 提取 `<think>…</think>` 块(v1.26.8:**状态机扫描,弃正则**——用户批评"老用正则不是个办法")。
11728
+ *
11729
+ * 逐字符扫描识别开/闭标签(大小写不敏感;`<think ...>` 允许属性变体;`</think >` 允许尾随空格),
11730
+ * 不依赖正则回溯,天然处理:
11731
+ * - **嵌套 `<think>`**(内层按内容处理,不递归——DeepSeek think 不会嵌套)
11732
+ * - **未闭合 `<think>`**(优雅截断:剩余全部作为 think 内容,不泄漏标记)
11733
+ * - **占位符冲突**(用 \u0001T<idx>\u0001——ASCII 控制字符,正文几乎不可能出现)
11734
+ *
11735
+ * @returns body(占位符替换后的正文)+ thinks(提取的 think 内容数组,保序)
11736
+ */
11737
+ function extractThinkBlocks(raw) {
11738
+ const thinks = [];
11739
+ const parts = [];
11740
+ let i = 0;
11741
+ while (i < raw.length) {
11742
+ const openTag = matchOpenThink(raw, i);
11743
+ if (!openTag) break;
11744
+ parts.push(raw.slice(i, openTag.tagStart));
11745
+ const closeTag = matchCloseThink(raw, openTag.contentStart);
11746
+ if (closeTag < 0) {
11747
+ const inner = raw.slice(openTag.contentStart);
11748
+ thinks.push(inner.trim());
11749
+ parts.push(`\u0001T${thinks.length - 1}\u0001`);
11750
+ i = raw.length;
11751
+ break;
11752
+ }
11753
+ const inner = raw.slice(openTag.contentStart, closeTag);
11754
+ thinks.push(inner.trim());
11755
+ parts.push(`\u0001T${thinks.length - 1}\u0001`);
11756
+ let j = closeTag + 7;
11757
+ while (j < raw.length && (raw[j] === " " || raw[j] === " " || raw[j] === "\n" || raw[j] === "\r")) j++;
11758
+ i = raw[j] === ">" ? j + 1 : closeTag + 8;
11759
+ }
11760
+ if (i < raw.length) parts.push(raw.slice(i));
11761
+ return {
11762
+ body: parts.join(""),
11763
+ thinks
11764
+ };
11765
+ }
11766
+ /** 从 from 起找 `<think` 开标签(大小写不敏感,允许属性);返回标签起点与内容起点,或 null */
11767
+ function matchOpenThink(s, from) {
11768
+ for (let i = from; i <= s.length - 7; i++) {
11769
+ if (s[i] !== "<" || s[i + 1] !== "t" && s[i + 1] !== "T") continue;
11770
+ if (s.slice(i + 1, i + 6).toLowerCase() !== "think") continue;
11771
+ const after = s[i + 6];
11772
+ if (after === ">") return {
11773
+ tagStart: i,
11774
+ contentStart: i + 7
11775
+ };
11776
+ if (after === " " || after === " " || after === "\n" || after === "\r") {
11777
+ const gt = s.indexOf(">", i + 7);
11778
+ if (gt < 0) return null;
11779
+ return {
11780
+ tagStart: i,
11781
+ contentStart: gt + 1
11782
+ };
11783
+ }
11784
+ }
11785
+ return null;
11786
+ }
11787
+ /** 从 contentStart 起找 `</think>` 闭合标签(大小写不敏感,允许 `</think >` 尾随空格);返回闭合标签起点或 -1 */
11788
+ function matchCloseThink(s, contentStart) {
11789
+ for (let i = contentStart; i <= s.length - 8; i++) {
11790
+ if (s[i] !== "<" || s[i + 1] !== "/") continue;
11791
+ if (s.slice(i + 2, i + 7).toLowerCase() !== "think") continue;
11792
+ const after = s[i + 7];
11793
+ if (after === ">") return i;
11794
+ if (after === " " || after === " " || after === "\n" || after === "\r") {
11795
+ let j = i + 8;
11796
+ while (j < s.length && (s[j] === " " || s[j] === " " || s[j] === "\n" || s[j] === "\r")) j++;
11797
+ if (s[j] === ">") return i;
11798
+ }
11799
+ }
11800
+ return -1;
11801
+ }
11802
+ /**
11727
11803
  * Markdown 渲染(v1.25.9,正经库 marked 服务端渲染——替代手写正则渲染器,S142 用户要求):
11728
- * ① 提取 `<think>…</think>` 块(占位符 \u0000T<idx>\u0000
11804
+ * ① 提取 `<think>…</think>` 块(v1.26.8 状态机扫描,占位符 \u0001T<idx>\u0001
11729
11805
  * ② 正文与 think 内容**先 escapeHtml 再 marked.parse**(GFM + breaks)——markdown 语法不受
11730
11806
  * 转义影响,原始 HTML 注入被消除(安全);代码块内 `<` 显示为实体(可接受)
11731
11807
  * ③ think 占位符:默认还原为 `<details class="think">` 折叠卡(🧠 思考过程,默认收起);
@@ -11733,17 +11809,12 @@ function escapeHtml(s) {
11733
11809
  * @param hideThink 为 true 时 `<think>` 内容完全不渲染(public 问答页体验)
11734
11810
  */
11735
11811
  function renderSkiffMarkdown(raw, hideThink = false) {
11736
- const thinks = [];
11737
- const body = raw.replace(/<think>([\s\S]*?)<\/think>/gi, (_m, inner) => {
11738
- const idx = thinks.length;
11739
- thinks.push(String(inner ?? "").trim());
11740
- return `\u0000T${idx}\u0000`;
11741
- });
11812
+ const { body, thinks } = extractThinkBlocks(raw);
11742
11813
  const parsed = f.parse(escapeHtml(body), {
11743
11814
  breaks: true,
11744
11815
  gfm: true
11745
11816
  });
11746
- return (typeof parsed === "string" ? parsed : "").replace(/\u0000T(\d+)\u0000/g, (_m, idx) => {
11817
+ return (typeof parsed === "string" ? parsed : "").replace(/\u0001T(\d+)\u0001/g, (_m, idx) => {
11747
11818
  if (hideThink) return "";
11748
11819
  const inner = thinks[Number(idx)] ?? "";
11749
11820
  const innerHtml = inner === "" ? "" : f.parse(escapeHtml(inner), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.26.7",
3
+ "version": "1.26.8",
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": {