@shgroup/dsh-serenity-hooks 1.18.3 → 1.18.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.18.3",
3
+ "version": "1.18.5",
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/index.js CHANGED
@@ -1924,16 +1924,18 @@ function decideGuard(input) {
1924
1924
  deny: `path escape blocked: "${pathArg}" 越出 CCC 根`,
1925
1925
  kind: "deny"
1926
1926
  };
1927
- const rel = relative(root, abs).split("\\").join("/");
1928
- if (rel === ".serenity-safe-on" || rel === ".serenity" || rel.startsWith(".serenity-safe-on/") || rel.startsWith(".serenity/")) return {
1929
- deny: `CCC 治理文件 "${rel}" 保留给用户,agent 不可写`,
1930
- kind: "deny"
1931
- };
1932
- const hit = matchBlacklist(rel, blacklist);
1933
- if (hit) return {
1934
- deny: hit.message ?? `blacklist blocked: "${pathArg}" 命中规则 "${hit.pattern}"`,
1935
- kind: "deny"
1936
- };
1927
+ if (toolName === "write" || toolName === "edit" || toolName === "str_replace_editor" || toolName === "cc_fs" || toolName === "bash" || toolName === "append" || toolName === "touch") {
1928
+ const rel = relative(root, abs).split("\\").join("/");
1929
+ if (rel === ".serenity-safe-on" || rel === ".serenity" || rel.startsWith(".serenity-safe-on/") || rel.startsWith(".serenity/")) return {
1930
+ deny: `CCC 治理文件 "${rel}" 保留给用户,agent 不可写`,
1931
+ kind: "deny"
1932
+ };
1933
+ const hit = matchBlacklist(rel, blacklist);
1934
+ if (hit) return {
1935
+ deny: hit.message ?? `blacklist blocked: "${pathArg}" 命中规则 "${hit.pattern}"`,
1936
+ kind: "deny"
1937
+ };
1938
+ }
1937
1939
  }
1938
1940
  return { kind: "allow" };
1939
1941
  }
@@ -3527,9 +3529,14 @@ const DEFAULT_COMPACTION_TOOLS = [
3527
3529
  /** 默认首轮锚定消息(用户指定:persona 设定 + we/us 人称——首轮模型以 we/us 自称,
3528
3530
  * 对齐 anchored 实测的 "we" 轨迹特征) */
3529
3531
  const DEFAULT_ANCHOR_MESSAGE = "You are a helpful software engineer assistant.The personal pronoun is us/we.";
3530
- /** 构建一个 epoch 感知晋升跟踪器(纯逻辑,可单测) */
3531
- function createEpochPromotion(promoteEvents) {
3532
- /** sessionId -> { boundary, promoted } */
3532
+ /**
3533
+ * 构建一个 epoch 感知晋升跟踪器(纯逻辑,可单测)。
3534
+ * requiredSignals:晋升所需信号数(boundary 后累计;默认 1)。
3535
+ * 多轮锚定(v4):两轮递进锚定时 requiredSignals = 锚定轮数——
3536
+ * 每条锚定回复(assistant/message)计一次,最后一条回复后晋升。
3537
+ */
3538
+ function createEpochPromotion(promoteEvents, requiredSignals = 1) {
3539
+ /** sessionId -> { boundary, signalCount }(boundary 后晋升信号计数) */
3533
3540
  const state = /* @__PURE__ */ new Map();
3534
3541
  const sessionIdOf = (session) => {
3535
3542
  if (session && typeof session === "object") {
@@ -3539,24 +3546,27 @@ function createEpochPromotion(promoteEvents) {
3539
3546
  };
3540
3547
  const scan = (session) => {
3541
3548
  let boundary = -1;
3542
- let promoted = false;
3549
+ let signalCount = 0;
3543
3550
  const events = session?.events;
3544
3551
  if (Array.isArray(events)) for (const event of events) {
3545
3552
  const e = event;
3546
3553
  const seq = typeof e.seq === "number" ? e.seq : 0;
3547
3554
  if (e.type === "compaction/end") {
3548
3555
  boundary = seq;
3549
- promoted = false;
3556
+ signalCount = 0;
3550
3557
  continue;
3551
3558
  }
3552
- if (promoteEvents.has(e.type) && seq > boundary) promoted = true;
3559
+ if (promoteEvents.has(e.type) && seq > boundary) signalCount++;
3553
3560
  }
3554
3561
  const entry = {
3555
3562
  boundary,
3556
- promoted
3563
+ promoted: signalCount >= requiredSignals
3557
3564
  };
3558
3565
  const sid = sessionIdOf(session);
3559
- if (sid) state.set(sid, entry);
3566
+ if (sid) state.set(sid, {
3567
+ boundary,
3568
+ signalCount
3569
+ });
3560
3570
  return entry;
3561
3571
  };
3562
3572
  return {
@@ -3579,7 +3589,12 @@ function createEpochPromotion(promoteEvents) {
3579
3589
  boundary: -1,
3580
3590
  promoted: true
3581
3591
  };
3582
- return state.get(sid) ?? scan(session);
3592
+ const s = state.get(sid);
3593
+ if (s) return {
3594
+ boundary: s.boundary,
3595
+ promoted: s.signalCount >= requiredSignals
3596
+ };
3597
+ return scan(session);
3583
3598
  },
3584
3599
  observe(session, event) {
3585
3600
  const sid = sessionIdOf(session);
@@ -3591,13 +3606,13 @@ function createEpochPromotion(promoteEvents) {
3591
3606
  if (e.type === "compaction/end") {
3592
3607
  state.set(sid, {
3593
3608
  boundary: seq,
3594
- promoted: false
3609
+ signalCount: 0
3595
3610
  });
3596
3611
  return;
3597
3612
  }
3598
- if (promoteEvents.has(e.type) && seq > entry.boundary && !entry.promoted) state.set(sid, {
3599
- ...entry,
3600
- promoted: true
3613
+ if (promoteEvents.has(e.type) && seq > entry.boundary) state.set(sid, {
3614
+ boundary: entry.boundary,
3615
+ signalCount: entry.signalCount + 1
3601
3616
  });
3602
3617
  }
3603
3618
  };
@@ -3620,12 +3635,18 @@ function sourceList(value, field, fallback) {
3620
3635
  function resolveBootstrapSettings(opts) {
3621
3636
  const promoteOn = opts.promoteOn ?? "either";
3622
3637
  if (promoteOn !== "either" && promoteOn !== "tool-call" && promoteOn !== "assistant-message") throw new TypeError(`bootstrap: promoteOn must be one of "tool-call", "assistant-message", "either"; got ${JSON.stringify(promoteOn)}`);
3638
+ let anchorMessages;
3639
+ if (Array.isArray(opts.anchorMessages)) {
3640
+ if (opts.anchorMessages.length === 0 || opts.anchorMessages.some((m) => typeof m !== "string" || m.length === 0)) throw new TypeError(`bootstrap: anchorMessages must be a non-empty array of non-empty strings`);
3641
+ anchorMessages = opts.anchorMessages;
3642
+ } else anchorMessages = [typeof opts.anchorMessage === "string" && opts.anchorMessage.length > 0 ? opts.anchorMessage : DEFAULT_ANCHOR_MESSAGE];
3623
3643
  return {
3624
3644
  bootstrapTools: stringList(opts.bootstrapTools, "bootstrapTools", DEFAULT_BOOTSTRAP_TOOLS),
3625
3645
  promoteEvents: opts.zeroTools ? PROMOTE_EVENTS["assistant-message"] : PROMOTE_EVENTS[promoteOn],
3646
+ requiredSignals: opts.zeroTools ? anchorMessages.length : 1,
3626
3647
  suppressedSources: sourceList(opts.suppressedContextSources, "suppressedContextSources", DEFAULT_SUPPRESSED_SOURCES),
3627
3648
  compactionTools: stringList(opts.compactionTools, "compactionTools", DEFAULT_COMPACTION_TOOLS),
3628
- anchorMessage: typeof opts.anchorMessage === "string" && opts.anchorMessage.length > 0 ? opts.anchorMessage : DEFAULT_ANCHOR_MESSAGE,
3649
+ anchorMessages,
3629
3650
  zeroTools: opts.zeroTools === true
3630
3651
  };
3631
3652
  }
@@ -3656,6 +3677,7 @@ function readBootstrapConfig(agent) {
3656
3677
  suppressedContextSources: b?.suppressedContextSources,
3657
3678
  compactionTools: b?.compactionTools,
3658
3679
  anchorMessage: b?.anchorMessage,
3680
+ anchorMessages: b?.anchorMessages,
3659
3681
  zeroTools: b?.zeroTools
3660
3682
  });
3661
3683
  }
@@ -3665,7 +3687,7 @@ function registerBootstrap(ctx) {
3665
3687
  const trackerFor = (root, settings) => {
3666
3688
  let t = trackers.get(root);
3667
3689
  if (!t) {
3668
- t = createEpochPromotion(settings.promoteEvents);
3690
+ t = createEpochPromotion(settings.promoteEvents, settings.requiredSignals);
3669
3691
  trackers.set(root, t);
3670
3692
  }
3671
3693
  return t;
@@ -3692,12 +3714,12 @@ function registerBootstrap(ctx) {
3692
3714
  if (message?.source?.kind === "plugin") return;
3693
3715
  const inbox = agent.inbox;
3694
3716
  if (!inbox?.prepend) return;
3695
- inbox.prepend("next-turn", {
3696
- id: `bootstrap-anchor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
3717
+ for (let i = settings.anchorMessages.length - 1; i >= 0; i--) inbox.prepend("next-turn", {
3718
+ id: `bootstrap-anchor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}-${i}`,
3697
3719
  role: "user",
3698
3720
  content: [{
3699
3721
  type: "text",
3700
- text: settings.anchorMessage
3722
+ text: settings.anchorMessages[i]
3701
3723
  }],
3702
3724
  source: {
3703
3725
  kind: "plugin",
@@ -3706,7 +3728,7 @@ function registerBootstrap(ctx) {
3706
3728
  summary: "bootstrap anchor turn"
3707
3729
  }
3708
3730
  });
3709
- warnOnce(`anchor turn injected: "${settings.anchorMessage.slice(0, 40)}…"`);
3731
+ warnOnce(`anchor turns injected: ${settings.anchorMessages.length} 条(${settings.anchorMessages[0].slice(0, 40)}…)`);
3710
3732
  } catch {}
3711
3733
  });
3712
3734
  let warned = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.18.3",
3
+ "version": "1.18.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": {