claude-memory-layer 1.0.2 → 1.0.3

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/dist/cli/index.js CHANGED
@@ -1192,11 +1192,22 @@ var Retriever = class {
1192
1192
  vectorStore;
1193
1193
  embedder;
1194
1194
  matcher;
1195
- constructor(eventStore, vectorStore, embedder, matcher) {
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 randomUUID2 } from "crypto";
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
- randomUUID2(),
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 randomUUID3 } from "crypto";
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 = randomUUID3();
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 randomUUID4 } from "crypto";
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
- [randomUUID4(), previous.id, current.id, score, type]
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({ storagePath }));
3914
+ serviceCache.set(hash, new MemoryService({
3915
+ storagePath,
3916
+ projectHash: hash,
3917
+ sharedStoreConfig
3918
+ }));
3092
3919
  }
3093
3920
  return serviceCache.get(hash);
3094
3921
  }