claude-brain 0.3.0

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.
Files changed (200) hide show
  1. package/README.md +157 -0
  2. package/VERSION +1 -0
  3. package/assets/CLAUDE.md +307 -0
  4. package/bunfig.toml +8 -0
  5. package/package.json +74 -0
  6. package/src/automation/auto-context.ts +240 -0
  7. package/src/automation/decision-detector.ts +452 -0
  8. package/src/automation/index.ts +11 -0
  9. package/src/automation/proactive-recall.ts +373 -0
  10. package/src/automation/project-detector.ts +297 -0
  11. package/src/cli/auto-setup.ts +74 -0
  12. package/src/cli/bin.ts +110 -0
  13. package/src/cli/commands/install-mcp.ts +50 -0
  14. package/src/cli/commands/serve.ts +129 -0
  15. package/src/cli/diagnose.ts +4 -0
  16. package/src/cli/health-check.ts +4 -0
  17. package/src/cli/migrate-chroma.ts +106 -0
  18. package/src/cli/setup.ts +4 -0
  19. package/src/config/defaults.ts +47 -0
  20. package/src/config/home.ts +55 -0
  21. package/src/config/index.ts +7 -0
  22. package/src/config/loader.ts +166 -0
  23. package/src/config/migration.ts +76 -0
  24. package/src/config/schema.ts +257 -0
  25. package/src/config/validator.ts +184 -0
  26. package/src/config/watcher.ts +86 -0
  27. package/src/context/assembler.ts +398 -0
  28. package/src/context/cache-manager.ts +101 -0
  29. package/src/context/formatter.ts +84 -0
  30. package/src/context/hierarchy.ts +85 -0
  31. package/src/context/index.ts +83 -0
  32. package/src/context/progress-tracker.ts +174 -0
  33. package/src/context/standards-manager.ts +267 -0
  34. package/src/context/types.ts +252 -0
  35. package/src/context/validator.ts +58 -0
  36. package/src/cross-project/affinity.ts +162 -0
  37. package/src/cross-project/generalizer.ts +283 -0
  38. package/src/cross-project/index.ts +13 -0
  39. package/src/cross-project/transfer.ts +201 -0
  40. package/src/diagnostics/index.ts +123 -0
  41. package/src/health/index.ts +229 -0
  42. package/src/index.ts +7 -0
  43. package/src/knowledge/entity-extractor.ts +416 -0
  44. package/src/knowledge/graph/builder.ts +159 -0
  45. package/src/knowledge/graph/linker.ts +201 -0
  46. package/src/knowledge/graph/memory-graph.ts +359 -0
  47. package/src/knowledge/graph/schema.ts +99 -0
  48. package/src/knowledge/graph/search.ts +168 -0
  49. package/src/knowledge/relationship-extractor.ts +108 -0
  50. package/src/memory/chroma/client.ts +169 -0
  51. package/src/memory/chroma/collection-manager.ts +94 -0
  52. package/src/memory/chroma/config.ts +46 -0
  53. package/src/memory/chroma/embeddings.ts +153 -0
  54. package/src/memory/chroma/index.ts +82 -0
  55. package/src/memory/chroma/migration.ts +270 -0
  56. package/src/memory/chroma/schemas.ts +69 -0
  57. package/src/memory/chroma/search.ts +315 -0
  58. package/src/memory/chroma/store.ts +694 -0
  59. package/src/memory/consolidation/archiver.ts +164 -0
  60. package/src/memory/consolidation/merger.ts +186 -0
  61. package/src/memory/consolidation/scorer.ts +138 -0
  62. package/src/memory/context-builder.ts +236 -0
  63. package/src/memory/database.ts +169 -0
  64. package/src/memory/embedding-utils.ts +156 -0
  65. package/src/memory/embeddings.ts +226 -0
  66. package/src/memory/episodic/detector.ts +108 -0
  67. package/src/memory/episodic/manager.ts +334 -0
  68. package/src/memory/episodic/summarizer.ts +179 -0
  69. package/src/memory/episodic/types.ts +52 -0
  70. package/src/memory/index.ts +395 -0
  71. package/src/memory/knowledge-extractor.ts +455 -0
  72. package/src/memory/learning.ts +378 -0
  73. package/src/memory/patterns.ts +396 -0
  74. package/src/memory/schema.ts +56 -0
  75. package/src/memory/search.ts +309 -0
  76. package/src/memory/store.ts +344 -0
  77. package/src/memory/types.ts +121 -0
  78. package/src/optimization/index.ts +10 -0
  79. package/src/optimization/precompute.ts +202 -0
  80. package/src/optimization/semantic-cache.ts +207 -0
  81. package/src/orchestrator/coordinator.ts +272 -0
  82. package/src/orchestrator/decision-logger.ts +228 -0
  83. package/src/orchestrator/event-emitter.ts +198 -0
  84. package/src/orchestrator/event-queue.ts +184 -0
  85. package/src/orchestrator/handlers/base-handler.ts +70 -0
  86. package/src/orchestrator/handlers/context-handler.ts +73 -0
  87. package/src/orchestrator/handlers/decision-handler.ts +204 -0
  88. package/src/orchestrator/handlers/index.ts +10 -0
  89. package/src/orchestrator/handlers/status-handler.ts +131 -0
  90. package/src/orchestrator/handlers/task-handler.ts +171 -0
  91. package/src/orchestrator/index.ts +275 -0
  92. package/src/orchestrator/task-parser.ts +284 -0
  93. package/src/orchestrator/types.ts +98 -0
  94. package/src/phase12/index.ts +456 -0
  95. package/src/prediction/context-anticipator.ts +198 -0
  96. package/src/prediction/decision-predictor.ts +184 -0
  97. package/src/prediction/index.ts +13 -0
  98. package/src/prediction/recommender.ts +268 -0
  99. package/src/reasoning/chain-retrieval.ts +247 -0
  100. package/src/reasoning/counterfactual.ts +248 -0
  101. package/src/reasoning/index.ts +13 -0
  102. package/src/reasoning/synthesizer.ts +169 -0
  103. package/src/retrieval/bm25/index.ts +300 -0
  104. package/src/retrieval/bm25/tokenizer.ts +184 -0
  105. package/src/retrieval/feedback/adaptive.ts +223 -0
  106. package/src/retrieval/feedback/index.ts +16 -0
  107. package/src/retrieval/feedback/metrics.ts +223 -0
  108. package/src/retrieval/feedback/store.ts +283 -0
  109. package/src/retrieval/fusion/index.ts +194 -0
  110. package/src/retrieval/fusion/rrf.ts +163 -0
  111. package/src/retrieval/index.ts +12 -0
  112. package/src/retrieval/pipeline.ts +375 -0
  113. package/src/retrieval/query/expander.ts +198 -0
  114. package/src/retrieval/query/index.ts +27 -0
  115. package/src/retrieval/query/intent-classifier.ts +236 -0
  116. package/src/retrieval/query/temporal-parser.ts +295 -0
  117. package/src/retrieval/reranker/index.ts +188 -0
  118. package/src/retrieval/reranker/model.ts +95 -0
  119. package/src/retrieval/service.ts +125 -0
  120. package/src/retrieval/types.ts +162 -0
  121. package/src/scripts/health-check.ts +118 -0
  122. package/src/scripts/setup.ts +122 -0
  123. package/src/server/handlers/call-tool.ts +194 -0
  124. package/src/server/handlers/index.ts +9 -0
  125. package/src/server/handlers/list-tools.ts +18 -0
  126. package/src/server/handlers/tools/analyze-decision-evolution.ts +71 -0
  127. package/src/server/handlers/tools/auto-remember.ts +200 -0
  128. package/src/server/handlers/tools/create-project.ts +135 -0
  129. package/src/server/handlers/tools/detect-trends.ts +80 -0
  130. package/src/server/handlers/tools/find-cross-project-patterns.ts +73 -0
  131. package/src/server/handlers/tools/get-activity-log.ts +194 -0
  132. package/src/server/handlers/tools/get-code-standards.ts +124 -0
  133. package/src/server/handlers/tools/get-corrections.ts +154 -0
  134. package/src/server/handlers/tools/get-decision-timeline.ts +86 -0
  135. package/src/server/handlers/tools/get-episode.ts +93 -0
  136. package/src/server/handlers/tools/get-patterns.ts +158 -0
  137. package/src/server/handlers/tools/get-phase12-status.ts +63 -0
  138. package/src/server/handlers/tools/get-project-context.ts +75 -0
  139. package/src/server/handlers/tools/get-recommendations.ts +65 -0
  140. package/src/server/handlers/tools/index.ts +33 -0
  141. package/src/server/handlers/tools/init-project.ts +710 -0
  142. package/src/server/handlers/tools/list-episodes.ts +80 -0
  143. package/src/server/handlers/tools/list-projects.ts +125 -0
  144. package/src/server/handlers/tools/rate-memory.ts +95 -0
  145. package/src/server/handlers/tools/recall-similar.ts +87 -0
  146. package/src/server/handlers/tools/recognize-pattern.ts +126 -0
  147. package/src/server/handlers/tools/record-correction.ts +125 -0
  148. package/src/server/handlers/tools/remember-decision.ts +153 -0
  149. package/src/server/handlers/tools/schemas.ts +241 -0
  150. package/src/server/handlers/tools/search-knowledge-graph.ts +89 -0
  151. package/src/server/handlers/tools/smart-context.ts +124 -0
  152. package/src/server/handlers/tools/update-progress.ts +114 -0
  153. package/src/server/handlers/tools/what-if-analysis.ts +73 -0
  154. package/src/server/http-api.ts +474 -0
  155. package/src/server/index.ts +40 -0
  156. package/src/server/mcp-server.ts +283 -0
  157. package/src/server/providers/index.ts +7 -0
  158. package/src/server/providers/prompts.ts +327 -0
  159. package/src/server/providers/resources.ts +427 -0
  160. package/src/server/services.ts +388 -0
  161. package/src/server/types.ts +39 -0
  162. package/src/server/utils/error-handler.ts +155 -0
  163. package/src/server/utils/index.ts +13 -0
  164. package/src/server/utils/memory-indicator.ts +83 -0
  165. package/src/server/utils/request-context.ts +122 -0
  166. package/src/server/utils/response-formatter.ts +124 -0
  167. package/src/server/utils/validators.ts +210 -0
  168. package/src/setup/index.ts +22 -0
  169. package/src/setup/wizard.ts +321 -0
  170. package/src/temporal/evolution.ts +197 -0
  171. package/src/temporal/index.ts +16 -0
  172. package/src/temporal/query-processor.ts +190 -0
  173. package/src/temporal/timeline.ts +259 -0
  174. package/src/temporal/trends.ts +263 -0
  175. package/src/tools/index.ts +24 -0
  176. package/src/tools/registry.ts +106 -0
  177. package/src/tools/schemas.test.ts +30 -0
  178. package/src/tools/schemas.ts +907 -0
  179. package/src/tools/types.ts +412 -0
  180. package/src/utils/circuit-breaker.ts +130 -0
  181. package/src/utils/cleanup.ts +34 -0
  182. package/src/utils/error-handler.ts +132 -0
  183. package/src/utils/error-messages.ts +60 -0
  184. package/src/utils/fallback.ts +45 -0
  185. package/src/utils/index.ts +54 -0
  186. package/src/utils/logger-utils.ts +80 -0
  187. package/src/utils/logger.ts +88 -0
  188. package/src/utils/phase12-helper.ts +56 -0
  189. package/src/utils/retry.ts +94 -0
  190. package/src/utils/transaction.ts +63 -0
  191. package/src/vault/frontmatter.ts +264 -0
  192. package/src/vault/index.ts +318 -0
  193. package/src/vault/paths.ts +106 -0
  194. package/src/vault/query.ts +422 -0
  195. package/src/vault/reader.ts +264 -0
  196. package/src/vault/templates.ts +186 -0
  197. package/src/vault/types.ts +73 -0
  198. package/src/vault/watcher.ts +277 -0
  199. package/src/vault/writer.ts +393 -0
  200. package/tsconfig.json +30 -0
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Temporal Query Processor
3
+ * Parses temporal expressions from natural language using chrono-node
4
+ */
5
+
6
+ import * as chrono from 'chrono-node'
7
+ import type { Logger } from 'pino'
8
+
9
+ export interface TemporalQuery {
10
+ /** Original query text */
11
+ original: string
12
+ /** Cleaned query with temporal expressions removed */
13
+ cleaned: string
14
+ /** Parsed start date (if any) */
15
+ startDate?: string
16
+ /** Parsed end date (if any) */
17
+ endDate?: string
18
+ /** Temporal intent detected */
19
+ intent: 'range' | 'before' | 'after' | 'point' | 'none'
20
+ /** Relative time expressions found */
21
+ expressions: string[]
22
+ }
23
+
24
+ export class TemporalQueryProcessor {
25
+ private logger: Logger
26
+
27
+ constructor(logger: Logger) {
28
+ this.logger = logger.child({ component: 'temporal-query-processor' })
29
+ }
30
+
31
+ /**
32
+ * Parse temporal expressions from a natural language query
33
+ */
34
+ parse(query: string): TemporalQuery {
35
+ const result: TemporalQuery = {
36
+ original: query,
37
+ cleaned: query,
38
+ intent: 'none',
39
+ expressions: []
40
+ }
41
+
42
+ try {
43
+ // Parse with chrono-node
44
+ const parsed = chrono.parse(query, new Date(), { forwardDate: false })
45
+
46
+ if (parsed.length === 0) {
47
+ // Try manual temporal patterns
48
+ return this.parseManualPatterns(query, result)
49
+ }
50
+
51
+ const ref = parsed[0]
52
+ result.expressions.push(ref.text)
53
+
54
+ // Remove temporal expression from query for cleaner semantic search
55
+ result.cleaned = query.replace(ref.text, '').replace(/\s+/g, ' ').trim()
56
+
57
+ if (ref.start && ref.end) {
58
+ // Date range
59
+ result.startDate = ref.start.date().toISOString()
60
+ result.endDate = ref.end.date().toISOString()
61
+ result.intent = 'range'
62
+ } else if (ref.start) {
63
+ const startDate = ref.start.date()
64
+
65
+ // Check context for before/after
66
+ const beforeIndex = query.toLowerCase().indexOf('before')
67
+ const afterIndex = query.toLowerCase().indexOf('after')
68
+ const sinceIndex = query.toLowerCase().indexOf('since')
69
+ const untilIndex = query.toLowerCase().indexOf('until')
70
+
71
+ if (beforeIndex >= 0 && beforeIndex < query.indexOf(ref.text)) {
72
+ result.endDate = startDate.toISOString()
73
+ result.intent = 'before'
74
+ } else if (
75
+ (afterIndex >= 0 && afterIndex < query.indexOf(ref.text)) ||
76
+ (sinceIndex >= 0 && sinceIndex < query.indexOf(ref.text))
77
+ ) {
78
+ result.startDate = startDate.toISOString()
79
+ result.intent = 'after'
80
+ } else if (untilIndex >= 0 && untilIndex < query.indexOf(ref.text)) {
81
+ result.endDate = startDate.toISOString()
82
+ result.intent = 'before'
83
+ } else {
84
+ // Default: treat as a point in time, create a window around it
85
+ const dayBefore = new Date(startDate)
86
+ dayBefore.setDate(dayBefore.getDate() - 1)
87
+ const dayAfter = new Date(startDate)
88
+ dayAfter.setDate(dayAfter.getDate() + 1)
89
+
90
+ result.startDate = dayBefore.toISOString()
91
+ result.endDate = dayAfter.toISOString()
92
+ result.intent = 'point'
93
+ }
94
+ }
95
+
96
+ // Handle multiple temporal expressions
97
+ for (let i = 1; i < parsed.length; i++) {
98
+ result.expressions.push(parsed[i].text)
99
+ result.cleaned = result.cleaned.replace(parsed[i].text, '').replace(/\s+/g, ' ').trim()
100
+ }
101
+ } catch (error) {
102
+ this.logger.debug({ error, query }, 'Failed to parse temporal expression')
103
+ }
104
+
105
+ return result
106
+ }
107
+
108
+ private parseManualPatterns(query: string, result: TemporalQuery): TemporalQuery {
109
+ const lowerQuery = query.toLowerCase()
110
+ const now = new Date()
111
+
112
+ // "last week", "last month", "last year"
113
+ const lastMatch = lowerQuery.match(/\b(?:in the )?last\s+(week|month|year|quarter|(\d+)\s*(days?|weeks?|months?))\b/)
114
+ if (lastMatch) {
115
+ result.expressions.push(lastMatch[0])
116
+ result.cleaned = query.replace(new RegExp(lastMatch[0], 'i'), '').replace(/\s+/g, ' ').trim()
117
+ result.endDate = now.toISOString()
118
+
119
+ const start = new Date(now)
120
+ if (lastMatch[1] === 'week') {
121
+ start.setDate(start.getDate() - 7)
122
+ } else if (lastMatch[1] === 'month') {
123
+ start.setMonth(start.getMonth() - 1)
124
+ } else if (lastMatch[1] === 'year') {
125
+ start.setFullYear(start.getFullYear() - 1)
126
+ } else if (lastMatch[1] === 'quarter') {
127
+ start.setMonth(start.getMonth() - 3)
128
+ } else if (lastMatch[2] && lastMatch[3]) {
129
+ const n = parseInt(lastMatch[2])
130
+ const unit = lastMatch[3].replace(/s$/, '')
131
+ if (unit === 'day') start.setDate(start.getDate() - n)
132
+ else if (unit === 'week') start.setDate(start.getDate() - n * 7)
133
+ else if (unit === 'month') start.setMonth(start.getMonth() - n)
134
+ }
135
+
136
+ result.startDate = start.toISOString()
137
+ result.intent = 'range'
138
+ return result
139
+ }
140
+
141
+ // "recently", "lately"
142
+ if (/\b(recently|lately)\b/.test(lowerQuery)) {
143
+ const match = lowerQuery.match(/\b(recently|lately)\b/)!
144
+ result.expressions.push(match[0])
145
+ result.cleaned = query.replace(new RegExp(match[0], 'i'), '').replace(/\s+/g, ' ').trim()
146
+ const start = new Date(now)
147
+ start.setDate(start.getDate() - 14) // 2 weeks for "recently"
148
+ result.startDate = start.toISOString()
149
+ result.endDate = now.toISOString()
150
+ result.intent = 'range'
151
+ return result
152
+ }
153
+
154
+ // "this week", "this month", "this year"
155
+ const thisMatch = lowerQuery.match(/\bthis\s+(week|month|year)\b/)
156
+ if (thisMatch) {
157
+ result.expressions.push(thisMatch[0])
158
+ result.cleaned = query.replace(new RegExp(thisMatch[0], 'i'), '').replace(/\s+/g, ' ').trim()
159
+ result.endDate = now.toISOString()
160
+
161
+ const start = new Date(now)
162
+ if (thisMatch[1] === 'week') {
163
+ start.setDate(start.getDate() - start.getDay())
164
+ start.setHours(0, 0, 0, 0)
165
+ } else if (thisMatch[1] === 'month') {
166
+ start.setDate(1)
167
+ start.setHours(0, 0, 0, 0)
168
+ } else if (thisMatch[1] === 'year') {
169
+ start.setMonth(0, 1)
170
+ start.setHours(0, 0, 0, 0)
171
+ }
172
+
173
+ result.startDate = start.toISOString()
174
+ result.intent = 'range'
175
+ return result
176
+ }
177
+
178
+ // "ever", "all time", "historically"
179
+ if (/\b(ever|all\s+time|historically|over\s+time)\b/.test(lowerQuery)) {
180
+ const match = lowerQuery.match(/\b(ever|all\s+time|historically|over\s+time)\b/)!
181
+ result.expressions.push(match[0])
182
+ result.cleaned = query.replace(new RegExp(match[0], 'i'), '').replace(/\s+/g, ' ').trim()
183
+ result.intent = 'range'
184
+ // No date constraints = all time
185
+ return result
186
+ }
187
+
188
+ return result
189
+ }
190
+ }
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Timeline Construction
3
+ * Builds chronological timelines from ChromaDB memories
4
+ */
5
+
6
+ import type { Logger } from 'pino'
7
+ import type { CollectionManager } from '@/memory/chroma/collection-manager'
8
+ import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
9
+
10
+ export interface TimelineEntry {
11
+ id: string
12
+ date: string
13
+ type: 'decision' | 'pattern' | 'correction'
14
+ project: string
15
+ content: string
16
+ metadata: Record<string, any>
17
+ }
18
+
19
+ export interface Timeline {
20
+ entries: TimelineEntry[]
21
+ project?: string
22
+ startDate?: string
23
+ endDate?: string
24
+ totalCount: number
25
+ }
26
+
27
+ export class TimelineBuilder {
28
+ private logger: Logger
29
+ private collections: CollectionManager
30
+ private embeddings?: EmbeddingProvider
31
+
32
+ constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
33
+ this.logger = logger.child({ component: 'timeline-builder' })
34
+ this.collections = collections
35
+ this.embeddings = embeddings
36
+ }
37
+
38
+ /**
39
+ * Build a timeline of decisions for a project or topic
40
+ */
41
+ async buildTimeline(options: {
42
+ project?: string
43
+ topic?: string
44
+ startDate?: string
45
+ endDate?: string
46
+ limit?: number
47
+ types?: Array<'decision' | 'pattern' | 'correction'>
48
+ } = {}): Promise<Timeline> {
49
+ const {
50
+ project,
51
+ topic,
52
+ startDate,
53
+ endDate,
54
+ limit = 50,
55
+ types = ['decision', 'pattern', 'correction']
56
+ } = options
57
+
58
+ const entries: TimelineEntry[] = []
59
+
60
+ // Fetch from each collection type
61
+ if (types.includes('decision')) {
62
+ const decisions = await this.fetchDecisions(project, topic, startDate, endDate, limit)
63
+ entries.push(...decisions)
64
+ }
65
+
66
+ if (types.includes('pattern')) {
67
+ const patterns = await this.fetchPatterns(project, topic, startDate, endDate, limit)
68
+ entries.push(...patterns)
69
+ }
70
+
71
+ if (types.includes('correction')) {
72
+ const corrections = await this.fetchCorrections(project, topic, startDate, endDate, limit)
73
+ entries.push(...corrections)
74
+ }
75
+
76
+ // Sort chronologically
77
+ entries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
78
+
79
+ // Apply limit after merge
80
+ const limited = entries.slice(0, limit)
81
+
82
+ return {
83
+ entries: limited,
84
+ project,
85
+ startDate: limited[0]?.date,
86
+ endDate: limited[limited.length - 1]?.date,
87
+ totalCount: limited.length
88
+ }
89
+ }
90
+
91
+ private async fetchDecisions(
92
+ project?: string,
93
+ topic?: string,
94
+ startDate?: string,
95
+ endDate?: string,
96
+ limit: number = 50
97
+ ): Promise<TimelineEntry[]> {
98
+ try {
99
+ const collection = await this.collections.getDecisions()
100
+
101
+ if (topic && this.embeddings) {
102
+ // Semantic search by topic
103
+ const embedding = await this.embeddings.generate(topic)
104
+ const where = this.buildWhere(project, startDate, endDate)
105
+ const results = await collection.query({
106
+ queryEmbeddings: [embedding],
107
+ nResults: limit,
108
+ where: Object.keys(where).length > 0 ? where : undefined,
109
+ include: ['documents', 'metadatas', 'distances']
110
+ })
111
+
112
+ return this.processQueryResults(results, 'decision')
113
+ }
114
+
115
+ // Direct fetch
116
+ const where = this.buildWhere(project, startDate, endDate)
117
+ const results = await collection.get({
118
+ where: Object.keys(where).length > 0 ? where : undefined,
119
+ include: ['documents', 'metadatas'],
120
+ limit
121
+ })
122
+
123
+ return results.ids.map((id, i) => ({
124
+ id,
125
+ date: (results.metadatas![i] as any)?.created_at || new Date().toISOString(),
126
+ type: 'decision' as const,
127
+ project: (results.metadatas![i] as any)?.project || '',
128
+ content: results.documents![i] as string,
129
+ metadata: results.metadatas![i] as Record<string, any>
130
+ }))
131
+ } catch (error) {
132
+ this.logger.warn({ error }, 'Failed to fetch decisions for timeline')
133
+ return []
134
+ }
135
+ }
136
+
137
+ private async fetchPatterns(
138
+ project?: string,
139
+ topic?: string,
140
+ startDate?: string,
141
+ endDate?: string,
142
+ limit: number = 50
143
+ ): Promise<TimelineEntry[]> {
144
+ try {
145
+ const collection = await this.collections.getPatterns()
146
+
147
+ if (topic && this.embeddings) {
148
+ const embedding = await this.embeddings.generate(topic)
149
+ const where = this.buildWhere(project, startDate, endDate)
150
+ const results = await collection.query({
151
+ queryEmbeddings: [embedding],
152
+ nResults: limit,
153
+ where: Object.keys(where).length > 0 ? where : undefined,
154
+ include: ['documents', 'metadatas', 'distances']
155
+ })
156
+
157
+ return this.processQueryResults(results, 'pattern')
158
+ }
159
+
160
+ const where = this.buildWhere(project, startDate, endDate)
161
+ const results = await collection.get({
162
+ where: Object.keys(where).length > 0 ? where : undefined,
163
+ include: ['documents', 'metadatas'],
164
+ limit
165
+ })
166
+
167
+ return results.ids.map((id, i) => ({
168
+ id,
169
+ date: (results.metadatas![i] as any)?.created_at || new Date().toISOString(),
170
+ type: 'pattern' as const,
171
+ project: (results.metadatas![i] as any)?.project || '',
172
+ content: results.documents![i] as string,
173
+ metadata: results.metadatas![i] as Record<string, any>
174
+ }))
175
+ } catch (error) {
176
+ this.logger.warn({ error }, 'Failed to fetch patterns for timeline')
177
+ return []
178
+ }
179
+ }
180
+
181
+ private async fetchCorrections(
182
+ project?: string,
183
+ topic?: string,
184
+ startDate?: string,
185
+ endDate?: string,
186
+ limit: number = 50
187
+ ): Promise<TimelineEntry[]> {
188
+ try {
189
+ const collection = await this.collections.getCorrections()
190
+
191
+ if (topic && this.embeddings) {
192
+ const embedding = await this.embeddings.generate(topic)
193
+ const where = this.buildWhere(project, startDate, endDate)
194
+ const results = await collection.query({
195
+ queryEmbeddings: [embedding],
196
+ nResults: limit,
197
+ where: Object.keys(where).length > 0 ? where : undefined,
198
+ include: ['documents', 'metadatas', 'distances']
199
+ })
200
+
201
+ return this.processQueryResults(results, 'correction')
202
+ }
203
+
204
+ const where = this.buildWhere(project, startDate, endDate)
205
+ const results = await collection.get({
206
+ where: Object.keys(where).length > 0 ? where : undefined,
207
+ include: ['documents', 'metadatas'],
208
+ limit
209
+ })
210
+
211
+ return results.ids.map((id, i) => ({
212
+ id,
213
+ date: (results.metadatas![i] as any)?.created_at || new Date().toISOString(),
214
+ type: 'correction' as const,
215
+ project: (results.metadatas![i] as any)?.project || '',
216
+ content: results.documents![i] as string,
217
+ metadata: results.metadatas![i] as Record<string, any>
218
+ }))
219
+ } catch (error) {
220
+ this.logger.warn({ error }, 'Failed to fetch corrections for timeline')
221
+ return []
222
+ }
223
+ }
224
+
225
+ private buildWhere(project?: string, startDate?: string, endDate?: string): Record<string, any> {
226
+ const conditions: any[] = []
227
+
228
+ if (project) {
229
+ conditions.push({ project: { $eq: project } })
230
+ }
231
+ if (startDate) {
232
+ conditions.push({ created_at: { $gte: startDate } })
233
+ }
234
+ if (endDate) {
235
+ conditions.push({ created_at: { $lte: endDate } })
236
+ }
237
+
238
+ if (conditions.length === 0) return {}
239
+ if (conditions.length === 1) return conditions[0]
240
+ return { $and: conditions }
241
+ }
242
+
243
+ private processQueryResults(results: any, type: 'decision' | 'pattern' | 'correction'): TimelineEntry[] {
244
+ if (!results.ids || !results.ids[0]) return []
245
+
246
+ const ids = results.ids[0] || []
247
+ const documents = results.documents?.[0] || []
248
+ const metadatas = results.metadatas?.[0] || []
249
+
250
+ return ids.map((id: string, i: number) => ({
251
+ id,
252
+ date: metadatas[i]?.created_at || new Date().toISOString(),
253
+ type,
254
+ project: metadatas[i]?.project || '',
255
+ content: documents[i] || '',
256
+ metadata: metadatas[i] || {}
257
+ }))
258
+ }
259
+ }