@vibe-cafe/vibe-usage 0.7.18 → 0.7.19
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/parsers/codex.js +21 -4
- package/src/tools.js +11 -0
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ npx @vibe-cafe/vibe-usage status # Show config & detected tools
|
|
|
47
47
|
| Tool | Data Location |
|
|
48
48
|
|------|---------------|
|
|
49
49
|
| Claude Code | `~/.claude/projects/` (tokens + sessions), `~/.claude/transcripts/` (sessions only) |
|
|
50
|
-
| Codex CLI | `~/.codex/sessions/` |
|
|
50
|
+
| Codex CLI | `~/.codex/sessions/` and `~/.codex/archived_sessions/` |
|
|
51
51
|
| GitHub Copilot CLI | `~/.copilot/session-state/*/events.jsonl` |
|
|
52
52
|
| Cursor | `state.vscdb` (SQLite, reads `cursorAuth/accessToken`, fetches CSV from `cursor.com`) |
|
|
53
53
|
| Gemini CLI | `~/.gemini/tmp/` |
|
package/package.json
CHANGED
package/src/parsers/codex.js
CHANGED
|
@@ -4,7 +4,18 @@ import { homedir } from 'node:os';
|
|
|
4
4
|
import { createInterface } from 'node:readline';
|
|
5
5
|
import { aggregateToBuckets, extractSessions } from './index.js';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// Codex stores live sessions in ~/.codex/sessions and, once a session is
|
|
8
|
+
// "completed", moves its rollout file verbatim into ~/.codex/archived_sessions.
|
|
9
|
+
// A session can be archived between two syncs, so scanning only the live dir
|
|
10
|
+
// loses that session's usage forever. We scan both: the parser is stateless
|
|
11
|
+
// and the server dedups on (source, sessionHash/bucket), so re-reading an
|
|
12
|
+
// archived file that was already synced from sessions/ is idempotent. Indexing
|
|
13
|
+
// both together also keeps fork replay-skip correct when a fork and its parent
|
|
14
|
+
// end up split across the two directories.
|
|
15
|
+
const SESSIONS_DIRS = [
|
|
16
|
+
join(homedir(), '.codex', 'sessions'),
|
|
17
|
+
join(homedir(), '.codex', 'archived_sessions'),
|
|
18
|
+
];
|
|
8
19
|
|
|
9
20
|
/**
|
|
10
21
|
* Recursively find all .jsonl files under a directory.
|
|
@@ -80,11 +91,11 @@ async function indexSessionFile(filePath) {
|
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
export async function parse() {
|
|
83
|
-
if (!existsSync
|
|
94
|
+
if (!SESSIONS_DIRS.some(existsSync)) return { buckets: [], sessions: [] };
|
|
84
95
|
|
|
85
96
|
const entries = [];
|
|
86
97
|
const sessionEvents = [];
|
|
87
|
-
const files = findJsonlFiles
|
|
98
|
+
const files = SESSIONS_DIRS.flatMap(findJsonlFiles);
|
|
88
99
|
if (files.length === 0) return { buckets: [], sessions: [] };
|
|
89
100
|
|
|
90
101
|
// Pass 1: index every session by its UUID and count its token_count
|
|
@@ -134,6 +145,12 @@ export async function parse() {
|
|
|
134
145
|
let tokenCountSeen = 0;
|
|
135
146
|
|
|
136
147
|
const sessionProject = fm.sessionProject;
|
|
148
|
+
// Group timing events by the real Codex session id, not the file path: the
|
|
149
|
+
// same session can briefly exist in both sessions/ and archived_sessions/
|
|
150
|
+
// (mid-archive, or a re-synced archive). Path-keyed grouping would emit it
|
|
151
|
+
// as two different sessionHashes and double-count its session stats. Fall
|
|
152
|
+
// back to the path only when the id is unknown (corrupt/missing meta).
|
|
153
|
+
const sessionKey = fm.sessionId || filePath;
|
|
137
154
|
|
|
138
155
|
let turnContextModel = 'unknown';
|
|
139
156
|
const prevTotal = new Map();
|
|
@@ -161,7 +178,7 @@ export async function parse() {
|
|
|
161
178
|
if (!isReplay) {
|
|
162
179
|
const isUserTurn = obj.type === 'turn_context' || obj.type === 'session_meta';
|
|
163
180
|
sessionEvents.push({
|
|
164
|
-
sessionId:
|
|
181
|
+
sessionId: sessionKey,
|
|
165
182
|
source: 'codex',
|
|
166
183
|
project: sessionProject,
|
|
167
184
|
timestamp: evTs,
|
package/src/tools.js
CHANGED
|
@@ -80,6 +80,16 @@ function findOpenclawDataDirs() {
|
|
|
80
80
|
return dirs;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// Codex keeps live sessions in ~/.codex/sessions and moves completed ones to
|
|
84
|
+
// ~/.codex/archived_sessions. Detect Codex if either dir exists, so a user
|
|
85
|
+
// whose sessions have all been archived is still recognized.
|
|
86
|
+
function findCodexDataDirs() {
|
|
87
|
+
return [
|
|
88
|
+
join(homedir(), '.codex', 'sessions'),
|
|
89
|
+
join(homedir(), '.codex', 'archived_sessions'),
|
|
90
|
+
].filter(existsSync);
|
|
91
|
+
}
|
|
92
|
+
|
|
83
93
|
export const TOOLS = [
|
|
84
94
|
{
|
|
85
95
|
name: 'Antigravity',
|
|
@@ -101,6 +111,7 @@ export const TOOLS = [
|
|
|
101
111
|
name: 'Codex CLI',
|
|
102
112
|
id: 'codex',
|
|
103
113
|
dataDir: join(homedir(), '.codex', 'sessions'),
|
|
114
|
+
detectDataDirs: findCodexDataDirs,
|
|
104
115
|
},
|
|
105
116
|
{
|
|
106
117
|
name: 'GitHub Copilot CLI',
|