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

126 lines (125 loc) • 5.65 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/. /** * Pure improve planning projections. * * Filesystem/database snapshot collection stays in `preparation.ts`; this leaf * receives immutable values and is shared by dry preview and live execution. * Keeping the limit/lane projection here prevents the two entry paths from * independently reconstructing "what would run". */ import { conceptIdFromTypeName } from "../../core/asset/resolve-ref.js"; import { parseMemoryName } from "./memory/derived-ref.js"; function canonicalMemoryConceptRef(ref) { const name = parseMemoryName(ref); return name === undefined ? undefined : conceptIdFromTypeName("memory", name); } /** * Project the refs that survive memory cleanup from either the planned archive * candidates (dry estimate) or the archives that actually succeeded (live * execution). Cleanup records use the legacy `memory:<name>` identity channel, * while improve candidates use canonical `memories/<name>` concept refs, so * both sides are normalized before comparison. */ export function projectMemoryCleanup(input) { const cleanupRefs = input.allowApply ? (input.mode === "estimate" ? input.candidateRefs : input.archivedRefs) : []; const removed = new Set(cleanupRefs.map(canonicalMemoryConceptRef).filter((ref) => ref !== undefined)); const postCleanupRefs = input.plannedRefs.filter((entry) => { const canonical = canonicalMemoryConceptRef(entry.ref); return canonical === undefined || !removed.has(canonical); }); return { postCleanupRefs, gate: { name: "cleanup", removed: input.plannedRefs.length - postCleanupRefs.length, reason: !input.allowApply ? "memory cleanup archive application is autonomy-gated" : input.mode === "estimate" ? "would be archived by memory cleanup" : "archived by memory cleanup", }, }; } /** Apply the final global cap to an already-ranked candidate snapshot. */ export function selectEffectiveImproveRefs(args) { const distillOnlySet = new Set(args.distillOnlyRefs.map((entry) => entry.ref)); const reflectAndDistill = args.rankedRefs.filter((entry) => !distillOnlySet.has(entry.ref)); const distillOnly = args.rankedRefs.filter((entry) => distillOnlySet.has(entry.ref)); // Preserve the established live ordering: ordinary reflect-path refs first, // then distill-only refs, with the rank order stable inside each partition. const allLoopRefs = [...reflectAndDistill, ...distillOnly]; const loopRefs = args.limit === undefined ? allLoopRefs : allLoopRefs.slice(0, args.limit); return { loopRefs, distillOnlyRefs: distillOnly, limitRemoved: allLoopRefs.length - loopRefs.length, }; } /** Build the stable public plan DTO from one invocation's selector observation. */ export function buildImproveExecutionPlan(input) { const effectiveRefs = input.effectiveRefs.map((entry) => ({ ref: entry.ref, lane: input.distillOnlyRefs.has(entry.ref) ? "distill-only" : (entry.eligibilitySource ?? "unknown"), reason: entry.reason, })); return { mode: input.dryRun ? "estimate" : "execution", dispatch: !input.dryRun, snapshot: { ...input.snapshot }, candidates: { rawInScope: input.rawInScope, selected: input.selectedRefs.length, effective: effectiveRefs.length, }, limits: { configured: { ...input.configuredLimits }, ...(input.effectiveLimit !== undefined ? { effective: input.effectiveLimit } : {}), // The replay lane is gone; the published plan keeps a zero allowance. additiveReplayAllowance: 0, ...(input.effectiveLimit !== undefined ? { totalCeiling: input.effectiveLimit } : {}), }, gates: input.gates.map((gate) => ({ ...gate })), effectiveRefs, processes: input.processes.map((row) => ({ ...row })), ...(input.proactive ? { proactive: { ...input.proactive, configured: { ...input.proactive.configured }, effective: { ...input.proactive.effective }, selectedRefs: [...input.proactive.selectedRefs], }, } : {}), consolidation: { ...input.consolidation, configured: { ...input.consolidation.configured }, effective: { ...input.consolidation.effective }, gates: { profile: { ...input.consolidation.gates.profile }, minimumPool: { ...input.consolidation.gates.minimumPool }, delta: { ...input.consolidation.gates.delta }, }, }, stages: [ { name: "consolidation", wouldRun: input.consolidation.wouldRun, reason: input.consolidation.reason, }, { name: "extract", wouldRun: input.stageConfig.extract.enabled, reason: input.stageConfig.extract.reason, }, { name: "memory-inference", wouldRun: input.stageConfig.memoryInference.enabled, reason: input.stageConfig.memoryInference.reason, }, ], triage: { ...input.triage }, }; }