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