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,200 +1,200 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto Remember Handler
|
|
3
|
-
* Automatically detects and saves decisions from text
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import type { ToolResponse } from '@/tools/types'
|
|
8
|
-
import { getPhase12Service, getVaultService, isServicesInitialized } from '@/server/services'
|
|
9
|
-
import { ToolValidator } from '@/server/utils/validators'
|
|
10
|
-
import { ResponseFormatter } from '@/server/utils/response-formatter'
|
|
11
|
-
import { ErrorHandler } from '@/server/utils/error-handler'
|
|
12
|
-
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'
|
|
13
|
-
import { AutoRememberSchema } from './schemas'
|
|
14
|
-
|
|
15
|
-
export async function handleAutoRemember(
|
|
16
|
-
args: unknown,
|
|
17
|
-
logger: Logger
|
|
18
|
-
): Promise<ToolResponse> {
|
|
19
|
-
try {
|
|
20
|
-
const input = ToolValidator.validate(args, AutoRememberSchema)
|
|
21
|
-
const { project_name, text, confidence_threshold } = input
|
|
22
|
-
|
|
23
|
-
logger.debug({
|
|
24
|
-
project_name,
|
|
25
|
-
textLength: text.length,
|
|
26
|
-
confidence_threshold
|
|
27
|
-
}, 'Auto-remember request')
|
|
28
|
-
|
|
29
|
-
if (!isServicesInitialized()) {
|
|
30
|
-
throw new McpError(
|
|
31
|
-
ErrorCode.InternalError,
|
|
32
|
-
'Services not initialized'
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const phase12 = getPhase12Service()
|
|
37
|
-
const vault = getVaultService()
|
|
38
|
-
|
|
39
|
-
// Verify project exists
|
|
40
|
-
const projectPaths = vault.getProjectPaths(project_name)
|
|
41
|
-
try {
|
|
42
|
-
await vault.reader.readMarkdownFile(projectPaths.decisions)
|
|
43
|
-
} catch {
|
|
44
|
-
throw new McpError(
|
|
45
|
-
ErrorCode.InvalidParams,
|
|
46
|
-
`Project "${project_name}" not found. Use list_projects to see available projects.`
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Detect decision in text
|
|
51
|
-
const detectedDecision = phase12.decisionDetector.detectDecision(text, project_name)
|
|
52
|
-
|
|
53
|
-
if (!detectedDecision) {
|
|
54
|
-
return ResponseFormatter.text(
|
|
55
|
-
`## No Decision Detected\n\n` +
|
|
56
|
-
`Analyzed ${text.length} characters but no clear decision was found.\n\n` +
|
|
57
|
-
`**Tips for auto-detection:**\n` +
|
|
58
|
-
`- Use phrases like "I recommend X because Y"\n` +
|
|
59
|
-
`- Include reasoning: "We should use X because..."\n` +
|
|
60
|
-
`- Be explicit: "The best approach is X"\n\n` +
|
|
61
|
-
`**Alternatively:** Use \`remember_decision\` to manually save a decision.`
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const parts: string[] = []
|
|
66
|
-
parts.push('## Decision Detected\n')
|
|
67
|
-
parts.push(`**Confidence:** ${Math.round(detectedDecision.confidence * 100)}%\n`)
|
|
68
|
-
parts.push(`**Decision:** ${detectedDecision.statement || detectedDecision.decision}\n`)
|
|
69
|
-
|
|
70
|
-
if (detectedDecision.context) {
|
|
71
|
-
parts.push(`**Context:** ${detectedDecision.context}\n`)
|
|
72
|
-
}
|
|
73
|
-
if (detectedDecision.reasoning) {
|
|
74
|
-
parts.push(`**Reasoning:** ${detectedDecision.reasoning}\n`)
|
|
75
|
-
}
|
|
76
|
-
if (detectedDecision.alternatives) {
|
|
77
|
-
parts.push(`**Alternatives:** ${detectedDecision.alternatives}\n`)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check if confidence meets threshold
|
|
81
|
-
if (detectedDecision.confidence < confidence_threshold) {
|
|
82
|
-
parts.push(`\n---\n`)
|
|
83
|
-
parts.push(`⚠️ **Not Auto-Saved** (confidence ${Math.round(detectedDecision.confidence * 100)}% < threshold ${Math.round(confidence_threshold * 100)}%)\n`)
|
|
84
|
-
parts.push(`\nTo save anyway, use \`remember_decision\` manually or lower the confidence_threshold.`)
|
|
85
|
-
|
|
86
|
-
logger.info({
|
|
87
|
-
project_name,
|
|
88
|
-
confidence: detectedDecision.confidence,
|
|
89
|
-
threshold: confidence_threshold,
|
|
90
|
-
saved: false
|
|
91
|
-
}, 'Decision detected but below threshold')
|
|
92
|
-
|
|
93
|
-
return ResponseFormatter.text(parts.join('\n'))
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Auto-save the decision to memory
|
|
97
|
-
const decisionId = await phase12.decisionDetector.autoSaveDecision(
|
|
98
|
-
detectedDecision,
|
|
99
|
-
project_name
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
if (decisionId) {
|
|
103
|
-
// Also write to vault decisions.md
|
|
104
|
-
try {
|
|
105
|
-
const decisionEntry = formatDecisionEntry({
|
|
106
|
-
id: decisionId,
|
|
107
|
-
project: project_name,
|
|
108
|
-
title: detectedDecision.decision,
|
|
109
|
-
context: detectedDecision.context,
|
|
110
|
-
decision: detectedDecision.decision,
|
|
111
|
-
reasoning: detectedDecision.reasoning,
|
|
112
|
-
alternatives: detectedDecision.alternatives,
|
|
113
|
-
tags: detectedDecision.tags || ['auto-detected'],
|
|
114
|
-
timestamp: new Date()
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
await vault.writer.appendContent(projectPaths.decisions, decisionEntry, '\n')
|
|
118
|
-
|
|
119
|
-
// Update frontmatter
|
|
120
|
-
const decisionsFile = await vault.reader.readMarkdownFile(projectPaths.decisions)
|
|
121
|
-
const currentCount = (decisionsFile.frontmatter.decision_count as number) || 0
|
|
122
|
-
await vault.writer.updateFrontmatter(projectPaths.decisions, {
|
|
123
|
-
decision_count: currentCount + 1,
|
|
124
|
-
last_updated: new Date().toISOString().split('T')[0]
|
|
125
|
-
})
|
|
126
|
-
} catch (vaultError) {
|
|
127
|
-
logger.warn({ vaultError }, 'Failed to write to vault, but memory save succeeded')
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
parts.push(`\n---\n`)
|
|
131
|
-
parts.push(`✅ **Auto-Saved Successfully!**\n`)
|
|
132
|
-
parts.push(`**ID:** ${decisionId}\n`)
|
|
133
|
-
parts.push(`**Project:** ${project_name}\n\n`)
|
|
134
|
-
parts.push(`This decision has been:\n`)
|
|
135
|
-
parts.push(`- Stored in semantic memory (searchable via \`recall_similar\`)\n`)
|
|
136
|
-
parts.push(`- Added to ${project_name}/decisions.md in your vault\n`)
|
|
137
|
-
|
|
138
|
-
logger.info({
|
|
139
|
-
project_name,
|
|
140
|
-
decisionId,
|
|
141
|
-
confidence: detectedDecision.confidence
|
|
142
|
-
}, 'Decision auto-saved')
|
|
143
|
-
} else {
|
|
144
|
-
parts.push(`\n---\n`)
|
|
145
|
-
parts.push(`⚠️ Failed to save decision. Check logs for details.`)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return ResponseFormatter.text(parts.join('\n'))
|
|
149
|
-
|
|
150
|
-
} catch (error) {
|
|
151
|
-
ErrorHandler.logError(logger, error, { tool: 'auto_remember', args })
|
|
152
|
-
|
|
153
|
-
if (error instanceof McpError) {
|
|
154
|
-
throw error
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
throw new McpError(
|
|
158
|
-
ErrorCode.InternalError,
|
|
159
|
-
`Auto-remember failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Format decision for vault markdown
|
|
166
|
-
*/
|
|
167
|
-
function formatDecisionEntry(decision: {
|
|
168
|
-
id: string
|
|
169
|
-
project: string
|
|
170
|
-
title: string
|
|
171
|
-
context: string
|
|
172
|
-
decision: string
|
|
173
|
-
reasoning: string
|
|
174
|
-
alternatives?: string
|
|
175
|
-
tags?: string[]
|
|
176
|
-
timestamp: Date
|
|
177
|
-
}): string {
|
|
178
|
-
const date = decision.timestamp.toISOString().split('T')[0]
|
|
179
|
-
|
|
180
|
-
let entry = `### Decision: ${decision.title}\n\n`
|
|
181
|
-
entry += `**Date:** ${date}\n\n`
|
|
182
|
-
entry += `**Context:** ${decision.context}\n\n`
|
|
183
|
-
entry += `**Decision:** ${decision.decision}\n\n`
|
|
184
|
-
entry += `**Reasoning:** ${decision.reasoning}\n\n`
|
|
185
|
-
|
|
186
|
-
if (decision.alternatives) {
|
|
187
|
-
entry += `**Alternatives Considered:** ${decision.alternatives}\n\n`
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (decision.tags) {
|
|
191
|
-
const tags = Array.isArray(decision.tags)
|
|
192
|
-
? decision.tags.join(', ')
|
|
193
|
-
: decision.tags
|
|
194
|
-
entry += `**Tags:** ${tags}\n\n`
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
entry += `*Auto-detected by Claude Brain*\n\n`
|
|
198
|
-
|
|
199
|
-
return entry + '---\n\n'
|
|
200
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Auto Remember Handler
|
|
3
|
+
* Automatically detects and saves decisions from text
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { ToolResponse } from '@/tools/types'
|
|
8
|
+
import { getPhase12Service, getVaultService, isServicesInitialized } from '@/server/services'
|
|
9
|
+
import { ToolValidator } from '@/server/utils/validators'
|
|
10
|
+
import { ResponseFormatter } from '@/server/utils/response-formatter'
|
|
11
|
+
import { ErrorHandler } from '@/server/utils/error-handler'
|
|
12
|
+
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'
|
|
13
|
+
import { AutoRememberSchema } from './schemas'
|
|
14
|
+
|
|
15
|
+
export async function handleAutoRemember(
|
|
16
|
+
args: unknown,
|
|
17
|
+
logger: Logger
|
|
18
|
+
): Promise<ToolResponse> {
|
|
19
|
+
try {
|
|
20
|
+
const input = ToolValidator.validate(args, AutoRememberSchema)
|
|
21
|
+
const { project_name, text, confidence_threshold } = input
|
|
22
|
+
|
|
23
|
+
logger.debug({
|
|
24
|
+
project_name,
|
|
25
|
+
textLength: text.length,
|
|
26
|
+
confidence_threshold
|
|
27
|
+
}, 'Auto-remember request')
|
|
28
|
+
|
|
29
|
+
if (!isServicesInitialized()) {
|
|
30
|
+
throw new McpError(
|
|
31
|
+
ErrorCode.InternalError,
|
|
32
|
+
'Services not initialized'
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const phase12 = getPhase12Service()
|
|
37
|
+
const vault = getVaultService()
|
|
38
|
+
|
|
39
|
+
// Verify project exists
|
|
40
|
+
const projectPaths = vault.getProjectPaths(project_name)
|
|
41
|
+
try {
|
|
42
|
+
await vault.reader.readMarkdownFile(projectPaths.decisions)
|
|
43
|
+
} catch {
|
|
44
|
+
throw new McpError(
|
|
45
|
+
ErrorCode.InvalidParams,
|
|
46
|
+
`Project "${project_name}" not found. Use list_projects to see available projects.`
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Detect decision in text
|
|
51
|
+
const detectedDecision = phase12.decisionDetector.detectDecision(text, project_name)
|
|
52
|
+
|
|
53
|
+
if (!detectedDecision) {
|
|
54
|
+
return ResponseFormatter.text(
|
|
55
|
+
`## No Decision Detected\n\n` +
|
|
56
|
+
`Analyzed ${text.length} characters but no clear decision was found.\n\n` +
|
|
57
|
+
`**Tips for auto-detection:**\n` +
|
|
58
|
+
`- Use phrases like "I recommend X because Y"\n` +
|
|
59
|
+
`- Include reasoning: "We should use X because..."\n` +
|
|
60
|
+
`- Be explicit: "The best approach is X"\n\n` +
|
|
61
|
+
`**Alternatively:** Use \`remember_decision\` to manually save a decision.`
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const parts: string[] = []
|
|
66
|
+
parts.push('## Decision Detected\n')
|
|
67
|
+
parts.push(`**Confidence:** ${Math.round(detectedDecision.confidence * 100)}%\n`)
|
|
68
|
+
parts.push(`**Decision:** ${detectedDecision.statement || detectedDecision.decision}\n`)
|
|
69
|
+
|
|
70
|
+
if (detectedDecision.context) {
|
|
71
|
+
parts.push(`**Context:** ${detectedDecision.context}\n`)
|
|
72
|
+
}
|
|
73
|
+
if (detectedDecision.reasoning) {
|
|
74
|
+
parts.push(`**Reasoning:** ${detectedDecision.reasoning}\n`)
|
|
75
|
+
}
|
|
76
|
+
if (detectedDecision.alternatives) {
|
|
77
|
+
parts.push(`**Alternatives:** ${detectedDecision.alternatives}\n`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if confidence meets threshold
|
|
81
|
+
if (detectedDecision.confidence < confidence_threshold) {
|
|
82
|
+
parts.push(`\n---\n`)
|
|
83
|
+
parts.push(`⚠️ **Not Auto-Saved** (confidence ${Math.round(detectedDecision.confidence * 100)}% < threshold ${Math.round(confidence_threshold * 100)}%)\n`)
|
|
84
|
+
parts.push(`\nTo save anyway, use \`remember_decision\` manually or lower the confidence_threshold.`)
|
|
85
|
+
|
|
86
|
+
logger.info({
|
|
87
|
+
project_name,
|
|
88
|
+
confidence: detectedDecision.confidence,
|
|
89
|
+
threshold: confidence_threshold,
|
|
90
|
+
saved: false
|
|
91
|
+
}, 'Decision detected but below threshold')
|
|
92
|
+
|
|
93
|
+
return ResponseFormatter.text(parts.join('\n'))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Auto-save the decision to memory
|
|
97
|
+
const decisionId = await phase12.decisionDetector.autoSaveDecision(
|
|
98
|
+
detectedDecision,
|
|
99
|
+
project_name
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if (decisionId) {
|
|
103
|
+
// Also write to vault decisions.md
|
|
104
|
+
try {
|
|
105
|
+
const decisionEntry = formatDecisionEntry({
|
|
106
|
+
id: decisionId,
|
|
107
|
+
project: project_name,
|
|
108
|
+
title: detectedDecision.decision,
|
|
109
|
+
context: detectedDecision.context,
|
|
110
|
+
decision: detectedDecision.decision,
|
|
111
|
+
reasoning: detectedDecision.reasoning,
|
|
112
|
+
alternatives: detectedDecision.alternatives,
|
|
113
|
+
tags: detectedDecision.tags || ['auto-detected'],
|
|
114
|
+
timestamp: new Date()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
await vault.writer.appendContent(projectPaths.decisions, decisionEntry, '\n')
|
|
118
|
+
|
|
119
|
+
// Update frontmatter
|
|
120
|
+
const decisionsFile = await vault.reader.readMarkdownFile(projectPaths.decisions)
|
|
121
|
+
const currentCount = (decisionsFile.frontmatter.decision_count as number) || 0
|
|
122
|
+
await vault.writer.updateFrontmatter(projectPaths.decisions, {
|
|
123
|
+
decision_count: currentCount + 1,
|
|
124
|
+
last_updated: new Date().toISOString().split('T')[0]
|
|
125
|
+
})
|
|
126
|
+
} catch (vaultError) {
|
|
127
|
+
logger.warn({ vaultError }, 'Failed to write to vault, but memory save succeeded')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
parts.push(`\n---\n`)
|
|
131
|
+
parts.push(`✅ **Auto-Saved Successfully!**\n`)
|
|
132
|
+
parts.push(`**ID:** ${decisionId}\n`)
|
|
133
|
+
parts.push(`**Project:** ${project_name}\n\n`)
|
|
134
|
+
parts.push(`This decision has been:\n`)
|
|
135
|
+
parts.push(`- Stored in semantic memory (searchable via \`recall_similar\`)\n`)
|
|
136
|
+
parts.push(`- Added to ${project_name}/decisions.md in your vault\n`)
|
|
137
|
+
|
|
138
|
+
logger.info({
|
|
139
|
+
project_name,
|
|
140
|
+
decisionId,
|
|
141
|
+
confidence: detectedDecision.confidence
|
|
142
|
+
}, 'Decision auto-saved')
|
|
143
|
+
} else {
|
|
144
|
+
parts.push(`\n---\n`)
|
|
145
|
+
parts.push(`⚠️ Failed to save decision. Check logs for details.`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return ResponseFormatter.text(parts.join('\n'))
|
|
149
|
+
|
|
150
|
+
} catch (error) {
|
|
151
|
+
ErrorHandler.logError(logger, error, { tool: 'auto_remember', args })
|
|
152
|
+
|
|
153
|
+
if (error instanceof McpError) {
|
|
154
|
+
throw error
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
throw new McpError(
|
|
158
|
+
ErrorCode.InternalError,
|
|
159
|
+
`Auto-remember failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Format decision for vault markdown
|
|
166
|
+
*/
|
|
167
|
+
function formatDecisionEntry(decision: {
|
|
168
|
+
id: string
|
|
169
|
+
project: string
|
|
170
|
+
title: string
|
|
171
|
+
context: string
|
|
172
|
+
decision: string
|
|
173
|
+
reasoning: string
|
|
174
|
+
alternatives?: string
|
|
175
|
+
tags?: string[]
|
|
176
|
+
timestamp: Date
|
|
177
|
+
}): string {
|
|
178
|
+
const date = decision.timestamp.toISOString().split('T')[0]
|
|
179
|
+
|
|
180
|
+
let entry = `### Decision: ${decision.title}\n\n`
|
|
181
|
+
entry += `**Date:** ${date}\n\n`
|
|
182
|
+
entry += `**Context:** ${decision.context}\n\n`
|
|
183
|
+
entry += `**Decision:** ${decision.decision}\n\n`
|
|
184
|
+
entry += `**Reasoning:** ${decision.reasoning}\n\n`
|
|
185
|
+
|
|
186
|
+
if (decision.alternatives) {
|
|
187
|
+
entry += `**Alternatives Considered:** ${decision.alternatives}\n\n`
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (decision.tags) {
|
|
191
|
+
const tags = Array.isArray(decision.tags)
|
|
192
|
+
? decision.tags.join(', ')
|
|
193
|
+
: decision.tags
|
|
194
|
+
entry += `**Tags:** ${tags}\n\n`
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
entry += `*Auto-detected by Claude Brain*\n\n`
|
|
198
|
+
|
|
199
|
+
return entry + '---\n\n'
|
|
200
|
+
}
|
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Brain Tool Handler
|
|
3
|
-
* Phase 16: Unified single tool that replaces all 25 MCP tools
|
|
4
|
-
*
|
|
5
|
-
* Accepts natural language, classifies intent server-side,
|
|
6
|
-
* routes internally, and returns a unified response.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { Logger } from 'pino'
|
|
10
|
-
import type { ToolResponse } from '@/tools/types'
|
|
11
|
-
import { ToolValidator } from '@/server/utils/validators'
|
|
12
|
-
import { ResponseFormatter } from '@/server/utils/response-formatter'
|
|
13
|
-
import { withMemoryIndicator } from '@/server/utils/memory-indicator'
|
|
14
|
-
import { ErrorHandler } from '@/server/utils/error-handler'
|
|
15
|
-
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'
|
|
16
|
-
import { BrainSchema } from './schemas'
|
|
17
|
-
import { getBrainRouter } from '@/routing/router'
|
|
18
|
-
|
|
19
|
-
export async function handleBrain(
|
|
20
|
-
args: unknown,
|
|
21
|
-
logger: Logger
|
|
22
|
-
): Promise<ToolResponse> {
|
|
23
|
-
try {
|
|
24
|
-
const input = ToolValidator.validate(args, BrainSchema)
|
|
25
|
-
const { message, project } = input
|
|
26
|
-
|
|
27
|
-
logger.debug(
|
|
28
|
-
{
|
|
29
|
-
messageLength: message.length,
|
|
30
|
-
project,
|
|
31
|
-
messagePreview: message.slice(0, 80)
|
|
32
|
-
},
|
|
33
|
-
'Brain tool called'
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
const router = getBrainRouter(logger)
|
|
37
|
-
const response = await router.route({ message, project })
|
|
38
|
-
|
|
39
|
-
logger.info(
|
|
40
|
-
{
|
|
41
|
-
action: response.action,
|
|
42
|
-
summary: response.summary,
|
|
43
|
-
relevantItems: response.relevantItems
|
|
44
|
-
},
|
|
45
|
-
'Brain tool response'
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
// Format response
|
|
49
|
-
if (response.action === 'none' && !response.content) {
|
|
50
|
-
return ResponseFormatter.text(response.summary || 'No action needed.')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const parts: string[] = []
|
|
54
|
-
|
|
55
|
-
if (response.summary) {
|
|
56
|
-
parts.push(`**${response.summary}**`)
|
|
57
|
-
parts.push('')
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (response.content) {
|
|
61
|
-
parts.push(response.content)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const content = parts.join('\n')
|
|
65
|
-
|
|
66
|
-
// Add memory indicator if we found relevant items
|
|
67
|
-
if (response.relevantItems > 0 && response.action === 'retrieved') {
|
|
68
|
-
return ResponseFormatter.text(withMemoryIndicator(content, response.relevantItems))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return ResponseFormatter.text(content)
|
|
72
|
-
|
|
73
|
-
} catch (error) {
|
|
74
|
-
ErrorHandler.logError(logger, error, { tool: 'brain', args })
|
|
75
|
-
|
|
76
|
-
if (error instanceof McpError) {
|
|
77
|
-
throw error
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
throw new McpError(
|
|
81
|
-
ErrorCode.InternalError,
|
|
82
|
-
`Brain tool failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Brain Tool Handler
|
|
3
|
+
* Phase 16: Unified single tool that replaces all 25 MCP tools
|
|
4
|
+
*
|
|
5
|
+
* Accepts natural language, classifies intent server-side,
|
|
6
|
+
* routes internally, and returns a unified response.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Logger } from 'pino'
|
|
10
|
+
import type { ToolResponse } from '@/tools/types'
|
|
11
|
+
import { ToolValidator } from '@/server/utils/validators'
|
|
12
|
+
import { ResponseFormatter } from '@/server/utils/response-formatter'
|
|
13
|
+
import { withMemoryIndicator } from '@/server/utils/memory-indicator'
|
|
14
|
+
import { ErrorHandler } from '@/server/utils/error-handler'
|
|
15
|
+
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'
|
|
16
|
+
import { BrainSchema } from './schemas'
|
|
17
|
+
import { getBrainRouter } from '@/routing/router'
|
|
18
|
+
|
|
19
|
+
export async function handleBrain(
|
|
20
|
+
args: unknown,
|
|
21
|
+
logger: Logger
|
|
22
|
+
): Promise<ToolResponse> {
|
|
23
|
+
try {
|
|
24
|
+
const input = ToolValidator.validate(args, BrainSchema)
|
|
25
|
+
const { message, project } = input
|
|
26
|
+
|
|
27
|
+
logger.debug(
|
|
28
|
+
{
|
|
29
|
+
messageLength: message.length,
|
|
30
|
+
project,
|
|
31
|
+
messagePreview: message.slice(0, 80)
|
|
32
|
+
},
|
|
33
|
+
'Brain tool called'
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const router = getBrainRouter(logger)
|
|
37
|
+
const response = await router.route({ message, project })
|
|
38
|
+
|
|
39
|
+
logger.info(
|
|
40
|
+
{
|
|
41
|
+
action: response.action,
|
|
42
|
+
summary: response.summary,
|
|
43
|
+
relevantItems: response.relevantItems
|
|
44
|
+
},
|
|
45
|
+
'Brain tool response'
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
// Format response
|
|
49
|
+
if (response.action === 'none' && !response.content) {
|
|
50
|
+
return ResponseFormatter.text(response.summary || 'No action needed.')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const parts: string[] = []
|
|
54
|
+
|
|
55
|
+
if (response.summary) {
|
|
56
|
+
parts.push(`**${response.summary}**`)
|
|
57
|
+
parts.push('')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (response.content) {
|
|
61
|
+
parts.push(response.content)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const content = parts.join('\n')
|
|
65
|
+
|
|
66
|
+
// Add memory indicator if we found relevant items
|
|
67
|
+
if (response.relevantItems > 0 && response.action === 'retrieved') {
|
|
68
|
+
return ResponseFormatter.text(withMemoryIndicator(content, response.relevantItems))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return ResponseFormatter.text(content)
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
ErrorHandler.logError(logger, error, { tool: 'brain', args })
|
|
75
|
+
|
|
76
|
+
if (error instanceof McpError) {
|
|
77
|
+
throw error
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw new McpError(
|
|
81
|
+
ErrorCode.InternalError,
|
|
82
|
+
`Brain tool failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
}
|