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/scripts/postinstall.mjs
CHANGED
|
@@ -1,341 +1,341 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Postinstall script for claude-brain.
|
|
5
|
-
* Runs automatically after `npm install -g claude-brain` or `bun install -g claude-brain`.
|
|
6
|
-
* Pure Node.js — no TypeScript, no path aliases, no Bun APIs.
|
|
7
|
-
* Always exits 0 so it never blocks the install.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { mkdirSync, writeFileSync, readFileSync, existsSync, renameSync } from 'node:fs'
|
|
11
|
-
import { join, dirname } from 'node:path'
|
|
12
|
-
import { homedir } from 'node:os'
|
|
13
|
-
import { execSync } from 'node:child_process'
|
|
14
|
-
import { fileURLToPath } from 'node:url'
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
17
|
-
const __dirname = dirname(__filename)
|
|
18
|
-
|
|
19
|
-
const PREFIX = '[claude-brain]'
|
|
20
|
-
const HOME = join(homedir(), '.claude-brain')
|
|
21
|
-
const CLAUDE_DIR = join(homedir(), '.claude')
|
|
22
|
-
const CLAUDE_SETTINGS = join(CLAUDE_DIR, 'settings.json')
|
|
23
|
-
const CLAUDE_MD_PATH = join(CLAUDE_DIR, 'CLAUDE.md')
|
|
24
|
-
const HOOK_MARKER = 'claude-brain-hook'
|
|
25
|
-
|
|
26
|
-
function log(msg) {
|
|
27
|
-
console.error(`${PREFIX} ${msg}`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── Step 0: Skip if not a global install ─────────────────
|
|
31
|
-
|
|
32
|
-
function shouldSkip() {
|
|
33
|
-
// CI environments
|
|
34
|
-
if (process.env.CI === 'true' || process.env.CI === '1') {
|
|
35
|
-
return 'CI environment detected'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// If we're inside a node_modules directory, it's a local install
|
|
39
|
-
const scriptDir = dirname(__filename)
|
|
40
|
-
if (scriptDir.includes('node_modules') && !scriptDir.includes('global')) {
|
|
41
|
-
// Check if this is actually a global install by looking deeper
|
|
42
|
-
// bun global installs go to ~/.bun/install/global/node_modules
|
|
43
|
-
// npm global installs go to /usr/local/lib/node_modules or ~/.npm-global
|
|
44
|
-
const isGlobalPath =
|
|
45
|
-
scriptDir.includes('.bun/install/global') ||
|
|
46
|
-
scriptDir.includes('/usr/local/lib/node_modules') ||
|
|
47
|
-
scriptDir.includes('/usr/lib/node_modules') ||
|
|
48
|
-
scriptDir.includes('npm-global') ||
|
|
49
|
-
scriptDir.includes('AppData/Roaming/npm')
|
|
50
|
-
|
|
51
|
-
if (!isGlobalPath) {
|
|
52
|
-
return 'local install (not global)'
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return null
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ── Step 1: Create ~/.claude-brain/ ──────────────────────
|
|
60
|
-
|
|
61
|
-
function setupHomeDirectory() {
|
|
62
|
-
if (existsSync(join(HOME, 'data'))) {
|
|
63
|
-
log('Home directory already initialized')
|
|
64
|
-
return true
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
log(`Setting up ${HOME}/...`)
|
|
68
|
-
|
|
69
|
-
const dirs = [
|
|
70
|
-
join(HOME, 'data'),
|
|
71
|
-
join(HOME, 'data', 'chroma'),
|
|
72
|
-
join(HOME, 'logs'),
|
|
73
|
-
join(HOME, 'vault'),
|
|
74
|
-
join(HOME, 'vault', 'Projects'),
|
|
75
|
-
join(HOME, 'vault', 'Global'),
|
|
76
|
-
join(HOME, 'hooks'),
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
for (const dir of dirs) {
|
|
80
|
-
mkdirSync(dir, { recursive: true })
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Write default .env if not present
|
|
84
|
-
const envPath = join(HOME, '.env')
|
|
85
|
-
if (!existsSync(envPath)) {
|
|
86
|
-
writeFileSync(envPath, `# Claude Brain Configuration
|
|
87
|
-
# Generated by postinstall
|
|
88
|
-
VAULT_PATH=${join(HOME, 'vault')}
|
|
89
|
-
LOG_LEVEL=info
|
|
90
|
-
NODE_ENV=production
|
|
91
|
-
|
|
92
|
-
# ChromaDB Configuration
|
|
93
|
-
CHROMA_MODE=client-server
|
|
94
|
-
CHROMA_HOST=localhost
|
|
95
|
-
CHROMA_PORT=8000
|
|
96
|
-
CHROMA_EMBEDDING_PROVIDER=transformers
|
|
97
|
-
`, 'utf-8')
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Write default global standards
|
|
101
|
-
const standardsPath = join(HOME, 'vault', 'Global', 'standards.md')
|
|
102
|
-
if (!existsSync(standardsPath)) {
|
|
103
|
-
writeFileSync(standardsPath, `---
|
|
104
|
-
type: global-standards
|
|
105
|
-
last_updated: ${new Date().toISOString().split('T')[0]}
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
# Global Coding Standards
|
|
109
|
-
|
|
110
|
-
## General
|
|
111
|
-
- Write clear, readable code
|
|
112
|
-
- Prefer explicit over implicit
|
|
113
|
-
- Keep functions focused and small
|
|
114
|
-
|
|
115
|
-
## TypeScript
|
|
116
|
-
- Use strict mode
|
|
117
|
-
- Prefer const over let
|
|
118
|
-
- Add JSDoc comments for public APIs
|
|
119
|
-
`, 'utf-8')
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
log('Home directory initialized')
|
|
123
|
-
return true
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ── Step 2: Install ChromaDB via pip ─────────────────────
|
|
127
|
-
|
|
128
|
-
function installChromaDB() {
|
|
129
|
-
// Check if already installed
|
|
130
|
-
try {
|
|
131
|
-
execSync('chroma --version', { stdio: 'pipe', timeout: 5000 })
|
|
132
|
-
log('ChromaDB already installed')
|
|
133
|
-
return true
|
|
134
|
-
} catch {}
|
|
135
|
-
|
|
136
|
-
// Check for Python
|
|
137
|
-
let pythonCmd = null
|
|
138
|
-
for (const cmd of ['python3', 'python']) {
|
|
139
|
-
try {
|
|
140
|
-
const ver = execSync(`${cmd} --version`, { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 })
|
|
141
|
-
if (ver.includes('3.')) {
|
|
142
|
-
pythonCmd = cmd
|
|
143
|
-
break
|
|
144
|
-
}
|
|
145
|
-
} catch {}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!pythonCmd) {
|
|
149
|
-
log('Python 3 not found — skipping ChromaDB install (SQLite fallback will be used)')
|
|
150
|
-
return false
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
log('Installing ChromaDB...')
|
|
154
|
-
|
|
155
|
-
const pipCommands = pythonCmd === 'python3'
|
|
156
|
-
? ['pip3 install chromadb', 'python3 -m pip install chromadb']
|
|
157
|
-
: ['pip install chromadb', 'python -m pip install chromadb']
|
|
158
|
-
|
|
159
|
-
for (const cmd of pipCommands) {
|
|
160
|
-
try {
|
|
161
|
-
execSync(cmd, { stdio: 'pipe', timeout: 300_000 })
|
|
162
|
-
log('ChromaDB installed')
|
|
163
|
-
return true
|
|
164
|
-
} catch {}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
log('ChromaDB install failed — SQLite fallback will be used')
|
|
168
|
-
return false
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ── Step 3: Register MCP server ──────────────────────────
|
|
172
|
-
|
|
173
|
-
function registerMcpServer() {
|
|
174
|
-
// Check if claude CLI exists
|
|
175
|
-
try {
|
|
176
|
-
execSync('claude --version', { stdio: 'pipe', timeout: 5000 })
|
|
177
|
-
} catch {
|
|
178
|
-
log('Claude CLI not found — skipping MCP registration')
|
|
179
|
-
log(' Run manually: claude mcp add claude-brain -- claude-brain serve')
|
|
180
|
-
return false
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Check if already configured
|
|
184
|
-
try {
|
|
185
|
-
const result = execSync('claude mcp list', { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 })
|
|
186
|
-
if (result.includes('claude-brain')) {
|
|
187
|
-
log('MCP server already registered')
|
|
188
|
-
return true
|
|
189
|
-
}
|
|
190
|
-
} catch {}
|
|
191
|
-
|
|
192
|
-
// Register
|
|
193
|
-
try {
|
|
194
|
-
execSync('claude mcp add claude-brain -- claude-brain serve', {
|
|
195
|
-
stdio: 'pipe',
|
|
196
|
-
timeout: 15000,
|
|
197
|
-
})
|
|
198
|
-
log('Registered as MCP server in Claude Code')
|
|
199
|
-
return true
|
|
200
|
-
} catch (err) {
|
|
201
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
202
|
-
if (msg.includes('already') || msg.includes('exists')) {
|
|
203
|
-
log('MCP server already registered')
|
|
204
|
-
return true
|
|
205
|
-
}
|
|
206
|
-
log('MCP registration failed — run manually: claude mcp add claude-brain -- claude-brain serve')
|
|
207
|
-
return false
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// ── Step 4: Install hooks ────────────────────────────────
|
|
212
|
-
|
|
213
|
-
function installHooks() {
|
|
214
|
-
// Read existing settings
|
|
215
|
-
let settings = {}
|
|
216
|
-
if (existsSync(CLAUDE_SETTINGS)) {
|
|
217
|
-
try {
|
|
218
|
-
settings = JSON.parse(readFileSync(CLAUDE_SETTINGS, 'utf-8'))
|
|
219
|
-
} catch {}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Check if already installed
|
|
223
|
-
function hasOurHooks(entries) {
|
|
224
|
-
if (!Array.isArray(entries)) return false
|
|
225
|
-
return entries.some(entry =>
|
|
226
|
-
entry && Array.isArray(entry.hooks) &&
|
|
227
|
-
entry.hooks.some(h => typeof h.command === 'string' && h.command.includes(HOOK_MARKER))
|
|
228
|
-
)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (settings.hooks && (hasOurHooks(settings.hooks.PostToolUse) || hasOurHooks(settings.hooks.Stop))) {
|
|
232
|
-
log('Hooks already installed')
|
|
233
|
-
return true
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Build hook command
|
|
237
|
-
const scriptPath = join(HOME, 'hooks', 'brain-hook.ts')
|
|
238
|
-
function buildCmd(event) {
|
|
239
|
-
return `bun "${scriptPath}" --event ${event} # ${HOOK_MARKER}`
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (!settings.hooks) settings.hooks = {}
|
|
243
|
-
|
|
244
|
-
// PostToolUse
|
|
245
|
-
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = []
|
|
246
|
-
settings.hooks.PostToolUse.push({
|
|
247
|
-
matcher: '',
|
|
248
|
-
hooks: [{ type: 'command', command: buildCmd('PostToolUse') }],
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
// Stop
|
|
252
|
-
if (!settings.hooks.Stop) settings.hooks.Stop = []
|
|
253
|
-
settings.hooks.Stop.push({
|
|
254
|
-
matcher: '',
|
|
255
|
-
hooks: [{ type: 'command', command: buildCmd('Stop') }],
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
// Write atomically
|
|
259
|
-
if (!existsSync(CLAUDE_DIR)) {
|
|
260
|
-
mkdirSync(CLAUDE_DIR, { recursive: true })
|
|
261
|
-
}
|
|
262
|
-
const tmpPath = CLAUDE_SETTINGS + '.tmp'
|
|
263
|
-
writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8')
|
|
264
|
-
renameSync(tmpPath, CLAUDE_SETTINGS)
|
|
265
|
-
|
|
266
|
-
log('Hooks installed')
|
|
267
|
-
return true
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// ── Step 5: Install CLAUDE.md ────────────────────────────
|
|
271
|
-
|
|
272
|
-
function installClaudeMd() {
|
|
273
|
-
// Find the assets/CLAUDE.md relative to this script
|
|
274
|
-
// scripts/postinstall.mjs → assets/CLAUDE.md
|
|
275
|
-
const assetsPath = join(__dirname, '..', 'assets', 'CLAUDE.md')
|
|
276
|
-
|
|
277
|
-
if (!existsSync(assetsPath)) {
|
|
278
|
-
log('CLAUDE.md asset not found — skipping')
|
|
279
|
-
return false
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Only install if no CLAUDE.md exists yet (don't overwrite user customizations)
|
|
283
|
-
if (existsSync(CLAUDE_MD_PATH)) {
|
|
284
|
-
// Check if it already mentions claude-brain
|
|
285
|
-
const existing = readFileSync(CLAUDE_MD_PATH, 'utf-8')
|
|
286
|
-
if (existing.includes('brain') || existing.includes('Brain')) {
|
|
287
|
-
log('CLAUDE.md already configured')
|
|
288
|
-
return true
|
|
289
|
-
}
|
|
290
|
-
// Append our section
|
|
291
|
-
const addition = readFileSync(assetsPath, 'utf-8')
|
|
292
|
-
writeFileSync(CLAUDE_MD_PATH, existing.trimEnd() + '\n\n' + addition, 'utf-8')
|
|
293
|
-
log('Appended brain instructions to existing CLAUDE.md')
|
|
294
|
-
return true
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Create new
|
|
298
|
-
if (!existsSync(CLAUDE_DIR)) {
|
|
299
|
-
mkdirSync(CLAUDE_DIR, { recursive: true })
|
|
300
|
-
}
|
|
301
|
-
const content = readFileSync(assetsPath, 'utf-8')
|
|
302
|
-
writeFileSync(CLAUDE_MD_PATH, content, 'utf-8')
|
|
303
|
-
log('Installed CLAUDE.md')
|
|
304
|
-
return true
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ── Main ─────────────────────────────────────────────────
|
|
308
|
-
|
|
309
|
-
async function main() {
|
|
310
|
-
const skipReason = shouldSkip()
|
|
311
|
-
if (skipReason) {
|
|
312
|
-
log(`Skipping postinstall (${skipReason})`)
|
|
313
|
-
return
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
log('Running postinstall setup...')
|
|
317
|
-
console.error('')
|
|
318
|
-
|
|
319
|
-
const results = {
|
|
320
|
-
home: false,
|
|
321
|
-
chromadb: false,
|
|
322
|
-
mcp: false,
|
|
323
|
-
hooks: false,
|
|
324
|
-
claudemd: false,
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
try { results.home = setupHomeDirectory() } catch (e) { log(`Home setup failed: ${e.message}`) }
|
|
328
|
-
try { results.chromadb = installChromaDB() } catch (e) { log(`ChromaDB install failed: ${e.message}`) }
|
|
329
|
-
try { results.mcp = registerMcpServer() } catch (e) { log(`MCP registration failed: ${e.message}`) }
|
|
330
|
-
try { results.hooks = installHooks() } catch (e) { log(`Hook install failed: ${e.message}`) }
|
|
331
|
-
try { results.claudemd = installClaudeMd() } catch (e) { log(`CLAUDE.md install failed: ${e.message}`) }
|
|
332
|
-
|
|
333
|
-
console.error('')
|
|
334
|
-
log('Setup complete! Restart Claude Code to activate.')
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
main().catch(err => {
|
|
338
|
-
log(`Postinstall error: ${err.message}`)
|
|
339
|
-
}).finally(() => {
|
|
340
|
-
process.exit(0)
|
|
341
|
-
})
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall script for claude-brain.
|
|
5
|
+
* Runs automatically after `npm install -g claude-brain` or `bun install -g claude-brain`.
|
|
6
|
+
* Pure Node.js — no TypeScript, no path aliases, no Bun APIs.
|
|
7
|
+
* Always exits 0 so it never blocks the install.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync, renameSync } from 'node:fs'
|
|
11
|
+
import { join, dirname } from 'node:path'
|
|
12
|
+
import { homedir } from 'node:os'
|
|
13
|
+
import { execSync } from 'node:child_process'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
17
|
+
const __dirname = dirname(__filename)
|
|
18
|
+
|
|
19
|
+
const PREFIX = '[claude-brain]'
|
|
20
|
+
const HOME = join(homedir(), '.claude-brain')
|
|
21
|
+
const CLAUDE_DIR = join(homedir(), '.claude')
|
|
22
|
+
const CLAUDE_SETTINGS = join(CLAUDE_DIR, 'settings.json')
|
|
23
|
+
const CLAUDE_MD_PATH = join(CLAUDE_DIR, 'CLAUDE.md')
|
|
24
|
+
const HOOK_MARKER = 'claude-brain-hook'
|
|
25
|
+
|
|
26
|
+
function log(msg) {
|
|
27
|
+
console.error(`${PREFIX} ${msg}`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Step 0: Skip if not a global install ─────────────────
|
|
31
|
+
|
|
32
|
+
function shouldSkip() {
|
|
33
|
+
// CI environments
|
|
34
|
+
if (process.env.CI === 'true' || process.env.CI === '1') {
|
|
35
|
+
return 'CI environment detected'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// If we're inside a node_modules directory, it's a local install
|
|
39
|
+
const scriptDir = dirname(__filename)
|
|
40
|
+
if (scriptDir.includes('node_modules') && !scriptDir.includes('global')) {
|
|
41
|
+
// Check if this is actually a global install by looking deeper
|
|
42
|
+
// bun global installs go to ~/.bun/install/global/node_modules
|
|
43
|
+
// npm global installs go to /usr/local/lib/node_modules or ~/.npm-global
|
|
44
|
+
const isGlobalPath =
|
|
45
|
+
scriptDir.includes('.bun/install/global') ||
|
|
46
|
+
scriptDir.includes('/usr/local/lib/node_modules') ||
|
|
47
|
+
scriptDir.includes('/usr/lib/node_modules') ||
|
|
48
|
+
scriptDir.includes('npm-global') ||
|
|
49
|
+
scriptDir.includes('AppData/Roaming/npm')
|
|
50
|
+
|
|
51
|
+
if (!isGlobalPath) {
|
|
52
|
+
return 'local install (not global)'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Step 1: Create ~/.claude-brain/ ──────────────────────
|
|
60
|
+
|
|
61
|
+
function setupHomeDirectory() {
|
|
62
|
+
if (existsSync(join(HOME, 'data'))) {
|
|
63
|
+
log('Home directory already initialized')
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log(`Setting up ${HOME}/...`)
|
|
68
|
+
|
|
69
|
+
const dirs = [
|
|
70
|
+
join(HOME, 'data'),
|
|
71
|
+
join(HOME, 'data', 'chroma'),
|
|
72
|
+
join(HOME, 'logs'),
|
|
73
|
+
join(HOME, 'vault'),
|
|
74
|
+
join(HOME, 'vault', 'Projects'),
|
|
75
|
+
join(HOME, 'vault', 'Global'),
|
|
76
|
+
join(HOME, 'hooks'),
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
for (const dir of dirs) {
|
|
80
|
+
mkdirSync(dir, { recursive: true })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Write default .env if not present
|
|
84
|
+
const envPath = join(HOME, '.env')
|
|
85
|
+
if (!existsSync(envPath)) {
|
|
86
|
+
writeFileSync(envPath, `# Claude Brain Configuration
|
|
87
|
+
# Generated by postinstall
|
|
88
|
+
VAULT_PATH=${join(HOME, 'vault')}
|
|
89
|
+
LOG_LEVEL=info
|
|
90
|
+
NODE_ENV=production
|
|
91
|
+
|
|
92
|
+
# ChromaDB Configuration
|
|
93
|
+
CHROMA_MODE=client-server
|
|
94
|
+
CHROMA_HOST=localhost
|
|
95
|
+
CHROMA_PORT=8000
|
|
96
|
+
CHROMA_EMBEDDING_PROVIDER=transformers
|
|
97
|
+
`, 'utf-8')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Write default global standards
|
|
101
|
+
const standardsPath = join(HOME, 'vault', 'Global', 'standards.md')
|
|
102
|
+
if (!existsSync(standardsPath)) {
|
|
103
|
+
writeFileSync(standardsPath, `---
|
|
104
|
+
type: global-standards
|
|
105
|
+
last_updated: ${new Date().toISOString().split('T')[0]}
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
# Global Coding Standards
|
|
109
|
+
|
|
110
|
+
## General
|
|
111
|
+
- Write clear, readable code
|
|
112
|
+
- Prefer explicit over implicit
|
|
113
|
+
- Keep functions focused and small
|
|
114
|
+
|
|
115
|
+
## TypeScript
|
|
116
|
+
- Use strict mode
|
|
117
|
+
- Prefer const over let
|
|
118
|
+
- Add JSDoc comments for public APIs
|
|
119
|
+
`, 'utf-8')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
log('Home directory initialized')
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ── Step 2: Install ChromaDB via pip ─────────────────────
|
|
127
|
+
|
|
128
|
+
function installChromaDB() {
|
|
129
|
+
// Check if already installed
|
|
130
|
+
try {
|
|
131
|
+
execSync('chroma --version', { stdio: 'pipe', timeout: 5000 })
|
|
132
|
+
log('ChromaDB already installed')
|
|
133
|
+
return true
|
|
134
|
+
} catch {}
|
|
135
|
+
|
|
136
|
+
// Check for Python
|
|
137
|
+
let pythonCmd = null
|
|
138
|
+
for (const cmd of ['python3', 'python']) {
|
|
139
|
+
try {
|
|
140
|
+
const ver = execSync(`${cmd} --version`, { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 })
|
|
141
|
+
if (ver.includes('3.')) {
|
|
142
|
+
pythonCmd = cmd
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
} catch {}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!pythonCmd) {
|
|
149
|
+
log('Python 3 not found — skipping ChromaDB install (SQLite fallback will be used)')
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
log('Installing ChromaDB...')
|
|
154
|
+
|
|
155
|
+
const pipCommands = pythonCmd === 'python3'
|
|
156
|
+
? ['pip3 install chromadb', 'python3 -m pip install chromadb']
|
|
157
|
+
: ['pip install chromadb', 'python -m pip install chromadb']
|
|
158
|
+
|
|
159
|
+
for (const cmd of pipCommands) {
|
|
160
|
+
try {
|
|
161
|
+
execSync(cmd, { stdio: 'pipe', timeout: 300_000 })
|
|
162
|
+
log('ChromaDB installed')
|
|
163
|
+
return true
|
|
164
|
+
} catch {}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
log('ChromaDB install failed — SQLite fallback will be used')
|
|
168
|
+
return false
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── Step 3: Register MCP server ──────────────────────────
|
|
172
|
+
|
|
173
|
+
function registerMcpServer() {
|
|
174
|
+
// Check if claude CLI exists
|
|
175
|
+
try {
|
|
176
|
+
execSync('claude --version', { stdio: 'pipe', timeout: 5000 })
|
|
177
|
+
} catch {
|
|
178
|
+
log('Claude CLI not found — skipping MCP registration')
|
|
179
|
+
log(' Run manually: claude mcp add claude-brain -- claude-brain serve')
|
|
180
|
+
return false
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check if already configured
|
|
184
|
+
try {
|
|
185
|
+
const result = execSync('claude mcp list', { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 })
|
|
186
|
+
if (result.includes('claude-brain')) {
|
|
187
|
+
log('MCP server already registered')
|
|
188
|
+
return true
|
|
189
|
+
}
|
|
190
|
+
} catch {}
|
|
191
|
+
|
|
192
|
+
// Register
|
|
193
|
+
try {
|
|
194
|
+
execSync('claude mcp add claude-brain -- claude-brain serve', {
|
|
195
|
+
stdio: 'pipe',
|
|
196
|
+
timeout: 15000,
|
|
197
|
+
})
|
|
198
|
+
log('Registered as MCP server in Claude Code')
|
|
199
|
+
return true
|
|
200
|
+
} catch (err) {
|
|
201
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
202
|
+
if (msg.includes('already') || msg.includes('exists')) {
|
|
203
|
+
log('MCP server already registered')
|
|
204
|
+
return true
|
|
205
|
+
}
|
|
206
|
+
log('MCP registration failed — run manually: claude mcp add claude-brain -- claude-brain serve')
|
|
207
|
+
return false
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ── Step 4: Install hooks ────────────────────────────────
|
|
212
|
+
|
|
213
|
+
function installHooks() {
|
|
214
|
+
// Read existing settings
|
|
215
|
+
let settings = {}
|
|
216
|
+
if (existsSync(CLAUDE_SETTINGS)) {
|
|
217
|
+
try {
|
|
218
|
+
settings = JSON.parse(readFileSync(CLAUDE_SETTINGS, 'utf-8'))
|
|
219
|
+
} catch {}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check if already installed
|
|
223
|
+
function hasOurHooks(entries) {
|
|
224
|
+
if (!Array.isArray(entries)) return false
|
|
225
|
+
return entries.some(entry =>
|
|
226
|
+
entry && Array.isArray(entry.hooks) &&
|
|
227
|
+
entry.hooks.some(h => typeof h.command === 'string' && h.command.includes(HOOK_MARKER))
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (settings.hooks && (hasOurHooks(settings.hooks.PostToolUse) || hasOurHooks(settings.hooks.Stop))) {
|
|
232
|
+
log('Hooks already installed')
|
|
233
|
+
return true
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Build hook command
|
|
237
|
+
const scriptPath = join(HOME, 'hooks', 'brain-hook.ts')
|
|
238
|
+
function buildCmd(event) {
|
|
239
|
+
return `bun "${scriptPath}" --event ${event} # ${HOOK_MARKER}`
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!settings.hooks) settings.hooks = {}
|
|
243
|
+
|
|
244
|
+
// PostToolUse
|
|
245
|
+
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = []
|
|
246
|
+
settings.hooks.PostToolUse.push({
|
|
247
|
+
matcher: '',
|
|
248
|
+
hooks: [{ type: 'command', command: buildCmd('PostToolUse') }],
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
// Stop
|
|
252
|
+
if (!settings.hooks.Stop) settings.hooks.Stop = []
|
|
253
|
+
settings.hooks.Stop.push({
|
|
254
|
+
matcher: '',
|
|
255
|
+
hooks: [{ type: 'command', command: buildCmd('Stop') }],
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
// Write atomically
|
|
259
|
+
if (!existsSync(CLAUDE_DIR)) {
|
|
260
|
+
mkdirSync(CLAUDE_DIR, { recursive: true })
|
|
261
|
+
}
|
|
262
|
+
const tmpPath = CLAUDE_SETTINGS + '.tmp'
|
|
263
|
+
writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8')
|
|
264
|
+
renameSync(tmpPath, CLAUDE_SETTINGS)
|
|
265
|
+
|
|
266
|
+
log('Hooks installed')
|
|
267
|
+
return true
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ── Step 5: Install CLAUDE.md ────────────────────────────
|
|
271
|
+
|
|
272
|
+
function installClaudeMd() {
|
|
273
|
+
// Find the assets/CLAUDE.md relative to this script
|
|
274
|
+
// scripts/postinstall.mjs → assets/CLAUDE.md
|
|
275
|
+
const assetsPath = join(__dirname, '..', 'assets', 'CLAUDE.md')
|
|
276
|
+
|
|
277
|
+
if (!existsSync(assetsPath)) {
|
|
278
|
+
log('CLAUDE.md asset not found — skipping')
|
|
279
|
+
return false
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Only install if no CLAUDE.md exists yet (don't overwrite user customizations)
|
|
283
|
+
if (existsSync(CLAUDE_MD_PATH)) {
|
|
284
|
+
// Check if it already mentions claude-brain
|
|
285
|
+
const existing = readFileSync(CLAUDE_MD_PATH, 'utf-8')
|
|
286
|
+
if (existing.includes('brain') || existing.includes('Brain')) {
|
|
287
|
+
log('CLAUDE.md already configured')
|
|
288
|
+
return true
|
|
289
|
+
}
|
|
290
|
+
// Append our section
|
|
291
|
+
const addition = readFileSync(assetsPath, 'utf-8')
|
|
292
|
+
writeFileSync(CLAUDE_MD_PATH, existing.trimEnd() + '\n\n' + addition, 'utf-8')
|
|
293
|
+
log('Appended brain instructions to existing CLAUDE.md')
|
|
294
|
+
return true
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Create new
|
|
298
|
+
if (!existsSync(CLAUDE_DIR)) {
|
|
299
|
+
mkdirSync(CLAUDE_DIR, { recursive: true })
|
|
300
|
+
}
|
|
301
|
+
const content = readFileSync(assetsPath, 'utf-8')
|
|
302
|
+
writeFileSync(CLAUDE_MD_PATH, content, 'utf-8')
|
|
303
|
+
log('Installed CLAUDE.md')
|
|
304
|
+
return true
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ── Main ─────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
async function main() {
|
|
310
|
+
const skipReason = shouldSkip()
|
|
311
|
+
if (skipReason) {
|
|
312
|
+
log(`Skipping postinstall (${skipReason})`)
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
log('Running postinstall setup...')
|
|
317
|
+
console.error('')
|
|
318
|
+
|
|
319
|
+
const results = {
|
|
320
|
+
home: false,
|
|
321
|
+
chromadb: false,
|
|
322
|
+
mcp: false,
|
|
323
|
+
hooks: false,
|
|
324
|
+
claudemd: false,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try { results.home = setupHomeDirectory() } catch (e) { log(`Home setup failed: ${e.message}`) }
|
|
328
|
+
try { results.chromadb = installChromaDB() } catch (e) { log(`ChromaDB install failed: ${e.message}`) }
|
|
329
|
+
try { results.mcp = registerMcpServer() } catch (e) { log(`MCP registration failed: ${e.message}`) }
|
|
330
|
+
try { results.hooks = installHooks() } catch (e) { log(`Hook install failed: ${e.message}`) }
|
|
331
|
+
try { results.claudemd = installClaudeMd() } catch (e) { log(`CLAUDE.md install failed: ${e.message}`) }
|
|
332
|
+
|
|
333
|
+
console.error('')
|
|
334
|
+
log('Setup complete! Restart Claude Code to activate.')
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
main().catch(err => {
|
|
338
|
+
log(`Postinstall error: ${err.message}`)
|
|
339
|
+
}).finally(() => {
|
|
340
|
+
process.exit(0)
|
|
341
|
+
})
|