Files
can1357 e9888367d1 refactor: migrated packages to internal utility modules and removed external dependencies
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
2026-08-05 13:39:09 +02:00

106 lines
3.7 KiB
TypeScript

import type { AvailableCommand } from "@oh-my-pi/pi-utils/acp";
import type { SkillsSettings } from "../config/settings";
import type { LoadedCustomCommand } from "../extensibility/custom-commands";
import type { ExtensionRunner } from "../extensibility/extensions";
import { getSkillSlashCommandName, type Skill } from "../extensibility/skills";
import { type FileSlashCommand, loadSlashCommands } from "../extensibility/slash-commands";
import { ACP_BUILTIN_RESERVED_NAMES, isAcpBuiltinShadowedName } from "./acp-builtins";
import { BUILTIN_SLASH_COMMANDS_INTERNAL } from "./builtin-registry";
export type AvailableSlashCommandSource = "builtin" | "skill" | "extension" | "custom" | "mcp_prompt" | "file";
export interface InternalAvailableSlashCommand {
name: string;
aliases?: string[];
description?: string;
input?: { hint: string };
subcommands?: Array<{ name: string; description?: string; usage?: string }>;
source: AvailableSlashCommandSource;
}
export interface AvailableCommandsSession {
readonly extensionRunner?: ExtensionRunner;
readonly customCommands: ReadonlyArray<LoadedCustomCommand>;
readonly mcpPromptCommands?: ReadonlyArray<LoadedCustomCommand>;
readonly skills: ReadonlyArray<Skill>;
readonly skillsSettings?: SkillsSettings;
setSlashCommands(slashCommands: FileSlashCommand[]): void;
sessionManager: { getCwd(): string };
}
export async function buildAvailableSlashCommands(
session: AvailableCommandsSession,
loadFileCommands: (cwd: string) => Promise<FileSlashCommand[]> = cwd => loadSlashCommands({ cwd }),
): Promise<InternalAvailableSlashCommand[]> {
const commands: InternalAvailableSlashCommand[] = [];
const seenNames = new Set<string>();
const appendCommand = (command: InternalAvailableSlashCommand): void => {
if (seenNames.has(command.name)) return;
seenNames.add(command.name);
commands.push(command);
};
for (const command of BUILTIN_SLASH_COMMANDS_INTERNAL) {
if (!command.handle) continue;
const hint = command.acpInputHint ?? command.inlineHint;
appendCommand({
name: command.name,
aliases: command.aliases,
description: command.acpDescription ?? command.description,
input: hint ? { hint } : undefined,
subcommands: command.subcommands,
source: "builtin",
});
}
if (session.skillsSettings?.enableSkillCommands) {
for (const skill of session.skills) {
appendCommand({
name: getSkillSlashCommandName(skill),
description: skill.description || `Run ${skill.name} skill`,
input: { hint: "arguments" },
source: "skill",
});
}
}
const runner = session.extensionRunner;
if (runner) {
for (const command of runner.getRegisteredCommands(ACP_BUILTIN_RESERVED_NAMES)) {
if (isAcpBuiltinShadowedName(command.name)) continue;
appendCommand({
name: command.name,
description: command.description ?? "(extension command)",
input: { hint: "arguments" },
source: "extension",
});
}
}
for (const command of session.customCommands) {
const source: AvailableSlashCommandSource = command.path?.startsWith("mcp:") ? "mcp_prompt" : "custom";
appendCommand({
name: command.command.name,
description: command.command.description,
input: { hint: "arguments" },
source,
});
}
const fileCommands = await loadFileCommands(session.sessionManager.getCwd());
session.setSlashCommands(fileCommands);
for (const command of fileCommands) {
appendCommand({ name: command.name, description: command.description, source: "file" });
}
return commands;
}
export function toAcpAvailableCommands(commands: readonly InternalAvailableSlashCommand[]): AvailableCommand[] {
return commands.map(command => ({
name: command.name,
description: command.description ?? "",
input: command.input,
}));
}