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,184 +1,184 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EventQueue - Priority-based event queue with retry support
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Logger } from 'pino'
|
|
6
|
-
import type { Event, EventQueueItem, QueueStatus, EventPriority } from './types'
|
|
7
|
-
|
|
8
|
-
const PRIORITY_ORDER: Record<EventPriority, number> = {
|
|
9
|
-
urgent: 0,
|
|
10
|
-
high: 1,
|
|
11
|
-
normal: 2,
|
|
12
|
-
low: 3
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class EventQueue {
|
|
16
|
-
private queue: EventQueueItem[]
|
|
17
|
-
private processing: boolean = false
|
|
18
|
-
private logger: Logger
|
|
19
|
-
|
|
20
|
-
constructor(logger: Logger) {
|
|
21
|
-
this.logger = logger.child({ component: 'event-queue' })
|
|
22
|
-
this.queue = []
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Add event to queue with priority ordering
|
|
27
|
-
*/
|
|
28
|
-
enqueue(event: Event, maxRetries: number = 3): void {
|
|
29
|
-
const item: EventQueueItem = {
|
|
30
|
-
event,
|
|
31
|
-
retries: 0,
|
|
32
|
-
maxRetries
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Insert based on priority
|
|
36
|
-
const insertIndex = this.queue.findIndex(
|
|
37
|
-
i => PRIORITY_ORDER[i.event.priority] > PRIORITY_ORDER[event.priority]
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
if (insertIndex === -1) {
|
|
41
|
-
this.queue.push(item)
|
|
42
|
-
} else {
|
|
43
|
-
this.queue.splice(insertIndex, 0, item)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.logger.debug(
|
|
47
|
-
{ eventId: event.id, priority: event.priority, queueSize: this.queue.length },
|
|
48
|
-
'Event enqueued'
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get next ready event from queue
|
|
54
|
-
*/
|
|
55
|
-
dequeue(): EventQueueItem | undefined {
|
|
56
|
-
// Filter out items scheduled for future
|
|
57
|
-
const now = new Date()
|
|
58
|
-
const readyIndex = this.queue.findIndex(
|
|
59
|
-
item => !item.scheduledFor || item.scheduledFor <= now
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
if (readyIndex === -1) {
|
|
63
|
-
return undefined
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return this.queue.splice(readyIndex, 1)[0]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Peek at next event without removing it
|
|
71
|
-
*/
|
|
72
|
-
peek(): EventQueueItem | undefined {
|
|
73
|
-
const now = new Date()
|
|
74
|
-
return this.queue.find(item => !item.scheduledFor || item.scheduledFor <= now)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Reschedule failed event with exponential backoff
|
|
79
|
-
*/
|
|
80
|
-
reschedule(item: EventQueueItem, delayMs: number): boolean {
|
|
81
|
-
item.retries++
|
|
82
|
-
item.scheduledFor = new Date(Date.now() + delayMs)
|
|
83
|
-
|
|
84
|
-
if (item.retries < item.maxRetries) {
|
|
85
|
-
// Add back to queue (at end, will be sorted by time)
|
|
86
|
-
this.queue.push(item)
|
|
87
|
-
this.logger.info(
|
|
88
|
-
{ eventId: item.event.id, retries: item.retries, delayMs },
|
|
89
|
-
'Event rescheduled'
|
|
90
|
-
)
|
|
91
|
-
return true
|
|
92
|
-
} else {
|
|
93
|
-
this.logger.error(
|
|
94
|
-
{ eventId: item.event.id, retries: item.retries },
|
|
95
|
-
'Event exceeded max retries'
|
|
96
|
-
)
|
|
97
|
-
return false
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get queue size
|
|
103
|
-
*/
|
|
104
|
-
size(): number {
|
|
105
|
-
return this.queue.length
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Get count of ready (not scheduled) items
|
|
110
|
-
*/
|
|
111
|
-
readyCount(): number {
|
|
112
|
-
const now = new Date()
|
|
113
|
-
return this.queue.filter(item => !item.scheduledFor || item.scheduledFor <= now).length
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Check if queue is empty
|
|
118
|
-
*/
|
|
119
|
-
isEmpty(): boolean {
|
|
120
|
-
return this.queue.length === 0
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Clear queue
|
|
125
|
-
*/
|
|
126
|
-
clear(): void {
|
|
127
|
-
const previousSize = this.queue.length
|
|
128
|
-
this.queue = []
|
|
129
|
-
this.logger.debug({ previousSize }, 'Queue cleared')
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Set processing state
|
|
134
|
-
*/
|
|
135
|
-
setProcessing(value: boolean): void {
|
|
136
|
-
this.processing = value
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Check if currently processing
|
|
141
|
-
*/
|
|
142
|
-
isProcessing(): boolean {
|
|
143
|
-
return this.processing
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get queue status
|
|
148
|
-
*/
|
|
149
|
-
getStatus(): QueueStatus {
|
|
150
|
-
return {
|
|
151
|
-
size: this.queue.length,
|
|
152
|
-
processing: this.processing,
|
|
153
|
-
events: this.queue.map(item => ({
|
|
154
|
-
id: item.event.id,
|
|
155
|
-
type: item.event.type,
|
|
156
|
-
priority: item.event.priority,
|
|
157
|
-
retries: item.retries,
|
|
158
|
-
scheduledFor: item.scheduledFor
|
|
159
|
-
}))
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Get events by type
|
|
165
|
-
*/
|
|
166
|
-
getEventsByType(type: Event['type']): EventQueueItem[] {
|
|
167
|
-
return this.queue.filter(item => item.event.type === type)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Remove events matching a predicate
|
|
172
|
-
*/
|
|
173
|
-
removeWhere(predicate: (item: EventQueueItem) => boolean): number {
|
|
174
|
-
const initialLength = this.queue.length
|
|
175
|
-
this.queue = this.queue.filter(item => !predicate(item))
|
|
176
|
-
const removed = initialLength - this.queue.length
|
|
177
|
-
|
|
178
|
-
if (removed > 0) {
|
|
179
|
-
this.logger.debug({ removed }, 'Events removed from queue')
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return removed
|
|
183
|
-
}
|
|
184
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* EventQueue - Priority-based event queue with retry support
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Logger } from 'pino'
|
|
6
|
+
import type { Event, EventQueueItem, QueueStatus, EventPriority } from './types'
|
|
7
|
+
|
|
8
|
+
const PRIORITY_ORDER: Record<EventPriority, number> = {
|
|
9
|
+
urgent: 0,
|
|
10
|
+
high: 1,
|
|
11
|
+
normal: 2,
|
|
12
|
+
low: 3
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class EventQueue {
|
|
16
|
+
private queue: EventQueueItem[]
|
|
17
|
+
private processing: boolean = false
|
|
18
|
+
private logger: Logger
|
|
19
|
+
|
|
20
|
+
constructor(logger: Logger) {
|
|
21
|
+
this.logger = logger.child({ component: 'event-queue' })
|
|
22
|
+
this.queue = []
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Add event to queue with priority ordering
|
|
27
|
+
*/
|
|
28
|
+
enqueue(event: Event, maxRetries: number = 3): void {
|
|
29
|
+
const item: EventQueueItem = {
|
|
30
|
+
event,
|
|
31
|
+
retries: 0,
|
|
32
|
+
maxRetries
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Insert based on priority
|
|
36
|
+
const insertIndex = this.queue.findIndex(
|
|
37
|
+
i => PRIORITY_ORDER[i.event.priority] > PRIORITY_ORDER[event.priority]
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (insertIndex === -1) {
|
|
41
|
+
this.queue.push(item)
|
|
42
|
+
} else {
|
|
43
|
+
this.queue.splice(insertIndex, 0, item)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.logger.debug(
|
|
47
|
+
{ eventId: event.id, priority: event.priority, queueSize: this.queue.length },
|
|
48
|
+
'Event enqueued'
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get next ready event from queue
|
|
54
|
+
*/
|
|
55
|
+
dequeue(): EventQueueItem | undefined {
|
|
56
|
+
// Filter out items scheduled for future
|
|
57
|
+
const now = new Date()
|
|
58
|
+
const readyIndex = this.queue.findIndex(
|
|
59
|
+
item => !item.scheduledFor || item.scheduledFor <= now
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if (readyIndex === -1) {
|
|
63
|
+
return undefined
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return this.queue.splice(readyIndex, 1)[0]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Peek at next event without removing it
|
|
71
|
+
*/
|
|
72
|
+
peek(): EventQueueItem | undefined {
|
|
73
|
+
const now = new Date()
|
|
74
|
+
return this.queue.find(item => !item.scheduledFor || item.scheduledFor <= now)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Reschedule failed event with exponential backoff
|
|
79
|
+
*/
|
|
80
|
+
reschedule(item: EventQueueItem, delayMs: number): boolean {
|
|
81
|
+
item.retries++
|
|
82
|
+
item.scheduledFor = new Date(Date.now() + delayMs)
|
|
83
|
+
|
|
84
|
+
if (item.retries < item.maxRetries) {
|
|
85
|
+
// Add back to queue (at end, will be sorted by time)
|
|
86
|
+
this.queue.push(item)
|
|
87
|
+
this.logger.info(
|
|
88
|
+
{ eventId: item.event.id, retries: item.retries, delayMs },
|
|
89
|
+
'Event rescheduled'
|
|
90
|
+
)
|
|
91
|
+
return true
|
|
92
|
+
} else {
|
|
93
|
+
this.logger.error(
|
|
94
|
+
{ eventId: item.event.id, retries: item.retries },
|
|
95
|
+
'Event exceeded max retries'
|
|
96
|
+
)
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get queue size
|
|
103
|
+
*/
|
|
104
|
+
size(): number {
|
|
105
|
+
return this.queue.length
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get count of ready (not scheduled) items
|
|
110
|
+
*/
|
|
111
|
+
readyCount(): number {
|
|
112
|
+
const now = new Date()
|
|
113
|
+
return this.queue.filter(item => !item.scheduledFor || item.scheduledFor <= now).length
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if queue is empty
|
|
118
|
+
*/
|
|
119
|
+
isEmpty(): boolean {
|
|
120
|
+
return this.queue.length === 0
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Clear queue
|
|
125
|
+
*/
|
|
126
|
+
clear(): void {
|
|
127
|
+
const previousSize = this.queue.length
|
|
128
|
+
this.queue = []
|
|
129
|
+
this.logger.debug({ previousSize }, 'Queue cleared')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Set processing state
|
|
134
|
+
*/
|
|
135
|
+
setProcessing(value: boolean): void {
|
|
136
|
+
this.processing = value
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check if currently processing
|
|
141
|
+
*/
|
|
142
|
+
isProcessing(): boolean {
|
|
143
|
+
return this.processing
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get queue status
|
|
148
|
+
*/
|
|
149
|
+
getStatus(): QueueStatus {
|
|
150
|
+
return {
|
|
151
|
+
size: this.queue.length,
|
|
152
|
+
processing: this.processing,
|
|
153
|
+
events: this.queue.map(item => ({
|
|
154
|
+
id: item.event.id,
|
|
155
|
+
type: item.event.type,
|
|
156
|
+
priority: item.event.priority,
|
|
157
|
+
retries: item.retries,
|
|
158
|
+
scheduledFor: item.scheduledFor
|
|
159
|
+
}))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get events by type
|
|
165
|
+
*/
|
|
166
|
+
getEventsByType(type: Event['type']): EventQueueItem[] {
|
|
167
|
+
return this.queue.filter(item => item.event.type === type)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Remove events matching a predicate
|
|
172
|
+
*/
|
|
173
|
+
removeWhere(predicate: (item: EventQueueItem) => boolean): number {
|
|
174
|
+
const initialLength = this.queue.length
|
|
175
|
+
this.queue = this.queue.filter(item => !predicate(item))
|
|
176
|
+
const removed = initialLength - this.queue.length
|
|
177
|
+
|
|
178
|
+
if (removed > 0) {
|
|
179
|
+
this.logger.debug({ removed }, 'Events removed from queue')
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return removed
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BaseHandler - Abstract base class for event handlers
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Logger } from 'pino'
|
|
6
|
-
import type { Event, EventHandler, EventType, EventPriority } from '../types'
|
|
7
|
-
|
|
8
|
-
export abstract class BaseHandler implements EventHandler {
|
|
9
|
-
abstract name: string
|
|
10
|
-
abstract types: EventType[]
|
|
11
|
-
abstract priority: EventPriority
|
|
12
|
-
|
|
13
|
-
protected logger: Logger
|
|
14
|
-
|
|
15
|
-
constructor(logger: Logger) {
|
|
16
|
-
// Logger child will be created in subclasses after name is defined
|
|
17
|
-
this.logger = logger
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Initialize logger with component name
|
|
22
|
-
* Call this in subclass constructor after setting name
|
|
23
|
-
*/
|
|
24
|
-
protected initLogger(logger: Logger): void {
|
|
25
|
-
this.logger = logger.child({ component: this.name })
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
abstract handle(event: Event): Promise<void>
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Log that we're handling an event
|
|
32
|
-
*/
|
|
33
|
-
protected logHandling(event: Event): void {
|
|
34
|
-
this.logger.info(
|
|
35
|
-
{ eventId: event.id, type: event.type },
|
|
36
|
-
'Handling event'
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Log a successful handling
|
|
42
|
-
*/
|
|
43
|
-
protected logSuccess(event: Event, details?: Record<string, unknown>): void {
|
|
44
|
-
this.logger.info(
|
|
45
|
-
{ eventId: event.id, type: event.type, ...details },
|
|
46
|
-
'Event handled successfully'
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Log a failed handling
|
|
52
|
-
*/
|
|
53
|
-
protected logError(event: Event, error: unknown): void {
|
|
54
|
-
this.logger.error(
|
|
55
|
-
{
|
|
56
|
-
eventId: event.id,
|
|
57
|
-
type: event.type,
|
|
58
|
-
error: error instanceof Error ? error.message : String(error)
|
|
59
|
-
},
|
|
60
|
-
'Event handling failed'
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Check if the event should be handled based on file path
|
|
66
|
-
*/
|
|
67
|
-
protected shouldHandleFile(filePath: string, patterns: string[]): boolean {
|
|
68
|
-
return patterns.some(pattern => filePath.endsWith(pattern))
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* BaseHandler - Abstract base class for event handlers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Logger } from 'pino'
|
|
6
|
+
import type { Event, EventHandler, EventType, EventPriority } from '../types'
|
|
7
|
+
|
|
8
|
+
export abstract class BaseHandler implements EventHandler {
|
|
9
|
+
abstract name: string
|
|
10
|
+
abstract types: EventType[]
|
|
11
|
+
abstract priority: EventPriority
|
|
12
|
+
|
|
13
|
+
protected logger: Logger
|
|
14
|
+
|
|
15
|
+
constructor(logger: Logger) {
|
|
16
|
+
// Logger child will be created in subclasses after name is defined
|
|
17
|
+
this.logger = logger
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initialize logger with component name
|
|
22
|
+
* Call this in subclass constructor after setting name
|
|
23
|
+
*/
|
|
24
|
+
protected initLogger(logger: Logger): void {
|
|
25
|
+
this.logger = logger.child({ component: this.name })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
abstract handle(event: Event): Promise<void>
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Log that we're handling an event
|
|
32
|
+
*/
|
|
33
|
+
protected logHandling(event: Event): void {
|
|
34
|
+
this.logger.info(
|
|
35
|
+
{ eventId: event.id, type: event.type },
|
|
36
|
+
'Handling event'
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Log a successful handling
|
|
42
|
+
*/
|
|
43
|
+
protected logSuccess(event: Event, details?: Record<string, unknown>): void {
|
|
44
|
+
this.logger.info(
|
|
45
|
+
{ eventId: event.id, type: event.type, ...details },
|
|
46
|
+
'Event handled successfully'
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log a failed handling
|
|
52
|
+
*/
|
|
53
|
+
protected logError(event: Event, error: unknown): void {
|
|
54
|
+
this.logger.error(
|
|
55
|
+
{
|
|
56
|
+
eventId: event.id,
|
|
57
|
+
type: event.type,
|
|
58
|
+
error: error instanceof Error ? error.message : String(error)
|
|
59
|
+
},
|
|
60
|
+
'Event handling failed'
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if the event should be handled based on file path
|
|
66
|
+
*/
|
|
67
|
+
protected shouldHandleFile(filePath: string, patterns: string[]): boolean {
|
|
68
|
+
return patterns.some(pattern => filePath.endsWith(pattern))
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ContextUpdateHandler - Handles context.md file changes and cache invalidation
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Logger } from 'pino'
|
|
6
|
-
import type { Event, EventType, EventPriority } from '../types'
|
|
7
|
-
import type { VaultReader } from '@/vault'
|
|
8
|
-
import { BaseHandler } from './base-handler'
|
|
9
|
-
import type { EventBus } from '../event-emitter'
|
|
10
|
-
|
|
11
|
-
export class ContextUpdateHandler extends BaseHandler {
|
|
12
|
-
name = 'context-update-handler'
|
|
13
|
-
types: EventType[] = ['file:modified']
|
|
14
|
-
priority: EventPriority = 'low'
|
|
15
|
-
|
|
16
|
-
private vaultReader: VaultReader
|
|
17
|
-
private eventBus: EventBus | null = null
|
|
18
|
-
|
|
19
|
-
constructor(logger: Logger, vaultReader: VaultReader) {
|
|
20
|
-
super(logger)
|
|
21
|
-
this.initLogger(logger)
|
|
22
|
-
this.vaultReader = vaultReader
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Set the event bus for emitting context events
|
|
27
|
-
*/
|
|
28
|
-
setEventBus(eventBus: EventBus): void {
|
|
29
|
-
this.eventBus = eventBus
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async handle(event: Event): Promise<void> {
|
|
33
|
-
this.logHandling(event)
|
|
34
|
-
|
|
35
|
-
const filePath = event.payload.path as string
|
|
36
|
-
|
|
37
|
-
// Only process context.md files
|
|
38
|
-
if (!this.shouldHandleFile(filePath, ['context.md'])) {
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
// Invalidate cache for this file
|
|
44
|
-
this.vaultReader.invalidateCache(filePath)
|
|
45
|
-
|
|
46
|
-
this.logger.info(
|
|
47
|
-
{ filePath },
|
|
48
|
-
'Project context updated, cache invalidated'
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
// Emit context update event if event bus is available
|
|
52
|
-
if (this.eventBus) {
|
|
53
|
-
// Try to extract project name from path
|
|
54
|
-
const projectMatch = filePath.match(/Projects[\/\\]([^\/\\]+)[\/\\]/)
|
|
55
|
-
const project = projectMatch ? projectMatch[1] : undefined
|
|
56
|
-
|
|
57
|
-
this.eventBus.emitEvent(
|
|
58
|
-
'project:updated',
|
|
59
|
-
{
|
|
60
|
-
type: 'context-update',
|
|
61
|
-
filePath,
|
|
62
|
-
project
|
|
63
|
-
},
|
|
64
|
-
this.name
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
this.logSuccess(event, { filePath })
|
|
69
|
-
} catch (error) {
|
|
70
|
-
this.logError(event, error)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* ContextUpdateHandler - Handles context.md file changes and cache invalidation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Logger } from 'pino'
|
|
6
|
+
import type { Event, EventType, EventPriority } from '../types'
|
|
7
|
+
import type { VaultReader } from '@/vault'
|
|
8
|
+
import { BaseHandler } from './base-handler'
|
|
9
|
+
import type { EventBus } from '../event-emitter'
|
|
10
|
+
|
|
11
|
+
export class ContextUpdateHandler extends BaseHandler {
|
|
12
|
+
name = 'context-update-handler'
|
|
13
|
+
types: EventType[] = ['file:modified']
|
|
14
|
+
priority: EventPriority = 'low'
|
|
15
|
+
|
|
16
|
+
private vaultReader: VaultReader
|
|
17
|
+
private eventBus: EventBus | null = null
|
|
18
|
+
|
|
19
|
+
constructor(logger: Logger, vaultReader: VaultReader) {
|
|
20
|
+
super(logger)
|
|
21
|
+
this.initLogger(logger)
|
|
22
|
+
this.vaultReader = vaultReader
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Set the event bus for emitting context events
|
|
27
|
+
*/
|
|
28
|
+
setEventBus(eventBus: EventBus): void {
|
|
29
|
+
this.eventBus = eventBus
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async handle(event: Event): Promise<void> {
|
|
33
|
+
this.logHandling(event)
|
|
34
|
+
|
|
35
|
+
const filePath = event.payload.path as string
|
|
36
|
+
|
|
37
|
+
// Only process context.md files
|
|
38
|
+
if (!this.shouldHandleFile(filePath, ['context.md'])) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
// Invalidate cache for this file
|
|
44
|
+
this.vaultReader.invalidateCache(filePath)
|
|
45
|
+
|
|
46
|
+
this.logger.info(
|
|
47
|
+
{ filePath },
|
|
48
|
+
'Project context updated, cache invalidated'
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
// Emit context update event if event bus is available
|
|
52
|
+
if (this.eventBus) {
|
|
53
|
+
// Try to extract project name from path
|
|
54
|
+
const projectMatch = filePath.match(/Projects[\/\\]([^\/\\]+)[\/\\]/)
|
|
55
|
+
const project = projectMatch ? projectMatch[1] : undefined
|
|
56
|
+
|
|
57
|
+
this.eventBus.emitEvent(
|
|
58
|
+
'project:updated',
|
|
59
|
+
{
|
|
60
|
+
type: 'context-update',
|
|
61
|
+
filePath,
|
|
62
|
+
project
|
|
63
|
+
},
|
|
64
|
+
this.name
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.logSuccess(event, { filePath })
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this.logError(event, error)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|