mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-03 20:59:22 +08:00
refactor/code-cli
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b497a49826 | refactor(env-utils): consolidate shell/binary env handling and clean up BinaryManager (#16594) | ||
|
|
efecdd5007 |
refactor(binary-manager): unify CLI binary acquisition behind mise-backed BinaryManager (#15184)
### What this PR does **Before this PR**, Cherry Studio managed external CLI binaries through five uncoordinated mechanisms — each requiring its own download script, IPC channel, and on-disk layout: | Mechanism | Where it lived | How it worked | |---|---|---| | rtk extraction | `src/main/utils/rtk.ts` + `AgentBootstrapService` | Copies bundled binary to `~/.cherrystudio/bin/` | | OpenClaw installer | `resources/scripts/install-openclaw.js` | Downloads from GitHub/mirror with custom extraction | | CodeCliService | `src/main/services/CodeCliService.ts` | `bun install -g` to `~/.cherrystudio/install/global/` | | ripgrep | `node_modules/@anthropic-ai/claude-agent-sdk/vendor/` | Vendored, hardcoded path in `FileStorage` | | (old) MiseService | `src/main/services/MiseService.ts` | Bundled mise + `mise use -g` | **After this PR**, a single `BinaryManager` lifecycle service owns all third-party CLI binary acquisition. It wraps [mise](https://mise.jdx.dev) as the only acquisition backend (no custom `BinaryBackend` interface — mise's polyglot grammar already covers `npm:`, `pipx:`, `github:`, registry entries). Tools install into an isolated environment under `~/.cherrystudio/mise/` so user-level mise installs are never touched. `uv`, `bun`, `rg`, and mise itself ship bundled at build time for instant first-run availability; everything else flows through mise on demand. <img width=\"1304\" height=\"714\" alt=\"BinaryManager settings UI\" src=\"https://github.com/user-attachments/assets/7a4b78ab-5aa2-4e97-9ab7-134b20a4d78d\" /> <img width=\"1165\" height=\"748\" alt=\"Three-state managed vs bundled vs not-installed\" src=\"https://github.com/user-attachments/assets/a0dcfb7d-8bc3-4acd-b563-0fc04d99e252\" /> <img width=\"523\" height=\"328\" alt=\"Custom tool dialog\" src=\"https://github.com/user-attachments/assets/90c3ee95-7f2a-4daf-a334-f20de6ff5ca2\" /> Fixes #15183. Addresses #15370. ### Why we need it and why it was done in this way Adding a new managed CLI tool should be a one-line preset entry — not 4+ files of bespoke download/extract/IPC code. mise is a mature polyglot tool manager that already speaks the backends Cherry needs. **Tradeoffs made:** - **mise bundled at build time** (~15 MB per platform) rather than downloaded at first run — faster first-run UX, no chicken-and-egg on a fresh install. - **Fully isolated mise environment** (\`HOME\`/\`XDG_*\`/\`MISE_*\` all relocated under \`feature.binaries.data\`) — Cherry never reads or writes the user's own \`~/.config/mise/\` or \`~/.local/share/mise/\`. - **No custom \`BinaryBackend\` interface.** mise's grammar (\`npm:\`, \`pipx:\`, \`github:\`, registry) is already polyglot; wrapping it would be a shallow seam that re-implements what mise owns. Removing this abstraction makes consumers simpler (deletion test passes). - **Auth-token policy: opt-in only.** Ambient \`GITHUB_TOKEN\` / \`GH_TOKEN\` are not forwarded into mise's process env. Users who hit GitHub's unauthenticated 60 req/hr API limit can set \`CHERRY_GITHUB_TOKEN\` to raise it to 5000 req/hr without consenting to share their general shell token. - **China mirror auto-detection.** \`isUserInChina()\` toggles \`NPM_CONFIG_REGISTRY=registry.npmmirror.com\` + \`PIP_INDEX_URL=pypi.tuna.tsinghua.edu.cn\` for every npm/pipx backend transparently. **Alternatives considered:** - *Keep per-tool install scripts.* Doesn't scale — each new tool is 4+ files of duplicated logic. - *Use mise from user's \`PATH\`.* Would depend on user having mise installed and could conflict with their config. - *Custom \`BinaryBackend\` abstraction.* Shallow wrapper over mise's grammar; no second backend in sight; deletion test passes. **Scope (what's in / what's out):** - **In:** uv, bun, ripgrep, claude-code, openclaw, gh, opencode, gemini-cli, lark, kimi-cli, qwen-code, iflow-cli, github-copilot-cli — anything mise can install as a single relocatable binary. - **Out:** \`OvmsManager\` (multi-file server provisioning, hardware detection, generated config); Tesseract OCR data (not a binary; lives with \`OvOcrService\`). ### Breaking changes None at the user-facing layer. v2 data is throwaway per CLAUDE.md, so the preference-key rename (\`feature.mise.*\` → \`feature.binaries.*\`) intentionally ships without a migrator. ### Special notes for your reviewer **Architecture & docs** - \`docs/references/binary-manager/README.md\` — scope criterion, persisted/contract surface, bundled-vs-mise state contract, China mirror behavior, \`CHERRY_GITHUB_TOKEN\` opt-in, adding a new managed binary. - \`CLAUDE.md\` adds a \`**MUST READ**\` link next to Lifecycle / Window Manager / Data / Paths. - The mise-shim-wins-over-\`cherry.bin\` precedence rule is documented in the README's "State contract" section. **Code orientation** - \`src/main/services/BinaryManager.ts\` — the lifecycle service. Wraps mise via \`runMise()\`; isolated env in \`buildIsolatedEnv()\`; bundled extraction with atomic tmp+rename; per-tool try/catch so a single failure can't abort init; \`isManagedBinaryReady()\` verifies the resolved file is executable (not just that mise thinks it's installed). - \`packages/shared/data/presets/binary-tools.ts\` — \`PREDEFINED_BINARY_TOOLS\` registry; \`tool\` field is a mise spec. - \`src/renderer/src/pages/settings/McpSettings/EnvironmentDependencies.tsx\` — three-state UI (\`managed\` / \`bundled\` / \`not-installed\`) backed by \`Binary_GetState\` + \`Binary_ProbeBundled\`. - \`scripts/download-binaries.js\` — build-time downloader for mise / uv / bun / rg (HTTPS + sha256-verified, archive-aware extraction). **Migration** - \`OpenClawService.install()\` is now two lines delegating to \`BinaryManager\` — \`install-openclaw.js\` is gone. - \`CodeCliService\` no longer uses \`bun install -g\`; the \`BUN_INSTALL\` / \`~/.cherrystudio/install/global/\` path is removed. - \`FileStorage.getRipgrepBinaryPath()\` now resolves via \`getBinaryPath('rg')\`; the vendored SDK rg is no longer used. - \`extractRtkBinaries\` + the \`AgentBootstrapService\` call are deleted. \`rtkRewrite()\` degrades gracefully when rtk is absent; \`rtkAvailable\` caches with a 60s TTL so install-via-mise takes effect without restart. **Multi-round review** Two adversarial review rounds against this branch (Bug Hunter / Security / Architecture / Correctness) ran during development; both rounds' High-severity findings are addressed in commits \`70afde6af\` and \`1d864439d\`. R3 known follow-ups (architecture duplications in \`CodeCliService\`'s switch statements, etc.) are tracked as Medium and intentionally deferred. ### Checklist - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: Write code that humans can understand and Keep it simple - [x] Refactor: Leaves binary acquisition meaningfully cleaner than before (five mechanisms → one) - [x] Upgrade: v2 data is throwaway; no migrator needed and the absence is intentional - [x] Documentation: \`docs/references/binary-manager/README.md\` + \`CLAUDE.md\` Architecture section - [x] Self-review: Two multi-perspective review rounds against the branch; all Highs addressed ### Release note \`\`\`release-note NONE \`\`\` --------- Signed-off-by: Vaayne <liu.vaayne@gmail.com> Signed-off-by: Vaayne Liu <vaayne@macos.shared> Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com> |