@max-null/dsh-memory 0.5.0 → 0.6.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/dist/remote.js CHANGED
@@ -43,6 +43,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
43
43
  import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol';
44
44
  import { MemoryId } from "./engine.js";
45
45
  import { SELF_DESCRIPTION } from "./self.js";
46
+ import { DEFAULT_INJECTION_BUDGET, DEFAULT_SUMMARY_CHARS, renderInjection } from "./injection.js";
46
47
  /** Client-callable memory surface; registered as the `memory` Typert namespace. */
47
48
  let MemoryGateway = (() => {
48
49
  let _classSuper = TypertRemoteService;
@@ -109,11 +110,17 @@ let MemoryGateway = (() => {
109
110
  return this.ctx.memory.list({}, cwd);
110
111
  }
111
112
  /**
112
- * 注入预览(0.3.5):开发者查看当前注入到 system prompt 的记忆内容
113
- * ——self 自述 + 实际注入的 global approved+injected 记忆。
113
+ * 注入预览(0.3.5 + 0.5.2):开发者查看当前注入到 system prompt 的记忆
114
+ * 内容——self 自述 + 当前会话工作区(cwd)的 approved+injected 记忆,
115
+ * 经摘要化 + 预算截断(与 memory:recall 同源渲染)。
114
116
  */
115
- injectionPreview() {
116
- return { self: SELF_DESCRIPTION, injected: this.ctx.memory.recallRecords() };
117
+ async injectionPreview(cwd, budget, summaryChars) {
118
+ if (cwd !== undefined)
119
+ await this.ctx.memory.ensureProjectOpen(cwd);
120
+ return {
121
+ self: SELF_DESCRIPTION,
122
+ ...renderInjection(this.ctx.memory.recallRecords(cwd), budget ?? DEFAULT_INJECTION_BUDGET, summaryChars ?? DEFAULT_SUMMARY_CHARS),
123
+ };
117
124
  }
118
125
  };
119
126
  })();
package/dist/routes.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { SELF_DESCRIPTION } from "./self.js";
3
+ import { DEFAULT_INJECTION_BUDGET, DEFAULT_SUMMARY_CHARS, renderInjection } from "./injection.js";
3
4
  const require = createRequire(import.meta.url);
4
5
  /** Body size bound of one JSON request. */
5
6
  const MAX_BODY_BYTES = 1 << 20;
@@ -97,6 +98,27 @@ function cwdOf(payload) {
97
98
  const value = payload?.cwd;
98
99
  return typeof value === 'string' && value !== '' ? value : undefined;
99
100
  }
101
+ /** 取 memory 服务(未挂载 503 且明确失败)。 */
102
+ function requireMemory(ctx) {
103
+ const memory = ctx.get('memory');
104
+ if (memory === undefined)
105
+ throw new MemoryApiError('service-unavailable', 'memory service unavailable', 503);
106
+ return memory;
107
+ }
108
+ /** 模板记录投影(0.6.0):不暴露本地文件路径(meta.path 引擎内部使用)。 */
109
+ function promptProjection(record) {
110
+ const meta = record.meta;
111
+ return {
112
+ id: String(record.id),
113
+ name: meta?.name ?? '',
114
+ ...meta?.dimension === undefined ? {} : { dimension: meta.dimension },
115
+ ...meta?.difficulty === undefined ? {} : { difficulty: meta.difficulty },
116
+ ...meta === undefined ? {} : { tags: meta.tags },
117
+ summary: meta?.summary ?? record.content.slice(0, 200),
118
+ source: meta?.source ?? 'user',
119
+ namespace: record.namespace,
120
+ };
121
+ }
100
122
  /** 挂载 /memory/api 路由(apply 调用)。 */
101
123
  export function mountMemoryApi(ctx) {
102
124
  // webServer/webRuntime 由 index.ts 的 inject 声明(Context 类型未扩展,断言访问)
@@ -168,11 +190,77 @@ export function mountMemoryApi(ctx) {
168
190
  ...record.keywords === undefined ? {} : { keywords: record.keywords },
169
191
  }, cwdOf(record));
170
192
  },
171
- 'injectionPreview': () => {
193
+ 'injectionPreview': async (payload) => {
172
194
  const memory = ctx.get('memory');
173
195
  if (memory === undefined)
174
196
  throw new MemoryApiError('service-unavailable', 'memory service unavailable', 503);
175
- return { self: SELF_DESCRIPTION, injected: memory.recallRecords() };
197
+ const record = payload;
198
+ const cwd = cwdOf(record);
199
+ if (cwd !== undefined)
200
+ await memory.ensureProjectOpen(cwd);
201
+ // 0.5.2:预览与真实注入同源(renderInjection)——摘要化 + 预算截断一致
202
+ const budget = typeof record?.budget === 'number' && record.budget > 0
203
+ ? record.budget
204
+ : record?.budget === null ? null : DEFAULT_INJECTION_BUDGET;
205
+ const summaryChars = typeof record?.summaryChars === 'number' && record.summaryChars > 0 ? record.summaryChars : DEFAULT_SUMMARY_CHARS;
206
+ return { self: SELF_DESCRIPTION, ...renderInjection(memory.recallRecords(cwd), budget, summaryChars) };
207
+ },
208
+ // ── 提示词模板库(0.6.0)──
209
+ 'prompt.list': async (payload) => {
210
+ const memory = requireMemory(ctx);
211
+ const record = (payload ?? {});
212
+ const cwd = cwdOf(record);
213
+ await memory.refreshPromptIndex(cwd);
214
+ const namespace = record.namespace === 'project' || record.namespace === 'global' ? record.namespace : undefined;
215
+ const records = await memory.list({ kind: 'prompt', ...namespace === undefined ? {} : { namespace } }, cwd);
216
+ return records.map(promptProjection);
217
+ },
218
+ 'prompt.get': (payload) => {
219
+ const memory = requireMemory(ctx);
220
+ const record = (payload ?? {});
221
+ const lookup = typeof record.name === 'string' ? record.name : typeof record.id === 'string' ? record.id : '';
222
+ if (lookup === '') {
223
+ throw new MemoryApiError('bad-request', 'missing or invalid "id"/"name"');
224
+ }
225
+ return memory.promptGet(lookup, cwdOf(record)).then(file => ({
226
+ name: file.meta.name,
227
+ ...file.meta.dimension === undefined ? {} : { dimension: file.meta.dimension },
228
+ ...file.meta.difficulty === undefined ? {} : { difficulty: file.meta.difficulty },
229
+ tags: file.meta.tags,
230
+ body: file.body,
231
+ ...file.fallback === null ? {} : { fallback: file.fallback },
232
+ }));
233
+ },
234
+ 'prompt.add': (payload) => {
235
+ const memory = requireMemory(ctx);
236
+ const record = (payload ?? {});
237
+ if (typeof record.name !== 'string' || record.name === '')
238
+ throw new MemoryApiError('bad-request', 'missing or invalid "name"');
239
+ if (typeof record.content !== 'string' || record.content === '')
240
+ throw new MemoryApiError('bad-request', 'missing or invalid "content"');
241
+ return memory.promptAdd({
242
+ name: record.name,
243
+ content: record.content,
244
+ ...typeof record.dimension === 'string' ? { dimension: record.dimension } : {},
245
+ ...typeof record.difficulty === 'string' ? { difficulty: record.difficulty } : {},
246
+ ...Array.isArray(record.tags) ? { tags: record.tags.filter((tag) => typeof tag === 'string') } : {},
247
+ ...typeof record.fallback === 'string' ? { fallback: record.fallback } : {},
248
+ ...record.namespace === 'project' ? { namespace: 'project' } : {},
249
+ source: 'user',
250
+ }, cwdOf(record)).then(promptProjection);
251
+ },
252
+ 'prompt.remove': (payload) => {
253
+ const memory = requireMemory(ctx);
254
+ const record = (payload ?? {});
255
+ const lookup = typeof record.name === 'string' ? record.name : typeof record.id === 'string' ? record.id : '';
256
+ if (lookup === '') {
257
+ throw new MemoryApiError('bad-request', 'missing or invalid "id"/"name"');
258
+ }
259
+ return memory.promptRemove(lookup, cwdOf(record));
260
+ },
261
+ 'prompt.refresh': (payload) => {
262
+ const memory = requireMemory(ctx);
263
+ return memory.refreshPromptIndex(cwdOf((payload ?? {})));
176
264
  },
177
265
  };
178
266
  const fence = (req) => isTrusted(req, webRuntime.trustedHosts);
package/dist/self.js CHANGED
@@ -18,8 +18,8 @@ const SELF_VERSION = (() => {
18
18
  export const SELF_DESCRIPTION = `[记忆系统自述] 当前环境内置跨会话记忆服务(dsh-memory v${SELF_VERSION})。`
19
19
  + '工作机制:①记忆以明文 JSON 存储(global→$DSH_HOME/storages、工作区→会话工作区 .dsh/storages 随 git 分享);'
20
20
  + '②模型写入即 suggested(待审核),仅人工审核(memory_confirm)后才 approved;'
21
- + '③每轮注入 system prompt 的只有「global 的 approved + injected 开关打开」的记忆(常驻注入由用户控制,审核≠注入);'
22
- + '④工作区记忆按会话工作区路由,靠 memory_search 检索(含待审核条目,可先评估再引用);'
21
+ + '③每轮注入 system prompt 的 = 「global 的 approved + injected」+「当前会话工作区的 approved + injected」,逐条为单行摘要(内容全文靠 memory_search 检索),并受注入预算限制(超预算按最近更新优先,省略条数在面板「注入预览」可见;常驻注入由用户控制,审核≠注入);'
22
+ + '④工作区记忆按会话工作区路由(存储跟随仓库),memory_search 为 BM25 检索(中文 2-gram + 关键词加权,可配置语义融合),可检索任意状态(含待审核条目,可先评估再引用);'
23
23
  + '⑤修正过时内容用 memory_update(改动重置待审核,注入开关保留)。'
24
24
  + `可用记忆工具共 6 个:memory_save / memory_list / memory_search / memory_confirm / memory_forget / memory_update。`
25
25
  + '使用建议:相关历史上下文先 memory_search 检索再引用;新习惯/约定用 memory_save 写入(落在待审核)。'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@max-null/dsh-memory",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Cross-session plaintext memory plugin for the DeepSeek Harness — deterministic BM25 recall, human-owned, no embeddings",
5
5
  "license": "MIT",
6
6
  "publishConfig": {