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