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.
@@ -1188,11 +1188,22 @@ var Retriever = class {
1188
1188
  vectorStore;
1189
1189
  embedder;
1190
1190
  matcher;
1191
- constructor(eventStore, vectorStore, embedder, matcher) {
1191
+ sharedStore;
1192
+ sharedVectorStore;
1193
+ constructor(eventStore, vectorStore, embedder, matcher, sharedOptions) {
1192
1194
  this.eventStore = eventStore;
1193
1195
  this.vectorStore = vectorStore;
1194
1196
  this.embedder = embedder;
1195
1197
  this.matcher = matcher;
1198
+ this.sharedStore = sharedOptions?.sharedStore;
1199
+ this.sharedVectorStore = sharedOptions?.sharedVectorStore;
1200
+ }
1201
+ /**
1202
+ * Set shared stores after construction
1203
+ */
1204
+ setSharedStores(sharedStore, sharedVectorStore) {
1205
+ this.sharedStore = sharedStore;
1206
+ this.sharedVectorStore = sharedVectorStore;
1196
1207
  }
1197
1208
  /**
1198
1209
  * Retrieve relevant memories for a query
@@ -1219,6 +1230,75 @@ var Retriever = class {
1219
1230
  context
1220
1231
  };
1221
1232
  }
1233
+ /**
1234
+ * Retrieve with unified search (project + shared)
1235
+ */
1236
+ async retrieveUnified(query, options = {}) {
1237
+ const projectResult = await this.retrieve(query, options);
1238
+ if (!options.includeShared || !this.sharedStore || !this.sharedVectorStore) {
1239
+ return projectResult;
1240
+ }
1241
+ try {
1242
+ const queryEmbedding = await this.embedder.embed(query);
1243
+ const sharedVectorResults = await this.sharedVectorStore.search(
1244
+ queryEmbedding.vector,
1245
+ {
1246
+ limit: options.topK || 5,
1247
+ minScore: options.minScore || 0.7,
1248
+ excludeProjectHash: options.projectHash
1249
+ }
1250
+ );
1251
+ const sharedMemories = [];
1252
+ for (const result of sharedVectorResults) {
1253
+ const entry = await this.sharedStore.get(result.entryId);
1254
+ if (entry) {
1255
+ if (!options.projectHash || entry.sourceProjectHash !== options.projectHash) {
1256
+ sharedMemories.push(entry);
1257
+ await this.sharedStore.recordUsage(entry.entryId);
1258
+ }
1259
+ }
1260
+ }
1261
+ const unifiedContext = this.buildUnifiedContext(projectResult, sharedMemories);
1262
+ return {
1263
+ ...projectResult,
1264
+ context: unifiedContext,
1265
+ totalTokens: this.estimateTokens(unifiedContext),
1266
+ sharedMemories
1267
+ };
1268
+ } catch (error) {
1269
+ console.error("Shared search failed:", error);
1270
+ return projectResult;
1271
+ }
1272
+ }
1273
+ /**
1274
+ * Build unified context combining project and shared memories
1275
+ */
1276
+ buildUnifiedContext(projectResult, sharedMemories) {
1277
+ let context = projectResult.context;
1278
+ if (sharedMemories.length > 0) {
1279
+ context += "\n\n## Cross-Project Knowledge\n\n";
1280
+ for (const memory of sharedMemories.slice(0, 3)) {
1281
+ context += `### ${memory.title}
1282
+ `;
1283
+ if (memory.symptoms.length > 0) {
1284
+ context += `**Symptoms:** ${memory.symptoms.join(", ")}
1285
+ `;
1286
+ }
1287
+ context += `**Root Cause:** ${memory.rootCause}
1288
+ `;
1289
+ context += `**Solution:** ${memory.solution}
1290
+ `;
1291
+ if (memory.technologies && memory.technologies.length > 0) {
1292
+ context += `**Technologies:** ${memory.technologies.join(", ")}
1293
+ `;
1294
+ }
1295
+ context += `_Confidence: ${(memory.confidence * 100).toFixed(0)}%_
1296
+
1297
+ `;
1298
+ }
1299
+ }
1300
+ return context;
1301
+ }
1222
1302
  /**
1223
1303
  * Retrieve memories from a specific session
1224
1304
  */
@@ -1574,6 +1654,658 @@ function createGraduationPipeline(eventStore) {
1574
1654
  return new GraduationPipeline(eventStore);
1575
1655
  }
1576
1656
 
1657
+ // src/core/shared-event-store.ts
1658
+ var SharedEventStore = class {
1659
+ constructor(dbPath) {
1660
+ this.dbPath = dbPath;
1661
+ this.db = createDatabase(dbPath);
1662
+ }
1663
+ db;
1664
+ initialized = false;
1665
+ async initialize() {
1666
+ if (this.initialized)
1667
+ return;
1668
+ await dbRun(this.db, `
1669
+ CREATE TABLE IF NOT EXISTS shared_troubleshooting (
1670
+ entry_id VARCHAR PRIMARY KEY,
1671
+ source_project_hash VARCHAR NOT NULL,
1672
+ source_entry_id VARCHAR NOT NULL,
1673
+ title VARCHAR NOT NULL,
1674
+ symptoms JSON NOT NULL,
1675
+ root_cause TEXT NOT NULL,
1676
+ solution TEXT NOT NULL,
1677
+ topics JSON NOT NULL,
1678
+ technologies JSON,
1679
+ confidence REAL NOT NULL DEFAULT 0.8,
1680
+ usage_count INTEGER DEFAULT 0,
1681
+ last_used_at TIMESTAMP,
1682
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1683
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1684
+ UNIQUE(source_project_hash, source_entry_id)
1685
+ )
1686
+ `);
1687
+ await dbRun(this.db, `
1688
+ CREATE TABLE IF NOT EXISTS shared_best_practices (
1689
+ entry_id VARCHAR PRIMARY KEY,
1690
+ source_project_hash VARCHAR NOT NULL,
1691
+ source_entry_id VARCHAR NOT NULL,
1692
+ title VARCHAR NOT NULL,
1693
+ content_json JSON NOT NULL,
1694
+ topics JSON NOT NULL,
1695
+ confidence REAL NOT NULL DEFAULT 0.8,
1696
+ usage_count INTEGER DEFAULT 0,
1697
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1698
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1699
+ UNIQUE(source_project_hash, source_entry_id)
1700
+ )
1701
+ `);
1702
+ await dbRun(this.db, `
1703
+ CREATE TABLE IF NOT EXISTS shared_common_errors (
1704
+ entry_id VARCHAR PRIMARY KEY,
1705
+ source_project_hash VARCHAR NOT NULL,
1706
+ source_entry_id VARCHAR NOT NULL,
1707
+ title VARCHAR NOT NULL,
1708
+ error_pattern TEXT NOT NULL,
1709
+ solution TEXT NOT NULL,
1710
+ topics JSON NOT NULL,
1711
+ technologies JSON,
1712
+ confidence REAL NOT NULL DEFAULT 0.8,
1713
+ usage_count INTEGER DEFAULT 0,
1714
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1715
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1716
+ UNIQUE(source_project_hash, source_entry_id)
1717
+ )
1718
+ `);
1719
+ await dbRun(this.db, `
1720
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_confidence
1721
+ ON shared_troubleshooting(confidence DESC)
1722
+ `);
1723
+ await dbRun(this.db, `
1724
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_usage
1725
+ ON shared_troubleshooting(usage_count DESC)
1726
+ `);
1727
+ await dbRun(this.db, `
1728
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_source
1729
+ ON shared_troubleshooting(source_project_hash)
1730
+ `);
1731
+ this.initialized = true;
1732
+ }
1733
+ getDatabase() {
1734
+ return this.db;
1735
+ }
1736
+ isInitialized() {
1737
+ return this.initialized;
1738
+ }
1739
+ async close() {
1740
+ await dbClose(this.db);
1741
+ this.initialized = false;
1742
+ }
1743
+ };
1744
+ function createSharedEventStore(dbPath) {
1745
+ return new SharedEventStore(dbPath);
1746
+ }
1747
+
1748
+ // src/core/shared-store.ts
1749
+ import { randomUUID as randomUUID2 } from "crypto";
1750
+ var SharedStore = class {
1751
+ constructor(sharedEventStore) {
1752
+ this.sharedEventStore = sharedEventStore;
1753
+ }
1754
+ get db() {
1755
+ return this.sharedEventStore.getDatabase();
1756
+ }
1757
+ /**
1758
+ * Promote a verified troubleshooting entry to shared storage
1759
+ */
1760
+ async promoteEntry(input) {
1761
+ const entryId = randomUUID2();
1762
+ await dbRun(
1763
+ this.db,
1764
+ `INSERT INTO shared_troubleshooting (
1765
+ entry_id, source_project_hash, source_entry_id,
1766
+ title, symptoms, root_cause, solution, topics,
1767
+ technologies, confidence, promoted_at
1768
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
1769
+ ON CONFLICT (source_project_hash, source_entry_id)
1770
+ DO UPDATE SET
1771
+ title = excluded.title,
1772
+ symptoms = excluded.symptoms,
1773
+ root_cause = excluded.root_cause,
1774
+ solution = excluded.solution,
1775
+ topics = excluded.topics,
1776
+ technologies = excluded.technologies,
1777
+ confidence = CASE
1778
+ WHEN excluded.confidence > shared_troubleshooting.confidence
1779
+ THEN excluded.confidence
1780
+ ELSE shared_troubleshooting.confidence
1781
+ END`,
1782
+ [
1783
+ entryId,
1784
+ input.sourceProjectHash,
1785
+ input.sourceEntryId,
1786
+ input.title,
1787
+ JSON.stringify(input.symptoms),
1788
+ input.rootCause,
1789
+ input.solution,
1790
+ JSON.stringify(input.topics),
1791
+ JSON.stringify(input.technologies || []),
1792
+ input.confidence
1793
+ ]
1794
+ );
1795
+ return entryId;
1796
+ }
1797
+ /**
1798
+ * Search troubleshooting entries by text query
1799
+ */
1800
+ async search(query, options) {
1801
+ const topK = options?.topK || 5;
1802
+ const minConfidence = options?.minConfidence || 0.5;
1803
+ const searchPattern = `%${query}%`;
1804
+ const rows = await dbAll(
1805
+ this.db,
1806
+ `SELECT * FROM shared_troubleshooting
1807
+ WHERE (title LIKE ? OR root_cause LIKE ? OR solution LIKE ?)
1808
+ AND confidence >= ?
1809
+ ORDER BY confidence DESC, usage_count DESC
1810
+ LIMIT ?`,
1811
+ [searchPattern, searchPattern, searchPattern, minConfidence, topK]
1812
+ );
1813
+ return rows.map(this.rowToEntry);
1814
+ }
1815
+ /**
1816
+ * Search by topics
1817
+ */
1818
+ async searchByTopics(topics, options) {
1819
+ const topK = options?.topK || 5;
1820
+ if (topics.length === 0) {
1821
+ return [];
1822
+ }
1823
+ const topicConditions = topics.map(() => `topics LIKE ?`).join(" OR ");
1824
+ const topicParams = topics.map((t) => `%"${t}"%`);
1825
+ let query = `SELECT * FROM shared_troubleshooting WHERE (${topicConditions})`;
1826
+ const params = [...topicParams];
1827
+ if (options?.excludeProjectHash) {
1828
+ query += ` AND source_project_hash != ?`;
1829
+ params.push(options.excludeProjectHash);
1830
+ }
1831
+ query += ` ORDER BY confidence DESC, usage_count DESC LIMIT ?`;
1832
+ params.push(topK);
1833
+ const rows = await dbAll(this.db, query, params);
1834
+ return rows.map(this.rowToEntry);
1835
+ }
1836
+ /**
1837
+ * Record usage of a shared entry (for ranking)
1838
+ */
1839
+ async recordUsage(entryId) {
1840
+ await dbRun(
1841
+ this.db,
1842
+ `UPDATE shared_troubleshooting
1843
+ SET usage_count = usage_count + 1,
1844
+ last_used_at = CURRENT_TIMESTAMP
1845
+ WHERE entry_id = ?`,
1846
+ [entryId]
1847
+ );
1848
+ }
1849
+ /**
1850
+ * Get entry by ID
1851
+ */
1852
+ async get(entryId) {
1853
+ const rows = await dbAll(
1854
+ this.db,
1855
+ `SELECT * FROM shared_troubleshooting WHERE entry_id = ?`,
1856
+ [entryId]
1857
+ );
1858
+ if (rows.length === 0)
1859
+ return null;
1860
+ return this.rowToEntry(rows[0]);
1861
+ }
1862
+ /**
1863
+ * Get entry by source (project hash + entry ID)
1864
+ */
1865
+ async getBySource(projectHash, sourceEntryId) {
1866
+ const rows = await dbAll(
1867
+ this.db,
1868
+ `SELECT * FROM shared_troubleshooting
1869
+ WHERE source_project_hash = ? AND source_entry_id = ?`,
1870
+ [projectHash, sourceEntryId]
1871
+ );
1872
+ if (rows.length === 0)
1873
+ return null;
1874
+ return this.rowToEntry(rows[0]);
1875
+ }
1876
+ /**
1877
+ * Check if an entry already exists in shared store
1878
+ */
1879
+ async exists(projectHash, sourceEntryId) {
1880
+ const result = await dbAll(
1881
+ this.db,
1882
+ `SELECT COUNT(*) as count FROM shared_troubleshooting
1883
+ WHERE source_project_hash = ? AND source_entry_id = ?`,
1884
+ [projectHash, sourceEntryId]
1885
+ );
1886
+ return (result[0]?.count || 0) > 0;
1887
+ }
1888
+ /**
1889
+ * Get all entries (with limit for safety)
1890
+ */
1891
+ async getAll(options) {
1892
+ const limit = options?.limit || 100;
1893
+ const rows = await dbAll(
1894
+ this.db,
1895
+ `SELECT * FROM shared_troubleshooting
1896
+ ORDER BY confidence DESC, usage_count DESC
1897
+ LIMIT ?`,
1898
+ [limit]
1899
+ );
1900
+ return rows.map(this.rowToEntry);
1901
+ }
1902
+ /**
1903
+ * Get total count
1904
+ */
1905
+ async count() {
1906
+ const result = await dbAll(
1907
+ this.db,
1908
+ `SELECT COUNT(*) as count FROM shared_troubleshooting`
1909
+ );
1910
+ return result[0]?.count || 0;
1911
+ }
1912
+ /**
1913
+ * Get statistics
1914
+ */
1915
+ async getStats() {
1916
+ const countResult = await dbAll(
1917
+ this.db,
1918
+ `SELECT COUNT(*) as count FROM shared_troubleshooting`
1919
+ );
1920
+ const total = countResult[0]?.count || 0;
1921
+ const avgResult = await dbAll(
1922
+ this.db,
1923
+ `SELECT AVG(confidence) as avg FROM shared_troubleshooting`
1924
+ );
1925
+ const averageConfidence = avgResult[0]?.avg || 0;
1926
+ const usageResult = await dbAll(
1927
+ this.db,
1928
+ `SELECT SUM(usage_count) as total FROM shared_troubleshooting`
1929
+ );
1930
+ const totalUsageCount = usageResult[0]?.total || 0;
1931
+ const entries = await this.getAll({ limit: 1e3 });
1932
+ const topicCounts = {};
1933
+ for (const entry of entries) {
1934
+ for (const topic of entry.topics) {
1935
+ topicCounts[topic] = (topicCounts[topic] || 0) + 1;
1936
+ }
1937
+ }
1938
+ const topTopics = Object.entries(topicCounts).map(([topic, count]) => ({ topic, count })).sort((a, b) => b.count - a.count).slice(0, 10);
1939
+ return { total, averageConfidence, topTopics, totalUsageCount };
1940
+ }
1941
+ /**
1942
+ * Delete an entry
1943
+ */
1944
+ async delete(entryId) {
1945
+ const before = await this.count();
1946
+ await dbRun(
1947
+ this.db,
1948
+ `DELETE FROM shared_troubleshooting WHERE entry_id = ?`,
1949
+ [entryId]
1950
+ );
1951
+ const after = await this.count();
1952
+ return before > after;
1953
+ }
1954
+ rowToEntry(row) {
1955
+ return {
1956
+ entryId: row.entry_id,
1957
+ sourceProjectHash: row.source_project_hash,
1958
+ sourceEntryId: row.source_entry_id,
1959
+ title: row.title,
1960
+ symptoms: JSON.parse(row.symptoms || "[]"),
1961
+ rootCause: row.root_cause,
1962
+ solution: row.solution,
1963
+ topics: JSON.parse(row.topics || "[]"),
1964
+ technologies: JSON.parse(row.technologies || "[]"),
1965
+ confidence: row.confidence,
1966
+ usageCount: row.usage_count || 0,
1967
+ lastUsedAt: row.last_used_at ? toDate(row.last_used_at) : void 0,
1968
+ promotedAt: toDate(row.promoted_at),
1969
+ createdAt: toDate(row.created_at)
1970
+ };
1971
+ }
1972
+ };
1973
+ function createSharedStore(sharedEventStore) {
1974
+ return new SharedStore(sharedEventStore);
1975
+ }
1976
+
1977
+ // src/core/shared-vector-store.ts
1978
+ import * as lancedb2 from "@lancedb/lancedb";
1979
+ var SharedVectorStore = class {
1980
+ constructor(dbPath) {
1981
+ this.dbPath = dbPath;
1982
+ }
1983
+ db = null;
1984
+ table = null;
1985
+ tableName = "shared_knowledge";
1986
+ /**
1987
+ * Initialize LanceDB connection
1988
+ */
1989
+ async initialize() {
1990
+ if (this.db)
1991
+ return;
1992
+ this.db = await lancedb2.connect(this.dbPath);
1993
+ try {
1994
+ const tables = await this.db.tableNames();
1995
+ if (tables.includes(this.tableName)) {
1996
+ this.table = await this.db.openTable(this.tableName);
1997
+ }
1998
+ } catch {
1999
+ this.table = null;
2000
+ }
2001
+ }
2002
+ /**
2003
+ * Add or update a shared vector record
2004
+ */
2005
+ async upsert(record) {
2006
+ await this.initialize();
2007
+ if (!this.db) {
2008
+ throw new Error("Database not initialized");
2009
+ }
2010
+ const data = {
2011
+ id: record.id,
2012
+ entryId: record.entryId,
2013
+ entryType: record.entryType,
2014
+ content: record.content,
2015
+ vector: record.vector,
2016
+ topics: JSON.stringify(record.topics),
2017
+ sourceProjectHash: record.sourceProjectHash || ""
2018
+ };
2019
+ if (!this.table) {
2020
+ this.table = await this.db.createTable(this.tableName, [data]);
2021
+ } else {
2022
+ try {
2023
+ await this.table.delete(`entryId = '${record.entryId}'`);
2024
+ } catch {
2025
+ }
2026
+ await this.table.add([data]);
2027
+ }
2028
+ }
2029
+ /**
2030
+ * Add multiple records in batch
2031
+ */
2032
+ async upsertBatch(records) {
2033
+ if (records.length === 0)
2034
+ return;
2035
+ await this.initialize();
2036
+ if (!this.db) {
2037
+ throw new Error("Database not initialized");
2038
+ }
2039
+ const data = records.map((record) => ({
2040
+ id: record.id,
2041
+ entryId: record.entryId,
2042
+ entryType: record.entryType,
2043
+ content: record.content,
2044
+ vector: record.vector,
2045
+ topics: JSON.stringify(record.topics),
2046
+ sourceProjectHash: record.sourceProjectHash || ""
2047
+ }));
2048
+ if (!this.table) {
2049
+ this.table = await this.db.createTable(this.tableName, data);
2050
+ } else {
2051
+ await this.table.add(data);
2052
+ }
2053
+ }
2054
+ /**
2055
+ * Search for similar vectors
2056
+ */
2057
+ async search(queryVector, options = {}) {
2058
+ await this.initialize();
2059
+ if (!this.table) {
2060
+ return [];
2061
+ }
2062
+ const { limit = 5, minScore = 0.7, excludeProjectHash, entryType } = options;
2063
+ let query = this.table.search(queryVector).distanceType("cosine").limit(limit * 2);
2064
+ const filters = [];
2065
+ if (excludeProjectHash) {
2066
+ filters.push(`sourceProjectHash != '${excludeProjectHash}'`);
2067
+ }
2068
+ if (entryType) {
2069
+ filters.push(`entryType = '${entryType}'`);
2070
+ }
2071
+ if (filters.length > 0) {
2072
+ query = query.where(filters.join(" AND "));
2073
+ }
2074
+ const results = await query.toArray();
2075
+ return results.filter((r) => {
2076
+ const distance = r._distance || 0;
2077
+ const score = 1 - distance / 2;
2078
+ return score >= minScore;
2079
+ }).slice(0, limit).map((r) => {
2080
+ const distance = r._distance || 0;
2081
+ const score = 1 - distance / 2;
2082
+ return {
2083
+ id: r.id,
2084
+ entryId: r.entryId,
2085
+ content: r.content,
2086
+ score,
2087
+ entryType: r.entryType
2088
+ };
2089
+ });
2090
+ }
2091
+ /**
2092
+ * Delete vector by entry ID
2093
+ */
2094
+ async delete(entryId) {
2095
+ if (!this.table)
2096
+ return;
2097
+ await this.table.delete(`entryId = '${entryId}'`);
2098
+ }
2099
+ /**
2100
+ * Get total count
2101
+ */
2102
+ async count() {
2103
+ if (!this.table)
2104
+ return 0;
2105
+ return this.table.countRows();
2106
+ }
2107
+ /**
2108
+ * Check if vector exists for entry
2109
+ */
2110
+ async exists(entryId) {
2111
+ if (!this.table)
2112
+ return false;
2113
+ try {
2114
+ const results = await this.table.search([]).where(`entryId = '${entryId}'`).limit(1).toArray();
2115
+ return results.length > 0;
2116
+ } catch {
2117
+ return false;
2118
+ }
2119
+ }
2120
+ };
2121
+ function createSharedVectorStore(dbPath) {
2122
+ return new SharedVectorStore(dbPath);
2123
+ }
2124
+
2125
+ // src/core/shared-promoter.ts
2126
+ import { randomUUID as randomUUID3 } from "crypto";
2127
+ var SharedPromoter = class {
2128
+ constructor(sharedStore, sharedVectorStore, embedder, config) {
2129
+ this.sharedStore = sharedStore;
2130
+ this.sharedVectorStore = sharedVectorStore;
2131
+ this.embedder = embedder;
2132
+ this.config = config;
2133
+ }
2134
+ /**
2135
+ * Check if an entry is eligible for promotion
2136
+ */
2137
+ isEligibleForPromotion(entry) {
2138
+ if (entry.entryType !== "troubleshooting") {
2139
+ return false;
2140
+ }
2141
+ if (entry.stage !== "verified" && entry.stage !== "certified") {
2142
+ return false;
2143
+ }
2144
+ if (entry.status !== "active") {
2145
+ return false;
2146
+ }
2147
+ return true;
2148
+ }
2149
+ /**
2150
+ * Promote a verified troubleshooting entry to shared storage
2151
+ */
2152
+ async promoteEntry(entry, projectHash) {
2153
+ if (!this.isEligibleForPromotion(entry)) {
2154
+ return {
2155
+ success: false,
2156
+ skipped: true,
2157
+ skipReason: `Entry not eligible: type=${entry.entryType}, stage=${entry.stage}, status=${entry.status}`
2158
+ };
2159
+ }
2160
+ const exists = await this.sharedStore.exists(projectHash, entry.entryId);
2161
+ if (exists) {
2162
+ return {
2163
+ success: true,
2164
+ skipped: true,
2165
+ skipReason: "Entry already exists in shared store"
2166
+ };
2167
+ }
2168
+ try {
2169
+ const content = entry.contentJson;
2170
+ const confidence = this.calculateConfidence(entry);
2171
+ const minConfidence = this.config?.minConfidenceForPromotion ?? 0.8;
2172
+ if (confidence < minConfidence) {
2173
+ return {
2174
+ success: false,
2175
+ skipped: true,
2176
+ skipReason: `Confidence ${confidence} below threshold ${minConfidence}`
2177
+ };
2178
+ }
2179
+ const input = {
2180
+ sourceProjectHash: projectHash,
2181
+ sourceEntryId: entry.entryId,
2182
+ title: entry.title,
2183
+ symptoms: content.symptoms || [],
2184
+ rootCause: content.rootCause || "",
2185
+ solution: content.solution || "",
2186
+ topics: this.extractTopics(entry),
2187
+ technologies: content.technologies || [],
2188
+ confidence
2189
+ };
2190
+ const entryId = await this.sharedStore.promoteEntry(input);
2191
+ const embeddingContent = this.createEmbeddingContent(input);
2192
+ const embedding = await this.embedder.embed(embeddingContent);
2193
+ await this.sharedVectorStore.upsert({
2194
+ id: randomUUID3(),
2195
+ entryId,
2196
+ entryType: "troubleshooting",
2197
+ content: embeddingContent,
2198
+ vector: embedding.vector,
2199
+ topics: input.topics,
2200
+ sourceProjectHash: projectHash
2201
+ });
2202
+ return {
2203
+ success: true,
2204
+ entryId
2205
+ };
2206
+ } catch (error) {
2207
+ return {
2208
+ success: false,
2209
+ error: error instanceof Error ? error.message : String(error)
2210
+ };
2211
+ }
2212
+ }
2213
+ /**
2214
+ * Batch promote multiple entries
2215
+ */
2216
+ async promoteEntries(entries, projectHash) {
2217
+ const results = /* @__PURE__ */ new Map();
2218
+ for (const entry of entries) {
2219
+ const result = await this.promoteEntry(entry, projectHash);
2220
+ results.set(entry.entryId, result);
2221
+ }
2222
+ return results;
2223
+ }
2224
+ /**
2225
+ * Extract topics from entry
2226
+ */
2227
+ extractTopics(entry) {
2228
+ const topics = [];
2229
+ const titleWords = entry.title.toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 3 && !this.isStopWord(w));
2230
+ topics.push(...titleWords);
2231
+ const content = entry.contentJson;
2232
+ if (content.topics && Array.isArray(content.topics)) {
2233
+ topics.push(...content.topics.map((t) => String(t).toLowerCase()));
2234
+ }
2235
+ if (content.technologies && Array.isArray(content.technologies)) {
2236
+ topics.push(...content.technologies.map((t) => String(t).toLowerCase()));
2237
+ }
2238
+ return [...new Set(topics)];
2239
+ }
2240
+ /**
2241
+ * Check if word is a stop word
2242
+ */
2243
+ isStopWord(word) {
2244
+ const stopWords = /* @__PURE__ */ new Set([
2245
+ "the",
2246
+ "and",
2247
+ "for",
2248
+ "with",
2249
+ "this",
2250
+ "that",
2251
+ "from",
2252
+ "have",
2253
+ "been",
2254
+ "were",
2255
+ "are",
2256
+ "was",
2257
+ "had",
2258
+ "has",
2259
+ "will",
2260
+ "would",
2261
+ "could",
2262
+ "should",
2263
+ "when",
2264
+ "where",
2265
+ "what",
2266
+ "which",
2267
+ "while",
2268
+ "error",
2269
+ "problem",
2270
+ "issue"
2271
+ ]);
2272
+ return stopWords.has(word);
2273
+ }
2274
+ /**
2275
+ * Calculate confidence score for entry
2276
+ */
2277
+ calculateConfidence(entry) {
2278
+ let confidence = 0.8;
2279
+ if (entry.stage === "certified") {
2280
+ confidence = 0.95;
2281
+ }
2282
+ return Math.min(confidence, 1);
2283
+ }
2284
+ /**
2285
+ * Create embedding content from input
2286
+ */
2287
+ createEmbeddingContent(input) {
2288
+ const parts = [];
2289
+ parts.push(`Problem: ${input.title}`);
2290
+ if (input.symptoms.length > 0) {
2291
+ parts.push(`Symptoms: ${input.symptoms.join(", ")}`);
2292
+ }
2293
+ if (input.rootCause) {
2294
+ parts.push(`Root Cause: ${input.rootCause}`);
2295
+ }
2296
+ if (input.solution) {
2297
+ parts.push(`Solution: ${input.solution}`);
2298
+ }
2299
+ if (input.technologies && input.technologies.length > 0) {
2300
+ parts.push(`Technologies: ${input.technologies.join(", ")}`);
2301
+ }
2302
+ return parts.join("\n");
2303
+ }
2304
+ };
2305
+ function createSharedPromoter(sharedStore, sharedVectorStore, embedder, config) {
2306
+ return new SharedPromoter(sharedStore, sharedVectorStore, embedder, config);
2307
+ }
2308
+
1577
2309
  // src/core/metadata-extractor.ts
1578
2310
  function createToolObservationEmbedding(toolName, metadata, success) {
1579
2311
  const parts = [];
@@ -1599,7 +2331,7 @@ function createToolObservationEmbedding(toolName, metadata, success) {
1599
2331
  }
1600
2332
 
1601
2333
  // src/core/working-set-store.ts
1602
- import { randomUUID as randomUUID2 } from "crypto";
2334
+ import { randomUUID as randomUUID4 } from "crypto";
1603
2335
  var WorkingSetStore = class {
1604
2336
  constructor(eventStore, config) {
1605
2337
  this.eventStore = eventStore;
@@ -1620,7 +2352,7 @@ var WorkingSetStore = class {
1620
2352
  `INSERT OR REPLACE INTO working_set (id, event_id, added_at, relevance_score, topics, expires_at)
1621
2353
  VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)`,
1622
2354
  [
1623
- randomUUID2(),
2355
+ randomUUID4(),
1624
2356
  eventId,
1625
2357
  relevanceScore,
1626
2358
  JSON.stringify(topics || []),
@@ -1804,7 +2536,7 @@ function createWorkingSetStore(eventStore, config) {
1804
2536
  }
1805
2537
 
1806
2538
  // src/core/consolidated-store.ts
1807
- import { randomUUID as randomUUID3 } from "crypto";
2539
+ import { randomUUID as randomUUID5 } from "crypto";
1808
2540
  var ConsolidatedStore = class {
1809
2541
  constructor(eventStore) {
1810
2542
  this.eventStore = eventStore;
@@ -1816,7 +2548,7 @@ var ConsolidatedStore = class {
1816
2548
  * Create a new consolidated memory
1817
2549
  */
1818
2550
  async create(input) {
1819
- const memoryId = randomUUID3();
2551
+ const memoryId = randomUUID5();
1820
2552
  await dbRun(
1821
2553
  this.db,
1822
2554
  `INSERT INTO consolidated_memories
@@ -2343,7 +3075,7 @@ function createConsolidationWorker(workingSetStore, consolidatedStore, config) {
2343
3075
  }
2344
3076
 
2345
3077
  // src/core/continuity-manager.ts
2346
- import { randomUUID as randomUUID4 } from "crypto";
3078
+ import { randomUUID as randomUUID6 } from "crypto";
2347
3079
  var ContinuityManager = class {
2348
3080
  constructor(eventStore, config) {
2349
3081
  this.eventStore = eventStore;
@@ -2497,7 +3229,7 @@ var ContinuityManager = class {
2497
3229
  `INSERT INTO continuity_log
2498
3230
  (log_id, from_context_id, to_context_id, continuity_score, transition_type, created_at)
2499
3231
  VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
2500
- [randomUUID4(), previous.id, current.id, score, type]
3232
+ [randomUUID6(), previous.id, current.id, score, type]
2501
3233
  );
2502
3234
  }
2503
3235
  /**
@@ -2623,6 +3355,7 @@ function getProjectStoragePath(projectPath) {
2623
3355
  return path.join(os.homedir(), ".claude-code", "memory", "projects", hash);
2624
3356
  }
2625
3357
  var REGISTRY_PATH = path.join(os.homedir(), ".claude-code", "memory", "session-registry.json");
3358
+ var SHARED_STORAGE_PATH = path.join(os.homedir(), ".claude-code", "memory", "shared");
2626
3359
  function loadSessionRegistry() {
2627
3360
  try {
2628
3361
  if (fs.existsSync(REGISTRY_PATH)) {
@@ -2678,11 +3411,20 @@ var MemoryService = class {
2678
3411
  consolidationWorker = null;
2679
3412
  continuityManager = null;
2680
3413
  endlessMode = "session";
3414
+ // Shared Store components (cross-project knowledge)
3415
+ sharedEventStore = null;
3416
+ sharedStore = null;
3417
+ sharedVectorStore = null;
3418
+ sharedPromoter = null;
3419
+ sharedStoreConfig = null;
3420
+ projectHash = null;
2681
3421
  constructor(config) {
2682
3422
  const storagePath = this.expandPath(config.storagePath);
2683
3423
  if (!fs.existsSync(storagePath)) {
2684
3424
  fs.mkdirSync(storagePath, { recursive: true });
2685
3425
  }
3426
+ this.projectHash = config.projectHash || null;
3427
+ this.sharedStoreConfig = config.sharedStoreConfig ?? { enabled: true };
2686
3428
  this.eventStore = new EventStore(path.join(storagePath, "events.duckdb"));
2687
3429
  this.vectorStore = new VectorStore(path.join(storagePath, "vectors"));
2688
3430
  this.embedder = config.embeddingModel ? new Embedder(config.embeddingModel) : getDefaultEmbedder();
@@ -2715,8 +3457,36 @@ var MemoryService = class {
2715
3457
  this.endlessMode = "endless";
2716
3458
  await this.initializeEndlessMode();
2717
3459
  }
3460
+ if (this.sharedStoreConfig?.enabled !== false) {
3461
+ await this.initializeSharedStore();
3462
+ }
2718
3463
  this.initialized = true;
2719
3464
  }
3465
+ /**
3466
+ * Initialize Shared Store components
3467
+ */
3468
+ async initializeSharedStore() {
3469
+ const sharedPath = this.sharedStoreConfig?.sharedStoragePath ? this.expandPath(this.sharedStoreConfig.sharedStoragePath) : SHARED_STORAGE_PATH;
3470
+ if (!fs.existsSync(sharedPath)) {
3471
+ fs.mkdirSync(sharedPath, { recursive: true });
3472
+ }
3473
+ this.sharedEventStore = createSharedEventStore(
3474
+ path.join(sharedPath, "shared.duckdb")
3475
+ );
3476
+ await this.sharedEventStore.initialize();
3477
+ this.sharedStore = createSharedStore(this.sharedEventStore);
3478
+ this.sharedVectorStore = createSharedVectorStore(
3479
+ path.join(sharedPath, "vectors")
3480
+ );
3481
+ await this.sharedVectorStore.initialize();
3482
+ this.sharedPromoter = createSharedPromoter(
3483
+ this.sharedStore,
3484
+ this.sharedVectorStore,
3485
+ this.embedder,
3486
+ this.sharedStoreConfig || void 0
3487
+ );
3488
+ this.retriever.setSharedStores(this.sharedStore, this.sharedVectorStore);
3489
+ }
2720
3490
  /**
2721
3491
  * Start a new session
2722
3492
  */
@@ -2823,6 +3593,13 @@ var MemoryService = class {
2823
3593
  if (this.vectorWorker) {
2824
3594
  await this.vectorWorker.processAll();
2825
3595
  }
3596
+ if (options?.includeShared && this.sharedStore) {
3597
+ return this.retriever.retrieveUnified(query, {
3598
+ ...options,
3599
+ includeShared: true,
3600
+ projectHash: this.projectHash || void 0
3601
+ });
3602
+ }
2826
3603
  return this.retriever.retrieve(query, options);
2827
3604
  }
2828
3605
  /**
@@ -2879,6 +3656,49 @@ var MemoryService = class {
2879
3656
  return header + result.context;
2880
3657
  }
2881
3658
  // ============================================================
3659
+ // Shared Store Methods (Cross-Project Knowledge)
3660
+ // ============================================================
3661
+ /**
3662
+ * Check if shared store is enabled and initialized
3663
+ */
3664
+ isSharedStoreEnabled() {
3665
+ return this.sharedStore !== null;
3666
+ }
3667
+ /**
3668
+ * Promote an entry to shared storage
3669
+ */
3670
+ async promoteToShared(entry) {
3671
+ if (!this.sharedPromoter || !this.projectHash) {
3672
+ return {
3673
+ success: false,
3674
+ error: "Shared store not initialized or project hash not set"
3675
+ };
3676
+ }
3677
+ return this.sharedPromoter.promoteEntry(entry, this.projectHash);
3678
+ }
3679
+ /**
3680
+ * Get shared store statistics
3681
+ */
3682
+ async getSharedStoreStats() {
3683
+ if (!this.sharedStore)
3684
+ return null;
3685
+ return this.sharedStore.getStats();
3686
+ }
3687
+ /**
3688
+ * Search shared troubleshooting entries
3689
+ */
3690
+ async searchShared(query, options) {
3691
+ if (!this.sharedStore)
3692
+ return [];
3693
+ return this.sharedStore.search(query, options);
3694
+ }
3695
+ /**
3696
+ * Get project hash for this service
3697
+ */
3698
+ getProjectHash() {
3699
+ return this.projectHash;
3700
+ }
3701
+ // ============================================================
2882
3702
  // Endless Mode Methods
2883
3703
  // ============================================================
2884
3704
  /**
@@ -3098,6 +3918,9 @@ var MemoryService = class {
3098
3918
  if (this.vectorWorker) {
3099
3919
  this.vectorWorker.stop();
3100
3920
  }
3921
+ if (this.sharedEventStore) {
3922
+ await this.sharedEventStore.close();
3923
+ }
3101
3924
  await this.eventStore.close();
3102
3925
  }
3103
3926
  /**
@@ -3120,11 +3943,15 @@ function getDefaultMemoryService() {
3120
3943
  }
3121
3944
  return serviceCache.get(GLOBAL_KEY);
3122
3945
  }
3123
- function getMemoryServiceForProject(projectPath) {
3946
+ function getMemoryServiceForProject(projectPath, sharedStoreConfig) {
3124
3947
  const hash = hashProjectPath(projectPath);
3125
3948
  if (!serviceCache.has(hash)) {
3126
3949
  const storagePath = getProjectStoragePath(projectPath);
3127
- serviceCache.set(hash, new MemoryService({ storagePath }));
3950
+ serviceCache.set(hash, new MemoryService({
3951
+ storagePath,
3952
+ projectHash: hash,
3953
+ sharedStoreConfig
3954
+ }));
3128
3955
  }
3129
3956
  return serviceCache.get(hash);
3130
3957
  }