import { CheckListIcon, SparklesIcon } from "@hugeicons/core-free-icons"; import { usePlanStore } from "../store/planStore"; /** * Outcome of intercepting a slash command from the composer. * * - `"handled"`: command ran; the composer should NOT send a chat message. * - `"send-prompt"`: replace the user's text with `prompt` and send normally. * - `"none"`: not a slash command; let the composer behave as usual. */ export type SlashOutcome = | { kind: "handled"; toast?: string } | { kind: "send-prompt"; prompt: string; commandName?: string } | { kind: "none" }; const INIT_PROMPT = `Scan this workspace and produce TERAX.md at the workspace root with: - One-paragraph project description. - Build / test / dev commands. - Architecture overview (subsystems, data flow, key dirs). - Conventions worth knowing (naming, patterns, gotchas). - Paths to entry points. Use grep/glob/list_directory/read_file to explore. Cap TERAX.md under 200 lines. Use write_file to create it (will go through normal approval).`; export type SlashCommandMeta = { name: string; invocation: string; label: string; icon: typeof SparklesIcon; }; export const SLASH_COMMANDS: Record = { init: { name: "init", invocation: "/init", label: "Initialize workspace", icon: SparklesIcon, }, plan: { name: "plan", invocation: "/plan", label: "Plan mode", icon: CheckListIcon, }, }; export const TERAX_CMD_RE = /^(?:\n+|$)/; export function wrapWithCommandMarker(prompt: string, name: string): string { return `\n\n${prompt}`; } export function tryRunSlashCommand(input: string): SlashOutcome { const trimmed = input.trim(); const lead = trimmed[0]; if (lead !== "/" && lead !== "#") return { kind: "none" }; const [head, ...rest] = trimmed.slice(1).split(/\s+/); if (lead === "#" && !SLASH_COMMANDS[head]) return { kind: "none" }; const tail = rest.join(" ").trim(); switch (head) { case "plan": { const store = usePlanStore.getState(); if (tail === "off" || tail === "exit") { store.disable(); return { kind: "handled", toast: "Plan mode off" }; } store.toggle(); const nowActive = usePlanStore.getState().active; return { kind: "handled", toast: nowActive ? "Plan mode on" : "Plan mode off", }; } case "init": { return { kind: "send-prompt", prompt: INIT_PROMPT, commandName: "init", }; } default: return { kind: "none" }; } }