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.
Files changed (246) hide show
  1. package/README.md +191 -191
  2. package/VERSION +1 -1
  3. package/assets/CLAUDE-unified.md +11 -11
  4. package/assets/CLAUDE.md +11 -11
  5. package/bunfig.toml +8 -8
  6. package/package.json +80 -80
  7. package/packs/backend/node.json +173 -173
  8. package/packs/core/javascript.json +176 -176
  9. package/packs/core/typescript.json +222 -222
  10. package/packs/frontend/react.json +254 -254
  11. package/packs/meta/testing.json +172 -172
  12. package/src/automation/auto-context.ts +240 -240
  13. package/src/automation/decision-detector.ts +452 -452
  14. package/src/automation/index.ts +11 -11
  15. package/src/automation/phase12-manager.ts +456 -456
  16. package/src/automation/proactive-recall.ts +373 -373
  17. package/src/automation/project-detector.ts +310 -310
  18. package/src/automation/repo-scanner.ts +205 -205
  19. package/src/cli/auto-setup.ts +82 -82
  20. package/src/cli/bin.ts +202 -202
  21. package/src/cli/commands/chroma.ts +573 -573
  22. package/src/cli/commands/git-hook.ts +189 -189
  23. package/src/cli/commands/hooks.ts +213 -213
  24. package/src/cli/commands/init.ts +122 -122
  25. package/src/cli/commands/install-mcp.ts +92 -92
  26. package/src/cli/commands/pack.ts +197 -197
  27. package/src/cli/commands/serve.ts +167 -167
  28. package/src/cli/commands/start.ts +42 -42
  29. package/src/cli/commands/uninstall-mcp.ts +41 -41
  30. package/src/cli/commands/update.ts +121 -121
  31. package/src/cli/diagnose.ts +4 -4
  32. package/src/cli/health-check.ts +4 -4
  33. package/src/cli/migrate-chroma.ts +106 -106
  34. package/src/cli/setup.ts +4 -4
  35. package/src/cli/ui/animations.ts +80 -80
  36. package/src/cli/ui/components.ts +82 -82
  37. package/src/cli/ui/index.ts +4 -4
  38. package/src/cli/ui/logo.ts +36 -36
  39. package/src/cli/ui/theme.ts +55 -55
  40. package/src/config/defaults.ts +50 -50
  41. package/src/config/home.ts +55 -55
  42. package/src/config/index.ts +7 -7
  43. package/src/config/loader.ts +166 -166
  44. package/src/config/migration.ts +76 -76
  45. package/src/config/schema.ts +360 -360
  46. package/src/config/validator.ts +184 -184
  47. package/src/config/watcher.ts +86 -86
  48. package/src/context/assembler.ts +398 -398
  49. package/src/context/cache-manager.ts +101 -101
  50. package/src/context/formatter.ts +84 -84
  51. package/src/context/hierarchy.ts +85 -85
  52. package/src/context/index.ts +83 -83
  53. package/src/context/progress-tracker.ts +174 -174
  54. package/src/context/standards-manager.ts +287 -287
  55. package/src/context/types.ts +252 -252
  56. package/src/context/validator.ts +58 -58
  57. package/src/diagnostics/index.ts +123 -123
  58. package/src/health/index.ts +229 -229
  59. package/src/hooks/brain-hook.ts +112 -112
  60. package/src/hooks/capture.ts +168 -168
  61. package/src/hooks/deduplicator.ts +72 -72
  62. package/src/hooks/git-capture.ts +109 -109
  63. package/src/hooks/git-hook-installer.ts +207 -207
  64. package/src/hooks/index.ts +20 -20
  65. package/src/hooks/installer.ts +191 -194
  66. package/src/hooks/passive-classifier.ts +366 -366
  67. package/src/hooks/queue.ts +129 -129
  68. package/src/hooks/session-tracker.ts +275 -275
  69. package/src/hooks/types.ts +47 -47
  70. package/src/index.ts +7 -7
  71. package/src/intelligence/cross-project/affinity.ts +162 -162
  72. package/src/intelligence/cross-project/generalizer.ts +283 -283
  73. package/src/intelligence/cross-project/index.ts +13 -13
  74. package/src/intelligence/cross-project/transfer.ts +201 -201
  75. package/src/intelligence/index.ts +24 -24
  76. package/src/intelligence/optimization/index.ts +10 -10
  77. package/src/intelligence/optimization/precompute.ts +202 -202
  78. package/src/intelligence/optimization/semantic-cache.ts +207 -207
  79. package/src/intelligence/prediction/context-anticipator.ts +198 -198
  80. package/src/intelligence/prediction/decision-predictor.ts +184 -184
  81. package/src/intelligence/prediction/index.ts +13 -13
  82. package/src/intelligence/prediction/recommender.ts +268 -268
  83. package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
  84. package/src/intelligence/reasoning/counterfactual.ts +248 -248
  85. package/src/intelligence/reasoning/index.ts +13 -13
  86. package/src/intelligence/reasoning/synthesizer.ts +169 -169
  87. package/src/intelligence/temporal/evolution.ts +197 -197
  88. package/src/intelligence/temporal/index.ts +16 -16
  89. package/src/intelligence/temporal/query-processor.ts +190 -190
  90. package/src/intelligence/temporal/timeline.ts +259 -259
  91. package/src/intelligence/temporal/trends.ts +263 -263
  92. package/src/knowledge/entity-extractor.ts +416 -416
  93. package/src/knowledge/graph/builder.ts +185 -185
  94. package/src/knowledge/graph/linker.ts +201 -201
  95. package/src/knowledge/graph/memory-graph.ts +359 -359
  96. package/src/knowledge/graph/schema.ts +99 -99
  97. package/src/knowledge/graph/search.ts +168 -168
  98. package/src/knowledge/relationship-extractor.ts +108 -108
  99. package/src/memory/chroma/client.ts +174 -174
  100. package/src/memory/chroma/collection-manager.ts +94 -94
  101. package/src/memory/chroma/config.ts +57 -57
  102. package/src/memory/chroma/embeddings.ts +153 -153
  103. package/src/memory/chroma/index.ts +82 -82
  104. package/src/memory/chroma/migration.ts +270 -270
  105. package/src/memory/chroma/schemas.ts +69 -69
  106. package/src/memory/chroma/search.ts +315 -315
  107. package/src/memory/chroma/store.ts +741 -741
  108. package/src/memory/consolidation/archiver.ts +164 -164
  109. package/src/memory/consolidation/merger.ts +186 -186
  110. package/src/memory/consolidation/scorer.ts +138 -138
  111. package/src/memory/context-builder.ts +236 -236
  112. package/src/memory/database.ts +169 -169
  113. package/src/memory/embedding-utils.ts +156 -156
  114. package/src/memory/embeddings.ts +226 -226
  115. package/src/memory/episodic/detector.ts +108 -108
  116. package/src/memory/episodic/manager.ts +351 -351
  117. package/src/memory/episodic/summarizer.ts +179 -179
  118. package/src/memory/episodic/types.ts +52 -52
  119. package/src/memory/index.ts +582 -582
  120. package/src/memory/knowledge-extractor.ts +455 -455
  121. package/src/memory/learning.ts +378 -378
  122. package/src/memory/patterns.ts +396 -396
  123. package/src/memory/schema.ts +88 -88
  124. package/src/memory/search.ts +309 -309
  125. package/src/memory/store.ts +787 -787
  126. package/src/memory/types.ts +121 -121
  127. package/src/orchestrator/coordinator.ts +272 -272
  128. package/src/orchestrator/decision-logger.ts +228 -228
  129. package/src/orchestrator/event-emitter.ts +198 -198
  130. package/src/orchestrator/event-queue.ts +184 -184
  131. package/src/orchestrator/handlers/base-handler.ts +70 -70
  132. package/src/orchestrator/handlers/context-handler.ts +73 -73
  133. package/src/orchestrator/handlers/decision-handler.ts +204 -204
  134. package/src/orchestrator/handlers/index.ts +10 -10
  135. package/src/orchestrator/handlers/status-handler.ts +131 -131
  136. package/src/orchestrator/handlers/task-handler.ts +171 -171
  137. package/src/orchestrator/index.ts +275 -275
  138. package/src/orchestrator/task-parser.ts +284 -284
  139. package/src/orchestrator/types.ts +98 -98
  140. package/src/packs/index.ts +9 -9
  141. package/src/packs/loader.ts +134 -134
  142. package/src/packs/manager.ts +204 -204
  143. package/src/packs/ranker.ts +78 -78
  144. package/src/packs/types.ts +81 -81
  145. package/src/phase12/index.ts +5 -5
  146. package/src/retrieval/bm25/index.ts +300 -300
  147. package/src/retrieval/bm25/tokenizer.ts +184 -184
  148. package/src/retrieval/feedback/adaptive.ts +223 -223
  149. package/src/retrieval/feedback/index.ts +16 -16
  150. package/src/retrieval/feedback/metrics.ts +223 -223
  151. package/src/retrieval/feedback/store.ts +283 -283
  152. package/src/retrieval/fusion/index.ts +194 -194
  153. package/src/retrieval/fusion/rrf.ts +163 -163
  154. package/src/retrieval/index.ts +12 -12
  155. package/src/retrieval/pipeline.ts +375 -375
  156. package/src/retrieval/query/expander.ts +198 -198
  157. package/src/retrieval/query/index.ts +27 -27
  158. package/src/retrieval/query/intent-classifier.ts +236 -236
  159. package/src/retrieval/query/temporal-parser.ts +295 -295
  160. package/src/retrieval/reranker/index.ts +188 -188
  161. package/src/retrieval/reranker/model.ts +95 -95
  162. package/src/retrieval/service.ts +125 -125
  163. package/src/retrieval/types.ts +162 -162
  164. package/src/routing/entity-extractor.ts +428 -428
  165. package/src/routing/intent-classifier.ts +436 -436
  166. package/src/routing/response-filter.ts +258 -254
  167. package/src/routing/router.ts +1322 -1314
  168. package/src/routing/search-engine.ts +475 -475
  169. package/src/routing/types.ts +94 -84
  170. package/src/scripts/health-check.ts +118 -118
  171. package/src/scripts/setup.ts +122 -122
  172. package/src/server/handlers/call-tool.ts +156 -156
  173. package/src/server/handlers/index.ts +9 -9
  174. package/src/server/handlers/list-tools.ts +35 -35
  175. package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
  176. package/src/server/handlers/tools/auto-remember.ts +200 -200
  177. package/src/server/handlers/tools/brain.ts +85 -85
  178. package/src/server/handlers/tools/create-project.ts +135 -135
  179. package/src/server/handlers/tools/detect-trends.ts +144 -144
  180. package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
  181. package/src/server/handlers/tools/get-activity-log.ts +194 -194
  182. package/src/server/handlers/tools/get-code-standards.ts +124 -124
  183. package/src/server/handlers/tools/get-corrections.ts +154 -154
  184. package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
  185. package/src/server/handlers/tools/get-episode.ts +103 -103
  186. package/src/server/handlers/tools/get-patterns.ts +158 -158
  187. package/src/server/handlers/tools/get-phase12-status.ts +63 -63
  188. package/src/server/handlers/tools/get-project-context.ts +75 -75
  189. package/src/server/handlers/tools/get-recommendations.ts +145 -145
  190. package/src/server/handlers/tools/index.ts +31 -31
  191. package/src/server/handlers/tools/init-project.ts +757 -757
  192. package/src/server/handlers/tools/list-episodes.ts +90 -90
  193. package/src/server/handlers/tools/list-projects.ts +125 -125
  194. package/src/server/handlers/tools/rate-memory.ts +101 -101
  195. package/src/server/handlers/tools/recall-similar.ts +87 -87
  196. package/src/server/handlers/tools/recognize-pattern.ts +126 -126
  197. package/src/server/handlers/tools/record-correction.ts +125 -125
  198. package/src/server/handlers/tools/remember-decision.ts +153 -153
  199. package/src/server/handlers/tools/schemas.ts +253 -253
  200. package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
  201. package/src/server/handlers/tools/smart-context.ts +146 -146
  202. package/src/server/handlers/tools/update-progress.ts +131 -131
  203. package/src/server/handlers/tools/what-if-analysis.ts +135 -135
  204. package/src/server/http-api.ts +693 -693
  205. package/src/server/index.ts +40 -40
  206. package/src/server/mcp-server.ts +283 -283
  207. package/src/server/providers/index.ts +7 -7
  208. package/src/server/providers/prompts.ts +327 -327
  209. package/src/server/providers/resources.ts +622 -622
  210. package/src/server/services.ts +468 -468
  211. package/src/server/types.ts +39 -39
  212. package/src/server/utils/error-handler.ts +155 -155
  213. package/src/server/utils/index.ts +13 -13
  214. package/src/server/utils/memory-indicator.ts +83 -83
  215. package/src/server/utils/request-context.ts +122 -122
  216. package/src/server/utils/response-formatter.ts +129 -124
  217. package/src/server/utils/validators.ts +210 -210
  218. package/src/setup/index.ts +48 -48
  219. package/src/setup/wizard.ts +461 -461
  220. package/src/tools/index.ts +24 -24
  221. package/src/tools/registry.ts +115 -115
  222. package/src/tools/schemas.test.ts +30 -30
  223. package/src/tools/schemas.ts +617 -617
  224. package/src/tools/types.ts +412 -412
  225. package/src/utils/circuit-breaker.ts +130 -130
  226. package/src/utils/cleanup.ts +34 -34
  227. package/src/utils/error-handler.ts +132 -132
  228. package/src/utils/error-messages.ts +60 -60
  229. package/src/utils/fallback.ts +45 -45
  230. package/src/utils/index.ts +54 -54
  231. package/src/utils/logger-utils.ts +80 -80
  232. package/src/utils/logger.ts +88 -88
  233. package/src/utils/phase12-helper.ts +56 -56
  234. package/src/utils/retry.ts +94 -94
  235. package/src/utils/timing.ts +47 -47
  236. package/src/utils/transaction.ts +63 -63
  237. package/src/vault/frontmatter.ts +264 -264
  238. package/src/vault/index.ts +318 -318
  239. package/src/vault/paths.ts +106 -106
  240. package/src/vault/query.ts +422 -422
  241. package/src/vault/reader.ts +264 -264
  242. package/src/vault/templates.ts +186 -186
  243. package/src/vault/types.ts +73 -73
  244. package/src/vault/watcher.ts +277 -277
  245. package/src/vault/writer.ts +413 -413
  246. package/tsconfig.json +30 -30
@@ -1,436 +1,436 @@
1
- /**
2
- * Brain Intent Classifier
3
- * Phase 16 + Phase 19: Rule-based intent classification for the unified brain() tool
4
- *
5
- * Priority-ordered — first confident match wins.
6
- * No LLM calls, pure pattern matching.
7
- *
8
- * Phase 19 changes:
9
- * - B1: Question confidence raised (? → 0.95, question word → 0.90)
10
- * - B2: session_start narrowed (must be at start + no progress indicators)
11
- * - B3: Temporal signal detection added to secondary intents
12
- */
13
-
14
- export type Intent =
15
- | 'session_start'
16
- | 'context_needed'
17
- | 'decision_made'
18
- | 'store_this'
19
- | 'pattern_found'
20
- | 'mistake_learned'
21
- | 'progress_update'
22
- | 'question'
23
- | 'comparison'
24
- | 'exploration'
25
- | 'list_all'
26
- | 'update_memory'
27
- | 'delete_memory'
28
- | 'no_action'
29
-
30
- export interface ClassificationResult {
31
- primary: Intent
32
- confidence: number
33
- secondary: Intent[]
34
- }
35
-
36
- // Decision-indicating phrases
37
- const DECISION_PHRASES = [
38
- 'i recommend', 'you should use', 'the best approach',
39
- 'i suggest', 'better to use', 'prefer using',
40
- 'go with', 'decided to', "let's use", 'we will use',
41
- 'the solution is', 'implement using', 'going with',
42
- 'switching to', 'adopting', 'we chose', 'the plan is to',
43
- 'i decided that', 'decided that', 'choosing', 'we picked',
44
- 'settled on', 'committing to', 'opting for', 'sticking with'
45
- ]
46
-
47
- // Explicit "store this" phrases — the user wants to persist something
48
- const STORE_PHRASES = [
49
- 'remember:', 'remember this:', 'remember that',
50
- 'note to self:', 'note to self', 'note:', 'save this:',
51
- 'save this', 'store this', 'keep this', 'record this',
52
- 'i prefer', 'my preference is', 'my convention is',
53
- 'i like to', 'i always', 'always use', 'never use this',
54
- 'from now on', 'going forward', 'the rule is',
55
- 'my approach is', 'my standard is', 'the standard is',
56
- 'we should always', 'we should never',
57
- 'i want to remember', 'don\'t forget',
58
- 'for future reference', 'for the record',
59
- 'important:', 'key decision:', 'takeaway:',
60
- // Issue 3: Declarative patterns ("X should be Y")
61
- 'should be', 'must be', 'needs to be', 'has to be',
62
- 'is set to', 'will be set', 'is always', 'are always',
63
- 'is configured to', 'is configured as',
64
- // Issue 6: "I learned that" is a store, not a mistake
65
- 'i learned that'
66
- ]
67
-
68
- const REASONING_PHRASES = [
69
- 'because', 'since', 'due to', 'as it', 'which provides',
70
- 'this allows', 'this ensures', 'given that', 'considering',
71
- 'the reason is', 'this way'
72
- ]
73
-
74
- // Mistake/correction indicators
75
- const MISTAKE_PHRASES = [
76
- 'bug was', 'the issue was', 'the problem was', 'mistake was',
77
- 'should have', "shouldn't have", 'should not have',
78
- 'lesson learned', "don't use", 'avoid using',
79
- 'the fix is', 'the fix was', 'fixed by', 'solved by',
80
- 'was wrong', 'was broken', 'was incorrect',
81
- 'gotcha:', 'pitfall:', 'watch out for', 'be careful with',
82
- 'turns out that'
83
- ]
84
-
85
- // Progress indicators
86
- const PROGRESS_PHRASES = [
87
- 'finished', 'completed', 'done with', 'implemented',
88
- 'built', 'created', 'added', 'fixed', 'resolved',
89
- 'shipped', 'deployed', 'merged', 'released',
90
- "i'm working on", 'currently working', 'making progress',
91
- 'just did', 'just finished',
92
- // Phase 23b: present-tense statement patterns
93
- "i'm implementing", "i'm building", "i'm adding",
94
- "i'm fixing", "i'm refactoring", "i'm setting up",
95
- "i'm migrating", "i'm updating", "i'm creating",
96
- 'started implementing', 'started building', 'started adding'
97
- ]
98
-
99
- // Comparison indicators
100
- const COMPARISON_PHRASES = [
101
- ' vs ', ' versus ', 'or should', 'compared to', 'comparing ',
102
- 'which is better', 'should i use', 'should we use',
103
- 'what if we switch', 'what if we change', 'what if we replace',
104
- 'pros and cons', 'tradeoffs', 'trade-offs'
105
- ]
106
-
107
- // Pattern indicators
108
- const PATTERN_PHRASES = [
109
- 'pattern:', 'best practice:', 'anti-pattern:', 'reusable solution',
110
- 'reusable approach', 'common issue:', 'this pattern',
111
- 'recognized pattern', 'document this pattern'
112
- ]
113
-
114
- // Exploration indicators
115
- const EXPLORATION_PHRASES = [
116
- 'show me', 'timeline', 'trends', 'evolution of',
117
- 'history of', 'graph', 'how has', 'what happened',
118
- 'decisions about', 'when did we', 'list episodes'
119
- ]
120
-
121
- // Session start indicators — Phase 19: narrowed to require start-of-message
122
- const SESSION_START_PHRASES = [
123
- 'starting work', 'beginning work', 'resuming',
124
- 'picking up', 'getting started', 'opening',
125
- 'starting on', 'working on', 'beginning on'
126
- ]
127
-
128
- // Progress indicators that disqualify session_start
129
- const PROGRESS_INDICATORS = [
130
- 'finished', 'completed', 'done', 'fixed', 'resolved',
131
- 'shipped', 'deployed', 'merged', 'released', 'just did',
132
- 'making progress', 'currently working'
133
- ]
134
-
135
- // Question indicators
136
- const QUESTION_WORDS = [
137
- 'what', 'how', 'when', 'why', 'where', 'which',
138
- 'who', 'can', 'does', 'is', 'are', 'should', 'could', 'would'
139
- ]
140
-
141
- // No-action indicators
142
- const NO_ACTION_PHRASES = [
143
- 'ok', 'okay', 'thanks', 'thank you', 'got it',
144
- 'sure', 'yes', 'no', 'cool', 'nice', 'great',
145
- 'understood', 'noted', 'alright', 'right'
146
- ]
147
-
148
- // List/browse indicators
149
- const LIST_PHRASES = [
150
- 'list all', 'show all', 'what decisions',
151
- 'what have i decided', 'all my decisions', 'all decisions',
152
- 'everything about', 'what do i know', 'what do we know',
153
- 'show me everything', 'list decisions', 'list memories',
154
- 'browse', 'dump all', 'show my',
155
- // Issue 4: Additional list phrases
156
- 'list everything', "everything i've stored", "everything i know",
157
- "what have i stored", "stored in my brain", "what's in my brain",
158
- "what have i remembered", "what do i have stored"
159
- ]
160
-
161
- // Update/correct existing memory
162
- const UPDATE_PHRASES = [
163
- 'actually,', 'actually ', 'correction:', 'update that',
164
- 'i changed my mind', 'changed my mind', 'change that to', 'instead of what i said',
165
- 'supersedes', 'override', 'revise that', 'amend that',
166
- 'that should be', 'update the decision', 'modify that',
167
- 'replace that with', 'no wait', 'scratch that, use',
168
- // Phase 23b: additional update triggers
169
- 'switch to', 'instead use', 'use instead', 'no longer using',
170
- 'moved to', 'migrated to', 'replaced with'
171
- ]
172
-
173
- // Delete/forget memory
174
- const DELETE_PHRASES = [
175
- 'forget that', 'forget about', 'delete that', 'delete the',
176
- 'remove that memory', 'remove that decision', 'that was wrong',
177
- 'discard that', 'erase that', 'undo that decision',
178
- 'remove the memory', 'clear that', 'drop that'
179
- ]
180
-
181
- // Phase 19 B3: Temporal signal phrases
182
- const TEMPORAL_PHRASES = [
183
- 'last week', 'last month', 'last year', 'yesterday', 'today',
184
- 'this week', 'this month', 'this year',
185
- 'since january', 'since february', 'since march', 'since april',
186
- 'since may', 'since june', 'since july', 'since august',
187
- 'since september', 'since october', 'since november', 'since december',
188
- 'in january', 'in february', 'in march', 'in april',
189
- 'in may', 'in june', 'in july', 'in august',
190
- 'in september', 'in october', 'in november', 'in december',
191
- 'ago', 'recently', 'before', 'after', 'during',
192
- 'last few days', 'past week', 'past month',
193
- 'earlier this', 'earlier today', 'over the past'
194
- ]
195
-
196
- export class IntentClassifier {
197
- /**
198
- * Classify the intent of a message
199
- */
200
- classify(message: string): ClassificationResult {
201
- const lower = message.toLowerCase().trim()
202
- const secondary: Intent[] = []
203
-
204
- // Phase 19 B3: Detect temporal signals for secondary intent
205
- const hasTemporal = this.hasTemporalSignal(lower)
206
-
207
- // Check in priority order — first confident match wins
208
-
209
- // 1. no_action: very short messages, greetings, acknowledgments
210
- if (this.isNoAction(lower)) {
211
- return { primary: 'no_action', confidence: 0.95, secondary: [] }
212
- }
213
-
214
- // 2. delete_memory: "forget that", "delete", "remove"
215
- if (this.isDeleteMemory(lower)) {
216
- return { primary: 'delete_memory', confidence: 0.90, secondary }
217
- }
218
-
219
- // 3. update_memory: "actually", "correction:", "change that to"
220
- if (this.isUpdateMemory(lower)) {
221
- return { primary: 'update_memory', confidence: 0.85, secondary }
222
- }
223
-
224
- // 4. store_this: explicit "remember:", "save this:", "I prefer" (never for questions)
225
- if (this.isStoreThis(lower, message)) {
226
- if (this.hasDecisionSignal(lower)) secondary.push('decision_made')
227
- return { primary: 'store_this', confidence: 0.90, secondary }
228
- }
229
-
230
- // 5. decision_made: decision phrases + reasoning (never for questions)
231
- if (this.isDecisionMade(lower, message)) {
232
- if (this.hasComparisonSignal(lower)) secondary.push('comparison')
233
- return { primary: 'decision_made', confidence: 0.85, secondary }
234
- }
235
-
236
- // 6. mistake_learned: correction/bug/lesson indicators
237
- if (this.isMistakeLearned(lower)) {
238
- return { primary: 'mistake_learned', confidence: 0.85, secondary }
239
- }
240
-
241
- // 7. list_all: "list all", "what decisions", "show all"
242
- if (this.isListAll(lower, message)) {
243
- return { primary: 'list_all', confidence: 0.85, secondary }
244
- }
245
-
246
- // 8. progress_update: completed task indicators (NOT questions)
247
- if (this.isProgressUpdate(lower, message)) {
248
- if (this.hasSessionSignal(lower)) secondary.push('session_start')
249
- return { primary: 'progress_update', confidence: 0.85, secondary }
250
- }
251
-
252
- // 9. comparison: vs, which is better, etc.
253
- if (this.isComparison(lower)) {
254
- if (this.isQuestion(lower, message)) secondary.push('question')
255
- if (hasTemporal) secondary.push('exploration')
256
- return { primary: 'comparison', confidence: 0.85, secondary }
257
- }
258
-
259
- // 10. pattern_found: explicit pattern documentation
260
- if (this.isPatternFound(lower)) {
261
- return { primary: 'pattern_found', confidence: 0.80, secondary }
262
- }
263
-
264
- // 11. session_start: starting/resuming work (Phase 19: narrowed check)
265
- if (this.isSessionStart(lower)) {
266
- secondary.push('context_needed')
267
- return { primary: 'session_start', confidence: 0.90, secondary }
268
- }
269
-
270
- // 12. exploration: timeline, trends, graph, history
271
- if (this.isExploration(lower)) {
272
- if (this.isQuestion(lower, message)) secondary.push('question')
273
- if (hasTemporal) secondary.push('exploration')
274
- return { primary: 'exploration', confidence: 0.75, secondary }
275
- }
276
-
277
- // 13. question: starts with question word or ends with ?
278
- // Phase 19 B1: Higher confidence for questions
279
- if (this.isQuestion(lower, message)) {
280
- if (this.hasComparisonSignal(lower)) secondary.push('comparison')
281
- if (this.hasExplorationSignal(lower)) secondary.push('exploration')
282
- if (hasTemporal) secondary.push('exploration')
283
-
284
- // Phase 19 B1: ? → 0.95, question word → 0.90
285
- const confidence = message.trim().endsWith('?') ? 0.95 : 0.90
286
- return { primary: 'question', confidence, secondary }
287
- }
288
-
289
- // 14. Default: context_needed
290
- if (hasTemporal) secondary.push('exploration')
291
- return { primary: 'context_needed', confidence: 0.60, secondary }
292
- }
293
-
294
- private isNoAction(lower: string): boolean {
295
- if (lower.length > 30) return false
296
- const words = lower.split(/\s+/)
297
- if (words.length > 5) return false
298
- return NO_ACTION_PHRASES.some(p => lower === p || lower === p + '.' || lower === p + '!')
299
- }
300
-
301
- private isStoreThis(lower: string, original?: string): boolean {
302
- // Questions are never storage requests — "Do I prefer X?" is a query, not "I prefer X"
303
- if (original?.trim().endsWith('?')) return false
304
- const firstWord = lower.split(/\s+/)[0] || ''
305
- if (QUESTION_WORDS.includes(firstWord)) return false
306
- // Phase 19 B4: Additional question guards
307
- if (this.startsWithQuestionPattern(lower)) return false
308
- return STORE_PHRASES.some(p => lower.includes(p))
309
- }
310
-
311
- private isDecisionMade(lower: string, original?: string): boolean {
312
- // Questions are never decisions — "Did I decide to use X?" is a query
313
- if (original?.trim().endsWith('?')) return false
314
- const firstWord = lower.split(/\s+/)[0] || ''
315
- if (QUESTION_WORDS.includes(firstWord)) return false
316
- // Phase 19 B4: Additional question guards
317
- if (this.startsWithQuestionPattern(lower)) return false
318
-
319
- const hasDecision = DECISION_PHRASES.some(p => lower.includes(p))
320
- if (!hasDecision) return false
321
- // Higher confidence if reasoning is also present
322
- const hasReasoning = REASONING_PHRASES.some(p => lower.includes(p))
323
- return hasReasoning || lower.length > 30
324
- }
325
-
326
- private isMistakeLearned(lower: string): boolean {
327
- return MISTAKE_PHRASES.some(p => lower.includes(p))
328
- }
329
-
330
- private isListAll(lower: string, _original: string): boolean {
331
- return LIST_PHRASES.some(p => lower.includes(p))
332
- }
333
-
334
- private isProgressUpdate(lower: string, original: string): boolean {
335
- // Must not be a question
336
- if (original.trim().endsWith('?')) return false
337
- const firstWord = lower.split(/\s+/)[0] || ''
338
- if (QUESTION_WORDS.includes(firstWord)) return false
339
-
340
- return PROGRESS_PHRASES.some(p => lower.includes(p))
341
- }
342
-
343
- private isComparison(lower: string): boolean {
344
- return COMPARISON_PHRASES.some(p => lower.includes(p))
345
- }
346
-
347
- private isPatternFound(lower: string): boolean {
348
- const hasPattern = PATTERN_PHRASES.some(p => lower.includes(p))
349
- return hasPattern && lower.length > 50
350
- }
351
-
352
- /**
353
- * Phase 19 B2: Narrowed session_start detection.
354
- * Must start at beginning of message AND have no progress indicators.
355
- * "working on X" in the middle of a sentence is not a session start.
356
- */
357
- private isSessionStart(lower: string): boolean {
358
- // Must NOT have progress indicators (e.g. "finished working on X" is progress, not session start)
359
- if (PROGRESS_INDICATORS.some(p => lower.includes(p))) return false
360
-
361
- // Phase 19 B2: Session phrases must match near the start of the message
362
- for (const phrase of SESSION_START_PHRASES) {
363
- const idx = lower.indexOf(phrase)
364
- if (idx !== -1 && idx <= 5) {
365
- return true
366
- }
367
- }
368
- return false
369
- }
370
-
371
- private isExploration(lower: string): boolean {
372
- return EXPLORATION_PHRASES.some(p => lower.includes(p))
373
- }
374
-
375
- private isQuestion(lower: string, original: string): boolean {
376
- if (original.trim().endsWith('?')) return true
377
- const firstWord = lower.split(/\s+/)[0] || ''
378
- if (QUESTION_WORDS.includes(firstWord)) return true
379
- // Phase 19 B4: "do I", "did we", "have we", "can we" patterns
380
- if (this.startsWithQuestionPattern(lower)) return true
381
- return false
382
- }
383
-
384
- private isUpdateMemory(lower: string): boolean {
385
- return UPDATE_PHRASES.some(p => lower.includes(p))
386
- }
387
-
388
- private isDeleteMemory(lower: string): boolean {
389
- return DELETE_PHRASES.some(p => lower.includes(p))
390
- }
391
-
392
- // Secondary signal checks
393
- private hasDecisionSignal(lower: string): boolean {
394
- return DECISION_PHRASES.some(p => lower.includes(p))
395
- }
396
-
397
- private hasComparisonSignal(lower: string): boolean {
398
- return COMPARISON_PHRASES.some(p => lower.includes(p))
399
- }
400
-
401
- private hasExplorationSignal(lower: string): boolean {
402
- return EXPLORATION_PHRASES.some(p => lower.includes(p))
403
- }
404
-
405
- private hasSessionSignal(lower: string): boolean {
406
- return SESSION_START_PHRASES.some(p => lower.includes(p))
407
- }
408
-
409
- /**
410
- * Phase 19 B3: Detect temporal signals in the message.
411
- * Used to add 'temporal' context to secondary intents.
412
- */
413
- hasTemporalSignal(lower: string): boolean {
414
- return TEMPORAL_PHRASES.some(p => lower.includes(p))
415
- }
416
-
417
- /**
418
- * Phase 19 B4: Extended question guards.
419
- * Catches "do I", "did we", "have we", "can we" etc. patterns
420
- * that start with auxiliary verbs not in the QUESTION_WORDS list.
421
- */
422
- private startsWithQuestionPattern(lower: string): boolean {
423
- const questionStarters = [
424
- 'do i ', 'do we ', 'do you ',
425
- 'did i ', 'did we ', 'did you ',
426
- 'have i ', 'have we ', 'have you ',
427
- 'has it ', 'has the ',
428
- 'can i ', 'can we ', 'can you ',
429
- 'will i ', 'will we ', 'will you ',
430
- 'am i ', 'was i ', 'were we ',
431
- 'shall we ', 'shall i ',
432
- 'tell me '
433
- ]
434
- return questionStarters.some(p => lower.startsWith(p))
435
- }
436
- }
1
+ /**
2
+ * Brain Intent Classifier
3
+ * Phase 16 + Phase 19: Rule-based intent classification for the unified brain() tool
4
+ *
5
+ * Priority-ordered — first confident match wins.
6
+ * No LLM calls, pure pattern matching.
7
+ *
8
+ * Phase 19 changes:
9
+ * - B1: Question confidence raised (? → 0.95, question word → 0.90)
10
+ * - B2: session_start narrowed (must be at start + no progress indicators)
11
+ * - B3: Temporal signal detection added to secondary intents
12
+ */
13
+
14
+ export type Intent =
15
+ | 'session_start'
16
+ | 'context_needed'
17
+ | 'decision_made'
18
+ | 'store_this'
19
+ | 'pattern_found'
20
+ | 'mistake_learned'
21
+ | 'progress_update'
22
+ | 'question'
23
+ | 'comparison'
24
+ | 'exploration'
25
+ | 'list_all'
26
+ | 'update_memory'
27
+ | 'delete_memory'
28
+ | 'no_action'
29
+
30
+ export interface ClassificationResult {
31
+ primary: Intent
32
+ confidence: number
33
+ secondary: Intent[]
34
+ }
35
+
36
+ // Decision-indicating phrases
37
+ const DECISION_PHRASES = [
38
+ 'i recommend', 'you should use', 'the best approach',
39
+ 'i suggest', 'better to use', 'prefer using',
40
+ 'go with', 'decided to', "let's use", 'we will use',
41
+ 'the solution is', 'implement using', 'going with',
42
+ 'switching to', 'adopting', 'we chose', 'the plan is to',
43
+ 'i decided that', 'decided that', 'choosing', 'we picked',
44
+ 'settled on', 'committing to', 'opting for', 'sticking with'
45
+ ]
46
+
47
+ // Explicit "store this" phrases — the user wants to persist something
48
+ const STORE_PHRASES = [
49
+ 'remember:', 'remember this:', 'remember that',
50
+ 'note to self:', 'note to self', 'note:', 'save this:',
51
+ 'save this', 'store this', 'keep this', 'record this',
52
+ 'i prefer', 'my preference is', 'my convention is',
53
+ 'i like to', 'i always', 'always use', 'never use this',
54
+ 'from now on', 'going forward', 'the rule is',
55
+ 'my approach is', 'my standard is', 'the standard is',
56
+ 'we should always', 'we should never',
57
+ 'i want to remember', 'don\'t forget',
58
+ 'for future reference', 'for the record',
59
+ 'important:', 'key decision:', 'takeaway:',
60
+ // Issue 3: Declarative patterns ("X should be Y")
61
+ 'should be', 'must be', 'needs to be', 'has to be',
62
+ 'is set to', 'will be set', 'is always', 'are always',
63
+ 'is configured to', 'is configured as',
64
+ // Issue 6: "I learned that" is a store, not a mistake
65
+ 'i learned that'
66
+ ]
67
+
68
+ const REASONING_PHRASES = [
69
+ 'because', 'since', 'due to', 'as it', 'which provides',
70
+ 'this allows', 'this ensures', 'given that', 'considering',
71
+ 'the reason is', 'this way'
72
+ ]
73
+
74
+ // Mistake/correction indicators
75
+ const MISTAKE_PHRASES = [
76
+ 'bug was', 'the issue was', 'the problem was', 'mistake was',
77
+ 'should have', "shouldn't have", 'should not have',
78
+ 'lesson learned', "don't use", 'avoid using',
79
+ 'the fix is', 'the fix was', 'fixed by', 'solved by',
80
+ 'was wrong', 'was broken', 'was incorrect',
81
+ 'gotcha:', 'pitfall:', 'watch out for', 'be careful with',
82
+ 'turns out that'
83
+ ]
84
+
85
+ // Progress indicators
86
+ const PROGRESS_PHRASES = [
87
+ 'finished', 'completed', 'done with', 'implemented',
88
+ 'built', 'created', 'added', 'fixed', 'resolved',
89
+ 'shipped', 'deployed', 'merged', 'released',
90
+ "i'm working on", 'currently working', 'making progress',
91
+ 'just did', 'just finished',
92
+ // Phase 23b: present-tense statement patterns
93
+ "i'm implementing", "i'm building", "i'm adding",
94
+ "i'm fixing", "i'm refactoring", "i'm setting up",
95
+ "i'm migrating", "i'm updating", "i'm creating",
96
+ 'started implementing', 'started building', 'started adding'
97
+ ]
98
+
99
+ // Comparison indicators
100
+ const COMPARISON_PHRASES = [
101
+ ' vs ', ' versus ', 'or should', 'compared to', 'comparing ',
102
+ 'which is better', 'should i use', 'should we use',
103
+ 'what if we switch', 'what if we change', 'what if we replace',
104
+ 'pros and cons', 'tradeoffs', 'trade-offs'
105
+ ]
106
+
107
+ // Pattern indicators
108
+ const PATTERN_PHRASES = [
109
+ 'pattern:', 'best practice:', 'anti-pattern:', 'reusable solution',
110
+ 'reusable approach', 'common issue:', 'this pattern',
111
+ 'recognized pattern', 'document this pattern'
112
+ ]
113
+
114
+ // Exploration indicators
115
+ const EXPLORATION_PHRASES = [
116
+ 'show me', 'timeline', 'trends', 'evolution of',
117
+ 'history of', 'graph', 'how has', 'what happened',
118
+ 'decisions about', 'when did we', 'list episodes'
119
+ ]
120
+
121
+ // Session start indicators — Phase 19: narrowed to require start-of-message
122
+ const SESSION_START_PHRASES = [
123
+ 'starting work', 'beginning work', 'resuming',
124
+ 'picking up', 'getting started', 'opening',
125
+ 'starting on', 'working on', 'beginning on'
126
+ ]
127
+
128
+ // Progress indicators that disqualify session_start
129
+ const PROGRESS_INDICATORS = [
130
+ 'finished', 'completed', 'done', 'fixed', 'resolved',
131
+ 'shipped', 'deployed', 'merged', 'released', 'just did',
132
+ 'making progress', 'currently working'
133
+ ]
134
+
135
+ // Question indicators
136
+ const QUESTION_WORDS = [
137
+ 'what', 'how', 'when', 'why', 'where', 'which',
138
+ 'who', 'can', 'does', 'is', 'are', 'should', 'could', 'would'
139
+ ]
140
+
141
+ // No-action indicators
142
+ const NO_ACTION_PHRASES = [
143
+ 'ok', 'okay', 'thanks', 'thank you', 'got it',
144
+ 'sure', 'yes', 'no', 'cool', 'nice', 'great',
145
+ 'understood', 'noted', 'alright', 'right'
146
+ ]
147
+
148
+ // List/browse indicators
149
+ const LIST_PHRASES = [
150
+ 'list all', 'show all', 'what decisions',
151
+ 'what have i decided', 'all my decisions', 'all decisions',
152
+ 'everything about', 'what do i know', 'what do we know',
153
+ 'show me everything', 'list decisions', 'list memories',
154
+ 'browse', 'dump all', 'show my',
155
+ // Issue 4: Additional list phrases
156
+ 'list everything', "everything i've stored", "everything i know",
157
+ "what have i stored", "stored in my brain", "what's in my brain",
158
+ "what have i remembered", "what do i have stored"
159
+ ]
160
+
161
+ // Update/correct existing memory
162
+ const UPDATE_PHRASES = [
163
+ 'actually,', 'actually ', 'correction:', 'update that',
164
+ 'i changed my mind', 'changed my mind', 'change that to', 'instead of what i said',
165
+ 'supersedes', 'override', 'revise that', 'amend that',
166
+ 'that should be', 'update the decision', 'modify that',
167
+ 'replace that with', 'no wait', 'scratch that, use',
168
+ // Phase 23b: additional update triggers
169
+ 'switch to', 'instead use', 'use instead', 'no longer using',
170
+ 'moved to', 'migrated to', 'replaced with'
171
+ ]
172
+
173
+ // Delete/forget memory
174
+ const DELETE_PHRASES = [
175
+ 'forget that', 'forget about', 'delete that', 'delete the',
176
+ 'remove that memory', 'remove that decision', 'that was wrong',
177
+ 'discard that', 'erase that', 'undo that decision',
178
+ 'remove the memory', 'clear that', 'drop that'
179
+ ]
180
+
181
+ // Phase 19 B3: Temporal signal phrases
182
+ const TEMPORAL_PHRASES = [
183
+ 'last week', 'last month', 'last year', 'yesterday', 'today',
184
+ 'this week', 'this month', 'this year',
185
+ 'since january', 'since february', 'since march', 'since april',
186
+ 'since may', 'since june', 'since july', 'since august',
187
+ 'since september', 'since october', 'since november', 'since december',
188
+ 'in january', 'in february', 'in march', 'in april',
189
+ 'in may', 'in june', 'in july', 'in august',
190
+ 'in september', 'in october', 'in november', 'in december',
191
+ 'ago', 'recently', 'before', 'after', 'during',
192
+ 'last few days', 'past week', 'past month',
193
+ 'earlier this', 'earlier today', 'over the past'
194
+ ]
195
+
196
+ export class IntentClassifier {
197
+ /**
198
+ * Classify the intent of a message
199
+ */
200
+ classify(message: string): ClassificationResult {
201
+ const lower = message.toLowerCase().trim()
202
+ const secondary: Intent[] = []
203
+
204
+ // Phase 19 B3: Detect temporal signals for secondary intent
205
+ const hasTemporal = this.hasTemporalSignal(lower)
206
+
207
+ // Check in priority order — first confident match wins
208
+
209
+ // 1. no_action: very short messages, greetings, acknowledgments
210
+ if (this.isNoAction(lower)) {
211
+ return { primary: 'no_action', confidence: 0.95, secondary: [] }
212
+ }
213
+
214
+ // 2. delete_memory: "forget that", "delete", "remove"
215
+ if (this.isDeleteMemory(lower)) {
216
+ return { primary: 'delete_memory', confidence: 0.90, secondary }
217
+ }
218
+
219
+ // 3. update_memory: "actually", "correction:", "change that to"
220
+ if (this.isUpdateMemory(lower)) {
221
+ return { primary: 'update_memory', confidence: 0.85, secondary }
222
+ }
223
+
224
+ // 4. store_this: explicit "remember:", "save this:", "I prefer" (never for questions)
225
+ if (this.isStoreThis(lower, message)) {
226
+ if (this.hasDecisionSignal(lower)) secondary.push('decision_made')
227
+ return { primary: 'store_this', confidence: 0.90, secondary }
228
+ }
229
+
230
+ // 5. decision_made: decision phrases + reasoning (never for questions)
231
+ if (this.isDecisionMade(lower, message)) {
232
+ if (this.hasComparisonSignal(lower)) secondary.push('comparison')
233
+ return { primary: 'decision_made', confidence: 0.85, secondary }
234
+ }
235
+
236
+ // 6. mistake_learned: correction/bug/lesson indicators
237
+ if (this.isMistakeLearned(lower)) {
238
+ return { primary: 'mistake_learned', confidence: 0.85, secondary }
239
+ }
240
+
241
+ // 7. list_all: "list all", "what decisions", "show all"
242
+ if (this.isListAll(lower, message)) {
243
+ return { primary: 'list_all', confidence: 0.85, secondary }
244
+ }
245
+
246
+ // 8. progress_update: completed task indicators (NOT questions)
247
+ if (this.isProgressUpdate(lower, message)) {
248
+ if (this.hasSessionSignal(lower)) secondary.push('session_start')
249
+ return { primary: 'progress_update', confidence: 0.85, secondary }
250
+ }
251
+
252
+ // 9. comparison: vs, which is better, etc.
253
+ if (this.isComparison(lower)) {
254
+ if (this.isQuestion(lower, message)) secondary.push('question')
255
+ if (hasTemporal) secondary.push('exploration')
256
+ return { primary: 'comparison', confidence: 0.85, secondary }
257
+ }
258
+
259
+ // 10. pattern_found: explicit pattern documentation
260
+ if (this.isPatternFound(lower)) {
261
+ return { primary: 'pattern_found', confidence: 0.80, secondary }
262
+ }
263
+
264
+ // 11. session_start: starting/resuming work (Phase 19: narrowed check)
265
+ if (this.isSessionStart(lower)) {
266
+ secondary.push('context_needed')
267
+ return { primary: 'session_start', confidence: 0.90, secondary }
268
+ }
269
+
270
+ // 12. exploration: timeline, trends, graph, history
271
+ if (this.isExploration(lower)) {
272
+ if (this.isQuestion(lower, message)) secondary.push('question')
273
+ if (hasTemporal) secondary.push('exploration')
274
+ return { primary: 'exploration', confidence: 0.75, secondary }
275
+ }
276
+
277
+ // 13. question: starts with question word or ends with ?
278
+ // Phase 19 B1: Higher confidence for questions
279
+ if (this.isQuestion(lower, message)) {
280
+ if (this.hasComparisonSignal(lower)) secondary.push('comparison')
281
+ if (this.hasExplorationSignal(lower)) secondary.push('exploration')
282
+ if (hasTemporal) secondary.push('exploration')
283
+
284
+ // Phase 19 B1: ? → 0.95, question word → 0.90
285
+ const confidence = message.trim().endsWith('?') ? 0.95 : 0.90
286
+ return { primary: 'question', confidence, secondary }
287
+ }
288
+
289
+ // 14. Default: context_needed
290
+ if (hasTemporal) secondary.push('exploration')
291
+ return { primary: 'context_needed', confidence: 0.60, secondary }
292
+ }
293
+
294
+ private isNoAction(lower: string): boolean {
295
+ if (lower.length > 30) return false
296
+ const words = lower.split(/\s+/)
297
+ if (words.length > 5) return false
298
+ return NO_ACTION_PHRASES.some(p => lower === p || lower === p + '.' || lower === p + '!')
299
+ }
300
+
301
+ private isStoreThis(lower: string, original?: string): boolean {
302
+ // Questions are never storage requests — "Do I prefer X?" is a query, not "I prefer X"
303
+ if (original?.trim().endsWith('?')) return false
304
+ const firstWord = lower.split(/\s+/)[0] || ''
305
+ if (QUESTION_WORDS.includes(firstWord)) return false
306
+ // Phase 19 B4: Additional question guards
307
+ if (this.startsWithQuestionPattern(lower)) return false
308
+ return STORE_PHRASES.some(p => lower.includes(p))
309
+ }
310
+
311
+ private isDecisionMade(lower: string, original?: string): boolean {
312
+ // Questions are never decisions — "Did I decide to use X?" is a query
313
+ if (original?.trim().endsWith('?')) return false
314
+ const firstWord = lower.split(/\s+/)[0] || ''
315
+ if (QUESTION_WORDS.includes(firstWord)) return false
316
+ // Phase 19 B4: Additional question guards
317
+ if (this.startsWithQuestionPattern(lower)) return false
318
+
319
+ const hasDecision = DECISION_PHRASES.some(p => lower.includes(p))
320
+ if (!hasDecision) return false
321
+ // Higher confidence if reasoning is also present
322
+ const hasReasoning = REASONING_PHRASES.some(p => lower.includes(p))
323
+ return hasReasoning || lower.length > 30
324
+ }
325
+
326
+ private isMistakeLearned(lower: string): boolean {
327
+ return MISTAKE_PHRASES.some(p => lower.includes(p))
328
+ }
329
+
330
+ private isListAll(lower: string, _original: string): boolean {
331
+ return LIST_PHRASES.some(p => lower.includes(p))
332
+ }
333
+
334
+ private isProgressUpdate(lower: string, original: string): boolean {
335
+ // Must not be a question
336
+ if (original.trim().endsWith('?')) return false
337
+ const firstWord = lower.split(/\s+/)[0] || ''
338
+ if (QUESTION_WORDS.includes(firstWord)) return false
339
+
340
+ return PROGRESS_PHRASES.some(p => lower.includes(p))
341
+ }
342
+
343
+ private isComparison(lower: string): boolean {
344
+ return COMPARISON_PHRASES.some(p => lower.includes(p))
345
+ }
346
+
347
+ private isPatternFound(lower: string): boolean {
348
+ const hasPattern = PATTERN_PHRASES.some(p => lower.includes(p))
349
+ return hasPattern && lower.length > 50
350
+ }
351
+
352
+ /**
353
+ * Phase 19 B2: Narrowed session_start detection.
354
+ * Must start at beginning of message AND have no progress indicators.
355
+ * "working on X" in the middle of a sentence is not a session start.
356
+ */
357
+ private isSessionStart(lower: string): boolean {
358
+ // Must NOT have progress indicators (e.g. "finished working on X" is progress, not session start)
359
+ if (PROGRESS_INDICATORS.some(p => lower.includes(p))) return false
360
+
361
+ // Phase 19 B2: Session phrases must match near the start of the message
362
+ for (const phrase of SESSION_START_PHRASES) {
363
+ const idx = lower.indexOf(phrase)
364
+ if (idx !== -1 && idx <= 5) {
365
+ return true
366
+ }
367
+ }
368
+ return false
369
+ }
370
+
371
+ private isExploration(lower: string): boolean {
372
+ return EXPLORATION_PHRASES.some(p => lower.includes(p))
373
+ }
374
+
375
+ private isQuestion(lower: string, original: string): boolean {
376
+ if (original.trim().endsWith('?')) return true
377
+ const firstWord = lower.split(/\s+/)[0] || ''
378
+ if (QUESTION_WORDS.includes(firstWord)) return true
379
+ // Phase 19 B4: "do I", "did we", "have we", "can we" patterns
380
+ if (this.startsWithQuestionPattern(lower)) return true
381
+ return false
382
+ }
383
+
384
+ private isUpdateMemory(lower: string): boolean {
385
+ return UPDATE_PHRASES.some(p => lower.includes(p))
386
+ }
387
+
388
+ private isDeleteMemory(lower: string): boolean {
389
+ return DELETE_PHRASES.some(p => lower.includes(p))
390
+ }
391
+
392
+ // Secondary signal checks
393
+ private hasDecisionSignal(lower: string): boolean {
394
+ return DECISION_PHRASES.some(p => lower.includes(p))
395
+ }
396
+
397
+ private hasComparisonSignal(lower: string): boolean {
398
+ return COMPARISON_PHRASES.some(p => lower.includes(p))
399
+ }
400
+
401
+ private hasExplorationSignal(lower: string): boolean {
402
+ return EXPLORATION_PHRASES.some(p => lower.includes(p))
403
+ }
404
+
405
+ private hasSessionSignal(lower: string): boolean {
406
+ return SESSION_START_PHRASES.some(p => lower.includes(p))
407
+ }
408
+
409
+ /**
410
+ * Phase 19 B3: Detect temporal signals in the message.
411
+ * Used to add 'temporal' context to secondary intents.
412
+ */
413
+ hasTemporalSignal(lower: string): boolean {
414
+ return TEMPORAL_PHRASES.some(p => lower.includes(p))
415
+ }
416
+
417
+ /**
418
+ * Phase 19 B4: Extended question guards.
419
+ * Catches "do I", "did we", "have we", "can we" etc. patterns
420
+ * that start with auxiliary verbs not in the QUESTION_WORDS list.
421
+ */
422
+ private startsWithQuestionPattern(lower: string): boolean {
423
+ const questionStarters = [
424
+ 'do i ', 'do we ', 'do you ',
425
+ 'did i ', 'did we ', 'did you ',
426
+ 'have i ', 'have we ', 'have you ',
427
+ 'has it ', 'has the ',
428
+ 'can i ', 'can we ', 'can you ',
429
+ 'will i ', 'will we ', 'will you ',
430
+ 'am i ', 'was i ', 'were we ',
431
+ 'shall we ', 'shall i ',
432
+ 'tell me '
433
+ ]
434
+ return questionStarters.some(p => lower.startsWith(p))
435
+ }
436
+ }