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
72 lines (71 loc) • 3.39 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/.
import { queryImproveRuns } from "../../storage/repositories/improve-runs-repository.js";
import { queryTaskHistory } from "../../storage/repositories/task-history-repository.js";
import { projectImproveRunSummary } from "./improve-metrics.js";
/**
* Load `task_history` rows whose `task_id` begins `akm-improve` (the scheduled
* improve tasks: `akm-improve-frequent`, `akm-improve-proactive-weekly`, …) in
* the window, widened ±5 min so a task that fired just before the window opened
* still matches a run inside it. Used to attribute each improve run to the task
* that launched it.
*/
function loadImproveTaskRuns(db, since, until) {
const sinceMs = new Date(since).getTime();
const untilMs = until ? new Date(until).getTime() : undefined;
const widenedSince = new Date(sinceMs - 5 * 60 * 1000).toISOString();
const widenedUntil = untilMs !== undefined ? new Date(untilMs + 5 * 60 * 1000).toISOString() : undefined;
const runs = [];
for (const row of queryTaskHistory(db, { since: widenedSince, until: widenedUntil })) {
if (!row.task_id.startsWith("akm-improve"))
continue;
const startMs = new Date(row.started_at).getTime();
if (!Number.isFinite(startMs))
continue;
const endIso = row.completed_at ?? row.failed_at;
const endMs = endIso ? new Date(endIso).getTime() : Number.NaN;
runs.push({ taskId: row.task_id, startMs, endMs });
}
return runs;
}
/**
* Attribute an improve run to the scheduled task that launched it by matching
* start times within ±5 min, scored by start delta (plus end delta when both
* ends are known). Port of the health-report skill's `match_task_id`. Returns
* `"manual"` when no scheduled improve task matches.
*/
export function matchImproveTaskId(startedAt, completedAt, taskRuns) {
const startMs = new Date(startedAt).getTime();
if (!Number.isFinite(startMs))
return "manual";
const endMs = new Date(completedAt).getTime();
let best;
let bestScore = Number.POSITIVE_INFINITY;
for (const task of taskRuns) {
const startDelta = Math.abs(task.startMs - startMs);
if (startDelta > 5 * 60 * 1000)
continue;
let score = startDelta;
if (Number.isFinite(endMs) && Number.isFinite(task.endMs))
score += Math.abs(task.endMs - endMs);
if (score < bestScore) {
bestScore = score;
best = task.taskId;
}
}
return best ?? "manual";
}
export function buildPerRunSummaries(db, since, until) {
const rows = queryImproveRuns(db, since, until);
const improveTaskRuns = loadImproveTaskRuns(db, since, until);
const summaries = [];
for (const row of rows) {
const startMs = new Date(row.started_at).getTime();
const endMs = new Date(row.completed_at).getTime();
const wallTimeMs = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs >= startMs ? endMs - startMs : 0;
const taskId = matchImproveTaskId(row.started_at, row.completed_at, improveTaskRuns);
summaries.push(projectImproveRunSummary(row, wallTimeMs, taskId));
}
return summaries;
}