@tokscale/cli 1.0.17 → 1.0.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/dist/cli.js +214 -91
- package/dist/cli.js.map +1 -1
- package/dist/graph-types.d.ts +1 -1
- package/dist/graph-types.d.ts.map +1 -1
- package/dist/native-runner.d.ts +1 -2
- package/dist/native-runner.d.ts.map +1 -1
- package/dist/native-runner.js +11 -39
- package/dist/native-runner.js.map +1 -1
- package/dist/native.d.ts +9 -30
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +31 -138
- package/dist/native.js.map +1 -1
- package/dist/sessions/types.d.ts +1 -1
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/submit.d.ts +2 -0
- package/dist/submit.d.ts.map +1 -1
- package/dist/submit.js +32 -16
- package/dist/submit.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +14 -7
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/DailyView.d.ts.map +1 -1
- package/dist/tui/components/DailyView.js +25 -8
- package/dist/tui/components/DailyView.js.map +1 -1
- package/dist/tui/components/DateBreakdownPanel.js +2 -2
- package/dist/tui/components/DateBreakdownPanel.js.map +1 -1
- package/dist/tui/components/Footer.d.ts.map +1 -1
- package/dist/tui/components/Footer.js +2 -3
- package/dist/tui/components/Footer.js.map +1 -1
- package/dist/tui/components/LoadingSpinner.d.ts.map +1 -1
- package/dist/tui/components/LoadingSpinner.js +1 -2
- package/dist/tui/components/LoadingSpinner.js.map +1 -1
- package/dist/tui/components/ModelView.js +2 -2
- package/dist/tui/components/ModelView.js.map +1 -1
- package/dist/tui/config/settings.d.ts +4 -4
- package/dist/tui/config/settings.d.ts.map +1 -1
- package/dist/tui/config/settings.js +11 -4
- package/dist/tui/config/settings.js.map +1 -1
- package/dist/tui/hooks/useData.d.ts.map +1 -1
- package/dist/tui/hooks/useData.js +29 -42
- package/dist/tui/hooks/useData.js.map +1 -1
- package/dist/tui/types/index.d.ts +2 -2
- package/dist/tui/types/index.d.ts.map +1 -1
- package/dist/tui/types/index.js +3 -1
- package/dist/tui/types/index.js.map +1 -1
- package/dist/tui/utils/colors.d.ts +1 -0
- package/dist/tui/utils/colors.d.ts.map +1 -1
- package/dist/tui/utils/colors.js +7 -0
- package/dist/tui/utils/colors.js.map +1 -1
- package/dist/wrapped.d.ts.map +1 -1
- package/dist/wrapped.js +20 -48
- package/dist/wrapped.js.map +1 -1
- package/package.json +2 -2
- package/src/cli.ts +232 -97
- package/src/graph-types.ts +1 -1
- package/src/native-runner.js +4 -0
- package/src/native-runner.ts +12 -42
- package/src/native.ts +47 -207
- package/src/sessions/types.ts +1 -1
- package/src/submit.ts +36 -22
- package/src/tui/App.tsx +10 -7
- package/src/tui/components/DailyView.tsx +29 -11
- package/src/tui/components/DateBreakdownPanel.tsx +2 -2
- package/src/tui/components/Footer.tsx +7 -2
- package/src/tui/components/LoadingSpinner.tsx +1 -2
- package/src/tui/components/ModelView.tsx +2 -2
- package/src/tui/config/settings.ts +18 -9
- package/src/tui/hooks/useData.ts +36 -47
- package/src/tui/types/index.ts +5 -4
- package/src/tui/utils/colors.ts +7 -0
- package/src/wrapped.ts +21 -54
- package/dist/graph.d.ts +0 -29
- package/dist/graph.d.ts.map +0 -1
- package/dist/graph.js +0 -383
- package/dist/graph.js.map +0 -1
- package/dist/pricing.d.ts +0 -58
- package/dist/pricing.d.ts.map +0 -1
- package/dist/pricing.js +0 -232
- package/dist/pricing.js.map +0 -1
- package/dist/sessions/claudecode.d.ts +0 -8
- package/dist/sessions/claudecode.d.ts.map +0 -1
- package/dist/sessions/claudecode.js +0 -84
- package/dist/sessions/claudecode.js.map +0 -1
- package/dist/sessions/codex.d.ts +0 -8
- package/dist/sessions/codex.d.ts.map +0 -1
- package/dist/sessions/codex.js +0 -158
- package/dist/sessions/codex.js.map +0 -1
- package/dist/sessions/gemini.d.ts +0 -8
- package/dist/sessions/gemini.d.ts.map +0 -1
- package/dist/sessions/gemini.js +0 -66
- package/dist/sessions/gemini.js.map +0 -1
- package/dist/sessions/index.d.ts +0 -32
- package/dist/sessions/index.d.ts.map +0 -1
- package/dist/sessions/index.js +0 -96
- package/dist/sessions/index.js.map +0 -1
- package/dist/sessions/opencode.d.ts +0 -9
- package/dist/sessions/opencode.d.ts.map +0 -1
- package/dist/sessions/opencode.js +0 -69
- package/dist/sessions/opencode.js.map +0 -1
- package/dist/sessions/reports.d.ts +0 -58
- package/dist/sessions/reports.d.ts.map +0 -1
- package/dist/sessions/reports.js +0 -337
- package/dist/sessions/reports.js.map +0 -1
- package/src/graph.ts +0 -485
- package/src/pricing.ts +0 -309
- package/src/sessions/claudecode.ts +0 -119
- package/src/sessions/codex.ts +0 -227
- package/src/sessions/gemini.ts +0 -108
- package/src/sessions/index.ts +0 -126
- package/src/sessions/opencode.ts +0 -117
- package/src/sessions/reports.ts +0 -475
package/src/sessions/gemini.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gemini CLI session parser
|
|
3
|
-
* Reads from ~/.gemini/tmp/{projectHash}/chats/session-*.json
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as fs from "node:fs";
|
|
7
|
-
import * as path from "node:path";
|
|
8
|
-
import * as os from "node:os";
|
|
9
|
-
import { createUnifiedMessage, type UnifiedMessage, type TokenBreakdown } from "./types.js";
|
|
10
|
-
|
|
11
|
-
interface GeminiMessage {
|
|
12
|
-
id: string;
|
|
13
|
-
timestamp: string;
|
|
14
|
-
type: "user" | "gemini";
|
|
15
|
-
content: string;
|
|
16
|
-
tokens?: {
|
|
17
|
-
input: number;
|
|
18
|
-
output: number;
|
|
19
|
-
cached: number;
|
|
20
|
-
thoughts: number;
|
|
21
|
-
tool: number;
|
|
22
|
-
total: number;
|
|
23
|
-
};
|
|
24
|
-
model?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface GeminiSession {
|
|
28
|
-
sessionId: string;
|
|
29
|
-
projectHash: string;
|
|
30
|
-
startTime: string;
|
|
31
|
-
lastUpdated: string;
|
|
32
|
-
messages: GeminiMessage[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getGeminiBasePath(): string {
|
|
36
|
-
return path.join(os.homedir(), ".gemini");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function parseGeminiMessages(): UnifiedMessage[] {
|
|
40
|
-
const basePath = getGeminiBasePath();
|
|
41
|
-
const tmpPath = path.join(basePath, "tmp");
|
|
42
|
-
|
|
43
|
-
if (!fs.existsSync(tmpPath)) {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const messages: UnifiedMessage[] = [];
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
// Find all project directories
|
|
51
|
-
const projectDirs = fs
|
|
52
|
-
.readdirSync(tmpPath, { withFileTypes: true })
|
|
53
|
-
.filter((d) => d.isDirectory())
|
|
54
|
-
.map((d) => path.join(tmpPath, d.name));
|
|
55
|
-
|
|
56
|
-
for (const projectDir of projectDirs) {
|
|
57
|
-
const chatsDir = path.join(projectDir, "chats");
|
|
58
|
-
if (!fs.existsSync(chatsDir)) continue;
|
|
59
|
-
|
|
60
|
-
// Find all session JSON files
|
|
61
|
-
const sessionFiles = fs
|
|
62
|
-
.readdirSync(chatsDir)
|
|
63
|
-
.filter((f) => f.startsWith("session-") && f.endsWith(".json"));
|
|
64
|
-
|
|
65
|
-
for (const sessionFile of sessionFiles) {
|
|
66
|
-
try {
|
|
67
|
-
const content = fs.readFileSync(path.join(chatsDir, sessionFile), "utf-8");
|
|
68
|
-
const session = JSON.parse(content) as GeminiSession;
|
|
69
|
-
|
|
70
|
-
for (const msg of session.messages) {
|
|
71
|
-
// Only process gemini messages with token data and timestamp
|
|
72
|
-
if (msg.type !== "gemini" || !msg.tokens || !msg.model || !msg.timestamp) continue;
|
|
73
|
-
|
|
74
|
-
const timestamp = new Date(msg.timestamp).getTime();
|
|
75
|
-
|
|
76
|
-
// Skip invalid timestamps
|
|
77
|
-
if (isNaN(timestamp)) continue;
|
|
78
|
-
|
|
79
|
-
const tokens: TokenBreakdown = {
|
|
80
|
-
input: msg.tokens.input || 0,
|
|
81
|
-
output: msg.tokens.output || 0,
|
|
82
|
-
cacheRead: msg.tokens.cached || 0,
|
|
83
|
-
cacheWrite: 0, // Gemini doesn't track cache write
|
|
84
|
-
reasoning: msg.tokens.thoughts || 0,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
messages.push(
|
|
88
|
-
createUnifiedMessage(
|
|
89
|
-
"gemini",
|
|
90
|
-
msg.model,
|
|
91
|
-
"google",
|
|
92
|
-
session.sessionId,
|
|
93
|
-
timestamp,
|
|
94
|
-
tokens
|
|
95
|
-
)
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
// Skip malformed files
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
} catch {
|
|
104
|
-
// Skip inaccessible directories
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return messages;
|
|
108
|
-
}
|
package/src/sessions/index.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session parsers for different AI coding assistant formats
|
|
3
|
-
*
|
|
4
|
-
* This module provides TypeScript fallback parsers that match the Rust
|
|
5
|
-
* implementations in packages/core/src/sessions/. Used when native module
|
|
6
|
-
* is not available.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export * from "./types.js";
|
|
10
|
-
export { parseOpenCodeMessages, getOpenCodeStoragePath } from "./opencode.js";
|
|
11
|
-
export { parseClaudeCodeMessages, getClaudeCodeProjectsPath } from "./claudecode.js";
|
|
12
|
-
export { parseCodexMessages, getCodexSessionsPath } from "./codex.js";
|
|
13
|
-
export { parseGeminiMessages, getGeminiBasePath } from "./gemini.js";
|
|
14
|
-
|
|
15
|
-
import type { UnifiedMessage, SourceType } from "./types.js";
|
|
16
|
-
import { parseOpenCodeMessages } from "./opencode.js";
|
|
17
|
-
import { parseClaudeCodeMessages } from "./claudecode.js";
|
|
18
|
-
import { parseCodexMessages } from "./codex.js";
|
|
19
|
-
import { parseGeminiMessages } from "./gemini.js";
|
|
20
|
-
|
|
21
|
-
export interface ParsedMessages {
|
|
22
|
-
messages: UnifiedMessage[];
|
|
23
|
-
opencodeCount: number;
|
|
24
|
-
claudeCount: number;
|
|
25
|
-
codexCount: number;
|
|
26
|
-
geminiCount: number;
|
|
27
|
-
processingTimeMs: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface ParseOptions {
|
|
31
|
-
sources?: SourceType[];
|
|
32
|
-
since?: string;
|
|
33
|
-
until?: string;
|
|
34
|
-
year?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Check if a message date is within the filter range
|
|
39
|
-
*/
|
|
40
|
-
function isDateInRange(date: string, since?: string, until?: string, year?: string): boolean {
|
|
41
|
-
// Year filter
|
|
42
|
-
if (year && !date.startsWith(year)) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Since filter
|
|
47
|
-
if (since && date < since) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Until filter
|
|
52
|
-
if (until && date > until) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Parse all local session sources using TypeScript fallback parsers
|
|
61
|
-
*/
|
|
62
|
-
export function parseLocalSources(options: ParseOptions = {}): ParsedMessages {
|
|
63
|
-
const startTime = performance.now();
|
|
64
|
-
const sources = options.sources;
|
|
65
|
-
|
|
66
|
-
const allMessages: UnifiedMessage[] = [];
|
|
67
|
-
let opencodeCount = 0;
|
|
68
|
-
let claudeCount = 0;
|
|
69
|
-
let codexCount = 0;
|
|
70
|
-
let geminiCount = 0;
|
|
71
|
-
|
|
72
|
-
// Parse OpenCode
|
|
73
|
-
if (!sources || sources.includes("opencode")) {
|
|
74
|
-
const messages = parseOpenCodeMessages();
|
|
75
|
-
for (const msg of messages) {
|
|
76
|
-
if (isDateInRange(msg.date, options.since, options.until, options.year)) {
|
|
77
|
-
allMessages.push(msg);
|
|
78
|
-
opencodeCount++;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Parse Claude Code
|
|
84
|
-
if (!sources || sources.includes("claude")) {
|
|
85
|
-
const messages = parseClaudeCodeMessages();
|
|
86
|
-
for (const msg of messages) {
|
|
87
|
-
if (isDateInRange(msg.date, options.since, options.until, options.year)) {
|
|
88
|
-
allMessages.push(msg);
|
|
89
|
-
claudeCount++;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Parse Codex
|
|
95
|
-
if (!sources || sources.includes("codex")) {
|
|
96
|
-
const messages = parseCodexMessages();
|
|
97
|
-
for (const msg of messages) {
|
|
98
|
-
if (isDateInRange(msg.date, options.since, options.until, options.year)) {
|
|
99
|
-
allMessages.push(msg);
|
|
100
|
-
codexCount++;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Parse Gemini
|
|
106
|
-
if (!sources || sources.includes("gemini")) {
|
|
107
|
-
const messages = parseGeminiMessages();
|
|
108
|
-
for (const msg of messages) {
|
|
109
|
-
if (isDateInRange(msg.date, options.since, options.until, options.year)) {
|
|
110
|
-
allMessages.push(msg);
|
|
111
|
-
geminiCount++;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const processingTimeMs = performance.now() - startTime;
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
messages: allMessages,
|
|
120
|
-
opencodeCount,
|
|
121
|
-
claudeCount,
|
|
122
|
-
codexCount,
|
|
123
|
-
geminiCount,
|
|
124
|
-
processingTimeMs,
|
|
125
|
-
};
|
|
126
|
-
}
|
package/src/sessions/opencode.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenCode session parser
|
|
3
|
-
* Reads from ~/.local/share/opencode/storage/message/
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as fs from "node:fs";
|
|
7
|
-
import * as path from "node:path";
|
|
8
|
-
import * as os from "node:os";
|
|
9
|
-
import { createUnifiedMessage, type UnifiedMessage, type TokenBreakdown } from "./types.js";
|
|
10
|
-
|
|
11
|
-
interface OpenCodeMessageFile {
|
|
12
|
-
id: string;
|
|
13
|
-
sessionID: string;
|
|
14
|
-
role: "assistant" | "user";
|
|
15
|
-
modelID?: string;
|
|
16
|
-
providerID?: string;
|
|
17
|
-
cost: number;
|
|
18
|
-
tokens?: {
|
|
19
|
-
input: number;
|
|
20
|
-
output: number;
|
|
21
|
-
reasoning: number;
|
|
22
|
-
cache: {
|
|
23
|
-
read: number;
|
|
24
|
-
write: number;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
time: {
|
|
28
|
-
created: number;
|
|
29
|
-
completed?: number;
|
|
30
|
-
};
|
|
31
|
-
agent?: string;
|
|
32
|
-
mode?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function normalizeAgentName(agent: string): string {
|
|
36
|
-
const agentLower = agent.toLowerCase();
|
|
37
|
-
|
|
38
|
-
if (agentLower.includes("plan")) {
|
|
39
|
-
if (agentLower.includes("omo") || agentLower.includes("sisyphus")) {
|
|
40
|
-
return "Planner-Sisyphus";
|
|
41
|
-
}
|
|
42
|
-
return agent;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (agentLower === "omo" || agentLower === "sisyphus") {
|
|
46
|
-
return "Sisyphus";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return agent;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function getOpenCodeStoragePath(): string {
|
|
53
|
-
const dataHome = process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share");
|
|
54
|
-
return path.join(dataHome, "opencode", "storage");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function parseOpenCodeMessages(): UnifiedMessage[] {
|
|
58
|
-
const storagePath = getOpenCodeStoragePath();
|
|
59
|
-
const messagePath = path.join(storagePath, "message");
|
|
60
|
-
|
|
61
|
-
if (!fs.existsSync(messagePath)) {
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const messages: UnifiedMessage[] = [];
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const sessionDirs = fs
|
|
69
|
-
.readdirSync(messagePath)
|
|
70
|
-
.map((dir) => path.join(messagePath, dir))
|
|
71
|
-
.filter((dir) => fs.statSync(dir).isDirectory());
|
|
72
|
-
|
|
73
|
-
for (const sessionDir of sessionDirs) {
|
|
74
|
-
const sessionId = path.basename(sessionDir);
|
|
75
|
-
const files = fs.readdirSync(sessionDir).filter((f) => f.endsWith(".json"));
|
|
76
|
-
|
|
77
|
-
for (const file of files) {
|
|
78
|
-
try {
|
|
79
|
-
const content = fs.readFileSync(path.join(sessionDir, file), "utf-8");
|
|
80
|
-
const msg = JSON.parse(content) as OpenCodeMessageFile;
|
|
81
|
-
|
|
82
|
-
if (msg.role === "assistant" && msg.tokens && msg.modelID) {
|
|
83
|
-
const tokens: TokenBreakdown = {
|
|
84
|
-
input: msg.tokens.input || 0,
|
|
85
|
-
output: msg.tokens.output || 0,
|
|
86
|
-
cacheRead: msg.tokens.cache?.read || 0,
|
|
87
|
-
cacheWrite: msg.tokens.cache?.write || 0,
|
|
88
|
-
reasoning: msg.tokens.reasoning || 0,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const agentOrMode = msg.mode || msg.agent;
|
|
92
|
-
const agent = agentOrMode ? normalizeAgentName(agentOrMode) : undefined;
|
|
93
|
-
|
|
94
|
-
messages.push(
|
|
95
|
-
createUnifiedMessage(
|
|
96
|
-
"opencode",
|
|
97
|
-
msg.modelID,
|
|
98
|
-
msg.providerID || "unknown",
|
|
99
|
-
sessionId,
|
|
100
|
-
msg.time.created,
|
|
101
|
-
tokens,
|
|
102
|
-
msg.cost || 0,
|
|
103
|
-
agent
|
|
104
|
-
)
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// Skip malformed files
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
// Skip inaccessible directories
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return messages;
|
|
117
|
-
}
|