@zoria-lind/dsh-ecolink-adapter 0.2.0 → 0.2.2

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.
@@ -1,189 +1,189 @@
1
- // dsh-ecolink-adapter v1(E1 通道分离):记忆注入模块。
2
- // 与网页端扩展同源的核心逻辑(复用 ../extension/core 的选择器/提示词纯函数):
3
- // - 直读 memory.json(只读,mtime 缓存——唯一写者是 ecolink-service)
4
- // - 【指令通道,默认开】agent/pre-step 每轮幂等追加一条 source.kind='plugin' 的
5
- // 快照消息承载 [dsh-ecolink 指令] 块(照抄内核 dsh-time-context 的成熟做法:
6
- // prepend 注册 + await next() + 末尾 append createUserMessage;决策里的 messages
7
- // 只喂本步请求、不写入会话事件)。不改写用户消息 → 不碰前缀缓存。
8
- // - 【内容通道,默认关(contentInjectionEnabled 逃生舱)】旧行为:改写用户消息注入
9
- // 记忆块(打分 + 预算 + #记忆名 + singleInjection 会话去重)。
10
- // - 块标记 [dsh-ecolink 记忆] / [dsh-ecolink 指令]:幂等剥离(DSH 每 step 重发
11
- // inbox 同一消息,与网页端同款防残留逻辑)
12
- // 稳定性铁律:任何异常 → 静默放行,不注入。
13
- // 内核事实(09 §A 已核实):agent/* 事件载荷由 agentEvents() 自动 {...payload, agent} 融合
14
- // → pre-step 载荷直接有 payload.agent(v0 的 agent/status 跟踪 hack 据此移除)。
15
-
16
- import { existsSync, readFileSync, statSync } from 'node:fs'
17
- import { homedir } from 'node:os'
18
- import { join } from 'node:path'
19
- import { selectMemories, effectiveBudget, parseMemoryCommand } from '../../../extension/core/selector.mjs'
20
- import { buildInjectedBlock, buildInstructionBlock, stripAllBlocks } from '../../../extension/core/prompt.mjs'
21
- import { resolveKernelModule } from '../kernel.js'
22
-
23
- const INSTRUCTION_SUMMARY = 'ecolink-instruction'
24
-
25
- function expandHome(dir) {
26
- if (typeof dir !== 'string' || dir.length === 0) return dir
27
- if (dir === '~' || dir.startsWith('~/') || dir.startsWith('~\\')) return join(homedir(), dir.slice(2))
28
- return dir
29
- }
30
-
31
- export function createMemoryInjectModule(ctx, config, stats, deps = {}) {
32
- if (!config?.enabled) return () => {}
33
- if (!ctx || typeof ctx.on !== 'function') return () => {}
34
-
35
- const poolPath = expandHome(deps.poolPath ?? config.poolPath)
36
-
37
- // createUserMessage:测试经 deps 注入假实现(显式 null = 强制禁用,模拟解析失败);
38
- // 生产从 @deepseek-ai/dsh-llm 解析(失败 → 指令通道静默禁用,警告一次)
39
- let createUserMessage = null
40
- if (deps.createUserMessage === null) {
41
- // 强制禁用路径(测试用)
42
- } else if (typeof deps.createUserMessage === 'function') {
43
- createUserMessage = deps.createUserMessage
44
- } else {
45
- const llm = resolveKernelModule('@deepseek-ai/dsh-llm')
46
- if (llm && typeof llm.createUserMessage === 'function') {
47
- createUserMessage = llm.createUserMessage
48
- } else {
49
- console.warn('[dsh-ecolink-adapter] 未能解析 @deepseek-ai/dsh-llm,指令通道禁用(记忆注入不受影响)')
50
- }
51
- }
52
-
53
- // 池读取:mtime 缓存(TTL 兜底 + 文件变化立即重读);失败返回 null → 不注入
54
- let poolCache = { mtimeMs: 0, at: 0, data: null }
55
- function readPool() {
56
- try {
57
- if (!existsSync(poolPath)) return null
58
- const st = statSync(poolPath)
59
- const now = Date.now()
60
- if (poolCache.data && st.mtimeMs === poolCache.mtimeMs && now - poolCache.at < config.poolTtlMs) {
61
- return poolCache.data
62
- }
63
- const data = JSON.parse(readFileSync(poolPath, 'utf8'))
64
- poolCache = { mtimeMs: st.mtimeMs, at: now, data }
65
- return data
66
- } catch {
67
- return poolCache.data // 读失败:用旧缓存或 null
68
- }
69
- }
70
-
71
- // 指令消息识别(幂等剥旧用:summary 唯一属于本插件的指令快照)
72
- const isOwnInstruction = (m) => m?.source?.kind === 'plugin'
73
- && m?.source?.plugin === 'ecolink-adapter'
74
- && m?.source?.summary === INSTRUCTION_SUMMARY
75
-
76
- // 指令快照消息(与内核 dsh-time-context 同款形状:form='snapshot' + sections)
77
- // E9.1:指令块内追加"读路径"指引——旧版只教写不教读,模型不知道池可查,
78
- // "你还记得吗"类问题零工具调用凭印象回答(2026-09-14 实测)。
79
- // E9.2:从"建议"升级为"硬规则"——查池是回答记忆类问题的前提,查之前禁止
80
- // 答"不知道/不记得"(模型常因"当前上下文没有"而诚实地说不知道,但池是另一回事)
81
- const READ_HINT = '跨端记忆查询(强制规则):当用户询问或提及"之前记过什么/你还记得吗/我的偏好/日程安排/考试安排/习惯/计划"等任何可能与历史记忆有关的问题时,第一步必须先运行 /ecolink-diff 命令查询记忆池(本会话首次调用返回全量),需要细节时再用 read 工具读 ~/.dsh-memory/memory.json 核对。禁止在未查询记忆池的情况下回答"不知道/不记得/没有记录"——记忆池与本对话上下文是两回事,池里有而上下文没有是常态。'
82
- function buildInstructionMessage() {
83
- const text = buildInstructionBlock().replace('[/dsh-ecolink 指令]', READ_HINT + '\n[/dsh-ecolink 指令]')
84
- return createUserMessage({
85
- content: [{ type: 'text', text }],
86
- source: { kind: 'plugin', plugin: 'ecolink-adapter', form: 'snapshot', summary: INSTRUCTION_SUMMARY, sections: [{ name: 'ecolink-instruction', text }] },
87
- })
88
- }
89
-
90
- // 内容通道(E1 逃生舱):旧行为的按消息改写注入
91
- function injectContentIntoMessages(messages) {
92
- const sk = String(currentAgent?.session?.id ?? currentAgent?.id ?? 'default')
93
- if (config.singleInjection && injectedSessions.has(sk)) return { messages, changed: false }
94
-
95
- const pool = readPool()
96
- if (!pool) return { messages, changed: false }
97
- const shared = pool.shared_pool ?? []
98
- const sessionPools = pool.session_pools ?? {}
99
-
100
- const out = []
101
- let changed = false
102
- for (const message of messages) {
103
- const srcKind = message?.source?.kind
104
- if (srcKind !== undefined && srcKind !== 'user') { out.push(message); continue }
105
- const content = message?.content
106
- const text = typeof content === 'string' ? content
107
- : Array.isArray(content) ? content.filter((b) => b?.type === 'text').map((b) => b.text).join('\n')
108
- : ''
109
- if (!text || text.trim().length === 0) { out.push(message); continue }
110
-
111
- // #记忆名 显式调用 → 只注入该会话记忆;否则共享池 + 全部会话池
112
- const cmd = parseMemoryCommand(text, sessionPools)
113
- let items
114
- let sessionName = null
115
- if (cmd) {
116
- const sp = sessionPools[cmd]
117
- items = (sp?.memories ?? []).map((m) => ({ ...m, identity: sp?.identity }))
118
- sessionName = sp?.identity
119
- } else {
120
- items = [
121
- ...shared,
122
- ...Object.entries(sessionPools).flatMap(([, sp]) => (sp?.memories ?? []).map((m) => ({ ...m, identity: sp?.identity }))),
123
- ]
124
- }
125
- const budget = effectiveBudget(text, config.maxInjectionChars)
126
- const { memories } = selectMemories(items, text, budget)
127
- if (memories.length === 0) { out.push(message); continue }
128
-
129
- const clean = stripAllBlocks(text)
130
- const composed = buildInjectedBlock(memories, sessionName) + '\n\n' + clean
131
- if (composed === text) { out.push(message); continue }
132
- out.push({ ...message, content: typeof content === 'string' ? composed : [{ type: 'text', text: composed }] })
133
- changed = true
134
- stats?.bump('ecolinkAdapter.injected', 1)
135
- }
136
- if (changed) injectedSessions.add(sk)
137
- return { messages: out, changed }
138
- }
139
-
140
- // 当前 agent(pre-step 载荷自带 agent,内核 agentEvents() 融合;保底用上次 running 状态)
141
- let currentAgent
142
- const onStatus = (payload) => {
143
- if (payload?.status === 'running' && payload?.agent) currentAgent = payload.agent
144
- }
145
- ctx.on?.('agent/status', onStatus)
146
-
147
- const injectedSessions = new Set()
148
-
149
- const handler = async (payload, next) => {
150
- const decision = await next()
151
- try {
152
- if (!decision || decision.kind !== 'enter') return decision
153
- if (payload?.signal?.aborted) return decision
154
- if (!config.injectEnabled) return decision
155
- const messages = Array.isArray(decision.messages) ? decision.messages : []
156
- if (messages.length === 0) return decision
157
-
158
- currentAgent = payload?.agent ?? currentAgent
159
- let out = messages
160
- let changed = false
161
-
162
- // ① 指令通道(默认开):剥旧指令快照 → 末尾追加新指令(每轮幂等,不改写用户消息)
163
- if (config.instructionEnabled && createUserMessage) {
164
- const kept = out.filter((m) => !isOwnInstruction(m))
165
- out = [...kept, buildInstructionMessage()]
166
- changed = true
167
- stats?.bump('ecolinkAdapter.instructed', 1)
168
- }
169
-
170
- // ② 内容通道(默认关):改写用户消息注入记忆块
171
- if (config.contentInjectionEnabled) {
172
- const r = injectContentIntoMessages(out)
173
- out = r.messages
174
- changed = changed || r.changed
175
- }
176
-
177
- return changed ? { ...decision, messages: out } : decision
178
- } catch (err) {
179
- console.warn(`[dsh-ecolink-adapter] 注入失败,静默放行(${err?.message ?? err})`)
180
- return decision
181
- }
182
- }
183
-
184
- ctx.on('agent/pre-step', handler, { prepend: true })
185
- return () => {
186
- ctx.off('agent/pre-step', handler)
187
- ctx.off?.('agent/status', onStatus)
188
- }
189
- }
1
+ // dsh-ecolink-adapter v1(E1 通道分离):记忆注入模块。
2
+ // 与网页端扩展同源的核心逻辑(复用 ../extension/core 的选择器/提示词纯函数):
3
+ // - 直读 memory.json(只读,mtime 缓存——唯一写者是 ecolink-service)
4
+ // - 【指令通道,默认开】agent/pre-step 每轮幂等追加一条 source.kind='plugin' 的
5
+ // 快照消息承载 [dsh-ecolink 指令] 块(照抄内核 dsh-time-context 的成熟做法:
6
+ // prepend 注册 + await next() + 末尾 append createUserMessage;决策里的 messages
7
+ // 只喂本步请求、不写入会话事件)。不改写用户消息 → 不碰前缀缓存。
8
+ // - 【内容通道,默认关(contentInjectionEnabled 逃生舱)】旧行为:改写用户消息注入
9
+ // 记忆块(打分 + 预算 + #记忆名 + singleInjection 会话去重)。
10
+ // - 块标记 [dsh-ecolink 记忆] / [dsh-ecolink 指令]:幂等剥离(DSH 每 step 重发
11
+ // inbox 同一消息,与网页端同款防残留逻辑)
12
+ // 稳定性铁律:任何异常 → 静默放行,不注入。
13
+ // 内核事实(09 §A 已核实):agent/* 事件载荷由 agentEvents() 自动 {...payload, agent} 融合
14
+ // → pre-step 载荷直接有 payload.agent(v0 的 agent/status 跟踪 hack 据此移除)。
15
+
16
+ import { existsSync, readFileSync, statSync } from 'node:fs'
17
+ import { homedir } from 'node:os'
18
+ import { join } from 'node:path'
19
+ import { selectMemories, effectiveBudget, parseMemoryCommand } from '../../../extension/core/selector.mjs'
20
+ import { buildInjectedBlock, buildInstructionBlock, stripAllBlocks } from '../../../extension/core/prompt.mjs'
21
+ import { resolveKernelModule } from '../kernel.js'
22
+
23
+ const INSTRUCTION_SUMMARY = 'ecolink-instruction'
24
+
25
+ function expandHome(dir) {
26
+ if (typeof dir !== 'string' || dir.length === 0) return dir
27
+ if (dir === '~' || dir.startsWith('~/') || dir.startsWith('~\\')) return join(homedir(), dir.slice(2))
28
+ return dir
29
+ }
30
+
31
+ export function createMemoryInjectModule(ctx, config, stats, deps = {}) {
32
+ if (!config?.enabled) return () => {}
33
+ if (!ctx || typeof ctx.on !== 'function') return () => {}
34
+
35
+ const poolPath = expandHome(deps.poolPath ?? config.poolPath)
36
+
37
+ // createUserMessage:测试经 deps 注入假实现(显式 null = 强制禁用,模拟解析失败);
38
+ // 生产从 @deepseek-ai/dsh-llm 解析(失败 → 指令通道静默禁用,警告一次)
39
+ let createUserMessage = null
40
+ if (deps.createUserMessage === null) {
41
+ // 强制禁用路径(测试用)
42
+ } else if (typeof deps.createUserMessage === 'function') {
43
+ createUserMessage = deps.createUserMessage
44
+ } else {
45
+ const llm = resolveKernelModule('@deepseek-ai/dsh-llm')
46
+ if (llm && typeof llm.createUserMessage === 'function') {
47
+ createUserMessage = llm.createUserMessage
48
+ } else {
49
+ console.warn('[dsh-ecolink-adapter] 未能解析 @deepseek-ai/dsh-llm,指令通道禁用(记忆注入不受影响)')
50
+ }
51
+ }
52
+
53
+ // 池读取:mtime 缓存(TTL 兜底 + 文件变化立即重读);失败返回 null → 不注入
54
+ let poolCache = { mtimeMs: 0, at: 0, data: null }
55
+ function readPool() {
56
+ try {
57
+ if (!existsSync(poolPath)) return null
58
+ const st = statSync(poolPath)
59
+ const now = Date.now()
60
+ if (poolCache.data && st.mtimeMs === poolCache.mtimeMs && now - poolCache.at < config.poolTtlMs) {
61
+ return poolCache.data
62
+ }
63
+ const data = JSON.parse(readFileSync(poolPath, 'utf8'))
64
+ poolCache = { mtimeMs: st.mtimeMs, at: now, data }
65
+ return data
66
+ } catch {
67
+ return poolCache.data // 读失败:用旧缓存或 null
68
+ }
69
+ }
70
+
71
+ // 指令消息识别(幂等剥旧用:summary 唯一属于本插件的指令快照)
72
+ // v4 source 约定(2026-10-01):kind = 'plugin:<插件名>',不再有 plugin 字段
73
+ const isOwnInstruction = (m) => m?.source?.kind === 'plugin:ecolink-adapter'
74
+ && m?.source?.summary === INSTRUCTION_SUMMARY
75
+
76
+ // 指令快照消息(与内核 dsh-time-context 同款形状:form='snapshot' + sections)
77
+ // E9.1:指令块内追加"读路径"指引——旧版只教写不教读,模型不知道池可查,
78
+ // "你还记得吗"类问题零工具调用凭印象回答(2026-09-14 实测)。
79
+ // E9.2:从"建议"升级为"硬规则"——查池是回答记忆类问题的前提,查之前禁止
80
+ // 答"不知道/不记得"(模型常因"当前上下文没有"而诚实地说不知道,但池是另一回事)
81
+ const READ_HINT = '跨端记忆查询(强制规则):当用户询问或提及"之前记过什么/你还记得吗/我的偏好/日程安排/考试安排/习惯/计划"等任何可能与历史记忆有关的问题时,第一步必须先运行 /ecolink-diff 命令查询记忆池(本会话首次调用返回全量),需要细节时再用 read 工具读 ~/.dsh-memory/memory.json 核对。禁止在未查询记忆池的情况下回答"不知道/不记得/没有记录"——记忆池与本对话上下文是两回事,池里有而上下文没有是常态。'
82
+ function buildInstructionMessage() {
83
+ const text = buildInstructionBlock().replace('[/dsh-ecolink 指令]', READ_HINT + '\n[/dsh-ecolink 指令]')
84
+ return createUserMessage({
85
+ content: [{ type: 'text', text }],
86
+ source: { kind: 'plugin:ecolink-adapter', form: 'snapshot', summary: INSTRUCTION_SUMMARY, sections: [{ name: 'ecolink-instruction', text }] },
87
+ })
88
+ }
89
+
90
+ // 内容通道(E1 逃生舱):旧行为的按消息改写注入
91
+ function injectContentIntoMessages(messages) {
92
+ const sk = String(currentAgent?.session?.id ?? currentAgent?.id ?? 'default')
93
+ if (config.singleInjection && injectedSessions.has(sk)) return { messages, changed: false }
94
+
95
+ const pool = readPool()
96
+ if (!pool) return { messages, changed: false }
97
+ const shared = pool.shared_pool ?? []
98
+ const sessionPools = pool.session_pools ?? {}
99
+
100
+ const out = []
101
+ let changed = false
102
+ for (const message of messages) {
103
+ const srcKind = message?.source?.kind
104
+ if (srcKind !== undefined && srcKind !== 'user') { out.push(message); continue }
105
+ const content = message?.content
106
+ const text = typeof content === 'string' ? content
107
+ : Array.isArray(content) ? content.filter((b) => b?.type === 'text').map((b) => b.text).join('\n')
108
+ : ''
109
+ if (!text || text.trim().length === 0) { out.push(message); continue }
110
+
111
+ // #记忆名 显式调用 → 只注入该会话记忆;否则共享池 + 全部会话池
112
+ const cmd = parseMemoryCommand(text, sessionPools)
113
+ let items
114
+ let sessionName = null
115
+ if (cmd) {
116
+ const sp = sessionPools[cmd]
117
+ items = (sp?.memories ?? []).map((m) => ({ ...m, identity: sp?.identity }))
118
+ sessionName = sp?.identity
119
+ } else {
120
+ items = [
121
+ ...shared,
122
+ ...Object.entries(sessionPools).flatMap(([, sp]) => (sp?.memories ?? []).map((m) => ({ ...m, identity: sp?.identity }))),
123
+ ]
124
+ }
125
+ const budget = effectiveBudget(text, config.maxInjectionChars)
126
+ const { memories } = selectMemories(items, text, budget)
127
+ if (memories.length === 0) { out.push(message); continue }
128
+
129
+ const clean = stripAllBlocks(text)
130
+ const composed = buildInjectedBlock(memories, sessionName) + '\n\n' + clean
131
+ if (composed === text) { out.push(message); continue }
132
+ out.push({ ...message, content: typeof content === 'string' ? composed : [{ type: 'text', text: composed }] })
133
+ changed = true
134
+ stats?.bump('ecolinkAdapter.injected', 1)
135
+ }
136
+ if (changed) injectedSessions.add(sk)
137
+ return { messages: out, changed }
138
+ }
139
+
140
+ // 当前 agent(pre-step 载荷自带 agent,内核 agentEvents() 融合;保底用上次 running 状态)
141
+ let currentAgent
142
+ const onStatus = (payload) => {
143
+ if (payload?.status === 'running' && payload?.agent) currentAgent = payload.agent
144
+ }
145
+ ctx.on?.('agent/status', onStatus)
146
+
147
+ const injectedSessions = new Set()
148
+
149
+ const handler = async (payload, next) => {
150
+ const decision = await next()
151
+ try {
152
+ if (!decision || decision.kind !== 'enter') return decision
153
+ if (payload?.signal?.aborted) return decision
154
+ if (!config.injectEnabled) return decision
155
+ const messages = Array.isArray(decision.messages) ? decision.messages : []
156
+ if (messages.length === 0) return decision
157
+
158
+ currentAgent = payload?.agent ?? currentAgent
159
+ let out = messages
160
+ let changed = false
161
+
162
+ // ① 指令通道(默认开):剥旧指令快照 → 末尾追加新指令(每轮幂等,不改写用户消息)
163
+ if (config.instructionEnabled && createUserMessage) {
164
+ const kept = out.filter((m) => !isOwnInstruction(m))
165
+ out = [...kept, buildInstructionMessage()]
166
+ changed = true
167
+ stats?.bump('ecolinkAdapter.instructed', 1)
168
+ }
169
+
170
+ // ② 内容通道(默认关):改写用户消息注入记忆块
171
+ if (config.contentInjectionEnabled) {
172
+ const r = injectContentIntoMessages(out)
173
+ out = r.messages
174
+ changed = changed || r.changed
175
+ }
176
+
177
+ return changed ? { ...decision, messages: out } : decision
178
+ } catch (err) {
179
+ console.warn(`[dsh-ecolink-adapter] 注入失败,静默放行(${err?.message ?? err})`)
180
+ return decision
181
+ }
182
+ }
183
+
184
+ ctx.on('agent/pre-step', handler, { prepend: true })
185
+ return () => {
186
+ ctx.off('agent/pre-step', handler)
187
+ ctx.off?.('agent/status', onStatus)
188
+ }
189
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoria-lind/dsh-ecolink-adapter",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "dsh-ecolink DSH 适配层:直读本地记忆池、pre-step 注入(打分+预算+会话去重)、#记忆名 过滤,打通网页端记忆生态",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,6 +21,9 @@
21
21
  "!service/test.mjs",
22
22
  "!service/fix-pool.mjs"
23
23
  ],
24
+ "engines": {
25
+ "node": ">=18.0.0"
26
+ },
24
27
  "repository": {
25
28
  "type": "git",
26
29
  "url": "git+https://github.com/Zoria-Lind/dsh-ecolink.git"
@@ -28,6 +31,15 @@
28
31
  "dsh": {
29
32
  "bundle": {
30
33
  "patch": "./adapter/cordis.patch.yml"
34
+ },
35
+ "compatibility": {
36
+ "dsh": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.6-rc.0 <0.1.7-0 || >=0.1.7-rc.0 <0.2.0-0",
37
+ "dshReleases": {
38
+ "0.1.5-rc.1": "compatible",
39
+ "0.1.5-rc.2": "compatible",
40
+ "0.1.7-rc.1": "compatible",
41
+ "0.2.0-rc.2": "compatible"
42
+ }
31
43
  }
32
44
  },
33
45
  "keywords": [
package/service/README.md CHANGED
@@ -61,9 +61,17 @@ node service/server.mjs
61
61
 
62
62
  所有响应 JSON;写操作经内部队列串行化,落盘为 tmp+rename 原子写;文件损坏时自动备份并空池重启。
63
63
 
64
- ## 压缩(0.2.0 重构:事务暂存 + 动态下限)
64
+ ## 压缩(0.2.0 重构:**双池事务**)
65
65
 
66
- 双模式(网页端免费模型 / API)共用同一套**事务**:开始 → 暂存 → 新标签普通入池 → 验收 → 提交或回滚。旧记忆从压缩开始到验收前,**始终有一份完整落盘副本**(`<poolDir>/staging.json`),压缩事故类(误删/清池)在机制上不可能发生。
66
+ 两个池:主池(`memory.json`,日常读写)+ 暂存池(`staging.json`,压缩期间的托管区)。
67
+
68
+ ```
69
+ 开始 ──▶ 过时记忆:主池 ──▶ 暂存池(主池清空该批;旧记忆全程有落盘副本,可随时回滚)
70
+ 压缩 ──▶ 模型输出新标签 ──▶ 普通收割/同步 ──▶ 主池
71
+ 验收 ──▶ 达标:清空暂存池(提交) │ 不达标/失败:暂存池原样放回主池(回滚,零丢失)
72
+ ```
73
+
74
+ 双模式(网页端免费模型 / API)共用同一套事务,压缩事故类(误删/清池)在机制上不可能发生。
67
75
 
68
76
  1. **暂存(stage)**:过时记忆整体移入 staging.json,主池清空该批;压缩清单即暂存条目(每行 `[key] 内容`,供模型复用原 key 做同 key 覆盖);
69
77
  2. **压缩**:模型逐条阅读清单,输出说明 `压缩完成(重复 N 条)`(N = 模型统计的完全重复/高度重叠条数)+ 完整属性标签(`<DSM:memory_write key="…" importance="always|called">内容</…>`);标签经普通收割/同步通道入主池;
@@ -1,37 +1,37 @@
1
- {
2
- "name": "@zoria-lind/dsh-ecolink-service",
3
- "version": "0.2.0",
4
- "description": "dsh-ecolink 本地记忆服务:网页扩展与 DSH 共享记忆池的唯一写者(零依赖、127.0.0.1、token 鉴权)",
5
- "license": "MIT",
6
- "type": "module",
7
- "main": "server.mjs",
8
- "exports": {
9
- ".": "./server.mjs"
10
- },
11
- "bin": {
12
- "ecolink-service": "server.mjs"
13
- },
14
- "files": [
15
- "server.mjs",
16
- "pool.mjs",
17
- "compress.mjs",
18
- "config.example.json",
19
- "README.md",
20
- "LICENSE"
21
- ],
22
- "engines": {
23
- "node": ">=18.0.0"
24
- },
25
- "repository": {
26
- "type": "git",
27
- "url": "git+https://github.com/Zoria-Lind/dsh-ecolink.git",
28
- "directory": "service"
29
- },
30
- "keywords": [
31
- "dsh",
32
- "deepseek-harness",
33
- "memory",
34
- "ecolink",
35
- "local-service"
36
- ]
37
- }
1
+ {
2
+ "name": "@zoria-lind/dsh-ecolink-service",
3
+ "version": "0.2.2",
4
+ "description": "dsh-ecolink 本地记忆服务:网页扩展与 DSH 共享记忆池的唯一写者(零依赖、127.0.0.1、token 鉴权)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "server.mjs",
8
+ "exports": {
9
+ ".": "./server.mjs"
10
+ },
11
+ "bin": {
12
+ "ecolink-service": "server.mjs"
13
+ },
14
+ "files": [
15
+ "server.mjs",
16
+ "pool.mjs",
17
+ "compress.mjs",
18
+ "config.example.json",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Zoria-Lind/dsh-ecolink.git",
28
+ "directory": "service"
29
+ },
30
+ "keywords": [
31
+ "dsh",
32
+ "deepseek-harness",
33
+ "memory",
34
+ "ecolink",
35
+ "local-service"
36
+ ]
37
+ }