feat: OpenCode feature parity — plugin + skills + hooks#616
Open
ZeR020 wants to merge 1 commit into
Open
Conversation
Add full OpenCode integration matching Claude Code parity: - TypeScript plugin (tool.execute.after for grep/glob graph augmentation, experimental.chat.system.transform for session reminder) - Consolidated codebase-memory skill installation - Plugin auto-discovered from ~/.config/opencode/plugins/ (no config entry needed) - Skill auto-discovered from ~/.config/opencode/skills/ Design note: uses tool.execute.after (NOT .before as proposed in DeusData#585) because source verification against anomalyco/opencode proved .before output mutation has no effect — the tool uses original args, not output.args. The .after hook mutates output.output which is model-visible. Non-blocking: all plugin failures silently swallowed (consistent with Claude Code hook gate script behavior). TOCTOU-safe fchmod pattern. Defensive binary-path quote rejection (security). 5 new tests: plugin install/idempotent/quote-reject/remove, skills install. Closes DeusData#585
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #585. Adds full OpenCode feature parity with Claude Code:
~/.config/opencode/plugins/cbm-augment.ts) — auto-discovered, noopencode.jsonentry neededcodebase-memoryskill (~/.config/opencode/skills/codebase-memory/SKILL.md) — same skill content as Claude CodeDesign Decision:
tool.execute.after(not.before)Issue #585 proposed
tool.execute.beforefor context injection. However, source verification againstanomalyco/opencodeproved that.beforeis non-functional for this purpose:tool.execute.before(packages/opencode/src/session/tools.ts:82):args. Output{ args }is a fresh object; mutation has zero effect — the tool uses the originalargsvariable, not the mutated output.tool.execute.after(packages/opencode/src/session/tools.ts:92):output.output(type:string) is model-visible tool result text.output.outputin place IS model-visible.input.argsavailable (haspatternfor grep/glob).This PR uses
.afterso that graph context is appended to the tool result the model actually sees.How It Works
Plugin (
cbm-augment.ts)tool.execute.afterhook:input.toolis"grep"or"glob"(OpenCode uses lowercase tool names)"Grep"/"Glob"for the agent-agnostichook-augmentbinary<binary> hook-augment, writes{"tool_name":"Grep","tool_input":{"pattern":"..."}}to stdinhookSpecificOutput.additionalContextfrom stdoutoutput.outputwith\n\nseparatorcbm-code-discovery-gate)experimental.chat.system.transformhook:output.system(rebuilt fresh each turn, no accumulation)CMM_SESSION_REMINDER_CMDused by Codex/Gemini/AntigravityInstall/Uninstall
Install path (
install_cli_agent_configs):cbm_install_skills(skills_dir, true, dry_run)— reuses existing functioncbm_upsert_opencode_plugin(home, binary_path, dry_run)— writes plugin with embedded binary path--plan) recordsskills+pluginentries without mutatingUninstall path (
uninstall_cli_agents):cbm_remove_skills(skills_dir, dry_run)cbm_remove_opencode_plugin(home, dry_run)— unlinks plugin file (unlike Claude Code which leaves inert scripts, OpenCode auto-discovers plugins so the file must be deleted)Security
fchmod(fileno(f), ...)beforefclose(f)(same pattern ascbm_install_hook_gate_script)"are rejected (prevents injection into the TypeScriptBIN = "%s"string)Tests
5 new tests in
tests/test_cli.c:cli_upsert_opencode_plugin_fresh— verifies plugin file written with correct binary path, hook names, andsatisfies Plugincli_upsert_opencode_plugin_idempotent— verifies re-install overwrites cleanly with new pathcli_upsert_opencode_plugin_rejects_quote— verifies security: binary paths with"are rejectedcli_remove_opencode_plugin— verifies install → remove → file gone, and idempotent removecli_opencode_skills_installed— verifies SKILL.md written to correct path with correct contentAll 5 pass. 5698 total tests pass. 1 pre-existing failure (
incr_full_indexintest_incremental.c) is unrelated — an RSS memory threshold assertion that's environment-dependent.Files Changed
src/cli/cli.c(+149 lines):opencode_plugin_contentstatic string,cbm_upsert_opencode_plugin(),cbm_remove_opencode_plugin(), install/uninstall path modificationssrc/cli/cli.h(+9 lines): function declarationstests/test_cli.c(+130 lines): 5 new tests +RUN_TESTregistrations