Compare commits

..

14 Commits

Author SHA1 Message Date
github-actions[bot]
d62f1dd207 release: v0.1.9 2025-12-05 00:45:40 +00:00
YeonGyu-Kim
aff7cad615 fix: resolve tree-sitter wasm initialization error with locateFile option 2025-12-05 09:45:04 +09:00
github-actions[bot]
e021ec954a release: v0.1.8 2025-12-05 00:30:07 +00:00
YeonGyu-Kim
1390970973 fix: skip publish if version already exists on registry 2025-12-05 09:29:08 +09:00
YeonGyu-Kim
a72bfe5c02 docs: consolidate README.en.md into README.md 2025-12-05 09:29:08 +09:00
YeonGyu-Kim
f10c15d83d feat: wire comment-checker hook to main plugin 2025-12-05 09:29:08 +09:00
github-actions[bot]
fdb39ba404 release: v0.1.7 2025-12-05 00:24:20 +00:00
YeonGyu-Kim
36ef885141 fix: trust @ast-grep/napi in CI to enable native module install scripts 2025-12-05 04:29:40 +09:00
YeonGyu-Kim
909ce37826 fix: remove --ignore-scripts from bun install, add build verification step 2025-12-05 04:19:13 +09:00
YeonGyu-Kim
132bb3c373 fix: add --ignore-scripts to npm publish to prevent CI build failure 2025-12-05 04:16:53 +09:00
YeonGyu-Kim
180d16b977 fix: prevent plugin crash by removing non-function exports from barrel files
BREAKING: OpenCode plugin loader calls all exports as functions.
Exporting non-function values (schemas, constants, types) causes TypeError.

Changes:
- Remove OhMyOpenCodeConfigSchema export from root index.ts
- Replace 'export *' with explicit function exports in hooks/index.ts
- Remove 'export *' from comment-checker/index.ts
2025-12-05 04:08:59 +09:00
YeonGyu-Kim
eba89a6626 hotfix: move McpNameSchema to src/mcp/types.ts for proper module organization 2025-12-05 03:58:21 +09:00
YeonGyu-Kim
0a82787614 hotfix: use McpName from config schema instead of duplicate type definition 2025-12-05 03:56:14 +09:00
YeonGyu-Kim
a1a2d2fdb3 hotfix: add empty content message recovery to session recovery 2025-12-05 03:54:51 +09:00
14 changed files with 310 additions and 219 deletions

View File

@@ -48,10 +48,37 @@ jobs:
run: npm config set registry https://registry.npmjs.org
- name: Install dependencies
run: bun install --ignore-scripts
run: bun install
env:
BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"
- name: Debug environment
run: |
echo "=== Bun version ==="
bun --version
echo "=== Node version ==="
node --version
echo "=== Current directory ==="
pwd
echo "=== List src/ ==="
ls -la src/
echo "=== package.json scripts ==="
cat package.json | jq '.scripts'
- name: Build
run: bun run build
run: |
echo "=== Running bun build ==="
bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi
echo "=== bun build exit code: $? ==="
echo "=== Running tsc ==="
tsc --emitDeclarationOnly
echo "=== Running build:schema ==="
bun run build:schema
- name: Verify build output
run: |
ls -la dist/
test -f dist/index.js || (echo "ERROR: dist/index.js not found!" && exit 1)
- name: Publish
run: bun run script/publish.ts

View File

@@ -1,191 +0,0 @@
English | [한국어](README.ko.md)
## Contents
- [Oh My OpenCode](#oh-my-opencode)
- [Installation](#installation)
- [Configuration](#configuration)
- [Disable specific MCPs](#disable-specific-mcps)
- [TL;DR](#tldr)
- [Why OpenCode \& Why Oh My OpenCode](#why-opencode--why-oh-my-opencode)
- [Features](#features)
- [Hooks](#hooks)
- [Agents](#agents)
- [Tools](#tools)
- [Built-in LSP Tools](#built-in-lsp-tools)
- [Built-in AST-Grep Tools](#built-in-ast-grep-tools)
- [Safe Grep](#safe-grep)
- [Built-in MCPs](#built-in-mcps)
- [Other Features](#other-features)
- [Author's Note](#authors-note)
- [Warnings](#warnings)
# Oh My OpenCode
Oh My OpenCode
oMoMoMoMoMo···
If you work in tech, you likely appreciated [Claude Code](https://www.claude.com/product/claude-code).
If you are a hacker, you will fucking falling in love with [OpenCode](https://github.com/sst/opencode).
You don't write code just for a paycheck? You write because you genuinely love it?
To you, OpenCode will feel like the paradigm shift from Windows to Linux. Not you? It's still worth the investment. Give it 10 minutes. Your work and life will improve. I promise.
## Installation
Add to `~/.config/opencode/opencode.json`:
```json
{
"plugin": [
"oh-my-opencode"
]
}
```
## Configuration
You can configure Oh My OpenCode by creating a `oh-my-opencode.json` (or `.oh-my-opencode.json`) file in your project root.
### JSON Schema Support
For autocompletion and validation in VS Code (or other editors), add the `$schema` property to your configuration file.
**Using Remote Schema (Recommended):**
```json
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/dist/oh-my-opencode.schema.json",
"disabled_mcps": ["context7"]
}
```
**Using Local Schema:**
```json
{
"$schema": "./node_modules/oh-my-opencode/dist/oh-my-opencode.schema.json"
}
```
### Disable specific MCPs
If you want to disable specific built-in MCPs, you can use the `disabled_mcps` option.
```json
{
"disabled_mcps": ["context7", "websearch_exa"]
}
```
## TL;DR
- **Model Setup Required**
- This plugin utilizes models from [OpenCode Zen](https://opencode.ai/docs/zen/), Google, OpenAI, and Anthropic.
- For Anthropic models, use [OpenCode's built-in Claude Code Max Plan login](https://opencode.ai/docs/providers/#anthropic).
- For OpenAI models, I recommend the [OpenCode-OpenAI-Codex-Auth plugin](https://github.com/numman-ali/opencode-openai-codex-auth).
- For Gemini and GPT, use [VibeProxy (macOS Only)](https://github.com/automazeio/vibeproxy) or [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI).
- **Truth be told, the rest is optional. Just install it. Once set up, no further learning is required. It simply evolves.**
- **Paste this document into Claude Code, OpenCode, or Cursor, instruct it to install, and ask for assistance if needed. It works seamlessly.**
- If you are an LLM Agent, install the required plugins and dependencies, then run `opencode auth login` via tmux to assist the user with configuration.
## Why OpenCode & Why Oh My OpenCode
OpenCode is limitlessly extensible and customizable. Zero screen flicker.
[LSP](https://opencode.ai/docs/lsp/), [linters, formatters](https://opencode.ai/docs/formatters/)? Automatic and fully configurable.
You can mix and orchestrate models to your exact specifications.
It is feature-rich. It is elegant. It handles the terminal without hesitation. It is high-performance.
But here is the catch: the learning curve is steep. There is a lot to master.
Inspired by [AmpCode](https://ampcode.com) and [Claude Code](https://code.claude.com/docs/en/overview), I have implemented their features here—often with superior execution.
Because this is OpenCode.
Consider this a superior AmpCode, a superior Claude Code, or simply a specialized distribution.
I believe in the right tool for the job. For your wallet's sake, use CLIProxyAPI or VibeProxy. Employ the best LLMs from frontier labs. You are in command.
**Note**: This setup is highly opinionated. It represents the generic component of my personal configuration, so it evolves constantly. I have spent tokens worth $20,000 just for my personal programming usages, and this plugin represents the apex of that experience. You simply inherit the best. If you have superior ideas, PRs are welcome.
## Features
### Hooks
- **Todo Continuation Enforcer**: Forces the agent to complete all tasks before exiting. Eliminates the common LLM issue of "giving up halfway".
- **Context Window Monitor**: Implements [Context Window Anxiety Management](https://agentic-patterns.com/patterns/context-window-anxiety-management/). When context usage exceeds 70%, it reminds the agent that resources are sufficient, preventing rushed or low-quality output.
- **Session Notification**: Sends a native OS notification when the job is done (macOS, Linux, Windows).
- **Session Recovery**: Automatically recovers from API errors by injecting missing tool results and correcting thinking block violations, ensuring session stability.
- **Comment Checker**: Detects and reports unnecessary comments after code modifications. Smartly ignores valid patterns (BDD, directives, docstrings, shebangs) to keep the codebase clean from AI-generated artifacts.
### Agents
- **oracle** (`openai/gpt-5.1`): The architect. Expert in code reviews and strategy. Uses GPT-5.1 for its unmatched logic and reasoning capabilities. Inspired by AmpCode.
- **librarian** (`anthropic/claude-haiku-4-5`): Multi-repo analysis, documentation lookup, and implementation examples. Haiku is chosen for its speed, competence, excellent tool usage, and cost-efficiency. Inspired by AmpCode.
- **explore** (`opencode/grok-code`): Fast exploration and pattern matching. Claude Code uses Haiku; we use Grok. It is currently free, blazing fast, and intelligent enough for file traversal. Inspired by Claude Code.
- **frontend-ui-ux-engineer** (`google/gemini-3-pro-preview`): A designer turned developer. Creates stunning UIs. Uses Gemini because its creativity and UI code generation are superior.
- **document-writer** (`google/gemini-3-pro-preview`): A technical writing expert. Gemini is a wordsmith; it writes prose that flows naturally.
### Tools
#### Built-in LSP Tools
[OpenCode provides LSP](https://opencode.ai/docs/lsp/), but only for analysis. Oh My OpenCode equips you with navigation and refactoring tools matching the same specification.
- **lsp_hover**: Get type info, docs, signatures at position
- **lsp_goto_definition**: Jump to symbol definition
- **lsp_find_references**: Find all usages across workspace
- **lsp_document_symbols**: Get file's symbol outline
- **lsp_workspace_symbols**: Search symbols by name across project
- **lsp_diagnostics**: Get errors/warnings before build
- **lsp_servers**: List available LSP servers
- **lsp_prepare_rename**: Validate rename operation
- **lsp_rename**: Rename symbol across workspace
- **lsp_code_actions**: Get available quick fixes/refactorings
- **lsp_code_action_resolve**: Apply a code action
#### Built-in AST-Grep Tools
- **ast_grep_search**: AST-aware code pattern search (25 languages)
- **ast_grep_replace**: AST-aware code replacement
#### Safe Grep
- **safe_grep**: Content search with safety limits (5min timeout, 10MB output).
- The default `grep` lacks safeguards. On a large codebase, a broad pattern can cause CPU overload and indefinite hanging.
- `safe_grep` enforces strict limits.
- **Note**: Default `grep` is disabled to prevent Agent confusion. `safe_grep` delivers full `grep` functionality with safety assurance.
#### Built-in MCPs
- **websearch_exa**: Exa AI web search. Performs real-time web searches and can scrape content from specific URLs. Returns LLM-optimized context from relevant websites.
- **context7**: Library documentation lookup. Fetches up-to-date documentation for any library to assist with accurate coding.
### Other Features
- **Terminal Title**: Auto-updates terminal title with session status (idle ○, processing ◐, tool ⚡, error ✖). Supports tmux.
## Author's Note
Install Oh My OpenCode. Do not waste time configuring OpenCode from scratch.
I have resolved the friction so you don't have to. The answers are in this plugin. If OpenCode is Arch Linux, Oh My OpenCode is [Omarchy](https://omarchy.org/).
Enjoy the multi-model stability and rich feature set that other harnesses promise but fail to deliver.
I will continue testing and updating here. I am the primary user of this project.
- Who possesses the best raw logic?
- Who is the debugging god?
- Who writes the best prose?
- Who dominates frontend?
- Who owns backend?
- Which model is fastest for daily driving?
- What new features are other harnesses shipping?
Do not overthink it. I have done the thinking. I will integrate the best practices. I will update this.
If this sounds arrogant and you have a superior solution, send a PR. You are welcome.
As of now, I have no affiliation with any of the projects or models mentioned here. This plugin is purely based on personal experimentation and preference.
I constructed 99% of this project using OpenCode. I focused on functional verification. This documentation has been personally reviewed and comprehensively rewritten, so you can rely on it with confidence.
## Warnings
- If you are on [1.0.132](https://github.com/sst/opencode/releases/tag/v1.0.132) or lower, OpenCode has a bug that might break config.
- [The fix](https://github.com/sst/opencode/pull/5040) was merged after 1.0.132, so use a newer version.

View File

@@ -1,4 +1,4 @@
[English](README.en.md) | 한국어
[English](README.md) | 한국어
## 목차

View File

@@ -1 +0,0 @@
README.en.md

191
README.md Normal file
View File

@@ -0,0 +1,191 @@
English | [한국어](README.ko.md)
## Contents
- [Oh My OpenCode](#oh-my-opencode)
- [Installation](#installation)
- [Configuration](#configuration)
- [Disable specific MCPs](#disable-specific-mcps)
- [TL;DR](#tldr)
- [Why OpenCode \& Why Oh My OpenCode](#why-opencode--why-oh-my-opencode)
- [Features](#features)
- [Hooks](#hooks)
- [Agents](#agents)
- [Tools](#tools)
- [Built-in LSP Tools](#built-in-lsp-tools)
- [Built-in AST-Grep Tools](#built-in-ast-grep-tools)
- [Safe Grep](#safe-grep)
- [Built-in MCPs](#built-in-mcps)
- [Other Features](#other-features)
- [Author's Note](#authors-note)
- [Warnings](#warnings)
# Oh My OpenCode
Oh My OpenCode
oMoMoMoMoMo···
If you work in tech, you likely appreciated [Claude Code](https://www.claude.com/product/claude-code).
If you are a hacker, you will fucking falling in love with [OpenCode](https://github.com/sst/opencode).
You don't write code just for a paycheck? You write because you genuinely love it?
To you, OpenCode will feel like the paradigm shift from Windows to Linux. Not you? It's still worth the investment. Give it 10 minutes. Your work and life will improve. I promise.
## Installation
Add to `~/.config/opencode/opencode.json`:
```json
{
"plugin": [
"oh-my-opencode"
]
}
```
## Configuration
You can configure Oh My OpenCode by creating a `oh-my-opencode.json` (or `.oh-my-opencode.json`) file in your project root.
### JSON Schema Support
For autocompletion and validation in VS Code (or other editors), add the `$schema` property to your configuration file.
**Using Remote Schema (Recommended):**
```json
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/dist/oh-my-opencode.schema.json",
"disabled_mcps": ["context7"]
}
```
**Using Local Schema:**
```json
{
"$schema": "./node_modules/oh-my-opencode/dist/oh-my-opencode.schema.json"
}
```
### Disable specific MCPs
If you want to disable specific built-in MCPs, you can use the `disabled_mcps` option.
```json
{
"disabled_mcps": ["context7", "websearch_exa"]
}
```
## TL;DR
- **Model Setup Required**
- This plugin utilizes models from [OpenCode Zen](https://opencode.ai/docs/zen/), Google, OpenAI, and Anthropic.
- For Anthropic models, use [OpenCode's built-in Claude Code Max Plan login](https://opencode.ai/docs/providers/#anthropic).
- For OpenAI models, I recommend the [OpenCode-OpenAI-Codex-Auth plugin](https://github.com/numman-ali/opencode-openai-codex-auth).
- For Gemini and GPT, use [VibeProxy (macOS Only)](https://github.com/automazeio/vibeproxy) or [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI).
- **Truth be told, the rest is optional. Just install it. Once set up, no further learning is required. It simply evolves.**
- **Paste this document into Claude Code, OpenCode, or Cursor, instruct it to install, and ask for assistance if needed. It works seamlessly.**
- If you are an LLM Agent, install the required plugins and dependencies, then run `opencode auth login` via tmux to assist the user with configuration.
## Why OpenCode & Why Oh My OpenCode
OpenCode is limitlessly extensible and customizable. Zero screen flicker.
[LSP](https://opencode.ai/docs/lsp/), [linters, formatters](https://opencode.ai/docs/formatters/)? Automatic and fully configurable.
You can mix and orchestrate models to your exact specifications.
It is feature-rich. It is elegant. It handles the terminal without hesitation. It is high-performance.
But here is the catch: the learning curve is steep. There is a lot to master.
Inspired by [AmpCode](https://ampcode.com) and [Claude Code](https://code.claude.com/docs/en/overview), I have implemented their features here—often with superior execution.
Because this is OpenCode.
Consider this a superior AmpCode, a superior Claude Code, or simply a specialized distribution.
I believe in the right tool for the job. For your wallet's sake, use CLIProxyAPI or VibeProxy. Employ the best LLMs from frontier labs. You are in command.
**Note**: This setup is highly opinionated. It represents the generic component of my personal configuration, so it evolves constantly. I have spent tokens worth $20,000 just for my personal programming usages, and this plugin represents the apex of that experience. You simply inherit the best. If you have superior ideas, PRs are welcome.
## Features
### Hooks
- **Todo Continuation Enforcer**: Forces the agent to complete all tasks before exiting. Eliminates the common LLM issue of "giving up halfway".
- **Context Window Monitor**: Implements [Context Window Anxiety Management](https://agentic-patterns.com/patterns/context-window-anxiety-management/). When context usage exceeds 70%, it reminds the agent that resources are sufficient, preventing rushed or low-quality output.
- **Session Notification**: Sends a native OS notification when the job is done (macOS, Linux, Windows).
- **Session Recovery**: Automatically recovers from API errors by injecting missing tool results and correcting thinking block violations, ensuring session stability.
- **Comment Checker**: Detects and reports unnecessary comments after code modifications. Smartly ignores valid patterns (BDD, directives, docstrings, shebangs) to keep the codebase clean from AI-generated artifacts.
### Agents
- **oracle** (`openai/gpt-5.1`): The architect. Expert in code reviews and strategy. Uses GPT-5.1 for its unmatched logic and reasoning capabilities. Inspired by AmpCode.
- **librarian** (`anthropic/claude-haiku-4-5`): Multi-repo analysis, documentation lookup, and implementation examples. Haiku is chosen for its speed, competence, excellent tool usage, and cost-efficiency. Inspired by AmpCode.
- **explore** (`opencode/grok-code`): Fast exploration and pattern matching. Claude Code uses Haiku; we use Grok. It is currently free, blazing fast, and intelligent enough for file traversal. Inspired by Claude Code.
- **frontend-ui-ux-engineer** (`google/gemini-3-pro-preview`): A designer turned developer. Creates stunning UIs. Uses Gemini because its creativity and UI code generation are superior.
- **document-writer** (`google/gemini-3-pro-preview`): A technical writing expert. Gemini is a wordsmith; it writes prose that flows naturally.
### Tools
#### Built-in LSP Tools
[OpenCode provides LSP](https://opencode.ai/docs/lsp/), but only for analysis. Oh My OpenCode equips you with navigation and refactoring tools matching the same specification.
- **lsp_hover**: Get type info, docs, signatures at position
- **lsp_goto_definition**: Jump to symbol definition
- **lsp_find_references**: Find all usages across workspace
- **lsp_document_symbols**: Get file's symbol outline
- **lsp_workspace_symbols**: Search symbols by name across project
- **lsp_diagnostics**: Get errors/warnings before build
- **lsp_servers**: List available LSP servers
- **lsp_prepare_rename**: Validate rename operation
- **lsp_rename**: Rename symbol across workspace
- **lsp_code_actions**: Get available quick fixes/refactorings
- **lsp_code_action_resolve**: Apply a code action
#### Built-in AST-Grep Tools
- **ast_grep_search**: AST-aware code pattern search (25 languages)
- **ast_grep_replace**: AST-aware code replacement
#### Safe Grep
- **safe_grep**: Content search with safety limits (5min timeout, 10MB output).
- The default `grep` lacks safeguards. On a large codebase, a broad pattern can cause CPU overload and indefinite hanging.
- `safe_grep` enforces strict limits.
- **Note**: Default `grep` is disabled to prevent Agent confusion. `safe_grep` delivers full `grep` functionality with safety assurance.
#### Built-in MCPs
- **websearch_exa**: Exa AI web search. Performs real-time web searches and can scrape content from specific URLs. Returns LLM-optimized context from relevant websites.
- **context7**: Library documentation lookup. Fetches up-to-date documentation for any library to assist with accurate coding.
### Other Features
- **Terminal Title**: Auto-updates terminal title with session status (idle ○, processing ◐, tool ⚡, error ✖). Supports tmux.
## Author's Note
Install Oh My OpenCode. Do not waste time configuring OpenCode from scratch.
I have resolved the friction so you don't have to. The answers are in this plugin. If OpenCode is Arch Linux, Oh My OpenCode is [Omarchy](https://omarchy.org/).
Enjoy the multi-model stability and rich feature set that other harnesses promise but fail to deliver.
I will continue testing and updating here. I am the primary user of this project.
- Who possesses the best raw logic?
- Who is the debugging god?
- Who writes the best prose?
- Who dominates frontend?
- Who owns backend?
- Which model is fastest for daily driving?
- What new features are other harnesses shipping?
Do not overthink it. I have done the thinking. I will integrate the best practices. I will update this.
If this sounds arrogant and you have a superior solution, send a PR. You are welcome.
As of now, I have no affiliation with any of the projects or models mentioned here. This plugin is purely based on personal experimentation and preference.
I constructed 99% of this project using OpenCode. I focused on functional verification. This documentation has been personally reviewed and comprehensively rewritten, so you can rely on it with confidence.
## Warnings
- If you are on [1.0.132](https://github.com/sst/opencode/releases/tag/v1.0.132) or lower, OpenCode has a bug that might break config.
- [The fix](https://github.com/sst/opencode/pull/5040) was merged after 1.0.132, so use a newer version.

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode",
"version": "0.1.2",
"version": "0.1.9",
"description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -57,6 +57,7 @@
"bun": ">=1.0.0"
},
"trustedDependencies": [
"@ast-grep/cli"
"@ast-grep/cli",
"@ast-grep/napi"
]
}

View File

@@ -63,10 +63,11 @@ async function generateChangelog(previous: string): Promise<string> {
async function buildAndPublish(): Promise<void> {
console.log("\nPublishing to npm...")
// --ignore-scripts: workflow에서 이미 빌드 완료, prepublishOnly 재실행 방지
if (process.env.CI) {
await $`npm publish --access public --provenance`
await $`npm publish --access public --provenance --ignore-scripts`
} else {
await $`npm publish --access public`
await $`npm publish --access public --ignore-scripts`
}
}
@@ -86,11 +87,25 @@ async function gitTagAndRelease(newVersion: string, changelog: string): Promise<
await $`gh release create v${newVersion} --title "v${newVersion}" --notes ${releaseNotes}`
}
async function checkVersionExists(version: string): Promise<boolean> {
try {
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/${version}`)
return res.ok
} catch {
return false
}
}
async function main() {
const previous = await fetchPreviousVersion()
const newVersion = versionOverride || (bump ? bumpVersion(previous, bump) : bumpVersion(previous, "patch"))
console.log(`New version: ${newVersion}\n`)
if (await checkVersionExists(newVersion)) {
console.log(`Version ${newVersion} already exists on npm. Skipping publish.`)
process.exit(0)
}
await updatePackageVersion(newVersion)
const changelog = await generateChangelog(previous)
await buildAndPublish()

View File

@@ -1,4 +1,5 @@
import { z } from "zod"
import { McpNameSchema } from "../mcp/types"
const PermissionValue = z.enum(["ask", "allow", "deny"])
@@ -23,8 +24,6 @@ export const AgentNameSchema = z.enum([
"document-writer",
])
export const McpNameSchema = z.enum(["websearch_exa", "context7"])
export const AgentOverrideConfigSchema = z.object({
model: z.string().optional(),
temperature: z.number().min(0).max(2).optional(),
@@ -53,5 +52,6 @@ export const OhMyOpenCodeConfigSchema = z.object({
export type OhMyOpenCodeConfig = z.infer<typeof OhMyOpenCodeConfigSchema>
export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>
export type AgentOverrides = z.infer<typeof AgentOverridesSchema>
export type McpName = z.infer<typeof McpNameSchema>
export type AgentName = z.infer<typeof AgentNameSchema>
export { McpNameSchema, type McpName } from "../mcp/types"

View File

@@ -47,7 +47,11 @@ export async function detectComments(
try {
const Parser = (await import("web-tree-sitter")).default
await Parser.init()
const treeSitterWasmPath = require.resolve("web-tree-sitter/tree-sitter.wasm")
await Parser.init({
locateFile: () => treeSitterWasmPath,
})
const parser = new Parser()

View File

@@ -94,8 +94,4 @@ export function createCommentCheckerHooks() {
}
}
export * from "./types"
export * from "./constants"
export * from "./detector"
export * from "./filters"
export * from "./output"

View File

@@ -1,5 +1,5 @@
export * from "./todo-continuation-enforcer"
export * from "./context-window-monitor"
export * from "./session-notification"
export * from "./session-recovery"
export * from "./comment-checker"
export { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
export { createContextWindowMonitorHook } from "./context-window-monitor"
export { createSessionNotification } from "./session-notification"
export { createSessionRecoveryHook } from "./session-recovery"
export { createCommentCheckerHooks } from "./comment-checker"

View File

@@ -1,7 +1,7 @@
/**
* Session Recovery - Message State Error Recovery
*
* Handles THREE specific scenarios:
* Handles FOUR specific scenarios:
* 1. tool_use block exists without tool_result
* - Recovery: inject tool_result with "cancelled" content
*
@@ -10,6 +10,9 @@
*
* 3. Thinking disabled but message contains thinking blocks
* - Recovery: strip thinking/redacted_thinking blocks
*
* 4. Empty content message (non-empty content required)
* - Recovery: delete the empty message via revert
*/
import type { PluginInput } from "@opencode-ai/plugin"
@@ -17,7 +20,7 @@ import type { createOpencodeClient } from "@opencode-ai/sdk"
type Client = ReturnType<typeof createOpencodeClient>
type RecoveryErrorType = "tool_result_missing" | "thinking_block_order" | "thinking_disabled_violation" | null
type RecoveryErrorType = "tool_result_missing" | "thinking_block_order" | "thinking_disabled_violation" | "empty_content_message" | null
interface MessageInfo {
id?: string
@@ -75,6 +78,10 @@ function detectErrorType(error: unknown): RecoveryErrorType {
return "thinking_disabled_violation"
}
if (message.includes("non-empty content") || message.includes("must have non-empty content")) {
return "empty_content_message"
}
return null
}
@@ -204,6 +211,35 @@ async function recoverThinkingDisabledViolation(
return false
}
async function recoverEmptyContentMessage(
client: Client,
sessionID: string,
failedAssistantMsg: MessageData,
directory: string
): Promise<boolean> {
const messageID = failedAssistantMsg.info?.id
const parentMsgID = failedAssistantMsg.info?.parentID
if (!messageID) {
return false
}
// Revert to parent message (delete the empty message)
const revertTargetID = parentMsgID || messageID
try {
await client.session.revert({
path: { id: sessionID },
body: { messageID: revertTargetID },
query: { directory },
})
return true
} catch {
return false
}
}
async function fallbackRevertStrategy(
client: Client,
sessionID: string,
@@ -308,11 +344,13 @@ export function createSessionRecoveryHook(ctx: PluginInput) {
tool_result_missing: "Tool Crash Recovery",
thinking_block_order: "Thinking Block Recovery",
thinking_disabled_violation: "Thinking Strip Recovery",
empty_content_message: "Empty Message Recovery",
}
const toastMessages: Record<RecoveryErrorType & string, string> = {
tool_result_missing: "Injecting cancelled tool results...",
thinking_block_order: "Fixing message structure...",
thinking_disabled_violation: "Stripping thinking blocks...",
empty_content_message: "Deleting empty message...",
}
const toastTitle = toastTitles[errorType]
const toastMessage = toastMessages[errorType]
@@ -336,6 +374,8 @@ export function createSessionRecoveryHook(ctx: PluginInput) {
success = await recoverThinkingBlockOrder(ctx.client, sessionID, failedMsg, ctx.directory)
} else if (errorType === "thinking_disabled_violation") {
success = await recoverThinkingDisabledViolation(ctx.client, sessionID, failedMsg)
} else if (errorType === "empty_content_message") {
success = await recoverEmptyContentMessage(ctx.client, sessionID, failedMsg, ctx.directory)
}
return success

View File

@@ -1,6 +1,6 @@
import type { Plugin } from "@opencode-ai/plugin"
import { createBuiltinAgents } from "./agents"
import { createTodoContinuationEnforcer, createContextWindowMonitorHook, createSessionRecoveryHook } from "./hooks"
import { createTodoContinuationEnforcer, createContextWindowMonitorHook, createSessionRecoveryHook, createCommentCheckerHooks } from "./hooks"
import { updateTerminalTitle } from "./features/terminal"
import { builtinTools } from "./tools"
import { createBuiltinMcps } from "./mcp"
@@ -43,6 +43,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
const todoContinuationEnforcer = createTodoContinuationEnforcer(ctx)
const contextWindowMonitor = createContextWindowMonitorHook(ctx)
const sessionRecovery = createSessionRecoveryHook(ctx)
const commentChecker = createCommentCheckerHooks()
updateTerminalTitle({ sessionId: "main" })
@@ -161,7 +162,9 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
}
},
"tool.execute.before": async (input, _output) => {
"tool.execute.before": async (input, output) => {
await commentChecker["tool.execute.before"](input, output)
if (input.sessionID === mainSessionID) {
updateTerminalTitle({
sessionId: input.sessionID,
@@ -175,6 +178,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
"tool.execute.after": async (input, output) => {
await contextWindowMonitor["tool.execute.after"](input, output)
await commentChecker["tool.execute.after"](input, output)
if (input.sessionID === mainSessionID) {
updateTerminalTitle({
@@ -190,7 +194,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
export default OhMyOpenCodePlugin
export { OhMyOpenCodeConfigSchema } from "./config"
export type {
OhMyOpenCodeConfig,
AgentName,

View File

@@ -1,7 +1,8 @@
import { websearch_exa } from "./websearch-exa"
import { context7 } from "./context7"
import type { McpName } from "./types"
export type McpName = "websearch_exa" | "context7"
export { McpNameSchema, type McpName } from "./types"
const allBuiltinMcps: Record<McpName, { type: "remote"; url: string; enabled: boolean }> = {
websearch_exa,

5
src/mcp/types.ts Normal file
View File

@@ -0,0 +1,5 @@
import { z } from "zod"
export const McpNameSchema = z.enum(["websearch_exa", "context7"])
export type McpName = z.infer<typeof McpNameSchema>