// biome-ignore-all lint/suspicious/noExplicitAny: necessary for TuiPluginApi dynamic state access // biome-ignore-all lint/a11y/noStaticElementInteractions: TUI elements, not DOM /** @jsxImportSource @opentui/solid */ import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from '@opencode-ai/plugin/tui' import { createMemo, createSignal, For, Show } from 'solid-js' // ── Static Data ────────────────────────────────────────────────────────────── async function readPantheonVersion(api: TuiPluginApi): Promise { // Try 1: package.json via worktree absolute path try { const worktree = ((api.state as any).path?.worktree ?? '') as string const filePath = worktree ? `${worktree}/package.json` : 'package.json' const result = await api.client.file.read({ query: { path: filePath } }) const content = typeof result.content === 'string' ? result.content : String(result.content ?? '') const match = content.match(/"version":\s*"([^"]+)"/) if (match?.[1]) return match[1] } catch { /* fall through */ } // Try 2: git describe (tag-based version) try { const proc = (api as any).client?.process if (typeof proc?.exec === 'function') { const result = await proc.exec({ command: 'git', args: ['describe', '--tags', '--always'] }) const stdout = (result.stdout ?? result.output ?? '') as string const tag = stdout.trim().replace(/^v/, '') if (tag) return tag } } catch { /* fall through */ } return '4.0.0' } const COMMANDS = [ { name: '/pantheon', desc: 'Council synthesis' }, { name: '/pantheon-status', desc: 'System status' }, { name: '/pantheon-audit', desc: 'Full audit (v2)' }, { name: '/pantheon-cancel', desc: 'Cancel task' }, { name: '/pantheon-deepwork', desc: 'Deep work mode' }, { name: '/pantheon-focus', desc: 'Focus on scope' }, { name: '/pantheon-optimize', desc: 'Optimize + archive' }, { name: '/pantheon-sketch', desc: 'Quick prototype' }, { name: '/pantheon-install', desc: 'Install agents' }, { name: '/pantheon-update', desc: 'Create release' }, { name: '/pantheon-remember', desc: 'Memory store/recall' }, { name: '/pantheon-search', desc: 'Memory search' }, { name: '/pantheon-consolidate', desc: 'Merge memories' }, { name: '/pantheon-forget', desc: 'Compress memories' }, ] as const const AGENTS = [ { name: 'zeus', tier: 'default' as const, role: 'Orchestrator' }, { name: 'athena', tier: 'premium' as const, role: 'Strategic planner' }, { name: 'apollo', tier: 'fast' as const, role: 'Codebase discovery' }, { name: 'hermes', tier: 'default' as const, role: 'Backend' }, { name: 'aphrodite', tier: 'default' as const, role: 'Frontend' }, { name: 'demeter', tier: 'default' as const, role: 'Database' }, { name: 'themis', tier: 'premium' as const, role: 'Quality & security' }, { name: 'prometheus', tier: 'default' as const, role: 'Infrastructure' }, { name: 'hephaestus', tier: 'default' as const, role: 'AI pipelines' }, { name: 'nyx', tier: 'fast' as const, role: 'Observability' }, { name: 'gaia', tier: 'fast' as const, role: 'Remote sensing' }, { name: 'iris', tier: 'fast' as const, role: 'GitHub operations' }, { name: 'mnemosyne', tier: 'fast' as const, role: 'Memory bank' }, { name: 'talos', tier: 'fast' as const, role: 'Hotfixes' }, ] as const // ── Helpers ────────────────────────────────────────────────────────────────── function _fmt(v: number): string { return new Intl.NumberFormat('en-US').format(Math.max(0, Math.round(v))) } function safeNum(v: unknown): number { return typeof v === 'number' && Number.isFinite(v) ? v : 0 } // ── View ───────────────────────────────────────────────────────────────────── function View(props: { api: TuiPluginApi; sessionID: string; version: string }) { const [showCommands, setShowCommands] = createSignal(false) const [showAgents, setShowAgents] = createSignal(false) const [showConfig, setShowConfig] = createSignal(false) const [showMemory, setShowMemory] = createSignal(false) const theme = () => props.api.theme.current const branch = createMemo(() => props.api.state.vcs?.branch ? `\u2387 ${props.api.state.vcs.branch}` : null, ) // Config info const configInfo = createMemo(() => { const cfg = (props.api.state as any).config if (!cfg) return null return { plugins: Array.isArray(cfg.plugin) ? cfg.plugin : [], mcpCount: cfg.mcp ? Object.keys(cfg.mcp).length : 0, autoCompaction: cfg.compaction?.auto === true, } }) // Memory info const memoryInfo = createMemo(() => { const mem = (props.api.state as any).memory if (mem) { const entries = safeNum(mem?.entries) || safeNum(mem?.count) return entries > 0 ? { entries } : null } return null }) return ( {/* ══ Header ══ */} ⚡ Pantheon · {props.version} {/* ══ Branch (conditional) ══ */} {(b) => ( {b()} )} {/* ══ Commands (collapsible) ══ */} setShowCommands((x) => !x)}> {showCommands() ? '\u25bc' : '\u25b6'} Commands ({COMMANDS.length}) {(cmd) => ( { e.stopPropagation() try { const cmdApi = (props.api as any).command const cmdName = cmd.name.replace('/', '') if (cmdApi?.trigger?.(cmdName)) return } catch {} // Fallback: show toast with the command props.api.ui?.toast?.({ title: 'Command', message: `Type ${cmd.name} in chat`, }) }} > {cmd.name} — {cmd.desc} )} {/* ══ Agents (collapsible) ══ */} setShowAgents((x) => !x)}> {showAgents() ? '\u25bc' : '\u25b6'} Agents ({AGENTS.length}) {(agent) => ( {agent.tier === 'premium' ? '\u2726 ' : '\u00b7 '} {agent.name} — {agent.role} )} {/* ══ Config (collapsible) ══ */} setShowConfig((x) => !x)}> {showConfig() ? '\u25bc' : '\u25b6'} Config (no config data) } > {(cfg) => ( Plugins: {cfg().plugins.length > 0 ? cfg().plugins.join(', ') : '(none)'} MCP servers configured: {cfg().mcpCount} Auto-compaction: {cfg().autoCompaction ? 'ON' : 'OFF'} )} {/* ══ Memory (collapsible) ══ */} setShowMemory((x) => !x)}> {showMemory() ? '\u25bc' : '\u25b6'} Memory (no memory data) } > {(mem) => ( Entries: {mem().entries} )} ) } // ── Plugin ─────────────────────────────────────────────────────────────────── const tui: TuiPlugin = async (api, _options, _meta) => { const version = await readPantheonVersion(api) api.slots.register({ order: 900, slots: { sidebar_content(_ctx, props) { return }, }, }) } const plugin: TuiPluginModule & { id: string } = { id: 'pantheon.tui', tui, } export default plugin