add-skill-kit 3.2.3 → 3.2.5

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 (126) hide show
  1. package/README.md +1 -1
  2. package/bin/lib/commands/help.js +0 -4
  3. package/bin/lib/commands/install.js +90 -9
  4. package/bin/lib/ui.js +1 -1
  5. package/lib/agent-cli/__tests__/adaptive_engine.test.js +190 -0
  6. package/lib/agent-cli/__tests__/integration/cross_script.test.js +222 -0
  7. package/lib/agent-cli/__tests__/integration/full_cycle.test.js +230 -0
  8. package/lib/agent-cli/__tests__/pattern_analyzer.test.js +173 -0
  9. package/lib/agent-cli/__tests__/pre_execution_check.test.js +167 -0
  10. package/lib/agent-cli/__tests__/skill_injector.test.js +191 -0
  11. package/lib/agent-cli/bin/agent.js +191 -0
  12. package/lib/agent-cli/dashboard/dashboard_server.js +340 -0
  13. package/lib/agent-cli/dashboard/index.html +538 -0
  14. package/lib/agent-cli/lib/audit.js +154 -0
  15. package/lib/agent-cli/lib/audit.test.js +100 -0
  16. package/lib/agent-cli/lib/auto-learn.js +319 -0
  17. package/lib/agent-cli/lib/auto_preview.py +148 -0
  18. package/lib/agent-cli/lib/backup.js +138 -0
  19. package/lib/agent-cli/lib/backup.test.js +78 -0
  20. package/lib/agent-cli/lib/checklist.py +222 -0
  21. package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
  22. package/lib/agent-cli/lib/completion.js +149 -0
  23. package/lib/agent-cli/lib/config.js +35 -0
  24. package/lib/agent-cli/lib/eslint-fix.js +238 -0
  25. package/lib/agent-cli/lib/evolution-signal.js +215 -0
  26. package/lib/agent-cli/lib/export.js +86 -0
  27. package/lib/agent-cli/lib/export.test.js +65 -0
  28. package/lib/agent-cli/lib/fix.js +337 -0
  29. package/lib/agent-cli/lib/fix.test.js +80 -0
  30. package/lib/agent-cli/lib/gemini-export.js +83 -0
  31. package/lib/agent-cli/lib/generate-registry.js +42 -0
  32. package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
  33. package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
  34. package/lib/agent-cli/lib/ignore.js +116 -0
  35. package/lib/agent-cli/lib/ignore.test.js +58 -0
  36. package/lib/agent-cli/lib/init.js +124 -0
  37. package/lib/agent-cli/lib/learn.js +255 -0
  38. package/lib/agent-cli/lib/learn.test.js +70 -0
  39. package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
  40. package/lib/agent-cli/lib/proposals.js +199 -0
  41. package/lib/agent-cli/lib/proposals.test.js +56 -0
  42. package/lib/agent-cli/lib/recall.js +820 -0
  43. package/lib/agent-cli/lib/recall.test.js +107 -0
  44. package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
  45. package/lib/agent-cli/lib/session_manager.py +120 -0
  46. package/lib/agent-cli/lib/settings.js +227 -0
  47. package/lib/agent-cli/lib/skill-learn.js +296 -0
  48. package/lib/agent-cli/lib/stats.js +132 -0
  49. package/lib/agent-cli/lib/stats.test.js +94 -0
  50. package/lib/agent-cli/lib/types.js +33 -0
  51. package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
  52. package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
  53. package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
  54. package/lib/agent-cli/lib/ui/common.js +83 -0
  55. package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
  56. package/lib/agent-cli/lib/ui/custom-select.js +69 -0
  57. package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
  58. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
  59. package/lib/agent-cli/lib/ui/export-ui.js +94 -0
  60. package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
  61. package/lib/agent-cli/lib/ui/help-ui.js +49 -0
  62. package/lib/agent-cli/lib/ui/index.js +199 -0
  63. package/lib/agent-cli/lib/ui/init-ui.js +56 -0
  64. package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
  65. package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
  66. package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
  67. package/lib/agent-cli/lib/ui/pretty.js +145 -0
  68. package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
  69. package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
  70. package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
  71. package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
  72. package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
  73. package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
  74. package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
  75. package/lib/agent-cli/lib/verify_all.py +327 -0
  76. package/lib/agent-cli/lib/watcher.js +181 -0
  77. package/lib/agent-cli/lib/watcher.test.js +85 -0
  78. package/lib/agent-cli/package.json +51 -0
  79. package/lib/agent-cli/scripts/adaptive_engine.js +381 -0
  80. package/lib/agent-cli/scripts/dashboard_server.js +224 -0
  81. package/lib/agent-cli/scripts/error_sensor.js +565 -0
  82. package/lib/agent-cli/scripts/learn_from_failure.js +225 -0
  83. package/lib/agent-cli/scripts/pattern_analyzer.js +781 -0
  84. package/lib/agent-cli/scripts/pre_execution_check.js +623 -0
  85. package/lib/agent-cli/scripts/rule_sharing.js +374 -0
  86. package/lib/agent-cli/scripts/skill_injector.js +387 -0
  87. package/lib/agent-cli/scripts/success_sensor.js +500 -0
  88. package/lib/agent-cli/scripts/user_correction_sensor.js +426 -0
  89. package/lib/agent-cli/services/auto-learn-service.js +247 -0
  90. package/lib/agent-cli/src/MIGRATION.md +418 -0
  91. package/lib/agent-cli/src/README.md +367 -0
  92. package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
  93. package/lib/agent-cli/src/core/evolution/index.js +17 -0
  94. package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
  95. package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
  96. package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
  97. package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
  98. package/lib/agent-cli/src/core/index.js +15 -0
  99. package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
  100. package/lib/agent-cli/src/core/learning/index.js +12 -0
  101. package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
  102. package/lib/agent-cli/src/core/scanning/index.js +14 -0
  103. package/lib/agent-cli/src/data/index.js +13 -0
  104. package/lib/agent-cli/src/data/repositories/index.js +8 -0
  105. package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
  106. package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
  107. package/lib/agent-cli/src/data/storage/index.js +8 -0
  108. package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
  109. package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
  110. package/lib/agent-cli/src/infrastructure/index.js +13 -0
  111. package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
  112. package/lib/agent-cli/src/services/export-service.js +162 -0
  113. package/lib/agent-cli/src/services/index.js +13 -0
  114. package/lib/agent-cli/src/services/learning-service.js +99 -0
  115. package/lib/agent-cli/types/index.d.ts +343 -0
  116. package/lib/agent-cli/utils/benchmark.js +269 -0
  117. package/lib/agent-cli/utils/logger.js +303 -0
  118. package/lib/agent-cli/utils/ml_patterns.js +300 -0
  119. package/lib/agent-cli/utils/recovery.js +312 -0
  120. package/lib/agent-cli/utils/telemetry.js +290 -0
  121. package/lib/agentskillskit-cli/README.md +21 -0
  122. package/{node_modules/agentskillskit-cli/bin → lib/agentskillskit-cli}/ag-smart.js +15 -15
  123. package/lib/agentskillskit-cli/package.json +51 -0
  124. package/package.json +19 -9
  125. /package/bin/{cli.js → kit.js} +0 -0
  126. /package/{node_modules/agentskillskit-cli → lib/agent-cli}/README.md +0 -0
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Logger Utility - Configurable logging with levels and file output
3
+ *
4
+ * Part of FAANG-Grade Auto-Learn System
5
+ *
6
+ * Features:
7
+ * - 4 log levels: DEBUG, INFO, WARN, ERROR
8
+ * - Console output (default)
9
+ * - File output (optional)
10
+ * - Timestamps
11
+ * - Lazy evaluation for debug messages
12
+ *
13
+ * Usage:
14
+ * import { logger, setLogLevel, enableFileLogging } from './logger.js';
15
+ * logger.debug('Debug message', { data });
16
+ * logger.info('Info message');
17
+ * logger.warn('Warning message');
18
+ * logger.error('Error message', error);
19
+ */
20
+
21
+ import fs from 'fs';
22
+ import path from 'path';
23
+ import { fileURLToPath } from 'url';
24
+
25
+ const __filename = fileURLToPath(import.meta.url);
26
+ const __dirname = path.dirname(__filename);
27
+
28
+ // ==================== LOG LEVELS ====================
29
+
30
+ const LOG_LEVELS = {
31
+ DEBUG: 0,
32
+ INFO: 1,
33
+ WARN: 2,
34
+ ERROR: 3,
35
+ SILENT: 4
36
+ };
37
+
38
+ // ==================== COLORS ====================
39
+
40
+ const colors = {
41
+ reset: '\x1b[0m',
42
+ red: '\x1b[31m',
43
+ green: '\x1b[32m',
44
+ yellow: '\x1b[33m',
45
+ blue: '\x1b[34m',
46
+ cyan: '\x1b[36m',
47
+ gray: '\x1b[90m',
48
+ bold: '\x1b[1m'
49
+ };
50
+
51
+ const levelColors = {
52
+ DEBUG: colors.gray,
53
+ INFO: colors.cyan,
54
+ WARN: colors.yellow,
55
+ ERROR: colors.red
56
+ };
57
+
58
+ const levelIcons = {
59
+ DEBUG: '🔍',
60
+ INFO: 'ℹ️',
61
+ WARN: '⚠️',
62
+ ERROR: '❌'
63
+ };
64
+
65
+ // ==================== STATE ====================
66
+
67
+ let currentLevel = LOG_LEVELS.INFO;
68
+ let fileLoggingEnabled = false;
69
+ let logFilePath = null;
70
+
71
+ // ==================== CONFIGURATION ====================
72
+
73
+ /**
74
+ * Set the minimum log level
75
+ * @param {keyof typeof LOG_LEVELS} level - 'DEBUG', 'INFO', 'WARN', 'ERROR', or 'SILENT'
76
+ */
77
+ function setLogLevel(level) {
78
+ if (LOG_LEVELS[level] !== undefined) {
79
+ currentLevel = LOG_LEVELS[level];
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Enable file logging
85
+ * @param {string} filePath - Path to log file
86
+ */
87
+ function enableFileLogging(filePath) {
88
+ fileLoggingEnabled = true;
89
+ logFilePath = filePath;
90
+
91
+ // Ensure directory exists
92
+ const dir = path.dirname(filePath);
93
+ if (!fs.existsSync(dir)) {
94
+ fs.mkdirSync(dir, { recursive: true });
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Disable file logging
100
+ */
101
+ function disableFileLogging() {
102
+ fileLoggingEnabled = false;
103
+ logFilePath = null;
104
+ }
105
+
106
+ // ==================== FORMATTING ====================
107
+
108
+ /**
109
+ * Format log message with timestamp
110
+ */
111
+ function formatMessage(level, message, data) {
112
+ const timestamp = new Date().toISOString();
113
+ const icon = levelIcons[level];
114
+ const color = levelColors[level];
115
+
116
+ let formatted = `${color}${icon} [${timestamp.split('T')[1].split('.')[0]}] [${level}]${colors.reset} ${message}`;
117
+
118
+ if (data !== undefined) {
119
+ if (typeof data === 'object') {
120
+ formatted += ` ${colors.gray}${JSON.stringify(data)}${colors.reset}`;
121
+ } else {
122
+ formatted += ` ${colors.gray}${data}${colors.reset}`;
123
+ }
124
+ }
125
+
126
+ return formatted;
127
+ }
128
+
129
+ /**
130
+ * Format for file (no colors)
131
+ */
132
+ function formatForFile(level, message, data) {
133
+ const timestamp = new Date().toISOString();
134
+ let formatted = `[${timestamp}] [${level}] ${message}`;
135
+
136
+ if (data !== undefined) {
137
+ if (typeof data === 'object') {
138
+ formatted += ` ${JSON.stringify(data)}`;
139
+ } else {
140
+ formatted += ` ${data}`;
141
+ }
142
+ }
143
+
144
+ return formatted;
145
+ }
146
+
147
+ // ==================== WRITE FUNCTIONS ====================
148
+
149
+ /**
150
+ * Write to console
151
+ */
152
+ function writeToConsole(level, formatted) {
153
+ if (level === 'ERROR') {
154
+ console.error(formatted);
155
+ } else if (level === 'WARN') {
156
+ console.warn(formatted);
157
+ } else {
158
+ console.log(formatted);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Write to file (async)
164
+ */
165
+ function writeToFile(formatted) {
166
+ if (fileLoggingEnabled && logFilePath) {
167
+ try {
168
+ fs.appendFileSync(logFilePath, formatted + '\n');
169
+ } catch (err) {
170
+ // Silently fail file logging
171
+ }
172
+ }
173
+ }
174
+
175
+ // ==================== LOG FUNCTIONS ====================
176
+
177
+ /**
178
+ * Log at specified level
179
+ */
180
+ function log(level, message, data) {
181
+ if (LOG_LEVELS[level] < currentLevel) {
182
+ return;
183
+ }
184
+
185
+ // Console output
186
+ const formatted = formatMessage(level, message, data);
187
+ writeToConsole(level, formatted);
188
+
189
+ // File output
190
+ if (fileLoggingEnabled) {
191
+ const fileFormatted = formatForFile(level, message, data);
192
+ writeToFile(fileFormatted);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Debug log (lowest priority)
198
+ * @param {string} message - Log message
199
+ * @param {any} [data] - Optional data to log
200
+ */
201
+ function debug(message, data) {
202
+ log('DEBUG', message, data);
203
+ }
204
+
205
+ /**
206
+ * Info log
207
+ * @param {string} message - Log message
208
+ * @param {any} [data] - Optional data to log
209
+ */
210
+ function info(message, data) {
211
+ log('INFO', message, data);
212
+ }
213
+
214
+ /**
215
+ * Warning log
216
+ * @param {string} message - Log message
217
+ * @param {any} [data] - Optional data to log
218
+ */
219
+ function warn(message, data) {
220
+ log('WARN', message, data);
221
+ }
222
+
223
+ /**
224
+ * Error log (highest priority)
225
+ * @param {string} message - Log message
226
+ * @param {any} [data] - Optional error or data
227
+ */
228
+ function error(message, data) {
229
+ log('ERROR', message, data);
230
+ }
231
+
232
+ // ==================== SPECIALIZED LOGGERS ====================
233
+
234
+ /**
235
+ * Create a logger with fixed prefix
236
+ * @param {string} prefix - Prefix for all log messages
237
+ */
238
+ function createLogger(prefix) {
239
+ return {
240
+ debug: (msg, data) => debug(`[${prefix}] ${msg}`, data),
241
+ info: (msg, data) => info(`[${prefix}] ${msg}`, data),
242
+ warn: (msg, data) => warn(`[${prefix}] ${msg}`, data),
243
+ error: (msg, data) => error(`[${prefix}] ${msg}`, data)
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Log timing for operations
249
+ * @param {string} label - Operation label
250
+ */
251
+ function time(label) {
252
+ const start = Date.now();
253
+ return {
254
+ end: () => {
255
+ const duration = Date.now() - start;
256
+ debug(`${label} completed`, { duration: `${duration}ms` });
257
+ return duration;
258
+ }
259
+ };
260
+ }
261
+
262
+ // ==================== LOGGER OBJECT ====================
263
+
264
+ const logger = {
265
+ debug,
266
+ info,
267
+ warn,
268
+ error,
269
+ time,
270
+ createLogger,
271
+ setLevel: setLogLevel,
272
+ enableFile: enableFileLogging,
273
+ disableFile: disableFileLogging,
274
+ LOG_LEVELS
275
+ };
276
+
277
+ // ==================== CLI SUPPORT ====================
278
+
279
+ // Check for environment variable
280
+ if (process.env.LOG_LEVEL) {
281
+ setLogLevel(process.env.LOG_LEVEL.toUpperCase());
282
+ }
283
+
284
+ // Check for LOG_FILE environment variable
285
+ if (process.env.LOG_FILE) {
286
+ enableFileLogging(process.env.LOG_FILE);
287
+ }
288
+
289
+ export {
290
+ logger,
291
+ debug,
292
+ info,
293
+ warn,
294
+ error,
295
+ setLogLevel,
296
+ enableFileLogging,
297
+ disableFileLogging,
298
+ createLogger,
299
+ time,
300
+ LOG_LEVELS
301
+ };
302
+
303
+ export default logger;
@@ -0,0 +1,300 @@
1
+ /**
2
+ * ML Pattern Matching Utility
3
+ *
4
+ * Provides intelligent pattern matching using similarity algorithms:
5
+ * - Levenshtein distance
6
+ * - Jaccard similarity
7
+ * - Fuzzy matching with confidence scores
8
+ *
9
+ * Usage:
10
+ * import { findSimilar, matchWithConfidence } from './ml_patterns.js';
11
+ *
12
+ * const matches = findSimilar('missing-await', patterns, 0.7);
13
+ * const result = matchWithConfidence(intent, rules);
14
+ */
15
+
16
+ // ==================== LEVENSHTEIN DISTANCE ====================
17
+
18
+ /**
19
+ * Calculate Levenshtein distance between two strings
20
+ * @param {string} a - First string
21
+ * @param {string} b - Second string
22
+ * @returns {number} Edit distance
23
+ */
24
+ function levenshtein(a, b) {
25
+ const matrix = [];
26
+
27
+ for (let i = 0; i <= b.length; i++) {
28
+ matrix[i] = [i];
29
+ }
30
+
31
+ for (let j = 0; j <= a.length; j++) {
32
+ matrix[0][j] = j;
33
+ }
34
+
35
+ for (let i = 1; i <= b.length; i++) {
36
+ for (let j = 1; j <= a.length; j++) {
37
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
38
+ matrix[i][j] = matrix[i - 1][j - 1];
39
+ } else {
40
+ matrix[i][j] = Math.min(
41
+ matrix[i - 1][j - 1] + 1, // substitution
42
+ matrix[i][j - 1] + 1, // insertion
43
+ matrix[i - 1][j] + 1 // deletion
44
+ );
45
+ }
46
+ }
47
+ }
48
+
49
+ return matrix[b.length][a.length];
50
+ }
51
+
52
+ /**
53
+ * Calculate similarity ratio (0-1) using Levenshtein
54
+ * @param {string} a - First string
55
+ * @param {string} b - Second string
56
+ * @returns {number} Similarity ratio (1 = identical)
57
+ */
58
+ function levenshteinSimilarity(a, b) {
59
+ const distance = levenshtein(a.toLowerCase(), b.toLowerCase());
60
+ const maxLen = Math.max(a.length, b.length);
61
+ return maxLen === 0 ? 1 : 1 - distance / maxLen;
62
+ }
63
+
64
+ // ==================== JACCARD SIMILARITY ====================
65
+
66
+ /**
67
+ * Tokenize string into words/n-grams
68
+ * @param {string} str - Input string
69
+ * @param {number} n - N-gram size (default: 2)
70
+ */
71
+ function tokenize(str, n = 2) {
72
+ const normalized = str.toLowerCase().replace(/[^a-z0-9]/g, ' ').trim();
73
+ const words = normalized.split(/\s+/).filter(w => w.length > 0);
74
+
75
+ if (n === 1) return new Set(words);
76
+
77
+ const ngrams = new Set();
78
+ for (const word of words) {
79
+ for (let i = 0; i <= word.length - n; i++) {
80
+ ngrams.add(word.slice(i, i + n));
81
+ }
82
+ }
83
+ return ngrams;
84
+ }
85
+
86
+ /**
87
+ * Calculate Jaccard similarity (0-1)
88
+ * @param {string} a - First string
89
+ * @param {string} b - Second string
90
+ * @returns {number} Similarity ratio
91
+ */
92
+ function jaccardSimilarity(a, b) {
93
+ const setA = tokenize(a);
94
+ const setB = tokenize(b);
95
+
96
+ const intersection = new Set([...setA].filter(x => setB.has(x)));
97
+ const union = new Set([...setA, ...setB]);
98
+
99
+ return union.size === 0 ? 0 : intersection.size / union.size;
100
+ }
101
+
102
+ // ==================== COMBINED SIMILARITY ====================
103
+
104
+ /**
105
+ * Calculate weighted combined similarity
106
+ * @param {string} a - First string
107
+ * @param {string} b - Second string
108
+ * @returns {number} Combined similarity (0-1)
109
+ */
110
+ function combinedSimilarity(a, b) {
111
+ const lev = levenshteinSimilarity(a, b);
112
+ const jac = jaccardSimilarity(a, b);
113
+
114
+ // Weighted average: Levenshtein more weight for short strings
115
+ const lenFactor = Math.min(a.length, b.length) / 10;
116
+ const levWeight = Math.max(0.3, 0.7 - lenFactor * 0.1);
117
+ const jacWeight = 1 - levWeight;
118
+
119
+ return lev * levWeight + jac * jacWeight;
120
+ }
121
+
122
+ // ==================== FUZZY MATCHING ====================
123
+
124
+ /**
125
+ * Find similar patterns from a list
126
+ * @param {string} query - Query string
127
+ * @param {string[]} patterns - List of patterns to search
128
+ * @param {number} threshold - Minimum similarity (default: 0.6)
129
+ * @returns {Array<{pattern: string, similarity: number}>}
130
+ */
131
+ function findSimilar(query, patterns, threshold = 0.6) {
132
+ const matches = [];
133
+
134
+ for (const pattern of patterns) {
135
+ const similarity = combinedSimilarity(query, pattern);
136
+ if (similarity >= threshold) {
137
+ matches.push({ pattern, similarity: Math.round(similarity * 100) / 100 });
138
+ }
139
+ }
140
+
141
+ return matches.sort((a, b) => b.similarity - a.similarity);
142
+ }
143
+
144
+ /**
145
+ * Check if two strings are fuzzy equal
146
+ * @param {string} a - First string
147
+ * @param {string} b - Second string
148
+ * @param {number} threshold - Minimum similarity
149
+ */
150
+ function fuzzyEquals(a, b, threshold = 0.8) {
151
+ return combinedSimilarity(a, b) >= threshold;
152
+ }
153
+
154
+ // ==================== RULE MATCHING ====================
155
+
156
+ /**
157
+ * Match intent against rules with confidence scores
158
+ * @param {string} intent - User intent
159
+ * @param {Array<{id: string, pattern: string, severity: string}>} rules
160
+ * @param {number} threshold - Minimum confidence
161
+ * @returns {Array<{rule: object, confidence: number, matchType: string}>}
162
+ */
163
+ function matchWithConfidence(intent, rules, threshold = 0.5) {
164
+ const matches = [];
165
+ const intentLower = intent.toLowerCase();
166
+
167
+ for (const rule of rules) {
168
+ const patternLower = rule.pattern.toLowerCase();
169
+
170
+ // Exact match
171
+ if (intentLower.includes(patternLower)) {
172
+ matches.push({
173
+ rule,
174
+ confidence: 1.0,
175
+ matchType: 'EXACT'
176
+ });
177
+ continue;
178
+ }
179
+
180
+ // Word boundary match
181
+ const words = intentLower.split(/\s+/);
182
+ const patternWords = patternLower.split(/[-_\s]+/);
183
+ const wordMatch = patternWords.some(pw =>
184
+ words.some(w => w.includes(pw) || pw.includes(w))
185
+ );
186
+
187
+ if (wordMatch) {
188
+ const similarity = combinedSimilarity(intent, rule.pattern);
189
+ if (similarity >= threshold) {
190
+ matches.push({
191
+ rule,
192
+ confidence: Math.round(similarity * 100) / 100,
193
+ matchType: 'PARTIAL'
194
+ });
195
+ }
196
+ continue;
197
+ }
198
+
199
+ // Fuzzy match
200
+ const similarity = combinedSimilarity(intent, rule.pattern);
201
+ if (similarity >= threshold) {
202
+ matches.push({
203
+ rule,
204
+ confidence: Math.round(similarity * 100) / 100,
205
+ matchType: 'FUZZY'
206
+ });
207
+ }
208
+ }
209
+
210
+ return matches.sort((a, b) => b.confidence - a.confidence);
211
+ }
212
+
213
+ // ==================== PATTERN CLUSTERING ====================
214
+
215
+ /**
216
+ * Cluster similar patterns together
217
+ * @param {string[]} patterns - List of patterns
218
+ * @param {number} threshold - Similarity threshold for clustering
219
+ * @returns {Array<{representative: string, members: string[]}>}
220
+ */
221
+ function clusterPatterns(patterns, threshold = 0.7) {
222
+ const clusters = [];
223
+ const assigned = new Set();
224
+
225
+ for (const pattern of patterns) {
226
+ if (assigned.has(pattern)) continue;
227
+
228
+ const cluster = {
229
+ representative: pattern,
230
+ members: [pattern]
231
+ };
232
+
233
+ for (const other of patterns) {
234
+ if (other === pattern || assigned.has(other)) continue;
235
+
236
+ if (combinedSimilarity(pattern, other) >= threshold) {
237
+ cluster.members.push(other);
238
+ assigned.add(other);
239
+ }
240
+ }
241
+
242
+ assigned.add(pattern);
243
+ clusters.push(cluster);
244
+ }
245
+
246
+ return clusters;
247
+ }
248
+
249
+ /**
250
+ * Find representative pattern for a group
251
+ * @param {string[]} patterns - Group of similar patterns
252
+ */
253
+ function findRepresentative(patterns) {
254
+ if (patterns.length === 0) return null;
255
+ if (patterns.length === 1) return patterns[0];
256
+
257
+ // Find pattern closest to all others
258
+ let bestPattern = patterns[0];
259
+ let bestScore = 0;
260
+
261
+ for (const candidate of patterns) {
262
+ let score = 0;
263
+ for (const other of patterns) {
264
+ score += combinedSimilarity(candidate, other);
265
+ }
266
+ if (score > bestScore) {
267
+ bestScore = score;
268
+ bestPattern = candidate;
269
+ }
270
+ }
271
+
272
+ return bestPattern;
273
+ }
274
+
275
+ // ==================== EXPORTS ====================
276
+
277
+ export {
278
+ levenshtein,
279
+ levenshteinSimilarity,
280
+ jaccardSimilarity,
281
+ combinedSimilarity,
282
+ tokenize,
283
+ findSimilar,
284
+ fuzzyEquals,
285
+ matchWithConfidence,
286
+ clusterPatterns,
287
+ findRepresentative
288
+ };
289
+
290
+ export default {
291
+ levenshtein,
292
+ levenshteinSimilarity,
293
+ jaccardSimilarity,
294
+ combinedSimilarity,
295
+ findSimilar,
296
+ fuzzyEquals,
297
+ matchWithConfidence,
298
+ clusterPatterns,
299
+ findRepresentative
300
+ };