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 +1 -1
- package/package.json +1 -1
- package/server/index.js +13 -5
- package/server/parser.js +22 -0
- package/server/sync.js +35 -0
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
|
-

|
|
14
|
+

|
|
15
15
|
|
|
16
16
|
## What You'll See
|
|
17
17
|
|
package/package.json
CHANGED
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
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
|
|