@hir4ta/mneme 0.19.0 → 0.20.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/.claude-plugin/plugin.json +1 -1
- package/dist/lib/incremental-save.js +116 -8
- package/dist/public/assets/{index-CVJnAGLW.js → index-CFkxnncE.js} +84 -69
- package/dist/public/assets/index-t_srr1OD.css +1 -0
- package/dist/public/assets/{react-force-graph-2d-DZOG11W0.js → react-force-graph-2d-D3wGjFqA.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server.js +22 -1
- package/package.json +1 -1
- package/dist/public/assets/index-BgqCALAg.css +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mneme",
|
|
3
3
|
"description": "A plugin that provides long-term memory for Claude Code. It automatically saves context lost during auto-compact, offering features for session restoration, recording technical decisions, and learning developer patterns.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.20.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "hir4ta"
|
|
7
7
|
},
|
|
@@ -193,6 +193,26 @@ function updateSaveState(db, claudeSessionId, lastSavedTimestamp, lastSavedLine)
|
|
|
193
193
|
`);
|
|
194
194
|
stmt.run(lastSavedTimestamp, lastSavedLine, claudeSessionId);
|
|
195
195
|
}
|
|
196
|
+
function extractSlashCommand(content) {
|
|
197
|
+
const match = content.match(/<command-name>([^<]+)<\/command-name>/);
|
|
198
|
+
return match ? match[1] : void 0;
|
|
199
|
+
}
|
|
200
|
+
function extractToolResultMeta(content) {
|
|
201
|
+
return content.filter((c) => c.type === "tool_result" && c.tool_use_id).map((c) => {
|
|
202
|
+
const contentStr = typeof c.content === "string" ? c.content : c.content ? JSON.stringify(c.content) : "";
|
|
203
|
+
const lineCount = contentStr.split("\n").length;
|
|
204
|
+
const filePathMatch = contentStr.match(
|
|
205
|
+
/^(?:\s*\d+[→|]\s*)?([^\n]+\.(ts|js|py|json|md|sql|sh|tsx|jsx))/
|
|
206
|
+
);
|
|
207
|
+
return {
|
|
208
|
+
toolUseId: c.tool_use_id || "",
|
|
209
|
+
success: !c.is_error,
|
|
210
|
+
contentLength: contentStr.length,
|
|
211
|
+
lineCount: lineCount > 1 ? lineCount : void 0,
|
|
212
|
+
filePath: filePathMatch ? filePathMatch[1] : void 0
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
}
|
|
196
216
|
async function parseTranscriptIncremental(transcriptPath, lastSavedLine) {
|
|
197
217
|
const fileStream = fs.createReadStream(transcriptPath);
|
|
198
218
|
const rl = readline.createInterface({
|
|
@@ -211,18 +231,78 @@ async function parseTranscriptIncremental(transcriptPath, lastSavedLine) {
|
|
|
211
231
|
}
|
|
212
232
|
}
|
|
213
233
|
}
|
|
234
|
+
const planModeEvents = [];
|
|
235
|
+
for (const entry of entries) {
|
|
236
|
+
if (entry.type === "assistant" && Array.isArray(entry.message?.content)) {
|
|
237
|
+
for (const c of entry.message.content) {
|
|
238
|
+
if (c.type === "tool_use") {
|
|
239
|
+
if (c.name === "EnterPlanMode") {
|
|
240
|
+
planModeEvents.push({ timestamp: entry.timestamp, entering: true });
|
|
241
|
+
} else if (c.name === "ExitPlanMode") {
|
|
242
|
+
planModeEvents.push({
|
|
243
|
+
timestamp: entry.timestamp,
|
|
244
|
+
entering: false
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function isInPlanMode(timestamp) {
|
|
252
|
+
let inPlanMode = false;
|
|
253
|
+
for (const event of planModeEvents) {
|
|
254
|
+
if (event.timestamp > timestamp) break;
|
|
255
|
+
inPlanMode = event.entering;
|
|
256
|
+
}
|
|
257
|
+
return inPlanMode;
|
|
258
|
+
}
|
|
259
|
+
const progressEvents = /* @__PURE__ */ new Map();
|
|
260
|
+
for (const entry of entries) {
|
|
261
|
+
if (entry.type === "progress" && entry.data?.type) {
|
|
262
|
+
const event = {
|
|
263
|
+
type: entry.data.type,
|
|
264
|
+
timestamp: entry.timestamp,
|
|
265
|
+
hookEvent: entry.data.hookEvent,
|
|
266
|
+
hookName: entry.data.hookName,
|
|
267
|
+
toolName: entry.data.toolName
|
|
268
|
+
};
|
|
269
|
+
const key = entry.timestamp.slice(0, 16);
|
|
270
|
+
if (!progressEvents.has(key)) {
|
|
271
|
+
progressEvents.set(key, []);
|
|
272
|
+
}
|
|
273
|
+
progressEvents.get(key)?.push(event);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
214
276
|
const userMessages = entries.filter((e) => {
|
|
215
277
|
if (e.type !== "user" || e.message?.role !== "user") return false;
|
|
278
|
+
if (e.isMeta === true) return false;
|
|
216
279
|
const content = e.message?.content;
|
|
217
280
|
if (typeof content !== "string") return false;
|
|
218
281
|
if (content.startsWith("<local-command-stdout>")) return false;
|
|
219
282
|
if (content.startsWith("<local-command-caveat>")) return false;
|
|
220
283
|
return true;
|
|
221
|
-
}).map((e) =>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
284
|
+
}).map((e) => {
|
|
285
|
+
const content = e.message?.content;
|
|
286
|
+
return {
|
|
287
|
+
timestamp: e.timestamp,
|
|
288
|
+
content,
|
|
289
|
+
isCompactSummary: e.isCompactSummary || false,
|
|
290
|
+
slashCommand: extractSlashCommand(content)
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
const toolResultsByTimestamp = /* @__PURE__ */ new Map();
|
|
294
|
+
for (const entry of entries) {
|
|
295
|
+
if (entry.type === "user" && Array.isArray(entry.message?.content)) {
|
|
296
|
+
const results = extractToolResultMeta(
|
|
297
|
+
entry.message.content
|
|
298
|
+
);
|
|
299
|
+
if (results.length > 0) {
|
|
300
|
+
const key = entry.timestamp.slice(0, 16);
|
|
301
|
+
const existing = toolResultsByTimestamp.get(key) || [];
|
|
302
|
+
toolResultsByTimestamp.set(key, [...existing, ...results]);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
226
306
|
const assistantMessages = entries.filter((e) => e.type === "assistant").map((e) => {
|
|
227
307
|
const contentArray = e.message?.content;
|
|
228
308
|
if (!Array.isArray(contentArray)) return null;
|
|
@@ -249,6 +329,7 @@ async function parseTranscriptIncremental(transcriptPath, lastSavedLine) {
|
|
|
249
329
|
);
|
|
250
330
|
if (turnResponses.length > 0) {
|
|
251
331
|
const allToolDetails = turnResponses.flatMap((r) => r.toolDetails);
|
|
332
|
+
const timeKey = user.timestamp.slice(0, 16);
|
|
252
333
|
interactions.push({
|
|
253
334
|
timestamp: user.timestamp,
|
|
254
335
|
user: user.content,
|
|
@@ -256,7 +337,12 @@ async function parseTranscriptIncremental(transcriptPath, lastSavedLine) {
|
|
|
256
337
|
assistant: turnResponses.filter((r) => r.text).map((r) => r.text).join("\n"),
|
|
257
338
|
isCompactSummary: user.isCompactSummary,
|
|
258
339
|
toolsUsed: [...new Set(allToolDetails.map((t) => t.name))],
|
|
259
|
-
toolDetails: allToolDetails
|
|
340
|
+
toolDetails: allToolDetails,
|
|
341
|
+
// New metadata
|
|
342
|
+
inPlanMode: isInPlanMode(user.timestamp) || void 0,
|
|
343
|
+
slashCommand: user.slashCommand,
|
|
344
|
+
toolResults: toolResultsByTimestamp.get(timeKey),
|
|
345
|
+
progressEvents: progressEvents.get(timeKey)
|
|
260
346
|
});
|
|
261
347
|
}
|
|
262
348
|
}
|
|
@@ -366,7 +452,18 @@ async function incrementalSave(claudeSessionId, transcriptPath, projectPath) {
|
|
|
366
452
|
try {
|
|
367
453
|
const metadata = JSON.stringify({
|
|
368
454
|
toolsUsed: interaction.toolsUsed,
|
|
369
|
-
toolDetails: interaction.toolDetails
|
|
455
|
+
toolDetails: interaction.toolDetails,
|
|
456
|
+
// New metadata fields
|
|
457
|
+
...interaction.inPlanMode && { inPlanMode: true },
|
|
458
|
+
...interaction.slashCommand && {
|
|
459
|
+
slashCommand: interaction.slashCommand
|
|
460
|
+
},
|
|
461
|
+
...interaction.toolResults && interaction.toolResults.length > 0 && {
|
|
462
|
+
toolResults: interaction.toolResults
|
|
463
|
+
},
|
|
464
|
+
...interaction.progressEvents && interaction.progressEvents.length > 0 && {
|
|
465
|
+
progressEvents: interaction.progressEvents
|
|
466
|
+
}
|
|
370
467
|
});
|
|
371
468
|
insertStmt.run(
|
|
372
469
|
mnemeSessionId,
|
|
@@ -385,6 +482,17 @@ async function incrementalSave(claudeSessionId, transcriptPath, projectPath) {
|
|
|
385
482
|
);
|
|
386
483
|
insertedCount++;
|
|
387
484
|
if (interaction.assistant) {
|
|
485
|
+
const assistantMetadata = JSON.stringify({
|
|
486
|
+
toolsUsed: interaction.toolsUsed,
|
|
487
|
+
toolDetails: interaction.toolDetails,
|
|
488
|
+
...interaction.inPlanMode && { inPlanMode: true },
|
|
489
|
+
...interaction.toolResults && interaction.toolResults.length > 0 && {
|
|
490
|
+
toolResults: interaction.toolResults
|
|
491
|
+
},
|
|
492
|
+
...interaction.progressEvents && interaction.progressEvents.length > 0 && {
|
|
493
|
+
progressEvents: interaction.progressEvents
|
|
494
|
+
}
|
|
495
|
+
});
|
|
388
496
|
insertStmt.run(
|
|
389
497
|
mnemeSessionId,
|
|
390
498
|
claudeSessionId,
|
|
@@ -396,7 +504,7 @@ async function incrementalSave(claudeSessionId, transcriptPath, projectPath) {
|
|
|
396
504
|
"assistant",
|
|
397
505
|
interaction.assistant,
|
|
398
506
|
interaction.thinking || null,
|
|
399
|
-
|
|
507
|
+
assistantMetadata,
|
|
400
508
|
interaction.timestamp,
|
|
401
509
|
0
|
|
402
510
|
);
|