Give acquireSharedMutationLock a default five-minute timeout so missed releases fail with a scoped error instead of hanging the smoke suite indefinitely.
Keep explicit timeout overrides intact and add isolated mutex coverage for default timeout, override timeout, and release handoff behavior.
The spinner row used flexWrap="wrap" which caused the status text
(thinking indicator, timer, token count) to wrap to a new line when
content width hit a boundary condition. This produced a visible
layout jump — especially during thinking transitions when the status
text changes width.
Additionally, TaskItem rendered icons without overflow constraints,
so when text content overflowed the available width, orphaned icon
characters (checkmarks, squares) leaked into visible rows.
Changes:
- Use flexWrap="nowrap" on spinner row containers to keep status on
one line, relying on the existing progressive width gating to hide
elements that don't fit
- Replace magic number in availableSpace calculation with a named
constant for clarity
- Add overflowX="hidden" on TaskItem to clip overflowing content
* fix(websearch): surface adapter failure when auto mode falls back to native (#994)
When `WEB_SEARCH_PROVIDER=auto` and the configured adapter chain fails
on a recoverable error (DuckDuckGo "rate-limited from this network",
adapter timeout, 5xx, etc.), the tool falls through to the native
Anthropic / Codex web-search path silently. The only signal that the
adapter failed is a `console.error` line — it never reaches the tool
result the user sees. On rate-limit-prone networks (datacenter IPs,
VPNs) this manifests as "no results found" with no actionable hint,
exactly the symptom reported in #994.
This change captures the adapter error in `adapterFallthroughNotice`
inside the catch branch and prepends it to the eventual native / Codex
output via a small pure helper, `withAdapterFallthroughNotice`. The
hits-present and native-error paths are unchanged; the helper only
mutates a shallow copy when a notice is set, and is a no-op otherwise.
Result: users on a rate-limited adapter chain who get native results
also see *why* the adapter failed, and users whose native search also
returns nothing finally get the actionable diagnostic (configure
TAVILY_API_KEY / FIRECRAWL_API_KEY / etc.) instead of a silent empty.
Test coverage in WebSearchTool.test.ts asserts the pure-helper
contract: no-op when notice is undefined, prepend-not-mutate when a
notice is provided.
* fix(websearch): narrow #994 fix to the reachable adapter-failure surface
Address @techbrewboss feedback: the previous patch's
`adapterFallthroughNotice` machinery and the
`withAdapterFallthroughNotice` helper were unreachable under the
current provider selection.
`shouldUseAdapterProvider()` and `hasNativeSearchFallback()` are
mutually exclusive in auto mode — when a native path exists
(firstParty/vertex/foundry/Codex) the adapter is never tried, and when
the adapter IS tried (openai-shim providers) there is no native
fallback. So the assignment at `adapterFallthroughNotice = ...` and
both `withAdapterFallthroughNotice(...)` call sites could never fire.
Narrow the PR to the path that #994 actually hits today: an
openai-shim provider (moonshot/minimax/nvidia-nim/github copilot) where
the adapter fails transiently and there is no native fallback. The
existing throw at that branch already surfaces the underlying adapter
error verbatim; extract `buildAdapterUnavailableError(provider, errMsg)`
so it is directly testable and cannot regress, and replace the dead
notice helper + its tests with focused coverage of the reachable
message.
Drop the no-op shallow-copy `withAdapterFallthroughNotice` helper and
its two tests; keep the descriptive error throw as the single,
reachable surfacing path.
Closes#402 — JavaScript heap OOM during large tasks.
The CLI entry point only set --max-old-space-size=8192 when
CLAUDE_CODE_REMOTE=true, leaving local users with V8's ~2 GB default
ceiling. Long agentic tasks (multi-file refactors, large prompts, tool
loops) hit that ceiling and abort with:
FATAL ERROR: Ineffective mark-compacts near heap limit
Allocation failed - JavaScript heap out of memory
Fix: remove the CCR gate and apply the 8 GB cap unconditionally, with a
user-override guard -- if the runner already set NODE_OPTIONS
--max-old-space-size to an explicit value, their setting is preserved
(no silent clobbering).
Files changed:
- src/entrypoints/cli.tsx — remove CLAUDE_CODE_REMOTE guard, add
user-override predicate, update comments
- src/entrypoints/cli.test.ts — 6 regression tests (new file)
* feat(opengateway): add Gemini 3.1 Flash Lite + GLM 5.1 FP8 to catalog
Opengateway now routes non-Xiaomi models through GMI Cloud (configured
in opengateway/src/providers.ts via modelIds:
- google/gemini-3.1-flash-lite-preview
- zai-org/GLM-5.1-FP8
Adding both as catalog entries on the gitlawb-opengateway gateway
descriptor so openclaude users see them in the model picker when the
Opengateway preset is active. Each catalog entry reuses the existing
upstream model descriptor (`gemini-3.1-flash-lite-preview`, `GLM-5.1`)
for capability metadata; the apiName uses the full vendor-prefixed
form the gateway routes on.
No new model/brand/vendor descriptors needed — only the gateway
catalog gets the new IDs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* update opengateway
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix flaky smoke build checks
Replace feature-flag build preprocessing with a Bun onLoad transform so smoke/build no longer rewrites tracked src files while tests may be reading them.
Keep telemetry stubs ahead of the feature transform in both CLI and SDK builds, preserve non-empty text token counts in hybrid context splitting, and make the corrupted Orama stress test assert against the actual project directory used by the test.
Verified with bun run smoke, bun test src/utils/hybridContextStrategy.test.ts, bun test src/utils/knowledgeGraph.stress.test.ts --rerun-each 3, and bun test --max-concurrency=1.
* Harden KnowledgeGraph smoke stress isolation
Give each KnowledgeGraph stress test its own temporary config directory and remove it during teardown so Orama, SQLite, and corrupted-file state cannot bleed between stress cases or later PR test runs.
Reviewed at least 20 open PRs and found the recurring smoke-and-tests failure cluster is the full unit suite, especially KnowledgeGraph corrupted Orama recovery. Verified with bun test src/utils/knowledgeGraph.stress.test.ts --rerun-each 5, bun test --max-concurrency=1, and bun run smoke.
* Harden smoke test isolation
Audit and harden broad smoke-adjacent test suites for process-global leaks, including env/config restoration, shared registry/module mock cleanup, fetch/axios/mock restoration, and global MACRO/platform/sandbox mutations.
Replace fragile render sleeps in interactive tests with output-driven waits, and isolate provider/model/profile tests behind the shared mutation lock so unrelated PRs do not inherit stale process state.
Make SQLite knowledge graph cleanup clear closed on-disk databases before best-effort file cleanup, with coverage for the stale database reset path.
Verified: bun run smoke; bun test --max-concurrency=1; python -m pytest -q python/tests; bun run security:pr-scan -- --base origin/main; bun run test:provider; npm run test:provider-recommendation.
* Harden test isolation across smoke suite
Guard process-global test mutations with the shared mutation lock across env, module mock, config cache, and storage tests.\n\nDeep-copy global config snapshots, restore transient globals precisely, and make plugin/LSP mocks expose compatible export surfaces so concurrent test loading does not poison unrelated suites.\n\nReplace fixed SDK cleanup sleeps with call polling to remove timing sensitivity.\n\nVerification:\n- bun test --max-concurrency=1\n- bun run smoke\n- python -m pytest -q python/tests\n- bun run test:provider\n- npm run test:provider-recommendation\n- bun run security:pr-scan -- --base origin/main\n- git diff --check
* Close remaining test global-state leaks
Guard remaining cache, plugin, console, and VS Code module-mock tests with the shared mutation lock.\n\nThis follow-up audit covers non-env process-global state that can leak across test files: tool schema cache, cache stats tracker state, plugin loader caches, console.error replacement, and VS Code mock.module usage.\n\nVerification:\n- leak-surface scans for env/global/mock.module/cache outliers\n- duplicate top-level mock collision cluster\n- affected tests cluster\n- bun test --max-concurrency=1\n- bun run smoke\n- git diff --check
* Guard remaining mock restore cleanup
Lock tests that call bun:test mock.restore without installing module mocks themselves.\n\nmock.restore is process-global, so these cleanup hooks can still tear down another test file's active module mocks when files run concurrently.\n\nVerification:\n- expanded leak scans for env, globals, module mocks, mock.restore, timers, argv, and caches\n- bun test src/components/useCodexOAuthFlow.test.tsx src/services/github/deviceFlow.test.ts\n- bun test --max-concurrency=1\n- bun run smoke\n- git diff --check
* Harden test isolation for smoke stability
Serialize tests that mutate process-global state behind the shared mutation lock, including process.env, transient globals, global config/cache state, storage mocks, and Bun module mocks.
Add isolated env mutex instances for SDK mutex tests so timeout coverage no longer manipulates the live process-global mutex.
Move top-level mock.module setup behind lock acquisition and restore mocks before releasing locks to prevent cross-file leakage under parallel smoke runs.
Verified with: bun test --max-concurrency=1; bun test; bun run smoke.
* chore: centralize Bun version and refresh CI tool pins
- add .bun-version as the shared Bun source of truth for workflows and Docker builds
- update PR and release workflows to read Bun from bun-version-file
- refresh pinned GitHub Actions and Docker action SHAs to newer low-risk releases
- align contributor docs with Bun 1.3.13 guidance
* test: stabilize reset and provider profile persistence
Harden knowledge graph reset behavior across Windows file-lock scenarios by improving SQLite and JSON reset signaling, preserving a safe JSON source of truth when SQLite cannot be cleared, and adding direct storage regression coverage.
Also centralize deterministic config-home handling for tests, tighten provider profile persistence path resolution and cleanup semantics, isolate environment-sensitive suites with the env mutex, and remove flaky external npx dependency from the SDK consumer type test.
* test: fix Codex OAuth callback flake
Investigate the real provider smoke failure from GitHub Actions and fix the root cause instead of patching the symptom.
- make Codex OAuth callback host explicit and consistent across redirect URI generation and listener binding
- allow safe loopback host overrides for localhost, 127.0.0.1, and ::1
- harden Codex OAuth tests with env/fetch isolation so they do not poison neighboring provider suites
- pin the OAuth callback tests to 127.0.0.1 to avoid localhost IPv4/IPv6 family mismatch flakes in CI
Validated with bun test src/services/api/codexOAuth.test.ts, bun test src/services/api/providerConfig.codexSecureStorage.test.ts, and bun run test:provider.
* test: harden Codex OAuth callback tests
Investigate the recurring provider-smoke OAuth failures across multiple PR runs and fix the flaky callback test design at the root.
- remove the free-port reservation race from Codex OAuth tests
- add bounded callback retry only for loopback listener warm-up during the in-process OAuth test flow
- move ephemeral callback port support into an explicit CodexOAuthService test seam instead of widening production env parsing
- keep runtime callback-port semantics unchanged while adding regression coverage for callback host and port parsing
Validated with targeted Codex OAuth tests and repeated provider-bucket reruns to check for recurring flake.
* test: serialize provider shared-state suites
Fix the recurring provider smoke flake at the root cause by serializing test suites that mutate process.env or globalThis.fetch.
Add a shared test mutation lock and wire it into the provider bucket so Codex OAuth no longer races with unrelated provider/config/openai shim tests under Bun's parallel test execution. Cleanup now releases the lock in finally blocks, and the shared lock waits indefinitely by default to avoid timeout-based CI flakes.
* test: fix smoke root causes and noisy suites
Replace the Codex OAuth test's live loopback listener dependency with an injected listener seam, avoid module-mock leakage across provider suites, and clean up the auth-code listener test setup.
Also harden noisy storage and search tests by asserting expected log output, isolating SQLite masterpiece persistence per test cwd, and removing routine benchmark/stress logging from passing runs.
* build: harden Bun version install in Docker
Validate the repo-tracked .bun-version value before using it in the Docker build stage, strip line endings, and install Bun through a quoted semver-only variable instead of raw shell expansion.
* test: replace flaky conversation arc benchmark
Fix the recurring smoke failure caused by an absolute wall-clock assertion in the normal unit suite. Replace the CI-speed-sensitive conversation arc benchmark with deterministic regression coverage that verifies repeated fact extraction, expected entity shapes, bounded graph growth, and populated-summary behavior.
* test: isolate shared-state smoke suites
* test: restore codex credential mocks between suites
* test: fix shared-state and provider init-order flakes
* test: isolate remaining shared-state smoke suites
Serialize the remaining smoke-sensitive suites that mutate process env, CLAUDE_CONFIG_DIR, fetch, or SDK session globals.
Add shared lock coverage to discovery, agent/skills loading, platform storage, and SDK lifecycle/preserved-segment tests. Restore session and cwd state inside the lock boundary so parallel files cannot leak bootstrap state into knowledge graph and SDK isolation tests.
Validated with repeated smoke and full-suite passes:
- bun run smoke (2x)
- bun test
- bun test --max-concurrency=1
- bun run test:provider
- python -m pytest -q python/tests
- npm run test:provider-recommendation
Two related fixes to the OpenAI-compatible streaming parser:
1. Detect `data: {"error": {...}}` events inside the stream and throw a
proper APIError. OpenAI sends this when a stream fails after headers
have been sent, and intermediaries (gateways, proxies) use it to
signal structured failures without dropping the TCP connection.
Previously this chunk was silently dropped and the parser kept
waiting for [DONE], producing the confusing "unexpected response"
error after the stream ended without a proper close.
2. When finish_reason is "length" (model hit max_tokens, OR an upstream
watchdog synthesized a graceful end after detecting a stalled
stream), append a visible "[Response truncated]" hint inline. Mirrors
the existing content_filter hint pattern. Users now know to ask the
model to continue rather than wondering why the answer cut off.
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(provider): add Gitlawb Opengateway as default provider with MiMo
Registers https://opengateway.gitlawb.com/v1/xiaomi-mimo as a first-class
gateway descriptor in openclaude. Pins it first in the provider picker
order (ahead of anthropic) and surfaces it with a green [FREE] badge in
the picker UI. Wires detectBestProvider() to fall back to opengateway
with mimo-v2.5-pro when no other credentials or local services are
detected, making fresh installs work zero-config during the Xiaomi
free-inference partnership window.
- src/integrations/gateways/gitlawb-opengateway.ts: gateway descriptor,
static catalog of all five mimo models, requiresAuth: false
- src/integrations/artifactGenerator.ts: sort comparator pins
gitlawb-opengateway before anthropic
- src/utils/providerAutoDetect.ts: opengateway is the last-resort
fallback; OPENGATEWAY_BASE_URL env override for local dev;
skipOpengatewayFallback escape hatch for tests
- src/components/ProviderManager.tsx: getPresetLabel renders a green
[FREE] badge for the opengateway preset, matching the existing
[Sponsor] badge pattern used for xiaomi-mimo
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(provider): keep Codex OAuth after DeepSeek with Opengateway pinned
Pinning Gitlawb Opengateway at the top of the preset list shifted every
subsequent index by 1, which dropped Codex OAuth from "after DeepSeek"
to "before DeepSeek" because the splice insertion index was a hardcoded
6. Bumps the insertion index to 7 to keep Codex OAuth in its established
position, and updates PRESET_ORDER in ProviderManager.test.tsx so the
keyboard-navigation harness lines up with the new layout.
Restores 9 ProviderManager tests that were timing out because
navigateToPreset() was landing on the wrong row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Added 'Don't take over' rule to AgentTool prompt to prevent models from overriding forks based on partial output.
- Refined 'Don't peek' rule to explicitly direct models to use SendMessage for course-correction instead of Read.
- Clarified that override decisions belong to the Review phase.
The `ollama launch openclaude` syntax in README and advanced-setup.md
was docs-only (added in #716), gated on the companion
ollama/ollama#15618 integration that has not landed upstream. Users
following these instructions get `Error: unknown integration:
openclaude` (issue #744 originally, #1134 now).
Remove the misleading section + table mention so the env-var setup
above remains the documented path. Can be re-added once the upstream
ollama integration ships.
Closes#1134
Prevent the legacy .openclaude-profile.json fallback from overriding startup env when a modern configured provider profile has already selected a concrete provider configuration.
Thread the configured-profile signal from CLI bootstrap into buildStartupEnvFromProfile(), add a concrete-selection helper for the new guard, and preserve the legacy file as a first-run fallback when startup env is incomplete.
Also fix the follow-up falsey-flag regression so disabled CLAUDE_CODE_USE_* values do not count as active startup selections, and add regression tests covering stale legacy overrides, incomplete startup env, and falsey provider flags.
Verified with: bun test src/utils/providerProfile.test.ts --test-name-pattern " buildStartupEnvFromProfile\
* feat(provider): add Xiaomi MiMo integration
Add Xiaomi MiMo as an official OpenAI-compatible provider with provider-profile persistence, env-only detection, and sponsor labeling in the provider picker.
Co-Authored-By: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
* feat(provider): rebase Xiaomi MiMo as top-level provider
Promote Xiaomi MiMo from generic OpenAI-compatible shim route to a
first-class top-level provider matching the MiniMax pattern. Includes
brand/model descriptors, env-only detection, provider auto-detect,
status labels, legacy provider type, model picker, and profile env
persistence.
Co-Authored-By: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
* Fix Xiaomi MiMo provider integration
Promote Xiaomi MiMo as a first-tier OpenAI-compatible vendor and align its descriptor with the integration guide.
Use the resolving Xiaomi MiMo API host while normalizing the stale docs host alias, wire Xiaomi catalog options into /model, and ensure model selection/display uses OPENAI_MODEL for Xiaomi instead of Claude defaults.
Update provider profile/startup handling, OpenAI shim detection, docs, generated integration artifacts, and focused regression tests.
Verification: bun run integrations:check; focused bun test provider/model suites; bun run build; bun run smoke.
* Fix MiMo startup profile base URL normalization
---------
Co-authored-by: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
Co-authored-by: JATMN <the@jat.mn>
The gpt-5.5 model descriptor was set to the OpenAI API ceiling of
1,050,000 tokens, but in this repo gpt-5.5 is primarily routed through
the Codex transport (src/services/api/providerConfig.ts), whose practical
request limit is ~272k. The mismatch caused /context to under-report
usage and auto-compact to fire after the request had already exceeded the
effective window, surfacing as a mid-turn 500 'input exceeds the context
window of this model'.
Pin the descriptor to the Codex limit so /context shows realistic
budgets and auto-compact triggers before the failure. Provider-aware
context windows via the existing route catalog system remain the
correct long-term fix; this is the conservative interim.
Fixes#1118
* feat(groq): implement dynamic model discovery for OpenAI compatibility
* fix(groq): use hybrid catalog, fix model filter regex to exclude guard/whisper/safeguard/orpheus models, map contextWindow, and add mapModel test coverage
Known provider presets already carry endpoint and advanced transport defaults, so their create flow now asks only for the user-controlled model and any required API key while keeping Custom on the full setup path. Preset defaults also ignore stale generic OpenAI endpoint/model env values so xAI and other vendors keep their descriptor-backed defaults.
Constraint: Preset providers still need model choice because users may want a provider-specific default model.
Rejected: Save known presets without asking for model | this removed a real user choice and caused provider/model confusion.
Confidence: high
Scope-risk: moderate
Directive: Keep full endpoint/API mode/header setup reserved for Custom unless a preset explicitly needs user-entered advanced transport details.
Tested: bun test src/components/ProviderManager.test.tsx src/utils/providerProfiles.test.ts src/integrations/routeMetadata.test.ts src/integrations/index.test.ts
Tested: git diff --check
GitHub Models onboarding (and Codex) hand out OAuth tokens that expire.
When they do, the API returns 401 with a body like 'IDE token expired:
unauthorized: token expired'. The classifier was returning the generic
'Verify API key, token source, and endpoint-specific auth headers' hint,
which sends users hunting for an API key they never set — the actual fix
is to re-run /onboard-github (or /login for Codex/Claude).
Detect the token-expired signal in the 401/403 body and surface a
re-auth-pointing hint. Other 401 cases (bad API key) keep the existing
generic hint. Regression tests cover both branches.
Fixes#1042
* chore(build): clean up external dependency validation warnings
Remove 2 unused externals (@opentelemetry/sdk-trace-node, ink) and add
12 missing packages to package.json that are dynamically imported at
runtime but weren't declared as dependencies. Also remove the unused
@opentelemetry/sdk-trace-node dependency.
This eliminates all 13 build validation warnings:
- 8 missing OTel exporter deps (http, proto, grpc variants + prometheus)
- 4 missing AWS SDK deps (bedrock, bedrock-runtime, sts, credential-providers)
- 1 missing Azure dep (@azure/identity)
- ink external pointed to local reimplementation, not npm package
- sdk-trace-node was declared external but never imported
Build validation now passes cleanly with 0 warnings.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
* chore(build): eliminate external validation warnings
Remove unused @opentelemetry/sdk-trace-node from externals and package.json
(it's not imported anywhere in src/). Remove ink from SDK_ONLY_EXTERNALS
(the project reimplements ink locally at src/ink/). Add OPTIONAL_RUNTIME_EXTERNALS
list for packages that are dynamically imported but intentionally not direct
deps — OTel protocol exporters and cloud provider SDKs are resolved from
transitive deps or installed by users who need them.
Validation now passes with 0 warnings instead of 13.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
* feat(telemetry): full OpenTelemetry purge — remove all tracking dependencies
Replace all @opentelemetry/* runtime dependencies with no-op stubs,
delete OTel-only source modules, and remove 10 @opentelemetry packages
from package.json plus @growthbook/growthbook.
Key changes:
- Delete 5 OTel-only modules (instrumentation, betaSessionTracing,
bigqueryExporter, logger, firstPartyEventLoggingExporter)
- Replace 9 modules with no-op stubs (sessionTracing, events,
telemetryAttributes, firstPartyEventLogger, growthbook, index,
sink, datadog, sinkKillswitch, perfettoTracing)
- Remove all @opentelemetry/* imports from bootstrap/state.ts,
entrypoints/init.ts, and ~20 caller files
- Remove all OTel counter types, meter/provider state from state.ts
- Clean externals.ts: remove 27 @opentelemetry/* entries
- Clean build.ts: remove OTel native-stub namespace exports
- Simplify no-telemetry-plugin.ts: remove redundant source-level stubs
- Remove 10 @opentelemetry/* + @growthbook/growthbook from package.json
- GrowthBook stub reads local ~/.claude/feature-flags.json for overrides
Co-Authored-By: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
* fix format
* chore: regenerate lockfile after OTel dependency removal
Co-Authored-By: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
* fix(growthbook): route gate helpers through local flag overrides
checkStatsigFeatureGate_CACHED_MAY_BE_STALE() and
checkGate_CACHED_OR_BLOCKING() now resolve from
~/.claude/feature-flags.json like getFeatureValue_* does,
so gates like tengu_thinkback, tengu_ccr_bridge, and
VS Code upsells can be flipped on locally. Security gates
(checkSecurityRestrictionGate) remain hard-false.
Also adds 5 tests covering gate helper override behavior
and unifies JSDoc wording for _getFlagValue-routed functions.
Co-Authored-By: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
Implement sponsored tip system with registry, scheduler integration,
and config-gated frequency control. Sponsored tips appear based on
startup count frequency (default: 1 per 10 startups) and are
tracked separately from regular tip history.
Co-authored-by: OpenClaude (zai-org-glm-5-1) <openclaude@gitlawb.com>
Codex OAuth first-run setup saved the new provider profile without making it the active provider profile, while still switching the current process environment. That left the current session and next startup disagreeing about which provider should be used.
This makes the saved OAuth profile active unless it is already active, preserving the existing current-session activation and credential persistence flow.
Constraint: First-run setup intentionally creates the profile with makeActive: false before OAuth credentials are persisted.
Rejected: Only update the current session env | next startup would still use the previous active provider.
Confidence: high
Scope-risk: narrow
Directive: Codex OAuth onboarding must keep activeProviderProfileId, stored credential profileId, and current-session provider env aligned.
Tested: bun test src/components/ProviderManager.test.tsx
Tested: git diff --check
Not-tested: repo-wide bun run typecheck, existing unrelated missing-module/type errors block it
stripAllLeadingEnvVars used [^\]]* for the array subscript component of the
ENV_VAR_PATTERN, which accepted $(cmd), ${var}, and backtick expressions.
Bash evaluates subscripts during assignment parsing, so a command like
FOO[$(denied_cmd)]=val harmless executed the denied command as a side effect
while the deny-rule check only saw `harmless`.
Changed subscript character class to [^\]$`{(]* to exclude the characters
that introduce all bash expansion forms:
- $ blocks $(cmd), ${var}, $((expr))
- ` blocks backtick command substitution
- { and ( are belt-and-suspenders guards
Safe numeric and identifier subscripts (FOO[0], FOO[idx]) continue to match.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevent generated missing-module noop functions from entering the built-in command registry.
Add a runtime isCommand guard in src/types/command.ts and apply it when building the COMMANDS() list so bare noopN tree-shaking stubs are excluded before they can appear in slash-command autocomplete.
Add focused tests covering rejection of noop-style stubs and acceptance of valid command objects.
Refs Gitlawb/openclaude#1132.
* fix(codex): default missing 'type' on MCP tool properties to avoid 400 (#1114)
MCP tools sometimes register properties without an explicit `type` (e.g. a
generic `value` field intended to accept any JSON). Codex Responses strict
mode then rejects the tool registration with
`schema must have a 'type' key`. Add `ensureSchemaType()` to infer a type
from sibling keys (`properties` -> object, `items` -> array, `enum`/`const`
-> value type) and fall back to `string` for fully empty nodes.
Combinator-only schemas (`anyOf`/`oneOf`/`allOf`) are left alone so their
branches keep their semantics.
Fixes#1114
* fix(codex): normalize empty MCP object schemas
Ensure Codex strict tool schemas include an explicit empty properties object when MCP tools provide required keys without properties.
Co-Authored-By: OpenClaude (gpt-5.5) <openclaude@gitlawb.com>
---------
Co-authored-by: gnanam1990 <gnanasekaran.sekareee@gmail.com>
Co-authored-by: OpenClaude (gpt-5.5) <openclaude@gitlawb.com>
Closes#1051 (BUG-01).
The regex `/\s-\S*e/` in `validateZshDangerousCommands` only required
`e` to appear *somewhere* after `-`, so any flag that happened to
contain `e` — `-reset`, `-reverse`, `-message`, etc. — tripped the
"dangerous fc" path and surfaced an interactive permission prompt to
the user even though those flags do not invoke an editor and have
nothing to do with the `fc -e <editor>` eval vector the check is
trying to catch.
Replace with `/\s-[a-zA-Z]{0,3}e(?:\s|$)/` so:
* `e` must be the last letter in the flag bundle (followed by
whitespace or end-of-string), not anywhere inside it
* the bundle is capped at 4 chars total, matching the shape of
real POSIX `fc` short-flag bundles (`-e`, `-le`, `-lne`)
The bundle cap is what distinguishes us from the issue's initial
suggested fix `/\s-[a-zA-Z]*e(?:\s|$)/`, which still false-positives
on `-reverse` and `-message` because both end in `e` and the unbounded
`*` swallows the entire word.
New regression tests in `bashSecurity.test.ts` cover the real-flag
positive cases (`-e`, `-le`, `-lne`) and the long-flag negative cases
called out in the bug report (`-reset`, `-reverse`, `-message`), plus
`-l` to confirm the safe list flag still passes through.
* fix(bashSecurity): reject nested heredoc ranges in stripSafeHeredocSubstitutions
isSafeHeredoc already rejects nested $(cat <<'A'...A) matches to prevent
stale-index corruption when stripping in reverse order. Apply the same guard
to stripSafeHeredocSubstitutions, which was missing it.
Without the check, a nested inner range stripped first leaves outer.end stale.
result.slice(outer.end) then skips any trailing content (e.g., `; rm -rf /`),
silently hiding it from downstream validators.
Fix: return null on nested ranges so callers fall back to full command validation.
* test(bashSecurity): add regression tests for stripSafeHeredocSubstitutions
Covers: single heredoc strip, nested heredoc null-return (stale-index
regression), no heredoc present, and multiple non-nested heredocs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(urlRedaction): export shouldRedactUrlQueryParam as the single source of truth
The credential-param-name list lives in `src/utils/urlRedaction.ts` and
is the canonical coverage used by `redactUrlForDisplay`. A second copy
in `src/services/api/openaiShim.ts` had drifted, dropping `passwd`,
`pwd`, `auth`, and `apikey` — see follow-up commit replacing the shim
copy with this export.
Tests pin the four regression cases (`?passwd=`, `?pwd=`, `?auth=`,
`?apikey=`) and assert the helper accepts the same set across both
underscore and dash separators, so any future fork trips the test
instead of silently re-introducing the leak.
Refs #1069
* fix(openai-shim): use shared shouldRedactUrlQueryParam to redact ?auth/?passwd/?pwd in diagnostics
The shim's local `SENSITIVE_URL_QUERY_PARAM_NAMES` (10 entries) had
drifted from the canonical 14-entry list in `urlRedaction.ts`. Three
of the missing names — `passwd`, `pwd`, `auth` — are not substrings
of any shim-list token, so `redactUrlForDiagnostics` was emitting
them verbatim into the self-heal retry log, transport-error log,
HTTP-error log, and toolless retry log.
Replace the local copy with an import from the canonical module so
both code paths stay in lock-step. The post-redaction
`redactSecretValueForDisplay` env-secret pass is preserved — it's
the second layer that catches credentials hardcoded directly into
the URL string when the param name itself is non-obvious.
Closes#1069
* feat(providerConfig): add OPENCLAUDE_LOCAL_FAST_PATH opt-out for local backends
Local OpenAI-compatible endpoints (llama.cpp, vLLM, Ollama, LM Studio,
…) do not implement the cloud-side caching/strict-validation behaviours
that several pre-send transforms target — byte-stable serialization
hashes nothing, strict tool-schema rewrites are accepted as-is, and
tool-result tiering compresses against contexts that already live in
local RAM.
`getLocalFastPathConfig(baseUrl)` returns a flag bundle so callers can
skip those transforms uniformly. By default the helper auto-detects via
the existing `isLocalProviderUrl` (loopback / RFC1918 / .local / ULA).
`OPENCLAUDE_LOCAL_FAST_PATH=1|0|auto` overrides the detection — useful
when a remote LAN host needs the same treatment, or when a user wants
to keep the cloud transforms even on localhost while debugging.
Tests cover auto-detect on every host class, all truthy/falsy aliases,
the explicit `env` argument override, and `auto`/empty/garbage fall-
through to detection.
Refs #1016
* perf(openai-shim): wire local fast path through compress/strict/serialize
Apply the local fast-path opt-out at the three pre-send transforms that
showed up in the issue #1016 audit of v0.5+ regressions against ~45
tok/s local backends:
- compressToolHistory: skip the tool_result tier walk; on a single-
user local box the conversation lives in RAM and the tier-walk is
pure CPU per request.
- convertTools strict mode: drop the recursive
`additionalProperties: false` rewrite; local llama.cpp / vLLM /
Ollama accept the original Anthropic schema unchanged.
- request body serialization: fall back to native `JSON.stringify`
instead of `stableStringify`; local backends do not implement
implicit prefix caching, so the deep key-sort hashes nothing.
Behaviour for cloud providers is unchanged — every call site still
runs the full pipeline when `getLocalFastPathConfig(baseUrl).enabled`
is false. The GitHub Copilot `/responses` retry path (which is GitHub-
specific and never reachable for a local baseUrl) keeps the byte-
stable serialization to preserve the existing prefix-caching contract.
Refs #1016
* feat(xai): add Grok 4.3 as default model
Add Grok 4.3 to xAI model metadata and make it the provider default while preserving explicit Grok 4 and Grok 3 selections.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
* fix(xai): correct Grok 4.3 context window to 1M tokens
Grok 4.3 docs list 1,000,000 token context window. The PR had
incorrectly registered 2,000,000, which would allow local budgeting
to retain ~2x the supported input size before compaction triggers,
leading to provider-side failures.
- src/integrations/models/xai.ts: set contextWindow to 1_000_000
- src/utils/context.test.ts: update expectation to match
🤖 Generated with [OpenClaude](https://github.com/Gitlawb/openclaude)
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
* Centralize OpenClaude display name
Add PRODUCT_DISPLAY_NAME as the shared product display label and use it across prompt identity, onboarding, permission dialogs, hook/agent UI, and tool permission messages.
Update onboarding security copy to a single security note, remove the prompt injection note, and replace remaining user-facing Claude possessives with the product display name where appropriate.
* Restore plan author display name
* Restore onboarding prompt injection warning
Reinstate the two-item security notes layout that was collapsed during the product display name cleanup.
Keep the OpenClaude PRODUCT_DISPLAY_NAME branding while restoring a concise prompt-injection/trusted-code warning that does not depend on the external Claude Code docs link.
Verification: parsed src/components/Onboarding.tsx with TypeScript createSourceFile.
---------
Co-authored-by: JATMN <12479882+jatmn@users.noreply.github.com>
* fix(agents): coerce non-string whenToUse to prevent crash on save (#1086)
The new-agent confirm step crashed with `whenToUse.replace is not a
function` when an LLM (e.g., qwen3.5:9b) returned a non-string value
for the `whenToUse` field. The downstream YAML escape in
formatAgentAsMarkdown assumed a string and threw mid-write.
Tighten the parse boundary in generateAgent to require non-empty strings
for identifier/whenToUse/systemPrompt, and add a defensive coercion in
formatAgentAsMarkdown so any future caller producing a non-string value
fails closed (writes an empty description) rather than crashing the
agent creation flow.
* fix(agents): truly fail closed for non-string whenToUse
Address review feedback on #1087: the prior `String(value ?? '')` fallback
serialized non-string values as "42", "[object Object]", etc., which
contradicted the stated fail-closed intent and silently saved garbage as
the agent description. Switch to `typeof === 'string' ? : ''` so invalid
metadata writes an empty description instead.
Tighten the regression test to assert the exact serialized `description: ""`
output for undefined/null/number/array/object inputs, rather than only
asserting "does not throw".
* feat: make Orama the default search engine with robust JSON-backed hybrid architecture
* fix: return empty string for no-hit knowledge searches and add regression test
* fix: replace unsupported Unicode glyphs with widely available alternatives
Replace TUI characters from obscure Unicode blocks (Miscellaneous Technical,
Dentistry Symbols) that render as tofu boxes on most Linux terminal fonts,
including all Nerd Font variants.
Replacements:
- ⏵⏵ (U+23F5) → ▶▶ (U+25B6) — permission mode indicator
- ⎿ (U+23BF) → └ (U+2514) — tool output connector bracket
U+23F5 and U+23BF are not present in any common monospace or Nerd Font.
U+25B6 and U+2514 (Box Drawing) are universally supported.
Fixes rendering on Linux terminals (kitty, xterm, Ptyxis), Windows terminal
emulators (MobaXterm, PuTTY), and mosh sessions.
Related upstream issues:
- anthropics/claude-code#24102
- anthropics/claude-code#39127
- anthropics/claude-code#53080
* fix: replace remaining escaped \u23BF glyphs with \u2514
The initial patch replaced literal ⎿ characters but missed 5
escaped \u23BF forms in AgentProgressLine, SystemTextMessage,
and UserLocalCommandOutputMessage. These render to the same
unsupported U+23BF codepoint at runtime, producing tofu boxes
on terminals without CJK serif fonts.
Addresses reviewer feedback from jatmn and techbrewboss.
* feat(knowledge): introduce local Orama persistence (clean phase 1)
- Added @orama/orama and persistence plugin.
- Implemented optional local-only Orama backend in knowledgeGraph.ts.
- Gated Orama logic behind OPENCLAUDE_KNOWLEDGE_ORAMA=1.
- Converted knowledge and conversation arc functions to async.
- Fixed circular dependency between knowledgeGraph and sessionStorage by moving getProjectsDir to envUtils.
- Updated all call sites and tests to handle async Knowledge API.
- Verified build and tests pass on latest main.
* fix: address PR review comments for knowledge feature (async finalizeArcTurn and Orama cleanup)
* test: add comprehensive stress and edge case testing for Orama Knowledge Graph
* fix: prevent test pollution by restoring Orama env flag in stress test
* refactor: harden Knowledge architecture with concurrency locks, optimized I/O, and consolidated state