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,57 @@
1
+ import { estimateOutputTokens } from './output-estimator.js';
2
+ /**
3
+ * Extract token usage from StatuslineStdin and calculate delta from previous snapshot.
4
+ */
5
+ export function extractTokens(stdin, previousSnapshot, modelName, agentName) {
6
+ const currentUsage = stdin.context_window.current_usage;
7
+ if (!currentUsage) {
8
+ return createEmptyExtraction(modelName, agentName);
9
+ }
10
+ // Calculate deltas
11
+ const inputDelta = previousSnapshot
12
+ ? currentUsage.input_tokens - previousSnapshot.inputTokens
13
+ : currentUsage.input_tokens;
14
+ const cacheDelta = previousSnapshot
15
+ ? currentUsage.cache_creation_input_tokens - previousSnapshot.cacheCreationTokens
16
+ : currentUsage.cache_creation_input_tokens;
17
+ const cacheReadDelta = previousSnapshot
18
+ ? currentUsage.cache_read_input_tokens - previousSnapshot.cacheReadTokens
19
+ : currentUsage.cache_read_input_tokens;
20
+ // Estimate output tokens (from output-estimator.ts)
21
+ const outputTokens = estimateOutputTokens(inputDelta, modelName);
22
+ return {
23
+ inputTokens: Math.max(0, inputDelta),
24
+ outputTokens,
25
+ cacheCreationTokens: Math.max(0, cacheDelta),
26
+ cacheReadTokens: Math.max(0, cacheReadDelta),
27
+ modelName,
28
+ agentName,
29
+ isEstimated: true,
30
+ timestamp: new Date().toISOString()
31
+ };
32
+ }
33
+ /**
34
+ * Create current snapshot for next delta calculation.
35
+ */
36
+ export function createSnapshot(stdin) {
37
+ const usage = stdin.context_window.current_usage;
38
+ return {
39
+ inputTokens: usage?.input_tokens ?? 0,
40
+ cacheCreationTokens: usage?.cache_creation_input_tokens ?? 0,
41
+ cacheReadTokens: usage?.cache_read_input_tokens ?? 0,
42
+ timestamp: new Date().toISOString()
43
+ };
44
+ }
45
+ function createEmptyExtraction(modelName, agentName) {
46
+ return {
47
+ inputTokens: 0,
48
+ outputTokens: 0,
49
+ cacheCreationTokens: 0,
50
+ cacheReadTokens: 0,
51
+ modelName,
52
+ agentName,
53
+ isEstimated: true,
54
+ timestamp: new Date().toISOString()
55
+ };
56
+ }
57
+ //# sourceMappingURL=token-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-extractor.js","sourceRoot":"","sources":["../../src/analytics/token-extractor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AA0B7D;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAsB,EACtB,gBAAsC,EACtC,SAAiB,EACjB,SAAkB;IAElB,MAAM,YAAY,GAAG,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;IAExD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,qBAAqB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,mBAAmB;IACnB,MAAM,UAAU,GAAG,gBAAgB;QACjC,CAAC,CAAC,YAAY,CAAC,YAAY,GAAG,gBAAgB,CAAC,WAAW;QAC1D,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC;IAE9B,MAAM,UAAU,GAAG,gBAAgB;QACjC,CAAC,CAAC,YAAY,CAAC,2BAA2B,GAAG,gBAAgB,CAAC,mBAAmB;QACjF,CAAC,CAAC,YAAY,CAAC,2BAA2B,CAAC;IAE7C,MAAM,cAAc,GAAG,gBAAgB;QACrC,CAAC,CAAC,YAAY,CAAC,uBAAuB,GAAG,gBAAgB,CAAC,eAAe;QACzE,CAAC,CAAC,YAAY,CAAC,uBAAuB,CAAC;IAEzC,oDAAoD;IACpD,MAAM,YAAY,GAAG,oBAAoB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAEjE,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;QACpC,YAAY;QACZ,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;QAC5C,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC;QAC5C,SAAS;QACT,SAAS;QACT,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAsB;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;IAEjD,OAAO;QACL,WAAW,EAAE,KAAK,EAAE,YAAY,IAAI,CAAC;QACrC,mBAAmB,EAAE,KAAK,EAAE,2BAA2B,IAAI,CAAC;QAC5D,eAAe,EAAE,KAAK,EAAE,uBAAuB,IAAI,CAAC;QACpD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,SAAkB;IAClE,OAAO;QACL,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,mBAAmB,EAAE,CAAC;QACtB,eAAe,EAAE,CAAC;QAClB,SAAS;QACT,SAAS;QACT,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
- import { TokenUsage, SessionTokenStats } from './types.js';
1
+ import { TokenUsage, SessionTokenStats, AggregateTokenStats } from './types.js';
2
2
  export declare class TokenTracker {
3
3
  private currentSessionId;
4
4
  private sessionStats;
@@ -12,6 +12,12 @@ export declare class TokenTracker {
12
12
  loadSessionStats(sessionId?: string): Promise<SessionTokenStats | null>;
13
13
  private rebuildStatsFromLog;
14
14
  getSessionStats(): SessionTokenStats;
15
+ getAllStats(): Promise<AggregateTokenStats>;
16
+ getTopAgentsAllSessions(limit?: number): Promise<Array<{
17
+ agent: string;
18
+ tokens: number;
19
+ cost: number;
20
+ }>>;
15
21
  getTopAgents(limit?: number): Promise<Array<{
16
22
  agent: string;
17
23
  tokens: number;
@@ -1 +1 @@
1
- {"version":3,"file":"token-tracker.d.ts","sourceRoot":"","sources":["../../src/analytics/token-tracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAO3D,qBAAa,YAAY;IACvB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,YAAY,CAAoB;gBAE5B,SAAS,CAAC,EAAE,MAAM;IAK9B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,sBAAsB;IAexB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAiB3E,WAAW;IAQzB,OAAO,CAAC,kBAAkB;YAsBZ,gBAAgB;IAIxB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAe/D,mBAAmB;IAsBjC,eAAe,IAAI,iBAAiB;IAI9B,YAAY,CAAC,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAsBhG,cAAc,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CA4BlE;AAKD,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAKhE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAGlE"}
1
+ {"version":3,"file":"token-tracker.d.ts","sourceRoot":"","sources":["../../src/analytics/token-tracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQhF,qBAAa,YAAY;IACvB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,YAAY,CAAoB;gBAE5B,SAAS,CAAC,EAAE,MAAM;IAK9B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,sBAAsB;IAexB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAiB3E,WAAW;IAOzB,OAAO,CAAC,kBAAkB;YAqBZ,gBAAgB;IAIxB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAe/D,mBAAmB;IAoBjC,eAAe,IAAI,iBAAiB;IAI9B,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAkF3C,uBAAuB,CAAC,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAY3G,YAAY,CAAC,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAsBhG,cAAc,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CA2BlE;AAKD,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAKhE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAGlE"}
@@ -1,8 +1,9 @@
1
1
  import { readState, writeState, StateLocation } from '../features/state-manager/index.js';
2
2
  import * as fs from 'fs/promises';
3
3
  import * as path from 'path';
4
- const TOKEN_LOG_FILE = '.omc/state/token-tracking.jsonl';
5
- const SESSION_STATS_FILE = '.omc/state/session-token-stats.json';
4
+ import { homedir } from 'os';
5
+ const TOKEN_LOG_FILE = path.join(homedir(), '.omc', 'state', 'token-tracking.jsonl');
6
+ const SESSION_STATS_FILE = path.join(homedir(), '.omc', 'state', 'session-token-stats.json');
6
7
  export class TokenTracker {
7
8
  currentSessionId;
8
9
  sessionStats;
@@ -41,10 +42,9 @@ export class TokenTracker {
41
42
  await this.saveSessionStats();
42
43
  }
43
44
  async appendToLog(record) {
44
- const logPath = path.resolve(process.cwd(), TOKEN_LOG_FILE);
45
- const logDir = path.dirname(logPath);
45
+ const logDir = path.dirname(TOKEN_LOG_FILE);
46
46
  await fs.mkdir(logDir, { recursive: true });
47
- await fs.appendFile(logPath, JSON.stringify(record) + '\n', 'utf-8');
47
+ await fs.appendFile(TOKEN_LOG_FILE, JSON.stringify(record) + '\n', 'utf-8');
48
48
  }
49
49
  updateSessionStats(record) {
50
50
  this.sessionStats.totalInputTokens += record.inputTokens;
@@ -52,13 +52,12 @@ export class TokenTracker {
52
52
  this.sessionStats.totalCacheCreation += record.cacheCreationTokens;
53
53
  this.sessionStats.totalCacheRead += record.cacheReadTokens;
54
54
  this.sessionStats.lastUpdate = record.timestamp;
55
- // Group by agent
56
- if (record.agentName) {
57
- if (!this.sessionStats.byAgent[record.agentName]) {
58
- this.sessionStats.byAgent[record.agentName] = [];
59
- }
60
- this.sessionStats.byAgent[record.agentName].push(record);
55
+ // Group by agent (use "(main session)" for entries without agentName)
56
+ const agentKey = record.agentName || '(main session)';
57
+ if (!this.sessionStats.byAgent[agentKey]) {
58
+ this.sessionStats.byAgent[agentKey] = [];
61
59
  }
60
+ this.sessionStats.byAgent[agentKey].push(record);
62
61
  // Group by model
63
62
  if (!this.sessionStats.byModel[record.modelName]) {
64
63
  this.sessionStats.byModel[record.modelName] = [];
@@ -66,12 +65,12 @@ export class TokenTracker {
66
65
  this.sessionStats.byModel[record.modelName].push(record);
67
66
  }
68
67
  async saveSessionStats() {
69
- writeState('session-token-stats', this.sessionStats, StateLocation.LOCAL);
68
+ writeState('session-token-stats', this.sessionStats, StateLocation.GLOBAL);
70
69
  }
71
70
  async loadSessionStats(sessionId) {
72
71
  const sid = sessionId || this.currentSessionId;
73
72
  // Try to load from state
74
- const result = readState('session-token-stats', StateLocation.LOCAL);
73
+ const result = readState('session-token-stats', StateLocation.GLOBAL);
75
74
  if (result.exists && result.data && result.data.sessionId === sid) {
76
75
  this.sessionStats = result.data;
77
76
  return result.data;
@@ -80,9 +79,8 @@ export class TokenTracker {
80
79
  return this.rebuildStatsFromLog(sid);
81
80
  }
82
81
  async rebuildStatsFromLog(sessionId) {
83
- const logPath = path.resolve(process.cwd(), TOKEN_LOG_FILE);
84
82
  try {
85
- const content = await fs.readFile(logPath, 'utf-8');
83
+ const content = await fs.readFile(TOKEN_LOG_FILE, 'utf-8');
86
84
  const lines = content.trim().split('\n');
87
85
  const stats = this.initializeSessionStats();
88
86
  stats.sessionId = sessionId;
@@ -101,6 +99,85 @@ export class TokenTracker {
101
99
  getSessionStats() {
102
100
  return { ...this.sessionStats };
103
101
  }
102
+ async getAllStats() {
103
+ const { calculateCost } = await import('./cost-estimator.js');
104
+ const stats = {
105
+ totalInputTokens: 0,
106
+ totalOutputTokens: 0,
107
+ totalCacheCreation: 0,
108
+ totalCacheRead: 0,
109
+ totalCost: 0,
110
+ byAgent: {},
111
+ byModel: {},
112
+ sessionCount: 0,
113
+ entryCount: 0,
114
+ firstEntry: null,
115
+ lastEntry: null
116
+ };
117
+ try {
118
+ const content = await fs.readFile(TOKEN_LOG_FILE, 'utf-8');
119
+ const lines = content.trim().split('\n').filter(line => line.trim());
120
+ if (lines.length === 0) {
121
+ return stats;
122
+ }
123
+ const sessions = new Set();
124
+ for (const line of lines) {
125
+ const record = JSON.parse(line);
126
+ stats.entryCount++;
127
+ // Track unique sessions
128
+ sessions.add(record.sessionId);
129
+ // Track timestamps
130
+ if (!stats.firstEntry || record.timestamp < stats.firstEntry) {
131
+ stats.firstEntry = record.timestamp;
132
+ }
133
+ if (!stats.lastEntry || record.timestamp > stats.lastEntry) {
134
+ stats.lastEntry = record.timestamp;
135
+ }
136
+ // Aggregate totals
137
+ stats.totalInputTokens += record.inputTokens;
138
+ stats.totalOutputTokens += record.outputTokens;
139
+ stats.totalCacheCreation += record.cacheCreationTokens;
140
+ stats.totalCacheRead += record.cacheReadTokens;
141
+ // Calculate cost for this record
142
+ const cost = calculateCost({
143
+ modelName: record.modelName,
144
+ inputTokens: record.inputTokens,
145
+ outputTokens: record.outputTokens,
146
+ cacheCreationTokens: record.cacheCreationTokens,
147
+ cacheReadTokens: record.cacheReadTokens
148
+ });
149
+ stats.totalCost += cost.totalCost;
150
+ // Aggregate by agent (use "(main session)" for entries without agentName)
151
+ const agentKey = record.agentName || '(main session)';
152
+ if (!stats.byAgent[agentKey]) {
153
+ stats.byAgent[agentKey] = { tokens: 0, cost: 0 };
154
+ }
155
+ stats.byAgent[agentKey].tokens += record.inputTokens + record.outputTokens;
156
+ stats.byAgent[agentKey].cost += cost.totalCost;
157
+ // Aggregate by model
158
+ if (!stats.byModel[record.modelName]) {
159
+ stats.byModel[record.modelName] = { tokens: 0, cost: 0 };
160
+ }
161
+ stats.byModel[record.modelName].tokens += record.inputTokens + record.outputTokens;
162
+ stats.byModel[record.modelName].cost += cost.totalCost;
163
+ }
164
+ stats.sessionCount = sessions.size;
165
+ return stats;
166
+ }
167
+ catch (error) {
168
+ // If file doesn't exist or is empty, return empty stats
169
+ return stats;
170
+ }
171
+ }
172
+ async getTopAgentsAllSessions(limit = 5) {
173
+ const allStats = await this.getAllStats();
174
+ const agentStats = Object.entries(allStats.byAgent).map(([agent, stats]) => ({
175
+ agent,
176
+ tokens: stats.tokens,
177
+ cost: stats.cost
178
+ }));
179
+ return agentStats.sort((a, b) => b.cost - a.cost).slice(0, limit);
180
+ }
104
181
  async getTopAgents(limit = 5) {
105
182
  const { calculateCost } = await import('./cost-estimator.js');
106
183
  const agentStats = Object.entries(this.sessionStats.byAgent).map(([agent, usages]) => {
@@ -120,11 +197,10 @@ export class TokenTracker {
120
197
  return agentStats.sort((a, b) => b.cost - a.cost).slice(0, limit);
121
198
  }
122
199
  async cleanupOldLogs(retentionDays = 30) {
123
- const logPath = path.resolve(process.cwd(), TOKEN_LOG_FILE);
124
200
  const cutoffDate = new Date();
125
201
  cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
126
202
  try {
127
- const content = await fs.readFile(logPath, 'utf-8');
203
+ const content = await fs.readFile(TOKEN_LOG_FILE, 'utf-8');
128
204
  const lines = content.trim().split('\n');
129
205
  let kept = 0;
130
206
  let removed = 0;
@@ -138,7 +214,7 @@ export class TokenTracker {
138
214
  removed++;
139
215
  return false;
140
216
  });
141
- await fs.writeFile(logPath, filteredLines.join('\n') + '\n', 'utf-8');
217
+ await fs.writeFile(TOKEN_LOG_FILE, filteredLines.join('\n') + '\n', 'utf-8');
142
218
  return removed;
143
219
  }
144
220
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"token-tracker.js","sourceRoot":"","sources":["../../src/analytics/token-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"token-tracker.js","sourceRoot":"","sources":["../../src/analytics/token-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { TranscriptEntry } from './types.js';
2
+ /**
3
+ * Options for transcript parsing.
4
+ */
5
+ export interface ParseTranscriptOptions {
6
+ /**
7
+ * AbortSignal to cancel parsing mid-stream.
8
+ */
9
+ signal?: AbortSignal;
10
+ /**
11
+ * Callback for parse errors (allows custom logging).
12
+ */
13
+ onParseError?: (line: string, error: Error) => void;
14
+ }
15
+ /**
16
+ * Streaming JSONL parser for transcript files.
17
+ * Parses line-by-line without loading the entire file into memory.
18
+ *
19
+ * @param filePath - Path to the transcript JSONL file
20
+ * @param options - Parsing options including AbortSignal
21
+ * @yields TranscriptEntry objects
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const controller = new AbortController();
26
+ * for await (const entry of parseTranscript('transcript.jsonl', { signal: controller.signal })) {
27
+ * console.log(entry);
28
+ * }
29
+ * ```
30
+ */
31
+ export declare function parseTranscript(filePath: string, options?: ParseTranscriptOptions): AsyncGenerator<TranscriptEntry>;
32
+ /**
33
+ * Load all entries from a transcript file into memory.
34
+ * Use this for smaller files or when you need all entries at once.
35
+ * For large files, prefer the streaming `parseTranscript()` generator.
36
+ *
37
+ * @param filePath - Path to the transcript JSONL file
38
+ * @param options - Parsing options
39
+ * @returns Array of all transcript entries
40
+ */
41
+ export declare function loadTranscript(filePath: string, options?: ParseTranscriptOptions): Promise<TranscriptEntry[]>;
42
+ //# sourceMappingURL=transcript-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-parser.d.ts","sourceRoot":"","sources":["../../src/analytics/transcript-parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAuB,eAAe,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,cAAc,CAAC,eAAe,CAAC,CA2DjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,EAAE,CAAC,CAQ5B"}
@@ -0,0 +1,90 @@
1
+ import * as fs from 'fs';
2
+ import * as readline from 'readline';
3
+ /**
4
+ * Streaming JSONL parser for transcript files.
5
+ * Parses line-by-line without loading the entire file into memory.
6
+ *
7
+ * @param filePath - Path to the transcript JSONL file
8
+ * @param options - Parsing options including AbortSignal
9
+ * @yields TranscriptEntry objects
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const controller = new AbortController();
14
+ * for await (const entry of parseTranscript('transcript.jsonl', { signal: controller.signal })) {
15
+ * console.log(entry);
16
+ * }
17
+ * ```
18
+ */
19
+ export async function* parseTranscript(filePath, options = {}) {
20
+ const { signal, onParseError } = options;
21
+ // Check if file exists
22
+ if (!fs.existsSync(filePath)) {
23
+ throw new Error(`Transcript file not found: ${filePath}`);
24
+ }
25
+ const fileStream = fs.createReadStream(filePath, { encoding: 'utf8' });
26
+ const rl = readline.createInterface({
27
+ input: fileStream,
28
+ crlfDelay: Infinity // Treat \r\n as single line break
29
+ });
30
+ // Handle abort signal
31
+ const abortHandler = () => {
32
+ rl.close();
33
+ fileStream.destroy();
34
+ };
35
+ if (signal) {
36
+ signal.addEventListener('abort', abortHandler);
37
+ }
38
+ try {
39
+ for await (const line of rl) {
40
+ // Check abort before processing each line
41
+ if (signal?.aborted) {
42
+ break;
43
+ }
44
+ // Skip empty lines
45
+ if (!line.trim()) {
46
+ continue;
47
+ }
48
+ try {
49
+ const entry = JSON.parse(line);
50
+ yield entry;
51
+ }
52
+ catch (error) {
53
+ // Handle malformed JSON gracefully
54
+ const parseError = error instanceof Error ? error : new Error(String(error));
55
+ if (onParseError) {
56
+ onParseError(line, parseError);
57
+ }
58
+ else {
59
+ // Default: log warning and skip line
60
+ console.warn(`[transcript-parser] Skipping malformed line: ${parseError.message}`);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ finally {
66
+ // Clean up
67
+ if (signal) {
68
+ signal.removeEventListener('abort', abortHandler);
69
+ }
70
+ rl.close();
71
+ fileStream.destroy();
72
+ }
73
+ }
74
+ /**
75
+ * Load all entries from a transcript file into memory.
76
+ * Use this for smaller files or when you need all entries at once.
77
+ * For large files, prefer the streaming `parseTranscript()` generator.
78
+ *
79
+ * @param filePath - Path to the transcript JSONL file
80
+ * @param options - Parsing options
81
+ * @returns Array of all transcript entries
82
+ */
83
+ export async function loadTranscript(filePath, options = {}) {
84
+ const entries = [];
85
+ for await (const entry of parseTranscript(filePath, options)) {
86
+ entries.push(entry);
87
+ }
88
+ return entries;
89
+ }
90
+ //# sourceMappingURL=transcript-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-parser.js","sourceRoot":"","sources":["../../src/analytics/transcript-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAkBrC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,eAAe,CACpC,QAAgB,EAChB,UAAkC,EAAE;IAEpC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAEzC,uBAAuB;IACvB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,UAAU;QACjB,SAAS,EAAE,QAAQ,CAAC,kCAAkC;KACvD,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,UAAU,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;YAC5B,0CAA0C;YAC1C,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACpB,MAAM;YACR,CAAC;YAED,mBAAmB;YACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;gBAClD,MAAM,KAAK,CAAC;YACd,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,mCAAmC;gBACnC,MAAM,UAAU,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAE7E,IAAI,YAAY,EAAE,CAAC;oBACjB,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACjC,CAAC;qBAAM,CAAC;oBACN,qCAAqC;oBACrC,OAAO,CAAC,IAAI,CAAC,gDAAgD,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrF,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,WAAW;QACX,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACpD,CAAC;QACD,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,UAAU,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,UAAkC,EAAE;IAEpC,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Metadata for a discovered transcript file
3
+ */
4
+ export interface TranscriptFile {
5
+ projectPath: string;
6
+ projectDir: string;
7
+ sessionId: string;
8
+ filePath: string;
9
+ fileSize: number;
10
+ modifiedTime: Date;
11
+ }
12
+ /**
13
+ * Result of scanning for transcripts
14
+ */
15
+ export interface ScanResult {
16
+ transcripts: TranscriptFile[];
17
+ totalSize: number;
18
+ projectCount: number;
19
+ }
20
+ /**
21
+ * Options for scanning transcripts
22
+ */
23
+ export interface ScanOptions {
24
+ projectFilter?: string;
25
+ minDate?: Date;
26
+ }
27
+ /**
28
+ * Decode project directory name back to original path.
29
+ *
30
+ * The encoding scheme used by Claude Code is lossy - it converts all path
31
+ * separators (/) to dashes (-), but legitimate dashes in directory names
32
+ * also become dashes, making them indistinguishable.
33
+ *
34
+ * Strategy:
35
+ * 1. Try simple decode (all dashes -> slashes) and check if path exists
36
+ * 2. If not, try to reconstruct by checking filesystem for partial matches
37
+ * 3. Fall back to simple decode if nothing else works
38
+ *
39
+ * Example: "-home-bellman-my-project"
40
+ * - Simple decode: "/home/bellman/my/project" (WRONG if "my-project" is one dir)
41
+ * - Smart decode: "/home/bellman/my-project" (checks filesystem)
42
+ *
43
+ * @internal Exported for testing
44
+ */
45
+ export declare function decodeProjectPath(dirName: string): string;
46
+ /**
47
+ * Scan for all transcript files in ~/.claude/projects/
48
+ */
49
+ export declare function scanTranscripts(options?: ScanOptions): Promise<ScanResult>;
50
+ //# sourceMappingURL=transcript-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-scanner.d.ts","sourceRoot":"","sources":["../../src/analytics/transcript-scanner.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA+CzD;AAkBD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA8EpF"}
@@ -0,0 +1,149 @@
1
+ import { readdir, stat } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ /**
6
+ * UUID regex pattern for session IDs
7
+ */
8
+ const UUID_REGEX = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
9
+ /**
10
+ * Decode project directory name back to original path.
11
+ *
12
+ * The encoding scheme used by Claude Code is lossy - it converts all path
13
+ * separators (/) to dashes (-), but legitimate dashes in directory names
14
+ * also become dashes, making them indistinguishable.
15
+ *
16
+ * Strategy:
17
+ * 1. Try simple decode (all dashes -> slashes) and check if path exists
18
+ * 2. If not, try to reconstruct by checking filesystem for partial matches
19
+ * 3. Fall back to simple decode if nothing else works
20
+ *
21
+ * Example: "-home-bellman-my-project"
22
+ * - Simple decode: "/home/bellman/my/project" (WRONG if "my-project" is one dir)
23
+ * - Smart decode: "/home/bellman/my-project" (checks filesystem)
24
+ *
25
+ * @internal Exported for testing
26
+ */
27
+ export function decodeProjectPath(dirName) {
28
+ if (!dirName.startsWith('-')) {
29
+ return dirName;
30
+ }
31
+ // Simple decode: replace all dashes with slashes
32
+ const simplePath = '/' + dirName.slice(1).replace(/-/g, '/');
33
+ // If simple decode exists, we're done
34
+ if (existsSync(simplePath)) {
35
+ return simplePath;
36
+ }
37
+ // Try to reconstruct by checking filesystem for partial matches
38
+ const segments = dirName.slice(1).split('-');
39
+ const possiblePaths = [];
40
+ // Generate all possible interpretations by trying different hyphen positions
41
+ function generatePaths(parts, index, currentPath) {
42
+ if (index >= parts.length) {
43
+ possiblePaths.push(currentPath);
44
+ return;
45
+ }
46
+ // Try adding next segment as a new directory
47
+ generatePaths(parts, index + 1, currentPath + '/' + parts[index]);
48
+ // Try combining with previous segment using hyphen (if not first segment)
49
+ if (index > 0 && currentPath) {
50
+ const pathParts = currentPath.split('/');
51
+ const lastPart = pathParts.pop() || '';
52
+ const newPath = pathParts.join('/') + '/' + lastPart + '-' + parts[index];
53
+ generatePaths(parts, index + 1, newPath);
54
+ }
55
+ }
56
+ generatePaths(segments, 0, '');
57
+ // Find the first path that exists on filesystem
58
+ for (const path of possiblePaths) {
59
+ if (existsSync(path)) {
60
+ return path;
61
+ }
62
+ }
63
+ // Fall back to simple decode
64
+ return simplePath;
65
+ }
66
+ /**
67
+ * Check if a path matches a glob pattern (simple implementation)
68
+ */
69
+ function matchesPattern(path, pattern) {
70
+ if (!pattern)
71
+ return true;
72
+ // Convert glob pattern to regex
73
+ const regexPattern = pattern
74
+ .replace(/\./g, '\\.')
75
+ .replace(/\*/g, '.*')
76
+ .replace(/\?/g, '.');
77
+ const regex = new RegExp(`^${regexPattern}$`);
78
+ return regex.test(path);
79
+ }
80
+ /**
81
+ * Scan for all transcript files in ~/.claude/projects/
82
+ */
83
+ export async function scanTranscripts(options = {}) {
84
+ const projectsDir = join(homedir(), '.claude', 'projects');
85
+ const transcripts = [];
86
+ const projectDirs = new Set();
87
+ try {
88
+ // Read all project directories
89
+ const entries = await readdir(projectsDir, { withFileTypes: true });
90
+ for (const entry of entries) {
91
+ if (!entry.isDirectory())
92
+ continue;
93
+ const projectDir = entry.name;
94
+ const projectPath = decodeProjectPath(projectDir);
95
+ // Apply project filter if specified
96
+ if (!matchesPattern(projectPath, options.projectFilter)) {
97
+ continue;
98
+ }
99
+ const fullProjectPath = join(projectsDir, projectDir);
100
+ // Read all files in this project directory
101
+ const projectFiles = await readdir(fullProjectPath);
102
+ for (const fileName of projectFiles) {
103
+ // Skip sessions-index.json and any non-.jsonl files
104
+ if (fileName === 'sessions-index.json' || !fileName.endsWith('.jsonl')) {
105
+ continue;
106
+ }
107
+ // Extract session ID from filename
108
+ const sessionId = fileName.replace('.jsonl', '');
109
+ // Validate session ID format (must be UUID)
110
+ if (!UUID_REGEX.test(sessionId)) {
111
+ continue;
112
+ }
113
+ const filePath = join(fullProjectPath, fileName);
114
+ const fileStats = await stat(filePath);
115
+ // Apply date filter if specified
116
+ if (options.minDate && fileStats.mtime < options.minDate) {
117
+ continue;
118
+ }
119
+ transcripts.push({
120
+ projectPath,
121
+ projectDir,
122
+ sessionId,
123
+ filePath,
124
+ fileSize: fileStats.size,
125
+ modifiedTime: fileStats.mtime
126
+ });
127
+ projectDirs.add(projectDir);
128
+ }
129
+ }
130
+ }
131
+ catch (error) {
132
+ // If projects directory doesn't exist, return empty result
133
+ if (error.code === 'ENOENT') {
134
+ return {
135
+ transcripts: [],
136
+ totalSize: 0,
137
+ projectCount: 0
138
+ };
139
+ }
140
+ throw error;
141
+ }
142
+ const totalSize = transcripts.reduce((sum, t) => sum + t.fileSize, 0);
143
+ return {
144
+ transcripts,
145
+ totalSize,
146
+ projectCount: projectDirs.size
147
+ };
148
+ }
149
+ //# sourceMappingURL=transcript-scanner.js.map