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.
- point all repository links to Gitlawb/openclaude
- make shim opt-in by default to preserve Anthropic-first flow
- add command availability check with first-run install guidance
- render runtime and shim state dynamically in control center
- make command palette shortcut hint platform-aware
The Gemini provider uses Google's OpenAI-compatible endpoint
(generativelanguage.googleapis.com/v1beta/openai) but the client
routing condition in client.ts only checked CLAUDE_CODE_USE_OPENAI
and CLAUDE_CODE_USE_GITHUB — CLAUDE_CODE_USE_GEMINI was missing.
This caused every Gemini request to fall through to the Anthropic
client path. Since ANTHROPIC_API_KEY is not set when using Gemini,
the Anthropic SDK threw:
"Could not resolve authentication method. Expected either apiKey
or authToken to be set."
Fix: add CLAUDE_CODE_USE_GEMINI to the OpenAI shim routing condition
so Gemini requests correctly reach createOpenAIShimClient(), which
maps GEMINI_API_KEY → OPENAI_API_KEY and sets OPENAI_BASE_URL to
the Google endpoint.
Closes#176
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New contributors had to hunt through README and source files to find
required environment variables. This adds a single reference file at
repo root covering all supported providers with placeholder values,
inline comments, and sensible defaults.
Providers covered:
- Anthropic (default)
- OpenAI
- Google Gemini
- GitHub Models
- Ollama (local)
- AWS Bedrock
- Google Vertex AI
Also includes optional tuning vars: CLAUDE_CODE_MAX_RETRIES,
CLAUDE_CODE_UNATTENDED_RETRY, OPENCLAUDE_ENABLE_EXTENDED_KEYS,
OPENCLAUDE_DISABLE_CO_AUTHORED_BY, API_TIMEOUT_MS, CLAUDE_DEBUG.
Updated .gitignore to add !.env.example exception so the template
is not suppressed by the existing .env.* rule.
Closes#175
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously getRateLimitResetDelayMs only read the Anthropic-specific
'anthropic-ratelimit-unified-reset' header (Unix timestamp), returning
null for every other provider. This meant OpenAI, GitHub, and Codex
users in persistent retry mode (CLAUDE_CODE_UNATTENDED_RETRY=1) always
fell back to dumb exponential backoff even when the server included an
exact reset time in the response headers.
This change makes the function provider-aware:
- firstParty (Anthropic): existing behaviour preserved — reads
'anthropic-ratelimit-unified-reset' Unix timestamp
- openai / codex / github: reads 'x-ratelimit-reset-requests' and
'x-ratelimit-reset-tokens' (OpenAI relative duration strings like
"1s", "6m0s", "1h30m0s"), picks the larger of the two so retries
don't fire before both token and request limits have reset
- bedrock / vertex / foundry / gemini: returns null (no standard
reset header for these providers)
Adds parseOpenAIDuration() as an exported helper to convert OpenAI's
duration format into milliseconds.
16 new tests covering all provider paths and edge cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduce OpenClaude as a first-class VS Code extension with:
- Built-in Control Center sidebar for seamless workflow integration
- Terminal-first design with authentic monospace UI and ASCII styling
- Quick-launch buttons for OpenClaude terminal, repository access, and command palette
- Status display showing runtime and OpenAI shim configuration
- Dark theme optimized for focus and extended development sessions
- Proper extension manifest with activation events and contribution points
- Debug configuration for local development
This extension provides developers with direct access to OpenClaude
without leaving VS Code, enabling a tighter integration with the editor.
Finding 1 [CRITICAL] — sessionRunner leaks full process.env to child
Extract buildChildEnv() with an explicit allowlist of safe OS/runtime vars.
Child process no longer inherits ANTHROPIC_API_KEY, OPENAI_API_KEY, DB
credentials, or any other secret present in the parent shell environment.
Only CLAUDE_CODE_* bridge vars, PATH, HOME, and standard OS env are passed.
Finding 2 [HIGH] — USER_TYPE=ant activatable by external users
Add isAntEmployee() -> false constant in src/utils/buildConfig.ts.
Replace all three direct process.env.USER_TYPE === 'ant' checks in
setup.ts and onChangeAppState.ts so no external user can activate
Anthropic-internal code paths (commit attribution, system prompt clearing,
dangerously-skip-permissions bypass) by setting USER_TYPE in their shell.
Finding 3 [HIGH] — memoryScan.ts unlimited directory walk
Add MAX_DEPTH=3 guard on readdir({ recursive: true }) results.
Deep or symlink-looped memory directories no longer cause an unbounded
blocking walk before the MAX_MEMORY_FILES cap takes effect.
Finding 5 [HIGH] — buildSdkUrl uses string.includes for protocol detection
Replace apiBaseUrl.includes('localhost') with new URL(apiBaseUrl).hostname
comparison so a remote URL containing 'localhost' in its path no longer
incorrectly gets ws:// (unencrypted) instead of wss://.
Finding 6 [HIGH] — upstream proxy writes unvalidated CA cert to disk
Add isValidPemContent() validation before writeFile in the CA cert download
path. A compromised proxy sending non-PEM data (HTML, JSON, scripts) is now
rejected before it can be appended to the system CA bundle.
Each fix is covered by new unit tests (25 tests across 5 new test files).
All 52 tests pass. Build verified clean on v0.1.7.
Fixes#42
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WebSearch is currently disabled for all non-Anthropic providers (OpenAI
shim, DeepSeek, Ollama, etc.) because those providers have no native
search backend. This adds Firecrawl as a fallback that activates when
FIRECRAWL_API_KEY is set, unlocking web search for every model
openclaude supports.
WebFetch uses basic HTTP + Turndown for HTML-to-markdown conversion,
which fails silently on JS-rendered SPAs and bot-protected pages.
Firecrawl scrape replaces the fetch layer when FIRECRAWL_API_KEY is set,
returning clean markdown that handles dynamic content correctly.
Changes:
- WebSearchTool: add runFirecrawlSearch() using @mendable/firecrawl-js,
respects allowed_domains (post-filter) and blocked_domains (-site: operators),
includes result snippets alongside links. shouldUseFirecrawl() ensures
firstParty/Vertex/Foundry/Codex providers keep their native backends.
- WebFetchTool: add scrapeWithFirecrawl(), drops into the existing
applyPromptToMarkdown() pipeline so prompt processing is unchanged.
- Remove "Web search is only available in the US" restriction from
prompt when Firecrawl is active (it works globally).
Adds docs/mcp-servers.md — the first documentation on how to configure
MCP servers in OpenClaude. Covers .mcp.json setup, the Firecrawl MCP
server for web scraping and search, available tools, and a pattern for
adding multiple servers.
1. errors.ts: Add getCustomOffSwitchMessage() that returns a
provider-neutral message for 3P users instead of the hardcoded
"Opus is experiencing high load, please use /model to switch to
Sonnet" which is misleading for OpenAI/Gemini/Ollama users.
The original constant is preserved for backward-compatible string
matching in error handlers.
2. Onboarding.tsx: Skip the "approve API key" step when a 3P provider
is active. Previously, having ANTHROPIC_API_KEY in the environment
(e.g., from a previous Anthropic setup) triggered an irrelevant
Anthropic key approval UI even when using Gemini or OpenAI.
1. cli/update.ts: Block the update command for third-party providers.
The update mechanism downloads from Anthropic's GCS bucket, which
would silently replace the OpenClaude build (with the OpenAI shim)
with the upstream Claude Code binary (without it). Now shows an
actionable message directing users to rebuild from source.
2. codexShim.ts: Filter thinking blocks from assistant history, matching
the openaiShim behavior. Without this, thinking blocks were included
as plain text in assistant messages for the Codex transport but
excluded for the OpenAI transport — causing inconsistent history
when switching providers mid-session.
Three targeted fixes:
1. Replace Math.random() with crypto.randomUUID() for message and tool
call IDs in both openaiShim.ts and codexShim.ts. Math.random() is
not cryptographically secure and predictable in seeded environments.
2. Anchor Azure endpoint detection to parsed hostname instead of raw
URL regex. Adds support for Azure AI Foundry (services.ai.azure.com)
alongside existing cognitiveservices and openai Azure endpoints.
Prevents SSRF-style bypass via path segments.
3. Surface content safety filter blocks to the user. When Gemini or
Azure returns finish_reason 'content_filter' or 'safety', emit a
visible text block '[Content blocked by provider safety filter]'
instead of silently returning empty/truncated content with
stop_reason 'end_turn'. Applied to both streaming and non-streaming.