345 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
5f9faaf01d feat: support H5 mobile chat access
H5 browser use needs to keep local desktop WebUI testing open while giving remote phones a usable chat-first surface. This change scopes browser auth by origin and target host, hides non-chat desktop chrome on H5 mobile, compacts the empty-session composer, and unifies mobile selectors behind a full-width bottom sheet with an explicit close action.

Constraint: Local browser development may bypass H5 auth only for loopback or private LAN server hosts; public or remote hosts still require an H5 token.

Constraint: Mobile H5 scope is chat-first; settings and scheduled-task surfaces stay hidden instead of fully redesigned.

Rejected: Reuse desktop popovers on mobile | hover/anchored dropdown behavior leaves key actions hard to dismiss and cramped on narrow screens.

Rejected: Let any localhost origin bypass remote auth | it would let arbitrary local pages access public H5 servers without a token.

Confidence: medium

Scope-risk: moderate

Directive: Keep future H5 selector popups on MobileBottomSheet unless a selector needs a reviewed custom mobile interaction.

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx src/components/chat/ChatInput.test.tsx src/lib/desktopRuntime.test.ts src/components/shared/RepositoryLaunchControls.test.tsx src/components/controls/PermissionModeSelector.test.tsx src/components/controls/ModelSelector.test.tsx src/components/shared/DirectoryPicker.test.tsx src/__tests__/pages.test.tsx

Tested: bun test src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts

Tested: Chrome mobile viewport smoke for context, model, permission, project, branch, and worktree bottom sheets with no horizontal overflow.

Not-tested: Full bun run verify quality gate.
2026-05-10 11:30:03 +08:00
程序员阿江(Relakkes)
cc9bcb2017 Make H5 chat usable on phone-sized browsers
The browser H5 surface now switches to a phone-oriented shell: the sidebar becomes a closed-by-default drawer, chat stays primary, workspace and terminal panels stay off the mobile chat surface, composer controls use larger touch targets, and mobile menus avoid desktop-only widths and keyboard hints. Desktop and Tauri sidebar behavior remain on the existing store-driven path.

Constraint: H5 is personal/team browser access layered on the existing desktop web UI, so the normal desktop app must keep its current layout behavior.

Rejected: Share the global sidebarOpen default for mobile first paint | it can flash the drawer open before effects run on a phone.

Confidence: high

Scope-risk: moderate

Directive: Keep mobile-only layout branching behind useMobileViewport() && !isTauriRuntime() unless a future task explicitly redesigns the native desktop shell.

Tested: cd desktop && bunx vitest run src/hooks/useMobileViewport.test.tsx src/components/layout/AppShell.test.tsx src/components/layout/Sidebar.test.tsx src/pages/ActiveSession.test.tsx src/components/chat/ChatInput.test.tsx src/components/controls/PermissionModeSelector.test.tsx

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run build
2026-05-10 01:11:24 +08:00
程序员阿江(Relakkes)
b4242d894d Prevent remote H5 tokens from leaking into local browser sessions
Browser H5 startup now binds the in-memory bearer token only when the selected server URL is non-loopback, so stored remote credentials cannot follow a later localhost, 127.0.0.1, or IPv6 loopback startup. Token verification errors also use the structured HTTP status when available instead of relying only on message text.

Constraint: Browser H5 may reuse localStorage across remote and local server URLs.

Rejected: Clear all remembered H5 connection state on every loopback startup | preserving the remote URL is useful for the next remote retry and the token alone is the leak risk.

Confidence: high

Scope-risk: narrow

Directive: Keep browser auth token assignment gated by requiresH5AuthForServerUrl before adding new bootstrap paths.

Tested: cd desktop && bunx vitest run src/api/client.test.ts src/api/websocket.test.ts src/lib/desktopRuntime.test.ts src/components/layout/AppShell.test.tsx
2026-05-10 00:55:30 +08:00
程序员阿江(Relakkes)
5c1583f852 Preserve recoverable browser H5 startup paths behind proxies
Remote browser bootstrap now keeps reverse-proxy path prefixes, recognizes IPv6 loopback as local, and converts remote health or verify failures into recoverable H5 connection prompts instead of falling back to the generic startup error surface. Token invalidation clears only the stored token so users can retry without re-entering the server address.

Constraint: Review fixes must stay inside the existing Task 4 browser-runtime scope without changing the Tauri localhost startup path
Rejected: Clear both stored server URL and token on remote bootstrap failures | it forces unnecessary re-entry after stale credentials
Directive: Any future browser-mode startup error for non-loopback backends should remain recoverable through H5ConnectionView unless the desktop/Tauri contract changes
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bunx vitest run src/api/client.test.ts src/api/websocket.test.ts src/lib/desktopRuntime.test.ts src/components/layout/AppShell.test.tsx
Tested: cd desktop && bun run lint
Tested: git diff --check -- desktop/src/api/client.ts desktop/src/api/websocket.ts desktop/src/lib/desktopRuntime.ts desktop/src/components/layout/H5ConnectionView.tsx desktop/src/components/layout/AppShell.tsx desktop/src/api/client.test.ts desktop/src/api/websocket.test.ts desktop/src/lib/desktopRuntime.test.ts desktop/src/components/layout/AppShell.test.tsx
Not-tested: Live reverse-proxy browser session against a real remote H5 server
2026-05-10 00:35:42 +08:00
程序员阿江(Relakkes)
ba1807541a Enable authenticated browser bootstrap for remote H5 access
Browser-mode startup now preserves the desktop localhost path while prompting for H5 credentials when a non-loopback backend requires verification. The API client and websocket layer share a central token source so REST and session sockets authenticate consistently without leaking the token into diagnostics.

Constraint: Preserve the Tauri startup path and default localhost browser behavior
Rejected: Reuse the generic startup error view for H5 auth failures | it blocks the credential-entry recovery path
Directive: Non-loopback browser startup is the only path that should require saved H5 verification without re-checking the desktop bootstrap contract
Confidence: high
Scope-risk: moderate
Tested: cd desktop && bunx vitest run src/api/client.test.ts src/api/websocket.test.ts src/components/layout/AppShell.test.tsx
Tested: cd desktop && bun run lint
Tested: git diff --check -- desktop/src/api/client.ts desktop/src/api/websocket.ts desktop/src/lib/desktopRuntime.ts desktop/src/components/layout/H5ConnectionView.tsx desktop/src/components/layout/AppShell.tsx desktop/src/api/client.test.ts desktop/src/api/websocket.test.ts desktop/src/components/layout/AppShell.test.tsx
Not-tested: Live remote H5 browser session against a running server
2026-05-10 00:26:01 +08:00
程序员阿江(Relakkes)
4865b4f206 Keep H5 settings failures visible without persisting raw tokens
Limit the legacy fallback to missing H5 endpoints, preserve last known H5 settings on real load failures, and move the generated token lifetime into the General settings component so the raw token clears after copy or timeout instead of living in global state.

Constraint: Task 3 remains limited to desktop settings store, UI, and tests
Rejected: Treat every H5 load failure as disabled defaults | hides real outages and overwrites useful last-known state
Rejected: Keep raw tokens in Zustand until manually dismissed | re-exposes secrets after reopening Settings
Confidence: high
Scope-risk: narrow
Directive: Only 404/405 H5 endpoint misses should degrade to disabled defaults; all other H5 load failures must preserve state and surface h5AccessError
Tested: cd desktop && bunx vitest run src/__tests__/generalSettings.test.tsx src/stores/settingsStore.test.ts
Tested: cd desktop && bun run lint
Tested: git diff --check -- desktop/src/stores/settingsStore.ts desktop/src/pages/Settings.tsx desktop/src/stores/settingsStore.test.ts desktop/src/__tests__/generalSettings.test.tsx desktop/src/i18n/locales/en.ts desktop/src/i18n/locales/zh.ts
2026-05-10 00:14:34 +08:00
程序员阿江(Relakkes)
a677163e0d Make H5 browser access manageable from desktop settings
Add the desktop-side H5 settings client, store state, and General tab controls so users can opt in, regenerate tokens, manage origins, and copy the browser URL without touching unrelated desktop flows.

Constraint: Task 3 is limited to desktop Settings UI and store wiring only
Rejected: Expand into AppShell or browser runtime work now | reserved for later tasks in the plan
Confidence: high
Scope-risk: narrow
Directive: Keep H5 fetchAll integration tolerant of missing endpoint responses so existing settings loads do not regress
Tested: cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx src/stores/settingsStore.test.ts
Tested: cd desktop && bun run lint
2026-05-09 23:57:52 +08:00
程序员阿江(Relakkes)
065a80580b Render scheduled task summaries as markdown
Scheduled task results can contain assistant-authored markdown, but the
runs panel previously displayed that content as plain pre-wrapped text.
Reusing the desktop markdown renderer keeps task summaries aligned with
chat and settings surfaces while adding a compact prose variant for the
narrow log panel.

Constraint: Desktop task logs need dense formatting without introducing a new markdown dependency
Rejected: Keep whitespace-pre-wrap summary text | markdown syntax remains visible in completed task runs
Confidence: high
Scope-risk: narrow
Directive: Keep scheduled run summary rendering on the shared MarkdownRenderer path so links, lists, inline code, and future markdown fixes stay consistent
Tested: cd desktop && bun run test src/components/markdown/MarkdownRenderer.test.tsx src/components/tasks/TaskRunsPanel.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: bun run check:desktop
Tested: agent-browser E2E against isolated CLAUDE_CONFIG_DIR with real backend and Vite UI; verified strong/li/code/link DOM output and no raw markdown bold markers
Not-tested: Tauri native packaged app shell
2026-05-09 22:43:00 +08:00
程序员阿江(Relakkes)
da477c2b4b Merge session title sanitation into main
Bring the detached worktree fix onto local main after verifying the title-generation regression path and local quality checks.

Constraint: The worktree commit was based on an older main commit, while local main already contained later chat scroll fixes.
Confidence: high
Scope-risk: moderate
Directive: Keep title sanitation shared across CLI, server, and desktop read paths.
Tested: bun run check:server
Tested: bun run check:desktop
Tested: bun run verify (7 passed, 1 failed on existing aggregate agent-utils coverage baseline)
Not-tested: live model title-generation smoke
2026-05-09 22:34:54 +08:00
程序员阿江(Relakkes)
179f79b794 fix: sanitize generated session titles
Slash-command and skill prompts can enter the title-generation path as internal XML breadcrumbs. The async title request previously treated that transport metadata as user prose, so a generated ai-title could persist raw command tags and override the normal session title.

This routes title sources and generated title output through a shared sanitizer, preserving user-visible command names and arguments while dropping unrelated internal XML metadata. Desktop fallback title rendering now applies the same cleanup so existing transcripts with bad ai-title entries recover on read.

Constraint: Session titles can be produced by both desktop server logic and the SDK generate_session_title control request.
Rejected: Only clean desktop session display | leaves CLI and remote title generation able to persist bad titles again
Confidence: high
Scope-risk: moderate
Directive: Keep generated-title input and persisted-title readback on the shared sanitizer; do not add a title path that reads command XML directly.
Tested: bun test src/utils/__tests__/sessionTitle.test.ts src/utils/__tests__/sessionTitleText.test.ts
Tested: bun run check:server
Tested: bun run check:desktop
Tested: bun run verify (7 passed, 1 failed on existing aggregate agent-utils coverage baseline)
Not-tested: live model title-generation smoke
2026-05-09 22:34:27 +08:00
程序员阿江(Relakkes)
50d4679f51 Merge chat scroll recovery into main
Bring the detached worktree fix into the local main line while preserving the newer main behavior that passes session context into interactive chat message blocks.

Constraint: Local main already contains six unpublished commits on top of origin/main
Constraint: Merge conflict only affected MessageList message rendering around sessionId propagation
Rejected: Overwrite main's MessageBlock call shape | would regress AskUserQuestion and permission interactions that need sessionId
Confidence: high
Scope-risk: moderate
Directive: Keep MessageBlock sessionId propagation when editing chat rendering; AskUserQuestion depends on it
Tested: cd desktop && bun run test -- MessageList.test.tsx
Not-tested: Full verify after merge; previous verify remains blocked by agent-utils global coverage baseline
2026-05-09 21:52:31 +08:00
程序员阿江(Relakkes)
6382115de9 fix: keep chat tabs from losing scroll context
Chat sessions need predictable navigation when users switch tabs or read history during streaming. This preserves each session's scroll position, defaults fresh sessions to the latest message, and adds a compact jump-to-latest affordance when auto-follow is paused.

The PR gate also exposed that provider-scoped scheduled tasks must force the sdk-cli entrypoint when launched through the sidecar, so the same change records that runtime contract and its regression assertion.

Constraint: Desktop chat should not force-scroll while the user is reading older messages
Constraint: Scheduled task provider env must not inherit stale parent model runtime values
Rejected: Persist scroll positions in localStorage | session scroll is transient UI state and should not survive app restarts
Confidence: high
Scope-risk: moderate
Directive: Do not remove the sdk-cli entrypoint marker from provider-scoped cron tasks without rerunning the sidecar launcher regression
Tested: cd desktop && bun run test -- MessageList.test.tsx
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/cron-scheduler-launcher.test.ts src/utils/__tests__/themeWords.test.ts
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:native
Not-tested: bun run verify still fails on pre-existing agent-utils global coverage baseline below threshold
Not-tested: Chrome extension E2E blocked by Codex Chrome Extension communication timeout after plugin diagnostics passed
2026-05-09 21:51:34 +08:00
程序员阿江(Relakkes)
184323ba02 Merge AskUserQuestion multi-select fix into main
The detached desktop bugfix worktree contains the AskUserQuestion multi-select handling change, while local main already carries separate local commits. Merge instead of cherry-picking so main records the worktree integration point without dropping local-only history.

Constraint: Local main and the detached worktree had diverged
Rejected: Reset main to the worktree HEAD | would discard local main commits
Confidence: high
Scope-risk: narrow
Directive: Keep AskUserQuestion selection mode controlled by the explicit multiSelect marker
Tested: cd desktop && bun run test -- src/components/chat/AskUserQuestion.test.tsx src/components/chat/chatBlocks.test.tsx src/components/chat/MessageList.test.tsx
Tested: bun run check:desktop
Not-tested: Full root bun run verify after merge
2026-05-09 21:49:59 +08:00
程序员阿江(Relakkes)
60f69c2062 fix: respect AskUserQuestion multi-select markers
Desktop question prompts can carry CLI-provided multiSelect flags, so the answer UI now stores selections per question as arrays and only allows multiple checked options when that flag is true. The message renderer also passes the owning session id into permission UI so pending responses go back to the session that produced the prompt instead of whichever tab is active.

Constraint: AskUserQuestion input may arrive as either questions[] or single question shape
Rejected: Make all option questions multi-select | single-select prompts must remain constrained unless the CLI marks them multiSelect
Confidence: high
Scope-risk: narrow
Directive: Do not infer multi-select from option count; honor the explicit multiSelect flag
Tested: cd desktop && bun run test -- src/components/chat/AskUserQuestion.test.tsx src/components/chat/chatBlocks.test.tsx src/components/chat/MessageList.test.tsx
Tested: bun run check:desktop
Tested: Chrome/CDP smoke against /tmp/cc-haha-ask-user-real verified multi-select and single-select behavior
Not-tested: Chrome extension RPC path, which timed out in this environment despite native host checks passing
2026-05-09 21:48:16 +08:00
程序员阿江(Relakkes)
b31be5161c feat: support custom Computer Use Python interpreters
Computer Use setup could fail on machines where PATH discovery misses a valid Python installation, especially Windows or conda-style environments. Store an optional interpreter path, prefer it during environment checks and venv creation, and expose a desktop settings control for selecting or clearing it.

Constraint: Python discovery is environment-specific and cannot always be inferred from PATH.
Rejected: Continue falling back to PATH after an invalid custom path | hides a user-selected broken interpreter and makes diagnosis ambiguous.
Confidence: high
Scope-risk: moderate
Directive: Preserve unknown Computer Use config fields and keep blank interpreter paths normalized to automatic detection.
Tested: bun test src/utils/computerUse/preauthorizedConfig.test.ts src/server/__tests__/computer-use-python.test.ts src/server/__tests__/computer-use-api.test.ts
Tested: cd desktop && bun run test src/pages/ComputerUseSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: Computer Use browser smoke saved /opt/homebrew/bin/python3 and backend persisted then reset pythonPath to null
Not-tested: Full bun run check:server; existing cron-scheduler-launcher test expects CLAUDE_CODE_ENTRYPOINT=sdk-cli but received undefined.
Related: https://github.com/NanmiCoder/cc-haha/issues/331
2026-05-09 21:46:11 +08:00
程序员阿江(Relakkes)
623f4a5848 chore: bump desktop version to v0.2.2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 23:43:29 +08:00
Relakkes Yang
a0624eeb21 fix: restore Windows desktop notifications 2026-05-08 23:22:58 +08:00
程序员阿江(Relakkes)
f379a9928a fix: remove pr-checks lane and fix test env isolation
- Remove pr-checks lane from quality gate (not needed locally)
- Fix launcherRouting tests to pass explicit null envAppRoot to avoid CLAUDE_APP_ROOT pollution
- Fix cron-scheduler-launcher test: CLAUDE_CODE_ENTRYPOINT is correctly set to sdk-cli for scheduled tasks, update assertion and restore env var in cleanup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 21:00:06 +08:00
程序员阿江(Relakkes)
3794a9d9ef fix: surface worktree identity in session badge
The footer project chip previously kept showing only the source project and selected branch even after a session launched inside an isolated CLI worktree. That made an active worktree session look identical to a normal checkout, especially while agent tools were already operating under .claude/worktrees. The server now returns explicit worktree metadata from the session launch intent, and the desktop chip preserves the user-facing project and branch while appending the isolated worktree slug.

Constraint: CLI worktree branches are internal implementation details and should not replace the user-selected branch label.

Rejected: Show only the actual worktree git branch | it would expose worktree-desktop-* internals and make the business branch harder to read.

Confidence: high

Scope-risk: narrow

Directive: Keep normal checkout footer rendering unchanged; only add worktree identity when session metadata says isolation is enabled.

Tested: bun test src/server/__tests__/sessions.test.ts --test-name-pattern git-info

Tested: cd desktop && bun run test -- src/components/shared/ProjectContextChip.test.tsx

Tested: cd desktop && bun run lint

Tested: git diff --check
2026-05-08 18:08:30 +08:00
程序员阿江(Relakkes)
678ba18a6f fix: keep session git badge on the active CLI checkout
The chat footer previously read git-info from the persisted session file and refreshed only on tab changes. Repository launches can update the active CLI cwd after the composer has already rendered, so the footer could keep showing an older selected branch even while the running model was operating in the correct checkout.

Constraint: The active CLI process is the source of truth for a live session cwd
Rejected: Derive the footer branch only from persisted session metadata | metadata can lag behind startup and does not prove the current running cwd
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/sessions.test.ts --test-name-pattern "git-info should prefer"
Tested: cd desktop && bun run lint
Tested: git diff --check
2026-05-08 18:02:12 +08:00
程序员阿江(Relakkes)
b40ffb0714 feat: align desktop repository sessions with CLI worktrees
Desktop repository launches now defer isolated worktree creation until the
first user turn so the CLI owns worktree setup, cwd initialization, and
session metadata. The chat UI surfaces the pre-startup Git phase so users see
when a session is creating a worktree or switching a branch before model
output begins.

Constraint: Desktop must preserve the selected source checkout until a user actually sends a message
Constraint: CLI setup is the canonical owner for worktree creation and cwd initialization
Rejected: Create the worktree eagerly in the desktop session picker | it diverges from CLI session startup and creates worktrees before a conversation exists
Confidence: high
Scope-risk: moderate
Directive: Keep repository session startup routed through CLI worktree flags; do not reintroduce eager desktop worktree creation without testing transcript cwd and cleanup behavior
Tested: bun test src/server/__tests__/sessions.test.ts src/server/__tests__/conversation-service.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "worktree startup status"
Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
Tested: CLI init-only native worktree smoke from feature/rail
Tested: agent-browser UI flow with MiniMax-M2.7-highspeed in a /tmp repository
2026-05-08 16:08:58 +08:00
程序员阿江(Relakkes)
649c24b9d2 Merge commit 'a31b304' 2026-05-08 13:45:16 +08:00
程序员阿江(Relakkes)
a31b3045fd Preserve explicit desktop runtime selection
Desktop sessions can prewarm before the user-selected runtime reaches the server, and an empty-session draft could previously persist an inferred default runtime as if the user had explicitly selected it. The fix keeps new-session defaults implicit while preserving explicit draft selections, and waits for queued runtime restarts before the first turn is delivered to the CLI process.

Constraint: Runtime selection is session-scoped and may arrive while prewarm or first-turn startup is already in flight

Rejected: Always persist the current default provider/model into new sessions | this masks whether the user actually selected a runtime and can launch stale providers

Confidence: high

Scope-risk: moderate

Directive: Do not send user turns across pending runtime restarts without re-checking the session runtime override

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

Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx

Tested: git diff --check
2026-05-08 13:45:02 +08:00
程序员阿江(Relakkes)
592ace93d0 fix: avoid treating normal folders as repository warnings
Non-Git folders are valid launch targets for desktop sessions, so the composer should not render them as an inline repository warning. The branch and worktree controls remain hidden outside Git repositories while server-side repository validation still protects actual branch-launch requests.

Constraint: Non-Git directories must remain usable as ordinary session workdirs.
Rejected: Keep the inline not-Git warning | it reads like an error even though the user can continue normally.
Confidence: high
Scope-risk: narrow
Directive: Keep dirty-worktree and checked-out-branch warnings visible because those still require a launch-mode decision.
Tested: cd desktop && bun run test -- --run src/pages/EmptySession.test.tsx src/components/chat/ChatInput.test.tsx
Tested: bun run check:desktop
Tested: git diff --check -- desktop/src/components/shared/RepositoryLaunchControls.tsx desktop/src/pages/EmptySession.test.tsx desktop/src/i18n/locales/en.ts desktop/src/i18n/locales/zh.ts
Not-tested: Native Tauri packaged window visual check
2026-05-08 12:41:34 +08:00
程序员阿江(Relakkes)
eadbd4be14 Keep newly activated desktop tabs visible
When the tab strip overflows, newly opened sessions were active but could remain outside the visible horizontal viewport. The tab bar already owns element refs for drag and close behavior, so the focused fix scrolls the active tab into view after activation and refreshes overflow controls on the next frame.

Constraint: Preserve existing tab ordering, drag behavior, and close-button affordances.
Rejected: Reorder new sessions to the left | changes established tab order and makes history harder to scan.
Confidence: high
Scope-risk: narrow
Directive: Keep active-tab visibility behavior in TabBar so all activation paths share it.
Tested: cd desktop && bun run test -- TabBar
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: agent-browser overflow smoke with six tabs confirmed active Untitled Session fullyVisible=true
Not-tested: Full bun run verify gate.
2026-05-08 12:41:04 +08:00
程序员阿江(Relakkes)
8134436562 Fix macOS build artifacts to keep notification identity stable
The notification bridge fix was correct, but the local macOS build script still left Tauri's raw app and DMG outputs available with the executable's ad-hoc signing identifier. Opening that raw artifact made macOS treat notification authorization as a different app identity, so the UI could fall back to the unsupported environment state even though the canonical output worked.

Normalize the Tauri-produced app bundle in place before copying it to the canonical output, then replace the Tauri-generated DMG with the rebuilt canonical DMG. This keeps every path printed by the build script on the same bundle identity and prevents testers from accidentally opening the unstable raw artifact.

Constraint: Local test builds use ad-hoc signing, but macOS notification authorization still depends on stable app identity.
Rejected: Only tell testers to open canonical output | the script still printed and preserved misleading usable-looking artifacts.
Confidence: high
Scope-risk: narrow
Directive: Keep Tauri raw app and canonical app signing identifiers aligned before reporting build artifacts as runnable.
Tested: bash -n desktop/scripts/build-macos-arm64.sh
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: codesign -dv --verbose=4 shows com.claude-code-haha.desktop for both target bundle app and canonical app
Tested: hdiutil verify target DMG and canonical DMG
Tested: Computer Use opened target bundle app and verified Settings -> General shows notifications as authorized.
Not-tested: Fresh first-time notification prompt after resetting macOS notification permissions for this bundle id.
2026-05-08 11:11:20 +08:00
程序员阿江(Relakkes)
6b55ace2d7 Prevent model selector clipping in task modals
The model selector dropdown was rendered inside the modal scroll container. When the task form sat near the top of the dialog, the upward-opening menu could be clipped by the container and become impossible to scroll into view. The selector now portals the menu to the document body and positions it against the trigger with viewport-aware fixed coordinates.

Constraint: The same selector is used by chat/session controls and scheduled-task controls, so the fix must preserve existing runtime selection behavior.
Rejected: Increase modal scroll padding | still leaves the dropdown coupled to a clipping parent and breaks in other overflow containers.
Confidence: high
Scope-risk: narrow
Directive: Keep floating selector content outside scroll-clipping parents; update viewport positioning if the modal layout changes.
Tested: cd desktop && bun run test -- src/components/controls/ModelSelector.test.tsx src/components/tasks/NewTaskModal.test.tsx
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Manual packaged desktop app check.
2026-05-08 10:43:09 +08:00
程序员阿江(Relakkes)
ed2595b1c7 Merge scheduled task provider runtime support 2026-05-08 09:49:27 +08:00
程序员阿江(Relakkes)
7696e21dc2 Support provider runtimes for scheduled tasks
Scheduled tasks used the model selector in model-only mode, so a task could store a third-party model id without the provider runtime needed to execute it. The desktop task editor now stores the selected provider with the model, and the scheduler injects the same provider-scoped runtime env that desktop sessions use before launching the sidecar.

Constraint: Scheduled tasks run outside an active desktop websocket session, so provider runtime must be serialized on the task itself.
Rejected: Reuse session runtime localStorage for tasks | scheduled executions can run long after the UI session is gone.
Confidence: high
Scope-risk: moderate
Directive: Keep task execution provider env isolated from inherited process env; stale parent ANTHROPIC_* values must not override task provider choices.
Tested: cd desktop && bun run test -- src/components/tasks/NewTaskModal.test.tsx src/components/controls/ModelSelector.test.tsx
Tested: bun test src/server/__tests__/scheduled-tasks.test.ts src/server/__tests__/cron-scheduler-launcher.test.ts
Tested: bun run check:desktop
Tested: bun run check:server
Tested: git diff --check
Not-tested: Live third-party provider API call; covered by sidecar launch integration with provider proxy env.
2026-05-08 09:49:16 +08:00
程序员阿江(Relakkes)
7796fec691 fix: request macOS notifications from the main queue
The Rust command now keeps the synchronous bridge wait off the invoke thread, but the Objective-C bridge still initiated UserNotifications authorization from that worker. In a packaged app that path could fail immediately and the settings UI collapsed the error into an unsupported environment.

Start notification settings reads, authorization requests, and delivery submissions on the macOS main queue while keeping the blocking wait on the worker thread. This preserves foreground-safe notification delivery without deadlocking the UI or losing the system permission prompt.

Constraint: UserNotifications APIs are UI-adjacent and should be initiated on the app main queue.
Rejected: Only change the unsupported status copy | it would keep the authorization path broken.
Confidence: high
Scope-risk: narrow
Directive: Keep UserNotifications calls main-queue initiated while the synchronous wait remains off the main thread.
Tested: cd desktop/src-tauri && cargo test
Tested: bun run check:native
Tested: SKIP_INSTALL=1 ./scripts/build-macos-arm64.sh
Tested: codesign --verify --deep --strict --verbose=2 desktop/build-artifacts/macos-arm64/Claude Code Haha.app
Tested: hdiutil verify desktop/build-artifacts/macos-arm64/Claude Code Haha_0.2.1_aarch64.dmg
Tested: Computer Use opened /Users/nanmi/workspace/myself_code/claude-code-haha/desktop/build-artifacts/macos-arm64/Claude Code Haha.app and verified Settings -> General shows notifications as authorized after disable/enable.
Not-tested: Fresh first-time system notification prompt on a machine that has never granted this bundle identifier.
2026-05-08 09:43:25 +08:00
程序员阿江(Relakkes)
de9d044bdb fix: keep macOS notification bridge off the invoke thread
The macOS notification bridge synchronously waits for UserNotifications callbacks. Running that wait on the Tauri command caller can block the callback path and make permission reads time out, which the UI reports as an unsupported environment.

Route the bridge calls through a blocking worker so permission reads, permission prompts, and delivery checks do not stall the app thread that needs to service native notification callbacks.

Constraint: UserNotifications permission and delivery APIs complete asynchronously through macOS callbacks.
Rejected: Change the settings status label only | it would hide the failed native permission read without fixing notification delivery.
Confidence: high
Scope-risk: narrow
Directive: Keep macOS notification bridge calls off the invoke caller thread unless the Objective-C bridge becomes fully async.
Tested: cd desktop/src-tauri && cargo test
Tested: bun run check:native
Tested: cd desktop && bun run test --run src/lib/desktopNotifications.test.ts src/__tests__/generalSettings.test.tsx
Tested: SKIP_INSTALL=1 ./scripts/build-macos-arm64.sh
Tested: codesign --verify --deep --strict --verbose=2 desktop/build-artifacts/macos-arm64/Claude Code Haha.app
Tested: hdiutil verify desktop/build-artifacts/macos-arm64/Claude Code Haha_0.2.1_aarch64.dmg
Not-tested: Manual click-through of the newly built .app notification settings screen.
2026-05-08 09:27:20 +08:00
程序员阿江(Relakkes)
57a77453ed fix: isolate desktop provider runtimes per session
Desktop sessions can run against different saved providers at the same time, so the runtime selection must remain scoped to the session from WebSocket startup through the CLI request path. This adds parallel-session regression coverage, a browser-driven fake-provider E2E, and refreshes idle connected sessions after provider saves so stale provider edits are reapplied without disturbing active turns.

Constraint: Desktop provider credentials must stay session-scoped and must not leak across concurrent CLI child processes
Rejected: Rely on provider test connectivity alone | it does not exercise the desktop WebSocket, session runtime, or CLI request path
Confidence: high
Scope-risk: moderate
Directive: Do not change runtime selection persistence or provider env injection without rerunning the parallel provider browser E2E
Tested: cd desktop && bun run test src/stores/providerStore.test.ts src/stores/chatStore.test.ts
Tested: CLAUDE_CONFIG_DIR=/Users/nanmi/.claude bun test src/server/__tests__/conversations.test.ts --timeout 30000
Tested: desktop/scripts/e2e-parallel-providers-agent-browser.sh
Tested: bun run quality:smoke --provider-model custom:main:custom-main --provider-model minimax:main:minimax-main
Tested: cd desktop && bun run lint
Tested: git diff --check
Not-tested: bun run verify passes fully; coverage lane still fails on the existing agent-utils ratchet below baseline
2026-05-08 08:53:05 +08:00
程序员阿江(Relakkes)
0a4f2ae6b6 fix(desktop): keep Computer Use toggles stable
Settings refreshes can complete after the user changes Computer Use authorization state. The page now ignores stale config reads once a local mutation has happened, so enablement and grant controls no longer visually roll back and require a second operation.

Constraint: Computer Use config is shared between the desktop settings page and runtime MCP exposure.
Rejected: Refetch after every save | still allows older in-flight reads to overwrite newer local intent.
Confidence: high
Scope-risk: narrow
Directive: Do not apply async settings snapshots after a newer local authorization mutation without a freshness check.
Tested: cd desktop && bun run test -- src/pages/ComputerUseSettings.test.tsx
Tested: bun run check:desktop
Tested: bun run check:coverage
Not-tested: bun run verify is blocked by existing path-aware policy labels for broader dirty scope.
2026-05-07 21:33:33 +08:00
程序员阿江(Relakkes)
f01ba4eda6 Merge repository launch context controls into main
The detached worktree contains the session composer repository controls work: preserving launch context across empty chat tabs, exposing branch and worktree selection under the composer, tightening long-label truncation, and validating the launch paths with desktop tests. Main had moved forward independently, so this records the integration as a merge commit instead of rewriting either side.

Constraint: Merge into local main only; do not push or alter remote state.
Rejected: Rebase the detached worktree onto main | it would rewrite the already reviewed local commit chain and was unnecessary after a clean merge.
Confidence: high
Scope-risk: moderate
Directive: Keep repository context controls under the composer as a single-line rail; long repo or branch labels must truncate inside their own controls.
Tested: bun run check:desktop
Not-tested: Native Tauri packaged window visual check
2026-05-07 20:13:31 +08:00
程序员阿江(Relakkes)
5c738db3af fix: keep launch context rail on one line
Long branch names should be clipped inside the branch selector instead of forcing the repository context rail onto a second row. The rail now stays nowrap, the branch selector owns truncation, and the worktree mode selector keeps its readable fixed footprint.

Constraint: Preserve the existing composer and repository context layout shape.
Rejected: Let the rail wrap on long branch names | it creates the broken two-line state shown in the desktop composer.
Confidence: high
Scope-risk: narrow
Directive: Long repository or branch labels must truncate inside their own controls rather than changing the rail height.
Tested: cd desktop && bun run test -- --run src/pages/EmptySession.test.tsx src/components/chat/ChatInput.test.tsx src/components/shared/DirectoryPicker.test.tsx
Tested: bun run check:desktop
Tested: agent-browser selected a long branch on http://localhost:4790 and verified rail height 53px, branch width 260px, no horizontal overflow; screenshot /tmp/cc-haha-launch-rail-long-branch-nowrap.png
Not-tested: Native Tauri packaged window visual check
2026-05-07 19:59:19 +08:00
程序员阿江(Relakkes)
5675539ef0 fix: make worktree launch mode selectable
The worktree control is a mode choice, so it should behave like the branch selector instead of a hidden toggle. This adds a compact dropdown with current and isolated worktree options while preserving the existing launch layout and isolation guard.

Constraint: Keep the composer context rail layout unchanged.
Rejected: Keep the single-click toggle | the interaction hid the available modes and made the state harder to reason about.
Confidence: high
Scope-risk: narrow
Directive: Worktree mode must stay an explicit selection surface, not a hidden toggle.
Tested: cd desktop && bun run test -- --run src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx src/components/shared/DirectoryPicker.test.tsx
Tested: bun run check:desktop
Tested: agent-browser worktree dropdown desktop and mobile screenshots at /tmp/cc-haha-worktree-dropdown-menu.png, /tmp/cc-haha-worktree-dropdown-selected.png, /tmp/cc-haha-worktree-dropdown-mobile-menu.png, /tmp/cc-haha-worktree-dropdown-mobile-selected.png
Not-tested: Native Tauri packaged window visual check
2026-05-07 19:44:51 +08:00
程序员阿江(Relakkes)
ca4900ed0c fix: cluster repository launch chips
The composer context rail should read as one compact group, not three stretched controls. This change removes flex growth from the repository picker, caps branch width by content, softens the active worktree state, and removes hover borders that made secondary state controls look primary.

Constraint: Keep the existing composer and session layout unchanged.
Rejected: Use a prominent active outline for worktree | it made the state look like the primary action.
Confidence: high
Scope-risk: narrow
Directive: Keep this rail content-sized; long names should truncate inside chips instead of spreading across the bar.
Tested: cd desktop && bun run test -- --run src/components/shared/DirectoryPicker.test.tsx src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx
Tested: bun run check:desktop
Tested: agent-browser desktop screenshot /tmp/cc-haha-repo-controls-compact-worktree-active-final.png and mobile overflow check /tmp/cc-haha-repo-controls-compact-mobile-final.png
Not-tested: Native Tauri packaged window visual check
2026-05-07 18:40:25 +08:00
程序员阿江(Relakkes)
fd5dc097a7 fix: isolate desktop session streaming state
Desktop chat sessions can stream and reconnect concurrently, so shared in-process buffers must not be keyed only by process lifetime. This change scopes streaming delta buffers, task-tool refresh bookkeeping, and CLI task mutations to the session that produced the event. It also ignores stale client socket closes after a newer socket has replaced the active connection for the same session.

Constraint: Desktop users can keep multiple sessions and tabs active at the same time.
Rejected: Serialize all desktop streaming through one active session | would hide the race instead of preserving multi-session behavior.
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce process-global chat/task pending state without session keys and multi-session regression tests.
Tested: cd desktop && bun run test -- src/stores/chatStore.test.ts src/stores/cliTaskStore.test.ts
Tested: bun test src/server/__tests__/websocket-handler.test.ts
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:coverage | changed-lines 100%, fails only existing agent-utils baseline
Tested: bun run verify | 8 passed, 1 failed on existing agent-utils coverage baseline, 2 skipped
Not-tested: Real desktop dual-window manual smoke.
Related: https://github.com/NanmiCoder/cc-haha/issues/302
Related: https://github.com/NanmiCoder/cc-haha/issues/303
2026-05-07 18:33:57 +08:00
程序员阿江(Relakkes)
3606531f7e fix: tighten repository launch context bar
The launch controls live directly under the composer, so they need to read as a compact context rail rather than a second card. The styling now uses a lighter surface, shorter controls, bounded flex sizing, and explicit hover titles for long repository and branch names. Git repo status is passed into the picker so a freshly opened Git project does not briefly look like a plain folder.

Constraint: Keep the existing session/composer layout untouched; only refine the context bar under the input.
Rejected: Redesign the empty session layout | user explicitly scoped this to the lower context bar.
Confidence: high
Scope-risk: narrow
Directive: Do not grow this rail vertically without browser-checking long repo and branch names.
Tested: cd desktop && bun run test -- --run src/components/shared/DirectoryPicker.test.tsx src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx
Tested: bun run check:desktop
Tested: agent-browser long repo and long branch screenshots at /tmp/cc-haha-repo-controls-polished-git-long-branch-selected.png and /tmp/cc-haha-repo-controls-polished-mobile-long.png
Not-tested: Native Tauri packaged window visual check
2026-05-07 18:33:42 +08:00
程序员阿江(Relakkes)
09209ecefb fix: preserve repository context after session launch
Empty ActiveSession launch controls now use both loaded chat messages and persisted session messageCount, so historical sessions do not briefly fall back into new-session launch mode while message history is still loading. Regression coverage also locks the first-message branch launch flows for direct checkout and isolated worktree sessions.

Constraint: Historical session lists already know messageCount before chat history finishes loading
Rejected: Wait for history fetch before rendering composer controls | it keeps the wrong new-session affordance visible during reopen
Confidence: high
Scope-risk: narrow
Directive: Branch/worktree launch controls are only for messageCount-zero sessions; reopened history must render repository context chips
Tested: bun run test -- --run src/components/chat/ChatInput.test.tsx src/pages/ActiveSession.test.tsx src/__tests__/pages.test.tsx
Tested: bun run check:desktop
Tested: agent-browser /tmp repo direct branch launch on /private/tmp/cc-haha-repo-e2e-IP9mkb produced session 9089ae96-5dd6-4ea6-b88e-376ab081ca24 on workDir /private/tmp/cc-haha-repo-e2e-IP9mkb
Tested: agent-browser /tmp repo isolated worktree launch produced session 9ec657bd-e503-48b3-b52f-36e210fc5d64 on workDir /private/tmp/cc-haha-repo-e2e-IP9mkb/.claude/worktrees/desktop-main-9ec657bd
Not-tested: root bun run verify; desktop surface was covered with check:desktop and live browser smoke
2026-05-07 18:19:18 +08:00
程序员阿江(Relakkes)
0e705473ff fix: show repository controls in empty chat tabs
Empty active session tabs were still using the old directory-only picker, so sessions created from the sidebar lost the branch and worktree controls even when their workDir was a Git repository. Reuse the launch controls below the existing composer and replace only the empty session when the user changes repository launch options.

Constraint: Sidebar-created sessions land in ActiveSession, not the EmptySession landing view
Rejected: Reshape the whole session layout | the intended surface is only the controls below the composer
Confidence: high
Scope-risk: narrow
Directive: Keep repository launch controls shared between EmptySession and empty ActiveSession composer flows
Tested: bun run test -- --run src/__tests__/pages.test.tsx src/components/chat/ChatInput.test.tsx
Tested: bun run check:desktop
Tested: agent-browser sidebar new-session smoke at http://127.0.0.1:4790/ with screenshot /tmp/cc-haha-after-sidebar-new-session-controls.png
Not-tested: root bun run verify remains blocked by pre-existing root coverage gate outside desktop
2026-05-07 18:08:38 +08:00
程序员阿江(Relakkes)
0f220f4af5 fix: restore empty session launcher layout
The repository launch controls should extend the existing empty-session composer, not replace the session layout. This restores the previous mascot, title, composer sizing, textarea, and run button while keeping the project, branch, and worktree controls attached directly beneath the input.

Constraint: User requested the original session layout stay intact except for adding repository controls under the chat input
Rejected: Keep the Codex-style centered launcher rewrite | it changed too much of the existing session surface
Confidence: high
Scope-risk: narrow
Directive: Future changes to repository launch controls should treat EmptySession layout as fixed unless explicitly requested otherwise
Tested: cd desktop && bun run test -- --run src/components/shared/DirectoryPicker.test.tsx src/pages/EmptySession.test.tsx src/__tests__/pages.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: agent-browser screenshot /tmp/cc-haha-layout-restored-selected.png on localhost:4790
Not-tested: root bun run verify not rerun for this narrow layout correction
2026-05-07 17:56:33 +08:00
程序员阿江(Relakkes)
f3dc2399c2 fix: polish desktop launch repository controls
The empty-session launch surface needed to behave like a real coding-agent entry point: project, branch, and worktree choices are now visible together, and branch choices that cannot safely run in-place force an isolated worktree before session creation.

Constraint: Desktop launch flows must preserve repository safety when a target branch is dirty or checked out elsewhere
Rejected: Keep branch and worktree controls as detached chips | the selection state was easy to miss and visually inconsistent with the launcher
Confidence: high
Scope-risk: moderate
Directive: Do not remove the automatic worktree requirement without rechecking dirty and checked-out branch launches through the desktop UI
Tested: cd desktop && bun run test -- --run src/components/shared/DirectoryPicker.test.tsx src/pages/EmptySession.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: browser-driven desktop smoke on ports 4789/4790
Not-tested: bun run verify still has the pre-existing agent-utils coverage ratchet failure outside desktop
2026-05-07 17:47:42 +08:00
程序员阿江(Relakkes)
2dd8ee4a33 fix: keep open session tab titles in sync
Open session tabs can outlive the title value they were created with, while the sidebar and session detail view read from the refreshed session list. Refresh existing tab titles when a session tab is reopened and after session list refreshes so the top tab bar cannot keep a stale generated title.

Constraint: Sidebar filtering and session refresh should not leave already-open tabs with stale labels.
Rejected: Only rely on WebSocket title update events | restored tabs and already-open tabs can miss later session-list corrections.
Confidence: high
Scope-risk: narrow
Directive: Keep session tab titles derived from current session list data when available.
Tested: cd desktop && bun run test -- --run src/stores/tabStore.test.ts src/stores/sessionStore.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test -- --run
Tested: agent-browser smoke on http://127.0.0.1:1420/ confirmed top tabs match sidebar and session detail titles.
2026-05-07 16:38:27 +08:00
程序员阿江(Relakkes)
4c2881aaf0 Prevent duplicate desktop app instances
Notification clicks and repeated launches can enter the native app through OS-level activation paths, so the desktop runtime now registers Tauri's single-instance guard before sidecars or other plugins start. A second launch restores and focuses the existing main window instead of creating another app process.

Constraint: macOS and Windows launch paths must reuse the running desktop instance.
Rejected: Handle only notification click callbacks | does not cover Dock, shortcut, installer, or Windows relaunch paths.
Confidence: high
Scope-risk: narrow
Directive: Keep the single-instance plugin before sidecar startup so duplicate launches cannot create extra runtime processes.
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: open -n built app twice; desktop_count stayed 1 with pid 69821
Tested: bun run check:native
Tested: cargo test --manifest-path desktop/src-tauri/Cargo.toml
Tested: cd desktop && bun run test -- desktopNotifications.test.ts
Tested: cd desktop && bun run lint
2026-05-07 16:28:08 +08:00
程序员阿江(Relakkes)
7fbce35be6 fix: prevent malformed generated session titles
Session titles need to appear immediately, but the async AI title pass can return fenced or escaped JSON fragments. Keep the first-message title path fast, preserve optimistic client titles during background refresh, and only accept structured title responses that parse cleanly.

Constraint: Desktop sessions should stop showing Untitled/New Session after the first user turn.
Rejected: Accept short raw model output as a fallback | malformed JSON fragments are short enough to leak into the UI.
Confidence: high
Scope-risk: moderate
Directive: Do not loosen generated title parsing without regression coverage for fenced, escaped, and truncated JSON responses.
Tested: bun test src/server/__tests__/title-service.test.ts
Tested: bun run check:server
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/stores/sessionStore.test.ts src/pages/EmptySession.test.tsx
Tested: agent-browser smoke on http://127.0.0.1:1420/ confirmed sidebar and tab titles update without JSON fragments.
2026-05-07 16:28:08 +08:00
程序员阿江(Relakkes)
a340e41046 fix: make local desktop builds reflect current UI state
The desktop test package was able to reuse stale Tauri target output even after the frontend and sidecar were rebuilt, which made UI changes look missing after a build. The local macOS build script now clears that cache by default while retaining an opt-in incremental path.

The project selector also no longer repeats the active branch because branch and worktree are now first-class launch controls beside it.

Constraint: Local macOS test packages must prioritize freshness over incremental build speed
Rejected: Keep branch text in the project chip | duplicated the dedicated branch selector and made the launch row harder to scan
Confidence: high
Scope-risk: narrow
Directive: Keep branch selection behavior in RepositoryLaunchControls; DirectoryPicker should only identify the project
Tested: cd desktop && bun run test -- DirectoryPicker.test.tsx
Tested: cd desktop && bun run lint
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: Opened built app and confirmed sidecar /health returned ok
2026-05-07 15:57:40 +08:00
程序员阿江(Relakkes)
7ae885a114 fix: add safe Doctor rescue path for desktop upgrades
Online upgrades can strand users on stale desktop UI state or malformed local persistence. This adds a deny-by-default Doctor path that resets only regenerable desktop UI state, reports protected local files with redacted metadata, and keeps protected repair as a dry-run no-op until a reviewed backup-first flow exists.

Constraint: Chat transcripts, model/provider config, Skills, MCP, IM bindings, adapter sessions, OAuth tokens, plugins, and team/session records are user-owned protected state.
Rejected: Automatically rewrite malformed protected JSON | unsafe without schema-specific migrations and backups.
Rejected: Continue relying only on startup migrations | users need an explicit recovery action after a white screen.
Confidence: high
Scope-risk: moderate
Directive: Keep Doctor repair deny-by-default; do not mutate protected state without an explicit reviewed backup-first manual repair flow.
Tested: bun test src/server/__tests__/doctor-service.test.ts
Tested: cd desktop && bun run test src/components/ErrorBoundary.test.tsx src/lib/doctorRepair.test.ts src/__tests__/diagnosticsSettings.test.tsx src/components/layout/StartupErrorView.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:server
Tested: bun run verify (failed only existing agent-utils coverage baseline; changed-lines coverage 97.62%)
Not-tested: Packaged desktop manual Doctor click path.
2026-05-07 00:04:06 +08:00
程序员阿江(Relakkes)
fa47adc33a fix: prevent upgrade crashes from stale persistence
Desktop users can carry provider indexes, managed settings, localStorage state, and native update state from builds that no longer match current readers. This adds startup migrations and recovery paths before server and React state are consumed, plus a persistence upgrade gate so future storage protocol changes ship with old-format fixtures.

Constraint: Existing installs may contain malformed or legacy JSON/localStorage that must not block startup.
Constraint: Local verify should evaluate the current worktree diff rather than unrelated detached-worktree history.
Rejected: Treat invalid persisted state as fatal | reproduces white-screen and startup failure behavior for existing users.
Rejected: Bypass PR policy locally | hides real gate behavior and does not fix detached-worktree false positives.
Confidence: high
Scope-risk: moderate
Directive: Any local JSON, localStorage, or app config shape change must add a migration fixture and keep `bun run check:persistence-upgrade` green.
Tested: bun run check:persistence-upgrade; bun run check:policy; bun run check:desktop; bun run check:server; bun run check:native; bun run verify (9 passed, 1 coverage baseline failure)
Not-tested: Live provider baseline; existing user configs beyond covered fixtures
2026-05-06 23:20:21 +08:00
程序员阿江(Relakkes)
b156be8d8d feat: make PR quality verification self-enforcing
Contributors and coding agents need one local command that both reports and enforces the quality contract. This change turns the PR gate into the shared verification entrypoint, adds path-selected local lanes, tightens coverage accounting around changed lines, and documents the repair loop in contributor and agent-facing guidance.

Constraint: Ordinary PR verification must stay non-live and runnable without provider credentials
Constraint: Coverage policy updates in this commit require maintainer approval before push/merge
Rejected: Keep quality guidance only in docs | agents need executable scripts and AGENTS.md instructions to follow the loop consistently
Confidence: high
Scope-risk: broad
Directive: Do not bypass `bun run verify` for production changes; fix failed lanes and coverage reports instead of lowering thresholds
Tested: bun run check:policy
Tested: ALLOW_CLI_CORE_CHANGE=1 ALLOW_COVERAGE_BASELINE_CHANGE=1 bun run verify
Not-tested: live provider baseline; no provider credentials were required for this non-live PR gate
2026-05-06 22:33:43 +08:00