claude-brain 0.30.2 → 0.30.3
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 +241 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +29 -29
- package/package.json +7 -3
- 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 +531 -531
- package/src/automation/decision-detector.ts +452 -452
- 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 +210 -205
- package/src/cli/auto-setup.ts +75 -75
- package/src/cli/auto-start.ts +266 -266
- package/src/cli/bin.ts +264 -264
- package/src/cli/commands/autostart.ts +90 -90
- package/src/cli/commands/chroma.ts +578 -577
- package/src/cli/commands/export-training.ts +70 -70
- package/src/cli/commands/export.ts +130 -130
- package/src/cli/commands/git-hook.ts +183 -183
- package/src/cli/commands/hooks.ts +217 -217
- package/src/cli/commands/init.ts +123 -123
- package/src/cli/commands/install-mcp.ts +122 -111
- package/src/cli/commands/models.ts +979 -979
- package/src/cli/commands/pack.ts +200 -200
- package/src/cli/commands/refresh.ts +344 -339
- package/src/cli/commands/reindex.ts +120 -120
- package/src/cli/commands/serve.ts +466 -463
- package/src/cli/commands/start.ts +44 -44
- package/src/cli/commands/status.ts +220 -203
- package/src/cli/commands/uninstall-mcp.ts +45 -41
- package/src/cli/commands/update.ts +130 -124
- package/src/cli/migrate-chroma.ts +106 -106
- 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/code-intelligence/indexer.ts +352 -352
- package/src/code-intelligence/linker.ts +178 -178
- package/src/code-intelligence/parser.ts +484 -484
- package/src/code-intelligence/query.ts +291 -291
- package/src/code-intelligence/schema.ts +83 -83
- package/src/code-intelligence/types.ts +95 -95
- package/src/config/defaults.ts +52 -52
- package/src/config/home.ts +56 -56
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +192 -192
- package/src/config/schema.ts +446 -415
- package/src/config/validator.ts +182 -182
- package/src/context/assembler.ts +407 -400
- package/src/context/index.ts +79 -79
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +122 -121
- package/src/health/index.ts +233 -232
- package/src/hooks/brain-hook.ts +134 -131
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/claude-code-mastery.md +112 -112
- package/src/hooks/context-hook.ts +260 -245
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +211 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +306 -288
- package/src/hooks/interceptor-hook.ts +204 -201
- package/src/hooks/passive-classifier.ts +397 -397
- package/src/hooks/queue.ts +160 -129
- package/src/hooks/session-tracker.ts +312 -312
- package/src/hooks/types.ts +52 -52
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +7 -7
- package/src/intelligence/hf-downloader.ts +222 -222
- package/src/intelligence/hf-manifest.json +78 -78
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/inference-router.ts +762 -762
- package/src/intelligence/model-manager.ts +263 -245
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +213 -207
- package/src/intelligence/prediction/index.ts +7 -7
- package/src/intelligence/prediction/recommender.ts +276 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +243 -247
- package/src/intelligence/reasoning/index.ts +7 -7
- package/src/intelligence/temporal/evolution.ts +193 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +272 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/intelligence/tokenizer.ts +118 -118
- package/src/knowledge/entity-extractor.ts +447 -443
- 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 +166 -166
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +211 -192
- package/src/memory/chroma/collection-manager.ts +92 -92
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +177 -175
- 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 +319 -315
- package/src/memory/chroma/store.ts +755 -747
- package/src/memory/compression.ts +121 -121
- package/src/memory/consolidation/archiver.ts +162 -165
- package/src/memory/consolidation/merger.ts +182 -186
- package/src/memory/consolidation/scorer.ts +136 -136
- package/src/memory/database.ts +9 -0
- package/src/memory/dual-write.ts +145 -0
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +347 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/fts5-search.ts +692 -633
- package/src/memory/index.ts +943 -1060
- package/src/memory/migrations/add-fts5.ts +118 -108
- package/src/memory/patterns.ts +438 -438
- package/src/memory/pruning.ts +60 -60
- package/src/memory/schema.ts +88 -88
- package/src/memory/store.ts +911 -787
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- 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 -297
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +221 -221
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +221 -221
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +165 -165
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +203 -203
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +252 -252
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +189 -188
- package/src/retrieval/reranker/model.ts +99 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +454 -454
- package/src/routing/handlers/exploration-handler.ts +369 -0
- package/src/routing/handlers/index.ts +19 -0
- package/src/routing/handlers/memory-handler.ts +273 -0
- package/src/routing/handlers/mutation-handler.ts +241 -0
- package/src/routing/handlers/recall-handler.ts +642 -0
- package/src/routing/handlers/shared.ts +515 -0
- package/src/routing/handlers/types.ts +48 -0
- package/src/routing/intent-classifier.ts +552 -552
- package/src/routing/response-filter.ts +399 -391
- package/src/routing/router.ts +245 -2193
- package/src/routing/search-engine.ts +521 -514
- package/src/routing/types.ts +104 -94
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/auto-updater.ts +283 -276
- package/src/server/handlers/call-tool.ts +159 -159
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/auto-remember.ts +165 -165
- package/src/server/handlers/tools/brain.ts +86 -86
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/get-code-standards.ts +123 -123
- package/src/server/handlers/tools/get-corrections.ts +152 -152
- package/src/server/handlers/tools/get-patterns.ts +156 -156
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/index.ts +30 -30
- package/src/server/handlers/tools/init-project.ts +756 -756
- package/src/server/handlers/tools/list-projects.ts +126 -126
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +132 -132
- package/src/server/handlers/tools/record-correction.ts +131 -131
- package/src/server/handlers/tools/remember-decision.ts +168 -168
- package/src/server/handlers/tools/schemas.ts +179 -179
- package/src/server/handlers/tools/search-code.ts +122 -122
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/http-api.ts +215 -1229
- package/src/server/mcp-proxy.ts +85 -84
- package/src/server/mcp-server.ts +285 -284
- package/src/server/middleware/auth.ts +39 -0
- package/src/server/middleware/error-handler.ts +37 -0
- package/src/server/middleware/rate-limit.ts +53 -0
- package/src/server/middleware/validate.ts +42 -0
- package/src/server/pid-manager.ts +137 -136
- package/src/server/providers/resources.ts +581 -581
- package/src/server/routes/code.ts +228 -0
- package/src/server/routes/context.ts +26 -0
- package/src/server/routes/health.ts +19 -0
- package/src/server/routes/helpers.ts +100 -0
- package/src/server/routes/hooks.ts +197 -0
- package/src/server/routes/mcp.ts +47 -0
- package/src/server/routes/memory.ts +397 -0
- package/src/server/routes/models.ts +96 -0
- package/src/server/routes/projects.ts +89 -0
- package/src/server/routes/types.ts +21 -0
- package/src/server/schemas/api-schemas.ts +202 -0
- package/src/server/services.ts +720 -720
- package/src/server/utils/memory-indicator.ts +84 -84
- package/src/server/utils/response-formatter.ts +129 -129
- package/src/server/web-viewer.ts +1145 -1115
- package/src/setup/index.ts +38 -38
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.ts +666 -666
- package/src/tools/types.ts +412 -412
- package/src/training/data-store.ts +320 -298
- package/src/training/retrain-pipeline.ts +399 -394
- package/src/utils/error-handler.ts +136 -136
- package/src/utils/index.ts +58 -58
- package/src/utils/kill-port.ts +55 -53
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/safe-path.ts +43 -0
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/index.ts +4 -3
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +4 -1
- package/src/vault/reader.ts +44 -1
- package/src/vault/watcher.ts +24 -1
- package/src/vault/writer.ts +487 -413
- package/skills/persistent-memory/SKILL.md +0 -148
- package/skills/persistent-memory/references/tool-reference.md +0 -90
|
@@ -1,276 +1,283 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-updater for claude-brain.
|
|
3
|
-
* Checks npm for new versions periodically, auto-updates with ghost process cleanup and fresh restart.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs'
|
|
8
|
-
import { join, dirname, resolve } from 'node:path'
|
|
9
|
-
import { homedir, platform } from 'node:os'
|
|
10
|
-
import { fileURLToPath } from 'node:url'
|
|
11
|
-
import { killProcessOnPort } from '@/utils/kill-port'
|
|
12
|
-
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
14
|
-
const __dirname = dirname(__filename)
|
|
15
|
-
const PACKAGE_ROOT = resolve(__dirname, '..', '..')
|
|
16
|
-
|
|
17
|
-
interface UpdateCheckResult {
|
|
18
|
-
currentVersion: string
|
|
19
|
-
latestVersion: string | null
|
|
20
|
-
updateAvailable: boolean
|
|
21
|
-
lastChecked: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface AutoUpdateConfig {
|
|
25
|
-
enabled: boolean
|
|
26
|
-
checkIntervalHours: number
|
|
27
|
-
autoRestart: boolean
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const DEFAULT_CONFIG: AutoUpdateConfig = {
|
|
31
|
-
enabled: true,
|
|
32
|
-
checkIntervalHours: 24,
|
|
33
|
-
autoRestart: true,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const isWindows = platform() === 'win32'
|
|
37
|
-
|
|
38
|
-
export class AutoUpdater {
|
|
39
|
-
private dataDir: string
|
|
40
|
-
private checkFile: string
|
|
41
|
-
private config: AutoUpdateConfig
|
|
42
|
-
private timer: ReturnType<typeof setInterval> | null = null
|
|
43
|
-
private logger: { info: (...args:
|
|
44
|
-
|
|
45
|
-
constructor(config?: Partial<AutoUpdateConfig>, logger?:
|
|
46
|
-
this.config = { ...DEFAULT_CONFIG, ...config }
|
|
47
|
-
this.dataDir = join(homedir(), '.claude-brain', 'data')
|
|
48
|
-
this.checkFile = join(this.dataDir, 'update-check.json')
|
|
49
|
-
this.logger = logger ?? {
|
|
50
|
-
info: (...args:
|
|
51
|
-
warn: (...args:
|
|
52
|
-
error: (...args:
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Check npm registry for latest version */
|
|
57
|
-
async check(): Promise<UpdateCheckResult> {
|
|
58
|
-
const currentVersion = this.getCurrentVersion()
|
|
59
|
-
|
|
60
|
-
// Return cached result if checked recently
|
|
61
|
-
if (!this.shouldCheck()) {
|
|
62
|
-
try {
|
|
63
|
-
const cached = JSON.parse(readFileSync(this.checkFile, 'utf-8')) as UpdateCheckResult
|
|
64
|
-
return { ...cached, currentVersion }
|
|
65
|
-
} catch {
|
|
66
|
-
// Corrupted cache, proceed with fresh check
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let latestVersion: string | null = null
|
|
71
|
-
try {
|
|
72
|
-
const result =
|
|
73
|
-
encoding: 'utf-8',
|
|
74
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
75
|
-
timeout: 15_000,
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.logger.
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.timer
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
this.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Auto-updater for claude-brain.
|
|
3
|
+
* Checks npm for new versions periodically, auto-updates with ghost process cleanup and fresh restart.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { spawnSync, spawn } from 'node:child_process'
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs'
|
|
8
|
+
import { join, dirname, resolve } from 'node:path'
|
|
9
|
+
import { homedir, platform } from 'node:os'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
import { killProcessOnPort } from '@/utils/kill-port'
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
14
|
+
const __dirname = dirname(__filename)
|
|
15
|
+
const PACKAGE_ROOT = resolve(__dirname, '..', '..')
|
|
16
|
+
|
|
17
|
+
interface UpdateCheckResult {
|
|
18
|
+
currentVersion: string
|
|
19
|
+
latestVersion: string | null
|
|
20
|
+
updateAvailable: boolean
|
|
21
|
+
lastChecked: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface AutoUpdateConfig {
|
|
25
|
+
enabled: boolean
|
|
26
|
+
checkIntervalHours: number
|
|
27
|
+
autoRestart: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DEFAULT_CONFIG: AutoUpdateConfig = {
|
|
31
|
+
enabled: true,
|
|
32
|
+
checkIntervalHours: 24,
|
|
33
|
+
autoRestart: true,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const isWindows = platform() === 'win32'
|
|
37
|
+
|
|
38
|
+
export class AutoUpdater {
|
|
39
|
+
private dataDir: string
|
|
40
|
+
private checkFile: string
|
|
41
|
+
private config: AutoUpdateConfig
|
|
42
|
+
private timer: ReturnType<typeof setInterval> | null = null
|
|
43
|
+
private logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }
|
|
44
|
+
|
|
45
|
+
constructor(config?: Partial<AutoUpdateConfig>, logger?: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }) {
|
|
46
|
+
this.config = { ...DEFAULT_CONFIG, ...config }
|
|
47
|
+
this.dataDir = join(homedir(), '.claude-brain', 'data')
|
|
48
|
+
this.checkFile = join(this.dataDir, 'update-check.json')
|
|
49
|
+
this.logger = logger ?? {
|
|
50
|
+
info: (...args: unknown[]) => console.error('[auto-updater] INFO:', ...args),
|
|
51
|
+
warn: (...args: unknown[]) => console.error('[auto-updater] WARN:', ...args),
|
|
52
|
+
error: (...args: unknown[]) => console.error('[auto-updater] ERROR:', ...args),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Check npm registry for latest version */
|
|
57
|
+
async check(): Promise<UpdateCheckResult> {
|
|
58
|
+
const currentVersion = this.getCurrentVersion()
|
|
59
|
+
|
|
60
|
+
// Return cached result if checked recently
|
|
61
|
+
if (!this.shouldCheck()) {
|
|
62
|
+
try {
|
|
63
|
+
const cached = JSON.parse(readFileSync(this.checkFile, 'utf-8')) as UpdateCheckResult
|
|
64
|
+
return { ...cached, currentVersion }
|
|
65
|
+
} catch {
|
|
66
|
+
// Corrupted cache, proceed with fresh check
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let latestVersion: string | null = null
|
|
71
|
+
try {
|
|
72
|
+
const result = spawnSync('npm', ['view', 'claude-brain', 'version'], {
|
|
73
|
+
encoding: 'utf-8',
|
|
74
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
75
|
+
timeout: 15_000,
|
|
76
|
+
})
|
|
77
|
+
if (result.error || result.status !== 0) {
|
|
78
|
+
this.logger.warn('Failed to check npm registry for latest version')
|
|
79
|
+
} else {
|
|
80
|
+
latestVersion = result.stdout?.trim() || null
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
this.logger.warn('Failed to check npm registry for latest version')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const updateAvailable = latestVersion !== null && latestVersion !== currentVersion
|
|
87
|
+
const checkResult: UpdateCheckResult = {
|
|
88
|
+
currentVersion,
|
|
89
|
+
latestVersion,
|
|
90
|
+
updateAvailable,
|
|
91
|
+
lastChecked: new Date().toISOString(),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Persist check result
|
|
95
|
+
try {
|
|
96
|
+
mkdirSync(this.dataDir, { recursive: true })
|
|
97
|
+
writeFileSync(this.checkFile, JSON.stringify(checkResult, null, 2), 'utf-8')
|
|
98
|
+
} catch (err) {
|
|
99
|
+
this.logger.warn('Failed to write update check file:', err)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (updateAvailable) {
|
|
103
|
+
this.logger.info(`Update available: v${currentVersion} -> v${latestVersion}`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return checkResult
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Perform the update: kill ghosts -> update package -> restart */
|
|
110
|
+
async performUpdate(targetVersion: string): Promise<boolean> {
|
|
111
|
+
try {
|
|
112
|
+
this.logger.info(`Updating claude-brain to v${targetVersion}...`)
|
|
113
|
+
|
|
114
|
+
// Kill ghost processes
|
|
115
|
+
this.killGhostProcesses()
|
|
116
|
+
|
|
117
|
+
// Wait for ports to release
|
|
118
|
+
await this.sleep(2000)
|
|
119
|
+
|
|
120
|
+
// Try bun first, fallback to npm
|
|
121
|
+
const bunResult = spawnSync('bun', ['install', '-g', 'claude-brain@latest'], {
|
|
122
|
+
encoding: 'utf-8',
|
|
123
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
124
|
+
timeout: 120_000,
|
|
125
|
+
})
|
|
126
|
+
if (!bunResult.error && bunResult.status === 0) {
|
|
127
|
+
this.logger.info(`Updated to v${targetVersion} via bun`)
|
|
128
|
+
} else {
|
|
129
|
+
const npmResult = spawnSync('npm', ['install', '-g', 'claude-brain@latest'], {
|
|
130
|
+
encoding: 'utf-8',
|
|
131
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
132
|
+
timeout: 120_000,
|
|
133
|
+
})
|
|
134
|
+
if (!npmResult.error && npmResult.status === 0) {
|
|
135
|
+
this.logger.info(`Updated to v${targetVersion} via npm`)
|
|
136
|
+
} else {
|
|
137
|
+
this.logger.error('Install failed with both bun and npm:', npmResult.stderr || npmResult.error)
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (this.config.autoRestart) {
|
|
143
|
+
this.restartServer()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return true
|
|
147
|
+
} catch (err) {
|
|
148
|
+
this.logger.error('Update failed:', err)
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Schedule periodic background checks */
|
|
154
|
+
schedulePeriodicCheck(): void {
|
|
155
|
+
if (!this.config.enabled) return
|
|
156
|
+
if (this.timer) return
|
|
157
|
+
|
|
158
|
+
const intervalMs = this.config.checkIntervalHours * 3600 * 1000
|
|
159
|
+
|
|
160
|
+
this.timer = setInterval(async () => {
|
|
161
|
+
try {
|
|
162
|
+
const result = await this.check()
|
|
163
|
+
if (result.updateAvailable && result.latestVersion && this.config.enabled) {
|
|
164
|
+
await this.performUpdate(result.latestVersion)
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
this.logger.error('Periodic update check failed:', err)
|
|
168
|
+
}
|
|
169
|
+
}, intervalMs)
|
|
170
|
+
|
|
171
|
+
// Don't keep the process alive just for the update timer
|
|
172
|
+
if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {
|
|
173
|
+
this.timer.unref()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.logger.info(`Scheduled update checks every ${this.config.checkIntervalHours}h`)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Stop periodic checks */
|
|
180
|
+
stopPeriodicCheck(): void {
|
|
181
|
+
if (this.timer) {
|
|
182
|
+
clearInterval(this.timer)
|
|
183
|
+
this.timer = null
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Check if enough time has passed since last check */
|
|
188
|
+
private shouldCheck(): boolean {
|
|
189
|
+
if (!existsSync(this.checkFile)) return true
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const data = JSON.parse(readFileSync(this.checkFile, 'utf-8')) as UpdateCheckResult
|
|
193
|
+
if (!data.lastChecked) return true
|
|
194
|
+
|
|
195
|
+
const lastChecked = new Date(data.lastChecked).getTime()
|
|
196
|
+
const intervalMs = this.config.checkIntervalHours * 3600 * 1000
|
|
197
|
+
return Date.now() - lastChecked >= intervalMs
|
|
198
|
+
} catch {
|
|
199
|
+
return true
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Kill all ghost claude-brain processes */
|
|
204
|
+
private killGhostProcesses(): void {
|
|
205
|
+
const myPid = process.pid
|
|
206
|
+
|
|
207
|
+
// Kill by pattern
|
|
208
|
+
try {
|
|
209
|
+
if (isWindows) {
|
|
210
|
+
const result = spawnSync('wmic', [
|
|
211
|
+
'process', 'where',
|
|
212
|
+
`commandline like '%claude-brain%' and processid != ${myPid}`,
|
|
213
|
+
'get', 'processid', '/format:list',
|
|
214
|
+
], { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 })
|
|
215
|
+
const output = result.stdout || ''
|
|
216
|
+
const pids = output.match(/ProcessId=(\d+)/g)?.map(m => m.split('=')[1]) || []
|
|
217
|
+
for (const pid of pids) {
|
|
218
|
+
try { spawnSync('taskkill', ['/F', '/PID', pid!], { stdio: 'pipe', timeout: 5000 }) } catch {}
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
const result = spawnSync('pgrep', ['-f', 'claude-brain'], {
|
|
222
|
+
encoding: 'utf-8', stdio: 'pipe', timeout: 5000,
|
|
223
|
+
})
|
|
224
|
+
const output = result.stdout?.trim() || ''
|
|
225
|
+
const pids = output.split('\n').filter(p => p && Number(p) !== myPid)
|
|
226
|
+
for (const pid of pids) {
|
|
227
|
+
try { process.kill(Number(pid), 'SIGKILL') } catch {}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
// No matching processes — that's fine
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Kill by port 3000 using shared utility
|
|
235
|
+
killProcessOnPort(3000, myPid)
|
|
236
|
+
|
|
237
|
+
// Clean up stale PID files
|
|
238
|
+
const pidPath = join(this.dataDir, 'server.pid')
|
|
239
|
+
if (existsSync(pidPath)) {
|
|
240
|
+
try {
|
|
241
|
+
const pid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10)
|
|
242
|
+
if (!isNaN(pid) && pid !== myPid) {
|
|
243
|
+
try { process.kill(pid, 0) } catch {
|
|
244
|
+
// Process not running, remove stale PID file
|
|
245
|
+
try { unlinkSync(pidPath) } catch {}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
} catch {}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Spawn a fresh server instance and exit current */
|
|
253
|
+
private restartServer(): void {
|
|
254
|
+
this.logger.info('Restarting server with updated version...')
|
|
255
|
+
|
|
256
|
+
const child = spawn('claude-brain', ['serve'], {
|
|
257
|
+
detached: true,
|
|
258
|
+
stdio: 'ignore',
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
child.unref()
|
|
262
|
+
|
|
263
|
+
this.logger.info(`Spawned new server process (PID: ${child.pid}). Exiting current process.`)
|
|
264
|
+
process.exit(0)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Get current installed version from package.json */
|
|
268
|
+
private getCurrentVersion(): string {
|
|
269
|
+
try {
|
|
270
|
+
// Use the version from the package that's actually running
|
|
271
|
+
const pkgPath = join(PACKAGE_ROOT, 'package.json')
|
|
272
|
+
if (existsSync(pkgPath)) {
|
|
273
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
274
|
+
return pkg.version || 'unknown'
|
|
275
|
+
}
|
|
276
|
+
} catch {}
|
|
277
|
+
return 'unknown'
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private sleep(ms: number): Promise<void> {
|
|
281
|
+
return new Promise(resolve => setTimeout(resolve, ms))
|
|
282
|
+
}
|
|
283
|
+
}
|