Most reports now come from desktop users, so the templates need to collect the operating system, desktop version, reproduction path, configuration screenshots, and logs before maintainers can diagnose failures.
Constraint: Desktop releases are the dominant support surface for external users
Rejected: Keep CLI-first fields at the top | it delays collecting the information needed for Windows and macOS desktop failures
Confidence: high
Scope-risk: narrow
Directive: Keep desktop OS and app version fields near the top of future issue template edits
Tested: git diff --check -- .github/ISSUE_TEMPLATE/bug_report.md .github/ISSUE_TEMPLATE/question.md
Not-tested: GitHub issue form rendering in browser
Closing the desktop window should not tear down the local server when users expect the app to keep serving background work. The Tauri layer now owns that lifecycle: close hides the main window, tray actions restore or quit, and true quit paths still stop sidecars.
Constraint: Issue #213 asks for Windows close-to-background behavior, and macOS should follow the same desktop lifecycle.
Rejected: Frontend-only close handling | native window close events and OS menu actions need one Tauri-owned path.
Confidence: high
Scope-risk: moderate
Directive: Do not remove the explicit quit marker unless all updater, tray, and app-exit paths are rechecked.
Tested: cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check
Tested: cargo check --manifest-path desktop/src-tauri/Cargo.toml
Tested: cargo test --manifest-path desktop/src-tauri/Cargo.toml
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Not-tested: Windows cargo check on this macOS machine; x86_64-pc-windows-msvc cross-check stopped in ring because the host lacks Windows C/MSVC headers.
Related: https://github.com/NanmiCoder/cc-haha/issues/213
The release note is now the GitHub Release source of truth, and the desktop version files have been moved together so the tag-triggered workflow can package the same version consistently.
Constraint: release-desktop.yml reads release-notes/v0.1.8.md from the tagged commit
Rejected: Push tag without a release commit | workflow requires version files and notes in the tag
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep the release notes filename aligned with the tag before pushing future releases
Tested: bun run scripts/release.ts 0.1.8 --dry
Tested: bun run scripts/release.ts 0.1.8
Not-tested: Remote GitHub Actions build before pushing the tag
The session inspector now asks the resumed CLI for a fast structural context estimate instead of forcing the full token-counting API path. This preserves live CLI state for system prompt, tools, MCP tools, skills, and messages while avoiding the 20s timeout that made historical sessions appear stuck or fall back to transcript-only estimates.
Constraint: Inspector requests must return quickly for third-party providers and historical resumed sessions.
Rejected: Increase the server timeout | the slow path can still block on provider token counting and keeps the UI feeling broken.
Confidence: high
Scope-risk: narrow
Directive: Keep interactive inspector context on the estimateOnly control path unless the UI explicitly supports a slow precise refresh.
Tested: bun test src/server/__tests__/conversations.test.ts -t 'structured session inspection|Sonnet 4.6 transcript usage'
Tested: cd desktop && bun run test -- --run src/i18n/index.test.tsx
Tested: cd desktop && bun run build
Tested: direct /api/sessions/:id/inspection?includeContext=1 returned live context in 0.046867s with System prompt, System tools, MCP tools, Messages
Tested: agent-browser automation verified no loading/error and visible System prompt/System tools/MCP tools/Messages
Not-tested: bare root tsc --noEmit, because current tsconfig scans existing desktop/src-tauri/target generated binary assets unrelated to this change
Session inspection was coupling quick status and usage rendering to live context control requests, so a slow get_context_usage path could leave the desktop inspector stuck on a loading state. The desktop panel now loads basic inspection data first, renders a transcript-based context estimate immediately, and only asks for live context details as a background refinement.
The translation hook now returns a stable function per locale so effects that depend on translation do not reset and re-fetch after every render.
Constraint: Third-party provider sessions may not expose reliable live context capabilities through the control request path.
Rejected: Keep waiting on live get_context_usage for the context tab | it recreates the user-visible loading stall.
Rejected: Hardcode provider-specific context windows | provider capabilities are not always known from the desktop session record.
Confidence: high
Scope-risk: moderate
Directive: Do not make the inspector first render depend on live CLI control requests without a transcript or cached fallback.
Tested: bun test src/server/__tests__/conversations.test.ts -t "structured session inspection|Sonnet 4.6 transcript usage"
Tested: cd desktop && bun run test -- --run src/i18n/index.test.tsx
Tested: cd desktop && bun run build
Tested: git diff --check
Tested: agent-browser verified /context renders transcript estimate without Loading context data
Not-tested: Provider-specific true context-window discovery for every third-party vendor
Default desktop sessions with an active third-party provider were only passing the selected model into the CLI startup path. That allowed the child CLI to fall back to stale cc-haha settings env instead of the provider index, so the UI-selected provider could diverge from the key and endpoint used by the subprocess.
Route default sessions through the active provider id and make third-party Sonnet capability overrides explicit with a non-empty sentinel. This keeps provider runtime env sourced from providers.json and avoids treating third-party Sonnet models as first-party thinking-capable models.
Constraint: Third-party provider behavior is the product baseline for desktop users.
Rejected: Rely on synced cc-haha/settings.json env | it can be stale and caused provider/key routing mismatches.
Confidence: high
Scope-risk: narrow
Directive: Third-party desktop sessions must carry providerId into ConversationService; do not depend on global settings env for active providers.
Tested: bun test src/server/__tests__/conversations.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/provider-presets.test.ts src/utils/__tests__/thinking.test.ts
Tested: git diff --check
Third-party Anthropic-compatible providers can expose Claude model names without supporting every first-party runtime capability. Desktop sessions now preserve provider-specific capability overrides, keep selected provider runtime state across reconnects and restarts, and keep the provider dialog behavior aligned with the updated presets.
Constraint: Custom ANTHROPIC_BASE_URL endpoints must not be treated as first-party Anthropic for adaptive thinking support.
Rejected: Rename provider default Sonnet models | that would hide the compatibility issue instead of fixing runtime capability detection.
Confidence: high
Scope-risk: moderate
Directive: Do not enable Claude first-party capability defaults for custom Anthropic-compatible base URLs without provider verification.
Tested: bun test src/utils/__tests__/thinking.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/provider-presets.test.ts src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test src/components/shared/Modal.test.tsx --run
Tested: git diff --check
Provider setup now keeps API keys hidden by default while still allowing an explicit reveal, and the About page links users directly to release notes and issue feedback. Provider preset copy was also adjusted so promotional text stays intentional and current.
Constraint: Reuse the existing settings page structure and provider preset schema
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: cd desktop && bun run test -- generalSettings.test.tsx
Not-tested: Full desktop lint and production build
The README footer now separates community references from sponsors and donation content, so readers can see which upstream projects informed the UI stack and provider configuration approach.
Constraint: Keep acknowledgement placement near the footer without mixing references into sponsorship copy
Confidence: high
Scope-risk: narrow
Reversibility: clean
Tested: Reviewed README.md and README.en.md diff
Not-tested: Markdown site build
Provider setup now carries the metadata needed for sponsored and local Anthropic-compatible providers, while keeping provider URLs and API keys editable in the desktop form. The desktop UI also exposes API-key links, optional sponsor copy, full key visibility, and local no-key presets that can be activated into runtime settings.
Constraint: Local LM Studio and Ollama integrations require Anthropic-compatible root URLs rather than OpenAI /v1 URLs
Rejected: Keep local providers at the top of the preset list | user requested them immediately before Custom
Confidence: high
Scope-risk: moderate
Directive: Do not change local provider base URLs to /v1 without rechecking Anthropic compatibility docs
Tested: bun test src/server/__tests__/provider-presets.test.ts src/server/__tests__/providers.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test src/__tests__/generalSettings.test.tsx --run
Tested: git diff --cached --check
Tested: Web UI provider creation plus real sessions for LM Studio, Ollama, JiekouAI, and Shengsuanyun
Not-tested: Production packaged Tauri build
The sponsor section now reflects the active partners only, with
clickable referral copy and local logo assets so GitHub renders the
same layout in both Chinese and English READMEs.
Constraint: Chinese and English README sponsor sections must stay synchronized
Rejected: Keep LegionProxy as a lower-priority sponsor | user requested removing it
Confidence: high
Scope-risk: narrow
Tested: git diff --cached --check
Not-tested: GitHub rendered README preview
Kimi Code documents a separate Anthropic-compatible coding endpoint from the Moonshot open platform, so the built-in Kimi preset should point Claude-compatible traffic at the coding endpoint instead of the retired Moonshot anthropic path.
Constraint: Kimi Code Anthropic-compatible base URL is https://api.kimi.com/coding/ and this app appends /v1/messages at runtime.
Rejected: Use https://api.moonshot.cn/coding | official Kimi docs distinguish Kimi Code from the Moonshot open platform URLs.
Confidence: high
Scope-risk: narrow
Directive: Do not switch Kimi back to api.moonshot.cn/anthropic without rechecking current Kimi Code docs.
Tested: bun test src/server/__tests__/provider-presets.test.ts
Not-tested: Live Kimi API call with a real user key
The desktop terminal already supported independent PTY sessions, but it only lived inside settings. This change promotes it to a first-class tab workflow so users can open multiple host terminals without leaving the chat-oriented desktop layout.
Constraint: Tauri terminal sessions are process-backed and must stay mounted while switching tabs.
Rejected: Reuse the settings terminal as a navigated page only | it cannot support multiple independent terminal tabs.
Rejected: Hide inactive xterm panes with display none | xterm lost visible output after tab switches during E2E.
Confidence: high
Scope-risk: moderate
Directive: Keep inactive terminal panes mounted and avoid display none unless xterm repaint behavior is reverified.
Tested: bun run test src/components/layout/ContentRouter.test.tsx src/components/layout/Sidebar.test.tsx src/components/layout/TabBar.test.tsx src/pages/TerminalSettings.test.tsx
Tested: bun run lint
Tested: bun run build
Tested: ./scripts/build-macos-arm64.sh
Tested: Computer Use E2E against build-artifacts/macos-arm64 app for multiple terminals, command output retention, tab switching, and terminal cleanup
Not-tested: Intel macOS package
Subagent transcripts are stored in sidecar JSONL files, so the desktop history loader now links completed Agent results back to their sidecar tool activity and namespaces child tool ids before rendering. The chat renderer then keeps parented tool calls and orphaned child results out of the root session stream, while the Agent result preview strips runtime metadata from the user-facing answer.
Constraint: Subagent tool activity may live under ~/.claude/projects/{project}/{session}/subagents instead of the main session JSONL
Rejected: Rely only on adjacent message ordering | interleaved messages can split parent and child tool activity
Rejected: Show final Agent output inside the expanded card | expanded cards should show process activity while the modal shows the final answer
Confidence: high
Scope-risk: moderate
Directive: Do not remove child tool id namespacing without proving multiple subagents cannot emit colliding tool ids
Tested: bun test src/server/__tests__/sessions.test.ts
Tested: cd desktop && bun run test -- MessageList.test.tsx chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: agent-browser E2E with two dispatched subagents in /tmp/cc-haha-agent-e2e-q4Xm2s
Not-tested: Live streaming of sidecar subagent tool activity before the sidecar file is persisted
The model selector reused the light-theme primary fixed surface for selected rows, which made dark mode render a pale block with poor text contrast. This gives the selector its own selected-row tokens so dark mode can keep a low-luminance surface while light mode preserves the existing look.
Constraint: Keep the fix scoped to desktop theme tokens and the existing selector component
Rejected: Change primary-fixed globally | too broad because other components rely on that token semantics
Confidence: high
Scope-risk: narrow
Directive: Do not point selected model rows back to primary-fixed without checking dark-mode contrast
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
Not-tested: Browser screenshot capture blocked by an existing Chrome DevTools profile instance
The context tab needs both absolute token counts and percent-of-window values to stay scannable. Category rows now show the percent next to each token count, and the free-space summary card also reports remaining percent.
Constraint: Keep the compact terminal-inspired layout while restoring the numeric detail users rely on.
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run lint
Tested: git diff --check
Tested: agent-browser smoke test on http://127.0.0.1:2024/ for /context percentages
Not-tested: Packaged Tauri build.
Desktop slash commands now separate local UI panels from CLI turn execution. The session inspector exposes status, usage, and context data from the active session, including transcript and context fallbacks, so /status, /cost, and /context can render structured desktop UI instead of raw terminal text. The inspector and help surfaces now use the existing desktop i18n catalogs for English and Chinese labels.
Constraint: Desktop read-only slash commands must not spawn duplicate CLI processes or depend on submitting a normal user turn.
Rejected: Render raw CLI command text in chat | it keeps terminal-specific layout constraints and does not fit the desktop panel UX.
Confidence: high
Scope-risk: moderate
Directive: Keep /status, /cost, and /context routed through the local inspector unless the CLI exposes a structured interactive command protocol.
Tested: cd desktop && bun run lint
Tested: cd desktop && bun test src/components/chat/composerUtils.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run build
Tested: agent-browser smoke test on http://127.0.0.1:2024/ for /context localized inspector
Tested: git diff --check
Not-tested: Full packaged Tauri desktop build.
Desktop rewind previously used the visible user-message index as the primary selector. That can drift from the persisted active chain when hidden or non-rendered user messages exist, so the API now prefers a stable user message id and checks the selected prompt text before mutating transcript or files.
Constraint: Desktop UI can hide transcript entries that still exist in the persisted session chain
Rejected: Keep index-only rewind | can target an earlier user message after UI/server chain drift
Confidence: high
Scope-risk: moderate
Directive: Do not remove targetUserMessageId or expectedContent guards without reproducing shifted visible-index sessions
Tested: bun test src/server/__tests__/sessions.test.ts --timeout 20000
Tested: cd desktop && bun run test MessageList.test.tsx chatStore.test.ts -- --run
Tested: desktop/scripts/e2e-rewind-agent-browser.sh
Tested: desktop/scripts/e2e-rewind-complex-agent-browser.sh
Not-tested: Full desktop Vitest suite still has unrelated locale-sensitive failures
The local Apple Silicon packaging script produced app bundles that could
fail strict bundle validation because the outer .app had no sealed
resources. The fix shallow-signs only the copied canonical app bundle and
checks that the claude-sidecar code-signature hash stays unchanged.
Constraint: GitHub Actions release packaging must remain on the existing tauri-action path
Constraint: macOS Keychain ACLs are sensitive to sidecar code-signature hashes
Rejected: Set macOS signingIdentity in release CI | Tauri re-signs nested sidecars and can change Keychain caller identity
Confidence: high
Scope-risk: narrow
Directive: Do not deep-sign claude-sidecar without proving existing Keychain ACLs still work after upgrade
Tested: bash -n desktop/scripts/build-macos-arm64.sh
Tested: SKIP_INSTALL=1 desktop/scripts/build-macos-arm64.sh
Tested: codesign --verify --deep --strict --verbose=2 desktop/build-artifacts/macos-arm64/Claude\ Code\ Haha.app
Tested: open -n desktop/build-artifacts/macos-arm64/Claude\ Code\ Haha.app and /health returned ok
Not-tested: GitHub Actions release workflow, intentionally unchanged
The repository uses product-oriented branch prefixes rather than Codex-specific names, so the workspace guidance now records that convention for future local branch creation.
Constraint: Repository guidance should stay compact and only capture durable workflow rules.
Confidence: high
Scope-risk: narrow
Tested: not run; documentation-only change
A desktop session can pass the startup grace window and then lose its CLI subprocess before a result arrives. Previously that path only deleted the active process record, leaving the WebSocket client in an active turn with no terminal message. The process-exit handler now emits a synthetic CLI error result through the existing translation path so the UI receives both an error and message_complete. The mock SDK fixture can reproduce post-startup exits, and the integration test locks the terminal event behavior.
Constraint: The frontend already relies on result is_error translation to emit error plus message_complete.
Rejected: Add a separate WebSocket process-exit message type | it would duplicate existing result-error handling and require another frontend state path.
Confidence: high
Scope-risk: narrow
Directive: Keep process-exit failures on the same result-error path unless the client protocol gains a dedicated terminal error event.
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run lint
Tested: agent-browser against http://127.0.0.1:1421 with mock CLI late exit; page showed CLI process exited unexpectedly and composer became editable again
Desktop slash command handling needed a few follow-up guards after adding
CLI parity. Bare /clear remains a local desktop reset, but /clear with
arguments is rejected instead of silently discarding user text. Clear also
resets cached slash commands, compact boundaries preserve CLI-provided text,
and the help panel now discloses when the More section is truncated.
Constraint: Preserve the desktop /clear fast path without accepting accidental arguments
Rejected: Let /clear arguments fall through to the CLI | the CLI command still clears context and would keep the footgun
Confidence: high
Scope-risk: narrow
Directive: Keep desktop-local slash command guards in sync with CLI command argument semantics
Tested: cd desktop && bun run test src/stores/chatStore.test.ts src/__tests__/pages.test.tsx --run -t "clears local desktop chat state|ActiveSession routes /help"
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run lint
Tested: git diff --check
Not-tested: Full pages.test.tsx because unrelated locale-sensitive assertions are already present in that file
Desktop had no reliable handling for common local slash commands, so
commands like /clear, /help, /context, /cost, and /compact either looked
unresponsive or lost their CLI-specific side effects. This routes desktop
commands by behavior: local panels stay local, stateful clear resets the
session transcript, and CLI-local outputs are rendered in chat.
Constraint: Preserve existing CLI semantics for prompt, local, local-jsx, and compact slash commands
Rejected: Send every slash command through the normal chat path | local commands need desktop UI or session state side effects
Confidence: high
Scope-risk: moderate
Directive: Keep hidden aliases such as /plugins out of the visible command list unless they become canonical CLI commands
Tested: cd desktop && bun run test src/components/chat/composerUtils.test.ts src/stores/chatStore.test.ts --run
Tested: cd desktop && bun run test src/__tests__/pages.test.tsx --run -t "ActiveSession routes /plugin|ActiveSession routes /help|EmptySession slash picker includes dynamic skills"
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run lint
Tested: agent-browser E2E for /help, /plugin, /plugins, /cost, /clear, /context, /compact, /mcp, and normal text input
Not-tested: Root tsc project because it currently includes generated Tauri target assets and extracted native files
Add the sponsor entry to both README variants so GitHub visitors see the same partnership information in Chinese and English. The logo is kept in the docs image tree so the table can render without relying on a remote asset.
Constraint: Sponsorship section should use the table layout shown by the user
Rejected: Text-only sponsor row | it missed the logo-focused layout requested by the example
Confidence: high
Scope-risk: narrow
Directive: Keep README.md and README.en.md sponsorship entries aligned when adding or editing sponsors
Tested: git diff --cached --check
Not-tested: GitHub web rendering after push
The desktop release workflow reads release-notes/v0.1.6.md from the tagged commit, so this commit aligns version metadata, lockfile state, and release copy before creating the v0.1.6 tag.
Constraint: GitHub Actions packaging is triggered by pushed v*.*.* tags, not by a plain main push
Constraint: The release script expects release-notes/vX.Y.Z.md to exist in the tagged commit
Rejected: Push main without a tag | that would not start the desktop release workflow
Confidence: high
Scope-risk: narrow
Directive: Keep version files, Cargo.lock, release notes, and the release tag aligned for desktop releases
Tested: bun run scripts/release.ts 0.1.6 --dry
Tested: git diff --cached --check
Not-tested: Remote GitHub Actions run before pushing the tag
Desktop sessions could show MCP configuration in the UI while the CLI SDK child process still started cold on the first user message. Start eligible desktop chat sessions as soon as their websocket is connected, keep init metadata cached but muted, and wait briefly for MCP startup in SDK print mode so turn one sees the tools.
Constraint: Desktop wraps the existing CLI SDK bridge rather than owning MCP startup directly.
Rejected: Prewarm every restored tab | synthetic tabs such as settings would start unnecessary CLI subprocesses.
Confidence: high
Scope-risk: moderate
Directive: Do not remove the synthetic-tab guard without validating restored settings and scheduled-task tabs in the browser.
Tested: bun test src/server/__tests__/conversations.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/mcp.test.ts
Tested: cd desktop && bun run test -- chatStore.test.ts mcpSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: agent-browser E2E new session prewarm plus first message reuse with mock CLI
Not-tested: Full desktop Vitest suite still has pre-existing English-vs-Chinese copy assertion failures.
Plugin actions refresh the selected plugin detail after mutating enabled state. The detail component can enter its loading branch while a plugin is still selected, so every hook must run before that early return.
Constraint: React hook order must stay identical across the detail and loading render paths.
Rejected: Clear the selected plugin before reload | would hide the current context and add UI churn during short refreshes.
Confidence: high
Scope-risk: narrow
Directive: Keep PluginDetail hooks before loading and empty-state returns when adding detail-derived memoization.
Tested: cd desktop && bun run test src/__tests__/pluginsSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Not-tested: Full desktop Vitest suite has pre-existing locale assertion failures unrelated to this plugin fix.
Desktop sessions can switch provider and model while a CLI subprocess is already alive, so the server now serializes runtime restarts and marks provider-managed launches to prevent stale settings env from overriding the selected provider. Provider settings also write API key env consistently and clear stale managed keys before syncing.
This includes the related desktop/docs brand asset refresh and keeps the desktop locale default in Chinese, with tests updated to match the current provider semantics.
Constraint: Session-scoped model selection must win over cc-haha/settings.json and inherited ANTHROPIC_* values.
Rejected: Store the selected model as a global provider activeModel | chat runtime selection is per session.
Confidence: high
Scope-risk: moderate
Directive: Do not remove CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST without validating Desktop provider switching against stale settings env.
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/conversations.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/providers-real.test.ts
Tested: cd desktop && bun run test src/stores/settingsStore.test.ts
Tested: cd desktop && bun run lint
Tested: git diff --check
Not-tested: Full desktop production package/signing.
The detached worktree implementation adds a Settings terminal for command-based setup flows. The merge keeps the target branch's current adapter/runtime dependencies while adding the new portable-pty backend, xterm frontend, UTF-8 output handling, and host-shell environment propagation.
Constraint: Target branch had newer desktop dependency changes, including anyhow in the Tauri crate.
Constraint: Existing uncommitted work in the main worktree had to stay out of this merge commit.
Rejected: Fast-forward the checked-out branch under a dirty worktree | would risk mixing unrelated local changes into the branch state.
Confidence: high
Scope-risk: moderate
Directive: Treat the terminal as host-shell integration; keep PATH and UTF-8 locale handling together when changing startup behavior.
Tested: cargo fmt --check
Tested: cargo test --lib
Tested: cargo check
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test src/pages/TerminalSettings.test.tsx
Tested: git diff --check
Not-tested: Rebuilt macOS DMG from the target branch after merge.
Some setup flows end in a shell command instead of a natural-language install path, so Settings now exposes a host PTY terminal backed by portable-pty and xterm. The terminal inherits the user's login-shell environment, forces a UTF-8 locale when needed, and preserves split UTF-8 output so Chinese paths render correctly.
Constraint: Desktop GUI apps do not inherit the user's interactive shell PATH on macOS.
Constraint: Command output may split UTF-8 characters across PTY reads.
Rejected: Use Tauri shell commands only | users need an interactive PTY for copy-pasted install flows.
Rejected: Ask users to edit shell profiles | terminal setup should work out of the box.
Confidence: high
Scope-risk: moderate
Directive: Keep terminal startup tied to host environment checks; do not bundle runtimes to solve PATH issues.
Tested: cargo fmt --check; cargo test --lib; cargo check; cd desktop && bun run lint; cd desktop && bun run test src/pages/TerminalSettings.test.tsx; cd desktop && bun run build; cd desktop && bun run build:macos-arm64
Tested: Computer Use verified npm is available in the built macOS app terminal and Chinese output renders after UTF-8 decoding fix.
Not-tested: Native Windows/Linux package runtime validation.