@phren/cli
Version:
Knowledge layer for AI agents - CLI, MCP server, and data layer
126 lines (125 loc) • 4.65 kB
JavaScript
// Help formatters. Pure functions over the command registry.
import { commandsForModules, TOPIC_ORDER, DOC_TOPICS, lookupCommand, } from "./cli-registry.js";
const TOPIC_TITLES = {
core: "Core commands",
projects: "Projects",
skills: "Skills",
hooks: "Hooks",
config: "Configuration",
maintain: "Maintenance",
setup: "Setup",
stores: "Stores",
team: "Team",
};
const ALIGN_COL = 40;
function pad(usage, summary) {
const text = " " + usage;
if (!summary)
return text;
const gap = Math.max(2, ALIGN_COL - text.length);
return text + " ".repeat(gap) + summary;
}
function visibleCommands(snapshot) {
return commandsForModules(snapshot).filter((c) => !c.hidden);
}
function commandsInTopic(topic, snapshot) {
return visibleCommands(snapshot).filter((c) => c.topic === topic);
}
function renderCommandLine(cmd) {
return pad(cmd.usage, cmd.summary);
}
function renderCheatSheetLine(cmd) {
return pad(cmd.cheatUsage ?? cmd.usage, cmd.summary);
}
function renderSubcommandLine(sub) {
return pad(sub.usage, sub.summary);
}
function renderCommandWithSubs(cmd) {
const lines = [renderCommandLine(cmd)];
if (cmd.subcommands?.length) {
for (const sub of cmd.subcommands) {
lines.push(renderSubcommandLine(sub));
}
}
return lines;
}
// ── Cheat sheet (phren --help) ───────────────────────────────────────────────
export function formatCheatSheet(snapshot) {
const lines = [];
lines.push("phren - persistent memory for AI agents");
lines.push("");
lines.push(pad("phren", "Interactive memory shell"));
for (const cmd of visibleCommands(snapshot)) {
if (!cmd.featured)
continue;
lines.push(renderCheatSheetLine(cmd));
}
lines.push("");
lines.push(pad("phren manage <command>", "Alias for the top-level commands above"));
lines.push(pad("phren mem <command>", "Alias for `phren manage`"));
lines.push("");
lines.push(pad("phren help <topic>", "Detailed help"));
lines.push(`Topics: ${[...TOPIC_ORDER, ...Object.keys(DOC_TOPICS), "all"].join(", ")}`);
lines.push("");
return lines.join("\n");
}
// ── Topic help (phren help <topic>) ──────────────────────────────────────────
export function formatTopic(topic, snapshot) {
const cmds = commandsInTopic(topic, snapshot);
const lines = [];
lines.push(`${TOPIC_TITLES[topic]}:`);
for (const cmd of cmds) {
for (const line of renderCommandWithSubs(cmd)) {
lines.push(line);
}
}
lines.push("");
return lines.join("\n");
}
// ── Doc topic (phren help env) ───────────────────────────────────────────────
export function formatDocTopic(name) {
return DOC_TOPICS[name] ?? null;
}
// ── Single command (phren <name> --help / phren help <name>) ─────────────────
export function formatCommand(name, snapshot) {
const cmd = lookupCommand(name, snapshot);
if (!cmd)
return null;
const lines = [];
lines.push(`${cmd.usage}`);
lines.push(` ${cmd.summary}`);
if (cmd.subcommands?.length) {
lines.push("");
lines.push("Subcommands:");
for (const sub of cmd.subcommands) {
lines.push(renderSubcommandLine(sub));
}
}
lines.push("");
return lines.join("\n");
}
// ── Full help (phren help all) ───────────────────────────────────────────────
export function formatFullHelp(snapshot) {
const lines = [];
lines.push("phren - persistent knowledge for your agents");
lines.push("");
lines.push("Usage:");
lines.push(pad("phren", "Interactive shell"));
for (const cmd of visibleCommands(snapshot)) {
if (!cmd.featured)
continue;
lines.push(renderCheatSheetLine(cmd));
}
lines.push("");
for (const topic of TOPIC_ORDER) {
const cmds = commandsInTopic(topic, snapshot);
if (!cmds.length)
continue;
lines.push(formatTopic(topic, snapshot));
}
for (const [docName, body] of Object.entries(DOC_TOPICS)) {
lines.push(`${docName.charAt(0).toUpperCase()}${docName.slice(1)} reference:`);
lines.push(body);
}
return lines.join("\n");
}