fix(tui): truncate fractional mtimes in fresh plugin specifiers - #41891
Merged
Conversation
kitlangton
force-pushed
the
fresh-specifier-mtime
branch
from
August 12, 2026 01:04
990068c to
ae17370
Compare
kitlangton
force-pushed
the
fresh-specifier-mtime
branch
from
August 12, 2026 01:05
ae17370 to
74f6e95
Compare
kitlangton
enabled auto-merge (squash)
August 12, 2026 01:09
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.
What
External TUI plugins that use JSX or import
solid-js/@opentui/solidfail to load in the compiledopencode2binary unless a compatiblenode_moduleshappens to sit above the plugin file. The cause is one character:freshSpecifierappends rawstat.mtimeMsto the import specifier, and on APFS that value is almost always fractional —plugin.tsx?mtime=1786494961337.0317. The extra dot in the query makes Bun's compiled binaries skip runtime plugin hooks (the solid transform and theopentui:runtime-module:*resolvers) for that import.Before / After
Before: the TUI discovers
~/.config/opencode/plugins/tui/pr-indicator.tsxand imports it aspr-indicator.tsx?mtime=1786494961337.0317. OpenTUI's runtime plugin support never sees the import, so the JSX pragma falls through to Bun's native transpiler, which emitsimport "@opentui/solid/jsx-dev-runtime". That specifier resolves via ordinarynode_moduleswalking from the plugin's own directory:node_modules): hard failure — toastPlugin: Cannot find module '@opentui/solid/jsx-dev-runtime', plugin never loads@opentui/solidinstalled: loads a second solid instance, so the plugin renders once but host-store reactivity silently breaksAfter: the specifier is
pr-indicator.tsx?mtime=1786494961337. Runtime plugin hooks fire, JSX and solid imports rewrite to the host's embedded runtime modules, and the same plugin loads and stays reactive from any discovery directory.Verified against a minimal compiled repro (
ensureRuntimePluginSupport()+ dynamic import) built with the production build options: the fractional query fails deterministically, the truncated query loads, on both plain andminify + splitting + solid-pluginbuilds.How
packages/tui/src/plugin/discovery.ts:freshSpecifiertruncates the mtime to whole milliseconds before appending it, in both the Bun and Node branches, with a comment pinning why. Cache-bust granularity coarsens from sub-millisecond to 1ms, matching the core plugin supervisor (Date#getTime()); the watcher's 100ms reconcile debounce makes a same-millisecond staleness miss unreachable in practice.packages/tui/test/plugin-discovery.test.ts: regression test asserting a fractionalmtimeMsproduces a dot-free query.Scope
Bun.pluginonResolve/onLoad are silently bypassed whenever the import specifier's text after its last dot starts with a non-letter (?mtime=123.456), in plainbunand compiled binaries alike — it only surfaces as a hard failure in compiled binaries because the natively transpiled output can't resolve host packages. Reported upstream as Runtime Bun.plugin onResolve/onLoad silently bypassed when import query string contains a dot followed by a non-letter (e.g. ?mtime=123.456) oven-sh/bun#37699; this fix removes the only place we generate such specifiers.Testing
bun test test/plugin-discovery.test.ts— new regression test passes.bun testinpackages/tui— 661 pass / 0 fail.bun typecheckinpackages/tui— clean after rebasing ontov2with fix(core): restore bundler resolution for source-imported deps #41885 (an earlierv2HEAD breakage made the first CI run fail; unrelated to this change).~/.config/opencode/plugins/tui/pr-indicator.tsx) with the truncated specifier and fails with the fractional one.?mtime=builder, core's plugin supervisor, already interpolates integers).sequenceDiagram participant R as TUI reconcile participant B as Bun module loader participant P as runtime plugin hooks R->>B: import plugin.tsx?mtime=...337.0317 Note over B,P: before: hooks skipped (dot in query) B-->>R: Cannot find module '@opentui/solid/jsx-dev-runtime' R->>B: import plugin.tsx?mtime=...337 B->>P: onLoad / onResolve fire P-->>B: rewrite to opentui:runtime-module:* B-->>R: plugin loaded against host solid