Created
January 22, 2026 02:19
-
-
Save ShamanicArts/3043e1019f1375880ba651f37a63e95f to your computer and use it in GitHub Desktop.
awesome-opencode browser plugin - browse plugins, agents, themes from awesome-opencode collection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { Plugin } from "@opencode-ai/plugin" | |
| interface AwesomeEntry { | |
| name: string | |
| repo: string | |
| tagline: string | |
| description: string | |
| homepage?: string | |
| installation?: string | |
| tags?: string[] | |
| } | |
| interface AwesomeData { | |
| [category: string]: AwesomeEntry[] | |
| } | |
| interface AwesomeCache { | |
| sha: string | |
| data: AwesomeData | |
| } | |
| const REPO = "awesome-opencode/awesome-opencode" | |
| const BRANCH = "main" | |
| const CATEGORIES = ["plugins", "agents", "themes", "resources", "examples", "projects"] | |
| const CACHE_PATH = ".opencode/cache/awesome-opencode.json" | |
| async function getLatestSha($: any): Promise<string> { | |
| const sha = await $`gh api repos/${REPO}/commits/${BRANCH} --jq '.sha'`.text() | |
| return sha.trim() | |
| } | |
| async function readCache(directory: string): Promise<AwesomeCache | null> { | |
| try { | |
| const file = Bun.file(`${directory}/${CACHE_PATH}`) | |
| if (await file.exists()) { | |
| return await file.json() | |
| } | |
| } catch { | |
| // Cache doesn't exist or is invalid | |
| } | |
| return null | |
| } | |
| async function writeCache(directory: string, cache: AwesomeCache, $: any): Promise<void> { | |
| try { | |
| const path = `${directory}/${CACHE_PATH}` | |
| const dir = path.substring(0, path.lastIndexOf("/")) | |
| await $`mkdir -p ${dir}`.quiet() | |
| await Bun.write(path, JSON.stringify(cache, null, 2)) | |
| } catch { | |
| // Cache write failed, not critical | |
| } | |
| } | |
| async function fetchAwesomeData($: any, sha: string): Promise<AwesomeData> { | |
| const data: AwesomeData = {} | |
| for (const category of CATEGORIES) { | |
| try { | |
| const listJson = await $`gh api repos/${REPO}/contents/data/${category}?ref=${sha} --jq '.[].name'`.text() | |
| const files = listJson | |
| .trim() | |
| .split("\n") | |
| .filter((f: string) => f.endsWith(".yaml")) | |
| const entries: AwesomeEntry[] = [] | |
| for (const file of files) { | |
| try { | |
| const content = | |
| await $`gh api repos/${REPO}/contents/data/${category}/${file}?ref=${sha} --jq '.content' | base64 -d`.text() | |
| const entry = parseYaml(content) | |
| if (entry.name && entry.repo) { | |
| entries.push(entry) | |
| } | |
| } catch { | |
| // Skip invalid files | |
| } | |
| } | |
| data[category] = entries | |
| } catch { | |
| data[category] = [] | |
| } | |
| } | |
| return data | |
| } | |
| function parseYaml(content: string): AwesomeEntry { | |
| const lines = content.split("\n") | |
| const entry: any = {} | |
| for (const line of lines) { | |
| const match = line.match(/^(\w+):\s*(.*)$/) | |
| if (match) { | |
| const [, key, value] = match | |
| entry[key] = value.replace(/^["']|["']$/g, "") | |
| } | |
| } | |
| return entry as AwesomeEntry | |
| } | |
| function formatEntryMarkdown(entry: AwesomeEntry, category: string): string { | |
| let md = `## ${entry.name}\n\n` | |
| md += `**Category:** ${category}\n` | |
| md += `**Repository:** ${entry.repo}\n` | |
| if (entry.homepage) md += `**Homepage:** ${entry.homepage}\n` | |
| md += `\n> ${entry.tagline}\n\n` | |
| md += `${entry.description}\n` | |
| if (entry.installation) { | |
| md += `\n### Installation\n\n${entry.installation}\n` | |
| } | |
| if (entry.tags?.length) { | |
| md += `\n**Tags:** ${entry.tags.join(", ")}\n` | |
| } | |
| return md | |
| } | |
| export const awesomePlugin: Plugin = async ({ dialog, $, directory }) => { | |
| // Cache-first loading strategy for awesome-opencode data | |
| let awesomeData: AwesomeData | null = null | |
| // Try to load from cache immediately (instant startup) | |
| const cache = await readCache(directory) | |
| if (cache?.data) { | |
| awesomeData = cache.data | |
| } | |
| // Background: check if cache is stale and refresh if needed | |
| const refreshPromise = (async () => { | |
| try { | |
| const latestSha = await getLatestSha($) | |
| // If cache exists and SHA matches, we're done | |
| if (cache?.sha === latestSha) return | |
| // Cache is stale or doesn't exist - fetch fresh data | |
| const freshData = await fetchAwesomeData($, latestSha) | |
| awesomeData = freshData | |
| await writeCache(directory, { sha: latestSha, data: freshData }, $) | |
| } catch { | |
| // Background refresh failed, use cached data if available | |
| if (!awesomeData) awesomeData = {} | |
| } | |
| })() | |
| // If no cache, wait for initial fetch | |
| if (!cache) { | |
| await refreshPromise | |
| } | |
| return { | |
| config: async (input) => { | |
| input.command ??= {} | |
| input.command.awesome = { | |
| template: "[AWESOME_BROWSER_COMMAND]\n\n$ARGUMENTS", | |
| description: "Browse the awesome-opencode collection", | |
| } | |
| }, | |
| "chat.message": async (_input, output) => { | |
| const text = output.parts.find((p) => p.type === "text")?.text ?? "" | |
| if (!text.includes("[AWESOME_BROWSER_COMMAND]")) return | |
| // Wait for background refresh if still running | |
| await refreshPromise | |
| if (!awesomeData || Object.keys(awesomeData).length === 0) { | |
| throw new Error("__AWESOME_BROWSER_ABORTED__") | |
| } | |
| // Navigation state | |
| type State = | |
| | { screen: "category" } | |
| | { screen: "items"; category: string } | |
| | { screen: "details"; category: string; entry: AwesomeEntry } | |
| let state: State = { screen: "category" } | |
| while (true) { | |
| if (state.screen === "category") { | |
| const categoryOptions = CATEGORIES.filter((cat) => awesomeData![cat]?.length > 0).map((cat) => ({ | |
| value: cat, | |
| title: cat.charAt(0).toUpperCase() + cat.slice(1), | |
| description: `${awesomeData![cat].length} items`, | |
| })) | |
| const result = await dialog.show({ | |
| type: "select", | |
| mode: "modal", | |
| title: "Browse Awesome Opencode", | |
| options: categoryOptions, | |
| }) | |
| if (result.dismissed) throw new Error("__AWESOME_BROWSER_ABORTED__") | |
| state = { screen: "items", category: result.value as string } | |
| } else if (state.screen === "items") { | |
| const entries = awesomeData[state.category] || [] | |
| const itemOptions = entries.map((entry) => ({ | |
| value: entry, | |
| title: entry.name, | |
| description: entry.tagline, | |
| })) | |
| const result = await dialog.show({ | |
| type: "select", | |
| mode: "modal", | |
| title: `Select from ${state.category}`, | |
| options: itemOptions, | |
| keybind: [{ key: "left", value: "__BACK__", label: "← back" }], | |
| }) | |
| if (result.dismissed) throw new Error("__AWESOME_BROWSER_ABORTED__") | |
| if (result.value === "__BACK__") { | |
| state = { screen: "category" } | |
| } else { | |
| state = { screen: "details", category: state.category, entry: result.value as AwesomeEntry } | |
| } | |
| } else if (state.screen === "details") { | |
| const entry = state.entry | |
| // Show full details with proper options | |
| const detailOptions = [ | |
| { value: "__SELECT__", title: "✓ Select this", description: "Send details to assistant" }, | |
| ] | |
| const result = await dialog.show({ | |
| type: "select", | |
| mode: "modal", | |
| title: `${entry.name} — ${entry.tagline}`, | |
| message: entry.description, | |
| options: detailOptions, | |
| keybind: [{ key: "left", value: "__BACK__", label: "← back" }], | |
| }) | |
| if (result.dismissed) throw new Error("__AWESOME_BROWSER_ABORTED__") | |
| if (result.value === "__BACK__") { | |
| state = { screen: "items", category: state.category } | |
| } else if (result.value === "__SELECT__") { | |
| // User confirmed - send to LLM | |
| const markdown = formatEntryMarkdown(entry, state.category) | |
| const textPart = output.parts.find((p) => p.type === "text") | |
| if (textPart && "text" in textPart) { | |
| textPart.text = `User selected an item from awesome-opencode. Here are the details:\n\n${markdown}\n\nPlease provide a helpful summary and any additional context about this ${state.category.slice(0, -1)}.` | |
| } | |
| return | |
| } | |
| } | |
| } | |
| }, | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment