claude-usage-dashboard 1.5.1 → 1.5.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.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Your $200/month Max plan might be consuming **$15,000+/month** in API-equivalent
11
11
  npx claude-usage-dashboard
12
12
  ```
13
13
 
14
- ![Dashboard Screenshot](docs/screenshots/dashboard.png)
14
+ ![Dashboard Screenshot](docs/screenshots/dashboard.png?v=3)
15
15
 
16
16
  ## What You'll See
17
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-usage-dashboard",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Claude Code usage dashboard — token costs, quota cycle tracking, cache efficiency, multi-machine sync across all your devices",
5
5
  "main": "server/index.js",
6
6
  "bin": {
package/server/index.js CHANGED
@@ -35,11 +35,19 @@ const server = app.listen(PORT, () => {
35
35
  console.log('Press Ctrl+C to stop.');
36
36
  });
37
37
 
38
- process.on('SIGINT', () => {
39
- console.log('\nShutting down...');
40
- server.close(() => process.exit(0));
38
+ // Track connections so we can destroy them on shutdown
39
+ const connections = new Set();
40
+ server.on('connection', (conn) => {
41
+ connections.add(conn);
42
+ conn.on('close', () => connections.delete(conn));
41
43
  });
42
44
 
43
- process.on('SIGTERM', () => {
45
+ function shutdown() {
46
+ console.log('\nShutting down...');
47
+ for (const conn of connections) conn.destroy();
44
48
  server.close(() => process.exit(0));
45
- });
49
+ setTimeout(() => process.exit(0), 1000).unref();
50
+ }
51
+
52
+ process.on('SIGINT', shutdown);
53
+ process.on('SIGTERM', shutdown);
package/server/parser.js CHANGED
@@ -102,6 +102,28 @@ export function parseLogDirectory(baseDir) {
102
102
  record.projectDirName = dir.name;
103
103
  }
104
104
  allRecords.push(...records);
105
+
106
+ // Also parse subagent transcript files for this session
107
+ const sessionDirName = file.replace(/\.jsonl$/, '');
108
+ const subagentsPath = path.join(projectPath, sessionDirName, 'subagents');
109
+ let subagentFiles;
110
+ try {
111
+ subagentFiles = fs.readdirSync(subagentsPath)
112
+ .filter(f => f.endsWith('.jsonl'));
113
+ } catch {
114
+ continue;
115
+ }
116
+
117
+ for (const subFile of subagentFiles) {
118
+ const subFilePath = path.join(subagentsPath, subFile);
119
+ const subRecords = parseLogFile(subFilePath);
120
+ for (const record of subRecords) {
121
+ record.project = projectName;
122
+ record.projectDirName = dir.name;
123
+ record.sessionId = sessionDirName; // Group with parent session
124
+ }
125
+ allRecords.push(...subRecords);
126
+ }
105
127
  }
106
128
  }
107
129
 
package/server/sync.js CHANGED
@@ -54,6 +54,41 @@ export async function syncLocalToShared(localDir, syncDir, machineName) {
54
54
  } catch (err) {
55
55
  console.warn(`Sync warning: failed to sync ${file}: ${err.message}`);
56
56
  }
57
+
58
+ // Also sync subagent transcript files for this session
59
+ const sessionDirName = file.replace(/\.jsonl$/, '');
60
+ const localSubagentsPath = path.join(localProjPath, sessionDirName, 'subagents');
61
+ let subagentFiles;
62
+ try {
63
+ subagentFiles = (await fs.readdir(localSubagentsPath)).filter(f => f.endsWith('.jsonl'));
64
+ } catch {
65
+ continue;
66
+ }
67
+
68
+ for (const subFile of subagentFiles) {
69
+ const localSubFile = path.join(localSubagentsPath, subFile);
70
+ const sharedSubFile = path.join(machineDir, dir.name, sessionDirName, 'subagents', subFile);
71
+
72
+ try {
73
+ const localStat = await fs.stat(localSubFile);
74
+ let needsSync = false;
75
+
76
+ try {
77
+ const sharedStat = await fs.stat(sharedSubFile);
78
+ needsSync = localStat.size > sharedStat.size;
79
+ } catch {
80
+ needsSync = true;
81
+ }
82
+
83
+ if (needsSync) {
84
+ await fs.mkdir(path.join(machineDir, dir.name, sessionDirName, 'subagents'), { recursive: true });
85
+ await fs.copyFile(localSubFile, sharedSubFile);
86
+ syncedFiles++;
87
+ }
88
+ } catch (err) {
89
+ console.warn(`Sync warning: failed to sync subagent ${subFile}: ${err.message}`);
90
+ }
91
+ }
57
92
  }
58
93
  }
59
94