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
79 lines (78 loc) • 3.82 kB
JavaScript
// 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/.
/**
* Shared argument-parsing utilities for the AKM CLI entry point.
*
* These were extracted from `src/cli.ts` to eliminate repetition and keep the
* main CLI file focused on command definitions and routing.
*/
import { UsageError } from "../core/errors.js";
// findCittyTopLevelCommand(Index) + CittyArg(s)DefinitionForScan moved to
// ./invocation (chunk-9 WI-9.9 argv-normalization fold — that cluster had no
// internal imports, so it relocated cleanly); re-exported here so existing
// importers (tests/tasks-embedded.test.ts, commands/read/show.ts) are unaffected.
export { findCittyTopLevelCommand, findCittyTopLevelCommandIndex, } from "./invocation.js";
/**
* Return true when `args._[0]` is a member of `validSet`.
*
* Citty exposes unknown subcommands as `args._[0]` (the first positional).
* Several top-level commands (config, vault, wiki, workflow, tasks) need to
* detect whether a recognised subcommand was supplied so they can show a help
* banner rather than an unhelpful "unknown command" error.
*
* @param args Parsed citty argument object (must have an `_` array).
* @param validSet The set of recognised subcommand names for this command.
*/
export function hasSubcommand(args, validSet) {
const command = Array.isArray(args._) ? args._[0] : undefined;
return typeof command === "string" && validSet.has(command);
}
// ── Numeric flag parsing ─────────────────────────────────────────────────────
/**
* Parse a `--limit`-style flag value into a positive integer.
*
* Returns `undefined` when `raw` is `undefined` or empty (flag not supplied).
* Throws `UsageError` when the raw value is present but not a valid positive
* integer so the caller gets a structured, machine-readable error response.
*
* @param raw The raw string value from citty (may be undefined).
* @param flagName The flag name to include in the error message (e.g. `"--limit"`).
*/
export function parsePositiveIntFlag(raw, flagName = "--limit") {
if (raw === undefined)
return undefined;
const trimmed = raw.trim();
if (!trimmed)
return undefined;
// Strict digits: parseInt stops at the first non-digit, so "10x" silently
// became 10, "3.5" became 3, and "5 apples" became 5 — accepted rather than
// rejected as invalid.
if (!/^\d+$/.test(trimmed)) {
throw new UsageError(`Invalid ${flagName} value: "${raw}". Must be a positive integer.`, "INVALID_FLAG_VALUE");
}
const parsed = parseInt(trimmed, 10);
if (parsed <= 0) {
throw new UsageError(`Invalid ${flagName} value: "${raw}". Must be a positive integer.`, "INVALID_FLAG_VALUE");
}
return parsed;
}
// ── String flag parsing ──────────────────────────────────────────────────────
/**
* Extract a string value from a parsed citty argument object by key.
*
* Returns the trimmed string when present and non-empty, or `undefined`
* otherwise. Eliminates the repeated
* `typeof args.X === "string" && args.X.trim() ? args.X.trim() : undefined`
* pattern throughout the CLI command handlers.
*
* @param args The citty argument object (typed as unknown for flexibility).
* @param key The argument key to look up.
*/
export function getStringArg(args, key) {
const val = args[key];
if (typeof val !== "string")
return undefined;
const trimmed = val.trim();
return trimmed || undefined;
}