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

155 lines (154 loc) • 7.24 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/. /** * Chunk 1.5 (WI-1.5.1, D1.5-4) — the §2.3 "compile-time safety mitigation" * table for AKM's own presentation metadata. EXTENDED by chunk-2 WI-C * (`docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md` §2) to carry the per-`type` * renderer NAME + action builder, so this table becomes the `TYPE_PRESENTATION` * data table §2 mandates ("Renderer/action = data table keyed on the open * `type`, pointing at a named-function core module"). * * The open type token (chunk 1.5) trades the deleted closed asset-type * union's exhaustiveness checking for a runtime lookup. `TYPE_PRESENTATION` * restores that exhaustiveness for AKM's OWN known types (the compiler * demands an entry whenever {@link KnownType} gains a member), while * {@link presentationFor} stays open over `string` so foreign/adapter types * still resolve to a sane generic fallback instead of `undefined`/a throw. * * ── renderer/action provenance (WI-C, §2) ── * * The `renderer` NAMES and `action` builders below are the SINGLE SOURCE OF * TRUTH for search-hit rendering — chunk-3 folded the old mutable renderer/ * action registry singleton into this static table (reached via * {@link presentationFor}). They cover all built-in types — INCLUDING * the 15th type `instruction` (a read-like-knowledge markdown doc added for the * format-family adapters) and the 6 "static-only" mappings * (script/skill/command/agent/knowledge/memory) — §6 "6 renderer mappings". * The workflow action is the one function-valued builder; its * `buildWorkflowAction` body (`output/renderers.ts` — a cycle-sensitive module) * is reproduced inline here rather than imported, to keep this leaf import-free * (only `recognition-util`, D1-5's pure sink); `tests/core/adapter/ * akm-presentation.test.ts` pins the renderer/action values against drift. */ import { isKnownType } from "./recognition-util.js"; /** POSIX-shell single-quote a value — inlined from `output/renderers.ts#shellQuote` (cycle-sensitive; see file header). */ function shellQuote(value) { return `'${value.replace(/'/g, `'\\''`)}'`; } /** Reproduced from `output/renderers.ts#buildWorkflowAction` — the one function-valued `ACTION_BUILDERS.workflow` entry. */ function buildWorkflowAction(ref) { return `Start or resume execution with \`akm workflow run ${shellQuote(ref)}\`.`; } /** * Exhaustive over {@link KnownType} — a HAND-WRITTEN literal, not derived * from `KNOWN_TYPES` programmatically, so the compiler rejects this object * if a `KNOWN_TYPES` member is added without a corresponding entry here * (TypeScript's version of the `§7.3 shipped-assets lint` cross-check the * plan describes for later — "adding a KNOWN_TYPE forces a decision"). * * `renderer`/`action` are the built-in search-hit rendering data (WI-C, §2) — * see the file header. */ export const TYPE_PRESENTATION = { skill: { label: "Skill", renderer: "skill-md", action: (ref) => `akm show ${ref} -> follow the instructions`, fragmentRef: false, }, command: { label: "Command", renderer: "command-md", action: (ref) => `akm show ${ref} -> fill placeholders and dispatch`, fragmentRef: false, }, agent: { label: "Agent", renderer: "agent-md", action: (ref) => `akm show ${ref} -> dispatch with full prompt`, fragmentRef: false, }, knowledge: { label: "Knowledge", renderer: "knowledge-md", action: (ref) => `akm show ${ref} -> read reference material`, }, workflow: { label: "Workflow", renderer: "workflow-md", action: (ref) => buildWorkflowAction(ref), fragmentRef: false, }, script: { label: "Script", renderer: "script-source", action: (ref) => `akm show ${ref} -> execute the run command`, fragmentRef: false, }, memory: { label: "Memory", renderer: "memory-md", action: (ref) => `akm show ${ref} -> recall context` }, env: { label: "Env", renderer: "env-file", action: (ref) => `akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with the whole .env injected (prefer --clean to minimize inherited parent env; child stdout is not redacted). akm env export ${ref} --out <file> writes a sourceable script (values to a file, not stdout).`, }, secret: { label: "Secret", renderer: "secret-file", action: (ref) => `akm show ${ref} -> name only (value never shown); akm secret run ${ref} <VAR> -- <command> -> run with value injected into $VAR`, }, lesson: { label: "Lesson", renderer: "lesson-md", action: (ref) => `akm show ${ref} -> read the lesson and apply when_to_use`, }, task: { label: "Task", renderer: "task-yaml", action: (ref) => `akm show ${ref} -> inspect; akm task run <id> -> run now; akm task enable|disable ${ref} -> change local scheduling`, fragmentRef: false, }, session: { label: "Session", renderer: "session-md", action: (ref) => `akm show ${ref} -> read the session summary; follow the \`access\` frontmatter to open the raw log at \`log_path\``, }, fact: { label: "Fact", renderer: "fact-md", action: (ref) => `akm show ${ref} -> read the stash fact and apply it as durable context`, }, // `instruction` (CLAUDE.md / AGENTS.md) is a read-like-knowledge markdown // doc (spec §6/§7 instruction row, maintainer resolution 2026-07): it REUSES // the `knowledge-md` renderer and mirrors knowledge's read action, so an // instruction hit renders exactly like knowledge instead of the generic // fallback (the parity guard in akm-presentation.test.ts pins this). instruction: { label: "Instruction", renderer: "knowledge-md", action: (ref) => `akm show ${ref} -> read the project instructions`, fragmentRef: false, }, }; /** Generic fallback for a type outside {@link KNOWN_TYPES} — never `undefined`, never a throw. */ const DEFAULT_PRESENTATION = { label: "Asset" }; /** * Open-string lookup with a generic, non-`undefined` fallback (plan §2.3). * `undefined` (no type known yet) and any foreign/adapter type both resolve * to {@link DEFAULT_PRESENTATION}; only AKM's own {@link KNOWN_TYPES} get a * type-specific presentation. */ export function presentationFor(type) { if (type !== undefined && isKnownType(type)) return TYPE_PRESENTATION[type]; return DEFAULT_PRESENTATION; } /** * A missing declaration means a read-like reference or foreign type can expose * a safe selector. Built-in executable and instruction-bearing types opt out * explicitly above: their search match can be a fragment, but the advertised * action needs the parent canonical ref and its complete context. */ export function allowsFragmentRef(type) { return presentationFor(type).fragmentRef !== false; }