dsh-memento 0.2.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.
@@ -0,0 +1,43 @@
1
+ // lib/strings.mjs — 模型可见/命令面文案(零 DSH 依赖,纯数据)。
2
+ //
3
+ // 语言词表:en 为源文(冻结现状),zh 为本次新写的对应译文。渲染函数用
4
+ // pick(strings, language) 选表;语言词汇本身在 index.mjs 的 Config.language
5
+ // (默认 en,非法值加载期响亮失败)。
6
+
7
+ /** 快照冻结说明头。 */
8
+ export const SNAPSHOT_HEADER = {
9
+ en: '[dsh-memento: frozen memory snapshot — captured at session start; memory changes during this session do not update this block. To change memory, use the memory tool.]',
10
+ zh: '[dsh-memento:冻结记忆快照——会话启动时捕获;本会话内的记忆变更不更新此块。要修改记忆,请使用 memory 工具。]',
11
+ }
12
+
13
+ /** 快照分组标题(模型可见;en 与 DSH 核心提示一致,zh 为对应译文)。 */
14
+ export const GROUP_TITLES = {
15
+ en: {
16
+ 'user/user-global': 'User profile (global preferences, communication style, landmines)',
17
+ 'user/workspace': 'User preferences for this workspace',
18
+ 'agent/user-global': 'Environment facts and conventions (cross-workspace)',
19
+ 'agent/workspace': 'Workspace facts, conventions, and lessons',
20
+ },
21
+ zh: {
22
+ 'user/user-global': '用户画像(全局偏好、沟通风格、雷区)',
23
+ 'user/workspace': '本工作区的用户偏好',
24
+ 'agent/user-global': '环境事实与约定(跨工作区)',
25
+ 'agent/workspace': '本工作区的事实、约定与教训',
26
+ },
27
+ }
28
+
29
+ /** 快照待审批提案块标题。 */
30
+ export const PROPOSAL_HEADER = {
31
+ en: 'Pending memory proposals (reviewed by the user; approve or dismiss via the /memory proposals command)',
32
+ zh: '待审批记忆提案(由用户裁决;用 /memory proposals 命令 approve 或 dismiss)',
33
+ }
34
+
35
+ /**
36
+ * 按语言选文案表(未知语言回退 en;调用方已在加载期校验词汇)。
37
+ * @param {Record<string, unknown>} table - 语言键 → 文案。
38
+ * @param {string} language - 'en' | 'zh'。
39
+ * @returns {unknown} 所选文案。
40
+ */
41
+ export function pick(table, language) {
42
+ return table[language] ?? table.en
43
+ }
@@ -0,0 +1,31 @@
1
+ // lib/workspace.mjs — 工作区键与 agent 键(零 DSH 依赖)。
2
+ //
3
+ // workspace 层按会话 cwd 隔离:写时与快照时用同一个规范化函数生成键,
4
+ // Windows 下大小写不敏感(盘符/路径大小写差异不产生两个隔离层)。
5
+ // agent 键按 SessionHeader.agentPreset 隔离:'' = 共享层(未按 preset 组合的
6
+ // 部署全部落在同一层,行为与无此维度时一致)。
7
+
8
+ import path from 'node:path'
9
+
10
+ /**
11
+ * 把会话 cwd 规范化为 workspaceKey。空/非法 cwd 得到 ''(共享"无工作区"层,
12
+ * 仅测试与无 cwd 会话可达;正常 DSH 会话 cwd 必为绝对路径)。
13
+ * @param {string|undefined|null} cwd - 会话 cwd。
14
+ * @returns {string} 规范化键。
15
+ */
16
+ export function workspaceKeyOf(cwd) {
17
+ if (typeof cwd !== 'string' || cwd.length === 0) return ''
18
+ const resolved = path.resolve(cwd)
19
+ return process.platform === 'win32' ? resolved.toLowerCase() : resolved
20
+ }
21
+
22
+ /**
23
+ * 把会话的 agentPreset 规范化为 agentKey。空/缺失得到 ''(共享层)。
24
+ * @param {string|undefined|null} agentPreset - SessionHeader.agentPreset。
25
+ * @returns {string} 规范化键。
26
+ */
27
+ export function agentKeyOf(agentPreset) {
28
+ if (typeof agentPreset !== 'string' || agentPreset.length === 0) return ''
29
+ const trimmed = agentPreset.trim()
30
+ return process.platform === 'win32' ? trimmed.toLowerCase() : trimmed
31
+ }
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "dsh-memento",
3
+ "description": "Bounded, layered, approval-gated, auditable cross-session memory for DeepSeek Harness — a capability seam (ctx.memory service + local SQLite provider + memory tool + frozen snapshot injection), not another memory warehouse",
4
+ "version": "0.2.0",
5
+ "type": "module",
6
+ "main": "./index.mjs",
7
+ "types": "./types.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./types.d.ts",
11
+ "default": "./index.mjs"
12
+ },
13
+ "./client": {
14
+ "types": "./client/client.d.ts",
15
+ "default": "./client/client.js"
16
+ },
17
+ "./cordis.patch.yml": "./cordis.patch.yml",
18
+ "./package.json": "./package.json"
19
+ },
20
+ "files": [
21
+ "index.mjs",
22
+ "types.d.ts",
23
+ "lib",
24
+ "client",
25
+ "cordis.patch.yml",
26
+ "README.md",
27
+ "README.zh.md",
28
+ "README.es.md",
29
+ "README.pt.md",
30
+ "README.hi.md",
31
+ "ARCHITECTURE.md",
32
+ "CHANGELOG.md",
33
+ "LICENSE",
34
+ "THIRD_PARTY_NOTICES.md"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/PerryLink/dsh-memento.git"
39
+ },
40
+ "homepage": "https://github.com/PerryLink/dsh-memento#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/PerryLink/dsh-memento/issues"
43
+ },
44
+ "dsh": {
45
+ "bundle": {
46
+ "patch": "./cordis.patch.yml"
47
+ },
48
+ "client": {
49
+ "platform": "web",
50
+ "immediately": true
51
+ }
52
+ },
53
+ "peerDependencies": {
54
+ "@deepseek-ai/cordis": "^4.0.1",
55
+ "@deepseek-ai/dsh-session": ">=0.1.0-rc.6",
56
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.6",
57
+ "@deepseek-ai/schemastery": ">=3.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@deepseek-ai/cordis": "^4.0.1",
61
+ "@deepseek-ai/dsh-session": ">=0.1.0-rc.6",
62
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.6",
63
+ "@deepseek-ai/schemastery": ">=3.0.0",
64
+ "@types/node": "^26.2.0",
65
+ "typescript": "^7.0.2"
66
+ },
67
+ "scripts": {
68
+ "test": "node --test \"test/*.test.mjs\"",
69
+ "coverage": "node --test --experimental-test-coverage \"test/*.test.mjs\"",
70
+ "check:coverage": "node scripts/check-coverage.mjs",
71
+ "typecheck": "tsc -p tsconfig.check.json",
72
+ "check:readmes": "node scripts/verify-readmes.mjs"
73
+ },
74
+ "keywords": [
75
+ "dsh",
76
+ "dsh-plugin",
77
+ "deepseek-harness",
78
+ "memory",
79
+ "agent-memory",
80
+ "approval",
81
+ "audit",
82
+ "sqlite",
83
+ "cordis",
84
+ "llm"
85
+ ],
86
+ "engines": {
87
+ "node": "^22.19.0 || >=24.0.0"
88
+ },
89
+ "publishConfig": {
90
+ "access": "public"
91
+ },
92
+ "license": "Apache-2.0"
93
+ }
package/types.d.ts ADDED
@@ -0,0 +1,191 @@
1
+ // types.d.ts — dsh-memento 类型契约(声明合并)。
2
+ //
3
+ // 本插件入口是纯 ESM JavaScript;类型契约集中在本文件:
4
+ // - `declare module '@deepseek-ai/cordis'`:ctx.memory 服务(F1,三角色 seam 的
5
+ // Service Definition 面)。
6
+ // - `declare module '@deepseek-ai/dsh-session'`:memory/* 会话事件词汇(F7)。
7
+ // 注意 rc.6 尚无插件事件注册面(KNOWN_SESSION_EVENT_TYPES 不含 memory/*,
8
+ // 且 Session.append 无法标记 ignorable),运行时按已知集合自适应派发——
9
+ // 未被 harness 收录时跳过 append,审计由审批审计对 + 插件审计表承担;
10
+ // 词汇与载荷形状在本文件定死,harness 收录后即自动启用。
11
+
12
+ export type MemoryTrack = 'user' | 'agent'
13
+
14
+ export type MemoryScope = 'user-global' | 'workspace'
15
+
16
+ export type MemoryWritePolicy = 'ask' | 'auto' | 'off'
17
+
18
+ export type MemoryAction = 'add' | 'replace' | 'remove' | 'consolidate' | 'query' | 'seed'
19
+
20
+ /** 落盘条目(审计/会话事件的载荷形状)。 */
21
+ export interface MemoryEntry {
22
+ /** 条目 id(本插件生成,跨会话稳定)。 */
23
+ id: string
24
+ /** 轨道:user=用户画像,agent=环境事实/约定/教训。 */
25
+ track: MemoryTrack
26
+ /** 作用域:user-global 跨工作区,workspace 按会话 cwd。 */
27
+ scope: MemoryScope
28
+ /** workspace 条目的规范化 cwd 键;user-global 条目为空串。 */
29
+ workspaceKey: string
30
+ /** 规范化 agentPreset 键;'' = 共享层(所有 preset 可见)。 */
31
+ agentKey: string
32
+ /** 条目文本(预算计数字符 = JS 字符串长度)。 */
33
+ text: string
34
+ /** 来源标注(dsh-memento / memory-tool / claude 等)。 */
35
+ source: string
36
+ /** 创建时间(epoch ms)。 */
37
+ createdAt: number
38
+ /** 最近更新时间(epoch ms)。 */
39
+ updatedAt: number
40
+ /** 最近召回时间(epoch ms);从未命中为 null。 */
41
+ lastRecalled: number | null
42
+ /** 召回次数(query 排序用:高频即重要)。 */
43
+ recallCount: number
44
+ /** 最近一次写它的会话 id;无则 null。 */
45
+ sessionId: string | null
46
+ }
47
+
48
+ /** 写入输入(add/seed 用)。 */
49
+ export interface MemoryEntryInput {
50
+ track: MemoryTrack
51
+ scope: MemoryScope
52
+ text: string
53
+ source?: string
54
+ /** 显式 workspaceKey;省略时取写方会话 cwd。 */
55
+ workspaceKey?: string
56
+ /** 显式 agentKey;省略时取写方会话 agentPreset。 */
57
+ agentKey?: string
58
+ }
59
+
60
+ /** 会话最小形状(插件只读这些面;字段宽类型以兼容真实 Session/Agent)。 */
61
+ export interface MemorySessionLike {
62
+ id?: unknown
63
+ header?: { cwd?: unknown; agentPreset?: unknown }
64
+ append?: (type: string, data: unknown) => unknown
65
+ }
66
+
67
+ /** 审批服务最小形状(插件消费的 seam 面)。 */
68
+ export interface MemoryApprovalLike {
69
+ request(req: { agent?: unknown; toolName?: string; reason?: string; callId?: unknown; signal?: AbortSignal }): Promise<string>
70
+ overrideOf?(session: unknown): string | undefined
71
+ config?: { policy?: string }
72
+ }
73
+
74
+ /** 写上下文:审批路由与审计归属所必需。agent 缺失时写失败封闭。 */
75
+ export interface MemoryWriteContext {
76
+ /** 发起写的 agent(其 session 承载审批审计对)。 */
77
+ agent: { session?: MemorySessionLike | null } | null | undefined
78
+ /** 发起写的工具 callId(供 UI answerer 挂靠已流式化的工具调用)。 */
79
+ callId?: unknown
80
+ /** 取消信号:中止即 cancelled,不写任何东西。 */
81
+ signal?: AbortSignal
82
+ /** 可选自定义审批传输(turn 外命令路径注入;payload 携带完整写载荷)。 */
83
+ gate?: (payload: { action: string; track: string; scope: string; text: string; count?: number }, write: MemoryWriteContext) => Promise<string>
84
+ }
85
+
86
+ /** query 结果。 */
87
+ export interface MemoryQueryResult {
88
+ entries: MemoryEntry[]
89
+ total: number
90
+ truncated: boolean
91
+ }
92
+
93
+ /** 预算行。 */
94
+ export interface MemoryBudgetRow {
95
+ track: MemoryTrack
96
+ scope: MemoryScope
97
+ used: number
98
+ limit: number
99
+ }
100
+
101
+ /** 写成功后的用量(模型据此整合/删除后重试)。 */
102
+ export interface MemoryUsage {
103
+ track: MemoryTrack
104
+ scope: MemoryScope
105
+ used: number
106
+ limit: number
107
+ }
108
+
109
+ /** ctx.memory 服务:写方法内部强制过审批门,读方法无审批。 */
110
+ export interface MemoryService {
111
+ /** 模型可见文案与命令输出的语言(Config.language,'en' | 'zh')。 */
112
+ language: 'en' | 'zh'
113
+
114
+ /** 每轨每层当前用量与上限。 */
115
+ budgets(): MemoryBudgetRow[]
116
+
117
+ /** 子串查询(无审批);带 sessionId 时记 recalled 审计,带 session 时按已知事件类型自适应派发 memory/recalled。 */
118
+ query(filter?: { track?: MemoryTrack; scope?: MemoryScope; text?: string; limit?: number }, opts?: { sessionId?: string; session?: MemorySessionLike | null }): MemoryQueryResult
119
+
120
+ /** 新增条目(审批门 + 预算门)。 */
121
+ add(input: MemoryEntryInput, write: MemoryWriteContext): Promise<{ entry: MemoryEntry; usage: MemoryUsage }>
122
+
123
+ /** 按唯一子串替换(审批门 + 预算门;零/多命中报错)。 */
124
+ replace(input: { track: MemoryTrack; scope: MemoryScope; match: string; text: string; source?: string }, write: MemoryWriteContext): Promise<{ previous: MemoryEntry; entry: MemoryEntry; usage: MemoryUsage }>
125
+
126
+ /** 按唯一子串删除(审批门;零/多命中报错)。 */
127
+ remove(input: { track: MemoryTrack; scope: MemoryScope; match: string }, write: MemoryWriteContext): Promise<{ entry: MemoryEntry; usage: MemoryUsage }>
128
+
129
+ /** 整合多条为一条(一次审批 + Provider 单事务原子执行;零/多命中或超预算响亮失败)。 */
130
+ consolidate(input: { track: MemoryTrack; scope: MemoryScope; matches: string[]; text: string; source?: string; workspaceKey?: string; agentKey?: string }, write: MemoryWriteContext): Promise<{ removed: MemoryEntry[]; entry: MemoryEntry; usage: MemoryUsage }>
131
+
132
+ /** 批量种子(一次 ask 审批整批;任一条超预算整批拒绝)。 */
133
+ seed(inputs: MemoryEntryInput[], write: MemoryWriteContext): Promise<{ added: number; entries: MemoryEntry[] }>
134
+ }
135
+
136
+ declare module '@deepseek-ai/cordis' {
137
+ interface Context {
138
+ /** dsh-memento 记忆服务(本插件提供;其它插件可读写同一 store)。 */
139
+ memory: MemoryService
140
+ /** 审批 seam(本插件消费的最小面;由 DSH interaction 能力提供)。 */
141
+ approval: MemoryApprovalLike
142
+ }
143
+ interface Events {
144
+ /** 审批 waterfall(本插件 answerer 挂链)。 */
145
+ 'approval/request'(req: unknown, next: () => Promise<string>): Promise<string>
146
+ /** 可选服务就绪通知(withService 用)。 */
147
+ 'internal/service'(name: string): void
148
+ /** 会话事件桥(auto-capture 等观察面用)。 */
149
+ 'session/event'(session: unknown, event: unknown): void
150
+ }
151
+ }
152
+
153
+ declare module '@deepseek-ai/dsh-session' {
154
+ interface SessionEventMap {
155
+ /**
156
+ * 一条记忆条目已落盘(审批通过后的写成功)。日志只读事件,非 surface;
157
+ * 审计链 = approval/asked + approval/decided + 本事件 + 插件审计表。
158
+ * rc.6 无插件事件注册面时运行时跳过 append(见 types.d.ts 头注)。
159
+ */
160
+ 'memory/added': {
161
+ entry: MemoryEntry
162
+ source: string
163
+ sessionId: string
164
+ }
165
+ /** 一条记忆条目被 replace 改写(previous 为改写前内容)。 */
166
+ 'memory/updated': {
167
+ previous: MemoryEntry
168
+ entry: MemoryEntry
169
+ source: string
170
+ sessionId: string
171
+ }
172
+ /** 一条记忆条目被 remove 删除。 */
173
+ 'memory/removed': {
174
+ entry: MemoryEntry
175
+ source: string
176
+ sessionId: string
177
+ }
178
+ /** 一次 query 召回(记录过滤条件与命中数)。 */
179
+ 'memory/recalled': {
180
+ query: string
181
+ matches: number
182
+ sessionId: string
183
+ }
184
+ /** 会话启动时注入的冻结快照(text 与模型所见 systemPrompt 段逐字一致,S2)。 */
185
+ 'memory/snapshot': {
186
+ text: string
187
+ workspaceKey: string
188
+ at: number
189
+ }
190
+ }
191
+ }