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

83 lines (82 loc) • 5.16 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/. /** * The task source version router. * * Runs the bounded YAML front end ONCE (`readBoundedTaskSourceYaml`), reads * `root.version`, and dispatches into `parseTaskSourceV4Document`. The * runtime reads only task source v4 (#987): * * | root `version` | outcome | * |------------------------|-----------------------------------------------------------------| * | `4` | `parseTaskSourceV4Document` — the current grammar | * | `4`, some `schedule[]` entry carries `enabled` (0.9.15's grammar) | `TASK_SOURCE_INVALID` naming `akm migrate apply`, which removes the key | * | `2` or `3` | `TASK_SCHEMA_VERSION_UNSUPPORTED` naming `akm migrate apply`, which converts the file | * | any other number | `TASK_SCHEMA_VERSION_UNSUPPORTED`, naming the migrator | * | absent / not a number | `parseTaskSourceV4Document` — its own `TASK_SOURCE_INVALID` "version is required and must be 4" / "must be exactly 4" wording | * * `akm migrate apply` (`scripts/akm-migrate/`) is the one place a v2/v3 * document, or a v4 document carrying the retired `schedule[].enabled`, is * converted: it rewrites the file once, under a backup. Nothing here converts * in memory. Every caller reports the refusal for that one file — `akm task * sync` keeps reconciling every other task (#867). * * A missing or non-numeric `version:` is a MALFORMED v4 document, not a * legacy one — it routes into the v4 parser so the field error names the * one grammar `src` accepts. The front end's own pre-version failures * (source not a string, source too large, YAML parse/warning/expansion) * render with the label `task source`. */ import { UsageError } from "../../core/errors.js"; import { readBoundedTaskSourceYaml } from "./bounded-document.js"; import { parseTaskSourceV4Document, TASK_SOURCE_V4_VERSION } from "./task-source-v4.js"; /** Read the root `version` field without over-accepting non-number values (e.g. the string `"4"`). */ export function peekTaskSourceVersion(root) { if (root === null || typeof root !== "object" || Array.isArray(root)) return undefined; const value = root.version; return typeof value === "number" ? value : undefined; } const TASK_MIGRATE_HINT = "Run `akm migrate apply --dry-run` to preview the task-v3 to task-source-v4 conversion, then run `akm migrate apply`."; /** A v2/v3 document: `akm migrate apply` converts it; this release reads only v4. */ function legacyVersionError(filePath, version) { return new UsageError(`TASK_SCHEMA_VERSION_UNSUPPORTED: Task at ${filePath} uses task schema version ${version}; this release reads only version 4. Run \`akm migrate apply\` to convert it.`, "TASK_SCHEMA_VERSION_UNSUPPORTED", TASK_MIGRATE_HINT); } function unsupportedVersionError(filePath, version) { return new UsageError(`TASK_SCHEMA_VERSION_UNSUPPORTED: Task at ${filePath} uses task schema version ${version}, which this release does not accept.`, "TASK_SCHEMA_VERSION_UNSUPPORTED", TASK_MIGRATE_HINT); } /** * True when `root`'s `schedule:` is a sequence with at least one mapping * entry that carries an `enabled` key, regardless of that key's value or * type — the shape 0.9.15's v4 grammar accepted and this release's does * not (`schedule[].enabled`). Activation is host-local `scheduler.enabled`, * so the value is never read; `akm migrate apply` removes the key. */ export function v4ScheduleHasRetiredEnabledKey(root) { if (root === null || typeof root !== "object" || Array.isArray(root)) return false; const schedule = root.schedule; if (!Array.isArray(schedule)) return false; return schedule.some((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry) && Object.hasOwn(entry, "enabled")); } /** Parse task source YAML, routing per the table above. */ export function parseTaskSource(input) { const { root, lineAt } = readBoundedTaskSourceYaml(input, { sourceLabel: "task source" }); const version = peekTaskSourceVersion(root); if (version !== undefined && version !== TASK_SOURCE_V4_VERSION) { if (version === 2 || version === 3) throw legacyVersionError(input.filePath, version); throw unsupportedVersionError(input.filePath, version); } if (version === TASK_SOURCE_V4_VERSION && v4ScheduleHasRetiredEnabledKey(root)) { throw new UsageError(`Invalid task source v4 at ${input.filePath}: schedule[].enabled was removed (scheduler activation is host-local config). Run \`akm migrate apply\` to rewrite it.`, "TASK_SOURCE_INVALID", TASK_MIGRATE_HINT); } const documentOptions = { filePath: input.filePath, ...(input.workspaceRoot ? { workspaceRoot: input.workspaceRoot } : {}), lineAt, }; return Object.freeze({ version: 4, v4: parseTaskSourceV4Document(root, documentOptions) }); }