This sixth pass continues issue #314 with a message-focused micro-batch: three tiny message components that each only surfaced a single unused React import warning. The batch stays intentionally minimal and behavior-neutral.
Constraint: Keep pass 6 limited to one-line message-component cleanup with the same warning shape
Rejected: Mix in broader message component cleanup or unrelated typing fixes | would dilute the micro-pass and expand review scope unnecessarily
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue splitting by path + warning shape when easy one-line cleanups are available
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
This fifth cleanup pass follows issue #314 with another homogeneous, low-risk slice: three LogoV2 notice/upsell components that each only surfaced a single unused React import warning. Removing just those imports keeps the series moving without mixing in broader cleanup categories.
Constraint: Keep pass 5 to files with the same single-warning pattern
Rejected: Fold in unrelated LogoV2 files with wider warnings or other cleanup shapes | would make the pass less uniform and less reviewable
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue preferring single-pattern micro-passes when the compiler output presents them clearly
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
This fourth pass continues issue #314 with the smallest cleanup slice so far: six files that each surfaced the same single warning for an unused React import. Keeping the batch this focused improves review speed and removes noise without changing behavior or widening the cleanup scope.
Constraint: Limit this pass to single-warning files only so the intent stays obvious
Rejected: Combine this with broader typing or props-alias cleanup | unnecessary scope expansion for an already reviewable one-line pattern
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep using ultra-small homogeneous passes whenever the compiler output exposes them; they are cheap to review and easy to revert
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
This third pass continues the issue #314 cleanup series with four very small display-oriented components. The changes only remove unused React imports and reconnect existing Props aliases or parameter types where the files were otherwise surfacing straightforward compiler noise.
Constraint: Keep the pass limited to trivial display components with uniform low-risk cleanup shape
Rejected: Mix in files with unrelated missing-module or broader logic noise | weakens review focus and muddies verification
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer these tiny homogeneous slices while the repo still has wider baseline no-unused noise
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
This follow-up pass continues the phased unused-code cleanup from issue #314 with four dialog components that shared the same low-risk pattern: avoidable unused imports, dormant Props aliases, and untyped callback plumbing that only existed as compiler noise. The changes keep behavior intact while reducing the next layer of cleanup friction.
Constraint: Keep the second pass narrowly scoped and homogeneous so it stays easy to review beside PR #316
Rejected: Fold in EffortCallout and wider component cleanup at the same time | larger surface area and less uniform risk profile
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue batching future passes by shared cleanup pattern; leave broader refactors and compatibility placeholders for separate PRs
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
This first cleanup pass removes clearly unused imports and dead locals from a small set of components, and reconnects a few existing Props aliases to their component signatures so they stop surfacing as avoidable noise. The scope stays intentionally narrow to make the follow-up cleanup series easier to review and lower risk.
Constraint: Follow issue #314 with a components-only, low-risk first pass
Rejected: Broader sweep across commands/hooks/utils in the same PR | too much review surface for an initial cleanup pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep subsequent unused-code cleanups narrowly batched; treat signature/compatibility placeholders separately from straightforward import/alias cleanup
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (baseline repo noise remains outside this narrow pass)
Co-authored-by: anandh8x <test@example.com>
This seventh pass continues issue #314 with a two-file PromptInput micro-batch. Both files shared the same single-warning pattern for an unused React import, so the cleanup stays extremely small, behavior-neutral, and easy to review.
Constraint: Keep pass 7 to the exact two-file PromptInput pair with the same warning shape
Rejected: Fold in broader PromptInput cleanup or unrelated warnings | would expand scope beyond a simple micro-pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue harvesting paired file/test micro-batches when the compiler output exposes them cleanly
Tested: bun run build; bun run smoke; targeted noUnused grep for touched files via bun x tsc --noEmit --noUnusedLocals --noUnusedParameters --pretty false
Not-tested: full repo typecheck (broader baseline noise remains outside this pass)
Co-authored-by: anandh8x <test@example.com>
* added duck duck go for websearch tools that allowed free searching
* update readme
* Replace @phukon/duckduckgo-search with duck-duck-scrape and fix Firecrawl routing priority, and add DDG error handling
* refactor: streamline DuckDuckGo search fallback to use Firecrawl directly on rate limit
* docs: update README to clarify DuckDuckGo web search fallback and its limitations with TOS
* fix: disable experimental API betas by default to prevent 500 errors
Tool search (defer_loading), global cache scope, and context management
betas require internal Anthropic server-side support. External accounts
receive 500 Internal Server Error when these are sent.
Set CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=true by default in the CLI
entrypoint. Users with internal access can opt back in with =false.
Also includes: cache key stability fixes (Sonnet 1M latch, system-before-
messages key ordering, resume fingerprint isMeta skip), sideQuery default
cleanup, and /dream command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: standardize API headers to Headers type and enable tengu feature flags by default
* fix: address PR review — dream lock, MCP betas guard, redundant Partial
- Call recordConsolidation() programmatically in /dream instead of
delegating to model prompt (unreliable)
- Add CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS guard to MCP entrypoint
(was only in CLI entrypoint, causing 500s in MCP server mode)
- Remove redundant ? markers from SecretValueSource Partial<{}> type
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three compounding issues caused keyboard input to appear frozen or drop
characters on startup, particularly on Windows CMD/PowerShell and Mac
terminal environments.
Issue 1 — earlyInput disabled (cli.tsx):
The rebrand commit gated startCapturingEarlyInput() behind an opt-in
env flag (OPENCLAUDE_ENABLE_EARLY_INPUT=1), which meant any characters
typed before React finished mounting were silently dropped. Users who
type immediately after launch saw an empty input box with no indication
their keystrokes were lost. Flipped to an opt-out flag
(OPENCLAUDE_DISABLE_EARLY_INPUT=1) so early input capture is on by
default, matching the original upstream behaviour.
Issue 2 — stdin.resume() called before listener attached (App.tsx):
stdin.resume() put the stream into flowing mode before the data/readable
listener was registered. Any input arriving in that gap was queued and
delivered in a burst when the listener connected, which could flood
React's scheduler and stall input processing. Moved resume() to after
the listener is attached so the stream only flows once the handler is
ready.
Issue 3 — AnimatedAsterisk fires ~60 React re-renders in 3s (AnimatedAsterisk.tsx):
The startup screen colour sweep animation runs at 50ms intervals for
3000ms total. Each tick triggers a full re-render of the startup screen
subtree, which competes with stdin event processing in React's microtask
queue. On Windows, where the event loop scheduler is slower, this
reliably caused typing to lag or freeze for the first few seconds after
launch. The animation is now skipped on Windows (process.platform ===
'win32'), showing the icon in its settled state immediately. Mac and
Linux are unaffected.
Closes#228, #220, #205
Prevents collision with existing Claude Code installations that already
use ~/.claude for their own config, settings, and project data.
Migration compatibility: if ~/.openclaude does not yet exist but ~/.claude
does, the legacy path is kept automatically so existing openclaude users
don't lose their data on upgrade. New installs go straight to ~/.openclaude.
Users who need an explicit path can set CLAUDE_CONFIG_DIR.
Fixes#184
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
getPromptCachingEnabled() returned true for all providers including
Azure Foundry, OpenAI, Gemini, and GitHub. This caused cache_control
blocks to be injected into every request sent to 3P endpoints.
Azure Foundry's strict Responsible AI content filter treats unexpected
Anthropic-specific fields (cache_control: { type: "ephemeral" }) as
a jailbreak signal and rejects the request with a 400 error — even
for a simple prompt like "hi".
Fix: return false early when provider is not firstParty, bedrock, or
vertex — the only providers that understand and support prompt caching.
Fixes#273
Related: #267 (Finding 1)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: resolve keyboard freeze via sync render path and stable useAppState selectors
Two compounding React 19 defects caused keyboard input to freeze after
MCP notifications or rapid state updates:
Defect 2 (ink.tsx): The render() path used async updateContainer, which
batches updates across scheduler ticks. Keyboard events dispatched mid-render
drained faster than React processed them, causing input to appear frozen.
Fixed by switching to updateContainerSync + flushSyncWork (same pattern
already used in the unmount path).
Defect 4 (AppState.tsx): useAppState and useAppStateMaybeOutsideOfProvider
used React Compiler _c cache invalidation tied to selector identity. Inline
arrow selectors (new reference each render) invalidated the cache every cycle,
producing a new `get` function. useSyncExternalStore treats a new `get` as a
tearing signal, re-syncing state and re-rendering — causing a loop that
starved the input handler. Fixed with useRef + useCallback(fn, []) to give
useSyncExternalStore a permanently stable snapshot reference.
Note: AppState.tsx is React Compiler output. The _c bypass for these two
hooks is intentional — compiler cache invalidation on inline selectors is
the root cause of the tearing loop.
All 200 tests pass. Build and smoke test verified.
Closes#77, #220, #228
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: update selector refs during render instead of useLayoutEffect
Addresses review feedback on PR #266. The previous useLayoutEffect approach
updated selectorRef.current after the render phase, meaning a changed selector
(e.g. s => s.tasks[attachment.taskId] when taskId changes) would still read
stale data during the render it changed in.
Fix: assign selectorRef.current and storeRef.current directly during render
before useSyncExternalStore calls get(). Ref mutation during render is safe
here — it's synchronous and happens before the snapshot is read. get()
identity stays stable via useCallback(fn, []) so useSyncExternalStore never
sees a new subscription function and won't trigger re-render loops.
This is the standard pattern used by zustand and jotai for selector stability.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add agentModels and agentRouting to SettingsSchema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add agentRouting module for per-agent provider resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: thread providerOverride through OpenAI shim for per-agent routing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: getAnthropicClient accepts providerOverride for agent routing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: thread providerOverride through Options and queryModel calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: thread providerOverride through query loop and ToolUseContext
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: resolve agent routing in runAgent and inject providerOverride
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add Agent Routing configuration guide to README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add unit tests for resolveAgentProvider + plaintext api_key note
- 15 tests covering priority chain (name > subagentType > default > null)
- normalize() case-insensitive and hyphen/underscore equivalence
- Edge cases: null settings, missing config sections, non-existent model
- README note about api_key stored in plaintext
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* security: address code review — SSRF, credential leak, key collision
- base_url schema now uses z.string().url() for SSRF mitigation
- Strip auth headers (Authorization, x-api-key, api-key) from
defaultHeaders when providerOverride is active, preventing
Anthropic credentials from leaking to third-party endpoints
- Warn on duplicate normalized routing keys to prevent silent shadowing
- providerOverride.apiKey is never logged (verified via grep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: 冯俊辉 <fengjunhui@shiyanjia.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The login picker previously sent third-party users to a dead-end info screen
that only mentioned env vars. This change reuses the existing provider wizard
from the login flow so first-run setup can continue without requiring slash
command access first.
Constraint: The existing provider setup logic must remain the single source of truth
Rejected: Build a separate third-party auth wizard in ConsoleOAuthFlow | would duplicate provider setup behavior and drift over time
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep third-party onboarding routed through ProviderWizard unless the provider command flow is intentionally redesigned
Tested: bun test src/components/ConsoleOAuthFlow.test.tsx src/commands/provider/provider.test.tsx
Tested: tsc --noEmit via project diagnostics
Not-tested: Live gh-authenticated push and PR creation path
Co-authored-by: anandh8x <test@example.com>
Add flickerFreeMode to GlobalConfig so external users can enable
fullscreen alt-screen mode via /config instead of having to set
the CLAUDE_CODE_NO_FLICKER=1 env var manually.
Priority order in isFullscreenEnvEnabled():
CLAUDE_CODE_NO_FLICKER=0 → always off (env wins)
CLAUDE_CODE_NO_FLICKER=1 → always on (env wins)
tmux -CC detected → off (terminal safety guard)
config flickerFreeMode → user preference (new)
USER_TYPE=ant → internal default
The env var still takes full precedence so existing scripts and
automation are unaffected. The new setting only activates when
flickerFreeMode is explicitly set in config.
Normalize shell command stdout and stderr before the prompt-shell path and shared tool-result mappers use string operations. This prevents /security-review from crashing when a shell tool returns null output fields and adds regression coverage for both direct mapper calls and prompt generation.
Fixes#165
Co-authored-by: Claude <noreply@anthropic.com>
* ## PR: Add LM Studio Provider Support
### Summary
Adds comprehensive LM Studio integration to openclaude, following the same pattern as the existing Ollama provider. LM Studio is a popular local LLM inference tool that exposes an OpenAI-compatible API.
### Changes (4 files, 672 insertions)
**New Files:**
- `lmstudio_provider.py` (377 lines) - Full provider implementation with:
- Health check functions (`check_lmstudio_running`)
- Model listing (`list_lmstudio_models`)
- Chat completion (`lmstudio_chat`)
- Streaming support (`lmstudio_chat_stream`)
- Comprehensive docstring with setup instructions, troubleshooting, and model recommendations
- `test_lmstudio_provider.py` (227 lines) - Complete test suite with 12 passing tests covering:
- API URL construction
- Server health checks
- Model listing
- Chat completion functionality
**Modified Files:**
- `docs/quick-start-mac-linux.md` (+34 lines) - Added Option D: LM Studio with setup instructions and troubleshooting
- `docs/quick-start-windows.md` (+34 lines) - Added Option D: LM Studio with PowerShell syntax and troubleshooting
### Key Features
- No API key required (local inference)
- Default port: 1234 (LM Studio's standard)
- OpenAI-compatible API integration
- Consistent with existing provider patterns (Ollama, Atomic Chat)
- All tests passing (12/12)
### Usage
```bash
export CLAUDE_CODE_USE_OPENAI=1
export OPENAI_BASE_URL=http://localhost:1234/v1
export OPENAI_MODEL=your-model-name
openclaude
```
* made pr as doc only pr for lm studio
* LM studio recent ui changes fixes in doc
* added Instructions to env example to allow openclaude to be used system wide
* added suggested .env.example changes
I added the suggested .env.example changes suggested earlier within the pr thread
* feat: add --provider CLI flag for multi-provider support
Adds a --provider flag that maps friendly provider names to the
environment variables the codebase uses for provider detection.
No more manual env-var configuration — users can now simply run:
openclaude --provider openai --model gpt-4o
openclaude --provider gemini --model gemini-2.0-flash
openclaude --provider ollama --model llama3.2
openclaude --provider bedrock
openclaude --provider vertex
Implementation details:
- providerFlag.ts: core logic — maps provider names to env vars,
uses ??= so explicit env vars always win over the flag defaults
- providerFlag.test.ts: 18 tests covering all 7 providers,
error messages, model passthrough, and env-var precedence
- cli.tsx: early fast-path (mirrors --bare pattern) — sets env
vars before Commander option-building and module constants run
- main.tsx: adds --provider to Commander option chain for --help
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: custom OPENAI_BASE_URL always wins over Codex model alias detection
When OPENAI_MODEL=gpt-5.4 (or gpt-5.4-mini) and a custom OPENAI_BASE_URL
is set (Azure, OpenRouter, etc), the transport was incorrectly forced to
codex_responses because gpt-5.4 is in CODEX_ALIAS_MODELS. This caused
requests to be sent with Codex auth instead of the user's API key,
resulting in 401 Unauthorized errors.
Fix: only use codex_responses when the base URL is explicitly the Codex
endpoint, OR when no custom base URL is set and the model is a Codex
alias. An explicit OPENAI_BASE_URL always takes priority over model-name
based Codex detection.
Verified locally: gpt-5.4 via OpenRouter now correctly shows
Provider=OpenRouter, Endpoint=https://openrouter.ai/api/v1 instead of
routing to chatgpt.com/backend-api/codex.
Fixes#200, #203
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
React 19 requires `supportsMicrotasks: true` in the reconciler host
config so it can flush state updates from passive effects via
queueMicrotask. Without this, state updates triggered inside
useMcpConnectivityStatus were silently dropped, corrupting React's
internal executionContext and causing all keyboard input to freeze
after the "N MCP server(s) need auth" notification appeared.
Root cause (three-part fix):
1. reconciler.ts: declare supportsMicrotasks + scheduleMicrotask so
React 19 schedules passive-effect flushes correctly.
2. useMcpConnectivityStatus.tsx: wrap the MCP auth notification effect
in try/catch so any unexpected throw does not propagate into
flushPassiveEffects and permanently corrupt executionContext.
3. notifications.tsx: wrap addNotification, removeNotification, and
processQueue in try/catch for the same reason — these are called
from 12+ notification hooks across passive effects.
Also fixes a pre-existing test isolation bug in context.test.ts where
assigning `undefined` to process.env produced the string "undefined",
polluting the env for subsequent test files.
Resolves: #169, #205, #77
Images in the clipboard could fail to become pasted image attachments in OpenClaude. User-facing symptom: paste would detect that an image existed, but nothing would appear in the prompt, and bundled builds could also fail while converting BMP clipboard images into a format OpenClaude can send to the model.
Linux clipboard image paste had drifted between detection and extraction. checkImage accepted png/jpeg/jpg/gif/webp/bmp, but saveImage only tried image/png and image/bmp. When the clipboard advertised a JPEG, GIF, or WebP image, OpenClaude concluded that an image was present and then failed to write the temp screenshot file, so the paste path returned null and nothing was inserted into the prompt.
Bundled OpenClaude builds had a second failure mode. The build replaces image-processor-napi and sharp with explicit stub modules in bundled mode. getImageProcessor() treated those stubs as real processors, so BMP clipboard images reached sharp(imageBuffer).png() and then failed before they could be converted into a pasteable PNG for OpenClaude.
Keep the Linux clipboard commands generated from one MIME type list and reject __stub-marked image processors up front instead of failing in the middle of image paste.