mcp-memory-bucket 0.12.3 → 0.12.5
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.
|
@@ -629,9 +629,11 @@ export class MemoryRepository {
|
|
|
629
629
|
const existing = await this.get(folder, filename);
|
|
630
630
|
if (!existing)
|
|
631
631
|
throw new Error(`memory doc "${filename}" not found`);
|
|
632
|
-
// `paused` is local-cache-only and
|
|
633
|
-
// `existing` before spreading the rest into
|
|
634
|
-
|
|
632
|
+
// `paused` is local-cache-only and `body` is written separately as the markdown body, not
|
|
633
|
+
// frontmatter — both must be split off of `existing` before spreading the rest into
|
|
634
|
+
// `merged`, or they'd ride along into the MemoryFrontmatter written to disk (duplicating the
|
|
635
|
+
// body inside its own frontmatter as a `body:` key).
|
|
636
|
+
const { paused: existingPaused, body: _existingBody, ...existingForFile } = existing;
|
|
635
637
|
const merged = {
|
|
636
638
|
...existingForFile,
|
|
637
639
|
...frontmatter,
|
|
@@ -531,9 +531,11 @@ export class SkillRepository {
|
|
|
531
531
|
const existing = await this.get(name, folder);
|
|
532
532
|
if (!existing)
|
|
533
533
|
throw new Error(`skill with name "${name}" not found`);
|
|
534
|
-
// `paused` is local-cache-only and
|
|
535
|
-
// `existing` before spreading the rest into
|
|
536
|
-
|
|
534
|
+
// `paused` is local-cache-only and `body` is written separately as the markdown body, not
|
|
535
|
+
// frontmatter — both must be split off of `existing` before spreading the rest into
|
|
536
|
+
// `merged`, or they'd ride along into the SkillFrontmatter written to disk (duplicating the
|
|
537
|
+
// body inside its own frontmatter as a `body:` key).
|
|
538
|
+
const { paused: existingPaused, body: _existingBody, ...existingForFile } = existing;
|
|
537
539
|
// Builtin skills (e.g. memory-bucket-authoring) are the server's own always-present
|
|
538
540
|
// documentation, not user content — deprecating them would hide guidance every session needs.
|
|
539
541
|
const deprecated = this.isBuiltin(existing) ? existing.deprecated : frontmatter?.deprecated;
|
|
@@ -585,7 +587,9 @@ export class SkillRepository {
|
|
|
585
587
|
const newFilePath = path.join(newDir, 'SKILL.md');
|
|
586
588
|
// Rename changes the skill's id, so it becomes a fresh cache row — paused (local-only,
|
|
587
589
|
// keyed by id) does not carry over, same as it wouldn't survive deleting the cache file.
|
|
588
|
-
|
|
590
|
+
// `body` is split off too, for the same reason as in update() — it must not ride along into
|
|
591
|
+
// the SkillFrontmatter written to disk.
|
|
592
|
+
const { paused: _existingPaused, body: _existingBody, ...existingForFile } = existing;
|
|
589
593
|
const merged = { ...existingForFile, name: newName };
|
|
590
594
|
const fileContents = formatMarkdownFile(stripSourcePath(merged), existing.body);
|
|
591
595
|
const remote = this.remoteFor(existing.folder);
|
package/dist/src/store/sync.js
CHANGED
|
@@ -182,8 +182,42 @@ export function upsertFile(db, spec, filePath) {
|
|
|
182
182
|
.map((c) => `${c} = excluded.${c}`)
|
|
183
183
|
.join(', ');
|
|
184
184
|
const conflictTarget = scopedById ? 'folder, id' : 'source_path';
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
const insert = () => db
|
|
186
|
+
.prepare(`INSERT INTO ${spec.table} (${cols.join(', ')}) VALUES (${placeholders})
|
|
187
|
+
ON CONFLICT(${conflictTarget}) DO UPDATE SET ${updateClause}`)
|
|
188
|
+
.run(...values);
|
|
189
|
+
try {
|
|
190
|
+
insert();
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
// Belt-and-suspenders: the collision guards above are pre-checks against a fresh SELECT, and
|
|
194
|
+
// can still miss a stale row above (e.g. a source_path left over from before a folder/root
|
|
195
|
+
// rename, or a filesystem case-sensitivity mismatch between the path stored earlier and the
|
|
196
|
+
// one passed in now) — in which case the plain INSERT itself throws the raw SQLITE_CONSTRAINT
|
|
197
|
+
// error, which used to propagate straight out of upsertFile and abort the entire remote
|
|
198
|
+
// resync/poll tick for every OTHER file too (see the "initial remote skill resync failed"
|
|
199
|
+
// crash report this was added for). Self-heal instead: whatever row is squatting on this
|
|
200
|
+
// conflict target, evict it (same as a real delete would) and retry the insert once. If it
|
|
201
|
+
// still fails after that, log and skip this one file rather than taking the whole sync down.
|
|
202
|
+
if (err instanceof Error && 'code' in err && err.code === 'SQLITE_CONSTRAINT_UNIQUE') {
|
|
203
|
+
const staleSourcePath = scopedById
|
|
204
|
+
? db.prepare(`SELECT source_path FROM ${spec.table} WHERE folder = ? AND id = ?`).get(folder, id)?.source_path
|
|
205
|
+
: filePath;
|
|
206
|
+
if (staleSourcePath)
|
|
207
|
+
removeFile(db, spec.table, staleSourcePath);
|
|
208
|
+
try {
|
|
209
|
+
insert();
|
|
210
|
+
console.error(`[memory-bucket] recovered from a stale ${spec.table} row blocking ${filePath} (evicted ${staleSourcePath}) — re-indexed successfully`);
|
|
211
|
+
}
|
|
212
|
+
catch (retryErr) {
|
|
213
|
+
console.error(`[memory-bucket] SKIPPED indexing ${filePath}: unresolvable ${spec.table} conflict — ${retryErr.message}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
throw err;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
187
221
|
// ref_folder scopes these two tables' delete-then-reinsert the same way the skills upsert above
|
|
188
222
|
// does: two skills in different folders can now legitimately share an `id`, so ref_id alone is
|
|
189
223
|
// no longer enough to identify "this file's" search_index/doc_dates rows without also clobbering
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing skill_* (reusable coding patterns) and memory_* (point-in-time working context) tools over a markdown+frontmatter source, cached into SQLite at runtime.",
|
|
6
6
|
"repository": {
|