@shgroup/dsh-serenity-hooks 1.16.2 → 1.16.4
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 +366 -222
- package/package.json +5 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.4",
|
|
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
|
@@ -3,11 +3,11 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
|
3
3
|
import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
5
5
|
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
6
|
-
import { platform } from "node:os";
|
|
6
|
+
import { homedir, platform } from "node:os";
|
|
7
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
8
9
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
9
10
|
import { randomBytes } from "node:crypto";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
11
|
//#region src/ccc.ts
|
|
12
12
|
/**
|
|
13
13
|
* ccc.ts — CCC 纯逻辑层(零 DSH 依赖,可独立单测)
|
|
@@ -986,6 +986,225 @@ const sessionTool = defineTool({
|
|
|
986
986
|
}
|
|
987
987
|
});
|
|
988
988
|
//#endregion
|
|
989
|
+
//#region src/constants.ts
|
|
990
|
+
/** 常量(纯模块,零 DSH 依赖) */
|
|
991
|
+
/**
|
|
992
|
+
* ACC 版本:自动从 package.json 读取(单一真相源,消除与 CHANGELOG 的漂移)。
|
|
993
|
+
* 发布时只需改 package.json 的 version。
|
|
994
|
+
*/
|
|
995
|
+
const ACC_VERSION = (() => {
|
|
996
|
+
try {
|
|
997
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
998
|
+
return JSON.parse(readFileSync(join(here, "..", "package.json"), "utf-8")).version ?? "0.0.0";
|
|
999
|
+
} catch {
|
|
1000
|
+
return "0.0.0";
|
|
1001
|
+
}
|
|
1002
|
+
})();
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region src/seams/guards.ts
|
|
1005
|
+
/**
|
|
1006
|
+
* guards.ts — 拦截缝:安全模式 + 路径守卫(P3 语义的机械层)
|
|
1007
|
+
*
|
|
1008
|
+
* 纯决策逻辑(decideGuard)与 DSH 注册(registerGuards)分离:
|
|
1009
|
+
* 前者零 DSH 依赖可单测,后者把决策接到 tools/pre-execute 瀑布 + ctx.tools.guard 终局。
|
|
1010
|
+
*
|
|
1011
|
+
* 对应 opencode-serenity-plugin 的 tool.execute.before 路径守卫 + bash 开关 + 黑名单。
|
|
1012
|
+
*/
|
|
1013
|
+
/**
|
|
1014
|
+
* 安全模式 + 黑名单 + P3 路径守卫的纯决策。
|
|
1015
|
+
* 对齐 opencode-serenity-plugin 标准:安全模式 = **bash 禁用** + 写入黑名单;
|
|
1016
|
+
* write/edit 等工具仅受路径逃逸与黑名单约束(不整体禁用)。
|
|
1017
|
+
* 优先级:safe-mode bash > 路径越界 > 黑名单命中。
|
|
1018
|
+
*/
|
|
1019
|
+
function decideGuard(input) {
|
|
1020
|
+
const { root, toolName, safeModeOn, blacklist, pathArg } = input;
|
|
1021
|
+
if (safeModeOn && toolName === "bash") return {
|
|
1022
|
+
deny: `bash: 没有这个工具`,
|
|
1023
|
+
kind: "deny"
|
|
1024
|
+
};
|
|
1025
|
+
if (pathArg !== void 0) {
|
|
1026
|
+
const rel = relative(root, resolve(root, pathArg));
|
|
1027
|
+
if (rel.startsWith("..")) return {
|
|
1028
|
+
deny: `path escape blocked: "${pathArg}" 越出 CCC 根`,
|
|
1029
|
+
kind: "deny"
|
|
1030
|
+
};
|
|
1031
|
+
if (rel === ".serenity-safe-on" || rel === ".serenity" || rel.startsWith(".serenity-safe-on/") || rel.startsWith(".serenity/")) return {
|
|
1032
|
+
deny: `CCC 治理文件 "${rel}" 保留给用户,agent 不可写`,
|
|
1033
|
+
kind: "deny"
|
|
1034
|
+
};
|
|
1035
|
+
const hit = matchBlacklist(rel, blacklist);
|
|
1036
|
+
if (hit) return {
|
|
1037
|
+
deny: `blacklist blocked: "${pathArg}" 命中规则 "${hit}"`,
|
|
1038
|
+
kind: "deny"
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
return { kind: "allow" };
|
|
1042
|
+
}
|
|
1043
|
+
/** 从 exec 提取 agent 会话 cwd(CCC 根检测基准);无则回退进程 cwd */
|
|
1044
|
+
function resolveAgentCwd(exec) {
|
|
1045
|
+
return exec.agent?.session?.header?.cwd ?? process.cwd();
|
|
1046
|
+
}
|
|
1047
|
+
/** 安全模式开启时从模型工具列表隐藏的工具(只隐藏 bash;write/edit 保留) */
|
|
1048
|
+
const SAFE_MODE_DENY_TOOLS = ["bash"];
|
|
1049
|
+
/** agent key → restrict disposer(安全模式工具隐藏状态) */
|
|
1050
|
+
const safeModeRestrictions = /* @__PURE__ */ new Map();
|
|
1051
|
+
const restrictDiag = {
|
|
1052
|
+
lastKey: null,
|
|
1053
|
+
lastAttemptAt: null,
|
|
1054
|
+
lastSuccess: null,
|
|
1055
|
+
lastError: null,
|
|
1056
|
+
activeKeys: []
|
|
1057
|
+
};
|
|
1058
|
+
function getRestrictDiagnostics() {
|
|
1059
|
+
return {
|
|
1060
|
+
...restrictDiag,
|
|
1061
|
+
activeKeys: [...safeModeRestrictions.keys()]
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
/** 诊断落盘:AGENT_SESSIONS/.restrict-diag.json(文件通道,避免 HTTP 自锁) */
|
|
1065
|
+
function writeRestrictDiag(root) {
|
|
1066
|
+
try {
|
|
1067
|
+
const dir = resolve(root, "AGENT_SESSIONS");
|
|
1068
|
+
mkdirSync(dir, { recursive: true });
|
|
1069
|
+
writeFileSync(resolve(dir, ".restrict-diag.json"), JSON.stringify({
|
|
1070
|
+
...getRestrictDiagnostics(),
|
|
1071
|
+
cccRoot: root
|
|
1072
|
+
}, null, 2) + "\n", "utf-8");
|
|
1073
|
+
} catch {}
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* 同步安全模式工具隐藏:标记存在 → agent.ctx.tools.restrict deny 隐藏写工具;
|
|
1077
|
+
* 标记消失 → 解除。pre-step 每步调用 → 切换实时生效。
|
|
1078
|
+
*/
|
|
1079
|
+
function syncSafeModeRestriction(agent, root) {
|
|
1080
|
+
const key = agent.session.id ?? "global";
|
|
1081
|
+
const on = isSafeModeOn(root);
|
|
1082
|
+
const existing = safeModeRestrictions.get(key);
|
|
1083
|
+
if (on && !existing) try {
|
|
1084
|
+
const dispose = agent.ctx.tools.restrict({ deny: [...SAFE_MODE_DENY_TOOLS] });
|
|
1085
|
+
safeModeRestrictions.set(key, dispose);
|
|
1086
|
+
restrictDiag.lastKey = key;
|
|
1087
|
+
restrictDiag.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1088
|
+
restrictDiag.lastSuccess = true;
|
|
1089
|
+
restrictDiag.lastError = null;
|
|
1090
|
+
} catch (e) {
|
|
1091
|
+
restrictDiag.lastKey = key;
|
|
1092
|
+
restrictDiag.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1093
|
+
restrictDiag.lastSuccess = false;
|
|
1094
|
+
restrictDiag.lastError = e.message;
|
|
1095
|
+
console.error(`[serenity-hooks] restrict 失败 (key=${key}):`, e.message);
|
|
1096
|
+
}
|
|
1097
|
+
else if (!on && existing) {
|
|
1098
|
+
try {
|
|
1099
|
+
existing();
|
|
1100
|
+
} catch (e) {
|
|
1101
|
+
console.error(`[serenity-hooks] restrict 解除失败 (key=${key}):`, e.message);
|
|
1102
|
+
}
|
|
1103
|
+
safeModeRestrictions.delete(key);
|
|
1104
|
+
}
|
|
1105
|
+
writeRestrictDiag(root);
|
|
1106
|
+
}
|
|
1107
|
+
/** 从 exec 参数中提取常见路径字段(write/edit 工具);宽松读取 */
|
|
1108
|
+
function extractPathArg(exec) {
|
|
1109
|
+
const args = exec.arguments;
|
|
1110
|
+
if (args === null || typeof args !== "object") return void 0;
|
|
1111
|
+
const a = args;
|
|
1112
|
+
for (const key of [
|
|
1113
|
+
"path",
|
|
1114
|
+
"file_path",
|
|
1115
|
+
"target",
|
|
1116
|
+
"dst"
|
|
1117
|
+
]) {
|
|
1118
|
+
const v = a[key];
|
|
1119
|
+
if (typeof v === "string") return v;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* 注册守卫:tools/pre-execute 瀑布 + ctx.tools.guard 终局。
|
|
1124
|
+
* 两者都从 CCC 根实时读取配置(无状态、无缓存)。
|
|
1125
|
+
*/
|
|
1126
|
+
function registerGuards(ctx, opts = {}) {
|
|
1127
|
+
const configPaths = opts.configPaths;
|
|
1128
|
+
const evaluate = (exec) => {
|
|
1129
|
+
const root = findSerenityRoot(resolveAgentCwd(exec));
|
|
1130
|
+
if (!root) return { kind: "allow" };
|
|
1131
|
+
const safeModeOn = isSafeModeOn(root);
|
|
1132
|
+
const blacklist = readBlacklist(root, configPaths);
|
|
1133
|
+
const pathArg = extractPathArg(exec);
|
|
1134
|
+
return decideGuard({
|
|
1135
|
+
root,
|
|
1136
|
+
toolName: exec.name,
|
|
1137
|
+
safeModeOn,
|
|
1138
|
+
blacklist,
|
|
1139
|
+
pathArg
|
|
1140
|
+
});
|
|
1141
|
+
};
|
|
1142
|
+
ctx.on("tools/pre-execute", async (exec, next) => {
|
|
1143
|
+
const d = evaluate(exec);
|
|
1144
|
+
if (d.deny) return {
|
|
1145
|
+
kind: "deny",
|
|
1146
|
+
reason: d.deny
|
|
1147
|
+
};
|
|
1148
|
+
return next();
|
|
1149
|
+
});
|
|
1150
|
+
ctx.tools.guard((exec) => {
|
|
1151
|
+
return evaluate(exec).deny;
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
//#endregion
|
|
1155
|
+
//#region src/status.ts
|
|
1156
|
+
/**
|
|
1157
|
+
* status.ts — 状态与安全模式操作(纯逻辑,零 DSH 依赖,可独立单测)
|
|
1158
|
+
*
|
|
1159
|
+
* WebUI 停靠栏的数据源:ACC 版本 / CCC 根 / safe-mode 状态 / 黑名单 / keeper 阈值 / loop 模型。
|
|
1160
|
+
* setSafeMode 直接读写 .serenity-safe-on 标记(守卫实时读取,写即生效)。
|
|
1161
|
+
*/
|
|
1162
|
+
/** 读取已安装 DSH CLI 版本(npm 全局 @deepseek-ai/dsh);读不到返回 null */
|
|
1163
|
+
function readDshVersion() {
|
|
1164
|
+
try {
|
|
1165
|
+
const pkg = JSON.parse(readFileSync(join(homedir(), ".npm-global", "lib", "node_modules", "@deepseek-ai", "dsh", "package.json"), "utf-8"));
|
|
1166
|
+
return typeof pkg.version === "string" ? pkg.version : null;
|
|
1167
|
+
} catch {
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
function getStatus(cwd, configPaths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
1172
|
+
const root = findSerenityRoot(cwd);
|
|
1173
|
+
const restrict = getRestrictDiagnostics();
|
|
1174
|
+
const common = {
|
|
1175
|
+
accVersion: ACC_VERSION,
|
|
1176
|
+
dshVersion: readDshVersion(),
|
|
1177
|
+
nodeVersion: process.version
|
|
1178
|
+
};
|
|
1179
|
+
if (!root) return {
|
|
1180
|
+
root: null,
|
|
1181
|
+
...common,
|
|
1182
|
+
safeModeOn: false,
|
|
1183
|
+
blacklist: [],
|
|
1184
|
+
threshold: null,
|
|
1185
|
+
loopModel: null,
|
|
1186
|
+
restrict
|
|
1187
|
+
};
|
|
1188
|
+
const cfg = loadSerenityConfig(root, configPaths);
|
|
1189
|
+
return {
|
|
1190
|
+
root,
|
|
1191
|
+
...common,
|
|
1192
|
+
safeModeOn: isSafeModeOn(root),
|
|
1193
|
+
blacklist: readBlacklist(root, configPaths),
|
|
1194
|
+
threshold: cfg.sessionKeeper?.threshold ?? null,
|
|
1195
|
+
loopModel: cfg.loop?.defaultModel ?? null,
|
|
1196
|
+
restrict
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
/** 切换安全模式(写/删标记文件);返回实际生效状态 */
|
|
1200
|
+
function setSafeMode(root, on) {
|
|
1201
|
+
const marker = resolve(root, SAFE_MODE_MARKER);
|
|
1202
|
+
if (on) {
|
|
1203
|
+
if (!existsSync(marker)) writeFileSync(marker, (/* @__PURE__ */ new Date()).toISOString() + "\n", "utf-8");
|
|
1204
|
+
} else rmSync(marker, { force: true });
|
|
1205
|
+
return { on: isSafeModeOn(root) };
|
|
1206
|
+
}
|
|
1207
|
+
//#endregion
|
|
989
1208
|
//#region src/kit-ops.ts
|
|
990
1209
|
/**
|
|
991
1210
|
* kit-ops.ts — acc_kit 纯操作层(零 DSH 依赖)
|
|
@@ -1025,7 +1244,9 @@ function runKit(root, args) {
|
|
|
1025
1244
|
configPath,
|
|
1026
1245
|
p1: findSerenityRoot(root) !== null,
|
|
1027
1246
|
p2: gitRoot !== null,
|
|
1028
|
-
p3: "enforced-by-dsh-fs-sandbox"
|
|
1247
|
+
p3: "enforced-by-dsh-fs-sandbox",
|
|
1248
|
+
accVersion: ACC_VERSION,
|
|
1249
|
+
dshVersion: readDshVersion()
|
|
1029
1250
|
};
|
|
1030
1251
|
}
|
|
1031
1252
|
case "time": return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1498,6 +1719,24 @@ const cceTool = defineTool({
|
|
|
1498
1719
|
}
|
|
1499
1720
|
});
|
|
1500
1721
|
//#endregion
|
|
1722
|
+
//#region src/loop-preset-inherit.ts
|
|
1723
|
+
/**
|
|
1724
|
+
* 解析 loop agent 从父 agent 继承的 preset,并组装创建 setup 钩子。
|
|
1725
|
+
* @param parentCtx - 发起 loop 的 agent 的 scope ctx;无(headless/非 agent 上下文)时为 undefined。
|
|
1726
|
+
* @returns 继承结果:meta 用的 agentPreset 与创建 setup 钩子。
|
|
1727
|
+
*/
|
|
1728
|
+
function loopPresetInheritance(parentCtx) {
|
|
1729
|
+
if (parentCtx === void 0) return {};
|
|
1730
|
+
const agentPreset = parentCtx.get("agentPresets")?.composedPreset(parentCtx);
|
|
1731
|
+
if (agentPreset === void 0) return {};
|
|
1732
|
+
return {
|
|
1733
|
+
agentPreset,
|
|
1734
|
+
setup: (childCtx) => {
|
|
1735
|
+
childCtx.get("agentPresets")?.composeFrom(childCtx, parentCtx);
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
//#endregion
|
|
1501
1740
|
//#region src/loop-ops.ts
|
|
1502
1741
|
/**
|
|
1503
1742
|
* loop-ops.ts — acc_loop 纯逻辑层(零 DSH 依赖,可独立单测)
|
|
@@ -1587,9 +1826,13 @@ ${resumeNote}
|
|
|
1587
1826
|
* model(选)provider/model(如 minimax-cn-coding-plan/MiniMax-M3);缺省读 loop.defaultModel
|
|
1588
1827
|
* maxRounds(默认 100)轮次上限;每轮等待 agent **无超时**(loop 可永续,agent 工作多久等多久)
|
|
1589
1828
|
*
|
|
1590
|
-
* 机制:ctx.
|
|
1829
|
+
* 机制:ctx.agents.create()(带 setup 钩子)创建专用 agent(进程内),
|
|
1591
1830
|
* 每轮 followup → agent/status idle → 读 session.events 响应 → 写进度 → stop token 检查 → 续跑。
|
|
1592
1831
|
* 工厂模式:apply 时闭包捕获插件 ctx(工具 execute 无 ctx 参数)。
|
|
1832
|
+
*
|
|
1833
|
+
* preset 继承:setup 钩子里对子 agent 执行 agentPresets.composeFrom(对齐 subagent 先例),
|
|
1834
|
+
* 使 loop agent 继承发起方会话的 agent preset 工具(read/write/edit 等 preset 层工具)。
|
|
1835
|
+
* agentPresets 是可选服务——无 preset 装配的环境(无 roster 部署)退化为空工具层(历史行为)。
|
|
1593
1836
|
*/
|
|
1594
1837
|
function agentCwd$1(exec) {
|
|
1595
1838
|
return (exec.agent?.session)?.header?.cwd ?? process.cwd();
|
|
@@ -1629,6 +1872,7 @@ function lastAssistantText(agent) {
|
|
|
1629
1872
|
return "";
|
|
1630
1873
|
}
|
|
1631
1874
|
/** 创建 loop 工具(闭包捕获插件 ctx → 可访问 ctx.agentLoop) */
|
|
1875
|
+
/** 创建 loop 工具(闭包捕获插件 ctx → 可访问 ctx.agentLoop) */
|
|
1632
1876
|
function createLoopTool(ctx) {
|
|
1633
1877
|
return defineTool({
|
|
1634
1878
|
name: "loop",
|
|
@@ -1673,10 +1917,23 @@ function createLoopTool(ctx) {
|
|
|
1673
1917
|
const stopToken = newStopToken();
|
|
1674
1918
|
let progress = readProgress(root, label);
|
|
1675
1919
|
const startRound = progress ? Math.min(progress.round + 1, maxRounds) : 1;
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1920
|
+
const parentCtx = exec.agent?.ctx;
|
|
1921
|
+
const inherited = loopPresetInheritance(parentCtx);
|
|
1922
|
+
if (!ctx.agents) throw new Error("loop: ctx.agents 不可用");
|
|
1923
|
+
const sessionId = `loop-${label}`;
|
|
1924
|
+
const handle = await ctx.agents.create({
|
|
1925
|
+
sessionId,
|
|
1926
|
+
meta: {
|
|
1927
|
+
cwd: root,
|
|
1928
|
+
...inherited.agentPreset === void 0 ? {} : { agentPreset: inherited.agentPreset }
|
|
1929
|
+
},
|
|
1930
|
+
agentOptions: {
|
|
1931
|
+
provider,
|
|
1932
|
+
model: modelName
|
|
1933
|
+
},
|
|
1934
|
+
...inherited.setup === void 0 ? {} : { setup: inherited.setup }
|
|
1935
|
+
});
|
|
1936
|
+
const loopAgent = handle.agent;
|
|
1680
1937
|
let done = false;
|
|
1681
1938
|
let lastResponse = progress?.lastResponse ?? "";
|
|
1682
1939
|
let finalRound = startRound - 1;
|
|
@@ -1727,7 +1984,9 @@ function createLoopTool(ctx) {
|
|
|
1727
1984
|
updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1728
1985
|
lastResponse
|
|
1729
1986
|
});
|
|
1730
|
-
} finally {
|
|
1987
|
+
} finally {
|
|
1988
|
+
await handle.dispose().catch(() => {});
|
|
1989
|
+
}
|
|
1731
1990
|
const { json } = loopProgressPaths(root, label);
|
|
1732
1991
|
return {
|
|
1733
1992
|
done,
|
|
@@ -1747,157 +2006,6 @@ function createLoopTool(ctx) {
|
|
|
1747
2006
|
});
|
|
1748
2007
|
}
|
|
1749
2008
|
//#endregion
|
|
1750
|
-
//#region src/seams/guards.ts
|
|
1751
|
-
/**
|
|
1752
|
-
* guards.ts — 拦截缝:安全模式 + 路径守卫(P3 语义的机械层)
|
|
1753
|
-
*
|
|
1754
|
-
* 纯决策逻辑(decideGuard)与 DSH 注册(registerGuards)分离:
|
|
1755
|
-
* 前者零 DSH 依赖可单测,后者把决策接到 tools/pre-execute 瀑布 + ctx.tools.guard 终局。
|
|
1756
|
-
*
|
|
1757
|
-
* 对应 opencode-serenity-plugin 的 tool.execute.before 路径守卫 + bash 开关 + 黑名单。
|
|
1758
|
-
*/
|
|
1759
|
-
/**
|
|
1760
|
-
* 安全模式 + 黑名单 + P3 路径守卫的纯决策。
|
|
1761
|
-
* 对齐 opencode-serenity-plugin 标准:安全模式 = **bash 禁用** + 写入黑名单;
|
|
1762
|
-
* write/edit 等工具仅受路径逃逸与黑名单约束(不整体禁用)。
|
|
1763
|
-
* 优先级:safe-mode bash > 路径越界 > 黑名单命中。
|
|
1764
|
-
*/
|
|
1765
|
-
function decideGuard(input) {
|
|
1766
|
-
const { root, toolName, safeModeOn, blacklist, pathArg } = input;
|
|
1767
|
-
if (safeModeOn && toolName === "bash") return {
|
|
1768
|
-
deny: `bash: 没有这个工具`,
|
|
1769
|
-
kind: "deny"
|
|
1770
|
-
};
|
|
1771
|
-
if (pathArg !== void 0) {
|
|
1772
|
-
const rel = relative(root, resolve(root, pathArg));
|
|
1773
|
-
if (rel.startsWith("..")) return {
|
|
1774
|
-
deny: `path escape blocked: "${pathArg}" 越出 CCC 根`,
|
|
1775
|
-
kind: "deny"
|
|
1776
|
-
};
|
|
1777
|
-
if (rel === ".serenity-safe-on" || rel === ".serenity" || rel.startsWith(".serenity-safe-on/") || rel.startsWith(".serenity/")) return {
|
|
1778
|
-
deny: `CCC 治理文件 "${rel}" 保留给用户,agent 不可写`,
|
|
1779
|
-
kind: "deny"
|
|
1780
|
-
};
|
|
1781
|
-
const hit = matchBlacklist(rel, blacklist);
|
|
1782
|
-
if (hit) return {
|
|
1783
|
-
deny: `blacklist blocked: "${pathArg}" 命中规则 "${hit}"`,
|
|
1784
|
-
kind: "deny"
|
|
1785
|
-
};
|
|
1786
|
-
}
|
|
1787
|
-
return { kind: "allow" };
|
|
1788
|
-
}
|
|
1789
|
-
/** 从 exec 提取 agent 会话 cwd(CCC 根检测基准);无则回退进程 cwd */
|
|
1790
|
-
function resolveAgentCwd(exec) {
|
|
1791
|
-
return exec.agent?.session?.header?.cwd ?? process.cwd();
|
|
1792
|
-
}
|
|
1793
|
-
/** 安全模式开启时从模型工具列表隐藏的工具(只隐藏 bash;write/edit 保留) */
|
|
1794
|
-
const SAFE_MODE_DENY_TOOLS = ["bash"];
|
|
1795
|
-
/** agent key → restrict disposer(安全模式工具隐藏状态) */
|
|
1796
|
-
const safeModeRestrictions = /* @__PURE__ */ new Map();
|
|
1797
|
-
const restrictDiag = {
|
|
1798
|
-
lastKey: null,
|
|
1799
|
-
lastAttemptAt: null,
|
|
1800
|
-
lastSuccess: null,
|
|
1801
|
-
lastError: null,
|
|
1802
|
-
activeKeys: []
|
|
1803
|
-
};
|
|
1804
|
-
function getRestrictDiagnostics() {
|
|
1805
|
-
return {
|
|
1806
|
-
...restrictDiag,
|
|
1807
|
-
activeKeys: [...safeModeRestrictions.keys()]
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
/** 诊断落盘:AGENT_SESSIONS/.restrict-diag.json(文件通道,避免 HTTP 自锁) */
|
|
1811
|
-
function writeRestrictDiag(root) {
|
|
1812
|
-
try {
|
|
1813
|
-
const dir = resolve(root, "AGENT_SESSIONS");
|
|
1814
|
-
mkdirSync(dir, { recursive: true });
|
|
1815
|
-
writeFileSync(resolve(dir, ".restrict-diag.json"), JSON.stringify({
|
|
1816
|
-
...getRestrictDiagnostics(),
|
|
1817
|
-
cccRoot: root
|
|
1818
|
-
}, null, 2) + "\n", "utf-8");
|
|
1819
|
-
} catch {}
|
|
1820
|
-
}
|
|
1821
|
-
/**
|
|
1822
|
-
* 同步安全模式工具隐藏:标记存在 → agent.ctx.tools.restrict deny 隐藏写工具;
|
|
1823
|
-
* 标记消失 → 解除。pre-step 每步调用 → 切换实时生效。
|
|
1824
|
-
*/
|
|
1825
|
-
function syncSafeModeRestriction(agent, root) {
|
|
1826
|
-
const key = agent.session.id ?? "global";
|
|
1827
|
-
const on = isSafeModeOn(root);
|
|
1828
|
-
const existing = safeModeRestrictions.get(key);
|
|
1829
|
-
if (on && !existing) try {
|
|
1830
|
-
const dispose = agent.ctx.tools.restrict({ deny: [...SAFE_MODE_DENY_TOOLS] });
|
|
1831
|
-
safeModeRestrictions.set(key, dispose);
|
|
1832
|
-
restrictDiag.lastKey = key;
|
|
1833
|
-
restrictDiag.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1834
|
-
restrictDiag.lastSuccess = true;
|
|
1835
|
-
restrictDiag.lastError = null;
|
|
1836
|
-
} catch (e) {
|
|
1837
|
-
restrictDiag.lastKey = key;
|
|
1838
|
-
restrictDiag.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1839
|
-
restrictDiag.lastSuccess = false;
|
|
1840
|
-
restrictDiag.lastError = e.message;
|
|
1841
|
-
console.error(`[serenity-hooks] restrict 失败 (key=${key}):`, e.message);
|
|
1842
|
-
}
|
|
1843
|
-
else if (!on && existing) {
|
|
1844
|
-
try {
|
|
1845
|
-
existing();
|
|
1846
|
-
} catch (e) {
|
|
1847
|
-
console.error(`[serenity-hooks] restrict 解除失败 (key=${key}):`, e.message);
|
|
1848
|
-
}
|
|
1849
|
-
safeModeRestrictions.delete(key);
|
|
1850
|
-
}
|
|
1851
|
-
writeRestrictDiag(root);
|
|
1852
|
-
}
|
|
1853
|
-
/** 从 exec 参数中提取常见路径字段(write/edit 工具);宽松读取 */
|
|
1854
|
-
function extractPathArg(exec) {
|
|
1855
|
-
const args = exec.arguments;
|
|
1856
|
-
if (args === null || typeof args !== "object") return void 0;
|
|
1857
|
-
const a = args;
|
|
1858
|
-
for (const key of [
|
|
1859
|
-
"path",
|
|
1860
|
-
"file_path",
|
|
1861
|
-
"target",
|
|
1862
|
-
"dst"
|
|
1863
|
-
]) {
|
|
1864
|
-
const v = a[key];
|
|
1865
|
-
if (typeof v === "string") return v;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
/**
|
|
1869
|
-
* 注册守卫:tools/pre-execute 瀑布 + ctx.tools.guard 终局。
|
|
1870
|
-
* 两者都从 CCC 根实时读取配置(无状态、无缓存)。
|
|
1871
|
-
*/
|
|
1872
|
-
function registerGuards(ctx, opts = {}) {
|
|
1873
|
-
const configPaths = opts.configPaths;
|
|
1874
|
-
const evaluate = (exec) => {
|
|
1875
|
-
const root = findSerenityRoot(resolveAgentCwd(exec));
|
|
1876
|
-
if (!root) return { kind: "allow" };
|
|
1877
|
-
const safeModeOn = isSafeModeOn(root);
|
|
1878
|
-
const blacklist = readBlacklist(root, configPaths);
|
|
1879
|
-
const pathArg = extractPathArg(exec);
|
|
1880
|
-
return decideGuard({
|
|
1881
|
-
root,
|
|
1882
|
-
toolName: exec.name,
|
|
1883
|
-
safeModeOn,
|
|
1884
|
-
blacklist,
|
|
1885
|
-
pathArg
|
|
1886
|
-
});
|
|
1887
|
-
};
|
|
1888
|
-
ctx.on("tools/pre-execute", async (exec, next) => {
|
|
1889
|
-
const d = evaluate(exec);
|
|
1890
|
-
if (d.deny) return {
|
|
1891
|
-
kind: "deny",
|
|
1892
|
-
reason: d.deny
|
|
1893
|
-
};
|
|
1894
|
-
return next();
|
|
1895
|
-
});
|
|
1896
|
-
ctx.tools.guard((exec) => {
|
|
1897
|
-
return evaluate(exec).deny;
|
|
1898
|
-
});
|
|
1899
|
-
}
|
|
1900
|
-
//#endregion
|
|
1901
2009
|
//#region src/seams/loop.ts
|
|
1902
2010
|
/** 解析当前 dsh 会话 scope 的活跃会话 SESSION.md 绝对路径;无标记/越界返回 null */
|
|
1903
2011
|
function resolveActiveSession(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
@@ -2007,21 +2115,6 @@ function registerKeeper(ctx, opts = {}) {
|
|
|
2007
2115
|
});
|
|
2008
2116
|
}
|
|
2009
2117
|
//#endregion
|
|
2010
|
-
//#region src/constants.ts
|
|
2011
|
-
/** 常量(纯模块,零 DSH 依赖) */
|
|
2012
|
-
/**
|
|
2013
|
-
* ACC 版本:自动从 package.json 读取(单一真相源,消除与 CHANGELOG 的漂移)。
|
|
2014
|
-
* 发布时只需改 package.json 的 version。
|
|
2015
|
-
*/
|
|
2016
|
-
const ACC_VERSION = (() => {
|
|
2017
|
-
try {
|
|
2018
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
2019
|
-
return JSON.parse(readFileSync(join(here, "..", "package.json"), "utf-8")).version ?? "0.0.0";
|
|
2020
|
-
} catch {
|
|
2021
|
-
return "0.0.0";
|
|
2022
|
-
}
|
|
2023
|
-
})();
|
|
2024
|
-
//#endregion
|
|
2025
2118
|
//#region src/skills-discovery.ts
|
|
2026
2119
|
/**
|
|
2027
2120
|
* skills-discovery.ts — CCC 入口 skill 自动发现(纯逻辑,零 DSH 依赖)
|
|
@@ -2195,6 +2288,22 @@ function constraintsBlock(root) {
|
|
|
2195
2288
|
""
|
|
2196
2289
|
].join("\n");
|
|
2197
2290
|
}
|
|
2291
|
+
/**
|
|
2292
|
+
* EAP 自检提示块(DSH 扩展,无 osp 对应——osp 无此块)。
|
|
2293
|
+
* 每次输出前的机械自检清单,强化 EAP 表现(E↑ 显式/R↓ 可重建/S↑ 稳定)。
|
|
2294
|
+
* 独立块而非塞进 CCE/Constraints:后两者受 osp-alignment 逐字节断言约束。
|
|
2295
|
+
*/
|
|
2296
|
+
function eapBlock() {
|
|
2297
|
+
return [
|
|
2298
|
+
"",
|
|
2299
|
+
"=== Serenity EAP ===",
|
|
2300
|
+
"每次输出前自检(显式抽象原则:思维的价值 = 外部可重建性):",
|
|
2301
|
+
" • E↑ 显式 — 变量/实体明确定义,关系指明方向/基数,边界划定;不用歧义词(\"处理\"\"优化\"→具体化)",
|
|
2302
|
+
" • R↓ 可重建 — 关键决策记录理由与备选,不跳级讨论(先对齐上层再进下层)",
|
|
2303
|
+
" • S↑ 稳定 — 结构可重复生成,避免依赖隐含上下文",
|
|
2304
|
+
""
|
|
2305
|
+
].join("\n");
|
|
2306
|
+
}
|
|
2198
2307
|
/** 4) SKILL.md 全文:该 CCC 顶层入口 skill 原文(对齐 osp:原文直推,无包裹头;仅过滤治理内容) */
|
|
2199
2308
|
function entrySkillSectionText(root) {
|
|
2200
2309
|
const skills = findEntrySkills(root);
|
|
@@ -2245,12 +2354,13 @@ function sessionBlock(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
|
2245
2354
|
""
|
|
2246
2355
|
].join("\n");
|
|
2247
2356
|
}
|
|
2248
|
-
/** 完整系统提示词注入文本:ACC + CCE + Constraints + SKILL 全文 + Session(osp
|
|
2357
|
+
/** 完整系统提示词注入文本:ACC + CCE + Constraints + EAP + SKILL 全文 + Session(osp 顺序 + EAP 扩展) */
|
|
2249
2358
|
function serenitySystemPrompt(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
2250
2359
|
const parts = [
|
|
2251
2360
|
accBlock(root),
|
|
2252
2361
|
cceBlock(),
|
|
2253
|
-
constraintsBlock(root)
|
|
2362
|
+
constraintsBlock(root),
|
|
2363
|
+
eapBlock()
|
|
2254
2364
|
];
|
|
2255
2365
|
const skill = entrySkillSectionText(root);
|
|
2256
2366
|
if (skill) parts.push(skill);
|
|
@@ -2258,6 +2368,31 @@ function serenitySystemPrompt(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
|
2258
2368
|
if (session) parts.push(session);
|
|
2259
2369
|
return parts.join("\n\n");
|
|
2260
2370
|
}
|
|
2371
|
+
/**
|
|
2372
|
+
* Code Mode 适配行:当前 scope 以 Code Mode 呈现工具时(run_code 可见),
|
|
2373
|
+
* ACC 块按 native 语义指引"直接调用工具"会与"只有 run_code 可直接调用"的执行
|
|
2374
|
+
* 塌缩冲突(模型直呼工具名 → UNKNOWN_TOOL,拒绝信息误导)。追加一行说明,
|
|
2375
|
+
* 引导经 run_code 程序内 tools.* 调用。both 模式不塌缩,该行不误导(程序内
|
|
2376
|
+
* 调用同样合法),故按 run_code 可见性(code|both)统一附加。
|
|
2377
|
+
* @param ctx - 插件 ctx(读 tools 注册表)。
|
|
2378
|
+
* @param scope - 装配 scope(agent);无则按全局视图判断。
|
|
2379
|
+
* @returns 适配行(含换行前缀);非 code/both 返回空串。
|
|
2380
|
+
*/
|
|
2381
|
+
function codeModeAdaptationLine(ctx, scope) {
|
|
2382
|
+
try {
|
|
2383
|
+
if (!(ctx.tools.get("run_code", scope) !== void 0)) return "";
|
|
2384
|
+
} catch {
|
|
2385
|
+
return "";
|
|
2386
|
+
}
|
|
2387
|
+
return [
|
|
2388
|
+
"",
|
|
2389
|
+
"=== Serenity Code Mode ===",
|
|
2390
|
+
"当前会话以 Code Mode 呈现工具:模型直接调用 ACC 工具名(cc_fs/acc_msm 等)会被拒绝(UNKNOWN_TOOL)。",
|
|
2391
|
+
"请在一个 run_code 程序内经生成的 SDK 绑定调用:`await tools.cc_fs(...)`、`await tools.acc_msm(...)` 等。",
|
|
2392
|
+
"程序只返回你 print/return 的内容——务必 curate 输出。",
|
|
2393
|
+
""
|
|
2394
|
+
].join("\n");
|
|
2395
|
+
}
|
|
2261
2396
|
/** 从 assembly context 解析 agent cwd(subagent/后台 agent 同样带 agent) */
|
|
2262
2397
|
function agentCwd(context) {
|
|
2263
2398
|
return (context.agent?.session)?.header?.cwd;
|
|
@@ -2281,7 +2416,9 @@ function registerEntrySkillSectionGlobal(ctx) {
|
|
|
2281
2416
|
if (!cwd) return "";
|
|
2282
2417
|
const root = findSerenityRoot(cwd);
|
|
2283
2418
|
if (!root) return "";
|
|
2284
|
-
|
|
2419
|
+
const base = serenitySystemPrompt(root, agentScope$1(context));
|
|
2420
|
+
const codeLine = codeModeAdaptationLine(ctx, context.scope);
|
|
2421
|
+
return codeLine ? `${base}\n${codeLine}` : base;
|
|
2285
2422
|
}
|
|
2286
2423
|
});
|
|
2287
2424
|
console.log("[serenity-hooks] ✓ 全局入口 skill section 已注册(systemPrompt 就绪)");
|
|
@@ -2289,6 +2426,39 @@ function registerEntrySkillSectionGlobal(ctx) {
|
|
|
2289
2426
|
console.error(`[serenity-hooks] ✗ 全局入口 skill section 注册失败: ${err.message}(检查 inject 是否含 systemPrompt)`);
|
|
2290
2427
|
}
|
|
2291
2428
|
}
|
|
2429
|
+
/**
|
|
2430
|
+
* agent 级 scoped 注册(P0-1:抗 preset/动态插件同名 shadow)。
|
|
2431
|
+
*
|
|
2432
|
+
* 为什么 scoped:DSH 的 systemPrompt section 支持 scoped 层同名 shadow 全局
|
|
2433
|
+
* (agent.ctx.systemPrompt.section),且 scope 链最近层胜出。若 ACC 只注册全局
|
|
2434
|
+
* section,preset 或动态 Cordis 插件可在 scoped 层注册同名 `serenity-entry`
|
|
2435
|
+
* 遮蔽 ACC 身份。scoped 注册在 agent 自身层 = 最近层,任何外部组合无法覆盖。
|
|
2436
|
+
* 全局注册保留为 fallback(未走 session-start 的 agent / 冷恢复路径)。
|
|
2437
|
+
*
|
|
2438
|
+
* text 回调闭包持有 root 与 agent:content 固定(该 agent 的 CCC 身份),
|
|
2439
|
+
* code-mode 适配按装配 context.scope 判断(与全局版一致)。
|
|
2440
|
+
*/
|
|
2441
|
+
const sectionedAgents = /* @__PURE__ */ new Set();
|
|
2442
|
+
function registerEntrySkillSection(agent, root) {
|
|
2443
|
+
const key = agent.session.id ?? "global";
|
|
2444
|
+
if (sectionedAgents.has(key)) return false;
|
|
2445
|
+
try {
|
|
2446
|
+
const scope = agent.session.id ?? "default";
|
|
2447
|
+
agent.ctx.systemPrompt.section({
|
|
2448
|
+
name: "serenity-entry",
|
|
2449
|
+
order: -50,
|
|
2450
|
+
text: (context) => {
|
|
2451
|
+
const base = serenitySystemPrompt(root, scope);
|
|
2452
|
+
const codeLine = codeModeAdaptationLine(agent.ctx, context.scope);
|
|
2453
|
+
return codeLine ? `${base}\n${codeLine}` : base;
|
|
2454
|
+
}
|
|
2455
|
+
});
|
|
2456
|
+
sectionedAgents.add(key);
|
|
2457
|
+
return true;
|
|
2458
|
+
} catch {
|
|
2459
|
+
return false;
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2292
2462
|
//#endregion
|
|
2293
2463
|
//#region src/seams/context.ts
|
|
2294
2464
|
const DEFAULT_ENTRY_SKILL_MAX_CHARS = 3e4;
|
|
@@ -2345,6 +2515,7 @@ function registerContext(ctx, opts = {}) {
|
|
|
2345
2515
|
const root = findSerenityRoot(agent.session?.header?.cwd ?? process.cwd());
|
|
2346
2516
|
if (!root) return;
|
|
2347
2517
|
const key = agentKey(agent);
|
|
2518
|
+
registerEntrySkillSection(agent, root);
|
|
2348
2519
|
if (injected.has(key)) return;
|
|
2349
2520
|
injected.add(key);
|
|
2350
2521
|
agent.inject(accMessage(root, configPaths, entrySkillMaxChars, agentScope(agent)));
|
|
@@ -2360,9 +2531,12 @@ function registerContext(ctx, opts = {}) {
|
|
|
2360
2531
|
const root = findSerenityRoot(agent.session?.header?.cwd ?? process.cwd());
|
|
2361
2532
|
const key = agentKey(agent);
|
|
2362
2533
|
const downstream = await next();
|
|
2363
|
-
if (root)
|
|
2364
|
-
|
|
2365
|
-
|
|
2534
|
+
if (root) {
|
|
2535
|
+
try {
|
|
2536
|
+
syncSafeModeRestriction(agent, root);
|
|
2537
|
+
} catch {}
|
|
2538
|
+
registerEntrySkillSection(agent, root);
|
|
2539
|
+
}
|
|
2366
2540
|
if (!root || injected.has(key) || downstream.kind !== "enter") return downstream;
|
|
2367
2541
|
injected.add(key);
|
|
2368
2542
|
return {
|
|
@@ -2398,45 +2572,6 @@ function registerCompactRetention(ctx, opts = {}) {
|
|
|
2398
2572
|
});
|
|
2399
2573
|
}
|
|
2400
2574
|
//#endregion
|
|
2401
|
-
//#region src/status.ts
|
|
2402
|
-
/**
|
|
2403
|
-
* status.ts — 状态与安全模式操作(纯逻辑,零 DSH 依赖,可独立单测)
|
|
2404
|
-
*
|
|
2405
|
-
* WebUI 停靠栏的数据源:ACC 版本 / CCC 根 / safe-mode 状态 / 黑名单 / keeper 阈值 / loop 模型。
|
|
2406
|
-
* setSafeMode 直接读写 .serenity-safe-on 标记(守卫实时读取,写即生效)。
|
|
2407
|
-
*/
|
|
2408
|
-
function getStatus(cwd, configPaths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
2409
|
-
const root = findSerenityRoot(cwd);
|
|
2410
|
-
const restrict = getRestrictDiagnostics();
|
|
2411
|
-
if (!root) return {
|
|
2412
|
-
root: null,
|
|
2413
|
-
accVersion: ACC_VERSION,
|
|
2414
|
-
safeModeOn: false,
|
|
2415
|
-
blacklist: [],
|
|
2416
|
-
threshold: null,
|
|
2417
|
-
loopModel: null,
|
|
2418
|
-
restrict
|
|
2419
|
-
};
|
|
2420
|
-
const cfg = loadSerenityConfig(root, configPaths);
|
|
2421
|
-
return {
|
|
2422
|
-
root,
|
|
2423
|
-
accVersion: ACC_VERSION,
|
|
2424
|
-
safeModeOn: isSafeModeOn(root),
|
|
2425
|
-
blacklist: readBlacklist(root, configPaths),
|
|
2426
|
-
threshold: cfg.sessionKeeper?.threshold ?? null,
|
|
2427
|
-
loopModel: cfg.loop?.defaultModel ?? null,
|
|
2428
|
-
restrict
|
|
2429
|
-
};
|
|
2430
|
-
}
|
|
2431
|
-
/** 切换安全模式(写/删标记文件);返回实际生效状态 */
|
|
2432
|
-
function setSafeMode(root, on) {
|
|
2433
|
-
const marker = resolve(root, SAFE_MODE_MARKER);
|
|
2434
|
-
if (on) {
|
|
2435
|
-
if (!existsSync(marker)) writeFileSync(marker, (/* @__PURE__ */ new Date()).toISOString() + "\n", "utf-8");
|
|
2436
|
-
} else rmSync(marker, { force: true });
|
|
2437
|
-
return { on: isSafeModeOn(root) };
|
|
2438
|
-
}
|
|
2439
|
-
//#endregion
|
|
2440
2575
|
//#region src/api.ts
|
|
2441
2576
|
const ROUTE_PATH = "/serenity/status";
|
|
2442
2577
|
function readBody(req) {
|
|
@@ -2479,10 +2614,18 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
2479
2614
|
try {
|
|
2480
2615
|
if (req.method === "GET") {
|
|
2481
2616
|
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
2482
|
-
|
|
2617
|
+
const status = getStatus(resolveWorkspace(ctx, {
|
|
2483
2618
|
sessionId: url.searchParams.get("sessionId") ?? void 0,
|
|
2484
2619
|
workspace: url.searchParams.get("workspace") ?? void 0
|
|
2485
|
-
}), configPaths)
|
|
2620
|
+
}), configPaths);
|
|
2621
|
+
const runtime = ctx.get("codeRuntime");
|
|
2622
|
+
sendJson(res, 200, {
|
|
2623
|
+
...status,
|
|
2624
|
+
...runtime === void 0 ? { codeRuntime: null } : { codeRuntime: {
|
|
2625
|
+
language: runtime.language,
|
|
2626
|
+
isolation: runtime.isolation
|
|
2627
|
+
} }
|
|
2628
|
+
});
|
|
2486
2629
|
return;
|
|
2487
2630
|
}
|
|
2488
2631
|
if (req.method === "POST") {
|
|
@@ -2662,6 +2805,7 @@ const inject = [
|
|
|
2662
2805
|
"shellEnv",
|
|
2663
2806
|
"skills",
|
|
2664
2807
|
"agentLoop",
|
|
2808
|
+
"agents",
|
|
2665
2809
|
"systemPrompt"
|
|
2666
2810
|
];
|
|
2667
2811
|
const Config = z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.4",
|
|
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": {
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.5",
|
|
52
52
|
"@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.5",
|
|
53
|
+
"@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.5",
|
|
53
54
|
"@deepseek-ai/dsh-compaction": "^0.1.0-rc.5",
|
|
54
55
|
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.5",
|
|
55
56
|
"@deepseek-ai/dsh-llm": "^0.1.0-rc.5",
|
|
@@ -75,6 +76,9 @@
|
|
|
75
76
|
"@deepseek-ai/dsh-agent-loop": {
|
|
76
77
|
"optional": true
|
|
77
78
|
},
|
|
79
|
+
"@deepseek-ai/dsh-agent-presets": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
78
82
|
"@deepseek-ai/dsh-compaction": {
|
|
79
83
|
"optional": true
|
|
80
84
|
}
|