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.
@@ -133,7 +133,14 @@ var ConfigSchema = z.object({
133
133
  sessionSummary: z.boolean().default(true),
134
134
  insightExtraction: z.boolean().default(true),
135
135
  crossProjectLearning: z.boolean().default(false),
136
- singleWriterMode: z.boolean().default(true)
136
+ singleWriterMode: z.boolean().default(true),
137
+ sharedStore: z.object({
138
+ enabled: z.boolean().default(true),
139
+ autoPromote: z.boolean().default(true),
140
+ searchShared: z.boolean().default(true),
141
+ minConfidenceForPromotion: z.number().default(0.8),
142
+ sharedStoragePath: z.string().default("~/.claude-code/memory/shared")
143
+ }).default({})
137
144
  }).default({}),
138
145
  mode: z.enum(["session", "endless"]).default("session"),
139
146
  endless: z.object({
@@ -291,7 +298,8 @@ var EntryTypeSchema = z.enum([
291
298
  "task_note",
292
299
  "reference",
293
300
  "preference",
294
- "pattern"
301
+ "pattern",
302
+ "troubleshooting"
295
303
  ]);
296
304
  var EntrySchema = z.object({
297
305
  entryId: z.string(),
@@ -488,6 +496,34 @@ var ContinuityLogSchema = z.object({
488
496
  transitionType: TransitionTypeSchema,
489
497
  createdAt: z.date()
490
498
  });
499
+ var SharedEntryTypeSchema = z.enum([
500
+ "troubleshooting",
501
+ "best_practice",
502
+ "common_error"
503
+ ]);
504
+ var SharedTroubleshootingEntrySchema = z.object({
505
+ entryId: z.string(),
506
+ sourceProjectHash: z.string(),
507
+ sourceEntryId: z.string(),
508
+ title: z.string(),
509
+ symptoms: z.array(z.string()),
510
+ rootCause: z.string(),
511
+ solution: z.string(),
512
+ topics: z.array(z.string()),
513
+ technologies: z.array(z.string()).optional(),
514
+ confidence: z.number().min(0).max(1),
515
+ usageCount: z.number().default(0),
516
+ lastUsedAt: z.date().optional(),
517
+ promotedAt: z.date(),
518
+ createdAt: z.date()
519
+ });
520
+ var SharedStoreConfigSchema = z.object({
521
+ enabled: z.boolean().default(true),
522
+ autoPromote: z.boolean().default(true),
523
+ searchShared: z.boolean().default(true),
524
+ minConfidenceForPromotion: z.number().default(0.8),
525
+ sharedStoragePath: z.string().default("~/.claude-code/memory/shared")
526
+ });
491
527
 
492
528
  // src/core/canonical-key.ts
493
529
  import { createHash } from "crypto";
@@ -3129,11 +3165,22 @@ var Retriever = class {
3129
3165
  vectorStore;
3130
3166
  embedder;
3131
3167
  matcher;
3132
- constructor(eventStore, vectorStore, embedder, matcher) {
3168
+ sharedStore;
3169
+ sharedVectorStore;
3170
+ constructor(eventStore, vectorStore, embedder, matcher, sharedOptions) {
3133
3171
  this.eventStore = eventStore;
3134
3172
  this.vectorStore = vectorStore;
3135
3173
  this.embedder = embedder;
3136
3174
  this.matcher = matcher;
3175
+ this.sharedStore = sharedOptions?.sharedStore;
3176
+ this.sharedVectorStore = sharedOptions?.sharedVectorStore;
3177
+ }
3178
+ /**
3179
+ * Set shared stores after construction
3180
+ */
3181
+ setSharedStores(sharedStore, sharedVectorStore) {
3182
+ this.sharedStore = sharedStore;
3183
+ this.sharedVectorStore = sharedVectorStore;
3137
3184
  }
3138
3185
  /**
3139
3186
  * Retrieve relevant memories for a query
@@ -3160,6 +3207,75 @@ var Retriever = class {
3160
3207
  context
3161
3208
  };
3162
3209
  }
3210
+ /**
3211
+ * Retrieve with unified search (project + shared)
3212
+ */
3213
+ async retrieveUnified(query, options = {}) {
3214
+ const projectResult = await this.retrieve(query, options);
3215
+ if (!options.includeShared || !this.sharedStore || !this.sharedVectorStore) {
3216
+ return projectResult;
3217
+ }
3218
+ try {
3219
+ const queryEmbedding = await this.embedder.embed(query);
3220
+ const sharedVectorResults = await this.sharedVectorStore.search(
3221
+ queryEmbedding.vector,
3222
+ {
3223
+ limit: options.topK || 5,
3224
+ minScore: options.minScore || 0.7,
3225
+ excludeProjectHash: options.projectHash
3226
+ }
3227
+ );
3228
+ const sharedMemories = [];
3229
+ for (const result of sharedVectorResults) {
3230
+ const entry = await this.sharedStore.get(result.entryId);
3231
+ if (entry) {
3232
+ if (!options.projectHash || entry.sourceProjectHash !== options.projectHash) {
3233
+ sharedMemories.push(entry);
3234
+ await this.sharedStore.recordUsage(entry.entryId);
3235
+ }
3236
+ }
3237
+ }
3238
+ const unifiedContext = this.buildUnifiedContext(projectResult, sharedMemories);
3239
+ return {
3240
+ ...projectResult,
3241
+ context: unifiedContext,
3242
+ totalTokens: this.estimateTokens(unifiedContext),
3243
+ sharedMemories
3244
+ };
3245
+ } catch (error) {
3246
+ console.error("Shared search failed:", error);
3247
+ return projectResult;
3248
+ }
3249
+ }
3250
+ /**
3251
+ * Build unified context combining project and shared memories
3252
+ */
3253
+ buildUnifiedContext(projectResult, sharedMemories) {
3254
+ let context = projectResult.context;
3255
+ if (sharedMemories.length > 0) {
3256
+ context += "\n\n## Cross-Project Knowledge\n\n";
3257
+ for (const memory of sharedMemories.slice(0, 3)) {
3258
+ context += `### ${memory.title}
3259
+ `;
3260
+ if (memory.symptoms.length > 0) {
3261
+ context += `**Symptoms:** ${memory.symptoms.join(", ")}
3262
+ `;
3263
+ }
3264
+ context += `**Root Cause:** ${memory.rootCause}
3265
+ `;
3266
+ context += `**Solution:** ${memory.solution}
3267
+ `;
3268
+ if (memory.technologies && memory.technologies.length > 0) {
3269
+ context += `**Technologies:** ${memory.technologies.join(", ")}
3270
+ `;
3271
+ }
3272
+ context += `_Confidence: ${(memory.confidence * 100).toFixed(0)}%_
3273
+
3274
+ `;
3275
+ }
3276
+ }
3277
+ return context;
3278
+ }
3163
3279
  /**
3164
3280
  * Retrieve memories from a specific session
3165
3281
  */
@@ -4488,6 +4604,658 @@ var TaskProjector = class {
4488
4604
  return this.processAll();
4489
4605
  }
4490
4606
  };
4607
+
4608
+ // src/core/shared-event-store.ts
4609
+ var SharedEventStore = class {
4610
+ constructor(dbPath) {
4611
+ this.dbPath = dbPath;
4612
+ this.db = createDatabase(dbPath);
4613
+ }
4614
+ db;
4615
+ initialized = false;
4616
+ async initialize() {
4617
+ if (this.initialized)
4618
+ return;
4619
+ await dbRun(this.db, `
4620
+ CREATE TABLE IF NOT EXISTS shared_troubleshooting (
4621
+ entry_id VARCHAR PRIMARY KEY,
4622
+ source_project_hash VARCHAR NOT NULL,
4623
+ source_entry_id VARCHAR NOT NULL,
4624
+ title VARCHAR NOT NULL,
4625
+ symptoms JSON NOT NULL,
4626
+ root_cause TEXT NOT NULL,
4627
+ solution TEXT NOT NULL,
4628
+ topics JSON NOT NULL,
4629
+ technologies JSON,
4630
+ confidence REAL NOT NULL DEFAULT 0.8,
4631
+ usage_count INTEGER DEFAULT 0,
4632
+ last_used_at TIMESTAMP,
4633
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4634
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4635
+ UNIQUE(source_project_hash, source_entry_id)
4636
+ )
4637
+ `);
4638
+ await dbRun(this.db, `
4639
+ CREATE TABLE IF NOT EXISTS shared_best_practices (
4640
+ entry_id VARCHAR PRIMARY KEY,
4641
+ source_project_hash VARCHAR NOT NULL,
4642
+ source_entry_id VARCHAR NOT NULL,
4643
+ title VARCHAR NOT NULL,
4644
+ content_json JSON NOT NULL,
4645
+ topics JSON NOT NULL,
4646
+ confidence REAL NOT NULL DEFAULT 0.8,
4647
+ usage_count INTEGER DEFAULT 0,
4648
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4649
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4650
+ UNIQUE(source_project_hash, source_entry_id)
4651
+ )
4652
+ `);
4653
+ await dbRun(this.db, `
4654
+ CREATE TABLE IF NOT EXISTS shared_common_errors (
4655
+ entry_id VARCHAR PRIMARY KEY,
4656
+ source_project_hash VARCHAR NOT NULL,
4657
+ source_entry_id VARCHAR NOT NULL,
4658
+ title VARCHAR NOT NULL,
4659
+ error_pattern TEXT NOT NULL,
4660
+ solution TEXT NOT NULL,
4661
+ topics JSON NOT NULL,
4662
+ technologies JSON,
4663
+ confidence REAL NOT NULL DEFAULT 0.8,
4664
+ usage_count INTEGER DEFAULT 0,
4665
+ promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4666
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4667
+ UNIQUE(source_project_hash, source_entry_id)
4668
+ )
4669
+ `);
4670
+ await dbRun(this.db, `
4671
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_confidence
4672
+ ON shared_troubleshooting(confidence DESC)
4673
+ `);
4674
+ await dbRun(this.db, `
4675
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_usage
4676
+ ON shared_troubleshooting(usage_count DESC)
4677
+ `);
4678
+ await dbRun(this.db, `
4679
+ CREATE INDEX IF NOT EXISTS idx_shared_ts_source
4680
+ ON shared_troubleshooting(source_project_hash)
4681
+ `);
4682
+ this.initialized = true;
4683
+ }
4684
+ getDatabase() {
4685
+ return this.db;
4686
+ }
4687
+ isInitialized() {
4688
+ return this.initialized;
4689
+ }
4690
+ async close() {
4691
+ await dbClose(this.db);
4692
+ this.initialized = false;
4693
+ }
4694
+ };
4695
+ function createSharedEventStore(dbPath) {
4696
+ return new SharedEventStore(dbPath);
4697
+ }
4698
+
4699
+ // src/core/shared-store.ts
4700
+ import { randomUUID as randomUUID8 } from "crypto";
4701
+ var SharedStore = class {
4702
+ constructor(sharedEventStore) {
4703
+ this.sharedEventStore = sharedEventStore;
4704
+ }
4705
+ get db() {
4706
+ return this.sharedEventStore.getDatabase();
4707
+ }
4708
+ /**
4709
+ * Promote a verified troubleshooting entry to shared storage
4710
+ */
4711
+ async promoteEntry(input) {
4712
+ const entryId = randomUUID8();
4713
+ await dbRun(
4714
+ this.db,
4715
+ `INSERT INTO shared_troubleshooting (
4716
+ entry_id, source_project_hash, source_entry_id,
4717
+ title, symptoms, root_cause, solution, topics,
4718
+ technologies, confidence, promoted_at
4719
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
4720
+ ON CONFLICT (source_project_hash, source_entry_id)
4721
+ DO UPDATE SET
4722
+ title = excluded.title,
4723
+ symptoms = excluded.symptoms,
4724
+ root_cause = excluded.root_cause,
4725
+ solution = excluded.solution,
4726
+ topics = excluded.topics,
4727
+ technologies = excluded.technologies,
4728
+ confidence = CASE
4729
+ WHEN excluded.confidence > shared_troubleshooting.confidence
4730
+ THEN excluded.confidence
4731
+ ELSE shared_troubleshooting.confidence
4732
+ END`,
4733
+ [
4734
+ entryId,
4735
+ input.sourceProjectHash,
4736
+ input.sourceEntryId,
4737
+ input.title,
4738
+ JSON.stringify(input.symptoms),
4739
+ input.rootCause,
4740
+ input.solution,
4741
+ JSON.stringify(input.topics),
4742
+ JSON.stringify(input.technologies || []),
4743
+ input.confidence
4744
+ ]
4745
+ );
4746
+ return entryId;
4747
+ }
4748
+ /**
4749
+ * Search troubleshooting entries by text query
4750
+ */
4751
+ async search(query, options) {
4752
+ const topK = options?.topK || 5;
4753
+ const minConfidence = options?.minConfidence || 0.5;
4754
+ const searchPattern = `%${query}%`;
4755
+ const rows = await dbAll(
4756
+ this.db,
4757
+ `SELECT * FROM shared_troubleshooting
4758
+ WHERE (title LIKE ? OR root_cause LIKE ? OR solution LIKE ?)
4759
+ AND confidence >= ?
4760
+ ORDER BY confidence DESC, usage_count DESC
4761
+ LIMIT ?`,
4762
+ [searchPattern, searchPattern, searchPattern, minConfidence, topK]
4763
+ );
4764
+ return rows.map(this.rowToEntry);
4765
+ }
4766
+ /**
4767
+ * Search by topics
4768
+ */
4769
+ async searchByTopics(topics, options) {
4770
+ const topK = options?.topK || 5;
4771
+ if (topics.length === 0) {
4772
+ return [];
4773
+ }
4774
+ const topicConditions = topics.map(() => `topics LIKE ?`).join(" OR ");
4775
+ const topicParams = topics.map((t) => `%"${t}"%`);
4776
+ let query = `SELECT * FROM shared_troubleshooting WHERE (${topicConditions})`;
4777
+ const params = [...topicParams];
4778
+ if (options?.excludeProjectHash) {
4779
+ query += ` AND source_project_hash != ?`;
4780
+ params.push(options.excludeProjectHash);
4781
+ }
4782
+ query += ` ORDER BY confidence DESC, usage_count DESC LIMIT ?`;
4783
+ params.push(topK);
4784
+ const rows = await dbAll(this.db, query, params);
4785
+ return rows.map(this.rowToEntry);
4786
+ }
4787
+ /**
4788
+ * Record usage of a shared entry (for ranking)
4789
+ */
4790
+ async recordUsage(entryId) {
4791
+ await dbRun(
4792
+ this.db,
4793
+ `UPDATE shared_troubleshooting
4794
+ SET usage_count = usage_count + 1,
4795
+ last_used_at = CURRENT_TIMESTAMP
4796
+ WHERE entry_id = ?`,
4797
+ [entryId]
4798
+ );
4799
+ }
4800
+ /**
4801
+ * Get entry by ID
4802
+ */
4803
+ async get(entryId) {
4804
+ const rows = await dbAll(
4805
+ this.db,
4806
+ `SELECT * FROM shared_troubleshooting WHERE entry_id = ?`,
4807
+ [entryId]
4808
+ );
4809
+ if (rows.length === 0)
4810
+ return null;
4811
+ return this.rowToEntry(rows[0]);
4812
+ }
4813
+ /**
4814
+ * Get entry by source (project hash + entry ID)
4815
+ */
4816
+ async getBySource(projectHash, sourceEntryId) {
4817
+ const rows = await dbAll(
4818
+ this.db,
4819
+ `SELECT * FROM shared_troubleshooting
4820
+ WHERE source_project_hash = ? AND source_entry_id = ?`,
4821
+ [projectHash, sourceEntryId]
4822
+ );
4823
+ if (rows.length === 0)
4824
+ return null;
4825
+ return this.rowToEntry(rows[0]);
4826
+ }
4827
+ /**
4828
+ * Check if an entry already exists in shared store
4829
+ */
4830
+ async exists(projectHash, sourceEntryId) {
4831
+ const result = await dbAll(
4832
+ this.db,
4833
+ `SELECT COUNT(*) as count FROM shared_troubleshooting
4834
+ WHERE source_project_hash = ? AND source_entry_id = ?`,
4835
+ [projectHash, sourceEntryId]
4836
+ );
4837
+ return (result[0]?.count || 0) > 0;
4838
+ }
4839
+ /**
4840
+ * Get all entries (with limit for safety)
4841
+ */
4842
+ async getAll(options) {
4843
+ const limit = options?.limit || 100;
4844
+ const rows = await dbAll(
4845
+ this.db,
4846
+ `SELECT * FROM shared_troubleshooting
4847
+ ORDER BY confidence DESC, usage_count DESC
4848
+ LIMIT ?`,
4849
+ [limit]
4850
+ );
4851
+ return rows.map(this.rowToEntry);
4852
+ }
4853
+ /**
4854
+ * Get total count
4855
+ */
4856
+ async count() {
4857
+ const result = await dbAll(
4858
+ this.db,
4859
+ `SELECT COUNT(*) as count FROM shared_troubleshooting`
4860
+ );
4861
+ return result[0]?.count || 0;
4862
+ }
4863
+ /**
4864
+ * Get statistics
4865
+ */
4866
+ async getStats() {
4867
+ const countResult = await dbAll(
4868
+ this.db,
4869
+ `SELECT COUNT(*) as count FROM shared_troubleshooting`
4870
+ );
4871
+ const total = countResult[0]?.count || 0;
4872
+ const avgResult = await dbAll(
4873
+ this.db,
4874
+ `SELECT AVG(confidence) as avg FROM shared_troubleshooting`
4875
+ );
4876
+ const averageConfidence = avgResult[0]?.avg || 0;
4877
+ const usageResult = await dbAll(
4878
+ this.db,
4879
+ `SELECT SUM(usage_count) as total FROM shared_troubleshooting`
4880
+ );
4881
+ const totalUsageCount = usageResult[0]?.total || 0;
4882
+ const entries = await this.getAll({ limit: 1e3 });
4883
+ const topicCounts = {};
4884
+ for (const entry of entries) {
4885
+ for (const topic of entry.topics) {
4886
+ topicCounts[topic] = (topicCounts[topic] || 0) + 1;
4887
+ }
4888
+ }
4889
+ const topTopics = Object.entries(topicCounts).map(([topic, count]) => ({ topic, count })).sort((a, b) => b.count - a.count).slice(0, 10);
4890
+ return { total, averageConfidence, topTopics, totalUsageCount };
4891
+ }
4892
+ /**
4893
+ * Delete an entry
4894
+ */
4895
+ async delete(entryId) {
4896
+ const before = await this.count();
4897
+ await dbRun(
4898
+ this.db,
4899
+ `DELETE FROM shared_troubleshooting WHERE entry_id = ?`,
4900
+ [entryId]
4901
+ );
4902
+ const after = await this.count();
4903
+ return before > after;
4904
+ }
4905
+ rowToEntry(row) {
4906
+ return {
4907
+ entryId: row.entry_id,
4908
+ sourceProjectHash: row.source_project_hash,
4909
+ sourceEntryId: row.source_entry_id,
4910
+ title: row.title,
4911
+ symptoms: JSON.parse(row.symptoms || "[]"),
4912
+ rootCause: row.root_cause,
4913
+ solution: row.solution,
4914
+ topics: JSON.parse(row.topics || "[]"),
4915
+ technologies: JSON.parse(row.technologies || "[]"),
4916
+ confidence: row.confidence,
4917
+ usageCount: row.usage_count || 0,
4918
+ lastUsedAt: row.last_used_at ? toDate(row.last_used_at) : void 0,
4919
+ promotedAt: toDate(row.promoted_at),
4920
+ createdAt: toDate(row.created_at)
4921
+ };
4922
+ }
4923
+ };
4924
+ function createSharedStore(sharedEventStore) {
4925
+ return new SharedStore(sharedEventStore);
4926
+ }
4927
+
4928
+ // src/core/shared-vector-store.ts
4929
+ import * as lancedb2 from "@lancedb/lancedb";
4930
+ var SharedVectorStore = class {
4931
+ constructor(dbPath) {
4932
+ this.dbPath = dbPath;
4933
+ }
4934
+ db = null;
4935
+ table = null;
4936
+ tableName = "shared_knowledge";
4937
+ /**
4938
+ * Initialize LanceDB connection
4939
+ */
4940
+ async initialize() {
4941
+ if (this.db)
4942
+ return;
4943
+ this.db = await lancedb2.connect(this.dbPath);
4944
+ try {
4945
+ const tables = await this.db.tableNames();
4946
+ if (tables.includes(this.tableName)) {
4947
+ this.table = await this.db.openTable(this.tableName);
4948
+ }
4949
+ } catch {
4950
+ this.table = null;
4951
+ }
4952
+ }
4953
+ /**
4954
+ * Add or update a shared vector record
4955
+ */
4956
+ async upsert(record) {
4957
+ await this.initialize();
4958
+ if (!this.db) {
4959
+ throw new Error("Database not initialized");
4960
+ }
4961
+ const data = {
4962
+ id: record.id,
4963
+ entryId: record.entryId,
4964
+ entryType: record.entryType,
4965
+ content: record.content,
4966
+ vector: record.vector,
4967
+ topics: JSON.stringify(record.topics),
4968
+ sourceProjectHash: record.sourceProjectHash || ""
4969
+ };
4970
+ if (!this.table) {
4971
+ this.table = await this.db.createTable(this.tableName, [data]);
4972
+ } else {
4973
+ try {
4974
+ await this.table.delete(`entryId = '${record.entryId}'`);
4975
+ } catch {
4976
+ }
4977
+ await this.table.add([data]);
4978
+ }
4979
+ }
4980
+ /**
4981
+ * Add multiple records in batch
4982
+ */
4983
+ async upsertBatch(records) {
4984
+ if (records.length === 0)
4985
+ return;
4986
+ await this.initialize();
4987
+ if (!this.db) {
4988
+ throw new Error("Database not initialized");
4989
+ }
4990
+ const data = records.map((record) => ({
4991
+ id: record.id,
4992
+ entryId: record.entryId,
4993
+ entryType: record.entryType,
4994
+ content: record.content,
4995
+ vector: record.vector,
4996
+ topics: JSON.stringify(record.topics),
4997
+ sourceProjectHash: record.sourceProjectHash || ""
4998
+ }));
4999
+ if (!this.table) {
5000
+ this.table = await this.db.createTable(this.tableName, data);
5001
+ } else {
5002
+ await this.table.add(data);
5003
+ }
5004
+ }
5005
+ /**
5006
+ * Search for similar vectors
5007
+ */
5008
+ async search(queryVector, options = {}) {
5009
+ await this.initialize();
5010
+ if (!this.table) {
5011
+ return [];
5012
+ }
5013
+ const { limit = 5, minScore = 0.7, excludeProjectHash, entryType } = options;
5014
+ let query = this.table.search(queryVector).distanceType("cosine").limit(limit * 2);
5015
+ const filters = [];
5016
+ if (excludeProjectHash) {
5017
+ filters.push(`sourceProjectHash != '${excludeProjectHash}'`);
5018
+ }
5019
+ if (entryType) {
5020
+ filters.push(`entryType = '${entryType}'`);
5021
+ }
5022
+ if (filters.length > 0) {
5023
+ query = query.where(filters.join(" AND "));
5024
+ }
5025
+ const results = await query.toArray();
5026
+ return results.filter((r) => {
5027
+ const distance = r._distance || 0;
5028
+ const score = 1 - distance / 2;
5029
+ return score >= minScore;
5030
+ }).slice(0, limit).map((r) => {
5031
+ const distance = r._distance || 0;
5032
+ const score = 1 - distance / 2;
5033
+ return {
5034
+ id: r.id,
5035
+ entryId: r.entryId,
5036
+ content: r.content,
5037
+ score,
5038
+ entryType: r.entryType
5039
+ };
5040
+ });
5041
+ }
5042
+ /**
5043
+ * Delete vector by entry ID
5044
+ */
5045
+ async delete(entryId) {
5046
+ if (!this.table)
5047
+ return;
5048
+ await this.table.delete(`entryId = '${entryId}'`);
5049
+ }
5050
+ /**
5051
+ * Get total count
5052
+ */
5053
+ async count() {
5054
+ if (!this.table)
5055
+ return 0;
5056
+ return this.table.countRows();
5057
+ }
5058
+ /**
5059
+ * Check if vector exists for entry
5060
+ */
5061
+ async exists(entryId) {
5062
+ if (!this.table)
5063
+ return false;
5064
+ try {
5065
+ const results = await this.table.search([]).where(`entryId = '${entryId}'`).limit(1).toArray();
5066
+ return results.length > 0;
5067
+ } catch {
5068
+ return false;
5069
+ }
5070
+ }
5071
+ };
5072
+ function createSharedVectorStore(dbPath) {
5073
+ return new SharedVectorStore(dbPath);
5074
+ }
5075
+
5076
+ // src/core/shared-promoter.ts
5077
+ import { randomUUID as randomUUID9 } from "crypto";
5078
+ var SharedPromoter = class {
5079
+ constructor(sharedStore, sharedVectorStore, embedder, config) {
5080
+ this.sharedStore = sharedStore;
5081
+ this.sharedVectorStore = sharedVectorStore;
5082
+ this.embedder = embedder;
5083
+ this.config = config;
5084
+ }
5085
+ /**
5086
+ * Check if an entry is eligible for promotion
5087
+ */
5088
+ isEligibleForPromotion(entry) {
5089
+ if (entry.entryType !== "troubleshooting") {
5090
+ return false;
5091
+ }
5092
+ if (entry.stage !== "verified" && entry.stage !== "certified") {
5093
+ return false;
5094
+ }
5095
+ if (entry.status !== "active") {
5096
+ return false;
5097
+ }
5098
+ return true;
5099
+ }
5100
+ /**
5101
+ * Promote a verified troubleshooting entry to shared storage
5102
+ */
5103
+ async promoteEntry(entry, projectHash) {
5104
+ if (!this.isEligibleForPromotion(entry)) {
5105
+ return {
5106
+ success: false,
5107
+ skipped: true,
5108
+ skipReason: `Entry not eligible: type=${entry.entryType}, stage=${entry.stage}, status=${entry.status}`
5109
+ };
5110
+ }
5111
+ const exists = await this.sharedStore.exists(projectHash, entry.entryId);
5112
+ if (exists) {
5113
+ return {
5114
+ success: true,
5115
+ skipped: true,
5116
+ skipReason: "Entry already exists in shared store"
5117
+ };
5118
+ }
5119
+ try {
5120
+ const content = entry.contentJson;
5121
+ const confidence = this.calculateConfidence(entry);
5122
+ const minConfidence = this.config?.minConfidenceForPromotion ?? 0.8;
5123
+ if (confidence < minConfidence) {
5124
+ return {
5125
+ success: false,
5126
+ skipped: true,
5127
+ skipReason: `Confidence ${confidence} below threshold ${minConfidence}`
5128
+ };
5129
+ }
5130
+ const input = {
5131
+ sourceProjectHash: projectHash,
5132
+ sourceEntryId: entry.entryId,
5133
+ title: entry.title,
5134
+ symptoms: content.symptoms || [],
5135
+ rootCause: content.rootCause || "",
5136
+ solution: content.solution || "",
5137
+ topics: this.extractTopics(entry),
5138
+ technologies: content.technologies || [],
5139
+ confidence
5140
+ };
5141
+ const entryId = await this.sharedStore.promoteEntry(input);
5142
+ const embeddingContent = this.createEmbeddingContent(input);
5143
+ const embedding = await this.embedder.embed(embeddingContent);
5144
+ await this.sharedVectorStore.upsert({
5145
+ id: randomUUID9(),
5146
+ entryId,
5147
+ entryType: "troubleshooting",
5148
+ content: embeddingContent,
5149
+ vector: embedding.vector,
5150
+ topics: input.topics,
5151
+ sourceProjectHash: projectHash
5152
+ });
5153
+ return {
5154
+ success: true,
5155
+ entryId
5156
+ };
5157
+ } catch (error) {
5158
+ return {
5159
+ success: false,
5160
+ error: error instanceof Error ? error.message : String(error)
5161
+ };
5162
+ }
5163
+ }
5164
+ /**
5165
+ * Batch promote multiple entries
5166
+ */
5167
+ async promoteEntries(entries, projectHash) {
5168
+ const results = /* @__PURE__ */ new Map();
5169
+ for (const entry of entries) {
5170
+ const result = await this.promoteEntry(entry, projectHash);
5171
+ results.set(entry.entryId, result);
5172
+ }
5173
+ return results;
5174
+ }
5175
+ /**
5176
+ * Extract topics from entry
5177
+ */
5178
+ extractTopics(entry) {
5179
+ const topics = [];
5180
+ const titleWords = entry.title.toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 3 && !this.isStopWord(w));
5181
+ topics.push(...titleWords);
5182
+ const content = entry.contentJson;
5183
+ if (content.topics && Array.isArray(content.topics)) {
5184
+ topics.push(...content.topics.map((t) => String(t).toLowerCase()));
5185
+ }
5186
+ if (content.technologies && Array.isArray(content.technologies)) {
5187
+ topics.push(...content.technologies.map((t) => String(t).toLowerCase()));
5188
+ }
5189
+ return [...new Set(topics)];
5190
+ }
5191
+ /**
5192
+ * Check if word is a stop word
5193
+ */
5194
+ isStopWord(word) {
5195
+ const stopWords = /* @__PURE__ */ new Set([
5196
+ "the",
5197
+ "and",
5198
+ "for",
5199
+ "with",
5200
+ "this",
5201
+ "that",
5202
+ "from",
5203
+ "have",
5204
+ "been",
5205
+ "were",
5206
+ "are",
5207
+ "was",
5208
+ "had",
5209
+ "has",
5210
+ "will",
5211
+ "would",
5212
+ "could",
5213
+ "should",
5214
+ "when",
5215
+ "where",
5216
+ "what",
5217
+ "which",
5218
+ "while",
5219
+ "error",
5220
+ "problem",
5221
+ "issue"
5222
+ ]);
5223
+ return stopWords.has(word);
5224
+ }
5225
+ /**
5226
+ * Calculate confidence score for entry
5227
+ */
5228
+ calculateConfidence(entry) {
5229
+ let confidence = 0.8;
5230
+ if (entry.stage === "certified") {
5231
+ confidence = 0.95;
5232
+ }
5233
+ return Math.min(confidence, 1);
5234
+ }
5235
+ /**
5236
+ * Create embedding content from input
5237
+ */
5238
+ createEmbeddingContent(input) {
5239
+ const parts = [];
5240
+ parts.push(`Problem: ${input.title}`);
5241
+ if (input.symptoms.length > 0) {
5242
+ parts.push(`Symptoms: ${input.symptoms.join(", ")}`);
5243
+ }
5244
+ if (input.rootCause) {
5245
+ parts.push(`Root Cause: ${input.rootCause}`);
5246
+ }
5247
+ if (input.solution) {
5248
+ parts.push(`Solution: ${input.solution}`);
5249
+ }
5250
+ if (input.technologies && input.technologies.length > 0) {
5251
+ parts.push(`Technologies: ${input.technologies.join(", ")}`);
5252
+ }
5253
+ return parts.join("\n");
5254
+ }
5255
+ };
5256
+ function createSharedPromoter(sharedStore, sharedVectorStore, embedder, config) {
5257
+ return new SharedPromoter(sharedStore, sharedVectorStore, embedder, config);
5258
+ }
4491
5259
  export {
4492
5260
  AlignedEvidenceSchema,
4493
5261
  BlockerKindSchema,
@@ -4545,6 +5313,13 @@ export {
4545
5313
  Retriever,
4546
5314
  SearchIndexItemSchema,
4547
5315
  SessionSchema,
5316
+ SharedEntryTypeSchema,
5317
+ SharedEventStore,
5318
+ SharedPromoter,
5319
+ SharedStore,
5320
+ SharedStoreConfigSchema,
5321
+ SharedTroubleshootingEntrySchema,
5322
+ SharedVectorStore,
4548
5323
  TaskBlockersSetPayloadSchema,
4549
5324
  TaskCreatedPayloadSchema,
4550
5325
  TaskCurrentJsonSchema,
@@ -4567,6 +5342,10 @@ export {
4567
5342
  WorkingSetItemSchema,
4568
5343
  createGraduationPipeline,
4569
5344
  createRetriever,
5345
+ createSharedEventStore,
5346
+ createSharedPromoter,
5347
+ createSharedStore,
5348
+ createSharedVectorStore,
4570
5349
  createVectorWorker,
4571
5350
  createVectorWorkerV2,
4572
5351
  getDefaultAligner,