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
177 lines (176 loc) • 8.42 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 { sortExecutionJson } from "./json.js";
import { decodeExecutionSourceIdentity, } from "./source.js";
export const RESOLVED_EXECUTION_SCHEMA_VERSION = 1;
const COMMAND_KEYS = ["template", "argumentInput", "content", "source", "extensions"];
const PERSONA_KEYS = ["content", "source", "extensions"];
const ENGINE_KEYS = ["name", "kind", "platform", "settings", "extensions"];
const MODEL_KEYS = ["input", "interpretation", "resolved", "extensions"];
const AUTHORIZATION_KEYS = ["status", "reason", "policy"];
const RUNTIME_KEYS = ["timeoutMs", "workspace", "environment", "settings", "extensions"];
const NOTICE_KEYS = ["code", "severity", "adapter", "field", "message", "details"];
const IDENTITY_KEYS = ["ref", "bundle", "adapter", "file", "hash"];
const OPTIONAL_REQUEST_KEYS = [
"conversation",
"agent",
"persona",
"model",
"inference",
"outputSchema",
"tools",
"extensions",
];
/** Copy the own, defined fields named by `keys`; omitted stays omitted, `null` stays `null`. */
function pick(value, keys) {
const record = value;
const out = {};
for (const key of keys) {
if (Object.hasOwn(record, key) && record[key] !== undefined)
out[key] = record[key];
}
return out;
}
function requireRecord(value, path) {
if (value === null || typeof value !== "object" || Array.isArray(value)) {
throw new TypeError(`${path} must be an object`);
}
return value;
}
export function createResolvedCommand(input) {
if (typeof input.content !== "string")
throw new TypeError("resolved command content must be a string");
return Object.freeze({
template: input.source.content,
...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}),
content: input.content,
source: decodeExecutionSourceIdentity(input.source.identity),
...(input.source.extensions ? { extensions: input.source.extensions } : {}),
});
}
export function createInlineResolvedCommand(input) {
if (typeof input.template !== "string" || typeof input.content !== "string") {
throw new TypeError("inline command template and content must be strings");
}
return Object.freeze({
template: input.template,
...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}),
content: input.content,
source: null,
});
}
export function createResolvedPersona(source) {
return Object.freeze({
content: source.content,
source: decodeExecutionSourceIdentity(source.identity),
...(source.extensions ? { extensions: source.extensions } : {}),
});
}
/** Freeze one request without normalizing away optional-field presence. */
export function createResolvedExecutionRequest(input) {
if (!input.command || !input.engine || !input.authorization || !input.runtime || !input.notices) {
throw new TypeError("resolved execution request requires command, engine, authorization, runtime, and notices");
}
const out = {
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
command: input.command,
engine: input.engine,
authorization: input.authorization,
runtime: input.runtime,
notices: input.notices,
...pick(input, OPTIONAL_REQUEST_KEYS),
};
return Object.freeze(out);
}
/**
* Rehydrate a frozen JSON request after workflow resume/replay. Tolerant of
* unknown keys; refuses only a request written by a newer schema.
*/
export function decodeResolvedExecutionRequest(value) {
const input = requireRecord(value, "resolved execution request");
const version = input.schemaVersion;
if (version !== RESOLVED_EXECUTION_SCHEMA_VERSION) {
throw new TypeError(typeof version === "number" && version > RESOLVED_EXECUTION_SCHEMA_VERSION
? `resolved execution request schemaVersion ${version} was written by a newer akm; upgrade akm to run it`
: `unsupported resolved execution schemaVersion: ${String(version)}`);
}
const command = requireRecord(input.command, "command");
if (typeof command.template !== "string" || typeof command.content !== "string") {
throw new TypeError("command template and content must be strings");
}
const engine = requireRecord(input.engine, "engine");
if (typeof engine.name !== "string" || (engine.kind !== "agent" && engine.kind !== "sdk" && engine.kind !== "llm")) {
throw new TypeError("engine.name must be a string and engine.kind must be agent, sdk, or llm");
}
const notices = input.notices;
if (!Array.isArray(notices))
throw new TypeError("notices must be an array");
const request = {
command: Object.freeze({
...pick(command, COMMAND_KEYS),
source: command.source === null ? null : decodeExecutionSourceIdentity(command.source, "command.source"),
}),
engine: Object.freeze(pick(engine, ENGINE_KEYS)),
authorization: Object.freeze(pick(requireRecord(input.authorization, "authorization"), AUTHORIZATION_KEYS)),
runtime: Object.freeze(pick(requireRecord(input.runtime, "runtime"), RUNTIME_KEYS)),
notices: Object.freeze(notices.map((notice, index) => Object.freeze(pick(requireRecord(notice, `notices[${index}]`), NOTICE_KEYS)))),
};
if (Array.isArray(input.conversation)) {
request.conversation = Object.freeze(input.conversation.map((message, index) => Object.freeze(pick(requireRecord(message, `conversation[${index}]`), ["role", "content"]))));
}
if (Object.hasOwn(input, "agent") && input.agent !== undefined)
request.agent = input.agent;
if (Object.hasOwn(input, "persona") && input.persona !== undefined) {
if (input.persona === null)
request.persona = null;
else {
const persona = requireRecord(input.persona, "persona");
request.persona = Object.freeze({
...pick(persona, PERSONA_KEYS),
source: decodeExecutionSourceIdentity(persona.source, "persona.source"),
});
}
}
if (Object.hasOwn(input, "model") && input.model !== undefined) {
request.model = input.model === null ? null : Object.freeze(pick(requireRecord(input.model, "model"), MODEL_KEYS));
}
for (const key of ["inference", "outputSchema", "tools", "extensions"]) {
if (Object.hasOwn(input, key) && input[key] !== undefined)
request[key] = input[key];
}
return createResolvedExecutionRequest(request);
}
/** Stable bytes for freeze hashes and entrypoint-equivalence projections. */
export function canonicalResolvedExecutionRequest(request) {
const wire = {
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
command: {
...pick(request.command, COMMAND_KEYS),
source: request.command.source === null ? null : pick(request.command.source, IDENTITY_KEYS),
},
engine: pick(request.engine, ENGINE_KEYS),
authorization: pick(request.authorization, AUTHORIZATION_KEYS),
runtime: pick(request.runtime, RUNTIME_KEYS),
notices: request.notices.map((notice) => pick(notice, NOTICE_KEYS)),
};
if (request.conversation !== undefined) {
wire.conversation = request.conversation.map((message) => ({ role: message.role, content: message.content }));
}
if (Object.hasOwn(request, "agent") && request.agent !== undefined)
wire.agent = request.agent;
if (Object.hasOwn(request, "persona") && request.persona !== undefined) {
wire.persona =
request.persona === null
? null
: { ...pick(request.persona, PERSONA_KEYS), source: pick(request.persona.source, IDENTITY_KEYS) };
}
if (Object.hasOwn(request, "model") && request.model !== undefined) {
wire.model = request.model === null ? null : pick(request.model, MODEL_KEYS);
}
for (const key of ["inference", "outputSchema", "tools", "extensions"]) {
if (Object.hasOwn(request, key) && request[key] !== undefined)
wire[key] = request[key];
}
return `${JSON.stringify(sortExecutionJson(wire))}\n`;
}