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

115 lines (114 loc) • 5.31 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/. /** Deterministic lesson repairs and checks for `akm distill` (pure; the caller keeps the lesson-path guard). */ import { assembleAssetFromString, serializeFrontmatterQuoted } from "../../../core/asset/asset-serialize.js"; import { parseFrontmatter } from "../../../core/asset/frontmatter.js"; import { repairTruncatedDescription } from "../../../core/text-truncation.js"; import { isValidDescription, isValidWhenToUse, lessonQualityIssues, } from "../../proposal/validators/proposal-quality-validators.js"; /** * Fill a missing description / when_to_use from body lines that pass their * validators — small models often write a good body with no header. Never a * placeholder: those produced hundreds of broken proposals; a field nothing * qualifies for stays missing for lint to reject. */ export function autoRepairLessonFrontmatter(content, inputRef) { const parsed = parseFrontmatter(content); const fm = (parsed.data ?? {}); const missingDesc = typeof fm.description !== "string" || !fm.description.trim(); const missingWtu = typeof fm.when_to_use !== "string" || !fm.when_to_use.trim(); if (!missingDesc && !missingWtu) return content; const body = parsed.content.trim(); const stripMd = (l) => l .replace(/\*\*([^*]+)\*\*/g, "$1") .replace(/\*([^*]+)\*/g, "$1") .replace(/`([^`]+)`/g, "$1") .replace(/^[#*\->_]+\s*/, "") .replace(/:\s*$/, "") .trim(); // Leaked frontmatter lines in the body would yield `description: "description: …"`. const isYamlLike = (l) => /^---/.test(l) || /^[a-z_]+:\s/i.test(l); const bodyLines = body.split("\n").map(stripMd); let descLine; for (const l of bodyLines) { if (isYamlLike(l)) continue; if (l.length <= 10 || l.length >= 400) continue; if (isValidDescription(l, inputRef).ok) { descLine = l; break; } } let wtuLine; for (const l of bodyLines) { if (!/^(when |use when|apply when)/i.test(l)) continue; if (l.length >= 400) continue; if (isValidWhenToUse(l, inputRef).ok) { wtuLine = l; break; } } const repairedFm = { ...fm, ...(missingDesc && descLine ? { description: descLine } : {}), ...(missingWtu && wtuLine ? { when_to_use: wtuLine } : {}), }; const fmLines = serializeFrontmatterQuoted(repairedFm); if (Object.keys(repairedFm).length > 0) { return assembleAssetFromString(fmLines, body); } return content; } /** * Swap a conditional description ("When X, do Y") with a declarative * when_to_use — mis-fielded, as the description validator says — when both * then pass; this recovers most `^when` rejections at no LLM cost. */ export function autoSwapDescriptionWhenToUse(content, inputRef) { const parsedSwap = parseFrontmatter(content); const fmSwap = (parsedSwap.data ?? {}); const descRaw = typeof fmSwap.description === "string" ? fmSwap.description.trim() : ""; const wtuRaw = typeof fmSwap.when_to_use === "string" ? fmSwap.when_to_use.trim() : ""; const descStartsConditional = /^(when|if)\b/i.test(descRaw); const wtuStartsConditional = /^(when|if)\b/i.test(wtuRaw); if (descStartsConditional && !wtuStartsConditional && wtuRaw.length > 0) { const swappedDescCheck = isValidDescription(wtuRaw, inputRef); const swappedWtuCheck = isValidWhenToUse(descRaw, inputRef); if (swappedDescCheck.ok && swappedWtuCheck.ok) { const swappedFm = { ...fmSwap, description: wtuRaw, when_to_use: descRaw, }; const swappedFmLines = serializeFrontmatterQuoted(swappedFm); return { content: assembleAssetFromString(swappedFmLines, parsedSwap.content), swapped: 1 }; } } return { content, swapped: 0 }; } /** Complete a description cut mid-sentence from its own text or the body (#556); a complete one is untouched. */ export function repairLessonDescriptionTruncation(content) { const parsedRepair = parseFrontmatter(content); const fmRepair = (parsedRepair.data ?? {}); const descRepairRaw = typeof fmRepair.description === "string" ? fmRepair.description : ""; if (!descRepairRaw) return content; const repaired = repairTruncatedDescription(descRepairRaw, parsedRepair.content); if (repaired === descRepairRaw) return content; const repairedFmLines = serializeFrontmatterQuoted({ ...fmRepair, description: repaired }); return assembleAssetFromString(repairedFmLines, parsedRepair.content); } /** The shared lesson quality checks, for a lesson whose lint pass was clean. */ export function collectLessonQualityFindings(content, inputRef) { const fm = (parseFrontmatter(content).data ?? {}); return lessonQualityIssues(fm, content, inputRef).map((issue) => ({ kind: issue.kind, field: issue.field, message: `Distilled lesson for ${inputRef}${issue.text}`, })); }