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,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":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE7F,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC;YACzE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;YAC1E,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC;YACxE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;YACpE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,wBAAwB;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;YACvE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,4BAA4B;YAC5B,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE1E,uCAAuC;YACvC,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE1E,uCAAuC;YACvC,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1E,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3E,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,yBAAyB;YACzB,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClE,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC;YAC/E,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,sCAAsC;YACtC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,EAAE,4BAA4B,CAAC,CAAC;YACzE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,IAAI,GAAG,2DAA2D,CAAC;YACzE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,IAAI,GAAG,+DAA+D,CAAC;YAC7E,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,IAAI,GAAG,2DAA2D,CAAC;YACzE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,IAAI,GAAG,2DAA2D,CAAC;YACzE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,IAAI,GAAG,oCAAoC,CAAC;YAClD,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAEzC,6BAA6B;YAC7B,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,IAAI,GAAG,oCAAoC,CAAC;YAClD,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAE1C,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,KAAK,GAAG,4BAA4B,CAAC;YAC3C,MAAM,KAAK,GAAG,4BAA4B,CAAC;YAE3C,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAEtC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,QAAQ,GAAG,mGAAmG,CAAC;YACrH,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,IAAI,GAAG,0FAA0F,CAAC;YACxG,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAEzC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -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":""}