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/config/loader.ts
CHANGED
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
import { config as loadEnv } from 'dotenv'
|
|
4
|
-
import { ConfigSchema, type Config, type PartialConfig } from './schema'
|
|
5
|
-
import { defaultConfig } from './defaults'
|
|
6
|
-
import { getClaudeBrainHome, resolveHomePath } from './home'
|
|
7
|
-
|
|
8
|
-
const CONFIG_FILE_NAME = '.claudebrainrc.json'
|
|
9
|
-
|
|
10
|
-
/** Load configuration from a JSON file if it exists */
|
|
11
|
-
function loadFromFile(basePath: string): PartialConfig {
|
|
12
|
-
// Check basePath first, then Claude Brain home
|
|
13
|
-
for (const dir of [basePath, getClaudeBrainHome()]) {
|
|
14
|
-
const configPath = resolve(dir, CONFIG_FILE_NAME)
|
|
15
|
-
if (!existsSync(configPath)) {
|
|
16
|
-
continue
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const content = readFileSync(configPath, 'utf-8')
|
|
21
|
-
return JSON.parse(content) as PartialConfig
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.warn(`Warning: Failed to parse config file at ${configPath}:`, error)
|
|
24
|
-
return {}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return {}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Load configuration from environment variables */
|
|
32
|
-
function loadFromEnv(): PartialConfig {
|
|
33
|
-
// Skip .env loading if SKIP_DOTENV is set (for MCP servers where env is provided externally)
|
|
34
|
-
if (!process.env.SKIP_DOTENV) {
|
|
35
|
-
// Load .env from Claude Brain home directory
|
|
36
|
-
loadEnv({ path: resolve(getClaudeBrainHome(), '.env'), debug: false })
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const config: PartialConfig = {}
|
|
40
|
-
|
|
41
|
-
if (process.env.VAULT_PATH) {
|
|
42
|
-
config.vaultPath = process.env.VAULT_PATH
|
|
43
|
-
}
|
|
44
|
-
if (process.env.MCP_SERVER_NAME) {
|
|
45
|
-
config.serverName = process.env.MCP_SERVER_NAME
|
|
46
|
-
}
|
|
47
|
-
if (process.env.MCP_SERVER_VERSION) {
|
|
48
|
-
config.serverVersion = process.env.MCP_SERVER_VERSION
|
|
49
|
-
}
|
|
50
|
-
if (process.env.LOG_LEVEL) {
|
|
51
|
-
config.logLevel = process.env.LOG_LEVEL as Config['logLevel']
|
|
52
|
-
}
|
|
53
|
-
if (process.env.LOG_FILE_PATH) {
|
|
54
|
-
config.logFilePath = process.env.LOG_FILE_PATH
|
|
55
|
-
}
|
|
56
|
-
if (process.env.DB_PATH) {
|
|
57
|
-
config.dbPath = process.env.DB_PATH
|
|
58
|
-
}
|
|
59
|
-
if (process.env.PORT) {
|
|
60
|
-
config.port = parseInt(process.env.PORT, 10)
|
|
61
|
-
}
|
|
62
|
-
if (process.env.ENABLE_FILE_WATCH) {
|
|
63
|
-
config.enableFileWatch = process.env.ENABLE_FILE_WATCH === 'true'
|
|
64
|
-
}
|
|
65
|
-
if (process.env.CACHE_SIZE) {
|
|
66
|
-
config.cacheSize = parseInt(process.env.CACHE_SIZE, 10)
|
|
67
|
-
}
|
|
68
|
-
if (process.env.NODE_ENV) {
|
|
69
|
-
config.nodeEnv = process.env.NODE_ENV as Config['nodeEnv']
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Retrieval configuration
|
|
73
|
-
if (process.env.RETRIEVAL_ENABLED) {
|
|
74
|
-
config.retrieval = config.retrieval || {}
|
|
75
|
-
config.retrieval.enabled = process.env.RETRIEVAL_ENABLED === 'true'
|
|
76
|
-
}
|
|
77
|
-
if (process.env.RETRIEVAL_DENSE_WEIGHT) {
|
|
78
|
-
config.retrieval = config.retrieval || {}
|
|
79
|
-
config.retrieval.dense = config.retrieval.dense || {}
|
|
80
|
-
config.retrieval.dense.weight = parseFloat(process.env.RETRIEVAL_DENSE_WEIGHT)
|
|
81
|
-
}
|
|
82
|
-
if (process.env.RETRIEVAL_SPARSE_ENABLED) {
|
|
83
|
-
config.retrieval = config.retrieval || {}
|
|
84
|
-
config.retrieval.sparse = config.retrieval.sparse || {}
|
|
85
|
-
config.retrieval.sparse.enabled = process.env.RETRIEVAL_SPARSE_ENABLED === 'true'
|
|
86
|
-
}
|
|
87
|
-
if (process.env.RETRIEVAL_SPARSE_WEIGHT) {
|
|
88
|
-
config.retrieval = config.retrieval || {}
|
|
89
|
-
config.retrieval.sparse = config.retrieval.sparse || {}
|
|
90
|
-
config.retrieval.sparse.weight = parseFloat(process.env.RETRIEVAL_SPARSE_WEIGHT)
|
|
91
|
-
}
|
|
92
|
-
if (process.env.RETRIEVAL_FUSION_METHOD) {
|
|
93
|
-
config.retrieval = config.retrieval || {}
|
|
94
|
-
config.retrieval.fusion = config.retrieval.fusion || {}
|
|
95
|
-
config.retrieval.fusion.method = process.env.RETRIEVAL_FUSION_METHOD as 'rrf' | 'linear' | 'max'
|
|
96
|
-
}
|
|
97
|
-
if (process.env.RETRIEVAL_RRF_K) {
|
|
98
|
-
config.retrieval = config.retrieval || {}
|
|
99
|
-
config.retrieval.fusion = config.retrieval.fusion || {}
|
|
100
|
-
config.retrieval.fusion.rrfK = parseInt(process.env.RETRIEVAL_RRF_K, 10)
|
|
101
|
-
}
|
|
102
|
-
if (process.env.RETRIEVAL_RERANKER_ENABLED) {
|
|
103
|
-
config.retrieval = config.retrieval || {}
|
|
104
|
-
config.retrieval.reranker = config.retrieval.reranker || {}
|
|
105
|
-
config.retrieval.reranker.enabled = process.env.RETRIEVAL_RERANKER_ENABLED === 'true'
|
|
106
|
-
}
|
|
107
|
-
if (process.env.RETRIEVAL_RERANKER_MODEL) {
|
|
108
|
-
config.retrieval = config.retrieval || {}
|
|
109
|
-
config.retrieval.reranker = config.retrieval.reranker || {}
|
|
110
|
-
config.retrieval.reranker.model = process.env.RETRIEVAL_RERANKER_MODEL
|
|
111
|
-
}
|
|
112
|
-
if (process.env.RETRIEVAL_FEEDBACK_ENABLED) {
|
|
113
|
-
config.retrieval = config.retrieval || {}
|
|
114
|
-
config.retrieval.feedback = config.retrieval.feedback || {}
|
|
115
|
-
config.retrieval.feedback.enabled = process.env.RETRIEVAL_FEEDBACK_ENABLED === 'true'
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return config
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Merge multiple partial configs, later values override earlier */
|
|
122
|
-
function mergeConfigs(...configs: PartialConfig[]): PartialConfig {
|
|
123
|
-
return configs.reduce((acc, config) => {
|
|
124
|
-
return { ...acc, ...Object.fromEntries(Object.entries(config).filter(([_, v]) => v !== undefined)) }
|
|
125
|
-
}, {})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Load and validate configuration from all sources */
|
|
129
|
-
export async function loadConfig(basePath: string = process.cwd()): Promise<Config> {
|
|
130
|
-
const fileConfig = loadFromFile(basePath)
|
|
131
|
-
const envConfig = loadFromEnv()
|
|
132
|
-
|
|
133
|
-
const merged = mergeConfigs(defaultConfig, fileConfig, envConfig)
|
|
134
|
-
|
|
135
|
-
const result = ConfigSchema.safeParse(merged)
|
|
136
|
-
|
|
137
|
-
if (!result.success) {
|
|
138
|
-
const errors = result.error.errors
|
|
139
|
-
.map(e => ` - ${e.path.join('.')}: ${e.message}`)
|
|
140
|
-
.join('\n')
|
|
141
|
-
throw new Error(`Configuration validation failed:\n${errors}`)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Resolve relative paths against Claude Brain home
|
|
145
|
-
const data = result.data
|
|
146
|
-
data.logFilePath = resolveHomePath(data.logFilePath)
|
|
147
|
-
data.dbPath = resolveHomePath(data.dbPath)
|
|
148
|
-
if (data.chroma.path) {
|
|
149
|
-
data.chroma.path = resolveHomePath(data.chroma.path)
|
|
150
|
-
}
|
|
151
|
-
if (data.knowledge?.graph?.persistPath) {
|
|
152
|
-
data.knowledge.graph.persistPath = resolveHomePath(data.knowledge.graph.persistPath)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return data
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/** Validate a partial configuration object */
|
|
159
|
-
export function validateConfig(config: unknown): config is Config {
|
|
160
|
-
return ConfigSchema.safeParse(config).success
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** Get the path to the config file */
|
|
164
|
-
export function getConfigFilePath(basePath: string = process.cwd()): string {
|
|
165
|
-
return resolve(basePath, CONFIG_FILE_NAME)
|
|
166
|
-
}
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { config as loadEnv } from 'dotenv'
|
|
4
|
+
import { ConfigSchema, type Config, type PartialConfig } from './schema'
|
|
5
|
+
import { defaultConfig } from './defaults'
|
|
6
|
+
import { getClaudeBrainHome, resolveHomePath } from './home'
|
|
7
|
+
|
|
8
|
+
const CONFIG_FILE_NAME = '.claudebrainrc.json'
|
|
9
|
+
|
|
10
|
+
/** Load configuration from a JSON file if it exists */
|
|
11
|
+
function loadFromFile(basePath: string): PartialConfig {
|
|
12
|
+
// Check basePath first, then Claude Brain home
|
|
13
|
+
for (const dir of [basePath, getClaudeBrainHome()]) {
|
|
14
|
+
const configPath = resolve(dir, CONFIG_FILE_NAME)
|
|
15
|
+
if (!existsSync(configPath)) {
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const content = readFileSync(configPath, 'utf-8')
|
|
21
|
+
return JSON.parse(content) as PartialConfig
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.warn(`Warning: Failed to parse config file at ${configPath}:`, error)
|
|
24
|
+
return {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Load configuration from environment variables */
|
|
32
|
+
function loadFromEnv(): PartialConfig {
|
|
33
|
+
// Skip .env loading if SKIP_DOTENV is set (for MCP servers where env is provided externally)
|
|
34
|
+
if (!process.env.SKIP_DOTENV) {
|
|
35
|
+
// Load .env from Claude Brain home directory
|
|
36
|
+
loadEnv({ path: resolve(getClaudeBrainHome(), '.env'), debug: false })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const config: PartialConfig = {}
|
|
40
|
+
|
|
41
|
+
if (process.env.VAULT_PATH) {
|
|
42
|
+
config.vaultPath = process.env.VAULT_PATH
|
|
43
|
+
}
|
|
44
|
+
if (process.env.MCP_SERVER_NAME) {
|
|
45
|
+
config.serverName = process.env.MCP_SERVER_NAME
|
|
46
|
+
}
|
|
47
|
+
if (process.env.MCP_SERVER_VERSION) {
|
|
48
|
+
config.serverVersion = process.env.MCP_SERVER_VERSION
|
|
49
|
+
}
|
|
50
|
+
if (process.env.LOG_LEVEL) {
|
|
51
|
+
config.logLevel = process.env.LOG_LEVEL as Config['logLevel']
|
|
52
|
+
}
|
|
53
|
+
if (process.env.LOG_FILE_PATH) {
|
|
54
|
+
config.logFilePath = process.env.LOG_FILE_PATH
|
|
55
|
+
}
|
|
56
|
+
if (process.env.DB_PATH) {
|
|
57
|
+
config.dbPath = process.env.DB_PATH
|
|
58
|
+
}
|
|
59
|
+
if (process.env.PORT) {
|
|
60
|
+
config.port = parseInt(process.env.PORT, 10)
|
|
61
|
+
}
|
|
62
|
+
if (process.env.ENABLE_FILE_WATCH) {
|
|
63
|
+
config.enableFileWatch = process.env.ENABLE_FILE_WATCH === 'true'
|
|
64
|
+
}
|
|
65
|
+
if (process.env.CACHE_SIZE) {
|
|
66
|
+
config.cacheSize = parseInt(process.env.CACHE_SIZE, 10)
|
|
67
|
+
}
|
|
68
|
+
if (process.env.NODE_ENV) {
|
|
69
|
+
config.nodeEnv = process.env.NODE_ENV as Config['nodeEnv']
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Retrieval configuration
|
|
73
|
+
if (process.env.RETRIEVAL_ENABLED) {
|
|
74
|
+
config.retrieval = config.retrieval || {}
|
|
75
|
+
config.retrieval.enabled = process.env.RETRIEVAL_ENABLED === 'true'
|
|
76
|
+
}
|
|
77
|
+
if (process.env.RETRIEVAL_DENSE_WEIGHT) {
|
|
78
|
+
config.retrieval = config.retrieval || {}
|
|
79
|
+
config.retrieval.dense = config.retrieval.dense || {}
|
|
80
|
+
config.retrieval.dense.weight = parseFloat(process.env.RETRIEVAL_DENSE_WEIGHT)
|
|
81
|
+
}
|
|
82
|
+
if (process.env.RETRIEVAL_SPARSE_ENABLED) {
|
|
83
|
+
config.retrieval = config.retrieval || {}
|
|
84
|
+
config.retrieval.sparse = config.retrieval.sparse || {}
|
|
85
|
+
config.retrieval.sparse.enabled = process.env.RETRIEVAL_SPARSE_ENABLED === 'true'
|
|
86
|
+
}
|
|
87
|
+
if (process.env.RETRIEVAL_SPARSE_WEIGHT) {
|
|
88
|
+
config.retrieval = config.retrieval || {}
|
|
89
|
+
config.retrieval.sparse = config.retrieval.sparse || {}
|
|
90
|
+
config.retrieval.sparse.weight = parseFloat(process.env.RETRIEVAL_SPARSE_WEIGHT)
|
|
91
|
+
}
|
|
92
|
+
if (process.env.RETRIEVAL_FUSION_METHOD) {
|
|
93
|
+
config.retrieval = config.retrieval || {}
|
|
94
|
+
config.retrieval.fusion = config.retrieval.fusion || {}
|
|
95
|
+
config.retrieval.fusion.method = process.env.RETRIEVAL_FUSION_METHOD as 'rrf' | 'linear' | 'max'
|
|
96
|
+
}
|
|
97
|
+
if (process.env.RETRIEVAL_RRF_K) {
|
|
98
|
+
config.retrieval = config.retrieval || {}
|
|
99
|
+
config.retrieval.fusion = config.retrieval.fusion || {}
|
|
100
|
+
config.retrieval.fusion.rrfK = parseInt(process.env.RETRIEVAL_RRF_K, 10)
|
|
101
|
+
}
|
|
102
|
+
if (process.env.RETRIEVAL_RERANKER_ENABLED) {
|
|
103
|
+
config.retrieval = config.retrieval || {}
|
|
104
|
+
config.retrieval.reranker = config.retrieval.reranker || {}
|
|
105
|
+
config.retrieval.reranker.enabled = process.env.RETRIEVAL_RERANKER_ENABLED === 'true'
|
|
106
|
+
}
|
|
107
|
+
if (process.env.RETRIEVAL_RERANKER_MODEL) {
|
|
108
|
+
config.retrieval = config.retrieval || {}
|
|
109
|
+
config.retrieval.reranker = config.retrieval.reranker || {}
|
|
110
|
+
config.retrieval.reranker.model = process.env.RETRIEVAL_RERANKER_MODEL
|
|
111
|
+
}
|
|
112
|
+
if (process.env.RETRIEVAL_FEEDBACK_ENABLED) {
|
|
113
|
+
config.retrieval = config.retrieval || {}
|
|
114
|
+
config.retrieval.feedback = config.retrieval.feedback || {}
|
|
115
|
+
config.retrieval.feedback.enabled = process.env.RETRIEVAL_FEEDBACK_ENABLED === 'true'
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return config
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Merge multiple partial configs, later values override earlier */
|
|
122
|
+
function mergeConfigs(...configs: PartialConfig[]): PartialConfig {
|
|
123
|
+
return configs.reduce((acc, config) => {
|
|
124
|
+
return { ...acc, ...Object.fromEntries(Object.entries(config).filter(([_, v]) => v !== undefined)) }
|
|
125
|
+
}, {})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Load and validate configuration from all sources */
|
|
129
|
+
export async function loadConfig(basePath: string = process.cwd()): Promise<Config> {
|
|
130
|
+
const fileConfig = loadFromFile(basePath)
|
|
131
|
+
const envConfig = loadFromEnv()
|
|
132
|
+
|
|
133
|
+
const merged = mergeConfigs(defaultConfig, fileConfig, envConfig)
|
|
134
|
+
|
|
135
|
+
const result = ConfigSchema.safeParse(merged)
|
|
136
|
+
|
|
137
|
+
if (!result.success) {
|
|
138
|
+
const errors = result.error.errors
|
|
139
|
+
.map(e => ` - ${e.path.join('.')}: ${e.message}`)
|
|
140
|
+
.join('\n')
|
|
141
|
+
throw new Error(`Configuration validation failed:\n${errors}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Resolve relative paths against Claude Brain home
|
|
145
|
+
const data = result.data
|
|
146
|
+
data.logFilePath = resolveHomePath(data.logFilePath)
|
|
147
|
+
data.dbPath = resolveHomePath(data.dbPath)
|
|
148
|
+
if (data.chroma.path) {
|
|
149
|
+
data.chroma.path = resolveHomePath(data.chroma.path)
|
|
150
|
+
}
|
|
151
|
+
if (data.knowledge?.graph?.persistPath) {
|
|
152
|
+
data.knowledge.graph.persistPath = resolveHomePath(data.knowledge.graph.persistPath)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return data
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Validate a partial configuration object */
|
|
159
|
+
export function validateConfig(config: unknown): config is Config {
|
|
160
|
+
return ConfigSchema.safeParse(config).success
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Get the path to the config file */
|
|
164
|
+
export function getConfigFilePath(basePath: string = process.cwd()): string {
|
|
165
|
+
return resolve(basePath, CONFIG_FILE_NAME)
|
|
166
|
+
}
|
package/src/config/migration.ts
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import fs from 'fs/promises'
|
|
2
|
-
import type { Logger } from 'pino'
|
|
3
|
-
|
|
4
|
-
export interface ConfigVersion {
|
|
5
|
-
version: string
|
|
6
|
-
config: Record<string, any>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class ConfigMigration {
|
|
10
|
-
private logger: Logger
|
|
11
|
-
private currentVersion = '1.0.0'
|
|
12
|
-
|
|
13
|
-
constructor(logger: Logger) {
|
|
14
|
-
this.logger = logger.child({ component: 'config-migration' })
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async migrate(config: any): Promise<any> {
|
|
18
|
-
const configVersion = config.version || '0.0.0'
|
|
19
|
-
|
|
20
|
-
if (configVersion === this.currentVersion) {
|
|
21
|
-
return config
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
this.logger.info(
|
|
25
|
-
{ from: configVersion, to: this.currentVersion },
|
|
26
|
-
'Migrating configuration'
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
await this.backup(config)
|
|
30
|
-
|
|
31
|
-
let migrated = { ...config }
|
|
32
|
-
|
|
33
|
-
if (this.compareVersions(configVersion, '1.0.0') < 0) {
|
|
34
|
-
migrated = await this.migrateTo_1_0_0(migrated)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
migrated.version = this.currentVersion
|
|
38
|
-
|
|
39
|
-
return migrated
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private async migrateTo_1_0_0(config: any): Promise<any> {
|
|
43
|
-
this.logger.info('Migrating to version 1.0.0')
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
...config,
|
|
47
|
-
enableFileWatch: config.enableFileWatch ?? true,
|
|
48
|
-
serverVersion: config.serverVersion || '1.0.0'
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private async backup(config: any): Promise<void> {
|
|
53
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
54
|
-
const backupPath = `./data/config-backup-${timestamp}.json`
|
|
55
|
-
|
|
56
|
-
await fs.writeFile(
|
|
57
|
-
backupPath,
|
|
58
|
-
JSON.stringify(config, null, 2),
|
|
59
|
-
'utf-8'
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
this.logger.info({ backupPath }, 'Configuration backed up')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private compareVersions(v1: string, v2: string): number {
|
|
66
|
-
const parts1 = v1.split('.').map(Number)
|
|
67
|
-
const parts2 = v2.split('.').map(Number)
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < 3; i++) {
|
|
70
|
-
if (parts1[i] > parts2[i]) return 1
|
|
71
|
-
if (parts1[i] < parts2[i]) return -1
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return 0
|
|
75
|
-
}
|
|
76
|
-
}
|
|
1
|
+
import fs from 'fs/promises'
|
|
2
|
+
import type { Logger } from 'pino'
|
|
3
|
+
|
|
4
|
+
export interface ConfigVersion {
|
|
5
|
+
version: string
|
|
6
|
+
config: Record<string, any>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ConfigMigration {
|
|
10
|
+
private logger: Logger
|
|
11
|
+
private currentVersion = '1.0.0'
|
|
12
|
+
|
|
13
|
+
constructor(logger: Logger) {
|
|
14
|
+
this.logger = logger.child({ component: 'config-migration' })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async migrate(config: any): Promise<any> {
|
|
18
|
+
const configVersion = config.version || '0.0.0'
|
|
19
|
+
|
|
20
|
+
if (configVersion === this.currentVersion) {
|
|
21
|
+
return config
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.logger.info(
|
|
25
|
+
{ from: configVersion, to: this.currentVersion },
|
|
26
|
+
'Migrating configuration'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
await this.backup(config)
|
|
30
|
+
|
|
31
|
+
let migrated = { ...config }
|
|
32
|
+
|
|
33
|
+
if (this.compareVersions(configVersion, '1.0.0') < 0) {
|
|
34
|
+
migrated = await this.migrateTo_1_0_0(migrated)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
migrated.version = this.currentVersion
|
|
38
|
+
|
|
39
|
+
return migrated
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async migrateTo_1_0_0(config: any): Promise<any> {
|
|
43
|
+
this.logger.info('Migrating to version 1.0.0')
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
...config,
|
|
47
|
+
enableFileWatch: config.enableFileWatch ?? true,
|
|
48
|
+
serverVersion: config.serverVersion || '1.0.0'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async backup(config: any): Promise<void> {
|
|
53
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
54
|
+
const backupPath = `./data/config-backup-${timestamp}.json`
|
|
55
|
+
|
|
56
|
+
await fs.writeFile(
|
|
57
|
+
backupPath,
|
|
58
|
+
JSON.stringify(config, null, 2),
|
|
59
|
+
'utf-8'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
this.logger.info({ backupPath }, 'Configuration backed up')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private compareVersions(v1: string, v2: string): number {
|
|
66
|
+
const parts1 = v1.split('.').map(Number)
|
|
67
|
+
const parts2 = v2.split('.').map(Number)
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < 3; i++) {
|
|
70
|
+
if (parts1[i] > parts2[i]) return 1
|
|
71
|
+
if (parts1[i] < parts2[i]) return -1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return 0
|
|
75
|
+
}
|
|
76
|
+
}
|