Coding sessions need a native way to keep working until a stated completion condition is actually met. This adds a CLI /goal command, goal state and evaluator logic, and a headless-safe command filter so interactive and print-mode runs can both start a goal and continue when the evaluator says more work remains.
Constraint: The evaluator must work with saved third-party provider runtimes that may reject structured output schemas.
Constraint: Completion evidence must come from visible transcript text, not hidden goal prompts or assistant thinking blocks.
Rejected: Implement /goal as a bundled skill only | it would not own the query loop or support native continuation semantics.
Rejected: Expose all local-jsx commands to headless mode | interactive UI commands would become available in print mode.
Confidence: high
Scope-risk: moderate
Directive: Keep /goal evaluator evidence scoped to visible transcript text before adding richer completion signals.
Tested: bun test src/commands/headless.test.ts src/goals/goalState.test.ts src/goals/goalEvaluator.test.ts
Tested: bun run check:server
Tested: bun run verify
Tested: Real provider /goal smoke with MiniMax-M2.7-highspeed, including a two-turn continuation that logged Goal continuation #1 and completed with GOAL_SMOKE_LOOP_DONE.
Not-tested: Durable cross-process goal persistence for resumed sessions.
Workspace and transcript selections now flow into the composer as lightweight references so users can carry exact snippets into the next prompt without file-only workarounds. The prompt formatter keeps workspace and chat excerpts separate, and the composer avoids sending chat snippets as fake file attachments.
Constraint: Selection references must prepare model context without polluting backend file attachment payloads.
Rejected: Reuse file attachments for chat selections | would leak chat:// pseudo paths into file-oriented payloads.
Confidence: high
Scope-risk: moderate
Directive: Keep chat-selection references prompt-only unless the backend gains a first-class chat context attachment type.
Tested: bun run check:desktop
Tested: bun run verify
Tested: agent-browser UI smoke for workspace, user-message, and assistant-message selections
Not-tested: Strict Chrome extension channel; connection timed out, local browser automation covered the flow.
Desktop users can receive new sessions from IM adapters or scheduled tasks while the app stays open. The sidebar now refreshes on mount, visible focus, and a low-frequency visible-only interval, with a manual refresh control and in-flight request dedupe so the fix does not create avoidable polling pressure.
Constraint: Sessions can be created outside the desktop process by IM and scheduler entrypoints
Rejected: WebSocket push for this patch | broader server contract change than needed for the reported stale list
Confidence: high
Scope-risk: narrow
Directive: Keep session-list refresh visible-only and deduped before lowering intervals or adding more triggers
Tested: cd desktop && bunx vitest run src/components/layout/Sidebar.test.tsx src/i18n/index.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: Browser smoke on isolated desktop backend/frontend with refresh button click
Not-tested: Full coverage gate is blocked by unrelated root test port/timeouts; changed lines coverage reported 100% (59/59)
Feishu CardKit and DingTalk AI Card updates run inside the serialized adapter message path. A hung platform update can prevent the later message_complete event from being handled, leaving mobile IM users stuck on a partial streaming card.
This bounds platform card API calls and gives Feishu a final patch fallback when CardKit finalization fails, so a bad intermediate frame cannot permanently block the chat turn.
Constraint: Feishu and DingTalk card APIs are external network calls without reliable SDK-level deadline guarantees
Rejected: Disable streaming cards entirely | loses the live IM experience for normal fast responses
Confidence: high
Scope-risk: narrow
Directive: Keep IM card platform calls bounded because adapter server messages are serialized per chat
Tested: bun test adapters/feishu/__tests__/streaming-card.test.ts
Tested: bun test adapters/dingtalk/__tests__/ai-card.test.ts
Tested: bun run check:adapters
Tested: bunx tsc -p adapters/tsconfig.json --noEmit
Not-tested: Full bun run verify was interrupted during the coverage lane after dependency setup
Bring the detached worktree implementation for issue #407 back into
local main while preserving a merge boundary for review and rollback.
Constraint: Local main already contains post-release-boundary desktop fixes
Confidence: high
Scope-risk: narrow
Tested: bun run verify in detached worktree before merge
Not-tested: Full gate on local main before this merge commit
The desktop shell needed predictable zoom controls across macOS,
Windows, and Linux without depending on browser defaults. This adds a
small app zoom controller that persists a bounded zoom factor, maps the
IDE-style primary-modifier shortcuts, and uses native Tauri webview zoom
when available with a browser fallback for H5/dev runs.
Constraint: Issue #407 requested IDE-style zoom shortcuts across macOS, Windows, and Linux
Rejected: Enable Tauri built-in zoom hotkeys only | it would not cover browser/H5 fallback or app-owned persistence consistently
Confidence: high
Scope-risk: narrow
Directive: Keep app zoom bounded and validated before applying persisted localStorage values
Tested: bun run verify; browser smoke on http://127.0.0.1:45679/ with Meta+= and Meta+0
Not-tested: Manual Windows/Linux desktop runtime smoke
Superpowers can trigger plan approval or browser confirm flows inside the desktop shell. Tauri's dialog plugin shims window.confirm through the message command, but the desktop capability only allowed file open/save dialogs, so Windows rejected confirm with an ACL error and left the flow blocked.
Constraint: Tauri plugin-dialog 2.7 routes alert/confirm through the message permission.
Rejected: Grant dialog:default | broader than needed for this bugfix.
Confidence: high
Scope-risk: narrow
Directive: Keep dialog message permission whenever browser confirm or alert shims are available in desktop.
Tested: cd desktop && bun run test -- --run src/__tests__/tauriCapabilities.test.ts
Tested: bun run check:native
Tested: bun run check:desktop
The release needs a curated GitHub Release body and matching desktop/Tauri version metadata before the annotated tag can trigger the remote packaging workflow. The notes summarize the post-v0.2.5 H5 access recovery, sidebar batch management, file mention search alignment, and desktop polish while keeping generated dependency versions unchanged.
Constraint: GitHub Release body is sourced from release-notes/v0.2.6.md in the tagged commit
Constraint: Desktop package, Tauri config, Cargo.toml, and Cargo.lock must agree on the release version
Rejected: Run the release script directly after manual edits | its default commit message does not capture the release decision context
Confidence: high
Scope-risk: narrow
Directive: Keep future release notes aligned with the tagged version file before pushing tags
Tested: git diff --check
Tested: bun run scripts/release.ts 0.2.6 --dry
Not-tested: Full release gate; this commit only prepares release metadata after markdown review
The previous H5 preview no longer represented the current phone browser flow, so the README gallery now uses a composed image from the latest mobile screenshots while preserving the existing asset path and gallery proportions.
Scope-risk: narrow
Confidence: high
Tested: Viewed generated docs/images/desktop_ui/12_h5_access.png and confirmed dimensions are 2960x2100
Not-tested: Full docs build; image-only README asset replacement
Desktop search results were visually misleading when many directories shared the same basename, because the UI emphasized the basename and the server ranking allowed deep basename matches to outrank direct path-prefix matches. This makes search rows show the insertable relative path and ranks direct path-prefix matches before unrelated same-name directories.
Constraint: Desktop @ file suggestions should match the CLI mental model for path search.
Rejected: Keep basename plus parent-path rows | it hides the distinction between src/, src/hooks/, and desktop/src in the primary text.
Confidence: high
Scope-risk: narrow
Directive: Preserve path-prefix ranking ahead of basename-only matches for directory searches.
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: cd desktop && bun run test -- FileSearchMenu.test.tsx ChatInput.test.tsx
Tested: bun run check:server
Tested: bun run check:desktop
The generated logo asset carried both an opaque square canvas and an inner rounded tile, so the desktop empty state and sidebar rendered a visible nested background. Rebuilt the canonical app icon with transparent outside corners, one white rounded badge, and a centered mark, then regenerated the Tauri icon set and docs raster assets from that source.
Constraint: Existing desktop views consume /app-icon.png directly with no wrapper background to remove.
Rejected: Add CSS masking around each img usage | would leave native app icons and docs assets with the same nested canvas problem.
Confidence: high
Scope-risk: narrow
Directive: Keep desktop/src-tauri/app-icon.png as the canonical 1024 RGBA source before regenerating platform icons.
Tested: cd desktop && bun run build; npm run --loglevel=error docs:build; git diff --check; sips alpha and size checks; iconutil icns size ladder; Chrome DevTools light and forced-dark screenshots.
Not-tested: full bun run verify gate, per prior instruction to skip local gate for this logo pass.
Desktop @ file search was recursively walking the filesystem with a local skip list, which let Python and Node generated directories leak into results and diverged from CLI behavior. Route candidate discovery through the same git-first model: tracked files, untracked files with exclude-standard, and ripgrep fallback for non-git folders, then derive selectable directories from those candidates.
Constraint: Desktop picker must select both files and directories without surfacing ignored project artifacts.
Constraint: No new dependencies; reuse the existing git, ripgrep, settings, and ignore utilities.
Rejected: Maintain a hardcoded directory denylist | it would drift from CLI and miss project-specific ignore rules.
Rejected: Full recursive readdir scanning | it ignores git index semantics and makes large dependency trees visible.
Confidence: high
Scope-risk: moderate
Directive: Keep desktop @ file candidate discovery aligned with src/hooks/fileSuggestions.ts before changing ranking or ignore behavior.
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: cd desktop && bun run test -- FileSearchMenu.test.tsx ChatInput.test.tsx
Tested: cd desktop && bun run lint && bun run test -- --run && bun run build
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Native Windows/Linux manual UI smoke; path handling relies on cross-platform git/ripgrep wrappers and normalized relative paths.
The desktop app and documentation need to present the new logo consistently, so the canonical 1024px source icon now feeds the Tauri icon family, desktop public assets, README images, and VitePress brand imagery.
Constraint: Tauri bundle icons are generated assets and must be refreshed from the source icon rather than relying on README or public image replacement alone
Rejected: Rename logo paths | existing README, desktop, and docs references can keep stable paths and pick up the new files directly
Confidence: high
Scope-risk: moderate
Directive: Regenerate desktop/src-tauri/icons whenever desktop/src-tauri/app-icon.png changes
Tested: cd desktop && bun run build; npm run --loglevel=error docs:build; git diff --check; iconutil expanded icon.icns size ladder
Not-tested: full local quality gate per request
The previous batch selection state let adjacent selected sessions visually merge into a single block. This keeps the existing row structure but adds per-row spacing, a transparent baseline border, and a subtle selected-row shadow so the selection is easier to read without changing behavior.
Constraint: Keep the change local to the desktop sidebar and avoid new dependencies.
Rejected: Add global sidebar CSS tokens | unnecessary for this small component-level state and harder for changed-line coverage.
Confidence: high
Scope-risk: narrow
Directive: Keep batch selection spacing on the row wrapper so adjacent selected rows remain visually separated.
Tested: bun run verify
The pure white appearance option needed to avoid warm-theme leakage while preserving the existing warm classic brand theme. This adds the white theme mode, keeps local browser startup from reusing stale H5 server URLs in dev, and moves visible legacy warm surfaces onto theme tokens.
Constraint: H5 server auth policy, CORS policy, SDK routes, adapter routes, and IM access paths must not change for a visual theme fix
Rejected: Rename the original light theme to pure white | the original theme is a warm classic palette, not a neutral white workspace
Confidence: high
Scope-risk: moderate
Directive: Keep structural white-theme borders neutral; reserve the warm brand color for selected states, primary actions, and small accents
Tested: cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx src/lib/desktopRuntime.test.ts src/lib/persistenceMigrations.test.ts src/stores/uiStore.test.ts src/stores/settingsStore.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: bun test src/server/__tests__/settings.test.ts src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts
Tested: Browser smoke at http://127.0.0.1:5173 with data-theme=white, no H5 token prompt, /status inspector visible, inspector border #DDE3EA
Not-tested: Full bun run verify gate
The desktop chat composer is a single mounted component under the active session view, so switching tabs reused the same local draft state. The fix keeps unsent composer input and attachments keyed by session tab and restores the matching draft when the active tab changes.
Constraint: Must preserve unsent drafts while isolating them per session tab
Rejected: Force-remount ChatInput with a React key | wider UI lifecycle change and more risk to composer substate
Confidence: high
Scope-risk: narrow
Directive: Do not make composer draft state global without preserving per-session isolation
Tested: cd desktop && bun run test -- ChatInput.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: agent-browser reproduced the leak on an unmodified baseline and verified the fixed UI keeps history tab textarea empty while restoring the new tab draft
Not-tested: Windows 11 packaged release manual smoke
H5 access is a user-facing desktop sharing entrypoint, so it should not be buried inside the broad General settings surface. Move it into its own Settings tab and make the empty QR state point users at the token generation action before a scan link exists.
Constraint: Preserve the existing H5 store API and token lifecycle while changing only the desktop settings surface.
Rejected: Keep H5 access inside General with a larger visual block | still hides a strong product surface in a catch-all page.
Confidence: high
Scope-risk: narrow
Directive: Keep H5 access as a first-class settings entry unless the navigation model is redesigned holistically.
Tested: cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx src/i18n/index.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: bun run verify
Not-tested: Live H5 token generation against an enabled local H5 service; current local desktop state had H5 disabled.
Non-streaming adapter only read `output_tokens`/`input_tokens` (Anthropic-style),
but many OpenAI-compatible providers (e.g. Jiutian MoMA) return standard
`completion_tokens`/`prompt_tokens` fields. This caused a null reference
error when reading `output_tokens` from such responses.
The streaming adapter already handles `completion_tokens` correctly, and
the Azure adapter uses the same fallback pattern applied here.
Fixes#383
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The age-based quick cleanup buttons overlapped poorly with the sidebar time groups and created ambiguity around what would be deleted. Keeping batch mode focused on all/selected sessions makes the destructive path easier to understand while preserving the existing confirmation and server deletion behavior.
Constraint: Desktop batch deletion should stay routed through the existing selected-session confirmation flow.
Rejected: Rename the age-based cleanup buttons | still leaves a low-value destructive shortcut in the primary batch panel.
Confidence: high
Scope-risk: narrow
Directive: Add future destructive cleanup shortcuts only when their target set is unambiguous in the current filtered session list.
Tested: cd desktop && bun run test src/components/layout/Sidebar.test.tsx
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Manual desktop click-through after removing the buttons.
The H5 browser shell can load while deeper Settings tabs still exercise separate API routes. This adds MCP, plugin, and Agents endpoints to the H5 policy and integration matrices so the QR-token path is protected against page-level regressions.\n\nConstraint: H5 must expose existing desktop settings surfaces only after local opt-in and a valid H5 token.\nRejected: Rely on manual browser clicks alone | they missed the stopped-port failure mode and would not guard future regressions.\nConfidence: high\nScope-risk: narrow\nDirective: Add new Settings API surfaces to this H5 matrix when exposing them in the browser UI.\nTested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts\nTested: bun run check:server
The desktop sidecar can bind on LAN addresses for phone access, so the H5 settings switch must be an authorization boundary for remote capability routes, not only a token-mode toggle. Remote browser API, proxy, websocket, and SDK routes now fail closed while H5 is disabled; local desktop, Tauri, WebUI, adapter, and internal SDK paths remain tokenless. When H5 is enabled, remote API, proxy, and websocket requests must use the H5 token carried by the QR link, and the server API key cannot substitute for that H5 token.
Constraint: Desktop sidecar binds 0.0.0.0 while reporting loopback to local UI.
Constraint: Client-controlled Host and Origin headers cannot prove a local request; the boundary uses Bun requestIP instead.
Constraint: Static H5 shell and /health must still load so browser bootstrap can show a recovery flow.
Rejected: Trust loopback Host headers | LAN clients can spoof Host and Origin.
Rejected: Use ANTHROPIC_API_KEY as a remote H5 credential | it is not the phone pairing token and would weaken the QR-token boundary.
Confidence: high
Scope-risk: moderate
Directive: Do not make h5Enabled=false an open remote state for /api, /proxy, /ws, or /sdk routes.
Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts
Tested: bun run check:server
Browser startup previously accepted any 200 response from /health. In Vite-only runs that can be the SPA fallback HTML, which lets startup continue until a later API call fails with an opaque JSON parse error.
Constraint: The H5 shell and Vite dev server can both return 200 for unknown routes.
Rejected: Only improve the visible StartupError copy | it would still misclassify the backend readiness state
Confidence: high
Scope-risk: narrow
Directive: Keep the healthcheck shape validation aligned with src/server/index.ts /health responses
Tested: cd desktop && bun run test src/lib/desktopRuntime.test.ts
Tested: cd desktop && bun run test src/lib/desktopRuntime.test.ts src/__tests__/generalSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
H5 LAN access now uses an explicit desktop confirmation, then shows a QR launch URL that carries both the serverUrl and one-time-visible H5 token. Browser startup consumes that token from the QR URL, verifies it before storing, and requires auth for non-loopback H5 endpoints while preserving local desktop bootstrap behavior.
Constraint: LAN H5 exposes desktop capabilities and must be opt-in with a visible warning.
Constraint: QR launch has to preserve routed public URLs, so the link carries serverUrl as well as h5Token.
Rejected: Store the raw token in Zustand | it would make accidental UI diagnostics or snapshots more likely to leak it
Confidence: high
Scope-risk: moderate
Directive: Do not remove the serverUrl query parameter from QR links without testing non-root publicBaseUrl deployments
Tested: cd desktop && bun run test src/lib/desktopRuntime.test.ts src/__tests__/generalSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Remote browser access now needs the H5 token once LAN mode is enabled, but changing that mode remains a local desktop control-plane operation even when deployment auth is explicitly enabled. CORS also no longer treats a non-local same-origin alias as trusted unless it is the configured H5 public origin or allowlisted origin.
Constraint: H5 exposes desktop control surfaces on the LAN and must not let remote browsers enable their own access.
Constraint: Desktop WebView, localhost WebUI, SDK websocket, and IM adapter loopback calls must remain tokenless.
Rejected: Allow authenticated remote control-plane writes under SERVER_AUTH_REQUIRED | violates the local opt-in boundary for H5 exposure.
Confidence: high
Scope-risk: moderate
Directive: Do not relax /api/h5-access mutating endpoints for browser origins without adding a reviewed desktop-only trust signal.
Tested: bun test src/server/__tests__/h5-access-auth.test.ts
Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/middleware/cors.test.ts
Tested: bun run check:server
Wire request-scoped H5 auth and CORS decisions through the server so LAN browser API, proxy, and websocket access require the H5 token while loopback desktop, Tauri WebView, local adapter, SDK, and static shell paths keep their existing bootstrap behavior.
Constraint: Task 2 scope is limited to server auth/CORS wiring and the four requested files
Rejected: Global auth toggle for all requests | would incorrectly block loopback desktop and bootstrap asset flows
Directive: Keep static H5 shell and assets tokenless unless the browser-side bootstrap model changes
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/middleware/cors.test.ts
Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts | h5-access-auth blocked by missing zod dependency in src/server/api/haha-oauth.ts
Tested: LSP diagnostics clean for src/server/index.ts, src/server/middleware/cors.ts, src/server/__tests__/h5-access-auth.test.ts, src/server/middleware/cors.test.ts
Not-tested: h5-access-auth runtime assertions because this checkout is missing zod for haha-oauth imports
The classifier should not treat every /sdk path as trusted by pathname, because LAN-exposed servers already have a narrower local SDK trust boundary.
Constraint: Desktop local chat, Tauri WebView, loopback adapters, and local SDK routes must remain tokenless.
Rejected: Path-only /sdk trust | a non-local caller could reach the SDK route through a LAN-bound server.
Confidence: high
Scope-risk: narrow
Directive: Keep remote /sdk and hostile-origin loopback requests in the H5/browser bucket unless a dedicated SDK auth layer is verified.
Tested: bun test src/server/__tests__/h5-access-policy.test.ts
Add a small standalone request classifier and focused server tests so later H5 token enforcement can target LAN/browser requests without changing the current desktop, SDK, or adapter paths.
Constraint: Task scope is limited to a standalone classifier plus tests in two server files
Constraint: Local desktop WebView, loopback integrations, and /sdk routes must remain tokenless for now
Rejected: Integrate the classifier into auth middleware now | this task only introduces the reusable classification seam
Confidence: high
Scope-risk: narrow
Directive: Keep local-trusted and internal-sdk classifications tokenless unless the server auth integration changes with matching regression coverage
Tested: bun test src/server/__tests__/h5-access-policy.test.ts
Tested: per-file TypeScript diagnostics for src/server/h5AccessPolicy.ts and src/server/__tests__/h5-access-policy.test.ts
Not-tested: Full server auth middleware integration
Not-tested: bun run check:server remains red from pre-existing repo dependency and unrelated test failures
The worktree implementation is ready for local mainline testing, and main
only advanced with unrelated chat URL wrapping. Merge the completed batch
session-management change so the desktop UI and server API move together.
Constraint: Main already contains an unrelated chat URL wrapping fix
Confidence: high
Scope-risk: moderate
Directive: Keep the merged feature commit intact; it carries the detailed implementation rationale and verification record
Tested: Feature commit verified with server batch tests, server gate, desktop gate, and browser UI smoke before merge
Not-tested: Full verify rerun after merge; merge touched no conflicting files beyond the committed feature set
The sidebar had only single-session deletion, which made stale or noisy
session lists expensive to maintain. This adds a batch-management lane in
the desktop UI and a server endpoint that deletes multiple sessions while
preserving per-session failure reporting and cleanup behavior.
Constraint: Session deletion must preserve existing transcript and adapter cleanup semantics
Constraint: Desktop UI should reuse the shared confirmation dialog instead of introducing a second modal surface
Rejected: Delete all selected sessions through repeated client DELETE calls | weaker partial-failure handling and duplicated cleanup orchestration
Rejected: Use a generic checkmark entry icon | it did not communicate batch deletion clearly enough
Confidence: high
Scope-risk: moderate
Directive: Keep batch deletion routed through the server batch endpoint so rollback and adapter cleanup stay centralized
Tested: bun test src/server/__tests__/sessions.test.ts -t batch-delete
Tested: bun run check:server
Tested: cd desktop && bun run check:desktop
Tested: browser UI smoke for group select, shift range select, delete confirmation, 7/30 day cleanup, Cmd+A filtered selection, and Escape exit
Not-tested: Live provider-backed session generation; this change covers session list management after sessions already exist
Long uninterrupted URLs can otherwise force user message bubbles beyond the chat column. The fix keeps the bubble constrained to its parent and allows safe breaks inside continuous URL text, with the same guard applied to markdown paragraphs and links.
Constraint: Issue #378 reports desktop chat overflow when a conversation contains a long URL
Rejected: Add horizontal scrolling to user messages | this preserves the overflow instead of fixing normal chat readability
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bunx vitest run src/components/chat/UserMessage.test.tsx src/components/chat/MessageList.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: bun run check:desktop
Tested: browser layout fixture PASS shell=619 bubbleClient=619 bubbleScroll=619
Not-tested: full root quality gate
Related: https://github.com/NanmiCoder/cc-haha/issues/378
This release packages the emergency H5 token pause so upgraded users can resume desktop and browser chat without generating or carrying a token. The release notes document the temporary open-access behavior and the verification run used before tagging.
Constraint: v0.2.4 restored startup but token auth can still break chat flows for upgraded users
Rejected: Wait for a full token-auth redesign | users are actively blocked and H5 auth is not critical right now
Confidence: high
Scope-risk: narrow
Directive: Restore H5 token controls only with migration coverage and browser chat E2E
Tested: bun run scripts/release.ts 0.2.5 --dry
Tested: bun run scripts/release.ts 0.2.5
Tested: bun test src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts
Tested: bun run check:server
Tested: bun run check:desktop
The H5 token gate still caused chat startup and runtime failures after the desktop startup hotfix, so the default server path now stays open for browser and LAN access. Explicit auth remains available through SERVER_AUTH_REQUIRED=1 or --auth-required for deployments that intentionally need it.
Constraint: Current H5 token state is blocking active users from normal chat usage
Rejected: Keep automatic remote-host auth with broader client-side token handling | still leaves existing upgraded clients vulnerable to stale or missing token state
Confidence: high
Scope-risk: moderate
Directive: Do not re-enable default H5 token auth without a migration and end-to-end browser chat verification
Tested: bun test src/server/__tests__/h5-access-auth.test.ts src/server/middleware/cors.test.ts
Tested: cd desktop && bun run test src/lib/desktopRuntime.test.ts src/__tests__/generalSettings.test.tsx
Tested: bun run check:server
Tested: bun run check:desktop
This release moves the verified desktop H5-auth regression fix into the versioned artifact pipeline so blocked v0.2.3 users can receive a GitHub-built replacement quickly.
Constraint: GitHub Release body is sourced from release-notes/v0.2.4.md in the tagged commit.
Constraint: Release workflow requires the app, Tauri, Cargo, and lockfile versions to match the tag.
Rejected: Ship only the hotfix commit without a release tag | affected desktop users need packaged artifacts from the release workflow.
Confidence: high
Scope-risk: narrow
Directive: Keep v0.2.4 scoped to the startup auth regression; broader H5 improvements belong in a later release.
Tested: bun run scripts/release.ts 0.2.4 --dry
Tested: bun run scripts/release.ts 0.2.4
Not-tested: GitHub release workflow before push; it only runs after the tag is pushed.
The H5 LAN release made the desktop sidecar bind broadly and require auth for non-localhost hosts. The Tauri WebView still talks to the loopback control URL without an H5 bearer token, so startup requests were rejected before the app could load.
Constraint: Desktop WebView control requests must stay tokenless for the local sidecar.
Rejected: Reuse H5 token bootstrap for Tauri | would add remote-access state to the native app startup path.
Confidence: high
Scope-risk: narrow
Directive: Tauri WebView bypass is limited to loopback control hosts; do not extend it to LAN or public hosts without re-reviewing H5 auth boundaries.
Tested: bun test src/server/__tests__/h5-access-auth.test.ts
Tested: bun run check:server
Browser-mode startup now respects an explicit Vite desktop server URL before falling back to same-origin H5 serving. This keeps local desktop smoke tests pointed at the real API server while preserving same-origin behavior for packaged H5 access.
Constraint: Vite dev smoke serves the web app and API on different loopback ports
Rejected: Treat same-origin as always preferred | Vite would answer /api requests with HTML and the chat surface never becomes ready
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test -- src/lib/desktopRuntime.test.ts src/api/client.test.ts --run
Tested: bun run check:desktop
Tested: bun run quality:gate --mode baseline --allow-live --only 'provider-smoke:*' --only 'desktop-smoke:*' --provider-model codingplan:main:codingplan-main
Not-tested: Full bun run quality:pr after this commit; it will run again during push
The release push gate exposed that the MessageList scroll tests fired synthetic user scrolls before the component's programmatic auto-scroll guard had reset. Waiting for the requestAnimationFrame reset keeps the tests aligned with the runtime behavior where users cannot scroll in the same frame as mount auto-scroll.
Constraint: Pre-push quality gate must pass before publishing the release tag
Rejected: Bypass pre-push verification | would publish without the repo's required PR quality evidence
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test -- src/components/chat/MessageList.test.tsx --run
Tested: bun run check:desktop
Tested: bun run check:coverage
Not-tested: Full bun run quality:pr after this commit; it will run again during push
The post-v0.2.2 changes are now summarized in the release body with the user-facing highlights first, while process-only H5 hardening is described as part of the new feature instead of old-version bug fixes. Desktop and Tauri version files are aligned to the release note version.
Constraint: GitHub Release body is sourced from release-notes/vX.Y.Z.md in the tagged commit
Constraint: Problem fixes should describe issues users could have seen in prior releases, not internal fixups for unreleased work
Rejected: Put every fix commit under 问题修复 | mixes development cleanup with released-user regressions
Confidence: high
Scope-risk: narrow
Tested: git diff --check
Tested: git diff --cached --check
Tested: bun run scripts/release.ts 0.2.3 --dry
Tested: version consistency check for desktop package, Tauri config, Cargo.toml, and Cargo.lock
Not-tested: Full bun run verify; release note and version bump only
The README is now the first screen most users see before deciding whether to download the app, so it leads with the desktop workflow, recent app features, and current screenshots while keeping CLI-from-source setup compact.
Constraint: Homepage should still mention the leaked Claude Code source origin.
Rejected: Keep the expanded CLI quick start on the homepage | it pushed sponsor and desktop content too far down.
Confidence: high
Scope-risk: narrow
Tested: bun run --silent check:docs
Tested: README image reference checks for Chinese and English files
Not-tested: GitHub README rendering after push
H5 exposes the desktop chat surfaces in a much narrower viewport, so the empty-session composer needs the same inset treatment as active sessions and generated diff rows need intrinsic width instead of compressing long code into the phone viewport.
Constraint: Keep desktop layout and short diff-row backgrounds unchanged while enabling sideways scrolling on H5.
Rejected: Force wrapping long diff lines | it makes code harder to inspect and diverges from desktop diff behavior.
Confidence: high
Scope-risk: narrow
Directive: Keep workspace diff rows content-width driven when adjusting mobile code preview styling.
Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx --run
Tested: cd desktop && bun run test -- src/components/workspace/WorkspacePanel.test.tsx --run
Tested: cd desktop && bun run lint
Not-tested: Full bun run verify gate; change is scoped to desktop UI styling and covered by narrow Vitest plus typecheck.
The detached worktree fix corrects stale private-network H5 public URLs after the desktop server chooses a new ephemeral LAN port. Merge it into local main while leaving unrelated local release edits untouched.
Constraint: Local main already had unrelated unstaged desktop release metadata edits.
Rejected: Broad staging before the merge | would risk committing unrelated local release work.
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/h5-access-service.test.ts
Tested: bun run check:server
Not-tested: physical phone browser on local WiFi after merge
H5 access could keep returning a previously saved private-network URL even after the packaged desktop server moved to a new ephemeral LAN port. The public settings now prefer the current auto-detected LAN URL for local/private stored addresses while preserving explicit public reverse-proxy URLs.
Constraint: Packaged desktop H5 access uses an ephemeral server port and auto-publishes a LAN URL for phones on the same network.
Rejected: Always overwrite stored publicBaseUrl | public reverse-proxy deployments still need manual stable URLs.
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/h5-access-service.test.ts
Tested: bun test src/server/__tests__/h5-access-service.test.ts src/server/__tests__/h5-access-api.test.ts src/server/__tests__/h5-access-auth.test.ts
Tested: bun run check:server
Tested: manual LAN smoke with 0.0.0.0:5188 correcting stale 192.168.0.102:5179 to 192.168.0.102:5188
Not-tested: physical phone browser on local WiFi
The previous fix compared the venv's pyvenv.cfg `home` field with the
custom interpreter's directory, but Python's venv module skips the
wrapping venv when the source interpreter is itself in a venv (conda /
pyenv / hand-built venvs — which is the common case). The recorded
`home` then points to the base Python install, not the user-provided
path, causing the comparison to permanently fail and the UI to keep
showing "venv not ready" even right after a successful rebuild.
Switch to a marker file (~/.claude/.runtime/venv-base-interpreter.txt)
that records the exact `config.pythonPath` used at venv creation time.
Status check compares it verbatim with the current config. Falls back
to "match if both empty" when the marker is missing, which preserves
behavior for legacy users who never set a custom path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The dependency check ignored the custom Python path: it only verified
the global venv's stamp file, so switching to a fresh custom interpreter
still showed deps as installed even though the new interpreter's
environment was empty. Setup also reused the old venv built from a
different base interpreter.
Verify the existing venv via pyvenv.cfg's home field, but only when a
custom path is configured — users without a custom path keep the
original code path untouched, protecting existing installations.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Packaged desktop builds started the sidecar on loopback only, so phones on the same WiFi could not connect to the H5 URL. The server now binds to LAN interfaces while keeping the desktop control URL on loopback, serves the bundled H5 frontend, and reports a LAN public URL when H5 access is enabled.
Constraint: Packaged Tauri resources place ../dist under Contents/Resources/_up_/dist.
Rejected: Bind the desktop control URL to 0.0.0.0 | desktop clients should keep using loopback for local control.
Confidence: high
Scope-risk: moderate
Directive: Keep packaged H5 resource lookup aligned with Tauri resource mapping when changing bundle resources.
Tested: bun run check:server
Tested: cd desktop/src-tauri && cargo test --lib
Tested: cd desktop && bun run test -- desktopRuntime.test.ts generalSettings.test.tsx
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: Packaged claude-sidecar smoke served H5 HTML while listening on *:39876
Not-tested: Physical phone browser test on the local WiFi network
- Skip startDragging() on right-click to prevent Tauri IPC from
disrupting the contextmenu event on macOS
- Allow context menu to render when sidebar is collapsed
- Fix auto-dismiss effect to not self-clear contextMenu state
Providers like DeepSeek with 1M context windows can report
input_tokens that, when combined with output_tokens, exceed the
declared context window — causing the UI to show >100% usage.
Add an optional contextWindow parameter to calculateCurrentContextTokenTotal
that clamps the result to the window size. Pass it from analyzeContext
and sessionService where the window size is already available.
Backward compatible: callers that omit the parameter keep existing behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>