aiwg
Version:
Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo
162 lines • 5.79 kB
JavaScript
/**
* `aiwg rlm-cache` subcommand router.
*
* Subcommands:
* list — show all cached entries
* stats — aggregate statistics
* evict <hash> — remove one entry
* evict --older-than <Nd|Nh> — remove old entries
* clear --yes — wipe everything (requires --yes)
*
* @implements #1203
*/
import { clear, evict, list, resolveCacheRoot, stats } from './store.js';
export async function main(args) {
const sub = args[0];
const rest = args.slice(1);
switch (sub) {
case 'list':
handleList(rest);
break;
case 'stats':
handleStats(rest);
break;
case 'evict':
handleEvict(rest);
break;
case 'clear':
handleClear(rest);
break;
default:
printUsage();
if (sub)
throw new Error(`Unknown rlm-cache subcommand: ${sub}`);
}
}
function asJson(args) {
return args.includes('--json');
}
function handleList(args) {
const root = resolveCacheRoot();
const entries = list(root);
if (asJson(args)) {
console.log(JSON.stringify(entries, null, 2));
return;
}
if (entries.length === 0) {
console.log('No cached RLM results.');
console.log(`Cache root: ${root}`);
return;
}
console.log(`hash age model inputs cost($) query`);
console.log(`──────── ──── ─────────────────── ────── ─────── ─────`);
for (const e of entries) {
console.log(`${e.hash.slice(0, 8)} ${String(e.ageDays).padStart(3)}d ` +
`${e.model.padEnd(19).slice(0, 19)} ${String(e.inputCount).padStart(6)} ` +
`${e.costUsd === null ? ' — ' : e.costUsd.toFixed(4).padStart(7)} ${e.query}`);
}
console.log(`\n${entries.length} cached entries at ${root}`);
}
function handleStats(args) {
const root = resolveCacheRoot();
const s = stats(root);
if (asJson(args)) {
console.log(JSON.stringify(s, null, 2));
return;
}
if (s.totalEntries === 0) {
console.log('Cache is empty.');
console.log(`Cache root: ${root}`);
return;
}
console.log(`Cache root: ${root}`);
console.log(`Total entries: ${s.totalEntries}`);
console.log(`Total size: ${s.totalSizeKb} KiB`);
console.log(`Oldest entry: ${s.oldestAgeDays}d`);
console.log(`Newest entry: ${s.newestAgeDays}d`);
console.log(`Total cached cost: $${s.totalCostUsd.toFixed(4)}`);
}
function parseDuration(spec) {
// Accepts 30d, 2h, 14 (days)
const m = spec.match(/^(\d+)\s*([dh])?$/i);
if (!m)
throw new Error(`Invalid duration: ${spec} (use Nd or Nh)`);
const n = parseInt(m[1] ?? '', 10);
const unit = (m[2] ?? 'd').toLowerCase();
return unit === 'h' ? n / 24 : n;
}
function handleEvict(args) {
const root = resolveCacheRoot();
const olderIdx = args.indexOf('--older-than');
if (olderIdx !== -1 && args[olderIdx + 1]) {
const days = parseDuration(args[olderIdx + 1]);
const r = evict(root, { olderThanDays: days });
if (asJson(args)) {
console.log(JSON.stringify(r, null, 2));
}
else {
console.log(`Evicted ${r.evictedCount} entries (${Math.round(r.evictedBytes / 1024)} KiB) older than ${days}d.`);
}
return;
}
const hash = args.find((a) => /^[0-9a-f]{8,64}$/.test(a));
if (!hash) {
console.error('Usage: aiwg rlm-cache evict <hash> | --older-than <Nd|Nh>');
process.exitCode = 1;
return;
}
// Resolve short hash → full hash
const full = resolveHashPrefix(root, hash);
if (!full) {
console.error(`No cache entry matching: ${hash}`);
process.exitCode = 1;
return;
}
const r = evict(root, { hash: full });
if (asJson(args)) {
console.log(JSON.stringify(r, null, 2));
}
else if (r.evictedCount === 0) {
console.log(`No entry: ${full}`);
}
else {
console.log(`Evicted ${full} (${Math.round(r.evictedBytes / 1024)} KiB).`);
}
}
function resolveHashPrefix(root, prefix) {
const all = list(root);
const matches = all.filter((e) => e.hash.startsWith(prefix));
if (matches.length === 1 && matches[0])
return matches[0].hash;
if (matches.length > 1) {
console.error(`Ambiguous prefix '${prefix}' matches ${matches.length} entries.`);
return null;
}
return null;
}
function handleClear(args) {
if (!args.includes('--yes')) {
console.error('Refusing to clear cache without --yes confirmation.');
process.exitCode = 1;
return;
}
const root = resolveCacheRoot();
const r = clear(root);
if (asJson(args)) {
console.log(JSON.stringify(r, null, 2));
}
else {
console.log(`Cleared ${r.evictedCount} entries (${Math.round(r.evictedBytes / 1024)} KiB).`);
}
}
function printUsage() {
console.log('aiwg rlm-cache <subcommand>');
console.log('');
console.log('Subcommands:');
console.log(' list [--json] List all cached RLM results');
console.log(' stats [--json] Aggregate cache statistics');
console.log(' evict <hash> Remove a single entry by hash (prefix ok)');
console.log(' evict --older-than <Nd|Nh> Remove entries older than N days/hours');
console.log(' clear --yes Wipe entire cache (requires --yes)');
}
//# sourceMappingURL=cli.js.map