oh-my-claude-sisyphus 3.4.1 → 3.4.3

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 (135) hide show
  1. package/commands/cancel-ultraqa.md +1 -1
  2. package/dist/__tests__/analytics/analytics-summary.test.d.ts +2 -0
  3. package/dist/__tests__/analytics/analytics-summary.test.d.ts.map +1 -0
  4. package/dist/__tests__/analytics/analytics-summary.test.js +267 -0
  5. package/dist/__tests__/analytics/analytics-summary.test.js.map +1 -0
  6. package/dist/__tests__/analytics/backfill-dedup.test.d.ts +2 -0
  7. package/dist/__tests__/analytics/backfill-dedup.test.d.ts.map +1 -0
  8. package/dist/__tests__/analytics/backfill-dedup.test.js +179 -0
  9. package/dist/__tests__/analytics/backfill-dedup.test.js.map +1 -0
  10. package/dist/__tests__/analytics/backfill-engine.test.d.ts +2 -0
  11. package/dist/__tests__/analytics/backfill-engine.test.d.ts.map +1 -0
  12. package/dist/__tests__/analytics/backfill-engine.test.js +362 -0
  13. package/dist/__tests__/analytics/backfill-engine.test.js.map +1 -0
  14. package/dist/__tests__/analytics/cost-estimator.test.d.ts +2 -0
  15. package/dist/__tests__/analytics/cost-estimator.test.d.ts.map +1 -0
  16. package/dist/__tests__/analytics/cost-estimator.test.js +212 -0
  17. package/dist/__tests__/analytics/cost-estimator.test.js.map +1 -0
  18. package/dist/__tests__/analytics/output-estimator.test.d.ts +2 -0
  19. package/dist/__tests__/analytics/output-estimator.test.d.ts.map +1 -0
  20. package/dist/__tests__/analytics/output-estimator.test.js +106 -0
  21. package/dist/__tests__/analytics/output-estimator.test.js.map +1 -0
  22. package/dist/__tests__/analytics/token-extractor.test.d.ts +2 -0
  23. package/dist/__tests__/analytics/token-extractor.test.d.ts.map +1 -0
  24. package/dist/__tests__/analytics/token-extractor.test.js +121 -0
  25. package/dist/__tests__/analytics/token-extractor.test.js.map +1 -0
  26. package/dist/__tests__/analytics/transcript-parser.test.d.ts +2 -0
  27. package/dist/__tests__/analytics/transcript-parser.test.d.ts.map +1 -0
  28. package/dist/__tests__/analytics/transcript-parser.test.js +285 -0
  29. package/dist/__tests__/analytics/transcript-parser.test.js.map +1 -0
  30. package/dist/__tests__/analytics/transcript-scanner.test.d.ts +2 -0
  31. package/dist/__tests__/analytics/transcript-scanner.test.d.ts.map +1 -0
  32. package/dist/__tests__/analytics/transcript-scanner.test.js +401 -0
  33. package/dist/__tests__/analytics/transcript-scanner.test.js.map +1 -0
  34. package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts +2 -0
  35. package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts.map +1 -0
  36. package/dist/__tests__/analytics/transcript-token-extractor.test.js +175 -0
  37. package/dist/__tests__/analytics/transcript-token-extractor.test.js.map +1 -0
  38. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts +2 -0
  39. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts.map +1 -0
  40. package/dist/__tests__/hud/auto-tracking.integration.test.js +12 -0
  41. package/dist/__tests__/hud/auto-tracking.integration.test.js.map +1 -0
  42. package/dist/analytics/analytics-summary.d.ts +47 -0
  43. package/dist/analytics/analytics-summary.d.ts.map +1 -0
  44. package/dist/analytics/analytics-summary.js +170 -0
  45. package/dist/analytics/analytics-summary.js.map +1 -0
  46. package/dist/analytics/backfill-dedup.d.ts +49 -0
  47. package/dist/analytics/backfill-dedup.d.ts.map +1 -0
  48. package/dist/analytics/backfill-dedup.js +118 -0
  49. package/dist/analytics/backfill-dedup.js.map +1 -0
  50. package/dist/analytics/backfill-engine.d.ts +59 -0
  51. package/dist/analytics/backfill-engine.d.ts.map +1 -0
  52. package/dist/analytics/backfill-engine.js +163 -0
  53. package/dist/analytics/backfill-engine.js.map +1 -0
  54. package/dist/analytics/index.d.ts +8 -0
  55. package/dist/analytics/index.d.ts.map +1 -1
  56. package/dist/analytics/index.js +10 -0
  57. package/dist/analytics/index.js.map +1 -1
  58. package/dist/analytics/output-estimator.d.ts +26 -0
  59. package/dist/analytics/output-estimator.d.ts.map +1 -0
  60. package/dist/analytics/output-estimator.js +61 -0
  61. package/dist/analytics/output-estimator.js.map +1 -0
  62. package/dist/analytics/token-extractor.d.ts +31 -0
  63. package/dist/analytics/token-extractor.d.ts.map +1 -0
  64. package/dist/analytics/token-extractor.js +57 -0
  65. package/dist/analytics/token-extractor.js.map +1 -0
  66. package/dist/analytics/token-tracker.d.ts +7 -1
  67. package/dist/analytics/token-tracker.d.ts.map +1 -1
  68. package/dist/analytics/token-tracker.js +81 -0
  69. package/dist/analytics/token-tracker.js.map +1 -1
  70. package/dist/analytics/transcript-parser.d.ts +42 -0
  71. package/dist/analytics/transcript-parser.d.ts.map +1 -0
  72. package/dist/analytics/transcript-parser.js +90 -0
  73. package/dist/analytics/transcript-parser.js.map +1 -0
  74. package/dist/analytics/transcript-scanner.d.ts +50 -0
  75. package/dist/analytics/transcript-scanner.d.ts.map +1 -0
  76. package/dist/analytics/transcript-scanner.js +149 -0
  77. package/dist/analytics/transcript-scanner.js.map +1 -0
  78. package/dist/analytics/transcript-token-extractor.d.ts +19 -0
  79. package/dist/analytics/transcript-token-extractor.d.ts.map +1 -0
  80. package/dist/analytics/transcript-token-extractor.js +89 -0
  81. package/dist/analytics/transcript-token-extractor.js.map +1 -0
  82. package/dist/analytics/types.d.ts +52 -0
  83. package/dist/analytics/types.d.ts.map +1 -1
  84. package/dist/analytics/types.js.map +1 -1
  85. package/dist/cli/analytics.js +26 -1
  86. package/dist/cli/analytics.js.map +1 -1
  87. package/dist/cli/commands/backfill.d.ts +15 -0
  88. package/dist/cli/commands/backfill.d.ts.map +1 -0
  89. package/dist/cli/commands/backfill.js +146 -0
  90. package/dist/cli/commands/backfill.js.map +1 -0
  91. package/dist/cli/commands/stats.d.ts +1 -0
  92. package/dist/cli/commands/stats.d.ts.map +1 -1
  93. package/dist/cli/commands/stats.js +67 -31
  94. package/dist/cli/commands/stats.js.map +1 -1
  95. package/dist/cli/components/CostDashboard.d.ts +15 -0
  96. package/dist/cli/components/CostDashboard.d.ts.map +1 -0
  97. package/dist/cli/components/CostDashboard.js +15 -0
  98. package/dist/cli/components/CostDashboard.js.map +1 -0
  99. package/dist/cli/components/LiveStats.d.ts +16 -0
  100. package/dist/cli/components/LiveStats.d.ts.map +1 -0
  101. package/dist/cli/components/LiveStats.js +16 -0
  102. package/dist/cli/components/LiveStats.js.map +1 -0
  103. package/dist/cli/components/SessionBrowser.d.ts +14 -0
  104. package/dist/cli/components/SessionBrowser.d.ts.map +1 -0
  105. package/dist/cli/components/SessionBrowser.js +14 -0
  106. package/dist/cli/components/SessionBrowser.js.map +1 -0
  107. package/dist/cli/index.js +159 -3
  108. package/dist/cli/index.js.map +1 -1
  109. package/dist/cli/tui.d.ts +21 -0
  110. package/dist/cli/tui.d.ts.map +1 -0
  111. package/dist/cli/tui.js +21 -0
  112. package/dist/cli/tui.js.map +1 -0
  113. package/dist/hud/analytics-display.d.ts +16 -0
  114. package/dist/hud/analytics-display.d.ts.map +1 -1
  115. package/dist/hud/analytics-display.js +42 -0
  116. package/dist/hud/analytics-display.js.map +1 -1
  117. package/dist/hud/index.js +90 -3
  118. package/dist/hud/index.js.map +1 -1
  119. package/dist/hud/render.d.ts.map +1 -1
  120. package/dist/hud/render.js +27 -1
  121. package/dist/hud/render.js.map +1 -1
  122. package/dist/hud/types.d.ts +2 -0
  123. package/dist/hud/types.d.ts.map +1 -1
  124. package/dist/hud/types.js.map +1 -1
  125. package/docs/ANALYTICS-SYSTEM.md +150 -0
  126. package/docs/FULL-README.md +2 -2
  127. package/hooks/keyword-detector.sh +1 -1
  128. package/package.json +1 -1
  129. package/scripts/keyword-detector.mjs +1 -1
  130. package/scripts/persistent-mode.mjs +1 -1
  131. package/scripts/test-mutual-exclusion.ts +4 -4
  132. package/scripts/test-remember-tags.ts +6 -6
  133. package/scripts/test-session-injection.ts +4 -4
  134. package/skills/cancel-ultraqa/SKILL.md +1 -1
  135. package/skills/omc-setup/SKILL.md +30 -5
@@ -0,0 +1,106 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { estimateOutputTokens, extractSessionId } from '../../analytics/output-estimator.js';
3
+ describe('OutputEstimator', () => {
4
+ describe('estimateOutputTokens', () => {
5
+ it('should estimate Haiku output tokens (30% ratio)', () => {
6
+ const estimate = estimateOutputTokens(1000, 'claude-haiku-4-5-20251001');
7
+ expect(estimate).toBe(300); // 1000 * 0.30
8
+ });
9
+ it('should estimate Sonnet output tokens (40% ratio)', () => {
10
+ const estimate = estimateOutputTokens(1000, 'claude-sonnet-4-5-20250929');
11
+ expect(estimate).toBe(400); // 1000 * 0.40
12
+ });
13
+ it('should estimate Opus output tokens (50% ratio)', () => {
14
+ const estimate = estimateOutputTokens(1000, 'claude-opus-4-5-20251101');
15
+ expect(estimate).toBe(500); // 1000 * 0.50
16
+ });
17
+ it('should use default ratio for unknown models', () => {
18
+ const estimate = estimateOutputTokens(1000, 'claude-unknown-model');
19
+ expect(estimate).toBe(400); // Default to Sonnet 40%
20
+ });
21
+ it('should handle zero input tokens', () => {
22
+ const estimate = estimateOutputTokens(0, 'claude-sonnet-4-5-20250929');
23
+ expect(estimate).toBe(0);
24
+ });
25
+ it('should round to nearest integer', () => {
26
+ // 1000 * 0.30 = 300 (exact)
27
+ expect(estimateOutputTokens(1000, 'claude-haiku-4-5-20251001')).toBe(300);
28
+ // 1001 * 0.30 = 300.3 -> rounds to 300
29
+ expect(estimateOutputTokens(1001, 'claude-haiku-4-5-20251001')).toBe(300);
30
+ // 1005 * 0.30 = 301.5 -> rounds to 302
31
+ expect(estimateOutputTokens(1005, 'claude-haiku-4-5-20251001')).toBe(302);
32
+ });
33
+ it('should be case-insensitive for model names', () => {
34
+ expect(estimateOutputTokens(1000, 'CLAUDE-HAIKU-4-5-20251001')).toBe(300);
35
+ expect(estimateOutputTokens(1000, 'Claude-Sonnet-4-5-20250929')).toBe(400);
36
+ expect(estimateOutputTokens(1000, 'claude-OPUS-4-5-20251101')).toBe(500);
37
+ });
38
+ it('should handle various model name formats', () => {
39
+ // Different date formats
40
+ expect(estimateOutputTokens(1000, 'claude-haiku-4')).toBe(300);
41
+ expect(estimateOutputTokens(1000, 'claude-sonnet-4.5')).toBe(400);
42
+ expect(estimateOutputTokens(1000, 'claude-opus-4')).toBe(500);
43
+ });
44
+ it('should handle large token counts', () => {
45
+ const estimate = estimateOutputTokens(1_000_000, 'claude-sonnet-4-5-20250929');
46
+ expect(estimate).toBe(400_000); // 1,000,000 * 0.40
47
+ });
48
+ it('should handle fractional results', () => {
49
+ // 333 * 0.40 = 133.2 -> rounds to 133
50
+ const estimate = estimateOutputTokens(333, 'claude-sonnet-4-5-20250929');
51
+ expect(estimate).toBe(133);
52
+ });
53
+ });
54
+ describe('extractSessionId', () => {
55
+ it('should extract session ID from standard path', () => {
56
+ const path = '/home/user/.claude/projects/abcdef123456/transcript.jsonl';
57
+ const sessionId = extractSessionId(path);
58
+ expect(sessionId).toBe('abcdef123456');
59
+ });
60
+ it('should extract longer session IDs', () => {
61
+ const path = '/home/user/.claude/projects/a1b2c3d4e5f6abcd/transcript.jsonl';
62
+ const sessionId = extractSessionId(path);
63
+ expect(sessionId).toBe('a1b2c3d4e5f6abcd');
64
+ });
65
+ it('should handle uppercase session IDs', () => {
66
+ const path = '/home/user/.claude/projects/ABCDEF123456/transcript.jsonl';
67
+ const sessionId = extractSessionId(path);
68
+ expect(sessionId).toBe('ABCDEF123456');
69
+ });
70
+ it('should handle mixed case session IDs', () => {
71
+ const path = '/home/user/.claude/projects/AbCdEf123456/transcript.jsonl';
72
+ const sessionId = extractSessionId(path);
73
+ expect(sessionId).toBe('AbCdEf123456');
74
+ });
75
+ it('should fallback to hash for non-standard paths', () => {
76
+ const path = '/some/random/path/transcript.jsonl';
77
+ const sessionId = extractSessionId(path);
78
+ // Should be 16-char hex hash
79
+ expect(sessionId).toMatch(/^[a-f0-9]{16}$/i);
80
+ });
81
+ it('should be consistent for same non-standard path', () => {
82
+ const path = '/some/random/path/transcript.jsonl';
83
+ const sessionId1 = extractSessionId(path);
84
+ const sessionId2 = extractSessionId(path);
85
+ expect(sessionId1).toBe(sessionId2);
86
+ });
87
+ it('should produce different hashes for different paths', () => {
88
+ const path1 = '/path/one/transcript.jsonl';
89
+ const path2 = '/path/two/transcript.jsonl';
90
+ const hash1 = extractSessionId(path1);
91
+ const hash2 = extractSessionId(path2);
92
+ expect(hash1).not.toBe(hash2);
93
+ });
94
+ it('should handle very long paths', () => {
95
+ const longPath = '/very/long/path/with/many/.claude/projects/a1b2c3d4e5f6abcd/and/more/directories/transcript.jsonl';
96
+ const sessionId = extractSessionId(longPath);
97
+ expect(sessionId).toBe('a1b2c3d4e5f6abcd');
98
+ });
99
+ it('should match first projects/ pattern', () => {
100
+ const path = '/home/.claude/projects/a1b2c3d412345678/other/projects/a1b2c3d487654321/transcript.jsonl';
101
+ const sessionId = extractSessionId(path);
102
+ expect(sessionId).toBe('a1b2c3d412345678');
103
+ });
104
+ });
105
+ });
106
+ //# sourceMappingURL=output-estimator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-estimator.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/output-estimator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=token-extractor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-extractor.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/token-extractor.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { extractTokens, createSnapshot } from '../../analytics/token-extractor.js';
3
+ describe('TokenExtractor', () => {
4
+ let mockStdin;
5
+ beforeEach(() => {
6
+ mockStdin = {
7
+ transcript_path: '/path/to/transcript.jsonl',
8
+ cwd: '/home/user',
9
+ model: {
10
+ id: 'claude-sonnet-4-5-20250929',
11
+ display_name: 'Claude Sonnet 4.5'
12
+ },
13
+ context_window: {
14
+ context_window_size: 200000,
15
+ used_percentage: 35,
16
+ current_usage: {
17
+ input_tokens: 1000,
18
+ cache_creation_input_tokens: 500,
19
+ cache_read_input_tokens: 2000
20
+ }
21
+ }
22
+ };
23
+ });
24
+ describe('extractTokens', () => {
25
+ it('should extract tokens from StatuslineStdin without previous snapshot', () => {
26
+ const result = extractTokens(mockStdin, null, 'claude-sonnet-4-5-20250929');
27
+ expect(result.inputTokens).toBe(1000);
28
+ expect(result.cacheCreationTokens).toBe(500);
29
+ expect(result.cacheReadTokens).toBe(2000);
30
+ expect(result.modelName).toBe('claude-sonnet-4-5-20250929');
31
+ expect(result.isEstimated).toBe(true);
32
+ expect(result.timestamp).toBeDefined();
33
+ expect(result.agentName).toBeUndefined();
34
+ });
35
+ it('should calculate correct deltas with previous snapshot', () => {
36
+ const previousSnapshot = {
37
+ inputTokens: 600,
38
+ cacheCreationTokens: 200,
39
+ cacheReadTokens: 1000,
40
+ timestamp: '2026-01-24T00:00:00.000Z'
41
+ };
42
+ const result = extractTokens(mockStdin, previousSnapshot, 'claude-sonnet-4-5-20250929');
43
+ // Deltas: current - previous
44
+ expect(result.inputTokens).toBe(400); // 1000 - 600
45
+ expect(result.cacheCreationTokens).toBe(300); // 500 - 200
46
+ expect(result.cacheReadTokens).toBe(1000); // 2000 - 1000
47
+ });
48
+ it('should estimate output tokens for Haiku (30% ratio)', () => {
49
+ const result = extractTokens(mockStdin, null, 'claude-haiku-4-5-20251001');
50
+ // 1000 input tokens * 30% = 300
51
+ expect(result.outputTokens).toBe(300);
52
+ });
53
+ it('should estimate output tokens for Sonnet (40% ratio)', () => {
54
+ const result = extractTokens(mockStdin, null, 'claude-sonnet-4-5-20250929');
55
+ // 1000 input tokens * 40% = 400
56
+ expect(result.outputTokens).toBe(400);
57
+ });
58
+ it('should estimate output tokens for Opus (50% ratio)', () => {
59
+ const result = extractTokens(mockStdin, null, 'claude-opus-4-5-20251101');
60
+ // 1000 input tokens * 50% = 500
61
+ expect(result.outputTokens).toBe(500);
62
+ });
63
+ it('should handle zero output tokens correctly', () => {
64
+ mockStdin.context_window.current_usage = {
65
+ input_tokens: 0,
66
+ cache_creation_input_tokens: 0,
67
+ cache_read_input_tokens: 0
68
+ };
69
+ const result = extractTokens(mockStdin, null, 'claude-sonnet-4-5-20250929');
70
+ expect(result.outputTokens).toBe(0);
71
+ expect(result.inputTokens).toBe(0);
72
+ });
73
+ it('should include agentName when provided', () => {
74
+ const result = extractTokens(mockStdin, null, 'claude-sonnet-4-5-20250929', 'test-agent');
75
+ expect(result.agentName).toBe('test-agent');
76
+ });
77
+ it('should handle missing usage data gracefully', () => {
78
+ mockStdin.context_window.current_usage = undefined;
79
+ const result = extractTokens(mockStdin, null, 'claude-sonnet-4-5-20250929');
80
+ expect(result.inputTokens).toBe(0);
81
+ expect(result.outputTokens).toBe(0);
82
+ expect(result.cacheCreationTokens).toBe(0);
83
+ expect(result.cacheReadTokens).toBe(0);
84
+ });
85
+ it('should ensure non-negative deltas', () => {
86
+ const previousSnapshot = {
87
+ inputTokens: 2000, // Greater than current
88
+ cacheCreationTokens: 1000,
89
+ cacheReadTokens: 3000,
90
+ timestamp: '2026-01-24T00:00:00.000Z'
91
+ };
92
+ const result = extractTokens(mockStdin, previousSnapshot, 'claude-sonnet-4-5-20250929');
93
+ // Should clamp to 0 if delta is negative
94
+ expect(result.inputTokens).toBe(0); // max(0, 1000 - 2000)
95
+ });
96
+ });
97
+ describe('createSnapshot', () => {
98
+ it('should create snapshot from current usage', () => {
99
+ const snapshot = createSnapshot(mockStdin);
100
+ expect(snapshot.inputTokens).toBe(1000);
101
+ expect(snapshot.cacheCreationTokens).toBe(500);
102
+ expect(snapshot.cacheReadTokens).toBe(2000);
103
+ expect(snapshot.timestamp).toBeDefined();
104
+ });
105
+ it('should handle missing usage data in snapshot', () => {
106
+ mockStdin.context_window.current_usage = undefined;
107
+ const snapshot = createSnapshot(mockStdin);
108
+ expect(snapshot.inputTokens).toBe(0);
109
+ expect(snapshot.cacheCreationTokens).toBe(0);
110
+ expect(snapshot.cacheReadTokens).toBe(0);
111
+ });
112
+ it('should create fresh timestamp for each snapshot', () => {
113
+ const snapshot1 = createSnapshot(mockStdin);
114
+ const snapshot2 = createSnapshot(mockStdin);
115
+ // Timestamps should be different (or very close if fast)
116
+ expect(snapshot1.timestamp).toBeDefined();
117
+ expect(snapshot2.timestamp).toBeDefined();
118
+ });
119
+ });
120
+ });
121
+ //# sourceMappingURL=token-extractor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-extractor.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/token-extractor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transcript-parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-parser.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/transcript-parser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,285 @@
1
+ import { vi, describe, it, expect } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import { join } from 'path';
4
+ import { parseTranscript, loadTranscript } from '../../analytics/transcript-parser.js';
5
+ describe('transcript-parser', () => {
6
+ const fixturesDir = join(__dirname, '..', 'fixtures');
7
+ const sampleTranscriptPath = join(fixturesDir, 'sample-transcript.jsonl');
8
+ describe('parseTranscript()', () => {
9
+ it('yields entries in order', async () => {
10
+ const entries = [];
11
+ for await (const entry of parseTranscript(sampleTranscriptPath)) {
12
+ entries.push(entry);
13
+ }
14
+ expect(entries).toHaveLength(5);
15
+ // Verify order is preserved
16
+ expect(entries[0]).toMatchObject({
17
+ type: 'assistant',
18
+ sessionId: 'test-session-1',
19
+ timestamp: '2026-01-24T01:00:00.000Z',
20
+ });
21
+ expect(entries[1]).toMatchObject({
22
+ type: 'assistant',
23
+ sessionId: 'test-session-1',
24
+ timestamp: '2026-01-24T01:01:00.000Z',
25
+ });
26
+ expect(entries[4]).toMatchObject({
27
+ type: 'assistant',
28
+ sessionId: 'test-session-1',
29
+ timestamp: '2026-01-24T01:03:00.000Z',
30
+ });
31
+ });
32
+ it('parses usage data correctly', async () => {
33
+ const entries = [];
34
+ for await (const entry of parseTranscript(sampleTranscriptPath)) {
35
+ entries.push(entry);
36
+ }
37
+ const firstEntry = entries[0];
38
+ expect(firstEntry.message.usage).toEqual({
39
+ input_tokens: 100,
40
+ output_tokens: 50,
41
+ cache_creation_input_tokens: 0,
42
+ cache_read_input_tokens: 0,
43
+ });
44
+ const secondEntry = entries[1];
45
+ expect(secondEntry.message.usage).toEqual({
46
+ input_tokens: 200,
47
+ output_tokens: 80,
48
+ cache_creation_input_tokens: 500,
49
+ cache_read_input_tokens: 1000,
50
+ });
51
+ });
52
+ it('handles malformed JSON lines gracefully with default warning', async () => {
53
+ const tempPath = join(fixturesDir, 'malformed-test.jsonl');
54
+ const content = [
55
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:00:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":10,"output_tokens":5,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
56
+ 'INVALID JSON LINE',
57
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:01:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":20,"output_tokens":10,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
58
+ ].join('\n');
59
+ fs.writeFileSync(tempPath, content);
60
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
61
+ try {
62
+ const entries = [];
63
+ for await (const entry of parseTranscript(tempPath)) {
64
+ entries.push(entry);
65
+ }
66
+ expect(entries).toHaveLength(2);
67
+ expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('[transcript-parser] Skipping malformed line'));
68
+ }
69
+ finally {
70
+ consoleWarnSpy.mockRestore();
71
+ fs.unlinkSync(tempPath);
72
+ }
73
+ });
74
+ it('handles malformed JSON lines gracefully with custom error handler', async () => {
75
+ const tempPath = join(fixturesDir, 'malformed-custom-test.jsonl');
76
+ const content = [
77
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:00:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":10,"output_tokens":5,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
78
+ 'INVALID JSON LINE',
79
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:01:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":20,"output_tokens":10,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
80
+ ].join('\n');
81
+ fs.writeFileSync(tempPath, content);
82
+ const errors = [];
83
+ const onParseError = (line, error) => {
84
+ errors.push({ line, error });
85
+ };
86
+ try {
87
+ const entries = [];
88
+ for await (const entry of parseTranscript(tempPath, { onParseError })) {
89
+ entries.push(entry);
90
+ }
91
+ expect(entries).toHaveLength(2);
92
+ expect(errors).toHaveLength(1);
93
+ expect(errors[0].line).toBe('INVALID JSON LINE');
94
+ expect(errors[0].error).toBeInstanceOf(Error);
95
+ }
96
+ finally {
97
+ fs.unlinkSync(tempPath);
98
+ }
99
+ });
100
+ it('respects AbortSignal', async () => {
101
+ const controller = new AbortController();
102
+ const entries = [];
103
+ let count = 0;
104
+ for await (const entry of parseTranscript(sampleTranscriptPath, {
105
+ signal: controller.signal,
106
+ })) {
107
+ entries.push(entry);
108
+ count++;
109
+ if (count === 2) {
110
+ controller.abort();
111
+ }
112
+ }
113
+ expect(entries.length).toBeLessThan(5); // Should stop early
114
+ expect(entries).toHaveLength(2);
115
+ });
116
+ it('handles empty files', async () => {
117
+ const tempPath = join(fixturesDir, 'empty-test.jsonl');
118
+ fs.writeFileSync(tempPath, '');
119
+ try {
120
+ const entries = [];
121
+ for await (const entry of parseTranscript(tempPath)) {
122
+ entries.push(entry);
123
+ }
124
+ expect(entries).toHaveLength(0);
125
+ }
126
+ finally {
127
+ fs.unlinkSync(tempPath);
128
+ }
129
+ });
130
+ it('handles files with only empty lines', async () => {
131
+ const tempPath = join(fixturesDir, 'empty-lines-test.jsonl');
132
+ fs.writeFileSync(tempPath, '\n\n\n\n');
133
+ try {
134
+ const entries = [];
135
+ for await (const entry of parseTranscript(tempPath)) {
136
+ entries.push(entry);
137
+ }
138
+ expect(entries).toHaveLength(0);
139
+ }
140
+ finally {
141
+ fs.unlinkSync(tempPath);
142
+ }
143
+ });
144
+ it('throws if file does not exist', async () => {
145
+ const nonExistentPath = join(fixturesDir, 'non-existent.jsonl');
146
+ await expect(async () => {
147
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
148
+ for await (const entry of parseTranscript(nonExistentPath)) {
149
+ // Should not reach here
150
+ }
151
+ }).rejects.toThrow('Transcript file not found');
152
+ });
153
+ it('handles files with whitespace lines', async () => {
154
+ const tempPath = join(fixturesDir, 'whitespace-test.jsonl');
155
+ const content = [
156
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:00:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":10,"output_tokens":5,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
157
+ ' ',
158
+ '\t\t',
159
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:01:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":20,"output_tokens":10,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
160
+ ].join('\n');
161
+ fs.writeFileSync(tempPath, content);
162
+ try {
163
+ const entries = [];
164
+ for await (const entry of parseTranscript(tempPath)) {
165
+ entries.push(entry);
166
+ }
167
+ expect(entries).toHaveLength(2);
168
+ }
169
+ finally {
170
+ fs.unlinkSync(tempPath);
171
+ }
172
+ });
173
+ it('streams large files efficiently without loading all into memory', async () => {
174
+ // Create a large file with many entries
175
+ const tempPath = join(fixturesDir, 'large-test.jsonl');
176
+ const entryTemplate = {
177
+ type: 'assistant',
178
+ sessionId: 'large-test',
179
+ timestamp: '2026-01-24T00:00:00.000Z',
180
+ message: {
181
+ model: 'claude-sonnet-4-5-20250929',
182
+ role: 'assistant',
183
+ usage: {
184
+ input_tokens: 100,
185
+ output_tokens: 50,
186
+ cache_creation_input_tokens: 0,
187
+ cache_read_input_tokens: 0,
188
+ },
189
+ },
190
+ };
191
+ // Write 10,000 entries
192
+ const writeStream = fs.createWriteStream(tempPath);
193
+ for (let i = 0; i < 10000; i++) {
194
+ writeStream.write(JSON.stringify(entryTemplate) + '\n');
195
+ }
196
+ writeStream.end();
197
+ // Wait for write to complete
198
+ await new Promise((resolve) => writeStream.on('finish', resolve));
199
+ try {
200
+ let count = 0;
201
+ const startMemory = process.memoryUsage().heapUsed;
202
+ for await (const entry of parseTranscript(tempPath)) {
203
+ count++;
204
+ expect(entry.type).toBe('assistant');
205
+ // Check memory hasn't grown excessively (allow some growth for overhead)
206
+ if (count % 1000 === 0) {
207
+ const currentMemory = process.memoryUsage().heapUsed;
208
+ const memoryGrowth = currentMemory - startMemory;
209
+ // Should not grow by more than 50MB for streaming
210
+ expect(memoryGrowth).toBeLessThan(50 * 1024 * 1024);
211
+ }
212
+ }
213
+ expect(count).toBe(10000);
214
+ }
215
+ finally {
216
+ fs.unlinkSync(tempPath);
217
+ }
218
+ });
219
+ it('cleans up resources on abort', async () => {
220
+ const controller = new AbortController();
221
+ // Start parsing
222
+ const generator = parseTranscript(sampleTranscriptPath, {
223
+ signal: controller.signal,
224
+ });
225
+ // Get first entry
226
+ await generator.next();
227
+ // Abort immediately
228
+ controller.abort();
229
+ // Try to get next entry
230
+ const result = await generator.next();
231
+ expect(result.done).toBe(true);
232
+ });
233
+ });
234
+ describe('loadTranscript()', () => {
235
+ it('loads all entries into memory', async () => {
236
+ const entries = await loadTranscript(sampleTranscriptPath);
237
+ expect(entries).toHaveLength(5);
238
+ expect(entries[0].sessionId).toBe('test-session-1');
239
+ });
240
+ it('respects AbortSignal', async () => {
241
+ const controller = new AbortController();
242
+ // Abort after a short delay
243
+ setTimeout(() => controller.abort(), 10);
244
+ const entries = await loadTranscript(sampleTranscriptPath, {
245
+ signal: controller.signal,
246
+ });
247
+ // May or may not complete depending on timing, but should not throw
248
+ expect(Array.isArray(entries)).toBe(true);
249
+ });
250
+ it('handles custom error handler', async () => {
251
+ const tempPath = join(fixturesDir, 'malformed-load-test.jsonl');
252
+ const content = [
253
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:00:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":10,"output_tokens":5,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
254
+ 'INVALID',
255
+ '{"type":"assistant","sessionId":"test","timestamp":"2026-01-24T00:01:00.000Z","message":{"model":"claude-sonnet-4-5-20250929","role":"assistant","usage":{"input_tokens":20,"output_tokens":10,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}',
256
+ ].join('\n');
257
+ fs.writeFileSync(tempPath, content);
258
+ const errors = [];
259
+ const onParseError = (line) => {
260
+ errors.push(line);
261
+ };
262
+ try {
263
+ const entries = await loadTranscript(tempPath, { onParseError });
264
+ expect(entries).toHaveLength(2);
265
+ expect(errors).toHaveLength(1);
266
+ expect(errors[0]).toBe('INVALID');
267
+ }
268
+ finally {
269
+ fs.unlinkSync(tempPath);
270
+ }
271
+ });
272
+ it('returns empty array for empty file', async () => {
273
+ const tempPath = join(fixturesDir, 'empty-load-test.jsonl');
274
+ fs.writeFileSync(tempPath, '');
275
+ try {
276
+ const entries = await loadTranscript(tempPath);
277
+ expect(entries).toEqual([]);
278
+ }
279
+ finally {
280
+ fs.unlinkSync(tempPath);
281
+ }
282
+ });
283
+ });
284
+ });
285
+ //# sourceMappingURL=transcript-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-parser.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/transcript-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transcript-scanner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-scanner.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/transcript-scanner.test.ts"],"names":[],"mappings":""}