* fix(theme): remove stale React Compiler memo wrappers from theme hooks
Rebase on current main (includes #589 reconciler fix).
The React Compiler memo caches (_c) in useTheme() and usePreviewTheme()
use referential equality checks on destructured context values. These
caches can return stale references when the ThemeProvider's useMemo
recreates the context value object but the individual property
references (setThemeSetting, setPreviewTheme, etc.) compare equal —
the memo short-circuits and returns a cached tuple/object that still
holds the old closure captures.
This is a distinct bug from #589 (which fixed the ink reconciler's
commitUpdate path for host prop updates). #589 ensures that when
React _does_ re-render a component with new props, those props actually
reach the DOM node. But the memo wrappers here prevent React from
_even seeing_ the new context value in the first place — the hook
returns the stale cached result.
Removing the memo wrappers ensures useTheme() and usePreviewTheme()
always read the current context value, eliminating the stale-reference
path entirely.
* test(theme): add regression tests for useTheme()/usePreviewTheme() stale-value bug
These tests verify that context hooks always return fresh values after
ThemeProvider re-renders, even when React Compiler memo caches are in play.
- useTheme() must reflect currentTheme changes immediately after
setThemeSetting is called (not return a stale cached tuple).
- usePreviewTheme() must return functional actions after context
re-renders (not stale closures from before the theme change).
On current main (with _c memo wrappers), these tests expose the bug:
the memo cache compares setThemeSetting by reference (stable across
renders via useMemo) and short-circuits, returning the old cached result
with stale currentTheme.
* fix(test): correct import paths for ThemeProvider.test.tsx
Fix relative paths for ink.js, KeybindingSetup, AppStateProvider,
useStdin mock, systemTheme mock, and config mock to account for
the test file being in src/components/design-system/ rather than
src/components/.
* fix(test): rewrite ThemeProvider tests using Ink renderer
Use Ink's createRoot instead of react-dom/client, matching the pattern
from ThemePicker.test.tsx. The tests now render through Ink's terminal
renderer and check frame output for theme values, which is the same
environment ThemeProvider actually runs in.
* fix(test): correct all relative import paths for design-system/ depth
- ink.js, KeybindingSetup, AppStateProvider: ../ → ../../
- StructuredDiff: same pattern as ThemePicker test adjusted for depth
---------
Co-authored-by: root <root@vm7508.lumadock.com>
- Raise context window fallback from 8k to 128k for unknown OpenAI-compat models.
The 8k fallback caused effective context (8k minus output reservation) to go
negative, making auto-compact fire on every single message.
- Add safety floor in getEffectiveContextWindowSize(): effective context is
always at least reservedTokensForSummary + 13k buffer, ensuring the
auto-compact threshold stays positive.
- Add missing MiniMax model entries (M2.5, M2.5-highspeed, M2.1, M2.1-highspeed)
all at 204,800 context / 131,072 max output per MiniMax docs.
- Add tests for MiniMax variants, 128k fallback, and autoCompact floor.
Fixes#635
Co-authored-by: root <root@vm7508.lumadock.com>
The select cursor highlight was broken because isDeepStrictEqual in
use-select-navigation.ts and use-multi-select-state.ts would fail when
options contained identity-unstable properties (JSX label elements,
function onChange callbacks, computed disabled booleans). This caused
the reset logic to fire on every re-render, resetting focusedValue
back to the first option.
Replace isDeepStrictEqual with optionsNavigateEqual which only compares
properties that affect navigation behavior: value, disabled, and type.
ReactNode labels and function callbacks are intentionally excluded as
they are identity-unstable but don't change navigation semantics.
Fixes#472
Co-authored-by: OpenClaude Worker 3 <worker-3@openclaude.local>
* fix: defer startup plugin checks and suppress recommendation dialogs during startup window (issue #363)
Root cause: performStartupChecks() fires immediately on REPL mount,
triggering plugin loading which populates trackedFiles, which triggers
useLspPluginRecommendation to surface an LSP recommendation dialog.
Since promptTypingSuppressionActive is false before any user input,
getFocusedInputDialog() returns the dialog, unmounting PromptInput
entirely and making the CLI appear frozen.
Fix: Two-pronged approach:
1. Defer performStartupChecks by 1500ms and gate on
promptTypingSuppressionActive so startup checks dont run while
the user is typing or has early input buffered
2. Suppress lower-priority startup dialogs (LSP recommendation,
plugin hint, desktop upsell) until startupChecksStartedRef is
true, preventing them from stealing focus during the vulnerable
startup window
This also explains why --bare mode and disabling plugins work:
--bare mode skips plugin loading entirely, and disabling the
autoresearch plugin eliminates the LSP match, so lspRecommendation
stays null and PromptInput renders normally.
* fix: move startup checks effect after promptTypingSuppressionActive declaration
Fixes temporal dead zone warning flagged by code-quality bot.
promptTypingSuppressionActive is declared on line ~1340 but the
useEffect was on line ~800, causing a reference-before-declaration.
Also adds missing semicolons for style consistency.
* fix: gate startup checks on prompt readiness, not just a timeout (issue #363)
The previous approach used a fixed 1500ms timeout, but as gnanam1990
pointed out, if a user pauses for >1.5s before typing the timer can
still fire and recommendation dialogs can steal focus. This is a
timing mitigation, not a reliable fix.
New approach: gate startup checks on actual prompt readiness:
1. After first message submission (submitCount > 0) — always safe
2. After grace period (3s) elapsed AND user is idle — safe because
no dialog will interrupt an idle user who hasn't started typing
3. While user is actively typing — deferrred until they stop
This ensures startup checks never steal focus from a prompt the user
is about to type into, regardless of how long they pause before typing.
Also removes the old STARTUP_CHECK_DELAY_MS constant in favor of
STARTUP_GRACE_PERIOD_MS with clearer semantics.
* fix: move startup checks after submitCount declaration to avoid temporal dead zone
Code quality bot flagged that submitCount was used before its declaration.
Moved the entire startup checks block to after the submitCount useState
declaration. Also added nullish coalescing (submitCount ?? 0) per bot
suggestion.
* fix: gate startup checks strictly on first submission, remove grace period (issue #363)
As gnanam1990 pointed out, the 3s grace period still allows the failure
mode: if a user pauses for a few seconds before typing, startup checks
fire and recommendation dialogs steal focus. A grace period is still a
timing mitigation, not a reliable fix.
New approach: startup checks only run after the user has submitted their
first message (submitCount > 0). No grace period, no timeout. This
guarantees the prompt gets first interaction — no dialog can steal focus
before the user has actually used the CLI.
If the user never submits a message, startup checks never run. That's
acceptable because with no user interaction there's no need for plugin
installations or marketplace seeding.
---------
Co-authored-by: OpenClaude Worker 3 <worker-3@openclaude.local>
* fix: address code scanning alerts
Parse Gemini hostnames instead of matching raw URL substrings, redact gRPC error logs, and harden the Finder drag-drop test escape helper so the flagged paths are fixed without regressing working behavior.
* Potential fix for pull request finding 'CodeQL / Clear-text logging of sensitive information'
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* fix: restore safe grpc error summaries
A later autofix commit removed the exported gRPC error summarizer while the new regression test still imported it. Restore the safe name/code-only summary so CI stays green without reintroducing clear-text logging.
* fix: keep grpc logging generic
Remove the stale helper/test pair and keep the gRPC startup and stream logs free of error-derived data so the CodeQL clear-text logging alert stays closed while the rest of the security fixes remain intact.
---------
Co-authored-by: OpenClaude Worker 3 <worker-3@openclaude.local>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>