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
package/README.md CHANGED
@@ -135,6 +135,51 @@ Maximum parallelism with Haiku where possible, falling back to Sonnet/Opus for c
135
135
 
136
136
  ---
137
137
 
138
+ ## Analytics & Cost Tracking (v3.5.0)
139
+
140
+ Track your Claude Code usage across all sessions with automatic transcript analysis.
141
+
142
+ ### Backfill Historical Data
143
+
144
+ ```
145
+ omc backfill # Analyze all transcripts
146
+ omc backfill --from 2026-01-01 # From specific date
147
+ omc backfill --project "*/myproject/*" # Filter by project
148
+ ```
149
+
150
+ ### View Statistics
151
+
152
+ ```
153
+ omc stats # All sessions aggregate
154
+ omc stats --session # Current session only
155
+ omc stats --json # JSON output
156
+ ```
157
+
158
+ **Sample Output:**
159
+ ```
160
+ 📊 All Sessions Stats
161
+ Sessions: 18
162
+ Entries: 3356
163
+
164
+ 💰 Token Usage & Cost
165
+ Total Tokens: 4.36M
166
+ Total Cost: $2620.49
167
+
168
+ 🤖 Top Agents by Cost (All Sessions)
169
+ (main session) 700.7k tokens $1546.46
170
+ oh-my-claudecode:architect 1.18M tokens $432.68
171
+ oh-my-claudecode:planner 540.9k tokens $274.85
172
+ oh-my-claudecode:executor 306.9k tokens $77.43
173
+ ```
174
+
175
+ **Features:**
176
+ - Automatic backfill on first `omc stats` run
177
+ - Global storage in `~/.omc/state/` (cross-project)
178
+ - Proper agent attribution (main session vs spawned agents)
179
+ - Deduplication prevents double-counting
180
+
181
+ ---
182
+
138
183
  ## Data Analysis & Research (v3.4.0)
139
184
 
140
185
  ### Scientist Agent Tiers
@@ -13,7 +13,7 @@ The UltraQA cycling workflow has been cancelled. Clearing state file.
13
13
  Execute this command to cancel UltraQA:
14
14
 
15
15
  ```bash
16
- mkdir -p .sisyphus && echo '{"active": false, "cancelled_at": "'$(date -Iseconds)'", "reason": "User cancelled via /cancel-ultraqa"}' > .omc/ultraqa-state.json
16
+ mkdir -p .omc && echo '{"active": false, "cancelled_at": "'$(date -Iseconds)'", "reason": "User cancelled via /cancel-ultraqa"}' > .omc/ultraqa-state.json
17
17
  ```
18
18
 
19
19
  After running this command, the QA cycling will stop.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=analytics-summary.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-summary.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/analytics-summary.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,267 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import { getSummaryPath, createEmptySummary, loadAnalyticsFast, rebuildAnalyticsSummary } from '../../analytics/analytics-summary.js';
5
+ describe('AnalyticsSummary', () => {
6
+ const testSessionId = 'test-session-1';
7
+ const testDir = path.resolve(process.cwd(), '.omc/state');
8
+ beforeEach(async () => {
9
+ // Clean up test files before each test
10
+ try {
11
+ const summaryPath = path.resolve(process.cwd(), getSummaryPath(testSessionId));
12
+ await fs.unlink(summaryPath);
13
+ }
14
+ catch {
15
+ // File doesn't exist, that's fine
16
+ }
17
+ });
18
+ afterEach(async () => {
19
+ // Clean up test files after each test
20
+ try {
21
+ const summaryPath = path.resolve(process.cwd(), getSummaryPath(testSessionId));
22
+ await fs.unlink(summaryPath);
23
+ }
24
+ catch {
25
+ // File doesn't exist, that's fine
26
+ }
27
+ });
28
+ describe('getSummaryPath', () => {
29
+ it('should return correct path for session ID', () => {
30
+ const path = getSummaryPath('test-session-123');
31
+ expect(path).toBe('.omc/state/analytics-summary-test-session-123.json');
32
+ });
33
+ it('should handle different session IDs', () => {
34
+ const path1 = getSummaryPath('session-1');
35
+ const path2 = getSummaryPath('session-2');
36
+ expect(path1).not.toBe(path2);
37
+ });
38
+ });
39
+ describe('createEmptySummary', () => {
40
+ it('should create empty summary with correct structure', () => {
41
+ const summary = createEmptySummary(testSessionId);
42
+ expect(summary.sessionId).toBe(testSessionId);
43
+ expect(summary.lastUpdated).toBeDefined();
44
+ expect(summary.lastLogOffset).toBe(0);
45
+ expect(summary.totals).toEqual({
46
+ inputTokens: 0,
47
+ outputTokens: 0,
48
+ cacheCreationTokens: 0,
49
+ cacheReadTokens: 0,
50
+ estimatedCost: 0
51
+ });
52
+ expect(summary.topAgents).toEqual([]);
53
+ expect(summary.cacheHitRate).toBe(0);
54
+ });
55
+ it('should set valid ISO timestamp', () => {
56
+ const summary = createEmptySummary(testSessionId);
57
+ const timestamp = new Date(summary.lastUpdated);
58
+ expect(timestamp).toBeInstanceOf(Date);
59
+ expect(timestamp.getTime()).toBeGreaterThan(0);
60
+ });
61
+ });
62
+ describe('loadAnalyticsFast', () => {
63
+ it('should return null when no summary exists', async () => {
64
+ const summary = await loadAnalyticsFast(testSessionId);
65
+ expect(summary).toBeNull();
66
+ });
67
+ it('should load existing summary from cache', async () => {
68
+ // Create a summary file
69
+ const summaryPath = path.resolve(process.cwd(), getSummaryPath(testSessionId));
70
+ const testSummary = {
71
+ sessionId: testSessionId,
72
+ lastUpdated: new Date().toISOString(),
73
+ lastLogOffset: 5,
74
+ totals: {
75
+ inputTokens: 1000,
76
+ outputTokens: 400,
77
+ cacheCreationTokens: 500,
78
+ cacheReadTokens: 2000,
79
+ estimatedCost: 0.05
80
+ },
81
+ topAgents: [
82
+ { agent: 'executor', cost: 0.03, tokens: 500 }
83
+ ],
84
+ cacheHitRate: 75.5
85
+ };
86
+ await fs.mkdir(path.dirname(summaryPath), { recursive: true });
87
+ await fs.writeFile(summaryPath, JSON.stringify(testSummary, null, 2));
88
+ const loaded = await loadAnalyticsFast(testSessionId);
89
+ expect(loaded).toEqual(testSummary);
90
+ });
91
+ it('should handle corrupted summary file gracefully', async () => {
92
+ const summaryPath = path.resolve(process.cwd(), getSummaryPath(testSessionId));
93
+ await fs.mkdir(path.dirname(summaryPath), { recursive: true });
94
+ await fs.writeFile(summaryPath, 'invalid json {');
95
+ const result = await loadAnalyticsFast(testSessionId);
96
+ // Should return null on parse error
97
+ expect(result).toBeNull();
98
+ });
99
+ });
100
+ describe('rebuildAnalyticsSummary', () => {
101
+ it('should create summary for session with JSONL data', async () => {
102
+ // Create test JSONL file with sample data
103
+ const logPath = path.resolve(process.cwd(), '.omc/state/token-tracking.jsonl');
104
+ const testRecords = [
105
+ {
106
+ timestamp: new Date().toISOString(),
107
+ sessionId: testSessionId,
108
+ modelName: 'claude-sonnet-4-5-20250929',
109
+ inputTokens: 100,
110
+ outputTokens: 40,
111
+ cacheCreationTokens: 50,
112
+ cacheReadTokens: 200,
113
+ agentName: 'executor'
114
+ },
115
+ {
116
+ timestamp: new Date().toISOString(),
117
+ sessionId: testSessionId,
118
+ modelName: 'claude-haiku-4-5-20251001',
119
+ inputTokens: 200,
120
+ outputTokens: 60,
121
+ cacheCreationTokens: 100,
122
+ cacheReadTokens: 400,
123
+ agentName: 'architect'
124
+ }
125
+ ];
126
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
127
+ const jsonl = testRecords.map(r => JSON.stringify(r)).join('\n');
128
+ await fs.writeFile(logPath, jsonl);
129
+ try {
130
+ const summary = await rebuildAnalyticsSummary(testSessionId);
131
+ expect(summary.sessionId).toBe(testSessionId);
132
+ expect(summary.totals.inputTokens).toBe(300); // 100 + 200
133
+ expect(summary.totals.outputTokens).toBe(100); // 40 + 60
134
+ expect(summary.totals.cacheCreationTokens).toBe(150); // 50 + 100
135
+ expect(summary.totals.cacheReadTokens).toBe(600); // 200 + 400
136
+ expect(summary.topAgents.length).toBeGreaterThan(0);
137
+ }
138
+ finally {
139
+ await fs.unlink(logPath).catch(() => { });
140
+ }
141
+ });
142
+ it('should filter by session ID', async () => {
143
+ // Create test JSONL with multiple sessions
144
+ const logPath = path.resolve(process.cwd(), '.omc/state/token-tracking.jsonl');
145
+ const records = [
146
+ {
147
+ timestamp: new Date().toISOString(),
148
+ sessionId: testSessionId,
149
+ modelName: 'claude-sonnet-4-5-20250929',
150
+ inputTokens: 100,
151
+ outputTokens: 40,
152
+ cacheCreationTokens: 0,
153
+ cacheReadTokens: 0
154
+ },
155
+ {
156
+ timestamp: new Date().toISOString(),
157
+ sessionId: 'other-session',
158
+ modelName: 'claude-sonnet-4-5-20250929',
159
+ inputTokens: 1000,
160
+ outputTokens: 400,
161
+ cacheCreationTokens: 0,
162
+ cacheReadTokens: 0
163
+ }
164
+ ];
165
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
166
+ const jsonl = records.map(r => JSON.stringify(r)).join('\n');
167
+ await fs.writeFile(logPath, jsonl);
168
+ try {
169
+ const summary = await rebuildAnalyticsSummary(testSessionId);
170
+ // Should only include test-session-1 data
171
+ expect(summary.totals.inputTokens).toBe(100);
172
+ expect(summary.totals.outputTokens).toBe(40);
173
+ }
174
+ finally {
175
+ await fs.unlink(logPath).catch(() => { });
176
+ }
177
+ });
178
+ it('should calculate cache hit rate correctly', async () => {
179
+ const logPath = path.resolve(process.cwd(), '.omc/state/token-tracking.jsonl');
180
+ const record = {
181
+ timestamp: new Date().toISOString(),
182
+ sessionId: testSessionId,
183
+ modelName: 'claude-sonnet-4-5-20250929',
184
+ inputTokens: 100,
185
+ outputTokens: 40,
186
+ cacheCreationTokens: 100,
187
+ cacheReadTokens: 100
188
+ };
189
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
190
+ await fs.writeFile(logPath, JSON.stringify(record) + '\n');
191
+ try {
192
+ const summary = await rebuildAnalyticsSummary(testSessionId);
193
+ // Cache hit rate = cacheReadTokens / (inputTokens + cacheCreationTokens) * 100
194
+ // = 100 / (100 + 100) * 100 = 50%
195
+ expect(summary.cacheHitRate).toBe(50);
196
+ }
197
+ finally {
198
+ await fs.unlink(logPath).catch(() => { });
199
+ }
200
+ });
201
+ it('should accumulate agent costs into topAgents', async () => {
202
+ const logPath = path.resolve(process.cwd(), '.omc/state/token-tracking.jsonl');
203
+ const records = [
204
+ {
205
+ timestamp: new Date().toISOString(),
206
+ sessionId: testSessionId,
207
+ modelName: 'claude-sonnet-4-5-20250929',
208
+ inputTokens: 100,
209
+ outputTokens: 40,
210
+ cacheCreationTokens: 0,
211
+ cacheReadTokens: 0,
212
+ agentName: 'executor'
213
+ },
214
+ {
215
+ timestamp: new Date().toISOString(),
216
+ sessionId: testSessionId,
217
+ modelName: 'claude-sonnet-4-5-20250929',
218
+ inputTokens: 50,
219
+ outputTokens: 20,
220
+ cacheCreationTokens: 0,
221
+ cacheReadTokens: 0,
222
+ agentName: 'executor'
223
+ }
224
+ ];
225
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
226
+ const jsonl = records.map(r => JSON.stringify(r)).join('\n');
227
+ await fs.writeFile(logPath, jsonl);
228
+ try {
229
+ const summary = await rebuildAnalyticsSummary(testSessionId);
230
+ // Should have executor in topAgents
231
+ const executor = summary.topAgents.find(a => a.agent === 'executor');
232
+ expect(executor).toBeDefined();
233
+ expect(executor?.tokens).toBe(210); // (100 + 40) + (50 + 20)
234
+ }
235
+ finally {
236
+ await fs.unlink(logPath).catch(() => { });
237
+ }
238
+ });
239
+ it('should save summary to disk', async () => {
240
+ const logPath = path.resolve(process.cwd(), '.omc/state/token-tracking.jsonl');
241
+ const summaryPath = path.resolve(process.cwd(), getSummaryPath(testSessionId));
242
+ const record = {
243
+ timestamp: new Date().toISOString(),
244
+ sessionId: testSessionId,
245
+ modelName: 'claude-sonnet-4-5-20250929',
246
+ inputTokens: 100,
247
+ outputTokens: 40,
248
+ cacheCreationTokens: 0,
249
+ cacheReadTokens: 0
250
+ };
251
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
252
+ await fs.writeFile(logPath, JSON.stringify(record) + '\n');
253
+ try {
254
+ await rebuildAnalyticsSummary(testSessionId);
255
+ // Summary should be saved
256
+ const saved = await fs.readFile(summaryPath, 'utf-8');
257
+ const parsed = JSON.parse(saved);
258
+ expect(parsed.sessionId).toBe(testSessionId);
259
+ expect(parsed.totals.inputTokens).toBe(100);
260
+ }
261
+ finally {
262
+ await fs.unlink(logPath).catch(() => { });
263
+ }
264
+ });
265
+ });
266
+ });
267
+ //# sourceMappingURL=analytics-summary.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-summary.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/analytics-summary.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=backfill-dedup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill-dedup.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/backfill-dedup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,179 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ /**
3
+ * BackfillDedup Test Suite
4
+ *
5
+ * Tests for deduplication and backfilling of transcript entries.
6
+ * This ensures we don't double-count tokens when replaying or reconstructing
7
+ * transcript data.
8
+ */
9
+ describe('BackfillDedup', () => {
10
+ /**
11
+ * Mock BackfillDedup class for testing deduplication logic
12
+ */
13
+ class MockBackfillDedup {
14
+ processed = new Set();
15
+ lastBackfillTime;
16
+ constructor() {
17
+ this.lastBackfillTime = new Date().toISOString();
18
+ }
19
+ markProcessed(entryId) {
20
+ this.processed.add(entryId);
21
+ this.lastBackfillTime = new Date().toISOString();
22
+ }
23
+ isProcessed(entryId) {
24
+ return this.processed.has(entryId);
25
+ }
26
+ getStats() {
27
+ return {
28
+ totalProcessed: this.processed.size,
29
+ lastBackfillTime: this.lastBackfillTime
30
+ };
31
+ }
32
+ async reset() {
33
+ this.processed.clear();
34
+ this.lastBackfillTime = new Date().toISOString();
35
+ }
36
+ }
37
+ let dedup;
38
+ beforeEach(() => {
39
+ dedup = new MockBackfillDedup();
40
+ });
41
+ describe('initialization', () => {
42
+ it('should initialize with empty state', () => {
43
+ const stats = dedup.getStats();
44
+ expect(stats.totalProcessed).toBe(0);
45
+ expect(stats.lastBackfillTime).toBeDefined();
46
+ });
47
+ it('should have valid ISO timestamp on init', () => {
48
+ const stats = dedup.getStats();
49
+ const date = new Date(stats.lastBackfillTime);
50
+ expect(date).toBeInstanceOf(Date);
51
+ expect(date.getTime()).toBeGreaterThan(0);
52
+ });
53
+ });
54
+ describe('deduplication', () => {
55
+ it('should mark entries as processed', () => {
56
+ const entryId = 'session-1:2024-01-01T00:00:00Z:claude-sonnet-4.5:100:50';
57
+ expect(dedup.isProcessed(entryId)).toBe(false);
58
+ dedup.markProcessed(entryId);
59
+ expect(dedup.isProcessed(entryId)).toBe(true);
60
+ });
61
+ it('should track total processed count', () => {
62
+ dedup.markProcessed('entry-1');
63
+ expect(dedup.getStats().totalProcessed).toBe(1);
64
+ dedup.markProcessed('entry-2');
65
+ expect(dedup.getStats().totalProcessed).toBe(2);
66
+ dedup.markProcessed('entry-3');
67
+ expect(dedup.getStats().totalProcessed).toBe(3);
68
+ });
69
+ it('should not double-count duplicate marks', () => {
70
+ const entryId = 'session-1:2024-01-01T00:00:00Z:claude-sonnet-4.5:100:50';
71
+ dedup.markProcessed(entryId);
72
+ dedup.markProcessed(entryId); // Duplicate
73
+ dedup.markProcessed(entryId); // Another duplicate
74
+ expect(dedup.getStats().totalProcessed).toBe(1);
75
+ });
76
+ it('should handle multiple entry IDs with different patterns', () => {
77
+ const entries = [
78
+ 'session-1:2024-01-01T00:00:00Z:claude-sonnet-4.5:100:50',
79
+ 'session-1:2024-01-01T00:01:00Z:claude-opus-4.5:200:100',
80
+ 'session-2:2024-01-01T00:00:00Z:claude-haiku-4:50:25',
81
+ 'session-3:2024-01-02T00:00:00Z:claude-sonnet-4.5:150:75'
82
+ ];
83
+ entries.forEach(id => dedup.markProcessed(id));
84
+ expect(dedup.getStats().totalProcessed).toBe(4);
85
+ entries.forEach(id => {
86
+ expect(dedup.isProcessed(id)).toBe(true);
87
+ });
88
+ });
89
+ it('should distinguish between similar entry IDs', () => {
90
+ const entry1 = 'session-1:2024-01-01T00:00:00Z:claude-sonnet-4.5:100:50';
91
+ const entry2 = 'session-1:2024-01-01T00:00:00Z:claude-sonnet-4.5:100:51'; // Different output tokens
92
+ dedup.markProcessed(entry1);
93
+ expect(dedup.isProcessed(entry1)).toBe(true);
94
+ expect(dedup.isProcessed(entry2)).toBe(false);
95
+ });
96
+ it('should handle empty entry ID', () => {
97
+ const emptyId = '';
98
+ dedup.markProcessed(emptyId);
99
+ expect(dedup.isProcessed(emptyId)).toBe(true);
100
+ expect(dedup.getStats().totalProcessed).toBe(1);
101
+ });
102
+ it('should handle long entry IDs', () => {
103
+ const longId = 'a'.repeat(1000);
104
+ dedup.markProcessed(longId);
105
+ expect(dedup.isProcessed(longId)).toBe(true);
106
+ });
107
+ it('should update last backfill time on each mark', async () => {
108
+ const time1 = dedup.getStats().lastBackfillTime;
109
+ // Small delay to ensure time difference
110
+ await new Promise(resolve => setTimeout(resolve, 10));
111
+ dedup.markProcessed('entry-1');
112
+ const time2 = dedup.getStats().lastBackfillTime;
113
+ // time2 should be >= time1
114
+ expect(new Date(time2).getTime()).toBeGreaterThanOrEqual(new Date(time1).getTime());
115
+ });
116
+ });
117
+ describe('backfilling scenarios', () => {
118
+ it('should handle incremental backfills without duplication', () => {
119
+ // First batch
120
+ dedup.markProcessed('session-1:2024-01-01T00:00:00Z:model1:100:50');
121
+ dedup.markProcessed('session-1:2024-01-01T00:01:00Z:model1:200:100');
122
+ expect(dedup.getStats().totalProcessed).toBe(2);
123
+ // Second batch (replay + new)
124
+ dedup.markProcessed('session-1:2024-01-01T00:00:00Z:model1:100:50'); // Replay
125
+ dedup.markProcessed('session-1:2024-01-01T00:01:00Z:model1:200:100'); // Replay
126
+ dedup.markProcessed('session-1:2024-01-01T00:02:00Z:model1:300:150'); // New
127
+ expect(dedup.getStats().totalProcessed).toBe(3); // Not 5
128
+ });
129
+ it('should support out-of-order processing', () => {
130
+ const entries = [
131
+ 'session-1:2024-01-01T00:05:00Z:model1:100:50',
132
+ 'session-1:2024-01-01T00:02:00Z:model1:200:100',
133
+ 'session-1:2024-01-01T00:01:00Z:model1:300:150'
134
+ ];
135
+ entries.forEach(id => dedup.markProcessed(id));
136
+ expect(dedup.getStats().totalProcessed).toBe(3);
137
+ entries.forEach(id => {
138
+ expect(dedup.isProcessed(id)).toBe(true);
139
+ });
140
+ });
141
+ it('should handle high-volume dedup', () => {
142
+ // Simulate processing 10,000 entries with some duplicates
143
+ for (let i = 0; i < 10000; i++) {
144
+ const sessionId = `session-${i % 50}`;
145
+ const timestamp = new Date(Date.now() - (i * 1000)).toISOString();
146
+ const model = ['claude-sonnet-4.5', 'claude-haiku-4', 'claude-opus-4.5'][i % 3];
147
+ const tokens = (i % 1000) + 100;
148
+ const entryId = `${sessionId}:${timestamp}:${model}:${tokens}:${tokens / 2}`;
149
+ dedup.markProcessed(entryId);
150
+ }
151
+ const stats = dedup.getStats();
152
+ expect(stats.totalProcessed).toBeGreaterThan(0);
153
+ // With 50 sessions, 3 models, and varying timestamps, we should have many unique entries
154
+ expect(stats.totalProcessed).toBeLessThanOrEqual(10000);
155
+ });
156
+ });
157
+ describe('reset', () => {
158
+ it('should reset state correctly', async () => {
159
+ dedup.markProcessed('entry-1');
160
+ dedup.markProcessed('entry-2');
161
+ dedup.markProcessed('entry-3');
162
+ expect(dedup.getStats().totalProcessed).toBe(3);
163
+ await dedup.reset();
164
+ expect(dedup.getStats().totalProcessed).toBe(0);
165
+ expect(dedup.isProcessed('entry-1')).toBe(false);
166
+ expect(dedup.isProcessed('entry-2')).toBe(false);
167
+ expect(dedup.isProcessed('entry-3')).toBe(false);
168
+ });
169
+ it('should allow re-processing after reset', async () => {
170
+ dedup.markProcessed('entry-1');
171
+ expect(dedup.getStats().totalProcessed).toBe(1);
172
+ await dedup.reset();
173
+ expect(dedup.getStats().totalProcessed).toBe(0);
174
+ dedup.markProcessed('entry-1');
175
+ expect(dedup.getStats().totalProcessed).toBe(1);
176
+ });
177
+ });
178
+ });
179
+ //# sourceMappingURL=backfill-dedup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill-dedup.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/backfill-dedup.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=backfill-engine.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill-engine.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/backfill-engine.test.ts"],"names":[],"mappings":""}