15 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
892f5e193a fix(desktop): restore permission mode after exiting plan mode (#623)
桌面端用 bypassPermissions 进入计划模式、退出后,权限选择器停留在"计划模式",
导致下一个工具调用又弹权限申请。两层根因都修:

- 回传链路断裂:服务端 WS handler 把 CLI 广播的权限模式变化(status:null +
  permissionMode)当成 thinking 丢弃,桌面端协议也没有承载权限模式的入站消息,
  CLI 恢复后的权限永远同步不到 UI。新增 permission_mode_changed 回传通道,桌面端
  据此校正选择器(只更新本地、不回发避免回环;未知模式忽略)。

- 重启抹掉 prePlanMode:bypass→plan 因策略"切换涉及 bypass 就重启"而重启 CLI,
  新进程直接以 plan 启动、prePlanMode 为空,ExitPlanMode 只能恢复成 default 而非
  bypassPermissions。收窄 needsRestart 为只在"进入 bypass"时重启;从 bypass 切出
  保持进程不变、走进程内 transition,CLI 才会栈存 prePlanMode 并在退出 plan 时
  正确恢复 bypass,与 TUI 行为一致。

测试:服务端 ws-memory-events 新增权限回传 + 重启策略用例;桌面端 chatStore 新增
回传校正 + 防回环 + 未知模式忽略用例。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:29:01 +08:00
程序员阿江(Relakkes)
349955dbf2 fix: route agent slash through normal chat (#653)
/agent should behave like a normal session prompt that tells the main model to use the selected Agent tool. The previous forked command path buffered the subagent run behind local command output and forced desktop clients to wait for command completion instead of seeing the normal Agent interaction stream.

Constraint: Desktop /agent must preserve ordinary chat/session semantics and still require /agent <agent> <prompt>.
Rejected: Keep slash_agent SDK event bridging | it preserves the separate forked execution path instead of fixing the product flow.
Confidence: high
Scope-risk: moderate
Directive: Do not move /agent back to context: fork without proving the desktop normal Agent tool stream still works.
Tested: bun test src/commands/agent.test.ts src/utils/processUserInput/processSlashCommand.test.ts src/server/__tests__/ws-memory-events.test.ts
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx
Tested: git diff --check
Not-tested: bun run check:server is blocked before source checks by expired quarantine entries: server:cron-scheduler, server:providers-real, server:tasks, server:e2e:business-flow, server:e2e:full-flow
2026-06-03 11:41:12 +08:00
程序员阿江(Relakkes)
0ebb0582b0 fix: stream agent slash progress to desktop (#653)
The desktop /agent slash path runs before the normal query loop, so the old implementation waited for the forked command to finish and only surfaced the final local-command stdout. Emit foreground slash-agent task events from /agent, drain SDK events while QueryEngine waits for pre-query slash processing, and allow those current-turn events through the WebSocket pre-send mute gate.

Constraint: /agent is a forked slash command that does not produce ordinary assistant deltas until its final stdout is synthesized.

Rejected: Frontend-only loading state | would not expose real forked-agent progress or tool/tool-result updates.

Confidence: high

Scope-risk: moderate

Directive: Keep slash_agent task events scoped to /agent; ordinary slash command stdout and /goal event handling should remain on the existing local-command paths.

Tested: bun test src/QueryEngine.test.ts src/utils/processUserInput/processSlashCommand.test.ts src/server/__tests__/ws-memory-events.test.ts

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

Not-tested: bun run check:server is blocked by expired quarantine review entries: server:cron-scheduler, server:providers-real, server:tasks, server:e2e:business-flow, server:e2e:full-flow
2026-06-03 11:25:36 +08:00
程序员阿江(Relakkes)
998e85efab fix: localize synthetic business errors
Synthetic API errors were carrying only English display text, so desktop chat could not distinguish our compatibility guidance from raw upstream failures and recovery logic depended on those English strings.

Add stable business error codes for media, PDF, request-size, prompt-length, and auto-mode errors. Desktop chat now resolves those codes through locale keys and suppresses the stale English fallback for known business errors, while normalizeMessagesForAPI still supports legacy text matching for old transcripts.

Constraint: Raw upstream provider details must remain available for diagnostics but should not drive localized business UX.

Rejected: Localize src/services/api/errors.ts strings directly | that would make persisted transcript text and media recovery depend on the active UI language.

Confidence: high

Scope-risk: moderate

Directive: Add new user-facing synthetic API errors with businessErrorCode values before localizing their display text.

Tested: bun test src/services/api/errors.test.ts tests/mediaRecoveryAndEstimation.test.ts src/server/__tests__/ws-memory-events.test.ts

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

Tested: bun run check:server

Tested: bun run check:desktop

Not-tested: Manual desktop screenshot smoke for the rendered Chinese error card
2026-06-01 00:36:29 +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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
df9775a6eb Surface project memory where desktop users can act on it
The CLI already emits memory_saved events and stores Markdown memory files, but the desktop app had no usable surface for seeing or editing those writes. This adds a project memory API, a Settings memory editor, chat memory event cards, and routing from /memory or /context into the memory UI.

Constraint: Memory files live under Claude project storage and must remain plain Markdown editable by users.
Rejected: Only expose raw filesystem links | users need an in-app review and edit flow from chat.
Confidence: high
Scope-risk: moderate
Directive: Keep memory storage project-scoped and preserve unknown Markdown content when editing.
Tested: bun test src/server/__tests__/ws-memory-events.test.ts src/server/__tests__/memory.test.ts
Tested: bun run check:server
Tested: bun run check:desktop
Tested: agent-browser E2E for chat memory card, Open Memory navigation, and responsive Markdown editor layout
Not-tested: Live model auto-memory trigger rate with real provider credentials
2026-05-13 14:07:13 +08:00