claude-memory-layer 1.0.2 → 1.0.4
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/settings.local.json +3 -1
- package/.history/package_20260201133143.json +45 -0
- package/CLAUDE.md +14 -0
- package/dist/cli/index.js +836 -9
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +782 -3
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/session-end.js +836 -9
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +836 -9
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +836 -9
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +839 -10
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/services/memory-service.js +836 -9
- package/dist/services/memory-service.js.map +4 -4
- package/package.json +1 -1
- package/src/core/index.ts +6 -0
- package/src/core/retriever.ts +118 -2
- package/src/core/shared-event-store.ts +114 -0
- package/src/core/shared-promoter.ts +249 -0
- package/src/core/shared-store.ts +289 -0
- package/src/core/shared-vector-store.ts +203 -0
- package/src/core/types.ts +69 -2
- package/src/hooks/user-prompt-submit.ts +6 -2
- package/src/services/memory-service.ts +145 -6
package/dist/cli/index.js
CHANGED
|
@@ -1192,11 +1192,22 @@ var Retriever = class {
|
|
|
1192
1192
|
vectorStore;
|
|
1193
1193
|
embedder;
|
|
1194
1194
|
matcher;
|
|
1195
|
-
|
|
1195
|
+
sharedStore;
|
|
1196
|
+
sharedVectorStore;
|
|
1197
|
+
constructor(eventStore, vectorStore, embedder, matcher, sharedOptions) {
|
|
1196
1198
|
this.eventStore = eventStore;
|
|
1197
1199
|
this.vectorStore = vectorStore;
|
|
1198
1200
|
this.embedder = embedder;
|
|
1199
1201
|
this.matcher = matcher;
|
|
1202
|
+
this.sharedStore = sharedOptions?.sharedStore;
|
|
1203
|
+
this.sharedVectorStore = sharedOptions?.sharedVectorStore;
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Set shared stores after construction
|
|
1207
|
+
*/
|
|
1208
|
+
setSharedStores(sharedStore, sharedVectorStore) {
|
|
1209
|
+
this.sharedStore = sharedStore;
|
|
1210
|
+
this.sharedVectorStore = sharedVectorStore;
|
|
1200
1211
|
}
|
|
1201
1212
|
/**
|
|
1202
1213
|
* Retrieve relevant memories for a query
|
|
@@ -1223,6 +1234,75 @@ var Retriever = class {
|
|
|
1223
1234
|
context
|
|
1224
1235
|
};
|
|
1225
1236
|
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Retrieve with unified search (project + shared)
|
|
1239
|
+
*/
|
|
1240
|
+
async retrieveUnified(query, options = {}) {
|
|
1241
|
+
const projectResult = await this.retrieve(query, options);
|
|
1242
|
+
if (!options.includeShared || !this.sharedStore || !this.sharedVectorStore) {
|
|
1243
|
+
return projectResult;
|
|
1244
|
+
}
|
|
1245
|
+
try {
|
|
1246
|
+
const queryEmbedding = await this.embedder.embed(query);
|
|
1247
|
+
const sharedVectorResults = await this.sharedVectorStore.search(
|
|
1248
|
+
queryEmbedding.vector,
|
|
1249
|
+
{
|
|
1250
|
+
limit: options.topK || 5,
|
|
1251
|
+
minScore: options.minScore || 0.7,
|
|
1252
|
+
excludeProjectHash: options.projectHash
|
|
1253
|
+
}
|
|
1254
|
+
);
|
|
1255
|
+
const sharedMemories = [];
|
|
1256
|
+
for (const result of sharedVectorResults) {
|
|
1257
|
+
const entry = await this.sharedStore.get(result.entryId);
|
|
1258
|
+
if (entry) {
|
|
1259
|
+
if (!options.projectHash || entry.sourceProjectHash !== options.projectHash) {
|
|
1260
|
+
sharedMemories.push(entry);
|
|
1261
|
+
await this.sharedStore.recordUsage(entry.entryId);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
const unifiedContext = this.buildUnifiedContext(projectResult, sharedMemories);
|
|
1266
|
+
return {
|
|
1267
|
+
...projectResult,
|
|
1268
|
+
context: unifiedContext,
|
|
1269
|
+
totalTokens: this.estimateTokens(unifiedContext),
|
|
1270
|
+
sharedMemories
|
|
1271
|
+
};
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
console.error("Shared search failed:", error);
|
|
1274
|
+
return projectResult;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Build unified context combining project and shared memories
|
|
1279
|
+
*/
|
|
1280
|
+
buildUnifiedContext(projectResult, sharedMemories) {
|
|
1281
|
+
let context = projectResult.context;
|
|
1282
|
+
if (sharedMemories.length > 0) {
|
|
1283
|
+
context += "\n\n## Cross-Project Knowledge\n\n";
|
|
1284
|
+
for (const memory of sharedMemories.slice(0, 3)) {
|
|
1285
|
+
context += `### ${memory.title}
|
|
1286
|
+
`;
|
|
1287
|
+
if (memory.symptoms.length > 0) {
|
|
1288
|
+
context += `**Symptoms:** ${memory.symptoms.join(", ")}
|
|
1289
|
+
`;
|
|
1290
|
+
}
|
|
1291
|
+
context += `**Root Cause:** ${memory.rootCause}
|
|
1292
|
+
`;
|
|
1293
|
+
context += `**Solution:** ${memory.solution}
|
|
1294
|
+
`;
|
|
1295
|
+
if (memory.technologies && memory.technologies.length > 0) {
|
|
1296
|
+
context += `**Technologies:** ${memory.technologies.join(", ")}
|
|
1297
|
+
`;
|
|
1298
|
+
}
|
|
1299
|
+
context += `_Confidence: ${(memory.confidence * 100).toFixed(0)}%_
|
|
1300
|
+
|
|
1301
|
+
`;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return context;
|
|
1305
|
+
}
|
|
1226
1306
|
/**
|
|
1227
1307
|
* Retrieve memories from a specific session
|
|
1228
1308
|
*/
|
|
@@ -1578,6 +1658,658 @@ function createGraduationPipeline(eventStore) {
|
|
|
1578
1658
|
return new GraduationPipeline(eventStore);
|
|
1579
1659
|
}
|
|
1580
1660
|
|
|
1661
|
+
// src/core/shared-event-store.ts
|
|
1662
|
+
var SharedEventStore = class {
|
|
1663
|
+
constructor(dbPath) {
|
|
1664
|
+
this.dbPath = dbPath;
|
|
1665
|
+
this.db = createDatabase(dbPath);
|
|
1666
|
+
}
|
|
1667
|
+
db;
|
|
1668
|
+
initialized = false;
|
|
1669
|
+
async initialize() {
|
|
1670
|
+
if (this.initialized)
|
|
1671
|
+
return;
|
|
1672
|
+
await dbRun(this.db, `
|
|
1673
|
+
CREATE TABLE IF NOT EXISTS shared_troubleshooting (
|
|
1674
|
+
entry_id VARCHAR PRIMARY KEY,
|
|
1675
|
+
source_project_hash VARCHAR NOT NULL,
|
|
1676
|
+
source_entry_id VARCHAR NOT NULL,
|
|
1677
|
+
title VARCHAR NOT NULL,
|
|
1678
|
+
symptoms JSON NOT NULL,
|
|
1679
|
+
root_cause TEXT NOT NULL,
|
|
1680
|
+
solution TEXT NOT NULL,
|
|
1681
|
+
topics JSON NOT NULL,
|
|
1682
|
+
technologies JSON,
|
|
1683
|
+
confidence REAL NOT NULL DEFAULT 0.8,
|
|
1684
|
+
usage_count INTEGER DEFAULT 0,
|
|
1685
|
+
last_used_at TIMESTAMP,
|
|
1686
|
+
promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1687
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1688
|
+
UNIQUE(source_project_hash, source_entry_id)
|
|
1689
|
+
)
|
|
1690
|
+
`);
|
|
1691
|
+
await dbRun(this.db, `
|
|
1692
|
+
CREATE TABLE IF NOT EXISTS shared_best_practices (
|
|
1693
|
+
entry_id VARCHAR PRIMARY KEY,
|
|
1694
|
+
source_project_hash VARCHAR NOT NULL,
|
|
1695
|
+
source_entry_id VARCHAR NOT NULL,
|
|
1696
|
+
title VARCHAR NOT NULL,
|
|
1697
|
+
content_json JSON NOT NULL,
|
|
1698
|
+
topics JSON NOT NULL,
|
|
1699
|
+
confidence REAL NOT NULL DEFAULT 0.8,
|
|
1700
|
+
usage_count INTEGER DEFAULT 0,
|
|
1701
|
+
promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1702
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1703
|
+
UNIQUE(source_project_hash, source_entry_id)
|
|
1704
|
+
)
|
|
1705
|
+
`);
|
|
1706
|
+
await dbRun(this.db, `
|
|
1707
|
+
CREATE TABLE IF NOT EXISTS shared_common_errors (
|
|
1708
|
+
entry_id VARCHAR PRIMARY KEY,
|
|
1709
|
+
source_project_hash VARCHAR NOT NULL,
|
|
1710
|
+
source_entry_id VARCHAR NOT NULL,
|
|
1711
|
+
title VARCHAR NOT NULL,
|
|
1712
|
+
error_pattern TEXT NOT NULL,
|
|
1713
|
+
solution TEXT NOT NULL,
|
|
1714
|
+
topics JSON NOT NULL,
|
|
1715
|
+
technologies JSON,
|
|
1716
|
+
confidence REAL NOT NULL DEFAULT 0.8,
|
|
1717
|
+
usage_count INTEGER DEFAULT 0,
|
|
1718
|
+
promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1719
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1720
|
+
UNIQUE(source_project_hash, source_entry_id)
|
|
1721
|
+
)
|
|
1722
|
+
`);
|
|
1723
|
+
await dbRun(this.db, `
|
|
1724
|
+
CREATE INDEX IF NOT EXISTS idx_shared_ts_confidence
|
|
1725
|
+
ON shared_troubleshooting(confidence DESC)
|
|
1726
|
+
`);
|
|
1727
|
+
await dbRun(this.db, `
|
|
1728
|
+
CREATE INDEX IF NOT EXISTS idx_shared_ts_usage
|
|
1729
|
+
ON shared_troubleshooting(usage_count DESC)
|
|
1730
|
+
`);
|
|
1731
|
+
await dbRun(this.db, `
|
|
1732
|
+
CREATE INDEX IF NOT EXISTS idx_shared_ts_source
|
|
1733
|
+
ON shared_troubleshooting(source_project_hash)
|
|
1734
|
+
`);
|
|
1735
|
+
this.initialized = true;
|
|
1736
|
+
}
|
|
1737
|
+
getDatabase() {
|
|
1738
|
+
return this.db;
|
|
1739
|
+
}
|
|
1740
|
+
isInitialized() {
|
|
1741
|
+
return this.initialized;
|
|
1742
|
+
}
|
|
1743
|
+
async close() {
|
|
1744
|
+
await dbClose(this.db);
|
|
1745
|
+
this.initialized = false;
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
function createSharedEventStore(dbPath) {
|
|
1749
|
+
return new SharedEventStore(dbPath);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// src/core/shared-store.ts
|
|
1753
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1754
|
+
var SharedStore = class {
|
|
1755
|
+
constructor(sharedEventStore) {
|
|
1756
|
+
this.sharedEventStore = sharedEventStore;
|
|
1757
|
+
}
|
|
1758
|
+
get db() {
|
|
1759
|
+
return this.sharedEventStore.getDatabase();
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Promote a verified troubleshooting entry to shared storage
|
|
1763
|
+
*/
|
|
1764
|
+
async promoteEntry(input) {
|
|
1765
|
+
const entryId = randomUUID2();
|
|
1766
|
+
await dbRun(
|
|
1767
|
+
this.db,
|
|
1768
|
+
`INSERT INTO shared_troubleshooting (
|
|
1769
|
+
entry_id, source_project_hash, source_entry_id,
|
|
1770
|
+
title, symptoms, root_cause, solution, topics,
|
|
1771
|
+
technologies, confidence, promoted_at
|
|
1772
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
1773
|
+
ON CONFLICT (source_project_hash, source_entry_id)
|
|
1774
|
+
DO UPDATE SET
|
|
1775
|
+
title = excluded.title,
|
|
1776
|
+
symptoms = excluded.symptoms,
|
|
1777
|
+
root_cause = excluded.root_cause,
|
|
1778
|
+
solution = excluded.solution,
|
|
1779
|
+
topics = excluded.topics,
|
|
1780
|
+
technologies = excluded.technologies,
|
|
1781
|
+
confidence = CASE
|
|
1782
|
+
WHEN excluded.confidence > shared_troubleshooting.confidence
|
|
1783
|
+
THEN excluded.confidence
|
|
1784
|
+
ELSE shared_troubleshooting.confidence
|
|
1785
|
+
END`,
|
|
1786
|
+
[
|
|
1787
|
+
entryId,
|
|
1788
|
+
input.sourceProjectHash,
|
|
1789
|
+
input.sourceEntryId,
|
|
1790
|
+
input.title,
|
|
1791
|
+
JSON.stringify(input.symptoms),
|
|
1792
|
+
input.rootCause,
|
|
1793
|
+
input.solution,
|
|
1794
|
+
JSON.stringify(input.topics),
|
|
1795
|
+
JSON.stringify(input.technologies || []),
|
|
1796
|
+
input.confidence
|
|
1797
|
+
]
|
|
1798
|
+
);
|
|
1799
|
+
return entryId;
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Search troubleshooting entries by text query
|
|
1803
|
+
*/
|
|
1804
|
+
async search(query, options) {
|
|
1805
|
+
const topK = options?.topK || 5;
|
|
1806
|
+
const minConfidence = options?.minConfidence || 0.5;
|
|
1807
|
+
const searchPattern = `%${query}%`;
|
|
1808
|
+
const rows = await dbAll(
|
|
1809
|
+
this.db,
|
|
1810
|
+
`SELECT * FROM shared_troubleshooting
|
|
1811
|
+
WHERE (title LIKE ? OR root_cause LIKE ? OR solution LIKE ?)
|
|
1812
|
+
AND confidence >= ?
|
|
1813
|
+
ORDER BY confidence DESC, usage_count DESC
|
|
1814
|
+
LIMIT ?`,
|
|
1815
|
+
[searchPattern, searchPattern, searchPattern, minConfidence, topK]
|
|
1816
|
+
);
|
|
1817
|
+
return rows.map(this.rowToEntry);
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Search by topics
|
|
1821
|
+
*/
|
|
1822
|
+
async searchByTopics(topics, options) {
|
|
1823
|
+
const topK = options?.topK || 5;
|
|
1824
|
+
if (topics.length === 0) {
|
|
1825
|
+
return [];
|
|
1826
|
+
}
|
|
1827
|
+
const topicConditions = topics.map(() => `topics LIKE ?`).join(" OR ");
|
|
1828
|
+
const topicParams = topics.map((t) => `%"${t}"%`);
|
|
1829
|
+
let query = `SELECT * FROM shared_troubleshooting WHERE (${topicConditions})`;
|
|
1830
|
+
const params = [...topicParams];
|
|
1831
|
+
if (options?.excludeProjectHash) {
|
|
1832
|
+
query += ` AND source_project_hash != ?`;
|
|
1833
|
+
params.push(options.excludeProjectHash);
|
|
1834
|
+
}
|
|
1835
|
+
query += ` ORDER BY confidence DESC, usage_count DESC LIMIT ?`;
|
|
1836
|
+
params.push(topK);
|
|
1837
|
+
const rows = await dbAll(this.db, query, params);
|
|
1838
|
+
return rows.map(this.rowToEntry);
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Record usage of a shared entry (for ranking)
|
|
1842
|
+
*/
|
|
1843
|
+
async recordUsage(entryId) {
|
|
1844
|
+
await dbRun(
|
|
1845
|
+
this.db,
|
|
1846
|
+
`UPDATE shared_troubleshooting
|
|
1847
|
+
SET usage_count = usage_count + 1,
|
|
1848
|
+
last_used_at = CURRENT_TIMESTAMP
|
|
1849
|
+
WHERE entry_id = ?`,
|
|
1850
|
+
[entryId]
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Get entry by ID
|
|
1855
|
+
*/
|
|
1856
|
+
async get(entryId) {
|
|
1857
|
+
const rows = await dbAll(
|
|
1858
|
+
this.db,
|
|
1859
|
+
`SELECT * FROM shared_troubleshooting WHERE entry_id = ?`,
|
|
1860
|
+
[entryId]
|
|
1861
|
+
);
|
|
1862
|
+
if (rows.length === 0)
|
|
1863
|
+
return null;
|
|
1864
|
+
return this.rowToEntry(rows[0]);
|
|
1865
|
+
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Get entry by source (project hash + entry ID)
|
|
1868
|
+
*/
|
|
1869
|
+
async getBySource(projectHash, sourceEntryId) {
|
|
1870
|
+
const rows = await dbAll(
|
|
1871
|
+
this.db,
|
|
1872
|
+
`SELECT * FROM shared_troubleshooting
|
|
1873
|
+
WHERE source_project_hash = ? AND source_entry_id = ?`,
|
|
1874
|
+
[projectHash, sourceEntryId]
|
|
1875
|
+
);
|
|
1876
|
+
if (rows.length === 0)
|
|
1877
|
+
return null;
|
|
1878
|
+
return this.rowToEntry(rows[0]);
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Check if an entry already exists in shared store
|
|
1882
|
+
*/
|
|
1883
|
+
async exists(projectHash, sourceEntryId) {
|
|
1884
|
+
const result = await dbAll(
|
|
1885
|
+
this.db,
|
|
1886
|
+
`SELECT COUNT(*) as count FROM shared_troubleshooting
|
|
1887
|
+
WHERE source_project_hash = ? AND source_entry_id = ?`,
|
|
1888
|
+
[projectHash, sourceEntryId]
|
|
1889
|
+
);
|
|
1890
|
+
return (result[0]?.count || 0) > 0;
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* Get all entries (with limit for safety)
|
|
1894
|
+
*/
|
|
1895
|
+
async getAll(options) {
|
|
1896
|
+
const limit = options?.limit || 100;
|
|
1897
|
+
const rows = await dbAll(
|
|
1898
|
+
this.db,
|
|
1899
|
+
`SELECT * FROM shared_troubleshooting
|
|
1900
|
+
ORDER BY confidence DESC, usage_count DESC
|
|
1901
|
+
LIMIT ?`,
|
|
1902
|
+
[limit]
|
|
1903
|
+
);
|
|
1904
|
+
return rows.map(this.rowToEntry);
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Get total count
|
|
1908
|
+
*/
|
|
1909
|
+
async count() {
|
|
1910
|
+
const result = await dbAll(
|
|
1911
|
+
this.db,
|
|
1912
|
+
`SELECT COUNT(*) as count FROM shared_troubleshooting`
|
|
1913
|
+
);
|
|
1914
|
+
return result[0]?.count || 0;
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Get statistics
|
|
1918
|
+
*/
|
|
1919
|
+
async getStats() {
|
|
1920
|
+
const countResult = await dbAll(
|
|
1921
|
+
this.db,
|
|
1922
|
+
`SELECT COUNT(*) as count FROM shared_troubleshooting`
|
|
1923
|
+
);
|
|
1924
|
+
const total = countResult[0]?.count || 0;
|
|
1925
|
+
const avgResult = await dbAll(
|
|
1926
|
+
this.db,
|
|
1927
|
+
`SELECT AVG(confidence) as avg FROM shared_troubleshooting`
|
|
1928
|
+
);
|
|
1929
|
+
const averageConfidence = avgResult[0]?.avg || 0;
|
|
1930
|
+
const usageResult = await dbAll(
|
|
1931
|
+
this.db,
|
|
1932
|
+
`SELECT SUM(usage_count) as total FROM shared_troubleshooting`
|
|
1933
|
+
);
|
|
1934
|
+
const totalUsageCount = usageResult[0]?.total || 0;
|
|
1935
|
+
const entries = await this.getAll({ limit: 1e3 });
|
|
1936
|
+
const topicCounts = {};
|
|
1937
|
+
for (const entry of entries) {
|
|
1938
|
+
for (const topic of entry.topics) {
|
|
1939
|
+
topicCounts[topic] = (topicCounts[topic] || 0) + 1;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
const topTopics = Object.entries(topicCounts).map(([topic, count]) => ({ topic, count })).sort((a, b) => b.count - a.count).slice(0, 10);
|
|
1943
|
+
return { total, averageConfidence, topTopics, totalUsageCount };
|
|
1944
|
+
}
|
|
1945
|
+
/**
|
|
1946
|
+
* Delete an entry
|
|
1947
|
+
*/
|
|
1948
|
+
async delete(entryId) {
|
|
1949
|
+
const before = await this.count();
|
|
1950
|
+
await dbRun(
|
|
1951
|
+
this.db,
|
|
1952
|
+
`DELETE FROM shared_troubleshooting WHERE entry_id = ?`,
|
|
1953
|
+
[entryId]
|
|
1954
|
+
);
|
|
1955
|
+
const after = await this.count();
|
|
1956
|
+
return before > after;
|
|
1957
|
+
}
|
|
1958
|
+
rowToEntry(row) {
|
|
1959
|
+
return {
|
|
1960
|
+
entryId: row.entry_id,
|
|
1961
|
+
sourceProjectHash: row.source_project_hash,
|
|
1962
|
+
sourceEntryId: row.source_entry_id,
|
|
1963
|
+
title: row.title,
|
|
1964
|
+
symptoms: JSON.parse(row.symptoms || "[]"),
|
|
1965
|
+
rootCause: row.root_cause,
|
|
1966
|
+
solution: row.solution,
|
|
1967
|
+
topics: JSON.parse(row.topics || "[]"),
|
|
1968
|
+
technologies: JSON.parse(row.technologies || "[]"),
|
|
1969
|
+
confidence: row.confidence,
|
|
1970
|
+
usageCount: row.usage_count || 0,
|
|
1971
|
+
lastUsedAt: row.last_used_at ? toDate(row.last_used_at) : void 0,
|
|
1972
|
+
promotedAt: toDate(row.promoted_at),
|
|
1973
|
+
createdAt: toDate(row.created_at)
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
function createSharedStore(sharedEventStore) {
|
|
1978
|
+
return new SharedStore(sharedEventStore);
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// src/core/shared-vector-store.ts
|
|
1982
|
+
import * as lancedb2 from "@lancedb/lancedb";
|
|
1983
|
+
var SharedVectorStore = class {
|
|
1984
|
+
constructor(dbPath) {
|
|
1985
|
+
this.dbPath = dbPath;
|
|
1986
|
+
}
|
|
1987
|
+
db = null;
|
|
1988
|
+
table = null;
|
|
1989
|
+
tableName = "shared_knowledge";
|
|
1990
|
+
/**
|
|
1991
|
+
* Initialize LanceDB connection
|
|
1992
|
+
*/
|
|
1993
|
+
async initialize() {
|
|
1994
|
+
if (this.db)
|
|
1995
|
+
return;
|
|
1996
|
+
this.db = await lancedb2.connect(this.dbPath);
|
|
1997
|
+
try {
|
|
1998
|
+
const tables = await this.db.tableNames();
|
|
1999
|
+
if (tables.includes(this.tableName)) {
|
|
2000
|
+
this.table = await this.db.openTable(this.tableName);
|
|
2001
|
+
}
|
|
2002
|
+
} catch {
|
|
2003
|
+
this.table = null;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* Add or update a shared vector record
|
|
2008
|
+
*/
|
|
2009
|
+
async upsert(record) {
|
|
2010
|
+
await this.initialize();
|
|
2011
|
+
if (!this.db) {
|
|
2012
|
+
throw new Error("Database not initialized");
|
|
2013
|
+
}
|
|
2014
|
+
const data = {
|
|
2015
|
+
id: record.id,
|
|
2016
|
+
entryId: record.entryId,
|
|
2017
|
+
entryType: record.entryType,
|
|
2018
|
+
content: record.content,
|
|
2019
|
+
vector: record.vector,
|
|
2020
|
+
topics: JSON.stringify(record.topics),
|
|
2021
|
+
sourceProjectHash: record.sourceProjectHash || ""
|
|
2022
|
+
};
|
|
2023
|
+
if (!this.table) {
|
|
2024
|
+
this.table = await this.db.createTable(this.tableName, [data]);
|
|
2025
|
+
} else {
|
|
2026
|
+
try {
|
|
2027
|
+
await this.table.delete(`entryId = '${record.entryId}'`);
|
|
2028
|
+
} catch {
|
|
2029
|
+
}
|
|
2030
|
+
await this.table.add([data]);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
* Add multiple records in batch
|
|
2035
|
+
*/
|
|
2036
|
+
async upsertBatch(records) {
|
|
2037
|
+
if (records.length === 0)
|
|
2038
|
+
return;
|
|
2039
|
+
await this.initialize();
|
|
2040
|
+
if (!this.db) {
|
|
2041
|
+
throw new Error("Database not initialized");
|
|
2042
|
+
}
|
|
2043
|
+
const data = records.map((record) => ({
|
|
2044
|
+
id: record.id,
|
|
2045
|
+
entryId: record.entryId,
|
|
2046
|
+
entryType: record.entryType,
|
|
2047
|
+
content: record.content,
|
|
2048
|
+
vector: record.vector,
|
|
2049
|
+
topics: JSON.stringify(record.topics),
|
|
2050
|
+
sourceProjectHash: record.sourceProjectHash || ""
|
|
2051
|
+
}));
|
|
2052
|
+
if (!this.table) {
|
|
2053
|
+
this.table = await this.db.createTable(this.tableName, data);
|
|
2054
|
+
} else {
|
|
2055
|
+
await this.table.add(data);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Search for similar vectors
|
|
2060
|
+
*/
|
|
2061
|
+
async search(queryVector, options = {}) {
|
|
2062
|
+
await this.initialize();
|
|
2063
|
+
if (!this.table) {
|
|
2064
|
+
return [];
|
|
2065
|
+
}
|
|
2066
|
+
const { limit = 5, minScore = 0.7, excludeProjectHash, entryType } = options;
|
|
2067
|
+
let query = this.table.search(queryVector).distanceType("cosine").limit(limit * 2);
|
|
2068
|
+
const filters = [];
|
|
2069
|
+
if (excludeProjectHash) {
|
|
2070
|
+
filters.push(`sourceProjectHash != '${excludeProjectHash}'`);
|
|
2071
|
+
}
|
|
2072
|
+
if (entryType) {
|
|
2073
|
+
filters.push(`entryType = '${entryType}'`);
|
|
2074
|
+
}
|
|
2075
|
+
if (filters.length > 0) {
|
|
2076
|
+
query = query.where(filters.join(" AND "));
|
|
2077
|
+
}
|
|
2078
|
+
const results = await query.toArray();
|
|
2079
|
+
return results.filter((r) => {
|
|
2080
|
+
const distance = r._distance || 0;
|
|
2081
|
+
const score = 1 - distance / 2;
|
|
2082
|
+
return score >= minScore;
|
|
2083
|
+
}).slice(0, limit).map((r) => {
|
|
2084
|
+
const distance = r._distance || 0;
|
|
2085
|
+
const score = 1 - distance / 2;
|
|
2086
|
+
return {
|
|
2087
|
+
id: r.id,
|
|
2088
|
+
entryId: r.entryId,
|
|
2089
|
+
content: r.content,
|
|
2090
|
+
score,
|
|
2091
|
+
entryType: r.entryType
|
|
2092
|
+
};
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Delete vector by entry ID
|
|
2097
|
+
*/
|
|
2098
|
+
async delete(entryId) {
|
|
2099
|
+
if (!this.table)
|
|
2100
|
+
return;
|
|
2101
|
+
await this.table.delete(`entryId = '${entryId}'`);
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* Get total count
|
|
2105
|
+
*/
|
|
2106
|
+
async count() {
|
|
2107
|
+
if (!this.table)
|
|
2108
|
+
return 0;
|
|
2109
|
+
return this.table.countRows();
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Check if vector exists for entry
|
|
2113
|
+
*/
|
|
2114
|
+
async exists(entryId) {
|
|
2115
|
+
if (!this.table)
|
|
2116
|
+
return false;
|
|
2117
|
+
try {
|
|
2118
|
+
const results = await this.table.search([]).where(`entryId = '${entryId}'`).limit(1).toArray();
|
|
2119
|
+
return results.length > 0;
|
|
2120
|
+
} catch {
|
|
2121
|
+
return false;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
function createSharedVectorStore(dbPath) {
|
|
2126
|
+
return new SharedVectorStore(dbPath);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
// src/core/shared-promoter.ts
|
|
2130
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2131
|
+
var SharedPromoter = class {
|
|
2132
|
+
constructor(sharedStore, sharedVectorStore, embedder, config) {
|
|
2133
|
+
this.sharedStore = sharedStore;
|
|
2134
|
+
this.sharedVectorStore = sharedVectorStore;
|
|
2135
|
+
this.embedder = embedder;
|
|
2136
|
+
this.config = config;
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Check if an entry is eligible for promotion
|
|
2140
|
+
*/
|
|
2141
|
+
isEligibleForPromotion(entry) {
|
|
2142
|
+
if (entry.entryType !== "troubleshooting") {
|
|
2143
|
+
return false;
|
|
2144
|
+
}
|
|
2145
|
+
if (entry.stage !== "verified" && entry.stage !== "certified") {
|
|
2146
|
+
return false;
|
|
2147
|
+
}
|
|
2148
|
+
if (entry.status !== "active") {
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
return true;
|
|
2152
|
+
}
|
|
2153
|
+
/**
|
|
2154
|
+
* Promote a verified troubleshooting entry to shared storage
|
|
2155
|
+
*/
|
|
2156
|
+
async promoteEntry(entry, projectHash) {
|
|
2157
|
+
if (!this.isEligibleForPromotion(entry)) {
|
|
2158
|
+
return {
|
|
2159
|
+
success: false,
|
|
2160
|
+
skipped: true,
|
|
2161
|
+
skipReason: `Entry not eligible: type=${entry.entryType}, stage=${entry.stage}, status=${entry.status}`
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
const exists = await this.sharedStore.exists(projectHash, entry.entryId);
|
|
2165
|
+
if (exists) {
|
|
2166
|
+
return {
|
|
2167
|
+
success: true,
|
|
2168
|
+
skipped: true,
|
|
2169
|
+
skipReason: "Entry already exists in shared store"
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
try {
|
|
2173
|
+
const content = entry.contentJson;
|
|
2174
|
+
const confidence = this.calculateConfidence(entry);
|
|
2175
|
+
const minConfidence = this.config?.minConfidenceForPromotion ?? 0.8;
|
|
2176
|
+
if (confidence < minConfidence) {
|
|
2177
|
+
return {
|
|
2178
|
+
success: false,
|
|
2179
|
+
skipped: true,
|
|
2180
|
+
skipReason: `Confidence ${confidence} below threshold ${minConfidence}`
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
const input = {
|
|
2184
|
+
sourceProjectHash: projectHash,
|
|
2185
|
+
sourceEntryId: entry.entryId,
|
|
2186
|
+
title: entry.title,
|
|
2187
|
+
symptoms: content.symptoms || [],
|
|
2188
|
+
rootCause: content.rootCause || "",
|
|
2189
|
+
solution: content.solution || "",
|
|
2190
|
+
topics: this.extractTopics(entry),
|
|
2191
|
+
technologies: content.technologies || [],
|
|
2192
|
+
confidence
|
|
2193
|
+
};
|
|
2194
|
+
const entryId = await this.sharedStore.promoteEntry(input);
|
|
2195
|
+
const embeddingContent = this.createEmbeddingContent(input);
|
|
2196
|
+
const embedding = await this.embedder.embed(embeddingContent);
|
|
2197
|
+
await this.sharedVectorStore.upsert({
|
|
2198
|
+
id: randomUUID3(),
|
|
2199
|
+
entryId,
|
|
2200
|
+
entryType: "troubleshooting",
|
|
2201
|
+
content: embeddingContent,
|
|
2202
|
+
vector: embedding.vector,
|
|
2203
|
+
topics: input.topics,
|
|
2204
|
+
sourceProjectHash: projectHash
|
|
2205
|
+
});
|
|
2206
|
+
return {
|
|
2207
|
+
success: true,
|
|
2208
|
+
entryId
|
|
2209
|
+
};
|
|
2210
|
+
} catch (error) {
|
|
2211
|
+
return {
|
|
2212
|
+
success: false,
|
|
2213
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
/**
|
|
2218
|
+
* Batch promote multiple entries
|
|
2219
|
+
*/
|
|
2220
|
+
async promoteEntries(entries, projectHash) {
|
|
2221
|
+
const results = /* @__PURE__ */ new Map();
|
|
2222
|
+
for (const entry of entries) {
|
|
2223
|
+
const result = await this.promoteEntry(entry, projectHash);
|
|
2224
|
+
results.set(entry.entryId, result);
|
|
2225
|
+
}
|
|
2226
|
+
return results;
|
|
2227
|
+
}
|
|
2228
|
+
/**
|
|
2229
|
+
* Extract topics from entry
|
|
2230
|
+
*/
|
|
2231
|
+
extractTopics(entry) {
|
|
2232
|
+
const topics = [];
|
|
2233
|
+
const titleWords = entry.title.toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 3 && !this.isStopWord(w));
|
|
2234
|
+
topics.push(...titleWords);
|
|
2235
|
+
const content = entry.contentJson;
|
|
2236
|
+
if (content.topics && Array.isArray(content.topics)) {
|
|
2237
|
+
topics.push(...content.topics.map((t) => String(t).toLowerCase()));
|
|
2238
|
+
}
|
|
2239
|
+
if (content.technologies && Array.isArray(content.technologies)) {
|
|
2240
|
+
topics.push(...content.technologies.map((t) => String(t).toLowerCase()));
|
|
2241
|
+
}
|
|
2242
|
+
return [...new Set(topics)];
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Check if word is a stop word
|
|
2246
|
+
*/
|
|
2247
|
+
isStopWord(word) {
|
|
2248
|
+
const stopWords = /* @__PURE__ */ new Set([
|
|
2249
|
+
"the",
|
|
2250
|
+
"and",
|
|
2251
|
+
"for",
|
|
2252
|
+
"with",
|
|
2253
|
+
"this",
|
|
2254
|
+
"that",
|
|
2255
|
+
"from",
|
|
2256
|
+
"have",
|
|
2257
|
+
"been",
|
|
2258
|
+
"were",
|
|
2259
|
+
"are",
|
|
2260
|
+
"was",
|
|
2261
|
+
"had",
|
|
2262
|
+
"has",
|
|
2263
|
+
"will",
|
|
2264
|
+
"would",
|
|
2265
|
+
"could",
|
|
2266
|
+
"should",
|
|
2267
|
+
"when",
|
|
2268
|
+
"where",
|
|
2269
|
+
"what",
|
|
2270
|
+
"which",
|
|
2271
|
+
"while",
|
|
2272
|
+
"error",
|
|
2273
|
+
"problem",
|
|
2274
|
+
"issue"
|
|
2275
|
+
]);
|
|
2276
|
+
return stopWords.has(word);
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Calculate confidence score for entry
|
|
2280
|
+
*/
|
|
2281
|
+
calculateConfidence(entry) {
|
|
2282
|
+
let confidence = 0.8;
|
|
2283
|
+
if (entry.stage === "certified") {
|
|
2284
|
+
confidence = 0.95;
|
|
2285
|
+
}
|
|
2286
|
+
return Math.min(confidence, 1);
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Create embedding content from input
|
|
2290
|
+
*/
|
|
2291
|
+
createEmbeddingContent(input) {
|
|
2292
|
+
const parts = [];
|
|
2293
|
+
parts.push(`Problem: ${input.title}`);
|
|
2294
|
+
if (input.symptoms.length > 0) {
|
|
2295
|
+
parts.push(`Symptoms: ${input.symptoms.join(", ")}`);
|
|
2296
|
+
}
|
|
2297
|
+
if (input.rootCause) {
|
|
2298
|
+
parts.push(`Root Cause: ${input.rootCause}`);
|
|
2299
|
+
}
|
|
2300
|
+
if (input.solution) {
|
|
2301
|
+
parts.push(`Solution: ${input.solution}`);
|
|
2302
|
+
}
|
|
2303
|
+
if (input.technologies && input.technologies.length > 0) {
|
|
2304
|
+
parts.push(`Technologies: ${input.technologies.join(", ")}`);
|
|
2305
|
+
}
|
|
2306
|
+
return parts.join("\n");
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
function createSharedPromoter(sharedStore, sharedVectorStore, embedder, config) {
|
|
2310
|
+
return new SharedPromoter(sharedStore, sharedVectorStore, embedder, config);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
1581
2313
|
// src/core/metadata-extractor.ts
|
|
1582
2314
|
function createToolObservationEmbedding(toolName, metadata, success) {
|
|
1583
2315
|
const parts = [];
|
|
@@ -1603,7 +2335,7 @@ function createToolObservationEmbedding(toolName, metadata, success) {
|
|
|
1603
2335
|
}
|
|
1604
2336
|
|
|
1605
2337
|
// src/core/working-set-store.ts
|
|
1606
|
-
import { randomUUID as
|
|
2338
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
1607
2339
|
var WorkingSetStore = class {
|
|
1608
2340
|
constructor(eventStore, config) {
|
|
1609
2341
|
this.eventStore = eventStore;
|
|
@@ -1624,7 +2356,7 @@ var WorkingSetStore = class {
|
|
|
1624
2356
|
`INSERT OR REPLACE INTO working_set (id, event_id, added_at, relevance_score, topics, expires_at)
|
|
1625
2357
|
VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)`,
|
|
1626
2358
|
[
|
|
1627
|
-
|
|
2359
|
+
randomUUID4(),
|
|
1628
2360
|
eventId,
|
|
1629
2361
|
relevanceScore,
|
|
1630
2362
|
JSON.stringify(topics || []),
|
|
@@ -1808,7 +2540,7 @@ function createWorkingSetStore(eventStore, config) {
|
|
|
1808
2540
|
}
|
|
1809
2541
|
|
|
1810
2542
|
// src/core/consolidated-store.ts
|
|
1811
|
-
import { randomUUID as
|
|
2543
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
1812
2544
|
var ConsolidatedStore = class {
|
|
1813
2545
|
constructor(eventStore) {
|
|
1814
2546
|
this.eventStore = eventStore;
|
|
@@ -1820,7 +2552,7 @@ var ConsolidatedStore = class {
|
|
|
1820
2552
|
* Create a new consolidated memory
|
|
1821
2553
|
*/
|
|
1822
2554
|
async create(input) {
|
|
1823
|
-
const memoryId =
|
|
2555
|
+
const memoryId = randomUUID5();
|
|
1824
2556
|
await dbRun(
|
|
1825
2557
|
this.db,
|
|
1826
2558
|
`INSERT INTO consolidated_memories
|
|
@@ -2347,7 +3079,7 @@ function createConsolidationWorker(workingSetStore, consolidatedStore, config) {
|
|
|
2347
3079
|
}
|
|
2348
3080
|
|
|
2349
3081
|
// src/core/continuity-manager.ts
|
|
2350
|
-
import { randomUUID as
|
|
3082
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
2351
3083
|
var ContinuityManager = class {
|
|
2352
3084
|
constructor(eventStore, config) {
|
|
2353
3085
|
this.eventStore = eventStore;
|
|
@@ -2501,7 +3233,7 @@ var ContinuityManager = class {
|
|
|
2501
3233
|
`INSERT INTO continuity_log
|
|
2502
3234
|
(log_id, from_context_id, to_context_id, continuity_score, transition_type, created_at)
|
|
2503
3235
|
VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
|
|
2504
|
-
[
|
|
3236
|
+
[randomUUID6(), previous.id, current.id, score, type]
|
|
2505
3237
|
);
|
|
2506
3238
|
}
|
|
2507
3239
|
/**
|
|
@@ -2627,6 +3359,7 @@ function getProjectStoragePath(projectPath) {
|
|
|
2627
3359
|
return path.join(os.homedir(), ".claude-code", "memory", "projects", hash);
|
|
2628
3360
|
}
|
|
2629
3361
|
var REGISTRY_PATH = path.join(os.homedir(), ".claude-code", "memory", "session-registry.json");
|
|
3362
|
+
var SHARED_STORAGE_PATH = path.join(os.homedir(), ".claude-code", "memory", "shared");
|
|
2630
3363
|
var MemoryService = class {
|
|
2631
3364
|
eventStore;
|
|
2632
3365
|
vectorStore;
|
|
@@ -2642,11 +3375,20 @@ var MemoryService = class {
|
|
|
2642
3375
|
consolidationWorker = null;
|
|
2643
3376
|
continuityManager = null;
|
|
2644
3377
|
endlessMode = "session";
|
|
3378
|
+
// Shared Store components (cross-project knowledge)
|
|
3379
|
+
sharedEventStore = null;
|
|
3380
|
+
sharedStore = null;
|
|
3381
|
+
sharedVectorStore = null;
|
|
3382
|
+
sharedPromoter = null;
|
|
3383
|
+
sharedStoreConfig = null;
|
|
3384
|
+
projectHash = null;
|
|
2645
3385
|
constructor(config) {
|
|
2646
3386
|
const storagePath = this.expandPath(config.storagePath);
|
|
2647
3387
|
if (!fs.existsSync(storagePath)) {
|
|
2648
3388
|
fs.mkdirSync(storagePath, { recursive: true });
|
|
2649
3389
|
}
|
|
3390
|
+
this.projectHash = config.projectHash || null;
|
|
3391
|
+
this.sharedStoreConfig = config.sharedStoreConfig ?? { enabled: true };
|
|
2650
3392
|
this.eventStore = new EventStore(path.join(storagePath, "events.duckdb"));
|
|
2651
3393
|
this.vectorStore = new VectorStore(path.join(storagePath, "vectors"));
|
|
2652
3394
|
this.embedder = config.embeddingModel ? new Embedder(config.embeddingModel) : getDefaultEmbedder();
|
|
@@ -2679,8 +3421,36 @@ var MemoryService = class {
|
|
|
2679
3421
|
this.endlessMode = "endless";
|
|
2680
3422
|
await this.initializeEndlessMode();
|
|
2681
3423
|
}
|
|
3424
|
+
if (this.sharedStoreConfig?.enabled !== false) {
|
|
3425
|
+
await this.initializeSharedStore();
|
|
3426
|
+
}
|
|
2682
3427
|
this.initialized = true;
|
|
2683
3428
|
}
|
|
3429
|
+
/**
|
|
3430
|
+
* Initialize Shared Store components
|
|
3431
|
+
*/
|
|
3432
|
+
async initializeSharedStore() {
|
|
3433
|
+
const sharedPath = this.sharedStoreConfig?.sharedStoragePath ? this.expandPath(this.sharedStoreConfig.sharedStoragePath) : SHARED_STORAGE_PATH;
|
|
3434
|
+
if (!fs.existsSync(sharedPath)) {
|
|
3435
|
+
fs.mkdirSync(sharedPath, { recursive: true });
|
|
3436
|
+
}
|
|
3437
|
+
this.sharedEventStore = createSharedEventStore(
|
|
3438
|
+
path.join(sharedPath, "shared.duckdb")
|
|
3439
|
+
);
|
|
3440
|
+
await this.sharedEventStore.initialize();
|
|
3441
|
+
this.sharedStore = createSharedStore(this.sharedEventStore);
|
|
3442
|
+
this.sharedVectorStore = createSharedVectorStore(
|
|
3443
|
+
path.join(sharedPath, "vectors")
|
|
3444
|
+
);
|
|
3445
|
+
await this.sharedVectorStore.initialize();
|
|
3446
|
+
this.sharedPromoter = createSharedPromoter(
|
|
3447
|
+
this.sharedStore,
|
|
3448
|
+
this.sharedVectorStore,
|
|
3449
|
+
this.embedder,
|
|
3450
|
+
this.sharedStoreConfig || void 0
|
|
3451
|
+
);
|
|
3452
|
+
this.retriever.setSharedStores(this.sharedStore, this.sharedVectorStore);
|
|
3453
|
+
}
|
|
2684
3454
|
/**
|
|
2685
3455
|
* Start a new session
|
|
2686
3456
|
*/
|
|
@@ -2787,6 +3557,13 @@ var MemoryService = class {
|
|
|
2787
3557
|
if (this.vectorWorker) {
|
|
2788
3558
|
await this.vectorWorker.processAll();
|
|
2789
3559
|
}
|
|
3560
|
+
if (options?.includeShared && this.sharedStore) {
|
|
3561
|
+
return this.retriever.retrieveUnified(query, {
|
|
3562
|
+
...options,
|
|
3563
|
+
includeShared: true,
|
|
3564
|
+
projectHash: this.projectHash || void 0
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
2790
3567
|
return this.retriever.retrieve(query, options);
|
|
2791
3568
|
}
|
|
2792
3569
|
/**
|
|
@@ -2843,6 +3620,49 @@ var MemoryService = class {
|
|
|
2843
3620
|
return header + result.context;
|
|
2844
3621
|
}
|
|
2845
3622
|
// ============================================================
|
|
3623
|
+
// Shared Store Methods (Cross-Project Knowledge)
|
|
3624
|
+
// ============================================================
|
|
3625
|
+
/**
|
|
3626
|
+
* Check if shared store is enabled and initialized
|
|
3627
|
+
*/
|
|
3628
|
+
isSharedStoreEnabled() {
|
|
3629
|
+
return this.sharedStore !== null;
|
|
3630
|
+
}
|
|
3631
|
+
/**
|
|
3632
|
+
* Promote an entry to shared storage
|
|
3633
|
+
*/
|
|
3634
|
+
async promoteToShared(entry) {
|
|
3635
|
+
if (!this.sharedPromoter || !this.projectHash) {
|
|
3636
|
+
return {
|
|
3637
|
+
success: false,
|
|
3638
|
+
error: "Shared store not initialized or project hash not set"
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
return this.sharedPromoter.promoteEntry(entry, this.projectHash);
|
|
3642
|
+
}
|
|
3643
|
+
/**
|
|
3644
|
+
* Get shared store statistics
|
|
3645
|
+
*/
|
|
3646
|
+
async getSharedStoreStats() {
|
|
3647
|
+
if (!this.sharedStore)
|
|
3648
|
+
return null;
|
|
3649
|
+
return this.sharedStore.getStats();
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Search shared troubleshooting entries
|
|
3653
|
+
*/
|
|
3654
|
+
async searchShared(query, options) {
|
|
3655
|
+
if (!this.sharedStore)
|
|
3656
|
+
return [];
|
|
3657
|
+
return this.sharedStore.search(query, options);
|
|
3658
|
+
}
|
|
3659
|
+
/**
|
|
3660
|
+
* Get project hash for this service
|
|
3661
|
+
*/
|
|
3662
|
+
getProjectHash() {
|
|
3663
|
+
return this.projectHash;
|
|
3664
|
+
}
|
|
3665
|
+
// ============================================================
|
|
2846
3666
|
// Endless Mode Methods
|
|
2847
3667
|
// ============================================================
|
|
2848
3668
|
/**
|
|
@@ -3062,6 +3882,9 @@ var MemoryService = class {
|
|
|
3062
3882
|
if (this.vectorWorker) {
|
|
3063
3883
|
this.vectorWorker.stop();
|
|
3064
3884
|
}
|
|
3885
|
+
if (this.sharedEventStore) {
|
|
3886
|
+
await this.sharedEventStore.close();
|
|
3887
|
+
}
|
|
3065
3888
|
await this.eventStore.close();
|
|
3066
3889
|
}
|
|
3067
3890
|
/**
|
|
@@ -3084,11 +3907,15 @@ function getDefaultMemoryService() {
|
|
|
3084
3907
|
}
|
|
3085
3908
|
return serviceCache.get(GLOBAL_KEY);
|
|
3086
3909
|
}
|
|
3087
|
-
function getMemoryServiceForProject(projectPath) {
|
|
3910
|
+
function getMemoryServiceForProject(projectPath, sharedStoreConfig) {
|
|
3088
3911
|
const hash = hashProjectPath(projectPath);
|
|
3089
3912
|
if (!serviceCache.has(hash)) {
|
|
3090
3913
|
const storagePath = getProjectStoragePath(projectPath);
|
|
3091
|
-
serviceCache.set(hash, new MemoryService({
|
|
3914
|
+
serviceCache.set(hash, new MemoryService({
|
|
3915
|
+
storagePath,
|
|
3916
|
+
projectHash: hash,
|
|
3917
|
+
sharedStoreConfig
|
|
3918
|
+
}));
|
|
3092
3919
|
}
|
|
3093
3920
|
return serviceCache.get(hash);
|
|
3094
3921
|
}
|