import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; import { MinimalEditor, editorConfig, getEditorRef, setContextStats, updateGitInfo, ContextStats, } from "./MinimalEditor"; import { createEmptyFooter } from "./FooterManager"; import type { AgentEndEvent } from "@mariozechner/pi-coding-agent"; import type { ExtensionEvent } from "@mariozechner/pi-coding-agent"; import * as fs from "node:fs"; import * as path from "node:path"; import * as os from "node:os"; /** Help text for /prompt-prefix command */ const PROMPT_HELP = `%d=dir %D=path %cf%=ctx% %gb%=branch %gs%=git %td%=time %%=%`; /** Config file path */ const CONFIG_DIR = path.join(os.homedir(), ".config", "pi-ui-minimal"); const CONFIG_FILE = path.join(CONFIG_DIR, "config.json"); interface Config { prefix: string; } /** Load config from file */ function loadConfig(): Config { try { if (fs.existsSync(CONFIG_FILE)) { const data = fs.readFileSync(CONFIG_FILE, "utf-8"); const config = JSON.parse(data) as Config; if (config.prefix) { return config; } } } catch { // Ignore errors, use defaults } return { prefix: "%d > " }; } /** Save config to file */ function saveConfig(config: Config): void { try { fs.mkdirSync(CONFIG_DIR, { recursive: true }); fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8"); } catch { // Ignore write errors } } /** Hides default footer, removes editor borders, adds bold CWD prompt. */ export default function minimalFooter(pi: ExtensionAPI) { pi.on("session_start", (_event, ctx) => { // Hide default footer ctx.ui.setFooter(() => createEmptyFooter()); // Set custom editor component ctx.ui.setEditorComponent((tui, theme, keybindings) => new MinimalEditor(tui, theme as any, keybindings)); // Update cwd in config editorConfig.cwd = ctx.cwd; // Update git info on session start updateGitInfo(); // Load saved config (lowest priority) const savedConfig = loadConfig(); // PI_PS1 env var overrides saved config const ps1 = process.env.PI_PS1; if (ps1?.trim()) { editorConfig.prefix = ps1.trimStart(); } else { editorConfig.prefix = savedConfig.prefix; } // Subscribe to message_end events to update context fill percentage pi.on("message_end", (_evt: ExtensionEvent, ctx) => { const usage = ctx.getContextUsage(); if (usage && usage.percent !== null) { setContextStats({ tokens: usage.tokens ?? 0, contextWindow: usage.contextWindow, percent: Math.round(usage.percent), }); getEditorRef()?.invalidate(); } }); // Parse prompt argument: strip outer quotes if present, preserve internal spaces function parsePromptArg(input: string | undefined): string | null { if (!input) return null; // Strip outer matching quotes (single or double) const trimmed = input.trim(); if ( trimmed.length >= 2 && ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) ) { return trimmed.slice(1, -1); } return input; // Return original with spaces preserved } // Register /prompt-prefix command pi.registerCommand("prompt-prefix", { description: `Set prompt prefix (${PROMPT_HELP})`, handler: async (args, _ctx) => { const prefix = parsePromptArg(args); if (prefix !== null) { editorConfig.prefix = prefix; saveConfig({ prefix: editorConfig.prefix }); _ctx.ui.notify(`Prompt set: "${editorConfig.prefix}"`, "info"); getEditorRef()?.invalidate(); } else { _ctx.ui.notify(`Prompt: "${editorConfig.prefix}"\n${PROMPT_HELP}`, "info"); } }, }); }); } // Re-export for consumers export { MinimalEditor, editorConfig, setContextStats, getContextStats, setGitInfo, getGitInfo, updateGitInfo, ContextStats, GitInfo, } from "./MinimalEditor"; export { createEmptyFooter, hideFooter } from "./FooterManager";