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

69 lines (68 loc) • 3.34 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/. import { IMPROVE_AUTONOMY_CONFIG_KEY, isImproveAutonomyEnabled, } from "../../core/config/experimental.js"; /** The lanes `experimental.improveAutonomy` gates. */ export const AUTONOMY_LANES = ["memoryInference", "triagePromote", "memoryCleanup"]; const LANE_REASONS = { memoryInference: "writes derived memory children and rewrites parent frontmatter", triagePromote: "auto-accepts queued proposals into the stash (downgraded to queue)", memoryCleanup: "rewrites belief-state frontmatter and moves files into the cleanup archive", }; /** * The lanes that bypass the strategy config and ask the gate at their own call * site. They have no `processes.<name>.enabled` flag to downgrade, so * {@link applyAutonomyGate} cannot see them — anything reporting the full gated * set has to add these. */ export const DIRECT_AUTONOMY_LANES = ["memoryCleanup"]; function gatedLane(lane) { return { lane, configKey: IMPROVE_AUTONOMY_CONFIG_KEY, reason: LANE_REASONS[lane] }; } /** * Describe lanes for reporting — the warning line, the `improve_skipped` event, * and `akm task doctor` all render the same {@link GatedLane} shape, so the * lane name, config key, and reason cannot drift between the three surfaces. */ export function describeGatedLanes(lanes) { return lanes.map(gatedLane); } /** Configured capabilities that tasks doctor reports behind the autonomy gate. */ export function configuredDirectAutonomyLanes() { return [...DIRECT_AUTONOMY_LANES]; } /** * True when a lane may mutate. Used by the lane that bypasses the strategy * config; the other three are handled by {@link applyAutonomyGate}. */ export function isAutonomyLaneAllowed(_lane, config) { // Every lane shares one opt-in today. The parameter is kept so a call site // names the lane it is asking about — that name is what reaches the operator // in the skip event — and so a future per-lane split does not have to revisit // every caller. return isImproveAutonomyEnabled(config); } /** * Downgrade a strategy config to review-first unless autonomy is opted into. * * Returns the config to actually run plus every downgrade made. With autonomy on * the input is returned untouched and `gated` is empty. */ export function applyAutonomyGate(strategy, config) { if (isImproveAutonomyEnabled(config)) return { config: strategy, gated: [] }; const gated = []; const processes = { ...(strategy.processes ?? {}) }; if (processes.memoryInference?.enabled === true) { processes.memoryInference = { ...processes.memoryInference, enabled: false }; gated.push(gatedLane("memoryInference")); } // Triage stays ENABLED — queued proposals are still triaged, they just are not // auto-accepted. Disabling it would remove review work the user asked for, // which is the opposite of what a review-first default should do. if (processes.triage?.applyMode === "promote") { processes.triage = { ...processes.triage, applyMode: "queue" }; gated.push(gatedLane("triagePromote")); } return { config: { ...strategy, processes }, gated }; }