storyforge 0.4.18 → 0.4.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.
@@ -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,9 +110,7 @@ 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
  }
@@ -104,7 +118,10 @@ async function gatherCliUsage() {
104
118
  const claudeEntries = [];
105
119
  let claudeFileCount = 0;
106
120
  try {
107
- const blocks = await loadSessionBlockData();
121
+ const blocks = await loadSessionBlockData(
122
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
+ { offline: true }
124
+ );
108
125
  for (const block of blocks) {
109
126
  const entries = block.entries ?? [];
110
127
  for (const e of entries) {
@@ -120,8 +137,7 @@ async function gatherCliUsage() {
120
137
  input: u.inputTokens ?? 0,
121
138
  cacheRead: u.cacheReadInputTokens ?? 0,
122
139
  cacheCreate: u.cacheCreationInputTokens ?? 0,
123
- output: u.outputTokens ?? 0,
124
- costUSD: e.costUSD
140
+ output: u.outputTokens ?? 0
125
141
  }
126
142
  });
127
143
  }
package/dist/index.js CHANGED
@@ -866,7 +866,7 @@ async function devCommand(options) {
866
866
  const pathname = url.pathname;
867
867
  if (pathname === "/api/cli-usage") {
868
868
  try {
869
- const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-EC5NOILQ.js");
869
+ const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-NX33FYQ6.js");
870
870
  const g = global;
871
871
  const now = Date.now();
872
872
  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.19",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "bin": {