@shgroup/dsh-serenity-hooks 1.51.3 → 1.51.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/{ccc-DG4Oc7I1.js → ccc-DXky9UZu.js} +26 -1
- package/lib/{ccc-roots-DtiMVRPo.js → ccc-roots-Bo0HKLlM.js} +2 -2
- package/lib/ccc.d.ts +30 -0
- package/lib/index.js +104 -39
- package/lib/{message-source-LnJwIqLm.js → message-source-BExngUPX.js} +1 -1
- package/lib/seams/guards.d.ts +10 -2
- package/lib/{skiff-role-DQZ6eR51.js → skiff-role-BSg6Qu9k.js} +1 -1
- package/lib/status.d.ts +2 -0
- package/lib/{weixin-route-7BtOiy4X.js → weixin-route-BNyH5ghC.js} +1 -1
- 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.51.
|
|
3
|
+
"version": "1.51.4",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——12 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag/diagram;后三个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.7-rc.1(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
@@ -156,6 +156,31 @@ function readExclusiveTools(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
|
156
156
|
return list.filter((x) => typeof x === "string" && x.trim() !== "").map((x) => x.trim());
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
159
|
+
* 读取 CCC 声明的「安全模式期间隐藏的工具」清单(`safeMode.hiddenTools`,v1.51.4)。
|
|
160
|
+
*
|
|
161
|
+
* 语义(R↓):**标记文件存在 ⇒ 才生效**。deny = `['bash', ...本清单]`(并集去重);
|
|
162
|
+
* 标记消失 ⇒ 连同 `bash` 一起解除(调用点在 `syncSafeModeRestriction`,与基础表同一处)。
|
|
163
|
+
*
|
|
164
|
+
* 失败方向 = **fail-open**(与 `exclusiveTools` 的 fail-closed 相反,理由不同):
|
|
165
|
+
* 未配置 / 字段缺失 / 配置损坏 ⇒ **空数组** = 只隐藏基础表。本键是**附加**屏蔽,
|
|
166
|
+
* 读不到声明就等于"没有证据要求多藏";且**隐藏是危险方向**(藏掉 agent 真正要用的工具
|
|
167
|
+
* 会静默损害能力),而配置损坏本身已有 `loadSerenityConfig` 的响亮告警(不静默)。
|
|
168
|
+
*
|
|
169
|
+
* 🔴 名字在此**不做**校验——未注册的名字会被 DSH `restrict` 拒绝(宿主契约逐字:
|
|
170
|
+
* "Empty filters, unknown names, scope-local names, and reserved transport names **fail**")
|
|
171
|
+
* ⇒ **调用方必须按"失败退化为基础表"处理**(见 `syncSafeModeRestriction`),
|
|
172
|
+
* 否则 CCC 写错一个名字会连 `bash` 的隐藏一起丢掉。
|
|
173
|
+
*
|
|
174
|
+
* @param root CCC 根
|
|
175
|
+
* @param paths 候选配置相对路径
|
|
176
|
+
* @returns 去空白后的工具名列表(非字符串/空白项被丢弃)
|
|
177
|
+
*/
|
|
178
|
+
function readSafeModeHiddenTools(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
179
|
+
const list = loadSerenityConfig(root, paths).safeMode?.hiddenTools;
|
|
180
|
+
if (!Array.isArray(list)) return [];
|
|
181
|
+
return list.filter((x) => typeof x === "string" && x.trim() !== "").map((x) => x.trim());
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
159
184
|
* 读取 CCC 声明的「轨迹默认 skill」清单(`trajectory.skills`,v1.44.0)。
|
|
160
185
|
*
|
|
161
186
|
* 语义与失败方向(R↓):
|
|
@@ -214,4 +239,4 @@ function matchBlacklist(relPath, rules) {
|
|
|
214
239
|
return null;
|
|
215
240
|
}
|
|
216
241
|
//#endregion
|
|
217
|
-
export { findSerenityRoot as a, matchBlacklist as c, readCccName as d, readExclusiveTools as f,
|
|
242
|
+
export { resolveInside as _, findSerenityRoot as a, matchBlacklist as c, readCccName as d, readExclusiveTools as f, readUtf8 as g, readTrajectorySkills as h, findGitRoot as i, pathInside as l, readSafeModeHiddenTools as m, SAFE_MODE_MARKER as n, isSafeModeOn as o, readHandymanConfig as p, classifyPath as r, loadSerenityConfig as s, DEFAULT_SERENITY_CONFIG_PATHS as t, readBlacklist as u };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { a as hostSessions, i as hostService } from "./access-CNccNtgf.js";
|
|
3
|
-
import { a as findSerenityRoot } from "./ccc-
|
|
3
|
+
import { a as findSerenityRoot } from "./ccc-DXky9UZu.js";
|
|
4
4
|
import { basename } from "node:path";
|
|
5
5
|
//#region src/ccc-roots.ts
|
|
6
6
|
/**
|
|
@@ -150,7 +150,7 @@ async function listCccs(ctx, opts = {}) {
|
|
|
150
150
|
if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
|
|
151
151
|
let rolesOf = null;
|
|
152
152
|
if (opts.withRoles === true) {
|
|
153
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
153
|
+
const { readSkiffRoles } = await import("./skiff-role-BSg6Qu9k.js").then((n) => n.u);
|
|
154
154
|
rolesOf = (root) => [...readSkiffRoles(root).keys()];
|
|
155
155
|
}
|
|
156
156
|
return c.roots.map((root) => ({
|
package/lib/ccc.d.ts
CHANGED
|
@@ -57,6 +57,15 @@ interface SerenityConfig {
|
|
|
57
57
|
};
|
|
58
58
|
safeMode?: {
|
|
59
59
|
blacklist?: string[];
|
|
60
|
+
/**
|
|
61
|
+
* **安全模式开启期间**额外从模型工具清单隐藏的工具(v1.51.4,owner 2026-10-09 令)。
|
|
62
|
+
*
|
|
63
|
+
* 语义(与 `exclusiveTools` 的区别,判据是"条件"):本键不是无条件的可见性白名单,
|
|
64
|
+
* 而是**条件屏蔽**——`\.serenity-safe-on` 标记存在时才隐藏,标记消失即**全部恢复**
|
|
65
|
+
* (基础表恒隐 `bash` 不受影响)。机制在 ACC、声明在 CCC(D23):
|
|
66
|
+
* ACC 代码里不出现任何具体工具名。
|
|
67
|
+
*/
|
|
68
|
+
hiddenTools?: string[];
|
|
60
69
|
};
|
|
61
70
|
/** localstore git 提交策略(S134 重设计):allow 可提交 / deny 禁提交(缺省 deny) */
|
|
62
71
|
localstore?: {
|
|
@@ -311,6 +320,27 @@ export declare function loadSerenityConfig(root: string, paths?: string[]): Sere
|
|
|
311
320
|
* @returns 去空白后的工具名列表(非字符串项被丢弃)
|
|
312
321
|
*/
|
|
313
322
|
export declare function readExclusiveTools(root: string, paths?: string[]): string[];
|
|
323
|
+
/**
|
|
324
|
+
* 读取 CCC 声明的「安全模式期间隐藏的工具」清单(`safeMode.hiddenTools`,v1.51.4)。
|
|
325
|
+
*
|
|
326
|
+
* 语义(R↓):**标记文件存在 ⇒ 才生效**。deny = `['bash', ...本清单]`(并集去重);
|
|
327
|
+
* 标记消失 ⇒ 连同 `bash` 一起解除(调用点在 `syncSafeModeRestriction`,与基础表同一处)。
|
|
328
|
+
*
|
|
329
|
+
* 失败方向 = **fail-open**(与 `exclusiveTools` 的 fail-closed 相反,理由不同):
|
|
330
|
+
* 未配置 / 字段缺失 / 配置损坏 ⇒ **空数组** = 只隐藏基础表。本键是**附加**屏蔽,
|
|
331
|
+
* 读不到声明就等于"没有证据要求多藏";且**隐藏是危险方向**(藏掉 agent 真正要用的工具
|
|
332
|
+
* 会静默损害能力),而配置损坏本身已有 `loadSerenityConfig` 的响亮告警(不静默)。
|
|
333
|
+
*
|
|
334
|
+
* 🔴 名字在此**不做**校验——未注册的名字会被 DSH `restrict` 拒绝(宿主契约逐字:
|
|
335
|
+
* "Empty filters, unknown names, scope-local names, and reserved transport names **fail**")
|
|
336
|
+
* ⇒ **调用方必须按"失败退化为基础表"处理**(见 `syncSafeModeRestriction`),
|
|
337
|
+
* 否则 CCC 写错一个名字会连 `bash` 的隐藏一起丢掉。
|
|
338
|
+
*
|
|
339
|
+
* @param root CCC 根
|
|
340
|
+
* @param paths 候选配置相对路径
|
|
341
|
+
* @returns 去空白后的工具名列表(非字符串/空白项被丢弃)
|
|
342
|
+
*/
|
|
343
|
+
export declare function readSafeModeHiddenTools(root: string, paths?: string[]): string[];
|
|
314
344
|
/**
|
|
315
345
|
* 读取 CCC 声明的「轨迹默认 skill」清单(`trajectory.skills`,v1.44.0)。
|
|
316
346
|
*
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { a as hostSessions, c as hostWeb, i as hostService, l as hostWebServer, n as hostInjected, o as hostSettings, r as hostLlm, s as hostSubagents, t as hostAgents } from "./access-CNccNtgf.js";
|
|
3
|
-
import { a as findSerenityRoot, c as matchBlacklist, d as readCccName$1, f as readExclusiveTools,
|
|
4
|
-
import { i as cccRootForExec, n as agentCwdFor, o as listCccs, r as cccRootForCwd, t as NO_CCC_FROM_AGENT_CWD } from "./ccc-roots-
|
|
5
|
-
import { A as localIdStamp, C as setActiveSessionInfo, D as isoLocal, E as useSession, O as localFileStamp, S as sessionsRoot, T as summarize, _ as namingTitleFor, a as pruneMissingBindings, b as resolveSessionByTitle, c as setBindingStore, d as clearActiveSessionInfo, f as createSession, g as listSessions, h as getActiveSessionInfo, i as listBoundSessionIds, k as localHuman, l as DEFAULT_SESSION_SCOPE, m as findSession, n as PLUGIN_SOURCE, o as readLastBound, p as extractSessionMdPathFromText, r as appendBound, s as resolveSessionTrajectoryLabel, t as ACC_MESSAGE_KIND, u as TRAJECTORY_ACTIONS, v as parseSessionContextFromEvents, w as showSession, x as sessionEvents$1, y as readActiveSessionMd } from "./message-source-
|
|
6
|
-
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-
|
|
3
|
+
import { _ as resolveInside, a as findSerenityRoot, c as matchBlacklist, d as readCccName$1, f as readExclusiveTools, h as readTrajectorySkills, i as findGitRoot, l as pathInside, m as readSafeModeHiddenTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readHandymanConfig, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-DXky9UZu.js";
|
|
4
|
+
import { i as cccRootForExec, n as agentCwdFor, o as listCccs, r as cccRootForCwd, t as NO_CCC_FROM_AGENT_CWD } from "./ccc-roots-Bo0HKLlM.js";
|
|
5
|
+
import { A as localIdStamp, C as setActiveSessionInfo, D as isoLocal, E as useSession, O as localFileStamp, S as sessionsRoot, T as summarize, _ as namingTitleFor, a as pruneMissingBindings, b as resolveSessionByTitle, c as setBindingStore, d as clearActiveSessionInfo, f as createSession, g as listSessions, h as getActiveSessionInfo, i as listBoundSessionIds, k as localHuman, l as DEFAULT_SESSION_SCOPE, m as findSession, n as PLUGIN_SOURCE, o as readLastBound, p as extractSessionMdPathFromText, r as appendBound, s as resolveSessionTrajectoryLabel, t as ACC_MESSAGE_KIND, u as TRAJECTORY_ACTIONS, v as parseSessionContextFromEvents, w as showSession, x as sessionEvents$1, y as readActiveSessionMd } from "./message-source-BExngUPX.js";
|
|
6
|
+
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-BNyH5ghC.js";
|
|
7
7
|
import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, o as ACC_VERSION, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-BjIX_KD1.js";
|
|
8
|
-
import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-
|
|
8
|
+
import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-BSg6Qu9k.js";
|
|
9
9
|
import { a as ACP_HTTP_PORT, c as MAIN_WEB_PORT, d as WEIXIN_SEND_PORT, l as MECHANISM_PORTS, n as readSimpleSettings, o as FACE_PORTS, r as registerSettingsSection, s as GATEWAY_PORT, u as SKIFF_DEBUG_PORT } from "./settings-section-xHABl8nk.js";
|
|
10
10
|
import { a as markdownToPlainText, c as sendTyping, i as getUpdates, l as sniffImageExt, n as downloadMedia, o as sendFileMessage, r as getConfig, s as sendTextMessage, t as TypingStatus } from "./weixin-api-BrRcPiQs.js";
|
|
11
11
|
import { createRequire } from "node:module";
|
|
@@ -1091,6 +1091,7 @@ Directory of ACC capabilities — each area lists where to go for details (guide
|
|
|
1091
1091
|
⑦ 注册表与安全 → mech-registry.json 由 container_admin msm register/deregister 管理(写保护——不可直接编辑)
|
|
1092
1092
|
dashboard health 输出 registry 完整性检查;损坏恢复指引见 health registry.issues
|
|
1093
1093
|
CCC 级开关:exclusiveTools(声明专属工具)/ safeMode.blacklist(写路径黑名单)
|
|
1094
|
+
/ safeMode.hiddenTools(**安全模式开启期间**额外隐藏的工具,v1.51.4)
|
|
1094
1095
|
CCC 级 skill 供给:trajectory.skills(v1.44.0——**本 CCC 每条轨迹都带**,含 skiff 会话;与轨迹自己的 frontmatter 声明取并集)
|
|
1095
1096
|
|
|
1096
1097
|
每区:一句话定位 + 详细入口(工具名 / guide 子命令)。详情永远以对应工具的 guide/ccc-config 为单一真相源。
|
|
@@ -1205,11 +1206,21 @@ deny 时写入自动确保 .gitignore 含该文件(物理保证),container
|
|
|
1205
1206
|
Config:
|
|
1206
1207
|
{ "hooks": { "autoRestoreSession": false } }
|
|
1207
1208
|
|
|
1208
|
-
── 5. safeMode
|
|
1209
|
+
── 5. safeMode(黑名单 + 开启期间隐藏的工具)──
|
|
1209
1210
|
safe-mode 由 WebUI 开关控制(写 .serenity-safe-on 标记);黑名单路径受 guards seam 拦截。
|
|
1210
1211
|
|
|
1212
|
+
▸ blacklist:写路径黑名单(同下 Config)。
|
|
1213
|
+
▸ hiddenTools(v1.51.4,owner 2026-10-09 令):**仅在安全模式开启期间**额外从模型工具
|
|
1214
|
+
清单隐藏的工具(ACC 基础表恒隐 bash)。打开 safe-mode 生效、**关掉即全部恢复**;
|
|
1215
|
+
改本键**热生效**(下一个 pre-step 重算,无需重启)。声明在 CCC(D23)——ACC 代码里
|
|
1216
|
+
不出现任何具体工具名。
|
|
1217
|
+
⚠️ 写一个**本 CCC 未注册**的名字会让**整次 restrict 失败**(DSH 契约逐字:"unknown
|
|
1218
|
+
names … fail")⇒ 此时**退化为只隐藏基础表**并在日志响亮报错(绝不因一个错名丢掉
|
|
1219
|
+
safe-mode 的核心隐藏)。诊断:\`AGENT_SESSIONS/.restrict-diag.json\` 的 \`denyByKey\`。
|
|
1220
|
+
⚠️ 隐藏 = **从 schema 移除**(agent 根本看不到该工具)⇒ 别把 skill/文档还在教的工具写进来。
|
|
1221
|
+
|
|
1211
1222
|
Config:
|
|
1212
|
-
{ "safeMode": { "blacklist": [".secrets/"] } }
|
|
1223
|
+
{ "safeMode": { "blacklist": [".secrets/"], "hiddenTools": ["workflow", "job_kill"] } }
|
|
1213
1224
|
|
|
1214
1225
|
── 6. skiff.roles(F4 认知子集角色)──
|
|
1215
1226
|
Skiff 角色 = 全知全能 trajectory 的任意子集(CCC 定义)。每角色独立模型 + 双白名单
|
|
@@ -8713,21 +8724,25 @@ function decideGuard(input) {
|
|
|
8713
8724
|
function resolveAgentCwd(exec) {
|
|
8714
8725
|
return exec.agent?.session?.header?.cwd ?? process.cwd();
|
|
8715
8726
|
}
|
|
8716
|
-
/**
|
|
8727
|
+
/**
|
|
8728
|
+
* 安全模式开启时从模型工具列表隐藏的工具 —— **基础表**(只隐藏 bash;write/edit 保留)。
|
|
8729
|
+
* 它**恒隐**、与 CCC 配置无关;CCC 声明的 `safeMode.hiddenTools` 是**附加**项(见下)。
|
|
8730
|
+
*/
|
|
8717
8731
|
const SAFE_MODE_DENY_TOOLS = ["bash"];
|
|
8718
|
-
/** agent key → restrict disposer(安全模式工具隐藏状态) */
|
|
8719
8732
|
const safeModeRestrictions = /* @__PURE__ */ new Map();
|
|
8720
8733
|
const restrictDiag = {
|
|
8721
8734
|
lastKey: null,
|
|
8722
8735
|
lastAttemptAt: null,
|
|
8723
8736
|
lastSuccess: null,
|
|
8724
8737
|
lastError: null,
|
|
8725
|
-
activeKeys: []
|
|
8738
|
+
activeKeys: [],
|
|
8739
|
+
denyByKey: {}
|
|
8726
8740
|
};
|
|
8727
8741
|
function getRestrictDiagnostics() {
|
|
8728
8742
|
return {
|
|
8729
8743
|
...restrictDiag,
|
|
8730
|
-
activeKeys: [...safeModeRestrictions.keys()]
|
|
8744
|
+
activeKeys: [...safeModeRestrictions.keys()],
|
|
8745
|
+
denyByKey: Object.fromEntries([...safeModeRestrictions].map(([k, v]) => [k, v.deny]))
|
|
8731
8746
|
};
|
|
8732
8747
|
}
|
|
8733
8748
|
/** 诊断落盘:AGENT_SESSIONS/.restrict-diag.json(文件通道,避免 HTTP 自锁) */
|
|
@@ -8742,35 +8757,85 @@ function writeRestrictDiag(root) {
|
|
|
8742
8757
|
} catch {}
|
|
8743
8758
|
}
|
|
8744
8759
|
/**
|
|
8745
|
-
* 同步安全模式工具隐藏:标记存在 → agent.ctx.tools.restrict deny
|
|
8746
|
-
*
|
|
8760
|
+
* 同步安全模式工具隐藏:标记存在 → `agent.ctx.tools.restrict deny` 隐藏
|
|
8761
|
+
* **基础表(bash)∪ CCC 声明的 `safeMode.hiddenTools`**;标记消失 → 全部解除。
|
|
8762
|
+
* pre-step 每步调用 ⇒ 开/关/**改声明**三种变化都实时生效(v1.51.4 起含"改声明")。
|
|
8763
|
+
*
|
|
8764
|
+
* 与 `readSafeModeHiddenTools` 的分工(R↓):本函数负责**形状与失败退化**,reader 只管取值。
|
|
8765
|
+
* 🔴 退化规则:DSH 契约规定 **未注册的工具名会让整次 restrict 失败**("unknown names … fail")
|
|
8766
|
+
* ⇒ 绝不能让 CCC 写错一个名字就丢掉 safe-mode 的核心隐藏(bash)。失败时退化为**只隐藏基础表**,
|
|
8767
|
+
* 并在日志响亮报错;退化态**按期望签名记账**,不会每步重试刷屏。
|
|
8747
8768
|
*/
|
|
8748
8769
|
function syncSafeModeRestriction(agent, root) {
|
|
8749
8770
|
const key = agent.session.id ?? "global";
|
|
8750
8771
|
const on = isSafeModeOn(root);
|
|
8751
8772
|
const existing = safeModeRestrictions.get(key);
|
|
8752
|
-
if (on
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8773
|
+
if (!on) {
|
|
8774
|
+
if (existing !== void 0) {
|
|
8775
|
+
try {
|
|
8776
|
+
existing.dispose();
|
|
8777
|
+
} catch (e) {
|
|
8778
|
+
console.error(`[serenity-hooks] restrict 解除失败 (key=${key}):`, e.message);
|
|
8779
|
+
}
|
|
8780
|
+
safeModeRestrictions.delete(key);
|
|
8781
|
+
}
|
|
8782
|
+
writeRestrictDiag(root);
|
|
8783
|
+
return;
|
|
8784
|
+
}
|
|
8785
|
+
let declared = [];
|
|
8786
|
+
try {
|
|
8787
|
+
declared = readSafeModeHiddenTools(root);
|
|
8788
|
+
} catch (e) {
|
|
8789
|
+
console.error(`[serenity-hooks] safeMode.hiddenTools 判据读取失败 (key=${key}):`, e.message);
|
|
8790
|
+
}
|
|
8791
|
+
const deny = [.../* @__PURE__ */ new Set([...SAFE_MODE_DENY_TOOLS, ...declared])];
|
|
8792
|
+
const signature = deny.join(",");
|
|
8793
|
+
if (existing !== void 0 && existing.signature === signature) {
|
|
8794
|
+
writeRestrictDiag(root);
|
|
8795
|
+
return;
|
|
8796
|
+
}
|
|
8797
|
+
if (existing !== void 0) {
|
|
8798
|
+
try {
|
|
8799
|
+
existing.dispose();
|
|
8800
|
+
} catch (e) {
|
|
8801
|
+
console.error(`[serenity-hooks] restrict 重算前解除失败 (key=${key}):`, e.message);
|
|
8802
|
+
}
|
|
8803
|
+
safeModeRestrictions.delete(key);
|
|
8804
|
+
}
|
|
8805
|
+
let applied = deny;
|
|
8806
|
+
let dispose;
|
|
8807
|
+
try {
|
|
8808
|
+
dispose = agent.ctx.tools.restrict({ deny: [...deny] });
|
|
8759
8809
|
} catch (e) {
|
|
8760
8810
|
restrictDiag.lastKey = key;
|
|
8761
8811
|
restrictDiag.lastAttemptAt = isoLocal();
|
|
8762
8812
|
restrictDiag.lastSuccess = false;
|
|
8763
8813
|
restrictDiag.lastError = e.message;
|
|
8764
|
-
console.error(`[serenity-hooks] restrict
|
|
8765
|
-
|
|
8766
|
-
else if (!on && existing) {
|
|
8814
|
+
console.error(`[serenity-hooks] restrict 失败,已退化为基础表(多为 safeMode.hiddenTools 里有本 CCC **未注册**的工具名)(key=${key}):`, e.message);
|
|
8815
|
+
applied = [...SAFE_MODE_DENY_TOOLS];
|
|
8767
8816
|
try {
|
|
8768
|
-
|
|
8769
|
-
} catch (
|
|
8770
|
-
|
|
8817
|
+
dispose = agent.ctx.tools.restrict({ deny: applied });
|
|
8818
|
+
} catch (e2) {
|
|
8819
|
+
restrictDiag.lastError = `${e.message} / 退化亦失败: ${e2.message}`;
|
|
8820
|
+
console.error(`[serenity-hooks] restrict 退化失败(守卫仍兜底拦截)(key=${key}):`, e2.message);
|
|
8821
|
+
safeModeRestrictions.set(key, {
|
|
8822
|
+
signature,
|
|
8823
|
+
deny: [],
|
|
8824
|
+
dispose: () => {}
|
|
8825
|
+
});
|
|
8826
|
+
writeRestrictDiag(root);
|
|
8827
|
+
return;
|
|
8771
8828
|
}
|
|
8772
|
-
safeModeRestrictions.delete(key);
|
|
8773
8829
|
}
|
|
8830
|
+
restrictDiag.lastKey = key;
|
|
8831
|
+
restrictDiag.lastAttemptAt = isoLocal();
|
|
8832
|
+
restrictDiag.lastSuccess = true;
|
|
8833
|
+
restrictDiag.lastError = null;
|
|
8834
|
+
safeModeRestrictions.set(key, {
|
|
8835
|
+
signature,
|
|
8836
|
+
deny: applied,
|
|
8837
|
+
dispose
|
|
8838
|
+
});
|
|
8774
8839
|
writeRestrictDiag(root);
|
|
8775
8840
|
}
|
|
8776
8841
|
/** 条件可见的 IM 工具名(与 tools/im-bridge.ts 的注册名一致) */
|
|
@@ -10393,11 +10458,11 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10393
10458
|
sendJson$4(res, 400, { error: chk.error });
|
|
10394
10459
|
return;
|
|
10395
10460
|
}
|
|
10396
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
10461
|
+
const { readWeixinSettings } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10397
10462
|
const { weixinBridgeStatus } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
10398
10463
|
const settings = readWeixinSettings(chk.root);
|
|
10399
10464
|
const bridge = weixinBridgeStatus().find((b) => b.ccc === chk.root);
|
|
10400
|
-
const { readWeixinCredential } = await import("./weixin-route-
|
|
10465
|
+
const { readWeixinCredential } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10401
10466
|
const accounts = (settings.accounts ?? []).map((a) => ({
|
|
10402
10467
|
accountId: a.accountId,
|
|
10403
10468
|
name: a.name ?? void 0,
|
|
@@ -10429,7 +10494,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10429
10494
|
const { fetchQRCode } = await import("./weixin-api-BrRcPiQs.js").then((n) => n.u);
|
|
10430
10495
|
const { randomUUID } = await import("node:crypto");
|
|
10431
10496
|
for (const [key, v] of weixinLogins) if (Date.now() - v.startedAt > WEIXIN_LOGIN_TTL_MS) weixinLogins.delete(key);
|
|
10432
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
10497
|
+
const { readWeixinSettings } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10433
10498
|
const qr = await fetchQRCode({ botType: readWeixinSettings(root).botType ?? void 0 });
|
|
10434
10499
|
const loginKey = randomUUID();
|
|
10435
10500
|
weixinLogins.set(loginKey, {
|
|
@@ -10450,7 +10515,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10450
10515
|
sendJson$4(res, 400, { error: "missing accountId" });
|
|
10451
10516
|
return;
|
|
10452
10517
|
}
|
|
10453
|
-
const { removeWeixinAccount } = await import("./weixin-route-
|
|
10518
|
+
const { removeWeixinAccount } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10454
10519
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
10455
10520
|
removeWeixinAccount(root, body.accountId);
|
|
10456
10521
|
syncCccBridge(ctx, root);
|
|
@@ -10463,8 +10528,8 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10463
10528
|
sendJson$4(res, 400, { error: "invalid routes (expected [{user, role}, ...])" });
|
|
10464
10529
|
return;
|
|
10465
10530
|
}
|
|
10466
|
-
const { saveWeixinRoutes } = await import("./weixin-route-
|
|
10467
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
10531
|
+
const { saveWeixinRoutes } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10532
|
+
const { readSkiffRoles } = await import("./skiff-role-BSg6Qu9k.js").then((n) => n.u);
|
|
10468
10533
|
const roles = readSkiffRoles(root);
|
|
10469
10534
|
for (const r of routes) if (!roles.has(r.role)) {
|
|
10470
10535
|
sendJson$4(res, 400, { error: `unknown role: ${r.role} (not in ${root} skiff.roles)` });
|
|
@@ -10476,7 +10541,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10476
10541
|
}
|
|
10477
10542
|
if (body.action === "set-enabled") {
|
|
10478
10543
|
const enabled = body.enabled === true;
|
|
10479
|
-
const { readWeixinSettings, setWeixinEnabled } = await import("./weixin-route-
|
|
10544
|
+
const { readWeixinSettings, setWeixinEnabled } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10480
10545
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
10481
10546
|
const settings = readWeixinSettings(root);
|
|
10482
10547
|
if (enabled && (settings.accounts ?? []).length === 0) {
|
|
@@ -10520,7 +10585,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10520
10585
|
return;
|
|
10521
10586
|
}
|
|
10522
10587
|
const { pollQRStatus } = await import("./weixin-api-BrRcPiQs.js").then((n) => n.u);
|
|
10523
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
10588
|
+
const { readWeixinSettings } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10524
10589
|
const settings = readWeixinSettings(login.root);
|
|
10525
10590
|
const status = await pollQRStatus({
|
|
10526
10591
|
baseUrl: void 0,
|
|
@@ -10535,7 +10600,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
10535
10600
|
});
|
|
10536
10601
|
return;
|
|
10537
10602
|
}
|
|
10538
|
-
const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./weixin-route-
|
|
10603
|
+
const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./weixin-route-BNyH5ghC.js").then((n) => n.u);
|
|
10539
10604
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
10540
10605
|
const accountId = nextWeixinAccountId(settings);
|
|
10541
10606
|
upsertWeixinAccount(login.root, {
|
|
@@ -16688,7 +16753,7 @@ function manualOutputFallbackNeeded(input) {
|
|
|
16688
16753
|
*/
|
|
16689
16754
|
async function resolveCccRootByAlias(ctx, alias) {
|
|
16690
16755
|
try {
|
|
16691
|
-
const { listCccs } = await import("./ccc-roots-
|
|
16756
|
+
const { listCccs } = await import("./ccc-roots-Bo0HKLlM.js").then((n) => n.a);
|
|
16692
16757
|
const entries = await listCccs(ctx);
|
|
16693
16758
|
const byName = entries.find((e) => e.name === alias);
|
|
16694
16759
|
if (byName) return byName.root;
|
|
@@ -17187,7 +17252,7 @@ function syncHumanChannel(ctx) {
|
|
|
17187
17252
|
(async () => {
|
|
17188
17253
|
try {
|
|
17189
17254
|
stopMachineLoops();
|
|
17190
|
-
const { listCccs } = await import("./ccc-roots-
|
|
17255
|
+
const { listCccs } = await import("./ccc-roots-Bo0HKLlM.js").then((n) => n.a);
|
|
17191
17256
|
for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
|
|
17192
17257
|
} catch {}
|
|
17193
17258
|
})();
|
|
@@ -17423,7 +17488,7 @@ function matchCcc(input, candidates) {
|
|
|
17423
17488
|
}
|
|
17424
17489
|
/** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
|
|
17425
17490
|
async function collectCandidates(ctx) {
|
|
17426
|
-
const { listCccs } = await import("./ccc-roots-
|
|
17491
|
+
const { listCccs } = await import("./ccc-roots-Bo0HKLlM.js").then((n) => n.a);
|
|
17427
17492
|
const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
|
|
17428
17493
|
const seen = /* @__PURE__ */ new Set();
|
|
17429
17494
|
const out = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as cccRootForCwd } from "./ccc-roots-
|
|
1
|
+
import { r as cccRootForCwd } from "./ccc-roots-Bo0HKLlM.js";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/time.ts
|
package/lib/seams/guards.d.ts
CHANGED
|
@@ -39,11 +39,19 @@ interface RestrictDiagnostics {
|
|
|
39
39
|
lastSuccess: boolean | null;
|
|
40
40
|
lastError: string | null;
|
|
41
41
|
activeKeys: string[];
|
|
42
|
+
/** v1.51.4:每个 key **实际生效**的 deny 清单(排查"某工具为什么/为什么没被隐藏") */
|
|
43
|
+
denyByKey: Record<string, string[]>;
|
|
42
44
|
}
|
|
43
45
|
export declare function getRestrictDiagnostics(): RestrictDiagnostics;
|
|
44
46
|
/**
|
|
45
|
-
* 同步安全模式工具隐藏:标记存在 → agent.ctx.tools.restrict deny
|
|
46
|
-
*
|
|
47
|
+
* 同步安全模式工具隐藏:标记存在 → `agent.ctx.tools.restrict deny` 隐藏
|
|
48
|
+
* **基础表(bash)∪ CCC 声明的 `safeMode.hiddenTools`**;标记消失 → 全部解除。
|
|
49
|
+
* pre-step 每步调用 ⇒ 开/关/**改声明**三种变化都实时生效(v1.51.4 起含"改声明")。
|
|
50
|
+
*
|
|
51
|
+
* 与 `readSafeModeHiddenTools` 的分工(R↓):本函数负责**形状与失败退化**,reader 只管取值。
|
|
52
|
+
* 🔴 退化规则:DSH 契约规定 **未注册的工具名会让整次 restrict 失败**("unknown names … fail")
|
|
53
|
+
* ⇒ 绝不能让 CCC 写错一个名字就丢掉 safe-mode 的核心隐藏(bash)。失败时退化为**只隐藏基础表**,
|
|
54
|
+
* 并在日志响亮报错;退化态**按期望签名记账**,不会每步重试刷屏。
|
|
47
55
|
*/
|
|
48
56
|
export declare function syncSafeModeRestriction(agent: Agent, root: string): void;
|
|
49
57
|
/** im-bridge 隐藏诊断(排查"工具为什么不在清单里") */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import {
|
|
2
|
+
import { _ as resolveInside, g as readUtf8, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-DXky9UZu.js";
|
|
3
3
|
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
//#region src/skiff-role.ts
|
|
5
5
|
/**
|
package/lib/status.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ interface SerenityStatus {
|
|
|
56
56
|
lastSuccess: boolean | null;
|
|
57
57
|
lastError: string | null;
|
|
58
58
|
activeKeys: string[];
|
|
59
|
+
/** v1.51.4:每个 key **实际生效**的 deny 清单(含 safeMode.hiddenTools 的并集) */
|
|
60
|
+
denyByKey: Record<string, string[]>;
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
63
|
export declare function getStatus(cwd: string, configPaths?: string[]): SerenityStatus;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-
|
|
2
|
+
import { s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-DXky9UZu.js";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { createHash } from "node:crypto";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.51.
|
|
3
|
+
"version": "1.51.4",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:12 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag/diagram)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.7-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|