@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 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), `~/.claude/transcripts/` (sessions only); also scans `$CLAUDE_CONFIG_DIR` and data-bearing `~/.claude-*` profiles, selects the most complete duplicate session, and streams logs so large active sessions are not silently omitted. Cache creation tokens are included in input usage. |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-cafe/vibe-usage",
3
- "version": "0.10.5",
3
+ "version": "0.10.6",
4
4
  "description": "Track your AI coding tool token usage and sync to vibecafe.ai",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -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
- * VIBE_USAGE_CLAUDE_DIRS is a test/diagnostic override. It replaces discovery
27
- * with a path.delimiter-separated root list.
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