UNPKG

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

81 lines (80 loc) • 4 kB
// 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/. /** Usage rows (search / show / curate / feedback) in the window, oldest first. */ export function listUsageEventRows(db, filter) { const sourceSql = filter.source === undefined ? "" : " AND source = ?"; const sourceParams = filter.source === undefined ? [] : [filter.source]; // `created_at` has whole-second resolution, so a row written during the // bound's own second (e.g. `--until` defaulting to now) is still inside the // half-open window: round a fractional bound up to the next second. const untilMs = Date.parse(filter.untilIso); const untilBound = new Date(Math.ceil(untilMs / 1000) * 1000).toISOString(); return db .prepare(`SELECT id, event_type, query, entry_id, entry_ref, signal, metadata, source, created_at FROM usage_events WHERE datetime(created_at) >= datetime(?) AND datetime(created_at) < datetime(?)${sourceSql} ORDER BY datetime(created_at), id`) .all(filter.sinceIso, untilBound, ...sourceParams); } /** * `select` events (a show within 60 s of a search that returned the ref) in the * window. The events stream stores the ref as the user typed it (often * bundle-less), so the caller resolves it to the durable ref. */ export function listSelectEvents(db, sinceIso, untilIso) { return db .prepare(`SELECT ts, ref FROM events WHERE event_type = 'select' AND ref IS NOT NULL AND ts >= ? AND ts < ? ORDER BY id`) .all(sinceIso, untilIso); } /** `index_completed` events (one per `akm index` run) in the window, oldest first. */ export function listIndexCompletedEvents(db, sinceIso, untilIso) { return db .prepare(`SELECT ts, metadata_json FROM events WHERE event_type = 'index_completed' AND ts >= ? AND ts < ? ORDER BY id`) .all(sinceIso, untilIso); } /** The `limit` assets with the lowest `outcome_score`, ties broken by ref. */ export function listLowestOutcomeAssets(db, limit) { return db .prepare(`SELECT asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate, negative_feedback_count, accepted_change_count, outcome_score, updated_at FROM asset_outcome ORDER BY outcome_score ASC, asset_ref ASC LIMIT ?`) .all(limit); } /** Proposal counts by status, for proposals last updated in the window. */ export function countProposalsByStatus(db, sinceIso, untilIso) { const rows = db .prepare(`SELECT status, COUNT(*) AS n FROM proposals WHERE updated_at >= ? AND updated_at < ? GROUP BY status ORDER BY status`) .all(sinceIso, untilIso); return Object.fromEntries(rows.map((row) => [row.status, row.n])); } /** * Workflow runs created in the window by status, and the tokens their unit * attempts spent by model. Attempts, not the unit projection, so a retried * unit keeps the tokens of every attempt. */ export function summarizeWorkflowRuns(db, sinceIso, untilIso) { const statusRows = db .prepare(`SELECT status, COUNT(*) AS n FROM workflow_runs WHERE created_at >= ? AND created_at < ? GROUP BY status ORDER BY status`) .all(sinceIso, untilIso); const modelRows = db .prepare(`SELECT COALESCE(model, 'unattributed') AS model, SUM(tokens) AS tokens FROM workflow_run_unit_attempts WHERE tokens IS NOT NULL AND started_at >= ? AND started_at < ? GROUP BY COALESCE(model, 'unattributed') ORDER BY model`) .all(sinceIso, untilIso); return { runs: statusRows.reduce((sum, row) => sum + row.n, 0), byStatus: Object.fromEntries(statusRows.map((row) => [row.status, row.n])), tokens: modelRows.reduce((sum, row) => sum + row.tokens, 0), byModel: Object.fromEntries(modelRows.map((row) => [row.model, row.tokens])), }; }