* 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>
* 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
@mendable/firecrawl-js@4.18.1 (lazy-loaded by WebSearch + WebFetch) requires
Node >=22, and CI runs Node 22 + 24, but package.json still advertised
>=20.0.0. Result: npm install on Node 20 surfaced an EBADENGINE warning that
users routinely ignored, then exploded with a cryptic syntax error the first
time a web tool actually pulled firecrawl in.
Bump engines.node to >=22.0.0 so npm refuses Node 20 up front, and refresh
the stale comment in withResolvers.ts that still pointed at the long-gone
>=18.0.0 baseline.
Closes#1009 (engine half — the EACCES half is standard global-install perms,
not openclaude's to fix).
* feat(sdk): add SDK foundation — type declarations, errors, and utilities
Adds standalone SDK building blocks with no SDK source dependencies:
- sdk.d.ts: ambient type declarations for SDK bundle
- coreSchemas.ts + coreTypes.generated.ts: Zod schemas and generated types
- errors.ts: SDK-specific error classes
- validation.ts: input validation utilities
- messageFilters.ts: extracted message filter logic
- handlePromptSubmit.ts: imports from messageFilters
- 16 generated-types tests
* fix(sdk): narrow assertFunction type from broad Function to callable signature
Code review finding: assertFunction used `asserts value is Function` which
accepts any function-like value without narrowing. Changed to
`(...args: any[]) => any` for better type safety.
* fix(sdk): update sdk.d.ts header — manually maintained, not generated
Reviewer noted the header said "Generated from index.ts" but no generator
produces this file. Updated to "Manually maintained — keep in sync with
index.ts". Drift detection added in validate-externals.ts (PR 3).
* fix(sdk): align sdk.d.ts types with canonical coreTypes.generated.ts
Tighten SDK public type contract to resolve reviewer blockers:
- PermissionResult: unknown[] → precise 6-shape discriminated union
(addRules/replaceRules/removeRules/setMode/addDirectories/removeDirectories)
- SDKSessionInfo: snake_case → camelCase (sessionId, lastModified, etc.)
- ForkSessionResult: session_id → sessionId
- SDKPermissionRequestMessage: uuid + session_id now required
- SDKPermissionTimeoutMessage: added uuid + session_id
- SessionMessage: parent_uuid → parentUuid
- SDKMessage/SDKUserMessage/SDKResultMessage: replaced loose inline
definitions with re-exports from coreTypes.generated.ts
* feat(sdk): wire existing code modules + SDK shared utilities
Modifies core modules for SDK integration:
- QueryEngine, tools, state, commands: SDK type hooks
- SDK shared utilities (shared.ts, permissions.ts)
- 21 SDK tests (shared-utils, permissions)
Stack: main ← pr1-foundation ← pr2-sdk-core
* feat(sdk): add snake_case ↔ camelCase key mapping utilities
casing.ts provides recursive key transformation for the SDK boundary
layer. Internal runtime uses snake_case; public API exposes camelCase.
Will be used by shared.ts, sessions.ts, query.ts at export boundaries.
* test(sdk): add tests for snake_case ↔ camelCase mapping utilities
Covers snakeToCamel, camelToSnake, mapKeysToCamel, mapKeysToSnake
including nested objects, arrays, null/undefined, and round-trips.
* feat(sdk): add SDK runtime — query engine, sessions, build pipeline
Completes the SDK implementation:
- SDK build target (dist/sdk.mjs) with TUI dependency stubbing
- External dependency lists (scripts/externals.ts)
- SDK type generation from Zod schemas (scripts/generate-sdk-types.ts)
- External validation (scripts/validate-externals.ts)
- SDK source: index, query, v2, sessions modules
- agentSdkTypes: re-exports SDK functions (query, createSession, etc.)
- 136 SDK tests + 7 build scanner tests
Stack: main ← pr1-foundation ← pr2-sdk-core ← pr3-sdk-runtime
* fix(sdk): align internal SDK types with camelCase public contract
shared.ts: SDKSessionInfo, ForkSessionResult, SessionMessage fields
now use camelCase matching sdk.d.ts. SDKPermissionRequestMessage and
SDKPermissionTimeoutMessage gain required uuid + session_id fields.
permissions.ts: onPermissionRequest/onTimeout callbacks now include
uuid and session_id in emitted messages.
* fix(sdk): update runtime modules to use camelCase field names
sessions.ts: toSDKSessionInfo outputs camelCase keys, entryToSessionMessage
uses parentUuid, forkSession returns sessionId.
query.ts: reads sessionId from listSessions/forkSession results
instead of snake_case session_id.
* fix(test): update session tests to use camelCase field names
session_id → sessionId in forkSession result assertions and
getSessionMessages calls.
* fix(sdk): prevent permission timeout race condition with once-only resolve wrapper
Add createOnceOnlyResolve utility to prevent double-resolution of promises
when timeout and host response happen simultaneously. This ensures
deterministic behavior in the permission handling flow.
* fix(sdk): improve race condition test robustness
* fix(sdk): handle consecutive underscores in snakeToCamel conversion
Changes:
- Use _+([a-z]) regex to match multiple consecutive underscores before letters
- Add lookahead (?=. ) to preserve underscore-letter pairs at string end
- Handle dunder names (__proto__, __typename) by stripping wrapper and capitalizing
- Add tests for consecutive underscores and trailing underscore preservation
* fix(sdk): include original error message in permission callback denial
When a canUseTool callback throws an error, the catch block now
includes the original error message in the denial message, making
debugging easier for SDK consumers.
* feat(sdk): add optional timeout to env mutex for deadlock prevention
Add timeout parameter to acquireEnvMutex() to prevent infinite waits
in deadlock scenarios. The timeout is optional and defaults to no timeout
(wait forever) for backward compatibility.
Returns a MutexAcquireResult object with acquired status and optional
timeout reason for failed acquisitions.
* fix(sdk): remove timed-out callback from mutex queue to prevent deadlock
* test(sdk): add missing error path and timeout scenario tests
Add tests for timeout scenarios when host doesn't respond to permission
requests, fallback behavior when no onPermissionRequest callback, and
MCP connection edge cases for undefined/empty config.
* fix(sdk): address code review issues - race conditions, validation, error handling
- Add createPermissionTarget() factory that applies onceOnlyResolve at
registration time, fixing race condition where timeout and host response
could both try to resolve the same promise
- Add try-catch to releaseEnvMutex() to prevent permanent lock if callback throws
- Extract DEFAULT_PERMISSION_TIMEOUT_MS constant (30 seconds)
- Add MCP config validation rejecting null, non-objects, and arrays
- Preserve error stack traces in MCP connection failures
- Add runtime validation to mapMessageToSDK for null/non-object/invalid type
- Update tests to use createPermissionTarget and add validation tests
* fix(sdk): syntax fixes and MCP connection error handling
- Remove extra closing parenthesis in permissions.ts
- Remove extra closing braces in shared.ts type definitions
- Wrap MCP connection in try/catch to continue without MCP tools on failure
* fix(sdk): syntax fixes, MCP error handling, and logic clarity
- Remove extra closing parenthesis in permissions.ts
- Remove extra closing braces in shared.ts type definitions
- Wrap MCP connection in try/catch to continue without MCP tools on failure
- Clarify thinkingConfig logic: use ?? true instead of !== false
- Add explanatory comment about thinkingEnabled default behavior
- Apply createOnceOnlyResolve wrapper in QueryImpl.registerPendingPermission
* fix(sdk): comprehensive error handling and resource cleanup
- Add try-catch around injectAgents() to gracefully handle plugin agent
tool validation failures (prevents test crashes from unknown 'LS' tool)
- Add console.warn logging to agent loading/injection catch blocks for
debugging visibility (matches v2.ts pattern)
- Add pendingPermissionPrompts.clear() to close() and interrupt() methods
in both query.ts and v2.ts to prevent memory accumulation
- Add close() method to SDKSession interface and SDKSessionImpl
- Wrap MCP connection in query.ts with try-catch (matches v2.ts behavior)
- Add timeoutQueue cleanup in finally blocks (query.ts + v2.ts)
- Remove error.stack from MCP error messages to prevent internal path leak
All 208 SDK tests pass. TypeScript errors are pre-existing.
* fix(sdk): address code review non-blocking issues
- Add SDKAgentLoadFailureMessage type for agent load failure events
- Emit agent definition/injection failures to SDK message stream
- Add tool name to permission timeout denial message
- Replace 'as any' casts with proper typed state access
- Fix supportedCommands to use correct mcp.commands/plugins.commands paths
- Update test for correct AppState structure
* fix(sdk): address code review blocking and non-blocking issues
Blocking Issues Fixed:
- MCP cleanup missing on session/query close - now disconnects MCP clients
to prevent resource leaks in long-running processes with multiple sessions
- Engine reference not cleared on close - now sets _engine = null to prevent
memory leaks
- Added MCP cleanup tests (9 new tests covering cleanup scenarios)
Non-Blocking Issues Fixed:
- Removed redundant catch block that just rethrew errors (query.ts)
- Fixed inconsistent timeout denial message format (permissions.ts)
- Fixed hardcoded tool name 'Bash' in test (permissions.test.ts)
- Exported PermissionResolveDecision type for SDK consumers (index.ts)
All 217 SDK tests pass.
* fix(sdk): address code review type consistency issues
- Add close() method to SDKSession interface (documented but missing from type)
- Fix SDKSessionInfo, ForkSessionResult, SessionMessage field naming:
snake_case → camelCase to match sdk.d.ts public contract and implementation
- Add uuid and session_id to SDKPermissionTimeoutMessage for correlation
- Fix JSDoc comment in forkSession to use sessionId (not session_id)
These changes align internal types (shared.ts) with the public SDK contract
(sdk.d.ts) and actual implementation output. The merge from origin/main
introduced snake_case types that mismatched camelCase implementation and tests.
* fix: restore openclaude.json comment in REPL.tsx
Merge 0f3aa7a incorrectly took main's side for this comment, reverting
PR2 fix c725c48. Project has migrated to ~/.openclaude.json, not ~/.claude.json.
This is the only PR2 fix lost during merge - all other PR2 fixes
(permissions.ts race conditions, state.ts parentSessionId, etc.)
are preserved in PR3 via subsequent fix commits.
* fix(sdk): add missing type declarations to sdk.d.ts
Add SDKAgentLoadFailureMessage and PermissionResolveDecision to sdk.d.ts
to resolve type declaration drift detected by build validation.
- SDKAgentLoadFailureMessage: Agent loading failure notification
(stage: definitions/injection, error_message)
- PermissionResolveDecision: SDK-specific permission resolution result
(allow with updatedInput, deny with message + decisionReason)
Build validation now passes: 56 exports match between index.ts and sdk.d.ts.
* fix(sdk): resource leak and null safety in close/interrupt paths
- unstable_v2_prompt: wrap session in try/finally to guarantee
session.close() on both success and error paths, preventing
MCP connection and engine resource leaks
- QueryImpl.interrupt(): add null guard on _engine so calling
interrupt() after close() is a safe no-op instead of throwing
- SDKSessionImpl.interrupt(): add matching null guard for v2
sessions, consistent with the Query fix
- QueryImpl.close(): call this.interrupt() before cleanup to
properly stop in-flight engine operations, matching v2's close()
pattern and ensuring engine.interrupt() runs before nulling
* fix(sdk): abort AbortController in SDKSessionImpl.close() to prevent resource leak
SDKSessionImpl.close() was not aborting the AbortController, unlike
QueryImpl.close() which does. This meant in-flight HTTP requests and
async operations could continue running after session closure.
- Store AbortController reference via _abortController field + late-bind setter
- Abort and null the controller in close(), mirroring QueryImpl pattern
- Also null _appStateStore in close() to release state snapshots
- Wire abortController through createEngineFromOptions return value
* fix(sdk): index ALL entries in byUuid for compact preserved segment
The byUuid map must index system compact_boundary entries, not just
user/assistant. When anchorUuid === boundary.uuid, the relink walk
needs to find the boundary in byUuid.
Changes:
- query.ts: Index ALL non-sidechain entries (user, assistant, system)
- v2.ts: Same fix — index ALL entries, leaf selection user/assistant only
- Add regression test: boundary.uuid as anchorUuid scenario
Test verifies preserved messages kept, stale pre-compact dropped,
post-boundary chain intact when anchorUuid points to boundary itself.
* fix(sdk): complete preserved segment handling for compact resumes
Multiple fixes for compact-aware transcript loading:
1. Index ALL entries in byUuid (including system compact_boundary)
- Needed when anchorUuid === boundary.uuid
2. Keep anchorUuid when pruning preserved segment entries
- The anchor is the parent of preserved head after relink
- Deleting it breaks the conversation chain
3. Filter system entries from final messages
- compact_boundary is metadata, shouldn't pass to engine
4. Fix test timestamp format (ISO 8601 requires 2-digit hours)
- '2025-01-04T0:00:00Z' → '2025-01-04T00:00:00Z'
5. Update test expectations for anchor inclusion
- When anchor is a stale entry, it appears in messages
- preserved(4) + anchor(1) + post(4) = 9 max
All 224 SDK tests pass.
* fix(sdk): MCP type:sdk tools properly convert SdkMcpToolDefinition to Tool
- Import MCPTool base from tools/MCPTool/MCPTool.js
- Spread MCPTool properties for proper Tool interface compliance
- Add tools field to SdkMcpSdkConfig type declaration
- Add regression tests for type:sdk tools wiring
Fix ensures in-process SDK tools match Tool interface expected
by QueryEngine and permission handlers.
* test(sdk): strengthen preserved segment and MCP tools tests
Preserved segment test improvements:
- Fix content extraction (access message.content, not message)
- Add exact count assert: messages.length === 6
- Add exact content asserts: preserved turn 1/2, post-boundary present
- Assert no stale, no system entries in final messages
MCP tools test additions:
- Direct test of connectSdkMcpServers() function
- Assert clients.length === 0 (in-process, no MCP connections)
- Assert tools.length === 1 with proper name/description
- Verify handler works via direct call (not via Tool.call which needs context)
* fix(sdk): published types complete, init errors fatal, permission session IDs
Three fixes for SDK production readiness:
1. HIGH: Published SDK types incomplete
- Add coreTypes.generated.d.ts to package.json "files" array
- sdk.d.ts re-exports from ./sdk/coreTypes.generated.js which was missing
- TypeScript consumers would get module resolution errors
2. MEDIUM: query() swallows real init() failures
- Add _engineWasInjected field to track pre-injected vs fresh engine
- Check _engineWasInjected, not _engine !== null (always true after setEngine)
- Auth/config/init errors now properly fatal for normal query() calls
3. MEDIUM: SDK permission events lose real session id
- Pass sessionId to createExternalCanUseTool() in both query.ts and v2.ts
- Permission_request/timeout messages now have correct session_id
- Hosts can correlate permission callbacks to sessions
Test result: 225 pass, 0 fail
* fix(sdk): complete package types + dynamic permission session_id
Two fixes for SDK production readiness:
1. Published SDK types now include actual definitions
- Replace 215-byte wrapper with 63KB coreTypes.generated.ts
- TypeScript consumers get full type definitions (SDKMessage, etc.)
- npm pack now includes real generated types
2. Permission event session_id dynamic for all query() paths
- createExternalCanUseTool accepts string | (() => string | undefined)
- query.ts passes () => queryImpl.sessionId getter
- Fresh/fork/continue queries emit correct session_id at event time
- V2 passes static sessionId (stable at creation/resume)
- Add 4 tests: static sessionId, getter resolution, undefined fallback, timeout
Test result: 229 pass, 0 fail
* fix(sdk): fix sdk.d.ts for real TypeScript consumer compilation
Two issues prevented external consumers from compiling against packed SDK types:
1. SDKRateLimitError used constructor parameter properties (readonly resetsAt,
readonly rateLimitType) which are invalid in .d.ts declarations — moved to
class properties with separate constructor signature.
2. Re-exported SDKMessage/SDKUserMessage/SDKResultMessage were not imported
into local scope — added import type alongside export type so TypeScript
can resolve them for use in other declarations within the same file.
Added package-consumer-types.test.ts that compiles a real temp project against
the SDK types with skipLibCheck:false, catching both regressions.
* fix(sdk): eliminate React/Ink imports from SDK bundle
SDK bundle leaked React/Ink imports via tool UI modules, keybindings,
react-compiler-runtime, and spawnMultiAgent's static React import.
Changes:
- Stub root ink.js barrel, tool UI.js, keybindings/, react-compiler-runtime,
It2SetupPrompt, and React hook files in SDK build
- Add local no-op stub for react/jsx-dev-runtime (jsxDEV returns null)
- Convert spawnMultiAgent's static React/It2SetupPrompt imports to dynamic
await import() — spawnTeammate logic stays fully intact
- Add post-build leakage validation (fails on from "react"/"ink"/jsx-dev-runtime)
- Remove react/jsx-dev-runtime from SDK externals (now handled by build plugin)
* fix(sdk): wire disallowedTools through permission context
QueryOptions.disallowedTools was declared but never used. buildPermissionContext()
now passes it to alwaysDenyRules.cliArg so getTools() filters denied tools from
the model-visible list. Also added to V2 SDKSessionOptions for API consistency.
* fix(sdk): defer permission warning to execution time
createDefaultCanUseTool() warned at construction time even when the caller
provided canUseTool/onPermissionRequest. Move warning to first actual default
denial so valid SDK consumers never see false warnings. Add tests for
disallowedTools filtering, tool exclusion, and warning timing.
* refactor(sdk): extract transcript helpers + fix permission typing
- Extract shared transcript utilities to transcript.ts
(parseJsonlEntries, findLastCompactBoundary, applyPreservedSegmentRelinks,
buildConversationChain, stripExtraFields) deduplicating query.ts and v2.ts
- Add PermissionTarget interface to hide internal pendingPermissionPrompts
map from createExternalCanUseTool, with deletePendingPermission and
denyPendingPermission methods on QueryImpl and SDKSessionImpl
- Fix sessionId stability: preserve constructor UUID for fresh queries
when continue:true finds no existing sessions, and when explicit
sessionId does not resolve to a valid transcript file
- Add getMcpClients/setMcpClients to QueryEngine for SDK cleanup access
* fix(sdk): resolve remaining TypeScript errors in SDK modules
- Fix PermissionDecision type compatibility: import from types/permissions
and cast PermissionResolveDecision to PermissionDecision properly
- Fix AsyncIterator/AsyncGenerator: async generators must return
AsyncGenerator (which implements AsyncIterable), not AsyncIterator
- Fix Map method callable errors: cast additionalWorkingDirectories
to Map<string, unknown> before calling .set() and .keys()
- Fix ApiKeySource type: map internal ApiKeySource to SDK's narrower
type using conversion function, spread info before apiKeySource
to avoid override
- Fix MCP config scope type: cast 'session' scope to ScopedMcpServerConfig
for connectToServer compatibility
- Add PermissionMode import and cast for decisionReason.mode
- Deny pending permissions in interrupt(): resolve all pending promises
with deny before clearing the map (both query.ts and v2.ts)
* fix(sdk): correct init skip logic and test mocks
- query.ts: skip init() entirely for injected engines (mocks, SDK host
overrides) instead of calling init() and swallowing errors. Pass
{ injected: false } from query() factory to distinguish real engine
from test mocks.
- mock-engine.ts: add getMcpClients() and setMcpClients() methods to
match QueryEngine API added in this PR.
- permissions.test.ts: use filterToolsByDenyRules instead of getTools
for disallowedTools tests, with proper base tool fixtures.
* fix: address code review feedback for exports and build script
package.json exports (Breaking Change Mitigation):
- Add "./package.json": "./package.json" for tool compatibility
- Add "./dist/cli.mjs": "./dist/cli.mjs" for CLI bundle access
- Keep ./sdk as sole library entrypoint
- Root import intentionally blocked (CLI-first package, no main field)
build.ts (Bug Fix):
- Add | undefined to result/sdkResult type declarations
- Add optional chaining: result?.success, sdkResult?.success
- Prevents TypeError masking actual build errors when Bun.build throws
tests/sdk/package-consumer-types.test.ts:
- Update simulated exports to match real package.json
- Add tests verifying exports map structure and file existence
---------
Co-authored-by: Ali Alakbarli <ali.alakbarli@users.noreply.github.com>
* setting up
* updated plan with missing notes for discovery cache
* build out inital checklist and planning adjustments
* Phase 1A-1D
* Fix descriptor-backed provider profile routing
- preserve GitHub, Bedrock, and Vertex runtime flags during profile activation\n- serialize descriptor-backed startup profiles into legacy-compatible persisted kinds\n- add regression coverage for activation, restart round-trip, and saved-profile switching\n- guard integration registration so repeated imports stay idempotent in tests
* feat: finish phase 1 provider descriptor routing
Complete the Phase 1E CLI/usage migration work and the Phase 1F verification pass for descriptor-backed providers.
Details:
- derive valid --provider values from descriptor registry and compatibility mappings instead of a fixed list
- preserve special CLI semantics for ollama and minimax while allowing descriptor-backed OpenAI-compatible routes such as deepseek and openrouter to pick up descriptor base URLs
- add getUsageDescriptor() so /usage resolves vendor/gateway metadata and follows usage delegation
- switch Settings Usage rendering to descriptor-backed usage resolution for Anthropic, MiniMax, and neutral unsupported fallbacks
- make integration loading idempotent via ensureIntegrationsLoaded() so registry-backed helpers survive tests that clear the registry
- fix compatibility mapping for mistral so the preset routes through vendorId=openai with gatewayId=mistral rather than a nonexistent direct vendor route
- harden provider profile and startup tests so descriptor-backed providers, legacy OpenAI startup files, and unknown stored providers round-trip correctly
- remove a stale ollama model mock that was leaking across the full model test suite
- update plan/progress.md with the current 1E complete / 1F in-progress verification state and the note that repo-wide typecheck failures are pre-existing outside this migration slice
Verification:
- bun test src/commands/usage/index.test.ts src/integrations/compatibility.test.ts src/utils/providerFlag.test.ts src/utils/providerProfiles.test.ts src/utils/providerProfile.test.ts src/utils/model/modelCache.test.ts src/integrations/index.test.ts src/integrations/registry.test.ts
- filtered bun run typecheck output for the files changed in this branch is clean
* Phase 2 planning
* feat: complete phase 2A validation and discovery cache
* fix: address review findings for phase 2 cache and validation
Fixes the follow-up review issues from the Phase 2A / 2A.5 work.
Completed work:
- made discovery cache stale entries reachable through getCachedModels(..., { includeStale: true }) while keeping fresh-by-default behavior unchanged
- kept recordDiscoveryError stale-data preservation useful to later /model consumers by exposing stale and error-only entries through the public helper API
- extended descriptor-backed validation routing metadata with host alias matching support
- updated MiniMax validation routing to recognize both api.minimax.io and api.minimax.chat endpoints
- added regression coverage for stale cache reads, error-only cache entries, and MiniMax chat-host validation
- updated progress.md notes so the recorded 2A.5 helper behavior matches the implementation
* feat: complete phase 2B discovery and readiness migration
Implement descriptor-backed discovery and readiness routing for Phase 2B.
Highlights:
- add src/integrations/discoveryService.ts to execute declarative catalog.discovery configs with shared discovery-cache integration
- add hybrid merge behavior so curated descriptor catalog entries stay ahead of discovered duplicates
- add typed startup readiness metadata via ReadinessProbeKind and wire gateway descriptors for ollama, atomic-chat, lmstudio, and openrouter
- export probeOllamaModelCatalog() so discovery can distinguish unreachable Ollama from reachable-but-empty catalogs
- migrate ProviderManager and /provider flows to probeRouteReadiness() while preserving existing Ollama messaging
- route bootstrap local model discovery through descriptor-backed discovery for recognized local routes, while keeping legacy fallback for generic custom endpoints
- add resolveDiscoveryRouteIdFromBaseUrl() so bootstrap can share descriptor-backed discovery and local provider labels
- preserve explicit provider env precedence during applySavedProfileToCurrentSession() after focused verification exposed the regression
- update plan/progress.md to mark Phase 2B complete and record the verification notes
Verification:
- bun test src/integrations/discoveryService.test.ts
- bun test src/components/ProviderManager.test.tsx
- bun test src/commands/provider/provider.test.tsx
- bun test src/utils/providerDiscovery.test.ts src/integrations/registry.test.ts src/integrations/index.test.ts
- filtered bun run typecheck for the touched 2B files returned FILTER_CLEAN
* feat: complete phase 2c provider metadata migration
Finish the Phase 2C runtime metadata adoption work on cheeky-cooking-moon.
Provider UI metadata:
- add shared route metadata and provider preset UI metadata helpers
- move preset labels/defaults, route type labels, and custom-header capability checks onto descriptor-backed lookups
- update ProviderManager and /provider summaries/setup copy to read shared descriptor metadata instead of bespoke switches
- extend local gateway descriptors with default model metadata used by the shared UI helpers
Model discovery UX:
- add route catalog option builders for descriptor-backed /model rendering
- update /model to resolve the active route, read cached route catalogs before rendering, and trigger background refresh when cached discovery is stale
- add /model refresh plus in-picker refresh via modelPicker:refresh and the r keybinding
- clear discovery cache on manual refresh and surface non-blocking loading/success/stale-error states in ModelPicker
- keep descriptor-backed dynamic and hybrid routes on the shared discovery cache service
Verification and hardening:
- fix combined test pollution by isolating /model test module imports and using real OpenRouter descriptor metadata during shared runs
- update progress.md to mark Phase 2C complete with verification notes
- verified with bun test for provider profiles, ProviderManager, /provider, /model, discovery cache, and provider validation suites
* feat: complete phase 2d runtime provider alignment
Align descriptor-backed runtime provider behavior with the legacy APIProvider surface so active routes, OpenAI shim behavior, and resume handling all resolve through the same metadata path.
Add runtimeMetadata.ts to centralize active route detection, OpenAI shim overrides, and native-format inference. Update provider resolution to map descriptor-backed routes onto legacy provider categories while preserving existing compatibility fallbacks for Foundry, NVIDIA NIM, MiniMax, GitHub, Bedrock, and Vertex.
Move request-shaping rules onto descriptor metadata for DeepSeek, Moonshot, Kimi Code, Gemini, Mistral, GitHub, and local gateways, including reasoning_content preservation, deepseek-compatible thinking payloads, max_tokens field selection, and store field stripping. Treat GitHub Claude native transport as Anthropic-native during conversation recovery so thinking blocks survive resume flows.
Extend focused tests for provider resolution, OpenAI shim request shaping, and conversation recovery, and update phase tracking notes in progress.md to mark 2D complete with verification details.
* feat: complete phase 2e drift audit
Complete the Phase 2E verification and drift-audit packet for the descriptor migration branch.
Add representative provider-summary coverage for descriptor-backed OpenRouter routing plus Gemini and Mistral current-provider summaries in src/commands/provider/provider.test.tsx. Extend ProviderManager coverage with first-run Atomic Chat discovery-backed setup and a regression test proving the set-active picker now uses descriptor-backed provider-type labels.
Replace stale saved-profile picker wording in ProviderManager so saved profiles no longer collapse to a coarse anthropic/openai-compatible split and instead render the route's descriptor-backed provider type label.
Add plan/phase-2e-drift-audit.md documenting the remaining intentional switch sites and non-switch provider branches across provider summaries, active-route detection, OpenAI shim env remapping, auth/header exceptions, and conversation recovery. Update plan/progress.md to mark Phase 2 and 2E complete on-branch, record focused verification, and note the follow-up hardening completed during audit review.
Verification completed during this packet: bun test src/components/ProviderManager.test.tsx src/commands/provider/provider.test.tsx src/utils/providerValidation.test.ts src/integrations/discoveryService.test.ts src/commands/model/model.test.tsx and bun test src/utils/providerDiscovery.test.ts src/utils/model/providers.test.ts src/services/api/openaiShim.test.ts src/utils/conversationRecovery.test.ts. Filtered typecheck output still shows pre-existing baseline noise in src/services/api/openaiShim.ts and src/utils/conversationRecovery.ts only.
* fix: close phase 2 provider parity follow-through
Complete the skipped provider-surface follow-up discovered during the post-Phase-2 review.
- add focused status coverage for NVIDIA NIM and MiniMax sessions
- add Mistral entries to legacy teammate/model compatibility configs
- fill deprecation placeholders for the widened APIProvider surface
- add focused regression tests for status and teammate fallbacks
- update the Phase 2 drift audit and progress tracker with the compatibility-bridge notes and Phase 3 staging context
* phase 3 planning
* refactor: start phase 3a dead-switch cleanup
Begin the Phase 3 cleanup pass with the metadata-only dead-switch removals that are safe to land independently on cheeky-cooking-moon.
Completed work:
- updated plan/progress.md to move Phase 3 and Phase 3A into IN_PROGRESS, added slice-level checklists, and recorded what remains intentionally deferred to later packets
- removed duplicated OpenAI-compatible status-display branches in src/utils/status.tsx by routing openai/codex/nvidia-nim/minimax through shared metadata helpers
- replaced the pure transport-kind label switch in src/integrations/routeMetadata.ts with shared label metadata
- replaced the pure provider-label switch in src/components/CostThresholdDialog.tsx with a shared provider-label map
- added focused regression coverage in src/utils/status.test.ts, src/integrations/routeMetadata.test.ts, and src/components/CostThresholdDialog.test.ts
Verification:
- bun test src/utils/status.test.ts src/utils/swarm/teammateModel.test.ts src/utils/model/providers.test.ts
- bun test src/integrations/routeMetadata.test.ts src/utils/status.test.ts src/components/CostThresholdDialog.test.ts src/utils/model/providers.test.ts
- filtered bun run typecheck for the touched status/routeMetadata/CostThresholdDialog files returned FILTER_CLEAN
* refactor: complete phase 3b and 3c cleanup
Complete the uncommitted Phase 3B compatibility rename work and the Phase 3C env-shaping consolidation on cheeky-cooking-moon.
Phase 3B:
- introduce LegacyAPIProvider while keeping APIProvider as the public compatibility alias
- introduce LegacyProviderModelConfig and LEGACY_PROVIDER_MODEL_CONFIGS while keeping ModelConfig and ALL_MODEL_CONFIGS as compatibility exports
- switch modelStrings, deprecation helpers, and provider profile compatibility naming onto the legacy/compatibility terminology
Phase 3C:
- add shared managed-env clear/apply helpers in providerProfile.ts and route buildLaunchEnv through the shared compatibility env shaper
- route applyProviderProfileToProcessEnv through the same compatibility env shaper so config-backed profiles and startup/session env construction stay aligned
- preserve explicit exception behavior for github, mistral, bedrock, vertex, bankr aliasing, MiniMax fallback detection, and NVIDIA NIM mode markers
- reduce createOpenAIShimClient to the remaining credential alias hydration that resolveProviderRequest does not already cover
- fix applySavedProfileToCurrentSession so saved-profile switching can move away from stale GitHub env selections
- add regression coverage for NVIDIA NIM env stamping and stale Codex-managed env clearing
- update progress.md to mark Phase 3B and 3C complete on branch and record the verification notes
Verification:
- bun test src/utils/model/providers.test.ts src/utils/providerProfiles.test.ts src/utils/swarm/teammateModel.test.ts src/utils/status.test.ts
- bun test src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts src/services/api/openaiShim.test.ts
- filtered bun run typecheck confirmed no new hits in providerProfile.ts or providerProfiles.ts; remaining openaiShim.ts hits are existing repo baseline debt
* docs: complete phase 3d audit and architecture note
Complete the Phase 3D final audit/documentation packet on cheeky-cooking-moon.
Work completed:
- add plan/phase-3d-final-audit.md with the final post-Phase-3 inventory of remaining provider-specific runtime branches
- classify the remaining exceptions as intentional long-term runtime differences or temporary env/config compatibility bridges
- confirm the audit did not uncover new missed runtime migration work that requires additional Phase 3 code changes
- add docs/architecture/integrations.md to document the descriptor-first architecture, current constraints, known exceptions, and follow-on guidance for future cleanup
- update plan/progress.md to mark Phase 3D complete on branch, mark 3C merged on branch, and point the tracker at Phase 4A next
Key exception categories documented:
- github dual-mode transport behavior
- mistral dedicated route/runtime shaping
- bedrock/vertex/foundry native Anthropic-family paths
- Azure and Bankr request-auth/header differences
- Gemini, DeepSeek, and Moonshot/Kimi OpenAI-shim quirks
- MiniMax dedicated usage handling
- native web-search gating
- env-only MiniMax and NVIDIA NIM compatibility fallbacks
- env/config compatibility bridges such as route detection, --provider shaping, and startup/provider summaries
Notes:
- this packet is branch-local audit/documentation work only; no runtime code paths were changed
- no new tests were required for the audit/doc pass
* docs: stage phase 4 tracker and codex profile guard
Add the Phase 4 documentation/reference-samples plan to progress.md in the same packet/checkpoint structure as earlier phases, and reconcile the Phase 3 tracker summary with the completed cleanup state. Also fix applySavedProfileToCurrentSession so Codex saved-profile activation does not overwrite an already explicit live provider selection, while still clearing stale profile-managed markers when needed.
* docs: complete phase 4a and 4b guides
Expand the integrations architecture note with descriptor authoring, routing-contract, transport-boundary, and compatibility-layer guidance. Add overview and glossary docs under docs/integrations/, plus new how-to guides for adding vendors and gateways with one-file and two-file patterns, discovery cache guidance, token-field guidance, and compatibility follow-through. Update progress.md to mark Phase 4 in progress, Phase 4A complete, and Phase 4B complete with notes about the new docs structure and guide outputs.
* docs: complete phase 4 integration docs
Add the remaining descriptor contributor guides for models, anthropic proxies, and /usage support.
Add a reference sample pack and a common-pitfalls checklist, update the integrations overview, and reconcile plan/progress.md so Phase 4 is marked complete on cheeky-cooking-moon with the current implementation boundaries called out explicitly.
* docs: reconcile tracker waivers and checkpoints
Update plan/progress.md to formally waive the remaining repo-wide typecheck item for Phase 1F as pre-existing debt outside the descriptor migration scope, and mark the Phase 4 branch-local checkpoints as landed on cheeky-cooking-moon with the corresponding commit references.
* Align Z.AI merge fallout with descriptors
Reviewed the upstream main merge against plan/cheeky-cooking-moon.md and removed drift from the old switch/helper-based Z.AI provider path.
Moved Z.AI reasoning, context-window, and max-output metadata into the descriptor route catalog so thinking support can read catalog capabilities instead of URL/model helper checks.
Removed the standalone src/utils/zaiProvider.ts helper and updated startup/provider-discovery labeling to resolve known direct routes through descriptor route metadata.
Simplified --provider handling for Z.AI by letting descriptor defaults provide the base URL and default model through the generic OpenAI-compatible provider branch.
Updated startup and provider-discovery tests for descriptor-backed labels, added Z.AI descriptor-label coverage, and documented the post-main-merge reconciliation in plan/progress.md.
Verification before commit: bun test src/utils/providerFlag.test.ts src/utils/providerProfiles.test.ts src/utils/thinking.test.ts src/components/StartupScreen.test.ts src/utils/providerDiscovery.test.ts; bun test src/integrations/compatibility.test.ts src/integrations/index.test.ts src/integrations/registry.test.ts src/services/api/openaiShim.test.ts; git diff --check.
* fix: restore descriptor migration behavior and isolate provider tests
Restore the descriptor-era Anthropic/OpenAI boundary during conversation recovery by threading the legacy provider category into usesAnthropicNativeMessageFormat instead of relying on ambient env-only route detection.
Harden branch-added provider-facing tests so they do not inherit leaked bun mock.module state from neighboring suites. Status, thinking, teammate fallback, and GitHub model options tests now restore mocks and/or import fresh modules under explicit provider context.
Update bugfix assertions to validate the descriptor-backed openaiShim contract for removeBodyFields/store stripping instead of the pre-refactor inline conditionals.
Validation:
- focused status/thinking/conversationRecovery/bugfix suites pass
- full bun test --max-concurrency=1 is down to the existing conversationArc perf benchmark failure only
- bun run smoke
- bun run build
- npm pack
* fix: close descriptor review drift and provider regressions
Address the follow-up review against plan/cheeky-cooking-moon.md by fixing the remaining runtime drift and locking the behavior with focused coverage.
Completed work:
- make NVIDIA NIM descriptor-backed auth consistent across validation, --provider env shaping, and openaiShim request auth so NVIDIA_API_KEY works without requiring OPENAI_API_KEY
- resolve /usage from the active descriptor route instead of collapsing most OpenAI-compatible providers into the legacy openai bucket
- honor discoveryRefreshMode in /model so manual, on-open, background-if-stale, and startup catalogs no longer behave identically
- clarify docs/progress notes so the branch no longer overstates one-file additive onboarding while loader and preset/UI compatibility surfaces are still manual
Verification:
- bun test src/services/api/openaiShim.test.ts src/utils/providerValidation.test.ts src/utils/providerFlag.test.ts src/utils/model/providers.test.ts src/commands/usage/index.test.ts src/commands/model/model.test.tsx
* docs(plan): require descriptor-native gateway onboarding closure
Investigated the current descriptor onboarding flow and documented the remaining manual choke points in the loader, preset compatibility mapping, provider UI metadata, and handwritten preset typing.
Tighten cheeky-cooking-moon so additive onboarding is a hard requirement, add Phase 3E for descriptor-native onboarding closure, and update the progress tracker to reflect that follow-up work instead of treating the branch as fully complete.
* feat(integrations): close descriptor-native onboarding
Implement the Phase 3E generated-artifact workflow for integration onboarding.
- add integration artifact generation and check scripts
- generate loader inventory, preset manifest, and preset type from descriptors
- move preset participation onto descriptor preset metadata for preset-facing vendors and gateways
- derive compatibility and provider UI metadata from the generated manifest
- remove descriptor-level preset ordering and sort presets by description with standard alphanumeric ordering
- pin the custom preset to the bottom automatically in generated ordering
- add validation for duplicate preset ids and incomplete preset metadata
- add generator tests for representative gateway and direct-vendor onboarding
- refresh ProviderManager tests for generated preset ordering
- update architecture/how-to/reference docs and progress tracking for the new regeneration workflow
* Fix provider profile and discovery drift
Honor route-specific auth env vars across descriptor-backed OpenAI-compatible routes by centralizing credential resolution and using it in validation, bootstrap, discovery, and the OpenAI shim.
Persist Anthropic startup fallbacks as native anthropic profiles and restore them correctly at startup so the legacy startup file stays aligned with the active provider.
Wire discoveryRefreshMode='startup' into startup and provider activation flows, with LM Studio as a live startup-refresh example, and add regression coverage for validation, startup env shaping, discovery refresh, and shim auth handling.
* Pin Anthropic provider preset to the top
Keep the existing custom gateway preset pinned to the bottom while moving the Anthropic preset ahead of the description-sorted remainder.
Regenerate the integration preset manifest/order and extend the artifact generator coverage to lock in both ordering rules.
Validation: bun test src/integrations/artifactGenerator.test.ts src/components/ConsoleOAuthFlow.test.tsx; bun run build
* docs: refresh integration and setup guides
Update the new descriptor-era integration docs so they read as current contributor guidance instead of rollout notes, and align the authoring examples with the actual runtime metadata flow.
Highlights:
- add a CONTRIBUTING.md pointer to the integration overview and focused how-to guides
- remove branch/phase-specific wording from the integration docs
- fix OpenAI-compatible header guidance to use transportConfig.openaiShim headers and custom-header flags
- clarify anthropic proxy onboarding around generated loader support
- refresh advanced setup with current Codex, Gemini, Mistral, and profile-launch details
- fix LiteLLM /provider instructions and clarify local no-auth behavior
- tighten quick-start and non-technical cross-links so users can find the advanced provider docs
* fix: close descriptor integration drift
Apply descriptor-backed static headers to OpenAI-compatible request execution and model discovery, preserving request-specific header precedence.
Allow Gemini profile launch with API key, access-token, or ADC credentials, and align Gemini fallback defaults with the descriptor/docs default model.
Add regression coverage for descriptor header propagation, Gemini defaults, and discovery auth/header behavior.
* post-phase follow-up task added
* Fix xAI merge follow-ups
Route env-only XAI_API_KEY sessions through the OpenAI-compatible shim using descriptor-backed xAI defaults, and map the xAI key into OPENAI_API_KEY for shim auth.
Hydrate legacy profile: xai startup env with xAI descriptor defaults, preserving XAI_API_KEY and OpenAI-compatible launch behavior.
Update progress tracking for post-merge xAI descriptor inventory and clarify that profile-owned custom headers remain open despite adjacent auth/static-header plumbing.
Add regression coverage for env-only xAI client routing, legacy xAI launch env, shell key precedence, and the Gemini/OpenAI client test isolation issue.
* Complete profile custom headers follow-up
Add persisted provider-profile customHeaders support with shared parsing and sanitization for compact Name: value input. Reject malformed and reserved auth/internal headers before saving or applying profile-owned headers.
Expose a descriptor-gated /provider custom headers step, preserve headers during profile edit/update, and apply supported profile headers through ANTHROPIC_CUSTOM_HEADERS for active env and startup fallback profiles.
Propagate profile headers into descriptor discovery refresh and bootstrap model discovery while preserving descriptor/profile/auth merge order. Add focused regression coverage and mark the progress tracker packet complete.
* Allow api-key custom provider headers
Permit api-key in /provider custom header input and preserve it when OpenAI-compatible shim requests are built. This is intentional for gateway providers that require an api-key header in addition to, or instead of, standard bearer auth.
Keep managed credential headers protected by continuing to reject/strip authorization and x-api-key, plus Anthropic/Claude-owned headers. Add parser, profile env, and outgoing request coverage for the intended behavior.
* fix: restore API mode picker for OpenAI-compatible profiles
Use descriptor transport metadata instead of the legacy provider id when deciding whether provider profiles support OpenAI-compatible options. This restores the Chat Completions vs Responses picker for the Custom OpenAI-compatible preset after it moved to the descriptor-backed custom route.
Preserve apiFormat and custom auth header profile fields for all routes whose transportConfig.kind is openai-compatible, so selecting Responses is saved and applied as OPENAI_API_FORMAT=responses.
Tests: bun test src/components/ProviderManager.test.tsx; bun test src/utils/providerProfiles.test.ts; bun run build; bun run smoke
* fix: respect explicit provider routing with xAI env
Ensure env-only XAI_API_KEY fallback does not take over when Bedrock, Vertex, or Foundry has been explicitly selected. This preserves native transport routing while still allowing bare xAI env setup to use the OpenAI-compatible shim.
Restore api-key to the managed custom-header blocklist now that /provider exposes the API mode/auth-header controls for OpenAI-compatible profiles. The shim and provider override paths strip api-key again, while OPENAI_AUTH_HEADER=api-key remains available for explicit auth configuration.
Tests: bun test src/services/api/client.test.ts src/utils/providerCustomHeaders.test.ts src/utils/providerProfiles.test.ts src/services/api/openaiShim.test.ts; bun run build; bun run integrations:check; bun run smoke
* docs: fix integration drift
Align integration and setup docs with the current implementation.
- show model descriptor examples as array default exports, matching the generated MODEL_DESCRIPTOR_GROUPS loader contract
- document provider-scoped model env vars instead of implying OPENAI_MODEL globally overrides ANTHROPIC_MODEL
- clarify generated provider preset ordering: anthropic first, custom last, description-sorted middle entries
- update LiteLLM examples and /provider guidance to use the /v1 OpenAI-compatible base URL
Verification: bun run integrations:check
* Fix provider discovery cache isolation
* Stabilize provider env tests
* Stabilize provider test isolation
Completed work:
- Isolated GitHub model option tests from cached availableModels settings.
- Isolated startup discovery tests from live process.env provider flag races.
- Mocked teammate provider fallback tests at the provider helper boundary.
- Moved cost threshold provider labels into a pure helper for deterministic tests while preserving runtime active-provider behavior.
Validation:
- bun test src/components/CostThresholdDialog.test.ts src/integrations/discoveryService.test.ts src/utils/model src/utils/swarm
- bun run build
- bun run smoke
* test: isolate startup screen model settings
Clear the session settings cache and persisted global model around StartupScreen provider-detection tests.
This prevents earlier provider/model suites from leaking saved non-Anthropic models into the default Anthropic startup assertions.
Verified with: bun test src/components/StartupScreen.test.ts src/integrations/discoveryService.test.ts src/utils/model/modelOptions.github.test.ts
Full bun test now only fails the unrelated Conversation Arc sub-millisecond performance benchmark.
* test: isolate route discovery and github model options
Restore Bun module mocks around discoveryService tests before loading fresh route-discovery modules.
Pin the GitHub model-options test to a complete providers.js mock so cached provider mocks from other suites cannot hide Copilot options.
Verified with: bun test src/integrations/discoveryService.test.ts src/utils/model/modelOptions.github.test.ts
Also ran full bun test; only the unrelated Conversation Arc sub-millisecond performance benchmark fails locally.
* test: avoid startup discovery cache collision
Use the 127.0.0.1 LM Studio alias in refreshStartupDiscoveryForActiveRoute so it still resolves the active route from env but does not share the cache partition with the preceding startup refresh test.
This keeps the assertion on network refresh stable under Bun 1.3.11 serialized runs.
Verified with: bun test --max-concurrency=1 src/integrations/discoveryService.test.ts src/utils/model/modelOptions.github.test.ts
Also ran full bun test --max-concurrency=1; only the unrelated Conversation Arc perf benchmark fails locally.
* fix: isolate OpenAI-compatible route credentials
Restrict OpenAI-compatible shim auth to provider overrides, resolved route credentials, or explicit OPENAI_API_KEY instead of ambient provider-specific secrets.
Remove NVIDIA and Bankr compatibility fallbacks that could promote provider-specific API keys into unrelated OpenAI-compatible routes. Preserve Bankr base URL/model compatibility before route credential resolution so Bankr still resolves through descriptor credentials.
Clear stale NVIDIA_NIM and copied OPENAI_API_KEY values when switching away from NVIDIA NIM, Bankr, or xAI provider flags to avoid carrying provider secrets across route boundaries.
Add regressions for stale NVIDIA, MiniMax, and Bankr keys not leaking into OpenRouter-style routes, plus provider-flag cleanup for copied NVIDIA/Bankr/xAI keys.
Validation: bun test src/services/api/openaiShim.test.ts; bun test src/utils/providerFlag.test.ts; bun run build; bun run smoke.
* fix: guard model discovery privacy paths
Suppress descriptor and legacy model discovery while essential-only traffic mode is active.
Use the partitioned discovery cache key for /model cache reads, stale checks, and manual refresh clears, including route-specific credentials and custom headers.
Partition legacy local OpenAI additional model caches by credentials and routing headers to avoid catalog reuse across profiles.
Add coverage for OpenRouter route credentials, descriptor privacy suppression, legacy discovery privacy suppression, and local cache scope partitioning.
* Fix artifact checks and knowledge graph persistence
Normalize generated integration artifact comparisons so Windows line endings do not make checked-in artifacts appear stale.
Skip knowledge graph entity persistence when re-adding an existing entity with identical attributes, avoiding repeated disk writes during automatic fact extraction and restoring the conversation arc performance benchmark.
Verified with bun test src/integrations/artifactGenerator.test.ts --max-concurrency=1, bun test src/utils/conversationArc.perf.test.ts --max-concurrency=1, and bun test --max-concurrency=1.
* test: isolate privacy discovery cache path
The descriptor discovery privacy test could observe stale OpenRouter cache data populated by an earlier test and receive source=stale-cache instead of static. Use a test-specific API key so the privacy assertion gets its own discovery cache partition while still verifying that nonessential traffic disables network discovery.
Verified with bun test src/integrations/discoveryService.test.ts --max-concurrency=1 and bun test --max-concurrency=1.
* test: accept cached privacy discovery result
* test: set privacy gate before discovery import
* test: prevent discovery privacy mock bleed
Guard descriptor model discovery directly on CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC so nonessential traffic stays disabled even if the privacyLevel module is mocked in-process.
Reduce broad fastMode test mocks for shared modules and use real state/config test hooks, preventing Bun module mock namespaces from leaking into discovery and /model tests.
Verified with bun test src/utils/fastMode.test.ts src/utils/model/openaiModelDiscovery.test.ts src/integrations/discoveryService.test.ts src/commands/model/model.test.tsx --max-concurrency=1 and bun test --max-concurrency=1.
* test: prevent discovery privacy mock bleed
Add an env-level fallback guard to descriptor model discovery so disabled nonessential traffic cannot be bypassed by stale mocked privacy helpers.
Tighten the fastMode regression tests by setting real bootstrap/config state only after the tested module is imported, avoiding broad module mocks that can leak into unrelated discovery tests or behave differently under Bun in CI.
Verified with focused discovery/fastMode/model suites and the full serial bun test suite.
* fix: harden fast mode test isolation
Ignore non-string GrowthBook values when resolving the fast mode unavailable reason so boolean flag payloads cannot surface as false.
Make the affected regression tests install explicit provider mocks for their own scenarios and reset env state, preventing stale provider mocks from changing fastMode and conversation recovery behavior across the serial Bun test run.
* test: harden fast mode module mocks
Expand the fastMode GrowthBook and provider test mocks so later imports in the same Bun test process can resolve the named exports they expect. This prevents order-sensitive failures when model command tests run after fast mode tests.\n\nVerified with: bun test --max-concurrency=1
* feat: consolidate integration runtime metadata
Move OpenAI-compatible model runtime limits into descriptor-backed brand and model metadata, adding Gemini, GLM, MiniMax, Mistral, Nemotron, xAI, and OpenAI-compatible alias descriptor groups. Update generated integration artifacts, route catalog option handling, thinking capability lookup, and docs to use modelDescriptorId-backed runtime metadata.
Split OpenAI shim capability flags into supportsApiFormatSelection and supportsAuthHeaders, and update provider profile sanitization, ProviderManager forms, descriptor validation, and integration authoring docs so fixed routes do not preserve unsupported API format or auth-header settings.
Harden env-only MiniMax and xAI routing. Resolve shared route intent before client setup, reject conflicting OpenAI base URLs, preserve provider-specific base overrides, sanitize stale OpenAI shim knobs, copy provider credentials intentionally, and keep legacy provider labels, context windows, max output limits, model lists, and provider switching aligned.
Refresh MiniMax defaults and catalog entries, add descriptor-backed runtime limits for migrated models, preserve external OpenAI limit overrides, and add regression coverage for env-only MiniMax/xAI, provider-profile capability stripping, route catalog options, copied credential cleanup, and context/runtime limit detection.
Verification performed: bun test src/utils/providerFlag.test.ts; bun test src/services/api/client.test.ts src/utils/model/providers.test.ts src/integrations/routeMetadata.test.ts; bun test src/utils/context.test.ts src/utils/thinking.test.ts src/services/compact/autoCompact.test.ts; bun test src/integrations/routeMetadata.test.ts src/services/api/client.test.ts src/utils/model/providers.test.ts src/utils/providerValidation.test.ts src/integrations/index.test.ts src/utils/status.test.ts; bun run build; bun run smoke.
* test: isolate provider env in conversation recovery
Snapshot and restore all provider-selection environment variables used by the GitHub native Claude resume test instead of only restoring the GitHub flag and OPENAI_MODEL.
The full single-concurrency suite exposed that earlier tests can leave higher-priority provider flags in process.env, causing deserializeMessages to resolve a non-GitHub provider and strip thinking blocks even though the test intended to exercise GitHub native Claude transport.
The test now clears provider routing env before setting CLAUDE_CODE_USE_GITHUB=1 and OPENAI_MODEL=claude-sonnet-4-6, then restores the original env values in afterEach.
Verification: bun test src/utils/conversationRecovery.test.ts; bun test --max-concurrency=1.
* test: isolate conversation recovery provider state
* test: pin conversation recovery provider mock
* test: isolate knowledge graph persistence
* fix: make knowledge graph reset synchronous
* test: restore integration registry after unit tests
* remove plans dir
* delete plans
* Fix provider routing test failures
Restore the missing first-party Anthropic auth routing imports used by getAnthropicClient so OpenAI-compatible provider client creation no longer throws at runtime.
Keep GitHub provider resolution from inheriting OPENAI_API_FORMAT=responses so GitHub GPT-4 and gpt-5-mini models continue to use chat completions while Codex-flavored models still route to responses.
Reset OPENAI_API_FORMAT in the affected API provider tests to prevent environment leakage across serial Bun test runs.
Verified with: bun test --max-concurrency=1
* fix: restore provider-specific model routing
Resolve generic OpenAI-compatible profiles by their known descriptor base URLs so saved MiniMax, xAI, NVIDIA NIM, OpenRouter, and DeepSeek profiles use the correct route catalogs instead of the generic OpenAI model list.
Fix MiniMax defaults and display handling so provider-specific model IDs are not rendered as Claude Opus defaults, add current MiniMax M2.7 options, and cover the regressions with focused route/model tests.
Also clean up descriptor follow-ups from review: remove the dead OpenAI shim store-strip fallback list, preserve gateway vendor IDs for Bedrock/Vertex/GitHub profile resolution, and keep the ModelPicker compiled-form changes in this PR.
* test: cover provider precedence review fixes
Remove import-time ANTHROPIC_BASE_URL and ANTHROPIC_MODEL reads from the Anthropic descriptor so descriptor defaults stay static and live env handling remains in preset metadata.
Add getAPIProvider precedence coverage documenting that explicit Gemini/OpenAI flags beat env-only MiniMax API key inference.
Add a regression check to keep the removed openaiShim hardcoded descriptor route fallback list from returning.
---------
Co-authored-by: TechBrewBoss <dash@hicap.ai>
* feat(web): openclaude landing — runs anywhere, uses anything
A new marketing site for openclaude under web/, plus the minimal root
infrastructure to build, ignore, and gate it without affecting the
published npm package.
Landing page (web/)
- Vite + React 19 with monospace gitlawb typography (sf mono / fira code).
- Hero: pill, two-line wordmark "runs anywhere. / uses anything.",
copy-to-clipboard install command, github cta.
- Six feature rows in hermes-style "title — sentence" format on hairline
dividers (any model, real tools, profiles per repo, streaming,
gateway routing, editor + server modes).
- Install block: same copyable command + three numbered steps.
- One-line footer with brand, version, gitlawb link, and license.
- Light theme is the default with a no-flash bootstrap script and a
☀ / ☾ toggle persisted to localStorage.
- New orange terminal-face logo at 36px in the nav.
- Body wash: dual orange radial gradients for warmth on both themes.
Root infra
- web/ excluded from npm publish via .npmignore (belt-and-suspenders
alongside the existing files whitelist).
- web/ excluded from docker context (.dockerignore).
- web:dev / web:build / web:preview / web:typecheck scripts in
package.json that delegate via --cwd web (no root deps added).
- web typecheck + build added to the pr-checks workflow.
- web/dist/ and web/*.tsbuildinfo ignored.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
* added vercel in .gitignore
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
The vendored-binary lookup at vendor/ripgrep/<arch>-<platform>/rg never
resolved in this fork — that directory does not ship — so users without
a system rg had no working fallback. Switch to the @vscode/ripgrep
package so Microsoft maintains the platform/arch matrix and the binary
is delivered via npm.
- src/utils/ripgrep.ts: replace hand-rolled vendor-path resolution with
rgPath from @vscode/ripgrep. Lazy require so a missing package falls
through to the system rg branch instead of throwing at import.
Drop builtinExists from the config args; builtinCommand is now a
string-or-null. The system override (USE_BUILTIN_RIPGREP=0), the
Bun-compiled standalone embedded mode, the macOS codesign hook, and
all retry/timeout/error logic are preserved untouched.
- scripts/build.ts: mark @vscode/ripgrep as external. The package
resolves rgPath via __dirname at runtime, so bundling would freeze
the build host's absolute path into dist/cli.mjs.
- src/utils/ripgrep.test.ts: update for the new config shape and add
tests covering USE_BUILTIN_RIPGREP=0, embedded mode, last-resort
fallback, and null builtin path.
Tested locally on Linux (Bun 1.3.13). macOS (codesign hook) and
Windows (rg.exe extension) need contributor verification.
* chore: rebrand user-facing copy to OpenClaude
Replace lingering Claude Code branding in CLI, tips, and runtime UI with OpenClaude/openclaude, including the startup tip Gitlawb mention.
Co-Authored-By: Claude GPT-5.4 <noreply@openclaude.dev>
* chore: address branding-sweep review feedback
- PermissionRequest.tsx: rebrand the two remaining "Claude needs your
approval/permission" notifications to OpenClaude (review-artifact and
generic tool permission paths).
- main.tsx, teleport.tsx, session.tsx, WebFetchTool/utils.ts,
skills/bundled/{debug,updateConfig}.ts: replace leftover `claude --…`
CLI hints and "Claude Code" labels missed by the original sweep.
- main.tsx: drop the inline gitlawb.com marketing copy from the
stale-prompt tip; keep it a pure rebrand.
- auth.ts: finish the half-rename so both `claude setup-token` and
`claude auth login` references in the same error block now read
`openclaude …`.
- mcp/client.ts: keep `name: 'claude-code'` for MCP server allowlist
compatibility (now explicit via comment) and replace the
"Anthropic's agentic coding tool" description with an OpenClaude one.
- MCPSettings.tsx: point the empty-server-list hint at
https://github.com/Gitlawb/openclaude instead of code.claude.com.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: replace help link with OpenClaude repo URL
Replace https://code.claude.com/docs/en/overview with
https://github.com/Gitlawb/openclaude in the help screen.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
---------
Co-authored-by: Claude GPT-5.4 <noreply@openclaude.dev>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
* gRPC Server
* gRPC fix
* UpdProto
* fix: address PR review feedback for gRPC server
- Update bun.lock for new dependencies (frozen-lockfile CI fix)
- Add multi-turn session persistence via initialMessages
- Replace hardcoded done payload with real token counts
- Default bind to localhost instead of 0.0.0.0
* fix(grpc): startup parity, cancel interrupt, and cli text fallback
- Replace enableConfigs() with await init() in start-grpc.ts for full
bootstrap parity with the main CLI (env vars, CA certs, mTLS, proxy,
OAuth, Windows shell)
- Call engine.interrupt() before call.end() in the cancel handler so
in-flight model/tool execution is actually stopped
- Show done.full_text in the CLI client when no text_chunk was received,
preventing silent drops when streaming is unavailable
* fix(grpc): wire session_id end-to-end and remove dead provider field
- Move session_id from ClientMessage into ChatRequest to fix proto-loader
oneofs encoding bug and make the field functional
- Implement in-memory session store so reconnecting with the same
session_id resumes conversation context across streams
- Remove ChatRequest.provider — per-request provider routing requires
global process.env mutation, unsafe for concurrent clients; provider
is configured via env vars at server startup
* fix(grpc): mirror CLI auth bootstrap in start-grpc and fix tool_name field
scripts/start-grpc.ts now runs the same provider/auth bootstrap as the
normal CLI entrypoint: enableConfigs, safe env vars, Gemini/GitHub token
hydration, saved-profile resolution with warn-and-fallback, and provider
validation before the server binds.
ToolCallResult.tool_name was being populated with the tool_use_id UUID.
Added a toolNameById map (filled in canUseTool) so tool_name now carries
the actual tool name (e.g. "Bash"). The UUID moves to a new tool_use_id
field (proto field 4) for client-side correlation.
* fix(grpc): add tool_use_id to ToolCallStart and interrupt engine on stream close
Two blocker-level issues flagged in code review:
- ToolCallStart was missing tool_use_id, making it impossible for clients
to correlate tool_start events with tool_result when the same tool runs
multiple times. Added tool_use_id = 3 to the proto message and populated
it from the toolUseID parameter in canUseTool.
- On stream close without an explicit CancelSignal the server only nulled
the engine reference, leaving the underlying model/tool work running
as an orphan. Added engine.interrupt() in the call.on('end') handler
to stop work immediately when the client disconnects.
* fix(grpc): resolve pending promises on disconnect and guard post-cancel writes
Four lifecycle and contract issues identified during proactive review:
- Pending permission Promises in canUseTool would hang forever if the
client disconnected mid-stream. On call 'end', all pending resolvers
are now called with 'no' so the engine can unblock and terminate.
- The done message and session save could fire after call.end() when
a CancelSignal arrived mid-generation. Added an `interrupted` flag
set on both cancel and stream close to gate all post-loop writes.
- The session map had no eviction policy, allowing unbounded memory
growth. Capped at MAX_SESSIONS=1000 with FIFO eviction of the
oldest entry.
- Field 3 was silently absent from ChatRequest. Added `reserved 3`
to document the gap and prevent accidental reuse in future.
* fix(grpc): reset previousMessages on each new request to prevent session history leak
previousMessages was declared at stream scope and only overwritten when
the incoming session_id already existed in the session store. A second
request on the same stream with a new session_id would silently inherit
the first request's conversation history in initialMessages instead of
starting fresh, violating the session contract.
Fix: reset previousMessages to [] at the start of each ChatRequest
before the session-store lookup.
* fix(grpc): reset interrupted flag between requests and guard against concurrent ChatRequest
Two stream-scoped state bugs found during proactive audit:
- The `interrupted` flag was never reset between requests on the same
stream. If the first request was cancelled, all subsequent requests
would silently skip the done message, causing the client to hang.
- A second ChatRequest arriving while the first was still processing
would overwrite the engine reference, corrupting the lifecycle of
both requests. Now returns ALREADY_EXISTS error instead. Engine is
nulled after the for-await loop completes so subsequent requests
can proceed normally.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* security: force lodash-es 4.18.0 for transitive dependencies
PR #225 bumped the direct lodash-es dependency to 4.18.0, but
@anthropic-ai/sandbox-runtime still pulled lodash-es@4.17.23 via its
own ^4.17.23 range. The transitive copy was vulnerable to:
- HIGH: Code Injection via _.template (GHSA-r5fr-rjxr-66jc)
- MODERATE: Prototype Pollution via _.unset/_.omit (GHSA-f23m-r3pf-42rh)
Added overrides field in package.json to force all copies to 4.18.0.
bun audit now reports zero vulnerabilities.
* fix: use lodash-es 4.18.1 instead of deprecated 4.18.0
lodash-es 4.18.0 is explicitly deprecated by the maintainer with
the message "Bad release. Please use lodash-es@4.17.23 instead."
Updated both the direct dependency and the override to 4.18.1, which
is the latest non-deprecated release that patches the CVEs.
* 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
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).
- Introduced a new provider profile for Atomic Chat, allowing it to be used alongside existing providers.
- Updated `package.json` to include a new development script for launching Atomic Chat.
- Modified `smart_router.py` to recognize Atomic Chat as a local provider that does not require an API key.
- Enhanced provider discovery and launch scripts to handle Atomic Chat, including model listing and connection checks.
- Added tests to ensure proper environment setup and behavior for Atomic Chat profiles.
This update expands the functionality of the application to support local LLMs via Atomic Chat, improving versatility for users.
Removes caret (^) ranges from all 74 dependencies in package.json,
locking each to the exact version resolved in bun.lock.
Motivation: the axios supply chain attack of March 31 2026 demonstrated
that caret ranges are a live attack vector. axios@^1.14.0 would have
resolved to the trojanized 1.14.1 (bundled plain-crypto-js RAT, C2
sfrclak.com). Both 1.14.1 and 0.30.4 were unpublished within 24h.
Key pins:
axios ^1.14.0 → 1.14.0 (trojanized 1.14.1 blocked)
undici ^7.3.0 → 7.24.6 (7 CVEs between 7.3 and 7.24)
yaml ^2.7.0 → 2.8.3 (CVE-2026-33532 fix)
ajv ^8.17.0 → 8.18.0 (ReDoS fix)
lodash-es ^4.17.21 → 4.17.23 (prototype pollution fix)
zod ^3.24.0 → 3.25.76 (large range locked)
All 74 deps verified: integrity hashes match npm registry, no known
supply chain incidents, no postinstall scripts in lockfile.