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
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 17: CLI Hooks Command
|
|
3
|
-
* Manages passive learning hooks (install/uninstall/status/enable/disable)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
renderLogo, theme, heading, successText, warningText, errorText, dimText,
|
|
8
|
-
box, summaryPanel, withSpinner,
|
|
9
|
-
} from '@/cli/ui/index.js'
|
|
10
|
-
import { installHooks, uninstallHooks, isHooksInstalled, getHookScriptPath } from '@/hooks/installer'
|
|
11
|
-
import { readQueue } from '@/hooks/queue'
|
|
12
|
-
|
|
13
|
-
export async function runHooks() {
|
|
14
|
-
const subcommand = process.argv[3] || 'status'
|
|
15
|
-
|
|
16
|
-
switch (subcommand) {
|
|
17
|
-
case 'install':
|
|
18
|
-
await handleInstall()
|
|
19
|
-
break
|
|
20
|
-
case 'uninstall':
|
|
21
|
-
await handleUninstall()
|
|
22
|
-
break
|
|
23
|
-
case 'status':
|
|
24
|
-
await handleStatus()
|
|
25
|
-
break
|
|
26
|
-
case 'enable':
|
|
27
|
-
await handleToggle(true)
|
|
28
|
-
break
|
|
29
|
-
case 'disable':
|
|
30
|
-
await handleToggle(false)
|
|
31
|
-
break
|
|
32
|
-
default:
|
|
33
|
-
console.log()
|
|
34
|
-
console.log(errorText(`Unknown hooks subcommand: ${subcommand}`))
|
|
35
|
-
printHooksHelp()
|
|
36
|
-
process.exit(1)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function handleInstall() {
|
|
41
|
-
console.log()
|
|
42
|
-
console.log(renderLogo())
|
|
43
|
-
console.log()
|
|
44
|
-
console.log(heading('Install Passive Learning Hooks'))
|
|
45
|
-
console.log()
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
let result: { installed: boolean; message: string } | undefined
|
|
49
|
-
await withSpinner('Installing hooks into Claude Code', async () => {
|
|
50
|
-
result = installHooks()
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
console.log()
|
|
54
|
-
if (result?.installed) {
|
|
55
|
-
console.log(box([
|
|
56
|
-
successText(result.message),
|
|
57
|
-
'',
|
|
58
|
-
dimText('Hooks will fire on every tool call in Claude Code.'),
|
|
59
|
-
dimText('Knowledge is captured and sent to the brain server.'),
|
|
60
|
-
dimText('Session summaries are auto-stored when conversations end.'),
|
|
61
|
-
'',
|
|
62
|
-
`${theme.dim('Hook script:')} ${getHookScriptPath()}`,
|
|
63
|
-
`${theme.dim('Settings:')} ~/.claude/settings.json`,
|
|
64
|
-
'',
|
|
65
|
-
dimText('Hooks are enabled by default. To disable:'),
|
|
66
|
-
` ${theme.bold('export CLAUDE_BRAIN_HOOKS_ENABLED=false')}`,
|
|
67
|
-
].join('\n'), 'Hooks Installed'))
|
|
68
|
-
}
|
|
69
|
-
} catch (err) {
|
|
70
|
-
console.log()
|
|
71
|
-
console.log(box(
|
|
72
|
-
errorText(`Failed to install hooks: ${err instanceof Error ? err.message : String(err)}`),
|
|
73
|
-
'Error'
|
|
74
|
-
))
|
|
75
|
-
process.exit(1)
|
|
76
|
-
}
|
|
77
|
-
console.log()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async function handleUninstall() {
|
|
81
|
-
console.log()
|
|
82
|
-
console.log(renderLogo())
|
|
83
|
-
console.log()
|
|
84
|
-
console.log(heading('Uninstall Passive Learning Hooks'))
|
|
85
|
-
console.log()
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
let result: { uninstalled: boolean; message: string } | undefined
|
|
89
|
-
await withSpinner('Removing hooks from Claude Code', async () => {
|
|
90
|
-
result = uninstallHooks()
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
console.log()
|
|
94
|
-
if (result?.uninstalled) {
|
|
95
|
-
console.log(box(
|
|
96
|
-
successText(result.message),
|
|
97
|
-
'Hooks Removed'
|
|
98
|
-
))
|
|
99
|
-
}
|
|
100
|
-
} catch (err) {
|
|
101
|
-
console.log()
|
|
102
|
-
console.log(box(
|
|
103
|
-
errorText(`Failed to uninstall hooks: ${err instanceof Error ? err.message : String(err)}`),
|
|
104
|
-
'Error'
|
|
105
|
-
))
|
|
106
|
-
process.exit(1)
|
|
107
|
-
}
|
|
108
|
-
console.log()
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async function handleStatus() {
|
|
112
|
-
console.log()
|
|
113
|
-
console.log(renderLogo())
|
|
114
|
-
console.log()
|
|
115
|
-
console.log(heading('Hook Status'))
|
|
116
|
-
console.log()
|
|
117
|
-
|
|
118
|
-
const installed = isHooksInstalled()
|
|
119
|
-
const queueItems = readQueue()
|
|
120
|
-
const envEnabled = process.env.CLAUDE_BRAIN_HOOKS_ENABLED !== 'false'
|
|
121
|
-
|
|
122
|
-
const items = [
|
|
123
|
-
{ label: 'Installed', value: installed ? 'Yes' : 'No', status: installed ? 'success' as const : 'warning' as const },
|
|
124
|
-
{ label: 'Env enabled', value: envEnabled ? 'Yes' : 'No', status: envEnabled ? 'success' as const : 'info' as const },
|
|
125
|
-
{ label: 'Queue items', value: String(queueItems.length), status: queueItems.length > 0 ? 'warning' as const : 'info' as const },
|
|
126
|
-
{ label: 'Hook script', value: getHookScriptPath(), status: 'info' as const },
|
|
127
|
-
]
|
|
128
|
-
|
|
129
|
-
console.log(summaryPanel('Passive Learning Hooks', items))
|
|
130
|
-
|
|
131
|
-
// Try to fetch live stats from the server
|
|
132
|
-
try {
|
|
133
|
-
const port = parseInt(process.env.CLAUDE_BRAIN_PORT || '3000', 10)
|
|
134
|
-
const res = await fetch(`http://localhost:${port}/api/hooks/status`, {
|
|
135
|
-
signal: AbortSignal.timeout(2000),
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
if (res.ok) {
|
|
139
|
-
const data = await res.json() as any
|
|
140
|
-
if (data.success && data.data) {
|
|
141
|
-
console.log()
|
|
142
|
-
const serverItems = [
|
|
143
|
-
{ label: 'Total captured', value: String(data.data.totalCaptured || 0), status: 'info' as const },
|
|
144
|
-
{ label: 'Total skipped', value: String(data.data.totalSkipped || 0), status: 'info' as const },
|
|
145
|
-
{ label: 'Total merged', value: String(data.data.totalMerged || 0), status: 'info' as const },
|
|
146
|
-
{ label: 'Active sessions', value: String(data.data.activeSessions || 0), status: 'info' as const },
|
|
147
|
-
{ label: 'Last capture', value: data.data.lastCaptureAt || 'Never', status: 'info' as const },
|
|
148
|
-
]
|
|
149
|
-
console.log(summaryPanel('Server Stats', serverItems))
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
} catch {
|
|
153
|
-
console.log()
|
|
154
|
-
console.log(dimText(' (Server not running — no live stats available)'))
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
console.log()
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async function handleToggle(enable: boolean) {
|
|
161
|
-
console.log()
|
|
162
|
-
console.log(renderLogo())
|
|
163
|
-
console.log()
|
|
164
|
-
|
|
165
|
-
const action = enable ? 'Enabling' : 'Disabling'
|
|
166
|
-
console.log(heading(`${action} Passive Learning`))
|
|
167
|
-
console.log()
|
|
168
|
-
|
|
169
|
-
// Toggle via env hint (actual config toggle would need config file editing)
|
|
170
|
-
if (enable) {
|
|
171
|
-
console.log(box([
|
|
172
|
-
successText('Hooks are enabled by default since v0.10.0.'),
|
|
173
|
-
'',
|
|
174
|
-
dimText('If previously disabled, remove the env variable:'),
|
|
175
|
-
` ${theme.bold('unset CLAUDE_BRAIN_HOOKS_ENABLED')}`,
|
|
176
|
-
'',
|
|
177
|
-
dimText('Hooks capture Edit/Write/Bash events automatically.'),
|
|
178
|
-
dimText('Session summaries are stored when conversations end.'),
|
|
179
|
-
].join('\n'), 'Enable Hooks'))
|
|
180
|
-
} else {
|
|
181
|
-
console.log(box([
|
|
182
|
-
warningText('To disable hooks, set the environment variable:'),
|
|
183
|
-
'',
|
|
184
|
-
` ${theme.bold('export CLAUDE_BRAIN_HOOKS_ENABLED=false')}`,
|
|
185
|
-
'',
|
|
186
|
-
dimText('This stops hook processing without uninstalling.'),
|
|
187
|
-
].join('\n'), 'Disable Hooks'))
|
|
188
|
-
}
|
|
189
|
-
console.log()
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function printHooksHelp() {
|
|
193
|
-
console.log()
|
|
194
|
-
const commands = [
|
|
195
|
-
['install', 'Install hooks into Claude Code settings'],
|
|
196
|
-
['uninstall', 'Remove hooks from Claude Code settings'],
|
|
197
|
-
['status', 'Show hook installation and capture stats'],
|
|
198
|
-
['enable', 'Enable passive learning (show instructions)'],
|
|
199
|
-
['disable', 'Disable passive learning (show instructions)'],
|
|
200
|
-
]
|
|
201
|
-
|
|
202
|
-
const cmdLines = commands
|
|
203
|
-
.map(([cmd, desc]) => ` ${theme.primary(cmd!.padEnd(14))} ${dimText(desc!)}`)
|
|
204
|
-
.join('\n')
|
|
205
|
-
|
|
206
|
-
console.log(box([
|
|
207
|
-
theme.bold('Usage:') + ' ' + dimText('claude-brain hooks [subcommand]'),
|
|
208
|
-
'',
|
|
209
|
-
theme.bold('Subcommands:'),
|
|
210
|
-
cmdLines,
|
|
211
|
-
].join('\n'), 'Hooks Help'))
|
|
212
|
-
console.log()
|
|
213
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Phase 17: CLI Hooks Command
|
|
3
|
+
* Manages passive learning hooks (install/uninstall/status/enable/disable)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
renderLogo, theme, heading, successText, warningText, errorText, dimText,
|
|
8
|
+
box, summaryPanel, withSpinner,
|
|
9
|
+
} from '@/cli/ui/index.js'
|
|
10
|
+
import { installHooks, uninstallHooks, isHooksInstalled, getHookScriptPath } from '@/hooks/installer'
|
|
11
|
+
import { readQueue } from '@/hooks/queue'
|
|
12
|
+
|
|
13
|
+
export async function runHooks() {
|
|
14
|
+
const subcommand = process.argv[3] || 'status'
|
|
15
|
+
|
|
16
|
+
switch (subcommand) {
|
|
17
|
+
case 'install':
|
|
18
|
+
await handleInstall()
|
|
19
|
+
break
|
|
20
|
+
case 'uninstall':
|
|
21
|
+
await handleUninstall()
|
|
22
|
+
break
|
|
23
|
+
case 'status':
|
|
24
|
+
await handleStatus()
|
|
25
|
+
break
|
|
26
|
+
case 'enable':
|
|
27
|
+
await handleToggle(true)
|
|
28
|
+
break
|
|
29
|
+
case 'disable':
|
|
30
|
+
await handleToggle(false)
|
|
31
|
+
break
|
|
32
|
+
default:
|
|
33
|
+
console.log()
|
|
34
|
+
console.log(errorText(`Unknown hooks subcommand: ${subcommand}`))
|
|
35
|
+
printHooksHelp()
|
|
36
|
+
process.exit(1)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function handleInstall() {
|
|
41
|
+
console.log()
|
|
42
|
+
console.log(renderLogo())
|
|
43
|
+
console.log()
|
|
44
|
+
console.log(heading('Install Passive Learning Hooks'))
|
|
45
|
+
console.log()
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
let result: { installed: boolean; message: string } | undefined
|
|
49
|
+
await withSpinner('Installing hooks into Claude Code', async () => {
|
|
50
|
+
result = installHooks()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
console.log()
|
|
54
|
+
if (result?.installed) {
|
|
55
|
+
console.log(box([
|
|
56
|
+
successText(result.message),
|
|
57
|
+
'',
|
|
58
|
+
dimText('Hooks will fire on every tool call in Claude Code.'),
|
|
59
|
+
dimText('Knowledge is captured and sent to the brain server.'),
|
|
60
|
+
dimText('Session summaries are auto-stored when conversations end.'),
|
|
61
|
+
'',
|
|
62
|
+
`${theme.dim('Hook script:')} ${getHookScriptPath()}`,
|
|
63
|
+
`${theme.dim('Settings:')} ~/.claude/settings.json`,
|
|
64
|
+
'',
|
|
65
|
+
dimText('Hooks are enabled by default. To disable:'),
|
|
66
|
+
` ${theme.bold('export CLAUDE_BRAIN_HOOKS_ENABLED=false')}`,
|
|
67
|
+
].join('\n'), 'Hooks Installed'))
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.log()
|
|
71
|
+
console.log(box(
|
|
72
|
+
errorText(`Failed to install hooks: ${err instanceof Error ? err.message : String(err)}`),
|
|
73
|
+
'Error'
|
|
74
|
+
))
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
console.log()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function handleUninstall() {
|
|
81
|
+
console.log()
|
|
82
|
+
console.log(renderLogo())
|
|
83
|
+
console.log()
|
|
84
|
+
console.log(heading('Uninstall Passive Learning Hooks'))
|
|
85
|
+
console.log()
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
let result: { uninstalled: boolean; message: string } | undefined
|
|
89
|
+
await withSpinner('Removing hooks from Claude Code', async () => {
|
|
90
|
+
result = uninstallHooks()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
console.log()
|
|
94
|
+
if (result?.uninstalled) {
|
|
95
|
+
console.log(box(
|
|
96
|
+
successText(result.message),
|
|
97
|
+
'Hooks Removed'
|
|
98
|
+
))
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
console.log()
|
|
102
|
+
console.log(box(
|
|
103
|
+
errorText(`Failed to uninstall hooks: ${err instanceof Error ? err.message : String(err)}`),
|
|
104
|
+
'Error'
|
|
105
|
+
))
|
|
106
|
+
process.exit(1)
|
|
107
|
+
}
|
|
108
|
+
console.log()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function handleStatus() {
|
|
112
|
+
console.log()
|
|
113
|
+
console.log(renderLogo())
|
|
114
|
+
console.log()
|
|
115
|
+
console.log(heading('Hook Status'))
|
|
116
|
+
console.log()
|
|
117
|
+
|
|
118
|
+
const installed = isHooksInstalled()
|
|
119
|
+
const queueItems = readQueue()
|
|
120
|
+
const envEnabled = process.env.CLAUDE_BRAIN_HOOKS_ENABLED !== 'false'
|
|
121
|
+
|
|
122
|
+
const items = [
|
|
123
|
+
{ label: 'Installed', value: installed ? 'Yes' : 'No', status: installed ? 'success' as const : 'warning' as const },
|
|
124
|
+
{ label: 'Env enabled', value: envEnabled ? 'Yes' : 'No', status: envEnabled ? 'success' as const : 'info' as const },
|
|
125
|
+
{ label: 'Queue items', value: String(queueItems.length), status: queueItems.length > 0 ? 'warning' as const : 'info' as const },
|
|
126
|
+
{ label: 'Hook script', value: getHookScriptPath(), status: 'info' as const },
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
console.log(summaryPanel('Passive Learning Hooks', items))
|
|
130
|
+
|
|
131
|
+
// Try to fetch live stats from the server
|
|
132
|
+
try {
|
|
133
|
+
const port = parseInt(process.env.CLAUDE_BRAIN_PORT || '3000', 10)
|
|
134
|
+
const res = await fetch(`http://localhost:${port}/api/hooks/status`, {
|
|
135
|
+
signal: AbortSignal.timeout(2000),
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
if (res.ok) {
|
|
139
|
+
const data = await res.json() as any
|
|
140
|
+
if (data.success && data.data) {
|
|
141
|
+
console.log()
|
|
142
|
+
const serverItems = [
|
|
143
|
+
{ label: 'Total captured', value: String(data.data.totalCaptured || 0), status: 'info' as const },
|
|
144
|
+
{ label: 'Total skipped', value: String(data.data.totalSkipped || 0), status: 'info' as const },
|
|
145
|
+
{ label: 'Total merged', value: String(data.data.totalMerged || 0), status: 'info' as const },
|
|
146
|
+
{ label: 'Active sessions', value: String(data.data.activeSessions || 0), status: 'info' as const },
|
|
147
|
+
{ label: 'Last capture', value: data.data.lastCaptureAt || 'Never', status: 'info' as const },
|
|
148
|
+
]
|
|
149
|
+
console.log(summaryPanel('Server Stats', serverItems))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
console.log()
|
|
154
|
+
console.log(dimText(' (Server not running — no live stats available)'))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function handleToggle(enable: boolean) {
|
|
161
|
+
console.log()
|
|
162
|
+
console.log(renderLogo())
|
|
163
|
+
console.log()
|
|
164
|
+
|
|
165
|
+
const action = enable ? 'Enabling' : 'Disabling'
|
|
166
|
+
console.log(heading(`${action} Passive Learning`))
|
|
167
|
+
console.log()
|
|
168
|
+
|
|
169
|
+
// Toggle via env hint (actual config toggle would need config file editing)
|
|
170
|
+
if (enable) {
|
|
171
|
+
console.log(box([
|
|
172
|
+
successText('Hooks are enabled by default since v0.10.0.'),
|
|
173
|
+
'',
|
|
174
|
+
dimText('If previously disabled, remove the env variable:'),
|
|
175
|
+
` ${theme.bold('unset CLAUDE_BRAIN_HOOKS_ENABLED')}`,
|
|
176
|
+
'',
|
|
177
|
+
dimText('Hooks capture Edit/Write/Bash events automatically.'),
|
|
178
|
+
dimText('Session summaries are stored when conversations end.'),
|
|
179
|
+
].join('\n'), 'Enable Hooks'))
|
|
180
|
+
} else {
|
|
181
|
+
console.log(box([
|
|
182
|
+
warningText('To disable hooks, set the environment variable:'),
|
|
183
|
+
'',
|
|
184
|
+
` ${theme.bold('export CLAUDE_BRAIN_HOOKS_ENABLED=false')}`,
|
|
185
|
+
'',
|
|
186
|
+
dimText('This stops hook processing without uninstalling.'),
|
|
187
|
+
].join('\n'), 'Disable Hooks'))
|
|
188
|
+
}
|
|
189
|
+
console.log()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function printHooksHelp() {
|
|
193
|
+
console.log()
|
|
194
|
+
const commands = [
|
|
195
|
+
['install', 'Install hooks into Claude Code settings'],
|
|
196
|
+
['uninstall', 'Remove hooks from Claude Code settings'],
|
|
197
|
+
['status', 'Show hook installation and capture stats'],
|
|
198
|
+
['enable', 'Enable passive learning (show instructions)'],
|
|
199
|
+
['disable', 'Disable passive learning (show instructions)'],
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
const cmdLines = commands
|
|
203
|
+
.map(([cmd, desc]) => ` ${theme.primary(cmd!.padEnd(14))} ${dimText(desc!)}`)
|
|
204
|
+
.join('\n')
|
|
205
|
+
|
|
206
|
+
console.log(box([
|
|
207
|
+
theme.bold('Usage:') + ' ' + dimText('claude-brain hooks [subcommand]'),
|
|
208
|
+
'',
|
|
209
|
+
theme.bold('Subcommands:'),
|
|
210
|
+
cmdLines,
|
|
211
|
+
].join('\n'), 'Hooks Help'))
|
|
212
|
+
console.log()
|
|
213
|
+
}
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Init Command
|
|
3
|
-
* Phase 22: Scans a repository and stores initial project context.
|
|
4
|
-
*
|
|
5
|
-
* Usage: claude-brain init [path] [--force]
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import path from 'path'
|
|
9
|
-
import {
|
|
10
|
-
renderLogo, theme, heading, successText, warningText, dimText,
|
|
11
|
-
box, withSpinner,
|
|
12
|
-
} from '@/cli/ui/index.js'
|
|
13
|
-
import { scanRepo } from '@/automation/repo-scanner'
|
|
14
|
-
|
|
15
|
-
export async function runInit() {
|
|
16
|
-
console.log()
|
|
17
|
-
console.log(renderLogo())
|
|
18
|
-
console.log()
|
|
19
|
-
console.log(heading('Initialize Project'))
|
|
20
|
-
console.log()
|
|
21
|
-
|
|
22
|
-
// Parse arguments
|
|
23
|
-
const args = process.argv.slice(3)
|
|
24
|
-
const force = args.includes('--force')
|
|
25
|
-
const repoPath = path.resolve(
|
|
26
|
-
args.find(a => !a.startsWith('--')) || process.cwd()
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
console.log(` ${theme.bold('Path:')} ${dimText(repoPath)}`)
|
|
30
|
-
if (force) {
|
|
31
|
-
console.log(` ${theme.bold('Mode:')} ${dimText('Force re-scan')}`)
|
|
32
|
-
}
|
|
33
|
-
console.log()
|
|
34
|
-
|
|
35
|
-
// Phase 23b: Validate project directory
|
|
36
|
-
const { existsSync: dirExists } = await import('fs')
|
|
37
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || ''
|
|
38
|
-
if (repoPath === homeDir) {
|
|
39
|
-
console.log(warningText(' This is your home directory — not a project root.'))
|
|
40
|
-
console.log(dimText(' Run this inside a project directory, or pass a path: claude-brain init /path/to/project'))
|
|
41
|
-
console.log()
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const hasGit = dirExists(path.join(repoPath, '.git'))
|
|
46
|
-
const hasPackageJson = dirExists(path.join(repoPath, 'package.json'))
|
|
47
|
-
const hasCargoToml = dirExists(path.join(repoPath, 'Cargo.toml'))
|
|
48
|
-
const hasPyproject = dirExists(path.join(repoPath, 'pyproject.toml'))
|
|
49
|
-
const hasGoMod = dirExists(path.join(repoPath, 'go.mod'))
|
|
50
|
-
const isProject = hasGit || hasPackageJson || hasCargoToml || hasPyproject || hasGoMod
|
|
51
|
-
|
|
52
|
-
if (!isProject && !force) {
|
|
53
|
-
console.log(warningText(' No project markers found (no .git, package.json, Cargo.toml, etc.)'))
|
|
54
|
-
console.log(dimText(' Use --force to scan anyway, or run inside a project directory.'))
|
|
55
|
-
console.log()
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Scan the repo
|
|
60
|
-
const context = await withSpinner('Scanning repository', () => scanRepo(repoPath))
|
|
61
|
-
|
|
62
|
-
if (!context.name) {
|
|
63
|
-
console.log(warningText(' Could not detect project name. Specify a path to a project root.'))
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Display results
|
|
68
|
-
console.log(successText(` Project: ${context.name}`))
|
|
69
|
-
|
|
70
|
-
if (context.techStack.length > 0) {
|
|
71
|
-
console.log(` ${theme.bold('Tech stack:')} ${dimText(context.techStack.join(', '))}`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (context.description) {
|
|
75
|
-
const desc = context.description.split('\n')[0]?.slice(0, 100) || ''
|
|
76
|
-
console.log(` ${theme.bold('Description:')} ${dimText(desc)}`)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (context.recentActivity) {
|
|
80
|
-
const commits = context.recentActivity.split('\n').length
|
|
81
|
-
console.log(` ${theme.bold('Recent commits:')} ${dimText(String(commits))}`)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (context.projectInstructions) {
|
|
85
|
-
console.log(` ${theme.bold('CLAUDE.md:')} ${dimText('found')}`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Try to store context via brain
|
|
89
|
-
try {
|
|
90
|
-
const summary = [
|
|
91
|
-
`Project "${context.name}" initialized.`,
|
|
92
|
-
context.techStack.length > 0 ? `Tech stack: ${context.techStack.join(', ')}.` : '',
|
|
93
|
-
context.description ? `Description: ${context.description.split('\n')[0]?.slice(0, 200)}` : '',
|
|
94
|
-
context.structure ? `Structure:\n${context.structure.split('\n').slice(0, 15).join('\n')}` : '',
|
|
95
|
-
context.recentActivity ? `Recent git activity:\n${context.recentActivity}` : '',
|
|
96
|
-
context.projectInstructions ? `CLAUDE.md contents:\n${context.projectInstructions.slice(0, 500)}` : ''
|
|
97
|
-
].filter(Boolean).join('\n\n')
|
|
98
|
-
|
|
99
|
-
// Write to a local init file so the MCP server can pick it up
|
|
100
|
-
const { existsSync, mkdirSync } = await import('fs')
|
|
101
|
-
const { writeFileSync } = await import('fs')
|
|
102
|
-
const dataDir = path.join(repoPath, '.claude-brain')
|
|
103
|
-
if (!existsSync(dataDir)) {
|
|
104
|
-
mkdirSync(dataDir, { recursive: true })
|
|
105
|
-
}
|
|
106
|
-
writeFileSync(path.join(dataDir, 'init-context.md'), summary)
|
|
107
|
-
|
|
108
|
-
console.log()
|
|
109
|
-
console.log(successText(` Initial context saved to .claude-brain/init-context.md`))
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.log(warningText(` Could not save context: ${error instanceof Error ? error.message : 'unknown error'}`))
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log()
|
|
115
|
-
console.log(box([
|
|
116
|
-
heading('Project initialized!'),
|
|
117
|
-
'',
|
|
118
|
-
dimText('Brain will auto-load this context in future sessions.'),
|
|
119
|
-
dimText('Use brain tool to store additional decisions and patterns.'),
|
|
120
|
-
].join('\n'), 'Done'))
|
|
121
|
-
console.log()
|
|
122
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Init Command
|
|
3
|
+
* Phase 22: Scans a repository and stores initial project context.
|
|
4
|
+
*
|
|
5
|
+
* Usage: claude-brain init [path] [--force]
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'path'
|
|
9
|
+
import {
|
|
10
|
+
renderLogo, theme, heading, successText, warningText, dimText,
|
|
11
|
+
box, withSpinner,
|
|
12
|
+
} from '@/cli/ui/index.js'
|
|
13
|
+
import { scanRepo } from '@/automation/repo-scanner'
|
|
14
|
+
|
|
15
|
+
export async function runInit() {
|
|
16
|
+
console.log()
|
|
17
|
+
console.log(renderLogo())
|
|
18
|
+
console.log()
|
|
19
|
+
console.log(heading('Initialize Project'))
|
|
20
|
+
console.log()
|
|
21
|
+
|
|
22
|
+
// Parse arguments
|
|
23
|
+
const args = process.argv.slice(3)
|
|
24
|
+
const force = args.includes('--force')
|
|
25
|
+
const repoPath = path.resolve(
|
|
26
|
+
args.find(a => !a.startsWith('--')) || process.cwd()
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
console.log(` ${theme.bold('Path:')} ${dimText(repoPath)}`)
|
|
30
|
+
if (force) {
|
|
31
|
+
console.log(` ${theme.bold('Mode:')} ${dimText('Force re-scan')}`)
|
|
32
|
+
}
|
|
33
|
+
console.log()
|
|
34
|
+
|
|
35
|
+
// Phase 23b: Validate project directory
|
|
36
|
+
const { existsSync: dirExists } = await import('fs')
|
|
37
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || ''
|
|
38
|
+
if (repoPath === homeDir) {
|
|
39
|
+
console.log(warningText(' This is your home directory — not a project root.'))
|
|
40
|
+
console.log(dimText(' Run this inside a project directory, or pass a path: claude-brain init /path/to/project'))
|
|
41
|
+
console.log()
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const hasGit = dirExists(path.join(repoPath, '.git'))
|
|
46
|
+
const hasPackageJson = dirExists(path.join(repoPath, 'package.json'))
|
|
47
|
+
const hasCargoToml = dirExists(path.join(repoPath, 'Cargo.toml'))
|
|
48
|
+
const hasPyproject = dirExists(path.join(repoPath, 'pyproject.toml'))
|
|
49
|
+
const hasGoMod = dirExists(path.join(repoPath, 'go.mod'))
|
|
50
|
+
const isProject = hasGit || hasPackageJson || hasCargoToml || hasPyproject || hasGoMod
|
|
51
|
+
|
|
52
|
+
if (!isProject && !force) {
|
|
53
|
+
console.log(warningText(' No project markers found (no .git, package.json, Cargo.toml, etc.)'))
|
|
54
|
+
console.log(dimText(' Use --force to scan anyway, or run inside a project directory.'))
|
|
55
|
+
console.log()
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Scan the repo
|
|
60
|
+
const context = await withSpinner('Scanning repository', () => scanRepo(repoPath))
|
|
61
|
+
|
|
62
|
+
if (!context.name) {
|
|
63
|
+
console.log(warningText(' Could not detect project name. Specify a path to a project root.'))
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Display results
|
|
68
|
+
console.log(successText(` Project: ${context.name}`))
|
|
69
|
+
|
|
70
|
+
if (context.techStack.length > 0) {
|
|
71
|
+
console.log(` ${theme.bold('Tech stack:')} ${dimText(context.techStack.join(', '))}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (context.description) {
|
|
75
|
+
const desc = context.description.split('\n')[0]?.slice(0, 100) || ''
|
|
76
|
+
console.log(` ${theme.bold('Description:')} ${dimText(desc)}`)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (context.recentActivity) {
|
|
80
|
+
const commits = context.recentActivity.split('\n').length
|
|
81
|
+
console.log(` ${theme.bold('Recent commits:')} ${dimText(String(commits))}`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (context.projectInstructions) {
|
|
85
|
+
console.log(` ${theme.bold('CLAUDE.md:')} ${dimText('found')}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Try to store context via brain
|
|
89
|
+
try {
|
|
90
|
+
const summary = [
|
|
91
|
+
`Project "${context.name}" initialized.`,
|
|
92
|
+
context.techStack.length > 0 ? `Tech stack: ${context.techStack.join(', ')}.` : '',
|
|
93
|
+
context.description ? `Description: ${context.description.split('\n')[0]?.slice(0, 200)}` : '',
|
|
94
|
+
context.structure ? `Structure:\n${context.structure.split('\n').slice(0, 15).join('\n')}` : '',
|
|
95
|
+
context.recentActivity ? `Recent git activity:\n${context.recentActivity}` : '',
|
|
96
|
+
context.projectInstructions ? `CLAUDE.md contents:\n${context.projectInstructions.slice(0, 500)}` : ''
|
|
97
|
+
].filter(Boolean).join('\n\n')
|
|
98
|
+
|
|
99
|
+
// Write to a local init file so the MCP server can pick it up
|
|
100
|
+
const { existsSync, mkdirSync } = await import('fs')
|
|
101
|
+
const { writeFileSync } = await import('fs')
|
|
102
|
+
const dataDir = path.join(repoPath, '.claude-brain')
|
|
103
|
+
if (!existsSync(dataDir)) {
|
|
104
|
+
mkdirSync(dataDir, { recursive: true })
|
|
105
|
+
}
|
|
106
|
+
writeFileSync(path.join(dataDir, 'init-context.md'), summary)
|
|
107
|
+
|
|
108
|
+
console.log()
|
|
109
|
+
console.log(successText(` Initial context saved to .claude-brain/init-context.md`))
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.log(warningText(` Could not save context: ${error instanceof Error ? error.message : 'unknown error'}`))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log()
|
|
115
|
+
console.log(box([
|
|
116
|
+
heading('Project initialized!'),
|
|
117
|
+
'',
|
|
118
|
+
dimText('Brain will auto-load this context in future sessions.'),
|
|
119
|
+
dimText('Use brain tool to store additional decisions and patterns.'),
|
|
120
|
+
].join('\n'), 'Done'))
|
|
121
|
+
console.log()
|
|
122
|
+
}
|