@shgroup/dsh-serenity-hooks 1.79.5 → 1.81.0
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-roots-DAwz9Li1.js → ccc-roots-4LwGLCXa.js} +1 -1
- package/lib/index.js +76 -13
- package/lib/{message-source-DiP3Uve3.js → message-source-CfqdGIi2.js} +25 -3
- package/lib/{profile-5TQ_C1xi.js → profile-CiRWh2a2.js} +15 -0
- package/lib/{session-tdlJDS9i.js → session-KBRbYb52.js} +149 -12
- package/lib/{settings-B-vn8j4g.js → settings-Dj4_ppTC.js} +1 -1
- package/lib/trajectory/policy/profile.d.ts +27 -0
- package/lib/trajectory/policy/rules.d.ts +18 -0
- package/lib/trajectory/prompt-injection.d.ts +73 -0
- 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.
|
|
3
|
+
"version": "1.81.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
@@ -227,7 +227,7 @@ async function listCccs(ctx, opts = {}) {
|
|
|
227
227
|
if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
|
|
228
228
|
let rolesOf = null;
|
|
229
229
|
if (opts.withRoles === true) {
|
|
230
|
-
const { listTrajectoryConstraints } = await import("./profile-
|
|
230
|
+
const { listTrajectoryConstraints } = await import("./profile-CiRWh2a2.js").then((n) => n.i);
|
|
231
231
|
rolesOf = (root) => {
|
|
232
232
|
try {
|
|
233
233
|
return listTrajectoryConstraints(root).map((p) => p.code);
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { i as __toESM, n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
|
|
2
|
-
import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-
|
|
2
|
+
import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-4LwGLCXa.js";
|
|
3
3
|
import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readCheapWorkerConfig, h as readSafeModeHiddenTools, i as findGitRoot, l as pathInside, m as readExclusiveTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-CyYJL4F2.js";
|
|
4
|
-
import { A as sessionEvents, B as isoLocal, C as listSessions, E as parseTrajectoryCode, F as trajectoryDescOf, H as localHuman, I as useSession, L as TRAJECTORY_FILENAME, M as setActiveSessionInfo, N as showSession, O as readTrajectoryUid, P as summarize, R as TRAJECTORY_LEGACY_FILENAMES, S as listActiveTrajectories, T as parseSessionContextFromEvents, U as localIdStamp, V as localFileStamp, _ as createSession, a as readTrajectoryConstraintAt, b as getActiveSessionInfo, c as trajectoryConstraintForSession, f as COGNITIVE_TRAJECTORY_ACTIONS, g as clearActiveSessionInfo, h as archiveSession, j as sessionsRoot, k as resolveSessionByTitle, m as UID_FILENAME, n as isTrajectoryConstrained, o as readTrajectoryConstraintByCode, r as listTrajectoryConstraints, s as replacesDefaultIdentity, t as TRAJECTORY_CONSTRAINT_FILENAME, v as extractSessionMdPathFromText, w as namingTitleFor, y as findSession, z as readTrajectoryFile } from "./profile-
|
|
4
|
+
import { A as sessionEvents, B as isoLocal, C as listSessions, E as parseTrajectoryCode, F as trajectoryDescOf, H as localHuman, I as useSession, L as TRAJECTORY_FILENAME, M as setActiveSessionInfo, N as showSession, O as readTrajectoryUid, P as summarize, R as TRAJECTORY_LEGACY_FILENAMES, S as listActiveTrajectories, T as parseSessionContextFromEvents, U as localIdStamp, V as localFileStamp, _ as createSession, a as readTrajectoryConstraintAt, b as getActiveSessionInfo, c as trajectoryConstraintForSession, f as COGNITIVE_TRAJECTORY_ACTIONS, g as clearActiveSessionInfo, h as archiveSession, j as sessionsRoot, k as resolveSessionByTitle, m as UID_FILENAME, n as isTrajectoryConstrained, o as readTrajectoryConstraintByCode, r as listTrajectoryConstraints, s as replacesDefaultIdentity, t as TRAJECTORY_CONSTRAINT_FILENAME, v as extractSessionMdPathFromText, w as namingTitleFor, y as findSession, z as readTrajectoryFile } from "./profile-CiRWh2a2.js";
|
|
5
5
|
import { n as checkLocalstoreGitCompliance, o as readStore, s as runLocalStore, t as LOCALSTORE_SCOPES } from "./service-DDmHSglV.js";
|
|
6
|
-
import { _ as
|
|
7
|
-
import { A as buildResourceIndex, C as verifyPassword, D as recordToolUsage, E as verifyTotpCode, F as hasTrajectoryPrompt, M as isSafeSkillName, N as truncateContent, O as REFERENCE_DIR, P as TRAJECTORY_PROMPT_FILENAME, S as toWire, T as MECHANISM_PORTS, _ as registerEntrySkillSectionGlobal, a as trajectoryConstraintFor, b as projectKnownWorkspaces, c as trajectoryWorkspaceMdPath, d as CHEAP_WORKER_GUIDE, f as providerAvailabilityError, g as registerEntrySkillSection, h as registerCognitiveTrajectorySkillSection, i as getTrajectoryAgent, j as buildResourceNameSuffix, k as SKILL_ONTOLOGY_FILE, l as unregisterTrajectorySession, m as splitModel, n as createTrajectoryAgent, o as trajectoryConstraintMsmGate, p as requireWhitelistedModel, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as askTrajectory, u as workspaceCognitiveTrajectoryLine, v as applyWirePatch, w as FACE_PORTS, x as readAdvancedSettings, y as migrateLegacyLocalstore } from "./session-
|
|
6
|
+
import { _ as resolveConstraintSystemPrompt, a as listBoundSessionIds, d as constraintCognitiveTrajectory, f as constraintSystemPromptSource, g as profileWriteWhitelist, h as profileToolWhitelist, i as carrierState, l as TRAJECTORY_CONSTRAINT_HINT, n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND, v as ACC_VERSION, y as findPackageRoot } from "./message-source-CfqdGIi2.js";
|
|
7
|
+
import { A as buildResourceIndex, C as verifyPassword, D as recordToolUsage, E as verifyTotpCode, F as hasTrajectoryPrompt, M as isSafeSkillName, N as truncateContent, O as REFERENCE_DIR, P as TRAJECTORY_PROMPT_FILENAME, S as toWire, T as MECHANISM_PORTS, _ as registerEntrySkillSectionGlobal, a as trajectoryConstraintFor, b as projectKnownWorkspaces, c as trajectoryWorkspaceMdPath, d as CHEAP_WORKER_GUIDE, f as providerAvailabilityError, g as registerEntrySkillSection, h as registerCognitiveTrajectorySkillSection, i as getTrajectoryAgent, j as buildResourceNameSuffix, k as SKILL_ONTOLOGY_FILE, l as unregisterTrajectorySession, m as splitModel, n as createTrajectoryAgent, o as trajectoryConstraintMsmGate, p as requireWhitelistedModel, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as askTrajectory, u as workspaceCognitiveTrajectoryLine, v as applyWirePatch, w as FACE_PORTS, x as readAdvancedSettings, y as migrateLegacyLocalstore } from "./session-KBRbYb52.js";
|
|
8
8
|
import { n as hasSessionLogById, r as sessionsRootDir } from "./cleanup-C-92qnDs.js";
|
|
9
|
-
import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-
|
|
9
|
+
import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-Dj4_ppTC.js";
|
|
10
10
|
import { REGISTERED_TOOLS } from "./invariant.js";
|
|
11
11
|
import { a as readFeishuCredential, d as weixinSessionIdForTrajectory, i as matchWeixinRoute, l as sanitizeFileName$1, n as extractWeixinText, o as readWeixinCredential, r as hasVoiceItem, s as readWeixinSettings, t as extractWeixinMedia, u as weixinInboundDir } from "./route-Dr0SFD8A.js";
|
|
12
12
|
import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-BMk2w2KY.js";
|
|
@@ -10727,6 +10727,7 @@ becomes a 轨迹约束; delete it and it goes back to being an ordinary trajecto
|
|
|
10727
10727
|
"model": "provider/model", // optional; **不写 = 用会话当前模型**(不回退 cheap-worker;每轮生效)
|
|
10728
10728
|
"tools": ["read","grep","msm",...], // optional; **不写 = 不收窄**。显式 [] = 全隐藏(除 skill)
|
|
10729
10729
|
"msms": ["msm-a","msm-b"], // optional; **不写 = 不收窄**。register/deregister 恒拒
|
|
10730
|
+
"writes": ["AGENT_SESSIONS/<我的目录>/"], // optional; **不写 = 不收窄**。显式 [] = 一个写都落不下
|
|
10730
10731
|
"cognitiveTrajectory": { "session": true, "keeper": true, "rebuild": true }, // 缺省 TRUE(见下)
|
|
10731
10732
|
"resident": { "serves": "..." }, // optional; 对外用途自述(见 trajectory-self 章)
|
|
10732
10733
|
"cro": { "host": "<machine name>" } // optional: which machine may run this trajectory's CRO program
|
|
@@ -10752,6 +10753,20 @@ becomes a 轨迹约束; delete it and it goes back to being an ordinary trajecto
|
|
|
10752
10753
|
🔴 判据是**字段在不在**,不是**数组空不空**(D181)。旧版把两者混成"空 = 全拒",
|
|
10753
10754
|
于是「只想声明常驻」的人被静默锁死 —— 那是本仓实测踩过的坑(D179(b))。
|
|
10754
10755
|
|
|
10756
|
+
── \`writes\`: the THIRD whitelist — the PATH dimension(owner 2026-10-20 令)──
|
|
10757
|
+
\`tools\` 管的是**工具名**,管不了"这个工具能写哪儿":给了 \`write\` 之后,路径守卫只拦
|
|
10758
|
+
「逃出 CCC」与黑名单,**拦不住它去写别人的轨迹或 docs/**。\`writes\` 补的正是这一维。
|
|
10759
|
+
|
|
10760
|
+
- **不写** ⇒ 不收窄(写权限 = 路径守卫那几条,与之前完全一致)
|
|
10761
|
+
- \`"writes": []\` ⇒ **一个写都落不下**(显式意图;只影响写,不影响读)
|
|
10762
|
+
- \`"writes": ["AGENT_SESSIONS/<我的目录>/", "_tmp/"]\` ⇒ 写类工具的**目标路径**必须落在这些前缀内
|
|
10763
|
+
- 条目可以是**相对 CCC 根**的路径,也可以是绝对路径;判定按"目标在这个目录之内(含自身)"
|
|
10764
|
+
- 只管**写类**工具(\`write\` / \`edit\` / \`container_fs\` 的写动作 / \`append\` / \`touch\`),**读不受影响**
|
|
10765
|
+
- 越界拒绝时**会指名允许的前缀与当前目标**(D186:不许不出声;出声必须指对路)
|
|
10766
|
+
|
|
10767
|
+
⇒ 典型用法(两条 IM 轨迹):给 \`write\`/\`edit\` 写自己的身体,同时把写面收窄到自己那一格:
|
|
10768
|
+
\`"tools": ["read","write","edit",...], "writes": ["AGENT_SESSIONS/<code 目录>/"]\`
|
|
10769
|
+
|
|
10755
10770
|
── cognitiveTrajectory: why the defaults are TRUE ──
|
|
10756
10771
|
The workspace of a 轨迹约束 is its own SESSION.md. Setting these to false would cut it off from
|
|
10757
10772
|
its own body, so \`session\`/\`keeper\`/\`rebuild\` all default to true. Set false explicitly only
|
|
@@ -10792,6 +10807,11 @@ function validateTrajectoryConstraint(root) {
|
|
|
10792
10807
|
}
|
|
10793
10808
|
})())) issues.push(`trajectory "${p.code}": no trajectory prompt (add ${TRAJECTORY_PROMPT_FILENAME} in the trajectory dir — recommended — or the legacy systemPromptFile/systemPrompt)`);
|
|
10794
10809
|
for (const m of p.msms ?? []) if (!registered.has(m)) issues.push(`trajectory "${p.code}": msms "${m}" is not registered in mech-registry.json`);
|
|
10810
|
+
for (const w of p.writes ?? []) try {
|
|
10811
|
+
resolveInside(root, w);
|
|
10812
|
+
} catch (err) {
|
|
10813
|
+
issues.push(`trajectory "${p.code}": writes "${w}" is outside the CCC root (${String(err?.message ?? err)}) — a write prefix outside the container can never match; use a path relative to the CCC root`);
|
|
10814
|
+
}
|
|
10795
10815
|
if (p.model && allowedModels && !allowedModels.has(p.model)) issues.push(`trajectory "${p.code}": model "${p.model}" not in cheap-worker.models (${[...allowedModels].join(", ") || "(none)"})`);
|
|
10796
10816
|
}
|
|
10797
10817
|
return {
|
|
@@ -10824,6 +10844,7 @@ function listTrajectoryConstraintSummary(root) {
|
|
|
10824
10844
|
model: p.model ?? "(unchanged)",
|
|
10825
10845
|
msms: wl(p.msms, "(unrestricted)"),
|
|
10826
10846
|
tools: wl(p.tools, "(unrestricted)"),
|
|
10847
|
+
writes: wl(p.writes, "(unrestricted)"),
|
|
10827
10848
|
...p.resident !== void 0 ? { resident: p.resident.serves !== void 0 ? p.resident.serves : "(no serves)" } : {},
|
|
10828
10849
|
cognitiveTrajectory: constraintCognitiveTrajectory(p),
|
|
10829
10850
|
promptSource: constraintSystemPromptSource(p, hasTrajectoryPrompt(root, p.dirName)),
|
|
@@ -10892,6 +10913,34 @@ const TRAJECTORY_SELF_GUIDE = [
|
|
|
10892
10913
|
⚠️ 与 SESSION.md 的分工(别写重了):
|
|
10893
10914
|
SESSION.md = **发生了什么**(日志、决策、当前状态)
|
|
10894
10915
|
PROMPT.md = **我是谁、怎么工作**(章程;很少改,改了就改变行为)`,
|
|
10916
|
+
"",
|
|
10917
|
+
`── 我的章程怎么进来:追加(缺省)还是替换 ──
|
|
10918
|
+
|
|
10919
|
+
\`trajectory.json\` 的 \`prompt\` 段(**不写它 = 追加**,既有行为逐字不变):
|
|
10920
|
+
|
|
10921
|
+
\`\`\`jsonc
|
|
10922
|
+
{
|
|
10923
|
+
"prompt": {
|
|
10924
|
+
"injection": "replace", // append(缺省)| replace
|
|
10925
|
+
"replaces": ["metaphor", "principles", "cce", "eap"] // 可选;不写 = 四块全换
|
|
10926
|
+
}
|
|
10927
|
+
}
|
|
10928
|
+
\`\`\`
|
|
10929
|
+
|
|
10930
|
+
| 模式 | 结果 |
|
|
10931
|
+
|---|---|
|
|
10932
|
+
| \`append\`(缺省) | 宁静号各块照常注入,我的 \`PROMPT.md\` **追加**在它们之后 |
|
|
10933
|
+
| \`replace\` | 我点名的**约束块**不再注入,我的 \`PROMPT.md\` **站到它们原来的位置**(紧跟身份块) |
|
|
10934
|
+
|
|
10935
|
+
可替换的四块:\`metaphor\`(世界模型)/\`principles\`(信念与边界)/\`cce\`(连续性纪律)/\`eap\`(输出标准)。
|
|
10936
|
+
🔴 **身份块(\`=== Serenity ACC ===\`)不可替换** —— 它回答"我在哪儿工作",不是"按什么章法工作";
|
|
10937
|
+
写进去会被丢弃并指名告警。
|
|
10938
|
+
|
|
10939
|
+
🔴 **两条硬前提**(缺一即**降级回 append** 并告警,绝不静默):
|
|
10940
|
+
① \`replace\` 需要**真的有一份 \`PROMPT.md\`** —— 没有替代物的替换 = 静默清空纪律;
|
|
10941
|
+
② \`append\` 下写 \`replaces\` 不生效(会告诉你,别以为它管用)。
|
|
10942
|
+
|
|
10943
|
+
⚠️ 想表达"我一块都不想换" ⇒ 写 \`"replaces": []\`(显式空数组),它**不等于**不写(不写 = 四块全换)。`,
|
|
10895
10944
|
"",
|
|
10896
10945
|
`── 常驻:自己声明"欢迎别人来麻烦我"(trajectory.json 的 resident 字段)──
|
|
10897
10946
|
|
|
@@ -10927,9 +10976,11 @@ const TRAJECTORY_SELF_GUIDE = [
|
|
|
10927
10976
|
| \`model\` | 用会话当前的模型(**不会**回退到 cheap-worker) | **每轮**(改文件下一轮即生效) |
|
|
10928
10977
|
| \`tools\` | **不收窄**工具面 | 每轮 |
|
|
10929
10978
|
| \`msms\` | **不收窄** MSM 面 | 每轮 |
|
|
10979
|
+
| \`writes\` | **不收窄**写路径(写权限 = 路径守卫那几条) | 每轮 |
|
|
10930
10980
|
| \`resident\` | 不出现在常驻名单里(不参与"被找") | 每轮 |
|
|
10931
10981
|
| \`cognitiveTrajectory\` | 三项纪律全参与(true) | 每轮 |
|
|
10932
10982
|
| \`systemPromptFile\` / \`systemPrompt\` | 用 ACC 的通用身份(**不替换**) | 保存即生效 |
|
|
10983
|
+
| \`prompt\` | 追加模式:宁静号各块照常注入,章程排在它们之后 | **每轮**(改文件下一轮即生效) |
|
|
10933
10984
|
|
|
10934
10985
|
🔴 **"没写" 与 "写了空数组" 是两种意思**:
|
|
10935
10986
|
\`"tools": []\`(显式空数组)= **我一个都不给** ⇒ 除 \`skill\` 外全部工具被隐藏。
|
|
@@ -10937,8 +10988,10 @@ const TRAJECTORY_SELF_GUIDE = [
|
|
|
10937
10988
|
⇒ 想只声明常驻?那就**只写 resident**,别的键一个都不要写。
|
|
10938
10989
|
|
|
10939
10990
|
🔴 **写 \`trajectory.json\` 本身不改任何默认行为** —— 它只是"我把设定放这儿了"。
|
|
10940
|
-
只有当某个 key
|
|
10941
|
-
|
|
10991
|
+
只有当某个 key **真的取代了默认**时才改变装配,目前只有两处:
|
|
10992
|
+
① 自带章程 \`systemPromptFile\` / \`systemPrompt\`(取代 ACC 身份);
|
|
10993
|
+
② \`prompt.injection = "replace"\`(**只**取代四个约束块,**不动**身份块)。
|
|
10994
|
+
其余字段都不影响。`,
|
|
10942
10995
|
"",
|
|
10943
10996
|
`── 想限制自己(白名单 / 模型 / 纪律参与项)──
|
|
10944
10997
|
|
|
@@ -10947,7 +11000,9 @@ const TRAJECTORY_SELF_GUIDE = [
|
|
|
10947
11000
|
`── 写完之后怎么验(别只看文档,要能机械判定)──
|
|
10948
11001
|
|
|
10949
11002
|
章程生效了吗 改 PROMPT.md 后**在同一会话里**看下一轮的系统提示词段是否变化(保存即生效)
|
|
10950
|
-
|
|
11003
|
+
注入模式生效了吗 改 trajectory.json 的 prompt 段后,**同一会话下一轮**:replace 下四块消失、
|
|
11004
|
+
我的章程紧跟身份块;⛔ 不需要重启(这两者都是每轮现读)
|
|
11005
|
+
我声明了什么 container_admin config list —— 逐轨迹列出 model/tools/msms/writes 的**生效值**;
|
|
10951
11006
|
没写的字段印 \`(unchanged)\` / \`(unrestricted)\`,不是伪装成某个默认值
|
|
10952
11007
|
配置合法吗 container_admin config validate —— msms 均已注册 / model 在可用表里
|
|
10953
11008
|
常驻被看见了吗 cognitive_trajectory action=resident —— 我出现在名单里,且 serves 可读
|
|
@@ -11532,6 +11587,14 @@ function decideGuard(input) {
|
|
|
11532
11587
|
deny: "tool not allowed in this 轨迹约束 trajectory",
|
|
11533
11588
|
kind: "deny"
|
|
11534
11589
|
};
|
|
11590
|
+
const writeScopes = profileWriteWhitelist(profile);
|
|
11591
|
+
if (writeScopes !== null && pathArg !== void 0 && isWriteTool(toolName, action)) {
|
|
11592
|
+
const abs = resolve(root, pathArg);
|
|
11593
|
+
if (!writeScopes.some((scope) => pathInside(resolve(root, scope), abs))) return {
|
|
11594
|
+
deny: `${toolName}: write outside this trajectory's declared write scope (allowed: ${writeScopes.length > 0 ? writeScopes.join(" / ") : "(none — \"writes\" is an empty array)"}); target: ${pathArg} — add the prefix to this trajectory's trajectory.json "writes" if the write is intended`,
|
|
11595
|
+
kind: "deny"
|
|
11596
|
+
};
|
|
11597
|
+
}
|
|
11535
11598
|
}
|
|
11536
11599
|
if (safeModeOn && toolName === "bash") return {
|
|
11537
11600
|
deny: `bash: no such tool`,
|
|
@@ -14085,7 +14148,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
14085
14148
|
});
|
|
14086
14149
|
}
|
|
14087
14150
|
const { saveWeixinRoutes } = await import("./route-Dr0SFD8A.js").then((n) => n.c);
|
|
14088
|
-
const { findDirNameByCode } = await import("./profile-
|
|
14151
|
+
const { findDirNameByCode } = await import("./profile-CiRWh2a2.js").then((n) => n.i);
|
|
14089
14152
|
for (const r of routes) if (findDirNameByCode(root, r.trajectory) === null) {
|
|
14090
14153
|
sendJson$2(res, 400, { error: `unknown trajectory: ${r.trajectory} (no such trajectory code in ${root})` });
|
|
14091
14154
|
return;
|
|
@@ -19082,7 +19145,7 @@ const MEDIA_MAX_BYTES = 20971520;
|
|
|
19082
19145
|
*/
|
|
19083
19146
|
async function resolveCccRootByAlias(ctx, alias) {
|
|
19084
19147
|
try {
|
|
19085
|
-
const { listCccs } = await import("./ccc-roots-
|
|
19148
|
+
const { listCccs } = await import("./ccc-roots-4LwGLCXa.js").then((n) => n.a);
|
|
19086
19149
|
const entries = await listCccs(ctx);
|
|
19087
19150
|
const byName = entries.find((e) => e.name === alias);
|
|
19088
19151
|
if (byName) return byName.root;
|
|
@@ -19150,7 +19213,7 @@ async function resolveInboundTarget(ctx, input) {
|
|
|
19150
19213
|
});
|
|
19151
19214
|
return null;
|
|
19152
19215
|
}
|
|
19153
|
-
const { findDirNameByCode } = await import("./profile-
|
|
19216
|
+
const { findDirNameByCode } = await import("./profile-CiRWh2a2.js").then((n) => n.i);
|
|
19154
19217
|
if (findDirNameByCode(root, target.role) === null) {
|
|
19155
19218
|
const detail = `目标 CCC "${target.ccc}" 内没有编码为 "${target.role}" 的认知轨迹`;
|
|
19156
19219
|
console.error(`[serenity-hooks] ✗ human-channel: ${detail}(account=${input.account} user=${input.user})—— 该消息**未投递**,请改订阅表里的目标编码`);
|
|
@@ -19990,7 +20053,7 @@ function syncHumanChannel(ctx) {
|
|
|
19990
20053
|
(async () => {
|
|
19991
20054
|
try {
|
|
19992
20055
|
stopMachineLoops();
|
|
19993
|
-
const { listCccs } = await import("./ccc-roots-
|
|
20056
|
+
const { listCccs } = await import("./ccc-roots-4LwGLCXa.js").then((n) => n.a);
|
|
19994
20057
|
for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
|
|
19995
20058
|
} catch {}
|
|
19996
20059
|
})();
|
|
@@ -20254,7 +20317,7 @@ function matchCcc(input, candidates) {
|
|
|
20254
20317
|
}
|
|
20255
20318
|
/** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
|
|
20256
20319
|
async function collectCandidates(ctx) {
|
|
20257
|
-
const { listCccs } = await import("./ccc-roots-
|
|
20320
|
+
const { listCccs } = await import("./ccc-roots-4LwGLCXa.js").then((n) => n.a);
|
|
20258
20321
|
const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
|
|
20259
20322
|
const seen = /* @__PURE__ */ new Set();
|
|
20260
20323
|
const out = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as cccRootForCwd } from "./ccc-roots-
|
|
1
|
+
import { r as cccRootForCwd } from "./ccc-roots-4LwGLCXa.js";
|
|
2
2
|
import { _ as resolveInside, g as readUtf8 } from "./ccc-CyYJL4F2.js";
|
|
3
|
-
import { A as sessionEvents, E as parseTrajectoryCode, b as getActiveSessionInfo, j as sessionsRoot, x as getLastActiveSessionInfo } from "./profile-
|
|
3
|
+
import { A as sessionEvents, E as parseTrajectoryCode, b as getActiveSessionInfo, j as sessionsRoot, x as getLastActiveSessionInfo } from "./profile-CiRWh2a2.js";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -105,6 +105,28 @@ function profileToolWhitelist(profile) {
|
|
|
105
105
|
function profileMsmWhitelist(profile) {
|
|
106
106
|
return new Set(profile?.msms ?? []);
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* 该轨迹可**写**的路径前缀(owner 2026-10-20 令:「轨迹设定自己的写白名单」)。
|
|
110
|
+
*
|
|
111
|
+
* 🔴 与 `profileToolWhitelist` 共用同一条判据(D181/D183):**字段在不在,不是数组空不空**。
|
|
112
|
+
*
|
|
113
|
+
* | `writes` | 返回 | 语义 |
|
|
114
|
+
* |---|---|---|
|
|
115
|
+
* | 缺省 | **`null`** | 不收窄(写权限 = 路径守卫那几条,与今天一致) |
|
|
116
|
+
* | `[]` | `[]`(空数组) | **一个写都落不下**(显式意图) |
|
|
117
|
+
* | `['a/']` | `['a/']` | 写目标必须落在 `a/` 之内 |
|
|
118
|
+
*
|
|
119
|
+
* ⛔ **调用方不许把 `null` 当 `[]`** —— 那会把"我没想到这件事"读成"我不许写任何东西",
|
|
120
|
+
* 正是 S196 被静默锁死的形态(D179(b))。
|
|
121
|
+
*
|
|
122
|
+
* ⚠️ 返回的是**原始条目**(相对 CCC 根或绝对路径都可),解析成绝对路径由调用方按自己的 root 做 ——
|
|
123
|
+
* 本模块不持有 root(判据在 `seams/guards.ts`)。
|
|
124
|
+
*/
|
|
125
|
+
function profileWriteWhitelist(profile) {
|
|
126
|
+
if (!profile) return null;
|
|
127
|
+
if (profile.writes === void 0) return null;
|
|
128
|
+
return profile.writes;
|
|
129
|
+
}
|
|
108
130
|
/** 轨迹纪律参与项(`profile` 缺省已在 `readTrajectoryConstraintAt` 归一为全 true) */
|
|
109
131
|
function constraintCognitiveTrajectory(profile) {
|
|
110
132
|
return {
|
|
@@ -799,4 +821,4 @@ const ACC_MESSAGE_KIND = "plugin:dsh-serenity-hooks";
|
|
|
799
821
|
/** ACC 注入消息的统一来源值(各缝共用;需要 `form` 时按 `ContextFormed` 另加字段)。 */
|
|
800
822
|
const PLUGIN_SOURCE = { kind: ACC_MESSAGE_KIND };
|
|
801
823
|
//#endregion
|
|
802
|
-
export {
|
|
824
|
+
export { resolveConstraintSystemPrompt as _, listBoundSessionIds as a, setBindingStore as c, constraintCognitiveTrajectory as d, constraintSystemPromptSource as f, profileWriteWhitelist as g, profileToolWhitelist as h, carrierState as i, TRAJECTORY_CONSTRAINT_HINT as l, profileMsmWhitelist as m, PLUGIN_SOURCE as n, readLastBound as o, createProfilePromptReader as p, appendBound as r, resolveSessionCognitiveTrajectoryLabel as s, ACC_MESSAGE_KIND as t, buildTrajectoryBasePrompt as u, ACC_VERSION as v, findPackageRoot as y };
|
|
@@ -1078,6 +1078,19 @@ function readTrajectoryConstraintAt(trajectoryDir, root) {
|
|
|
1078
1078
|
}
|
|
1079
1079
|
const tools = strListMaybe(obj.tools);
|
|
1080
1080
|
const msms = strListMaybe(obj.msms);
|
|
1081
|
+
const writes = strListMaybe(obj.writes);
|
|
1082
|
+
/**
|
|
1083
|
+
* 提示词注入模式(owner 2026-10-20):只搬运,不判决。
|
|
1084
|
+
*
|
|
1085
|
+
* 🔴 判决在 `planPromptInjection()` —— 那里有唯一的合法性表与降级规则。
|
|
1086
|
+
* 这里若也判一次(比如把未知值归一成 append),就会有两处真相:
|
|
1087
|
+
* 一处静默改值、一处告警,读数是矛盾的(D151 同族)。
|
|
1088
|
+
*/
|
|
1089
|
+
const promptRaw = obj.prompt;
|
|
1090
|
+
const prompt = promptRaw !== null && typeof promptRaw === "object" && !Array.isArray(promptRaw) ? {
|
|
1091
|
+
...typeof promptRaw.injection === "string" ? { injection: promptRaw.injection } : {},
|
|
1092
|
+
...strListMaybe(promptRaw.replaces) !== void 0 ? { replaces: strListMaybe(promptRaw.replaces) } : {}
|
|
1093
|
+
} : void 0;
|
|
1081
1094
|
return {
|
|
1082
1095
|
dirName,
|
|
1083
1096
|
code,
|
|
@@ -1085,7 +1098,9 @@ function readTrajectoryConstraintAt(trajectoryDir, root) {
|
|
|
1085
1098
|
...model !== void 0 ? { model } : {},
|
|
1086
1099
|
...tools !== void 0 ? { tools } : {},
|
|
1087
1100
|
...msms !== void 0 ? { msms } : {},
|
|
1101
|
+
...writes !== void 0 ? { writes } : {},
|
|
1088
1102
|
...resident !== void 0 ? { resident } : {},
|
|
1103
|
+
...prompt !== void 0 ? { prompt } : {},
|
|
1089
1104
|
cognitiveTrajectory: {
|
|
1090
1105
|
session: boolOrTrue(ct.session),
|
|
1091
1106
|
keeper: boolOrTrue(ct.keeper),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { n as agentCwdFor, r as cccRootForCwd, s as hostAgents } from "./ccc-roots-
|
|
1
|
+
import { n as agentCwdFor, r as cccRootForCwd, s as hostAgents } from "./ccc-roots-4LwGLCXa.js";
|
|
2
2
|
import { g as readUtf8, o as isSafeModeOn, p as readCognitiveTrajectorySkills, u as readBlacklist } from "./ccc-CyYJL4F2.js";
|
|
3
|
-
import { B as isoLocal, D as readActiveSessionMd, a as readTrajectoryConstraintAt, c as trajectoryConstraintForSession, d as unregisterTrajectorySession$1, j as sessionsRoot, l as registerTrajectorySession$1, p as DEFAULT_SESSION_SCOPE, u as trajectoryDirNameForSession } from "./profile-
|
|
3
|
+
import { B as isoLocal, D as readActiveSessionMd, a as readTrajectoryConstraintAt, c as trajectoryConstraintForSession, d as unregisterTrajectorySession$1, j as sessionsRoot, l as registerTrajectorySession$1, p as DEFAULT_SESSION_SCOPE, u as trajectoryDirNameForSession } from "./profile-CiRWh2a2.js";
|
|
4
4
|
import { a as readGitTrack, i as localstorePath } from "./service-DDmHSglV.js";
|
|
5
|
-
import {
|
|
5
|
+
import { d as constraintCognitiveTrajectory, m as profileMsmWhitelist, n as PLUGIN_SOURCE, o as readLastBound, p as createProfilePromptReader, u as buildTrajectoryBasePrompt, v as ACC_VERSION } from "./message-source-CfqdGIi2.js";
|
|
6
6
|
import { basename, dirname, join, resolve } from "node:path";
|
|
7
7
|
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
@@ -1379,6 +1379,110 @@ function applyWirePatch(wire) {
|
|
|
1379
1379
|
return updateAdvancedSettings(patch);
|
|
1380
1380
|
}
|
|
1381
1381
|
//#endregion
|
|
1382
|
+
//#region src/trajectory/prompt-injection.ts
|
|
1383
|
+
/**
|
|
1384
|
+
* trajectory/prompt-injection.ts — **轨迹提示词的注入模式**(owner 2026-10-20 令)
|
|
1385
|
+
*
|
|
1386
|
+
* ## owner 的原话与动机(本模块的全部设计依据)
|
|
1387
|
+
*
|
|
1388
|
+
* > 「某条角色轨迹目前工作起来,容易多做多想,主要原因我认为还是宁静号原本的提示词注入导致的,
|
|
1389
|
+
* > 所以我认为轨迹提示词的设定要容许更高的复杂度,轨迹自身的配置里要有提示词注入选项:
|
|
1390
|
+
* > **默认追加**,可以设定为**替换宁静号系统提示词的约束部分**;同时要确认
|
|
1391
|
+
* > 对该提示词和设定的修改可以**热生效**。」
|
|
1392
|
+
*
|
|
1393
|
+
* ## 两个模式(判据只有这两个,别再开第三个)
|
|
1394
|
+
*
|
|
1395
|
+
* | 模式 | 行为 |
|
|
1396
|
+
* |---|---|
|
|
1397
|
+
* | `append`(**缺省**) | 容器与质量各块照常注入,轨迹提示词**追加**在第 ⑧ 位 —— 这是 2026-10-19 起的既有行为,**不变** |
|
|
1398
|
+
* | `replace` | 轨迹提示词**取代**指定的「约束块」,并站到它们原来的位置上(紧跟 ACC 身份) |
|
|
1399
|
+
*
|
|
1400
|
+
* ## 🔴 可替换的块 = 四个「约束块」,**身份块永不在列**
|
|
1401
|
+
*
|
|
1402
|
+
* `metaphor`(世界模型)/`principles`(信念与边界)/`cce`(连续性纪律)/`eap`(输出质量标准)。
|
|
1403
|
+
* **`identity`(`=== Serenity ACC ===`)刻意不可替换**:它回答的是"这条轨迹在哪里工作",
|
|
1404
|
+
* 不是"按什么章法工作";把它换掉会让同一个容器里的轨迹**彼此不再共享同一套边界**,
|
|
1405
|
+
* 而那正是 §5.9b 四层模型里"容器层永不可覆盖"那一条要保的东西。
|
|
1406
|
+
* ⚠️ 若以后确实要开放身份块,那是一次**标准级**决定(specs §5.9b),不是加个字符串。
|
|
1407
|
+
*
|
|
1408
|
+
* ## 三条失败语义(都**响亮**,不静默降级)
|
|
1409
|
+
*
|
|
1410
|
+
* 1. **未知块名** ⇒ 丢弃该项并指名("教一个会静默不生效的写法"是最坏的一类文档债)。
|
|
1411
|
+
* 2. **`replace` 但没有轨迹提示词** ⇒ **不执行替换**,按 `append` 走并告警 ——
|
|
1412
|
+
* 「替换」需要一个替代物;没有替代物的替换 = **静默清空纪律**,那不是本选项的意思。
|
|
1413
|
+
* 3. **`append` 却写了 `replaces`** ⇒ `replaces` 不生效并告警(同上:不教空头写法)。
|
|
1414
|
+
*
|
|
1415
|
+
* 本模块是**纯函数**(不读盘、不打日志):读盘在调用方(`seams/system-prompt.ts`),
|
|
1416
|
+
* 日志也由调用方按 `problems` 打 —— 这样判据可单测,且告警去重只在一个地方。
|
|
1417
|
+
*/
|
|
1418
|
+
/** 注入模式的闭集(**新增模式 = 改标准**,不是加一个字符串值) */
|
|
1419
|
+
const PROMPT_INJECTION_MODES = ["append", "replace"];
|
|
1420
|
+
/**
|
|
1421
|
+
* 可被轨迹提示词取代的块(**有意排除 `identity`**,见文件头)。
|
|
1422
|
+
*
|
|
1423
|
+
* ⚠️ 这些 id 必须与 `seams/system-prompt.ts` 里实际的块一一对应;
|
|
1424
|
+
* 改块名/加块时**同批改这里**,否则本选项会静默失配(D143 同族)。
|
|
1425
|
+
*/
|
|
1426
|
+
const REPLACEABLE_PROMPT_BLOCKS = [
|
|
1427
|
+
"metaphor",
|
|
1428
|
+
"principles",
|
|
1429
|
+
"cce",
|
|
1430
|
+
"eap"
|
|
1431
|
+
];
|
|
1432
|
+
const DEFAULT_PLAN = {
|
|
1433
|
+
mode: "append",
|
|
1434
|
+
replaces: /* @__PURE__ */ new Set(),
|
|
1435
|
+
promptPosition: "late",
|
|
1436
|
+
problems: []
|
|
1437
|
+
};
|
|
1438
|
+
/**
|
|
1439
|
+
* 判决一次注入(纯函数)。
|
|
1440
|
+
*
|
|
1441
|
+
* @param raw `trajectory.json` 的 `prompt` 段(原样;`undefined` = 没写 = 缺省追加)
|
|
1442
|
+
* @param hasTrajectoryPrompt 该轨迹目录里**是否真有** `PROMPT.md`(调用方查,本函数不做 IO)
|
|
1443
|
+
*/
|
|
1444
|
+
function planPromptInjection(raw, hasTrajectoryPrompt) {
|
|
1445
|
+
if (raw === void 0) return DEFAULT_PLAN;
|
|
1446
|
+
const problems = [];
|
|
1447
|
+
const declared = typeof raw.injection === "string" ? raw.injection.trim() : "";
|
|
1448
|
+
if (declared !== "" && !PROMPT_INJECTION_MODES.includes(declared)) {
|
|
1449
|
+
problems.push(`prompt.injection 的取值「${declared}」不是合法模式(只有 ${PROMPT_INJECTION_MODES.join(" / ")})⇒ 按 append 处理`);
|
|
1450
|
+
return {
|
|
1451
|
+
...DEFAULT_PLAN,
|
|
1452
|
+
problems
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
if ((declared === "replace" ? "replace" : "append") === "append") {
|
|
1456
|
+
if (raw.replaces !== void 0) problems.push("prompt.replaces 只在 injection=\"replace\" 下生效(当前是 append)⇒ 已忽略");
|
|
1457
|
+
return {
|
|
1458
|
+
...DEFAULT_PLAN,
|
|
1459
|
+
problems
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
if (!hasTrajectoryPrompt) {
|
|
1463
|
+
problems.push("prompt.injection=\"replace\" 但轨迹目录里没有 PROMPT.md ⇒ 不执行替换(按 append 处理):替换需要一个替代物,否则就是静默清空纪律");
|
|
1464
|
+
return {
|
|
1465
|
+
...DEFAULT_PLAN,
|
|
1466
|
+
problems
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
const wanted = raw.replaces;
|
|
1470
|
+
let picked;
|
|
1471
|
+
if (wanted === void 0) picked = [...REPLACEABLE_PROMPT_BLOCKS];
|
|
1472
|
+
else {
|
|
1473
|
+
const invalid = wanted.filter((n) => !REPLACEABLE_PROMPT_BLOCKS.includes(n));
|
|
1474
|
+
if (invalid.length > 0) problems.push(`prompt.replaces 含不可替换的块名:${invalid.join(" / ")}(可替换的只有 ${REPLACEABLE_PROMPT_BLOCKS.join(" / ")};身份块 identity 刻意不可替换)⇒ 已忽略这些项`);
|
|
1475
|
+
picked = wanted.filter((n) => REPLACEABLE_PROMPT_BLOCKS.includes(n));
|
|
1476
|
+
}
|
|
1477
|
+
const replaces = new Set(picked);
|
|
1478
|
+
return {
|
|
1479
|
+
mode: "replace",
|
|
1480
|
+
replaces,
|
|
1481
|
+
promptPosition: replaces.size === 0 ? "late" : "constraint",
|
|
1482
|
+
problems
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
//#endregion
|
|
1382
1486
|
//#region src/seams/system-prompt.ts
|
|
1383
1487
|
/** 读取 persona 彩蛋配置(plugin 全局;未配置 → mode='' 彩蛋关闭) */
|
|
1384
1488
|
function readPersonaSettings() {
|
|
@@ -1805,13 +1909,15 @@ function sessionBlock(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
|
1805
1909
|
function serenitySystemPrompt(root, scope = DEFAULT_SESSION_SCOPE, dirName) {
|
|
1806
1910
|
const persona = readPersonaSettings();
|
|
1807
1911
|
const personaOn = persona.mode !== "" && persona.overrideText.trim() !== "";
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1912
|
+
const trajReader = dirName === void 0 ? null : createTrajectoryPromptReader(root, dirName);
|
|
1913
|
+
const trajPrompt = trajReader === null ? "" : trajectoryPromptBlock(trajReader());
|
|
1914
|
+
const plan = planInjectionFor(root, dirName, trajPrompt !== "");
|
|
1915
|
+
const parts = [identityBlock(root)];
|
|
1916
|
+
if (plan.promptPosition === "constraint" && trajPrompt !== "") parts.push(trajPrompt);
|
|
1917
|
+
if (!plan.replaces.has("metaphor")) parts.push(metaphorBlock());
|
|
1918
|
+
if (!plan.replaces.has("principles")) parts.push(principlesBlock(root, personaOn));
|
|
1919
|
+
if (!plan.replaces.has("cce")) parts.push(cceBlock());
|
|
1920
|
+
if (!plan.replaces.has("eap")) parts.push(eapBlock());
|
|
1815
1921
|
if (personaOn) {
|
|
1816
1922
|
const expr = personaBlock(persona.mode, persona.overrideText);
|
|
1817
1923
|
if (expr !== "") parts.push(expr);
|
|
@@ -1820,14 +1926,45 @@ function serenitySystemPrompt(root, scope = DEFAULT_SESSION_SCOPE, dirName) {
|
|
|
1820
1926
|
if (state) parts.push(state);
|
|
1821
1927
|
const skill = entrySkillSectionText(root);
|
|
1822
1928
|
if (skill) parts.push(skill);
|
|
1823
|
-
|
|
1824
|
-
if (trajPrompt !== "") parts.push(trajPrompt);
|
|
1929
|
+
if (plan.promptPosition === "late" && trajPrompt !== "") parts.push(trajPrompt);
|
|
1825
1930
|
parts.push(toolsBlock());
|
|
1826
1931
|
const session = sessionBlock(root, scope);
|
|
1827
1932
|
if (session) parts.push(session);
|
|
1828
1933
|
return parts.join("\n\n");
|
|
1829
1934
|
}
|
|
1830
1935
|
/**
|
|
1936
|
+
* 解析该轨迹的**注入判决**(每次装配现读;坏设定只告警一次,不阻断装配)。
|
|
1937
|
+
*
|
|
1938
|
+
* 🔴 为什么热路径可以读盘:`trajectory.json` 是**每轮都要读**的本来就有的东西
|
|
1939
|
+
* (工具白名单 / model / resident 都走同一条读取路径),多读一次不会改变复杂度量级;
|
|
1940
|
+
* 而**缓存**会让"改了设定但没生效"重新变成一个只能靠重启解释的现象 ——
|
|
1941
|
+
* owner 这次的原话里明确要求「对提示词和设定的修改可以热生效」。
|
|
1942
|
+
*
|
|
1943
|
+
* @param root CCC 根
|
|
1944
|
+
* @param dirName 绑定的轨迹目录名(`undefined` ⇒ 追加模式,无轨迹上下文)
|
|
1945
|
+
* @param hasTrajectoryPrompt 该轨迹目录里是否真有 `PROMPT.md`(`replace` 的前提)
|
|
1946
|
+
*/
|
|
1947
|
+
function planInjectionFor(root, dirName, hasTrajectoryPrompt) {
|
|
1948
|
+
if (dirName === void 0) return planPromptInjection(void 0, false);
|
|
1949
|
+
let raw;
|
|
1950
|
+
try {
|
|
1951
|
+
raw = readTrajectoryConstraintAt(join(sessionsRoot(root), dirName), root)?.prompt;
|
|
1952
|
+
} catch {
|
|
1953
|
+
raw = void 0;
|
|
1954
|
+
}
|
|
1955
|
+
const plan = planPromptInjection(raw, hasTrajectoryPrompt);
|
|
1956
|
+
for (const p of plan.problems) {
|
|
1957
|
+
const key = `${root}\u0000${dirName}\u0000${p}`;
|
|
1958
|
+
if (!warnedPromptInjection.has(key)) {
|
|
1959
|
+
warnedPromptInjection.add(key);
|
|
1960
|
+
console.warn(`[serenity-hooks] ✗ 轨迹提示词注入设定(${dirName}):${p}`);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return plan;
|
|
1964
|
+
}
|
|
1965
|
+
/** 同一(CCC × 轨迹 × 原因)只告警一次:每轮装配都执行,不去重会刷屏(但**不静默**) */
|
|
1966
|
+
const warnedPromptInjection = /* @__PURE__ */ new Set();
|
|
1967
|
+
/**
|
|
1831
1968
|
* Code Mode 适配行:当前 scope 以 Code Mode 呈现工具时(run_code 可见),
|
|
1832
1969
|
* ACC 块按 native 语义指引"直接调用工具"会与"只有 run_code 可直接调用"的执行
|
|
1833
1970
|
* 塌缩冲突(模型直呼工具名 → UNKNOWN_TOOL,拒绝信息误导)。追加一行说明,
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* ⚠️ **文件名 `profile` 与 `trajectory-constraint.json` / `TrajectoryConstraint` 等符号名一律不动**:
|
|
32
32
|
* 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
|
|
33
33
|
*/
|
|
34
|
+
import type { RawPromptInjection } from '../prompt-injection.js';
|
|
34
35
|
/**
|
|
35
36
|
* 🆕 **声明文件的文件名**(2026-10-19 owner 裁 Q2:短名 `trajectory.json`)。
|
|
36
37
|
*
|
|
@@ -66,6 +67,20 @@ export interface TrajectoryConstraint {
|
|
|
66
67
|
tools?: string[];
|
|
67
68
|
/** MSM 白名单;缺省/空数组语义同 `tools`(D181) */
|
|
68
69
|
msms?: string[];
|
|
70
|
+
/**
|
|
71
|
+
* **写路径白名单**(owner 2026-10-20 令:「ACC 如果支持轨迹设定自己的写白名单就好了」)。
|
|
72
|
+
*
|
|
73
|
+
* `tools` 只管**工具名**,管不了"这个工具能写哪儿"——一旦给了 `write`,路径守卫只拦
|
|
74
|
+
* "逃出 CCC"与黑名单,**拦不住它去写别人的轨迹或 `docs/`**。本字段补的就是这一维。
|
|
75
|
+
*
|
|
76
|
+
* 🔴 判据与 D181 同一条:**字段在不在,不是数组空不空**。
|
|
77
|
+
* - 缺省(`undefined`)⇒ **不收窄**(写权限 = 路径守卫那几条);
|
|
78
|
+
* - `[]` ⇒ **一个写都落不下**(显式意图,不告警);
|
|
79
|
+
* - 非空 ⇒ 写类工具的**目标路径**必须落在这些前缀内(相对 CCC 根,或其绝对路径)。
|
|
80
|
+
*
|
|
81
|
+
* 只约束**写类**工具(`write`/`edit`/`container_fs` 写动作/`append`/`touch`);读不受影响。
|
|
82
|
+
*/
|
|
83
|
+
writes?: string[];
|
|
69
84
|
/** 轨迹纪律参与项(**缺省全 true**,见上方 R↓) */
|
|
70
85
|
cognitiveTrajectory: {
|
|
71
86
|
session: boolean;
|
|
@@ -86,6 +101,18 @@ export interface TrajectoryConstraint {
|
|
|
86
101
|
resident?: {
|
|
87
102
|
serves?: string;
|
|
88
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* **提示词注入模式**(owner 2026-10-20 令)—— 轨迹提示词**怎么**进入系统提示词。
|
|
106
|
+
*
|
|
107
|
+
* - 缺省(字段不写)⇒ `append`:容器与质量各块照常注入,轨迹提示词追加在第 ⑧ 位。
|
|
108
|
+
* - `{ "injection": "replace", "replaces": [...] }` ⇒ 轨迹提示词**取代**指定的约束块
|
|
109
|
+
* (`metaphor` / `principles` / `cce` / `eap`;缺省全换),并站到它们的原位上。
|
|
110
|
+
* **身份块(`=== Serenity ACC ===`)刻意不可替换** —— 判据见 `trajectory/prompt-injection.ts`。
|
|
111
|
+
*
|
|
112
|
+
* ⚠️ 本字段**只搬运值**,合法性与降级判决在 `planPromptInjection()`(纯函数、可单测);
|
|
113
|
+
* 两份实现会让"文件里写的"与"实际生效的"分叉。
|
|
114
|
+
*/
|
|
115
|
+
prompt?: RawPromptInjection;
|
|
89
116
|
}
|
|
90
117
|
/**
|
|
91
118
|
* 读一个目录下的 `trajectory-constraint.json`(**纯读,不施加约束**)。
|
|
@@ -45,6 +45,24 @@ export declare const TRAJECTORY_CONSTRAINT_HINT = "systemPromptFile hot-reloads
|
|
|
45
45
|
export declare function profileToolWhitelist(profile: TrajectoryConstraint | null | undefined): Set<string> | null;
|
|
46
46
|
/** 该轨迹会话可 exec 的 MSM 白名单(`msm` 工具内部再过滤;独立于工具白名单) */
|
|
47
47
|
export declare function profileMsmWhitelist(profile: TrajectoryConstraint | null | undefined): Set<string>;
|
|
48
|
+
/**
|
|
49
|
+
* 该轨迹可**写**的路径前缀(owner 2026-10-20 令:「轨迹设定自己的写白名单」)。
|
|
50
|
+
*
|
|
51
|
+
* 🔴 与 `profileToolWhitelist` 共用同一条判据(D181/D183):**字段在不在,不是数组空不空**。
|
|
52
|
+
*
|
|
53
|
+
* | `writes` | 返回 | 语义 |
|
|
54
|
+
* |---|---|---|
|
|
55
|
+
* | 缺省 | **`null`** | 不收窄(写权限 = 路径守卫那几条,与今天一致) |
|
|
56
|
+
* | `[]` | `[]`(空数组) | **一个写都落不下**(显式意图) |
|
|
57
|
+
* | `['a/']` | `['a/']` | 写目标必须落在 `a/` 之内 |
|
|
58
|
+
*
|
|
59
|
+
* ⛔ **调用方不许把 `null` 当 `[]`** —— 那会把"我没想到这件事"读成"我不许写任何东西",
|
|
60
|
+
* 正是 S196 被静默锁死的形态(D179(b))。
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ 返回的是**原始条目**(相对 CCC 根或绝对路径都可),解析成绝对路径由调用方按自己的 root 做 ——
|
|
63
|
+
* 本模块不持有 root(判据在 `seams/guards.ts`)。
|
|
64
|
+
*/
|
|
65
|
+
export declare function profileWriteWhitelist(profile: TrajectoryConstraint | null | undefined): string[] | null;
|
|
48
66
|
/** 轨迹纪律参与项(`profile` 缺省已在 `readTrajectoryConstraintAt` 归一为全 true) */
|
|
49
67
|
export declare function constraintCognitiveTrajectory(profile: TrajectoryConstraint | null | undefined): {
|
|
50
68
|
session: boolean;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trajectory/prompt-injection.ts — **轨迹提示词的注入模式**(owner 2026-10-20 令)
|
|
3
|
+
*
|
|
4
|
+
* ## owner 的原话与动机(本模块的全部设计依据)
|
|
5
|
+
*
|
|
6
|
+
* > 「某条角色轨迹目前工作起来,容易多做多想,主要原因我认为还是宁静号原本的提示词注入导致的,
|
|
7
|
+
* > 所以我认为轨迹提示词的设定要容许更高的复杂度,轨迹自身的配置里要有提示词注入选项:
|
|
8
|
+
* > **默认追加**,可以设定为**替换宁静号系统提示词的约束部分**;同时要确认
|
|
9
|
+
* > 对该提示词和设定的修改可以**热生效**。」
|
|
10
|
+
*
|
|
11
|
+
* ## 两个模式(判据只有这两个,别再开第三个)
|
|
12
|
+
*
|
|
13
|
+
* | 模式 | 行为 |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | `append`(**缺省**) | 容器与质量各块照常注入,轨迹提示词**追加**在第 ⑧ 位 —— 这是 2026-10-19 起的既有行为,**不变** |
|
|
16
|
+
* | `replace` | 轨迹提示词**取代**指定的「约束块」,并站到它们原来的位置上(紧跟 ACC 身份) |
|
|
17
|
+
*
|
|
18
|
+
* ## 🔴 可替换的块 = 四个「约束块」,**身份块永不在列**
|
|
19
|
+
*
|
|
20
|
+
* `metaphor`(世界模型)/`principles`(信念与边界)/`cce`(连续性纪律)/`eap`(输出质量标准)。
|
|
21
|
+
* **`identity`(`=== Serenity ACC ===`)刻意不可替换**:它回答的是"这条轨迹在哪里工作",
|
|
22
|
+
* 不是"按什么章法工作";把它换掉会让同一个容器里的轨迹**彼此不再共享同一套边界**,
|
|
23
|
+
* 而那正是 §5.9b 四层模型里"容器层永不可覆盖"那一条要保的东西。
|
|
24
|
+
* ⚠️ 若以后确实要开放身份块,那是一次**标准级**决定(specs §5.9b),不是加个字符串。
|
|
25
|
+
*
|
|
26
|
+
* ## 三条失败语义(都**响亮**,不静默降级)
|
|
27
|
+
*
|
|
28
|
+
* 1. **未知块名** ⇒ 丢弃该项并指名("教一个会静默不生效的写法"是最坏的一类文档债)。
|
|
29
|
+
* 2. **`replace` 但没有轨迹提示词** ⇒ **不执行替换**,按 `append` 走并告警 ——
|
|
30
|
+
* 「替换」需要一个替代物;没有替代物的替换 = **静默清空纪律**,那不是本选项的意思。
|
|
31
|
+
* 3. **`append` 却写了 `replaces`** ⇒ `replaces` 不生效并告警(同上:不教空头写法)。
|
|
32
|
+
*
|
|
33
|
+
* 本模块是**纯函数**(不读盘、不打日志):读盘在调用方(`seams/system-prompt.ts`),
|
|
34
|
+
* 日志也由调用方按 `problems` 打 —— 这样判据可单测,且告警去重只在一个地方。
|
|
35
|
+
*/
|
|
36
|
+
/** 注入模式的闭集(**新增模式 = 改标准**,不是加一个字符串值) */
|
|
37
|
+
export declare const PROMPT_INJECTION_MODES: readonly ["append", "replace"];
|
|
38
|
+
export type PromptInjectionMode = (typeof PROMPT_INJECTION_MODES)[number];
|
|
39
|
+
/**
|
|
40
|
+
* 可被轨迹提示词取代的块(**有意排除 `identity`**,见文件头)。
|
|
41
|
+
*
|
|
42
|
+
* ⚠️ 这些 id 必须与 `seams/system-prompt.ts` 里实际的块一一对应;
|
|
43
|
+
* 改块名/加块时**同批改这里**,否则本选项会静默失配(D143 同族)。
|
|
44
|
+
*/
|
|
45
|
+
export declare const REPLACEABLE_PROMPT_BLOCKS: readonly ["metaphor", "principles", "cce", "eap"];
|
|
46
|
+
export type ReplaceablePromptBlock = (typeof REPLACEABLE_PROMPT_BLOCKS)[number];
|
|
47
|
+
/** `trajectory.json` 里 `prompt` 段的**原始**形态(校验在本模块做,profile 只管搬运) */
|
|
48
|
+
export interface RawPromptInjection {
|
|
49
|
+
injection?: string;
|
|
50
|
+
replaces?: string[];
|
|
51
|
+
}
|
|
52
|
+
/** 一次装配要用的**判决**(纯数据;调用方据此决定注入哪些块、提示词放哪) */
|
|
53
|
+
export interface PromptInjectionPlan {
|
|
54
|
+
/** 实际生效的模式(`replace` 的前提不成立时会被降级成 `append`) */
|
|
55
|
+
mode: PromptInjectionMode;
|
|
56
|
+
/** `replace` 时**真正**被取代的块(`append` ⇒ 空集) */
|
|
57
|
+
replaces: ReadonlySet<ReplaceablePromptBlock>;
|
|
58
|
+
/**
|
|
59
|
+
* 轨迹提示词的位置:
|
|
60
|
+
* · `constraint` —— 站到被取代块的原位(紧跟身份)
|
|
61
|
+
* · `late` —— 第 ⑧ 位(追加形态,既有行为)
|
|
62
|
+
*/
|
|
63
|
+
promptPosition: 'constraint' | 'late';
|
|
64
|
+
/** 需要**响亮**告警的原因(空数组 = 一切正常)。调用方负责按轨迹去重后打日志 */
|
|
65
|
+
problems: string[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 判决一次注入(纯函数)。
|
|
69
|
+
*
|
|
70
|
+
* @param raw `trajectory.json` 的 `prompt` 段(原样;`undefined` = 没写 = 缺省追加)
|
|
71
|
+
* @param hasTrajectoryPrompt 该轨迹目录里**是否真有** `PROMPT.md`(调用方查,本函数不做 IO)
|
|
72
|
+
*/
|
|
73
|
+
export declare function planPromptInjection(raw: RawPromptInjection | undefined, hasTrajectoryPrompt: boolean): PromptInjectionPlan;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.81.0",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|