897 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
673523f3fd fix: keep IM session streams subscribed across desktop views
Telegram and desktop can attach to the same session while a turn is streaming. The WebSocket handler now tracks output callbacks per client and broadcasts session messages instead of replacing the previous subscriber. Telegram thinking deltas are accumulated before editing the placeholder so the preview does not collapse to the latest tiny chunk.

Constraint: Desktop and IM adapters may observe the same active session concurrently
Rejected: Keep a single session output callback | a later desktop view can steal Telegram's live content and completion events
Confidence: high
Scope-risk: moderate
Directive: Do not collapse session output callbacks back to one callback without a multi-client streaming regression
Tested: bun run check:server (828 pass); bun run check:adapters (358 pass); git diff --check
Not-tested: Live Telegram Bot API smoke against the packaged app
2026-05-23 16:19:39 +08:00
程序员阿江(Relakkes)
28ddcd0afd Keep local main from replaying answered AskUserQuestion prompts
Merge the worktree fix that preserves CLI AskUserQuestion toolUseResult metadata across history replay and live WebSocket translation, then filters stale unresolved cards when no pending permission is active.

Constraint: main had advanced past the worktree base, so this requires a non-fast-forward local merge.
Confidence: high
Scope-risk: moderate
Directive: Keep AskUserQuestion rendering driven by CLI transcript metadata instead of desktop-only lifecycle inference.
Tested: git merge-tree 3f384a1d5f5f48f0c7eb848b2dfacb4527fd5059 main 853e3db6ecbeb9a39f333c65aa7eddc32d613d7b
Tested: worktree commit already passed server focused tests, desktop focused tests, check:server, desktop lint, desktop build, and git diff --check.
Not-tested: Re-running full verification after the merge commit.
2026-05-23 15:58:57 +08:00
程序员阿江(Relakkes)
853e3db6ec fix: keep AskUserQuestion state aligned with CLI answers
The CLI transcript already records each AskUserQuestion once, but the desktop bridge dropped the structured toolUseResult answers from both history replay and live WebSocket tool results. That made answered question cards look unresolved and allowed stale cards to reappear during the gap before the next permission request.

Constraint: Desktop should render the CLI question stream directly without inventing separate question lifecycle state.
Rejected: Hide all previous AskUserQuestion cards after submit | would remove resolved answer history instead of preserving transcript context.
Confidence: high
Scope-risk: moderate
Directive: Preserve toolUseResult metadata when adapting CLI transcript entries; AskUserQuestion answer state depends on the structured answers object, not the prose tool_result string.
Tested: bun test src/server/__tests__/sessions.test.ts --timeout 30000
Tested: bun test src/server/__tests__/ws-memory-events.test.ts --timeout 30000
Tested: cd desktop && bun run test src/stores/chatStore.test.ts
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx
Tested: bun run check:server
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
Not-tested: Full bun run verify and live desktop browser smoke.
2026-05-23 15:58:15 +08:00
程序员阿江(Relakkes)
5f3da46354 fix: keep OpenAI proxy streams past request timeout
OpenAI-compatible streaming requests previously used the shared AI request timeout as a full-body AbortSignal. That made long SSE generations stop mid-answer after the configured timeout even when the upstream had already started streaming.

The proxy now applies the configured timeout only while opening streaming upstream requests and keeps non-streaming requests on the existing full-request timeout.

Constraint: The global AI request timeout is documented as covering provider requests and streaming first responses, not total stream duration.
Rejected: Increase the default timeout | long plan-mode answers can still exceed any fixed full-stream limit.
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/proxy-network-settings.test.ts
Tested: bun run check:server
2026-05-23 14:10:58 +08:00
程序员阿江(Relakkes)
3f384a1d5f Merge filesystem workspace access fix into local main
Bring in the selected-workspace filesystem access fix from the detached
investigation worktree so Windows projects outside the user home can use
desktop @ file search.

Constraint: Preserve local main history while landing the detached worktree fix
Confidence: high
Scope-risk: moderate
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: bun run check:server
Not-tested: Windows packaged desktop smoke after merge
2026-05-22 19:48:15 +08:00
程序员阿江(Relakkes)
4dc705db3c fix: allow selected workspaces in filesystem browser
Desktop file mentions should follow the workspace the user opened, but
the filesystem browser only trusted the home and temp roots. Register
workspace roots after repository context, session creation, and session
git-info resolution so Windows projects on another drive can be searched
without turning the browse API into arbitrary disk access.

Constraint: Windows users can open repositories outside C:\\Users, such as D:\\workspace\\code\\cc-haha
Constraint: Filesystem browse must not become an unbounded local disk reader
Rejected: Add a global user-configurable filesystem whitelist | broader product and persistence surface than this bug needs
Rejected: Allow every requested browse path | would bypass the intended filesystem boundary
Confidence: high
Scope-risk: moderate
Directive: Register only workspace roots that the server has already resolved through session or repository flows
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: bun run check:server
Not-tested: Windows packaged desktop smoke
2026-05-22 19:48:05 +08:00
程序员阿江(Relakkes)
a0f702aaeb Merge H5 LAN address fix into local main 2026-05-22 19:46:59 +08:00
程序员阿江(Relakkes)
da8308debf fix: preserve manual H5 LAN addresses
Manual H5 LAN hosts should survive auto LAN discovery, because the detected adapter can be a WSL or Docker virtual interface instead of the physical network reachable by a phone. The settings UI now asks for the host or IP separately and reuses the current service port for the normal LAN workflow, while still accepting full URLs for reverse proxy setups.

Constraint: H5 auto discovery may see multiple private IPv4 adapters on Windows hosts.
Rejected: Treat all private URLs as stale auto-discovery output | this overwrites intentional LAN choices.
Rejected: Let users manually type the port for the normal LAN path | the server already owns the bound port and the UI can reuse it.
Confidence: high
Scope-risk: moderate
Tested: bun test src/server/__tests__/h5-access-service.test.ts
Tested: bun test src/server/__tests__/h5-access-api.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/__tests__/h5-access-policy.test.ts
Tested: bun run check:server
Tested: bun run check:desktop
Not-tested: Real Windows plus WSL/Docker plus phone LAN smoke.
2026-05-22 19:46:50 +08:00
程序员阿江(Relakkes)
4918cd8032 Merge compact state fix into local main
Bring the desktop compact state repair from the validation worktree into
local main after focused, full local, packaged-app, and coverage checks.

Constraint: Local main was clean and shared the same base commit as the validation worktree.
Confidence: high
Scope-risk: moderate
Directive: Keep compact status null handling and tail compact-card cleanup together.
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:policy
Tested: bun run check:native
Tested: bun run check:coverage
Tested: SKIP_INSTALL=1 PRESERVE_TAURI_TARGET=1 ./desktop/scripts/build-macos-arm64.sh
Not-tested: Full live auto-compact threshold trigger in packaged app; Tauri sidecar did not inherit CLAUDE_AUTOCOMPACT_PCT_OVERRIDE during manual smoke.
Related: cb922b01
2026-05-22 19:17:05 +08:00
程序员阿江(Relakkes)
cb922b018d fix: prevent desktop compact state from sticking
Desktop compact events can arrive as a start status followed by a null
CLI status or by a summary boundary. Preserve the visible transcript while
making either completion path clear transient compacting UI so the session
cannot remain stuck after auto-compact or cancellation.

Constraint: Desktop receives compact state through translated CLI SDK status events.
Rejected: Collapse old transcript into a single compact card | hides useful history and caused issue #568.
Confidence: high
Scope-risk: moderate
Directive: Do not drop status=null compact exits without validating desktop chat state transitions.
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:policy
Tested: bun run check:native
Tested: bun run check:coverage
Tested: SKIP_INSTALL=1 PRESERVE_TAURI_TARGET=1 ./desktop/scripts/build-macos-arm64.sh
Tested: Real packaged macOS app with GPT-5.5 completed two live turns without staying in running state.
Not-tested: Full live auto-compact threshold trigger in packaged app; Tauri sidecar did not inherit CLAUDE_AUTOCOMPACT_PCT_OVERRIDE during manual smoke.
Related: https://github.com/NanmiCoder/cc-haha/issues/567
Related: https://github.com/NanmiCoder/cc-haha/issues/568
2026-05-22 19:16:53 +08:00
程序员阿江(Relakkes)
d9bd75b5e5 fix: stabilize Computer Use dependency installs
Computer Use now rejects Python runtimes below 3.9 before running pip,
keeps Pillow on the Python 3.9-compatible 11.x line, and falls back from
the configured mirror to the default PyPI index when dependency installs
fail.

Constraint: Pillow 11.3 requires Python 3.9+, while user machines may resolve a different Python than expected
Rejected: Downgrade Pillow to the Python 3.8-compatible 10.x line | current product direction assumes modern Python installs
Confidence: high
Scope-risk: narrow
Directive: Keep runtime package ranges aligned with the setup Python minimum before changing either side
Tested: bun test src/server/__tests__/computer-use-api.test.ts src/server/__tests__/computer-use-requirements.test.ts src/server/__tests__/computer-use-python.test.ts src/utils/computerUse/pipInstall.test.ts
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run check:policy
Not-tested: Real Windows 10 machine dependency install against the reported user environment
2026-05-22 19:16:45 +08:00
程序员阿江(Relakkes)
6b62b6c633 Merge code rendering compatibility fix into local main
Bring the detached worktree fix back to the local main branch so modern WebUI keeps Shiki rendering while legacy WebKit can fall back before loading Shiki.

Constraint: Local main already contains unreleased commits ahead of origin/main.
Confidence: high
Scope-risk: moderate
Tested: Worktree commit passed focused CodeViewer test, desktop lint, desktop build, startup bundle scan, and real WebUI Shiki smoke before merge.
Not-tested: Re-running the full desktop gate after merge.
2026-05-22 17:55:45 +08:00
程序员阿江(Relakkes)
4fce6014a6 fix: preserve Shiki code rendering with legacy fallback
Code blocks should keep the richer Shiki rendering in modern WebUI while avoiding the old WebKit startup crash path by loading Shiki lazily and falling back to Prism only when the runtime cannot safely parse or execute it.

Constraint: Issue #461 is triggered by older Safari/WebKit parsing modern RegExp syntax during startup.
Rejected: Replace Shiki entirely with Prism | visual quality regressed for normal WebUI usage.
Confidence: high
Scope-risk: moderate
Directive: Keep Shiki out of the startup path unless macOS 12 WebView compatibility is re-verified.
Tested: cd desktop && bun run test -- --run src/components/chat/CodeViewer.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: Real WebUI smoke on http://127.0.0.1:1420/ verified six code blocks rendered with data-highlight-engine=shiki.
Not-tested: Physical macOS 12 WebView runtime.
Related: https://github.com/NanmiCoder/cc-haha/issues/461
2026-05-22 17:55:33 +08:00
程序员阿江(Relakkes)
1431a8a1c1 Merge Telegram streaming readability fix into local main
The Telegram adapter fix was developed in a detached worktree from a shared base while local main already contained newer desktop fixes. Merge the narrow worktree commit into main so the local checkout keeps those existing commits and gains the Telegram streaming behavior.

Constraint: Local main had already advanced independently after the worktree base.
Rejected: Rebase local main onto the worktree commit | rewrites the user's local main history unnecessarily.
Confidence: high
Scope-risk: narrow
Directive: Keep this as a local integration merge; do not push unless explicitly requested.
Tested: bun run check:adapters
Tested: cd desktop && bun run build:sidecars
Not-tested: Live Telegram Bot API run with a real bot token.
2026-05-21 17:35:15 +08:00
程序员阿江(Relakkes)
05b183158c fix: keep long Telegram streams readable
Telegram Bot API text edits share the same practical message length ceiling as sends, so streaming one growing placeholder can stop exposing new assistant output once the text approaches the limit. The adapter now seals full chunks, opens a fresh editable placeholder, and routes Telegram outbound text through a table-to-bullet formatter for phone readability.

Constraint: Telegram text messages and edits must stay below the platform message limit.
Rejected: Wait until message_complete to split the answer | users still lose streaming visibility during long replies.
Confidence: high
Scope-risk: narrow
Directive: Keep Telegram-specific streaming state in adapters/telegram/format.ts instead of spreading chunk math across message handlers.
Tested: bun test adapters/telegram/__tests__/telegram.test.ts adapters/common/__tests__/format.test.ts
Tested: cd adapters && bunx tsc --noEmit
Tested: bun run check:adapters
Tested: cd desktop && bun run build:sidecars
Not-tested: Live Telegram Bot API run with a real bot token.
2026-05-21 17:34:51 +08:00
程序员阿江(Relakkes)
cb8bdce316 Merge worktree fix for desktop branch display
Bring the issue #539 fix from the detached Codex worktree into the canonical local main checkout so desktop sessions in materialized worktrees report the actual checked-out branch.

Constraint: Local main had advanced independently, so this could not fast-forward cleanly.
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/sessions.test.ts -t "git-info"
Tested: /tmp/cc-haha-issue-539-verify API reproduction returned the worktree branch
Tested: bun run check:server
2026-05-21 17:21:22 +08:00
程序员阿江(Relakkes)
09c7167a49 fix: prevent worktree sessions showing source branch
Desktop git-info preserved the launch branch before checking the active worktree cwd, so materialized isolated worktree sessions could keep showing the source branch instead of the branch Git had checked out in the worktree. The API now switches to the real cwd branch only once the session has actually entered its planned worktree, while direct branch launches still keep their stable launch branch.

Constraint: Direct branch launches still need stable launch metadata when the source checkout later changes.
Rejected: Always prefer git rev-parse output | would regress direct launch sessions that intentionally show the selected branch.
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/sessions.test.ts -t "git-info"
Tested: /tmp/cc-haha-issue-539-verify API reproduction returned the worktree branch
Tested: bun run check:server
2026-05-21 17:21:02 +08:00
程序员阿江(Relakkes)
861d88225c fix: improve AskUserQuestion desktop rendering
Desktop AskUserQuestion could show duplicate unresolved cards when restored history and a live permission request overlapped. The custom response field was also single-line, making long restored-context answers hard to read or edit.

This keeps the active unresolved AskUserQuestion card aligned with the live permission request, preserves resolved history, and switches custom responses to a multiline editor with Ctrl/Cmd+Enter submission.

Constraint: Desktop issue reports #542 and #543 both hit the AskUserQuestion chat surface.
Rejected: Hide all AskUserQuestion history while pending | resolved answers should remain visible in the transcript.
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test src/components/chat/AskUserQuestion.test.tsx
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: bun run check:desktop
Not-tested: Live Windows desktop manual restore flow from the issue attachment.
2026-05-21 17:20:39 +08:00
程序员阿江(Relakkes)
a159ee3511 fix: stream ChatGPT OAuth title requests
ChatGPT Codex requires streamed Responses API requests, including hidden non-chat paths such as title generation. Keep the OAuth adapter streaming upstream while preserving JSON responses for non-streaming Anthropic callers, and route ChatGPT Official titles through the OAuth Codex endpoint.

Constraint: ChatGPT Codex rejects non-streaming requests with HTTP 400
Rejected: Disable AI title generation for ChatGPT OAuth | would leave first-session metadata degraded
Confidence: high
Scope-risk: narrow
Tested: bun test src/services/openaiAuth/fetch.test.ts
Tested: bun test src/server/__tests__/title-service.test.ts
Tested: bun run check:server
Tested: git diff --check
Not-tested: Live ChatGPT OAuth account round trip after remote build
v0.2.9
2026-05-21 15:31:56 +08:00
程序员阿江(Relakkes)
5798756e3f Prepare v0.2.9 release candidate
This records the v0.2.9 release notes and aligns desktop package,
Tauri, and Cargo metadata so the release script can create the final
annotated tag after manual validation.

Constraint: Release tag creation is intentionally deferred for manual smoke validation.
Rejected: Run scripts/release.ts now | it would create the release commit and annotated tag before manual review.
Confidence: high
Scope-risk: narrow
Directive: Do not create v0.2.9 tag until the manual release check is complete.
Tested: bun run scripts/release.ts 0.2.9 --dry
Tested: bun run check:native
Not-tested: Full bun run verify and live ChatGPT Official OAuth smoke
2026-05-21 14:28:12 +08:00
程序员阿江(Relakkes)
0c43b270b9 fix: Align OpenAI Codex context windows
ChatGPT Official runs through Codex OAuth, so context accounting should follow
the Codex model catalog and its effective context window instead of public API
limits. This keeps GPT-5.5 at the same usable window shown by Codex while
preserving GPT-5.4's larger Codex window.

Constraint: Codex OAuth model metadata applies effective_context_window_percent to raw catalog windows
Rejected: Use public API GPT-5.5 1.05M context | Codex app and OAuth runtime clamp this model to the smaller effective window
Confidence: high
Scope-risk: narrow
Directive: Keep ChatGPT Official context values aligned to Codex model catalog behavior, not generic OpenAI API docs
Tested: bun test src/services/openaiAuth/models.test.ts src/services/compact/autoCompact.test.ts src/server/__tests__/providers.test.ts
Tested: bun run check:server
Tested: git diff --check
Not-tested: Manual desktop screenshot after rebuilding the app
2026-05-21 14:15:09 +08:00
程序员阿江(Relakkes)
e437199b81 fix: Surface API retry progress in desktop chat
CLI retry events already include retry attempts, delay, and upstream status, but
the desktop WebSocket translation dropped api_retry system messages. The desktop
chat now keeps the current retry state in session state and renders a compact
active-turn indicator with attempt count, HTTP status, and countdown.

Constraint: Desktop users need visible feedback during provider retry waits after auth or network failures.
Rejected: Add retry rows to the transcript | retry heartbeats would clutter chat history instead of describing the active turn.
Confidence: high
Scope-risk: moderate
Directive: Keep api_retry as active-turn state; do not persist retry heartbeats into transcript history without a product decision.
Tested: bun test src/server/__tests__/ws-memory-events.test.ts
Tested: cd desktop && bun run test src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:server
Tested: Browser smoke with temp CLAUDE_CONFIG_DIR and mock OpenAI-compatible 503 endpoint, screenshot /tmp/cc-haha-retry-ui.png
Not-tested: Live ChatGPT logout retry path against OpenAI production auth.
2026-05-20 18:48:36 +08:00
程序员阿江(Relakkes)
9612fae4c2 docs: refine agent operating contract
Restructure the repository guidance around agent behavior, project surfaces, and verification routing so future coding agents can choose fast inner-loop checks without losing the PR and release quality gates.

Constraint: AGENTS.md wording is covered by the feature quality contract tests.
Constraint: Release workflow currently builds from tags and is not a substitute for local release verification.
Rejected: Keep the old command inventory with appended guidance | it preserved duplication and left verification budgeting ambiguous.
Confidence: high
Scope-risk: narrow
Directive: Keep future guidance tied to real package scripts and workflow behavior.
Tested: bun test scripts/pr/quality-contract.test.ts
Tested: bun run check:policy
Not-tested: Full bun run verify, documentation-only guidance change.
2026-05-20 18:04:58 +08:00
程序员阿江(Relakkes)
02bf65ce07 fix: Preserve ChatGPT Official after desktop restart
The WebSocket runtime treated every active provider id as stale unless it existed in the saved custom-provider list. ChatGPT Official is an in-memory built-in provider, so restarting the desktop could activate Claude Official and rewrite the provider index back to null before a new session launched. Keep built-in OpenAI provider ids valid in runtime validation, while preserving the stale custom-provider cleanup path.

This also keeps the General network timeout UI aligned with the authoritative timeout behavior by allowing precise typed values and updating the user-facing hint.

Constraint: ChatGPT Official is a built-in provider id and is not stored in the custom providers array.
Rejected: Persist ChatGPT Official as a synthetic saved provider | it would mix token-backed built-ins with user-managed providers and complicate secret persistence.
Confidence: high
Scope-risk: moderate
Directive: Runtime provider validation must include built-in provider ids as well as saved custom provider ids.
Tested: bun test src/server/__tests__/conversations.test.ts -t "preserve ChatGPT Official"
Tested: bun test src/server/__tests__/conversations.test.ts -t "stale persisted|preserve ChatGPT Official"
Tested: bun run check:server
Tested: bun run check:desktop
Not-tested: Full bun run verify after the final interruption; user explicitly asked to stop verification and commit directly.
Not-tested: Manual desktop restart with a real ChatGPT OAuth account in the packaged app.
2026-05-20 18:00:22 +08:00
程序员阿江(Relakkes)
4343b3f039 fix: Make General proxy timeout authoritative
Non-stream OpenAI-compatible proxy requests still kept the previous 300s timeout floor after the unified network settings merge. That made lower General AI timeout settings ineffective for normal proxy traffic, even though the setting is meant to be the final provider request timeout.

Constraint: Unified network settings must remain the final timeout and proxy override for provider protocol paths.
Rejected: Keep the 300s non-stream floor | it makes low timeout settings ineffective for normal proxy requests.
Confidence: high
Scope-risk: narrow
Directive: Do not reintroduce per-protocol timeout floors without updating the General network settings contract and tests.
Tested: bun test src/server/__tests__/proxy-network-settings.test.ts
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/network-settings.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/proxy-network-settings.test.ts
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Live provider request against a real upstream proxy.
2026-05-20 17:48:01 +08:00
程序员阿江(Relakkes)
88ac83d42f Merge unified AI network settings into main
The worktree implementation adds one General settings surface for AI request timeout and proxy configuration. This merge keeps main's newer attribution-signing and ChatGPT Official provider paths while preserving the unified network override across CLI sessions, provider checks, and OpenAI-compatible proxy forwarding.

Constraint: Main had newer attribution and official-provider changes touching the same server integration points
Rejected: Prefer the worktree proxy body verbatim | it would drop main's signed CCH attribution wrapper
Rejected: Keep provider preset timeouts above General | it would violate the single timeout control requirement
Confidence: high
Scope-risk: moderate
Directive: General network settings must remain the final AI request timeout and proxy override for every provider protocol
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/network-settings.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/proxy-network-settings.test.ts
Tested: cd desktop && bun run test -- --run src/stores/settingsStore.test.ts src/__tests__/generalSettings.test.tsx
Not-tested: Full bun run verify after resolving main merge conflicts
2026-05-20 17:30:10 +08:00
程序员阿江(Relakkes)
005bfbca8c fix: Match Codex token exchange request shape
OpenAI returns token-exchange failures at the OAuth boundary, so the desktop ChatGPT login path should send the same Codex-compatible headers as the reference implementation and preserve enough sanitized response detail to diagnose upstream rejections.

Constraint: OpenAI authorization codes and token responses are sensitive and must not be logged verbatim.
Rejected: Retry the pasted authorization code during debugging | the code is single-use sensitive material and the next generated code gives cleaner evidence.
Confidence: medium
Scope-risk: narrow
Directive: Keep token exchange diagnostics sanitized; do not include raw OAuth codes, refresh tokens, access tokens, or id tokens in errors.
Tested: bun test src/services/openaiAuth/client.test.ts
Tested: bun test src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts src/services/openaiAuth/fetch.test.ts src/services/openaiAuth/storage.test.ts
Tested: bun run check:server
Tested: bun run verify
Not-tested: Full successful live OAuth exchange with a fresh user authorization code.
2026-05-20 17:28:28 +08:00
程序员阿江(Relakkes)
055a07be1a fix: Prevent ChatGPT OAuth authorization from failing before callback
OpenAI rejects Codex OAuth authorize URLs when the redirect URI uses the desktop API server's dynamic port. The desktop ChatGPT Official flow now starts a temporary Codex callback listener and generates the authorize URL with that callback port, while keeping token exchange and storage in the existing desktop OAuth service.

Constraint: OpenAI Codex OAuth client accepts the Codex-compatible localhost callback shape, not arbitrary desktop API ports.
Rejected: Keep routing the callback through the desktop server port | that fails before the browser can return an authorization code.
Confidence: high
Scope-risk: narrow
Directive: Do not put non-Codex query parameters or dynamic desktop ports into the OpenAI authorize URL without live authorization-page verification.
Tested: bun test src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts
Tested: bun test src/services/openaiAuth/client.test.ts src/services/openaiAuth/fetch.test.ts src/services/openaiAuth/storage.test.ts
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Completing a real account OAuth approval in the browser after the fix.
2026-05-20 17:04:38 +08:00
程序员阿江(Relakkes)
671358656b Integrate direct TUI provider env recovery into local main
Local main had advanced independently with OpenAI OAuth URL handling, while the detached worktree fixed stale cc-haha provider env for direct TUI launches. Merge the verified worktree commit so source and desktop-terminal TUI paths both derive provider runtime env from the active provider index.

Constraint: Local main is the canonical checkout for this repository
Rejected: git merge --ff-only 3a42ca20 | local main and the detached worktree had one commit of independent divergence
Confidence: high
Scope-risk: moderate
Directive: Keep provider runtime env changes represented on local main before any release or PR work
Tested: bun test src/server/__tests__/provider-runtime-env.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/conversation-service.test.ts
Tested: bun run check:server
Not-tested: Live provider request from embedded terminal TUI after the local-main merge
2026-05-20 00:11:46 +08:00
程序员阿江(Relakkes)
3a42ca2067 Prevent stale provider proxy env in direct TUI launches
Direct TUI launches read cc-haha managed settings without the desktop host's session-env injection, so a stale proxy URL could survive after switching to an Anthropic-compatible provider. The provider runtime env calculation now has one shared source of truth and CLI config loading recomputes managed provider env from the active provider index before applying it.

Constraint: Direct source-based TUI usage must keep working with .env when no desktop provider is configured
Rejected: Inject desktop runtime only from the embedded terminal shell | native terminals and source TUI launches would still read stale managed settings
Confidence: high
Scope-risk: moderate
Directive: Keep provider env derivation shared between ProviderService and CLI managedEnv loading
Tested: bun test src/server/__tests__/provider-runtime-env.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/conversation-service.test.ts
Tested: bun run check:server
Not-tested: Live provider request from embedded terminal TUI
2026-05-20 00:11:22 +08:00
程序员阿江(Relakkes)
bc998eab3a Prevent OpenAI auth from rejecting Codex OAuth URLs
OpenAI rejects the authorize URL before callback when non-Codex query
parameters are sent. The ChatGPT OAuth flow now matches the sub2api
Codex-compatible shape by keeping originator out of the authorize URL
and using OpenAI-specific hex state and PKCE verifier values.

Constraint: The Codex OAuth client expects the standard authorize query shape used by sub2api.
Rejected: Keep originator=opencode in the OAuth URL | originator is a later ChatGPT API request header concern, not an OAuth authorize parameter.
Confidence: high
Scope-risk: narrow
Tested: bun test src/services/openaiAuth/client.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts src/services/openaiAuth/fetch.test.ts src/services/openaiAuth/storage.test.ts
Tested: git diff --check
Tested: bun run check:server
Not-tested: Live browser OAuth authorization against a real OpenAI account.
2026-05-20 00:11:05 +08:00
程序员阿江(Relakkes)
10d75852bb fix: Preserve direct TUI input in native terminals
Direct native CLI launches already inherit their user's shell environment, so recapturing a login interactive shell from the same TTY is unnecessary and can interfere with prompt input on macOS terminals.

The desktop and non-interactive subprocess paths still keep the shell-env bridge because they do not own the user's interactive terminal.

Constraint: Windows was already excluded from terminal shell env capture, which explains why v0.2.8 remained healthy there.

Rejected: Disable terminal shell env capture globally | desktop subprocesses still need the captured login-shell environment.

Confidence: high

Scope-risk: narrow

Directive: Do not re-enable interactive shell env capture for direct TTY launches without a native PTY input regression test.

Tested: bun test src/utils/terminalShellEnvironment.test.ts src/utils/mcpStdioEnvironment.test.ts

Tested: Native PTY smoke confirmed typed characters appear in claude-haha prompt

Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh

Not-tested: Full bun run verify was intentionally not completed after user requested only a local macOS build
2026-05-19 23:43:16 +08:00
程序员阿江(Relakkes)
dffe83b83a Merge branch 'feat/chatgpt-official-oauth-provider' 2026-05-19 23:35:09 +08:00
程序员阿江(Relakkes)
a4aba9ec5a Show context compaction as transcript state
Desktop users need to see automatic context compaction as a transient transcript state instead of a stray stdout bubble or large card. The UI now collapses prior visible content into a compact timeline divider, shows the compacting phase, then updates the same divider with the completed summary affordance.

Constraint: CLI compaction emits both status and synthetic transcript artifacts that must be normalized before rendering

Rejected: Keep the existing small pill marker | it did not show the in-progress state and looked like chat content

Confidence: high

Scope-risk: moderate

Directive: Do not render local compact stdout as a user-visible chat message

Tested: cd desktop && bun run test -- src/components/chat/MessageList.test.tsx src/stores/chatStore.test.ts

Tested: bun test src/server/__tests__/ws-memory-events.test.ts

Tested: bun run check:desktop

Not-tested: full root bun run verify after the final UI iteration
2026-05-19 23:13:01 +08:00
程序员阿江(Relakkes)
8bd122c967 Keep message fork controls inline
Desktop transcript messages already expose copy controls in the shared action row. The fork affordance was rendered as its own zero-height hover row, which left the icon below Copy and made the action feel detached from the message toolbar. Moving the fork button into the existing action bar keeps the controls aligned while preserving the original branch-session API path.

Constraint: Desktop message actions should stay visually grouped for both user and assistant messages

Rejected: Keep a separate fork-only hover row | it reproduces the two-line layout regression shown in the desktop UI

Confidence: high

Scope-risk: narrow

Directive: Keep future per-message actions inside MessageActionBar unless they need a different interaction surface

Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --pool forks --poolOptions.forks.singleFork=true

Tested: cd desktop && bun run test src/i18n/index.test.tsx --pool forks --poolOptions.forks.singleFork=true

Tested: cd desktop && bun run lint

Tested: bun run check:desktop

Not-tested: Full live desktop backend fork-click E2E
2026-05-19 23:11:03 +08:00
程序员阿江(Relakkes)
df60c77472 fix: add Claude Code billing attribution compatibility 2026-05-19 22:35:05 +08:00
程序员阿江(Relakkes)
abd782494e fix: keep desktop composer toolbar out of multiline input
The active-session composer used an absolute toolbar overlay and textarea bottom padding to reserve space. When the input grew and scrolled, the caret could render inside that reserved overlay area, making it appear to pass through the controls.

Move the non-hero toolbar back into normal layout flow and remove the oversized textarea bottom padding so the text area and controls occupy separate boxes.

Constraint: Active-session and hero composer variants share the component, so keep the change scoped to the non-hero toolbar path.
Rejected: Increase textarea bottom padding | preserves the overlapping layout that caused the caret artifact.
Confidence: high
Scope-risk: narrow
Directive: Do not reintroduce an absolutely positioned toolbar over the active-session textarea without validating multiline caret rendering.
Tested: cd desktop && bun run test src/components/chat/ChatInput.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: Browser DOM check confirmed textarea and toolbar no longer overlap.
2026-05-19 22:26:18 +08:00
程序员阿江(Relakkes)
11ce6a2064 Merge desktop session status indicators into main
The detached worktree contains the completed desktop navigation status change. Local main has advanced independently, so this merge records the integration while preserving existing unrelated worktree edits.

Constraint: Local main has unrelated dirty src/ changes that must remain untouched
Rejected: Fast-forward merge | local main and the detached worktree commit diverged after fed9b6c9
Confidence: high
Scope-risk: narrow
Directive: Do not treat the unrelated dirty src/ files as part of this desktop UI merge
Tested: cd desktop && bun run test src/components/layout/TabBar.test.tsx src/components/layout/Sidebar.test.tsx --pool forks --poolOptions.forks.singleFork=true
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: real desktop session in /private/tmp/cc-haha-real-status-fsip8S using gpt-5.5 Sub2API-ChatGPT; running markers appeared in sidebar and tab, then cleared after CCH_STATUS_REAL_DONE
2026-05-19 22:14:29 +08:00
程序员阿江(Relakkes)
318bf336b0 Expose active session state across desktop navigation
Multiple desktop sessions can run at the same time, so navigation surfaces need a compact shared signal instead of making users open each conversation to check progress. The sidebar and tab bar now derive running state from both persisted tab status and live chat state, while session rows keep worktree and updated-time metadata aligned on the right.

Constraint: Reuse existing tab/chat state without changing session persistence or server APIs
Rejected: Add another session status field | duplicated state would drift from chatStore and tabStore
Confidence: high
Scope-risk: narrow
Directive: Keep sidebar and tab running indicators sourced from the same state rules
Tested: cd desktop && bun run test src/components/layout/TabBar.test.tsx src/components/layout/Sidebar.test.tsx --pool forks --poolOptions.forks.singleFork=true
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: real desktop session in /private/tmp/cc-haha-real-status-fsip8S using gpt-5.5 Sub2API-ChatGPT; running markers appeared in sidebar and tab, then cleared after CCH_STATUS_REAL_DONE
2026-05-19 22:13:54 +08:00
程序员阿江(Relakkes)
685560f62c Keep stopped background tasks from looking alive
A desktop session can receive a successful TaskStop result without a matching task_notification bookend. The transcript already proves the background command was stopped, but the desktop store kept the local_bash task record in running state, leaving the card spinner active after the assistant turn had ended.

This change derives the stopped background-task update from successful TaskStop/KillShell tool results and upserts the transcript task card through the existing background task merge path. Failed TaskStop results are ignored so an unsuccessful stop cannot hide still-running work.

Constraint: Some persisted and live task-stop paths only surface as ordinary tool_result messages.
Rejected: Change composer/run-button state | that would couple input availability to background task bookkeeping and miss the stuck task card.
Confidence: high
Scope-risk: narrow
Directive: Keep TaskStop result handling gated on non-error results; failed stops must not mark background tasks terminal.
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Full root verify gate; change is scoped to desktop store and covered by check:desktop.
2026-05-19 21:58:31 +08:00
程序员阿江(Relakkes)
5b0ab7aa8a Route OpenAI OAuth callback through desktop server
The ChatGPT Official OAuth start flow already generated the Codex /auth/callback redirect, but the desktop server only handled the older /callback/openai path. Real HTTP and UI E2E exposed the mismatch, so the server now routes the Codex callback path while retaining the legacy alias.

Constraint: OpenAI Codex OAuth client code owns OPENAI_CODEX_REDIRECT_PATH.

Rejected: Change the generated redirect back to /callback/openai | that would diverge from the shared OpenAI Codex OAuth client path.

Confidence: high

Scope-risk: narrow

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: HTTP E2E passed at /var/folders/sx/hl8zlmxd7gx9b58_1t2zhp5r0000gn/T/cc-haha-openai-oauth-e2e-4uWfok/result.json.

Tested: UI E2E passed at /var/folders/sx/hl8zlmxd7gx9b58_1t2zhp5r0000gn/T/cc-haha-openai-oauth-ui-e2e-ZyQ60q/result.json.
2026-05-19 19:01:23 +08:00
程序员阿江(Relakkes)
9e45724290 Merge local main into ChatGPT OAuth provider work
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
2026-05-19 18:35:55 +08:00
程序员阿江(Relakkes)
fed9b6c9f6 Merge desktop branch-from-here support into main
Bring the verified worktree implementation into local main while preserving the existing local main commits and unrelated dirty working tree changes.

Constraint: Local main already had unrelated uncommitted provider/runtime edits, so the merge only touches the desktop branch feature paths.
Confidence: high
Scope-risk: moderate
Tested: bun run verify before merge; merge completed without conflicts
Not-tested: Post-merge full quality gate on dirty local main
2026-05-19 18:31:47 +08:00
程序员阿江(Relakkes)
73e915ac6b Enable desktop branching from transcript messages
Desktop users need the same branch-from-here workflow that the CLI already exposed, so the branch creation logic now lives in a shared transcript utility and the desktop app routes completed message actions through the server API. The UI hydrates transcript ids after live completions so newly generated turns can be branched immediately without a refresh.

Constraint: Source sessions must remain unmodified while branch sessions inherit the active transcript chain and persistence metadata.
Rejected: Keep a desktop-only branch implementation | it would drift from CLI /branch semantics and duplicate transcript filtering rules
Confidence: high
Scope-risk: moderate
Directive: Do not remove the post-completion transcript hydration without a real-model desktop E2E for just-finished messages
Tested: bun run verify; Chrome Web UI E2E with real gpt-5.5 provider on ports 45678/45679
Not-tested: Provider-specific behavior beyond the configured Sub2API-ChatGPT route
2026-05-19 18:31:24 +08:00
程序员阿江(Relakkes)
8cce7ac8bb fix: Route Claude attribution by model name
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.
2026-05-19 18:12:57 +08:00
程序员阿江(Relakkes)
8b7abb41b7 feat: Add unified AI network settings
Settings General now owns AI request timeout and proxy policy so Anthropic-native and OpenAI-compatible provider paths share one user-visible control. The desktop UI persists the network settings, the server proxy and provider checks read them directly, and CLI sessions receive the same timeout/proxy environment.

Constraint: Provider request behavior must be consistent across Anthropic, OpenAI Chat, and OpenAI Responses formats
Rejected: Keep preset API_TIMEOUT_MS precedence | it would make the General timeout control unreliable for some providers
Confidence: high
Scope-risk: moderate
Directive: Do not add protocol-specific AI request timeout controls without preserving General as the final override
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/network-settings.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/proxy-network-settings.test.ts
Tested: cd desktop && bun run test -- --run src/stores/settingsStore.test.ts src/__tests__/generalSettings.test.tsx
Tested: bun run check:desktop
Tested: bun run check:server
Not-tested: socks5 manual proxy support; manual proxy validation currently accepts HTTP/HTTPS URLs only
2026-05-19 17:48:05 +08:00
程序员阿江(Relakkes)
63ef7b1a5b Preserve DeepSeek reasoning history for OpenAI chat proxies
DeepSeek-compatible OpenAI Chat providers require assistant reasoning_content to be replayed on later tool-call turns when thinking mode is active. The Anthropic-to-OpenAI chat transform now keeps that replay behavior behind an explicit compatibility option, and the proxy only enables it for DeepSeek/OpenCode base URLs so generic OpenAI-compatible providers keep their previous request shape.

Constraint: DeepSeek thinking mode rejects follow-up requests when prior assistant reasoning_content is omitted

Rejected: Trigger compatibility by model name | would affect unrelated OpenAI-compatible providers using DeepSeek model ids

Confidence: high

Scope-risk: narrow

Directive: Do not broaden this compatibility gate without proving other OpenAI-compatible providers accept these non-standard fields

Tested: Fixed-port Web UI harness with copied DeepSeek OpenAI Chat provider reproduced the 400 and passed through local proxy after the fix

Tested: bun test src/server/__tests__/proxy-transform.test.ts

Tested: bun run check:server

Tested: git diff --check

Not-tested: Direct OpenCode Go subscription endpoint, unavailable locally
2026-05-19 17:40:43 +08:00
程序员阿江(Relakkes)
dc0307f4c1 fix: Stabilize desktop CLI launcher TTY startup
The desktop app exposed the bundled sidecar directly as the user shell command, which could be suspended by macOS job control when the interactive TUI read from the controlling terminal. Unix installs now write a lightweight launcher wrapper, using a nested PTY on macOS interactive terminals while preserving direct exec behavior for non-interactive commands and Windows binaries.

Constraint: Bundled desktop sidecars must remain usable from user terminals without requiring a separate CLI installation
Rejected: Copy the Bun sidecar directly on macOS | interactive TUI startup can suspend with SIGTTIN
Confidence: high
Scope-risk: narrow
Directive: Do not remove the macOS PTY wrapper without testing interactive TUI startup in a real terminal
Tested: bun test src/server/__tests__/desktop-cli-launcher.test.ts
Tested: bun run check:server
Tested: claude-haha --version
Tested: Real TTY interactive launch no longer printed suspended tty input
2026-05-19 17:02:29 +08:00
程序员阿江(Relakkes)
e1c2f54f14 fix: Improve settings extension browsing
Settings needed a faster way to find local skills, and the plugin overview was wasting space by forcing summary cards into a tall right rail. Keep skill discovery client-side over the already-loaded list and flatten plugin metrics into a compact header so release notes can point issue #513 at the exact user-facing fix.

Fixes #513

Constraint: Settings skills data is already loaded locally through /api/skills
Rejected: Add server-side skill search | unnecessary API surface for a small local filter
Confidence: high
Scope-risk: narrow
Directive: Keep Settings extension browsing read-only unless an install/edit flow is explicitly added
Tested: bun run check:desktop
Related: #513
2026-05-19 16:07:07 +08:00
程序员阿江(Relakkes)
55d4c80823 Center v0.2.8 notes on /goal and Agent readability
The release boundary was already prepared, but recent desktop Agent display fixes landed after it and /goal needed to be described as a new user-facing feature rather than a restored hidden workflow. Update the release body before tagging so GitHub Release content matches the shipped surface.

Constraint: release workflow reads release-notes/v0.2.8.md from the tagged commit

Rejected: Leave /goal as recovery wording | users never saw the hidden implementation as a public feature

Confidence: high

Scope-risk: narrow

Tested: git diff --check -- release-notes/v0.2.8.md

Tested: bun run scripts/release.ts 0.2.8 --dry

Tested: cd desktop && bun run test -- run src/components/chat/MessageList.test.tsx -t agent

Tested: cd desktop && bun run build

Not-tested: Full live release gate in this turn
v0.2.8
2026-05-19 04:22:09 +08:00