mirror of
https://github.com/jarrodwatts/claude-hud.git
synced 2026-05-21 15:52:37 +00:00
* fix: consolidate CLAUDE_CONFIG_DIR handling and keychain fallback * chore: remove dist artifacts from this PR * chore: bump version to 0.0.8 * docs: expand 0.0.8 changelog from post-0.0.7 commits
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import * as fs from 'node:fs';
|
|
import * as path from 'node:path';
|
|
import * as os from 'node:os';
|
|
import type { StdinData } from './types.js';
|
|
import { getHudPluginDir } from './claude-config-dir.js';
|
|
|
|
const SPEED_WINDOW_MS = 2000;
|
|
|
|
interface SpeedCache {
|
|
outputTokens: number;
|
|
timestamp: number;
|
|
}
|
|
|
|
export type SpeedTrackerDeps = {
|
|
homeDir: () => string;
|
|
now: () => number;
|
|
};
|
|
|
|
const defaultDeps: SpeedTrackerDeps = {
|
|
homeDir: () => os.homedir(),
|
|
now: () => Date.now(),
|
|
};
|
|
|
|
function getCachePath(homeDir: string): string {
|
|
return path.join(getHudPluginDir(homeDir), '.speed-cache.json');
|
|
}
|
|
|
|
function readCache(homeDir: string): SpeedCache | null {
|
|
try {
|
|
const cachePath = getCachePath(homeDir);
|
|
if (!fs.existsSync(cachePath)) return null;
|
|
const content = fs.readFileSync(cachePath, 'utf8');
|
|
const parsed = JSON.parse(content) as SpeedCache;
|
|
if (typeof parsed.outputTokens !== 'number' || typeof parsed.timestamp !== 'number') {
|
|
return null;
|
|
}
|
|
return parsed;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function writeCache(homeDir: string, cache: SpeedCache): void {
|
|
try {
|
|
const cachePath = getCachePath(homeDir);
|
|
const cacheDir = path.dirname(cachePath);
|
|
if (!fs.existsSync(cacheDir)) {
|
|
fs.mkdirSync(cacheDir, { recursive: true });
|
|
}
|
|
fs.writeFileSync(cachePath, JSON.stringify(cache), 'utf8');
|
|
} catch {
|
|
// Ignore cache write failures
|
|
}
|
|
}
|
|
|
|
export function getOutputSpeed(stdin: StdinData, overrides: Partial<SpeedTrackerDeps> = {}): number | null {
|
|
const outputTokens = stdin.context_window?.current_usage?.output_tokens;
|
|
if (typeof outputTokens !== 'number' || !Number.isFinite(outputTokens)) {
|
|
return null;
|
|
}
|
|
|
|
const deps = { ...defaultDeps, ...overrides };
|
|
const now = deps.now();
|
|
const homeDir = deps.homeDir();
|
|
const previous = readCache(homeDir);
|
|
|
|
let speed: number | null = null;
|
|
if (previous && outputTokens >= previous.outputTokens) {
|
|
const deltaTokens = outputTokens - previous.outputTokens;
|
|
const deltaMs = now - previous.timestamp;
|
|
if (deltaTokens > 0 && deltaMs > 0 && deltaMs <= SPEED_WINDOW_MS) {
|
|
speed = deltaTokens / (deltaMs / 1000);
|
|
}
|
|
}
|
|
|
|
writeCache(homeDir, { outputTokens, timestamp: now });
|
|
return speed;
|
|
}
|