@danielmarbach/mnemonic-mcp 0.20.0 → 0.21.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/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/build/git.d.ts +3 -0
- package/build/git.d.ts.map +1 -1
- package/build/git.js +142 -119
- package/build/git.js.map +1 -1
- package/build/index.js +144 -61
- package/build/index.js.map +1 -1
- package/build/project-introspection.d.ts +2 -0
- package/build/project-introspection.d.ts.map +1 -1
- package/build/project-introspection.js +58 -0
- package/build/project-introspection.js.map +1 -1
- package/build/structured-content.d.ts +104 -48
- package/build/structured-content.d.ts.map +1 -1
- package/build/structured-content.js +29 -26
- package/build/structured-content.js.map +1 -1
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { getRelationshipPreview } from "./relationships.js";
|
|
|
19
19
|
import { cleanMarkdown } from "./markdown.js";
|
|
20
20
|
import { MnemonicConfigStore, readVaultSchemaVersion } from "./config.js";
|
|
21
21
|
import { CONSOLIDATION_MODES, PROTECTED_BRANCH_BEHAVIORS, PROJECT_POLICY_SCOPES, WRITE_SCOPES, isProtectedBranch, resolveProtectedBranchBehavior, resolveProtectedBranchPatterns, resolveConsolidationMode, resolveWriteScope, } from "./project-memory-policy.js";
|
|
22
|
-
import { classifyTheme, classifyThemeWithGraduation, computeThemesWithGraduation, summarizePreview, titleCaseTheme, withinThemeScore, anchorScore, computeConnectionDiversity, } from "./project-introspection.js";
|
|
22
|
+
import { classifyTheme, classifyThemeWithGraduation, computeThemesWithGraduation, summarizePreview, titleCaseTheme, daysSinceUpdate, withinThemeScore, anchorScore, computeConnectionDiversity, workingStateScore, extractNextAction, } from "./project-introspection.js";
|
|
23
23
|
import { getEffectiveMetadata } from "./role-suggestions.js";
|
|
24
24
|
import { detectProject, getCurrentGitBranch, resolveProjectIdentity } from "./project.js";
|
|
25
25
|
import { VaultManager } from "./vault.js";
|
|
@@ -321,6 +321,18 @@ async function resolveProject(cwd) {
|
|
|
321
321
|
getProjectIdentityOverride: async (projectId) => configStore.getProjectIdentityOverride(projectId),
|
|
322
322
|
});
|
|
323
323
|
}
|
|
324
|
+
function toProjectRef(project) {
|
|
325
|
+
return project ? { id: project.id, name: project.name } : undefined;
|
|
326
|
+
}
|
|
327
|
+
function noteProjectRef(note) {
|
|
328
|
+
if (!note.project || !note.projectName) {
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
id: note.project,
|
|
333
|
+
name: note.projectName,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
324
336
|
async function resolveProjectIdentityForCwd(cwd) {
|
|
325
337
|
if (!cwd)
|
|
326
338
|
return undefined;
|
|
@@ -1815,9 +1827,10 @@ server.registerTool("recall", {
|
|
|
1815
1827
|
.describe("'project' = only this project's memories (project-scoped storage), " +
|
|
1816
1828
|
"'global' = only unscoped memories (main/global storage), " +
|
|
1817
1829
|
"'all' = both, with project notes boosted (default)"),
|
|
1830
|
+
lifecycle: z.enum(["temporary", "permanent"]).optional().describe("Filter results by lifecycle. Useful for recovering working-state with `lifecycle: temporary` after `project_memory_summary` orientation."),
|
|
1818
1831
|
}),
|
|
1819
1832
|
outputSchema: RecallResultSchema,
|
|
1820
|
-
}, async ({ query, cwd, limit, minSimilarity, mode, verbose, tags, scope }) => {
|
|
1833
|
+
}, async ({ query, cwd, limit, minSimilarity, mode, verbose, tags, scope, lifecycle }) => {
|
|
1821
1834
|
const t0Recall = performance.now();
|
|
1822
1835
|
await ensureBranchSynced(cwd);
|
|
1823
1836
|
const project = await resolveProject(cwd);
|
|
@@ -1863,6 +1876,9 @@ server.registerTool("recall", {
|
|
|
1863
1876
|
if (!tags.every((t) => noteTags.has(t)))
|
|
1864
1877
|
continue;
|
|
1865
1878
|
}
|
|
1879
|
+
if (lifecycle && note.lifecycle !== lifecycle) {
|
|
1880
|
+
continue;
|
|
1881
|
+
}
|
|
1866
1882
|
const isProjectNote = note.project !== undefined;
|
|
1867
1883
|
const isCurrentProject = project && note.project === project.id;
|
|
1868
1884
|
if (scope === "project") {
|
|
@@ -1967,8 +1983,7 @@ server.registerTool("recall", {
|
|
|
1967
1983
|
title: note.title,
|
|
1968
1984
|
score,
|
|
1969
1985
|
boosted,
|
|
1970
|
-
project: note
|
|
1971
|
-
projectName: note.projectName,
|
|
1986
|
+
project: noteProjectRef(note),
|
|
1972
1987
|
vault: storageLabel(vault),
|
|
1973
1988
|
tags: note.tags,
|
|
1974
1989
|
lifecycle: note.lifecycle,
|
|
@@ -2142,8 +2157,7 @@ server.registerTool("update", {
|
|
|
2142
2157
|
title: updated.title,
|
|
2143
2158
|
fieldsModified: changes,
|
|
2144
2159
|
timestamp: now,
|
|
2145
|
-
project: updated
|
|
2146
|
-
projectName: updated.projectName,
|
|
2160
|
+
project: noteProjectRef(updated),
|
|
2147
2161
|
lifecycle: updated.lifecycle,
|
|
2148
2162
|
persistence,
|
|
2149
2163
|
};
|
|
@@ -2247,8 +2261,7 @@ server.registerTool("forget", {
|
|
|
2247
2261
|
action: "forgotten",
|
|
2248
2262
|
id,
|
|
2249
2263
|
title: note.title,
|
|
2250
|
-
project: note
|
|
2251
|
-
projectName: note.projectName,
|
|
2264
|
+
project: noteProjectRef(note),
|
|
2252
2265
|
relationshipsCleaned: vaultChanges.size > 0 ? Array.from(vaultChanges.values()).reduce((sum, files) => sum + files.length - 1, 0) : 0,
|
|
2253
2266
|
vaultsModified: Array.from(vaultChanges.keys()).map(v => storageLabel(v)),
|
|
2254
2267
|
retry,
|
|
@@ -2326,10 +2339,10 @@ server.registerTool("get", {
|
|
|
2326
2339
|
id: note.id,
|
|
2327
2340
|
title: note.title,
|
|
2328
2341
|
content: note.content,
|
|
2329
|
-
project: note
|
|
2330
|
-
projectName: note.projectName,
|
|
2342
|
+
project: noteProjectRef(note),
|
|
2331
2343
|
tags: note.tags,
|
|
2332
2344
|
lifecycle: note.lifecycle,
|
|
2345
|
+
alwaysLoad: note.alwaysLoad,
|
|
2333
2346
|
relatedTo: note.relatedTo,
|
|
2334
2347
|
createdAt: note.createdAt,
|
|
2335
2348
|
updatedAt: note.updatedAt,
|
|
@@ -2340,7 +2353,7 @@ server.registerTool("get", {
|
|
|
2340
2353
|
const lines = [];
|
|
2341
2354
|
for (const note of found) {
|
|
2342
2355
|
lines.push(`## ${note.title} (${note.id})`);
|
|
2343
|
-
lines.push(`project: ${note.
|
|
2356
|
+
lines.push(`project: ${note.project?.name ?? "global"} | stored: ${note.vault} | lifecycle: ${note.lifecycle}`);
|
|
2344
2357
|
if (note.tags.length > 0)
|
|
2345
2358
|
lines.push(`tags: ${note.tags.join(", ")}`);
|
|
2346
2359
|
lines.push("");
|
|
@@ -2405,8 +2418,7 @@ server.registerTool("where_is_memory", {
|
|
|
2405
2418
|
action: "located",
|
|
2406
2419
|
id: note.id,
|
|
2407
2420
|
title: note.title,
|
|
2408
|
-
project: note
|
|
2409
|
-
projectName: note.projectName,
|
|
2421
|
+
project: noteProjectRef(note),
|
|
2410
2422
|
vault: vaultLabel,
|
|
2411
2423
|
updatedAt: note.updatedAt,
|
|
2412
2424
|
relatedCount,
|
|
@@ -2484,8 +2496,7 @@ server.registerTool("list", {
|
|
|
2484
2496
|
const structuredNotes = entries.map(({ note, vault }) => ({
|
|
2485
2497
|
id: note.id,
|
|
2486
2498
|
title: note.title,
|
|
2487
|
-
project: note
|
|
2488
|
-
projectName: note.projectName,
|
|
2499
|
+
project: noteProjectRef(note),
|
|
2489
2500
|
tags: note.tags,
|
|
2490
2501
|
lifecycle: note.lifecycle,
|
|
2491
2502
|
vault: storageLabel(vault),
|
|
@@ -2786,16 +2797,21 @@ server.registerTool("recent_memories", {
|
|
|
2786
2797
|
limit: z.number().int().min(1).max(20).optional().default(5),
|
|
2787
2798
|
includePreview: z.boolean().optional().default(true),
|
|
2788
2799
|
includeStorage: z.boolean().optional().default(true),
|
|
2800
|
+
lifecycle: z.enum(["temporary", "permanent"]).optional().describe("Filter results by lifecycle. Useful for recovering working-state with `lifecycle: temporary` after `project_memory_summary` orientation."),
|
|
2789
2801
|
}),
|
|
2790
2802
|
outputSchema: RecentResultSchema,
|
|
2791
|
-
}, async ({ cwd, scope, storedIn, limit, includePreview, includeStorage }) => {
|
|
2803
|
+
}, async ({ cwd, scope, storedIn, limit, includePreview, includeStorage, lifecycle }) => {
|
|
2792
2804
|
await ensureBranchSynced(cwd);
|
|
2793
2805
|
const { project, entries } = await collectVisibleNotes(cwd, scope, undefined, storedIn);
|
|
2794
|
-
|
|
2806
|
+
let filteredEntries = entries;
|
|
2807
|
+
if (lifecycle) {
|
|
2808
|
+
filteredEntries = entries.filter(({ note }) => note.lifecycle === lifecycle);
|
|
2809
|
+
}
|
|
2810
|
+
const recent = [...filteredEntries]
|
|
2795
2811
|
.sort((a, b) => b.note.updatedAt.localeCompare(a.note.updatedAt))
|
|
2796
2812
|
.slice(0, limit);
|
|
2797
2813
|
if (recent.length === 0) {
|
|
2798
|
-
const structuredContent = { action: "recent_shown", project: project
|
|
2814
|
+
const structuredContent = { action: "recent_shown", project: toProjectRef(project), count: 0, limit: limit || 5, notes: [] };
|
|
2799
2815
|
return { content: [{ type: "text", text: "No memories found." }], structuredContent };
|
|
2800
2816
|
}
|
|
2801
2817
|
const header = project && scope !== "global"
|
|
@@ -2810,8 +2826,7 @@ server.registerTool("recent_memories", {
|
|
|
2810
2826
|
const structuredNotes = recent.map(({ note, vault }) => ({
|
|
2811
2827
|
id: note.id,
|
|
2812
2828
|
title: note.title,
|
|
2813
|
-
project: note
|
|
2814
|
-
projectName: note.projectName,
|
|
2829
|
+
project: noteProjectRef(note),
|
|
2815
2830
|
tags: note.tags,
|
|
2816
2831
|
lifecycle: note.lifecycle,
|
|
2817
2832
|
vault: storageLabel(vault),
|
|
@@ -2820,8 +2835,7 @@ server.registerTool("recent_memories", {
|
|
|
2820
2835
|
}));
|
|
2821
2836
|
const structuredContent = {
|
|
2822
2837
|
action: "recent_shown",
|
|
2823
|
-
project: project
|
|
2824
|
-
projectName: project?.name,
|
|
2838
|
+
project: toProjectRef(project),
|
|
2825
2839
|
count: recent.length,
|
|
2826
2840
|
limit: limit || 5,
|
|
2827
2841
|
notes: structuredNotes,
|
|
@@ -2860,7 +2874,7 @@ server.registerTool("memory_graph", {
|
|
|
2860
2874
|
await ensureBranchSynced(cwd);
|
|
2861
2875
|
const { project, entries } = await collectVisibleNotes(cwd, scope, undefined, storedIn);
|
|
2862
2876
|
if (entries.length === 0) {
|
|
2863
|
-
const structuredContent = { action: "graph_shown", project: project
|
|
2877
|
+
const structuredContent = { action: "graph_shown", project: toProjectRef(project), nodes: [], limit, truncated: false };
|
|
2864
2878
|
return { content: [{ type: "text", text: "No memories found." }], structuredContent };
|
|
2865
2879
|
}
|
|
2866
2880
|
const visibleIds = new Set(entries.map((entry) => entry.note.id));
|
|
@@ -2875,7 +2889,7 @@ server.registerTool("memory_graph", {
|
|
|
2875
2889
|
})
|
|
2876
2890
|
.filter(Boolean);
|
|
2877
2891
|
if (lines.length === 0) {
|
|
2878
|
-
const structuredContent = { action: "graph_shown", project: project
|
|
2892
|
+
const structuredContent = { action: "graph_shown", project: toProjectRef(project), nodes: [], limit, truncated: false };
|
|
2879
2893
|
return { content: [{ type: "text", text: "No relationships found for that scope." }], structuredContent };
|
|
2880
2894
|
}
|
|
2881
2895
|
const header = project && scope !== "global"
|
|
@@ -2899,8 +2913,7 @@ server.registerTool("memory_graph", {
|
|
|
2899
2913
|
.filter((node) => node.edges.length > 0);
|
|
2900
2914
|
const structuredContent = {
|
|
2901
2915
|
action: "graph_shown",
|
|
2902
|
-
project: project
|
|
2903
|
-
projectName: project?.name,
|
|
2916
|
+
project: toProjectRef(project),
|
|
2904
2917
|
nodes: structuredNodes,
|
|
2905
2918
|
limit,
|
|
2906
2919
|
truncated: structuredNodes.length < entries.filter(e => (e.note.relatedTo?.length ?? 0) > 0).length,
|
|
@@ -2920,6 +2933,7 @@ server.registerTool("project_memory_summary", {
|
|
|
2920
2933
|
"Returns:\n" +
|
|
2921
2934
|
"- A synthesized project-level summary based on stored memories\n" +
|
|
2922
2935
|
"- Bounded 1-hop relationship previews on orientation entry points (primaryEntry and suggestedNext)\n\n" +
|
|
2936
|
+
"- Optional compact working-state recovery hints when relevant temporary notes exist\n\n" +
|
|
2923
2937
|
"Read-only.\n\n" +
|
|
2924
2938
|
"Typical next step:\n" +
|
|
2925
2939
|
"- Use `recall` or `list` to drill down into specific areas.",
|
|
@@ -3060,6 +3074,48 @@ server.registerTool("project_memory_summary", {
|
|
|
3060
3074
|
.slice(0, recentLimit);
|
|
3061
3075
|
sections.push(`\nRecent activity (start here):`);
|
|
3062
3076
|
sections.push(...recent.map(e => `- ${e.note.updatedAt} — ${e.note.title}`));
|
|
3077
|
+
const temporaryEntries = projectEntries
|
|
3078
|
+
.filter((entry) => entry.note.lifecycle === "temporary")
|
|
3079
|
+
.map((entry) => {
|
|
3080
|
+
const metadata = effectiveMetadataById.get(entry.note.id)?.metadata;
|
|
3081
|
+
const score = workingStateScore(entry.note, metadata);
|
|
3082
|
+
const nextAction = extractNextAction(entry.note);
|
|
3083
|
+
const relatedCount = entry.note.relatedTo?.length ?? 0;
|
|
3084
|
+
const days = daysSinceUpdate(entry.note.updatedAt);
|
|
3085
|
+
const rationaleParts = [`updated ${days < 1 ? "today" : `${Math.round(days)}d ago`}`];
|
|
3086
|
+
if (relatedCount > 0)
|
|
3087
|
+
rationaleParts.push(`${relatedCount} linked note${relatedCount === 1 ? "" : "s"}`);
|
|
3088
|
+
if (nextAction)
|
|
3089
|
+
rationaleParts.push("explicit next action");
|
|
3090
|
+
if (metadata?.role === "plan" || metadata?.role === "context")
|
|
3091
|
+
rationaleParts.push(`${metadata.role} note`);
|
|
3092
|
+
return {
|
|
3093
|
+
entry,
|
|
3094
|
+
score,
|
|
3095
|
+
rationale: rationaleParts.join(", "),
|
|
3096
|
+
preview: summarizePreview(entry.note.content, 120),
|
|
3097
|
+
nextAction,
|
|
3098
|
+
};
|
|
3099
|
+
})
|
|
3100
|
+
.filter((candidate) => candidate.score > -Infinity)
|
|
3101
|
+
.sort((a, b) => b.score - a.score || b.entry.note.updatedAt.localeCompare(a.entry.note.updatedAt))
|
|
3102
|
+
.slice(0, 3);
|
|
3103
|
+
const workingState = temporaryEntries.length > 0
|
|
3104
|
+
? {
|
|
3105
|
+
summary: temporaryEntries.length === 1
|
|
3106
|
+
? `1 temporary note may help resume active work.`
|
|
3107
|
+
: `${temporaryEntries.length} temporary notes may help resume active work.`,
|
|
3108
|
+
recoveryHint: "Orient with project_memory_summary first, then inspect these temporary notes if you need to continue in-progress work.",
|
|
3109
|
+
notes: temporaryEntries.map(({ entry, rationale, preview, nextAction }) => ({
|
|
3110
|
+
id: entry.note.id,
|
|
3111
|
+
title: entry.note.title,
|
|
3112
|
+
updatedAt: entry.note.updatedAt,
|
|
3113
|
+
rationale,
|
|
3114
|
+
preview,
|
|
3115
|
+
nextAction,
|
|
3116
|
+
})),
|
|
3117
|
+
}
|
|
3118
|
+
: undefined;
|
|
3063
3119
|
// Anchor notes with diversity constraint (project-scoped only)
|
|
3064
3120
|
const scoredAnchorCandidates = projectEntries
|
|
3065
3121
|
.map(e => {
|
|
@@ -3209,11 +3265,14 @@ server.registerTool("project_memory_summary", {
|
|
|
3209
3265
|
}
|
|
3210
3266
|
const suggestedEnriched = await Promise.all(suggestedCandidates.map(enrichOrientationNote));
|
|
3211
3267
|
const suggestedRelationships = await Promise.all(suggestedCandidates.map(enrichOrientationNoteWithRelationships));
|
|
3268
|
+
const recentPermanent = recent.find((entry) => entry.note.lifecycle === "permanent");
|
|
3269
|
+
const fallbackEntry = recentPermanent ?? recent[0];
|
|
3270
|
+
const permanentOverrideUsed = Boolean(recentPermanent && recent[0] && recentPermanent.note.id !== recent[0].note.id);
|
|
3212
3271
|
// Enrich fallback primaryEntry when no anchors exist
|
|
3213
3272
|
let fallbackEnriched = {};
|
|
3214
3273
|
let fallbackRelationships = {};
|
|
3215
|
-
if (!primaryAnchor &&
|
|
3216
|
-
const fallbackNote =
|
|
3274
|
+
if (!primaryAnchor && fallbackEntry) {
|
|
3275
|
+
const fallbackNote = fallbackEntry.note;
|
|
3217
3276
|
const vault = noteVaultMap.get(fallbackNote.id);
|
|
3218
3277
|
if (vault) {
|
|
3219
3278
|
const filePath = `${vault.notesRelDir}/${fallbackNote.id}.md`;
|
|
@@ -3235,11 +3294,13 @@ server.registerTool("project_memory_summary", {
|
|
|
3235
3294
|
...primaryRelationships,
|
|
3236
3295
|
}
|
|
3237
3296
|
: {
|
|
3238
|
-
id:
|
|
3239
|
-
title:
|
|
3240
|
-
rationale:
|
|
3241
|
-
? "Most recent note — no high-centrality anchors found"
|
|
3242
|
-
:
|
|
3297
|
+
id: fallbackEntry?.note.id ?? projectEntries[0]?.note.id ?? "",
|
|
3298
|
+
title: fallbackEntry?.note.title ?? projectEntries[0]?.note.title ?? "No notes",
|
|
3299
|
+
rationale: permanentOverrideUsed
|
|
3300
|
+
? "Most recent permanent note — no high-centrality anchors found"
|
|
3301
|
+
: fallbackEntry
|
|
3302
|
+
? "Most recent note — no high-centrality anchors found"
|
|
3303
|
+
: "Only note available",
|
|
3243
3304
|
...fallbackEnriched,
|
|
3244
3305
|
...fallbackRelationships,
|
|
3245
3306
|
},
|
|
@@ -3285,6 +3346,18 @@ server.registerTool("project_memory_summary", {
|
|
|
3285
3346
|
sections.push(` - ${w}`);
|
|
3286
3347
|
}
|
|
3287
3348
|
}
|
|
3349
|
+
if (workingState) {
|
|
3350
|
+
sections.push(`\nWorking state:`);
|
|
3351
|
+
sections.push(workingState.summary);
|
|
3352
|
+
sections.push(`Recovery hint: ${workingState.recoveryHint}`);
|
|
3353
|
+
for (const note of workingState.notes) {
|
|
3354
|
+
sections.push(`- ${note.title} (\`${note.id}\`) — ${note.rationale}`);
|
|
3355
|
+
sections.push(` Preview: ${note.preview}`);
|
|
3356
|
+
if (note.nextAction) {
|
|
3357
|
+
sections.push(` Next action: ${note.nextAction}`);
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3288
3361
|
// Related global notes (optional, anchor-based similarity)
|
|
3289
3362
|
const structuredContent = {
|
|
3290
3363
|
action: "project_summary_shown",
|
|
@@ -3304,6 +3377,7 @@ server.registerTool("project_memory_summary", {
|
|
|
3304
3377
|
})),
|
|
3305
3378
|
anchors,
|
|
3306
3379
|
orientation,
|
|
3380
|
+
workingState,
|
|
3307
3381
|
relatedGlobal,
|
|
3308
3382
|
};
|
|
3309
3383
|
console.error(`[summary:timing] ${(performance.now() - t0Summary).toFixed(1)}ms`);
|
|
@@ -4059,8 +4133,7 @@ async function detectDuplicates(entries, threshold, project) {
|
|
|
4059
4133
|
const structuredContent = {
|
|
4060
4134
|
action: "consolidated",
|
|
4061
4135
|
strategy: "detect-duplicates",
|
|
4062
|
-
project: project
|
|
4063
|
-
projectName: project?.name,
|
|
4136
|
+
project: toProjectRef(project),
|
|
4064
4137
|
notesProcessed: entries.length,
|
|
4065
4138
|
notesModified: 0,
|
|
4066
4139
|
};
|
|
@@ -4147,8 +4220,7 @@ function findClusters(entries, project) {
|
|
|
4147
4220
|
const structuredContent = {
|
|
4148
4221
|
action: "consolidated",
|
|
4149
4222
|
strategy: "find-clusters",
|
|
4150
|
-
project: project
|
|
4151
|
-
projectName: project?.name,
|
|
4223
|
+
project: toProjectRef(project),
|
|
4152
4224
|
notesProcessed: entries.length,
|
|
4153
4225
|
notesModified: 0,
|
|
4154
4226
|
themeGroups,
|
|
@@ -4235,8 +4307,7 @@ async function suggestMerges(entries, threshold, defaultConsolidationMode, proje
|
|
|
4235
4307
|
const structuredContent = {
|
|
4236
4308
|
action: "consolidated",
|
|
4237
4309
|
strategy: "suggest-merges",
|
|
4238
|
-
project: project
|
|
4239
|
-
projectName: project?.name,
|
|
4310
|
+
project: toProjectRef(project),
|
|
4240
4311
|
notesProcessed: entries.length,
|
|
4241
4312
|
notesModified: 0,
|
|
4242
4313
|
};
|
|
@@ -4260,8 +4331,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
4260
4331
|
const structuredContent = {
|
|
4261
4332
|
action: "consolidated",
|
|
4262
4333
|
strategy: "execute-merge",
|
|
4263
|
-
project: project
|
|
4264
|
-
projectName: project?.name,
|
|
4334
|
+
project: toProjectRef(project),
|
|
4265
4335
|
notesProcessed: entries.length,
|
|
4266
4336
|
notesModified: 0,
|
|
4267
4337
|
warnings: ["execute-merge requires at least two distinct sourceIds."],
|
|
@@ -4272,8 +4342,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
4272
4342
|
const structuredContent = {
|
|
4273
4343
|
action: "consolidated",
|
|
4274
4344
|
strategy: "execute-merge",
|
|
4275
|
-
project: project
|
|
4276
|
-
projectName: project?.name,
|
|
4345
|
+
project: toProjectRef(project),
|
|
4277
4346
|
notesProcessed: entries.length,
|
|
4278
4347
|
notesModified: 0,
|
|
4279
4348
|
warnings: ["execute-merge requires a non-empty targetTitle."],
|
|
@@ -4288,8 +4357,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
4288
4357
|
const structuredContent = {
|
|
4289
4358
|
action: "consolidated",
|
|
4290
4359
|
strategy: "execute-merge",
|
|
4291
|
-
project: project
|
|
4292
|
-
projectName: project?.name,
|
|
4360
|
+
project: toProjectRef(project),
|
|
4293
4361
|
notesProcessed: entries.length,
|
|
4294
4362
|
notesModified: 0,
|
|
4295
4363
|
warnings: [`Source note '${id}' not found.`],
|
|
@@ -4324,8 +4392,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
4324
4392
|
const structuredContent = {
|
|
4325
4393
|
action: "consolidated",
|
|
4326
4394
|
strategy: "execute-merge",
|
|
4327
|
-
project: project
|
|
4328
|
-
projectName: project?.name,
|
|
4395
|
+
project: toProjectRef(project),
|
|
4329
4396
|
notesProcessed: entries.length,
|
|
4330
4397
|
notesModified: 0,
|
|
4331
4398
|
warnings: [message],
|
|
@@ -4537,8 +4604,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
4537
4604
|
const structuredContent = {
|
|
4538
4605
|
action: "consolidated",
|
|
4539
4606
|
strategy: "execute-merge",
|
|
4540
|
-
project: project
|
|
4541
|
-
projectName: project?.name,
|
|
4607
|
+
project: toProjectRef(project),
|
|
4542
4608
|
notesProcessed: entries.length,
|
|
4543
4609
|
notesModified: vaultChanges.size,
|
|
4544
4610
|
persistence,
|
|
@@ -4578,8 +4644,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
|
|
|
4578
4644
|
const structuredContent = {
|
|
4579
4645
|
action: "consolidated",
|
|
4580
4646
|
strategy: "prune-superseded",
|
|
4581
|
-
project: project
|
|
4582
|
-
projectName: project?.name,
|
|
4647
|
+
project: toProjectRef(project),
|
|
4583
4648
|
notesProcessed: entries.length,
|
|
4584
4649
|
notesModified: 0,
|
|
4585
4650
|
warnings: [`prune-superseded requires consolidationMode="delete". Current mode: ${consolidationMode}.`],
|
|
@@ -4611,8 +4676,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
|
|
|
4611
4676
|
const structuredContent = {
|
|
4612
4677
|
action: "consolidated",
|
|
4613
4678
|
strategy: "prune-superseded",
|
|
4614
|
-
project: project
|
|
4615
|
-
projectName: project?.name,
|
|
4679
|
+
project: toProjectRef(project),
|
|
4616
4680
|
notesProcessed: entries.length,
|
|
4617
4681
|
notesModified: 0,
|
|
4618
4682
|
};
|
|
@@ -4641,8 +4705,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
|
|
|
4641
4705
|
const structuredContent = {
|
|
4642
4706
|
action: "consolidated",
|
|
4643
4707
|
strategy: "prune-superseded",
|
|
4644
|
-
project: project
|
|
4645
|
-
projectName: project?.name,
|
|
4708
|
+
project: toProjectRef(project),
|
|
4646
4709
|
notesProcessed: entries.length,
|
|
4647
4710
|
notesModified: 0,
|
|
4648
4711
|
warnings: [message],
|
|
@@ -4697,8 +4760,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
|
|
|
4697
4760
|
const structuredContent = {
|
|
4698
4761
|
action: "consolidated",
|
|
4699
4762
|
strategy: "prune-superseded",
|
|
4700
|
-
project: project
|
|
4701
|
-
projectName: project?.name,
|
|
4763
|
+
project: toProjectRef(project),
|
|
4702
4764
|
notesProcessed: entries.length,
|
|
4703
4765
|
notesModified: vaultChanges.size,
|
|
4704
4766
|
retry,
|
|
@@ -4726,8 +4788,7 @@ async function dryRunAll(entries, threshold, defaultConsolidationMode, project,
|
|
|
4726
4788
|
const structuredContent = {
|
|
4727
4789
|
action: "consolidated",
|
|
4728
4790
|
strategy: "dry-run",
|
|
4729
|
-
project: project
|
|
4730
|
-
projectName: project?.name,
|
|
4791
|
+
project: toProjectRef(project),
|
|
4731
4792
|
notesProcessed: entries.length,
|
|
4732
4793
|
notesModified: 0,
|
|
4733
4794
|
};
|
|
@@ -4773,11 +4834,32 @@ server.registerPrompt("mnemonic-workflow-hint", {
|
|
|
4773
4834
|
"- For repo-related tasks, pass `cwd` so mnemonic can route project memories correctly.\n\n" +
|
|
4774
4835
|
"Workflow: `recall`/`list` -> `get` -> `update` or `remember` -> `relate`/`consolidate`/`move_memory`. Use `discover_tags` only when tag choice is ambiguous.\n\n" +
|
|
4775
4836
|
"Roles are optional prioritization hints, not schema. Lifecycle still governs durability. `role: plan` does not imply `temporary`. Inferred roles are internal hints only. Prioritization is language-independent by default.\n\n" +
|
|
4837
|
+
"### Working-state continuity\n\n" +
|
|
4838
|
+
"Preserve in-progress work as temporary notes when continuation value is high. Recovery happens after project orientation.\n\n" +
|
|
4839
|
+
"**Checkpoint note structure (temporary notes):**\n" +
|
|
4840
|
+
"- Title pattern: 'WIP: <topic>' or 'Checkpoint: <description>'\n" +
|
|
4841
|
+
"- Opening paragraph: current status and next immediate step\n" +
|
|
4842
|
+
"- Body: what was attempted, what worked, blockers, alternatives considered\n" +
|
|
4843
|
+
"- End with explicit next action and confidence level\n\n" +
|
|
4844
|
+
"**Checkpoint note guidance:**\n" +
|
|
4845
|
+
"- One checkpoint per active task or investigation thread\n" +
|
|
4846
|
+
"- Update the same checkpoint note as work progresses (don't create new ones)\n" +
|
|
4847
|
+
"- Link to related decisions: use `relate` to connect temporary checkpoints to permanent decisions\n" +
|
|
4848
|
+
"- Consolidate into a durable note when complete; let lifecycle defaults delete temporary scaffolding unless you intentionally need preserved history\n\n" +
|
|
4849
|
+
"**Recovery workflow:**\n" +
|
|
4850
|
+
"- Call `project_memory_summary` first for orientation (do not skip to recovery)\n" +
|
|
4851
|
+
"- Use `lifecycle: temporary` for active plans, WIP checkpoints, draft investigations, and unvalidated options\n" +
|
|
4852
|
+
"- Use `lifecycle: permanent` for decisions, discovered constraints, bug causes, and reusable lessons\n" +
|
|
4853
|
+
"- After orientation, recover working-state from temporary notes via `recall` with lifecycle filter\n" +
|
|
4854
|
+
"- Consolidate temporary notes into durable ones once knowledge stabilizes\n" +
|
|
4855
|
+
"- Recovery is a follow-on step, not a replacement for orientation\n\n" +
|
|
4776
4856
|
"### Anti-patterns\n\n" +
|
|
4777
4857
|
"- Bad: call `remember` immediately because the user said 'remember'.\n" +
|
|
4778
4858
|
"- Good: `recall` or `list` first, then `get`, then `update` or `remember`.\n" +
|
|
4779
4859
|
"- Bad: create another note when `recall` or `list` already found the same decision.\n" +
|
|
4780
|
-
"- Good: `update` the existing memory and relate it if needed.\n
|
|
4860
|
+
"- Good: `update` the existing memory and relate it if needed.\n" +
|
|
4861
|
+
"- Bad: skip orientation and jump straight to working-state recovery.\n" +
|
|
4862
|
+
"- Good: `project_memory_summary` first, then recover temporary notes.\n\n" +
|
|
4781
4863
|
"### Storage model\n\n" +
|
|
4782
4864
|
"Memories can live in:\n" +
|
|
4783
4865
|
"- `main-vault` for global knowledge\n" +
|
|
@@ -4790,7 +4872,8 @@ server.registerPrompt("mnemonic-workflow-hint", {
|
|
|
4790
4872
|
"### Tiny examples\n\n" +
|
|
4791
4873
|
"- Existing bug note found by `recall` -> inspect with `get` -> refine with `update`.\n" +
|
|
4792
4874
|
"- No matching note found by `recall` -> optional `discover_tags` with note context -> create with `remember`.\n" +
|
|
4793
|
-
"- Two notes overlap heavily -> inspect -> clean up with `consolidate
|
|
4875
|
+
"- Two notes overlap heavily -> inspect -> clean up with `consolidate`.\n" +
|
|
4876
|
+
"- Resume work: `project_memory_summary` -> `recall` (lifecycle: temporary) -> continue from temporary notes.",
|
|
4794
4877
|
},
|
|
4795
4878
|
},
|
|
4796
4879
|
],
|