@pcircle/memesh 4.4.0 → 4.5.1

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 (198) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.mcp.json +1 -1
  4. package/README.de.md +32 -12
  5. package/README.es.md +13 -12
  6. package/README.fr.md +31 -11
  7. package/README.ja.md +13 -12
  8. package/README.ko.md +14 -13
  9. package/README.md +41 -16
  10. package/README.pt.md +30 -10
  11. package/README.th.md +16 -9
  12. package/README.vi.md +32 -12
  13. package/README.zh-CN.md +14 -13
  14. package/README.zh-TW.md +14 -13
  15. package/dashboard/dist/index.html +10 -10
  16. package/dist/cli/view-live.js +1 -1
  17. package/dist/cli/view.d.ts.map +1 -1
  18. package/dist/cli/view.js +2 -2
  19. package/dist/cli/view.js.map +1 -1
  20. package/dist/core/analytics.d.ts +7 -3
  21. package/dist/core/analytics.d.ts.map +1 -1
  22. package/dist/core/analytics.js +8 -8
  23. package/dist/core/analytics.js.map +1 -1
  24. package/dist/core/auto-tagger.d.ts.map +1 -1
  25. package/dist/core/auto-tagger.js.map +1 -1
  26. package/dist/core/config.d.ts +5 -3
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/config.js +30 -14
  29. package/dist/core/config.js.map +1 -1
  30. package/dist/core/demo.d.ts +2 -2
  31. package/dist/core/demo.d.ts.map +1 -1
  32. package/dist/core/demo.js.map +1 -1
  33. package/dist/core/digest-validator.d.ts.map +1 -1
  34. package/dist/core/digest-validator.js +3 -1
  35. package/dist/core/digest-validator.js.map +1 -1
  36. package/dist/core/doctor.d.ts +3 -0
  37. package/dist/core/doctor.d.ts.map +1 -1
  38. package/dist/core/doctor.js +255 -101
  39. package/dist/core/doctor.js.map +1 -1
  40. package/dist/core/dreamer.d.ts +35 -7
  41. package/dist/core/dreamer.d.ts.map +1 -1
  42. package/dist/core/dreamer.js +394 -41
  43. package/dist/core/dreamer.js.map +1 -1
  44. package/dist/core/embedder.d.ts +3 -5
  45. package/dist/core/embedder.d.ts.map +1 -1
  46. package/dist/core/embedder.js +26 -95
  47. package/dist/core/embedder.js.map +1 -1
  48. package/dist/core/extractor.d.ts.map +1 -1
  49. package/dist/core/extractor.js +2 -1
  50. package/dist/core/extractor.js.map +1 -1
  51. package/dist/core/failure-analyzer.d.ts.map +1 -1
  52. package/dist/core/failure-analyzer.js +2 -1
  53. package/dist/core/failure-analyzer.js.map +1 -1
  54. package/dist/core/graph.d.ts +4 -4
  55. package/dist/core/graph.d.ts.map +1 -1
  56. package/dist/core/graph.js.map +1 -1
  57. package/dist/core/install-hooks.d.ts +1 -0
  58. package/dist/core/install-hooks.d.ts.map +1 -1
  59. package/dist/core/install-hooks.js +0 -0
  60. package/dist/core/install-hooks.js.map +1 -1
  61. package/dist/core/kg-backfill.d.ts +4 -4
  62. package/dist/core/kg-backfill.d.ts.map +1 -1
  63. package/dist/core/kg-backfill.js +1 -1
  64. package/dist/core/kg-backfill.js.map +1 -1
  65. package/dist/core/lesson-engine.d.ts +1 -0
  66. package/dist/core/lesson-engine.d.ts.map +1 -1
  67. package/dist/core/lesson-engine.js +1 -0
  68. package/dist/core/lesson-engine.js.map +1 -1
  69. package/dist/core/lifecycle.d.ts +4 -4
  70. package/dist/core/lifecycle.d.ts.map +1 -1
  71. package/dist/core/lifecycle.js +1 -1
  72. package/dist/core/lifecycle.js.map +1 -1
  73. package/dist/core/llm-client.d.ts.map +1 -1
  74. package/dist/core/llm-client.js +3 -6
  75. package/dist/core/llm-client.js.map +1 -1
  76. package/dist/core/llm-telemetry.d.ts +4 -4
  77. package/dist/core/llm-telemetry.d.ts.map +1 -1
  78. package/dist/core/llm-telemetry.js +1 -1
  79. package/dist/core/llm-telemetry.js.map +1 -1
  80. package/dist/core/llm-validator.d.ts +1 -0
  81. package/dist/core/llm-validator.d.ts.map +1 -1
  82. package/dist/core/llm-validator.js +33 -10
  83. package/dist/core/llm-validator.js.map +1 -1
  84. package/dist/core/memory-tool.d.ts.map +1 -1
  85. package/dist/core/memory-tool.js +4 -0
  86. package/dist/core/memory-tool.js.map +1 -1
  87. package/dist/core/operations.d.ts.map +1 -1
  88. package/dist/core/operations.js +23 -8
  89. package/dist/core/operations.js.map +1 -1
  90. package/dist/core/output-language.d.ts +6 -0
  91. package/dist/core/output-language.d.ts.map +1 -0
  92. package/dist/core/output-language.js +25 -0
  93. package/dist/core/output-language.js.map +1 -0
  94. package/dist/core/paths.d.ts +3 -0
  95. package/dist/core/paths.d.ts.map +1 -1
  96. package/dist/core/paths.js +67 -1
  97. package/dist/core/paths.js.map +1 -1
  98. package/dist/core/patterns.d.ts +2 -3
  99. package/dist/core/patterns.d.ts.map +1 -1
  100. package/dist/core/patterns.js +1 -5
  101. package/dist/core/patterns.js.map +1 -1
  102. package/dist/core/project-tags.d.ts +3 -3
  103. package/dist/core/project-tags.d.ts.map +1 -1
  104. package/dist/core/project-tags.js.map +1 -1
  105. package/dist/core/projects.d.ts +2 -2
  106. package/dist/core/projects.d.ts.map +1 -1
  107. package/dist/core/projects.js.map +1 -1
  108. package/dist/core/schema-export.d.ts.map +1 -1
  109. package/dist/core/schema-export.js +0 -34
  110. package/dist/core/schema-export.js.map +1 -1
  111. package/dist/core/serializer.d.ts.map +1 -1
  112. package/dist/core/serializer.js +45 -4
  113. package/dist/core/serializer.js.map +1 -1
  114. package/dist/core/stats.d.ts +2 -2
  115. package/dist/core/stats.d.ts.map +1 -1
  116. package/dist/core/stats.js.map +1 -1
  117. package/dist/core/transcript-extractor.d.ts +88 -0
  118. package/dist/core/transcript-extractor.d.ts.map +1 -0
  119. package/dist/core/transcript-extractor.js +417 -0
  120. package/dist/core/transcript-extractor.js.map +1 -0
  121. package/dist/core/transcript-source.d.ts +21 -0
  122. package/dist/core/transcript-source.d.ts.map +1 -0
  123. package/dist/core/transcript-source.js +142 -0
  124. package/dist/core/transcript-source.js.map +1 -0
  125. package/dist/core/types.d.ts +17 -7
  126. package/dist/core/types.d.ts.map +1 -1
  127. package/dist/core/types.js +2 -0
  128. package/dist/core/types.js.map +1 -1
  129. package/dist/db.d.ts +5 -5
  130. package/dist/db.d.ts.map +1 -1
  131. package/dist/db.js +165 -17
  132. package/dist/db.js.map +1 -1
  133. package/dist/knowledge-graph.d.ts +3 -2
  134. package/dist/knowledge-graph.d.ts.map +1 -1
  135. package/dist/knowledge-graph.js +19 -10
  136. package/dist/knowledge-graph.js.map +1 -1
  137. package/dist/mcp/server.js +2 -1
  138. package/dist/mcp/server.js.map +1 -1
  139. package/dist/skills-manifest.json +28 -33
  140. package/dist/storage/conflicts.d.ts +3 -3
  141. package/dist/storage/conflicts.d.ts.map +1 -1
  142. package/dist/storage/conflicts.js.map +1 -1
  143. package/dist/storage/fts-index.d.ts +4 -4
  144. package/dist/storage/fts-index.d.ts.map +1 -1
  145. package/dist/storage/fts-index.js.map +1 -1
  146. package/dist/storage/sqlite.d.ts +20 -0
  147. package/dist/storage/sqlite.d.ts.map +1 -0
  148. package/dist/storage/sqlite.js +64 -0
  149. package/dist/storage/sqlite.js.map +1 -0
  150. package/dist/storage/vector-index.d.ts +3 -0
  151. package/dist/storage/vector-index.d.ts.map +1 -0
  152. package/dist/storage/vector-index.js +7 -0
  153. package/dist/storage/vector-index.js.map +1 -0
  154. package/dist/transports/cli/cli.d.ts.map +1 -1
  155. package/dist/transports/cli/cli.js +278 -91
  156. package/dist/transports/cli/cli.js.map +1 -1
  157. package/dist/transports/http/retired-routes.d.ts.map +1 -1
  158. package/dist/transports/http/retired-routes.js +1 -0
  159. package/dist/transports/http/retired-routes.js.map +1 -1
  160. package/dist/transports/http/server.d.ts +7 -0
  161. package/dist/transports/http/server.d.ts.map +1 -1
  162. package/dist/transports/http/server.js +165 -79
  163. package/dist/transports/http/server.js.map +1 -1
  164. package/dist/transports/mcp/handlers.d.ts +4 -96
  165. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  166. package/dist/transports/mcp/handlers.js +26 -59
  167. package/dist/transports/mcp/handlers.js.map +1 -1
  168. package/dist/transports/schemas.d.ts +10 -30
  169. package/dist/transports/schemas.d.ts.map +1 -1
  170. package/dist/transports/schemas.js +5 -29
  171. package/dist/transports/schemas.js.map +1 -1
  172. package/hooks/hooks.json +0 -10
  173. package/package.json +6 -19
  174. package/scripts/hooks/_generated/core-paths.js +67 -1
  175. package/scripts/hooks/_generated/sqlite.js +71 -0
  176. package/scripts/hooks/_shared.js +286 -195
  177. package/scripts/hooks/post-commit.js +52 -10
  178. package/scripts/hooks/pre-compact.js +10 -7
  179. package/scripts/hooks/pre-edit-recall.js +4 -8
  180. package/scripts/hooks/session-start.js +95 -47
  181. package/scripts/hooks/session-summary.js +120 -52
  182. package/scripts/hooks/user-prompt-intent.js +3 -2
  183. package/skills/memesh/SKILL.md +3 -2
  184. package/dist/core/skill-usage-log.d.ts +0 -11
  185. package/dist/core/skill-usage-log.d.ts.map +0 -1
  186. package/dist/core/skill-usage-log.js +0 -125
  187. package/dist/core/skill-usage-log.js.map +0 -1
  188. package/dist/core/verifier.d.ts +0 -40
  189. package/dist/core/verifier.d.ts.map +0 -1
  190. package/dist/core/verifier.js +0 -206
  191. package/dist/core/verifier.js.map +0 -1
  192. package/dist/mcp/launcher.d.ts +0 -3
  193. package/dist/mcp/launcher.d.ts.map +0 -1
  194. package/dist/mcp/launcher.js +0 -37
  195. package/dist/mcp/launcher.js.map +0 -1
  196. package/scripts/hooks/pre-bash-orchestration-nudge.js +0 -155
  197. package/scripts/postinstall-rebuild.mjs +0 -41
  198. package/skills/agentic-orchestration/SKILL.md +0 -399
@@ -3,6 +3,22 @@
3
3
  // Session Auto-Capture — Stop hook
4
4
  // Extracts knowledge from completed Claude Code sessions
5
5
  // and stores as session-insight entities in MeMesh.
6
+ //
7
+ // THIS HOOK STAYS, and that was an open question rather than an assumption.
8
+ // `dream run --from-transcripts` reads the same sessions from their raw JSONL
9
+ // and does not depend on this hook having fired, so the obvious next step was
10
+ // to retire the hook as redundant. Measured first, on a real graph
11
+ // (2026-08-09, 214 active entities, ollama nomic-embed-text, L2 over the same
12
+ // `name + observations` text the runtime embeds):
13
+ //
14
+ // every transcript-mined memory -> its nearest hook-captured entity
15
+ // min 0.784 p25 0.821 p50 0.865 max 0.946
16
+ // within 0.55: 0 of 47. within 0.70: 0 of 47.
17
+ //
18
+ // Nothing the transcript miner produced came within 0.78 of anything this hook
19
+ // recorded. They are not two views of the same material: this hook records what
20
+ // HAPPENED (files touched, commands run, commits), the miner extracts what was
21
+ // DECIDED and what was LEARNED. Retiring either one loses a whole category.
6
22
 
7
23
  import { createRequire } from 'module';
8
24
  import { basename, join } from 'path';
@@ -11,6 +27,7 @@ import { spawn } from 'child_process';
11
27
  import os from 'os';
12
28
  import { pathToFileURL } from 'url';
13
29
  import {
30
+ AUTO_CAPTURE_TAG,
14
31
  captureEntity,
15
32
  decideAutoUpdateHook,
16
33
  getMemeshDirFromDbPath,
@@ -19,6 +36,8 @@ import {
19
36
  isAutoCaptureEnabled,
20
37
  openHookDb,
21
38
  readUpdateCheckCache,
39
+ recordHookRun,
40
+ stampHookRunOnly,
22
41
  resolveAutoUpdatePolicy,
23
42
  resolvePluginRoot,
24
43
  spawnAutoUpdate,
@@ -70,6 +89,7 @@ function parseTranscript(transcriptPath) {
70
89
  const bashCommands = [];
71
90
  const errorsEncountered = [];
72
91
  let toolCallCount = 0;
92
+ let readFailed = false;
73
93
 
74
94
  try {
75
95
  const lines = readFileSync(transcriptPath, 'utf8').split('\n').filter(l => l.trim());
@@ -133,10 +153,15 @@ function parseTranscript(transcriptPath) {
133
153
  } catch (err) {
134
154
  // The transcript file itself could not be read, which empties this
135
155
  // session's entire capture — filesEdited/errors/toolCallCount all return
136
- // zero, so downstream `toolCallCount < 3` bails and no session insight,
137
- // failure analysis or lesson is produced. An absent file is the normal
138
- // "not written yet" case; anything else is a real fault worth a trace.
156
+ // zero. Left unflagged, those zeros are indistinguishable from a
157
+ // genuinely quiet session, and the light-session bail downstream would
158
+ // STAMP the heartbeat repeated permission/I-O failures keeping doctor
159
+ // green while every session's capture is lost. `readFailed` is the
160
+ // distinct signal: capture was lost, not skipped. An absent file
161
+ // (ENOENT) is the vanished-transcript race, which the caller already
162
+ // treats as a correct nothing-to-do decision.
139
163
  if (err?.code !== 'ENOENT') {
164
+ readFailed = true;
140
165
  try {
141
166
  process.stderr.write(
142
167
  `[memesh session-summary] transcript ${transcriptPath} unreadable ` +
@@ -146,7 +171,7 @@ function parseTranscript(transcriptPath) {
146
171
  }
147
172
  }
148
173
 
149
- return { filesEdited: [...filesEdited], bashCommands, errorsEncountered, toolCallCount };
174
+ return { filesEdited: [...filesEdited], bashCommands, errorsEncountered, toolCallCount, readFailed };
150
175
  }
151
176
 
152
177
  // Main: read stdin, extract insights, store in DB
@@ -176,7 +201,23 @@ process.stdin.on('end', async () => {
176
201
 
177
202
  const sessionId = inputData.session_id || 'unknown';
178
203
  const transcriptPath = inputData.transcript_path;
179
- const cwd = inputData.cwd || process.cwd();
204
+
205
+ // `cwd` decides the project tag, and the project tag decides which
206
+ // sessions `session-start` injects and which memories `pre-edit-recall`
207
+ // surfaces. Falling back to `process.cwd()` — the hook process's launch
208
+ // directory, which is unspecified for a Stop hook — tagged the session with
209
+ // whatever happened to be current. Measured: a payload with no `cwd` filed
210
+ // the whole session under `project:memesh-llm-memory`, a project it had
211
+ // nothing to do with, silently. That leaks one project's file names, bash
212
+ // commands and error text into another project's context.
213
+ //
214
+ // `post-commit` refuses this exact case and says why: better to miss one
215
+ // capture than to file it under the wrong project. Same rule here.
216
+ if (!inputData.cwd) {
217
+ try { process.stderr.write(`[memesh session-summary] cwd absent in payload (keys: ${Object.keys(inputData).join(',')}); cannot resolve project, skipping capture\n`); } catch {}
218
+ return exit0();
219
+ }
220
+ const cwd = inputData.cwd;
180
221
  // Default-allow: when Claude Code's Stop payload omits
181
222
  // `was_in_agentic_loop` (it has been silently absent in production
182
223
  // for an unknown number of releases — symptom: zero session-insight
@@ -198,7 +239,13 @@ process.stdin.on('end', async () => {
198
239
  // but did nothing, the exact sibling of the `was_in_agentic_loop` absence
199
240
  // above. Removed; the `toolCallCount < 3` check below is the real
200
241
  // low-signal filter.
201
- if (!wasAgenticLoop) return exit0();
242
+ // From here down the payload is well-formed and attributable — every
243
+ // bail is the hook deciding "nothing worth saving", which is a
244
+ // successful run and stamps the heartbeat. The bails ABOVE this line
245
+ // (empty stdin, malformed JSON, missing cwd) are schema-flip shapes: if
246
+ // Claude Code's payload changed under us, capture is effectively dead,
247
+ // and a heartbeat would mask exactly that.
248
+ if (!wasAgenticLoop) { stampHookRunOnly(process.env, 'session-summary'); return exit0(); }
202
249
  // Trace why we're skipping. Two failure modes:
203
250
  // (a) transcript_path absent — schema flip, Claude Code stopped
204
251
  // sending the field. Same bug shape as `was_in_agentic_loop`
@@ -214,14 +261,25 @@ process.stdin.on('end', async () => {
214
261
  }
215
262
  if (!existsSync(transcriptPath)) {
216
263
  try { process.stderr.write(`[memesh session-summary] transcript_path ${transcriptPath} does not exist; skipping capture\n`); } catch {}
264
+ // The payload named a transcript and the FILE is gone (log rotation
265
+ // race) — the hook itself ran fine, so this stamps. A payload that
266
+ // never carried the field at all (schema flip) bails above, unstamped.
267
+ stampHookRunOnly(process.env, 'session-summary');
217
268
  return exit0();
218
269
  }
219
270
 
220
271
  // Parse transcript
221
- const { filesEdited, bashCommands, errorsEncountered, toolCallCount } = parseTranscript(transcriptPath);
272
+ const { filesEdited, bashCommands, errorsEncountered, toolCallCount, readFailed } = parseTranscript(transcriptPath);
273
+
274
+ // An unreadable transcript is NOT a quiet session: the capture was
275
+ // LOST (permissions, I/O), and a heartbeat here would keep doctor green
276
+ // through exactly the repeated failure it exists to expose. No stamp —
277
+ // parseTranscript already traced the fault to stderr.
278
+ if (readFailed) return exit0();
222
279
 
223
- // Skip sessions with too little activity
224
- if (toolCallCount < 3) return exit0();
280
+ // Skip sessions with too little activity — the single most common
281
+ // healthy exit, so it MUST stamp (see stampHookRunOnly).
282
+ if (toolCallCount < 3) { stampHookRunOnly(process.env, 'session-summary'); return exit0(); }
225
283
 
226
284
  // Hoisted to outer-try scope so the LLM failure-analysis block
227
285
  // below (which runs AFTER db.close()) can reference it. Earlier
@@ -232,36 +290,27 @@ process.stdin.on('end', async () => {
232
290
  const projectName = getProjectName(cwd);
233
291
 
234
292
  // Open DB via shared helper — applies SCHEMA_SQL + status migration.
235
- // sqlite-vec is loaded separately because only this hook needs it
236
- // (for embedding-aware recall-effectiveness tracking).
237
293
  // { fts: true } guarantees the entities_fts table exists so captureEntity()
238
294
  // can keep it in sync — session-insight memories must be FTS-recallable.
239
- const handle = openHookDb(process.env, { fts: true });
240
- if (!handle) {
241
- // Native module unavailable (plugin-marketplace cache install with no
242
- // node_modules). Skip session-capture work, but still let the
243
- // auto-update tail below run auto-update is a separate concern from
244
- // session-capture, and a transient DB-availability blip should not
245
- // mask a security-override patch upgrade. Throwing this sentinel
246
- // routes through the existing catch, which already stderr-traces;
247
- // execution then falls through to runAutoUpdateAtStop().
248
- throw new Error('skip-session-capture: better-sqlite3 unavailable');
249
- }
250
- const { db } = handle;
251
- // sqlite-vec is also a native module; same plugin-cache scenario applies
252
- // (the cache tarball ships neither node_module). Resolve through a
253
- // try/require here so a missing vec module degrades the same way as a
254
- // missing better-sqlite3 instead of throwing into the outer catch as a
255
- // bug-shaped error.
256
- let sqliteVec;
257
- try {
258
- sqliteVec = require('sqlite-vec');
259
- } catch {
260
- throw new Error('skip-session-capture: sqlite-vec unavailable');
261
- }
295
+ //
296
+ // sqlite-vec is NOT loaded here, and used to be. The comment said it was
297
+ // needed "for embedding-aware recall-effectiveness tracking" but this
298
+ // hook runs exactly two statements, `PRAGMA table_info(entities)` and
299
+ // `SELECT id FROM entities WHERE name = ?`, and `captureEntity` in
300
+ // _shared.js touches no vectors either. Nothing here has ever used the
301
+ // extension.
302
+ //
303
+ // It was not free. sqlite-vec ships its engine as a per-platform file
304
+ // through optionalDependencies, and on a platform it does not publish the
305
+ // load threw — past the `require` guard, which never fired because the JS
306
+ // wrapper resolves fine and the throw happens later inside
307
+ // `sqliteVec.load()`. Measured with the platform binary hidden: the whole
308
+ // Stop capture vanished (0 entities against a control run's 1) and the
309
+ // user got a `Require stack:` dump on stderr. An extension nobody calls
310
+ // was silently costing every session on those platforms its memory.
311
+ const { db } = openHookDb(process.env, { fts: true });
312
+ let writeFailed = false;
262
313
  try {
263
- sqliteVec.load(db);
264
-
265
314
  // Duplicate detection: if we already captured this session, bail.
266
315
  //
267
316
  // Use the FULL session_id rather than the first 8 chars: real
@@ -270,11 +319,18 @@ process.stdin.on('end', async () => {
270
319
  // share the prefix and silently skipped the second session
271
320
  // entirely. The contract is one stored capture per distinct
272
321
  // session_id, so the dedup key has to be the full id.
322
+ //
323
+ // A dedup bail is a SUCCESSFUL run — the loop executed and correctly
324
+ // decided there was nothing to do — so it stamps the heartbeat like
325
+ // the capture path below does. Only a throw leaves no stamp.
273
326
  const alreadyCaptured = db.prepare("SELECT id FROM entities WHERE name = ?").get(`session-${sessionId}-files`);
274
- if (alreadyCaptured) return exit0();
327
+ if (alreadyCaptured) {
328
+ recordHookRun(db, 'session-summary');
329
+ return exit0();
330
+ }
275
331
 
276
332
  // Build and store session memories
277
- const baseTags = ['source:auto-capture', `session:${sessionId}`, `project:${projectName}`];
333
+ const baseTags = [AUTO_CAPTURE_TAG, `session:${sessionId}`, `project:${projectName}`];
278
334
 
279
335
  // Producer for pre-edit-recall's Strategy 1 (`file:<name>` tag lookup).
280
336
  // That read path queries both the full basename and the extension-less
@@ -299,7 +355,11 @@ process.stdin.on('end', async () => {
299
355
  // only, skipping the FTS reindex the sibling hooks did — which left every
300
356
  // session-insight memory unrecallable via the FTS keyword path.
301
357
  function storeMemory(name, type, observations, tags) {
302
- captureEntity(db, { name, type, observations, tags });
358
+ // null = the entity row could not be resolved = this write did NOT
359
+ // happen (captureEntity's contract). A run with a failed write must
360
+ // not stamp the heartbeat below — "alive" would be a lie about the
361
+ // exact thing the heartbeat certifies.
362
+ if (!captureEntity(db, { name, type, observations, tags })) writeFailed = true;
303
363
  }
304
364
 
305
365
  // Rule 1: File editing session summary
@@ -446,6 +506,14 @@ process.stdin.on('end', async () => {
446
506
  // missing-column failure is visible without crashing the hook.
447
507
  try { process.stderr.write(`[memesh session-summary] recall-effectiveness write: ${err?.message || err}\n`); } catch {}
448
508
  }
509
+
510
+ // Heartbeat AFTER capture, so the stamp certifies "the capture loop
511
+ // completed", not "a database handle existed". A throw above skips it,
512
+ // and so does a captureEntity null return (writeFailed) — a run whose
513
+ // write did not land must not read as alive. (The recall-effectiveness
514
+ // block catches its own errors — session memories were already stored
515
+ // by then, so the run still counts.)
516
+ if (!writeFailed) recordHookRun(db, 'session-summary');
449
517
  } finally {
450
518
  db.close();
451
519
  }
@@ -502,12 +570,12 @@ process.stdin.on('end', async () => {
502
570
  }
503
571
  } catch (err) {
504
572
  // Never crash Claude Code — leave a trace for debugging.
505
- // Suppress the expected "skip-session-capture" sentinel (raised when
506
- // better-sqlite3 is unavailable in a marketplace-cache install). All
507
- // other errors are real bugs and deserve a trace.
508
- if (!String(err?.message || '').startsWith('skip-session-capture:')) {
509
- try { process.stderr.write(`[memesh session-summary] ${err?.message || err}\n`); } catch {}
510
- }
573
+ //
574
+ // Every error is traced now. There used to be a suppression branch for a
575
+ // `skip-session-capture:` sentinel, thrown when sqlite-vec was missing
576
+ // an extension this hook never used. The thrower is gone, so the branch
577
+ // could only ever hide a real error from here on.
578
+ try { process.stderr.write(`[memesh session-summary] ${err?.message || err}\n`); } catch {}
511
579
  }
512
580
 
513
581
  // Spawn auto-update if policy + cache permit. Runs after all session work
@@ -643,18 +711,18 @@ function writeDreamHistory(history) {
643
711
 
644
712
  /**
645
713
  * Count episodic entities for the given project over the configured
646
- * window. Read-only uses the hook's _shared openHookDb helper which
647
- * is already on the import path.
714
+ * window. Only issues a SELECT, but the handle is openHookDb's ordinary
715
+ * read-write one (it runs the schema/migration chain) — there is no
716
+ * read-only variant on the hook side, and this call site must not stamp
717
+ * the heartbeat (recordHookRun is per-hook-exit, never per-open).
648
718
  */
649
719
  function countEpisodicEntities(projectName) {
650
720
  let handle;
651
721
  try {
652
722
  handle = openHookDb();
653
- // openHookDb returns null if better-sqlite3 isn't loadable;
654
- // otherwise { db, dbPath }. Don't try to call db.prepare() on
655
- // the wrapper itself (the previous version did and silently
656
- // skipped the gate, defeating the trigger's whole purpose).
657
- if (!handle?.db) return 0;
723
+ // { db, dbPath } don't call db.prepare() on the wrapper itself (an
724
+ // earlier version did, and silently skipped the gate, defeating the
725
+ // trigger's whole purpose).
658
726
  const db = handle.db;
659
727
  const since = new Date(Date.now() - DREAM_WINDOW_DAYS * 86400000).toISOString();
660
728
  const types = DREAM_EPISODIC_TYPES.map(() => '?').join(',');
@@ -81,7 +81,7 @@ export function buildHint() {
81
81
  '1. Decide WHAT to remember from the conversation context. Be specific — pick observations',
82
82
  ' that will be useful in *future* sessions, not session-local state.',
83
83
  '',
84
- '2. Decide the SCOPE (this drives namespace + tags):',
84
+ '2. Decide the SCOPE for a NEW memory (this drives namespace + tags):',
85
85
  ' • Machine-level / cross-project / preferences → memesh namespace=personal',
86
86
  ' • Project-internal decision / pattern / lesson → memesh + project tag (e.g. tag:project:memesh)',
87
87
  ' • Universal / public best practice → memesh namespace=global (rare)',
@@ -91,7 +91,8 @@ export function buildHint() {
91
91
  ' • type: one of (decision, pattern, lesson_learned, bug, process, preference, etc.)',
92
92
  ' • observations: array of specific facts / steps / rationale',
93
93
  ' • tags: relevant tags (programming language, framework, domain)',
94
- ' • namespace: personal (default) | team | global',
94
+ ' • namespace: personal | team | global — OMIT for a memory that already exists.',
95
+ ' Supplying it MOVES that memory out of the scope it is in.',
95
96
  '',
96
97
  '4. Confirm to the user with: entity name + memesh ID returned by the tool.',
97
98
  '</memesh-remember-intent>',
@@ -29,9 +29,8 @@ If MeMesh is installed as a Claude Code plugin, these happen **without any actio
29
29
 
30
30
  | Hook | When | What it does |
31
31
  |------|------|-------------|
32
- | **SessionStart** | Every session begins | Auto-recalls top memories for current project + surfaces lesson warnings + (opt-in) agentic-orchestration banner |
32
+ | **SessionStart** | Every session begins | Auto-recalls top memories for current project + surfaces lesson warnings |
33
33
  | **PreToolUse (Edit)** | Before editing files | Injects memories related to the file or project |
34
- | **PreToolUse (Bash)** | Before bash commands | (Opt-in) Nudges Claude to dispatch high-verifiability commands as background agents |
35
34
  | **UserPromptSubmit** | When you submit a prompt | Detects "remember this" intent (5 languages: en, es, fr, pt, zh-TW) and reminds Claude to use memesh |
36
35
  | **PostToolUse (Commit)** | After `git commit` | Auto-tracks commit with diff stats as a memory entity |
37
36
  | **Stop** | Session ends | Auto-captures session knowledge + runs LLM failure analysis → lessons |
@@ -104,7 +103,9 @@ Archives (soft-delete). Never permanently removes.
104
103
  ### Memories are getting verbose
105
104
  ```bash
106
105
  memesh dream run --project myapp # propose digests for clusters of noisy memories
106
+ memesh dream run --from-transcripts # OR: mine this project's Claude Code sessions for memory
107
107
  memesh dream list # review what it proposed
108
+ memesh dream show <id> # inspect one proposal in full before accepting
108
109
  memesh dream accept <id> # apply one, or: memesh dream reject <id>
109
110
  ```
110
111
  Nothing changes until a proposal is accepted, and sources are archived rather
@@ -1,11 +0,0 @@
1
- export declare function logSkillEvent(event: string, path?: string): void;
2
- export interface SkillUsageSummary {
3
- total_events: number;
4
- events_by_name: Record<string, number>;
5
- first_event?: string;
6
- last_event?: string;
7
- log_path: string;
8
- log_bytes: number;
9
- }
10
- export declare function summariseSkillUsage(path?: string): SkillUsageSummary;
11
- //# sourceMappingURL=skill-usage-log.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"skill-usage-log.d.ts","sourceRoot":"","sources":["../../src/core/skill-usage-log.ts"],"names":[],"mappings":"AAmIA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAqBhE;AAMD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAkCpE"}
@@ -1,125 +0,0 @@
1
- import { appendFileSync, chmodSync, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, renameSync, unlinkSync, writeFileSync, } from 'fs';
2
- import { dirname, join } from 'path';
3
- import { memeshDir } from './paths.js';
4
- const MAX_BYTES = 10 * 1024 * 1024;
5
- const TRUNCATE_KEEP = 6 * 1024 * 1024;
6
- function defaultLogPath() {
7
- return join(memeshDir(), 'skill-usage.jsonl');
8
- }
9
- function ensureParent(path) {
10
- try {
11
- const dir = dirname(path);
12
- if (!existsSync(dir))
13
- mkdirSync(dir, { recursive: true, mode: 0o700 });
14
- }
15
- catch {
16
- }
17
- }
18
- function rotateIfNeeded(path) {
19
- let fd = null;
20
- let tmpPath = null;
21
- try {
22
- try {
23
- fd = openSync(path, 'r');
24
- }
25
- catch {
26
- return;
27
- }
28
- const { size } = fstatSync(fd);
29
- if (size < MAX_BYTES * 1.2)
30
- return;
31
- const readLen = Math.min(TRUNCATE_KEEP, size);
32
- const offset = size - readLen;
33
- const buf = Buffer.alloc(readLen);
34
- let totalRead = 0;
35
- while (totalRead < readLen) {
36
- const n = readSync(fd, buf, totalRead, readLen - totalRead, offset + totalRead);
37
- if (n === 0)
38
- break;
39
- totalRead += n;
40
- }
41
- closeSync(fd);
42
- fd = null;
43
- const tail = buf.subarray(0, totalRead);
44
- const firstNl = tail.indexOf(0x0a);
45
- const aligned = firstNl >= 0 ? tail.subarray(firstNl + 1) : tail;
46
- tmpPath = `${path}.rot.${process.pid}.${Date.now()}`;
47
- writeFileSync(tmpPath, aligned, { mode: 0o600 });
48
- renameSync(tmpPath, path);
49
- tmpPath = null;
50
- }
51
- catch {
52
- }
53
- finally {
54
- if (fd !== null) {
55
- try {
56
- closeSync(fd);
57
- }
58
- catch { }
59
- }
60
- if (tmpPath !== null) {
61
- try {
62
- unlinkSync(tmpPath);
63
- }
64
- catch { }
65
- }
66
- }
67
- }
68
- export function logSkillEvent(event, path) {
69
- const target = path ?? defaultLogPath();
70
- try {
71
- ensureParent(target);
72
- rotateIfNeeded(target);
73
- const line = JSON.stringify({ ts: new Date().toISOString(), event }) + '\n';
74
- appendFileSync(target, line);
75
- try {
76
- chmodSync(target, 0o600);
77
- }
78
- catch { }
79
- }
80
- catch {
81
- }
82
- }
83
- export function summariseSkillUsage(path) {
84
- const target = path ?? defaultLogPath();
85
- const out = {
86
- total_events: 0,
87
- events_by_name: {},
88
- log_path: target,
89
- log_bytes: 0,
90
- };
91
- if (!existsSync(target))
92
- return out;
93
- let raw;
94
- try {
95
- const buf = readFileSync(target);
96
- out.log_bytes = buf.length;
97
- raw = buf.toString('utf8');
98
- }
99
- catch {
100
- return out;
101
- }
102
- for (const line of raw.split('\n')) {
103
- if (!line.trim())
104
- continue;
105
- let parsed;
106
- try {
107
- parsed = JSON.parse(line);
108
- }
109
- catch {
110
- continue;
111
- }
112
- if (!parsed.event || typeof parsed.event !== 'string')
113
- continue;
114
- out.total_events += 1;
115
- out.events_by_name[parsed.event] = (out.events_by_name[parsed.event] ?? 0) + 1;
116
- if (parsed.ts) {
117
- if (!out.first_event || parsed.ts < out.first_event)
118
- out.first_event = parsed.ts;
119
- if (!out.last_event || parsed.ts > out.last_event)
120
- out.last_event = parsed.ts;
121
- }
122
- }
123
- return out;
124
- }
125
- //# sourceMappingURL=skill-usage-log.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"skill-usage-log.js","sourceRoot":"","sources":["../../src/core/skill-usage-log.ts"],"names":[],"mappings":"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"}
@@ -1,40 +0,0 @@
1
- export interface ExternalCheck {
2
- pass: boolean;
3
- summary?: string;
4
- }
5
- export interface VerifyAgentWorkInput {
6
- agent_id: string;
7
- workdir: string;
8
- base?: string;
9
- claim?: {
10
- expected_files?: number;
11
- };
12
- report?: {
13
- pass: boolean;
14
- typecheck?: ExternalCheck;
15
- tests?: ExternalCheck;
16
- lint?: ExternalCheck;
17
- build?: ExternalCheck;
18
- summary?: string;
19
- };
20
- }
21
- export type Verdict = 'pass' | 'fail' | 'unverified';
22
- export interface RealityCheckResult {
23
- files_changed: number;
24
- expected_files: number | null;
25
- match: boolean | null;
26
- base: string | null;
27
- verdict: Verdict;
28
- pass: boolean;
29
- summary: string;
30
- }
31
- export interface VerifyAgentWorkResult {
32
- entity_name: string;
33
- verdict: Verdict;
34
- pass: boolean;
35
- reality_check: RealityCheckResult;
36
- external_report: VerifyAgentWorkInput['report'] | null;
37
- timestamp: string;
38
- }
39
- export declare function verifyAgentWork(input: VerifyAgentWorkInput): VerifyAgentWorkResult;
40
- //# sourceMappingURL=verifier.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/core/verifier.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,OAAO,CAAC;QACd,SAAS,CAAC,EAAE,aAAa,CAAC;QAC1B,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,IAAI,CAAC,EAAE,aAAa,CAAC;QACrB,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAmBD,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IAkBjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IAejB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,kBAAkB,CAAC;IAClC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACvD,SAAS,EAAE,MAAM,CAAC;CACnB;AA8OD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CA8DlF"}