claude-brain 0.15.2 → 0.16.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 +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +29 -11
- package/bunfig.toml +8 -8
- package/package.json +82 -82
- 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/scripts/postinstall.mjs +341 -341
- 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 +209 -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/refresh.ts +323 -0
- package/src/cli/commands/serve.ts +167 -173
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +124 -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 +128 -112
- package/src/hooks/capture.ts +168 -205
- 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 +194 -194
- package/src/hooks/passive-classifier.ts +404 -723
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +312 -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 +155 -155
- 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 +450 -436
- package/src/routing/response-filter.ts +261 -258
- package/src/routing/router.ts +1441 -1322
- package/src/routing/search-engine.ts +515 -475
- package/src/routing/types.ts +94 -94
- 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 -129
- 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/cli/auto-update.ts +0 -157
package/src/config/home.ts
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
|
-
import { resolve, isAbsolute, join } from 'node:path'
|
|
3
|
-
import { homedir } from 'node:os'
|
|
4
|
-
|
|
5
|
-
const DEFAULT_HOME = join(homedir(), '.claude-brain')
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns the root path for Claude Brain's home directory.
|
|
9
|
-
* Uses CLAUDE_BRAIN_HOME env var if set, otherwise ~/.claude-brain/
|
|
10
|
-
*/
|
|
11
|
-
export function getClaudeBrainHome(): string {
|
|
12
|
-
const envHome = process.env.CLAUDE_BRAIN_HOME
|
|
13
|
-
if (envHome) {
|
|
14
|
-
return resolve(envHome)
|
|
15
|
-
}
|
|
16
|
-
return DEFAULT_HOME
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Resolves a relative path against the Claude Brain home directory.
|
|
21
|
-
* Absolute paths pass through unchanged.
|
|
22
|
-
*/
|
|
23
|
-
export function resolveHomePath(rel: string): string {
|
|
24
|
-
if (isAbsolute(rel)) {
|
|
25
|
-
return rel
|
|
26
|
-
}
|
|
27
|
-
return resolve(getClaudeBrainHome(), rel)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Checks if the home directory has been initialized (data/ exists).
|
|
32
|
-
*/
|
|
33
|
-
export function isHomeInitialized(): boolean {
|
|
34
|
-
return existsSync(join(getClaudeBrainHome(), 'data'))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Returns an object with all standard paths within the Claude Brain home directory.
|
|
39
|
-
*/
|
|
40
|
-
export function getHomePaths() {
|
|
41
|
-
const root = getClaudeBrainHome()
|
|
42
|
-
return {
|
|
43
|
-
root,
|
|
44
|
-
env: join(root, '.env'),
|
|
45
|
-
data: join(root, 'data'),
|
|
46
|
-
chroma: join(root, 'data', 'chroma'),
|
|
47
|
-
db: join(root, 'data', 'memory.db'),
|
|
48
|
-
knowledgeGraph: join(root, 'data', 'knowledge-graph.json'),
|
|
49
|
-
logs: join(root, 'logs'),
|
|
50
|
-
logFile: join(root, 'logs', 'claude-brain.log'),
|
|
51
|
-
vault: join(root, 'vault'),
|
|
52
|
-
vaultProjects: join(root, 'vault', 'Projects'),
|
|
53
|
-
vaultGlobal: join(root, 'vault', 'Global'),
|
|
54
|
-
}
|
|
55
|
-
}
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { resolve, isAbsolute, join } from 'node:path'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
|
|
5
|
+
const DEFAULT_HOME = join(homedir(), '.claude-brain')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns the root path for Claude Brain's home directory.
|
|
9
|
+
* Uses CLAUDE_BRAIN_HOME env var if set, otherwise ~/.claude-brain/
|
|
10
|
+
*/
|
|
11
|
+
export function getClaudeBrainHome(): string {
|
|
12
|
+
const envHome = process.env.CLAUDE_BRAIN_HOME
|
|
13
|
+
if (envHome) {
|
|
14
|
+
return resolve(envHome)
|
|
15
|
+
}
|
|
16
|
+
return DEFAULT_HOME
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resolves a relative path against the Claude Brain home directory.
|
|
21
|
+
* Absolute paths pass through unchanged.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveHomePath(rel: string): string {
|
|
24
|
+
if (isAbsolute(rel)) {
|
|
25
|
+
return rel
|
|
26
|
+
}
|
|
27
|
+
return resolve(getClaudeBrainHome(), rel)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks if the home directory has been initialized (data/ exists).
|
|
32
|
+
*/
|
|
33
|
+
export function isHomeInitialized(): boolean {
|
|
34
|
+
return existsSync(join(getClaudeBrainHome(), 'data'))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns an object with all standard paths within the Claude Brain home directory.
|
|
39
|
+
*/
|
|
40
|
+
export function getHomePaths() {
|
|
41
|
+
const root = getClaudeBrainHome()
|
|
42
|
+
return {
|
|
43
|
+
root,
|
|
44
|
+
env: join(root, '.env'),
|
|
45
|
+
data: join(root, 'data'),
|
|
46
|
+
chroma: join(root, 'data', 'chroma'),
|
|
47
|
+
db: join(root, 'data', 'memory.db'),
|
|
48
|
+
knowledgeGraph: join(root, 'data', 'knowledge-graph.json'),
|
|
49
|
+
logs: join(root, 'logs'),
|
|
50
|
+
logFile: join(root, 'logs', 'claude-brain.log'),
|
|
51
|
+
vault: join(root, 'vault'),
|
|
52
|
+
vaultProjects: join(root, 'vault', 'Projects'),
|
|
53
|
+
vaultGlobal: join(root, 'vault', 'Global'),
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/config/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { ConfigSchema, LogLevelSchema, type Config, type LogLevel, type PartialConfig } from './schema'
|
|
2
|
-
export { defaultConfig } from './defaults'
|
|
3
|
-
export { loadConfig, validateConfig, getConfigFilePath } from './loader'
|
|
4
|
-
export { ConfigWatcher, createConfigWatcher, type ConfigWatcherEvents } from './watcher'
|
|
5
|
-
export { ConfigValidator, type ValidationResult, type ValidationError, type ValidationWarning } from './validator'
|
|
6
|
-
export { ConfigMigration } from './migration'
|
|
7
|
-
export { getClaudeBrainHome, resolveHomePath, isHomeInitialized, getHomePaths } from './home'
|
|
1
|
+
export { ConfigSchema, LogLevelSchema, type Config, type LogLevel, type PartialConfig } from './schema'
|
|
2
|
+
export { defaultConfig } from './defaults'
|
|
3
|
+
export { loadConfig, validateConfig, getConfigFilePath } from './loader'
|
|
4
|
+
export { ConfigWatcher, createConfigWatcher, type ConfigWatcherEvents } from './watcher'
|
|
5
|
+
export { ConfigValidator, type ValidationResult, type ValidationError, type ValidationWarning } from './validator'
|
|
6
|
+
export { ConfigMigration } from './migration'
|
|
7
|
+
export { getClaudeBrainHome, resolveHomePath, isHomeInitialized, getHomePaths } from './home'
|
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
|
+
}
|