storyforge 0.4.19 → 0.4.21
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.
|
@@ -75,6 +75,47 @@ function listJsonlFiles(rootDir) {
|
|
|
75
75
|
}
|
|
76
76
|
return out;
|
|
77
77
|
}
|
|
78
|
+
function parseClaudeFileDirect(file, seen) {
|
|
79
|
+
let content;
|
|
80
|
+
try {
|
|
81
|
+
content = fs.readFileSync(file, "utf-8");
|
|
82
|
+
} catch {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const out = [];
|
|
86
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
87
|
+
if (!raw.trim()) continue;
|
|
88
|
+
let obj;
|
|
89
|
+
try {
|
|
90
|
+
obj = JSON.parse(raw);
|
|
91
|
+
} catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const usage = obj?.message?.usage;
|
|
95
|
+
if (!usage) continue;
|
|
96
|
+
const messageId = obj?.message?.id;
|
|
97
|
+
if (messageId) {
|
|
98
|
+
if (seen.has(messageId)) continue;
|
|
99
|
+
seen.add(messageId);
|
|
100
|
+
}
|
|
101
|
+
const model = String(obj?.message?.model ?? "").toLowerCase();
|
|
102
|
+
if (!model) continue;
|
|
103
|
+
const tsRaw = obj?.timestamp ?? obj?.ts;
|
|
104
|
+
const ts = tsRaw ? new Date(tsRaw).getTime() : Date.now();
|
|
105
|
+
if (!Number.isFinite(ts)) continue;
|
|
106
|
+
out.push({
|
|
107
|
+
ts,
|
|
108
|
+
model,
|
|
109
|
+
usage: {
|
|
110
|
+
input: usage.input_tokens ?? 0,
|
|
111
|
+
cacheRead: usage.cache_read_input_tokens ?? 0,
|
|
112
|
+
cacheCreate: usage.cache_creation_input_tokens ?? 0,
|
|
113
|
+
output: usage.output_tokens ?? 0
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
78
119
|
function parseCodexFile(file) {
|
|
79
120
|
let content;
|
|
80
121
|
try {
|
|
@@ -115,13 +156,17 @@ function parseCodexFile(file) {
|
|
|
115
156
|
return out;
|
|
116
157
|
}
|
|
117
158
|
async function gatherCliUsage() {
|
|
159
|
+
const CCUSAGE_TIMEOUT_MS = 8e3;
|
|
118
160
|
const claudeEntries = [];
|
|
119
161
|
let claudeFileCount = 0;
|
|
162
|
+
let claudeError;
|
|
120
163
|
try {
|
|
121
|
-
const blocks = await
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
164
|
+
const blocks = await Promise.race([
|
|
165
|
+
loadSessionBlockData(),
|
|
166
|
+
new Promise(
|
|
167
|
+
(_, reject) => setTimeout(() => reject(new Error(`ccusage timed out after ${CCUSAGE_TIMEOUT_MS}ms (LiteLLM pricing fetch likely blocked)`)), CCUSAGE_TIMEOUT_MS)
|
|
168
|
+
)
|
|
169
|
+
]);
|
|
125
170
|
for (const block of blocks) {
|
|
126
171
|
const entries = block.entries ?? [];
|
|
127
172
|
for (const e of entries) {
|
|
@@ -144,7 +189,15 @@ async function gatherCliUsage() {
|
|
|
144
189
|
}
|
|
145
190
|
claudeFileCount = listJsonlFiles(path.join(os.homedir(), ".claude", "projects")).length;
|
|
146
191
|
} catch (err) {
|
|
147
|
-
|
|
192
|
+
claudeError = `ccusage unavailable, using fallback parser (${err.message?.slice(0, 80) ?? "unknown"})`;
|
|
193
|
+
console.error("[cli-usage] ccusage loader failed, falling back:", claudeError);
|
|
194
|
+
const claudeDir = path.join(os.homedir(), ".claude", "projects");
|
|
195
|
+
const claudeFiles = listJsonlFiles(claudeDir);
|
|
196
|
+
claudeFileCount = claudeFiles.length;
|
|
197
|
+
const seen = /* @__PURE__ */ new Set();
|
|
198
|
+
for (const f of claudeFiles) {
|
|
199
|
+
claudeEntries.push(...parseClaudeFileDirect(f, seen));
|
|
200
|
+
}
|
|
148
201
|
}
|
|
149
202
|
const codexDir = path.join(os.homedir(), ".codex", "sessions");
|
|
150
203
|
const codexFiles = listJsonlFiles(codexDir);
|
|
@@ -214,7 +267,8 @@ async function gatherCliUsage() {
|
|
|
214
267
|
sources: {
|
|
215
268
|
claudeFiles: claudeFileCount,
|
|
216
269
|
codexFiles: codexFiles.length,
|
|
217
|
-
skipped: 0
|
|
270
|
+
skipped: 0,
|
|
271
|
+
claudeError
|
|
218
272
|
}
|
|
219
273
|
};
|
|
220
274
|
}
|
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-P3LK7WEE.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-P3LK7WEE.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) {
|