@modusensus/dsh-mneme 0.7.10 → 0.7.12

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.
Files changed (158) hide show
  1. package/README.en.md +437 -0
  2. package/README.md +364 -166
  3. package/bin/cli.mjs +603 -0
  4. package/{dsh-mneme/cordis.patch.yml → cordis.patch.yml} +1 -0
  5. package/lib/api-standalone.js +264 -0
  6. package/{dsh-mneme/lib → lib}/api.js +133 -289
  7. package/{dsh-mneme/lib → lib}/client.js +1008 -922
  8. package/{dsh-mneme/lib → lib}/config.js +54 -99
  9. package/{dsh-mneme/lib → lib}/dream/decisions.js +94 -143
  10. package/{dsh-mneme/lib → lib}/dream/sleep.js +12 -152
  11. package/{dsh-mneme/lib → lib}/dream.js +22 -168
  12. package/{dsh-mneme/src → lib}/hot-memory.js +0 -7
  13. package/{dsh-mneme/lib → lib}/index.js +45 -42
  14. package/{dsh-mneme/lib → lib}/inject.js +11 -53
  15. package/{dsh-mneme/src → lib}/mirror.js +1 -12
  16. package/{dsh-mneme/lib → lib}/quality-filter.js +1 -3
  17. package/{dsh-mneme/lib → lib}/reranker.js +1 -4
  18. package/{dsh-mneme/lib → lib}/service.js +20 -410
  19. package/{dsh-mneme/src → lib}/settings.js +34 -64
  20. package/{dsh-mneme/lib → lib}/store.js +38 -450
  21. package/{dsh-mneme/lib → lib}/summarize.js +10 -10
  22. package/lib/tools.js +274 -0
  23. package/package.json +45 -19
  24. package/{dsh-mneme/scripts → scripts}/e2e-dsh.js +3 -4
  25. package/{dsh-mneme/scripts → scripts}/sync-lib.js +5 -10
  26. package/src/api-standalone.js +264 -0
  27. package/{dsh-mneme/src → src}/api.js +133 -289
  28. package/{dsh-mneme/src → src}/config.js +54 -99
  29. package/{dsh-mneme/src → src}/dream/decisions.js +94 -143
  30. package/{dsh-mneme/src → src}/dream/sleep.js +12 -152
  31. package/{dsh-mneme/src → src}/dream.js +22 -168
  32. package/{dsh-mneme/lib → src}/hot-memory.js +0 -7
  33. package/{dsh-mneme/src → src}/index.js +45 -42
  34. package/{dsh-mneme/src → src}/inject.js +11 -53
  35. package/{dsh-mneme/lib → src}/mirror.js +1 -12
  36. package/{dsh-mneme/src → src}/quality-filter.js +1 -3
  37. package/{dsh-mneme/src → src}/reranker.js +1 -4
  38. package/{dsh-mneme/src → src}/service.js +20 -410
  39. package/{dsh-mneme/lib → src}/settings.js +34 -64
  40. package/{dsh-mneme/src → src}/store.js +38 -450
  41. package/{dsh-mneme/src → src}/summarize.js +10 -10
  42. package/src/tools.js +274 -0
  43. package/{dsh-mneme/test → test}/api.test.js +45 -156
  44. package/{dsh-mneme/test → test}/client.test.js +10 -206
  45. package/{dsh-mneme/test → test}/config.test.js +0 -21
  46. package/{dsh-mneme/test → test}/dream.test.js +1 -160
  47. package/{dsh-mneme/test → test}/graph-api.test.js +0 -34
  48. package/{dsh-mneme/test → test}/hot-memory.test.js +0 -29
  49. package/test/inject.test.js +120 -0
  50. package/{dsh-mneme/test → test}/llm-audit.test.js +4 -4
  51. package/{dsh-mneme/test → test}/reasoning-effort.test.js +0 -27
  52. package/{dsh-mneme/test → test}/recall-layer.test.js +5 -26
  53. package/{dsh-mneme/test → test}/reranker.test.js +0 -43
  54. package/{dsh-mneme/test → test}/service-search.test.js +0 -25
  55. package/{dsh-mneme/test → test}/service.test.js +0 -106
  56. package/{dsh-mneme/test → test}/settings.test.js +16 -35
  57. package/{dsh-mneme/test → test}/sleep.test.js +4 -171
  58. package/test/standalone-api.test.js +326 -0
  59. package/{dsh-mneme/test → test}/store.test.js +0 -76
  60. package/{dsh-mneme/test → test}/summarize.test.js +16 -15
  61. package/test/tools.test.js +265 -0
  62. package/.github/workflows/publish.yml +0 -58
  63. package/.github/workflows/test.yml +0 -32
  64. package/CHANGELOG.md +0 -91
  65. package/CONTRIBUTING.md +0 -293
  66. package/SECURITY.md +0 -718
  67. package/docs/devlog/2026-08-14-dsh-mneme-dev-log.md +0 -247
  68. package/docs/devlog/2026-08-15-dsh-mneme-audit-stress-dev-log.md +0 -145
  69. package/docs/devlog/2026-08-15-dsh-mneme-pipeline-dev-log.md +0 -56
  70. package/docs/devlog/2026-08-15-dsh-mneme-reflection-dev-log.md +0 -77
  71. package/docs/devlog/2026-08-15-dsh-mneme-review-fixes-dev-log.md +0 -64
  72. package/docs/devlog/2026-08-15-dsh-mneme-semantic-dev-log.md +0 -90
  73. package/dsh-mneme/CHANGELOG.md +0 -419
  74. package/dsh-mneme/LICENSE +0 -21
  75. package/dsh-mneme/README.md +0 -501
  76. package/dsh-mneme/docs/AGENT_MEMORY_RESEARCH.md +0 -183
  77. package/dsh-mneme/docs/ENTITIES.md +0 -245
  78. package/dsh-mneme/docs/LOCAL_MODEL.md +0 -141
  79. package/dsh-mneme/docs/MIGRATION.md +0 -127
  80. package/dsh-mneme/docs/SEMANTIC.md +0 -256
  81. package/dsh-mneme/docs/SLEEP.md +0 -163
  82. package/dsh-mneme/lib/dream/tag-extractor.js +0 -156
  83. package/dsh-mneme/lib/heat.js +0 -136
  84. package/dsh-mneme/lib/parser/tag.js +0 -59
  85. package/dsh-mneme/lib/parser/wiki-link.js +0 -38
  86. package/dsh-mneme/lib/search/tag-boost.js +0 -61
  87. package/dsh-mneme/lib/tools.js +0 -458
  88. package/dsh-mneme/package-lock.json +0 -1936
  89. package/dsh-mneme/package.json +0 -83
  90. package/dsh-mneme/scripts/check-sync.js +0 -42
  91. package/dsh-mneme/src/client.js +0 -2242
  92. package/dsh-mneme/src/dream/tag-extractor.js +0 -156
  93. package/dsh-mneme/src/heat.js +0 -136
  94. package/dsh-mneme/src/parser/tag.js +0 -59
  95. package/dsh-mneme/src/parser/wiki-link.js +0 -38
  96. package/dsh-mneme/src/search/tag-boost.js +0 -61
  97. package/dsh-mneme/src/tools.js +0 -458
  98. package/dsh-mneme/test/boundary-v0625.test.js +0 -82
  99. package/dsh-mneme/test/directory.test.js +0 -134
  100. package/dsh-mneme/test/heat.test.js +0 -148
  101. package/dsh-mneme/test/inject.test.js +0 -206
  102. package/dsh-mneme/test/layered-types-stats.test.js +0 -144
  103. package/dsh-mneme/test/lib-smoke.test.js +0 -109
  104. package/dsh-mneme/test/normalize-decisions.test.js +0 -120
  105. package/dsh-mneme/test/provenance.test.js +0 -103
  106. package/dsh-mneme/test/recall-runs.test.js +0 -93
  107. package/dsh-mneme/test/sleep-heat.test.js +0 -112
  108. package/dsh-mneme/test/tag-boost.test.js +0 -125
  109. package/dsh-mneme/test/tag.test.js +0 -426
  110. package/dsh-mneme/test/tools.test.js +0 -674
  111. package/dsh-mneme/test/updated-at-semantics.test.js +0 -113
  112. package/dsh-mneme/test/wiki-link.test.js +0 -332
  113. package//346/250/252/345/271/205.png +0 -0
  114. /package/{dsh-mneme/lib → lib}/commands.js +0 -0
  115. /package/{dsh-mneme/lib → lib}/dream/clustering.js +0 -0
  116. /package/{dsh-mneme/lib → lib}/embedding.js +0 -0
  117. /package/{dsh-mneme/lib → lib}/entities/extractor.js +0 -0
  118. /package/{dsh-mneme/lib → lib}/local-embedder.js +0 -0
  119. /package/{dsh-mneme/lib → lib}/search/adaptive.js +0 -0
  120. /package/{dsh-mneme/lib → lib}/search/bm25.js +0 -0
  121. /package/{dsh-mneme/lib → lib}/vector-index.js +0 -0
  122. /package/{dsh-mneme/scripts → scripts}/benchmark-embed.js +0 -0
  123. /package/{dsh-mneme/scripts → scripts}/benchmark-recall.js +0 -0
  124. /package/{dsh-mneme/scripts → scripts}/benchmark-rerank.js +0 -0
  125. /package/{dsh-mneme/scripts → scripts}/stress-dsh.js +0 -0
  126. /package/{dsh-mneme/src → src}/commands.js +0 -0
  127. /package/{dsh-mneme/src → src}/dream/clustering.js +0 -0
  128. /package/{dsh-mneme/src → src}/embedding.js +0 -0
  129. /package/{dsh-mneme/src → src}/entities/extractor.js +0 -0
  130. /package/{dsh-mneme/src → src}/local-embedder.js +0 -0
  131. /package/{dsh-mneme/src → src}/search/adaptive.js +0 -0
  132. /package/{dsh-mneme/src → src}/search/bm25.js +0 -0
  133. /package/{dsh-mneme/src → src}/vector-index.js +0 -0
  134. /package/{dsh-mneme/test → test}/audit.test.js +0 -0
  135. /package/{dsh-mneme/test → test}/benchmark.test.js +0 -0
  136. /package/{dsh-mneme/test → test}/clustering.test.js +0 -0
  137. /package/{dsh-mneme/test → test}/commands.test.js +0 -0
  138. /package/{dsh-mneme/test → test}/conflict-freeze.test.js +0 -0
  139. /package/{dsh-mneme/test → test}/entities.test.js +0 -0
  140. /package/{dsh-mneme/test → test}/epistemic.test.js +0 -0
  141. /package/{dsh-mneme/test → test}/fnew-0112.test.js +0 -0
  142. /package/{dsh-mneme/test → test}/fnew-03.test.js +0 -0
  143. /package/{dsh-mneme/test → test}/helpers/dream-mock.js +0 -0
  144. /package/{dsh-mneme/test → test}/local-embedder.test.js +0 -0
  145. /package/{dsh-mneme/test → test}/mirror-dirty.test.js +0 -0
  146. /package/{dsh-mneme/test → test}/mirror-edit-digest.test.js +0 -0
  147. /package/{dsh-mneme/test → test}/mirror-generation.test.js +0 -0
  148. /package/{dsh-mneme/test → test}/mirror.test.js +0 -0
  149. /package/{dsh-mneme/test → test}/peer-blockers.test.js +0 -0
  150. /package/{dsh-mneme/test → test}/policy-epoch.test.js +0 -0
  151. /package/{dsh-mneme/test → test}/quality-filter.test.js +0 -0
  152. /package/{dsh-mneme/test → test}/recall-evals.test.js +0 -0
  153. /package/{dsh-mneme/test → test}/receipt-chain.test.js +0 -0
  154. /package/{dsh-mneme/test → test}/reflection.test.js +0 -0
  155. /package/{dsh-mneme/test → test}/search-fusion.test.js +0 -0
  156. /package/{dsh-mneme/test → test}/semantic.test.js +0 -0
  157. /package/{dsh-mneme/test → test}/stress.test.js +0 -0
  158. /package/{dsh-mneme/test → test}/vector-index.test.js +0 -0
@@ -1,7 +1,7 @@
1
1
  import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
2
2
 
3
3
  const SUMMARY_PROMPT = `你是记忆库提炼助手。根据下面的会话内容,提炼 2-3 条值得跨会话记住的记忆。
4
- 只输出 JSON 数组,每项形如 {"type":"preference|project|decision|history|user|fact","title":"简短标题","content":"一句话内容","importance":1-5}。
4
+ 只输出 JSON 数组,每项形如 {"type":"preference|project|decision|history","title":"简短标题","content":"一句话内容","importance":1-5}。
5
5
  不要输出任何其他文字。`;
6
6
 
7
7
  /** Extract a JSON array from LLM output that may contain prose around it. */
@@ -17,7 +17,7 @@ export function parseSummaryJson(raw) {
17
17
  return [];
18
18
  }
19
19
  if (!Array.isArray(arr)) return [];
20
- const VALID = new Set(["preference", "project", "decision", "history", "user", "fact"]);
20
+ const VALID = new Set(["preference", "project", "decision", "history"]);
21
21
  return arr.filter(
22
22
  (item) =>
23
23
  item &&
@@ -76,11 +76,15 @@ function toProtocolChunk(chunk) {
76
76
  // events must not leak into the memory store. Events without a data payload
77
77
  // (minimal test doubles) pass the kind check and are handled by the content
78
78
  // check below.
79
+ // DSH ≥0.1.2-rc removed the Session.events property; events are only reachable
80
+ // via snapshotEvents(). Older DSH builds still expose .events, so fall back.
81
+ function getSessionEvents(session) {
82
+ return session?.snapshotEvents?.() ?? session?.events ?? [];
83
+ }
84
+
79
85
  function collectMessages(session) {
80
86
  const messages = [];
81
- // DSH 0.1.2-rc.1 Session 改用 snapshotEvents(),兼容旧版 .events
82
- const events = session.snapshotEvents?.() ?? session.events ?? [];
83
- for (const event of events) {
87
+ for (const event of getSessionEvents(session)) {
84
88
  const kind = event.data?.source?.kind;
85
89
  if (event.type !== "user/message") continue;
86
90
  if (kind !== undefined && kind !== "user") continue;
@@ -184,11 +188,7 @@ export function createSummarizer(ctx, service, config) {
184
188
  .join("");
185
189
  const entries = parseSummaryJson(text || assembledText);
186
190
  for (const entry of entries) {
187
- // Provenance: the summarizer runs on a real session (turn/end hook), so
188
- // session.id is always available here — it rides both the human-readable
189
- // source label and the structured session_id column (v0.5.x memory
190
- // provenance, the raw material for v0.6.0 reasoning-path / drift analysis).
191
- service.saveWithDedupe({ ...entry, source: `session:${session.id}`, session_id: session.id });
191
+ service.saveWithDedupe({ ...entry, source: `session:${session.id}` });
192
192
  }
193
193
  } finally {
194
194
  if (audit) {
package/lib/tools.js ADDED
@@ -0,0 +1,274 @@
1
+ import { defineTool } from "@deepseek-ai/dsh-tools";
2
+
3
+ const TEXT_OUTPUT = (text) => [{ type: "text", text }];
4
+
5
+ // Wire shape emitted by service.toApiList: shared by memory_search and
6
+ // memory_list so their output schemas always declare every key the runtime
7
+ // value carries (additionalProperties: false would reject undeclared keys).
8
+ const MEMORY_ITEM_SCHEMA = {
9
+ type: "object",
10
+ additionalProperties: false,
11
+ properties: {
12
+ id: { type: "string", required: true },
13
+ type: { type: "string", required: true },
14
+ title: { type: "string", required: true },
15
+ content: { type: "string", required: true },
16
+ tags: { type: "array", items: { type: "string" } },
17
+ importance: { type: "integer", required: true },
18
+ source: { type: "string" },
19
+ created_at: { type: "string", required: true },
20
+ updated_at: { type: "string", required: true }
21
+ }
22
+ };
23
+
24
+ export function createTools(ctx, service, config, embedder) {
25
+ const tools = [
26
+ defineTool({
27
+ name: "memory_save",
28
+ description:
29
+ "Persist one memory entry for future sessions (user preferences, project state, decisions). " +
30
+ "Call this when the user states a durable preference, a project decision is made, or a lesson is learned. " +
31
+ "Merges into an existing entry of the same type when the title matches.",
32
+ parameters: {
33
+ type: { type: "string", required: true, enum: ["preference", "project", "decision", "history"], description: "preference=user profile; project=project knowledge/state; decision=key decision; history=conversation summary" },
34
+ title: { type: "string", required: true, description: "Short unique title" },
35
+ content: { type: "string", required: true, description: "Memory body" },
36
+ tags: { type: "array", items: { type: "string" }, description: "Optional tags" },
37
+ importance: { type: "integer", description: "1-5; >= threshold auto-injects into future sessions" },
38
+ source: { type: "string", description: "Optional provenance" }
39
+ },
40
+ output: {
41
+ schema: {
42
+ type: "object",
43
+ additionalProperties: false,
44
+ properties: {
45
+ action: { type: "string", required: true, enum: ["created", "merged"] },
46
+ id: { type: "string", required: true }
47
+ }
48
+ },
49
+ render: (_args, value) => TEXT_OUTPUT(`memory ${value.action}: ${value.id}`)
50
+ },
51
+ async execute(args) {
52
+ const { action, memory } = service.saveWithDedupe({
53
+ type: args.type,
54
+ title: args.title,
55
+ content: args.content,
56
+ tags: args.tags ?? [],
57
+ importance: args.importance ?? 3,
58
+ source: args.source ?? "tool"
59
+ });
60
+ return { action, id: memory.id };
61
+ }
62
+ }),
63
+
64
+ defineTool({
65
+ name: "memory_search",
66
+ description: "Search the cross-session memory store. Use when you need past context: how a problem was solved, user preferences, project decisions. Substring-matches title/content/tags, and augments results with semantic (vector) recall + optional rerank when an embeddings provider is configured. Returns matching entries with source and timestamps.",
67
+ parameters: {
68
+ query: { type: "string", required: true, description: "Search text; substring match over title/content/tags" },
69
+ limit: { type: "integer", description: "Max results (default 20)" },
70
+ mode: { type: "string", enum: ["auto", "keyword", "vector", "hybrid"], description: "auto (default) = keyword hits first + vector fill when enabled; keyword = text only; vector = semantic recall first (falls back to keyword); hybrid = vector leads, keyword fills remaining slots" },
71
+ semantic: { type: "boolean", description: "Shorthand: enable semantic (vector) recall (same as mode=vector when true)" },
72
+ rerank: { type: "boolean", description: "Run cross-encoder rerank over candidates when a local reranker is configured (default true)" }
73
+ },
74
+ output: {
75
+ schema: {
76
+ type: "object",
77
+ additionalProperties: false,
78
+ properties: {
79
+ items: {
80
+ type: "array", required: true,
81
+ items: MEMORY_ITEM_SCHEMA
82
+ }
83
+ }
84
+ },
85
+ render: (_args, value) => TEXT_OUTPUT(`Found ${value.items.length} memory entr${value.items.length === 1 ? "y" : "ies"}.`)
86
+ },
87
+ async execute(args) {
88
+ const limit = args.limit ?? 20;
89
+ const mode = args.semantic === true && !args.mode ? "vector" : args.mode ?? "auto";
90
+ const rows = await service.searchMemories(args.query, {
91
+ mode,
92
+ topK: limit,
93
+ useRerank: args.rerank !== false
94
+ });
95
+ return { items: service.toApiList(rows) };
96
+ }
97
+ }),
98
+
99
+ defineTool({
100
+ name: "memory_list",
101
+ description: "List memory entries by type, high-importance first, then newest, paginated. Set include_archived=true to also list archived (hidden) entries so they can be located and restored.",
102
+ parameters: {
103
+ type: { type: "string", enum: ["preference", "project", "decision", "history"], description: "Filter by type; omit for all" },
104
+ limit: { type: "integer", description: "Page size (default 50)" },
105
+ offset: { type: "integer", description: "Page offset (default 0)" },
106
+ include_archived: { type: "boolean", description: "Include archived (hidden) entries so they can be found and restored (default false)" }
107
+ },
108
+ output: {
109
+ schema: {
110
+ type: "object",
111
+ additionalProperties: false,
112
+ properties: {
113
+ items: {
114
+ type: "array", required: true,
115
+ items: MEMORY_ITEM_SCHEMA
116
+ },
117
+ total: { type: "integer", required: true }
118
+ }
119
+ },
120
+ render: (_args, value) => TEXT_OUTPUT(`${value.items.length} memory entries (of ${value.total}).`)
121
+ },
122
+ async execute(args) {
123
+ const includeArchived = args.include_archived === true;
124
+ const rows = service.toApiList(service.list({
125
+ type: args.type,
126
+ limit: args.limit ?? 50,
127
+ offset: args.offset ?? 0,
128
+ includeArchived
129
+ }));
130
+ return { items: rows, total: service.count(args.type, { includeArchived }) };
131
+ }
132
+ }),
133
+
134
+ defineTool({
135
+ name: "memory_update",
136
+ description: "Modify an existing memory entry (title, content, type, tags, importance).",
137
+ parameters: {
138
+ id: { type: "string", required: true, description: "Memory id" },
139
+ title: { type: "string" },
140
+ content: { type: "string" },
141
+ type: { type: "string", enum: ["preference", "project", "decision", "history"] },
142
+ tags: { type: "array", items: { type: "string" } },
143
+ importance: { type: "integer", description: "1-5" },
144
+ reason: { type: "string", description: "Optional context for the correction (what the user actually said/wanted), recorded for reflection" }
145
+ },
146
+ output: {
147
+ schema: {
148
+ type: "object",
149
+ additionalProperties: false,
150
+ properties: {
151
+ memory: {
152
+ type: "object",
153
+ additionalProperties: false,
154
+ properties: {
155
+ id: { type: "string", required: true },
156
+ title: { type: "string", required: true },
157
+ content: { type: "string", required: true }
158
+ }
159
+ }
160
+ }
161
+ },
162
+ render: (_args, value) => TEXT_OUTPUT(`Updated memory ${value.memory.id}: ${value.memory.title}`)
163
+ },
164
+ async execute(args) {
165
+ const memory = service.update(args.id, {
166
+ title: args.title,
167
+ content: args.content,
168
+ type: args.type,
169
+ tags: args.tags,
170
+ importance: args.importance
171
+ }, { query: args.reason });
172
+ return { memory: { id: memory.id, title: memory.title, content: memory.content } };
173
+ }
174
+ }),
175
+
176
+ defineTool({
177
+ name: "memory_delete",
178
+ description: "Permanently delete a memory entry.",
179
+ parameters: {
180
+ id: { type: "string", required: true }
181
+ },
182
+ output: {
183
+ schema: {
184
+ type: "object",
185
+ additionalProperties: false,
186
+ properties: { deleted: { type: "boolean", required: true } }
187
+ },
188
+ render: (_args, value) => TEXT_OUTPUT(value.deleted ? "Memory deleted." : "Memory not found.")
189
+ },
190
+ async execute(args) {
191
+ const existed = service.getById(args.id) !== undefined;
192
+ if (existed) service.remove(args.id);
193
+ return { deleted: existed };
194
+ }
195
+ }),
196
+
197
+ defineTool({
198
+ name: "memory_forget",
199
+ description:
200
+ "Stop a memory from being auto-injected and from appearing in searches and lists without deleting it. " +
201
+ "The entry stays in storage; pass forgotten: false to restore it.",
202
+ parameters: {
203
+ id: { type: "string", required: true },
204
+ forgotten: { type: "boolean", description: "Suppress (true, default) or restore (false) the entry's visibility" }
205
+ },
206
+ output: {
207
+ schema: {
208
+ type: "object",
209
+ additionalProperties: false,
210
+ properties: {
211
+ memory: {
212
+ type: "object",
213
+ additionalProperties: false,
214
+ properties: {
215
+ id: { type: "string", required: true },
216
+ forgotten: { type: "boolean", required: true }
217
+ }
218
+ }
219
+ }
220
+ },
221
+ render: (_args, value) => TEXT_OUTPUT(`Memory ${value.memory.id} injection ${value.memory.forgotten ? "suppressed" : "restored"}.`)
222
+ },
223
+ async execute(args) {
224
+ if (service.getById(args.id) === undefined) {
225
+ throw new Error("memory not found");
226
+ }
227
+ const memory = service.setForget(args.id, args.forgotten ?? true);
228
+ return { memory: { id: memory.id, forgotten: memory.forgotten } };
229
+ }
230
+ }),
231
+
232
+ defineTool({
233
+ name: "memory_archive",
234
+ description:
235
+ "Archive a memory (hide it from active lists, search, injection and dream consolidation) or restore it. " +
236
+ "Archived entries stay in storage and are recoverable: pass archived=false to restore, and use memory_list with " +
237
+ "include_archived=true to find archived entries.",
238
+ parameters: {
239
+ id: { type: "string", required: true, description: "Memory id" },
240
+ archived: { type: "boolean", description: "Archive (true, default) or restore (false) the entry" }
241
+ },
242
+ output: {
243
+ schema: {
244
+ type: "object",
245
+ additionalProperties: false,
246
+ properties: {
247
+ memory: {
248
+ type: "object",
249
+ additionalProperties: false,
250
+ properties: {
251
+ id: { type: "string", required: true },
252
+ archived: { type: "boolean", required: true }
253
+ }
254
+ }
255
+ }
256
+ },
257
+ render: (_args, value) => TEXT_OUTPUT(`Memory ${value.memory.id} ${value.memory.archived ? "archived" : "restored"}.`)
258
+ },
259
+ async execute(args) {
260
+ if (service.getById(args.id) === undefined) {
261
+ throw new Error("memory not found");
262
+ }
263
+ const memory = service.setArchived(args.id, args.archived ?? true);
264
+ return { memory: { id: memory.id, archived: memory.archived } };
265
+ }
266
+ })
267
+ ];
268
+
269
+ for (const tool of tools) {
270
+ ctx.tools.register(tool);
271
+ }
272
+
273
+ return tools;
274
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@modusensus/dsh-mneme",
3
- "version": "0.7.10",
4
- "description": "Structured memory engine for DeepSeek Harness. Offline semantic search, entity-attribute-timeline, autoDream self-consolidation, and human-editable Markdown storage.",
3
+ "description": "Cross-session memory plugin for DeepSeek Harness with autoDream consolidation: SQLite store, Markdown mirrors, 7 model tools, automatic injection, session summarization, user profile/rules, custom slash commands, vector (semantic) search, and a Web GUI panel",
4
+ "version": "0.7.12",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -12,16 +12,27 @@
12
12
  "url": "https://github.com/modusensus/dsh-mneme/issues"
13
13
  },
14
14
  "type": "module",
15
- "main": "./dsh-mneme/lib/index.js",
15
+ "main": "lib/index.js",
16
+ "bin": {
17
+ "dsh-mneme": "bin/cli.mjs"
18
+ },
16
19
  "exports": {
17
20
  ".": {
18
- "default": "./dsh-mneme/lib/index.js"
21
+ "default": "./lib/index.js"
19
22
  },
20
23
  "./client": {
21
- "default": "./dsh-mneme/lib/client.js"
24
+ "default": "./lib/client.js"
22
25
  },
23
- "./package.json": "./dsh-mneme/package.json"
26
+ "./package.json": "./package.json"
24
27
  },
28
+ "files": [
29
+ "bin",
30
+ "lib",
31
+ "src",
32
+ "scripts",
33
+ "test",
34
+ "cordis.patch.yml"
35
+ ],
25
36
  "dsh": {
26
37
  "client": {
27
38
  "inject": [
@@ -33,21 +44,9 @@
33
44
  "platform": "web"
34
45
  },
35
46
  "bundle": {
36
- "patch": "./dsh-mneme/cordis.patch.yml"
37
- },
38
- "marketplace": {
39
- "profiles": [
40
- "web"
41
- ],
42
- "requiresBuildApproval": false,
43
- "requiresRestart": true,
44
- "manualSteps": false
47
+ "patch": "./cordis.patch.yml"
45
48
  }
46
49
  },
47
- "scripts": {
48
- "prepack": "node dsh-mneme/scripts/check-sync.js",
49
- "prepublishOnly": "node -e \"const fs=require('fs');const v=JSON.parse(fs.readFileSync('./dsh-mneme/package.json','utf8')).version;const p=JSON.parse(fs.readFileSync('./package.json','utf8'));p.version=v;fs.writeFileSync('./package.json',JSON.stringify(p,null,2)+'\\n')\""
50
- },
51
50
  "peerDependencies": {
52
51
  "@deepseek-ai/cordis": "^4.0.1",
53
52
  "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6",
@@ -55,5 +54,32 @@
55
54
  "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
56
55
  "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
57
56
  "@deepseek-ai/schemastery": "^3.18.1"
57
+ },
58
+ "devDependencies": {
59
+ "@deepseek-ai/cordis": "^4.0.1",
60
+ "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6",
61
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
62
+ "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
63
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
64
+ "@deepseek-ai/schemastery": "^3.18.1",
65
+ "lucide": "^1.42.0"
66
+ },
67
+ "scripts": {
68
+ "sync": "node scripts/sync-lib.js",
69
+ "prepack": "npm run sync",
70
+ "test": "node --test test/*.test.js",
71
+ "e2e": "node scripts/e2e-dsh.js",
72
+ "stress": "node scripts/stress-dsh.js"
73
+ },
74
+ "dependencies": {
75
+ "@huggingface/transformers": "^4.2.0",
76
+ "morphicons": "^1.7.1"
77
+ },
78
+ "overrides": {
79
+ "adm-zip": "0.6.0"
80
+ },
81
+ "allowScripts": {
82
+ "onnxruntime-node@1.24.3": true,
83
+ "sharp@0.34.5": true
58
84
  }
59
85
  }
@@ -106,10 +106,9 @@ console.log("【1】插件装载");
106
106
  const checks = [];
107
107
  checks.push(["注册 7 个模型工具", registeredTools.length === 7]);
108
108
  checks.push(["注册 2 个注入上下文", injectContexts.length === 2 && injectContexts[0].name === "memory"]);
109
- // 契约是 20 条 exact 路由(实体清单接口后由 19 条扩到 20 条);该断言此前
110
- // 长期停在 9 条失去意义,现与 src/api.js routes 返回值对齐,prefix
111
- // fallback(/api/dsh-mneme 404)是兜底,不计入路由数。
112
- checks.push(["注册 20 条 API 路由", apiRoutes.filter((r) => r.kind === "exact").length === 20]);
109
+ // 契约是 14 条 exact 路由(v0.3 实体清单接口后由 13 条扩到 14 条);
110
+ // prefix fallback(/api/dsh-mneme 404)是兜底,不计入路由数。
111
+ checks.push(["注册 14 API 路由", apiRoutes.filter((r) => r.kind === "exact").length === 14]);
113
112
  for (const [label, ok] of checks) console.log(` ${ok ? "✅" : "❌"} ${label}`);
114
113
  if (!checks.every(([, ok]) => ok)) { console.log("\n装载检查失败,中止。"); process.exit(1); }
115
114
  console.log(` 工具:${registeredTools.map((t) => t.name).join(", ")}\n`);
@@ -1,16 +1,11 @@
1
1
  // Sync the src/ tree into lib/ — the distributable consumed by DSH (package
2
- // main is lib/index.js). src/ is the single source of truth for every module,
3
- // including client.js (the Web panel bundle); the sync only copies
4
- // src -> lib and never prunes output files.
2
+ // main is lib/index.js). lib/client.js (the Web panel bundle) is authored
3
+ // independently under lib/ and is left untouched: the sync only copies
4
+ // src -> lib, it never prunes lib-only files.
5
5
  //
6
6
  // Usage: npm run sync (also run automatically by `npm pack`/`npm publish`
7
7
  // via the prepack hook, so a published tarball always ships a fresh lib/).
8
- //
9
- // Note: copyFileSync (not cpSync) is used on purpose — cpSync removes the
10
- // destination first, which fails with EPERM/unlink on Windows when the path
11
- // is long enough to trigger the \\?\ extended-prefix (observed on publish).
12
- // copyFileSync truncates and rewrites in place, so it survives long paths.
13
- import { copyFileSync, existsSync, mkdirSync, readdirSync } from "node:fs";
8
+ import { cpSync, existsSync, mkdirSync, readdirSync } from "node:fs";
14
9
  import { join, relative } from "node:path";
15
10
  import { fileURLToPath } from "node:url";
16
11
 
@@ -36,7 +31,7 @@ for (const file of walk(srcDir)) {
36
31
  const rel = relative(srcDir, file);
37
32
  const dest = join(libDir, rel);
38
33
  mkdirSync(join(dest, ".."), { recursive: true });
39
- copyFileSync(file, dest);
34
+ cpSync(file, dest);
40
35
  copied++;
41
36
  console.log(`synced ${rel}`);
42
37
  }