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

91 lines (90 loc) • 4.4 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 fs from "node:fs"; import path from "node:path"; import { recognizeMatch } from "../core/adapter/recognize-match.js"; import { assetPathForName, deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, stashDirFor, } from "../core/asset/asset-placement.js"; import { conceptIdFromTypeName } from "../core/asset/resolve-ref.js"; import { hasErrnoCode, isWithin } from "../core/common.js"; import { NotFoundError, UsageError } from "../core/errors.js"; import { walkStashFlat } from "../indexer/walk/walker.js"; /** * Resolve an asset path from a stash directory, type, and name. */ export async function resolveAssetPath(stashDir, type, name) { try { return resolveInTypeDir(stashDir, stashDirFor(type), type, name); } catch (error) { if (!(error instanceof NotFoundError)) throw error; const fallback = await resolveByCanonicalName(stashDir, type, name); if (fallback) return fallback; throw error; } } /** * Try to resolve an asset path within a specific type directory. */ function resolveInTypeDir(stashDir, typeDir, type, name) { const root = path.join(stashDir, typeDir); const target = assetPathForName(type, root, name); const resolvedRoot = resolveAndValidateTypeRoot(root, type, name); const resolvedTarget = path.resolve(target); if (!isWithin(resolvedTarget, resolvedRoot)) { throw new UsageError("Ref resolves outside the stash root.", "PATH_ESCAPE_VIOLATION"); } if (!fs.existsSync(resolvedTarget) || !fs.statSync(resolvedTarget).isFile()) { throw new NotFoundError(`Stash asset not found for ref: ${conceptIdFromTypeName(type, name)}`, "ASSET_NOT_FOUND"); } const realTarget = fs.realpathSync(resolvedTarget); if (!isWithin(realTarget, resolvedRoot)) { throw new UsageError("Ref resolves outside the stash root.", "PATH_ESCAPE_VIOLATION"); } if (!isRelevantAssetFile(type, path.basename(resolvedTarget))) { if (type === "script") { throw new NotFoundError("Script ref must resolve to a file with a supported script extension. Refer to the akm documentation for the complete list of supported script extensions."); } throw new NotFoundError(`Stash asset not found for ref: ${conceptIdFromTypeName(type, name)}`, "ASSET_NOT_FOUND"); } return realTarget; } function resolveAndValidateTypeRoot(root, type, name) { const rootStat = readTypeRootStat(root, type, name); if (!rootStat.isDirectory()) { throw new NotFoundError(`Asset directory for ${type} assets is not accessible — got a file where a directory was expected for ref: ${conceptIdFromTypeName(type, name)}. ` + "Run `akm index` to rebuild the index, or check your source configuration.", "ASSET_NOT_FOUND", "Run `akm bundle list` to see your configured sources and verify the source path exists."); } return fs.realpathSync(root); } function readTypeRootStat(root, type, name) { try { return fs.statSync(root); } catch (error) { if (hasErrnoCode(error, "ENOENT")) { throw new NotFoundError(`Asset not found for ref: ${conceptIdFromTypeName(type, name)}. No ${type} assets are present in the configured source.`, "ASSET_NOT_FOUND", "Run `akm bundle list` to see your configured sources, or `akm index` to rebuild the search index."); } throw error; } } async function resolveByCanonicalName(stashDir, type, name) { const normalizedName = name.replace(/\\/g, "/"); for (const ctx of walkStashFlat(stashDir)) { const match = recognizeMatch(ctx); if (!match || match.type !== type) continue; const canonicalName = deriveCanonicalAssetNameFromStashRoot(type, stashDir, ctx.absPath); if (canonicalName !== normalizedName) continue; const realTarget = fs.realpathSync(ctx.absPath); const resolvedRoot = fs.realpathSync(stashDir); if (!isWithin(realTarget, resolvedRoot)) { throw new UsageError("Ref resolves outside the stash root.", "PATH_ESCAPE_VIOLATION"); } return realTarget; } return undefined; }