steelforesight/.agents/hooks/caveman-stats.js

120 lines
3.2 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const DEFAULT_BASELINE_MULTIPLIER = 2.9;
function readJsonl(filePath) {
if (!filePath || !fs.existsSync(filePath)) return [];
return fs
.readFileSync(filePath, "utf8")
.split(/\r?\n/)
.filter(Boolean)
.map((line) => {
try {
return JSON.parse(line);
} catch {
return null;
}
})
.filter(Boolean);
}
function collectUsage(entry) {
const candidates = [
entry.usage,
entry.message && entry.message.usage,
entry.response && entry.response.usage,
entry.result && entry.result.usage,
].filter(Boolean);
return candidates.reduce(
(sum, usage) => {
sum.input += Number(usage.input_tokens || usage.inputTokens || usage.prompt_tokens || 0);
sum.output += Number(usage.output_tokens || usage.outputTokens || usage.completion_tokens || 0);
return sum;
},
{ input: 0, output: 0 },
);
}
function compactNumber(value) {
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}m`;
if (value >= 1_000) return `${(value / 1_000).toFixed(1)}k`;
return String(value);
}
function formatNumber(value) {
return Math.round(value).toLocaleString("en-US");
}
function buildStats(input) {
const transcriptPath = input.transcript_path || input.transcriptPath;
const entries = readJsonl(transcriptPath);
const usage = entries.reduce(
(sum, entry) => {
const item = collectUsage(entry);
sum.input += item.input;
sum.output += item.output;
return sum;
},
{ input: 0, output: 0 },
);
const turns = entries.filter((entry) => entry.type === "assistant" || entry.type === "user").length;
const baselineOutput = Math.round(usage.output * DEFAULT_BASELINE_MULTIPLIER);
const saved = Math.max(0, baselineOutput - usage.output);
const percent = baselineOutput ? Math.round((saved / baselineOutput) * 100) : 0;
return {
turns,
input: usage.input,
output: usage.output,
baselineOutput,
saved,
percent,
transcriptPath,
};
}
function writeLifetimeSuffix(input, stats) {
const cwd = input.cwd || process.cwd();
const outPath = path.join(cwd, ".agents", "hooks", ".caveman-lifetime-savings");
try {
fs.writeFileSync(outPath, ` ${compactNumber(stats.saved)}`, "utf8");
} catch {
// Stats display should still work if this optional badge write fails.
}
}
function formatStats(stats) {
if (!stats.transcriptPath) {
return "No transcript path in hook input. Cannot compute real token stats.";
}
if (!stats.input && !stats.output) {
return [
"No token usage found in current transcript.",
`Transcript: ${stats.transcriptPath}`,
].join("\n");
}
return [
`Session: ${formatNumber(stats.turns)} turns`,
`Input: ${formatNumber(stats.input)} tokens`,
`Output: ${formatNumber(stats.output)} tokens (caveman)`,
`Baseline:${formatNumber(stats.baselineOutput).padStart(10)} tokens (estimated without caveman)`,
`Saved: ${formatNumber(stats.saved).padStart(10)} tokens (~${stats.percent}%)`,
].join("\n");
}
function run(input) {
const stats = buildStats(input || {});
writeLifetimeSuffix(input || {}, stats);
return formatStats(stats);
}
module.exports = { run, buildStats, formatStats };