akm-cli
Version:
akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur
46 lines (45 loc) • 2.29 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
/**
* `engine-last-used` support for `akm health` (#950).
*
* An engine bound to an enabled improve process that has not actually been
* invoked in weeks looks identical to a healthy one on every existing check —
* `default-llm-engine`/`configured-engines` only probe availability/reachability,
* never USE. This module answers "when did this engine last run, and for
* whom" by folding `llm_usage` events over a fixed lookback window,
* independent of the report's `--since` (mirrors `session-extraction`'s
* independent `SESSION_EXTRACTION_LEDGER_WINDOW_DAYS` window in `checks.ts`).
*/
import { daysToMs } from "../../core/common.js";
import { readEvents } from "../../core/events.js";
import { LLM_USAGE_EVENT } from "../../llm/usage-persist.js";
import { decodeLlmUsageRecord } from "../../llm/usage-telemetry.js";
/** Rolling window `engine-last-used` reads over, independent of `--since`. */
export const ENGINE_LAST_USED_LOOKBACK_DAYS = 30;
/** ISO cutoff for the `ENGINE_LAST_USED_LOOKBACK_DAYS` window, ending at `now()`. */
export function engineLastUsedSince(now) {
return new Date(now() - daysToMs(ENGINE_LAST_USED_LOOKBACK_DAYS)).toISOString();
}
/**
* Fold `llm_usage` events over the lookback window into the most recent call
* per engine. Best-effort like every other health probe: an event with no
* `engine` field (pre-#576 rows, or a call outside any resolved engine) is
* skipped rather than bucketed under a synthetic key.
*/
export function readLastEngineUsage(stateDbPath, now) {
const since = engineLastUsedSince(now);
const events = readEvents({ since, type: LLM_USAGE_EVENT }, { dbPath: stateDbPath }).events;
const lastUsed = new Map();
for (const event of events) {
const record = decodeLlmUsageRecord(event.metadata);
if (!record?.engine)
continue;
const existing = lastUsed.get(record.engine);
if (!existing || event.ts > existing.lastUsedAt) {
lastUsed.set(record.engine, { lastUsedAt: event.ts, process: record.process });
}
}
return lastUsed;
}