@danielmarbach/mnemonic-mcp 0.2.0 → 0.3.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.
- package/CHANGELOG.md +19 -0
- package/README.md +9 -1
- package/build/git.d.ts +2 -1
- package/build/git.d.ts.map +1 -1
- package/build/git.js +3 -2
- package/build/git.js.map +1 -1
- package/build/index.js +57 -18
- package/build/index.js.map +1 -1
- package/build/paths.d.ts +10 -0
- package/build/paths.d.ts.map +1 -0
- package/build/paths.js +28 -0
- package/build/paths.js.map +1 -0
- package/build/storage.js +9 -2
- package/build/storage.js.map +1 -1
- package/build/structured-content.d.ts +76 -42
- package/build/structured-content.d.ts.map +1 -1
- package/build/structured-content.js +2 -1
- package/build/structured-content.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to `mnemonic` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is loosely based on Keep a Changelog and uses semver-style version headings.
|
|
6
6
|
|
|
7
|
+
## [0.3.1] - 2026-03-11
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Path resolution now correctly supports home-directory shorthand (`~`) for user-configurable paths before absolute resolution. `VAULT_PATH` and `CLAUDE_HOME` no longer resolve to accidental cwd-relative paths when configured with tildes.
|
|
12
|
+
- `import-claude-memory` now applies the same home-aware path resolution to CLI options (`--cwd`, `--claude-home`) for consistent behavior across absolute and home-based paths.
|
|
13
|
+
|
|
14
|
+
## [0.3.0] - 2026-03-10
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `recall` now backfills missing and stale embeddings on demand before searching. Notes that arrived via `git pull` without a local embedding, or that were edited directly in an editor after their embedding was written, are re-embedded automatically. If Ollama is unavailable the backfill fails silently and recall continues with existing embeddings.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- `parseNote` in `Storage` now converts gray-matter `Date` objects to ISO strings for `createdAt` and `updatedAt`. YAML frontmatter with unquoted ISO timestamps is parsed by gray-matter as JS `Date` instances; notes arriving via `git pull` from another machine were affected, causing output validation errors on recall.
|
|
23
|
+
- `pushWithStatus` in `GitOps` now returns `{ status: "failed", error }` instead of throwing on push failure. Previously, any push error caused mutating MCP tools (`remember`, `update`, `consolidate`, etc.) to return `isError: true` even though the note was committed successfully. The `PersistenceStatus` schema gains a `"failed"` push status and a `pushError` field to surface the failure detail without blocking the operation.
|
|
24
|
+
- `consolidate` `execute-merge` now reuses an existing consolidated target note on retry when the same source notes already point to the same `supersedes` target with the same title. This prevents duplicate consolidated notes after partial-success retry flows and keeps repeated merge attempts idempotent without requiring caller-supplied ids.
|
|
25
|
+
|
|
7
26
|
## [0.2.0] - 2026-03-10
|
|
8
27
|
|
|
9
28
|
### Added
|
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ Packages are published to the public npm registry. No authentication required.
|
|
|
84
84
|
npm install @danielmarbach/mnemonic-mcp
|
|
85
85
|
|
|
86
86
|
# Specific release
|
|
87
|
-
npm install @danielmarbach/mnemonic-mcp@0.
|
|
87
|
+
npm install @danielmarbach/mnemonic-mcp@0.2.0
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
## MCP client config
|
|
@@ -369,6 +369,14 @@ No. The embeddings here are **local vector representations** generated by Ollama
|
|
|
369
369
|
|
|
370
370
|
When you call `recall` with `cwd`, mnemonic adds a fixed **+0.15 boost** to the cosine similarity score of every note belonging to the detected project. This is a soft boost, not a hard filter — global memories are still included when relevant. The boost ensures project-specific context floats to the top when you're working inside a repo while cross-project knowledge remains accessible further down the list.
|
|
371
371
|
|
|
372
|
+
**How does mnemonic differ from Beads?**
|
|
373
|
+
|
|
374
|
+
mnemonic and Beads address complementary concerns. mnemonic is a **knowledge graph**: it stores notes, relationships between them, and lets agents retrieve relevant context through semantic search. [Beads](https://github.com/steveyegge/beads) is a **task and dependency tracker**: it models work items and their dependencies so agents can determine what is ready to execute next. Both tools can coexist in the same workflow — mnemonic stores knowledge and reasoning while Beads manages execution.
|
|
375
|
+
|
|
376
|
+
**What are temporary notes?**
|
|
377
|
+
|
|
378
|
+
mnemonic distinguishes between two lifecycle states. `temporary` notes capture evolving working-state: hypotheses, in-progress plans, experiment results, draft reasoning. `permanent` notes capture durable knowledge: decisions, root cause explanations, architectural guidance, lessons learned. As an investigation progresses, a cluster of temporary notes is typically `consolidate`d into one or more permanent notes, and the scaffolding is discarded. This two-phase lifecycle keeps exploratory thinking from polluting long-term memory while still giving agents a place to reason incrementally before committing to a conclusion.
|
|
379
|
+
|
|
372
380
|
## Repository layout
|
|
373
381
|
|
|
374
382
|
```
|
package/build/git.d.ts
CHANGED
|
@@ -15,8 +15,9 @@ export interface CommitResult {
|
|
|
15
15
|
reason?: "git-disabled" | "no-changes";
|
|
16
16
|
}
|
|
17
17
|
export interface PushResult {
|
|
18
|
-
status: "pushed" | "skipped";
|
|
18
|
+
status: "pushed" | "skipped" | "failed";
|
|
19
19
|
reason?: "git-disabled" | "no-remote" | "auto-push-disabled";
|
|
20
|
+
error?: string;
|
|
20
21
|
}
|
|
21
22
|
export declare class GitOps {
|
|
22
23
|
private git;
|
package/build/git.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO;CAKzD;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,cAAc,GAAG,YAAY,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO;CAKzD;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,cAAc,GAAG,YAAY,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC,MAAM,CAAC,EAAE,cAAc,GAAG,WAAW,GAAG,oBAAoB,CAAC;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,OAAO,CAAU;gBAEb,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAgB;IAMpD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;;;;;;;;;;;;;;;;;OAkBG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKzE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAwB9F;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BjC,uEAAuE;IACjE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;YAiB7B,WAAW;YASX,oBAAoB;IASlC;;;OAGG;YACW,cAAc;CAuC7B"}
|
package/build/git.js
CHANGED
|
@@ -129,8 +129,9 @@ export class GitOps {
|
|
|
129
129
|
return { status: "pushed" };
|
|
130
130
|
}
|
|
131
131
|
catch (err) {
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
133
|
+
console.error(`[git] Push failed: ${message}`);
|
|
134
|
+
return { status: "failed", error: message };
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
// ── Private helpers ──────────────────────────────────────────────────────────
|
package/build/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAElD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,SAA4B,EAAE,KAAc;QACtD,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,KAAK,CAAC,OAAO,SAAS,YAAY,MAAM,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -17,12 +17,13 @@ import { detectProject, resolveProjectIdentity } from "./project.js";
|
|
|
17
17
|
import { VaultManager } from "./vault.js";
|
|
18
18
|
import { Migrator } from "./migration.js";
|
|
19
19
|
import { parseMemorySections } from "./import.js";
|
|
20
|
+
import { defaultClaudeHome, defaultVaultPath, resolveUserPath } from "./paths.js";
|
|
20
21
|
import { RememberResultSchema, RecallResultSchema, ListResultSchema, GetResultSchema, UpdateResultSchema, ForgetResultSchema, MoveResultSchema, RelateResultSchema, RecentResultSchema, MemoryGraphResultSchema, ProjectSummaryResultSchema, SyncResultSchema, WhereIsResultSchema, ConsolidateResultSchema, ProjectIdentityResultSchema, MigrationListResultSchema, MigrationExecuteResultSchema, PolicyResultSchema, } from "./structured-content.js";
|
|
21
22
|
// ── CLI Migration Command ─────────────────────────────────────────────────────
|
|
22
23
|
if (process.argv[2] === "migrate") {
|
|
23
24
|
const VAULT_PATH = process.env["VAULT_PATH"]
|
|
24
|
-
?
|
|
25
|
-
:
|
|
25
|
+
? resolveUserPath(process.env["VAULT_PATH"])
|
|
26
|
+
: defaultVaultPath();
|
|
26
27
|
async function runMigrationCli() {
|
|
27
28
|
const cwd = process.cwd();
|
|
28
29
|
const argv = process.argv.slice(3);
|
|
@@ -129,13 +130,12 @@ Examples:
|
|
|
129
130
|
}
|
|
130
131
|
// ── CLI: import-claude-memory ─────────────────────────────────────────────────
|
|
131
132
|
if (process.argv[2] === "import-claude-memory") {
|
|
132
|
-
const homeDir = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "~";
|
|
133
133
|
const VAULT_PATH = process.env["VAULT_PATH"]
|
|
134
|
-
?
|
|
135
|
-
:
|
|
134
|
+
? resolveUserPath(process.env["VAULT_PATH"])
|
|
135
|
+
: defaultVaultPath();
|
|
136
136
|
const CLAUDE_HOME = process.env["CLAUDE_HOME"]
|
|
137
|
-
?
|
|
138
|
-
:
|
|
137
|
+
? resolveUserPath(process.env["CLAUDE_HOME"])
|
|
138
|
+
: defaultClaudeHome();
|
|
139
139
|
function makeImportNoteId(title) {
|
|
140
140
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
141
141
|
const suffix = randomUUID().split("-")[0];
|
|
@@ -173,9 +173,9 @@ Examples:
|
|
|
173
173
|
}
|
|
174
174
|
const dryRun = argv.includes("--dry-run");
|
|
175
175
|
const cwdOption = argv.find(arg => arg.startsWith("--cwd="));
|
|
176
|
-
const targetCwd = cwdOption ?
|
|
176
|
+
const targetCwd = cwdOption ? resolveUserPath(cwdOption.split("=")[1]) : process.cwd();
|
|
177
177
|
const claudeHomeOption = argv.find(arg => arg.startsWith("--claude-home="));
|
|
178
|
-
const claudeHome = claudeHomeOption ?
|
|
178
|
+
const claudeHome = claudeHomeOption ? resolveUserPath(claudeHomeOption.split("=")[1]) : CLAUDE_HOME;
|
|
179
179
|
// Encode the project path the same way Claude Code does:
|
|
180
180
|
// /Users/foo/Projects/bar → -Users-foo-Projects-bar
|
|
181
181
|
// On Windows both \ and / are replaced with -
|
|
@@ -273,8 +273,8 @@ Examples:
|
|
|
273
273
|
}
|
|
274
274
|
// ── Config ────────────────────────────────────────────────────────────────────
|
|
275
275
|
const VAULT_PATH = process.env["VAULT_PATH"]
|
|
276
|
-
?
|
|
277
|
-
:
|
|
276
|
+
? resolveUserPath(process.env["VAULT_PATH"])
|
|
277
|
+
: defaultVaultPath();
|
|
278
278
|
const DEFAULT_RECALL_LIMIT = 5;
|
|
279
279
|
const DEFAULT_MIN_SIMILARITY = 0.3;
|
|
280
280
|
async function readPackageVersion() {
|
|
@@ -464,7 +464,7 @@ async function embedMissingNotes(storage, noteIds, force = false) {
|
|
|
464
464
|
}
|
|
465
465
|
if (!force) {
|
|
466
466
|
const existing = await storage.readEmbedding(note.id);
|
|
467
|
-
if (existing?.model === embedModel) {
|
|
467
|
+
if (existing?.model === embedModel && existing.updatedAt >= note.updatedAt) {
|
|
468
468
|
continue;
|
|
469
469
|
}
|
|
470
470
|
}
|
|
@@ -542,6 +542,7 @@ function buildPersistenceStatus(args) {
|
|
|
542
542
|
commitBody: args.commitBody,
|
|
543
543
|
commitReason: args.commit.reason,
|
|
544
544
|
pushReason: args.push.reason,
|
|
545
|
+
pushError: args.push.error,
|
|
545
546
|
},
|
|
546
547
|
durability: resolveDurability(args.commit, args.push),
|
|
547
548
|
};
|
|
@@ -1170,7 +1171,8 @@ server.registerTool("recall", {
|
|
|
1170
1171
|
description: "Semantic search over memories. " +
|
|
1171
1172
|
"When `cwd` is provided, searches both the project vault (.mnemonic/) and the " +
|
|
1172
1173
|
"main vault — project memories are boosted by +0.15 and shown first. " +
|
|
1173
|
-
"Without `cwd`, searches only the main vault."
|
|
1174
|
+
"Without `cwd`, searches only the main vault. " +
|
|
1175
|
+
"Missing or stale embeddings (e.g. from a git pull or direct editor edit) are backfilled on demand before searching.",
|
|
1174
1176
|
inputSchema: z.object({
|
|
1175
1177
|
query: z.string().describe("What to search for"),
|
|
1176
1178
|
cwd: projectParam,
|
|
@@ -1190,6 +1192,9 @@ server.registerTool("recall", {
|
|
|
1190
1192
|
const project = await resolveProject(cwd);
|
|
1191
1193
|
const queryVec = await embed(query);
|
|
1192
1194
|
const vaults = await vaultManager.searchOrder(cwd);
|
|
1195
|
+
for (const vault of vaults) {
|
|
1196
|
+
await embedMissingNotes(vault.storage).catch(() => { });
|
|
1197
|
+
}
|
|
1193
1198
|
const scored = [];
|
|
1194
1199
|
for (const vault of vaults) {
|
|
1195
1200
|
const embeddings = await vault.storage.listEmbeddings();
|
|
@@ -2414,8 +2419,9 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
2414
2419
|
sourceEntries.push(entry);
|
|
2415
2420
|
}
|
|
2416
2421
|
const consolidationMode = resolveEffectiveConsolidationMode(sourceEntries.map((entry) => entry.note), defaultConsolidationMode, explicitMode);
|
|
2422
|
+
const existingTargetEntry = findExistingExecuteMergeTarget(entries, sourceEntries, targetTitle);
|
|
2417
2423
|
const projectVault = cwd ? await vaultManager.getOrCreateProjectVault(cwd) : null;
|
|
2418
|
-
const targetVault = projectVault ?? vaultManager.main;
|
|
2424
|
+
const targetVault = existingTargetEntry?.vault ?? projectVault ?? vaultManager.main;
|
|
2419
2425
|
const now = new Date().toISOString();
|
|
2420
2426
|
// Build consolidated content
|
|
2421
2427
|
const sections = [];
|
|
@@ -2444,9 +2450,12 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
2444
2450
|
const combinedTags = tags ?? Array.from(new Set(sourceEntries.flatMap((e) => e.note.tags)));
|
|
2445
2451
|
// Collect all unique relationships from sources (excluding relationships among sources)
|
|
2446
2452
|
const sourceIdsSet = new Set(sourceIds);
|
|
2447
|
-
const
|
|
2448
|
-
|
|
2449
|
-
|
|
2453
|
+
const relationshipSources = existingTargetEntry
|
|
2454
|
+
? [...sourceEntries.map((entry) => entry.note), existingTargetEntry.note]
|
|
2455
|
+
: sourceEntries.map((entry) => entry.note);
|
|
2456
|
+
const allRelationships = mergeRelationshipsFromNotes(relationshipSources, sourceIdsSet);
|
|
2457
|
+
// Create or update the consolidated note
|
|
2458
|
+
const targetId = existingTargetEntry?.note.id ?? makeId(targetTitle);
|
|
2450
2459
|
const consolidatedNote = {
|
|
2451
2460
|
id: targetId,
|
|
2452
2461
|
title: targetTitle,
|
|
@@ -2456,7 +2465,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
2456
2465
|
project: project?.id,
|
|
2457
2466
|
projectName: project?.name,
|
|
2458
2467
|
relatedTo: allRelationships,
|
|
2459
|
-
createdAt: now,
|
|
2468
|
+
createdAt: existingTargetEntry?.note.createdAt ?? now,
|
|
2460
2469
|
updatedAt: now,
|
|
2461
2470
|
memoryVersion: 1,
|
|
2462
2471
|
};
|
|
@@ -2580,6 +2589,9 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
2580
2589
|
lines.push(`Consolidated ${sourceIds.length} notes into '${targetId}'`);
|
|
2581
2590
|
lines.push(`Mode: ${consolidationMode}`);
|
|
2582
2591
|
lines.push(`Stored in: ${targetVault.isProject ? "project-vault" : "main-vault"}`);
|
|
2592
|
+
if (existingTargetEntry) {
|
|
2593
|
+
lines.push("Idempotency: reused existing target note.");
|
|
2594
|
+
}
|
|
2583
2595
|
lines.push(formatPersistenceSummary(persistence));
|
|
2584
2596
|
switch (consolidationMode) {
|
|
2585
2597
|
case "supersedes":
|
|
@@ -2605,6 +2617,33 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
|
|
|
2605
2617
|
};
|
|
2606
2618
|
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
2607
2619
|
}
|
|
2620
|
+
function findExistingExecuteMergeTarget(entries, sourceEntries, targetTitle) {
|
|
2621
|
+
const normalizedTitle = targetTitle.trim();
|
|
2622
|
+
const targetSlug = slugify(normalizedTitle);
|
|
2623
|
+
const sourceIds = new Set(sourceEntries.map((entry) => entry.note.id));
|
|
2624
|
+
let sharedTargetIds;
|
|
2625
|
+
for (const entry of sourceEntries) {
|
|
2626
|
+
const supersededTargetIds = new Set((entry.note.relatedTo ?? [])
|
|
2627
|
+
.filter((rel) => rel.type === "supersedes")
|
|
2628
|
+
.map((rel) => rel.id)
|
|
2629
|
+
.filter((id) => !sourceIds.has(id)));
|
|
2630
|
+
if (supersededTargetIds.size === 0) {
|
|
2631
|
+
return undefined;
|
|
2632
|
+
}
|
|
2633
|
+
sharedTargetIds = sharedTargetIds
|
|
2634
|
+
? new Set([...sharedTargetIds].filter((id) => supersededTargetIds.has(id)))
|
|
2635
|
+
: supersededTargetIds;
|
|
2636
|
+
if (sharedTargetIds.size === 0) {
|
|
2637
|
+
return undefined;
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
const candidates = entries
|
|
2641
|
+
.filter((entry) => sharedTargetIds?.has(entry.note.id))
|
|
2642
|
+
.filter((entry) => entry.note.title.trim() === normalizedTitle)
|
|
2643
|
+
.filter((entry) => !targetSlug || entry.note.id === targetSlug || entry.note.id.startsWith(`${targetSlug}-`))
|
|
2644
|
+
.sort((left, right) => right.note.updatedAt.localeCompare(left.note.updatedAt));
|
|
2645
|
+
return candidates[0];
|
|
2646
|
+
}
|
|
2608
2647
|
async function pruneSuperseded(entries, consolidationMode, project) {
|
|
2609
2648
|
if (consolidationMode !== "delete") {
|
|
2610
2649
|
const structuredContent = {
|