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 CODEX_PRICES = {
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 codexPriceFor(model) {
25
+ function priceFor(model) {
18
26
  const lower = model.toLowerCase();
19
- if (CODEX_PRICES[lower]) return CODEX_PRICES[lower];
20
- for (const key of Object.keys(CODEX_PRICES)) {
21
- if (lower.startsWith(key)) return CODEX_PRICES[key];
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
- var CLI_USAGE_PARSER_VERSION = 3;
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
- if (typeof u.costUSD === "number") row.costUsd += u.costUSD;
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
- const price = codexPriceFor(model);
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
- void err;
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-EC5NOILQ.js");
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.4.18",
3
+ "version": "0.4.20",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "bin": {