fossel 1.1.0 → 1.1.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/README.md +17 -4
- package/dist/cli.js +483 -167
- package/dist/index.js +187 -64
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -212,6 +212,9 @@ function parseTags(raw) {
|
|
|
212
212
|
return [];
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
+
function normalizeNoteForReadDedupe(text) {
|
|
216
|
+
return text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
217
|
+
}
|
|
215
218
|
function buildFtsQuery(query) {
|
|
216
219
|
const terms = query.trim().split(/\s+/).map((term) => term.replace(/"/g, '""')).filter((term) => term.length > 0);
|
|
217
220
|
if (terms.length === 0) {
|
|
@@ -222,11 +225,19 @@ function buildFtsQuery(query) {
|
|
|
222
225
|
function fetchRepoContext(db, repo, limit, query) {
|
|
223
226
|
const rows = [];
|
|
224
227
|
const seen = /* @__PURE__ */ new Set();
|
|
228
|
+
const seenNormalized = /* @__PURE__ */ new Set();
|
|
225
229
|
const push = (memory, source, rank) => {
|
|
226
230
|
if (seen.has(memory.row_id)) {
|
|
227
231
|
return;
|
|
228
232
|
}
|
|
233
|
+
const normalized = normalizeNoteForReadDedupe(memory.note);
|
|
234
|
+
if (normalized && seenNormalized.has(normalized)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
229
237
|
seen.add(memory.row_id);
|
|
238
|
+
if (normalized) {
|
|
239
|
+
seenNormalized.add(normalized);
|
|
240
|
+
}
|
|
230
241
|
rows.push({ ...memory, source, rank });
|
|
231
242
|
};
|
|
232
243
|
const pinned = db.prepare(
|
|
@@ -472,6 +483,15 @@ function resolveRepoArg(input, cwd, db) {
|
|
|
472
483
|
};
|
|
473
484
|
}
|
|
474
485
|
|
|
486
|
+
// src/lib/workspace.ts
|
|
487
|
+
function getWorkspaceRoot() {
|
|
488
|
+
const fromEnv = process.env.FOSSEL_WORKSPACE?.trim();
|
|
489
|
+
if (fromEnv) {
|
|
490
|
+
return fromEnv;
|
|
491
|
+
}
|
|
492
|
+
return process.cwd();
|
|
493
|
+
}
|
|
494
|
+
|
|
475
495
|
// src/tools/dedupe-repo.ts
|
|
476
496
|
import { z } from "zod";
|
|
477
497
|
|
|
@@ -606,7 +626,7 @@ function registerDedupeRepoTool(server) {
|
|
|
606
626
|
async ({ repo, threshold, apply }) => {
|
|
607
627
|
try {
|
|
608
628
|
const db = getDb();
|
|
609
|
-
const resolved = resolveRepoArg(repo,
|
|
629
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
610
630
|
const rows = db.prepare(
|
|
611
631
|
`
|
|
612
632
|
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned, metadata_json
|
|
@@ -734,21 +754,56 @@ Re-run with apply=true to merge.`
|
|
|
734
754
|
|
|
735
755
|
// src/tools/delete.ts
|
|
736
756
|
import { z as z2 } from "zod";
|
|
757
|
+
|
|
758
|
+
// src/lib/memory.ts
|
|
759
|
+
function findMemoryByAnyId(db, input) {
|
|
760
|
+
const numeric = typeof input === "number" ? input : Number(input);
|
|
761
|
+
const isNumericId = Number.isInteger(numeric) && numeric > 0 && String(numeric) === String(input).trim();
|
|
762
|
+
if (isNumericId) {
|
|
763
|
+
const row = db.prepare(
|
|
764
|
+
`
|
|
765
|
+
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
|
|
766
|
+
FROM memories
|
|
767
|
+
WHERE rowid = ?
|
|
768
|
+
`
|
|
769
|
+
).get(numeric);
|
|
770
|
+
if (row) {
|
|
771
|
+
return row;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const stringInput = String(input).trim();
|
|
775
|
+
if (stringInput.length === 0) {
|
|
776
|
+
return null;
|
|
777
|
+
}
|
|
778
|
+
const stringRow = db.prepare(
|
|
779
|
+
`
|
|
780
|
+
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
|
|
781
|
+
FROM memories
|
|
782
|
+
WHERE id = ?
|
|
783
|
+
`
|
|
784
|
+
).get(stringInput);
|
|
785
|
+
return stringRow ?? null;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// src/tools/delete.ts
|
|
737
789
|
var deleteMemoryInputSchema = {
|
|
738
|
-
|
|
790
|
+
// Accept either the numeric row_id or the legacy nanoid string. Tools used
|
|
791
|
+
// to disagree about which form to take; this unifies them so callers can
|
|
792
|
+
// paste whichever id they have in front of them.
|
|
793
|
+
id: z2.union([z2.number().int().positive(), z2.string().trim().min(1)])
|
|
739
794
|
};
|
|
740
795
|
function registerDeleteMemoryTool(server) {
|
|
741
796
|
server.registerTool(
|
|
742
797
|
"delete_memory",
|
|
743
798
|
{
|
|
744
|
-
description: "Delete a memory from storage by id.",
|
|
799
|
+
description: "Delete a memory from storage by id. Accepts either the numeric row id or the legacy string id.",
|
|
745
800
|
inputSchema: deleteMemoryInputSchema
|
|
746
801
|
},
|
|
747
802
|
async ({ id }) => {
|
|
748
803
|
try {
|
|
749
804
|
const db = getDb();
|
|
750
|
-
const
|
|
751
|
-
if (!
|
|
805
|
+
const memory = findMemoryByAnyId(db, id);
|
|
806
|
+
if (!memory) {
|
|
752
807
|
return {
|
|
753
808
|
isError: true,
|
|
754
809
|
content: [
|
|
@@ -759,15 +814,15 @@ function registerDeleteMemoryTool(server) {
|
|
|
759
814
|
]
|
|
760
815
|
};
|
|
761
816
|
}
|
|
762
|
-
const deleteTx = db.transaction((
|
|
763
|
-
db.prepare("DELETE FROM memories WHERE
|
|
817
|
+
const deleteTx = db.transaction((rowId) => {
|
|
818
|
+
db.prepare("DELETE FROM memories WHERE rowid = ?").run(rowId);
|
|
764
819
|
});
|
|
765
|
-
deleteTx(
|
|
820
|
+
deleteTx(memory.row_id);
|
|
766
821
|
return {
|
|
767
822
|
content: [
|
|
768
823
|
{
|
|
769
824
|
type: "text",
|
|
770
|
-
text: `Deleted memory ${id}.`
|
|
825
|
+
text: `Deleted memory ${memory.row_id} (legacy: ${memory.id}).`
|
|
771
826
|
}
|
|
772
827
|
]
|
|
773
828
|
};
|
|
@@ -805,7 +860,7 @@ function registerGetContextTool(server) {
|
|
|
805
860
|
async ({ repo, query, limit, format }) => {
|
|
806
861
|
try {
|
|
807
862
|
const db = getDb();
|
|
808
|
-
const resolved = resolveRepoArg(repo,
|
|
863
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
809
864
|
const rows = fetchRepoContext(db, resolved.canonical, limit, query);
|
|
810
865
|
const text = formatContext(rows, {
|
|
811
866
|
repo: resolved.canonical,
|
|
@@ -863,7 +918,7 @@ function registerGetRepoContextTool(server) {
|
|
|
863
918
|
async ({ repo, limit }) => {
|
|
864
919
|
try {
|
|
865
920
|
const db = getDb();
|
|
866
|
-
const resolved = resolveRepoArg(repo,
|
|
921
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
867
922
|
const rows = db.prepare(
|
|
868
923
|
`
|
|
869
924
|
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
|
|
@@ -932,9 +987,10 @@ ${sections.join("\n\n")}`
|
|
|
932
987
|
// src/tools/pin.ts
|
|
933
988
|
import { z as z5 } from "zod";
|
|
934
989
|
var pinInputSchema = {
|
|
935
|
-
id
|
|
990
|
+
// Accept numeric row_id or legacy string id for parity with the other tools.
|
|
991
|
+
id: z5.union([z5.number().int().positive(), z5.string().trim().min(1)])
|
|
936
992
|
};
|
|
937
|
-
function setPinnedState(
|
|
993
|
+
function setPinnedState(rowId, pinned) {
|
|
938
994
|
const db = getDb();
|
|
939
995
|
const now = Math.floor(Date.now() / 1e3);
|
|
940
996
|
const updateResult = db.prepare(
|
|
@@ -943,7 +999,7 @@ function setPinnedState(memoryId, pinned) {
|
|
|
943
999
|
SET pinned = ?, updated_at = ?
|
|
944
1000
|
WHERE rowid = ?
|
|
945
1001
|
`
|
|
946
|
-
).run(pinned, now,
|
|
1002
|
+
).run(pinned, now, rowId);
|
|
947
1003
|
if (updateResult.changes === 0) {
|
|
948
1004
|
return null;
|
|
949
1005
|
}
|
|
@@ -953,7 +1009,7 @@ function setPinnedState(memoryId, pinned) {
|
|
|
953
1009
|
FROM memories
|
|
954
1010
|
WHERE rowid = ?
|
|
955
1011
|
`
|
|
956
|
-
).get(
|
|
1012
|
+
).get(rowId);
|
|
957
1013
|
}
|
|
958
1014
|
function registerPinMemoryTool(server) {
|
|
959
1015
|
server.registerTool(
|
|
@@ -964,7 +1020,20 @@ function registerPinMemoryTool(server) {
|
|
|
964
1020
|
},
|
|
965
1021
|
async ({ id }) => {
|
|
966
1022
|
try {
|
|
967
|
-
const
|
|
1023
|
+
const db = getDb();
|
|
1024
|
+
const target = findMemoryByAnyId(db, id);
|
|
1025
|
+
if (!target) {
|
|
1026
|
+
return {
|
|
1027
|
+
isError: true,
|
|
1028
|
+
content: [
|
|
1029
|
+
{
|
|
1030
|
+
type: "text",
|
|
1031
|
+
text: `Memory ${id} not found.`
|
|
1032
|
+
}
|
|
1033
|
+
]
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
const memory = setPinnedState(target.row_id, 1);
|
|
968
1037
|
if (!memory) {
|
|
969
1038
|
return {
|
|
970
1039
|
isError: true,
|
|
@@ -1008,7 +1077,20 @@ function registerUnpinMemoryTool(server) {
|
|
|
1008
1077
|
},
|
|
1009
1078
|
async ({ id }) => {
|
|
1010
1079
|
try {
|
|
1011
|
-
const
|
|
1080
|
+
const db = getDb();
|
|
1081
|
+
const target = findMemoryByAnyId(db, id);
|
|
1082
|
+
if (!target) {
|
|
1083
|
+
return {
|
|
1084
|
+
isError: true,
|
|
1085
|
+
content: [
|
|
1086
|
+
{
|
|
1087
|
+
type: "text",
|
|
1088
|
+
text: `Memory ${id} not found.`
|
|
1089
|
+
}
|
|
1090
|
+
]
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
const memory = setPinnedState(target.row_id, 0);
|
|
1012
1094
|
if (!memory) {
|
|
1013
1095
|
return {
|
|
1014
1096
|
isError: true,
|
|
@@ -1425,7 +1507,7 @@ function registerRememberTool(server) {
|
|
|
1425
1507
|
async ({ note, repo, type, tags }) => {
|
|
1426
1508
|
try {
|
|
1427
1509
|
const db = getDb();
|
|
1428
|
-
const resolved = resolveRepoArg(repo,
|
|
1510
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
1429
1511
|
const inferred = inferMemoryFromNote(note);
|
|
1430
1512
|
const finalType = type ?? inferred.type;
|
|
1431
1513
|
const finalTags = mergeTagLists2(tags, inferred.tags).slice(0, 5);
|
|
@@ -1542,7 +1624,7 @@ function registerResolveRepoTool(server) {
|
|
|
1542
1624
|
async ({ cwd }) => {
|
|
1543
1625
|
try {
|
|
1544
1626
|
const db = getDb();
|
|
1545
|
-
const target = cwd?.trim() ||
|
|
1627
|
+
const target = cwd?.trim() || getWorkspaceRoot();
|
|
1546
1628
|
const resolved = resolveRepo(target, db);
|
|
1547
1629
|
const payload = {
|
|
1548
1630
|
canonical: resolved.canonical,
|
|
@@ -1582,12 +1664,20 @@ var searchMemoryInputSchema = {
|
|
|
1582
1664
|
repo: z8.string().trim().min(1).optional(),
|
|
1583
1665
|
limit: z8.number().int().positive().max(50).default(5)
|
|
1584
1666
|
};
|
|
1585
|
-
function
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1667
|
+
function tokenizeQuery(query) {
|
|
1668
|
+
return query.toLowerCase().replace(/["()]/g, " ").split(/[\s/_\-.,;:!?]+/).map((token) => token.replace(/[^a-z0-9*]/g, "")).filter((token) => token.length >= 2);
|
|
1669
|
+
}
|
|
1670
|
+
function buildFtsQuery2(tokens) {
|
|
1671
|
+
if (tokens.length === 0) {
|
|
1672
|
+
return null;
|
|
1589
1673
|
}
|
|
1590
|
-
return
|
|
1674
|
+
return tokens.map((token) => `"${token.replace(/"/g, '""')}"`).join(" AND ");
|
|
1675
|
+
}
|
|
1676
|
+
function buildFtsQueryOr(tokens) {
|
|
1677
|
+
if (tokens.length === 0) {
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
return tokens.map((token) => `"${token.replace(/"/g, '""')}"`).join(" OR ");
|
|
1591
1681
|
}
|
|
1592
1682
|
function parseTags4(raw) {
|
|
1593
1683
|
try {
|
|
@@ -1597,37 +1687,66 @@ function parseTags4(raw) {
|
|
|
1597
1687
|
return [];
|
|
1598
1688
|
}
|
|
1599
1689
|
}
|
|
1690
|
+
function runFts(ftsQuery, resolvedRepo, limit) {
|
|
1691
|
+
const db = getDb();
|
|
1692
|
+
try {
|
|
1693
|
+
if (resolvedRepo) {
|
|
1694
|
+
return db.prepare(
|
|
1695
|
+
`
|
|
1696
|
+
SELECT m.rowid AS row_id, m.id, m.repo, m.type, m.note, m.tags,
|
|
1697
|
+
m.created_at, m.updated_at, m.pinned, bm25(memories_fts) AS rank
|
|
1698
|
+
FROM memories_fts
|
|
1699
|
+
JOIN memories AS m ON m.rowid = memories_fts.rowid
|
|
1700
|
+
WHERE memories_fts MATCH ? AND m.repo = ?
|
|
1701
|
+
ORDER BY rank
|
|
1702
|
+
LIMIT ?
|
|
1703
|
+
`
|
|
1704
|
+
).all(ftsQuery, resolvedRepo, limit);
|
|
1705
|
+
}
|
|
1706
|
+
return db.prepare(
|
|
1707
|
+
`
|
|
1708
|
+
SELECT m.rowid AS row_id, m.id, m.repo, m.type, m.note, m.tags,
|
|
1709
|
+
m.created_at, m.updated_at, m.pinned, bm25(memories_fts) AS rank
|
|
1710
|
+
FROM memories_fts
|
|
1711
|
+
JOIN memories AS m ON m.rowid = memories_fts.rowid
|
|
1712
|
+
WHERE memories_fts MATCH ?
|
|
1713
|
+
ORDER BY rank
|
|
1714
|
+
LIMIT ?
|
|
1715
|
+
`
|
|
1716
|
+
).all(ftsQuery, limit);
|
|
1717
|
+
} catch {
|
|
1718
|
+
return [];
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1600
1721
|
function registerSearchMemoryTool(server) {
|
|
1601
1722
|
server.registerTool(
|
|
1602
1723
|
"search_memory",
|
|
1603
1724
|
{
|
|
1604
|
-
description: "Search memories using full-text search with optional repository filtering.",
|
|
1725
|
+
description: "Search memories using full-text search with optional repository filtering. Falls back to recent + pinned context when the query has no exact matches.",
|
|
1605
1726
|
inputSchema: searchMemoryInputSchema
|
|
1606
1727
|
},
|
|
1607
1728
|
async ({ query, repo, limit }) => {
|
|
1608
1729
|
try {
|
|
1609
1730
|
const db = getDb();
|
|
1610
|
-
const
|
|
1611
|
-
const resolvedRepo = repo ? resolveRepoArg(repo,
|
|
1612
|
-
const
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
`
|
|
1630
|
-
).all(ftsQuery, limit);
|
|
1731
|
+
const tokens = tokenizeQuery(query);
|
|
1732
|
+
const resolvedRepo = repo ? resolveRepoArg(repo, getWorkspaceRoot(), db).canonical : void 0;
|
|
1733
|
+
const andQuery = buildFtsQuery2(tokens);
|
|
1734
|
+
let rows = [];
|
|
1735
|
+
if (andQuery) {
|
|
1736
|
+
rows = runFts(andQuery, resolvedRepo, limit);
|
|
1737
|
+
}
|
|
1738
|
+
if (rows.length === 0 && tokens.length > 1) {
|
|
1739
|
+
const orQuery = buildFtsQueryOr(tokens);
|
|
1740
|
+
if (orQuery) {
|
|
1741
|
+
rows = runFts(orQuery, resolvedRepo, limit);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
let usedFallback = false;
|
|
1745
|
+
if (rows.length === 0 && resolvedRepo) {
|
|
1746
|
+
const fallback = fetchRepoContext(db, resolvedRepo, limit);
|
|
1747
|
+
rows = fallback.map((row) => ({ ...row, rank: 0 }));
|
|
1748
|
+
usedFallback = fallback.length > 0;
|
|
1749
|
+
}
|
|
1631
1750
|
if (rows.length === 0) {
|
|
1632
1751
|
return {
|
|
1633
1752
|
content: [
|
|
@@ -1645,11 +1764,12 @@ function registerSearchMemoryTool(server) {
|
|
|
1645
1764
|
return `${index + 1}. [${row.repo}] ${row.type} (${row.row_id} | legacy: ${row.id})
|
|
1646
1765
|
${pinPrefix}${row.note}${tagsText}`;
|
|
1647
1766
|
}).join("\n\n");
|
|
1767
|
+
const header = usedFallback ? `No exact match for "${query}"${resolvedRepo ? ` in ${resolvedRepo}` : ""}; showing recent + pinned context:` : `Search results for "${query}"${resolvedRepo ? ` in ${resolvedRepo}` : ""}:`;
|
|
1648
1768
|
return {
|
|
1649
1769
|
content: [
|
|
1650
1770
|
{
|
|
1651
1771
|
type: "text",
|
|
1652
|
-
text:
|
|
1772
|
+
text: `${header}
|
|
1653
1773
|
|
|
1654
1774
|
${formatted}`
|
|
1655
1775
|
}
|
|
@@ -1690,7 +1810,7 @@ function registerStoreContextTool(server) {
|
|
|
1690
1810
|
async ({ repo, type, note, tags }) => {
|
|
1691
1811
|
try {
|
|
1692
1812
|
const db = getDb();
|
|
1693
|
-
const resolved = resolveRepoArg(repo,
|
|
1813
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
1694
1814
|
const now = Math.floor(Date.now() / 1e3);
|
|
1695
1815
|
const id = nanoid2();
|
|
1696
1816
|
const normalizedTags = Array.from(
|
|
@@ -1765,7 +1885,7 @@ function registerSummarizeRepoContextTool(server) {
|
|
|
1765
1885
|
async ({ repo }) => {
|
|
1766
1886
|
try {
|
|
1767
1887
|
const db = getDb();
|
|
1768
|
-
const resolved = resolveRepoArg(repo,
|
|
1888
|
+
const resolved = resolveRepoArg(repo, getWorkspaceRoot(), db);
|
|
1769
1889
|
const rows = db.prepare(
|
|
1770
1890
|
`
|
|
1771
1891
|
SELECT rowid AS row_id, type, note, pinned
|
|
@@ -1827,7 +1947,9 @@ ${entries.join("\n")}`);
|
|
|
1827
1947
|
// src/tools/update.ts
|
|
1828
1948
|
import { z as z11 } from "zod";
|
|
1829
1949
|
var updateMemoryInputSchema = {
|
|
1830
|
-
id
|
|
1950
|
+
// Accept numeric row_id or legacy string id so callers can paste whichever
|
|
1951
|
+
// form they have.
|
|
1952
|
+
id: z11.union([z11.number().int().positive(), z11.string().trim().min(1)]),
|
|
1831
1953
|
content: z11.string().trim().min(1).optional(),
|
|
1832
1954
|
memory_type: z11.enum(MEMORY_TYPES).optional()
|
|
1833
1955
|
};
|
|
@@ -1859,7 +1981,7 @@ function registerUpdateMemoryTool(server) {
|
|
|
1859
1981
|
server.registerTool(
|
|
1860
1982
|
"update_memory",
|
|
1861
1983
|
{
|
|
1862
|
-
description: "Update an existing memory by numeric
|
|
1984
|
+
description: "Update an existing memory by id (numeric or legacy string) with partial fields.",
|
|
1863
1985
|
inputSchema: updateMemoryInputSchema
|
|
1864
1986
|
},
|
|
1865
1987
|
async ({ id, content, memory_type }) => {
|
|
@@ -1876,14 +1998,8 @@ function registerUpdateMemoryTool(server) {
|
|
|
1876
1998
|
};
|
|
1877
1999
|
}
|
|
1878
2000
|
const db = getDb();
|
|
1879
|
-
const
|
|
1880
|
-
|
|
1881
|
-
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
|
|
1882
|
-
FROM memories
|
|
1883
|
-
WHERE rowid = ?
|
|
1884
|
-
`
|
|
1885
|
-
).get(id);
|
|
1886
|
-
if (!existing) {
|
|
2001
|
+
const target = findMemoryByAnyId(db, id);
|
|
2002
|
+
if (!target) {
|
|
1887
2003
|
return {
|
|
1888
2004
|
isError: true,
|
|
1889
2005
|
content: [
|
|
@@ -1894,6 +2010,13 @@ function registerUpdateMemoryTool(server) {
|
|
|
1894
2010
|
]
|
|
1895
2011
|
};
|
|
1896
2012
|
}
|
|
2013
|
+
const existing = db.prepare(
|
|
2014
|
+
`
|
|
2015
|
+
SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
|
|
2016
|
+
FROM memories
|
|
2017
|
+
WHERE rowid = ?
|
|
2018
|
+
`
|
|
2019
|
+
).get(target.row_id);
|
|
1897
2020
|
const now = Math.floor(Date.now() / 1e3);
|
|
1898
2021
|
const nextType = memory_type ?? existing.type;
|
|
1899
2022
|
const nextNote = content ?? existing.note;
|
|
@@ -1905,7 +2028,7 @@ function registerUpdateMemoryTool(server) {
|
|
|
1905
2028
|
SET type = ?, note = ?, note_normalized = ?, updated_at = ?
|
|
1906
2029
|
WHERE rowid = ?
|
|
1907
2030
|
`
|
|
1908
|
-
).run(nextType, nextNote, nextNormalized, now,
|
|
2031
|
+
).run(nextType, nextNote, nextNormalized, now, existing.row_id);
|
|
1909
2032
|
} else {
|
|
1910
2033
|
db.prepare(
|
|
1911
2034
|
`
|
|
@@ -1913,7 +2036,7 @@ function registerUpdateMemoryTool(server) {
|
|
|
1913
2036
|
SET type = ?, note = ?, updated_at = ?
|
|
1914
2037
|
WHERE rowid = ?
|
|
1915
2038
|
`
|
|
1916
|
-
).run(nextType, nextNote, now,
|
|
2039
|
+
).run(nextType, nextNote, now, existing.row_id);
|
|
1917
2040
|
}
|
|
1918
2041
|
const updated = db.prepare(
|
|
1919
2042
|
`
|
|
@@ -1921,7 +2044,7 @@ function registerUpdateMemoryTool(server) {
|
|
|
1921
2044
|
FROM memories
|
|
1922
2045
|
WHERE rowid = ?
|
|
1923
2046
|
`
|
|
1924
|
-
).get(
|
|
2047
|
+
).get(existing.row_id);
|
|
1925
2048
|
if (!updated) {
|
|
1926
2049
|
return {
|
|
1927
2050
|
isError: true,
|
|
@@ -1973,7 +2096,7 @@ function registerStartupContextResource(server) {
|
|
|
1973
2096
|
async (uri) => {
|
|
1974
2097
|
try {
|
|
1975
2098
|
const db = getDb();
|
|
1976
|
-
const resolved = resolveRepo(
|
|
2099
|
+
const resolved = resolveRepo(getWorkspaceRoot(), db);
|
|
1977
2100
|
const rows = fetchRepoContext(db, resolved.canonical, 5);
|
|
1978
2101
|
const text = formatContext(rows, {
|
|
1979
2102
|
repo: resolved.canonical,
|
|
@@ -2010,7 +2133,7 @@ async function startServer() {
|
|
|
2010
2133
|
initDb(dbPath);
|
|
2011
2134
|
const server = new McpServer({
|
|
2012
2135
|
name: "fossel",
|
|
2013
|
-
version: "1.1.
|
|
2136
|
+
version: "1.1.1"
|
|
2014
2137
|
});
|
|
2015
2138
|
registerRememberTool(server);
|
|
2016
2139
|
registerGetContextTool(server);
|