claude-brain 0.17.13 → 0.17.14
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/hooks/brain-hook.ts +4 -1
- package/src/hooks/context-hook.ts +4 -1
- package/src/hooks/installer.ts +4 -7
- package/src/routing/router.ts +54 -3
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.17.
|
|
1
|
+
0.17.14
|
package/package.json
CHANGED
package/src/hooks/brain-hook.ts
CHANGED
|
@@ -52,7 +52,10 @@ export async function main(): Promise<void> {
|
|
|
52
52
|
return
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
// BUG-006: Read port from --port arg (cross-platform) or env var fallback
|
|
56
|
+
const portIdx = process.argv.indexOf('--port')
|
|
57
|
+
const portArg = portIdx >= 0 ? process.argv[portIdx + 1] : undefined
|
|
58
|
+
const port = parseInt(portArg || process.env.CLAUDE_BRAIN_PORT || '3000', 10)
|
|
56
59
|
|
|
57
60
|
// For Stop events: trigger session-end summarization regardless of classification
|
|
58
61
|
if (input.hook_event_name === 'Stop' && input.session_id) {
|
|
@@ -85,7 +85,10 @@ async function main(): Promise<void> {
|
|
|
85
85
|
return
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
// BUG-006: Read port from --port arg (cross-platform) or env var fallback
|
|
89
|
+
const portIdx = process.argv.indexOf('--port')
|
|
90
|
+
const portArg = portIdx >= 0 ? process.argv[portIdx + 1] : undefined
|
|
91
|
+
const port = parseInt(portArg || process.env.CLAUDE_BRAIN_PORT || '3000', 10)
|
|
89
92
|
const baseUrl = `http://localhost:${port}`
|
|
90
93
|
|
|
91
94
|
let brainContext = ''
|
package/src/hooks/installer.ts
CHANGED
|
@@ -44,17 +44,14 @@ function writeSettings(settings: Record<string, any>): void {
|
|
|
44
44
|
renameSync(tmpPath, CLAUDE_SETTINGS_PATH)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
/** Build the hook command string, embedding the port so hooks work regardless of env
|
|
47
|
+
/** Build the hook command string, embedding the port so hooks work regardless of env.
|
|
48
|
+
* BUG-006: settings.json syncs across platforms. We use --port arg instead of
|
|
49
|
+
* platform-specific env var syntax (VAR=val on Unix, set VAR=val on Windows). */
|
|
48
50
|
function buildHookCommand(event: string, script: 'brain-hook' | 'context-hook' = 'brain-hook'): string {
|
|
49
51
|
const scriptPath = script === 'context-hook' ? getContextHookScriptPath() : getHookScriptPath()
|
|
50
52
|
const port = process.env.PORT || process.env.CLAUDE_BRAIN_PORT || '3000'
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
if (process.platform === 'win32') {
|
|
54
|
-
return `set CLAUDE_BRAIN_PORT=${port}&& bun "${scriptPath}" --event ${event} # ${HOOK_MARKER}`
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return `CLAUDE_BRAIN_PORT=${port} bun "${scriptPath}" --event ${event} # ${HOOK_MARKER}`
|
|
54
|
+
return `bun "${scriptPath}" --event ${event} --port ${port} # ${HOOK_MARKER}`
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
/**
|
package/src/routing/router.ts
CHANGED
|
@@ -798,6 +798,37 @@ export class BrainRouter {
|
|
|
798
798
|
const memory = getMemoryService()
|
|
799
799
|
const topic = entities.topic || message
|
|
800
800
|
const hasSpecificContent = this.hasDescriptiveContent(message)
|
|
801
|
+
const lower = message.toLowerCase()
|
|
802
|
+
|
|
803
|
+
// BUG-006 T6: Bulk delete — "delete all memories for project X"
|
|
804
|
+
if (lower.includes('delete all') || lower.includes('remove all') || lower.includes('clear all')) {
|
|
805
|
+
const bulkProject = entities.project || project || this.lastStoredProject
|
|
806
|
+
if (bulkProject) {
|
|
807
|
+
try {
|
|
808
|
+
const decisions = await memory.chroma.store.getDecisionsByProject(bulkProject)
|
|
809
|
+
if (decisions.length === 0) {
|
|
810
|
+
return {
|
|
811
|
+
action: 'none',
|
|
812
|
+
summary: 'No memories found',
|
|
813
|
+
content: `No memories found for project "${bulkProject}".`,
|
|
814
|
+
relevantItems: 0
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
for (const d of decisions) {
|
|
818
|
+
await memory.deleteDecision(d.id)
|
|
819
|
+
}
|
|
820
|
+
this.searchEngine.invalidateCache(bulkProject)
|
|
821
|
+
return {
|
|
822
|
+
action: 'stored',
|
|
823
|
+
summary: `Bulk deleted ${decisions.length} memories`,
|
|
824
|
+
content: `Deleted all ${decisions.length} memories for project "${bulkProject}".`,
|
|
825
|
+
relevantItems: 0
|
|
826
|
+
}
|
|
827
|
+
} catch {
|
|
828
|
+
// Bulk delete failed, fall through to single-item delete
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
801
832
|
|
|
802
833
|
if (hasSpecificContent) {
|
|
803
834
|
try {
|
|
@@ -967,8 +998,19 @@ export class BrainRouter {
|
|
|
967
998
|
// C11: Add graph results as "Related Concepts"
|
|
968
999
|
// When a project filter is active, cap graph results lower (0.25) so they don't
|
|
969
1000
|
// outrank project-scoped ChromaDB results. Without a project filter, cap at 0.4.
|
|
1001
|
+
// BUG-006 T4: Also require keyword overlap with query to prevent noise
|
|
970
1002
|
const graphScoreCap = searchProject ? 0.25 : 0.4
|
|
971
|
-
const
|
|
1003
|
+
const queryWordsForGraph = new Set(query.toLowerCase().split(/\s+/).filter(w => w.length > 2))
|
|
1004
|
+
const relevantGraphResults = graphResults.filter(g => {
|
|
1005
|
+
if (g.score < 0.6) return false
|
|
1006
|
+
// Require at least one query keyword to appear in graph content
|
|
1007
|
+
if (queryWordsForGraph.size > 0) {
|
|
1008
|
+
const contentLower = g.content.toLowerCase()
|
|
1009
|
+
const hasOverlap = [...queryWordsForGraph].some(w => contentLower.includes(w))
|
|
1010
|
+
if (!hasOverlap) return false
|
|
1011
|
+
}
|
|
1012
|
+
return true
|
|
1013
|
+
})
|
|
972
1014
|
if (relevantGraphResults.length > 0) {
|
|
973
1015
|
tiers.push({
|
|
974
1016
|
label: 'Related Concepts',
|
|
@@ -1132,12 +1174,21 @@ export class BrainRouter {
|
|
|
1132
1174
|
}
|
|
1133
1175
|
|
|
1134
1176
|
// Always include graph exploration — cap scores when project filter is active
|
|
1177
|
+
// BUG-006 T4: Also require keyword overlap with query to prevent noise
|
|
1135
1178
|
const explorationGraphCap = searchProject ? 0.25 : 0.5
|
|
1179
|
+
const explorationQueryWords = new Set(query.toLowerCase().split(/\s+/).filter(w => w.length > 2))
|
|
1136
1180
|
const graphResults = await this.searchEngine.searchGraph(query, 10)
|
|
1137
|
-
|
|
1181
|
+
const filteredGraphResults = graphResults.filter(g => {
|
|
1182
|
+
if (explorationQueryWords.size > 0) {
|
|
1183
|
+
const contentLower = g.content.toLowerCase()
|
|
1184
|
+
return [...explorationQueryWords].some(w => contentLower.includes(w))
|
|
1185
|
+
}
|
|
1186
|
+
return true
|
|
1187
|
+
})
|
|
1188
|
+
if (filteredGraphResults.length > 0) {
|
|
1138
1189
|
tiers.push({
|
|
1139
1190
|
label: 'Knowledge Graph',
|
|
1140
|
-
results:
|
|
1191
|
+
results: filteredGraphResults.map(g => ({
|
|
1141
1192
|
content: g.content,
|
|
1142
1193
|
score: Math.min(g.score, explorationGraphCap),
|
|
1143
1194
|
source: 'Knowledge Graph',
|