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
126 lines (125 loc) • 5.05 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/.
/**
* Setup wizard steps for agent platforms and agent-CLI selection: detect
* agent platform config dirs as stash sources, and pick a default agent CLI.
*/
import * as p from "../../cli/clack.js";
import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../../integrations/agent/index.js";
import { detectAgentPlatforms } from "../detect.js";
import { readAgentEngineSelection } from "../engine-config.js";
import { prompt } from "../prompt.js";
// The just-computed source list is threaded through the private setup draft.
export async function stepAgentPlatforms(current) {
const platforms = detectAgentPlatforms();
if (platforms.length === 0) {
p.log.info("No agent platform configurations detected.");
return [];
}
const existingPaths = new Set((current.additionalSources ?? []).map((s) => s.path));
// Filter out platforms already configured
const newPlatforms = platforms.filter((pl) => !existingPaths.has(pl.path));
if (newPlatforms.length === 0) {
p.log.info(`Detected ${platforms.length} agent platform(s), all already configured as bundle sources.`);
return [];
}
const selected = await prompt(() => p.multiselect({
message: "Found agent platform configurations. Add as bundle sources?",
options: newPlatforms.map((pl) => ({
value: pl.path,
label: pl.name,
hint: pl.path,
})),
required: false,
}));
const entries = [];
for (const selectedPath of selected) {
const platform = newPlatforms.find((pl) => pl.path === selectedPath);
if (platform) {
entries.push({
type: "filesystem",
path: platform.path,
name: platform.name.toLowerCase().replace(/\s+/g, "-"),
});
}
}
return entries;
}
/**
* Print a feature capability summary after both connection steps are complete.
*/
export function printCapabilitySummary(smallModelSkipped, agentConfigured) {
const lines = ["Setup complete. Here's what's enabled:", ""];
lines.push(" ✓ akm search, akm curate, akm show, akm index, akm remember — always available");
if (!smallModelSkipped) {
lines.push(" ✓ akm improve, akm remember --enrich — small model configured");
}
else {
lines.push(" ✗ akm improve, akm remember --enrich — run `akm setup` to enable");
}
if (agentConfigured) {
lines.push(" ✓ akm proposal new, akm improve, akm task — agent configured");
}
else {
lines.push(" ✗ akm proposal new, akm improve, akm task — run `akm setup` to enable");
}
p.note(lines.join("\n"), "Feature Summary");
}
export async function stepAgentSelection(current, detections) {
const currentAgentBlock = readAgentEngineSelection(current);
const available = detections.filter((d) => d.available);
if (available.length === 0) {
return currentAgentBlock;
}
const initialValue = pickDefaultAgentProfile(detections, currentAgentBlock?.default) ?? available[0]?.name;
const selectedDefault = await prompt(() => p.select({
message: "Which detected agent CLI should be the default?",
options: [
...available.map((d) => ({
value: d.name,
label: d.name,
hint: d.resolvedPath ?? d.bin,
})),
{ value: "disabled", label: "Disabled", hint: "do not configure a default agent CLI" },
],
initialValue,
}));
if (selectedDefault === "disabled") {
if (!currentAgentBlock?.engines) {
return undefined;
}
return {
...(currentAgentBlock ?? {}),
default: undefined,
};
}
return {
...(currentAgentBlock ?? {}),
default: selectedDefault,
};
}
/**
* Detect installed agent CLIs and produce an updated `agent` config block
* with a sensible `default` (the first detected profile that the user has
* not already overridden).
*
* Pure-ish: file system / PATH probes are routed through `detectFn` so
* tests can drive the branches without touching the real PATH.
*
* @internal Exported for testing only.
*/
export function stepAgentCliDetection(current, detectFn = detectAgentCliProfiles) {
const detections = detectFn(current);
const currentAgentBlock = readAgentEngineSelection(current);
const defaultName = pickDefaultAgentProfile(detections, currentAgentBlock?.default);
// No installed agents found and no existing config → leave block absent.
if (!defaultName && !currentAgentBlock) {
return { detections };
}
const agent = {
...(currentAgentBlock ?? {}),
...(defaultName ? { default: defaultName } : {}),
};
return { agent, detections };
}