claude-brain 0.3.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.
- package/README.md +157 -0
- package/VERSION +1 -0
- package/assets/CLAUDE.md +307 -0
- package/bunfig.toml +8 -0
- package/package.json +74 -0
- package/src/automation/auto-context.ts +240 -0
- package/src/automation/decision-detector.ts +452 -0
- package/src/automation/index.ts +11 -0
- package/src/automation/proactive-recall.ts +373 -0
- package/src/automation/project-detector.ts +297 -0
- package/src/cli/auto-setup.ts +74 -0
- package/src/cli/bin.ts +110 -0
- package/src/cli/commands/install-mcp.ts +50 -0
- package/src/cli/commands/serve.ts +129 -0
- package/src/cli/diagnose.ts +4 -0
- package/src/cli/health-check.ts +4 -0
- package/src/cli/migrate-chroma.ts +106 -0
- package/src/cli/setup.ts +4 -0
- package/src/config/defaults.ts +47 -0
- package/src/config/home.ts +55 -0
- package/src/config/index.ts +7 -0
- package/src/config/loader.ts +166 -0
- package/src/config/migration.ts +76 -0
- package/src/config/schema.ts +257 -0
- package/src/config/validator.ts +184 -0
- package/src/config/watcher.ts +86 -0
- package/src/context/assembler.ts +398 -0
- package/src/context/cache-manager.ts +101 -0
- package/src/context/formatter.ts +84 -0
- package/src/context/hierarchy.ts +85 -0
- package/src/context/index.ts +83 -0
- package/src/context/progress-tracker.ts +174 -0
- package/src/context/standards-manager.ts +267 -0
- package/src/context/types.ts +252 -0
- package/src/context/validator.ts +58 -0
- package/src/cross-project/affinity.ts +162 -0
- package/src/cross-project/generalizer.ts +283 -0
- package/src/cross-project/index.ts +13 -0
- package/src/cross-project/transfer.ts +201 -0
- package/src/diagnostics/index.ts +123 -0
- package/src/health/index.ts +229 -0
- package/src/index.ts +7 -0
- package/src/knowledge/entity-extractor.ts +416 -0
- package/src/knowledge/graph/builder.ts +159 -0
- package/src/knowledge/graph/linker.ts +201 -0
- package/src/knowledge/graph/memory-graph.ts +359 -0
- package/src/knowledge/graph/schema.ts +99 -0
- package/src/knowledge/graph/search.ts +168 -0
- package/src/knowledge/relationship-extractor.ts +108 -0
- package/src/memory/chroma/client.ts +169 -0
- package/src/memory/chroma/collection-manager.ts +94 -0
- package/src/memory/chroma/config.ts +46 -0
- package/src/memory/chroma/embeddings.ts +153 -0
- package/src/memory/chroma/index.ts +82 -0
- package/src/memory/chroma/migration.ts +270 -0
- package/src/memory/chroma/schemas.ts +69 -0
- package/src/memory/chroma/search.ts +315 -0
- package/src/memory/chroma/store.ts +694 -0
- package/src/memory/consolidation/archiver.ts +164 -0
- package/src/memory/consolidation/merger.ts +186 -0
- package/src/memory/consolidation/scorer.ts +138 -0
- package/src/memory/context-builder.ts +236 -0
- package/src/memory/database.ts +169 -0
- package/src/memory/embedding-utils.ts +156 -0
- package/src/memory/embeddings.ts +226 -0
- package/src/memory/episodic/detector.ts +108 -0
- package/src/memory/episodic/manager.ts +334 -0
- package/src/memory/episodic/summarizer.ts +179 -0
- package/src/memory/episodic/types.ts +52 -0
- package/src/memory/index.ts +395 -0
- package/src/memory/knowledge-extractor.ts +455 -0
- package/src/memory/learning.ts +378 -0
- package/src/memory/patterns.ts +396 -0
- package/src/memory/schema.ts +56 -0
- package/src/memory/search.ts +309 -0
- package/src/memory/store.ts +344 -0
- package/src/memory/types.ts +121 -0
- package/src/optimization/index.ts +10 -0
- package/src/optimization/precompute.ts +202 -0
- package/src/optimization/semantic-cache.ts +207 -0
- package/src/orchestrator/coordinator.ts +272 -0
- package/src/orchestrator/decision-logger.ts +228 -0
- package/src/orchestrator/event-emitter.ts +198 -0
- package/src/orchestrator/event-queue.ts +184 -0
- package/src/orchestrator/handlers/base-handler.ts +70 -0
- package/src/orchestrator/handlers/context-handler.ts +73 -0
- package/src/orchestrator/handlers/decision-handler.ts +204 -0
- package/src/orchestrator/handlers/index.ts +10 -0
- package/src/orchestrator/handlers/status-handler.ts +131 -0
- package/src/orchestrator/handlers/task-handler.ts +171 -0
- package/src/orchestrator/index.ts +275 -0
- package/src/orchestrator/task-parser.ts +284 -0
- package/src/orchestrator/types.ts +98 -0
- package/src/phase12/index.ts +456 -0
- package/src/prediction/context-anticipator.ts +198 -0
- package/src/prediction/decision-predictor.ts +184 -0
- package/src/prediction/index.ts +13 -0
- package/src/prediction/recommender.ts +268 -0
- package/src/reasoning/chain-retrieval.ts +247 -0
- package/src/reasoning/counterfactual.ts +248 -0
- package/src/reasoning/index.ts +13 -0
- package/src/reasoning/synthesizer.ts +169 -0
- package/src/retrieval/bm25/index.ts +300 -0
- package/src/retrieval/bm25/tokenizer.ts +184 -0
- package/src/retrieval/feedback/adaptive.ts +223 -0
- package/src/retrieval/feedback/index.ts +16 -0
- package/src/retrieval/feedback/metrics.ts +223 -0
- package/src/retrieval/feedback/store.ts +283 -0
- package/src/retrieval/fusion/index.ts +194 -0
- package/src/retrieval/fusion/rrf.ts +163 -0
- package/src/retrieval/index.ts +12 -0
- package/src/retrieval/pipeline.ts +375 -0
- package/src/retrieval/query/expander.ts +198 -0
- package/src/retrieval/query/index.ts +27 -0
- package/src/retrieval/query/intent-classifier.ts +236 -0
- package/src/retrieval/query/temporal-parser.ts +295 -0
- package/src/retrieval/reranker/index.ts +188 -0
- package/src/retrieval/reranker/model.ts +95 -0
- package/src/retrieval/service.ts +125 -0
- package/src/retrieval/types.ts +162 -0
- package/src/scripts/health-check.ts +118 -0
- package/src/scripts/setup.ts +122 -0
- package/src/server/handlers/call-tool.ts +194 -0
- package/src/server/handlers/index.ts +9 -0
- package/src/server/handlers/list-tools.ts +18 -0
- package/src/server/handlers/tools/analyze-decision-evolution.ts +71 -0
- package/src/server/handlers/tools/auto-remember.ts +200 -0
- package/src/server/handlers/tools/create-project.ts +135 -0
- package/src/server/handlers/tools/detect-trends.ts +80 -0
- package/src/server/handlers/tools/find-cross-project-patterns.ts +73 -0
- package/src/server/handlers/tools/get-activity-log.ts +194 -0
- package/src/server/handlers/tools/get-code-standards.ts +124 -0
- package/src/server/handlers/tools/get-corrections.ts +154 -0
- package/src/server/handlers/tools/get-decision-timeline.ts +86 -0
- package/src/server/handlers/tools/get-episode.ts +93 -0
- package/src/server/handlers/tools/get-patterns.ts +158 -0
- package/src/server/handlers/tools/get-phase12-status.ts +63 -0
- package/src/server/handlers/tools/get-project-context.ts +75 -0
- package/src/server/handlers/tools/get-recommendations.ts +65 -0
- package/src/server/handlers/tools/index.ts +33 -0
- package/src/server/handlers/tools/init-project.ts +710 -0
- package/src/server/handlers/tools/list-episodes.ts +80 -0
- package/src/server/handlers/tools/list-projects.ts +125 -0
- package/src/server/handlers/tools/rate-memory.ts +95 -0
- package/src/server/handlers/tools/recall-similar.ts +87 -0
- package/src/server/handlers/tools/recognize-pattern.ts +126 -0
- package/src/server/handlers/tools/record-correction.ts +125 -0
- package/src/server/handlers/tools/remember-decision.ts +153 -0
- package/src/server/handlers/tools/schemas.ts +241 -0
- package/src/server/handlers/tools/search-knowledge-graph.ts +89 -0
- package/src/server/handlers/tools/smart-context.ts +124 -0
- package/src/server/handlers/tools/update-progress.ts +114 -0
- package/src/server/handlers/tools/what-if-analysis.ts +73 -0
- package/src/server/http-api.ts +474 -0
- package/src/server/index.ts +40 -0
- package/src/server/mcp-server.ts +283 -0
- package/src/server/providers/index.ts +7 -0
- package/src/server/providers/prompts.ts +327 -0
- package/src/server/providers/resources.ts +427 -0
- package/src/server/services.ts +388 -0
- package/src/server/types.ts +39 -0
- package/src/server/utils/error-handler.ts +155 -0
- package/src/server/utils/index.ts +13 -0
- package/src/server/utils/memory-indicator.ts +83 -0
- package/src/server/utils/request-context.ts +122 -0
- package/src/server/utils/response-formatter.ts +124 -0
- package/src/server/utils/validators.ts +210 -0
- package/src/setup/index.ts +22 -0
- package/src/setup/wizard.ts +321 -0
- package/src/temporal/evolution.ts +197 -0
- package/src/temporal/index.ts +16 -0
- package/src/temporal/query-processor.ts +190 -0
- package/src/temporal/timeline.ts +259 -0
- package/src/temporal/trends.ts +263 -0
- package/src/tools/index.ts +24 -0
- package/src/tools/registry.ts +106 -0
- package/src/tools/schemas.test.ts +30 -0
- package/src/tools/schemas.ts +907 -0
- package/src/tools/types.ts +412 -0
- package/src/utils/circuit-breaker.ts +130 -0
- package/src/utils/cleanup.ts +34 -0
- package/src/utils/error-handler.ts +132 -0
- package/src/utils/error-messages.ts +60 -0
- package/src/utils/fallback.ts +45 -0
- package/src/utils/index.ts +54 -0
- package/src/utils/logger-utils.ts +80 -0
- package/src/utils/logger.ts +88 -0
- package/src/utils/phase12-helper.ts +56 -0
- package/src/utils/retry.ts +94 -0
- package/src/utils/transaction.ts +63 -0
- package/src/vault/frontmatter.ts +264 -0
- package/src/vault/index.ts +318 -0
- package/src/vault/paths.ts +106 -0
- package/src/vault/query.ts +422 -0
- package/src/vault/reader.ts +264 -0
- package/src/vault/templates.ts +186 -0
- package/src/vault/types.ts +73 -0
- package/src/vault/watcher.ts +277 -0
- package/src/vault/writer.ts +393 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Recognition System
|
|
3
|
+
* Phase 12: Advanced Memory & Intelligent Automation
|
|
4
|
+
*
|
|
5
|
+
* Detects recurring patterns across projects and decisions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Logger } from 'pino'
|
|
9
|
+
import type { MemoryManager } from './index'
|
|
10
|
+
import type { Decision, MemorySearchResult } from './types'
|
|
11
|
+
|
|
12
|
+
export interface Pattern {
|
|
13
|
+
id: string
|
|
14
|
+
type: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
15
|
+
description: string
|
|
16
|
+
occurrences: number
|
|
17
|
+
projects: string[]
|
|
18
|
+
examples: string[]
|
|
19
|
+
confidence: number
|
|
20
|
+
firstSeen: Date
|
|
21
|
+
lastSeen: Date
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DecisionWithProject {
|
|
25
|
+
decision: string
|
|
26
|
+
reasoning?: string
|
|
27
|
+
project: string
|
|
28
|
+
timestamp: Date
|
|
29
|
+
tags?: string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class PatternRecognizer {
|
|
33
|
+
private logger: Logger
|
|
34
|
+
private memory: MemoryManager
|
|
35
|
+
private patterns: Map<string, Pattern> = new Map()
|
|
36
|
+
|
|
37
|
+
constructor(logger: Logger, memory: MemoryManager) {
|
|
38
|
+
this.logger = logger.child({ component: 'pattern-recognizer' })
|
|
39
|
+
this.memory = memory
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Analyze all decisions to find patterns
|
|
44
|
+
*/
|
|
45
|
+
async analyzePatterns(): Promise<Pattern[]> {
|
|
46
|
+
this.logger.info('Analyzing patterns across all projects')
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Get all decisions from all projects
|
|
50
|
+
const allDecisions = await this.getAllDecisions()
|
|
51
|
+
|
|
52
|
+
if (allDecisions.length < 3) {
|
|
53
|
+
this.logger.info('Not enough decisions for pattern analysis')
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Group by similarity
|
|
58
|
+
const clusters = await this.clusterDecisions(allDecisions)
|
|
59
|
+
|
|
60
|
+
// Extract patterns from clusters
|
|
61
|
+
const patterns = this.extractPatterns(clusters)
|
|
62
|
+
|
|
63
|
+
// Store patterns
|
|
64
|
+
for (const pattern of patterns) {
|
|
65
|
+
this.patterns.set(pattern.id, pattern)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.logger.info(
|
|
69
|
+
{ patternCount: patterns.length },
|
|
70
|
+
'Pattern analysis complete'
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return patterns
|
|
74
|
+
} catch (error) {
|
|
75
|
+
this.logger.error({ error }, 'Failed to analyze patterns')
|
|
76
|
+
return []
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get all decisions from all projects
|
|
82
|
+
*/
|
|
83
|
+
private async getAllDecisions(): Promise<DecisionWithProject[]> {
|
|
84
|
+
const projects = this.memory.store.getProjects()
|
|
85
|
+
const allDecisions: DecisionWithProject[] = []
|
|
86
|
+
|
|
87
|
+
for (const project of projects) {
|
|
88
|
+
const decisions = this.memory.store.getProjectDecisions(project)
|
|
89
|
+
|
|
90
|
+
for (const decision of decisions) {
|
|
91
|
+
// Get associated memory for timestamp
|
|
92
|
+
const memory = this.memory.store.getMemory(decision.memoryId)
|
|
93
|
+
|
|
94
|
+
allDecisions.push({
|
|
95
|
+
decision: decision.decision,
|
|
96
|
+
reasoning: decision.reasoning,
|
|
97
|
+
project,
|
|
98
|
+
timestamp: memory?.createdAt || new Date(),
|
|
99
|
+
tags: decision.tags
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return allDecisions
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Cluster similar decisions together
|
|
109
|
+
*/
|
|
110
|
+
private async clusterDecisions(decisions: DecisionWithProject[]): Promise<DecisionWithProject[][]> {
|
|
111
|
+
const clusters: DecisionWithProject[][] = []
|
|
112
|
+
const processed = new Set<number>()
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < decisions.length; i++) {
|
|
115
|
+
if (processed.has(i)) continue
|
|
116
|
+
|
|
117
|
+
const decision = decisions[i]
|
|
118
|
+
const cluster: DecisionWithProject[] = [decision]
|
|
119
|
+
processed.add(i)
|
|
120
|
+
|
|
121
|
+
// Find similar decisions using semantic search
|
|
122
|
+
try {
|
|
123
|
+
const similar = await this.memory.searchRaw(
|
|
124
|
+
decision.decision,
|
|
125
|
+
{
|
|
126
|
+
limit: 10,
|
|
127
|
+
minSimilarity: 0.75
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
// Map similar results back to our decision array
|
|
132
|
+
for (const result of similar) {
|
|
133
|
+
if (result.decision) {
|
|
134
|
+
// Find matching decision in our array
|
|
135
|
+
for (let j = 0; j < decisions.length; j++) {
|
|
136
|
+
if (!processed.has(j) &&
|
|
137
|
+
decisions[j].decision === result.decision.decision) {
|
|
138
|
+
cluster.push(decisions[j])
|
|
139
|
+
processed.add(j)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.logger.warn({ error }, 'Error finding similar decisions')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Only add cluster if it has enough items
|
|
149
|
+
if (cluster.length >= 3) {
|
|
150
|
+
clusters.push(cluster)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return clusters
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Extract patterns from decision clusters
|
|
159
|
+
*/
|
|
160
|
+
private extractPatterns(clusters: DecisionWithProject[][]): Pattern[] {
|
|
161
|
+
const patterns: Pattern[] = []
|
|
162
|
+
|
|
163
|
+
for (const cluster of clusters) {
|
|
164
|
+
const pattern = this.analyzeCluster(cluster)
|
|
165
|
+
|
|
166
|
+
if (pattern) {
|
|
167
|
+
patterns.push(pattern)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return patterns
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Analyze a cluster to find the common pattern
|
|
176
|
+
*/
|
|
177
|
+
private analyzeCluster(cluster: DecisionWithProject[]): Pattern | null {
|
|
178
|
+
if (cluster.length < 3) return null
|
|
179
|
+
|
|
180
|
+
// Extract common keywords
|
|
181
|
+
const keywords = this.extractCommonKeywords(cluster)
|
|
182
|
+
|
|
183
|
+
if (keywords.length === 0) return null
|
|
184
|
+
|
|
185
|
+
// Determine pattern type
|
|
186
|
+
const type = this.determinePatternType(cluster)
|
|
187
|
+
|
|
188
|
+
// Create pattern description
|
|
189
|
+
const description = this.generatePatternDescription(keywords, type)
|
|
190
|
+
|
|
191
|
+
// Get unique projects
|
|
192
|
+
const projects = [...new Set(cluster.map(d => d.project))]
|
|
193
|
+
|
|
194
|
+
// Get timestamps
|
|
195
|
+
const timestamps = cluster.map(d => d.timestamp.getTime())
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
id: this.generatePatternId(description),
|
|
199
|
+
type,
|
|
200
|
+
description,
|
|
201
|
+
occurrences: cluster.length,
|
|
202
|
+
projects,
|
|
203
|
+
examples: cluster.slice(0, 3).map(d => d.decision),
|
|
204
|
+
confidence: this.calculateConfidence(cluster),
|
|
205
|
+
firstSeen: new Date(Math.min(...timestamps)),
|
|
206
|
+
lastSeen: new Date(Math.max(...timestamps))
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Extract common keywords from decisions
|
|
212
|
+
*/
|
|
213
|
+
private extractCommonKeywords(decisions: DecisionWithProject[]): string[] {
|
|
214
|
+
const wordFreq: Map<string, number> = new Map()
|
|
215
|
+
|
|
216
|
+
// Stop words to filter out
|
|
217
|
+
const stopWords = new Set([
|
|
218
|
+
'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
|
|
219
|
+
'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'were', 'been',
|
|
220
|
+
'be', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
|
|
221
|
+
'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'need',
|
|
222
|
+
'this', 'that', 'these', 'those', 'it', 'its', 'we', 'our', 'you',
|
|
223
|
+
'your', 'they', 'their', 'use', 'using', 'because', 'since'
|
|
224
|
+
])
|
|
225
|
+
|
|
226
|
+
for (const decision of decisions) {
|
|
227
|
+
const words = decision.decision
|
|
228
|
+
.toLowerCase()
|
|
229
|
+
.split(/\W+/)
|
|
230
|
+
.filter(w => w.length > 4 && !stopWords.has(w))
|
|
231
|
+
|
|
232
|
+
for (const word of words) {
|
|
233
|
+
wordFreq.set(word, (wordFreq.get(word) || 0) + 1)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Return top keywords that appear in multiple decisions
|
|
238
|
+
return Array.from(wordFreq.entries())
|
|
239
|
+
.filter(([_, count]) => count >= 2)
|
|
240
|
+
.sort((a, b) => b[1] - a[1])
|
|
241
|
+
.slice(0, 5)
|
|
242
|
+
.map(([word]) => word)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Determine pattern type from cluster
|
|
247
|
+
*/
|
|
248
|
+
private determinePatternType(cluster: DecisionWithProject[]): Pattern['type'] {
|
|
249
|
+
// Check for anti-pattern indicators
|
|
250
|
+
const hasNegative = cluster.some(d => {
|
|
251
|
+
const text = (d.reasoning || '').toLowerCase()
|
|
252
|
+
return text.includes('avoid') ||
|
|
253
|
+
text.includes("don't") ||
|
|
254
|
+
text.includes('problem') ||
|
|
255
|
+
text.includes('mistake') ||
|
|
256
|
+
text.includes('bad')
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
if (hasNegative) return 'anti-pattern'
|
|
260
|
+
|
|
261
|
+
// Check for best practice indicators
|
|
262
|
+
const hasBestPractice = cluster.some(d => {
|
|
263
|
+
const text = (d.reasoning || '').toLowerCase()
|
|
264
|
+
return text.includes('best practice') ||
|
|
265
|
+
text.includes('recommended') ||
|
|
266
|
+
text.includes('standard') ||
|
|
267
|
+
d.tags?.includes('best-practice')
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
if (hasBestPractice) return 'best-practice'
|
|
271
|
+
|
|
272
|
+
// Check for issue indicators
|
|
273
|
+
const hasIssue = cluster.some(d => {
|
|
274
|
+
const text = (d.reasoning || '').toLowerCase()
|
|
275
|
+
return text.includes('issue') ||
|
|
276
|
+
text.includes('bug') ||
|
|
277
|
+
text.includes('fix')
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
if (hasIssue) return 'common-issue'
|
|
281
|
+
|
|
282
|
+
return 'solution'
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Generate pattern description
|
|
287
|
+
*/
|
|
288
|
+
private generatePatternDescription(keywords: string[], type: Pattern['type']): string {
|
|
289
|
+
const keywordPhrase = keywords.join(', ')
|
|
290
|
+
|
|
291
|
+
switch (type) {
|
|
292
|
+
case 'anti-pattern':
|
|
293
|
+
return `Avoid: ${keywordPhrase} - identified as anti-pattern`
|
|
294
|
+
case 'best-practice':
|
|
295
|
+
return `Best practice: ${keywordPhrase}`
|
|
296
|
+
case 'common-issue':
|
|
297
|
+
return `Common issue: ${keywordPhrase}`
|
|
298
|
+
case 'solution':
|
|
299
|
+
default:
|
|
300
|
+
return `Common solution: ${keywordPhrase}`
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Calculate confidence score for pattern
|
|
306
|
+
*/
|
|
307
|
+
private calculateConfidence(cluster: DecisionWithProject[]): number {
|
|
308
|
+
// More occurrences = higher confidence
|
|
309
|
+
// More projects = higher confidence
|
|
310
|
+
const projects = new Set(cluster.map(d => d.project))
|
|
311
|
+
|
|
312
|
+
const occurrenceScore = Math.min(cluster.length / 10, 1)
|
|
313
|
+
const projectScore = Math.min(projects.size / 5, 1)
|
|
314
|
+
|
|
315
|
+
return (occurrenceScore + projectScore) / 2
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Generate unique ID for pattern
|
|
320
|
+
*/
|
|
321
|
+
private generatePatternId(description: string): string {
|
|
322
|
+
return description
|
|
323
|
+
.toLowerCase()
|
|
324
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
325
|
+
.slice(0, 50)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get patterns matching query
|
|
330
|
+
*/
|
|
331
|
+
async getRelevantPatterns(query: string): Promise<Pattern[]> {
|
|
332
|
+
const allPatterns = Array.from(this.patterns.values())
|
|
333
|
+
|
|
334
|
+
if (allPatterns.length === 0) {
|
|
335
|
+
// Try to analyze patterns first
|
|
336
|
+
await this.analyzePatterns()
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Score patterns by relevance
|
|
340
|
+
const scored = Array.from(this.patterns.values()).map(pattern => ({
|
|
341
|
+
pattern,
|
|
342
|
+
score: this.scorePatternRelevance(pattern, query)
|
|
343
|
+
}))
|
|
344
|
+
|
|
345
|
+
// Return top patterns
|
|
346
|
+
return scored
|
|
347
|
+
.filter(p => p.score > 0.3)
|
|
348
|
+
.sort((a, b) => b.score - a.score)
|
|
349
|
+
.slice(0, 5)
|
|
350
|
+
.map(p => p.pattern)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Score pattern relevance to query
|
|
355
|
+
*/
|
|
356
|
+
private scorePatternRelevance(pattern: Pattern, query: string): number {
|
|
357
|
+
const queryLower = query.toLowerCase()
|
|
358
|
+
const descLower = pattern.description.toLowerCase()
|
|
359
|
+
|
|
360
|
+
// Exact match
|
|
361
|
+
if (descLower.includes(queryLower)) return 1.0
|
|
362
|
+
|
|
363
|
+
// Word overlap
|
|
364
|
+
const queryWords = queryLower.split(/\W+/).filter(w => w.length > 2)
|
|
365
|
+
const descWords = descLower.split(/\W+/).filter(w => w.length > 2)
|
|
366
|
+
|
|
367
|
+
if (queryWords.length === 0) return 0
|
|
368
|
+
|
|
369
|
+
const overlap = queryWords.filter(w => descWords.includes(w)).length
|
|
370
|
+
|
|
371
|
+
return overlap / queryWords.length
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get all detected patterns
|
|
376
|
+
*/
|
|
377
|
+
getAllPatterns(): Pattern[] {
|
|
378
|
+
return Array.from(this.patterns.values())
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get patterns by type
|
|
383
|
+
*/
|
|
384
|
+
getPatternsByType(type: Pattern['type']): Pattern[] {
|
|
385
|
+
return Array.from(this.patterns.values())
|
|
386
|
+
.filter(p => p.type === type)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Clear all patterns (useful for re-analysis)
|
|
391
|
+
*/
|
|
392
|
+
clearPatterns(): void {
|
|
393
|
+
this.patterns.clear()
|
|
394
|
+
this.logger.info('Patterns cleared')
|
|
395
|
+
}
|
|
396
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Schema for Memory System
|
|
3
|
+
* Phase 3: Memory and Embedding System
|
|
4
|
+
*
|
|
5
|
+
* Uses SQLite with vectors stored as BLOBs (float32 arrays)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const MEMORY_SCHEMA = `
|
|
9
|
+
-- Main memories table
|
|
10
|
+
-- Stores content with vector embeddings for semantic search
|
|
11
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
project TEXT NOT NULL,
|
|
14
|
+
content TEXT NOT NULL,
|
|
15
|
+
embedding BLOB NOT NULL, -- Vector stored as BLOB (float32 array)
|
|
16
|
+
created_at TEXT NOT NULL,
|
|
17
|
+
updated_at TEXT NOT NULL,
|
|
18
|
+
metadata TEXT -- JSON metadata
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- Indexes for efficient filtering
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project
|
|
23
|
+
ON memories(project);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_memories_created
|
|
25
|
+
ON memories(created_at);
|
|
26
|
+
|
|
27
|
+
-- Decisions table (specific type of memory)
|
|
28
|
+
-- Links to memories for full embedding support
|
|
29
|
+
CREATE TABLE IF NOT EXISTS decisions (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
memory_id TEXT NOT NULL,
|
|
32
|
+
context TEXT NOT NULL,
|
|
33
|
+
decision TEXT NOT NULL,
|
|
34
|
+
reasoning TEXT NOT NULL,
|
|
35
|
+
alternatives TEXT,
|
|
36
|
+
outcome TEXT,
|
|
37
|
+
tags TEXT, -- JSON array of tags
|
|
38
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
-- Index for decision lookups
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_decisions_memory
|
|
43
|
+
ON decisions(memory_id);
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Schema version for migrations
|
|
48
|
+
*/
|
|
49
|
+
export const SCHEMA_VERSION = 1
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if schema needs migration
|
|
53
|
+
*/
|
|
54
|
+
export const MIGRATION_CHECK = `
|
|
55
|
+
SELECT name FROM sqlite_master WHERE type='table' AND name='memories';
|
|
56
|
+
`
|