oh-my-claude-sisyphus 3.4.2 → 3.5.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 (164) hide show
  1. package/README.md +45 -0
  2. package/commands/cancel-ultraqa.md +1 -1
  3. package/dist/__tests__/analytics/analytics-summary.test.d.ts +2 -0
  4. package/dist/__tests__/analytics/analytics-summary.test.d.ts.map +1 -0
  5. package/dist/__tests__/analytics/analytics-summary.test.js +267 -0
  6. package/dist/__tests__/analytics/analytics-summary.test.js.map +1 -0
  7. package/dist/__tests__/analytics/backfill-dedup.test.d.ts +2 -0
  8. package/dist/__tests__/analytics/backfill-dedup.test.d.ts.map +1 -0
  9. package/dist/__tests__/analytics/backfill-dedup.test.js +179 -0
  10. package/dist/__tests__/analytics/backfill-dedup.test.js.map +1 -0
  11. package/dist/__tests__/analytics/backfill-engine.test.d.ts +2 -0
  12. package/dist/__tests__/analytics/backfill-engine.test.d.ts.map +1 -0
  13. package/dist/__tests__/analytics/backfill-engine.test.js +362 -0
  14. package/dist/__tests__/analytics/backfill-engine.test.js.map +1 -0
  15. package/dist/__tests__/analytics/cost-estimator.test.d.ts +2 -0
  16. package/dist/__tests__/analytics/cost-estimator.test.d.ts.map +1 -0
  17. package/dist/__tests__/analytics/cost-estimator.test.js +212 -0
  18. package/dist/__tests__/analytics/cost-estimator.test.js.map +1 -0
  19. package/dist/__tests__/analytics/output-estimator.test.d.ts +2 -0
  20. package/dist/__tests__/analytics/output-estimator.test.d.ts.map +1 -0
  21. package/dist/__tests__/analytics/output-estimator.test.js +106 -0
  22. package/dist/__tests__/analytics/output-estimator.test.js.map +1 -0
  23. package/dist/__tests__/analytics/token-extractor.test.d.ts +2 -0
  24. package/dist/__tests__/analytics/token-extractor.test.d.ts.map +1 -0
  25. package/dist/__tests__/analytics/token-extractor.test.js +121 -0
  26. package/dist/__tests__/analytics/token-extractor.test.js.map +1 -0
  27. package/dist/__tests__/analytics/transcript-parser.test.d.ts +2 -0
  28. package/dist/__tests__/analytics/transcript-parser.test.d.ts.map +1 -0
  29. package/dist/__tests__/analytics/transcript-parser.test.js +285 -0
  30. package/dist/__tests__/analytics/transcript-parser.test.js.map +1 -0
  31. package/dist/__tests__/analytics/transcript-scanner.test.d.ts +2 -0
  32. package/dist/__tests__/analytics/transcript-scanner.test.d.ts.map +1 -0
  33. package/dist/__tests__/analytics/transcript-scanner.test.js +401 -0
  34. package/dist/__tests__/analytics/transcript-scanner.test.js.map +1 -0
  35. package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts +2 -0
  36. package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts.map +1 -0
  37. package/dist/__tests__/analytics/transcript-token-extractor.test.js +175 -0
  38. package/dist/__tests__/analytics/transcript-token-extractor.test.js.map +1 -0
  39. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts +2 -0
  40. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts.map +1 -0
  41. package/dist/__tests__/hud/auto-tracking.integration.test.js +12 -0
  42. package/dist/__tests__/hud/auto-tracking.integration.test.js.map +1 -0
  43. package/dist/__tests__/learner/auto-learner.test.d.ts +7 -0
  44. package/dist/__tests__/learner/auto-learner.test.d.ts.map +1 -0
  45. package/dist/__tests__/learner/auto-learner.test.js +507 -0
  46. package/dist/__tests__/learner/auto-learner.test.js.map +1 -0
  47. package/dist/__tests__/learner/matcher.test.d.ts +2 -0
  48. package/dist/__tests__/learner/matcher.test.d.ts.map +1 -0
  49. package/dist/__tests__/learner/matcher.test.js +330 -0
  50. package/dist/__tests__/learner/matcher.test.js.map +1 -0
  51. package/dist/analytics/analytics-summary.d.ts +47 -0
  52. package/dist/analytics/analytics-summary.d.ts.map +1 -0
  53. package/dist/analytics/analytics-summary.js +171 -0
  54. package/dist/analytics/analytics-summary.js.map +1 -0
  55. package/dist/analytics/backfill-dedup.d.ts +49 -0
  56. package/dist/analytics/backfill-dedup.d.ts.map +1 -0
  57. package/dist/analytics/backfill-dedup.js +115 -0
  58. package/dist/analytics/backfill-dedup.js.map +1 -0
  59. package/dist/analytics/backfill-engine.d.ts +59 -0
  60. package/dist/analytics/backfill-engine.d.ts.map +1 -0
  61. package/dist/analytics/backfill-engine.js +172 -0
  62. package/dist/analytics/backfill-engine.js.map +1 -0
  63. package/dist/analytics/index.d.ts +8 -0
  64. package/dist/analytics/index.d.ts.map +1 -1
  65. package/dist/analytics/index.js +10 -0
  66. package/dist/analytics/index.js.map +1 -1
  67. package/dist/analytics/output-estimator.d.ts +26 -0
  68. package/dist/analytics/output-estimator.d.ts.map +1 -0
  69. package/dist/analytics/output-estimator.js +61 -0
  70. package/dist/analytics/output-estimator.js.map +1 -0
  71. package/dist/analytics/query-engine.d.ts.map +1 -1
  72. package/dist/analytics/query-engine.js +3 -2
  73. package/dist/analytics/query-engine.js.map +1 -1
  74. package/dist/analytics/token-extractor.d.ts +31 -0
  75. package/dist/analytics/token-extractor.d.ts.map +1 -0
  76. package/dist/analytics/token-extractor.js +57 -0
  77. package/dist/analytics/token-extractor.js.map +1 -0
  78. package/dist/analytics/token-tracker.d.ts +7 -1
  79. package/dist/analytics/token-tracker.d.ts.map +1 -1
  80. package/dist/analytics/token-tracker.js +94 -18
  81. package/dist/analytics/token-tracker.js.map +1 -1
  82. package/dist/analytics/transcript-parser.d.ts +42 -0
  83. package/dist/analytics/transcript-parser.d.ts.map +1 -0
  84. package/dist/analytics/transcript-parser.js +90 -0
  85. package/dist/analytics/transcript-parser.js.map +1 -0
  86. package/dist/analytics/transcript-scanner.d.ts +50 -0
  87. package/dist/analytics/transcript-scanner.d.ts.map +1 -0
  88. package/dist/analytics/transcript-scanner.js +149 -0
  89. package/dist/analytics/transcript-scanner.js.map +1 -0
  90. package/dist/analytics/transcript-token-extractor.d.ts +35 -0
  91. package/dist/analytics/transcript-token-extractor.d.ts.map +1 -0
  92. package/dist/analytics/transcript-token-extractor.js +136 -0
  93. package/dist/analytics/transcript-token-extractor.js.map +1 -0
  94. package/dist/analytics/types.d.ts +65 -0
  95. package/dist/analytics/types.d.ts.map +1 -1
  96. package/dist/analytics/types.js.map +1 -1
  97. package/dist/cli/analytics.js +26 -1
  98. package/dist/cli/analytics.js.map +1 -1
  99. package/dist/cli/commands/backfill.d.ts +15 -0
  100. package/dist/cli/commands/backfill.d.ts.map +1 -0
  101. package/dist/cli/commands/backfill.js +146 -0
  102. package/dist/cli/commands/backfill.js.map +1 -0
  103. package/dist/cli/commands/stats.d.ts +1 -0
  104. package/dist/cli/commands/stats.d.ts.map +1 -1
  105. package/dist/cli/commands/stats.js +67 -31
  106. package/dist/cli/commands/stats.js.map +1 -1
  107. package/dist/cli/components/CostDashboard.d.ts +15 -0
  108. package/dist/cli/components/CostDashboard.d.ts.map +1 -0
  109. package/dist/cli/components/CostDashboard.js +15 -0
  110. package/dist/cli/components/CostDashboard.js.map +1 -0
  111. package/dist/cli/components/LiveStats.d.ts +16 -0
  112. package/dist/cli/components/LiveStats.d.ts.map +1 -0
  113. package/dist/cli/components/LiveStats.js +16 -0
  114. package/dist/cli/components/LiveStats.js.map +1 -0
  115. package/dist/cli/components/SessionBrowser.d.ts +14 -0
  116. package/dist/cli/components/SessionBrowser.d.ts.map +1 -0
  117. package/dist/cli/components/SessionBrowser.js +14 -0
  118. package/dist/cli/components/SessionBrowser.js.map +1 -0
  119. package/dist/cli/index.js +159 -3
  120. package/dist/cli/index.js.map +1 -1
  121. package/dist/cli/tui.d.ts +21 -0
  122. package/dist/cli/tui.d.ts.map +1 -0
  123. package/dist/cli/tui.js +21 -0
  124. package/dist/cli/tui.js.map +1 -0
  125. package/dist/hooks/learner/auto-invoke.d.ts +82 -0
  126. package/dist/hooks/learner/auto-invoke.d.ts.map +1 -0
  127. package/dist/hooks/learner/auto-invoke.js +234 -0
  128. package/dist/hooks/learner/auto-invoke.js.map +1 -0
  129. package/dist/hooks/learner/auto-learner.d.ts +55 -0
  130. package/dist/hooks/learner/auto-learner.d.ts.map +1 -0
  131. package/dist/hooks/learner/auto-learner.js +361 -0
  132. package/dist/hooks/learner/auto-learner.js.map +1 -0
  133. package/dist/hooks/learner/index.d.ts +3 -0
  134. package/dist/hooks/learner/index.d.ts.map +1 -1
  135. package/dist/hooks/learner/index.js +4 -0
  136. package/dist/hooks/learner/index.js.map +1 -1
  137. package/dist/hooks/learner/matcher.d.ts +40 -0
  138. package/dist/hooks/learner/matcher.d.ts.map +1 -0
  139. package/dist/hooks/learner/matcher.js +230 -0
  140. package/dist/hooks/learner/matcher.js.map +1 -0
  141. package/dist/hud/analytics-display.d.ts +16 -0
  142. package/dist/hud/analytics-display.d.ts.map +1 -1
  143. package/dist/hud/analytics-display.js +42 -0
  144. package/dist/hud/analytics-display.js.map +1 -1
  145. package/dist/hud/index.js +90 -3
  146. package/dist/hud/index.js.map +1 -1
  147. package/dist/hud/render.d.ts.map +1 -1
  148. package/dist/hud/render.js +27 -1
  149. package/dist/hud/render.js.map +1 -1
  150. package/dist/hud/types.d.ts +2 -0
  151. package/dist/hud/types.d.ts.map +1 -1
  152. package/dist/hud/types.js.map +1 -1
  153. package/docs/ANALYTICS-SYSTEM.md +150 -0
  154. package/hooks/keyword-detector.sh +1 -1
  155. package/package.json +1 -1
  156. package/scripts/keyword-detector.mjs +1 -1
  157. package/scripts/persistent-mode.mjs +1 -1
  158. package/scripts/test-mutual-exclusion.ts +4 -4
  159. package/scripts/test-remember-tags.ts +6 -6
  160. package/scripts/test-session-injection.ts +4 -4
  161. package/skills/cancel-ultraqa/SKILL.md +1 -1
  162. package/skills/local-skills-setup/SKILL.md +465 -0
  163. package/skills/omc-setup/SKILL.md +30 -5
  164. package/skills/skill/SKILL.md +406 -0
@@ -0,0 +1,330 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { matchSkills, fuzzyMatch, extractContext, calculateConfidence, } from '../../hooks/learner/matcher.js';
3
+ describe('Smart Skill Matcher', () => {
4
+ //=============================================
5
+ // 1. FUZZY MATCHING - Levenshtein Distance
6
+ //=============================================
7
+ describe('Fuzzy Matching - Levenshtein Distance', () => {
8
+ it('should return 100 for exact word match', () => {
9
+ const score = fuzzyMatch('typescript is great', 'typescript');
10
+ expect(score).toBe(100);
11
+ });
12
+ it('should handle typos with high similarity', () => {
13
+ // "typescrpt" vs "typescript" (missing 'i') - should get a decent score
14
+ const score = fuzzyMatch('fix typescrpt errors', 'typescript');
15
+ // 9 chars vs 10 chars, 1 edit distance -> similarity = (10-1)/10 = 90%
16
+ expect(score).toBeGreaterThanOrEqual(70);
17
+ });
18
+ it('should handle minor typos', () => {
19
+ // "javascrpt" vs "javascript" (missing 'i')
20
+ const score = fuzzyMatch('help with javascrpt', 'javascript');
21
+ expect(score).toBeGreaterThanOrEqual(70);
22
+ });
23
+ it('should give low score for unrelated words', () => {
24
+ const score = fuzzyMatch('hello world', 'typescript');
25
+ expect(score).toBeLessThan(60);
26
+ });
27
+ it('should handle word boundary correctly', () => {
28
+ // "type" is contained in prompt but "typescript" is the pattern
29
+ const score1 = fuzzyMatch('type something', 'typescript');
30
+ // This should be lower than exact match but partial match bonus applies
31
+ expect(score1).toBeGreaterThan(0);
32
+ });
33
+ it('should handle partial matches with inclusion', () => {
34
+ const score = fuzzyMatch('react typescript app', 'react');
35
+ expect(score).toBe(100); // Exact match
36
+ });
37
+ });
38
+ //=============================================
39
+ // 2. PATTERN MATCHING - Glob and Regex
40
+ //=============================================
41
+ describe('Pattern Matching - Glob and Regex', () => {
42
+ it('should match glob patterns with wildcard', () => {
43
+ const skills = [{ id: 'ts-skill', triggers: ['*.ts', 'typescript'] }];
44
+ const results = matchSkills('fix all .ts files', skills);
45
+ // Should match because "*.ts" pattern matches "ts" in the text
46
+ expect(results.length).toBeGreaterThanOrEqual(0); // Pattern converts to regex
47
+ });
48
+ it('should match explicit regex patterns', () => {
49
+ const skills = [{ id: 'error-skill', triggers: ['/error/i'] }];
50
+ const results = matchSkills('there is an ERROR in my code', skills);
51
+ expect(results.length).toBe(1);
52
+ expect(results[0].skillId).toBe('error-skill');
53
+ expect(results[0].matchType).toBe('pattern');
54
+ expect(results[0].confidence).toBe(90); // regex pattern = 90
55
+ });
56
+ it('should handle invalid regex gracefully', () => {
57
+ const skills = [{ id: 'bad-regex', triggers: ['/[invalid/'] }];
58
+ // Should not throw, should just skip the invalid pattern
59
+ const results = matchSkills('test prompt', skills);
60
+ expect(results).toEqual([]);
61
+ });
62
+ it('should match case-insensitive regex', () => {
63
+ const skills = [{ id: 'api-skill', triggers: ['/api/i'] }];
64
+ const results = matchSkills('Build an API endpoint', skills);
65
+ expect(results.length).toBe(1);
66
+ });
67
+ it('should handle glob with multiple wildcards', () => {
68
+ const skills = [{ id: 'glob-skill', triggers: ['*test*'] }];
69
+ const results = matchSkills('run my tests now', skills);
70
+ // ".*test.*" should match "tests"
71
+ expect(results.length).toBe(1);
72
+ expect(results[0].matchType).toBe('pattern');
73
+ });
74
+ });
75
+ //=============================================
76
+ // 3. CONTEXT EXTRACTION
77
+ //=============================================
78
+ describe('Context Extraction', () => {
79
+ describe('Error Detection', () => {
80
+ it('should detect TypeError', () => {
81
+ const ctx = extractContext('I got a TypeError: undefined is not a function');
82
+ expect(ctx.detectedErrors).toContain('TypeError');
83
+ });
84
+ it('should detect ReferenceError', () => {
85
+ const ctx = extractContext('ReferenceError: x is not defined');
86
+ expect(ctx.detectedErrors).toContain('ReferenceError');
87
+ });
88
+ it('should detect ENOENT', () => {
89
+ const ctx = extractContext('ENOENT: no such file or directory');
90
+ expect(ctx.detectedErrors).toContain('ENOENT');
91
+ });
92
+ it('should detect EACCES', () => {
93
+ const ctx = extractContext('EACCES: permission denied');
94
+ expect(ctx.detectedErrors).toContain('EACCES');
95
+ });
96
+ it('should detect ECONNREFUSED', () => {
97
+ const ctx = extractContext('ECONNREFUSED: connection refused');
98
+ expect(ctx.detectedErrors).toContain('ECONNREFUSED');
99
+ });
100
+ it('should detect stack trace lines', () => {
101
+ const ctx = extractContext('at Object.run (/home/user/file.ts:42:10)');
102
+ expect(ctx.detectedErrors.length).toBeGreaterThan(0);
103
+ });
104
+ it('should detect generic error keywords', () => {
105
+ const ctx = extractContext('The build failed with error code 1');
106
+ expect(ctx.detectedErrors.some(e => /error|failed/i.test(e))).toBe(true);
107
+ });
108
+ });
109
+ describe('File Path Detection', () => {
110
+ it('should detect src/ paths', () => {
111
+ const ctx = extractContext('check src/components/Button.tsx');
112
+ expect(ctx.detectedFiles.some(f => f.includes('src/'))).toBe(true);
113
+ });
114
+ it('should detect relative paths with extension', () => {
115
+ const ctx = extractContext('edit ./bar.js file');
116
+ expect(ctx.detectedFiles.some(f => f.includes('bar.js'))).toBe(true);
117
+ });
118
+ it('should detect nested paths', () => {
119
+ const ctx = extractContext('fix lib/utils/helpers.ts');
120
+ expect(ctx.detectedFiles.some(f => f.includes('helpers.ts') || f.includes('lib/'))).toBe(true);
121
+ });
122
+ it('should detect absolute paths', () => {
123
+ const ctx = extractContext('open /home/user/project/main.py');
124
+ expect(ctx.detectedFiles.some(f => f.includes('main.py') || f.includes('/home/'))).toBe(true);
125
+ });
126
+ });
127
+ describe('Pattern Detection', () => {
128
+ it('should detect async/await pattern', () => {
129
+ const ctx = extractContext('use async function and await the promise');
130
+ expect(ctx.detectedPatterns).toContain('async/await');
131
+ });
132
+ it('should detect promise pattern', () => {
133
+ const ctx = extractContext('return a Promise from the function');
134
+ expect(ctx.detectedPatterns).toContain('promise');
135
+ });
136
+ it('should detect callback pattern', () => {
137
+ const ctx = extractContext('pass a callback to the function');
138
+ expect(ctx.detectedPatterns).toContain('callback');
139
+ });
140
+ it('should detect regex pattern keyword', () => {
141
+ const ctx = extractContext('write a regex for email validation');
142
+ expect(ctx.detectedPatterns).toContain('regex');
143
+ });
144
+ it('should detect API pattern', () => {
145
+ const ctx = extractContext('create a REST API endpoint');
146
+ expect(ctx.detectedPatterns).toContain('api');
147
+ });
148
+ it('should detect typescript', () => {
149
+ const ctx = extractContext('convert this to TypeScript');
150
+ expect(ctx.detectedPatterns).toContain('typescript');
151
+ });
152
+ it('should detect react', () => {
153
+ const ctx = extractContext('build a React component');
154
+ expect(ctx.detectedPatterns).toContain('react');
155
+ });
156
+ it('should detect git', () => {
157
+ const ctx = extractContext('commit with git');
158
+ expect(ctx.detectedPatterns).toContain('git');
159
+ });
160
+ });
161
+ });
162
+ //=============================================
163
+ // 4. CONFIDENCE SCORING
164
+ //=============================================
165
+ describe('Confidence Scoring', () => {
166
+ it('should return 100 for exact match', () => {
167
+ const skills = [{ id: 'test-skill', triggers: ['deploy'] }];
168
+ const results = matchSkills('deploy the app', skills);
169
+ expect(results.length).toBe(1);
170
+ expect(results[0].confidence).toBe(100); // exact match: 100*0.7 + 100*0.3 = 100
171
+ });
172
+ it('should score fuzzy matches lower than exact', () => {
173
+ const skills = [
174
+ { id: 'exact', triggers: ['typescript'] },
175
+ { id: 'fuzzy', triggers: ['typescrpt'] }, // typo - will be fuzzy matched
176
+ ];
177
+ const results = matchSkills('help with typescript', skills);
178
+ // Should have exact match for 'typescript'
179
+ const exactMatch = results.find(r => r.skillId === 'exact');
180
+ expect(exactMatch).toBeDefined();
181
+ expect(exactMatch.confidence).toBe(100);
182
+ });
183
+ it('should filter results below threshold', () => {
184
+ const skills = [
185
+ { id: 'unrelated', triggers: ['zzznotmatch'] },
186
+ ];
187
+ const results = matchSkills('build my app', skills, { threshold: 30 });
188
+ expect(results.length).toBe(0);
189
+ });
190
+ it('should respect custom threshold', () => {
191
+ const skills = [
192
+ { id: 'test', triggers: ['typescript'] },
193
+ ];
194
+ const results = matchSkills('help with typescript', skills, { threshold: 50 });
195
+ expect(results.length).toBe(1);
196
+ expect(results[0].confidence).toBeGreaterThanOrEqual(50);
197
+ });
198
+ it('should limit results with maxResults', () => {
199
+ const skills = [
200
+ { id: 'skill1', triggers: ['test'] },
201
+ { id: 'skill2', triggers: ['test'] },
202
+ { id: 'skill3', triggers: ['test'] },
203
+ { id: 'skill4', triggers: ['test'] },
204
+ { id: 'skill5', triggers: ['test'] },
205
+ ];
206
+ const results = matchSkills('run tests', skills, { maxResults: 3 });
207
+ expect(results.length).toBe(3);
208
+ });
209
+ it('should calculate confidence correctly via helper', () => {
210
+ // Test the calculateConfidence helper directly
211
+ expect(calculateConfidence(1, 1, 'exact')).toBe(100);
212
+ expect(calculateConfidence(1, 2, 'exact')).toBe(50);
213
+ expect(calculateConfidence(1, 1, 'fuzzy')).toBe(70); // 100 * 0.7
214
+ expect(calculateConfidence(1, 1, 'pattern')).toBe(90); // 100 * 0.9
215
+ expect(calculateConfidence(0, 1, 'exact')).toBe(0);
216
+ expect(calculateConfidence(0, 0, 'exact')).toBe(0);
217
+ });
218
+ it('should sort results by confidence descending', () => {
219
+ const skills = [
220
+ { id: 'low', triggers: ['/fix/i'] }, // pattern = 90 base
221
+ { id: 'high', triggers: ['typescript'] }, // exact = 100 base
222
+ ];
223
+ const results = matchSkills('fix typescript errors', skills);
224
+ expect(results.length).toBe(2);
225
+ expect(results[0].skillId).toBe('high');
226
+ expect(results[1].skillId).toBe('low');
227
+ });
228
+ });
229
+ //=============================================
230
+ // 5. EDGE CASES
231
+ //=============================================
232
+ describe('Edge Cases', () => {
233
+ it('should handle empty prompt', () => {
234
+ const skills = [{ id: 'test', triggers: ['deploy'] }];
235
+ const results = matchSkills('', skills);
236
+ expect(results).toEqual([]);
237
+ });
238
+ it('should handle empty skills array', () => {
239
+ const results = matchSkills('deploy the app', []);
240
+ expect(results).toEqual([]);
241
+ });
242
+ it('should handle very long prompts', () => {
243
+ const longPrompt = 'typescript '.repeat(1000);
244
+ const skills = [{ id: 'ts', triggers: ['typescript'] }];
245
+ const results = matchSkills(longPrompt, skills);
246
+ expect(results.length).toBe(1);
247
+ expect(results[0].skillId).toBe('ts');
248
+ });
249
+ it('should handle special characters in prompt', () => {
250
+ const ctx = extractContext('Error: $#@!%^&*() invalid syntax');
251
+ // Should not crash
252
+ expect(ctx).toBeDefined();
253
+ expect(ctx.detectedErrors.length).toBeGreaterThanOrEqual(0);
254
+ });
255
+ it('should handle special characters in triggers', () => {
256
+ const skills = [{ id: 'special', triggers: ['c++'] }];
257
+ const results = matchSkills('help with c++ code', skills);
258
+ expect(results.length).toBe(1);
259
+ });
260
+ it('should handle unicode in prompt', () => {
261
+ const ctx = extractContext('fix the bug in function 函数名 with emoji 🚀');
262
+ expect(ctx).toBeDefined();
263
+ });
264
+ it('should handle skill with tags', () => {
265
+ const skills = [{
266
+ id: 'multi-tag',
267
+ triggers: ['deploy'],
268
+ tags: ['production', 'release'],
269
+ }];
270
+ const results = matchSkills('release to production', skills);
271
+ expect(results.length).toBe(1);
272
+ expect(results[0].matchedTriggers).toContain('production');
273
+ });
274
+ it('should handle whitespace-only prompt', () => {
275
+ const skills = [{ id: 'test', triggers: ['deploy'] }];
276
+ const results = matchSkills(' \t\n ', skills);
277
+ expect(results).toEqual([]);
278
+ });
279
+ it('should handle skill with empty triggers', () => {
280
+ const skills = [{ id: 'empty', triggers: [] }];
281
+ const results = matchSkills('test prompt', skills);
282
+ expect(results).toEqual([]);
283
+ });
284
+ it('should deduplicate detected context items', () => {
285
+ const ctx = extractContext('TypeError TypeError TypeError ENOENT ENOENT');
286
+ // Should dedupe
287
+ const typeErrorCount = ctx.detectedErrors.filter(e => e === 'TypeError').length;
288
+ expect(typeErrorCount).toBe(1);
289
+ });
290
+ });
291
+ //=============================================
292
+ // 6. INTEGRATION - Full Match Flow
293
+ //=============================================
294
+ describe('Integration - Full Match Flow', () => {
295
+ it('should match with context-aware results', () => {
296
+ const skills = [
297
+ { id: 'debug', triggers: ['error', 'fix', 'debug'] },
298
+ { id: 'deploy', triggers: ['deploy', 'release'] },
299
+ ];
300
+ const prompt = 'Fix the TypeError in src/utils.ts';
301
+ const results = matchSkills(prompt, skills);
302
+ expect(results.length).toBeGreaterThan(0);
303
+ const debugResult = results.find(r => r.skillId === 'debug');
304
+ expect(debugResult).toBeDefined();
305
+ expect(debugResult.context.detectedErrors).toContain('TypeError');
306
+ expect(debugResult.context.detectedFiles.length).toBeGreaterThan(0);
307
+ });
308
+ it('should prioritize exact matches over fuzzy', () => {
309
+ const skills = [
310
+ { id: 'typescript-skill', triggers: ['typescript'] },
311
+ ];
312
+ const results = matchSkills('I need help with typescript', skills);
313
+ expect(results[0].matchType).toBe('exact');
314
+ });
315
+ it('should handle mixed match types', () => {
316
+ const skills = [
317
+ { id: 'exact-match', triggers: ['deploy'] },
318
+ { id: 'pattern-match', triggers: ['/api/i'] },
319
+ { id: 'fuzzy-match', triggers: ['typescrpt'] }, // typo for typescript
320
+ ];
321
+ const results = matchSkills('deploy the API to typescript server', skills);
322
+ expect(results.length).toBeGreaterThanOrEqual(2);
323
+ const exactResult = results.find(r => r.skillId === 'exact-match');
324
+ const patternResult = results.find(r => r.skillId === 'pattern-match');
325
+ expect(exactResult).toBeDefined();
326
+ expect(patternResult).toBeDefined();
327
+ });
328
+ });
329
+ });
330
+ //# sourceMappingURL=matcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher.test.js","sourceRoot":"","sources":["../../../src/__tests__/learner/matcher.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Analytics Summary - Fast session analytics loading
3
+ *
4
+ * This module provides mtime-based caching for <10ms session load times.
5
+ */
6
+ export interface AnalyticsSummary {
7
+ sessionId: string;
8
+ lastUpdated: string;
9
+ lastLogOffset: number;
10
+ totals: {
11
+ inputTokens: number;
12
+ outputTokens: number;
13
+ cacheCreationTokens: number;
14
+ cacheReadTokens: number;
15
+ estimatedCost: number;
16
+ };
17
+ topAgents: Array<{
18
+ agent: string;
19
+ cost: number;
20
+ tokens: number;
21
+ }>;
22
+ cacheHitRate: number;
23
+ }
24
+ /**
25
+ * Get summary file path for session ID.
26
+ */
27
+ export declare function getSummaryPath(sessionId: string): string;
28
+ /**
29
+ * Initialize empty summary for new session.
30
+ */
31
+ export declare function createEmptySummary(sessionId: string): AnalyticsSummary;
32
+ /**
33
+ * Load analytics summary with mtime-based caching.
34
+ *
35
+ * Performance target: <10ms (vs 50-100ms full JSONL rebuild)
36
+ *
37
+ * Strategy:
38
+ * 1. Check if summary file exists and is fresh (mtime >= log mtime)
39
+ * 2. If fresh → return cached summary
40
+ * 3. If stale → rebuild incrementally from lastLogOffset
41
+ */
42
+ export declare function loadAnalyticsFast(sessionId: string): Promise<AnalyticsSummary | null>;
43
+ /**
44
+ * Force rebuild summary from scratch (ignore cache)
45
+ */
46
+ export declare function rebuildAnalyticsSummary(sessionId: string): Promise<AnalyticsSummary>;
47
+ //# sourceMappingURL=analytics-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-summary.d.ts","sourceRoot":"","sources":["../../src/analytics/analytics-summary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAetE;AA2HD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAqB3F;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAY1F"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Analytics Summary - Fast session analytics loading
3
+ *
4
+ * This module provides mtime-based caching for <10ms session load times.
5
+ */
6
+ import { homedir } from 'os';
7
+ import { join } from 'path';
8
+ /**
9
+ * Get summary file path for session ID.
10
+ */
11
+ export function getSummaryPath(sessionId) {
12
+ return join(homedir(), '.omc', 'state', `analytics-summary-${sessionId}.json`);
13
+ }
14
+ /**
15
+ * Initialize empty summary for new session.
16
+ */
17
+ export function createEmptySummary(sessionId) {
18
+ return {
19
+ sessionId,
20
+ lastUpdated: new Date().toISOString(),
21
+ lastLogOffset: 0,
22
+ totals: {
23
+ inputTokens: 0,
24
+ outputTokens: 0,
25
+ cacheCreationTokens: 0,
26
+ cacheReadTokens: 0,
27
+ estimatedCost: 0
28
+ },
29
+ topAgents: [],
30
+ cacheHitRate: 0
31
+ };
32
+ }
33
+ import * as fs from 'fs/promises';
34
+ import { calculateCost } from './cost-estimator.js';
35
+ /**
36
+ * Get file modification time
37
+ */
38
+ async function getFileMtime(filePath) {
39
+ try {
40
+ const stats = await fs.stat(filePath);
41
+ return stats.mtime;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ /**
48
+ * Update top agents list
49
+ */
50
+ function updateTopAgents(summary, agentName, cost, tokens) {
51
+ let agent = summary.topAgents.find(a => a.agent === agentName);
52
+ if (!agent) {
53
+ agent = { agent: agentName, cost: 0, tokens: 0 };
54
+ summary.topAgents.push(agent);
55
+ }
56
+ agent.cost += cost;
57
+ agent.tokens += tokens;
58
+ // Sort by cost and keep top 10
59
+ summary.topAgents.sort((a, b) => b.cost - a.cost);
60
+ summary.topAgents = summary.topAgents.slice(0, 10);
61
+ }
62
+ /**
63
+ * Calculate cache hit rate percentage
64
+ */
65
+ function calculateCacheHitRate(totals) {
66
+ const total = totals.inputTokens + totals.cacheCreationTokens;
67
+ if (total === 0)
68
+ return 0;
69
+ return (totals.cacheReadTokens / total) * 100;
70
+ }
71
+ /**
72
+ * Rebuild summary incrementally from JSONL log.
73
+ *
74
+ * Starts from lastLogOffset to avoid re-processing entire log.
75
+ */
76
+ async function rebuildSummaryIncremental(sessionId, summaryPath, logPath) {
77
+ let summary;
78
+ let startOffset = 0;
79
+ try {
80
+ // Try to load existing summary
81
+ const content = await fs.readFile(summaryPath, 'utf-8');
82
+ summary = JSON.parse(content);
83
+ startOffset = summary.lastLogOffset;
84
+ }
85
+ catch {
86
+ // Start fresh
87
+ summary = createEmptySummary(sessionId);
88
+ }
89
+ // Read JSONL from lastLogOffset
90
+ const logContent = await fs.readFile(logPath, 'utf-8');
91
+ const lines = logContent.split('\n').slice(startOffset);
92
+ for (const line of lines) {
93
+ if (!line.trim())
94
+ continue;
95
+ const record = JSON.parse(line);
96
+ if (record.sessionId !== sessionId)
97
+ continue;
98
+ // Update totals
99
+ summary.totals.inputTokens += record.inputTokens || 0;
100
+ summary.totals.outputTokens += record.outputTokens || 0;
101
+ summary.totals.cacheCreationTokens += record.cacheCreationTokens || 0;
102
+ summary.totals.cacheReadTokens += record.cacheReadTokens || 0;
103
+ // Update cost
104
+ const cost = calculateCost({
105
+ modelName: record.modelName,
106
+ inputTokens: record.inputTokens,
107
+ outputTokens: record.outputTokens,
108
+ cacheCreationTokens: record.cacheCreationTokens,
109
+ cacheReadTokens: record.cacheReadTokens
110
+ });
111
+ summary.totals.estimatedCost += cost.totalCost;
112
+ // Update top agents (use "(main session)" for entries without agentName)
113
+ const agentKey = record.agentName || '(main session)';
114
+ updateTopAgents(summary, agentKey, cost.totalCost, record.inputTokens + record.outputTokens);
115
+ }
116
+ // Update metadata
117
+ summary.lastUpdated = new Date().toISOString();
118
+ summary.lastLogOffset = startOffset + lines.length;
119
+ summary.cacheHitRate = calculateCacheHitRate(summary.totals);
120
+ // Save updated summary
121
+ const summaryDir = join(homedir(), '.omc', 'state');
122
+ await fs.mkdir(summaryDir, { recursive: true });
123
+ await fs.writeFile(summaryPath, JSON.stringify(summary, null, 2));
124
+ return summary;
125
+ }
126
+ /**
127
+ * Load analytics summary with mtime-based caching.
128
+ *
129
+ * Performance target: <10ms (vs 50-100ms full JSONL rebuild)
130
+ *
131
+ * Strategy:
132
+ * 1. Check if summary file exists and is fresh (mtime >= log mtime)
133
+ * 2. If fresh → return cached summary
134
+ * 3. If stale → rebuild incrementally from lastLogOffset
135
+ */
136
+ export async function loadAnalyticsFast(sessionId) {
137
+ const summaryPath = getSummaryPath(sessionId);
138
+ const logPath = join(homedir(), '.omc', 'state', 'token-tracking.jsonl');
139
+ try {
140
+ // Check if summary exists and is fresh
141
+ const summaryMtime = await getFileMtime(summaryPath);
142
+ const logMtime = await getFileMtime(logPath);
143
+ if (summaryMtime && logMtime && summaryMtime >= logMtime) {
144
+ // Summary is up-to-date, use cached version
145
+ const content = await fs.readFile(summaryPath, 'utf-8');
146
+ return JSON.parse(content);
147
+ }
148
+ // Need to rebuild (incremental if summary exists)
149
+ return await rebuildSummaryIncremental(sessionId, summaryPath, logPath);
150
+ }
151
+ catch (error) {
152
+ // No summary exists yet or error reading
153
+ return null;
154
+ }
155
+ }
156
+ /**
157
+ * Force rebuild summary from scratch (ignore cache)
158
+ */
159
+ export async function rebuildAnalyticsSummary(sessionId) {
160
+ const summaryPath = getSummaryPath(sessionId);
161
+ const logPath = join(homedir(), '.omc', 'state', 'token-tracking.jsonl');
162
+ // Delete existing summary to force full rebuild
163
+ try {
164
+ await fs.unlink(summaryPath);
165
+ }
166
+ catch {
167
+ // Ignore if doesn't exist
168
+ }
169
+ return await rebuildSummaryIncremental(sessionId, summaryPath, logPath);
170
+ }
171
+ //# sourceMappingURL=analytics-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-summary.js","sourceRoot":"","sources":["../../src/analytics/analytics-summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export interface DedupIndex {
2
+ processedIds: string[];
3
+ lastBackfillTime: string;
4
+ totalProcessed: number;
5
+ }
6
+ /**
7
+ * BackfillDedup provides fast deduplication for backfill operations.
8
+ *
9
+ * Uses in-memory Set for O(1) lookups and persists state to disk.
10
+ * Loads existing entries from token-tracking.jsonl on initialization.
11
+ */
12
+ export declare class BackfillDedup {
13
+ private processedSet;
14
+ private totalProcessed;
15
+ private lastBackfillTime;
16
+ /**
17
+ * Load existing processed IDs from backfill-index.json and scan token-tracking.jsonl
18
+ */
19
+ load(): Promise<void>;
20
+ /**
21
+ * Generate unique ID for a token usage entry
22
+ * Uses SHA256 hash to match transcript-token-extractor.ts format
23
+ */
24
+ private generateEntryId;
25
+ /**
26
+ * Check if an entry ID has already been processed
27
+ */
28
+ isProcessed(entryId: string): boolean;
29
+ /**
30
+ * Mark an entry ID as processed
31
+ */
32
+ markProcessed(entryId: string): void;
33
+ /**
34
+ * Persist deduplication state to backfill-index.json
35
+ */
36
+ save(): Promise<void>;
37
+ /**
38
+ * Clear all processed entries and delete index file
39
+ */
40
+ reset(): Promise<void>;
41
+ /**
42
+ * Get current statistics
43
+ */
44
+ getStats(): {
45
+ totalProcessed: number;
46
+ lastBackfillTime: string;
47
+ };
48
+ }
49
+ //# sourceMappingURL=backfill-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill-dedup.d.ts","sourceRoot":"","sources":["../../src/analytics/backfill-dedup.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,gBAAgB,CAAoC;IAE5D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIrC;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOpC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACH,QAAQ,IAAI;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;CAMjE"}