@shgroup/dsh-serenity-hooks 1.28.1 → 1.29.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/client.js +281 -76
- package/lib/gateway-dsh-auth.d.ts +47 -0
- package/lib/gateway-proxy.d.ts +18 -1
- package/lib/gateway.d.ts +2 -2
- package/lib/index.js +284 -35
- package/lib/msm-ops.d.ts +1 -1
- package/lib/seams/keeper.d.ts +1 -1
- package/lib/seams/system-prompt.d.ts +4 -1
- package/lib/session-cleanup-PahSNvjI.js +113 -0
- package/lib/session-cleanup.d.ts +60 -0
- package/lib/trajectory-assistant.d.ts +54 -0
- package/package.json +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
//#region src/session-cleanup.ts
|
|
4
|
+
/**
|
|
5
|
+
* session-cleanup.ts — DSH 平台旧会话自动清理(v1.29,S142 需求③)
|
|
6
|
+
*
|
|
7
|
+
* 背景(实证):DSH 会话物理存储 = `$DSH_HOME/sessions/`(缺省 ~/.dsh/sessions;
|
|
8
|
+
* base bundle cordis.patch.yml root: dshHomePath('sessions'))。磁盘布局:
|
|
9
|
+
* <root>/--<project-slug>--/<encoded-session-id>/session.jsonl(.zstd)
|
|
10
|
+
* DSH **无删除会话 API**(PersistenceCoordinator 仅 create/append/load/inspect/borrow,
|
|
11
|
+
* 无 delete/purge;workspace archiveSession 只加归档集不删文件)——物理删除只能直接
|
|
12
|
+
* 删文件。删除后一致性(利好):sessionPersistence.list() = readdir 扫描磁盘现存 →
|
|
13
|
+
* 物理删后 list 不再返回;WorkspaceRegistry 下次启动重建 header index 自动消失。
|
|
14
|
+
*
|
|
15
|
+
* 方案(S142 用户拍板):lastActive 基准 + 手动触发 + 不过滤不归档直接物理删;
|
|
16
|
+
* 安全底线 = live 会话保护跳过(删正在运行的会话 = 灾难)。
|
|
17
|
+
*
|
|
18
|
+
* 本模块纯逻辑(零 ctx 依赖):传入 sessionsRoot + liveIds,可单测。
|
|
19
|
+
*/
|
|
20
|
+
/** DSH 会话 root:env DSH_HOME → ~/.dsh(config-ops globalConfigPath 同款推导) */
|
|
21
|
+
function sessionsRootDir() {
|
|
22
|
+
const dshHome = process.env.DSH_HOME ?? join(process.env.HOME ?? "", ".dsh");
|
|
23
|
+
return join(dshHome, "sessions");
|
|
24
|
+
}
|
|
25
|
+
/** 一天的毫秒数 */
|
|
26
|
+
const DAY_MS = 864e5;
|
|
27
|
+
/**
|
|
28
|
+
* 扫描 sessions root,列出可清理候选:
|
|
29
|
+
* - 递归 `<root>/<project>/<session-id>/session.jsonl(.zstd)`(任意深度下找 *session* 文件)
|
|
30
|
+
* - 过滤 live(liveIds 集合)——安全底线
|
|
31
|
+
* - 过滤 lastActive >= cutoffMs(最后活动未达阈值 → 保留)
|
|
32
|
+
* root 不存在/为空 → 返回 [](非错误)。
|
|
33
|
+
*/
|
|
34
|
+
function collectEligibleSessions(root, cutoffMs, liveIds = /* @__PURE__ */ new Set()) {
|
|
35
|
+
if (!existsSync(root)) return [];
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const project of readdirSync(root, { withFileTypes: true })) {
|
|
38
|
+
if (!project.isDirectory()) continue;
|
|
39
|
+
const projectPath = join(root, project.name);
|
|
40
|
+
for (const entry of readdirSync(projectPath, { withFileTypes: true })) {
|
|
41
|
+
if (!entry.isDirectory()) continue;
|
|
42
|
+
const log = findSessionLog(join(projectPath, entry.name));
|
|
43
|
+
if (log === null) continue;
|
|
44
|
+
if (liveIds.has(entry.name)) continue;
|
|
45
|
+
let mtime;
|
|
46
|
+
try {
|
|
47
|
+
mtime = statSync(log).mtimeMs;
|
|
48
|
+
} catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (mtime >= cutoffMs) continue;
|
|
52
|
+
out.push({
|
|
53
|
+
id: entry.name,
|
|
54
|
+
project: project.name,
|
|
55
|
+
logPath: log,
|
|
56
|
+
lastActiveMs: mtime
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** 在会话目录下找 session 日志文件(.jsonl / .jsonl.zstd);无 → null */
|
|
63
|
+
function findSessionLog(sessionDirPath) {
|
|
64
|
+
for (const name of ["session.jsonl", "session.jsonl.zstd"]) {
|
|
65
|
+
const p = join(sessionDirPath, name);
|
|
66
|
+
if (existsSync(p)) return p;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 执行清理(用户拍板:直接物理删,不过滤不归档;dryRun 预览不删)。
|
|
72
|
+
* 删除 = rmSync 整个会话目录(recursive + force)。失败逐个记 errors 不中断。
|
|
73
|
+
*/
|
|
74
|
+
function performCleanup(root, cutoffMs, liveIds = /* @__PURE__ */ new Set(), opts = {}) {
|
|
75
|
+
const candidates = collectEligibleSessions(root, cutoffMs, liveIds);
|
|
76
|
+
if (opts.dryRun) return {
|
|
77
|
+
candidates,
|
|
78
|
+
result: null
|
|
79
|
+
};
|
|
80
|
+
const result = {
|
|
81
|
+
deleted: [],
|
|
82
|
+
errors: []
|
|
83
|
+
};
|
|
84
|
+
for (const c of candidates) {
|
|
85
|
+
const dir = dirOf(c.logPath);
|
|
86
|
+
try {
|
|
87
|
+
rmSync(dir, {
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
});
|
|
91
|
+
result.deleted.push(c.id);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
result.errors.push({
|
|
94
|
+
id: c.id,
|
|
95
|
+
reason: e.message
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
candidates,
|
|
101
|
+
result
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** 从日志路径取会话目录(父目录) */
|
|
105
|
+
function dirOf(logPath) {
|
|
106
|
+
return logPath.slice(0, logPath.lastIndexOf("/")) || logPath;
|
|
107
|
+
}
|
|
108
|
+
/** 便捷:默认 N 天前为 cutoff(供 API/调用方) */
|
|
109
|
+
function cutoffDaysAgo(days, nowMs = Date.now()) {
|
|
110
|
+
return nowMs - days * DAY_MS;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { cutoffDaysAgo, performCleanup, sessionsRootDir };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-cleanup.ts — DSH 平台旧会话自动清理(v1.29,S142 需求③)
|
|
3
|
+
*
|
|
4
|
+
* 背景(实证):DSH 会话物理存储 = `$DSH_HOME/sessions/`(缺省 ~/.dsh/sessions;
|
|
5
|
+
* base bundle cordis.patch.yml root: dshHomePath('sessions'))。磁盘布局:
|
|
6
|
+
* <root>/--<project-slug>--/<encoded-session-id>/session.jsonl(.zstd)
|
|
7
|
+
* DSH **无删除会话 API**(PersistenceCoordinator 仅 create/append/load/inspect/borrow,
|
|
8
|
+
* 无 delete/purge;workspace archiveSession 只加归档集不删文件)——物理删除只能直接
|
|
9
|
+
* 删文件。删除后一致性(利好):sessionPersistence.list() = readdir 扫描磁盘现存 →
|
|
10
|
+
* 物理删后 list 不再返回;WorkspaceRegistry 下次启动重建 header index 自动消失。
|
|
11
|
+
*
|
|
12
|
+
* 方案(S142 用户拍板):lastActive 基准 + 手动触发 + 不过滤不归档直接物理删;
|
|
13
|
+
* 安全底线 = live 会话保护跳过(删正在运行的会话 = 灾难)。
|
|
14
|
+
*
|
|
15
|
+
* 本模块纯逻辑(零 ctx 依赖):传入 sessionsRoot + liveIds,可单测。
|
|
16
|
+
*/
|
|
17
|
+
/** DSH 会话 root:env DSH_HOME → ~/.dsh(config-ops globalConfigPath 同款推导) */
|
|
18
|
+
export declare function sessionsRootDir(): string;
|
|
19
|
+
/** 一个候选会话(删除前预览信息) */
|
|
20
|
+
export interface CandidateSession {
|
|
21
|
+
/** 会话 id(目录名) */
|
|
22
|
+
id: string;
|
|
23
|
+
/** 项目目录(父目录名,如 --home-yh-home-home-serenity--) */
|
|
24
|
+
project: string;
|
|
25
|
+
/** 会话日志文件绝对路径 */
|
|
26
|
+
logPath: string;
|
|
27
|
+
/** 最后活动(mtime 退化——日志只追加,mtime ≈ 最后写) */
|
|
28
|
+
lastActiveMs: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 扫描 sessions root,列出可清理候选:
|
|
32
|
+
* - 递归 `<root>/<project>/<session-id>/session.jsonl(.zstd)`(任意深度下找 *session* 文件)
|
|
33
|
+
* - 过滤 live(liveIds 集合)——安全底线
|
|
34
|
+
* - 过滤 lastActive >= cutoffMs(最后活动未达阈值 → 保留)
|
|
35
|
+
* root 不存在/为空 → 返回 [](非错误)。
|
|
36
|
+
*/
|
|
37
|
+
export declare function collectEligibleSessions(root: string, cutoffMs: number, liveIds?: ReadonlySet<string>): CandidateSession[];
|
|
38
|
+
/** 在会话目录下找 session 日志文件(.jsonl / .jsonl.zstd);无 → null */
|
|
39
|
+
export declare function findSessionLog(sessionDirPath: string): string | null;
|
|
40
|
+
/** 删除执行结果 */
|
|
41
|
+
export interface CleanupResult {
|
|
42
|
+
deleted: string[];
|
|
43
|
+
/** 尝试删除但失败的会话目录(权限/竞态) */
|
|
44
|
+
errors: Array<{
|
|
45
|
+
id: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 执行清理(用户拍板:直接物理删,不过滤不归档;dryRun 预览不删)。
|
|
51
|
+
* 删除 = rmSync 整个会话目录(recursive + force)。失败逐个记 errors 不中断。
|
|
52
|
+
*/
|
|
53
|
+
export declare function performCleanup(root: string, cutoffMs: number, liveIds?: ReadonlySet<string>, opts?: {
|
|
54
|
+
dryRun?: boolean;
|
|
55
|
+
}): {
|
|
56
|
+
candidates: CandidateSession[];
|
|
57
|
+
result: CleanupResult | null;
|
|
58
|
+
};
|
|
59
|
+
/** 便捷:默认 N 天前为 cutoff(供 API/调用方) */
|
|
60
|
+
export declare function cutoffDaysAgo(days: number, nowMs?: number): number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trajectory-assistant.ts — 关卡化注入的统一命名与风格门面(v0.3,S142)
|
|
3
|
+
*
|
|
4
|
+
* 概念(用户拍板 2026-09-05):dsp 全部"过程中动态提示注入"统一命名为
|
|
5
|
+
* trajectory-assistant(轨迹助航员)。关卡设计思想塑造**结构与时机**
|
|
6
|
+
* (何时/何地注入),**不用于提示词用词**(D8 词法原则)——纯游戏黑话
|
|
7
|
+
* (BOSS/XP/level-up)禁止出现在提示词文本;CHECKPOINT/LIMIT/TUTORIAL 等
|
|
8
|
+
* 跨领域自然通用词允许。
|
|
9
|
+
*
|
|
10
|
+
* 本模块 = token 常量 + level-event 词汇表的**单一真相源**(避免前缀散落
|
|
11
|
+
* 各文件字符串字面量)+ 风格门面(plain 默认 / metaphor 星舰变体)。
|
|
12
|
+
* 仅当 style=metaphor 时前缀包装措辞变化;可行动正文不变 → 零行为漂移。
|
|
13
|
+
*
|
|
14
|
+
* 设计简写(L0 环境 / L1 教程 / L2 目标 / L3 检查点 / L4 极限 / L5 守卫 /
|
|
15
|
+
* L6 结算)仅在本模块注释与内部文档出现,永不浮现在提示词文本。
|
|
16
|
+
*
|
|
17
|
+
* 结算(settlement)挂点:D6 用户拍板——若 CCC 有标准 SESSION 复盘仪式,
|
|
18
|
+
* 结算视图归 trajectory-assistant。当前 close/archive 无复盘摘要 → 机制
|
|
19
|
+
* 延后,仅留 onSettlement 导出 seam(OP-1,无调用者)。
|
|
20
|
+
*/
|
|
21
|
+
/** 可见提示词前缀用词(跨领域自然词,D8:无游戏黑话) */
|
|
22
|
+
export declare const EVENT_LABEL: {
|
|
23
|
+
/** 计分同步提醒(原 TRAJECTORY-STEWARD) */
|
|
24
|
+
readonly checkpoint: "CHECKPOINT";
|
|
25
|
+
/** 上下文极限重建提醒(原 TRAJECTORY;LIMIT 替代被否的 BOSS——自然词) */
|
|
26
|
+
readonly limit: "LIMIT";
|
|
27
|
+
/** 极限强制升级(原 TRAJECTORY-ESCALATED) */
|
|
28
|
+
readonly limitMandatory: "LIMIT · MANDATORY";
|
|
29
|
+
/** 重建锚点头部(原 TRAJECTORY-REBUILD) */
|
|
30
|
+
readonly rebuild: "REBUILD";
|
|
31
|
+
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
32
|
+
readonly guard: "BOUNDARY GUARD";
|
|
33
|
+
};
|
|
34
|
+
/** 家族标识(所有动态注入统一前缀) */
|
|
35
|
+
export declare const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
36
|
+
/** 完整 token:`[TRAJECTORY-ASSISTANT · <LABEL>]` */
|
|
37
|
+
export declare function eventToken(event: keyof typeof EVENT_LABEL): string;
|
|
38
|
+
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
39
|
+
export declare const ACK_PREFIX = "TRAJECTORY-ASSISTANT-recorded";
|
|
40
|
+
export declare const ACK_SKIP_PREFIX = "TRAJECTORY-ASSISTANT-skipped";
|
|
41
|
+
/** 风格档位:plain(默认,精确文本)/ metaphor(借星舰词——产品隐喻非游戏词) */
|
|
42
|
+
export type TrajectoryStyle = 'plain' | 'metaphor';
|
|
43
|
+
/**
|
|
44
|
+
* 按风格生成前缀 token。plain = eventToken()(原样);metaphor 仅当有
|
|
45
|
+
* 星舰化变体时替换用词(当前等价保留——星舰词库隐喻域的既有措辞即
|
|
46
|
+
* "context limit/deck check" 类,不强制替换;扩展点留给未来实验)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function styledToken(event: keyof typeof EVENT_LABEL, style?: TrajectoryStyle): string;
|
|
49
|
+
/**
|
|
50
|
+
* 结算 seam(OP-1/D6):未来标准 SESSION 复盘仪式接入点。当前无调用者,
|
|
51
|
+
* 仅导出契约:onSettlement(cb) 在"工作完成且被用户认可"时触发——该信号
|
|
52
|
+
* 尚无可靠自动检测(D2 用户拍板记录为未解问题),实现留待仪式落地。
|
|
53
|
+
*/
|
|
54
|
+
export declare function onSettlement(_cb: (sessionId: string) => void): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
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": {
|