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,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Generalizer
|
|
3
|
+
* Finds common patterns across multiple projects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
8
|
+
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
9
|
+
|
|
10
|
+
export interface GeneralizedPattern {
|
|
11
|
+
description: string
|
|
12
|
+
projects: string[]
|
|
13
|
+
occurrences: number
|
|
14
|
+
confidence: number
|
|
15
|
+
examples: Array<{
|
|
16
|
+
project: string
|
|
17
|
+
content: string
|
|
18
|
+
id: string
|
|
19
|
+
}>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface GeneralizationResult {
|
|
23
|
+
patterns: GeneralizedPattern[]
|
|
24
|
+
projectsAnalyzed: string[]
|
|
25
|
+
totalDecisionsAnalyzed: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class PatternGeneralizer {
|
|
29
|
+
private logger: Logger
|
|
30
|
+
private collections: CollectionManager
|
|
31
|
+
private embeddings?: EmbeddingProvider
|
|
32
|
+
|
|
33
|
+
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
34
|
+
this.logger = logger.child({ component: 'pattern-generalizer' })
|
|
35
|
+
this.collections = collections
|
|
36
|
+
this.embeddings = embeddings
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Find patterns that appear across multiple projects
|
|
41
|
+
*/
|
|
42
|
+
async findCrossProjectPatterns(options: {
|
|
43
|
+
minProjects?: number
|
|
44
|
+
limit?: number
|
|
45
|
+
query?: string
|
|
46
|
+
} = {}): Promise<GeneralizationResult> {
|
|
47
|
+
const { minProjects = 2, limit = 20, query } = options
|
|
48
|
+
|
|
49
|
+
// Fetch all decisions
|
|
50
|
+
const allDecisions = await this.fetchAllDecisions(query)
|
|
51
|
+
|
|
52
|
+
// Group by project
|
|
53
|
+
const byProject = new Map<string, Array<{ id: string; content: string }>>()
|
|
54
|
+
for (const d of allDecisions) {
|
|
55
|
+
const project = d.project
|
|
56
|
+
if (!byProject.has(project)) byProject.set(project, [])
|
|
57
|
+
byProject.get(project)!.push({ id: d.id, content: d.content })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const projects = Array.from(byProject.keys())
|
|
61
|
+
|
|
62
|
+
if (projects.length < minProjects) {
|
|
63
|
+
return {
|
|
64
|
+
patterns: [],
|
|
65
|
+
projectsAnalyzed: projects,
|
|
66
|
+
totalDecisionsAnalyzed: allDecisions.length
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Find cross-project patterns using term overlap
|
|
71
|
+
const crossPatterns = this.findCommonTermPatterns(byProject, minProjects)
|
|
72
|
+
|
|
73
|
+
// If embeddings are available, also do semantic clustering
|
|
74
|
+
if (this.embeddings && allDecisions.length > 0) {
|
|
75
|
+
const semanticPatterns = await this.findSemanticClusters(allDecisions, minProjects)
|
|
76
|
+
crossPatterns.push(...semanticPatterns)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Deduplicate and rank
|
|
80
|
+
const deduped = this.deduplicatePatterns(crossPatterns)
|
|
81
|
+
const ranked = deduped
|
|
82
|
+
.sort((a, b) => b.occurrences * b.confidence - a.occurrences * a.confidence)
|
|
83
|
+
.slice(0, limit)
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
patterns: ranked,
|
|
87
|
+
projectsAnalyzed: projects,
|
|
88
|
+
totalDecisionsAnalyzed: allDecisions.length
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private async fetchAllDecisions(query?: string): Promise<Array<{
|
|
93
|
+
id: string
|
|
94
|
+
content: string
|
|
95
|
+
project: string
|
|
96
|
+
}>> {
|
|
97
|
+
try {
|
|
98
|
+
const collection = await this.collections.getDecisions()
|
|
99
|
+
|
|
100
|
+
if (query && this.embeddings) {
|
|
101
|
+
const embedding = await this.embeddings.generate(query)
|
|
102
|
+
const results = await collection.query({
|
|
103
|
+
queryEmbeddings: [embedding],
|
|
104
|
+
nResults: 100,
|
|
105
|
+
include: ['documents', 'metadatas', 'distances']
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
if (!results.ids || !results.ids[0]) return []
|
|
109
|
+
|
|
110
|
+
return results.ids[0].map((id: string, i: number) => ({
|
|
111
|
+
id,
|
|
112
|
+
content: results.documents?.[0]?.[i] || '',
|
|
113
|
+
project: (results.metadatas?.[0]?.[i] as any)?.project || ''
|
|
114
|
+
}))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const results = await collection.get({
|
|
118
|
+
include: ['documents', 'metadatas']
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
return results.ids.map((id, i) => ({
|
|
122
|
+
id,
|
|
123
|
+
content: results.documents![i] as string || '',
|
|
124
|
+
project: (results.metadatas![i] as any)?.project || ''
|
|
125
|
+
}))
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.logger.warn({ error }, 'Failed to fetch decisions for generalization')
|
|
128
|
+
return []
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private findCommonTermPatterns(
|
|
133
|
+
byProject: Map<string, Array<{ id: string; content: string }>>,
|
|
134
|
+
minProjects: number
|
|
135
|
+
): GeneralizedPattern[] {
|
|
136
|
+
// Extract key terms per project
|
|
137
|
+
const projectTerms = new Map<string, Map<string, Array<{ id: string; content: string }>>>()
|
|
138
|
+
|
|
139
|
+
for (const [project, decisions] of byProject) {
|
|
140
|
+
const terms = new Map<string, Array<{ id: string; content: string }>>()
|
|
141
|
+
|
|
142
|
+
for (const d of decisions) {
|
|
143
|
+
const words = this.extractKeyTerms(d.content)
|
|
144
|
+
|
|
145
|
+
for (const word of words) {
|
|
146
|
+
if (!terms.has(word)) terms.set(word, [])
|
|
147
|
+
terms.get(word)!.push(d)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
projectTerms.set(project, terms)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Find terms that appear across multiple projects
|
|
155
|
+
const allTerms = new Map<string, { projects: Set<string>; examples: Array<{ project: string; content: string; id: string }> }>()
|
|
156
|
+
|
|
157
|
+
for (const [project, terms] of projectTerms) {
|
|
158
|
+
for (const [term, decisions] of terms) {
|
|
159
|
+
if (!allTerms.has(term)) {
|
|
160
|
+
allTerms.set(term, { projects: new Set(), examples: [] })
|
|
161
|
+
}
|
|
162
|
+
const entry = allTerms.get(term)!
|
|
163
|
+
entry.projects.add(project)
|
|
164
|
+
for (const d of decisions.slice(0, 2)) {
|
|
165
|
+
entry.examples.push({ project, content: d.content.slice(0, 150), id: d.id })
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Filter to terms appearing in multiple projects
|
|
171
|
+
const patterns: GeneralizedPattern[] = []
|
|
172
|
+
|
|
173
|
+
for (const [term, data] of allTerms) {
|
|
174
|
+
if (data.projects.size >= minProjects) {
|
|
175
|
+
patterns.push({
|
|
176
|
+
description: `Common pattern around: "${term}"`,
|
|
177
|
+
projects: Array.from(data.projects),
|
|
178
|
+
occurrences: data.examples.length,
|
|
179
|
+
confidence: Math.min(data.projects.size / byProject.size, 1),
|
|
180
|
+
examples: data.examples.slice(0, 5)
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return patterns
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private async findSemanticClusters(
|
|
189
|
+
decisions: Array<{ id: string; content: string; project: string }>,
|
|
190
|
+
minProjects: number
|
|
191
|
+
): Promise<GeneralizedPattern[]> {
|
|
192
|
+
if (!this.embeddings) return []
|
|
193
|
+
|
|
194
|
+
const patterns: GeneralizedPattern[] = []
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
// Simple approach: for each decision, find similar ones across projects
|
|
198
|
+
const sample = decisions.slice(0, 20) // Limit to avoid too many embedding calls
|
|
199
|
+
|
|
200
|
+
for (const decision of sample) {
|
|
201
|
+
const collection = await this.collections.getDecisions()
|
|
202
|
+
const embedding = await this.embeddings.generate(decision.content)
|
|
203
|
+
|
|
204
|
+
const results = await collection.query({
|
|
205
|
+
queryEmbeddings: [embedding],
|
|
206
|
+
nResults: 10,
|
|
207
|
+
include: ['documents', 'metadatas', 'distances']
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
if (!results.ids || !results.ids[0]) continue
|
|
211
|
+
|
|
212
|
+
const crossProjectMatches: Array<{ project: string; content: string; id: string }> = []
|
|
213
|
+
const matchProjects = new Set<string>()
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < results.ids[0].length; i++) {
|
|
216
|
+
const similarity = 1 - (results.distances?.[0]?.[i] || 0)
|
|
217
|
+
if (similarity < 0.6) continue
|
|
218
|
+
|
|
219
|
+
const matchProject = (results.metadatas?.[0]?.[i] as any)?.project || ''
|
|
220
|
+
if (matchProject && matchProject !== decision.project) {
|
|
221
|
+
matchProjects.add(matchProject)
|
|
222
|
+
crossProjectMatches.push({
|
|
223
|
+
project: matchProject,
|
|
224
|
+
content: (results.documents?.[0]?.[i] || '').slice(0, 150),
|
|
225
|
+
id: results.ids[0][i]
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
matchProjects.add(decision.project)
|
|
231
|
+
|
|
232
|
+
if (matchProjects.size >= minProjects) {
|
|
233
|
+
patterns.push({
|
|
234
|
+
description: `Similar approaches: "${decision.content.slice(0, 100)}..."`,
|
|
235
|
+
projects: Array.from(matchProjects),
|
|
236
|
+
occurrences: crossProjectMatches.length + 1,
|
|
237
|
+
confidence: 0.7,
|
|
238
|
+
examples: [
|
|
239
|
+
{ project: decision.project, content: decision.content.slice(0, 150), id: decision.id },
|
|
240
|
+
...crossProjectMatches.slice(0, 4)
|
|
241
|
+
]
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
this.logger.debug({ error }, 'Failed to find semantic clusters')
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return patterns
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private deduplicatePatterns(patterns: GeneralizedPattern[]): GeneralizedPattern[] {
|
|
253
|
+
const seen = new Set<string>()
|
|
254
|
+
const deduped: GeneralizedPattern[] = []
|
|
255
|
+
|
|
256
|
+
for (const pattern of patterns) {
|
|
257
|
+
const key = pattern.description.toLowerCase().slice(0, 50)
|
|
258
|
+
if (!seen.has(key)) {
|
|
259
|
+
seen.add(key)
|
|
260
|
+
deduped.push(pattern)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return deduped
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private extractKeyTerms(text: string): string[] {
|
|
268
|
+
const stopWords = new Set([
|
|
269
|
+
'the', 'and', 'for', 'are', 'but', 'not', 'all', 'can', 'was',
|
|
270
|
+
'has', 'had', 'been', 'have', 'with', 'this', 'that', 'from',
|
|
271
|
+
'they', 'will', 'would', 'there', 'their', 'what', 'about',
|
|
272
|
+
'which', 'when', 'make', 'like', 'just', 'also', 'should',
|
|
273
|
+
'use', 'using', 'used', 'because', 'instead', 'project',
|
|
274
|
+
'decision', 'decided', 'recommend', 'context', 'reasoning'
|
|
275
|
+
])
|
|
276
|
+
|
|
277
|
+
return text
|
|
278
|
+
.toLowerCase()
|
|
279
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
280
|
+
.split(/\s+/)
|
|
281
|
+
.filter(w => w.length > 3 && !stopWords.has(w))
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Project Intelligence Module
|
|
3
|
+
* Phase 15.4 - Pattern generalization, project affinity, knowledge transfer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { PatternGeneralizer } from './generalizer'
|
|
7
|
+
export type { GeneralizedPattern, GeneralizationResult } from './generalizer'
|
|
8
|
+
|
|
9
|
+
export { AffinityCalculator } from './affinity'
|
|
10
|
+
export type { ProjectAffinity } from './affinity'
|
|
11
|
+
|
|
12
|
+
export { KnowledgeTransfer } from './transfer'
|
|
13
|
+
export type { TransferableKnowledge, TransferItem } from './transfer'
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Transfer
|
|
3
|
+
* Transfer knowledge from one project to another based on similarity
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
8
|
+
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
9
|
+
|
|
10
|
+
export interface TransferableKnowledge {
|
|
11
|
+
sourceProject: string
|
|
12
|
+
targetProject: string
|
|
13
|
+
items: TransferItem[]
|
|
14
|
+
affinityScore: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TransferItem {
|
|
18
|
+
type: 'decision' | 'pattern' | 'correction'
|
|
19
|
+
id: string
|
|
20
|
+
content: string
|
|
21
|
+
relevance: number
|
|
22
|
+
reasoning: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class KnowledgeTransfer {
|
|
26
|
+
private logger: Logger
|
|
27
|
+
private collections: CollectionManager
|
|
28
|
+
private embeddings?: EmbeddingProvider
|
|
29
|
+
|
|
30
|
+
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
31
|
+
this.logger = logger.child({ component: 'knowledge-transfer' })
|
|
32
|
+
this.collections = collections
|
|
33
|
+
this.embeddings = embeddings
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Find transferable knowledge from source project to apply to target project
|
|
38
|
+
*/
|
|
39
|
+
async findTransferable(sourceProject: string, targetProject: string, options: {
|
|
40
|
+
limit?: number
|
|
41
|
+
minRelevance?: number
|
|
42
|
+
} = {}): Promise<TransferableKnowledge> {
|
|
43
|
+
const { limit = 10, minRelevance = 0.4 } = options
|
|
44
|
+
|
|
45
|
+
// Get target project's decisions to understand its context
|
|
46
|
+
const targetContext = await this.getProjectContext(targetProject)
|
|
47
|
+
|
|
48
|
+
if (!targetContext) {
|
|
49
|
+
return {
|
|
50
|
+
sourceProject,
|
|
51
|
+
targetProject,
|
|
52
|
+
items: [],
|
|
53
|
+
affinityScore: 0
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Search source project for relevant knowledge
|
|
58
|
+
const items: TransferItem[] = []
|
|
59
|
+
|
|
60
|
+
// Decisions
|
|
61
|
+
const decisions = await this.searchSourceProject(
|
|
62
|
+
sourceProject,
|
|
63
|
+
targetContext,
|
|
64
|
+
'decisions',
|
|
65
|
+
limit,
|
|
66
|
+
minRelevance
|
|
67
|
+
)
|
|
68
|
+
items.push(...decisions)
|
|
69
|
+
|
|
70
|
+
// Patterns
|
|
71
|
+
const patterns = await this.searchSourceProject(
|
|
72
|
+
sourceProject,
|
|
73
|
+
targetContext,
|
|
74
|
+
'patterns',
|
|
75
|
+
limit,
|
|
76
|
+
minRelevance
|
|
77
|
+
)
|
|
78
|
+
items.push(...patterns)
|
|
79
|
+
|
|
80
|
+
// Corrections
|
|
81
|
+
const corrections = await this.searchSourceProject(
|
|
82
|
+
sourceProject,
|
|
83
|
+
targetContext,
|
|
84
|
+
'corrections',
|
|
85
|
+
limit,
|
|
86
|
+
minRelevance
|
|
87
|
+
)
|
|
88
|
+
items.push(...corrections)
|
|
89
|
+
|
|
90
|
+
// Sort by relevance
|
|
91
|
+
items.sort((a, b) => b.relevance - a.relevance)
|
|
92
|
+
|
|
93
|
+
// Calculate affinity
|
|
94
|
+
const affinityScore = items.length > 0
|
|
95
|
+
? items.reduce((sum, i) => sum + i.relevance, 0) / items.length
|
|
96
|
+
: 0
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
sourceProject,
|
|
100
|
+
targetProject,
|
|
101
|
+
items: items.slice(0, limit),
|
|
102
|
+
affinityScore
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private async getProjectContext(project: string): Promise<string | null> {
|
|
107
|
+
try {
|
|
108
|
+
const collection = await this.collections.getDecisions()
|
|
109
|
+
|
|
110
|
+
const results = await collection.get({
|
|
111
|
+
where: { project: { $eq: project } },
|
|
112
|
+
include: ['documents'],
|
|
113
|
+
limit: 20
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (results.ids.length === 0) return null
|
|
117
|
+
|
|
118
|
+
// Combine recent decisions into a context string
|
|
119
|
+
return results.documents!
|
|
120
|
+
.slice(0, 10)
|
|
121
|
+
.map(d => d as string)
|
|
122
|
+
.join(' ')
|
|
123
|
+
} catch (error) {
|
|
124
|
+
this.logger.debug({ error, project }, 'Failed to get project context')
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private async searchSourceProject(
|
|
130
|
+
sourceProject: string,
|
|
131
|
+
targetContext: string,
|
|
132
|
+
collectionType: 'decisions' | 'patterns' | 'corrections',
|
|
133
|
+
limit: number,
|
|
134
|
+
minRelevance: number
|
|
135
|
+
): Promise<TransferItem[]> {
|
|
136
|
+
try {
|
|
137
|
+
let collection
|
|
138
|
+
let type: 'decision' | 'pattern' | 'correction'
|
|
139
|
+
|
|
140
|
+
switch (collectionType) {
|
|
141
|
+
case 'decisions':
|
|
142
|
+
collection = await this.collections.getDecisions()
|
|
143
|
+
type = 'decision'
|
|
144
|
+
break
|
|
145
|
+
case 'patterns':
|
|
146
|
+
collection = await this.collections.getPatterns()
|
|
147
|
+
type = 'pattern'
|
|
148
|
+
break
|
|
149
|
+
case 'corrections':
|
|
150
|
+
collection = await this.collections.getCorrections()
|
|
151
|
+
type = 'correction'
|
|
152
|
+
break
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const where: any = { project: { $eq: sourceProject } }
|
|
156
|
+
|
|
157
|
+
let results: any
|
|
158
|
+
|
|
159
|
+
if (this.embeddings) {
|
|
160
|
+
// Use truncated target context for embedding
|
|
161
|
+
const queryText = targetContext.slice(0, 500)
|
|
162
|
+
const embedding = await this.embeddings.generate(queryText)
|
|
163
|
+
results = await collection.query({
|
|
164
|
+
queryEmbeddings: [embedding],
|
|
165
|
+
nResults: limit,
|
|
166
|
+
where,
|
|
167
|
+
include: ['documents', 'metadatas', 'distances']
|
|
168
|
+
})
|
|
169
|
+
} else {
|
|
170
|
+
results = await collection.query({
|
|
171
|
+
queryTexts: [targetContext.slice(0, 500)],
|
|
172
|
+
nResults: limit,
|
|
173
|
+
where,
|
|
174
|
+
include: ['documents', 'metadatas', 'distances']
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!results.ids || !results.ids[0]) return []
|
|
179
|
+
|
|
180
|
+
const items: TransferItem[] = []
|
|
181
|
+
|
|
182
|
+
for (let i = 0; i < results.ids[0].length; i++) {
|
|
183
|
+
const similarity = 1 - (results.distances?.[0]?.[i] || 0)
|
|
184
|
+
if (similarity < minRelevance) continue
|
|
185
|
+
|
|
186
|
+
items.push({
|
|
187
|
+
type,
|
|
188
|
+
id: results.ids[0][i],
|
|
189
|
+
content: results.documents?.[0]?.[i] || '',
|
|
190
|
+
relevance: similarity,
|
|
191
|
+
reasoning: `Relevant ${type} from ${sourceProject} (${Math.round(similarity * 100)}% match)`
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return items
|
|
196
|
+
} catch (error) {
|
|
197
|
+
this.logger.debug({ error, sourceProject, collectionType }, 'Failed to search source project')
|
|
198
|
+
return []
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import os from 'os'
|
|
2
|
+
import fs from 'fs/promises'
|
|
3
|
+
import { loadConfig } from '@/config'
|
|
4
|
+
import { resolveHomePath } from '@/config/home'
|
|
5
|
+
import { createLogger } from '@/utils/logger'
|
|
6
|
+
|
|
7
|
+
export class DiagnosticTool {
|
|
8
|
+
private logger: any
|
|
9
|
+
|
|
10
|
+
constructor(logger: any) {
|
|
11
|
+
this.logger = logger.child({ component: 'diagnostics' })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async run(): Promise<void> {
|
|
15
|
+
console.log('š Running diagnostics...\n')
|
|
16
|
+
|
|
17
|
+
await this.printSystemInfo()
|
|
18
|
+
await this.printConfiguration()
|
|
19
|
+
await this.printRecentLogs()
|
|
20
|
+
await this.printCommonIssues()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private async printSystemInfo(): Promise<void> {
|
|
24
|
+
console.log('š System Information')
|
|
25
|
+
console.log('ā'.repeat(50))
|
|
26
|
+
console.log(`OS: ${os.platform()} ${os.release()}`)
|
|
27
|
+
console.log(`Architecture: ${os.arch()}`)
|
|
28
|
+
console.log(`Node/Bun: ${process.version}`)
|
|
29
|
+
console.log(`Bun: ${process.versions.bun || 'Not detected'}`)
|
|
30
|
+
console.log(`Memory: ${Math.round(os.totalmem() / 1024 / 1024 / 1024)}GB total`)
|
|
31
|
+
console.log(`Free Memory: ${Math.round(os.freemem() / 1024 / 1024 / 1024)}GB`)
|
|
32
|
+
console.log(`CPUs: ${os.cpus().length}`)
|
|
33
|
+
console.log(`CWD: ${process.cwd()}`)
|
|
34
|
+
console.log()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async printConfiguration(): Promise<void> {
|
|
38
|
+
console.log('āļø Configuration')
|
|
39
|
+
console.log('ā'.repeat(50))
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const config = await loadConfig()
|
|
43
|
+
console.log(`Vault Path: ${config.vaultPath}`)
|
|
44
|
+
console.log(`Database Path: ${config.dbPath}`)
|
|
45
|
+
console.log(`Log Level: ${config.logLevel}`)
|
|
46
|
+
console.log(`File Watch: ${config.enableFileWatch}`)
|
|
47
|
+
console.log(`Server Name: ${config.serverName}`)
|
|
48
|
+
console.log(`Server Version: ${config.serverVersion}`)
|
|
49
|
+
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(`Error loading config: ${error}`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private async printRecentLogs(): Promise<void> {
|
|
58
|
+
console.log('š Recent Logs (last 20 lines)')
|
|
59
|
+
console.log('ā'.repeat(50))
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const logContent = await fs.readFile(resolveHomePath('./logs/claude-brain.log'), 'utf-8')
|
|
63
|
+
const lines = logContent.split('\n').filter(l => l.trim())
|
|
64
|
+
const recentLines = lines.slice(-20)
|
|
65
|
+
|
|
66
|
+
for (const line of recentLines) {
|
|
67
|
+
console.log(line)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.log('No logs found or unable to read logs')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private async printCommonIssues(): Promise<void> {
|
|
78
|
+
console.log('š” Common Issues & Solutions')
|
|
79
|
+
console.log('ā'.repeat(50))
|
|
80
|
+
|
|
81
|
+
const issues = [
|
|
82
|
+
{
|
|
83
|
+
symptom: 'MCP server not found in Claude Code',
|
|
84
|
+
solution: 'Check Claude Code config file has correct absolute path'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
symptom: 'Vault path not found',
|
|
88
|
+
solution: 'Verify VAULT_PATH in .env points to valid Obsidian vault'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
symptom: 'Embeddings fail',
|
|
92
|
+
solution: 'Check internet connection (first-time model download)'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
symptom: 'Tools return stubs',
|
|
96
|
+
solution: 'Rebuild with: bun run build'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
symptom: 'No projects found',
|
|
100
|
+
solution: 'Create project directory: Projects/your-project/'
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
for (const issue of issues) {
|
|
105
|
+
console.log(`\nā ${issue.symptom}`)
|
|
106
|
+
console.log(` š” ${issue.solution}`)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log('\n\nš For more help, check the documentation or logs.\n')
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function runDiagnostics() {
|
|
114
|
+
const logger = createLogger('info', resolveHomePath('./logs/diagnostics.log'))
|
|
115
|
+
const tool = new DiagnosticTool(logger)
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
await tool.run()
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('ā Diagnostics failed:', error)
|
|
121
|
+
process.exit(1)
|
|
122
|
+
}
|
|
123
|
+
}
|