@shgroup/dsh-serenity-hooks 1.19.3 → 1.19.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 +1 -1
- package/lib/index.js +44 -75
- 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.19.
|
|
3
|
+
"version": "1.19.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
|
@@ -3559,9 +3559,14 @@ const DEFAULT_COMPACTION_TOOLS = [
|
|
|
3559
3559
|
"grep",
|
|
3560
3560
|
"todo_write"
|
|
3561
3561
|
];
|
|
3562
|
-
/**
|
|
3563
|
-
*
|
|
3564
|
-
|
|
3562
|
+
/**
|
|
3563
|
+
* 协议级锚定消息序列(用户确认固化,2026-08-24 S142):任何 CCC 在抽象层都是
|
|
3564
|
+
* 宁静号/ACC——首轮锚定话语统一,无 CCC 配置面。两轮递进:
|
|
3565
|
+
* ① ACC 身份 + EAP 原则 + we/us 人称 + 先锚定后行动
|
|
3566
|
+
* ② 协作协议 5 条 + acknowledge 要求(只回确认,不做事)
|
|
3567
|
+
* 文本 = 原 home-serenity CCC 配置(anchorMessages),随零配置化固化进代码。
|
|
3568
|
+
*/
|
|
3569
|
+
const DEFAULT_ANCHOR_MESSAGES = ["You are the operator agent of Serenity — a cognitive container governed by the Abstract Cognitive Container (ACC) protocol.\nWe operate under the Explicit Abstraction Principle (EAP): the functional value of a thought equals its external reconstructability — every output we produce must be explicit (E↑), reconstructable (R↓), and stable (S↑).\nThe personal pronoun is us/we.\nWe anchor first, then act: the abstract layer precedes the concrete.\nPlease simply reply \"acknowledge\" — no action needed.", "Before we proceed, align on how we work:\n1. We read before we write — every decision grounds in what already exists in the container.\n2. Every output records its reasoning (R↓): decisions carry reasons and alternatives.\n3. We never jump levels — abstract layer first, then specifics.\n4. Every artifact we create is a durable cognitive anchor for the work that follows.\n5. We keep the container's state coherent (SESSION.md) as we advance.\nPlease simply reply \"acknowledge\" — no action needed."];
|
|
3565
3570
|
/**
|
|
3566
3571
|
* 构建一个 epoch 感知晋升跟踪器(纯逻辑,可单测)。
|
|
3567
3572
|
* requiredSignals:晋升所需信号数(boundary 后累计;默认 1)。
|
|
@@ -3572,9 +3577,10 @@ const DEFAULT_ANCHOR_MESSAGE = "You are a helpful software engineer assistant.Th
|
|
|
3572
3577
|
* 某些模型/协议(如 opencode-go-responses)的会话可能不产生标准
|
|
3573
3578
|
* `assistant/message` 晋升信号 → 永不晋升 → bootstrap 阶段工具被裁空
|
|
3574
3579
|
* (zeroTools 首请求 0 工具,ACC 工具不可见)。兜底:无论晋升信号是否
|
|
3575
|
-
*
|
|
3576
|
-
* promoteEvents)达到 maxRoundsFallback
|
|
3577
|
-
*
|
|
3580
|
+
* 到达,观察到的模型 step 数(`step/start` 事件计数,平台稳定事件,
|
|
3581
|
+
* responses/completions 都触发,独立于 promoteEvents)达到 maxRoundsFallback
|
|
3582
|
+
* 即强制 promoted(开放完整工具)。正常模型锚定轮数(requiredSignals)
|
|
3583
|
+
* 通常 ≤ 2 < 默认兜底 3,不受影响。
|
|
3578
3584
|
*/
|
|
3579
3585
|
function createEpochPromotion(promoteEvents, requiredSignals = 1, maxRoundsFallback = 3) {
|
|
3580
3586
|
/** sessionId -> { boundary, signalCount, rounds }(rounds = 兜底用回复轮计数) */
|
|
@@ -3601,7 +3607,7 @@ function createEpochPromotion(promoteEvents, requiredSignals = 1, maxRoundsFallb
|
|
|
3601
3607
|
continue;
|
|
3602
3608
|
}
|
|
3603
3609
|
if (promoteEvents.has(e.type) && seq > boundary) signalCount++;
|
|
3604
|
-
if (e.type === "
|
|
3610
|
+
if (e.type === "step/start" && seq > boundary) rounds++;
|
|
3605
3611
|
}
|
|
3606
3612
|
const entry = {
|
|
3607
3613
|
boundary,
|
|
@@ -3663,7 +3669,7 @@ function createEpochPromotion(promoteEvents, requiredSignals = 1, maxRoundsFallb
|
|
|
3663
3669
|
return;
|
|
3664
3670
|
}
|
|
3665
3671
|
if (promoteEvents.has(e.type) && seq > entry.boundary) entry.signalCount++;
|
|
3666
|
-
if (e.type === "
|
|
3672
|
+
if (e.type === "step/start" && seq > entry.boundary) entry.rounds++;
|
|
3667
3673
|
state.set(sid, entry);
|
|
3668
3674
|
}
|
|
3669
3675
|
};
|
|
@@ -3673,41 +3679,27 @@ const PROMOTE_EVENTS = {
|
|
|
3673
3679
|
"assistant-message": /* @__PURE__ */ new Set(["assistant/message"]),
|
|
3674
3680
|
either: /* @__PURE__ */ new Set(["tool/call", "assistant/message"])
|
|
3675
3681
|
};
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
}
|
|
3681
|
-
function sourceList(value, field, fallback) {
|
|
3682
|
-
if (value === void 0) return new Set(fallback);
|
|
3683
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.length === 0)) throw new TypeError(`bootstrap: ${field} must be an array of non-empty strings`);
|
|
3684
|
-
return new Set(value);
|
|
3685
|
-
}
|
|
3686
|
-
function resolveBootstrapSettings(opts) {
|
|
3687
|
-
const promoteOn = opts.promoteOn ?? "either";
|
|
3688
|
-
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)}`);
|
|
3689
|
-
let anchorMessages;
|
|
3690
|
-
if (Array.isArray(opts.anchorMessages)) {
|
|
3691
|
-
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`);
|
|
3692
|
-
anchorMessages = opts.anchorMessages;
|
|
3693
|
-
} else anchorMessages = [typeof opts.anchorMessage === "string" && opts.anchorMessage.length > 0 ? opts.anchorMessage : DEFAULT_ANCHOR_MESSAGE];
|
|
3682
|
+
/** 协议固有 bootstrap 设置:zeroTools=true(首请求 0 工具纯文字锚定轮)、
|
|
3683
|
+
* 晋升信号仅 assistant/message(对齐 zero-anchored-standard)、
|
|
3684
|
+
* requiredSignals = 锚定轮数(2 条消息 → 2 条回复后晋升)。无参——零配置面。 */
|
|
3685
|
+
function resolveBootstrapSettings() {
|
|
3694
3686
|
return {
|
|
3695
|
-
bootstrapTools:
|
|
3696
|
-
promoteEvents:
|
|
3697
|
-
requiredSignals:
|
|
3698
|
-
suppressedSources:
|
|
3699
|
-
compactionTools:
|
|
3700
|
-
anchorMessages,
|
|
3701
|
-
zeroTools:
|
|
3687
|
+
bootstrapTools: [...DEFAULT_BOOTSTRAP_TOOLS],
|
|
3688
|
+
promoteEvents: PROMOTE_EVENTS["assistant-message"],
|
|
3689
|
+
requiredSignals: DEFAULT_ANCHOR_MESSAGES.length,
|
|
3690
|
+
suppressedSources: new Set(DEFAULT_SUPPRESSED_SOURCES),
|
|
3691
|
+
compactionTools: [...DEFAULT_COMPACTION_TOOLS],
|
|
3692
|
+
anchorMessages: [...DEFAULT_ANCHOR_MESSAGES],
|
|
3693
|
+
zeroTools: true
|
|
3702
3694
|
};
|
|
3703
3695
|
}
|
|
3704
3696
|
/**
|
|
3705
|
-
* 注册 Anchored bootstrap
|
|
3706
|
-
*
|
|
3697
|
+
* 注册 Anchored bootstrap 机制(协议固有,零配置面——S142;按 agent cwd 定位 CCC root,
|
|
3698
|
+
* 晋升状态按 root 隔离,但设置全局一致):
|
|
3699
|
+
* 1. session/event 观察晋升信号(assistant/message + step/start 兜底 + compaction/end)
|
|
3707
3700
|
* 2. system-prompt/assemble:bootstrap 阶段目录窄化到 bootstrapTools(+compaction 后 compactionTools)
|
|
3708
3701
|
* 3. agent/pre-step:bootstrap 阶段剥离 suppressedSources 注入消息(降级保留全部)
|
|
3709
3702
|
*
|
|
3710
|
-
* CCC 的 serenity.json 配置 `bootstrap.enabled: true` 才生效(否则零影响);
|
|
3711
3703
|
* 摘除 = 删除 index.ts 中本注册行(独立模块)。
|
|
3712
3704
|
*/
|
|
3713
3705
|
/** 从 agent 解析 CCC 根(宽松;无 agent/无 CCC 返回 null) */
|
|
@@ -3716,31 +3708,16 @@ function agentRoot(agent) {
|
|
|
3716
3708
|
if (typeof cwd !== "string") return null;
|
|
3717
3709
|
return findSerenityRoot(cwd);
|
|
3718
3710
|
}
|
|
3719
|
-
/**
|
|
3720
|
-
|
|
3721
|
-
function readBootstrapConfig(agent) {
|
|
3722
|
-
const root = agentRoot(agent);
|
|
3723
|
-
if (!root) return resolveBootstrapSettings({});
|
|
3724
|
-
const b = loadSerenityConfig(root).bootstrap;
|
|
3725
|
-
return resolveBootstrapSettings({
|
|
3726
|
-
bootstrapTools: b?.bootstrapTools,
|
|
3727
|
-
promoteOn: b?.promoteOn,
|
|
3728
|
-
suppressedContextSources: b?.suppressedContextSources,
|
|
3729
|
-
compactionTools: b?.compactionTools,
|
|
3730
|
-
anchorMessage: b?.anchorMessage,
|
|
3731
|
-
anchorMessages: b?.anchorMessages,
|
|
3732
|
-
zeroTools: b?.zeroTools
|
|
3733
|
-
});
|
|
3734
|
-
}
|
|
3711
|
+
/** 协议固有设置(零配置面):所有 CCC 使用同一固化设置 */
|
|
3712
|
+
const SETTINGS = resolveBootstrapSettings();
|
|
3735
3713
|
function registerBootstrap(ctx) {
|
|
3736
|
-
const settingsByRoot = /* @__PURE__ */ new Map();
|
|
3737
3714
|
const trackers = /* @__PURE__ */ new Map();
|
|
3738
3715
|
/** 已锚定会话(进程内防重:子 agent 每会话只锚定一次) */
|
|
3739
3716
|
const anchoredSessions = /* @__PURE__ */ new Set();
|
|
3740
|
-
const trackerFor = (root
|
|
3717
|
+
const trackerFor = (root) => {
|
|
3741
3718
|
let t = trackers.get(root);
|
|
3742
3719
|
if (!t) {
|
|
3743
|
-
t = createEpochPromotion(
|
|
3720
|
+
t = createEpochPromotion(SETTINGS.promoteEvents, SETTINGS.requiredSignals);
|
|
3744
3721
|
trackers.set(root, t);
|
|
3745
3722
|
}
|
|
3746
3723
|
return t;
|
|
@@ -3751,16 +3728,12 @@ function registerBootstrap(ctx) {
|
|
|
3751
3728
|
if (typeof cwd !== "string") return;
|
|
3752
3729
|
const root = findSerenityRoot(cwd);
|
|
3753
3730
|
if (!root) return;
|
|
3754
|
-
|
|
3755
|
-
settingsByRoot.set(root, settings);
|
|
3756
|
-
trackerFor(root, settings).observe(session, event);
|
|
3731
|
+
trackerFor(root).observe(session, event);
|
|
3757
3732
|
} catch {}
|
|
3758
3733
|
});
|
|
3759
3734
|
ctx.on("agent/inbox/inserted", ({ agent, message }) => {
|
|
3760
3735
|
try {
|
|
3761
|
-
|
|
3762
|
-
if (!root) return;
|
|
3763
|
-
const settings = settingsByRoot.get(root) ?? readBootstrapConfig(agent);
|
|
3736
|
+
if (!agentRoot(agent)) return;
|
|
3764
3737
|
const session = agent.session;
|
|
3765
3738
|
const depth = session?.header?.delegationDepth ?? 0;
|
|
3766
3739
|
const sid = typeof session?.id === "string" ? session.id : void 0;
|
|
@@ -3771,12 +3744,12 @@ function registerBootstrap(ctx) {
|
|
|
3771
3744
|
if (message?.source?.kind === "plugin") return;
|
|
3772
3745
|
const inbox = agent.inbox;
|
|
3773
3746
|
if (!inbox?.prepend) return;
|
|
3774
|
-
for (let i =
|
|
3747
|
+
for (let i = SETTINGS.anchorMessages.length - 1; i >= 0; i--) inbox.prepend("next-turn", {
|
|
3775
3748
|
id: `bootstrap-anchor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}-${i}`,
|
|
3776
3749
|
role: "user",
|
|
3777
3750
|
content: [{
|
|
3778
3751
|
type: "text",
|
|
3779
|
-
text:
|
|
3752
|
+
text: SETTINGS.anchorMessages[i]
|
|
3780
3753
|
}],
|
|
3781
3754
|
source: {
|
|
3782
3755
|
kind: "plugin",
|
|
@@ -3786,7 +3759,7 @@ function registerBootstrap(ctx) {
|
|
|
3786
3759
|
}
|
|
3787
3760
|
});
|
|
3788
3761
|
if (sid !== void 0) anchoredSessions.add(sid);
|
|
3789
|
-
warnOnce(`anchor turns injected: ${
|
|
3762
|
+
warnOnce(`anchor turns injected: ${SETTINGS.anchorMessages.length} 条(${SETTINGS.anchorMessages[0].slice(0, 40)}…)`);
|
|
3790
3763
|
} catch {}
|
|
3791
3764
|
});
|
|
3792
3765
|
let warned = false;
|
|
@@ -3803,19 +3776,17 @@ function registerBootstrap(ctx) {
|
|
|
3803
3776
|
const agent = context.agent;
|
|
3804
3777
|
const root = agentRoot(agent);
|
|
3805
3778
|
if (!root) return assembled;
|
|
3806
|
-
const
|
|
3807
|
-
settingsByRoot.set(root, settings);
|
|
3808
|
-
const status = trackerFor(root, settings).status(agent);
|
|
3779
|
+
const status = trackerFor(root).status(agent);
|
|
3809
3780
|
if (status.promoted) return assembled;
|
|
3810
3781
|
const tools = assembled.tools;
|
|
3811
3782
|
if (!Array.isArray(tools)) return assembled;
|
|
3812
3783
|
const available = new Set(tools.map((tool) => tool.name).filter((n) => typeof n === "string"));
|
|
3813
|
-
if (
|
|
3784
|
+
if (SETTINGS.zeroTools) {
|
|
3814
3785
|
if (status.boundary < 0) return {
|
|
3815
3786
|
...assembled,
|
|
3816
3787
|
tools: []
|
|
3817
3788
|
};
|
|
3818
|
-
const keep = new Set(
|
|
3789
|
+
const keep = new Set(SETTINGS.compactionTools);
|
|
3819
3790
|
const missing = [...keep].filter((name) => !available.has(name));
|
|
3820
3791
|
if (missing.length > 0) {
|
|
3821
3792
|
warnOnce(`expected compaction tools missing=${JSON.stringify(missing)} — bootstrap disabled, full catalog exposed`);
|
|
@@ -3826,8 +3797,8 @@ function registerBootstrap(ctx) {
|
|
|
3826
3797
|
tools: tools.filter((tool) => typeof tool.name === "string" && keep.has(tool.name))
|
|
3827
3798
|
};
|
|
3828
3799
|
}
|
|
3829
|
-
const keep = new Set(
|
|
3830
|
-
if (status.boundary >= 0) for (const toolName of
|
|
3800
|
+
const keep = new Set(SETTINGS.bootstrapTools);
|
|
3801
|
+
if (status.boundary >= 0) for (const toolName of SETTINGS.compactionTools) keep.add(toolName);
|
|
3831
3802
|
const missing = [...keep].filter((name) => !available.has(name));
|
|
3832
3803
|
if (missing.length > 0) {
|
|
3833
3804
|
warnOnce(`expected bootstrap tools missing=${JSON.stringify(missing)} — bootstrap disabled, full catalog exposed`);
|
|
@@ -3848,14 +3819,12 @@ function registerBootstrap(ctx) {
|
|
|
3848
3819
|
try {
|
|
3849
3820
|
const root = agentRoot(agent);
|
|
3850
3821
|
if (!root) return decision;
|
|
3851
|
-
|
|
3852
|
-
settingsByRoot.set(root, settings);
|
|
3853
|
-
if (trackerFor(root, settings).status(agent).promoted || settings.suppressedSources.size === 0) return decision;
|
|
3822
|
+
if (trackerFor(root).status(agent).promoted || SETTINGS.suppressedSources.size === 0) return decision;
|
|
3854
3823
|
const messages = decision.messages;
|
|
3855
3824
|
if (!Array.isArray(messages)) return decision;
|
|
3856
3825
|
const kept = messages.filter((message) => {
|
|
3857
3826
|
const kind = message?.source?.kind;
|
|
3858
|
-
return typeof kind !== "string" || !
|
|
3827
|
+
return typeof kind !== "string" || !SETTINGS.suppressedSources.has(kind);
|
|
3859
3828
|
});
|
|
3860
3829
|
return kept.length === messages.length ? decision : {
|
|
3861
3830
|
...decision,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.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": {
|