310 Commits

Author SHA1 Message Date
程序员阿江(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)
2323e6ec47 Keep subagent progress readable in desktop sessions
Desktop sessions can receive task tools, background-agent lifecycle events, and child tool stream events in the same turn. The UI now keeps root Agent cards separate from task-management tools, preserves parent links when later stream events omit them, and surfaces completed background-agent result text from task notifications.

Constraint: Existing desktop session history can contain task-notification XML and live WS events with incomplete parent metadata.
Rejected: Render local_agent lifecycle messages as standalone cards | duplicates the Agent tool card and makes ownership unclear.
Confidence: high
Scope-risk: moderate
Directive: Do not collapse Agent and TaskCreate/TaskUpdate root tools into one generic group without checking multi-agent screenshots.
Tested: SKIP_INSTALL=1 PRESERVE_TAURI_TARGET=1 ./desktop/scripts/build-macos-arm64.sh
Tested: Real gpt-5.5 desktop E2E sessions under /tmp/cc-haha-subagent-e2e-20260519-025454 for 3 subagents, child tools, result dialog, and background Bash completion.
Not-tested: Full bun run verify gate.
2026-05-19 03:15:52 +08:00
程序员阿江(Relakkes)
dbe72e9668 Prevent empty provider model slots from reaching runtime
Provider presets and custom entries can leave haiku, sonnet, or opus blank when the main model is the intended fallback. Normalize those mappings at both the Settings UI and ProviderService boundaries so persisted provider config and generated runtime env stay consistent.

Constraint: Users may configure only a main model for custom providers.
Rejected: Keep blank secondary model slots | runtime env would still receive empty ANTHROPIC_DEFAULT_* values.
Confidence: high
Scope-risk: narrow
Directive: Keep UI and ProviderService normalization aligned for provider model mapping changes.
Tested: Not run per maintainer request.
Not-tested: Local test suite skipped by request.
2026-05-19 01:23:30 +08:00
程序员阿江(Relakkes)
1ff563d4b0 Expose ChatGPT Official model catalog
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
2026-05-18 23:39:31 +08:00
程序员阿江(Relakkes)
9a11f35bcd Route ChatGPT Official through OpenAI OAuth env
Activating the built-in ChatGPT provider now writes a dedicated OpenAI OAuth runtime environment instead of clearing provider state. The runtime points the CLI at the desktop-managed OpenAI token file, avoids Anthropic auth/base-url variables, reports auth from the OpenAI token file, and prevents Claude OAuth injection when ChatGPT Official is active.

Constraint: Default provider sessions read cc-haha managed settings, while session-scoped provider selections inject env directly from the desktop host.

Rejected: Treat ChatGPT Official as a generic OpenAI proxy provider | proxy routing would require API-key shaped auth and would leak it into the wrong runtime path.

Confidence: high

Scope-risk: moderate

Tested: bun test src/server/__tests__/providers.test.ts

Tested: bun test src/server/__tests__/conversation-service.test.ts

Tested: bun test src/services/openaiAuth/storage.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts

Tested: git diff --check
2026-05-18 23:28:34 +08:00
程序员阿江(Relakkes)
98fa5a0edd Harden OpenAI OAuth token file writes
The desktop OpenAI OAuth token store writes plaintext refresh credentials through a temporary file before rename. A failed rename previously left that temporary file behind in the server-side store, so the writer now mirrors the CLI storage cleanup path and removes failed temp files before surfacing the original write failure.

Constraint: OpenAI OAuth token files may contain refresh and id tokens.

Rejected: Rely on logout cleanup | failed writes can leave orphan temp files before logout runs.

Confidence: high

Scope-risk: narrow

Tested: bun test src/services/openaiAuth/storage.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts

Tested: git diff --check
2026-05-18 23:15:09 +08:00
程序员阿江(Relakkes)
0927c80cdc Unify desktop OpenAI OAuth token storage
Desktop OpenAI authorization lived in the cc-haha token file while the runtime only read secure storage, so desktop-managed logins could not refresh or authenticate CLI/runtime paths consistently. This teaches runtime storage to honor the explicit desktop token-file env, preserves refresh metadata when OpenAI omits fields, and keeps the desktop service writing the same compatible token shape.

Constraint: Desktop sessions must survive macOS Keychain ACL failures by using the desktop-managed token file when it is explicitly configured
Rejected: Keep refresh writes in secure storage only | runtime and desktop would remain split and refreshed tokens would drift
Confidence: high
Scope-risk: moderate
Tested: bun test src/services/openaiAuth/storage.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts
Tested: git diff --check
2026-05-18 22:56:26 +08:00
程序员阿江(Relakkes)
238ab65cf3 Clear stale provider env for ChatGPT Official activation
Switching from a saved provider to the built-in ChatGPT provider must remove previously managed Anthropic env without writing any OpenAI runtime env yet. This keeps Task 1 metadata-only while preventing stale provider settings from surviving the switch.

Constraint: Task 1 still must not write ChatGPT OAuth runtime env
Rejected: Return without touching settings.json | stale ANTHROPIC_* env survives from the previous provider
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/providers.test.ts --test-name-pattern "ChatGPT Official"
Tested: bun test src/server/__tests__/providers.test.ts
Tested: git diff --check
2026-05-18 22:49:26 +08:00
程序员阿江(Relakkes)
072b913fd2 Keep ChatGPT Official activation metadata-only until OAuth runtime lands
Task 1 should only persist the built-in provider selection. The generic managed env and proxy paths remain reserved for saved Anthropic-compatible providers until the dedicated OpenAI OAuth runtime is wired in a later task.

Constraint: Task 1 must not write managed provider env for openai-official
Rejected: Reuse buildManagedEnv for openai-official | writes placeholder Anthropic env before Task 3 runtime exists
Rejected: Return generic proxy config for openai-official | lets empty-key proxy resolution masquerade as a working runtime
Confidence: high
Scope-risk: narrow
Directive: Do not route openai-official through managed settings or generic proxy lookup until the dedicated OAuth runtime is implemented
Tested: bun test src/server/__tests__/providers.test.ts --test-name-pattern "ChatGPT Official"
Tested: bun test src/server/__tests__/providers.test.ts
Tested: bun run check:server
2026-05-18 22:46:36 +08:00
程序员阿江(Relakkes)
b3cc32e43d Add a typed ChatGPT provider runtime
ChatGPT OAuth needs a stable built-in provider identity and a runtime kind that survives provider index normalization. This keeps normal saved providers unchanged while letting the desktop treat openai-official as an active provider without storing secrets in providers.json.

Constraint: providers.json migration must preserve activeId=openai-official even when providers[] is empty
Constraint: ChatGPT Official metadata must stay token-free in the provider index
Rejected: Treat ChatGPT Official as a normal openai_responses provider row | it would require persisting a fake saved provider and would still lose activeId during migration
Confidence: high
Scope-risk: narrow
Directive: Do not teach later OpenAI OAuth work to depend on providers[] containing the built-in provider
Tested: bun test src/server/__tests__/providers.test.ts --test-name-pattern "ChatGPT Official provider metadata"
Tested: bun test src/server/__tests__/providers.test.ts
Tested: cd desktop && bun run lint
Tested: git diff --check
2026-05-18 22:35:30 +08:00
程序员阿江(Relakkes)
8a5b3467c5 Merge origin/main into local post-0.2.7 main
Remote main carries portable-mode, legacy Windows workdir recovery, and Feishu path-safety fixes while local main carries terminal shell, update proxy, slash-command, prompt-draft, AskUserQuestion, background-work, and shell-env changes. This merge keeps both lines by layering portable Bash-path defaults underneath the desktop terminal shell preference and preserving both update-proxy and app-mode settings state.

Constraint: Local main and origin/main diverged after v0.2.7 and both lines contain release-relevant desktop/runtime fixes

Rejected: Prefer either side's terminal settings wholesale | would drop either Windows portable Bash support or explicit desktop startup-shell support

Confidence: medium

Scope-risk: moderate

Directive: Keep portable Bash path as the system-default terminal fallback; explicit desktop startup-shell settings should continue to override it

Tested: cd desktop && bun run test -- --run src/pages/TerminalSettings.test.tsx src/stores/settingsStore.test.ts

Tested: cd desktop/src-tauri && cargo test terminal -- --nocapture

Tested: bun test src/server/__tests__/sessions.test.ts -t stale worktree

Tested: bun run check:desktop

Tested: bun run check:server

Tested: bun run check:native

Not-tested: Manual Windows packaged-app terminal/portable smoke
2026-05-18 20:05:24 +08:00
程序员阿江(Relakkes)
8cd8ed16f0 Merge terminal shell env fix into main
The worktree fix diverged from local main because main already contains local desktop update proxy work. Merge the completed worktree commit into main so the terminal-like environment behavior lands without rewriting either line of local history.

Constraint: Local main is not an ancestor of the worktree commit, so fast-forward merge is unavailable
Rejected: Rebase or cherry-pick the worktree commit | user requested a worktree-to-main merge
Confidence: high
Scope-risk: moderate
Directive: Preserve the terminal shell env merge order when touching desktop subprocess startup
Tested: bun run verify
Not-tested: Push or remote PR validation
2026-05-18 15:15:17 +08:00
程序员阿江(Relakkes)
af5175aa2a fix: Align desktop subprocesses with terminal shell env
Desktop launches can inherit a sparse GUI environment, while user runtimes such as nvm and Homebrew are often initialized from shell startup files. Capture a bounded login+interactive shell environment once and reuse it for desktop CLI sessions, scheduled tasks, and MCP stdio startup while keeping explicit MCP PATH and provider-managed env overrides authoritative.

Constraint: macOS app launches may omit user shell PATH and exported runtime variables
Rejected: Patch only MCP stdio | leaves normal desktop sessions and scheduled tasks inconsistent
Confidence: high
Scope-risk: moderate
Directive: Keep provider/OAuth scrubbing after shell env merging when changing child env builders
Tested: bun test src/utils/terminalShellEnvironment.test.ts src/utils/mcpStdioEnvironment.test.ts src/server/services/mcpHostPreflight.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/cron-scheduler-launcher.test.ts src/server/__tests__/mcp.test.ts
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Real desktop UI live-model smoke on an installed .app
2026-05-18 15:13:06 +08:00
程序员阿江(Relakkes)
010a4bf9d8 fix: preserve custom slash commands after live updates
The desktop command list could be replaced by a partial live CLI update after a turn, and the server fallback only knew about skills. Keep the client list stable while refreshing from the authoritative session endpoint, and include legacy .claude/commands entries in that endpoint.

Constraint: Claude Code custom slash commands still use .claude/commands/*.md alongside newer skill commands.
Rejected: Only union client-side updates | would still miss custom commands before CLI init and lose argument hints from the authoritative API.
Confidence: high
Scope-risk: moderate
Directive: Keep session slash command fallback aware of both skills and legacy command directories.
Tested: bun test src/server/__tests__/sessions.test.ts -t "slash-commands"
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:native
Not-tested: bun run verify remains red due unrelated/flaky coverage lane failures outside this change.
Related: https://github.com/NanmiCoder/cc-haha/issues/495
2026-05-18 14:38:40 +08:00
Relakkes Yang
3c3030fddf fix: recover legacy Windows session workdirs 2026-05-18 13:13:12 +08:00
程序员阿江(Relakkes)
3ebab4366d Merge remote main updates 2026-05-16 22:04:47 +08:00
程序员阿江(Relakkes)
45b6674726 Place goal background work in the transcript
Goal runs spawn visible background work while the conversation is active, so the desktop should show those events at their actual transcript position instead of pinning a separate panel above the chat. The UI now renders background task records as inline message events, repairs restored task state from transcript notifications, and keeps later task updates on the original event card.

Constraint: Existing transcripts only persist terminal task notifications, so the server now preserves their timestamps for deterministic restore ordering.

Rejected: Keep the page-level background-agent panel | it occluded the session content and duplicated message-flow information.

Confidence: high

Scope-risk: moderate

Directive: Background task message timestamps intentionally stay fixed after insertion; update the task content without moving the card in the transcript.

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

Tested: cd desktop && bun run lint

Tested: bun test src/server/__tests__/sessions.test.ts
2026-05-16 21:38:52 +08:00
Relakkes Yang
9fbfd906d0 fix: open Windows external targets reliably 2026-05-16 21:17:39 +08:00
程序员阿江(Relakkes)
3fb3d24911 Reveal background agent progress during goal runs
Desktop sessions previously only showed the final local-agent output, so long verification phases looked stalled even while the CLI was still working. The websocket bridge now forwards task start/progress events, and the desktop session state renders them as a compact background-agent panel below the active goal.

Constraint: CLI already emits task lifecycle events; desktop needed to consume the existing stream instead of polling transcript files.
Rejected: Wait for final task notifications only | that keeps the long-running phase invisible.
Confidence: high
Scope-risk: moderate
Directive: Keep task_started/task_progress available as structured desktop notifications when changing CLI event translation.
Tested: bun run verify (passed=8 failed=0 skipped=2)
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:native
Tested: bun run check:coverage
Not-tested: Post-formatting check:server rerun was intentionally stopped at user request.
2026-05-16 18:21:33 +08:00
程序员阿江(Relakkes)
174c6757f2 Drop prelaunch goal transcript compatibility
The /goal feature has not shipped, so the desktop and CLI paths should only understand the current set/clear protocol instead of carrying transitional transcript formats. This removes Goal created/replaced and old status-block parsing from hydration, WebSocket forwarding, and desktop history mapping.

Constraint: Feature is still pre-release, so historical Goal created/replaced transcript compatibility is unnecessary.

Rejected: Keep old status-block hydration | it preserves a surface that users never received and makes the simplified /goal protocol harder to reason about.

Confidence: high

Scope-risk: narrow

Directive: Do not re-add legacy /goal status-block parsing unless a shipped transcript format requires it.

Tested: bun test src/commands/goal/goal.test.tsx src/goals/goalState.test.ts src/goals/goalEvaluator.test.ts src/server/__tests__/ws-memory-events.test.ts src/server/__tests__/sessions.test.ts src/server/__tests__/conversations.test.ts

Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/pages/ActiveSession.test.tsx src/components/chat/composerUtils.test.ts src/__tests__/pages.test.tsx
2026-05-16 12:39:27 +08:00
程序员阿江(Relakkes)
818dc7a178 Merge simplified goal command into main
This merge carries the set/clear /goal behavior from the Codex worktree into local main while preserving main's memory-style desktop goal cards and compact active-goal banner.

Constraint: Local main already had unrelated version/Tauri/release-note worktree changes and a newer goal UI style.\nRejected: Overwrite main's goal card UI with the worktree version | user wanted the memory-style visual direction already present on main.\nConfidence: high\nScope-risk: moderate\nTested: bun test src/commands/goal/goal.test.tsx src/goals/goalState.test.ts src/goals/goalEvaluator.test.ts src/server/__tests__/ws-memory-events.test.ts src/server/__tests__/conversations.test.ts\nTested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/pages/ActiveSession.test.tsx src/components/chat/composerUtils.test.ts\nNot-tested: Full bun run verify on main was not rerun after merge because unrelated dirty release/version files are present in the main worktree.
2026-05-16 03:35:53 +08:00
程序员阿江(Relakkes)
606f3c0dc2 Simplify goal command into an immediate set-clear loop
The previous /goal surface exposed management subcommands that made the CLI and desktop behavior hard to reason about. This keeps the user-facing command close to Claude Code's set/clear interaction while preserving historical transcript hydration and the existing evaluator loop.

Constraint: Desktop must see a live goal event before the model reaches the next tool call.\nRejected: Keep status/pause/resume/complete slash subcommands | requested UX is only set and clear.\nConfidence: high\nScope-risk: moderate\nDirective: Keep /goal user-facing syntax compact; extend internals without expanding the slash picker unless product explicitly asks.\nTested: bun test src/commands/goal/goal.test.tsx src/goals/goalState.test.ts src/goals/goalEvaluator.test.ts src/server/__tests__/ws-memory-events.test.ts src/server/__tests__/conversations.test.ts\nTested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/pages/ActiveSession.test.tsx src/components/chat/composerUtils.test.ts\nTested: bun run check:server\nTested: cd desktop && bun run lint\nTested: cd desktop && bun run build\nTested: ./bin/claude-haha -p '/goal smoke verify immediate goal output' --output-format stream-json --include-partial-messages --max-turns 1 --no-session-persistence --verbose emitted immediate system.local_command_output before model stream\nTested: ./bin/claude-haha -p '/goal clear' --output-format stream-json --include-partial-messages --max-turns 1 --no-session-persistence --verbose exited with duration_api_ms=0 and No active goal\nNot-tested: Browser click smoke was blocked by Chrome DevTools transport closing and Computer Use cgWindowNotFound on this machine.
2026-05-16 03:28:48 +08:00
程序员阿江(Relakkes)
929ddd0ebe Refine goal session presentation
Goal sessions need to feel like an ongoing agent-loop state, not a large success alert dropped into the chat. The UI now uses compact status and event treatments, and session titles stay anchored to the original goal objective instead of later /goal status commands.

Constraint: /goal history uses local_command transcript entries and later status checks can append fresh AI titles.
Rejected: Keep the existing green cards | they duplicate the objective, consume too much vertical space, and read as one-off notifications instead of durable loop state.
Confidence: high
Scope-risk: narrow
Directive: Goal status UI should remain compact and stateful; do not reintroduce large centered cards for routine lifecycle events.
Tested: bun test src/server/__tests__/sessions.test.ts
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/pages/ActiveSession.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: Browser preview at 127.0.0.1:5179 with real session 3e9117d5-b792-43c9-bf57-7aec2b124f7e on desktop and mobile viewport
Not-tested: Packaged macOS app rebuild.
2026-05-16 01:28:09 +08:00
程序员阿江(Relakkes)
052cc4da5d Preserve goal command breadcrumbs for history restore
Desktop history can only render the original /goal prompt if the session API returns the raw system local_command transcript entries. The prior fix handled frontend rendering, but the server dropped those entries because they do not carry message.role.

This keeps only /goal local command input and goal-like output records in getSessionMessages while leaving other internal command breadcrumbs filtered.

Constraint: Real CLI transcripts store /goal input/output as system local_command records without message.role.
Rejected: Expose all local_command records | would leak unrelated internal command breadcrumbs such as /exit.
Confidence: high
Scope-risk: narrow
Directive: Keep this allowlist goal-specific unless another command explicitly needs visible history restore.
Tested: bun test src/server/__tests__/sessions.test.ts
Tested: bun test src/commands/goal/goal.test.tsx src/goals/goalState.test.ts src/goals/goalEvaluator.test.ts
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/pages/ActiveSession.test.tsx
Tested: cd desktop && bun run lint
Tested: real sessionService.getSessionMessages for 3e9117d5-b792-43c9-bf57-7aec2b124f7e returns initial /goal local_command entries
Not-tested: Packaged app rebuild after this server API fix.
2026-05-16 01:11:21 +08:00
程序员阿江(Relakkes)
c75ff0bf2d Merge /goal desktop visibility fix 2026-05-16 00:10:10 +08:00
程序员阿江(Relakkes)
87caeb8cb0 Keep typed slash command events visible in desktop
Desktop muted CLI output until the user turn was fully enqueued, which dropped early local_command events for typed slash commands such as /goal. The transcript still recorded the goal, but the live desktop client missed the goal event and active-goal indicator. This forwards only the current typed command lifecycle through the pre-turn mute gate while keeping unrelated startup chatter and stale command output suppressed.

Constraint: Desktop must show /goal creation immediately while preserving the pre-turn mute gate for SDK startup noise

Rejected: Forward all pre-turn local command output | would reintroduce stale or unrelated CLI chatter into fresh desktop turns

Confidence: high

Scope-risk: narrow

Directive: Do not widen this gate without verifying /cost, /context, /goal, and reconnect startup behavior

Tested: bun test src/server/__tests__/ws-memory-events.test.ts src/server/__tests__/conversations.test.ts -t 'local command output|/cost|/context|goal|pre-turn mute'

Tested: bun run check:server

Not-tested: live desktop manual smoke after rebuilding/restarting the app
2026-05-16 00:09:39 +08:00
程序员阿江(Relakkes)
b4a5c09b11 fix: expose plugin skills in new session slash commands
New desktop sessions populated slash suggestions from the session endpoint before the CLI had emitted init metadata. That endpoint only scanned user and project skill directories, while the plugin settings view and global skills API already saw enabled plugin skills such as superpowers. The session endpoint now reuses the global skill listing and merges it with any cached CLI slash commands, and both composer surfaces rank command-name matches before broad description matches so /su surfaces superpowers first.

Constraint: New sessions need plugin skills before the first real user turn starts the CLI.

Rejected: Start or restart a hidden CLI process on plugin enable | heavier than needed and still misses the REST slash-command fallback path.

Confidence: high

Scope-risk: moderate

Directive: Keep session slash commands and /api/skills on the same skill discovery path when changing plugin skill loading.

Tested: bun test src/server/__tests__/skills.test.ts src/server/__tests__/plugins.test.ts src/server/__tests__/sessions.test.ts

Tested: cd desktop && bun run test --run src/components/chat/composerUtils.test.ts src/pages/EmptySession.test.tsx src/components/chat/ChatInput.test.tsx

Tested: bun run check:server

Tested: cd desktop && bun run lint

Not-tested: Manual desktop click-through in the packaged app.
2026-05-16 00:03:44 +08:00
程序员阿江(Relakkes)
62713f30de Merge commit '376fc6de' 2026-05-15 23:27:02 +08:00
程序员阿江(Relakkes)
376fc6de62 Make /goal durable across CLI and desktop sessions
The goal flow needs to drive the agent loop and remain visible after desktop reconnects, so this change treats /goal output as a structured lifecycle signal across CLI, server, and desktop history restoration.

Constraint: The current TypeScript CLI does not share Codex's Rust app-server thread-goal database, so persistence is reconstructed from the existing session transcript.

Rejected: UI-only goal badges | would leave the CLI self-loop unable to recover active or completed goals after process restart.

Rejected: Add a new persisted store | larger migration surface than needed for the existing transcript-backed session model.

Confidence: high

Scope-risk: moderate

Directive: Keep future goal state changes mirrored in transcript-visible local command output or introduce a real migration-backed store.

Tested: bun test src/goals/goalEvaluator.test.ts src/goals/goalState.test.ts

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

Tested: bun run verify

Not-tested: Live provider baseline with a real model-driven goal loop.
2026-05-15 23:26:54 +08:00
程序员阿江(Relakkes)
6ec8ae626b fix: refresh server plugin skills after enable toggles
The previous hot-reload fix covered the running CLI process, but empty desktop sessions build their slash skill list through the server-side /api/skills path. If the server had already cached disabled plugin settings, /api/plugins/reload could still reload plugin state from stale settings and /api/skills stayed empty until a real chat spawned a fresh CLI.

Reset the server settings cache at the plugin reload boundary before clearing plugin caches. This keeps the desktop server, active CLI reload, and empty-session skills API aligned on enable-after-disable transitions.

Constraint: EmptySession uses /api/skills, not the active CLI slash-command cache

Rejected: Rely on starting a real CLI session to repopulate skills | delays visibility and makes empty-session slash commands stale

Confidence: high

Scope-risk: narrow

Directive: Plugin reload paths must invalidate settings before resolving enabledPlugins

Tested: bun test src/server/__tests__/skills.test.ts src/server/__tests__/plugins.test.ts

Tested: bun run check:server

Tested: cd desktop && bun run test --run src/pages/EmptySession.test.tsx src/stores/pluginStore.test.ts
2026-05-15 21:39:24 +08:00
程序员阿江(Relakkes)
70dc9ab111 fix: refresh plugin settings before slash reload
Desktop plugin enable and disable actions are written by the server process, while an already-running CLI owns its own settings cache. Reloading only the plugin caches left enabledPlugins stale after a disable-then-enable cycle, so the slash command list stayed empty until a new conversation spawned a fresh CLI.

Reset the settings cache at the active plugin refresh boundary before resolving enabled plugins. The regression test simulates an external desktop enable toggle after a cached disabled read and verifies the plugin slash command is restored in the same refresh.

Constraint: Desktop server and active CLI are separate processes with independent in-memory settings caches

Rejected: Restart the CLI on every plugin toggle | heavier user-visible lifecycle change and unnecessary once the reload handoff invalidates settings

Confidence: high

Scope-risk: narrow

Directive: Keep reload_plugins as the handoff that rereads settings before plugin command discovery

Tested: bun test src/server/__tests__/plugins.test.ts

Tested: bun run check:server
2026-05-15 20:56:30 +08:00
程序员阿江(Relakkes)
059d2f0ee0 Merge desktop plugin hot refresh into main 2026-05-15 19:51:22 +08:00
程序员阿江(Relakkes)
de63d82633 fix: keep desktop plugin changes visible without restarting chats
Plugin enablement already has a live CLI reload control path, so desktop now applies plugin changes by refreshing the active session instead of waiting for a future conversation startup. The server forwards reload_plugins to the active CLI session, refreshes session slash-command cache, and notifies the client. The desktop plugin store automatically reloads after mutating plugin state, and the empty-session composer refetches skills when plugin capabilities change.

Constraint: Existing CLI exposes reload_plugins as the supported hot-refresh mechanism for commands, agents, plugins, and MCP state.

Rejected: Start a hidden replacement CLI process | higher cost, extra process lifecycle risk, and less precise than the existing control channel.

Confidence: high

Scope-risk: moderate

Directive: Keep plugin refresh routed through reload_plugins unless the CLI control contract is removed or changed.

Tested: bun test src/server/__tests__/plugins.test.ts

Tested: cd desktop && bun run test --run src/stores/pluginStore.test.ts src/__tests__/pluginsSettings.test.tsx src/pages/EmptySession.test.tsx

Tested: bun run check:server

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run build

Not-tested: bun run check:desktop is blocked by a pre-existing color-mix compatibility failure in desktop/src/theme/globals.css.
2026-05-15 19:51:01 +08:00
程序员阿江(Relakkes)
7df77ac6e1 Merge provider thinking controls into local main
The detached worktree carried the verified desktop Thinking fixes, while local main already had one newer memory-path commit. This merge brings the provider/runtime Thinking behavior into main without rewriting the existing main history.

Constraint: Local main is the checked-out integration branch and was ahead of the worktree base
Rejected: Rebase the detached worktree onto main | unnecessary history rewrite for a local integration request
Rejected: Fast-forward main | impossible because main already had newer local commits
Confidence: high
Scope-risk: moderate
Directive: Keep c866adc9 as the feature commit for detailed implementation context
Tested: bun test src/server/__tests__/ws-memory-events.test.ts
Tested: bun run verify before integration on the feature commit
Not-tested: Full verify after the merge commit; merge was conflict-free except automatic conversationService integration
2026-05-15 19:35:49 +08:00
程序员阿江(Relakkes)
c866adc951 Honor desktop thinking controls for provider streams
Desktop sessions must treat the global Thinking toggle as the source of truth across active CLI sessions, title generation, and provider-compatible request bodies. DeepSeek-style streams can start with reasoning blocks before text, so the WebSocket bridge now keeps the UI in thinking state until text content actually starts.

Constraint: DeepSeek and MiniMax use Anthropic-compatible surfaces but expose thinking behavior through provider-specific request and stream shapes
Rejected: Keep provider-specific disabled-thinking env defaults | stale defaults kept overriding the user's global Thinking setting
Rejected: Treat every non-tool stream block as text | reasoning-only startup blocks created a blank streaming gap before the visible thinking bubble
Confidence: high
Scope-risk: moderate
Directive: Do not change thinking stream state transitions without replaying reasoning-before-text provider events
Tested: bun test src/server/__tests__/ws-memory-events.test.ts
Tested: bun run check:server
Tested: bun run verify
Not-tested: Live DeepSeek provider smoke with real quota
2026-05-15 19:35:12 +08:00
程序员阿江(Relakkes)
02f23d6e3b Keep desktop memory paths aligned with runtime
Desktop memory settings already resolves project memory through the current sanitized project directory, while spawned CLI sessions could compute an older path variant and fail to read indexed memory files. Pin the child runtime to the same memory directory and let memory preview links open related markdown files directly from the rendered panel.

Constraint: Existing memory files may already live under both legacy underscore and current hyphenated project directories.
Rejected: Symlink or merge memory directories | it could mix stale legacy memory entries into the active project index.
Confidence: high
Scope-risk: moderate
Directive: Keep Settings memory discovery and spawned CLI memory context on the same project identity before changing either sanitizer.
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/memory.test.ts
Tested: bun run check:server
Tested: cd desktop && bun run test -- MemorySettings MarkdownRenderer
Tested: cd desktop && bun run build
Tested: Browser smoke on local Vite/server for memory preview link navigation
Not-tested: bun run check:desktop still has pre-existing vite-config color-mix guard failure in desktop/src/theme/globals.css
2026-05-15 19:34:16 +08:00
程序员阿江(Relakkes)
4e969475f2 Improve session project sidebar controls
The session sidebar already uses project grouping, so the change adds header-level project actions instead of replacing project row controls. Sorting and organization choices are persisted through the existing desktop UI preferences file and mirrored into local cache for startup continuity.

Constraint: Keep the existing project tree, drag ordering, pinning, hiding, and Finder project-row actions intact.

Rejected: Replacing project row actions with the header menu | row-level Finder and per-project session actions are still useful and already covered by tests.

Confidence: high

Scope-risk: moderate

Directive: Do not store sidebar organization in global Claude settings; keep it under cc-haha desktop-ui preferences.

Tested: cd desktop && bun run test -- src/components/layout/Sidebar.test.tsx

Tested: bun test src/server/__tests__/desktop-ui-preferences.test.ts

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run build
2026-05-15 16:49:18 +08:00
程序员阿江(Relakkes)
5d9d1b009e Persist sidebar project preferences across desktop and H5
Sidebar project ordering, pinning, and hidden-project state must survive
browser access to the same local server, so the UI now stores these
preferences under the cc-haha config directory and keeps localStorage as
a migration/cache fallback.

Constraint: Browser and H5 localStorage is isolated from the Tauri WebView
Rejected: Keep sidebar project preferences only in localStorage | browser sessions would not share state
Rejected: Reuse cc-haha/settings.json | provider and H5 access settings should stay separate
Confidence: high
Scope-risk: moderate
Directive: Keep sidebar hide/remove semantics non-destructive; do not delete transcript files for project removal
Tested: cd desktop && bun run test -- src/components/layout/Sidebar.test.tsx --run
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/desktop-ui-preferences.test.ts
Tested: bun run check:persistence-upgrade
Tested: bun run check:server
2026-05-15 16:30:39 +08:00
程序员阿江(Relakkes)
0e78439f9d Group desktop sessions by project root
The desktop sidebar needed a project-first navigation model that keeps worktree sessions attached to their source project instead of scattering them as separate paths. The UI now renders sessions under project groups with project-level actions and persisted ordering, while the server exposes a logical project root for worktree transcripts.

Constraint: Existing memory directory tree work must remain separate from the session sidebar behavior.

Rejected: Group by raw transcript projectPath | worktree paths fragment the same repository into multiple sidebar projects.

Confidence: high

Scope-risk: moderate

Directive: Keep future sidebar grouping keyed by projectRoot before projectPath so isolated worktrees stay under their source repository.

Tested: cd desktop && bun run test -- src/components/layout/Sidebar.test.tsx

Tested: bun test src/server/__tests__/sessions.test.ts

Tested: git diff --check
2026-05-15 16:01:36 +08:00
程序员阿江(Relakkes)
e292d83282 fix: Prevent cached settings writes from resetting desktop preferences
Desktop settings writes update settings.json through SettingsService, while plugin
state writes use the shared CLI settings cache. Reset the shared cache after a
successful atomic SettingsService write so later plugin updates merge against the
fresh file instead of an older in-memory snapshot.

Constraint: Desktop general settings and plugin state share ~/.claude/settings.json but use different write paths
Rejected: Move plugin writes onto SettingsService | broader API change than needed for this regression
Confidence: high
Scope-risk: narrow
Directive: Keep cache invalidation aligned across all settings.json write paths
Tested: bun test src/server/__tests__/settings.test.ts -t "cached CLI settings"
Tested: bun test src/server/__tests__/settings.test.ts src/server/__tests__/plugins.test.ts
Tested: cd desktop && bun run test -- generalSettings settingsStore pluginsSettings
Tested: bun run check:server
Tested: git diff --check
Not-tested: Full bun run verify still fails on unrelated dirty desktop changed-line coverage and CSS color-mix gate
2026-05-15 10:54:40 +08:00
程序员阿江(Relakkes)
45ec701124 Bring responsive desktop sessions and thinking controls onto main
This merge carries the worktree fix into the local main branch so long multi-session desktop usage keeps rendering cost bounded while DeepSeek follows the shared General Settings Thinking toggle. It preserves running-session behavior and keeps legacy DeepSeek managed env from pinning thinking off after upgrade.

Constraint: User requested the worktree result merged into local main without pushing.
Confidence: high
Scope-risk: moderate
Directive: Keep DeepSeek controlled by the global Thinking setting; do not restore provider-specific disabled-thinking defaults without both toggle-state tests.
Tested: bun test src/server/__tests__/conversations.test.ts -t "global Thinking setting control DeepSeek"
Tested: bun test src/server/__tests__/persistence-upgrade.test.ts src/server/__tests__/provider-presets.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/title-service.test.ts src/utils/__tests__/thinking.test.ts src/utils/__tests__/providerManagedEnvCompat.test.ts
Tested: cd desktop && bun run test -- MessageList.test.tsx ContextUsageIndicator.test.tsx
Tested: bun run check:server
2026-05-14 22:42:30 +08:00
程序员阿江(Relakkes)
611f09a1a7 Keep long desktop sessions responsive while honoring thinking controls
Virtualized chat rendering keeps inactive long-running sessions cheap without disconnecting their CLI process, while DeepSeek now relies on the shared Thinking setting instead of a provider-specific disabled-thinking override. Existing legacy DeepSeek managed env is normalized so old local settings do not keep suppressing reasoning output after upgrade.

Constraint: Multiple desktop tabs must keep live sessions running and remain quick to switch without reconnecting.
Rejected: Pause or disconnect hidden sessions | would delay tab switching and interrupt streaming/tool state visibility.
Rejected: Keep DeepSeek disabled-thinking preset | conflicts with the General Settings Thinking control.
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce provider-specific disabled-thinking defaults for DeepSeek without testing both General Settings toggle states.
Tested: bun test src/server/__tests__/conversations.test.ts -t "global Thinking setting control DeepSeek"
Tested: bun test src/server/__tests__/persistence-upgrade.test.ts src/server/__tests__/provider-presets.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/title-service.test.ts src/utils/__tests__/thinking.test.ts src/utils/__tests__/providerManagedEnvCompat.test.ts
Tested: cd desktop && bun run test -- MessageList.test.tsx ContextUsageIndicator.test.tsx
Tested: bun run check:server
2026-05-14 22:42:01 +08:00
程序员阿江(Relakkes)
e070c4a0d0 Make upgrade failures diagnosable without deleting user state
Desktop startup can fail before React mounts on older WebViews, so an HTML-level watchdog now renders startup diagnostics even when the module bundle never reaches the app code. Persistent provider migration now imports legacy root provider config into cc-haha-owned storage without deleting the old source file, and plugin marketplace cleanup refuses obvious corrupted cache roots or outside paths.

Constraint: User explicitly accepted the current reviewed state for landing despite remaining review concerns.

Constraint: Global ~/.claude state is user-owned and protected; automatic repair must avoid deleting shared config, transcripts, skills, MCP, plugins, OAuth, adapters, and teams.

Rejected: Tell users to delete ~/.claude or ~/.claude/cc-haha | unsafe because it can destroy user-owned Claude state and still may not fix WebView compatibility failures.

Confidence: medium

Scope-risk: moderate

Directive: Do not weaken protected-path checks; future deletion paths should validate real paths and symlink behavior before recursive rm.

Tested: bun test src/utils/plugins/installedPluginsManager.test.ts src/utils/plugins/marketplaceManager.test.ts

Tested: bun run check:server

Tested: cd desktop && bun run test -- --run src/main.test.tsx index-html.test.ts vite-config.test.ts src/theme/globals.test.ts

Tested: cd desktop && bun run build

Tested: bun run check:coverage

Not-tested: live macOS 12/Safari 15 WKWebView startup on an affected machine.

Not-tested: H5 diagnostic URL redaction and symlink-escape hardening are known follow-up risks from review.
2026-05-14 18:04:47 +08:00
程序员阿江(Relakkes)
6b77120515 Align settings resource discovery with runtime
Settings reported false negatives for resources the runtime could load, because the API paths used narrower discovery rules than the execution path. This keeps the Settings surfaces read-only where appropriate while matching runtime visibility for linked skills, version-constrained plugins, and merged MCP sources.

Constraint: Settings MCP list must not actively connect to servers while loading.
Rejected: Add UI-specific fallbacks | would preserve drift between Settings and runtime loaders
Confidence: high
Scope-risk: moderate
Directive: Keep Settings resource listing backed by the same shared loader semantics as runtime discovery.
Tested: bun test src/server/__tests__/skills.test.ts
Tested: bun test src/server/__tests__/plugins.test.ts
Tested: bun test src/server/__tests__/mcp.test.ts
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Live external MCP connector account state
2026-05-13 22:11:24 +08:00
程序员阿江(Relakkes)
f455065997 Merge desktop memory surface into main
This brings the desktop memory worktree onto local main after main advanced with opener, IM, zoom, and autonomous goal work. The conflict resolution keeps both the selected-chat reference imports and memory event settings entrypoint in MessageList, and keeps both open-targets and memory API routes in the server router.

Constraint: main and feat/desktop-memory-surface diverged across desktop chat and server routing.
Constraint: desktop Vitest runs src-tauri tests under Vitest, so the Tauri config test cannot import bun:test.
Rejected: Fast-forward merge | main carried newer local commits not present on the memory branch.
Confidence: high
Scope-risk: moderate
Directive: Keep chat selection references, memory cards, open-target routes, and memory routes together when touching these files.
Tested: bun run check:desktop
Tested: bun run check:server
2026-05-13 21:05:54 +08:00
程序员阿江(Relakkes)
07050bb91c Allow packaged opener icons to load
Tauri WebView was allowed to call the desktop sidecar API, but the CSP still blocked image loads from that same local server, so extracted IDE icons degraded to the generic code glyph in packaged builds. macOS detection also trusted command shims before app bundles, which let stale JetBrains Toolbox scripts keep removed IDEs visible.

Constraint: Opener icons are served by the per-run desktop sidecar on localhost or 127.0.0.1

Rejected: Bundle a fixed static icon set | the product should use detected installed application icons across platforms

Rejected: Trust macOS command shims for detection | stale shims survive app removal and make the menu lie

Confidence: high

Scope-risk: narrow

Directive: Keep macOS IDE detection anchored to real app bundles before accepting command shims

Tested: bun test src/server/__tests__/open-target-service.test.ts src/server/__tests__/open-target-api.test.ts desktop/src-tauri/tauri-config.test.ts

Tested: cd desktop && bun run test -- src/api/client.test.ts src/api/openTargets.test.ts src/stores/openTargetStore.test.ts src/components/layout/OpenProjectMenu.test.tsx src/components/layout/TabBar.test.tsx

Tested: cd desktop && bun run lint
2026-05-13 18:42:30 +08:00