Skip to content

fix(install-targets): validate compiled OpenCode plugin before install#2041

Open
gaurav0107 wants to merge 4 commits into
affaan-m:mainfrom
gaurav0107:fix/2040-opencode-install-build-and-config-path
Open

fix(install-targets): validate compiled OpenCode plugin before install#2041
gaurav0107 wants to merge 4 commits into
affaan-m:mainfrom
gaurav0107:fix/2040-opencode-install-build-and-config-path

Conversation

@gaurav0107
Copy link
Copy Markdown
Contributor

@gaurav0107 gaurav0107 commented May 22, 2026

Summary

Fixes #2040.

OpenCode installs through node scripts/install-apply.js --target opencode --profile full end up with / slash commands visible in autocomplete but
silently non-functional — the plugin entry point loads, but .opencode/dist/
(the compiled JavaScript payload OpenCode actually executes) is missing from
fresh git clone checkouts because scripts/build-opencode.js only runs as
part of npm pack's prepack hook. This PR makes that broken-state install
fail fast with an actionable message instead of installing successfully and
leaving the user with a non-functional plugin surface.

Root cause

scripts/build-opencode.js produces .opencode/dist/{index.js, plugins/, tools/}.
That dist is wired into npm pack via prepack and the files array in
package.json, so npm-package consumers always get a working payload. But
the installer (scripts/install-apply.js → opencode-home) copies straight from
.opencode/ in the source repo and never checks for the compiled output. A
fresh clone has no dist/ (it's gitignored), so the installer happily copies
TypeScript sources into ~/.opencode/ and OpenCode then refuses to execute
them.

The reporter's traceback confirms this exact symptom: commands appear in the
autocomplete list (because commands/*.md does land), but pressing enter does
nothing (because plugin hooks/tools have no compiled JS to run).

Fix

scripts/lib/install-targets/opencode-home.js now declares a validate(input)
override that:

  • Returns the existing missing-home-dir issue when no home directory is
    resolvable (matches the helper's default behaviour for kind: 'home').
  • When input.repoRoot is provided, checks that <repoRoot>/.opencode/dist/index.js
    exists. If it doesn't, returns a single error-severity issue with code
    opencode-plugin-not-built whose message names the missing path and the
    exact build command (node scripts/build-opencode.js / npm run build:opencode).

registry.planInstallTargetScaffold already aborts on any error-severity
issue, so the user sees a clear, actionable failure instead of an apparently
successful install that breaks at runtime.

No public API changes. No change to install destinations, manifests, schemas,
or runtime behaviour for already-built repos.

Test plan

  • node tests/lib/install-targets.test.js — 38/38 passing (35 baseline + 3 new).
    • Adds the previously-missing per-adapter resolution test for opencode-home
      (matches the convention every other home adapter follows).
    • Adds a missing-build assertion using a fresh os.tmpdir() repoRoot.
    • Adds a built-payload assertion that materializes a stub dist/index.js and
      expects validate to return [].
  • node tests/scripts/install-apply.test.js — 28/28 passing (no regression;
    the suite never invokes --target opencode, so the new gate is opt-in).
  • node tests/scripts/build-opencode.test.js — 3/3 passing.
  • node tests/opencode-config.test.js — 3/3 passing.
  • node tests/docs/ecc2-release-surface.test.js — 28/28 passing (asserts
    the README content stays in the release surface manifest).
  • node tests/run-all.js — full suite, 2571/2571 passing.
  • npx markdownlint-cli .opencode/README.md — exit 0.
  • npx eslint scripts/lib/install-targets/opencode-home.js tests/lib/install-targets.test.js — clean.

Out of scope

Open questions I noticed while researching but deliberately did not roll into
this PR — happy to follow up in separate changes if the maintainer agrees:

  1. opencode-project adapter mirroring claude-project: would let users
    install ECC into a project-local .opencode/ (parallel to the recently-
    added claude-project). Useful but expands the surface (manifest, schema,
    request-validation), so kept out of this fix.
  2. Switching the home install root from ~/.opencode to ~/.config/opencode
    (the XDG path that upstream sst/opencode constructs from xdg-basedir):
    the issue reporter's "ATTEMP FIX" patches this. Worth noting that
    Global.Path.home + .opencode is in OpenCode's search order
    (packages/opencode/src/config/paths.ts),
    so the existing path is not actually broken — just non-canonical. Changing
    it is a behaviour shift for every existing install-state file and feels
    like maintainer territory.
  3. Auto-running build-opencode.js from inside the installer: would
    require tsc to be reachable on every install run, which regresses the
    fast-path. The validate gate keeps the toolchain boundary clean and lets
    prepack/CI own the compile step.

Summary by cubic

Fail fast when installing the OpenCode plugin from a fresh clone if the compiled payload is missing or the wrong type. The opencode-home target now requires .opencode/dist/index.js (file), .opencode/dist/plugins/ (dir), and .opencode/dist/tools/ (dir), and tells users to build first.

  • Bug Fixes
    • Added validate() that returns error opencode-plugin-not-built with missing paths and expected types; hints node scripts/build-opencode.js or npm run build:opencode; preserves missing-home-dir; no change when already built.
    • Treats ENOTDIR (e.g., .opencode/dist is a file) as a missing artefact instead of throwing; other I/O errors still surface.
    • Updated .opencode/README.md; tests cover adapter resolution, missing/partial builds, wrong types, ENOTDIR, and the built path.

Written for commit 8475841. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Documentation
    • Enhanced OpenCode home install guide with exact build + install commands and clarified new failure behavior when the build step is missing.
  • Bug Fixes
    • Added filesystem validation and clearer user-facing errors for missing, incomplete, or mis-typed compiled plugin artifacts under the build output.
  • Tests
    • Added automated tests covering missing, partial, wrong-type, ENOTDIR, and successful build scenarios for the home install workflow.

Review Change Stack

Fixes affaan-m#2040.

The OpenCode home installer copies plugin sources from `.opencode/` into the
user's install root, but only `.opencode/dist/` (produced by
`scripts/build-opencode.js`) contains the compiled JavaScript that OpenCode
actually loads. From a plain `git clone`, that directory does not exist
until `npm run build:opencode` (or `npm pack`/`prepack`) has run, so users
who go straight to `node scripts/install-apply.js --target opencode --profile
full` end up with `/` slash commands that show in autocomplete but silently
do nothing — the plugin entry point loads, the runtime has no JS to execute.

This change adds a `validate(input)` override on `opencode-home` that fails
fast with an actionable message pointing at `node scripts/build-opencode.js`
(or `npm run build:opencode`) when `.opencode/dist/index.js` is missing in
the source repo. It does not change the install destination or any other
runtime behaviour, and it has no effect when the plugin has already been
built (the common case once `prepack` runs during `npm pack`).

Tests:
- `tests/lib/install-targets.test.js`: adds the previously-missing
  per-adapter resolution test for `opencode-home`, plus two `validate()`
  cases that cover the missing-build and built-payload code paths via temp
  `repoRoot` directories.
- `node tests/run-all.js` is green (2571 passed, 0 failed).

Docs:
- `.opencode/README.md`: documents the build-first requirement under the
  existing "Direct Use" option so future users running the installer from
  a clone hit the build step before the validate gate fires.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2bd7869e-512b-477d-8c57-1c6f8dceb426

📥 Commits

Reviewing files that changed from the base of the PR and between 8753a3b and 8475841.

📒 Files selected for processing (2)
  • scripts/lib/install-targets/opencode-home.js
  • tests/lib/install-targets.test.js

📝 Walkthrough

Walkthrough

Adds a validator that requires a home directory and compiled OpenCode plugin payload under .opencode/dist before home install, wires it into the adapter, documents the required build step, and adds tests for missing, partial, wrong-type, ENOTDIR, and passing build cases using temp directories.

Changes

OpenCode Home Installation Validation

Layer / File(s) Summary
OpenCode home validation implementation
scripts/lib/install-targets/opencode-home.js
defaultValidateOpencodeHome() validates that a home directory is available (or emits missing-home-dir if not) and that compiled payload artifacts exist under .opencode/dist (index.js file, plugins and tools directories); the validator is wired into the exported adapter via the validate option.
Installation documentation
.opencode/README.md
Documents the mandatory build step before running the OpenCode home install, provides exact build and install commands, and clarifies failure/skip behavior when .opencode/dist/index.js is absent.
Validation tests
tests/lib/install-targets.test.js
Adds fs and os imports and tests that verify resolve/install-state paths under homeDir, assert a single opencode-plugin-not-built error for missing compiled payload, detect partial-build and wrong-artifact-type cases plus ENOTDIR behavior, and assert no validation issues when dist/plugins, dist/tools, and dist/index.js exist; tests use OS temp dirs with cleanup.

Sequence Diagram(s)

sequenceDiagram
  participant Installer as Installer (scripts/install-apply)
  participant Validator as defaultValidateOpencodeHome
  participant FS as FileSystem
  Installer->>Validator: validate({ repoRoot, homeDir })
  Validator->>FS: resolve and check repoRoot/.opencode/dist (index.js, plugins, tools)
  FS-->>Validator: existence/type results
  Validator-->>Installer: return validation issues[] or []
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through dist, checked index and trees,
Built plugins and tools bring installers ease,
Temp dirs tidy, tests keep errors small,
Home paths resolved before the install call,
A tiny carrot nod to builds that stand tall.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding validation for the compiled OpenCode plugin before installation.
Linked Issues check ✅ Passed The PR successfully implements the primary objective from #2040: detecting missing compiled artifacts and aborting with clear guidance instead of installing non-functional OpenCode.
Out of Scope Changes check ✅ Passed All changes are directly related to the primary objective. Secondary suggestions (XDG config paths, auto-build) were appropriately marked out of scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 22, 2026

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

@gaurav0107 gaurav0107 marked this pull request as ready for review May 22, 2026 16:18
@gaurav0107 gaurav0107 requested a review from affaan-m as a code owner May 22, 2026 16:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@scripts/lib/install-targets/opencode-home.js`:
- Around line 28-40: The current validation only checks compiledPluginPath
(using COMPILED_PLUGIN_RELATIVE_PATH) for .opencode/dist/index.js; update the
check in the function that returns buildValidationIssue to also verify the
existence of the runtime directories .opencode/dist/plugins and
.opencode/dist/tools (resolve them relative to input.repoRoot like
compiledPluginPath), collect any missing paths into a list and, if non-empty,
return buildValidationIssue('error','opencode-plugin-not-built', ...) with a
message describing all missing artifacts and include the missing paths in the
metadata so callers can see which specific files/directories failed validation.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 61d4a2ac-ea97-469e-9d07-5649b5eb4370

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8c7e7 and 3ef3b0e.

📒 Files selected for processing (3)
  • .opencode/README.md
  • scripts/lib/install-targets/opencode-home.js
  • tests/lib/install-targets.test.js

Comment thread scripts/lib/install-targets/opencode-home.js Outdated
Copy link
Copy Markdown
Contributor

@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.

No issues found across 3 files

Re-trigger cubic

…encode

CodeRabbit flagged that the opencode-home validate gate only checked
`.opencode/dist/index.js`, but the OpenCode runtime contract also needs
`.opencode/dist/plugins/` (plugin hooks) and `.opencode/dist/tools/`
(custom tools) — both are produced by `scripts/build-opencode.js` and
both are listed in `tests/scripts/build-opencode.test.js` as required
npm-pack contents. A half-finished or interrupted compile that left only
`index.js` would have squeezed past the previous gate and reproduced the
original `/`-commands-do-nothing symptom from affaan-m#2040.

The validate function now collects every missing required artefact into
a single `error` issue with `missingRelativePaths` metadata so the
maintainer (and any caller code) can see exactly which artefact triggered
the failure. The error message lists all missing paths in one line and
still points at `node scripts/build-opencode.js`.

A new test case `opencode adapter validate reports a partial build
(entry present, runtime dirs absent)` covers the half-built scenario,
and the existing "passes once compiled plugin payload exists" test now
materializes both subdirectories so it asserts the full happy path.

Full suite still green: `node tests/run-all.js` → 2572 passed, 0 failed.
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 22, 2026

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@scripts/lib/install-targets/opencode-home.js`:
- Around line 10-15: The current validation only uses existsSync and can accept
wrong entry types; update the install validation to verify types: for
COMPILED_PLUGIN_DIST_DIR and entries in REQUIRED_COMPILED_RELATIVE_PATHS ensure
index.js is a regular file and plugins and tools are directories by using
fs.statSync or fs.lstatSync and checking .isFile()/.isDirectory(); replace the
generic existsSync checks (references: COMPILED_PLUGIN_DIST_DIR,
REQUIRED_COMPILED_RELATIVE_PATHS, and the validation logic around the second
check block at lines ~33-38) with these explicit type checks and surface a clear
error when a path exists but has the wrong type.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a28b12e-c68f-4148-b276-277f98b0ff8b

📥 Commits

Reviewing files that changed from the base of the PR and between 3ef3b0e and 439fed9.

📒 Files selected for processing (2)
  • scripts/lib/install-targets/opencode-home.js
  • tests/lib/install-targets.test.js

Comment thread scripts/lib/install-targets/opencode-home.js
Per CodeRabbit: existsSync alone treats any filesystem entry as valid,
which would let a stray file at `.opencode/dist/plugins` (or tools)
squeeze past the gate even though OpenCode requires those entries to be
directories. The validator now stat()s each required artefact and asserts
`isFile()` for `dist/index.js` and `isDirectory()` for `dist/plugins` and
`dist/tools`, returning the same `opencode-plugin-not-built` issue with an
extra `expectedTypes` metadata array so callers can tell missing-vs-wrong-
type failures apart.

A new test materializes regular files where directories are expected and
asserts the validator flags `dist/plugins` and `dist/tools` while leaving
the correctly-typed `dist/index.js` alone. Existing happy-path and
partial-build tests continue to pass.

Full suite: 2573/2573 (one new test).
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 22, 2026

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@scripts/lib/install-targets/opencode-home.js`:
- Around line 18-27: The isExpectedType function only treats ENOENT as a
non-error; change its error handling to also treat ENOTDIR as a validation miss
by returning false when error.code === 'ENOTDIR' instead of rethrowing, so
callers like validate and planInstallTargetScaffold receive a false result
rather than an exception; update the catch in isExpectedType to check for both
'ENOENT' and 'ENOTDIR' and return false for those cases, and rethrow other
errors.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 42761317-f2db-4bfa-ade6-d510b8aefd25

📥 Commits

Reviewing files that changed from the base of the PR and between 439fed9 and 8753a3b.

📒 Files selected for processing (2)
  • scripts/lib/install-targets/opencode-home.js
  • tests/lib/install-targets.test.js

Comment thread scripts/lib/install-targets/opencode-home.js
Copy link
Copy Markdown
Contributor

@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.

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/lib/install-targets/opencode-home.js
…lidate

isExpectedType() previously rethrew every non-ENOENT filesystem error. When
an intermediate path component is a regular file (e.g. .opencode/dist itself
is a file rather than a directory), fs.statSync raises ENOTDIR — that escaped
out of the validate gate and crashed planInstallTargetScaffold instead of
producing the structured opencode-plugin-not-built issue.

Now both ENOENT and ENOTDIR collapse to a 'missing artefact' return so the
gate keeps producing the actionable error message. Other I/O errors (EACCES,
EIO, ...) still surface — those are real system faults the user needs to
see.

Adds a regression test that materialises .opencode/dist as a regular file
and asserts validate() does not throw and surfaces the structured issue.
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 22, 2026

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

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][LATEST] ECC installation for OPENCODE | Global or Specific

1 participant