Skip to content

Conversation

@code-yeongyu
Copy link
Owner

@code-yeongyu code-yeongyu commented Jan 4, 2026

Summary

Fixes the actual v1.1.1 permission compatibility issue by implementing runtime version detection and automatic migration.

What was wrong before

Previous PR #489 created utilities but didn't properly use them:

  • Mixed tools and permission in same config (invalid)
  • No runtime version detection applied
  • No migration for user JSON configs

What this PR does

  1. Version-aware agent restrictions (createAgentToolRestrictions)

    • v1.1.1+: Returns { permission: { tool: "deny" } }
    • Older: Returns { tools: { tool: false } }
  2. All builtin agents updated

    • oracle, explore, librarian, document-writer, frontend-ui-ux-engineer, multimodal-looker
    • All use createAgentToolRestrictions() instead of hardcoded formats
  3. Runtime migration in config-handler.ts

    • Migrates user agent configs from oh-my-opencode.json
    • Migrates project agent configs
    • Migrates Claude Code plugin agent configs
    • Migrates OpenCode's own agent config overrides

Migration logic

// v1.1.1+ detected
{ tools: { write: false } }  { permission: { write: "deny" } }

// Older version detected
{ permission: { write: "deny" } }  { tools: { write: false } }

Testing

  • 606 tests pass (1 pre-existing failure unrelated)
  • Typecheck passes
  • Build succeeds

Closes #487


🤖 100% written by Sisyphus

Generated with OhMyOpenCode


Summary by cubic

Fixes permission compatibility for OpenCode v1.1.1 by adding runtime version detection and automatic config migration. Updates all built-in agents to a version-aware restrictions helper to prevent mixed tools/permission formats.

  • Bug Fixes
    • Added createAgentToolRestrictions() that returns permission for v1.1.1+ and tools for older versions.
    • Auto-migrates agent configs at load (user, project, plugin, overrides) via migrateAgentConfig().
    • Updated agents (oracle, explore, librarian, document-writer, frontend-ui-ux-engineer, multimodal-looker) to use the helper.
    • Added helpers to migrate tools <-> permission formats and updated tests accordingly.

Written for commit 6c3ef65. Summary will update on new commits.

….1.1

- Rewrite permission-compat.ts with runtime version detection
- createAgentToolRestrictions() returns correct format per version
- v1.1.1+ uses permission format, older uses tools format
- Add migrateToolsToPermission/migratePermissionToTools helpers
- Update test suite for new API

🤖 Generated with assistance of OhMyOpenCode
https://github.com/code-yeongyu/oh-my-opencode
- Replace hardcoded tools: { X: false } format with version-aware utility
- All agents now use createAgentToolRestrictions([...])
- Ensures compatibility with both old and new OpenCode versions

🤖 Generated with assistance of OhMyOpenCode
https://github.com/code-yeongyu/oh-my-opencode
Migrate tools/permission format in user/project/plugin agent configs
based on detected OpenCode version at load time.

🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
@greptile-apps
Copy link

greptile-apps bot commented Jan 4, 2026

Greptile Summary

This PR properly implements OpenCode v1.1.1 permission system migration by fixing the incomplete approach from PR #489. The changes correctly apply version detection at runtime and migrate all agent configurations across the system.

Key improvements:

  • Simplified API: createAgentToolRestrictions() automatically returns the correct format based on detected OpenCode version (v1.1.1+ uses permission, older uses tools)
  • Comprehensive migration: All builtin agents (oracle, explore, librarian, document-writer, frontend-ui-ux-engineer, multimodal-looker) now use the helper function instead of hardcoded formats
  • Runtime config migration: User agents from oh-my-opencode.json, project agents, Claude Code plugin agents, and OpenCode's own agent overrides are all migrated at runtime via migrateAgentConfig()
  • Backward compatibility: Older versions automatically convert permissiontools, newer versions convert toolspermission

What was wrong in #489:

The previous PR created utilities but didn't properly integrate them - agents had mixed tools and permission in the same config (invalid), no runtime version detection was applied to agent creation, and user JSON configs weren't migrated.

Migration logic:

// v1.1.1+ detected
{ tools: { write: false } }  { permission: { write: "deny" } }

// Older version detected  
{ permission: { write: "deny" } }  { tools: { write: false } }

The implementation is clean, well-tested, and ensures both forward and backward compatibility across OpenCode versions.

Confidence Score: 5/5

  • This PR is safe to merge with no critical issues
  • The implementation is thorough and correct: version detection is cached and safe with fallback, all builtin agents consistently use the helper function, runtime migration covers all agent sources (user/project/plugin/opencode), tests validate the core logic, and the approach maintains backward compatibility while supporting the new v1.1.1 format
  • No files require special attention

Important Files Changed

Filename Overview
src/shared/permission-compat.ts Refactored to provide version-aware tool restrictions via createAgentToolRestrictions(), replacing complex utilities with simple migration helpers
src/plugin-handlers/config-handler.ts Added runtime migration for user, project, plugin, and OpenCode agent configs using migrateAgentConfig()
src/agents/oracle.ts Updated to use createAgentToolRestrictions() for version-aware permission format
src/agents/explore.ts Updated to use createAgentToolRestrictions() for version-aware permission format

Sequence Diagram

sequenceDiagram
    participant Plugin as Plugin Init
    participant ConfigHandler as config-handler.ts
    participant VersionDetect as opencode-version.ts
    participant PermCompat as permission-compat.ts
    participant Agents as Agent Configs
    
    Note over Plugin,Agents: Startup: Version Detection
    Plugin->>ConfigHandler: Load configuration
    ConfigHandler->>VersionDetect: getOpenCodeVersion()
    VersionDetect->>VersionDetect: execSync("opencode --version")
    VersionDetect-->>VersionDetect: Cache result
    
    Note over Plugin,Agents: Builtin Agent Creation
    ConfigHandler->>Agents: createBuiltinAgents()
    Agents->>PermCompat: createAgentToolRestrictions(denyTools)
    PermCompat->>VersionDetect: supportsNewPermissionSystem()
    alt v1.1.1+
        PermCompat-->>Agents: { permission: { tool: "deny" } }
    else Older version
        PermCompat-->>Agents: { tools: { tool: false } }
    end
    
    Note over Plugin,Agents: User Agent Migration
    ConfigHandler->>ConfigHandler: Load user agents (oh-my-opencode.json)
    ConfigHandler->>PermCompat: migrateAgentConfig(userAgent)
    PermCompat->>VersionDetect: supportsNewPermissionSystem()
    alt v1.1.1+ with tools config
        PermCompat->>PermCompat: migrateToolsToPermission()
        PermCompat-->>ConfigHandler: { permission: {...}, tools: deleted }
    else Older with permission config
        PermCompat->>PermCompat: migratePermissionToTools()
        PermCompat-->>ConfigHandler: { tools: {...}, permission: deleted }
    end
    
    Note over Plugin,Agents: Project & Plugin Agent Migration
    ConfigHandler->>PermCompat: migrateAgentConfig(projectAgent)
    ConfigHandler->>PermCompat: migrateAgentConfig(pluginAgent)
    ConfigHandler->>PermCompat: migrateAgentConfig(opencodeAgent)
    
    Note over Plugin,Agents: Final Config Assembly
    ConfigHandler-->>Plugin: Complete config with migrated agents
Loading

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.

4 issues found across 9 files

Confidence score: 3/5

  • src/plugin-handlers/config-handler.ts can reintroduce the legacy tools fields after migration, so agent configs might silently revert to an old format and undo the intended schema upgrade.
  • src/shared/permission-compat.ts still uses a loose typeof === "object" check, meaning arrays pass through and get migrated incorrectly (e.g., ['edit'] becoming { '0': 'allow' }), which could break permission handling.
  • Pay close attention to src/plugin-handlers/config-handler.ts, src/shared/permission-compat.ts - migration logic needs to stay consistent and reject arrays to avoid regressions.
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/permission-compat.ts">

<violation number="1" location="src/shared/permission-compat.ts:58">
P2: Use `isPlainObject` from `./deep-merge` instead of `typeof === &quot;object&quot;` check. The current check passes for arrays, which would cause incorrect migration (e.g., `[&quot;edit&quot;]` → `{ &quot;0&quot;: &quot;allow&quot; }`).</violation>

<violation number="2" location="src/shared/permission-compat.ts:68">
P2: Use `isPlainObject` from `./deep-merge` instead of `typeof === &quot;object&quot;` check. This ensures arrays are properly rejected and maintains consistency with other object checks in the codebase.</violation>
</file>

<file name="src/plugin-handlers/config-handler.ts">

<violation number="1" location="src/plugin-handlers/config-handler.ts:110">
P1: After migrating agent configs, this handler later re-adds `tools` for `explore`/`librarian`/`multimodal-looker`, which can undo the migration and reintroduce legacy fields. Consider applying the same version-aware restriction logic here (set `permission` instead of `tools` when the new system is detected), or run migration after these mutations so the final shape is consistent.</violation>

<violation number="2" location="src/plugin-handlers/config-handler.ts:195">
P2: Migration isn’t applied to `config.agent` overrides when Sisyphus is disabled (`...configAgent` is merged as-is). This can leave old-format agent configs un-migrated in that mode. Consider migrating `configAgent` in the else-branch too (e.g., map entries through `migrateAgentConfig`) so version compatibility is consistent regardless of Sisyphus enablement.</violation>
</file>

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

delete result.tools
}
} else {
if (result.permission && typeof result.permission === "object") {
Copy link

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

Choose a reason for hiding this comment

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

P2: Use isPlainObject from ./deep-merge instead of typeof === "object" check. This ensures arrays are properly rejected and maintains consistency with other object checks in the codebase.

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

<comment>Use `isPlainObject` from `./deep-merge` instead of `typeof === &quot;object&quot;` check. This ensures arrays are properly rejected and maintains consistency with other object checks in the codebase.</comment>

<file context>
@@ -1,72 +1,78 @@
+      delete result.tools
+    }
+  } else {
+    if (result.permission &amp;&amp; typeof result.permission === &quot;object&quot;) {
+      const existingTools = (result.tools as Record&lt;string, boolean&gt;) || {}
+      const migratedTools = migratePermissionToTools(
</file context>
Fix with Cubic

if (config.permission) {
result.permission = config.permission
if (supportsNewPermissionSystem()) {
if (result.tools && typeof result.tools === "object") {
Copy link

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

Choose a reason for hiding this comment

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

P2: Use isPlainObject from ./deep-merge instead of typeof === "object" check. The current check passes for arrays, which would cause incorrect migration (e.g., ["edit"]{ "0": "allow" }).

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

<comment>Use `isPlainObject` from `./deep-merge` instead of `typeof === &quot;object&quot;` check. The current check passes for arrays, which would cause incorrect migration (e.g., `[&quot;edit&quot;]` → `{ &quot;0&quot;: &quot;allow&quot; }`).</comment>

<file context>
@@ -1,72 +1,78 @@
-  if (config.permission) {
-    result.permission = config.permission
+  if (supportsNewPermissionSystem()) {
+    if (result.tools &amp;&amp; typeof result.tools === &quot;object&quot;) {
+      const existingPermission =
+        (result.permission as Record&lt;string, PermissionValue&gt;) || {}
</file context>
Fix with Cubic

: {};
.map(([key, value]) => [
key,
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
Copy link

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

Choose a reason for hiding this comment

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

P2: Migration isn’t applied to config.agent overrides when Sisyphus is disabled (...configAgent is merged as-is). This can leave old-format agent configs un-migrated in that mode. Consider migrating configAgent in the else-branch too (e.g., map entries through migrateAgentConfig) so version compatibility is consistent regardless of Sisyphus enablement.

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

<comment>Migration isn’t applied to `config.agent` overrides when Sisyphus is disabled (`...configAgent` is merged as-is). This can leave old-format agent configs un-migrated in that mode. Consider migrating `configAgent` in the else-branch too (e.g., map entries through `migrateAgentConfig`) so version compatibility is consistent regardless of Sisyphus enablement.</comment>

<file context>
@@ -162,15 +182,20 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
-        : {};
+            .map(([key, value]) =&gt; [
+              key,
+              value ? migrateAgentConfig(value as Record&lt;string, unknown&gt;) : value,
+            ])
+        )
</file context>
Fix with Cubic

const userAgents = Object.fromEntries(
Object.entries(rawUserAgents).map(([k, v]) => [
k,
v ? migrateAgentConfig(v as Record<string, unknown>) : v,
Copy link

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

Choose a reason for hiding this comment

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

P1: After migrating agent configs, this handler later re-adds tools for explore/librarian/multimodal-looker, which can undo the migration and reintroduce legacy fields. Consider applying the same version-aware restriction logic here (set permission instead of tools when the new system is detected), or run migration after these mutations so the final shape is consistent.

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

<comment>After migrating agent configs, this handler later re-adds `tools` for `explore`/`librarian`/`multimodal-looker`, which can undo the migration and reintroduce legacy fields. Consider applying the same version-aware restriction logic here (set `permission` instead of `tools` when the new system is detected), or run migration after these mutations so the final shape is consistent.</comment>

<file context>
@@ -95,13 +96,32 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
+    const userAgents = Object.fromEntries(
+      Object.entries(rawUserAgents).map(([k, v]) =&gt; [
+        k,
+        v ? migrateAgentConfig(v as Record&lt;string, unknown&gt;) : v,
+      ])
+    );
</file context>
Fix with Cubic

@code-yeongyu code-yeongyu merged commit 8f2209a into dev Jan 4, 2026
4 checks passed
@code-yeongyu code-yeongyu deleted the fix/v1.1.1-permission-migration branch January 4, 2026 20:28
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.

opencode v1.1.1 compatibility

2 participants