Files
feynman/extensions/research-tools/help.ts
Advait Paliwal f5570b4e5a Rename .pi to .feynman, rename citation agent to verifier, add website, skills, and docs
- Rename project config dir from .pi/ to .feynman/ (Pi supports this via piConfig.configDir)
- Rename citation agent to verifier across all prompts, agents, skills, and docs
- Add website with homepage and 24 doc pages (Astro + Tailwind)
- Add skills for all workflows (deep-research, lit, review, audit, replicate, compare, draft, autoresearch, watch, jobs, session-log, agentcomputer)
- Add Pi-native prompt frontmatter (args, section, topLevelCli) and read at runtime
- Remove sync-docs generation layer — docs are standalone
- Remove metadata/prompts.mjs and metadata/packages.mjs — not needed at runtime
- Rewrite README and homepage copy
- Add environment selection to /replicate before executing
- Add prompts/delegate.md and AGENTS.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:35:35 -07:00

94 lines
2.9 KiB
TypeScript

import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import {
extensionCommandSpecs,
formatSlashUsage,
getExtensionCommandSpec,
livePackageCommandGroups,
readPromptSpecs,
} from "../../metadata/commands.mjs";
import { APP_ROOT } from "./shared.js";
type HelpCommand = { usage: string; description: string };
type HelpSection = { title: string; commands: HelpCommand[] };
function buildHelpSections(pi: ExtensionAPI): HelpSection[] {
const liveCommands = new Map(pi.getCommands().map((command) => [command.name, command]));
const promptSpecs = readPromptSpecs(APP_ROOT);
const sections = new Map<string, HelpCommand[]>();
for (const command of promptSpecs.filter((entry) => entry.section !== "Internal")) {
const live = liveCommands.get(command.name);
if (!live) continue;
const items = sections.get(command.section) ?? [];
items.push({
usage: formatSlashUsage(command),
description: live.description ?? command.description,
});
sections.set(command.section, items);
}
for (const command of extensionCommandSpecs.filter((entry) => entry.publicDocs)) {
const live = liveCommands.get(command.name);
if (!live) continue;
const items = sections.get(command.section) ?? [];
items.push({
usage: formatSlashUsage(command),
description: live.description ?? command.description,
});
sections.set(command.section, items);
}
const ownedNames = new Set([
...promptSpecs.filter((entry) => entry.section !== "Internal").map((entry) => entry.name),
...extensionCommandSpecs.filter((entry) => entry.publicDocs).map((entry) => entry.name),
]);
for (const group of livePackageCommandGroups) {
const commands: HelpCommand[] = [];
for (const spec of group.commands) {
const command = liveCommands.get(spec.name);
if (!command || ownedNames.has(command.name)) continue;
commands.push({
usage: spec.usage,
description: command.description ?? "",
});
}
if (commands.length > 0) {
sections.set(group.title, commands);
}
}
return [
"Research Workflows",
"Project & Session",
"Setup",
"Agents & Delegation",
"Bundled Package Commands",
]
.map((title) => ({ title, commands: sections.get(title) ?? [] }))
.filter((section) => section.commands.length > 0);
}
export function registerHelpCommand(pi: ExtensionAPI): void {
pi.registerCommand("help", {
description:
getExtensionCommandSpec("help")?.description ??
"Show grouped Feynman commands and prefill the editor with a selected command.",
handler: async (_args, ctx) => {
const sections = buildHelpSections(pi);
const items = sections.flatMap((section) => [
`--- ${section.title} ---`,
...section.commands.map((cmd) => `${cmd.usage}${cmd.description}`),
]);
const selected = await ctx.ui.select("Feynman Help", items);
if (!selected || selected.startsWith("---")) return;
const usage = selected.split(" — ")[0];
ctx.ui.setEditorText(usage);
ctx.ui.notify(`Prefilled ${usage}`, "info");
},
});
}