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
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/.
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;
}