Load the authenticated Codex model catalog with a bundled fallback and carry model-native reasoning effort through the OpenAI OAuth transport. Keep desktop effort choices aligned with each model's advertised capabilities.
Constraint: Ultra remains a composite Codex delegation mode and is not exposed as a wire-level effort.
Confidence: high
Scope-risk: moderate
Tested: bun run check:server; bun run check:desktop; bun run check:persistence-upgrade; focused OAuth, WebSocket, and browser smoke checks
Not-tested: bun run verify
Desktop reasoning effort now follows the selected session runtime instead of the General settings surface. Session metadata records provider, model, and effort so reconnects and prewarm restarts preserve the per-session runtime, while the default effort is max for new sessions.
Constraint: Existing transcript and localStorage runtime data must remain readable without a required migration.
Rejected: Keep effort as a General setting | it made one session change leak into every other session.
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce global desktop effort controls without proving multi-session isolation.
Tested: bun run check:server
Tested: bun run check:desktop
Tested: bun run check:native
Tested: bun run check:policy
Tested: bun run check:coverage
Tested: cd desktop && bun run test -- src/components/controls/ModelSelector.test.tsx src/stores/chatStore.test.ts
Tested: bun test src/server/__tests__/settings.test.ts --test-name-pattern "effort"
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "runtime"
Not-tested: Live provider smoke for domestic providers without local credentials.
Local main added desktop branch-from-chat, attribution headers, sidecar packaging changes, and provider model normalization. The merge keeps those mainline changes while preserving ChatGPT Official provider metadata, OpenAI OAuth runtime env, provider-load guards, and model catalog behavior.
Constraint: Current worktree was detached; created feat/chatgpt-official-oauth-provider before merging to preserve the OAuth commit line.
Rejected: Rebase the OAuth line over main | the branch already contains many reviewed commits and a merge makes the integration point explicit.
Confidence: high
Scope-risk: moderate
Tested: bun test src/server/__tests__/providers.test.ts src/server/__tests__/settings.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/proxy-transform.test.ts src/utils/__tests__/providerManagedEnvCompat.test.ts src/services/api/client.test.ts src/services/openaiAuth/fetch.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts
Tested: cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx src/components/settings/ChatGPTOfficialLogin.test.tsx src/stores/providerStore.test.ts src/components/controls/ModelSelector.test.tsx --testNamePattern "ChatGPT|OpenAI OAuth|Providers tab|ChatGPTOfficialLogin|ModelSelector|providerStore"
Tested: git diff --cached --check
Provider-managed environments should preserve Claude attribution only when the selected model is actually Claude-prefixed. Non-Claude provider models now disable the attribution header so third-party providers do not inherit Claude-specific prompt metadata.
Constraint: Claude model detection is intentionally model-name based to match the requested provider policy.
Rejected: Remove attribution headers globally | official Claude-prefixed models should keep existing behavior.
Confidence: high
Scope-risk: moderate
Directive: Do not broaden this policy without live provider request-shape verification.
Tested: Targeted server, provider, settings, cron, and managed-env tests in prior verification pass.
Not-tested: Full verify gate after this commit.
When ChatGPT Official is active, the model API now returns the OpenAI Codex catalog and reads or writes the selected GPT model from cc-haha managed settings. Desktop provider activation also recognizes the built-in provider id and resets the current model to the OpenAI default instead of looking for a saved provider record.
Constraint: ChatGPT Official is a built-in provider and is not present in providers.json providers[].
Rejected: Reuse the four-slot provider model list | it hides GPT-5.5 and misrepresents the OpenAI catalog as Anthropic slot names.
Confidence: high
Scope-risk: moderate
Tested: bun test src/server/__tests__/settings.test.ts
Tested: bun test src/server/__tests__/providers.test.ts --test-name-pattern "ChatGPT Official|getProviderForProxy"
Tested: bun test src/server/__tests__/conversation-service.test.ts --test-name-pattern "ChatGPT Official|session-scoped provider"
Tested: cd desktop && bun run test src/stores/providerStore.test.ts
Tested: git diff --check
Desktop users can carry provider indexes, managed settings, localStorage state, and native update state from builds that no longer match current readers. This adds startup migrations and recovery paths before server and React state are consumed, plus a persistence upgrade gate so future storage protocol changes ship with old-format fixtures.
Constraint: Existing installs may contain malformed or legacy JSON/localStorage that must not block startup.
Constraint: Local verify should evaluate the current worktree diff rather than unrelated detached-worktree history.
Rejected: Treat invalid persisted state as fatal | reproduces white-screen and startup failure behavior for existing users.
Rejected: Bypass PR policy locally | hides real gate behavior and does not fix detached-worktree false positives.
Confidence: high
Scope-risk: moderate
Directive: Any local JSON, localStorage, or app config shape change must add a migration fixture and keep `bun run check:persistence-upgrade` green.
Tested: bun run check:persistence-upgrade; bun run check:policy; bun run check:desktop; bun run check:server; bun run check:native; bun run verify (9 passed, 1 coverage baseline failure)
Not-tested: Live provider baseline; existing user configs beyond covered fixtures
The desktop provider flow was still mixing provider-managed state with
`~/.claude/settings.json`, which let unrelated tools leak fields like
`ANTHROPIC_REASONING_MODEL` and `model` back into the active provider path.
This change moves the provider JSON editor onto `~/.claude/cc-haha/settings.json`,
routes provider settings through dedicated `/api/providers/settings` endpoints,
and makes model reads/writes under an active provider use the managed cc-haha
settings instead of the global user settings file.
Constraint: Active provider model selection must be isolated from legacy ~/.claude/settings.json
Rejected: Keep merging provider JSON with settingsApi.getUser() | external tools can reintroduce unrelated model fields into the provider flow
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Any future provider-model UI or runtime change should read/write cc-haha managed settings first, not the global user settings file
Tested: bun test src/server/__tests__/provider-presets.test.ts src/server/__tests__/settings.test.ts; cd desktop && bun run lint
Not-tested: Manual desktop provider modal interaction after the cc-haha settings API switch
Desktop-managed sessions were blocking the first visible token on slow or failing
regular MCP connections, which made the UI feel much slower than direct bin runs.
This keeps partial assistant streaming enabled for desktop sessions and moves
regular MCP connection work off the critical path only for sdk-url startup.
Constraint: Desktop sdk-url sessions must preserve chat responsiveness even when local MCP endpoints fail or hang
Rejected: Leave MCP startup fully blocking in sdk-url mode | first visible token stayed several seconds behind direct CLI runs
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep blocking MCP startup for plain -p sessions unless you re-measure first-turn latency and tool availability tradeoffs
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/conversations.test.ts; same-prompt timing comparison for direct bin vs sdk-url session path
Not-tested: Immediate first-turn availability of slow regular MCP tools in desktop sdk-url sessions
When a custom provider (e.g. MiniMax) is activated, settings.model still
contains the old Anthropic model ID. handleCurrentModel was returning this
raw ID as the model name instead of the provider's configured model.
Fix handleCurrentModel to use ANTHROPIC_MODEL from env (set by
syncToSettings when provider was activated) when no explicit model is
set. Also fix getRuntimeSettings to skip passing --model to CLI when a
provider is active and model is still the default — the CLI should read
ANTHROPIC_MODEL from env instead of receiving a wrong model ID override.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace getActiveProvider() calls with listProviders() + activeId lookup
- Convert ModelMapping to model list for API compatibility
- Widen provider form dialog from 600px to 720px
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement a full Provider management layer compatible with Claude Code's settings.json protocol.
- ProviderService: CRUD + activation + settings.json sync + HTTP connectivity test
- Provider REST API: 8 endpoints (list, get, create, update, delete, activate, test)
- API key masking in GET responses (sk-a****xyz)
- Models API refactored to read from active Provider dynamically
- 42 unit tests + 6 real-config integration tests, all passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Enforce auth on API/WS when non-localhost or SERVER_AUTH_REQUIRED=1
- Fix CronScheduler: add --verbose flag and correct stream-json message envelope
- Resolve session workdir from JSONL file instead of hardcoding process.cwd()
- Give Opus 4.6 1M a unique composite ID (claude-opus-4-6-20250610:1m)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add complete server-side implementation for the Claude Code Desktop App UI:
- REST API: sessions, conversations, settings, models, scheduled tasks,
search, agents, and status endpoints (9 modules, 30+ endpoints)
- WebSocket: real-time chat streaming with state transitions, ping/pong,
permission request forwarding, and stop generation support
- Services: sessionService (JSONL read/write, CLI-compatible),
settingsService (atomic writes), cronService, searchService (ripgrep),
agentService (YAML management)
- Middleware: CORS (localhost-only), auth, unified error handling
- Tests: 180 tests (unit + E2E + business flow), all passing
- Docs: PRD, UI design spec, server architecture design
Non-invasive: all new code under src/server/, no changes to existing CLI code.
CLI/UI data interop: reads/writes the same JSONL/JSON files as the CLI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>