diff --git a/.opencode/plugins/entire.ts b/.opencode/plugins/entire.ts deleted file mode 100644 index 0c02bfd..0000000 --- a/.opencode/plugins/entire.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Entire CLI plugin for OpenCode -// Auto-generated by `entire enable --agent opencode` -// Do not edit manually — changes will be overwritten on next install. -// Requires Bun runtime (used by OpenCode's plugin system for loading ESM plugins). -import type { Plugin } from "@opencode-ai/plugin" - -export const EntirePlugin: Plugin = async ({ $, directory }) => { - const ENTIRE_CMD = "entire" - // Track seen user messages to fire turn-start only once per message - const seenUserMessages = new Set() - // Track current session ID for message events (which don't include sessionID) - let currentSessionID: string | null = null - // In-memory store for message metadata (role, tokens, etc.) - const messageStore = new Map() - - /** - * Pipe JSON payload to an entire hooks command (async). - * Errors are logged but never thrown — plugin failures must not crash OpenCode. - */ - async function callHook(hookName: string, payload: Record) { - try { - const json = JSON.stringify(payload) - await $`echo ${json} | ${ENTIRE_CMD} hooks opencode ${hookName}`.quiet().nothrow() - } catch { - // Silently ignore — plugin failures must not crash OpenCode - } - } - - /** - * Synchronous variant for hooks that fire near process exit (turn-end, session-end). - * `opencode run` breaks its event loop on the same session.status idle event that - * triggers turn-end. The async callHook would be killed before completing. - * Bun.spawnSync blocks the event loop, preventing exit until the hook finishes. - */ - function callHookSync(hookName: string, payload: Record) { - try { - const json = JSON.stringify(payload) - Bun.spawnSync(["sh", "-c", `${ENTIRE_CMD} hooks opencode ${hookName}`], { - cwd: directory, - stdin: new TextEncoder().encode(json + "\n"), - stdout: "ignore", - stderr: "ignore", - }) - } catch { - // Silently ignore — plugin failures must not crash OpenCode - } - } - - return { - event: async ({ event }) => { - switch (event.type) { - case "session.created": { - const session = (event as any).properties?.info - if (!session?.id) break - // Reset per-session tracking state when switching sessions. - if (currentSessionID !== session.id) { - seenUserMessages.clear() - messageStore.clear() - } - currentSessionID = session.id - await callHook("session-start", { - session_id: session.id, - }) - break - } - - case "message.updated": { - const msg = (event as any).properties?.info - if (!msg) break - // Store message metadata (role, time, tokens, etc.) - messageStore.set(msg.id, msg) - break - } - - case "message.part.updated": { - const part = (event as any).properties?.part - if (!part?.messageID) break - - // Fire turn-start on the first text part of a new user message - const msg = messageStore.get(part.messageID) - if (msg?.role === "user" && part.type === "text" && !seenUserMessages.has(msg.id)) { - seenUserMessages.add(msg.id) - const sessionID = msg.sessionID ?? currentSessionID - if (sessionID) { - await callHook("turn-start", { - session_id: sessionID, - prompt: part.text ?? "", - }) - } - } - break - } - - case "session.status": { - // session.status fires in both TUI and non-interactive (run) mode. - // session.idle is deprecated and not reliably emitted in run mode. - const props = (event as any).properties - if (props?.status?.type !== "idle") break - const sessionID = props?.sessionID - if (!sessionID) break - // Use sync variant: `opencode run` exits on the same idle event, - // so an async hook would be killed before completing. - callHookSync("turn-end", { - session_id: sessionID, - }) - break - } - - case "session.compacted": { - const sessionID = (event as any).properties?.sessionID - if (!sessionID) break - await callHook("compaction", { - session_id: sessionID, - }) - break - } - - case "session.deleted": { - const session = (event as any).properties?.info - if (!session?.id) break - seenUserMessages.clear() - messageStore.clear() - currentSessionID = null - // Use sync variant: session-end may fire during shutdown. - callHookSync("session-end", { - session_id: session.id, - }) - break - } - } - }, - } -}