@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.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 (189) hide show
  1. package/README.md +152 -37
  2. package/agents/INDEX.md +183 -0
  3. package/agents/architect.md +247 -0
  4. package/agents/build-error-resolver.md +555 -0
  5. package/agents/catalyst-deployer.md +132 -0
  6. package/agents/code-reviewer.md +121 -0
  7. package/agents/compliance-auditor.md +148 -0
  8. package/agents/creator-architect.md +395 -0
  9. package/agents/deluge-reviewer.md +98 -0
  10. package/agents/doc-updater.md +471 -0
  11. package/agents/e2e-runner.md +711 -0
  12. package/agents/planner.md +122 -0
  13. package/agents/refactor-cleaner.md +309 -0
  14. package/agents/security-reviewer.md +582 -0
  15. package/agents/tdd-guide.md +302 -0
  16. package/config/versions.json +63 -0
  17. package/dist/hooks/hooks.json +209 -0
  18. package/dist/index.js +47 -0
  19. package/dist/lib/asset-value.js +609 -0
  20. package/dist/lib/client-manager.js +300 -0
  21. package/dist/lib/command-matcher.js +242 -0
  22. package/dist/lib/cross-session-patterns.js +754 -0
  23. package/dist/lib/intent-classifier.js +1075 -0
  24. package/dist/lib/package-manager.js +374 -0
  25. package/dist/lib/recommendation-engine.js +597 -0
  26. package/dist/lib/session-memory.js +489 -0
  27. package/dist/lib/skill-effectiveness.js +486 -0
  28. package/dist/lib/skill-matcher.js +595 -0
  29. package/dist/lib/tutorial-metrics.js +242 -0
  30. package/dist/lib/tutorial-progress.js +209 -0
  31. package/dist/lib/tutorial-renderer.js +431 -0
  32. package/dist/lib/utils.js +380 -0
  33. package/dist/lib/verify-formatter.js +143 -0
  34. package/dist/lib/workflow-state.js +249 -0
  35. package/hooks/hooks.json +209 -0
  36. package/package.json +5 -1
  37. package/scripts/aggregate-sessions.js +290 -0
  38. package/scripts/branch-name-validator.js +291 -0
  39. package/scripts/build.js +101 -0
  40. package/scripts/commands/client-switch.js +231 -0
  41. package/scripts/deprecate-skill.js +610 -0
  42. package/scripts/diagnose.js +324 -0
  43. package/scripts/doc-freshness.js +168 -0
  44. package/scripts/generate-weekly-digest.js +393 -0
  45. package/scripts/health-check.js +270 -0
  46. package/scripts/hooks/credential-check.js +101 -0
  47. package/scripts/hooks/evaluate-session.js +81 -0
  48. package/scripts/hooks/pre-compact.js +66 -0
  49. package/scripts/hooks/prompt-analyzer.js +276 -0
  50. package/scripts/hooks/prompt-router.js +422 -0
  51. package/scripts/hooks/quality-gate-enforcer.js +371 -0
  52. package/scripts/hooks/session-end.js +156 -0
  53. package/scripts/hooks/session-start.js +195 -0
  54. package/scripts/hooks/skill-injector.js +333 -0
  55. package/scripts/hooks/suggest-compact.js +58 -0
  56. package/scripts/lib/asset-value.js +609 -0
  57. package/scripts/lib/client-manager.js +300 -0
  58. package/scripts/lib/command-matcher.js +242 -0
  59. package/scripts/lib/cross-session-patterns.js +754 -0
  60. package/scripts/lib/intent-classifier.js +1075 -0
  61. package/scripts/lib/package-manager.js +374 -0
  62. package/scripts/lib/recommendation-engine.js +597 -0
  63. package/scripts/lib/session-memory.js +489 -0
  64. package/scripts/lib/skill-effectiveness.js +486 -0
  65. package/scripts/lib/skill-matcher.js +595 -0
  66. package/scripts/lib/tutorial-metrics.js +242 -0
  67. package/scripts/lib/tutorial-progress.js +209 -0
  68. package/scripts/lib/tutorial-renderer.js +431 -0
  69. package/scripts/lib/utils.js +380 -0
  70. package/scripts/lib/verify-formatter.js +143 -0
  71. package/scripts/lib/workflow-state.js +249 -0
  72. package/scripts/onboard.js +363 -0
  73. package/scripts/quarterly-report.js +692 -0
  74. package/scripts/setup-package-manager.js +204 -0
  75. package/scripts/sync-upstream.js +391 -0
  76. package/scripts/test.js +108 -0
  77. package/scripts/tutorial-runner.js +351 -0
  78. package/scripts/validate-all.js +201 -0
  79. package/scripts/verifiers/agents.js +245 -0
  80. package/scripts/verifiers/config.js +186 -0
  81. package/scripts/verifiers/environment.js +123 -0
  82. package/scripts/verifiers/hooks.js +188 -0
  83. package/scripts/verifiers/index.js +38 -0
  84. package/scripts/verifiers/persistence.js +140 -0
  85. package/scripts/verifiers/plugin.js +215 -0
  86. package/scripts/verifiers/skills.js +209 -0
  87. package/scripts/verify-setup.js +164 -0
  88. package/skills/INDEX.md +157 -0
  89. package/skills/backend-patterns/SKILL.md +586 -0
  90. package/skills/backend-patterns/catalyst-patterns.md +128 -0
  91. package/skills/bigquery-patterns/SKILL.md +27 -0
  92. package/skills/bigquery-patterns/performance-optimization.md +518 -0
  93. package/skills/bigquery-patterns/query-patterns.md +372 -0
  94. package/skills/bigquery-patterns/schema-design.md +78 -0
  95. package/skills/cloudstream-project-template/SKILL.md +20 -0
  96. package/skills/cloudstream-project-template/structure.md +65 -0
  97. package/skills/coding-standards/SKILL.md +524 -0
  98. package/skills/coding-standards/deluge-standards.md +83 -0
  99. package/skills/compliance-patterns/SKILL.md +28 -0
  100. package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
  101. package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
  102. package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
  103. package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
  104. package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
  105. package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
  106. package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
  107. package/skills/compliance-patterns/soc2/access-controls.md +344 -0
  108. package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
  109. package/skills/compliance-patterns/soc2/change-management.md +403 -0
  110. package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
  111. package/skills/consultancy-workflows/SKILL.md +19 -0
  112. package/skills/consultancy-workflows/client-isolation.md +21 -0
  113. package/skills/consultancy-workflows/documentation-automation.md +454 -0
  114. package/skills/consultancy-workflows/handoff-procedures.md +257 -0
  115. package/skills/consultancy-workflows/knowledge-capture.md +513 -0
  116. package/skills/consultancy-workflows/time-tracking.md +26 -0
  117. package/skills/continuous-learning/SKILL.md +84 -0
  118. package/skills/continuous-learning/config.json +18 -0
  119. package/skills/continuous-learning/evaluate-session.sh +60 -0
  120. package/skills/continuous-learning-v2/SKILL.md +126 -0
  121. package/skills/continuous-learning-v2/config.json +61 -0
  122. package/skills/frontend-patterns/SKILL.md +635 -0
  123. package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
  124. package/skills/gcp-data-engineering/SKILL.md +36 -0
  125. package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
  126. package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
  127. package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
  128. package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
  129. package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
  130. package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
  131. package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
  132. package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
  133. package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
  134. package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
  135. package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
  136. package/skills/security-review/SKILL.md +498 -0
  137. package/skills/security-review/compliance-checklist.md +53 -0
  138. package/skills/strategic-compact/SKILL.md +67 -0
  139. package/skills/tdd-workflow/SKILL.md +413 -0
  140. package/skills/tdd-workflow/zoho-testing.md +124 -0
  141. package/skills/tutorial/SKILL.md +249 -0
  142. package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
  143. package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
  144. package/skills/tutorial/lessons/01-basics.md +81 -0
  145. package/skills/tutorial/lessons/02-training.md +86 -0
  146. package/skills/tutorial/lessons/03-commands.md +109 -0
  147. package/skills/tutorial/lessons/04-workflows.md +115 -0
  148. package/skills/tutorial/lessons/05-compliance.md +116 -0
  149. package/skills/tutorial/lessons/06-zoho.md +121 -0
  150. package/skills/tutorial/lessons/07-hooks-system.md +277 -0
  151. package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
  152. package/skills/tutorial/lessons/09-client-management.md +215 -0
  153. package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
  154. package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
  155. package/skills/tutorial/lessons/12-rules-system.md +326 -0
  156. package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
  157. package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
  158. package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
  159. package/skills/tutorial/tracks/accelerated/README.md +134 -0
  160. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
  161. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
  162. package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
  163. package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
  164. package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
  165. package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
  166. package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
  167. package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
  168. package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
  169. package/skills/zoho-patterns/CHANGELOG.md +108 -0
  170. package/skills/zoho-patterns/SKILL.md +446 -0
  171. package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
  172. package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
  173. package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
  174. package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
  175. package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
  176. package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
  177. package/skills/zoho-patterns/creator/form-design.md +304 -0
  178. package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
  179. package/skills/zoho-patterns/creator/widget-integration.md +306 -0
  180. package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
  181. package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
  182. package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
  183. package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
  184. package/skills/zoho-patterns/deluge/error-handling.md +423 -0
  185. package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
  186. package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
  187. package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
  188. package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
  189. package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
@@ -0,0 +1,1075 @@
1
+ /**
2
+ * Intent Classifier - Semantic Intent Detection for Prompt Routing
3
+ *
4
+ * Detects user intent from natural language prompts and returns
5
+ * confidence scores for routing to appropriate commands/agents.
6
+ *
7
+ * Performance Target: <10ms per classification
8
+ *
9
+ * @module intent-classifier
10
+ */
11
+
12
+ /**
13
+ * Intent types supported by the classifier
14
+ */
15
+ const INTENT_TYPES = {
16
+ PLANNING: 'PLANNING',
17
+ TESTING: 'TESTING',
18
+ REVIEW: 'REVIEW',
19
+ SECURITY: 'SECURITY',
20
+ COMPLIANCE: 'COMPLIANCE',
21
+ ZOHO: 'ZOHO',
22
+ DEPLOY: 'DEPLOY',
23
+ REFACTOR: 'REFACTOR',
24
+ DEBUG: 'DEBUG',
25
+ // New intent types for full documentation alignment
26
+ LEARNING: 'LEARNING',
27
+ SETUP: 'SETUP',
28
+ HANDOFF: 'HANDOFF',
29
+ E2E: 'E2E',
30
+ DOCUMENTATION: 'DOCUMENTATION',
31
+ UNKNOWN: 'UNKNOWN',
32
+ };
33
+
34
+ /**
35
+ * Confidence thresholds
36
+ */
37
+ const THRESHOLDS = {
38
+ AUTO_CONVERT: 0.75, // High confidence - auto-convert without asking (lowered for better UX)
39
+ SUGGEST: 0.5, // Medium confidence - suggest but ask
40
+ MINIMUM: 0.25, // Below this, classify as UNKNOWN (lowered to support single-typo matches)
41
+ };
42
+
43
+ /**
44
+ * Intent patterns with weighted keywords and phrases
45
+ *
46
+ * Structure:
47
+ * - keywords: Single words that indicate intent (lower weight)
48
+ * - phrases: Multi-word patterns that strongly indicate intent (higher weight)
49
+ * - priority: Used for tie-breaking when multiple intents match
50
+ */
51
+ const INTENT_PATTERNS = {
52
+ PLANNING: {
53
+ keywords: [
54
+ 'plan',
55
+ 'design',
56
+ 'architect',
57
+ 'approach',
58
+ 'strategy',
59
+ 'structure',
60
+ 'organize',
61
+ 'figure',
62
+ 'think',
63
+ // Development verbs - critical for feature requests
64
+ 'create',
65
+ 'implement',
66
+ 'build',
67
+ 'develop',
68
+ 'make',
69
+ 'add',
70
+ 'integrate',
71
+ 'feature',
72
+ 'module',
73
+ 'component',
74
+ ],
75
+ phrases: [
76
+ /\b(how should|what's the best way|best approach)\b/i,
77
+ /\b(plan (for|the|this|a|an))\b/i,
78
+ /\b(need to plan)\b/i,
79
+ /\b(design (the|a|an))\b/i,
80
+ /\b(architect (a|an|the))\b/i,
81
+ /\b(help me (plan|design|architect))\b/i,
82
+ /\b(implementation strategy)\b/i,
83
+ /\b(figure out (how|the))\b/i,
84
+ /\bapproach (for|this|the)\b/i,
85
+ /\blets plan\b/i,
86
+ /\bwant to architect\b/i,
87
+ // Development verb phrases - critical for feature requests
88
+ /\b(add\s+(a\s+)?(feature|functionality|capability|endpoint|module|component))\b/i,
89
+ /\b(add\s+(a\s+)?(new\s+)?[a-z]+\s+(feature|to))\b/i,
90
+ /\b(create\s+(a|an|the|new))\b/i,
91
+ /\b(implement\s+(the|a|an|new))\b/i,
92
+ /\b(build\s+(the|a|an|new))\b/i,
93
+ /\b(develop\s+(the|a|an))\b/i,
94
+ /\b(integrate\s+(with|the|a))\b/i,
95
+ /\b(need\s+to\s+(create|build|implement|add|develop))\b/i,
96
+ /\b(help\s+me\s+(create|build|implement|add|develop))\b/i,
97
+ /\b(want\s+to\s+(create|build|implement|add|develop))\b/i,
98
+ /\bnew\s+(module|feature|system|api|endpoint|service|component)\b/i,
99
+ ],
100
+ priority: 3,
101
+ },
102
+
103
+ TESTING: {
104
+ keywords: [
105
+ 'test',
106
+ 'tests',
107
+ 'testing',
108
+ 'coverage',
109
+ 'tdd',
110
+ 'unit',
111
+ 'integration',
112
+ 'spec',
113
+ 'jest',
114
+ 'vitest',
115
+ // Technical synonyms
116
+ 'validate',
117
+ 'validation',
118
+ 'verify',
119
+ 'verification',
120
+ 'assert',
121
+ 'assertions',
122
+ 'suite',
123
+ 'specs',
124
+ 'mocha',
125
+ 'ava',
126
+ 'pytest',
127
+ 'qa',
128
+ 'mock',
129
+ 'stub',
130
+ 'fixture',
131
+ ],
132
+ phrases: [
133
+ /\b(write tests?)\b/i,
134
+ /\b(test (the|this|a|an))\b/i,
135
+ /\b(add (test )?coverage)\b/i,
136
+ /\b(help (me )?(with )?tdd)\b/i,
137
+ /\b(unit tests?)\b/i,
138
+ /\b(integration tests?)\b/i,
139
+ /\b(test coverage)\b/i,
140
+ /\bhelp me test\b/i,
141
+ /\btest.*class\b/i,
142
+ /\btest.*endpoint\b/i,
143
+ /\btest.*api\b/i,
144
+ // Technical synonym phrases
145
+ /\b(test suite)\b/i,
146
+ /\b(run (the )?tests?)\b/i,
147
+ /\b(validation (tests?|suite|logic))\b/i,
148
+ /\b(verify (the|this|that))\b/i,
149
+ /\b(quality (check|assurance))\b/i,
150
+ ],
151
+ priority: 3,
152
+ },
153
+
154
+ REVIEW: {
155
+ keywords: [
156
+ 'review',
157
+ 'check',
158
+ 'look',
159
+ 'examine',
160
+ 'audit',
161
+ 'inspect',
162
+ 'pr',
163
+ // Technical synonyms
164
+ 'critique',
165
+ 'evaluate',
166
+ 'assess',
167
+ 'analyze',
168
+ 'feedback',
169
+ 'approval',
170
+ 'lgtm',
171
+ ],
172
+ phrases: [
173
+ /\b(review (this|the|my))\b/i,
174
+ /\b(check (this|the|my))\b/i,
175
+ /\b(look at (this|the|these))\b/i,
176
+ /\b(audit (this|the))\b/i,
177
+ /\b(review my pr)\b/i,
178
+ /\b(code review)\b/i,
179
+ /\breview.*code\b/i,
180
+ /\bcheck.*implementation\b/i,
181
+ /\baudit.*file\b/i,
182
+ // Technical synonym phrases
183
+ /\b(give (me )?feedback)\b/i,
184
+ /\b(need (your )?approval)\b/i,
185
+ /\b(pull request)\b/i,
186
+ ],
187
+ priority: 2,
188
+ },
189
+
190
+ SECURITY: {
191
+ keywords: [
192
+ 'security',
193
+ 'vulnerability',
194
+ 'vulnerabilities',
195
+ 'xss',
196
+ 'injection',
197
+ 'auth',
198
+ 'authentication',
199
+ 'credential',
200
+ 'credentials',
201
+ 'owasp',
202
+ 'secure',
203
+ ],
204
+ phrases: [
205
+ /\b(security (check|review|audit|scan|vulnerabilit))\b/i,
206
+ /\b(check for (security|vulnerabilit))\b/i,
207
+ /\bxss\b/i,
208
+ /\bsql injection\b/i,
209
+ /\bowasp\b/i,
210
+ /\b(credential (handling|management))\b/i,
211
+ /\b(authentication (code|logic|flow))\b/i,
212
+ /\bvalidate.*credential\b/i,
213
+ ],
214
+ priority: 4,
215
+ },
216
+
217
+ COMPLIANCE: {
218
+ keywords: ['hipaa', 'soc2', 'pci', 'compliance', 'compliant', 'phi', 'ephi'],
219
+ phrases: [
220
+ /\bhipaa\b/i,
221
+ /\bsoc ?2\b/i,
222
+ /\bpci(-dss)?\b/i,
223
+ /\b(ensure|check|audit).*compliance\b/i,
224
+ /\bcompliance (check|audit|review|violation)\b/i,
225
+ /\bphi (handling|data)\b/i,
226
+ /\bpci compliant\b/i,
227
+ ],
228
+ priority: 5, // Highest priority - compliance is critical
229
+ },
230
+
231
+ ZOHO: {
232
+ keywords: ['zoho', 'creator', 'catalyst', 'deluge', 'crm', 'books', 'analytics'],
233
+ phrases: [
234
+ /\bzoho\b/i,
235
+ /\b(zoho )?(creator|catalyst)\b/i,
236
+ /\bdeluge\b/i,
237
+ /\b(creator (app|form|report))\b/i,
238
+ /\b(catalyst (function|deploy))\b/i,
239
+ /\bcrm (workflow|automation)\b/i,
240
+ /\bzoho books\b/i,
241
+ ],
242
+ priority: 4,
243
+ },
244
+
245
+ DEPLOY: {
246
+ keywords: [
247
+ 'deploy',
248
+ 'deployment',
249
+ 'release',
250
+ 'ship',
251
+ 'production',
252
+ 'prod',
253
+ 'publish',
254
+ 'live',
255
+ // Technical synonyms
256
+ 'launch',
257
+ 'rollout',
258
+ 'staging',
259
+ 'promote',
260
+ 'ci',
261
+ 'cd',
262
+ 'pipeline',
263
+ ],
264
+ phrases: [
265
+ /\bdeploy (to|this|the)\b/i,
266
+ /\bpush to prod(uction)?\b/i,
267
+ /\brelease (the|a|this|new)\b/i,
268
+ /\bship (this|the|it)\b/i,
269
+ /\bgo live\b/i,
270
+ /\bto production\b/i,
271
+ // Technical synonym phrases
272
+ /\b(launch (the|this|to))\b/i,
273
+ /\b(roll ?out)\b/i,
274
+ /\b(promote to (prod|production|staging))\b/i,
275
+ /\b(ci.?cd pipeline)\b/i,
276
+ ],
277
+ priority: 3,
278
+ },
279
+
280
+ REFACTOR: {
281
+ keywords: [
282
+ 'refactor',
283
+ 'cleanup',
284
+ 'clean',
285
+ 'consolidate',
286
+ 'simplify',
287
+ 'remove',
288
+ 'dead',
289
+ 'unused',
290
+ 'duplicate',
291
+ ],
292
+ phrases: [
293
+ /\brefactor\b/i,
294
+ /\bclean ?up\b/i,
295
+ /\bdead code\b/i,
296
+ /\bunused (import|code|variable|function)\b/i,
297
+ /\bremove (unused|dead|duplicate)\b/i,
298
+ /\bconsolidate\b/i,
299
+ ],
300
+ priority: 2,
301
+ },
302
+
303
+ DEBUG: {
304
+ keywords: [
305
+ 'fix',
306
+ 'bug',
307
+ 'error',
308
+ 'issue',
309
+ 'problem',
310
+ 'broken',
311
+ 'failing',
312
+ 'debug',
313
+ 'investigate',
314
+ 'wrong',
315
+ 'crash',
316
+ 'fail',
317
+ // Technical synonyms
318
+ 'troubleshoot',
319
+ 'diagnose',
320
+ 'trace',
321
+ 'stacktrace',
322
+ 'exception',
323
+ 'regression',
324
+ 'hotfix',
325
+ 'patch',
326
+ ],
327
+ phrases: [
328
+ /\bfix (this|the|a)?\s*(bug|error|issue)?\b/i,
329
+ /\bbug\b/i,
330
+ /\bnot working\b/i,
331
+ /\bkeeps? (failing|crashing|erroring|happening)\b/i,
332
+ /\bdebug\b/i,
333
+ /\binvestigate\b/i,
334
+ /\berror\b/i,
335
+ /\bbroken\b/i,
336
+ /\bfailing\b/i,
337
+ // Technical synonym phrases
338
+ /\b(troubleshoot (this|the))\b/i,
339
+ /\b(diagnose (this|the))\b/i,
340
+ /\b(root cause)\b/i,
341
+ /\b(stack trace)\b/i,
342
+ /\b(regression in)\b/i,
343
+ ],
344
+ priority: 2,
345
+ },
346
+
347
+ // New intent types for full documentation alignment
348
+
349
+ LEARNING: {
350
+ keywords: [
351
+ 'learn',
352
+ 'extract',
353
+ 'pattern',
354
+ 'patterns',
355
+ 'reusable',
356
+ 'insight',
357
+ 'capture',
358
+ 'knowledge',
359
+ ],
360
+ phrases: [
361
+ /\b(learn from|extract patterns?|capture (this|the) patterns?)\b/i,
362
+ /\b(make.*reusable)\b/i,
363
+ /\b(extract (a|the|this) patterns?)\b/i,
364
+ /\b(save.*for.*future)\b/i,
365
+ /\b(reusable patterns?)\b/i,
366
+ /\b(patterns?\s+from\s+(this|the))\b/i,
367
+ ],
368
+ priority: 2,
369
+ },
370
+
371
+ SETUP: {
372
+ keywords: ['setup', 'configure', 'install', 'initialize', 'onboard', 'bootstrap', 'init'],
373
+ phrases: [
374
+ /\b(set up|setup)\s+(the|a|an|new|my)?\b/i,
375
+ /\b(configure\s+(the|for|my))\b/i,
376
+ /\b(initialize\s+(the|a|new|my))\b/i,
377
+ /\b(install\s+(the|dependencies|packages|all))\b/i,
378
+ /\b(bootstrap\s+(the|a|new))\b/i,
379
+ /\b(get.*started)\b/i,
380
+ /\b(initial setup)\b/i,
381
+ ],
382
+ priority: 2,
383
+ },
384
+
385
+ HANDOFF: {
386
+ keywords: ['handoff', 'transfer', 'deliverable', 'handover', 'transition', 'turnover'],
387
+ phrases: [
388
+ /\b(hand ?off|handover)\b/i,
389
+ /\b(transfer to|transition to)\b/i,
390
+ /\b(create deliverable)\b/i,
391
+ /\b(client (handoff|documentation|delivery))\b/i,
392
+ /\b(prepare.*for.*handoff)\b/i,
393
+ /\b(deliverable.*for.*client)\b/i,
394
+ ],
395
+ priority: 2,
396
+ },
397
+
398
+ E2E: {
399
+ keywords: ['e2e', 'playwright', 'cypress', 'selenium', 'journey', 'puppeteer'],
400
+ phrases: [
401
+ /\b(e2e|end[- ]to[- ]end)\b/i,
402
+ /\b(playwright|cypress|selenium|puppeteer)\b/i,
403
+ /\b(user (flow|journey))\b/i,
404
+ /\b(browser test)\b/i,
405
+ /\b(e2e test)\b/i,
406
+ /\b(functional test)\b/i,
407
+ /\b(acceptance test)\b/i,
408
+ ],
409
+ priority: 3,
410
+ },
411
+
412
+ DOCUMENTATION: {
413
+ keywords: ['docs', 'document', 'documentation', 'readme', 'contributing', 'jsdoc', 'wiki'],
414
+ phrases: [
415
+ /\b(update|write|generate)\s+(docs|documentation|readme)\b/i,
416
+ /\b(document (the|this|a))\b/i,
417
+ /\b(add.*documentation)\b/i,
418
+ /\b(update.*readme)\b/i,
419
+ /\b(generate.*docs)\b/i,
420
+ /\b(write.*docs)\b/i,
421
+ ],
422
+ priority: 2,
423
+ },
424
+ };
425
+
426
+ /**
427
+ * Calculate Levenshtein distance between two strings
428
+ * Used for typo tolerance in keyword matching
429
+ * @param {string} a - First string
430
+ * @param {string} b - Second string
431
+ * @returns {number} Edit distance
432
+ */
433
+ function levenshteinDistance(a, b) {
434
+ if (a.length === 0) return b.length;
435
+ if (b.length === 0) return a.length;
436
+
437
+ // Early bailout for very different lengths
438
+ if (Math.abs(a.length - b.length) > 3) return Math.max(a.length, b.length);
439
+
440
+ const matrix = [];
441
+
442
+ // Initialize matrix
443
+ for (let i = 0; i <= b.length; i++) {
444
+ matrix[i] = [i];
445
+ }
446
+ for (let j = 0; j <= a.length; j++) {
447
+ matrix[0][j] = j;
448
+ }
449
+
450
+ // Fill in the rest
451
+ for (let i = 1; i <= b.length; i++) {
452
+ for (let j = 1; j <= a.length; j++) {
453
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
454
+ matrix[i][j] = matrix[i - 1][j - 1];
455
+ } else {
456
+ matrix[i][j] = Math.min(
457
+ matrix[i - 1][j - 1] + 1, // substitution
458
+ matrix[i][j - 1] + 1, // insertion
459
+ matrix[i - 1][j] + 1 // deletion
460
+ );
461
+ }
462
+ }
463
+ }
464
+
465
+ return matrix[b.length][a.length];
466
+ }
467
+
468
+ /**
469
+ * Check if a word is a typo of a keyword
470
+ * @param {string} word - Word to check
471
+ * @param {string} keyword - Target keyword
472
+ * @returns {boolean} True if word is likely a typo of keyword
473
+ */
474
+ function isTypoMatch(word, keyword) {
475
+ if (!word || !keyword) return false;
476
+
477
+ const a = word.toLowerCase();
478
+ const b = keyword.toLowerCase();
479
+
480
+ // Exact match
481
+ if (a === b) return true;
482
+
483
+ // No typo tolerance for short words (< 4 chars)
484
+ if (b.length < 4) return a === b;
485
+
486
+ const distance = levenshteinDistance(a, b);
487
+
488
+ // Allow up to 2 edits for longer words, 1 edit for medium words
489
+ const maxAllowed = b.length >= 6 ? 2 : 1;
490
+
491
+ return distance <= maxAllowed;
492
+ }
493
+
494
+ /**
495
+ * Common typos for critical keywords (optimization)
496
+ */
497
+ const COMMON_TYPOS = {
498
+ test: ['tets', 'tset', 'testt', 'tet', 'teast'],
499
+ deploy: ['deplay', 'deplyo', 'delpoy', 'depoly'],
500
+ review: ['reveiw', 'reviw', 'revew', 'reivew'],
501
+ plan: ['pln', 'paln', 'plna', 'plaan'],
502
+ security: ['secuirty', 'securty', 'secutiry', 'securtiy'],
503
+ refactor: ['refacter', 'refacor', 'refactr', 'refactro'],
504
+ build: ['biuld', 'buld', 'buidl', 'bulid'],
505
+ create: ['craete', 'creat', 'cerate', 'cereate'],
506
+ };
507
+
508
+ /**
509
+ * Find typo matches for a word against a list of keywords
510
+ * @param {string} word - Word to check
511
+ * @param {string[]} keywords - List of keywords to match against
512
+ * @returns {string|null} Matched keyword or null
513
+ */
514
+ function findTypoMatch(word, keywords) {
515
+ const lowerWord = word.toLowerCase();
516
+
517
+ // First check common typos dictionary (fast path)
518
+ for (const [keyword, typos] of Object.entries(COMMON_TYPOS)) {
519
+ if (keywords.includes(keyword) && typos.includes(lowerWord)) {
520
+ return keyword;
521
+ }
522
+ }
523
+
524
+ // Fallback to Levenshtein for other typos
525
+ for (const keyword of keywords) {
526
+ if (isTypoMatch(lowerWord, keyword)) {
527
+ return keyword;
528
+ }
529
+ }
530
+
531
+ return null;
532
+ }
533
+
534
+ /**
535
+ * Negation words that negate intent when preceding keywords
536
+ */
537
+ const NEGATION_PATTERNS = {
538
+ // Explicit negation words
539
+ words: /\b(don'?t|do not|no|never|skip|avoid|without|not|isn'?t|won'?t|cannot|can'?t|shouldn'?t|wouldn'?t|exclude|stop|halt|cease|prevent)\b/i,
540
+ // Negation phrases (more specific patterns)
541
+ phrases: [
542
+ /\b(don'?t|do not)\s+\w*\s*(test|deploy|review|plan|build|create|refactor)/i,
543
+ /\b(skip|avoid|no)\s+(the\s+)?(test|deploy|security|review|plan)/i,
544
+ /\b(not\s+(for|ready|to|going))\s+/i,
545
+ /\bnot\s+yet\b/i,
546
+ /\bno\s+need\s+(to|for)\b/i,
547
+ ],
548
+ };
549
+
550
+ /**
551
+ * Check if a keyword is negated in the prompt
552
+ * @param {string} prompt - Full prompt
553
+ * @param {string} keyword - Keyword to check
554
+ * @returns {boolean} True if keyword appears to be negated
555
+ */
556
+ function isKeywordNegated(prompt, keyword) {
557
+ const lowerPrompt = prompt.toLowerCase();
558
+ const keywordRegex = new RegExp(`\\b${keyword}\\b`, 'gi');
559
+ let match;
560
+
561
+ while ((match = keywordRegex.exec(lowerPrompt)) !== null) {
562
+ // Check the 50 characters before the keyword for negation
563
+ const beforeKeyword = lowerPrompt.slice(Math.max(0, match.index - 50), match.index);
564
+
565
+ // Look for negation words within 3 words of the keyword
566
+ const words = beforeKeyword.trim().split(/\s+/).slice(-4); // Last 4 words
567
+ const nearbyText = words.join(' ');
568
+
569
+ if (NEGATION_PATTERNS.words.test(nearbyText)) {
570
+ return true;
571
+ }
572
+ }
573
+
574
+ return false;
575
+ }
576
+
577
+ /**
578
+ * Detect all negated intents in a prompt
579
+ * @param {string} prompt - User prompt
580
+ * @returns {string[]} Array of negated intent types
581
+ */
582
+ function detectNegatedIntents(prompt) {
583
+ const negatedIntents = [];
584
+ const lowerPrompt = prompt.toLowerCase();
585
+
586
+ // Check each intent's keywords for negation
587
+ for (const [intentType, patterns] of Object.entries(INTENT_PATTERNS)) {
588
+ for (const keyword of patterns.keywords) {
589
+ if (lowerPrompt.includes(keyword) && isKeywordNegated(prompt, keyword)) {
590
+ if (!negatedIntents.includes(intentType)) {
591
+ negatedIntents.push(intentType);
592
+ }
593
+ break; // One negated keyword is enough
594
+ }
595
+ }
596
+ }
597
+
598
+ return negatedIntents;
599
+ }
600
+
601
+ /**
602
+ * Sentence type constants
603
+ */
604
+ const SENTENCE_TYPES = {
605
+ QUESTION: 'QUESTION',
606
+ COMMAND: 'COMMAND',
607
+ STATEMENT: 'STATEMENT',
608
+ };
609
+
610
+ /**
611
+ * Question word patterns for detecting inquiries
612
+ */
613
+ const QUESTION_PATTERNS = {
614
+ // Question words at start of sentence
615
+ startWords: /^(should|would|could|can|is|are|do|does|will|what|how|why|when|where|which|who|whom|whose|shall|may|might|has|have|had|was|were)\s/i,
616
+ // Question mark at end
617
+ endMark: /\?\s*$/,
618
+ // Conditional/hypothetical patterns
619
+ conditional: /^(if|whether)\s/i,
620
+ };
621
+
622
+ /**
623
+ * Detect if prompt is a question (inquiry) vs command/statement
624
+ * @param {string} prompt - User prompt
625
+ * @returns {object} { isQuestion: boolean, sentenceType: string }
626
+ */
627
+ function detectSentenceType(prompt) {
628
+ if (!prompt) return { isQuestion: false, sentenceType: SENTENCE_TYPES.STATEMENT };
629
+
630
+ const trimmed = prompt.trim();
631
+
632
+ // Check for question mark
633
+ if (QUESTION_PATTERNS.endMark.test(trimmed)) {
634
+ return { isQuestion: true, sentenceType: SENTENCE_TYPES.QUESTION };
635
+ }
636
+
637
+ // Check for question words at start
638
+ if (QUESTION_PATTERNS.startWords.test(trimmed)) {
639
+ return { isQuestion: true, sentenceType: SENTENCE_TYPES.QUESTION };
640
+ }
641
+
642
+ // Check for conditional/hypothetical
643
+ if (QUESTION_PATTERNS.conditional.test(trimmed)) {
644
+ return { isQuestion: true, sentenceType: SENTENCE_TYPES.QUESTION };
645
+ }
646
+
647
+ // Check for command words at start (imperative)
648
+ if (/^(please|let's|lets|let me|let us|help me|can you|could you|would you)\s/i.test(trimmed)) {
649
+ return { isQuestion: false, sentenceType: SENTENCE_TYPES.COMMAND };
650
+ }
651
+
652
+ return { isQuestion: false, sentenceType: SENTENCE_TYPES.STATEMENT };
653
+ }
654
+
655
+ /**
656
+ * Check if prompt is primarily non-ASCII (likely non-English)
657
+ * @param {string} prompt - User prompt
658
+ * @returns {boolean} True if majority is non-ASCII
659
+ */
660
+ function isNonAscii(prompt) {
661
+ if (!prompt) return false;
662
+ // Count printable ASCII characters (space to tilde)
663
+ const asciiChars = (prompt.match(/[\x20-\x7E]/g) || []).length;
664
+ const totalChars = prompt.replace(/\s/g, '').length; // Exclude whitespace
665
+ if (totalChars === 0) return false;
666
+ const ratio = asciiChars / totalChars;
667
+ return ratio < 0.5; // Less than 50% ASCII
668
+ }
669
+
670
+ /**
671
+ * Check if prompt starts with an explicit slash command
672
+ * @param {string} prompt - User prompt
673
+ * @returns {boolean} True if starts with /command
674
+ */
675
+ function isExplicitCommand(prompt) {
676
+ if (!prompt) return false;
677
+ return /^\/\w+/.test(prompt.trim());
678
+ }
679
+
680
+ /**
681
+ * Contextual reference patterns (pronouns, anaphora)
682
+ * These indicate the user is referring to something from prior context
683
+ */
684
+ const CONTEXTUAL_REFERENCE_PATTERNS = [
685
+ /\b(that|this|it|those|these|the same)\b/i,
686
+ /\b(do (it|that|the same|this))\b/i,
687
+ /\b(proceed|continue|go ahead|yes|okay|ok|sure)\b/i,
688
+ /\b(what (we|I) (said|discussed|mentioned))\b/i,
689
+ /\b(as (mentioned|discussed|before))\b/i,
690
+ /\b(like (before|last time))\b/i,
691
+ /\b(same (thing|as|approach))\b/i,
692
+ ];
693
+
694
+ /**
695
+ * Check if prompt contains contextual references requiring prior context
696
+ * @param {string} prompt - User prompt
697
+ * @returns {boolean} True if prompt has contextual references
698
+ */
699
+ function hasContextualReference(prompt) {
700
+ if (!prompt) return false;
701
+ return CONTEXTUAL_REFERENCE_PATTERNS.some((pattern) => pattern.test(prompt));
702
+ }
703
+
704
+ /**
705
+ * Prompt length limits for performance
706
+ */
707
+ const PROMPT_LIMITS = {
708
+ MAX_CHARS: 2000, // Truncate after this
709
+ PRIORITY_WINDOW: 500, // First N chars have highest weight
710
+ TAIL_WINDOW: 500, // Last N chars to keep
711
+ };
712
+
713
+ /**
714
+ * Intelligently truncate long prompts for classification
715
+ * Keeps beginning (likely has intent) and end (may have clarifications)
716
+ * @param {string} prompt - Original prompt
717
+ * @returns {object} { text: string, wasTruncated: boolean }
718
+ */
719
+ function truncateForClassification(prompt) {
720
+ if (!prompt || prompt.length <= PROMPT_LIMITS.MAX_CHARS) {
721
+ return { text: prompt || '', wasTruncated: false };
722
+ }
723
+
724
+ // Keep first 500 chars (likely contains intent)
725
+ const start = prompt.slice(0, PROMPT_LIMITS.PRIORITY_WINDOW);
726
+
727
+ // Keep last 500 chars (may contain clarifications/specifics)
728
+ const end = prompt.slice(-PROMPT_LIMITS.TAIL_WINDOW);
729
+
730
+ // Combine with indicator
731
+ return {
732
+ text: `${start} ... ${end}`,
733
+ wasTruncated: true,
734
+ };
735
+ }
736
+
737
+ /**
738
+ * Calculate match score for a single intent
739
+ * @param {string} prompt - Normalized prompt
740
+ * @param {object} patterns - Intent pattern config
741
+ * @param {string[]} negatedIntents - Intents that are negated in the prompt
742
+ * @param {string} intentType - The intent type being scored
743
+ * @returns {object} Score and match details
744
+ */
745
+ function calculateIntentScore(prompt, patterns, negatedIntents = [], intentType = '') {
746
+ let score = 0;
747
+ const matches = [];
748
+ const normalizedPrompt = prompt.toLowerCase();
749
+ let hasTypoMatch = false;
750
+
751
+ // If this intent is negated, return zero score
752
+ if (negatedIntents.includes(intentType)) {
753
+ return { score: 0, matches: [], priority: patterns.priority, isNegated: true, typoMatch: false };
754
+ }
755
+
756
+ // Check keywords (weight: 0.2 each, max contribution 0.6 - raised cap for better multi-keyword scoring)
757
+ let keywordScore = 0;
758
+ const matchedKeywords = new Set();
759
+
760
+ // First pass: exact keyword matches
761
+ for (const keyword of patterns.keywords) {
762
+ const regex = new RegExp(`\\b${keyword}\\b`, 'i');
763
+ if (regex.test(normalizedPrompt)) {
764
+ // Skip keywords that are individually negated
765
+ if (!isKeywordNegated(prompt, keyword)) {
766
+ keywordScore += 0.2;
767
+ matches.push({ type: 'keyword', match: keyword });
768
+ matchedKeywords.add(keyword);
769
+ }
770
+ }
771
+ }
772
+
773
+ // Second pass: typo matching (only for words not already matched, with reduced weight)
774
+ const words = normalizedPrompt.split(/\s+/);
775
+ for (const word of words) {
776
+ // Skip very short words and already matched words
777
+ if (word.length < 3) continue;
778
+
779
+ const typoKeyword = findTypoMatch(word, patterns.keywords);
780
+ if (typoKeyword && !matchedKeywords.has(typoKeyword)) {
781
+ // Check negation for the original typo word too
782
+ if (!isKeywordNegated(prompt, word)) {
783
+ keywordScore += 0.2; // Same as keyword weight (typo info tracked in match type)
784
+ matches.push({ type: 'typo', match: word, correctedTo: typoKeyword });
785
+ matchedKeywords.add(typoKeyword);
786
+ hasTypoMatch = true;
787
+ }
788
+ }
789
+ }
790
+
791
+ score += Math.min(keywordScore, 0.6);
792
+
793
+ // Check phrases (higher weight: 0.35 each, max 3 phrases count)
794
+ let phraseCount = 0;
795
+ for (const phrase of patterns.phrases) {
796
+ if (phrase.test(normalizedPrompt)) {
797
+ if (phraseCount < 3) {
798
+ score += 0.35;
799
+ phraseCount++;
800
+ }
801
+ matches.push({ type: 'phrase', match: phrase.toString() });
802
+ }
803
+ }
804
+
805
+ // Apply priority weight (normalize to keep score in 0-1 range)
806
+ const priorityBoost = (patterns.priority - 1) * 0.05;
807
+ score = Math.min(score + priorityBoost, 1.0);
808
+
809
+ return { score, matches, priority: patterns.priority, isNegated: false, typoMatch: hasTypoMatch };
810
+ }
811
+
812
+ /**
813
+ * Classify user intent from natural language prompt
814
+ *
815
+ * @param {string} prompt - User prompt to classify
816
+ * @param {object} context - Optional context for enhanced detection
817
+ * @param {string[]} context.technologies - Detected technologies in session
818
+ * @param {string} context.complianceMode - Active compliance mode (hipaa/soc2/pci-dss)
819
+ * @param {string[]} context.recentFiles - Recently accessed files
820
+ * @param {string} context.lastClassifiedIntent - Last classified intent from session
821
+ * @param {number} context.conversationTurn - Current conversation turn number
822
+ * @returns {object} Classification result
823
+ */
824
+ function classifyIntent(prompt, context = {}) {
825
+ const { lastClassifiedIntent = null } = context;
826
+ // Handle null/undefined/empty input
827
+ if (!prompt || typeof prompt !== 'string' || prompt.trim().length === 0) {
828
+ return {
829
+ primaryIntent: INTENT_TYPES.UNKNOWN,
830
+ confidence: 0,
831
+ secondaryIntents: [],
832
+ negatedIntents: [],
833
+ autoConvert: false,
834
+ suggestOnly: false,
835
+ ambiguous: false,
836
+ isInquiry: false,
837
+ sentenceType: SENTENCE_TYPES.STATEMENT,
838
+ wasTruncated: false,
839
+ skipRouting: false,
840
+ reason: 'empty_input',
841
+ };
842
+ }
843
+
844
+ const trimmedPrompt = prompt.trim();
845
+
846
+ // Truncate very long prompts for performance
847
+ const { text: normalizedPrompt, wasTruncated } = truncateForClassification(trimmedPrompt);
848
+
849
+ // Check for explicit slash commands first
850
+ if (isExplicitCommand(normalizedPrompt)) {
851
+ return {
852
+ primaryIntent: INTENT_TYPES.UNKNOWN,
853
+ confidence: 0,
854
+ secondaryIntents: [],
855
+ negatedIntents: [],
856
+ autoConvert: false,
857
+ suggestOnly: false,
858
+ ambiguous: false,
859
+ isInquiry: false,
860
+ sentenceType: SENTENCE_TYPES.COMMAND,
861
+ wasTruncated,
862
+ skipRouting: true,
863
+ reason: 'explicit_command',
864
+ };
865
+ }
866
+
867
+ // Check for non-ASCII (likely non-English) before length check
868
+ if (isNonAscii(normalizedPrompt)) {
869
+ return {
870
+ primaryIntent: INTENT_TYPES.UNKNOWN,
871
+ confidence: 0,
872
+ secondaryIntents: [],
873
+ negatedIntents: [],
874
+ autoConvert: false,
875
+ suggestOnly: false,
876
+ ambiguous: false,
877
+ isInquiry: false,
878
+ sentenceType: SENTENCE_TYPES.STATEMENT,
879
+ wasTruncated,
880
+ skipRouting: true,
881
+ reason: 'non_ascii',
882
+ };
883
+ }
884
+
885
+ // Check for contextual references (requires session context)
886
+ const hasContextRef = hasContextualReference(normalizedPrompt);
887
+
888
+ // If prompt is primarily contextual reference (short and refers to prior context)
889
+ // and we have session context, inherit intent
890
+ if (hasContextRef && lastClassifiedIntent && INTENT_TYPES[lastClassifiedIntent]) {
891
+ // Check if prompt has NO strong intent keywords (is purely contextual)
892
+ const explicitIntentKeywords =
893
+ /\b(plan|test|review|design|fix|deploy|refactor|build|create|add|setup|e2e|docs|handoff|learn|security|compliance)\b/i;
894
+
895
+ if (!explicitIntentKeywords.test(normalizedPrompt)) {
896
+ return {
897
+ primaryIntent: lastClassifiedIntent,
898
+ confidence: 0.6, // Reduced confidence for inherited intent
899
+ secondaryIntents: [],
900
+ negatedIntents: [],
901
+ autoConvert: false, // Don't auto-convert inherited intents
902
+ suggestOnly: true,
903
+ ambiguous: false,
904
+ isInquiry: false,
905
+ sentenceType: SENTENCE_TYPES.STATEMENT,
906
+ wasTruncated,
907
+ requiresContext: true, // Flag that this was context-dependent
908
+ inheritedFrom: 'session', // Mark as inherited
909
+ skipRouting: false,
910
+ reason: null,
911
+ };
912
+ }
913
+ }
914
+
915
+ // Check for very short prompts - but allow if explicit intent keyword found
916
+ if (normalizedPrompt.length < 10) {
917
+ // Allow short prompts with explicit high-confidence intent keywords
918
+ const explicitIntentKeywords =
919
+ /\b(plan|test|review|design|fix|deploy|refactor|build|create|add|setup|e2e|docs|handoff|learn)\b/i;
920
+
921
+ if (!explicitIntentKeywords.test(normalizedPrompt)) {
922
+ return {
923
+ primaryIntent: INTENT_TYPES.UNKNOWN,
924
+ confidence: 0.2,
925
+ secondaryIntents: [],
926
+ negatedIntents: [],
927
+ autoConvert: false,
928
+ suggestOnly: false,
929
+ ambiguous: false,
930
+ isInquiry: false,
931
+ sentenceType: SENTENCE_TYPES.STATEMENT,
932
+ wasTruncated: false,
933
+ requiresContext: hasContextRef, // Flag if context would help
934
+ skipRouting: false,
935
+ reason: 'too_short',
936
+ };
937
+ }
938
+ // Continue to classification for short prompts with explicit intent keywords
939
+ }
940
+
941
+ // Detect negated intents first
942
+ const negatedIntents = detectNegatedIntents(normalizedPrompt);
943
+
944
+ // Detect sentence type (question vs command)
945
+ const { isQuestion, sentenceType } = detectSentenceType(normalizedPrompt);
946
+
947
+ // Calculate scores for all intents
948
+ const scores = [];
949
+ for (const [intentType, patterns] of Object.entries(INTENT_PATTERNS)) {
950
+ const result = calculateIntentScore(normalizedPrompt, patterns, negatedIntents, intentType);
951
+ if (result.score > 0) {
952
+ scores.push({
953
+ intent: intentType,
954
+ score: result.score,
955
+ matches: result.matches,
956
+ priority: result.priority,
957
+ });
958
+ }
959
+ }
960
+
961
+ // Apply context boosts
962
+ if (context.complianceMode) {
963
+ const complianceScore = scores.find((s) => s.intent === 'COMPLIANCE');
964
+ if (complianceScore) {
965
+ complianceScore.score = Math.min(complianceScore.score + 0.2, 1.0);
966
+ } else {
967
+ // Check if prompt mentions data handling in compliance context
968
+ if (/\b(data|patient|user|customer|handling|export|import)\b/i.test(normalizedPrompt)) {
969
+ scores.push({
970
+ intent: 'COMPLIANCE',
971
+ score: 0.5,
972
+ matches: [{ type: 'context', match: 'compliance_mode_active' }],
973
+ priority: 5,
974
+ });
975
+ }
976
+ }
977
+ }
978
+
979
+ if (context.technologies) {
980
+ // Boost Zoho if Zoho technologies detected
981
+ if (context.technologies.some((t) => /zoho|creator|catalyst|deluge/i.test(t))) {
982
+ const zohoScore = scores.find((s) => s.intent === 'ZOHO');
983
+ if (zohoScore) {
984
+ zohoScore.score = Math.min(zohoScore.score + 0.15, 1.0);
985
+ }
986
+ }
987
+ }
988
+
989
+ // Sort by score (descending), then by priority (descending)
990
+ scores.sort((a, b) => {
991
+ if (b.score !== a.score) return b.score - a.score;
992
+ return b.priority - a.priority;
993
+ });
994
+
995
+ // No matches found
996
+ if (scores.length === 0 || scores[0].score < THRESHOLDS.MINIMUM) {
997
+ return {
998
+ primaryIntent: INTENT_TYPES.UNKNOWN,
999
+ confidence: scores.length > 0 ? scores[0].score : 0,
1000
+ secondaryIntents: [],
1001
+ negatedIntents,
1002
+ autoConvert: false,
1003
+ suggestOnly: false,
1004
+ ambiguous: true,
1005
+ isInquiry: isQuestion,
1006
+ sentenceType,
1007
+ wasTruncated,
1008
+ skipRouting: false,
1009
+ reason: 'no_strong_match',
1010
+ };
1011
+ }
1012
+
1013
+ const primaryResult = scores[0];
1014
+ const secondaryIntents = scores
1015
+ .slice(1)
1016
+ .filter((s) => s.score >= THRESHOLDS.MINIMUM)
1017
+ .map((s) => s.intent);
1018
+
1019
+ // Check for ambiguity (top two scores very close)
1020
+ const isAmbiguous =
1021
+ scores.length > 1 &&
1022
+ Math.abs(primaryResult.score - scores[1].score) < 0.1 &&
1023
+ primaryResult.score < THRESHOLDS.AUTO_CONVERT;
1024
+
1025
+ // For questions, don't auto-convert - user is asking, not commanding
1026
+ const effectiveAutoConvert = !isQuestion && primaryResult.score >= THRESHOLDS.AUTO_CONVERT;
1027
+
1028
+ return {
1029
+ primaryIntent: primaryResult.intent,
1030
+ confidence: primaryResult.score,
1031
+ secondaryIntents,
1032
+ negatedIntents, // NEW: Intents that user explicitly wants to avoid
1033
+ matches: primaryResult.matches,
1034
+ autoConvert: effectiveAutoConvert,
1035
+ suggestOnly:
1036
+ primaryResult.score >= THRESHOLDS.SUGGEST && primaryResult.score < THRESHOLDS.AUTO_CONVERT,
1037
+ ambiguous: isAmbiguous,
1038
+ isInquiry: isQuestion, // NEW: User is asking about this, not commanding
1039
+ sentenceType, // NEW: QUESTION, COMMAND, or STATEMENT
1040
+ wasTruncated, // NEW: True if prompt was truncated for performance
1041
+ requiresContext: hasContextRef && primaryResult.score < THRESHOLDS.SUGGEST, // NEW: Context would help
1042
+ skipRouting: false,
1043
+ reason: null,
1044
+ };
1045
+ }
1046
+
1047
+ module.exports = {
1048
+ classifyIntent,
1049
+ INTENT_TYPES,
1050
+ THRESHOLDS,
1051
+ // Exported for testing
1052
+ isNonAscii,
1053
+ isExplicitCommand,
1054
+ calculateIntentScore,
1055
+ INTENT_PATTERNS,
1056
+ // Negation detection exports
1057
+ isKeywordNegated,
1058
+ detectNegatedIntents,
1059
+ NEGATION_PATTERNS,
1060
+ // Typo tolerance exports
1061
+ levenshteinDistance,
1062
+ isTypoMatch,
1063
+ findTypoMatch,
1064
+ COMMON_TYPOS,
1065
+ // Question detection exports
1066
+ detectSentenceType,
1067
+ SENTENCE_TYPES,
1068
+ QUESTION_PATTERNS,
1069
+ // Long prompt handling exports
1070
+ truncateForClassification,
1071
+ PROMPT_LIMITS,
1072
+ // Session context exports
1073
+ hasContextualReference,
1074
+ CONTEXTUAL_REFERENCE_PATTERNS,
1075
+ };