Skip to content

Conversation

@sisyphus-dev-ai
Copy link
Collaborator

@sisyphus-dev-ai sisyphus-dev-ai commented Jan 7, 2026

Summary

Fixes #555 - oh-my-opencode now automatically detects and prevents conflicts with external opencode-elf and opencode-dcp plugins.

Problem

Users reported that after installing oh-my-opencode, their existing opencode-elf and opencode-dcp plugins stopped working. The root cause was:

  1. NOT a hook override issue: OpenCode's plugin architecture is additive - all plugins' hooks run in sequence
  2. The REAL problem: oh-my-opencode has its own comprehensive DCP and compaction system that conflicts with external plugins:
    • preemptive-compaction hook (enabled by default)
    • anthropic-context-window-limit-recovery hook (enabled by default)
    • compaction-context-injector hook (enabled by default)
    • Optional DCP via experimental.dcp_for_compaction

Both oh-my-opencode and external plugins were trying to manage the same session state, causing interference.

Solution

Implemented automatic plugin conflict detection:

  1. Auto-Detection: On startup, scans opencode.json for conflicting plugins:

    • DCP plugins: opencode-dcp, @opencode/dcp
    • ELF plugins: opencode-elf, @opencode/elf
    • Compaction plugins: opencode-compaction, @opencode/compaction
  2. Auto-Disable: Automatically disables oh-my-opencode hooks that would conflict:

    • For DCP plugins: disables anthropic-context-window-limit-recovery, preemptive-compaction, compaction-context-injector
    • For ELF plugins: disables context-window-monitor, directory-agents-injector, directory-readme-injector
    • For compaction plugins: disables preemptive-compaction, anthropic-context-window-limit-recovery, compaction-context-injector
  3. User Notification: Displays clear warning messages showing which hooks were auto-disabled

  4. Manual Override: Users can still manually configure via disabled_hooks config if needed

Changes

  • Add src/shared/plugin-compatibility.ts - Plugin conflict detection system
  • Update src/index.ts - Integrate detection at plugin initialization
  • Update README.md - Add Plugin Compatibility section with documentation
  • All tests pass (648/648)
  • Build succeeds with no type errors

Testing

  • ✅ All existing tests pass
  • ✅ Type check passes
  • ✅ Build succeeds
  • ✅ Schema generation works

Next Steps

Users with opencode-elf/opencode-dcp installed will automatically see warning messages and have conflicting hooks disabled. No manual configuration required, but users can override if needed via disabled_hooks config.


Summary by cubic

Automatically detect external DCP/ELF/compaction plugins and auto-disable conflicting oh-my-opencode hooks to prevent clashes. Fixes #555 so opencode-elf/opencode-dcp keep working without manual setup.

  • Bug Fixes
    • Scan project and user opencode.json/jsonc for known DCP, ELF, and compaction plugins.
    • Auto-disable specific hooks per plugin type and show a clear warning listing disabled hooks.
    • Integrate detection at startup and merge auto-disabled hooks with user-configured disabled_hooks.
    • Add plugin-compatibility module; update index.ts and README with compatibility details.

Written for commit 3609bb0. Summary will update on new commits.

- Add plugin compatibility detection system
- Auto-disable conflicting hooks when opencode-elf/opencode-dcp detected
- Display clear warning messages about auto-disabled hooks
- Add Plugin Compatibility section to README
- Resolves #555

The issue was that oh-my-opencode's built-in DCP and compaction features
were interfering with external opencode-elf and opencode-dcp plugins.
Now the plugin automatically detects these conflicts and disables
its own hooks to allow external plugins to work properly.

Users can still manually override via disabled_hooks config if needed.
@greptile-apps
Copy link

greptile-apps bot commented Jan 7, 2026

Greptile Summary

This PR implements automatic plugin conflict detection to resolve issues where oh-my-opencode's built-in DCP and context management features interfere with external opencode-dcp and opencode-elf plugins. The solution scans opencode.json at startup, detects conflicting plugins, and auto-disables corresponding oh-my-opencode hooks.

Major Changes:

  • Added src/shared/plugin-compatibility.ts with conflict detection logic for DCP, ELF, and compaction plugins
  • Modified src/index.ts to integrate auto-detection at plugin initialization
  • Updated README.md with comprehensive Plugin Compatibility documentation
  • Displays warning messages to users when conflicts are detected and hooks are auto-disabled

Issues Found:

  • Critical logic bug in plugin matching (plugin-compatibility.ts:110): The p.includes(pluginName) check is too broad and will cause false positives for unrelated plugins
  • User cannot override auto-disabled hooks (index.ts:78): The implementation combines auto-disabled and user-disabled hooks, preventing users from re-enabling hooks that were auto-disabled
  • Missing tests: The feature violates the TDD requirement per style guide - no test coverage for the new plugin detection system

Confidence Score: 2/5

  • This PR has logical errors that will cause incorrect behavior in production
  • While the approach is sound and addresses a real user need, the implementation has a critical logic bug (overly-broad plugin matching) that will cause false positives, and the design prevents users from overriding auto-detection. Additionally, the feature lacks test coverage despite TDD being mandatory per project guidelines.
  • Pay close attention to src/shared/plugin-compatibility.ts (line 110 has logic bug) and src/index.ts (line 78 prevents user override)

Important Files Changed

Filename Overview
src/shared/plugin-compatibility.ts New plugin conflict detection system with overly-broad plugin matching logic that could cause false positives
src/index.ts Integrates conflict detection at plugin initialization; user cannot override auto-disabled hooks
README.md Documentation added for Plugin Compatibility section, clearly explains auto-detection and manual control

Sequence Diagram

sequenceDiagram
    participant User
    participant OpenCode
    participant OhMyOpenCode as oh-my-opencode Plugin
    participant PluginCompat as plugin-compatibility.ts
    participant ConfigLoader as loadPluginConfig
    participant Hooks as Hook System

    User->>OpenCode: Start OpenCode
    OpenCode->>OhMyOpenCode: Initialize Plugin (ctx)
    
    Note over OhMyOpenCode: startTmuxCheck()
    
    OhMyOpenCode->>ConfigLoader: loadPluginConfig(directory)
    ConfigLoader-->>OhMyOpenCode: pluginConfig (with user disabled_hooks)
    
    OhMyOpenCode->>PluginCompat: detectConflictingPlugins(directory)
    
    PluginCompat->>PluginCompat: loadOpencodeConfig(directory)
    Note over PluginCompat: Check project/user opencode.json<br/>for plugin list
    
    PluginCompat->>PluginCompat: Check for DCP plugins<br/>(opencode-dcp, @opencode/dcp)
    PluginCompat->>PluginCompat: Check for ELF plugins<br/>(opencode-elf, @opencode/elf)
    PluginCompat->>PluginCompat: Check for Compaction plugins
    
    alt Conflicts Found
        PluginCompat->>PluginCompat: Build hooksToDisable array<br/>(preemptive-compaction, etc)
        PluginCompat-->>OhMyOpenCode: {hasConflicts: true, conflicts, hooksToDisable}
        
        OhMyOpenCode->>OhMyOpenCode: Combine autoDisabledHooks + userDisabledHooks
        Note over OhMyOpenCode: Issue: User cannot override<br/>auto-disabled hooks
        
        OhMyOpenCode->>User: warnAboutConflicts() - Display warning
        Note over User: ⚠️ Plugin Conflict Detection<br/>Auto-disabling N hooks
    else No Conflicts
        PluginCompat-->>OhMyOpenCode: {hasConflicts: false, conflicts: [], hooksToDisable: []}
    end
    
    OhMyOpenCode->>Hooks: Initialize hooks with isHookEnabled() checks
    Note over Hooks: Disabled hooks are not created/registered
    
    OhMyOpenCode-->>OpenCode: Plugin initialized
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. src/shared/plugin-compatibility.ts, line 1-161 (link)

    style: Missing tests for new plugin-compatibility feature. Per AGENTS.md:42-64, TDD is MANDATORY for new features. Should include test cases for:

    • Exact plugin name match
    • Versioned plugin match (e.g., [email protected])
    • False positives from overly-broad matching
    • Multiple conflicting plugins
    • No conflicts scenario
    • Config file not found
    • Invalid config file

    Context Used: Context from dashboard - AGENTS.md (source)

4 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

for (const pluginName of pluginNames) {
const hasPlugin = installedPlugins.some(
(p) =>
p === pluginName || p.startsWith(`${pluginName}@`) || p.includes(pluginName)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The p.includes(pluginName) check is too broad - will match unrelated plugins. For example, if pluginName is "dcp", this will match plugins like "my-dcp-custom", "cdcp-handler", or "opencode-backup-dcp". Should use more precise matching.

Suggested change
p === pluginName || p.startsWith(`${pluginName}@`) || p.includes(pluginName)
p === pluginName || p.startsWith(`${pluginName}@`)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/shared/plugin-compatibility.ts
Line: 110:110

Comment:
**logic:** The `p.includes(pluginName)` check is too broad - will match unrelated plugins. For example, if `pluginName` is `"dcp"`, this will match plugins like `"my-dcp-custom"`, `"cdcp-handler"`, or `"opencode-backup-dcp"`. Should use more precise matching.

```suggestion
          p === pluginName || p.startsWith(`${pluginName}@`)
```

How can I resolve this? If you propose a fix, please make it concise.

const conflictDetection = detectConflictingPlugins(ctx.directory);
const autoDisabledHooks = new Set(conflictDetection.hooksToDisable);
const userDisabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
const disabledHooks = new Set([...autoDisabledHooks, ...userDisabledHooks]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: User cannot re-enable hooks that were auto-disabled. The current logic combines both sets, but users might want to override auto-detection (e.g., they know their DCP plugin is compatible). Consider implementing priority: if user explicitly lists a hook in disabled_hooks, respect auto-detection; but provide a separate enabled_hooks_override config to force-enable specific hooks despite conflicts.

Current behavior:

  • Auto-disabled: ["preemptive-compaction"]
  • User config: disabled_hooks: []
  • Result: preemptive-compaction is still disabled (user cannot override)

The README states "Override auto-detection by explicitly configuring disabled_hooks" but this doesn't actually allow re-enabling auto-disabled hooks.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/index.ts
Line: 78:78

Comment:
**logic:** User cannot re-enable hooks that were auto-disabled. The current logic combines both sets, but users might want to override auto-detection (e.g., they know their DCP plugin is compatible). Consider implementing priority: if user explicitly lists a hook in `disabled_hooks`, respect auto-detection; but provide a separate `enabled_hooks_override` config to force-enable specific hooks despite conflicts.

Current behavior:
- Auto-disabled: `["preemptive-compaction"]`
- User config: `disabled_hooks: []`
- Result: `preemptive-compaction` is still disabled (user cannot override)

The README states "Override auto-detection by explicitly configuring `disabled_hooks`" but this doesn't actually allow re-enabling auto-disabled hooks.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files

Confidence score: 3/5

  • Auto-disabling hooks in src/shared/plugin-compatibility.ts uses .includes(pluginName), so unrelated package names containing the substring will falsely match and deactivate hooks users expect to run.
  • src/index.ts always applies previously auto-disabled hooks even when disabled_hooks is empty, meaning developers can’t re-enable them through config and remain stuck without those hooks.
  • Pay close attention to src/shared/plugin-compatibility.ts, src/index.ts - both contain logic that can unnecessarily disable hooks and prevent re-enabling them.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/shared/plugin-compatibility.ts">

<violation number="1" location="src/shared/plugin-compatibility.ts:110">
P1: The `.includes(pluginName)` check is overly broad and will cause false positives. Plugins like `"my-opencode-dcp-wrapper"` or `"not-opencode-elf-plugin"` would incorrectly match, auto-disabling hooks unnecessarily. Consider removing `.includes()` or replacing with a more specific check like `p.endsWith('/' + pluginName)` for scoped packages with different orgs.</violation>
</file>

<file name="src/index.ts">

<violation number="1" location="src/index.ts:78">
P2: Logic error: Users cannot re-enable hooks that were auto-disabled. The current implementation merges both sets (auto-disabled + user-disabled), so `disabled_hooks: []` in user config won't override auto-detection. This contradicts the README which states users can 'Override auto-detection by explicitly configuring disabled_hooks'. Consider adding an `enabled_hooks_override` config option or changing the logic so that explicitly omitting a hook from `disabled_hooks` re-enables it.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

for (const pluginName of pluginNames) {
const hasPlugin = installedPlugins.some(
(p) =>
p === pluginName || p.startsWith(`${pluginName}@`) || p.includes(pluginName)
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The .includes(pluginName) check is overly broad and will cause false positives. Plugins like "my-opencode-dcp-wrapper" or "not-opencode-elf-plugin" would incorrectly match, auto-disabling hooks unnecessarily. Consider removing .includes() or replacing with a more specific check like p.endsWith('/' + pluginName) for scoped packages with different orgs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/shared/plugin-compatibility.ts, line 110:

<comment>The `.includes(pluginName)` check is overly broad and will cause false positives. Plugins like `"my-opencode-dcp-wrapper"` or `"not-opencode-elf-plugin"` would incorrectly match, auto-disabling hooks unnecessarily. Consider removing `.includes()` or replacing with a more specific check like `p.endsWith('/' + pluginName)` for scoped packages with different orgs.</comment>

<file context>
@@ -0,0 +1,160 @@
+    for (const pluginName of pluginNames) {
+      const hasPlugin = installedPlugins.some(
+        (p) =>
+          p === pluginName || p.startsWith(`${pluginName}@`) || p.includes(pluginName)
+      );
+
</file context>
Fix with Cubic

const conflictDetection = detectConflictingPlugins(ctx.directory);
const autoDisabledHooks = new Set(conflictDetection.hooksToDisable);
const userDisabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
const disabledHooks = new Set([...autoDisabledHooks, ...userDisabledHooks]);
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Logic error: Users cannot re-enable hooks that were auto-disabled. The current implementation merges both sets (auto-disabled + user-disabled), so disabled_hooks: [] in user config won't override auto-detection. This contradicts the README which states users can 'Override auto-detection by explicitly configuring disabled_hooks'. Consider adding an enabled_hooks_override config option or changing the logic so that explicitly omitting a hook from disabled_hooks re-enables it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/index.ts, line 78:

<comment>Logic error: Users cannot re-enable hooks that were auto-disabled. The current implementation merges both sets (auto-disabled + user-disabled), so `disabled_hooks: []` in user config won't override auto-detection. This contradicts the README which states users can 'Override auto-detection by explicitly configuring disabled_hooks'. Consider adding an `enabled_hooks_override` config option or changing the logic so that explicitly omitting a hook from `disabled_hooks` re-enables it.</comment>

<file context>
@@ -62,17 +62,25 @@ import {
+  const conflictDetection = detectConflictingPlugins(ctx.directory);
+  const autoDisabledHooks = new Set(conflictDetection.hooksToDisable);
+  const userDisabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
+  const disabledHooks = new Set([...autoDisabledHooks, ...userDisabledHooks]);
+  
+  if (conflictDetection.hasConflicts) {
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OMO is to eager, it overrides other OpenCode plugins

2 participants