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
61 lines (60 loc) • 3.46 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/.
/**
* Run-parameter validation against the frozen plan's param schemas, a thin
* consumer of the shared input contract (`src/execution/input-contract.ts`):
* every declared param is optional, and the messages are the workflow ones.
*/
import { UsageError } from "../../core/errors.js";
import { materializeInputFlags, validateInputs, } from "../../execution/input-contract.js";
/** Every declared workflow param as an `InputDeclaration`, `required: false` — workflow params declare nothing required. */
function contractFromPlan(plan) {
const names = plan.params ?? Object.keys(plan.paramSchemas ?? {});
const contract = {};
for (const name of names) {
contract[name] = { schema: plan.paramSchemas?.[name] ?? {}, required: false };
}
return contract;
}
/** A child workflow's `params:` as an input contract, so one normalizer binds every composition surface. */
export { contractFromPlan as workflowParamContract };
function invalidParameter(name, message) {
return new UsageError(`Workflow parameter "--${name}" ${message}.`, "INVALID_FLAG_VALUE");
}
/** The workflow-parameter message/code vocabulary for `materializeInputFlags` (D3-N3) — today's five strings, unchanged. */
const WORKFLOW_PARAMETER_DIAGNOSTICS = {
unknownFlag: (name, declared) => {
const available = declared.map((n) => `--${n}`).join(", ");
return new UsageError(`Unknown workflow parameter "--${name}". Parameter flags must exactly match a declared workflow parameter.`, "UNKNOWN_FLAG", available ? `Declared parameters: ${available}.` : "This workflow declares no parameters.");
},
invalidValue: (name, detail) => invalidParameter(name, detail),
contractViolation: (errors) => new UsageError(`Workflow parameter flags do not satisfy the workflow's declared schemas:\n${errors
.map((error) => ` - ${error.replace(/^\$/, "params")}`)
.join("\n")}`, "INVALID_FLAG_VALUE"),
duplicateNonArray: (name) => invalidParameter(name, "was provided more than once but is not declared as an array"),
malformedJson: (name) => invalidParameter(name, "must contain valid JSON"),
};
/**
* Materialize exact-name CLI parameter flags against the plan being frozen for
* the run. The CLI deliberately carries raw values to this boundary so type
* coercion cannot race or drift from the persisted plan's schemas.
*/
export function materializeWorkflowParameterFlags(plan, flags) {
if (flags.length === 0)
return {};
return materializeInputFlags(contractFromPlan(plan), flags, WORKFLOW_PARAMETER_DIAGNOSTICS);
}
/**
* Validate a run's supplied params against the plan's frozen param schemas.
* Returns a flat list of human-readable, path-prefixed error strings (empty =
* valid). Params the plan does not declare a schema for are not constrained.
*/
export function validateWorkflowParams(plan, params) {
// A plan with no schemas must not start emitting `properties: {}` noise —
// preserved as an explicit early return, even
// though an empty contract would validate to `[]` regardless.
if (!plan.paramSchemas || Object.keys(plan.paramSchemas).length === 0)
return [];
return validateInputs(contractFromPlan(plan), params, { pathRoot: "params" });
}