Extend the injection effect in AssistantMessage to also append a ▾ trigger
after inline <code> elements whose text is a browser-localhost or remote URL,
so AI-written run URLs like \`http://localhost:9527/\` get the same open-with
menu that markdown <a> links already receive.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each file row in CurrentTurnChangeCard now has a sibling "open with" button
(open_in_new icon) that shows an OpenWithMenu, reusing buildOpenWithItems and
openWithContextForWorkspaceFile. HTML/XHTML files also get the in-app browser
option. Tests and i18n keys (openWith.title) included.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire createPicker into the preview-agent IIFE: enter/exit picker via host messages, bind DOM mousemove/click (capture phase) to picker hover/select, and on click emit a selection event carrying ElementMetadata + annotated screenshot. Route the selection event in previewEvents.ts through buildSelectionComposerText into queueComposerPrefill with the screenshot attachment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Routes preview://event (navigated/ready) from Rust into the browser store via a new subscribePreviewEvents subscriber; adds title field and setNavigated/setReady reducers to BrowserSessionState; BrowserSurface subscribes on mount to replace M1 optimistic nav-state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire L1 link routing into assistant message rendering. AssistantMessage now
accepts an optional sessionId and, when present, builds an onLinkClick that runs
handlePreviewLink against the running local server base (getServerBaseUrl) and
the browser/workspace panel stores, preventing default on handled links.
MessageList passes sessionId through in the assistant_text case.
Adds getServerBaseUrl() to desktopRuntime as a synchronous wrapper over the api
client's cached getBaseUrl().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implement a pure function that maps file extensions to their correct MIME types,
supporting common web assets (HTML, CSS, JS, JSON, images, fonts) with proper
charset declarations and fallback to application/octet-stream.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-session in-app mini-browser state: current URL, back/forward
history stack (historyIndex with forward-truncation on navigate),
loading flag, and element-picker toggle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Desktop image attachments were sent as @path references, which made the model invoke Read on the original file before the existing CLI image resizing path could run. This aligns desktop attachment materialization with the CLI behavior by resizing image data locally and sending SDK image content blocks, while preserving @path fallback for non-image files and failed image normalization.
Constraint: Desktop still needs local source paths for UI/context metadata while model input should avoid first-turn Read for images
Rejected: Route all attachments through @path | keeps the oversized image failure path for desktop images
Confidence: high
Scope-risk: moderate
Directive: Keep desktop image attachments aligned with CLI pasted-image processing before changing this path
Tested: bun test src/server/__tests__/conversation-attachments.test.ts
Tested: bun run check:server
Not-tested: Live GPT-5.5 proxy request with real provider credentials
Permission mode is a per-session runtime choice, while scheduled tasks cannot rely on a human approval loop. This removes the General settings permission surface, persists session permission metadata, and forces scheduled tasks to run with bypass permissions. Runtime permission changes now handle both directions across bypass boundaries, including startup/prewarm races, by persisting first and restarting only when the CLI launch mode must change.
Constraint: Scheduled tasks must be able to execute without a human standing by for authorization.
Constraint: The CLI only honors bypass permissions when launched with the skip-permissions flag, so switching to or from bypass requires a restart.
Rejected: Keep a global General permission default | it can leak across sessions and scheduled runs in ways the user cannot reason about.
Confidence: high
Scope-risk: broad
Directive: Do not reintroduce a global UI permission selector without proving it cannot affect unrelated sessions or automations.
Tested: bun test src/server/__tests__/conversations.test.ts -t "permission" --timeout 30000 (10 pass, 0 fail)
Tested: bun run check:server (858 pass, 0 fail)
Tested: cd desktop && bun run check:desktop (760 tests plus production build passed)
Tested: desktop/scripts/build-macos-arm64.sh and codesign verification passed
Tested: Real DeepSeek smoke validated plan, bypass, and scheduled task permission behavior
Not-tested: Did not repeat the full DeepSeek smoke after the final startup-race hardening; mock WebSocket permission regression and full server gate were rerun after that change.
Fixes#632
Desktop users have different multiline habits, and issue #631 calls out that Enter-only submission is too easy to trigger. This adds a persisted General setting that keeps Enter-send as the default while allowing Ctrl/Cmd+Enter submission for users who want plain Enter to insert a newline.
Constraint: Preserve existing Enter-to-send behavior as the default
Rejected: Change the global default to Ctrl/Cmd+Enter | would disrupt existing users
Confidence: high
Scope-risk: moderate
Directive: Keep active and empty session composers using the shared send shortcut helper
Tested: cd desktop && bun run test -- --run src/components/chat/ChatInput.test.tsx src/__tests__/generalSettings.test.tsx src/stores/settingsStore.test.ts
Tested: bun run check:desktop
Tested: cd desktop && bun run lint
Tested: Browser smoke on http://127.0.0.1:5174/?serverUrl=http%3A%2F%2F127.0.0.1%3A3456
Not-tested: Packaged Tauri app runtime
Related: #631
Tauri's desktop webview injects window.confirm through the dialog confirm command, but the default desktop capability only allowed the message dialog command. Windows release builds could therefore reject confirm at ACL time even though the browser-facing code path looked valid in local web development.
Constraint: Tauri plugin-dialog 2.7 still exposes window.confirm as plugin:dialog|confirm in the injected webview shim.
Rejected: Grant dialog:default | broader than the specific confirm compatibility gap.
Confidence: high
Scope-risk: narrow
Directive: Keep confirm permission covered while the desktop webview exposes browser confirm shims.
Tested: cd desktop && bun run test -- --run src/__tests__/tauriCapabilities.test.ts
Tested: bun run check:desktop
Tested: bun run check:native
Not-tested: Windows release package manual smoke
Desktop sessions already had CLI stream-idle recovery code available, but
child CLI processes did not enable it by default. A provider stream that
stopped producing chunks without closing could therefore leave the desktop UI
showing a running turn indefinitely.
Enable the existing watchdog for desktop-launched CLI sessions and lock the
launch environment with a focused regression test.
Constraint: Desktop provider streams must surface a terminal state when upstream TCP stalls silently.
Rejected: Add a frontend-only running-state timeout | it would mask the hung CLI stream without recovering the turn.
Confidence: high
Scope-risk: narrow
Directive: Keep desktop stream-stall handling at the CLI stream boundary unless the transport contract changes.
Tested: bun test src/server/__tests__/conversation-service.test.ts
Tested: bun run check:server
getLocalizedFallbackCommands previously passed a constructed key to t()
without checking if the translation actually resolved. When the i18n
table lacked an entry, t() returned the raw key (e.g.
'slashCmd.clear.description'), which dosubot flagged in PR #593.
Fix: default to the static English description, only override when
t(key) returns a different string. Add two tests covering missing-key
fallback and partial-translation scenarios.
Co-Authored-By: qwen3.6-plus <QwenLM@claude-code-best.win>
Prepare the desktop release metadata, concise release notes, and the final terminal help polish for the 0.3.1 release. The release note groups the post-0.3.0 work by user-facing area instead of listing every commit, and the desktop version metadata is aligned for the tag-triggered packaging workflow.
Constraint: GitHub Release body is sourced from release-notes/v0.3.1.md in the tagged commit
Rejected: List every post-0.3.0 commit in the release note | too noisy for this patch release
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test -- src/pages/TerminalSettings.test.tsx --run
Tested: bun run check:desktop
Tested: bun run check:native
Tested: bun run verify (passed=8 failed=0 skipped=2)
Not-tested: Live provider release gate
Normalize realpath results for Windows drive roots so D:\ does not round-trip to drive-relative D: and resolve back into the current repository.
Also tighten Sidebar hidden-project matching so a drive root does not match every child project on the same drive.
Tested: bun test src/server/__tests__/windows-drive-path.test.ts src/server/__tests__/sessions.test.ts src/server/__tests__/workspace-service.test.ts
Tested: cd desktop && bun run test -- --run src/components/layout/Sidebar.test.tsx
Tested: cd desktop && bun run build:windows-x64
Tested: bun run check:desktop
Not-tested: bun run check:server (failed on existing/environment failures including the pre-existing untracked FileReadTool test)
Confidence: high
Scope-risk: narrow
The terminal page used a header row, a status row, and an inner host-shell chrome, which reduced usable terminal space and made wheel scrolling fall into terminal scrollback while users were navigating Settings.
This collapses the terminal metadata and actions into one toolbar, removes the nested host-shell title bar, and forwards wheel input to the surrounding scroll container until the terminal is focused.
Constraint: TerminalSettings is shared by Settings, terminal tabs, and docked session terminals.
Rejected: Increase only the panel height | leaves duplicate chrome and scroll handoff unchanged
Confidence: high
Scope-risk: narrow
Directive: Keep terminal process lifetime separate from visual chrome; this change is layout and wheel routing only.
Tested: cd desktop && bun run test -- src/pages/TerminalSettings.test.tsx src/pages/ActiveSession.test.tsx src/components/layout/ContentRouter.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Not-tested: Manual Tauri window PTY smoke; browser screenshot unavailable in current tool environment