Repository navigation
fix(tui): reload local plugin dependency graphs - #47388
Merged
Merged
Conversation
jinhuang712
pushed a commit
to jinhuang712/opencode
that referenced
this pull request
Sep 26, 2026
Reload statically discovered local plugin dependencies through native module caches while preserving shared package identities and best-effort last-good registrations.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Editing a local CLI plugin's imported helper leaves its old UI running. Touching the entrypoint does not fix it: the entrypoint gets a fresh import identity, but its dependencies remain cached. Refactors that introduce a new helper export can consequently fail with a missing-export error even though the export exists on disk.
Reproduced on the PR base before implementation, first through
Host.loadand then in the real TUI with a nested helper.What Changes
Native reload, not a second module system
The earlier bundling approach was removed: local-plugin development does not need an independent module linker or immutable snapshots of every old callback's dependencies.
Demo
chat-before-after.mp4
Matched OpenCode Drive recordings with a demo workspace-check plugin at
session.composer.top, below the chat transcript and above the composer. Left: baseb274224af1. Right: final reviewed head91dc9af065. Both use the same 100×40 project, conversation, and source edits without a TUI restart; the panel was also exercised at 80 and 120 columns. The provider response and check statuses are fixture data, not real model calls or check-command executions. Startup and waiting are trimmed; each of three matched checkpoints shows 0.7 seconds of recording followed by a 2.5-second final-frame hold: helper edit, export rename, and repair. Assertions cover visible status, exact setup/cleanup counts, identical-save no-ops, and last-good fallback during invalid edits.Scope
Local CLI plugin source reloads only. This does not change server plugin reloads or package update behavior. Statically discoverable relative/file imports, including literal dynamic imports and free literal
require()calls, are tracked. Computed imports/requires and explicitly boundcreateRequire()calls retain native runtime behavior rather than becoming statically watched dependencies.This is best-effort development reload, not generation-isolated execution. A failed replacement keeps the previous registration, but its deferred imports/requires can observe the current cache and files. Restart only the TUI if a broken edit leaves a plugin inconsistent. Shared mutable local helpers are not a cross-plugin state contract; use an explicit shared package or host API for that state.
Verification
Using the repository's Bun 1.4.1:
require.resolve, lexical bindings, source metadata, wildcard/live re-exports, query/text import attributes, failed-evaluation recovery, cold/warm deferred imports, computed-only tracking exclusion, cycles, folded imports, nested package resolution, JSX helpers, export renames, identical/reverted contents, host and symlinked-package identity (including relative node_modules paths), atomic saves, and a real Node subprocess matrix covering plain/query/fragment imports and shared package identity.git diff --checkpass.