/** @jsxImportSource @opentui/solid */ /** * infinicode — mesh command palette * * Adds the OpenKernel mesh/kernel slash-commands natively to the TUI's `/` * command palette. Each command is dispatched to a LOCAL mesh node over HTTP * (POST /fed/command → kernel.command()), so the same command surface exposed by * `infinicode serve`'s console and the CLI is available right inside the TUI. * * The local node is started (or reused) by `infinicode run`, which injects: * INFINICODE_MESH_URL e.g. http://127.0.0.1:47913 * INFINICODE_MESH_TOKEN optional bearer token * * Argless commands (/nodes, /running, /activity, /whoami, /mesh-help) run * immediately and show output in an alert. Arg-taking commands (/node, /build, * /follow, /dispatch, /goal, /mission, /role) open a prompt first. */ import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui" type CommandResult = { ok?: boolean; text?: string; data?: unknown } const meshUrl = () => (process.env.INFINICODE_MESH_URL ?? "http://127.0.0.1:47913").replace(/\/+$/, "") const meshToken = () => process.env.INFINICODE_MESH_TOKEN /** POST a slash-command to the local mesh node and return its CommandResult. */ async function send(input: string): Promise { const token = meshToken() try { const res = await fetch(`${meshUrl()}/fed/command`, { method: "POST", headers: { "content-type": "application/json", ...(token ? { authorization: `Bearer ${token}` } : {}), }, body: JSON.stringify({ input }), signal: AbortSignal.timeout(30_000), }) if (!res.ok) return { ok: false, text: `mesh error ${res.status} — is a node running? (infinicode serve)` } return (await res.json()) as CommandResult } catch (e) { const msg = e instanceof Error ? e.message : String(e) return { ok: false, text: `no local mesh node reachable at ${meshUrl()} (${msg})` } } } /** Render a CommandResult in a scrollable alert dialog. */ function show(api: TuiPluginApi, title: string, res: CommandResult): void { const DialogAlert = api.ui.DialogAlert const message = (res.text && res.text.trim()) || (res.ok ? "(no output)" : "command failed") api.ui.dialog.setSize("large") api.ui.dialog.replace(() => ( api.ui.dialog.clear()} /> )) } /** Run a fixed slash-command now and show the result. */ function runNow(api: TuiPluginApi, title: string, input: string): void { api.ui.toast({ variant: "info", title: "mesh", message: `${input} …`, duration: 1200 }) void send(input).then((res) => show(api, title, res)) } /** Open a prompt, then dispatch ` `. */ function runWithArgs( api: TuiPluginApi, title: string, slash: string, placeholder: string, ): void { const DialogPrompt = api.ui.DialogPrompt api.ui.dialog.setSize("medium") api.ui.dialog.replace(() => ( { api.ui.dialog.clear() const input = args && args.trim() ? `${slash} ${args.trim()}` : slash api.ui.toast({ variant: "info", title: "mesh", message: `${input} …`, duration: 1200 }) void send(input).then((res) => show(api, title, res)) }} onCancel={() => api.ui.dialog.clear()} /> )) } interface Spec { name: string slashName: string title: string /** if set, prompt for args first with this placeholder; else run immediately */ arg?: string /** the underlying kernel slash-command (defaults to `/${slashName}`) */ cmd?: string } const SPECS: Spec[] = [ { name: "mesh_nodes", slashName: "nodes", title: "Mesh nodes" }, { name: "mesh_running", slashName: "running", title: "Running tasks" }, { name: "mesh_activity", slashName: "activity", title: "Mesh activity" }, { name: "mesh_whoami", slashName: "whoami", title: "This node" }, { name: "mesh_help", slashName: "mesh-help", title: "Mesh commands", cmd: "/help" }, { name: "mesh_node", slashName: "node", title: "Node control", arg: " ", cmd: "/node" }, { name: "mesh_build", slashName: "build", title: "Phased build", arg: " ", cmd: "/build" }, { name: "mesh_dispatch", slashName: "dispatch", title: "Dispatch task", arg: " ", cmd: "/dispatch" }, { name: "mesh_follow", slashName: "follow", title: "Follow run", arg: "", cmd: "/follow" }, { name: "mesh_goal", slashName: "goal", title: "New goal", arg: "", cmd: "/goal" }, { name: "mesh_mission", slashName: "mission", title: "Mission", arg: "", cmd: "/mission" }, { name: "mesh_role", slashName: "role", title: "Set role", arg: "", cmd: "/role" }, ] const tui: TuiPlugin = async (api, options) => { if (options?.enabled === false) return // No keybindings — these are palette-only slash commands. Empty bindings avoids // any dependency on the keymap-extras runtime module (which may not resolve for // an externally-loaded plugin) so registration can never fail to load. api.keymap.registerLayer({ commands: SPECS.map((s) => ({ name: s.name, title: s.title, category: "Mesh", namespace: "palette" as const, slashName: s.slashName, run() { const cmd = s.cmd ?? `/${s.slashName}` if (s.arg) runWithArgs(api, s.title, cmd, s.arg) else runNow(api, s.title, cmd) }, })), bindings: [], }) } const plugin: TuiPluginModule & { id: string } = { id: "infinicode-mesh-commands", tui, } export default plugin