@shgroup/dsh-serenity-hooks 1.16.13 → 1.16.14
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 +76 -88
- 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.16.
|
|
3
|
+
"version": "1.16.14",
|
|
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
|
@@ -806,109 +806,93 @@ function showSession(root, key) {
|
|
|
806
806
|
};
|
|
807
807
|
}
|
|
808
808
|
/**
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* 读取不再回退(隔离优先;升级后重新 use 一次即可)。
|
|
809
|
+
* 活动会话跟踪(S134 v1.16.14 内存化,对齐 osp active-state):
|
|
810
|
+
* **不落盘**——活跃会话状态在内存 Map(key = scope = dsh 会话 id),避免落盘标记
|
|
811
|
+
* 文件累积与跨会话串台(落盘版 `.dsh/active-sessions/<scope>` 已被此方案取代)。
|
|
812
|
+
* 进程重启恢复:从**当前会话历史(events)**解析 `[SESSION CONTEXT]` 标记(use 时注入),
|
|
813
|
+
* 只扫自己会话——无全局扫描、无跨会话污染。
|
|
815
814
|
*/
|
|
816
|
-
const ACTIVE_SESSIONS_DIR = join(".dsh", "active-sessions");
|
|
817
|
-
/** 旧版全局标记路径(v1.16.1 及以前 use 写入;新版本仅清理不再读取) */
|
|
818
|
-
const LEGACY_ACTIVE_SESSION_MARKER = join(".dsh", "active-session");
|
|
819
|
-
/** 默认 scope(agent.session.id 缺失时) */
|
|
820
815
|
const DEFAULT_SESSION_SCOPE = "default";
|
|
821
|
-
/**
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
/** scope
|
|
826
|
-
|
|
827
|
-
|
|
816
|
+
/** [SESSION CONTEXT] 恢复标记(use 时注入 events 历史;进程重启后从 events 解析) */
|
|
817
|
+
const SESSION_CONTEXT_MARKER = "[SESSION CONTEXT] Activated:";
|
|
818
|
+
/** 内存活跃会话:scope(dsh 会话 id)→ 会话信息(不落盘;并行多会话各自 key 隔离) */
|
|
819
|
+
const activeStore = /* @__PURE__ */ new Map();
|
|
820
|
+
/** 全局最近活跃(对齐 osp lastActive;供无 scope 上下文使用) */
|
|
821
|
+
let lastActive = null;
|
|
822
|
+
function getActiveSessionInfo(scope) {
|
|
823
|
+
return activeStore.get(scope) ?? null;
|
|
824
|
+
}
|
|
825
|
+
function setActiveSessionInfo(scope, info) {
|
|
826
|
+
activeStore.set(scope, info);
|
|
827
|
+
lastActive = info;
|
|
828
|
+
}
|
|
829
|
+
function clearActiveSessionInfo(scope) {
|
|
830
|
+
activeStore.delete(scope);
|
|
831
|
+
if (lastActive && ![...activeStore.values()].some((v) => v === lastActive)) lastActive = null;
|
|
828
832
|
}
|
|
829
|
-
/**
|
|
833
|
+
/**
|
|
834
|
+
* 激活会话:写内存 Map(scope)+ 返回含 `[SESSION CONTEXT]` 标记的 context
|
|
835
|
+
* (标记随工具结果进 events 历史——进程重启后从当前会话 events 解析恢复,对齐 osp)。
|
|
836
|
+
*/
|
|
830
837
|
function useSession(root, key, scope = DEFAULT_SESSION_SCOPE) {
|
|
831
838
|
const target = findSession(root, key);
|
|
832
839
|
if (!target) throw new Error(`未找到会话: ${key}`);
|
|
833
840
|
const md = join(sessionsRoot(root), target.dir, "SESSION.md");
|
|
834
841
|
if (!existsSync(md)) throw new Error(`会话 ${target.dir} 缺少 SESSION.md`);
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
if (existsSync(legacy)) rmSync(legacy, { force: true });
|
|
841
|
-
return {
|
|
842
|
-
dir: target.dir,
|
|
842
|
+
const dirName = target.dir;
|
|
843
|
+
const idMatch = dirName.match(/S(\d{3,})/);
|
|
844
|
+
setActiveSessionInfo(scope, {
|
|
845
|
+
sessionId: idMatch ? `S${idMatch[1]}` : dirName,
|
|
846
|
+
dirName,
|
|
843
847
|
mdPath: md
|
|
848
|
+
});
|
|
849
|
+
return {
|
|
850
|
+
dir: dirName,
|
|
851
|
+
mdPath: md,
|
|
852
|
+
context: `${SESSION_CONTEXT_MARKER} ${dirName}\nSESSION.md path: ${md}`
|
|
844
853
|
};
|
|
845
854
|
}
|
|
846
|
-
/** 关闭活动会话:删除
|
|
855
|
+
/** 关闭活动会话:删除 scope 的内存条目(+ lastActive 修正)——不落盘,无文件残留 */
|
|
847
856
|
function closeSession(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
848
|
-
|
|
849
|
-
if (existsSync(marker)) rmSync(marker, { force: true });
|
|
850
|
-
const legacy = resolve(root, LEGACY_ACTIVE_SESSION_MARKER);
|
|
851
|
-
if (existsSync(legacy)) rmSync(legacy, { force: true });
|
|
857
|
+
clearActiveSessionInfo(scope);
|
|
852
858
|
return { dir: "active-session cleared" };
|
|
853
859
|
}
|
|
854
|
-
/** 读取指定 scope 的活跃会话 SESSION.md
|
|
860
|
+
/** 读取指定 scope 的活跃会话 SESSION.md 绝对路径;无激活返回 null(读内存,不落盘) */
|
|
855
861
|
function readActiveSessionMd(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
856
|
-
|
|
857
|
-
if (!existsSync(marker)) return null;
|
|
858
|
-
const rel = readFileSync(marker, "utf-8").trim();
|
|
859
|
-
if (!rel) return null;
|
|
860
|
-
const abs = resolve(root, rel);
|
|
861
|
-
if (!abs.startsWith(resolve(root))) return null;
|
|
862
|
-
return abs;
|
|
863
|
-
}
|
|
864
|
-
/** 列出全部 scope 的活动标记(含 scope / mdRel / mtime);目录不存在返回空 */
|
|
865
|
-
function listActiveMarkers(root) {
|
|
866
|
-
const dir = resolve(root, ACTIVE_SESSIONS_DIR);
|
|
867
|
-
if (!existsSync(dir)) return [];
|
|
868
|
-
const out = [];
|
|
869
|
-
for (const entry of readdirSync(dir)) {
|
|
870
|
-
const full = join(dir, entry);
|
|
871
|
-
if (!statSync(full).isFile()) continue;
|
|
872
|
-
try {
|
|
873
|
-
const rel = readFileSync(full, "utf-8").trim();
|
|
874
|
-
if (!rel) continue;
|
|
875
|
-
out.push({
|
|
876
|
-
scope: entry,
|
|
877
|
-
mdRel: rel,
|
|
878
|
-
mtime: statSync(full).mtimeMs
|
|
879
|
-
});
|
|
880
|
-
} catch {}
|
|
881
|
-
}
|
|
882
|
-
return out;
|
|
862
|
+
return getActiveSessionInfo(scope)?.mdPath ?? null;
|
|
883
863
|
}
|
|
884
864
|
/**
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
* 返回恢复的会话信息;已有标记 / 无候选 / 全部越界 → null。
|
|
888
|
-
* 调用方负责根会话判定(subagent / loop 牛马不恢复——见 context.ts shouldAutoRestore)。
|
|
865
|
+
* 从会话历史(events)解析最后一条 [SESSION CONTEXT] 标记(进程重启恢复;
|
|
866
|
+
* 只扫**当前会话**自己的历史——无跨会话串台)。
|
|
889
867
|
*/
|
|
890
|
-
function
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
868
|
+
function parseSessionContextFromEvents(events) {
|
|
869
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
870
|
+
const strs = [];
|
|
871
|
+
collectStrings(events[i], strs);
|
|
872
|
+
for (const s of strs) {
|
|
873
|
+
const idx = s.indexOf(SESSION_CONTEXT_MARKER);
|
|
874
|
+
if (idx < 0) continue;
|
|
875
|
+
const dirName = s.slice(idx + 28).trim().split("\n")[0]?.trim() ?? "";
|
|
876
|
+
const mdMatch = s.match(/SESSION\.md path:\s*(\S+)/);
|
|
877
|
+
if (/^\d{4}-\d{2}-\d{2}--/.test(dirName) && mdMatch) {
|
|
878
|
+
const idMatch = dirName.match(/S(\d{3,})/);
|
|
879
|
+
return {
|
|
880
|
+
sessionId: idMatch ? `S${idMatch[1]}` : dirName,
|
|
881
|
+
dirName,
|
|
882
|
+
mdPath: mdMatch[1]
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
/** 递归收集对象/数组/字符串中的全部字符串(保留原文,无 JSON 转义) */
|
|
890
|
+
function collectStrings(v, out) {
|
|
891
|
+
if (typeof v === "string") {
|
|
892
|
+
out.push(v);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (v && typeof v === "object") for (const val of Object.values(v)) collectStrings(val, out);
|
|
912
896
|
}
|
|
913
897
|
function archiveSession(root, key) {
|
|
914
898
|
const target = findSession(root, key);
|
|
@@ -3113,10 +3097,14 @@ function registerContext(ctx, opts = {}) {
|
|
|
3113
3097
|
if (!root) return;
|
|
3114
3098
|
const key = agentKey(agent);
|
|
3115
3099
|
registerEntrySkillSection(agent, root);
|
|
3116
|
-
|
|
3100
|
+
const scope = agentScope(agent);
|
|
3101
|
+
if (shouldRestoreActive(agent) && getActiveSessionInfo(scope) === null) try {
|
|
3117
3102
|
if (loadSerenityConfig(root, configPaths).hooks?.autoRestoreSession ?? true) {
|
|
3118
|
-
const
|
|
3119
|
-
if (
|
|
3103
|
+
const info = parseSessionContextFromEvents(agent.session.events ?? []);
|
|
3104
|
+
if (info) {
|
|
3105
|
+
setActiveSessionInfo(scope, info);
|
|
3106
|
+
console.log(`[serenity-hooks] ↻ 从历史恢复激活会话: ${info.dirName}`);
|
|
3107
|
+
}
|
|
3120
3108
|
}
|
|
3121
3109
|
} catch {}
|
|
3122
3110
|
if (injected.has(key)) return;
|
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.14",
|
|
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": {
|