storyforge 0.4.18 → 0.4.20
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.
|
@@ -5,7 +5,15 @@ import * as fs from "fs";
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import * as os from "os";
|
|
7
7
|
import { loadSessionBlockData } from "ccusage/data-loader";
|
|
8
|
-
var
|
|
8
|
+
var PRICES = {
|
|
9
|
+
// Anthropic — claude.com/pricing
|
|
10
|
+
"claude-opus-4-7": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
11
|
+
"claude-opus-4-6": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
12
|
+
"claude-opus-4-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
13
|
+
"claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
14
|
+
"claude-sonnet-4-5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
15
|
+
"claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
|
|
16
|
+
// OpenAI — platform.openai.com/pricing
|
|
9
17
|
"gpt-5.5": { input: 5, output: 30 },
|
|
10
18
|
"gpt-5.4": { input: 2.5, output: 15 },
|
|
11
19
|
"gpt-5.4-mini": { input: 0.75, output: 4.5 },
|
|
@@ -14,15 +22,23 @@ var CODEX_PRICES = {
|
|
|
14
22
|
"gpt-5-codex": { input: 2.5, output: 15 },
|
|
15
23
|
"gpt-4o": { input: 2.5, output: 10 }
|
|
16
24
|
};
|
|
17
|
-
function
|
|
25
|
+
function priceFor(model) {
|
|
18
26
|
const lower = model.toLowerCase();
|
|
19
|
-
if (
|
|
20
|
-
for (const key of Object.keys(
|
|
21
|
-
if (lower.startsWith(key)) return
|
|
27
|
+
if (PRICES[lower]) return PRICES[lower];
|
|
28
|
+
for (const key of Object.keys(PRICES)) {
|
|
29
|
+
if (lower.startsWith(key)) return PRICES[key];
|
|
22
30
|
}
|
|
23
31
|
return null;
|
|
24
32
|
}
|
|
25
|
-
|
|
33
|
+
function computeCost(model, u) {
|
|
34
|
+
const p = priceFor(model);
|
|
35
|
+
if (!p) return 0;
|
|
36
|
+
let cost = u.input / 1e6 * p.input + u.output / 1e6 * p.output;
|
|
37
|
+
if (p.cacheRead != null) cost += u.cacheRead / 1e6 * p.cacheRead;
|
|
38
|
+
if (p.cacheWrite != null) cost += u.cacheCreate / 1e6 * p.cacheWrite;
|
|
39
|
+
return cost;
|
|
40
|
+
}
|
|
41
|
+
var CLI_USAGE_PARSER_VERSION = 4;
|
|
26
42
|
function emptyModelUsage(model) {
|
|
27
43
|
return { model, inputTokens: 0, cachedReadTokens: 0, cacheCreateTokens: 0, outputTokens: 0, costUsd: 0 };
|
|
28
44
|
}
|
|
@@ -32,7 +48,7 @@ function addToBucket(bucket, model, u) {
|
|
|
32
48
|
row.cachedReadTokens += u.cacheRead;
|
|
33
49
|
row.cacheCreateTokens += u.cacheCreate;
|
|
34
50
|
row.outputTokens += u.output;
|
|
35
|
-
|
|
51
|
+
row.costUsd += computeCost(model, u);
|
|
36
52
|
}
|
|
37
53
|
function startOfTodayMs(now = Date.now()) {
|
|
38
54
|
const d = new Date(now);
|
|
@@ -94,15 +110,14 @@ function parseCodexFile(file) {
|
|
|
94
110
|
const tsRaw = obj?.timestamp ?? obj?.event_msg?.timestamp ?? obj?.event_msg?.event_ts;
|
|
95
111
|
const ts = tsRaw ? new Date(tsRaw).getTime() : Date.now();
|
|
96
112
|
if (!Number.isFinite(ts)) continue;
|
|
97
|
-
|
|
98
|
-
const costUSD = price ? dInput / 1e6 * price.input + dOutput / 1e6 * price.output : void 0;
|
|
99
|
-
out.push({ ts, model, usage: { input: dInput, cacheRead: dCacheRead, cacheCreate: 0, output: dOutput, costUSD } });
|
|
113
|
+
out.push({ ts, model, usage: { input: dInput, cacheRead: dCacheRead, cacheCreate: 0, output: dOutput } });
|
|
100
114
|
}
|
|
101
115
|
return out;
|
|
102
116
|
}
|
|
103
117
|
async function gatherCliUsage() {
|
|
104
118
|
const claudeEntries = [];
|
|
105
119
|
let claudeFileCount = 0;
|
|
120
|
+
let claudeError;
|
|
106
121
|
try {
|
|
107
122
|
const blocks = await loadSessionBlockData();
|
|
108
123
|
for (const block of blocks) {
|
|
@@ -120,15 +135,15 @@ async function gatherCliUsage() {
|
|
|
120
135
|
input: u.inputTokens ?? 0,
|
|
121
136
|
cacheRead: u.cacheReadInputTokens ?? 0,
|
|
122
137
|
cacheCreate: u.cacheCreationInputTokens ?? 0,
|
|
123
|
-
output: u.outputTokens ?? 0
|
|
124
|
-
costUSD: e.costUSD
|
|
138
|
+
output: u.outputTokens ?? 0
|
|
125
139
|
}
|
|
126
140
|
});
|
|
127
141
|
}
|
|
128
142
|
}
|
|
129
143
|
claudeFileCount = listJsonlFiles(path.join(os.homedir(), ".claude", "projects")).length;
|
|
130
144
|
} catch (err) {
|
|
131
|
-
|
|
145
|
+
claudeError = err.message ?? String(err);
|
|
146
|
+
console.error("[cli-usage] ccusage loader failed:", claudeError);
|
|
132
147
|
}
|
|
133
148
|
const codexDir = path.join(os.homedir(), ".codex", "sessions");
|
|
134
149
|
const codexFiles = listJsonlFiles(codexDir);
|
|
@@ -198,7 +213,8 @@ async function gatherCliUsage() {
|
|
|
198
213
|
sources: {
|
|
199
214
|
claudeFiles: claudeFileCount,
|
|
200
215
|
codexFiles: codexFiles.length,
|
|
201
|
-
skipped: 0
|
|
216
|
+
skipped: 0,
|
|
217
|
+
claudeError
|
|
202
218
|
}
|
|
203
219
|
};
|
|
204
220
|
}
|
package/dist/index.js
CHANGED
|
@@ -839,6 +839,17 @@ async function devCommand(options) {
|
|
|
839
839
|
if (env.loaded.length > 0) {
|
|
840
840
|
log.info(`Loaded env: ${env.loaded.join(", ")} from ${env.sources.join(", ")}`);
|
|
841
841
|
}
|
|
842
|
+
void (async () => {
|
|
843
|
+
try {
|
|
844
|
+
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-7QODAG26.js");
|
|
845
|
+
const report = await gatherCliUsage();
|
|
846
|
+
const g = global;
|
|
847
|
+
g.__forgeCliUsageCache = { at: Date.now(), ver: CLI_USAGE_PARSER_VERSION, data: report };
|
|
848
|
+
log.info(`[cli-usage] warmed cache \xB7 ${report.sources.claudeFiles} claude, ${report.sources.codexFiles} codex sessions${report.sources.claudeError ? ` (claude error: ${report.sources.claudeError.slice(0, 80)})` : ""}`);
|
|
849
|
+
} catch (err) {
|
|
850
|
+
log.warn(`[cli-usage] warm-up failed: ${err.message}`);
|
|
851
|
+
}
|
|
852
|
+
})();
|
|
842
853
|
const counts = scanAssets(dir);
|
|
843
854
|
const total = Object.values(counts).reduce((a, b) => a + b, 0);
|
|
844
855
|
if (total > 0) {
|
|
@@ -866,7 +877,7 @@ async function devCommand(options) {
|
|
|
866
877
|
const pathname = url.pathname;
|
|
867
878
|
if (pathname === "/api/cli-usage") {
|
|
868
879
|
try {
|
|
869
|
-
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-
|
|
880
|
+
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-7QODAG26.js");
|
|
870
881
|
const g = global;
|
|
871
882
|
const now = Date.now();
|
|
872
883
|
if (g.__forgeCliUsageCache && g.__forgeCliUsageCache.ver === CLI_USAGE_PARSER_VERSION && now - g.__forgeCliUsageCache.at < 3e4) {
|