@vibe-cafe/vibe-usage 0.10.5 → 0.10.6
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/src/claude-roots.js +86 -4
- package/src/parsers/claude-code.js +3 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ npx @vibe-cafe/vibe-usage status # Show config & detected tools
|
|
|
51
51
|
|
|
52
52
|
| Tool | Data Location |
|
|
53
53
|
|------|---------------|
|
|
54
|
-
| Claude Code | `~/.claude/projects/` (tokens + sessions)
|
|
54
|
+
| Claude Code + Claude Desktop Code/Cowork | Claude Code data in `~/.claude/projects/` (tokens + sessions) and `~/.claude/transcripts/` (sessions only), plus Claude Desktop Cowork's per-session `.claude/projects/` directories. Also scans `$CLAUDE_CONFIG_DIR` and data-bearing `~/.claude-*` profiles. All variants use the existing `claude-code` source; the parser selects the most complete copy of each session so shared/copied transcripts are not counted twice. Logs are streamed and cache creation tokens are included in input usage. |
|
|
55
55
|
| Codex CLI | `$CODEX_HOME/sessions/` and `$CODEX_HOME/archived_sessions/` (default `~/.codex`), plus an optional temporary `--extra-codex-home` or manually persisted `codexExtraHome`; a versioned local index avoids re-reading unchanged rollouts and reads only safe append tails for ordinary sessions, while fork/sub-agent replay matching, duplicate suppression, and live/archive/cross-root deduplication retain their existing semantics |
|
|
56
56
|
| Grok | `$GROK_HOME/sessions/<encoded-cwd>/<session-id>/` (default `~/.grok`); token usage from `updates.jsonl` `turn_completed.usage` (per-model `modelUsage`, cache reads, reasoning); project from `summary.json` cwd; honors `GROK_HOME` |
|
|
57
57
|
| GitHub Copilot CLI | `~/.copilot/session-state/*/events.jsonl` |
|
package/package.json
CHANGED
package/src/claude-roots.js
CHANGED
|
@@ -2,6 +2,9 @@ import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs';
|
|
|
2
2
|
import { delimiter, join } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
|
|
5
|
+
const MAX_DESKTOP_DISCOVERY_DEPTH = 8;
|
|
6
|
+
const DESKTOP_NON_SESSION_DIRS = new Set(['rpm', 'skills']);
|
|
7
|
+
|
|
5
8
|
function expandHome(value) {
|
|
6
9
|
const trimmed = value.trim().replace(/[/\\]+$/, '');
|
|
7
10
|
if (trimmed === '~') return homedir();
|
|
@@ -15,18 +18,95 @@ function hasClaudeData(root) {
|
|
|
15
18
|
return existsSync(join(root, 'projects')) || existsSync(join(root, 'transcripts'));
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
function defaultClaudeDesktopDataDir() {
|
|
22
|
+
if (process.platform === 'darwin') {
|
|
23
|
+
return join(homedir(), 'Library', 'Application Support', 'Claude');
|
|
24
|
+
}
|
|
25
|
+
if (process.platform === 'win32') {
|
|
26
|
+
const appData = process.env.APPDATA?.trim();
|
|
27
|
+
return appData
|
|
28
|
+
? join(expandHome(appData), 'Claude')
|
|
29
|
+
: join(homedir(), 'AppData', 'Roaming', 'Claude');
|
|
30
|
+
}
|
|
31
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim();
|
|
32
|
+
return join(configHome ? expandHome(configHome) : join(homedir(), '.config'), 'Claude');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getClaudeDesktopDataDirs() {
|
|
36
|
+
const override = process.env.VIBE_USAGE_CLAUDE_DESKTOP_DIRS?.trim();
|
|
37
|
+
return override
|
|
38
|
+
? override.split(delimiter).map(expandHome).filter(Boolean)
|
|
39
|
+
: [defaultClaudeDesktopDataDir()];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function discoverDesktopRoots(dir, depth, roots, onWarning) {
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err?.code !== 'ENOENT') {
|
|
48
|
+
onWarning(`Claude Desktop: cannot read directory ${dir}: ${err.message}`);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Once a session root is found, do not descend into the user's Cowork files.
|
|
54
|
+
// Those directories can be large and are unrelated to Claude's transcript.
|
|
55
|
+
const claudeEntry = entries.find(
|
|
56
|
+
(entry) => entry.name === '.claude' && entry.isDirectory(),
|
|
57
|
+
);
|
|
58
|
+
if (claudeEntry) {
|
|
59
|
+
roots.push(join(dir, claudeEntry.name));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
if (!entry.isDirectory()) continue;
|
|
65
|
+
if (DESKTOP_NON_SESSION_DIRS.has(entry.name)) continue;
|
|
66
|
+
const candidate = join(dir, entry.name);
|
|
67
|
+
if (depth < MAX_DESKTOP_DISCOVERY_DEPTH) {
|
|
68
|
+
discoverDesktopRoots(candidate, depth + 1, roots, onWarning);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Find the private Claude Code state roots created for Claude Desktop Cowork.
|
|
75
|
+
* Desktop Code itself uses the normal ~/.claude root, while Cowork isolates
|
|
76
|
+
* each local-agent session below the Electron user-data directory.
|
|
77
|
+
*/
|
|
78
|
+
export function findClaudeDesktopRoots(
|
|
79
|
+
desktopDataDirs = getClaudeDesktopDataDirs(),
|
|
80
|
+
onWarning = () => {},
|
|
81
|
+
) {
|
|
82
|
+
const roots = [];
|
|
83
|
+
for (const dataDir of desktopDataDirs) {
|
|
84
|
+
discoverDesktopRoots(
|
|
85
|
+
join(dataDir, 'local-agent-mode-sessions'),
|
|
86
|
+
0,
|
|
87
|
+
roots,
|
|
88
|
+
onWarning,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return roots;
|
|
92
|
+
}
|
|
93
|
+
|
|
18
94
|
/**
|
|
19
|
-
* Return every Claude Code state root visible from this process.
|
|
95
|
+
* Return every Claude Code-compatible state root visible from this process.
|
|
20
96
|
*
|
|
21
97
|
* In addition to the default and CLAUDE_CONFIG_DIR, discover the documented
|
|
22
98
|
* multi-profile convention (~/.claude-work, ~/.claude-personal, ...). This is
|
|
23
99
|
* important for launchd/systemd and GUI processes, which commonly do not
|
|
24
100
|
* inherit the shell environment used to launch Claude Code.
|
|
25
101
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
102
|
+
* Claude Desktop Code uses the default Claude Code root. Cowork creates a
|
|
103
|
+
* private .claude root per local-agent session, so those roots are discovered
|
|
104
|
+
* recursively under the app's user-data directory.
|
|
105
|
+
*
|
|
106
|
+
* VIBE_USAGE_CLAUDE_DIRS is a test/diagnostic override. It replaces all normal
|
|
107
|
+
* and Desktop discovery with a path.delimiter-separated root list.
|
|
28
108
|
*/
|
|
29
|
-
export function getClaudeRoots() {
|
|
109
|
+
export function getClaudeRoots({ onWarning = () => {} } = {}) {
|
|
30
110
|
const override = process.env.VIBE_USAGE_CLAUDE_DIRS?.trim();
|
|
31
111
|
const roots = override
|
|
32
112
|
? override.split(delimiter).map(expandHome).filter(Boolean)
|
|
@@ -47,6 +127,8 @@ export function getClaudeRoots() {
|
|
|
47
127
|
} catch {
|
|
48
128
|
// The default/configured roots remain usable if home discovery fails.
|
|
49
129
|
}
|
|
130
|
+
|
|
131
|
+
roots.push(...findClaudeDesktopRoots(getClaudeDesktopDataDirs(), onWarning));
|
|
50
132
|
}
|
|
51
133
|
|
|
52
134
|
const seen = new Set();
|
|
@@ -272,7 +272,9 @@ export async function parse() {
|
|
|
272
272
|
warnings: [],
|
|
273
273
|
incomplete: false,
|
|
274
274
|
};
|
|
275
|
-
const roots = getClaudeRoots(
|
|
275
|
+
const roots = getClaudeRoots({
|
|
276
|
+
onWarning: (message) => addWarning(ctx, message),
|
|
277
|
+
});
|
|
276
278
|
const projectGroups = collectCandidates(roots, 'projects', ctx);
|
|
277
279
|
const projectSessionIds = new Set();
|
|
278
280
|
|