Skip to content

fix(opencode): don't crash the whole session when plugins/lib is missing#2538

Open
shanujans wants to merge 6 commits into
affaan-m:mainfrom
shanujans:fix/opencode-termux-missing-plugins-2530
Open

fix(opencode): don't crash the whole session when plugins/lib is missing#2538
shanujans wants to merge 6 commits into
affaan-m:mainfrom
shanujans:fix/opencode-termux-missing-plugins-2530

Conversation

@shanujans

Copy link
Copy Markdown

Fixes #2530

changed-files.ts statically imported ../plugins/lib/changed-files-store.js.
Since tools/index.ts re-exports every custom tool from one barrel file, a
missing/incomplete ~/.opencode/plugins directory (e.g. an interrupted
install on Termux/Android) made that single import throw during module
evaluation — which crashed the entire tools module, and with it, OpenCode
session startup, on the very first tool-loading pass.

This loads the store lazily inside execute() instead, so a missing
dependency only breaks the changed-files tool when it's actually invoked,
with a clear error pointing at ecc repair --target opencode. Every other
tool keeps working and the session no longer refuses to start.

Also adds a TROUBLESHOOTING.md entry for this crash, including a note that
the other half of #2530 (ProviderModelNotFoundError /
oh-my-opencode-slim.json) belongs to the third-party
oh-my-opencode-slim
plugin, not ECC — ECC never writes to ~/.config/opencode/.

Testing: Verified by removing the compiled plugins/ directory and
confirming the module still loads (no barrel-import crash) and only fails,
gracefully, at invocation. All existing test suites
(opencode-tools, opencode-config, opencode-plugin-hooks,
changed-files-store, build-opencode) pass.

@shanujans
shanujans requested a review from affaan-m as a code owner July 19, 2026 21:28
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changed-files tool and ECC hooks now load the changed-files store lazily and tolerate its absence. Tests cover missing and available stores, while troubleshooting documentation adds Termux/Android recovery guidance and provider model-prefix clarification.

Changes

OpenCode startup handling

Layer / File(s) Summary
Lazy changed-files store loading
.opencode/tools/changed-files.ts
Runtime store imports are deferred until tool execution, memoized, and converted to a targeted error when loading fails.
ECC hooks fallback and validation
.opencode/plugins/ecc-hooks.ts, tests/opencode-plugin-hooks.test.js
The plugin loads the store at runtime, logs failures, guards store operations, and tests behavior with both missing and available plugin files.
Termux startup troubleshooting
TROUBLESHOOTING.md
Adds guidance for missing plugin files, repair and diagnostic commands, provider model-prefix corrections, and the related examples/ documentation link.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenCode
  participant ECCHooksPlugin
  participant changedFilesStore
  OpenCode->>ECCHooksPlugin: initialize plugin
  ECCHooksPlugin->>changedFilesStore: dynamically import store
  changedFilesStore-->>ECCHooksPlugin: store module or load failure
  OpenCode->>ECCHooksPlugin: dispatch file/tool/session hook
  ECCHooksPlugin->>changedFilesStore: record or clear changes when available
Loading

Possibly related PRs

  • affaan-m/ECC#334: Both PRs modify ECCHooksPlugin hook handlers, including changed-files behavior.

Suggested reviewers: affaan-m, affaan-m

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #2530 also requires fixing openai/ model prefixes, but this PR only addresses the missing plugins path and leaves that requirement untouched. Either implement the model-prefix update in oh-my-opencode-slim.json or narrow the linked issue to the ECC-side missing plugins fix.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: preventing session crashes when plugins/lib is missing.
Description check ✅ Passed The description directly explains the missing-store crash, the lazy-load fix, and the troubleshooting docs.
Out of Scope Changes check ✅ Passed The changes stay focused on startup resilience, troubleshooting, and tests; no unrelated code paths were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a crash-on-startup regression on Termux/Android where a missing ~/.opencode/plugins/ directory caused the static import in changed-files.ts to throw during module evaluation, taking down the entire tools/index.ts barrel export and preventing OpenCode from starting. The fix converts the runtime import to a lazy dynamic import() inside execute(), isolated behind a module-level promise cache with retry-on-failure, so a missing dependency only breaks the one tool at invocation time rather than the whole session.

  • Lazy-load with promise cache: loadChangedFilesStore() stores the in-flight import() promise and resets it to undefined on failure, allowing subsequent invocations to retry (e.g. after running ecc repair).
  • TypeScript types preserved: The import type { ChangeType, TreeNode } at the top is a compile-time-only import — correctly kept to preserve type safety without any runtime module load.
  • TROUBLESHOOTING.md: Adds a targeted entry for the Termux/Android crash with symptom, cause, fix commands, and a note clarifying that the oh-my-opencode-slim model error belongs to a third-party plugin, not ECC.

Confidence Score: 5/5

Safe to merge — the change is a targeted, well-scoped fix that isolates a previously session-killing import failure to a single tool at invocation time.

The lazy-load pattern is implemented correctly: the promise cache prevents redundant parallel imports, the .catch() resets the cache to allow retries after ecc repair, and the compile-time import type keeps TypeScript type safety without any runtime module load. No existing behavior changes for users with a healthy install, and the error path now produces an actionable message rather than a startup crash.

No files require special attention.

Important Files Changed

Filename Overview
.opencode/tools/changed-files.ts Converts the static runtime import of changed-files-store.js to a lazy dynamic import with a module-level promise cache and retry-on-failure; type-only imports are correctly kept as compile-time import type.
TROUBLESHOOTING.md Adds a new section documenting the Termux/Android startup crash, its cause, repair commands, and a note attributing the unrelated oh-my-opencode-slim model error to a third-party plugin.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant OC as OpenCode Session
    participant TI as tools/index.ts (barrel)
    participant CF as changed-files.ts
    participant LS as loadChangedFilesStore()
    participant Store as plugins/lib/changed-files-store.js

    OC->>TI: load tools module
    TI->>CF: import changed-files.ts
    Note over CF: Only `import type` at top-level
    CF-->>TI: module ready
    TI-->>OC: all tools loaded

    OC->>CF: execute(args)
    CF->>LS: await loadChangedFilesStore()
    alt store not yet loaded
        LS->>Store: dynamic import()
        alt import succeeds
            Store-->>LS: module
            LS-->>CF: buildTree, getChangedPaths, hasChanges
        else import fails
            Store-->>LS: error
            LS->>LS: reset promise to undefined
            LS-->>CF: throw descriptive Error
        end
    else promise cached
        LS-->>CF: buildTree, getChangedPaths, hasChanges
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant OC as OpenCode Session
    participant TI as tools/index.ts (barrel)
    participant CF as changed-files.ts
    participant LS as loadChangedFilesStore()
    participant Store as plugins/lib/changed-files-store.js

    OC->>TI: load tools module
    TI->>CF: import changed-files.ts
    Note over CF: Only `import type` at top-level
    CF-->>TI: module ready
    TI-->>OC: all tools loaded

    OC->>CF: execute(args)
    CF->>LS: await loadChangedFilesStore()
    alt store not yet loaded
        LS->>Store: dynamic import()
        alt import succeeds
            Store-->>LS: module
            LS-->>CF: buildTree, getChangedPaths, hasChanges
        else import fails
            Store-->>LS: error
            LS->>LS: reset promise to undefined
            LS-->>CF: throw descriptive Error
        end
    else promise cached
        LS-->>CF: buildTree, getChangedPaths, hasChanges
    end
Loading

Reviews (2): Last reviewed commit: "fix: address review feedback (trailing n..." | Re-trigger Greptile

Comment thread TROUBLESHOOTING.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@TROUBLESHOOTING.md`:
- Around line 310-316: Update the Termux troubleshooting symptom in
TROUBLESHOOTING.md to document the new runtime error produced after lazy-loading
the changed-files dependency, while retaining the existing ResolveMessage
startup-crash example for older versions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3c1c461f-e65a-4666-b909-4de25a54727d

📥 Commits

Reviewing files that changed from the base of the PR and between 0071fa5 and 17a4d87.

📒 Files selected for processing (2)
  • .opencode/tools/changed-files.ts
  • TROUBLESHOOTING.md
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
🪛 markdownlint-cli2 (0.23.0)
TROUBLESHOOTING.md

[warning] 465-465: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (1)
.opencode/tools/changed-files.ts (1)

2-2: LGTM!

Also applies to: 23-49, 64-64, 105-105

Comment thread TROUBLESHOOTING.md Outdated
@shanujans

Copy link
Copy Markdown
Author

Re: the Linked Issues check — the openai/→opencode/ prefix issue lives in
~/.config/opencode/oh-my-opencode-slim.json, which belongs to the
third-party oh-my-opencode-slim plugin (https://github.com/alvinunreal/oh-my-opencode-slim),
not ECC. ECC never writes to ~/.config/opencode/, so there's nothing to fix
here for that half of #2530 — noted in the PR description and the new
TROUBLESHOOTING.md entry. This PR covers the actual ECC-side bug (missing
plugins/ crashing the whole tools barrel).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.opencode/tools/changed-files.ts (1)

23-35: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

The lazy-load fix does not cover all startup paths.

.opencode/plugins/ecc-hooks.ts still statically imports the missing store module, so OpenCode startup can fail before this tool's execute() method runs. Fix the hook import path, then align the troubleshooting wording.

  • .opencode/tools/changed-files.ts#L23-L35: extend lazy loading or remove the startup-time dependency from the hook path.
  • TROUBLESHOOTING.md#L318-L324: do not describe the startup crash as limited to older versions until that dependency is removed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.opencode/tools/changed-files.ts around lines 23 - 35, The lazy-loading
change in loadChangedFilesStore does not prevent startup failures caused by the
static store import in .opencode/plugins/ecc-hooks.ts; remove or defer that hook
dependency so the missing module is only loaded when needed. Update
.opencode/tools/changed-files.ts lines 23-35 as needed to cover the hook path,
and revise TROUBLESHOOTING.md lines 318-324 to describe the startup crash
without limiting it to older versions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.opencode/tools/changed-files.ts:
- Around line 23-35: The lazy-loading change in loadChangedFilesStore does not
prevent startup failures caused by the static store import in
.opencode/plugins/ecc-hooks.ts; remove or defer that hook dependency so the
missing module is only loaded when needed. Update
.opencode/tools/changed-files.ts lines 23-35 as needed to cover the hook path,
and revise TROUBLESHOOTING.md lines 318-324 to describe the startup crash
without limiting it to older versions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: db9aedf4-e752-4551-b005-cbab96280c1a

📥 Commits

Reviewing files that changed from the base of the PR and between 17a4d87 and d51e515.

📒 Files selected for processing (2)
  • .opencode/tools/changed-files.ts
  • TROUBLESHOOTING.md
📜 Review details
🔇 Additional comments (2)
.opencode/tools/changed-files.ts (1)

2-2: LGTM!

Also applies to: 64-64, 105-105

TROUBLESHOOTING.md (1)

336-340: LGTM!

Also applies to: 466-466

@daltino daltino left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This PR resolves a crash issue when the plugins/lib directory is missing by introducing lazy loading in changed-files.ts. The changes improve robustness and include helpful troubleshooting instructions in TROUBLESHOOTING.md for affected users. Overall, this is a straightforward fix with clear additions and no breaking changes. Nice work!

@shanujans

Copy link
Copy Markdown
Author

Pushed a follow-up commit addressing the CodeRabbit/Greptile feedback
(trailing newlines, updated symptom wording). Ready for review whenever
you get a chance-also happy to answer any questions about the
oh-my-opencode-slim scoping note.

@haelyra

haelyra commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Thank you for working on this! The lazy-load approach is a good idea and the troubleshooting note is helpful. Before we can merge it, please also cover the remaining startup path in .opencode/plugins/ecc-hooks.ts, which still appears to statically reach the missing store dependency, and then align the troubleshooting wording with that fix. We appreciate the effort here; once that last import path is handled, this should be in much better shape.

@ecc-tools

ecc-tools Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@shanujans

Copy link
Copy Markdown
Author

Good catch. I pushed a fix. ecc-hooks.ts had the same static-import
bug, and it's actually the more important one since it's OpenCode's
plugin entry point (loaded before tools/index.ts at session startup).
Applied the same lazy-load pattern there: the plugin now loads fine
even with plugins/lib missing, with a one-time warning and
changed-files tracking gracefully disabled instead of crashing the
whole session. Verified by removing plugins/lib and confirming the
plugin still initializes and all other hooks still fire. Updated
TROUBLESHOOTING.md to cover both paths. All existing tests pass.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.opencode/plugins/ecc-hooks.ts:
- Around line 107-125: Add regression tests for the lazy changed-files store
loading in the plugin initialization flow: verify a missing store resolves
startup, emits the warning, and leaves other hooks usable; verify successful
loading calls initStore and exercises every record and clear path. Provide unit,
integration, and end-to-end coverage, writing tests before implementation and
maintaining at least 80% coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 66e7b42e-deae-418d-b4e7-71ae2b0a570e

📥 Commits

Reviewing files that changed from the base of the PR and between d51e515 and 20f62ed.

📒 Files selected for processing (2)
  • .opencode/plugins/ecc-hooks.ts
  • TROUBLESHOOTING.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Delegate complex feature planning, architectural decisions, security-sensitive work, testing, reviews, and domain-specific tasks to the appropriate specialized agent; use parallel execution for independent operations.
Write tests before implementation and maintain at least 80% coverage; required test types are unit, integration, and end-to-end tests.
Validate all external and user input at system boundaries using schema-based validation, fail clearly, and never trust external data.
Before every commit, prevent hardcoded secrets, validate inputs, use parameterized SQL, sanitize HTML, enable CSRF protection, verify authentication and authorization, rate-limit endpoints, and avoid leaking sensitive data in errors.
Never hardcode secrets; use environment variables or a secret manager, validate required secrets at startup, and rotate exposed secrets immediately.
Always preserve immutability: create new objects and return copies instead of mutating existing objects.
Handle errors at every level, provide user-friendly UI messages, log detailed server-side context, and never silently swallow errors.
Prefer many small, focused files organized by feature or domain; keep functions under 50 lines, files under 800 lines, nesting at four levels or less, and identifiers readable and well named.
Plan complex work before implementation, identify dependencies and risks, and break the work into phases.
Use the TDD workflow: write a failing test, implement the minimum passing solution, then refactor and verify coverage.
When troubleshooting test failures, check test isolation, verify mocks, and fix the implementation rather than tests unless the tests are incorrect.
Use Conventional Commits with the format <type>: <description> and one of: feat, fix, refactor, docs, test, chore, perf, or ci.
For pull requests, analyze the full commit history, write a comprehensive summary, include a test plan, and push with -u.
Use a consistent API response envelope containing a success ind...

Files:

  • TROUBLESHOOTING.md
🔇 Additional comments (3)
.opencode/plugins/ecc-hooks.ts (2)

107-125: 🩺 Stability & Availability

Keep the startup fallback independent of logging failures.

log(...) delegates to client.app.log(...), but this new catch path neither awaits nor guards that call. If the SDK log request rejects while the store is missing, it can create an unhandled rejection and undermine the startup-resilience guarantee. Make this diagnostic best-effort and verify the SDK’s app.log failure semantics.

As per coding guidelines, handle errors at every level.

Source: Coding guidelines


16-21: LGTM!

Also applies to: 171-171, 215-224, 430-430, 445-445

TROUBLESHOOTING.md (1)

308-345: LGTM!

Also applies to: 470-470

Comment thread .opencode/plugins/ecc-hooks.ts
@ecc-tools

ecc-tools Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/opencode-plugin-hooks.test.js`:
- Around line 108-116: Update the warning assertion in the relevant test to
count matching warn entries and assert that exactly one matches, rather than
using client.logs.some(...). Preserve the existing level and message predicates
and the one-time warning expectation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6aabc3d6-3cf9-4fc1-8f0a-6035fa1f0f8a

📥 Commits

Reviewing files that changed from the base of the PR and between 20f62ed and b3dc200.

📒 Files selected for processing (1)
  • tests/opencode-plugin-hooks.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}

📄 CodeRabbit inference engine (.cursor/rules/common-coding-style.md)

**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}: Always create new objects, never mutate existing ones. Use immutable patterns to prevent hidden side effects and enable safe concurrency
Organize code into many small files (200-400 lines typical, 800 lines max) organized by feature/domain rather than by type
Always handle errors explicitly at every level and never silently swallow errors
Always validate all user input before processing at system boundaries
Use schema-based validation where available
Fail fast with clear error messages when validation fails
Never trust external data (API responses, user input, file content)
Ensure code is readable and well-named
Keep functions small (less than 50 lines)
Keep files focused (less than 800 lines)
Avoid deep nesting (more than 4 levels)
Do not use hardcoded values; use constants or configuration instead

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

No hardcoded secrets (API keys, passwords, tokens) - validate before any commit

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}: All user inputs must be validated
Enable CSRF protection on all state-changing endpoints
Verify authentication and authorization for all protected endpoints
Implement rate limiting on all endpoints to prevent abuse
Ensure error messages do not leak sensitive data in responses

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,sql}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Use parameterized queries to prevent SQL injection

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,html,php,java,cs,rb,go}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Implement XSS prevention by sanitizing HTML output

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp,properties,yml,yaml,json,env,config}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

NEVER hardcode secrets in source code - ALWAYS use environment variables or a secret manager

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript-coding-style.md)

**/*.{ts,tsx,js,jsx}: Use spread operator for immutable updates in TypeScript/JavaScript instead of direct mutation
Use async/await with try-catch for error handling in TypeScript/JavaScript
Use Zod for schema-based input validation in TypeScript/JavaScript
No console.log statements in production code; use proper logging libraries instead

**/*.{ts,tsx,js,jsx}: Auto-format JavaScript/TypeScript files using Prettier after edit
Warn about console.log statements in edited files
Check all modified files for console.log statements before session ends

**/*.{ts,tsx,js,jsx}: Use the ApiResponse interface pattern with generic type parameter: interface ApiResponse<T> { success: boolean; data?: T; error?: string; meta?: { total: number; page: number; limit: number; } }
Implement custom React hooks following the pattern: export a named function with use prefix, generic type parameters, and proper useEffect cleanup for side effects

**/*.{ts,tsx,js,jsx}: Never hardcode secrets; always use environment variables for sensitive credentials like API keys
Throw an error when required environment variables are not configured to fail fast and ensure security prerequisites are met

Use Playwright as the E2E testing framework for critical user flows in TypeScript/JavaScript

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write tests before implementation (test-driven development); target 80%+ coverage
Achieve minimum 80% test coverage across all three layers: Unit, Integration, and E2E
Use AAA structure (Arrange / Act / Assert) in tests with descriptive test names that explain behavior under test

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,jsx,tsx}: Always create new objects and never mutate in place; return new copies instead
Keep files between 200–400 lines typical, with a maximum of 800 lines
Extract helpers when a file exceeds 200 lines
Handle errors explicitly at every level; never swallow errors silently
Validate all user input before processing; use schema-based validation where available
Never trust external data (API responses, file content, query params); always validate
All user inputs must be validated and sanitized
Error messages must be scrubbed of sensitive internals
Use readable, well-named identifiers in all code
Keep functions under 50 lines
Keep files under 800 lines
Avoid nesting deeper than 4 levels
Implement comprehensive error handling in all code
Do not hardcode values; use constants or environment configuration instead
Do not use in-place mutation; always return new objects or state

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,json,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not hardcode secrets, API keys, passwords, or tokens

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts}: Use parameterized queries for all database writes (no string interpolation)
Auth/authz must be checked server-side for every sensitive path
Rate limiting must be applied to all public endpoints

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{jsx,tsx,js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

HTML output must be sanitized where applicable

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Required environment variables must be validated at startup

Files:

  • tests/opencode-plugin-hooks.test.js
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Delegate complex feature planning, architectural decisions, security-sensitive work, testing, reviews, and domain-specific tasks to the appropriate specialized agent; use parallel execution for independent operations.
Write tests before implementation and maintain at least 80% coverage; required test types are unit, integration, and end-to-end tests.
Validate all external and user input at system boundaries using schema-based validation, fail clearly, and never trust external data.
Before every commit, prevent hardcoded secrets, validate inputs, use parameterized SQL, sanitize HTML, enable CSRF protection, verify authentication and authorization, rate-limit endpoints, and avoid leaking sensitive data in errors.
Never hardcode secrets; use environment variables or a secret manager, validate required secrets at startup, and rotate exposed secrets immediately.
Always preserve immutability: create new objects and return copies instead of mutating existing objects.
Handle errors at every level, provide user-friendly UI messages, log detailed server-side context, and never silently swallow errors.
Prefer many small, focused files organized by feature or domain; keep functions under 50 lines, files under 800 lines, nesting at four levels or less, and identifiers readable and well named.
Plan complex work before implementation, identify dependencies and risks, and break the work into phases.
Use the TDD workflow: write a failing test, implement the minimum passing solution, then refactor and verify coverage.
When troubleshooting test failures, check test isolation, verify mocks, and fix the implementation rather than tests unless the tests are incorrect.
Use Conventional Commits with the format <type>: <description> and one of: feat, fix, refactor, docs, test, chore, perf, or ci.
For pull requests, analyze the full commit history, write a comprehensive summary, include a test plan, and push with -u.
Use a consistent API response envelope containing a success ind...

Files:

  • tests/opencode-plugin-hooks.test.js
🔇 Additional comments (1)
tests/opencode-plugin-hooks.test.js (1)

128-161: LGTM!

Comment thread tests/opencode-plugin-hooks.test.js Outdated
@ecc-tools

ecc-tools Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.opencode/plugins/ecc-hooks.ts (1)

114-118: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Publish the store only after initialization succeeds.

changedFilesStore is assigned before initStore(worktreePath). If initialization throws, the catch logs that tracking is disabled but the variable remains truthy, so later optional calls still invoke a failed or partially initialized store and may crash hooks. Initialize a local module first, then assign it only after initialization succeeds.

Proposed fix
-    changedFilesStore = await import("./lib/changed-files-store.js")
-    changedFilesStore.initStore(worktreePath)
+    const store = await import("./lib/changed-files-store.js")
+    store.initStore(worktreePath)
+    changedFilesStore = store
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.opencode/plugins/ecc-hooks.ts around lines 114 - 118, Update the
changedFilesStore initialization in the surrounding hook flow to import into a
local module variable, call initStore(worktreePath), and assign
changedFilesStore only after initialization completes successfully. Keep the
catch path leaving changedFilesStore unset so later optional calls cannot use a
failed or partially initialized store.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.opencode/plugins/ecc-hooks.ts:
- Around line 123-127: Update the warning log in the changed-files tracking
fallback around log("warn") to stop interpolating the raw reason/error message.
Use a generic repair-focused message that directs the user to run `ecc repair
--target opencode`, while preserving the statement that other ECC hooks remain
unaffected.
- Around line 123-129: Update the changed-files tracking warning log in the ECC
hook so synchronous failures from log are also swallowed: defer log execution
with Promise.resolve().then(() => log(...)).catch(() => {}) or use an equivalent
nested try/catch, preserving the existing warning message and startup behavior.

---

Outside diff comments:
In @.opencode/plugins/ecc-hooks.ts:
- Around line 114-118: Update the changedFilesStore initialization in the
surrounding hook flow to import into a local module variable, call
initStore(worktreePath), and assign changedFilesStore only after initialization
completes successfully. Keep the catch path leaving changedFilesStore unset so
later optional calls cannot use a failed or partially initialized store.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3da37eac-caee-41e2-a858-e5d340f724d2

📥 Commits

Reviewing files that changed from the base of the PR and between b3dc200 and 1e5a6ba.

📒 Files selected for processing (2)
  • .opencode/plugins/ecc-hooks.ts
  • tests/opencode-plugin-hooks.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}

📄 CodeRabbit inference engine (.cursor/rules/common-coding-style.md)

**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}: Always create new objects, never mutate existing ones. Use immutable patterns to prevent hidden side effects and enable safe concurrency
Organize code into many small files (200-400 lines typical, 800 lines max) organized by feature/domain rather than by type
Always handle errors explicitly at every level and never silently swallow errors
Always validate all user input before processing at system boundaries
Use schema-based validation where available
Fail fast with clear error messages when validation fails
Never trust external data (API responses, user input, file content)
Ensure code is readable and well-named
Keep functions small (less than 50 lines)
Keep files focused (less than 800 lines)
Avoid deep nesting (more than 4 levels)
Do not use hardcoded values; use constants or configuration instead

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

No hardcoded secrets (API keys, passwords, tokens) - validate before any commit

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}: All user inputs must be validated
Enable CSRF protection on all state-changing endpoints
Verify authentication and authorization for all protected endpoints
Implement rate limiting on all endpoints to prevent abuse
Ensure error messages do not leak sensitive data in responses

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,sql}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Use parameterized queries to prevent SQL injection

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,html,php,java,cs,rb,go}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Implement XSS prevention by sanitizing HTML output

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp,properties,yml,yaml,json,env,config}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

NEVER hardcode secrets in source code - ALWAYS use environment variables or a secret manager

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript-coding-style.md)

**/*.{ts,tsx,js,jsx}: Use spread operator for immutable updates in TypeScript/JavaScript instead of direct mutation
Use async/await with try-catch for error handling in TypeScript/JavaScript
Use Zod for schema-based input validation in TypeScript/JavaScript
No console.log statements in production code; use proper logging libraries instead

**/*.{ts,tsx,js,jsx}: Auto-format JavaScript/TypeScript files using Prettier after edit
Warn about console.log statements in edited files
Check all modified files for console.log statements before session ends

**/*.{ts,tsx,js,jsx}: Use the ApiResponse interface pattern with generic type parameter: interface ApiResponse<T> { success: boolean; data?: T; error?: string; meta?: { total: number; page: number; limit: number; } }
Implement custom React hooks following the pattern: export a named function with use prefix, generic type parameters, and proper useEffect cleanup for side effects

**/*.{ts,tsx,js,jsx}: Never hardcode secrets; always use environment variables for sensitive credentials like API keys
Throw an error when required environment variables are not configured to fail fast and ensure security prerequisites are met

Use Playwright as the E2E testing framework for critical user flows in TypeScript/JavaScript

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write tests before implementation (test-driven development); target 80%+ coverage
Achieve minimum 80% test coverage across all three layers: Unit, Integration, and E2E
Use AAA structure (Arrange / Act / Assert) in tests with descriptive test names that explain behavior under test

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,jsx,tsx}: Always create new objects and never mutate in place; return new copies instead
Keep files between 200–400 lines typical, with a maximum of 800 lines
Extract helpers when a file exceeds 200 lines
Handle errors explicitly at every level; never swallow errors silently
Validate all user input before processing; use schema-based validation where available
Never trust external data (API responses, file content, query params); always validate
All user inputs must be validated and sanitized
Error messages must be scrubbed of sensitive internals
Use readable, well-named identifiers in all code
Keep functions under 50 lines
Keep files under 800 lines
Avoid nesting deeper than 4 levels
Implement comprehensive error handling in all code
Do not hardcode values; use constants or environment configuration instead
Do not use in-place mutation; always return new objects or state

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,jsx,tsx,json,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not hardcode secrets, API keys, passwords, or tokens

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts}: Use parameterized queries for all database writes (no string interpolation)
Auth/authz must be checked server-side for every sensitive path
Rate limiting must be applied to all public endpoints

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{jsx,tsx,js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

HTML output must be sanitized where applicable

Files:

  • tests/opencode-plugin-hooks.test.js
**/*.{js,ts,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Required environment variables must be validated at startup

Files:

  • tests/opencode-plugin-hooks.test.js
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Delegate complex feature planning, architectural decisions, security-sensitive work, testing, reviews, and domain-specific tasks to the appropriate specialized agent; use parallel execution for independent operations.
Write tests before implementation and maintain at least 80% coverage; required test types are unit, integration, and end-to-end tests.
Validate all external and user input at system boundaries using schema-based validation, fail clearly, and never trust external data.
Before every commit, prevent hardcoded secrets, validate inputs, use parameterized SQL, sanitize HTML, enable CSRF protection, verify authentication and authorization, rate-limit endpoints, and avoid leaking sensitive data in errors.
Never hardcode secrets; use environment variables or a secret manager, validate required secrets at startup, and rotate exposed secrets immediately.
Always preserve immutability: create new objects and return copies instead of mutating existing objects.
Handle errors at every level, provide user-friendly UI messages, log detailed server-side context, and never silently swallow errors.
Prefer many small, focused files organized by feature or domain; keep functions under 50 lines, files under 800 lines, nesting at four levels or less, and identifiers readable and well named.
Plan complex work before implementation, identify dependencies and risks, and break the work into phases.
Use the TDD workflow: write a failing test, implement the minimum passing solution, then refactor and verify coverage.
When troubleshooting test failures, check test isolation, verify mocks, and fix the implementation rather than tests unless the tests are incorrect.
Use Conventional Commits with the format <type>: <description> and one of: feat, fix, refactor, docs, test, chore, perf, or ci.
For pull requests, analyze the full commit history, write a comprehensive summary, include a test plan, and push with -u.
Use a consistent API response envelope containing a success ind...

Files:

  • tests/opencode-plugin-hooks.test.js
🔇 Additional comments (2)
.opencode/plugins/ecc-hooks.ts (1)

18-21: LGTM!

Also applies to: 77-78, 176-176, 220-229, 435-435, 450-450

tests/opencode-plugin-hooks.test.js (1)

87-128: LGTM!

Also applies to: 129-164

Comment thread .opencode/plugins/ecc-hooks.ts Outdated
Comment thread .opencode/plugins/ecc-hooks.ts Outdated
@ecc-tools

ecc-tools Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@shanujans

Copy link
Copy Markdown
Author

All three addressed:

  • changedFilesStore is now only assigned after both the import and
    initStore() succeed, so a partial failure can't leave a
    half-initialized store reachable.
  • Dropped the raw error message from the warning (it could leak
    absolute filesystem paths) in favor of a generic repair-focused
    message.
  • Deferred the log() call via .then() instead of Promise.resolve(log()),
    since the latter evaluates log() eagerly and lets a synchronous
    throw escape the catch entirely. Verified by simulating a client
    whose app.log throws synchronously — previously this would have
    rejected the whole ECCHooksPlugin() call; now it doesn't.

All 9 tests pass, full opencode suite still green.

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 crashes on startup on Termux/Android due to model provider mismatch & missing plugins directory

3 participants