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
package/src/server/services.ts
CHANGED
|
@@ -1,468 +1,468 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Services Module
|
|
3
|
-
* Provides access to initialized services for tool handlers
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import { existsSync } from 'fs'
|
|
8
|
-
import * as path from 'path'
|
|
9
|
-
import { MemoryManager } from '@/memory'
|
|
10
|
-
import { VaultManager } from '@/vault'
|
|
11
|
-
import { ContextManager } from '@/context'
|
|
12
|
-
import { Phase12Manager } from '@/automation/phase12-manager'
|
|
13
|
-
import { RetrievalService } from '@/retrieval/service'
|
|
14
|
-
import { RetrievalPipeline } from '@/retrieval/pipeline'
|
|
15
|
-
import { InMemoryKnowledgeGraph } from '@/knowledge/graph/memory-graph'
|
|
16
|
-
import { GraphSearchEngine } from '@/knowledge/graph/search'
|
|
17
|
-
import { KnowledgeGraphBuilder } from '@/knowledge/graph/builder'
|
|
18
|
-
import { CrossReferenceLinker } from '@/knowledge/graph/linker'
|
|
19
|
-
import { EpisodeManager } from '@/memory/episodic/manager'
|
|
20
|
-
import { HookSessionTracker } from '@/hooks/session-tracker'
|
|
21
|
-
import type { Config } from '@/config'
|
|
22
|
-
import { SemanticCache } from '@/intelligence/optimization/semantic-cache'
|
|
23
|
-
import { PrecomputeEngine } from '@/intelligence/optimization/precompute'
|
|
24
|
-
|
|
25
|
-
export interface KnowledgeGraphServiceContainer {
|
|
26
|
-
graph: InMemoryKnowledgeGraph
|
|
27
|
-
search: GraphSearchEngine
|
|
28
|
-
builder: KnowledgeGraphBuilder
|
|
29
|
-
linker: CrossReferenceLinker
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Container for all shared services
|
|
34
|
-
*/
|
|
35
|
-
export interface Services {
|
|
36
|
-
memory: MemoryManager
|
|
37
|
-
vault: VaultManager
|
|
38
|
-
context: ContextManager
|
|
39
|
-
phase12: Phase12Manager
|
|
40
|
-
retrieval: RetrievalService | null
|
|
41
|
-
retrievalPipeline: RetrievalPipeline | null
|
|
42
|
-
knowledgeGraph: KnowledgeGraphServiceContainer | null
|
|
43
|
-
episodeManager: EpisodeManager | null
|
|
44
|
-
sessionTracker: HookSessionTracker | null
|
|
45
|
-
semanticCache: SemanticCache | null
|
|
46
|
-
precompute: PrecomputeEngine | null
|
|
47
|
-
logger: Logger
|
|
48
|
-
config: Config
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Singleton services instance
|
|
52
|
-
let services: Services | null = null
|
|
53
|
-
let initializationPromise: Promise<void> | null = null
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Initialize all services
|
|
57
|
-
* Should be called once during server startup
|
|
58
|
-
*/
|
|
59
|
-
export async function initializeServices(config: Config, logger: Logger): Promise<Services> {
|
|
60
|
-
// If already initialized, return existing services
|
|
61
|
-
if (services) {
|
|
62
|
-
logger.debug('Services already initialized')
|
|
63
|
-
return services
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// If initialization is in progress, wait for it
|
|
67
|
-
if (initializationPromise) {
|
|
68
|
-
await initializationPromise
|
|
69
|
-
return services!
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Start initialization
|
|
73
|
-
initializationPromise = (async () => {
|
|
74
|
-
const serviceLogger = logger.child({ component: 'services' })
|
|
75
|
-
serviceLogger.info('Initializing services...')
|
|
76
|
-
|
|
77
|
-
// Validate vault path configuration
|
|
78
|
-
if (!config.vaultPath) {
|
|
79
|
-
throw new Error('Vault path not configured. Set VAULT_PATH environment variable.')
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!existsSync(config.vaultPath)) {
|
|
83
|
-
serviceLogger.warn(
|
|
84
|
-
{ vaultPath: config.vaultPath },
|
|
85
|
-
'Vault path does not exist - will be created on first use'
|
|
86
|
-
)
|
|
87
|
-
} else {
|
|
88
|
-
const projectsPath = path.join(config.vaultPath, 'Projects')
|
|
89
|
-
if (!existsSync(projectsPath)) {
|
|
90
|
-
serviceLogger.warn(
|
|
91
|
-
{ projectsPath },
|
|
92
|
-
'Projects directory missing in vault - will be created when first project is added'
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Initialize Memory Manager
|
|
98
|
-
const memory = new MemoryManager(config.dbPath, logger)
|
|
99
|
-
await memory.initialize()
|
|
100
|
-
serviceLogger.info('Memory service initialized')
|
|
101
|
-
|
|
102
|
-
// Initialize Vault Manager
|
|
103
|
-
const vault = new VaultManager(config.vaultPath, logger, {
|
|
104
|
-
cacheEnabled: config.cacheSize > 0,
|
|
105
|
-
watchEnabled: config.enableFileWatch
|
|
106
|
-
})
|
|
107
|
-
await vault.initialize()
|
|
108
|
-
serviceLogger.info('Vault service initialized')
|
|
109
|
-
|
|
110
|
-
// Initialize Context Manager
|
|
111
|
-
const context = new ContextManager(logger, vault, memory)
|
|
112
|
-
serviceLogger.info('Context service initialized')
|
|
113
|
-
|
|
114
|
-
// Initialize Phase 12 Manager
|
|
115
|
-
const phase12 = new Phase12Manager(logger, vault, memory, context)
|
|
116
|
-
await phase12.initialize()
|
|
117
|
-
serviceLogger.info('Phase 12 service initialized')
|
|
118
|
-
|
|
119
|
-
// Initialize Retrieval Service (Phase 13) — requires ChromaDB
|
|
120
|
-
let retrieval: RetrievalService | null = null
|
|
121
|
-
if ((config.retrieval?.feedback?.enabled || config.retrieval?.enabled) && memory.isChromaDBEnabled()) {
|
|
122
|
-
retrieval = new RetrievalService(
|
|
123
|
-
logger,
|
|
124
|
-
memory.chroma.collections,
|
|
125
|
-
memory.chroma.embeddings,
|
|
126
|
-
config.retrieval
|
|
127
|
-
)
|
|
128
|
-
await retrieval.initialize()
|
|
129
|
-
serviceLogger.info('Retrieval service initialized')
|
|
130
|
-
} else if (config.retrieval?.enabled && !memory.isChromaDBEnabled()) {
|
|
131
|
-
serviceLogger.warn('Retrieval service requires ChromaDB, skipping initialization')
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Initialize Retrieval Pipeline (Phase 19) — hybrid search with BM25 + semantic + fusion
|
|
135
|
-
let retrievalPipeline: RetrievalPipeline | null = null
|
|
136
|
-
if (config.retrieval?.enabled && memory.isChromaDBEnabled()) {
|
|
137
|
-
try {
|
|
138
|
-
retrievalPipeline = new RetrievalPipeline(
|
|
139
|
-
logger,
|
|
140
|
-
memory.chroma.collections,
|
|
141
|
-
memory.chroma.embeddings,
|
|
142
|
-
config.retrieval
|
|
143
|
-
)
|
|
144
|
-
await retrievalPipeline.initialize()
|
|
145
|
-
serviceLogger.info('Retrieval pipeline initialized (hybrid search)')
|
|
146
|
-
} catch (error) {
|
|
147
|
-
serviceLogger.warn({ error }, 'Failed to initialize retrieval pipeline, continuing without hybrid search')
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Initialize Knowledge Graph Service (Phase 14)
|
|
152
|
-
let knowledgeGraph: KnowledgeGraphServiceContainer | null = null
|
|
153
|
-
if (config.knowledge?.graph?.enabled !== false) {
|
|
154
|
-
try {
|
|
155
|
-
const graph = new InMemoryKnowledgeGraph(logger)
|
|
156
|
-
const graphPersistPath = config.knowledge?.graph?.persistPath || './data/knowledge-graph.json'
|
|
157
|
-
|
|
158
|
-
// Load existing graph from disk
|
|
159
|
-
await graph.load(graphPersistPath)
|
|
160
|
-
|
|
161
|
-
const search = new GraphSearchEngine(graph, logger)
|
|
162
|
-
const builder = new KnowledgeGraphBuilder(graph, logger)
|
|
163
|
-
await builder.initialize()
|
|
164
|
-
const linker = new CrossReferenceLinker(graph, logger)
|
|
165
|
-
|
|
166
|
-
// Start auto-save
|
|
167
|
-
const autoSaveInterval = (config.knowledge?.graph?.autoSaveInterval || 60) * 1000
|
|
168
|
-
graph.startAutoSave(graphPersistPath, autoSaveInterval)
|
|
169
|
-
|
|
170
|
-
knowledgeGraph = { graph, search, builder, linker }
|
|
171
|
-
|
|
172
|
-
// Migrate existing decisions if graph is empty (requires ChromaDB)
|
|
173
|
-
if (graph.getNodeCount() === 0 && memory.isChromaDBEnabled()) {
|
|
174
|
-
serviceLogger.info('Empty graph detected, migrating existing decisions...')
|
|
175
|
-
const migrationResult = await builder.migrateExistingDecisions(memory.chroma.collections)
|
|
176
|
-
serviceLogger.info(
|
|
177
|
-
{ processed: migrationResult.processed, errors: migrationResult.errors },
|
|
178
|
-
'Initial graph migration complete'
|
|
179
|
-
)
|
|
180
|
-
} else if (graph.getNodeCount() === 0) {
|
|
181
|
-
serviceLogger.info('Empty graph detected, but ChromaDB unavailable — graph will populate as new decisions are stored')
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Hook builder into decision storage for real-time graph population
|
|
185
|
-
// Uses MemoryManager listener so it works for both ChromaDB and SQLite paths
|
|
186
|
-
memory.addDecisionStoredListener((input) => {
|
|
187
|
-
builder.processDecision(input)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
// Hook builder into decision deletion for graph synchronization
|
|
191
|
-
memory.addDecisionDeletedListener((id) => {
|
|
192
|
-
builder.removeDecision(id)
|
|
193
|
-
|
|
194
|
-
// Phase 20: Also unlink from active episodes
|
|
195
|
-
if (episodeManager) {
|
|
196
|
-
episodeManager.unlinkDecision(id)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Phase 20: Invalidate semantic cache for deleted decisions
|
|
200
|
-
if (semanticCache) {
|
|
201
|
-
semanticCache.clear()
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
serviceLogger.info(
|
|
206
|
-
{ nodes: graph.getNodeCount(), edges: graph.getEdgeCount() },
|
|
207
|
-
'Knowledge graph service initialized'
|
|
208
|
-
)
|
|
209
|
-
} catch (error) {
|
|
210
|
-
serviceLogger.warn({ error }, 'Failed to initialize knowledge graph, continuing without it')
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Initialize Episode Manager (Phase 14) — requires ChromaDB
|
|
215
|
-
let episodeManager: EpisodeManager | null = null
|
|
216
|
-
if (config.knowledge?.episodic?.enabled !== false && memory.isChromaDBEnabled()) {
|
|
217
|
-
try {
|
|
218
|
-
episodeManager = new EpisodeManager(
|
|
219
|
-
logger,
|
|
220
|
-
memory.chroma.collections,
|
|
221
|
-
memory.chroma.embeddings,
|
|
222
|
-
{ sessionGapMinutes: config.knowledge?.episodic?.sessionGapMinutes || 30 }
|
|
223
|
-
)
|
|
224
|
-
serviceLogger.info('Episode manager initialized')
|
|
225
|
-
} catch (error) {
|
|
226
|
-
serviceLogger.warn({ error }, 'Failed to initialize episode manager, continuing without it')
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Initialize Session Tracker (Phase 21) — promoted from serve.ts
|
|
231
|
-
let sessionTracker: HookSessionTracker | null = null
|
|
232
|
-
if (config.hooks?.enabled !== false) {
|
|
233
|
-
try {
|
|
234
|
-
sessionTracker = new HookSessionTracker(logger, episodeManager, config.hooks?.sessions, memory)
|
|
235
|
-
serviceLogger.info('Session tracker initialized')
|
|
236
|
-
} catch (error) {
|
|
237
|
-
serviceLogger.warn({ error }, 'Failed to initialize session tracker, continuing without it')
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Initialize Semantic Cache & Precompute (Phase 15) — requires ChromaDB
|
|
242
|
-
let semanticCache: SemanticCache | null = null
|
|
243
|
-
let precompute: PrecomputeEngine | null = null
|
|
244
|
-
if (config.advancedIntelligence?.enabled !== false && config.advancedIntelligence?.cache?.enabled !== false && memory.isChromaDBEnabled()) {
|
|
245
|
-
try {
|
|
246
|
-
const cacheConfig = config.advancedIntelligence?.cache || {}
|
|
247
|
-
semanticCache = new SemanticCache(logger, {
|
|
248
|
-
maxSize: cacheConfig.maxSize || 1000,
|
|
249
|
-
ttlMs: cacheConfig.ttlMs || 60 * 60 * 1000,
|
|
250
|
-
similarityThreshold: cacheConfig.similarityThreshold || 0.80,
|
|
251
|
-
embeddings: memory.chroma.embeddings
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
precompute = new PrecomputeEngine(logger, memory.chroma.collections, semanticCache)
|
|
255
|
-
await precompute.initialize()
|
|
256
|
-
precompute.startAutoRefresh(5 * 60 * 1000) // Refresh every 5 minutes
|
|
257
|
-
|
|
258
|
-
serviceLogger.info('Phase 15 semantic cache & precompute initialized')
|
|
259
|
-
} catch (error) {
|
|
260
|
-
serviceLogger.warn({ error }, 'Failed to initialize Phase 15 caching, continuing without it')
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Store services
|
|
265
|
-
services = {
|
|
266
|
-
memory,
|
|
267
|
-
vault,
|
|
268
|
-
context,
|
|
269
|
-
phase12,
|
|
270
|
-
retrieval,
|
|
271
|
-
retrievalPipeline,
|
|
272
|
-
knowledgeGraph,
|
|
273
|
-
episodeManager,
|
|
274
|
-
sessionTracker,
|
|
275
|
-
semanticCache,
|
|
276
|
-
precompute,
|
|
277
|
-
logger,
|
|
278
|
-
config
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
serviceLogger.info('All services initialized successfully')
|
|
282
|
-
})()
|
|
283
|
-
|
|
284
|
-
await initializationPromise
|
|
285
|
-
return services!
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Get initialized services
|
|
290
|
-
* Throws if services not initialized
|
|
291
|
-
*/
|
|
292
|
-
export function getServices(): Services {
|
|
293
|
-
if (!services) {
|
|
294
|
-
throw new Error('Services not initialized. Call initializeServices() first.')
|
|
295
|
-
}
|
|
296
|
-
return services
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Get memory service
|
|
301
|
-
* Throws if not initialized
|
|
302
|
-
*/
|
|
303
|
-
export function getMemoryService(): MemoryManager {
|
|
304
|
-
return getServices().memory
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Get vault service
|
|
309
|
-
* Throws if not initialized
|
|
310
|
-
*/
|
|
311
|
-
export function getVaultService(): VaultManager {
|
|
312
|
-
return getServices().vault
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export function getContextService(): ContextManager {
|
|
316
|
-
return getServices().context
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Get Phase 12 service
|
|
321
|
-
* Throws if not initialized
|
|
322
|
-
*/
|
|
323
|
-
export function getPhase12Service(): Phase12Manager {
|
|
324
|
-
return getServices().phase12
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Get Retrieval service
|
|
329
|
-
* Returns null if retrieval is not enabled
|
|
330
|
-
*/
|
|
331
|
-
export function getRetrievalService(): RetrievalService | null {
|
|
332
|
-
return getServices().retrieval
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Get Retrieval Pipeline (Phase 19)
|
|
337
|
-
* Returns null if hybrid search is not enabled
|
|
338
|
-
*/
|
|
339
|
-
export function getRetrievalPipeline(): RetrievalPipeline | null {
|
|
340
|
-
return getServices().retrievalPipeline
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Get Knowledge Graph service
|
|
345
|
-
* Returns null if knowledge graph is not enabled
|
|
346
|
-
*/
|
|
347
|
-
export function getKnowledgeGraphService(): KnowledgeGraphServiceContainer | null {
|
|
348
|
-
return getServices().knowledgeGraph
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Get Episode Manager service
|
|
353
|
-
* Returns null if episodic memory is not enabled
|
|
354
|
-
*/
|
|
355
|
-
export function getEpisodeService(): EpisodeManager | null {
|
|
356
|
-
return getServices().episodeManager
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Get Session Tracker service
|
|
361
|
-
* Returns null if hooks are not enabled
|
|
362
|
-
*/
|
|
363
|
-
export function getSessionTracker(): HookSessionTracker | null {
|
|
364
|
-
return getServices().sessionTracker
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Get Semantic Cache service
|
|
369
|
-
* Returns null if caching is not enabled
|
|
370
|
-
*/
|
|
371
|
-
export function getSemanticCacheService(): SemanticCache | null {
|
|
372
|
-
return getServices().semanticCache
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Get Precompute Engine service
|
|
377
|
-
* Returns null if caching is not enabled
|
|
378
|
-
*/
|
|
379
|
-
export function getPrecomputeService(): PrecomputeEngine | null {
|
|
380
|
-
return getServices().precompute
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Check if services are initialized
|
|
385
|
-
*/
|
|
386
|
-
export function isServicesInitialized(): boolean {
|
|
387
|
-
return services !== null
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Inject services for testing
|
|
392
|
-
* Allows tests to provide mock services without going through initializeServices
|
|
393
|
-
* @internal - Only use in tests
|
|
394
|
-
*/
|
|
395
|
-
export function _injectServicesForTesting(testServices: Services | null): void {
|
|
396
|
-
services = testServices
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Reset services for testing
|
|
401
|
-
* Clears the services singleton without proper shutdown
|
|
402
|
-
* @internal - Only use in tests
|
|
403
|
-
*/
|
|
404
|
-
export function _resetServicesForTesting(): void {
|
|
405
|
-
services = null
|
|
406
|
-
initializationPromise = null
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Shutdown all services gracefully
|
|
411
|
-
*/
|
|
412
|
-
export async function shutdownServices(): Promise<void> {
|
|
413
|
-
if (!services) {
|
|
414
|
-
return
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const serviceLogger = services.logger.child({ component: 'services' })
|
|
418
|
-
serviceLogger.info('Shutting down services...')
|
|
419
|
-
|
|
420
|
-
// End all active sessions
|
|
421
|
-
if (services.sessionTracker) {
|
|
422
|
-
try {
|
|
423
|
-
await services.sessionTracker.endAllSessions()
|
|
424
|
-
serviceLogger.info('Session tracker shut down')
|
|
425
|
-
} catch (error) {
|
|
426
|
-
serviceLogger.error({ error }, 'Failed to end sessions on shutdown')
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Save and stop knowledge graph
|
|
431
|
-
if (services.knowledgeGraph) {
|
|
432
|
-
services.knowledgeGraph.graph.stopAutoSave()
|
|
433
|
-
const persistPath = services.config.knowledge?.graph?.persistPath || './data/knowledge-graph.json'
|
|
434
|
-
try {
|
|
435
|
-
await services.knowledgeGraph.graph.save(persistPath)
|
|
436
|
-
serviceLogger.info('Knowledge graph saved on shutdown')
|
|
437
|
-
} catch (error) {
|
|
438
|
-
serviceLogger.error({ error }, 'Failed to save knowledge graph on shutdown')
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Stop precompute auto-refresh
|
|
443
|
-
if (services.precompute) {
|
|
444
|
-
services.precompute.stopAutoRefresh()
|
|
445
|
-
serviceLogger.info('Precompute engine stopped')
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Clear semantic cache
|
|
449
|
-
if (services.semanticCache) {
|
|
450
|
-
services.semanticCache.clear()
|
|
451
|
-
serviceLogger.info('Semantic cache cleared')
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Cleanup Phase 12
|
|
455
|
-
services.phase12.cleanup()
|
|
456
|
-
|
|
457
|
-
// Stop vault watcher
|
|
458
|
-
services.vault.stopWatching()
|
|
459
|
-
|
|
460
|
-
// Close memory database
|
|
461
|
-
services.memory.close()
|
|
462
|
-
|
|
463
|
-
// Clear reference
|
|
464
|
-
services = null
|
|
465
|
-
initializationPromise = null
|
|
466
|
-
|
|
467
|
-
serviceLogger.info('All services shut down')
|
|
468
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Shared Services Module
|
|
3
|
+
* Provides access to initialized services for tool handlers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import { existsSync } from 'fs'
|
|
8
|
+
import * as path from 'path'
|
|
9
|
+
import { MemoryManager } from '@/memory'
|
|
10
|
+
import { VaultManager } from '@/vault'
|
|
11
|
+
import { ContextManager } from '@/context'
|
|
12
|
+
import { Phase12Manager } from '@/automation/phase12-manager'
|
|
13
|
+
import { RetrievalService } from '@/retrieval/service'
|
|
14
|
+
import { RetrievalPipeline } from '@/retrieval/pipeline'
|
|
15
|
+
import { InMemoryKnowledgeGraph } from '@/knowledge/graph/memory-graph'
|
|
16
|
+
import { GraphSearchEngine } from '@/knowledge/graph/search'
|
|
17
|
+
import { KnowledgeGraphBuilder } from '@/knowledge/graph/builder'
|
|
18
|
+
import { CrossReferenceLinker } from '@/knowledge/graph/linker'
|
|
19
|
+
import { EpisodeManager } from '@/memory/episodic/manager'
|
|
20
|
+
import { HookSessionTracker } from '@/hooks/session-tracker'
|
|
21
|
+
import type { Config } from '@/config'
|
|
22
|
+
import { SemanticCache } from '@/intelligence/optimization/semantic-cache'
|
|
23
|
+
import { PrecomputeEngine } from '@/intelligence/optimization/precompute'
|
|
24
|
+
|
|
25
|
+
export interface KnowledgeGraphServiceContainer {
|
|
26
|
+
graph: InMemoryKnowledgeGraph
|
|
27
|
+
search: GraphSearchEngine
|
|
28
|
+
builder: KnowledgeGraphBuilder
|
|
29
|
+
linker: CrossReferenceLinker
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Container for all shared services
|
|
34
|
+
*/
|
|
35
|
+
export interface Services {
|
|
36
|
+
memory: MemoryManager
|
|
37
|
+
vault: VaultManager
|
|
38
|
+
context: ContextManager
|
|
39
|
+
phase12: Phase12Manager
|
|
40
|
+
retrieval: RetrievalService | null
|
|
41
|
+
retrievalPipeline: RetrievalPipeline | null
|
|
42
|
+
knowledgeGraph: KnowledgeGraphServiceContainer | null
|
|
43
|
+
episodeManager: EpisodeManager | null
|
|
44
|
+
sessionTracker: HookSessionTracker | null
|
|
45
|
+
semanticCache: SemanticCache | null
|
|
46
|
+
precompute: PrecomputeEngine | null
|
|
47
|
+
logger: Logger
|
|
48
|
+
config: Config
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Singleton services instance
|
|
52
|
+
let services: Services | null = null
|
|
53
|
+
let initializationPromise: Promise<void> | null = null
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize all services
|
|
57
|
+
* Should be called once during server startup
|
|
58
|
+
*/
|
|
59
|
+
export async function initializeServices(config: Config, logger: Logger): Promise<Services> {
|
|
60
|
+
// If already initialized, return existing services
|
|
61
|
+
if (services) {
|
|
62
|
+
logger.debug('Services already initialized')
|
|
63
|
+
return services
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If initialization is in progress, wait for it
|
|
67
|
+
if (initializationPromise) {
|
|
68
|
+
await initializationPromise
|
|
69
|
+
return services!
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Start initialization
|
|
73
|
+
initializationPromise = (async () => {
|
|
74
|
+
const serviceLogger = logger.child({ component: 'services' })
|
|
75
|
+
serviceLogger.info('Initializing services...')
|
|
76
|
+
|
|
77
|
+
// Validate vault path configuration
|
|
78
|
+
if (!config.vaultPath) {
|
|
79
|
+
throw new Error('Vault path not configured. Set VAULT_PATH environment variable.')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!existsSync(config.vaultPath)) {
|
|
83
|
+
serviceLogger.warn(
|
|
84
|
+
{ vaultPath: config.vaultPath },
|
|
85
|
+
'Vault path does not exist - will be created on first use'
|
|
86
|
+
)
|
|
87
|
+
} else {
|
|
88
|
+
const projectsPath = path.join(config.vaultPath, 'Projects')
|
|
89
|
+
if (!existsSync(projectsPath)) {
|
|
90
|
+
serviceLogger.warn(
|
|
91
|
+
{ projectsPath },
|
|
92
|
+
'Projects directory missing in vault - will be created when first project is added'
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Initialize Memory Manager
|
|
98
|
+
const memory = new MemoryManager(config.dbPath, logger)
|
|
99
|
+
await memory.initialize()
|
|
100
|
+
serviceLogger.info('Memory service initialized')
|
|
101
|
+
|
|
102
|
+
// Initialize Vault Manager
|
|
103
|
+
const vault = new VaultManager(config.vaultPath, logger, {
|
|
104
|
+
cacheEnabled: config.cacheSize > 0,
|
|
105
|
+
watchEnabled: config.enableFileWatch
|
|
106
|
+
})
|
|
107
|
+
await vault.initialize()
|
|
108
|
+
serviceLogger.info('Vault service initialized')
|
|
109
|
+
|
|
110
|
+
// Initialize Context Manager
|
|
111
|
+
const context = new ContextManager(logger, vault, memory)
|
|
112
|
+
serviceLogger.info('Context service initialized')
|
|
113
|
+
|
|
114
|
+
// Initialize Phase 12 Manager
|
|
115
|
+
const phase12 = new Phase12Manager(logger, vault, memory, context)
|
|
116
|
+
await phase12.initialize()
|
|
117
|
+
serviceLogger.info('Phase 12 service initialized')
|
|
118
|
+
|
|
119
|
+
// Initialize Retrieval Service (Phase 13) — requires ChromaDB
|
|
120
|
+
let retrieval: RetrievalService | null = null
|
|
121
|
+
if ((config.retrieval?.feedback?.enabled || config.retrieval?.enabled) && memory.isChromaDBEnabled()) {
|
|
122
|
+
retrieval = new RetrievalService(
|
|
123
|
+
logger,
|
|
124
|
+
memory.chroma.collections,
|
|
125
|
+
memory.chroma.embeddings,
|
|
126
|
+
config.retrieval
|
|
127
|
+
)
|
|
128
|
+
await retrieval.initialize()
|
|
129
|
+
serviceLogger.info('Retrieval service initialized')
|
|
130
|
+
} else if (config.retrieval?.enabled && !memory.isChromaDBEnabled()) {
|
|
131
|
+
serviceLogger.warn('Retrieval service requires ChromaDB, skipping initialization')
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Initialize Retrieval Pipeline (Phase 19) — hybrid search with BM25 + semantic + fusion
|
|
135
|
+
let retrievalPipeline: RetrievalPipeline | null = null
|
|
136
|
+
if (config.retrieval?.enabled && memory.isChromaDBEnabled()) {
|
|
137
|
+
try {
|
|
138
|
+
retrievalPipeline = new RetrievalPipeline(
|
|
139
|
+
logger,
|
|
140
|
+
memory.chroma.collections,
|
|
141
|
+
memory.chroma.embeddings,
|
|
142
|
+
config.retrieval
|
|
143
|
+
)
|
|
144
|
+
await retrievalPipeline.initialize()
|
|
145
|
+
serviceLogger.info('Retrieval pipeline initialized (hybrid search)')
|
|
146
|
+
} catch (error) {
|
|
147
|
+
serviceLogger.warn({ error }, 'Failed to initialize retrieval pipeline, continuing without hybrid search')
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Initialize Knowledge Graph Service (Phase 14)
|
|
152
|
+
let knowledgeGraph: KnowledgeGraphServiceContainer | null = null
|
|
153
|
+
if (config.knowledge?.graph?.enabled !== false) {
|
|
154
|
+
try {
|
|
155
|
+
const graph = new InMemoryKnowledgeGraph(logger)
|
|
156
|
+
const graphPersistPath = config.knowledge?.graph?.persistPath || './data/knowledge-graph.json'
|
|
157
|
+
|
|
158
|
+
// Load existing graph from disk
|
|
159
|
+
await graph.load(graphPersistPath)
|
|
160
|
+
|
|
161
|
+
const search = new GraphSearchEngine(graph, logger)
|
|
162
|
+
const builder = new KnowledgeGraphBuilder(graph, logger)
|
|
163
|
+
await builder.initialize()
|
|
164
|
+
const linker = new CrossReferenceLinker(graph, logger)
|
|
165
|
+
|
|
166
|
+
// Start auto-save
|
|
167
|
+
const autoSaveInterval = (config.knowledge?.graph?.autoSaveInterval || 60) * 1000
|
|
168
|
+
graph.startAutoSave(graphPersistPath, autoSaveInterval)
|
|
169
|
+
|
|
170
|
+
knowledgeGraph = { graph, search, builder, linker }
|
|
171
|
+
|
|
172
|
+
// Migrate existing decisions if graph is empty (requires ChromaDB)
|
|
173
|
+
if (graph.getNodeCount() === 0 && memory.isChromaDBEnabled()) {
|
|
174
|
+
serviceLogger.info('Empty graph detected, migrating existing decisions...')
|
|
175
|
+
const migrationResult = await builder.migrateExistingDecisions(memory.chroma.collections)
|
|
176
|
+
serviceLogger.info(
|
|
177
|
+
{ processed: migrationResult.processed, errors: migrationResult.errors },
|
|
178
|
+
'Initial graph migration complete'
|
|
179
|
+
)
|
|
180
|
+
} else if (graph.getNodeCount() === 0) {
|
|
181
|
+
serviceLogger.info('Empty graph detected, but ChromaDB unavailable — graph will populate as new decisions are stored')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Hook builder into decision storage for real-time graph population
|
|
185
|
+
// Uses MemoryManager listener so it works for both ChromaDB and SQLite paths
|
|
186
|
+
memory.addDecisionStoredListener((input) => {
|
|
187
|
+
builder.processDecision(input)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Hook builder into decision deletion for graph synchronization
|
|
191
|
+
memory.addDecisionDeletedListener((id) => {
|
|
192
|
+
builder.removeDecision(id)
|
|
193
|
+
|
|
194
|
+
// Phase 20: Also unlink from active episodes
|
|
195
|
+
if (episodeManager) {
|
|
196
|
+
episodeManager.unlinkDecision(id)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Phase 20: Invalidate semantic cache for deleted decisions
|
|
200
|
+
if (semanticCache) {
|
|
201
|
+
semanticCache.clear()
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
serviceLogger.info(
|
|
206
|
+
{ nodes: graph.getNodeCount(), edges: graph.getEdgeCount() },
|
|
207
|
+
'Knowledge graph service initialized'
|
|
208
|
+
)
|
|
209
|
+
} catch (error) {
|
|
210
|
+
serviceLogger.warn({ error }, 'Failed to initialize knowledge graph, continuing without it')
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Initialize Episode Manager (Phase 14) — requires ChromaDB
|
|
215
|
+
let episodeManager: EpisodeManager | null = null
|
|
216
|
+
if (config.knowledge?.episodic?.enabled !== false && memory.isChromaDBEnabled()) {
|
|
217
|
+
try {
|
|
218
|
+
episodeManager = new EpisodeManager(
|
|
219
|
+
logger,
|
|
220
|
+
memory.chroma.collections,
|
|
221
|
+
memory.chroma.embeddings,
|
|
222
|
+
{ sessionGapMinutes: config.knowledge?.episodic?.sessionGapMinutes || 30 }
|
|
223
|
+
)
|
|
224
|
+
serviceLogger.info('Episode manager initialized')
|
|
225
|
+
} catch (error) {
|
|
226
|
+
serviceLogger.warn({ error }, 'Failed to initialize episode manager, continuing without it')
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Initialize Session Tracker (Phase 21) — promoted from serve.ts
|
|
231
|
+
let sessionTracker: HookSessionTracker | null = null
|
|
232
|
+
if (config.hooks?.enabled !== false) {
|
|
233
|
+
try {
|
|
234
|
+
sessionTracker = new HookSessionTracker(logger, episodeManager, config.hooks?.sessions, memory)
|
|
235
|
+
serviceLogger.info('Session tracker initialized')
|
|
236
|
+
} catch (error) {
|
|
237
|
+
serviceLogger.warn({ error }, 'Failed to initialize session tracker, continuing without it')
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Initialize Semantic Cache & Precompute (Phase 15) — requires ChromaDB
|
|
242
|
+
let semanticCache: SemanticCache | null = null
|
|
243
|
+
let precompute: PrecomputeEngine | null = null
|
|
244
|
+
if (config.advancedIntelligence?.enabled !== false && config.advancedIntelligence?.cache?.enabled !== false && memory.isChromaDBEnabled()) {
|
|
245
|
+
try {
|
|
246
|
+
const cacheConfig = config.advancedIntelligence?.cache || {}
|
|
247
|
+
semanticCache = new SemanticCache(logger, {
|
|
248
|
+
maxSize: cacheConfig.maxSize || 1000,
|
|
249
|
+
ttlMs: cacheConfig.ttlMs || 60 * 60 * 1000,
|
|
250
|
+
similarityThreshold: cacheConfig.similarityThreshold || 0.80,
|
|
251
|
+
embeddings: memory.chroma.embeddings
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
precompute = new PrecomputeEngine(logger, memory.chroma.collections, semanticCache)
|
|
255
|
+
await precompute.initialize()
|
|
256
|
+
precompute.startAutoRefresh(5 * 60 * 1000) // Refresh every 5 minutes
|
|
257
|
+
|
|
258
|
+
serviceLogger.info('Phase 15 semantic cache & precompute initialized')
|
|
259
|
+
} catch (error) {
|
|
260
|
+
serviceLogger.warn({ error }, 'Failed to initialize Phase 15 caching, continuing without it')
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Store services
|
|
265
|
+
services = {
|
|
266
|
+
memory,
|
|
267
|
+
vault,
|
|
268
|
+
context,
|
|
269
|
+
phase12,
|
|
270
|
+
retrieval,
|
|
271
|
+
retrievalPipeline,
|
|
272
|
+
knowledgeGraph,
|
|
273
|
+
episodeManager,
|
|
274
|
+
sessionTracker,
|
|
275
|
+
semanticCache,
|
|
276
|
+
precompute,
|
|
277
|
+
logger,
|
|
278
|
+
config
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
serviceLogger.info('All services initialized successfully')
|
|
282
|
+
})()
|
|
283
|
+
|
|
284
|
+
await initializationPromise
|
|
285
|
+
return services!
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get initialized services
|
|
290
|
+
* Throws if services not initialized
|
|
291
|
+
*/
|
|
292
|
+
export function getServices(): Services {
|
|
293
|
+
if (!services) {
|
|
294
|
+
throw new Error('Services not initialized. Call initializeServices() first.')
|
|
295
|
+
}
|
|
296
|
+
return services
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get memory service
|
|
301
|
+
* Throws if not initialized
|
|
302
|
+
*/
|
|
303
|
+
export function getMemoryService(): MemoryManager {
|
|
304
|
+
return getServices().memory
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Get vault service
|
|
309
|
+
* Throws if not initialized
|
|
310
|
+
*/
|
|
311
|
+
export function getVaultService(): VaultManager {
|
|
312
|
+
return getServices().vault
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function getContextService(): ContextManager {
|
|
316
|
+
return getServices().context
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get Phase 12 service
|
|
321
|
+
* Throws if not initialized
|
|
322
|
+
*/
|
|
323
|
+
export function getPhase12Service(): Phase12Manager {
|
|
324
|
+
return getServices().phase12
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get Retrieval service
|
|
329
|
+
* Returns null if retrieval is not enabled
|
|
330
|
+
*/
|
|
331
|
+
export function getRetrievalService(): RetrievalService | null {
|
|
332
|
+
return getServices().retrieval
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get Retrieval Pipeline (Phase 19)
|
|
337
|
+
* Returns null if hybrid search is not enabled
|
|
338
|
+
*/
|
|
339
|
+
export function getRetrievalPipeline(): RetrievalPipeline | null {
|
|
340
|
+
return getServices().retrievalPipeline
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Get Knowledge Graph service
|
|
345
|
+
* Returns null if knowledge graph is not enabled
|
|
346
|
+
*/
|
|
347
|
+
export function getKnowledgeGraphService(): KnowledgeGraphServiceContainer | null {
|
|
348
|
+
return getServices().knowledgeGraph
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Get Episode Manager service
|
|
353
|
+
* Returns null if episodic memory is not enabled
|
|
354
|
+
*/
|
|
355
|
+
export function getEpisodeService(): EpisodeManager | null {
|
|
356
|
+
return getServices().episodeManager
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get Session Tracker service
|
|
361
|
+
* Returns null if hooks are not enabled
|
|
362
|
+
*/
|
|
363
|
+
export function getSessionTracker(): HookSessionTracker | null {
|
|
364
|
+
return getServices().sessionTracker
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get Semantic Cache service
|
|
369
|
+
* Returns null if caching is not enabled
|
|
370
|
+
*/
|
|
371
|
+
export function getSemanticCacheService(): SemanticCache | null {
|
|
372
|
+
return getServices().semanticCache
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Get Precompute Engine service
|
|
377
|
+
* Returns null if caching is not enabled
|
|
378
|
+
*/
|
|
379
|
+
export function getPrecomputeService(): PrecomputeEngine | null {
|
|
380
|
+
return getServices().precompute
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Check if services are initialized
|
|
385
|
+
*/
|
|
386
|
+
export function isServicesInitialized(): boolean {
|
|
387
|
+
return services !== null
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Inject services for testing
|
|
392
|
+
* Allows tests to provide mock services without going through initializeServices
|
|
393
|
+
* @internal - Only use in tests
|
|
394
|
+
*/
|
|
395
|
+
export function _injectServicesForTesting(testServices: Services | null): void {
|
|
396
|
+
services = testServices
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Reset services for testing
|
|
401
|
+
* Clears the services singleton without proper shutdown
|
|
402
|
+
* @internal - Only use in tests
|
|
403
|
+
*/
|
|
404
|
+
export function _resetServicesForTesting(): void {
|
|
405
|
+
services = null
|
|
406
|
+
initializationPromise = null
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Shutdown all services gracefully
|
|
411
|
+
*/
|
|
412
|
+
export async function shutdownServices(): Promise<void> {
|
|
413
|
+
if (!services) {
|
|
414
|
+
return
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const serviceLogger = services.logger.child({ component: 'services' })
|
|
418
|
+
serviceLogger.info('Shutting down services...')
|
|
419
|
+
|
|
420
|
+
// End all active sessions
|
|
421
|
+
if (services.sessionTracker) {
|
|
422
|
+
try {
|
|
423
|
+
await services.sessionTracker.endAllSessions()
|
|
424
|
+
serviceLogger.info('Session tracker shut down')
|
|
425
|
+
} catch (error) {
|
|
426
|
+
serviceLogger.error({ error }, 'Failed to end sessions on shutdown')
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Save and stop knowledge graph
|
|
431
|
+
if (services.knowledgeGraph) {
|
|
432
|
+
services.knowledgeGraph.graph.stopAutoSave()
|
|
433
|
+
const persistPath = services.config.knowledge?.graph?.persistPath || './data/knowledge-graph.json'
|
|
434
|
+
try {
|
|
435
|
+
await services.knowledgeGraph.graph.save(persistPath)
|
|
436
|
+
serviceLogger.info('Knowledge graph saved on shutdown')
|
|
437
|
+
} catch (error) {
|
|
438
|
+
serviceLogger.error({ error }, 'Failed to save knowledge graph on shutdown')
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Stop precompute auto-refresh
|
|
443
|
+
if (services.precompute) {
|
|
444
|
+
services.precompute.stopAutoRefresh()
|
|
445
|
+
serviceLogger.info('Precompute engine stopped')
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Clear semantic cache
|
|
449
|
+
if (services.semanticCache) {
|
|
450
|
+
services.semanticCache.clear()
|
|
451
|
+
serviceLogger.info('Semantic cache cleared')
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Cleanup Phase 12
|
|
455
|
+
services.phase12.cleanup()
|
|
456
|
+
|
|
457
|
+
// Stop vault watcher
|
|
458
|
+
services.vault.stopWatching()
|
|
459
|
+
|
|
460
|
+
// Close memory database
|
|
461
|
+
services.memory.close()
|
|
462
|
+
|
|
463
|
+
// Clear reference
|
|
464
|
+
services = null
|
|
465
|
+
initializationPromise = null
|
|
466
|
+
|
|
467
|
+
serviceLogger.info('All services shut down')
|
|
468
|
+
}
|