claude-brain 0.14.2 → 0.14.4
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 +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
package/src/hooks/capture.ts
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 17: Capture Engine
|
|
3
|
-
* Orchestrates passive classification + entity extraction with privacy filters.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { HookInput, CapturedKnowledge } from './types'
|
|
7
|
-
import type { HooksConfig } from '@/config/schema'
|
|
8
|
-
import { PassiveClassifier } from './passive-classifier'
|
|
9
|
-
|
|
10
|
-
// Reuse tech dictionaries from entity extractor for enrichment
|
|
11
|
-
const COMMON_TECH: Set<string> = new Set([
|
|
12
|
-
'typescript', 'javascript', 'python', 'rust', 'go', 'java', 'ruby', 'php', 'swift', 'kotlin',
|
|
13
|
-
'react', 'vue', 'angular', 'svelte', 'nextjs', 'nuxt', 'remix', 'astro', 'solid',
|
|
14
|
-
'express', 'fastify', 'hono', 'nestjs', 'django', 'flask', 'fastapi', 'rails', 'spring',
|
|
15
|
-
'mongodb', 'redis', 'postgresql', 'postgres', 'mysql', 'sqlite', 'dynamodb', 'firebase', 'supabase',
|
|
16
|
-
'prisma', 'drizzle', 'typeorm', 'sequelize', 'chromadb', 'pinecone',
|
|
17
|
-
'docker', 'kubernetes', 'aws', 'gcp', 'azure', 'vercel', 'netlify',
|
|
18
|
-
'webpack', 'vite', 'esbuild', 'bun', 'deno', 'node', 'npm', 'yarn', 'pnpm',
|
|
19
|
-
'jest', 'vitest', 'cypress', 'playwright',
|
|
20
|
-
'tailwind', 'bootstrap', 'zod', 'trpc', 'graphql', 'rest',
|
|
21
|
-
'jwt', 'oauth', 'openai', 'anthropic', 'langchain',
|
|
22
|
-
'git', 'github', 'gitlab', 'eslint', 'prettier',
|
|
23
|
-
'zustand', 'redux', 'pinia', 'mobx', 'jotai', 'recoil',
|
|
24
|
-
'storybook', 'turborepo', 'nx',
|
|
25
|
-
'microservices', 'serverless', 'monolith', 'ssr', 'ssg', 'spa', 'pwa', 'mcp', 'rag'
|
|
26
|
-
])
|
|
27
|
-
|
|
28
|
-
const TECH_ALIASES: Record<string, string> = {
|
|
29
|
-
'ts': 'typescript', 'js': 'javascript', 'py': 'python',
|
|
30
|
-
'react.js': 'react', 'reactjs': 'react', 'vue.js': 'vue', 'vuejs': 'vue',
|
|
31
|
-
'next.js': 'nextjs', 'nuxt.js': 'nuxt', 'nest.js': 'nestjs',
|
|
32
|
-
'express.js': 'express', 'node.js': 'node', 'nodejs': 'node',
|
|
33
|
-
'mongo': 'mongodb', 'pg': 'postgresql', 'k8s': 'kubernetes',
|
|
34
|
-
'tailwindcss': 'tailwind', 'tailwind-css': 'tailwind',
|
|
35
|
-
'gql': 'graphql', 'golang': 'go',
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Phase 20: Default privacy ignore paths for sensitive files */
|
|
39
|
-
const DEFAULT_IGNORE_PATHS = [
|
|
40
|
-
'node_modules/**', '.env*', '*.key', '*.pem', '*.p12', '*.pfx',
|
|
41
|
-
'.git/**', 'dist/**', 'build/**', '*.secret', 'credentials*',
|
|
42
|
-
'.aws/**', '.ssh/**'
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
export class BrainCapture {
|
|
46
|
-
private classifier: PassiveClassifier
|
|
47
|
-
private config: HooksConfig
|
|
48
|
-
|
|
49
|
-
constructor(config?: Partial<HooksConfig>) {
|
|
50
|
-
this.config = {
|
|
51
|
-
enabled: config?.enabled ?? true,
|
|
52
|
-
capture: {
|
|
53
|
-
toolUse: config?.capture?.toolUse ?? true,
|
|
54
|
-
fileEdits: config?.capture?.fileEdits ?? true,
|
|
55
|
-
bashCommands: config?.capture?.bashCommands ?? true,
|
|
56
|
-
userMessages: config?.capture?.userMessages ?? true,
|
|
57
|
-
},
|
|
58
|
-
privacy: {
|
|
59
|
-
ignorePaths: config?.privacy?.ignorePaths ?? DEFAULT_IGNORE_PATHS,
|
|
60
|
-
ignoreProjects: config?.privacy?.ignoreProjects ?? [],
|
|
61
|
-
minConfidence: config?.privacy?.minConfidence ?? 0.7,
|
|
62
|
-
},
|
|
63
|
-
sessions: {
|
|
64
|
-
enabled: config?.sessions?.enabled ?? true,
|
|
65
|
-
idleTimeoutMinutes: config?.sessions?.idleTimeoutMinutes ?? 30,
|
|
66
|
-
minEventsForSummary: config?.sessions?.minEventsForSummary ?? 3,
|
|
67
|
-
},
|
|
68
|
-
deduplication: {
|
|
69
|
-
skipThreshold: config?.deduplication?.skipThreshold ?? 0.95,
|
|
70
|
-
mergeThreshold: config?.deduplication?.mergeThreshold ?? 0.85,
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
this.classifier = new PassiveClassifier()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Process a hook input event.
|
|
78
|
-
* Returns captured knowledge or null if nothing worth capturing.
|
|
79
|
-
*/
|
|
80
|
-
process(input: HookInput): CapturedKnowledge | null {
|
|
81
|
-
if (!this.config.enabled) return null
|
|
82
|
-
|
|
83
|
-
// Privacy: check ignored paths
|
|
84
|
-
if (this.isPathIgnored(input.cwd)) return null
|
|
85
|
-
|
|
86
|
-
// Check capture toggles by tool type
|
|
87
|
-
if (!this.shouldCapture(input)) return null
|
|
88
|
-
|
|
89
|
-
// Classify tool output
|
|
90
|
-
const knowledge = this.classifier.classify(input)
|
|
91
|
-
if (!knowledge) return null
|
|
92
|
-
|
|
93
|
-
// Privacy: check ignored projects
|
|
94
|
-
if (knowledge.project && this.config.privacy.ignoreProjects.includes(knowledge.project)) {
|
|
95
|
-
return null
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Enrich with additional technology detection from content
|
|
99
|
-
knowledge.technologies = this.enrichTechnologies(knowledge)
|
|
100
|
-
|
|
101
|
-
// Filter by minimum confidence
|
|
102
|
-
if (knowledge.confidence < this.config.privacy.minConfidence) {
|
|
103
|
-
return null
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return knowledge
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Check if a path matches any ignore pattern */
|
|
110
|
-
private isPathIgnored(cwd: string): boolean {
|
|
111
|
-
if (!cwd || this.config.privacy.ignorePaths.length === 0) return false
|
|
112
|
-
const lowerCwd = cwd.toLowerCase()
|
|
113
|
-
return this.config.privacy.ignorePaths.some(pattern => {
|
|
114
|
-
const lowerPattern = pattern.toLowerCase()
|
|
115
|
-
// Simple glob: just check if pattern appears in path
|
|
116
|
-
if (lowerPattern.includes('*')) {
|
|
117
|
-
const regex = new RegExp(lowerPattern.replace(/\*/g, '.*'))
|
|
118
|
-
return regex.test(lowerCwd)
|
|
119
|
-
}
|
|
120
|
-
return lowerCwd.includes(lowerPattern)
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Check if this tool type should be captured based on config */
|
|
125
|
-
private shouldCapture(input: HookInput): boolean {
|
|
126
|
-
const toolName = input.tool_name?.toLowerCase()
|
|
127
|
-
if (!toolName) return false
|
|
128
|
-
|
|
129
|
-
switch (toolName) {
|
|
130
|
-
case 'edit':
|
|
131
|
-
case 'write':
|
|
132
|
-
return this.config.capture.fileEdits
|
|
133
|
-
case 'bash':
|
|
134
|
-
return this.config.capture.bashCommands
|
|
135
|
-
default:
|
|
136
|
-
return this.config.capture.toolUse
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Enrich technologies by scanning content text for known tech names */
|
|
141
|
-
private enrichTechnologies(knowledge: CapturedKnowledge): string[] {
|
|
142
|
-
const existing = new Set(knowledge.technologies)
|
|
143
|
-
const lower = knowledge.content.toLowerCase()
|
|
144
|
-
const words = lower.split(/[\s,;:()[\]{}"'`|/\\]+/)
|
|
145
|
-
|
|
146
|
-
for (const word of words) {
|
|
147
|
-
const cleaned = word.replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '')
|
|
148
|
-
if (cleaned.length < 2) continue
|
|
149
|
-
|
|
150
|
-
if (COMMON_TECH.has(cleaned) && !existing.has(cleaned)) {
|
|
151
|
-
existing.add(cleaned)
|
|
152
|
-
}
|
|
153
|
-
const alias = TECH_ALIASES[cleaned]
|
|
154
|
-
if (alias && !existing.has(alias)) {
|
|
155
|
-
existing.add(alias)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Check multi-word aliases
|
|
160
|
-
for (const [alias, normalized] of Object.entries(TECH_ALIASES)) {
|
|
161
|
-
if ((alias.includes('.') || alias.includes('-')) && lower.includes(alias) && !existing.has(normalized)) {
|
|
162
|
-
existing.add(normalized)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return Array.from(existing)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Phase 17: Capture Engine
|
|
3
|
+
* Orchestrates passive classification + entity extraction with privacy filters.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HookInput, CapturedKnowledge } from './types'
|
|
7
|
+
import type { HooksConfig } from '@/config/schema'
|
|
8
|
+
import { PassiveClassifier } from './passive-classifier'
|
|
9
|
+
|
|
10
|
+
// Reuse tech dictionaries from entity extractor for enrichment
|
|
11
|
+
const COMMON_TECH: Set<string> = new Set([
|
|
12
|
+
'typescript', 'javascript', 'python', 'rust', 'go', 'java', 'ruby', 'php', 'swift', 'kotlin',
|
|
13
|
+
'react', 'vue', 'angular', 'svelte', 'nextjs', 'nuxt', 'remix', 'astro', 'solid',
|
|
14
|
+
'express', 'fastify', 'hono', 'nestjs', 'django', 'flask', 'fastapi', 'rails', 'spring',
|
|
15
|
+
'mongodb', 'redis', 'postgresql', 'postgres', 'mysql', 'sqlite', 'dynamodb', 'firebase', 'supabase',
|
|
16
|
+
'prisma', 'drizzle', 'typeorm', 'sequelize', 'chromadb', 'pinecone',
|
|
17
|
+
'docker', 'kubernetes', 'aws', 'gcp', 'azure', 'vercel', 'netlify',
|
|
18
|
+
'webpack', 'vite', 'esbuild', 'bun', 'deno', 'node', 'npm', 'yarn', 'pnpm',
|
|
19
|
+
'jest', 'vitest', 'cypress', 'playwright',
|
|
20
|
+
'tailwind', 'bootstrap', 'zod', 'trpc', 'graphql', 'rest',
|
|
21
|
+
'jwt', 'oauth', 'openai', 'anthropic', 'langchain',
|
|
22
|
+
'git', 'github', 'gitlab', 'eslint', 'prettier',
|
|
23
|
+
'zustand', 'redux', 'pinia', 'mobx', 'jotai', 'recoil',
|
|
24
|
+
'storybook', 'turborepo', 'nx',
|
|
25
|
+
'microservices', 'serverless', 'monolith', 'ssr', 'ssg', 'spa', 'pwa', 'mcp', 'rag'
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
const TECH_ALIASES: Record<string, string> = {
|
|
29
|
+
'ts': 'typescript', 'js': 'javascript', 'py': 'python',
|
|
30
|
+
'react.js': 'react', 'reactjs': 'react', 'vue.js': 'vue', 'vuejs': 'vue',
|
|
31
|
+
'next.js': 'nextjs', 'nuxt.js': 'nuxt', 'nest.js': 'nestjs',
|
|
32
|
+
'express.js': 'express', 'node.js': 'node', 'nodejs': 'node',
|
|
33
|
+
'mongo': 'mongodb', 'pg': 'postgresql', 'k8s': 'kubernetes',
|
|
34
|
+
'tailwindcss': 'tailwind', 'tailwind-css': 'tailwind',
|
|
35
|
+
'gql': 'graphql', 'golang': 'go',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Phase 20: Default privacy ignore paths for sensitive files */
|
|
39
|
+
const DEFAULT_IGNORE_PATHS = [
|
|
40
|
+
'node_modules/**', '.env*', '*.key', '*.pem', '*.p12', '*.pfx',
|
|
41
|
+
'.git/**', 'dist/**', 'build/**', '*.secret', 'credentials*',
|
|
42
|
+
'.aws/**', '.ssh/**'
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
export class BrainCapture {
|
|
46
|
+
private classifier: PassiveClassifier
|
|
47
|
+
private config: HooksConfig
|
|
48
|
+
|
|
49
|
+
constructor(config?: Partial<HooksConfig>) {
|
|
50
|
+
this.config = {
|
|
51
|
+
enabled: config?.enabled ?? true,
|
|
52
|
+
capture: {
|
|
53
|
+
toolUse: config?.capture?.toolUse ?? true,
|
|
54
|
+
fileEdits: config?.capture?.fileEdits ?? true,
|
|
55
|
+
bashCommands: config?.capture?.bashCommands ?? true,
|
|
56
|
+
userMessages: config?.capture?.userMessages ?? true,
|
|
57
|
+
},
|
|
58
|
+
privacy: {
|
|
59
|
+
ignorePaths: config?.privacy?.ignorePaths ?? DEFAULT_IGNORE_PATHS,
|
|
60
|
+
ignoreProjects: config?.privacy?.ignoreProjects ?? [],
|
|
61
|
+
minConfidence: config?.privacy?.minConfidence ?? 0.7,
|
|
62
|
+
},
|
|
63
|
+
sessions: {
|
|
64
|
+
enabled: config?.sessions?.enabled ?? true,
|
|
65
|
+
idleTimeoutMinutes: config?.sessions?.idleTimeoutMinutes ?? 30,
|
|
66
|
+
minEventsForSummary: config?.sessions?.minEventsForSummary ?? 3,
|
|
67
|
+
},
|
|
68
|
+
deduplication: {
|
|
69
|
+
skipThreshold: config?.deduplication?.skipThreshold ?? 0.95,
|
|
70
|
+
mergeThreshold: config?.deduplication?.mergeThreshold ?? 0.85,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
this.classifier = new PassiveClassifier()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Process a hook input event.
|
|
78
|
+
* Returns captured knowledge or null if nothing worth capturing.
|
|
79
|
+
*/
|
|
80
|
+
process(input: HookInput): CapturedKnowledge | null {
|
|
81
|
+
if (!this.config.enabled) return null
|
|
82
|
+
|
|
83
|
+
// Privacy: check ignored paths
|
|
84
|
+
if (this.isPathIgnored(input.cwd)) return null
|
|
85
|
+
|
|
86
|
+
// Check capture toggles by tool type
|
|
87
|
+
if (!this.shouldCapture(input)) return null
|
|
88
|
+
|
|
89
|
+
// Classify tool output
|
|
90
|
+
const knowledge = this.classifier.classify(input)
|
|
91
|
+
if (!knowledge) return null
|
|
92
|
+
|
|
93
|
+
// Privacy: check ignored projects
|
|
94
|
+
if (knowledge.project && this.config.privacy.ignoreProjects.includes(knowledge.project)) {
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Enrich with additional technology detection from content
|
|
99
|
+
knowledge.technologies = this.enrichTechnologies(knowledge)
|
|
100
|
+
|
|
101
|
+
// Filter by minimum confidence
|
|
102
|
+
if (knowledge.confidence < this.config.privacy.minConfidence) {
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return knowledge
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Check if a path matches any ignore pattern */
|
|
110
|
+
private isPathIgnored(cwd: string): boolean {
|
|
111
|
+
if (!cwd || this.config.privacy.ignorePaths.length === 0) return false
|
|
112
|
+
const lowerCwd = cwd.toLowerCase()
|
|
113
|
+
return this.config.privacy.ignorePaths.some(pattern => {
|
|
114
|
+
const lowerPattern = pattern.toLowerCase()
|
|
115
|
+
// Simple glob: just check if pattern appears in path
|
|
116
|
+
if (lowerPattern.includes('*')) {
|
|
117
|
+
const regex = new RegExp(lowerPattern.replace(/\*/g, '.*'))
|
|
118
|
+
return regex.test(lowerCwd)
|
|
119
|
+
}
|
|
120
|
+
return lowerCwd.includes(lowerPattern)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Check if this tool type should be captured based on config */
|
|
125
|
+
private shouldCapture(input: HookInput): boolean {
|
|
126
|
+
const toolName = input.tool_name?.toLowerCase()
|
|
127
|
+
if (!toolName) return false
|
|
128
|
+
|
|
129
|
+
switch (toolName) {
|
|
130
|
+
case 'edit':
|
|
131
|
+
case 'write':
|
|
132
|
+
return this.config.capture.fileEdits
|
|
133
|
+
case 'bash':
|
|
134
|
+
return this.config.capture.bashCommands
|
|
135
|
+
default:
|
|
136
|
+
return this.config.capture.toolUse
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Enrich technologies by scanning content text for known tech names */
|
|
141
|
+
private enrichTechnologies(knowledge: CapturedKnowledge): string[] {
|
|
142
|
+
const existing = new Set(knowledge.technologies)
|
|
143
|
+
const lower = knowledge.content.toLowerCase()
|
|
144
|
+
const words = lower.split(/[\s,;:()[\]{}"'`|/\\]+/)
|
|
145
|
+
|
|
146
|
+
for (const word of words) {
|
|
147
|
+
const cleaned = word.replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '')
|
|
148
|
+
if (cleaned.length < 2) continue
|
|
149
|
+
|
|
150
|
+
if (COMMON_TECH.has(cleaned) && !existing.has(cleaned)) {
|
|
151
|
+
existing.add(cleaned)
|
|
152
|
+
}
|
|
153
|
+
const alias = TECH_ALIASES[cleaned]
|
|
154
|
+
if (alias && !existing.has(alias)) {
|
|
155
|
+
existing.add(alias)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check multi-word aliases
|
|
160
|
+
for (const [alias, normalized] of Object.entries(TECH_ALIASES)) {
|
|
161
|
+
if ((alias.includes('.') || alias.includes('-')) && lower.includes(alias) && !existing.has(normalized)) {
|
|
162
|
+
existing.add(normalized)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return Array.from(existing)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 17: Smart Deduplicator
|
|
3
|
-
* Three-tier dedup before storage:
|
|
4
|
-
* >0.95 similarity → skip (exact duplicate)
|
|
5
|
-
* 0.85–0.95 similarity → merge (update existing)
|
|
6
|
-
* <0.85 similarity → store_new
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { MemoryManager } from '@/memory'
|
|
10
|
-
import type { CapturedKnowledge, StoreAction } from './types'
|
|
11
|
-
import type { HooksConfig } from '@/config/schema'
|
|
12
|
-
|
|
13
|
-
export class SmartDeduplicator {
|
|
14
|
-
private skipThreshold: number
|
|
15
|
-
private mergeThreshold: number
|
|
16
|
-
|
|
17
|
-
constructor(config?: HooksConfig['deduplication']) {
|
|
18
|
-
this.skipThreshold = config?.skipThreshold ?? 0.95
|
|
19
|
-
this.mergeThreshold = config?.mergeThreshold ?? 0.85
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Check captured knowledge against existing memory
|
|
24
|
-
* and decide: store_new, merge, or skip
|
|
25
|
-
*/
|
|
26
|
-
async beforeStore(
|
|
27
|
-
knowledge: CapturedKnowledge,
|
|
28
|
-
memoryManager: MemoryManager
|
|
29
|
-
): Promise<StoreAction> {
|
|
30
|
-
try {
|
|
31
|
-
const results = await memoryManager.searchRaw(knowledge.content, {
|
|
32
|
-
project: knowledge.project,
|
|
33
|
-
limit: 3,
|
|
34
|
-
minSimilarity: this.mergeThreshold,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
if (!results || results.length === 0) {
|
|
38
|
-
return { action: 'store_new' }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const topResult = results[0]
|
|
42
|
-
const similarity = topResult.similarity ?? 0
|
|
43
|
-
|
|
44
|
-
if (similarity >= this.skipThreshold) {
|
|
45
|
-
return {
|
|
46
|
-
action: 'skip',
|
|
47
|
-
reason: `Duplicate (similarity: ${similarity.toFixed(3)})`,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (similarity >= this.mergeThreshold) {
|
|
52
|
-
const existingId = topResult.memory?.id || topResult.id
|
|
53
|
-
const existingContent = topResult.memory?.content ||
|
|
54
|
-
topResult.decision?.decision ||
|
|
55
|
-
''
|
|
56
|
-
const datestamp = new Date().toISOString().split('T')[0]
|
|
57
|
-
const mergedContent = `${existingContent}\n[Updated ${datestamp}]: ${knowledge.content}`
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
action: 'merge',
|
|
61
|
-
existingId,
|
|
62
|
-
mergedContent,
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return { action: 'store_new' }
|
|
67
|
-
} catch {
|
|
68
|
-
// If search fails, store as new to avoid data loss
|
|
69
|
-
return { action: 'store_new' }
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Phase 17: Smart Deduplicator
|
|
3
|
+
* Three-tier dedup before storage:
|
|
4
|
+
* >0.95 similarity → skip (exact duplicate)
|
|
5
|
+
* 0.85–0.95 similarity → merge (update existing)
|
|
6
|
+
* <0.85 similarity → store_new
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { MemoryManager } from '@/memory'
|
|
10
|
+
import type { CapturedKnowledge, StoreAction } from './types'
|
|
11
|
+
import type { HooksConfig } from '@/config/schema'
|
|
12
|
+
|
|
13
|
+
export class SmartDeduplicator {
|
|
14
|
+
private skipThreshold: number
|
|
15
|
+
private mergeThreshold: number
|
|
16
|
+
|
|
17
|
+
constructor(config?: HooksConfig['deduplication']) {
|
|
18
|
+
this.skipThreshold = config?.skipThreshold ?? 0.95
|
|
19
|
+
this.mergeThreshold = config?.mergeThreshold ?? 0.85
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Check captured knowledge against existing memory
|
|
24
|
+
* and decide: store_new, merge, or skip
|
|
25
|
+
*/
|
|
26
|
+
async beforeStore(
|
|
27
|
+
knowledge: CapturedKnowledge,
|
|
28
|
+
memoryManager: MemoryManager
|
|
29
|
+
): Promise<StoreAction> {
|
|
30
|
+
try {
|
|
31
|
+
const results = await memoryManager.searchRaw(knowledge.content, {
|
|
32
|
+
project: knowledge.project,
|
|
33
|
+
limit: 3,
|
|
34
|
+
minSimilarity: this.mergeThreshold,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
if (!results || results.length === 0) {
|
|
38
|
+
return { action: 'store_new' }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const topResult = results[0]
|
|
42
|
+
const similarity = topResult.similarity ?? 0
|
|
43
|
+
|
|
44
|
+
if (similarity >= this.skipThreshold) {
|
|
45
|
+
return {
|
|
46
|
+
action: 'skip',
|
|
47
|
+
reason: `Duplicate (similarity: ${similarity.toFixed(3)})`,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (similarity >= this.mergeThreshold) {
|
|
52
|
+
const existingId = topResult.memory?.id || topResult.id
|
|
53
|
+
const existingContent = topResult.memory?.content ||
|
|
54
|
+
topResult.decision?.decision ||
|
|
55
|
+
''
|
|
56
|
+
const datestamp = new Date().toISOString().split('T')[0]
|
|
57
|
+
const mergedContent = `${existingContent}\n[Updated ${datestamp}]: ${knowledge.content}`
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
action: 'merge',
|
|
61
|
+
existingId,
|
|
62
|
+
mergedContent,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { action: 'store_new' }
|
|
67
|
+
} catch {
|
|
68
|
+
// If search fails, store as new to avoid data loss
|
|
69
|
+
return { action: 'store_new' }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|