@soleri/core 2.1.0 → 2.4.0

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.
Files changed (207) hide show
  1. package/dist/brain/brain.d.ts +3 -1
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +60 -4
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +36 -1
  6. package/dist/brain/intelligence.d.ts.map +1 -1
  7. package/dist/brain/intelligence.js +119 -14
  8. package/dist/brain/intelligence.js.map +1 -1
  9. package/dist/brain/types.d.ts +32 -0
  10. package/dist/brain/types.d.ts.map +1 -1
  11. package/dist/control/identity-manager.d.ts +22 -0
  12. package/dist/control/identity-manager.d.ts.map +1 -0
  13. package/dist/control/identity-manager.js +233 -0
  14. package/dist/control/identity-manager.js.map +1 -0
  15. package/dist/control/intent-router.d.ts +32 -0
  16. package/dist/control/intent-router.d.ts.map +1 -0
  17. package/dist/control/intent-router.js +242 -0
  18. package/dist/control/intent-router.js.map +1 -0
  19. package/dist/control/types.d.ts +68 -0
  20. package/dist/control/types.d.ts.map +1 -0
  21. package/dist/control/types.js +9 -0
  22. package/dist/control/types.js.map +1 -0
  23. package/dist/curator/curator.d.ts +29 -0
  24. package/dist/curator/curator.d.ts.map +1 -1
  25. package/dist/curator/curator.js +135 -0
  26. package/dist/curator/curator.js.map +1 -1
  27. package/dist/facades/types.d.ts +1 -1
  28. package/dist/governance/governance.d.ts +42 -0
  29. package/dist/governance/governance.d.ts.map +1 -0
  30. package/dist/governance/governance.js +488 -0
  31. package/dist/governance/governance.js.map +1 -0
  32. package/dist/governance/index.d.ts +3 -0
  33. package/dist/governance/index.d.ts.map +1 -0
  34. package/dist/governance/index.js +2 -0
  35. package/dist/governance/index.js.map +1 -0
  36. package/dist/governance/types.d.ts +102 -0
  37. package/dist/governance/types.d.ts.map +1 -0
  38. package/dist/governance/types.js +3 -0
  39. package/dist/governance/types.js.map +1 -0
  40. package/dist/index.d.ts +32 -3
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +29 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/logging/logger.d.ts +37 -0
  45. package/dist/logging/logger.d.ts.map +1 -0
  46. package/dist/logging/logger.js +145 -0
  47. package/dist/logging/logger.js.map +1 -0
  48. package/dist/logging/types.d.ts +19 -0
  49. package/dist/logging/types.d.ts.map +1 -0
  50. package/dist/logging/types.js +2 -0
  51. package/dist/logging/types.js.map +1 -0
  52. package/dist/loop/loop-manager.d.ts +49 -0
  53. package/dist/loop/loop-manager.d.ts.map +1 -0
  54. package/dist/loop/loop-manager.js +105 -0
  55. package/dist/loop/loop-manager.js.map +1 -0
  56. package/dist/loop/types.d.ts +35 -0
  57. package/dist/loop/types.d.ts.map +1 -0
  58. package/dist/loop/types.js +8 -0
  59. package/dist/loop/types.js.map +1 -0
  60. package/dist/planning/gap-analysis.d.ts +29 -0
  61. package/dist/planning/gap-analysis.d.ts.map +1 -0
  62. package/dist/planning/gap-analysis.js +265 -0
  63. package/dist/planning/gap-analysis.js.map +1 -0
  64. package/dist/planning/gap-types.d.ts +29 -0
  65. package/dist/planning/gap-types.d.ts.map +1 -0
  66. package/dist/planning/gap-types.js +28 -0
  67. package/dist/planning/gap-types.js.map +1 -0
  68. package/dist/planning/planner.d.ts +150 -1
  69. package/dist/planning/planner.d.ts.map +1 -1
  70. package/dist/planning/planner.js +365 -2
  71. package/dist/planning/planner.js.map +1 -1
  72. package/dist/project/project-registry.d.ts +79 -0
  73. package/dist/project/project-registry.d.ts.map +1 -0
  74. package/dist/project/project-registry.js +276 -0
  75. package/dist/project/project-registry.js.map +1 -0
  76. package/dist/project/types.d.ts +28 -0
  77. package/dist/project/types.d.ts.map +1 -0
  78. package/dist/project/types.js +5 -0
  79. package/dist/project/types.js.map +1 -0
  80. package/dist/runtime/admin-extra-ops.d.ts +13 -0
  81. package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
  82. package/dist/runtime/admin-extra-ops.js +284 -0
  83. package/dist/runtime/admin-extra-ops.js.map +1 -0
  84. package/dist/runtime/admin-ops.d.ts +15 -0
  85. package/dist/runtime/admin-ops.d.ts.map +1 -0
  86. package/dist/runtime/admin-ops.js +322 -0
  87. package/dist/runtime/admin-ops.js.map +1 -0
  88. package/dist/runtime/capture-ops.d.ts +15 -0
  89. package/dist/runtime/capture-ops.d.ts.map +1 -0
  90. package/dist/runtime/capture-ops.js +345 -0
  91. package/dist/runtime/capture-ops.js.map +1 -0
  92. package/dist/runtime/core-ops.d.ts +7 -3
  93. package/dist/runtime/core-ops.d.ts.map +1 -1
  94. package/dist/runtime/core-ops.js +474 -8
  95. package/dist/runtime/core-ops.js.map +1 -1
  96. package/dist/runtime/curator-extra-ops.d.ts +9 -0
  97. package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
  98. package/dist/runtime/curator-extra-ops.js +59 -0
  99. package/dist/runtime/curator-extra-ops.js.map +1 -0
  100. package/dist/runtime/domain-ops.d.ts.map +1 -1
  101. package/dist/runtime/domain-ops.js +59 -13
  102. package/dist/runtime/domain-ops.js.map +1 -1
  103. package/dist/runtime/grading-ops.d.ts +14 -0
  104. package/dist/runtime/grading-ops.d.ts.map +1 -0
  105. package/dist/runtime/grading-ops.js +105 -0
  106. package/dist/runtime/grading-ops.js.map +1 -0
  107. package/dist/runtime/loop-ops.d.ts +13 -0
  108. package/dist/runtime/loop-ops.d.ts.map +1 -0
  109. package/dist/runtime/loop-ops.js +179 -0
  110. package/dist/runtime/loop-ops.js.map +1 -0
  111. package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
  112. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
  113. package/dist/runtime/memory-cross-project-ops.js +165 -0
  114. package/dist/runtime/memory-cross-project-ops.js.map +1 -0
  115. package/dist/runtime/memory-extra-ops.d.ts +13 -0
  116. package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
  117. package/dist/runtime/memory-extra-ops.js +173 -0
  118. package/dist/runtime/memory-extra-ops.js.map +1 -0
  119. package/dist/runtime/orchestrate-ops.d.ts +17 -0
  120. package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
  121. package/dist/runtime/orchestrate-ops.js +240 -0
  122. package/dist/runtime/orchestrate-ops.js.map +1 -0
  123. package/dist/runtime/planning-extra-ops.d.ts +17 -0
  124. package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
  125. package/dist/runtime/planning-extra-ops.js +300 -0
  126. package/dist/runtime/planning-extra-ops.js.map +1 -0
  127. package/dist/runtime/project-ops.d.ts +15 -0
  128. package/dist/runtime/project-ops.d.ts.map +1 -0
  129. package/dist/runtime/project-ops.js +181 -0
  130. package/dist/runtime/project-ops.js.map +1 -0
  131. package/dist/runtime/runtime.d.ts.map +1 -1
  132. package/dist/runtime/runtime.js +44 -1
  133. package/dist/runtime/runtime.js.map +1 -1
  134. package/dist/runtime/types.d.ts +21 -0
  135. package/dist/runtime/types.d.ts.map +1 -1
  136. package/dist/runtime/vault-extra-ops.d.ts +9 -0
  137. package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
  138. package/dist/runtime/vault-extra-ops.js +195 -0
  139. package/dist/runtime/vault-extra-ops.js.map +1 -0
  140. package/dist/telemetry/telemetry.d.ts +48 -0
  141. package/dist/telemetry/telemetry.d.ts.map +1 -0
  142. package/dist/telemetry/telemetry.js +87 -0
  143. package/dist/telemetry/telemetry.js.map +1 -0
  144. package/dist/vault/vault.d.ts +94 -0
  145. package/dist/vault/vault.d.ts.map +1 -1
  146. package/dist/vault/vault.js +340 -1
  147. package/dist/vault/vault.js.map +1 -1
  148. package/package.json +1 -1
  149. package/src/__tests__/admin-extra-ops.test.ts +420 -0
  150. package/src/__tests__/admin-ops.test.ts +271 -0
  151. package/src/__tests__/brain-intelligence.test.ts +205 -0
  152. package/src/__tests__/brain.test.ts +131 -0
  153. package/src/__tests__/capture-ops.test.ts +509 -0
  154. package/src/__tests__/core-ops.test.ts +266 -2
  155. package/src/__tests__/curator-extra-ops.test.ts +359 -0
  156. package/src/__tests__/domain-ops.test.ts +66 -0
  157. package/src/__tests__/governance.test.ts +522 -0
  158. package/src/__tests__/grading-ops.test.ts +340 -0
  159. package/src/__tests__/identity-manager.test.ts +243 -0
  160. package/src/__tests__/intent-router.test.ts +222 -0
  161. package/src/__tests__/logger.test.ts +200 -0
  162. package/src/__tests__/loop-ops.test.ts +398 -0
  163. package/src/__tests__/memory-cross-project-ops.test.ts +246 -0
  164. package/src/__tests__/memory-extra-ops.test.ts +352 -0
  165. package/src/__tests__/orchestrate-ops.test.ts +284 -0
  166. package/src/__tests__/planner.test.ts +331 -0
  167. package/src/__tests__/planning-extra-ops.test.ts +548 -0
  168. package/src/__tests__/project-ops.test.ts +367 -0
  169. package/src/__tests__/vault-extra-ops.test.ts +407 -0
  170. package/src/brain/brain.ts +114 -7
  171. package/src/brain/intelligence.ts +179 -10
  172. package/src/brain/types.ts +38 -0
  173. package/src/control/identity-manager.ts +354 -0
  174. package/src/control/intent-router.ts +326 -0
  175. package/src/control/types.ts +102 -0
  176. package/src/curator/curator.ts +213 -0
  177. package/src/governance/governance.ts +698 -0
  178. package/src/governance/index.ts +18 -0
  179. package/src/governance/types.ts +111 -0
  180. package/src/index.ts +102 -2
  181. package/src/logging/logger.ts +154 -0
  182. package/src/logging/types.ts +21 -0
  183. package/src/loop/loop-manager.ts +130 -0
  184. package/src/loop/types.ts +44 -0
  185. package/src/planning/gap-analysis.ts +506 -0
  186. package/src/planning/gap-types.ts +58 -0
  187. package/src/planning/planner.ts +478 -2
  188. package/src/project/project-registry.ts +358 -0
  189. package/src/project/types.ts +31 -0
  190. package/src/runtime/admin-extra-ops.ts +307 -0
  191. package/src/runtime/admin-ops.ts +329 -0
  192. package/src/runtime/capture-ops.ts +385 -0
  193. package/src/runtime/core-ops.ts +535 -7
  194. package/src/runtime/curator-extra-ops.ts +71 -0
  195. package/src/runtime/domain-ops.ts +65 -13
  196. package/src/runtime/grading-ops.ts +121 -0
  197. package/src/runtime/loop-ops.ts +194 -0
  198. package/src/runtime/memory-cross-project-ops.ts +192 -0
  199. package/src/runtime/memory-extra-ops.ts +186 -0
  200. package/src/runtime/orchestrate-ops.ts +272 -0
  201. package/src/runtime/planning-extra-ops.ts +327 -0
  202. package/src/runtime/project-ops.ts +196 -0
  203. package/src/runtime/runtime.ts +49 -1
  204. package/src/runtime/types.ts +21 -0
  205. package/src/runtime/vault-extra-ops.ts +225 -0
  206. package/src/telemetry/telemetry.ts +118 -0
  207. package/src/vault/vault.ts +412 -1
@@ -77,7 +77,8 @@ export class BrainIntelligence {
77
77
  tools_used TEXT NOT NULL DEFAULT '[]',
78
78
  files_modified TEXT NOT NULL DEFAULT '[]',
79
79
  plan_id TEXT,
80
- plan_outcome TEXT
80
+ plan_outcome TEXT,
81
+ extracted_at TEXT
81
82
  );
82
83
 
83
84
  CREATE TABLE IF NOT EXISTS brain_proposals (
@@ -161,9 +162,34 @@ export class BrainIntelligence {
161
162
  values.push(sessionId);
162
163
  db.prepare(`UPDATE brain_sessions SET ${updates.join(', ')} WHERE id = ?`).run(...values);
163
164
 
165
+ // Auto-extract knowledge if session has enough signal
166
+ this.autoExtractIfReady(this.getSession(sessionId)!);
167
+
168
+ // Return fresh session (extractedAt may have been set by auto-extract)
164
169
  return this.getSession(sessionId)!;
165
170
  }
166
171
 
172
+ /**
173
+ * Attempt auto-extraction after session end if the session has enough signal.
174
+ * Gate: at least 1 tool used OR 1 file modified OR a plan was associated.
175
+ * Silently skips if already extracted or insufficient data.
176
+ */
177
+ private autoExtractIfReady(session: BrainSession): void {
178
+ if (!session.endedAt) return;
179
+ if (session.extractedAt) return;
180
+
181
+ const hasSignal =
182
+ session.toolsUsed.length > 0 || session.filesModified.length > 0 || session.planId !== null;
183
+
184
+ if (!hasSignal) return;
185
+
186
+ try {
187
+ this.extractKnowledge(session.id);
188
+ } catch {
189
+ // Non-critical — don't break session end
190
+ }
191
+ }
192
+
167
193
  getSessionContext(limit = 10): SessionContext {
168
194
  const db = this.vault.getDb();
169
195
 
@@ -179,6 +205,7 @@ export class BrainIntelligence {
179
205
  files_modified: string;
180
206
  plan_id: string | null;
181
207
  plan_outcome: string | null;
208
+ extracted_at: string | null;
182
209
  }>;
183
210
 
184
211
  const sessions = rows.map((r) => this.rowToSession(r));
@@ -230,6 +257,8 @@ export class BrainIntelligence {
230
257
  COUNT(*) as total,
231
258
  SUM(CASE WHEN action = 'accepted' THEN 1 ELSE 0 END) as accepted,
232
259
  SUM(CASE WHEN action = 'dismissed' THEN 1 ELSE 0 END) as dismissed,
260
+ SUM(CASE WHEN action = 'modified' THEN 1 ELSE 0 END) as modified,
261
+ SUM(CASE WHEN action = 'failed' THEN 1 ELSE 0 END) as failed,
233
262
  MAX(created_at) as last_used
234
263
  FROM brain_feedback
235
264
  GROUP BY entry_id`,
@@ -239,6 +268,8 @@ export class BrainIntelligence {
239
268
  total: number;
240
269
  accepted: number;
241
270
  dismissed: number;
271
+ modified: number;
272
+ failed: number;
242
273
  last_used: string;
243
274
  }>;
244
275
 
@@ -265,7 +296,10 @@ export class BrainIntelligence {
265
296
  const spreadScore = Math.min(25, (uniqueContexts / SPREAD_MAX) * 25);
266
297
 
267
298
  // Success score: 25 * successRate
268
- const successRate = row.total > 0 ? row.accepted / row.total : 0;
299
+ // modified = 0.5 positive, failed = excluded (system error, not relevance)
300
+ const relevantTotal = row.total - row.failed;
301
+ const successRate =
302
+ relevantTotal > 0 ? (row.accepted + row.modified * 0.5) / relevantTotal : 0;
269
303
  const successScore = 25 * successRate;
270
304
 
271
305
  // Recency score: max(0, 25 * (1 - daysSince / RECENCY_DECAY_DAYS))
@@ -364,12 +398,17 @@ export class BrainIntelligence {
364
398
  }));
365
399
  }
366
400
 
367
- recommend(context: { domain?: string; task?: string; limit?: number }): PatternStrength[] {
401
+ recommend(context: {
402
+ domain?: string;
403
+ task?: string;
404
+ source?: string;
405
+ limit?: number;
406
+ }): PatternStrength[] {
368
407
  const limit = context.limit ?? 5;
369
408
  const strengths = this.getStrengths({
370
409
  domain: context.domain,
371
410
  minStrength: 30,
372
- limit: limit * 2,
411
+ limit: limit * 3,
373
412
  });
374
413
 
375
414
  // If task context provided, boost patterns with matching terms
@@ -383,9 +422,36 @@ export class BrainIntelligence {
383
422
  (s as { strength: number }).strength += overlap * 5;
384
423
  }
385
424
  }
386
- strengths.sort((a, b) => b.strength - a.strength);
387
425
  }
388
426
 
427
+ // Boost patterns with high source-specific acceptance rates
428
+ if (context.source) {
429
+ const db = this.vault.getDb();
430
+ for (const s of strengths) {
431
+ const row = db
432
+ .prepare(
433
+ `SELECT COUNT(*) as total,
434
+ SUM(CASE WHEN action = 'accepted' THEN 1 ELSE 0 END) as accepted,
435
+ SUM(CASE WHEN action = 'modified' THEN 1 ELSE 0 END) as modified
436
+ FROM brain_feedback
437
+ WHERE entry_id = (SELECT id FROM entries WHERE title = ? LIMIT 1)
438
+ AND source = ?`,
439
+ )
440
+ .get(s.pattern, context.source) as {
441
+ total: number;
442
+ accepted: number;
443
+ modified: number;
444
+ };
445
+
446
+ if (row.total >= 3) {
447
+ const sourceRate = (row.accepted + row.modified * 0.5) / row.total;
448
+ // Boost up to +10 points for high source-specific acceptance
449
+ (s as { strength: number }).strength += sourceRate * 10;
450
+ }
451
+ }
452
+ }
453
+
454
+ strengths.sort((a, b) => b.strength - a.strength);
389
455
  return strengths.slice(0, limit);
390
456
  }
391
457
 
@@ -510,6 +576,11 @@ export class BrainIntelligence {
510
576
  }
511
577
  }
512
578
 
579
+ // Mark session as extracted
580
+ db.prepare("UPDATE brain_sessions SET extracted_at = datetime('now') WHERE id = ?").run(
581
+ sessionId,
582
+ );
583
+
513
584
  return {
514
585
  sessionId,
515
586
  proposals,
@@ -517,6 +588,37 @@ export class BrainIntelligence {
517
588
  };
518
589
  }
519
590
 
591
+ resetExtracted(options?: { sessionId?: string; since?: string; all?: boolean }): {
592
+ reset: number;
593
+ } {
594
+ const db = this.vault.getDb();
595
+
596
+ if (options?.sessionId) {
597
+ const info = db
598
+ .prepare(
599
+ 'UPDATE brain_sessions SET extracted_at = NULL WHERE id = ? AND extracted_at IS NOT NULL',
600
+ )
601
+ .run(options.sessionId);
602
+ return { reset: info.changes };
603
+ }
604
+
605
+ if (options?.since) {
606
+ const info = db
607
+ .prepare('UPDATE brain_sessions SET extracted_at = NULL WHERE extracted_at >= ?')
608
+ .run(options.since);
609
+ return { reset: info.changes };
610
+ }
611
+
612
+ if (options?.all) {
613
+ const info = db
614
+ .prepare('UPDATE brain_sessions SET extracted_at = NULL WHERE extracted_at IS NOT NULL')
615
+ .run();
616
+ return { reset: info.changes };
617
+ }
618
+
619
+ return { reset: 0 };
620
+ }
621
+
520
622
  getProposals(options?: {
521
623
  sessionId?: string;
522
624
  promoted?: boolean;
@@ -556,10 +658,36 @@ export class BrainIntelligence {
556
658
  return rows.map((r) => this.rowToProposal(r));
557
659
  }
558
660
 
559
- promoteProposals(proposalIds: string[]): { promoted: number; failed: string[] } {
661
+ promoteProposals(
662
+ proposalIds: string[],
663
+ governanceGate?: {
664
+ evaluateCapture: (
665
+ projectPath: string,
666
+ entry: { type: string; category: string; title?: string },
667
+ ) => { action: string; reason?: string };
668
+ propose: (
669
+ projectPath: string,
670
+ entryData: {
671
+ entryId?: string;
672
+ title: string;
673
+ type: string;
674
+ category: string;
675
+ data?: Record<string, unknown>;
676
+ },
677
+ source?: string,
678
+ ) => number;
679
+ },
680
+ projectPath?: string,
681
+ ): {
682
+ promoted: number;
683
+ failed: string[];
684
+ gated: Array<{ id: string; action: string; reason?: string }>;
685
+ } {
560
686
  const db = this.vault.getDb();
561
687
  let promoted = 0;
562
688
  const failed: string[] = [];
689
+ const gated: Array<{ id: string; action: string; reason?: string }> = [];
690
+ const pp = projectPath ?? '.';
563
691
 
564
692
  for (const id of proposalIds) {
565
693
  const row = db.prepare('SELECT * FROM brain_proposals WHERE id = ?').get(id) as
@@ -583,10 +711,46 @@ export class BrainIntelligence {
583
711
 
584
712
  if (row.promoted) continue; // Already promoted
585
713
 
586
- // Add to vault as intelligence entry — map workflow to pattern since vault only accepts pattern/anti-pattern/rule
714
+ // Map type for vault
587
715
  const rawType = row.type;
588
716
  const vaultType: 'pattern' | 'anti-pattern' | 'rule' =
589
717
  rawType === 'anti-pattern' ? 'anti-pattern' : 'pattern';
718
+
719
+ // Governance gate (when provided)
720
+ if (governanceGate) {
721
+ const decision = governanceGate.evaluateCapture(pp, {
722
+ type: vaultType,
723
+ category: 'brain-intelligence',
724
+ title: row.title,
725
+ });
726
+
727
+ if (decision.action === 'propose') {
728
+ governanceGate.propose(
729
+ pp,
730
+ {
731
+ entryId: `proposal-${id}`,
732
+ title: row.title,
733
+ type: vaultType,
734
+ category: 'brain-intelligence',
735
+ data: {
736
+ severity: 'suggestion',
737
+ description: row.description,
738
+ tags: ['auto-extracted', row.rule],
739
+ },
740
+ },
741
+ 'brain-promote',
742
+ );
743
+ gated.push({ id, action: 'propose', reason: decision.reason });
744
+ continue;
745
+ }
746
+
747
+ if (decision.action !== 'capture') {
748
+ gated.push({ id, action: decision.action, reason: decision.reason });
749
+ continue;
750
+ }
751
+ }
752
+
753
+ // Capture into vault
590
754
  this.brain.enrichAndCapture({
591
755
  id: `proposal-${id}`,
592
756
  type: vaultType,
@@ -601,7 +765,7 @@ export class BrainIntelligence {
601
765
  promoted++;
602
766
  }
603
767
 
604
- return { promoted, failed };
768
+ return { promoted, failed, gated };
605
769
  }
606
770
 
607
771
  // ─── Intelligence Pipeline ────────────────────────────────────────
@@ -725,6 +889,7 @@ export class BrainIntelligence {
725
889
  files_modified: string;
726
890
  plan_id: string | null;
727
891
  plan_outcome: string | null;
892
+ extracted_at: string | null;
728
893
  }>;
729
894
  const sessions = sessionRows.map((r) => this.rowToSession(r));
730
895
 
@@ -790,8 +955,8 @@ export class BrainIntelligence {
790
955
  // Import sessions
791
956
  const insertSession = db.prepare(
792
957
  `INSERT OR IGNORE INTO brain_sessions
793
- (id, started_at, ended_at, domain, context, tools_used, files_modified, plan_id, plan_outcome)
794
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
958
+ (id, started_at, ended_at, domain, context, tools_used, files_modified, plan_id, plan_outcome, extracted_at)
959
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
795
960
  );
796
961
  for (const s of data.sessions) {
797
962
  const changes = insertSession.run(
@@ -804,6 +969,7 @@ export class BrainIntelligence {
804
969
  JSON.stringify(s.filesModified),
805
970
  s.planId,
806
971
  s.planOutcome,
972
+ s.extractedAt ?? null,
807
973
  );
808
974
  if (changes.changes > 0) result.imported.sessions++;
809
975
  }
@@ -883,6 +1049,7 @@ export class BrainIntelligence {
883
1049
  files_modified: string;
884
1050
  plan_id: string | null;
885
1051
  plan_outcome: string | null;
1052
+ extracted_at: string | null;
886
1053
  }
887
1054
  | undefined;
888
1055
 
@@ -900,6 +1067,7 @@ export class BrainIntelligence {
900
1067
  files_modified: string;
901
1068
  plan_id: string | null;
902
1069
  plan_outcome: string | null;
1070
+ extracted_at: string | null;
903
1071
  }): BrainSession {
904
1072
  return {
905
1073
  id: row.id,
@@ -911,6 +1079,7 @@ export class BrainIntelligence {
911
1079
  filesModified: JSON.parse(row.files_modified) as string[],
912
1080
  planId: row.plan_id,
913
1081
  planOutcome: row.plan_outcome,
1082
+ extractedAt: row.extracted_at,
914
1083
  };
915
1084
  }
916
1085
 
@@ -55,6 +55,43 @@ export interface QueryContext {
55
55
  tags?: string[];
56
56
  }
57
57
 
58
+ // ─── Feedback Types ───────────────────────────────────────────────
59
+
60
+ export type FeedbackType = 'accepted' | 'dismissed' | 'modified' | 'failed';
61
+ export type FeedbackSource = 'search' | 'recommendation' | 'tool-execution' | 'explicit';
62
+
63
+ export interface FeedbackInput {
64
+ query: string;
65
+ entryId: string;
66
+ action: FeedbackType;
67
+ source?: FeedbackSource;
68
+ confidence?: number;
69
+ duration?: number;
70
+ context?: string;
71
+ reason?: string;
72
+ }
73
+
74
+ export interface FeedbackEntry {
75
+ id: number;
76
+ query: string;
77
+ entryId: string;
78
+ action: FeedbackType;
79
+ source: FeedbackSource;
80
+ confidence: number;
81
+ duration: number | null;
82
+ context: string;
83
+ reason: string | null;
84
+ createdAt: number;
85
+ }
86
+
87
+ export interface FeedbackStats {
88
+ total: number;
89
+ byAction: Record<string, number>;
90
+ bySource: Record<string, number>;
91
+ acceptanceRate: number;
92
+ averageConfidence: number;
93
+ }
94
+
58
95
  // ─── Brain Intelligence Types ──────────────────────────────────────
59
96
 
60
97
  export interface PatternStrength {
@@ -87,6 +124,7 @@ export interface BrainSession {
87
124
  filesModified: string[];
88
125
  planId: string | null;
89
126
  planOutcome: string | null;
127
+ extractedAt: string | null;
90
128
  }
91
129
 
92
130
  export interface SessionLifecycleInput {