claude-brain 0.5.0 → 0.5.1
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/VERSION +1 -1
- package/package.json +1 -1
- package/src/cli/commands/chroma.ts +53 -17
- package/src/config/defaults.ts +1 -1
- package/src/config/schema.ts +1 -1
- package/src/memory/chroma/client.ts +1 -1
- package/src/memory/chroma/index.ts +1 -1
- package/src/memory/chroma/store.ts +27 -8
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.5.
|
|
1
|
+
0.5.1
|
package/package.json
CHANGED
|
@@ -29,25 +29,53 @@ function getChromaDataPath(): string {
|
|
|
29
29
|
* Find the chroma binary - checks PATH first, then common pip install locations
|
|
30
30
|
*/
|
|
31
31
|
function findChromaBinary(): string | null {
|
|
32
|
+
const isWindows = process.platform === 'win32'
|
|
33
|
+
const chromaName = isWindows ? 'chroma.exe' : 'chroma'
|
|
34
|
+
|
|
32
35
|
// Try bare 'chroma' first (on PATH)
|
|
33
36
|
try {
|
|
34
37
|
execSync('chroma --version', { stdio: 'pipe', timeout: 5000 })
|
|
35
38
|
return 'chroma'
|
|
36
39
|
} catch {}
|
|
37
40
|
|
|
38
|
-
// Search common pip install locations
|
|
39
41
|
const { homedir } = require('os')
|
|
40
42
|
const home = homedir()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
|
|
44
|
+
// Platform-specific search paths
|
|
45
|
+
const candidates: string[] = isWindows
|
|
46
|
+
? [
|
|
47
|
+
// Windows pip install locations
|
|
48
|
+
join(home, 'AppData', 'Local', 'Programs', 'Python', 'Python39', 'Scripts', chromaName),
|
|
49
|
+
join(home, 'AppData', 'Local', 'Programs', 'Python', 'Python310', 'Scripts', chromaName),
|
|
50
|
+
join(home, 'AppData', 'Local', 'Programs', 'Python', 'Python311', 'Scripts', chromaName),
|
|
51
|
+
join(home, 'AppData', 'Local', 'Programs', 'Python', 'Python312', 'Scripts', chromaName),
|
|
52
|
+
join(home, 'AppData', 'Local', 'Programs', 'Python', 'Python313', 'Scripts', chromaName),
|
|
53
|
+
// Windows user pip install (pip install --user)
|
|
54
|
+
join(home, 'AppData', 'Roaming', 'Python', 'Python39', 'Scripts', chromaName),
|
|
55
|
+
join(home, 'AppData', 'Roaming', 'Python', 'Python310', 'Scripts', chromaName),
|
|
56
|
+
join(home, 'AppData', 'Roaming', 'Python', 'Python311', 'Scripts', chromaName),
|
|
57
|
+
join(home, 'AppData', 'Roaming', 'Python', 'Python312', 'Scripts', chromaName),
|
|
58
|
+
join(home, 'AppData', 'Roaming', 'Python', 'Python313', 'Scripts', chromaName),
|
|
59
|
+
// Scoop / Chocolatey / winget
|
|
60
|
+
join(home, 'scoop', 'shims', chromaName),
|
|
61
|
+
'C:\\Python39\\Scripts\\' + chromaName,
|
|
62
|
+
'C:\\Python310\\Scripts\\' + chromaName,
|
|
63
|
+
'C:\\Python311\\Scripts\\' + chromaName,
|
|
64
|
+
'C:\\Python312\\Scripts\\' + chromaName,
|
|
65
|
+
'C:\\Python313\\Scripts\\' + chromaName,
|
|
66
|
+
]
|
|
67
|
+
: [
|
|
68
|
+
// macOS pip install locations
|
|
69
|
+
join(home, 'Library', 'Python', '3.9', 'bin', chromaName),
|
|
70
|
+
join(home, 'Library', 'Python', '3.10', 'bin', chromaName),
|
|
71
|
+
join(home, 'Library', 'Python', '3.11', 'bin', chromaName),
|
|
72
|
+
join(home, 'Library', 'Python', '3.12', 'bin', chromaName),
|
|
73
|
+
join(home, 'Library', 'Python', '3.13', 'bin', chromaName),
|
|
74
|
+
// Linux pip install locations
|
|
75
|
+
join(home, '.local', 'bin', chromaName),
|
|
76
|
+
'/usr/local/bin/' + chromaName,
|
|
77
|
+
'/opt/homebrew/bin/' + chromaName,
|
|
78
|
+
]
|
|
51
79
|
|
|
52
80
|
for (const candidate of candidates) {
|
|
53
81
|
try {
|
|
@@ -58,15 +86,23 @@ function findChromaBinary(): string | null {
|
|
|
58
86
|
} catch {}
|
|
59
87
|
}
|
|
60
88
|
|
|
61
|
-
// Try finding via python -m site
|
|
89
|
+
// Try finding via python -m site (works on all platforms)
|
|
90
|
+
const pythonCmd = isWindows ? 'python' : 'python3'
|
|
62
91
|
try {
|
|
63
|
-
const sitePackages = execSync(
|
|
92
|
+
const sitePackages = execSync(`${pythonCmd} -c "import site; print(site.getusersitepackages())"`, {
|
|
64
93
|
encoding: 'utf-8', stdio: 'pipe', timeout: 5000
|
|
65
94
|
}).trim()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
|
|
96
|
+
let binDir: string
|
|
97
|
+
if (isWindows) {
|
|
98
|
+
// Windows: C:\Users\x\AppData\Roaming\Python\Python311\site-packages → Scripts
|
|
99
|
+
binDir = sitePackages.replace(/[\\\/]site-packages$/, '\\Scripts')
|
|
100
|
+
} else {
|
|
101
|
+
// Unix: /Users/x/Library/Python/3.9/lib/python/site-packages → bin
|
|
102
|
+
binDir = sitePackages.replace(/\/lib\/.*/, '/bin')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const chromaPath = join(binDir, chromaName)
|
|
70
106
|
if (existsSync(chromaPath)) {
|
|
71
107
|
execSync(`"${chromaPath}" --version`, { stdio: 'pipe', timeout: 5000 })
|
|
72
108
|
return chromaPath
|
package/src/config/defaults.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { PartialConfig } from './schema'
|
|
|
3
3
|
/** Default configuration values for Claude Brain */
|
|
4
4
|
export const defaultConfig: PartialConfig = {
|
|
5
5
|
serverName: 'claude-brain',
|
|
6
|
-
serverVersion: '0.5.
|
|
6
|
+
serverVersion: '0.5.1',
|
|
7
7
|
logLevel: 'info',
|
|
8
8
|
logFilePath: './logs/claude-brain.log',
|
|
9
9
|
dbPath: './data/memory.db',
|
package/src/config/schema.ts
CHANGED
|
@@ -196,7 +196,7 @@ export const ConfigSchema = z.object({
|
|
|
196
196
|
serverName: z.string().default('claude-brain'),
|
|
197
197
|
|
|
198
198
|
/** Server version in semver format */
|
|
199
|
-
serverVersion: z.string().regex(/^\d+\.\d+\.\d+$/, 'Version must be semver format').default('0.5.
|
|
199
|
+
serverVersion: z.string().regex(/^\d+\.\d+\.\d+$/, 'Version must be semver format').default('0.5.1'),
|
|
200
200
|
|
|
201
201
|
/** Logging level */
|
|
202
202
|
logLevel: LogLevelSchema.default('info'),
|
|
@@ -6,6 +6,25 @@ import type { DecisionMetadata, MemoryMetadata } from './schemas'
|
|
|
6
6
|
import type { EmbeddingProvider } from './embeddings'
|
|
7
7
|
import type { SearchResult } from './search'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Sanitize metadata for ChromaDB v3.x compatibility.
|
|
11
|
+
* Strips undefined/null values (ChromaDB only accepts string, number, boolean).
|
|
12
|
+
*/
|
|
13
|
+
function sanitizeMetadata(metadata: Record<string, any>): Record<string, string | number | boolean> {
|
|
14
|
+
const clean: Record<string, string | number | boolean> = {}
|
|
15
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
16
|
+
if (value === undefined || value === null) continue
|
|
17
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
18
|
+
clean[key] = value
|
|
19
|
+
} else if (Array.isArray(value)) {
|
|
20
|
+
clean[key] = JSON.stringify(value)
|
|
21
|
+
} else {
|
|
22
|
+
clean[key] = String(value)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return clean
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
export interface StoreDecisionInput {
|
|
10
29
|
project: string
|
|
11
30
|
context: string
|
|
@@ -145,7 +164,7 @@ export class ChromaMemoryStore {
|
|
|
145
164
|
await collection.add({
|
|
146
165
|
ids: [id],
|
|
147
166
|
documents: [input.decision],
|
|
148
|
-
metadatas: [metadata as Record<string, any>],
|
|
167
|
+
metadatas: [sanitizeMetadata(metadata as Record<string, any>)],
|
|
149
168
|
...(embeddings ? { embeddings } : {})
|
|
150
169
|
})
|
|
151
170
|
|
|
@@ -166,7 +185,7 @@ export class ChromaMemoryStore {
|
|
|
166
185
|
await memoriesCollection.add({
|
|
167
186
|
ids: [id], // Use same ID for cross-reference
|
|
168
187
|
documents: [memoryContent],
|
|
169
|
-
metadatas: [memoryMetadata],
|
|
188
|
+
metadatas: [sanitizeMetadata(memoryMetadata)],
|
|
170
189
|
...(embeddings ? { embeddings } : {})
|
|
171
190
|
})
|
|
172
191
|
|
|
@@ -230,7 +249,7 @@ export class ChromaMemoryStore {
|
|
|
230
249
|
await collection.add({
|
|
231
250
|
ids: [id],
|
|
232
251
|
documents: [input.description],
|
|
233
|
-
metadatas: [metadata],
|
|
252
|
+
metadatas: [sanitizeMetadata(metadata)],
|
|
234
253
|
...(embeddings ? { embeddings } : {})
|
|
235
254
|
})
|
|
236
255
|
|
|
@@ -252,7 +271,7 @@ export class ChromaMemoryStore {
|
|
|
252
271
|
await memoriesCollection.add({
|
|
253
272
|
ids: [id],
|
|
254
273
|
documents: [memoryContent],
|
|
255
|
-
metadatas: [memoryMetadata],
|
|
274
|
+
metadatas: [sanitizeMetadata(memoryMetadata)],
|
|
256
275
|
...(embeddings ? { embeddings } : {})
|
|
257
276
|
})
|
|
258
277
|
|
|
@@ -304,7 +323,7 @@ export class ChromaMemoryStore {
|
|
|
304
323
|
await collection.add({
|
|
305
324
|
ids: [id],
|
|
306
325
|
documents: [input.correction],
|
|
307
|
-
metadatas: [metadata],
|
|
326
|
+
metadatas: [sanitizeMetadata(metadata)],
|
|
308
327
|
...(embeddings ? { embeddings } : {})
|
|
309
328
|
})
|
|
310
329
|
|
|
@@ -325,7 +344,7 @@ export class ChromaMemoryStore {
|
|
|
325
344
|
await memoriesCollection.add({
|
|
326
345
|
ids: [id],
|
|
327
346
|
documents: [memoryContent],
|
|
328
|
-
metadatas: [memoryMetadata],
|
|
347
|
+
metadatas: [sanitizeMetadata(memoryMetadata)],
|
|
329
348
|
...(embeddings ? { embeddings } : {})
|
|
330
349
|
})
|
|
331
350
|
|
|
@@ -367,7 +386,7 @@ export class ChromaMemoryStore {
|
|
|
367
386
|
await collection.add({
|
|
368
387
|
ids: [id],
|
|
369
388
|
documents: [input.content],
|
|
370
|
-
metadatas: [metadata as Record<string, any>],
|
|
389
|
+
metadatas: [sanitizeMetadata(metadata as Record<string, any>)],
|
|
371
390
|
...(embeddings ? { embeddings } : {})
|
|
372
391
|
})
|
|
373
392
|
|
|
@@ -409,7 +428,7 @@ export class ChromaMemoryStore {
|
|
|
409
428
|
await collection.upsert({
|
|
410
429
|
ids: [id],
|
|
411
430
|
documents: [input.decision],
|
|
412
|
-
metadatas: [metadata as Record<string, any>],
|
|
431
|
+
metadatas: [sanitizeMetadata(metadata as Record<string, any>)],
|
|
413
432
|
...(embeddings ? { embeddings } : {})
|
|
414
433
|
})
|
|
415
434
|
|