refactor(opencode): restructure config and replace legacy plugins

Rewrites opencode.json, drops the with-context, websearch and terminal-bell
plugins, adds plugins that strip Claude-only commands and OMC MCP servers,
and vendors the impeccable, web-design-guidelines and frontend-workflow skills.
This commit is contained in:
David Ibia
2026-10-03 16:27:47 +01:00
parent 3a31f12366
commit a750f158f5
71 changed files with 21048 additions and 1499 deletions
@@ -0,0 +1,55 @@
type PrefixRule = {
readonly kind: "prefix"
readonly prefix: string
readonly reason: string
}
type ExactRule = {
readonly kind: "exact"
readonly name: string
readonly reason: string
}
export type ClaudeOnlyCommandRule = PrefixRule | ExactRule
export const CLAUDE_ONLY_COMMAND_RULES: readonly ClaudeOnlyCommandRule[] = [
{
kind: "prefix",
prefix: "oh-my-claudecode:",
reason: "Operates the Oh My ClaudeCode runtime and workflows.",
},
{
kind: "prefix",
prefix: "claude-notifications-go:",
reason: "Configures notification hooks, binaries, and files for Claude Code.",
},
{
kind: "exact",
name: "remember:doctor",
reason: "Executes diagnostics through CLAUDE_PLUGIN_ROOT; remember:remember stays because it supports multiple agent hosts.",
},
{
kind: "exact",
name: "mcp-server-dev:build-mcpb",
reason: "Produces Anthropic MCPB bundles with claude_desktop compatibility; the server and app builders stay because they target multiple MCP hosts.",
},
] as const
function matchesRule(name: string, rule: ClaudeOnlyCommandRule): boolean {
switch (rule.kind) {
case "prefix":
return name.startsWith(rule.prefix)
case "exact":
return name === rule.name
default:
return assertNever(rule)
}
}
function assertNever(value: never): never {
throw new Error(`Unhandled rule: ${JSON.stringify(value)}`)
}
export function isClaudeOnlyCommand(name: string): boolean {
return CLAUDE_ONLY_COMMAND_RULES.some((rule) => matchesRule(name, rule))
}
-8
View File
@@ -1,8 +0,0 @@
{
"name": "opencode-plugins",
"version": "1.0.0",
"description": "OpenCode plugins for dotfiles",
"dependencies": {
"@opencode-ai/plugin": "^1.0.51"
}
}
@@ -0,0 +1,15 @@
import type { Plugin } from "@opencode-ai/plugin"
import { isClaudeOnlyCommand } from "./lib/claude-only-command-registry.ts"
export const StripClaudeOnlyCommandsPlugin: Plugin = async () => ({
config: async (config) => {
if (!config.command) return
for (const name of Object.keys(config.command)) {
if (isClaudeOnlyCommand(name)) {
delete config.command[name]
}
}
},
})
+15
View File
@@ -0,0 +1,15 @@
import type { Plugin } from "@opencode-ai/plugin"
const OMC_MCP_PREFIX = "oh-my-claudecode:"
export const StripOmcMcpPlugin: Plugin = async () => ({
config: async (config) => {
if (!config.mcp) return
for (const name of Object.keys(config.mcp)) {
if (name.startsWith(OMC_MCP_PREFIX)) {
delete config.mcp[name]
}
}
},
})
-12
View File
@@ -1,12 +0,0 @@
import type { Plugin } from "@opencode-ai/plugin"
export const NotificationPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
// Send notification on session completion
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}
-73
View File
@@ -1,73 +0,0 @@
import { type Plugin, tool } from "@opencode-ai/plugin";
export const PerplexitySearch: Plugin = async (ctx) => {
return {
tool: {
search: tool({
description:
"Run a quick search query to search the internet for results using Perplexity AI. Use this for quick lookups, latest information, and documentation.",
args: {
query: tool.schema.string().describe("Search query to execute"),
},
execute: async (args) => {
const url = "https://api.perplexity.ai/chat/completions";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.PERPLEXITY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "sonar",
messages: [
{
role: "user",
content: args.query,
},
],
}),
});
const data = await response.json();
return JSON.stringify({
answer: data.choices?.[0]?.message?.content,
citations: data.citations || [],
sources: data.search_results || [],
});
},
}),
deepResearch: tool({
description:
"Conduct an in-depth research using Perplexity's deep research model. Use this for exhaustive research, detailed analysis, comprehensive reports, or complex multi-source synthesis.",
args: {
query: tool.schema.string().describe("Research query or topic for exhaustive analysis"),
},
execute: async (args) => {
const url = "https://api.perplexity.ai/chat/completions";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.PERPLEXITY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "sonar-deep-research",
messages: [
{
role: "user",
content: args.query,
},
],
}),
});
const data = await response.json();
return JSON.stringify({
report: data.choices?.[0]?.message?.content,
citations: data.citations || [],
sources: data.search_results || [],
});
},
}),
},
};
};
-1
View File
@@ -1 +0,0 @@
/Users/davidibia/Projects/MCP/with-context-mcp/plugin/with-context.ts