Apply the naming-conventions §6.1 acronym-casing rule (MCP -> Mcp) to the
MCP* PascalCase identifier family across the codebase (McpServer, McpTool,
McpToolResponse, BuiltinMcpServerNames, McpService, etc.) plus the local
identifiers boundMcp/enableMcp/disableMcp and the didiMcp registry key.
Regenerate the OpenAPI spec from the renamed schemas.
Deliberately left unchanged (not naming-convention identifiers): persisted
field keys read by migrators (enabledMCPs), v1 Redux selectors (selectMCP),
string values (ExaMCP, logger labels), and UPPER_SNAKE constants (MCP_*).
Also fix naming issues in the data reference docs that prompted this:
- JSONStreamReader -> JsonStreamReader (match the real class name)
- rowToMCPServer -> rowToMcpServer (match the real function name)
- replace the TopicService getInstance() skeleton with a direct singleton
- sync stale MCPServer/MCPTool/McpService references in affected docs
Move all renderer source from src/renderer/src/* up one level to
src/renderer/*, removing the redundant nested src directory.
- Update path aliases (@renderer, @types, @logger, @data) and TanStack
Router paths in electron.vite.config.ts; update tsconfig.{json,web,node}
path mappings and include globs.
- Fix Vite root-relative script paths in the 8 renderer HTML entries.
- Update cross-process relative imports in main/preload (language,
apiServer models, preload index) to drop the /src segment.
- Switch renderer test imports of the logger mock to the @test-mocks alias.
- Update hardcoded renderer paths in scripts and their fixtures, lint
configs (eslint/oxlint/biome), CODEOWNERS, docs, and the data-classify tool.
- Convert deep (../../+) relative imports within the renderer to the
@renderer alias (69 files, 108 imports); keep single-level relatives.
- Fix doc links broken by the move and correct one pre-existing broken
link in naming-conventions.md.
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).
Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.
The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
Normalise the bundle id casing from com.cherryai.CherryStudio to
com.cherryai.cherrystudio so it follows the dominant lowercase
convention used by modern AI tools (Anthropic Claude, OpenAI Codex,
Raycast, Docker) and the reverse-DNS norm. macOS LaunchServices is
case-insensitive, so this is a no-op on existing installs - bundle-id
bound state stays as it was after 4439d3b28, and no new breaking-changes
entry is needed.
Touches the same five definition points as the original rebrand
(electron-builder appId, notarize appBundleId, AppUserModelID, selection
self-detection, preview workflow replaceAll/appId) plus the
breaking-changes doc body. The doc's historical commit-subject reference
for 4439d3b28 deliberately retains its original PascalCase to remain a
faithful quote of that commit's subject.
Rename the app bundle id from com.kangfenmao.CherryStudio to
com.cherryai.CherryStudio at every definition point: electron-builder
appId (packaging source of truth), macOS notarization appBundleId,
Windows AppUserModelID, and the selection self-detection allowlist.
Daily preview builds now use com.cherryai.CherryStudio.preview (a distinct
channel id rather than a case-only variant that macOS would treat as the
same app); the workflow replaceAll search strings are updated to the new
id so the preview identity patch keeps matching.
Incidental cleanups bundled in:
- Drop the unused MAIN_VITE_BUNDLE_ID env override; env.d.ts now declares
the actually-used MAIN_VITE_CHERRYAI_CLIENT_SECRET instead of leaning on
vite/client's any index signature.
- Remove the stale @kangfenmao/keyv-storage from pnpm.onlyBuiltDependencies.
- SearchService: use @main/core/platform isDev over electron-toolkit is.dev.
<!-- Template from
https://github.com/kubevirt/kubevirt/blob/main/.github/PULL_REQUEST_TEMPLATE.md?-->
<!-- Thanks for sending a pull request! Here are some tips for you:
1. Consider creating this PR as draft:
https://github.com/CherryHQ/cherry-studio/blob/main/CONTRIBUTING.md
-->
<!--
🚨 Branch Strategy Change (Effective April 3, 2026) 🚨
The `main` branch is now under CODE FREEZE.
- main branch: Only accepts critical bug fixes via `hotfix/*` branches.
Fix PRs must be minimal in scope and must not include any refactoring
code.
- v2 branch: All new features, refactoring, and optimizations should be
submitted to the `v2` branch.
If you are submitting a bug fix to main, please ensure your PR is from a
`hotfix/*` branch.
-->
### What this PR does
Before this PR:
GitCode release sync builds signed Windows artifacts and uploads them to
GitCode in one self-hosted Windows signing job. If the signing runner
has unreliable outbound network connectivity, the GitCode release
creation or asset upload can fail after the signed artifacts were
already built. The workflow also has no dry-run mode for validating a
manual release sync.
After this PR:
The workflow builds signed Windows artifacts on the Windows signing
runner, uploads them as a short-lived GitHub Actions artifact, then
performs GitCode release creation and asset upload from `ubuntu-latest`.
Manual dispatch supports a `dry_run` mode that previews the release
payload and upload file list without creating the GitCode release.
Windows code signing also retries timestamping across multiple timestamp
servers before failing.
<!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)`
format, will close the issue(s) when PR gets merged)*: -->
Fixes # None
### Why we need it and why it was done in this way
The following tradeoffs were made:
The release sync now uses an intermediate GitHub Actions artifact to
pass signed Windows files from the signing runner to the Ubuntu sync
job. This adds one artifact upload/download step, but keeps certificate
access constrained to the signing runner while moving GitCode API
traffic to a more reliable hosted runner.
The following alternatives were considered:
Keeping GitCode sync on the signing runner was simpler, but it leaves
release sync vulnerable to transient network failures on that runner.
Retrying only the GitCode upload would not address timestamp-server
flakiness during Windows signing, so this PR also adds timestamp server
fallback and retry support in `scripts/win-sign.js`.
Links to places where the discussion took place: N/A
### Breaking changes
None.
### Special notes for your reviewer
Validation performed:
- `pnpm format`
- `pnpm lint` (passed with one pre-existing unrelated React hook warning
in
`src/renderer/src/pages/settings/ProviderSettings/ModelList/ManageModelsPopup.tsx`)
- `pnpm test`
- Parsed `.github/workflows/sync-to-gitcode.yml` with the repository
`yaml` package
`actionlint` was attempted, but the npm package named `actionlint` does
not expose a binary and this environment does not have Go installed to
run the upstream Go tool directly.
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [ ] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
<!-- Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->
```release-note
NONE
```
Signed-off-by: zhibisora <73344387+zhibisora@users.noreply.github.com>
### What this PR does
Before this PR:
Tailwind canonical class suggestions such as `w-[420px] -> w-105` had to
be fixed manually, and the PR style reminder workflow only reported
newly introduced legacy renderer CSS variables.
After this PR:
Adds `pnpm styles:canonical <path>` to rewrite static Tailwind class
strings to their canonical Tailwind v4 forms. The PR style reminders
workflow now comments on both newly introduced legacy CSS variables and
Tailwind canonical class suggestions.
<!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)`
format, will close the issue(s) when PR gets merged)*: -->
Fixes #
### Why we need it and why it was done in this way
The following tradeoffs were made:
The canonical class fixer is conservative: it only rewrites static JSX
`class` / `className` strings and static `cn(...)` string inputs,
leaving dynamic template literals untouched. It uses Tailwind's own
design system canonicalization instead of maintaining a manual mapping
table.
The following alternatives were considered:
A regex-only implementation was avoided because Tailwind
canonicalization depends on Tailwind v4 parsing and theme behavior. A
separate PR workflow comment was also avoided so the style reminders
comment remains the single bot comment.
Links to places where the discussion took place: N/A
### Breaking changes
None.
### Special notes for your reviewer
Compatibility aliases and legacy marker/env fallback were removed; the
PR workflow now uses the `style-reminders` script, marker, and output
naming.
Validation performed:
- `pnpm test:scripts --
scripts/__tests__/check-pr-style-reminders.test.ts
scripts/__tests__/fix-tailwind-canonical-classes.test.ts`
- `pnpm build:check`
- `git diff --check`
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
<!-- Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->
```release-note
NONE
```
---------
Signed-off-by: kangfenmao <kangfenmao@qq.com>
### What this PR does
Before this PR:
Cherry Studio supported 11 languages but did not include Vietnamese.
After this PR:
Vietnamese (vi-VN / Tiếng Việt) is fully supported with 4016 translated
keys across both renderer and main processes. Ant Design components
correctly display Vietnamese locale. All 106 previously leaked
non-Vietnamese strings have been re-translated.
### Why we need it and why it was done in this way
Vietnamese users represent a growing segment of Cherry Studio's user
base. Adding vi-VN follows the same pattern as all existing
machine-translated locales (de-DE, es-ES, fr-FR, etc.):
1. Register `vi-VN` in the `LanguageVarious` TypeScript union type
2. Add locale entries to all `Record<LanguageVarious, ...>` maps (i18n,
dayjs, EmojiPicker)
3. Add `vi-VN` to main process `locales.ts` for menu/dialog translations
4. Add `vi-VN` case to `AntdProvider.tsx` for Ant Design component
localization
5. Add language selector option in GeneralSettings
6. Add `'vi-vn': 'Vietnamese'` to the auto-translate script's
`languageMap`
7. Generate the initial `vi-vn.json` translation file and fix 106
wrong-language entries
The following tradeoffs were made:
- EmojiPicker falls back to English data/i18n for Vietnamese since
`emoji-picker-element` doesn't ship Vietnamese locale data. This is
consistent with how Romanian and Greek are handled.
The following alternatives were considered:
- Manual translation: rejected in favor of machine translation for
consistency with other non-CJK locales, and because the CI pipeline
auto-maintains translations going forward.
### Breaking changes
None.
### Special notes for your reviewer
- The `vi-vn.json` file (~6000 lines) is machine-translated. 106 entries
that originally leaked from other locales (German, Spanish, French,
Italian, Thai, Japanese, Korean, etc.) were detected and re-translated.
- Compared to the previous PR (#14277), this version additionally
updates `src/main/utils/locales.ts` (main process translations) and
`src/renderer/src/context/AntdProvider.tsx` (Ant Design locale), which
were missing before.
- No changes to the CI workflow (`auto-i18n.yml`) were needed — it
auto-discovers all JSON files in the `translate/` directory.
- All checks pass: `pnpm lint`, `pnpm test` (4107 tests), `pnpm
typecheck`, `pnpm i18n:check`.
### 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: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [x] Documentation: A user-guide update was considered and is present
(link) or not required. Check this only when the PR introduces or
changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code before requesting review
from others
### Release note
```release-note
Added Vietnamese (Tiếng Việt) language support with complete UI translations and automatic translation maintenance via CI.
```
### Screenshots
| Agent Page | Assistant Page | Settings Page |
|:---:|:---:|:---:|
|

|

|

|
---------
Signed-off-by: zhengke090@gmail.com <zhengke090@126.com>
Co-authored-by: zhengke090@gmail.com <zhengke090@126.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: SuYao <sy20010504@gmail.com>
Co-authored-by: George·Dong <98630204+GeorgeDong32@users.noreply.github.com>
### What this PR does
fix#13833
Before this PR:
Spawned Claude Code child processes did not reliably use the app's
configured proxy settings. HTTP proxy mode could work, but SOCKS proxy
mode could hang before the SDK returned any initial stream events.
After this PR:
Spawned Claude Code child processes inherit a dedicated Node-only proxy
bootstrap that applies the app's configured proxy settings for
fetch/undici, http/https, and axios. SOCKS proxy mode now avoids
exporting incompatible HTTP proxy env vars and emits clearer diagnostics
when proxy injection is active.
Fixes # None
### Why we need it and why it was done in this way
Claude Code runs as a standalone spawned `cli.js` process, so
main-process proxy patching and Electron session proxy configuration do
not automatically apply to it. This change builds a separate proxy
bootstrap, injects it only when proxy settings are configured, and keeps
the child-process proxy behavior aligned with the app's proxy settings
without changing the Claude SDK package itself.
The following tradeoffs were made:
- Added a separate build artifact for the Claude Code child-process
proxy bootstrap.
- Added child-process-specific proxy diagnostics to improve debugging
when proxy routing fails.
- Split SOCKS proxy environment handling from HTTP proxy handling to
avoid incompatible env combinations.
The following alternatives were considered:
- Relying only on inherited shell proxy environment variables.
- Relying on Electron session proxy configuration from the main process.
- Patching the Claude SDK package directly instead of injecting a local
bootstrap.
Links to places where the discussion took place: None
### Breaking changes
None.
If this PR introduces breaking changes, please describe the changes and
the impact on users.
No breaking changes.
### Special notes for your reviewer
- `out/proxy/index.js` is built as a standalone child-process bootstrap
and unpacked for packaged app usage.
- SOCKS proxy mode now exports `ALL_PROXY` / `SOCKS_PROXY` for the
Claude child process instead of forcing `HTTP_PROXY` / `HTTPS_PROXY` to
a SOCKS URL.
- Added tests covering HTTP vs SOCKS child-process proxy environment
generation.
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
<!-- Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->
```release-note
Fixed Claude Code agent sessions so spawned child processes respect configured HTTP and SOCKS proxy settings.
```
---------
Signed-off-by: beyondkmp <beyondkmp@gmail.com>
Signed-off-by: Payne Fu <payne@Paynes-MacBook-Air.local>
Co-authored-by: Payne Fu <payne@Paynes-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: 亢奋猫 <kangfenmao@qq.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
### What this PR does
fix#13833
Before this PR:
Spawned Claude Code child processes did not reliably use the app's
configured proxy settings. HTTP proxy mode could work, but SOCKS proxy
mode could hang before the SDK returned any initial stream events.
After this PR:
Spawned Claude Code child processes inherit a dedicated Node-only proxy
bootstrap that applies the app's configured proxy settings for
fetch/undici, http/https, and axios. SOCKS proxy mode now avoids
exporting incompatible HTTP proxy env vars and emits clearer diagnostics
when proxy injection is active.
Fixes # None
### Why we need it and why it was done in this way
Claude Code runs as a standalone spawned `cli.js` process, so
main-process proxy patching and Electron session proxy configuration do
not automatically apply to it. This change builds a separate proxy
bootstrap, injects it only when proxy settings are configured, and keeps
the child-process proxy behavior aligned with the app's proxy settings
without changing the Claude SDK package itself.
The following tradeoffs were made:
- Added a separate build artifact for the Claude Code child-process
proxy bootstrap.
- Added child-process-specific proxy diagnostics to improve debugging
when proxy routing fails.
- Split SOCKS proxy environment handling from HTTP proxy handling to
avoid incompatible env combinations.
The following alternatives were considered:
- Relying only on inherited shell proxy environment variables.
- Relying on Electron session proxy configuration from the main process.
- Patching the Claude SDK package directly instead of injecting a local
bootstrap.
Links to places where the discussion took place: None
### Breaking changes
None.
If this PR introduces breaking changes, please describe the changes and
the impact on users.
No breaking changes.
### Special notes for your reviewer
- `out/proxy/index.js` is built as a standalone child-process bootstrap
and unpacked for packaged app usage.
- SOCKS proxy mode now exports `ALL_PROXY` / `SOCKS_PROXY` for the
Claude child process instead of forcing `HTTP_PROXY` / `HTTPS_PROXY` to
a SOCKS URL.
- Added tests covering HTTP vs SOCKS child-process proxy environment
generation.
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
<!-- Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->
```release-note
Fixed Claude Code agent sessions so spawned child processes respect configured HTTP and SOCKS proxy settings.
```
---------
Signed-off-by: beyondkmp <beyondkmp@gmail.com>
Signed-off-by: Payne Fu <payne@Paynes-MacBook-Air.local>
Co-authored-by: Payne Fu <payne@Paynes-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: 亢奋猫 <kangfenmao@qq.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
### What this PR does
Before this PR:
Agent Bash tool calls output raw, verbose shell command results that
consume excessive LLM tokens.
After this PR:
Bash commands are transparently rewritten via
[rtk](https://github.com/rtk-ai/rtk) to produce concise, LLM-friendly
output — reducing token consumption by 60-90% on common shell commands
(`cat`, `grep`, `find`, `ls`, etc.).
<img width="647" height="578" alt="image"
src="https://github.com/user-attachments/assets/438de126-c79d-4b69-bf3b-65a220671900"
/>
Fixes#13600
### Why we need it and why it was done in this way
rtk is a single Rust binary (MIT licensed, zero dependencies) that
rewrites shell commands into optimized versions. When a command has no
rtk equivalent, it passes through unchanged — zero risk of breaking
existing workflows.
The integration follows three layers:
1. **Build time**: `scripts/download-rtk-binaries.js` downloads
platform-specific rtk and jq binaries into `resources/binaries/`
(bundled via existing `asarUnpack: resources/**`)
2. **First run**: `extractRtkBinaries()` copies binaries from app
resources to `~/.cherrystudio/bin/` (follows existing binary
distribution pattern used by bun, uv, openclaw)
3. **Runtime**: A `PreToolUse` hook in the Claude Code service
intercepts Bash tool calls, runs `rtk rewrite "<command>"`, and
substitutes the optimized command if available
The following tradeoffs were made:
- Binaries are bundled in the app package (increases app size ~5MB)
rather than downloaded on demand — ensures rtk is always available
without network dependency
- jq is bundled alongside rtk for potential external hook script usage,
even though the TypeScript hook doesn't need it
- `rtkRewrite()` is async (non-blocking) to avoid stalling the main
process event loop
The following alternatives were considered:
- On-demand download (like bun/uv install scripts) — rejected because
rtk should "always be on" per requirements
- System PATH detection only — rejected because it requires users to
install rtk manually
### Breaking changes
None. The rtk rewrite is transparent and falls back gracefully when rtk
is unavailable or a command has no optimized version.
### Special notes for your reviewer
- The download script is non-fatal: if binary download fails during
build, the build continues without rtk
- The hook runs before the existing `preToolUseHook` (permission
handling), so commands are rewritten before permission checks
- Version guard requires rtk >= 0.23.0 (when `rtk rewrite` subcommand
was introduced)
### 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: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A user-guide update was considered and is present
(link) or not required
- [x] Self-review: I have reviewed my own code before requesting review
from others
### Release note
```release-note
Integrate rtk to automatically optimize agent shell commands for 60-90% token savings
```
---------
Signed-off-by: Vaayne <liu.vaayne@gmail.com>
### What this PR does
Before this PR:
The Claude Agent SDK's minified `sdk.mjs` was patched at `postinstall`
time via regex-based replacements (`scripts/patch-claude-agent-sdk.ts`)
to convert `spawn` to `fork` with IPC stdio. This broke on every SDK
version bump when variable names changed.
After this PR:
Uses the SDK's built-in `spawnClaudeCodeProcess` option (available since
v0.2.81) to provide a custom `fork()`-based process spawner, eliminating
the need for any postinstall patching.
### Why we need it and why it was done in this way
The following tradeoffs were made:
- We handle stderr ourselves in the custom spawner because the SDK only
reads stderr inside its internal `spawnLocalProcess()`, not when
`spawnClaudeCodeProcess` is provided.
The following alternatives were considered:
- Keeping the postinstall patch: rejected because it's fragile and
breaks on SDK updates.
- Using `spawn` with explicit `node` path: rejected because `fork()`
automatically uses `process.execPath` which works reliably in both dev
and packaged Electron (where `node` may not be on PATH).
### Breaking changes
None.
### Special notes for your reviewer
- `fork()` with `ELECTRON_RUN_AS_NODE=1` makes the Electron binary act
as Node.js, which is the same behavior the postinstall patch achieved.
- The IPC channel (`'ipc'` in stdio) is added for safety/compatibility
but isn't actively used by the SDK protocol (confirmed by searching the
minified source for `.send()` and `on('message')` on the process object
— zero hits).
- Net deletion of ~600 lines.
### 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: You have left the code cleaner than you found it (Boy
Scout Rule)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: Not required — internal refactoring with no
user-facing change
- [x] Self-review: I have reviewed my own code before requesting review
from others
### Release note
```release-note
NONE
```
Signed-off-by: beyondkmp <beyondkmp@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### What this PR does
Before this PR:
The app crashes on startup with `ReferenceError: DOMMatrix is not
defined` because `@napi-rs/canvas` platform-specific binaries were
missing from `optionalDependencies`.
<img width="620" height="587" alt="image"
src="https://github.com/user-attachments/assets/20269613-cb89-460b-8854-2140ecac289c"
/>
After this PR:
Platform-specific binaries for `@napi-rs/canvas` are properly declared
in `optionalDependencies` and handled in `before-pack.js`, fixing the
startup crash.
### Why we need it and why it was done in this way
The following tradeoffs were made:
- Only mainstream platforms are included (Linux x64/arm64 glibc/musl,
macOS x64/arm64, Windows x64/arm64)
- Excluded rarely-used platforms: linux-arm-gnueabihf (32-bit ARM),
linux-riscv64-gnu (RISC-V), android-arm64 (Android)
The following alternatives were considered:
None - this follows the existing pattern used for `@img/sharp`,
`@libsql`, and `@napi-rs/system-ocr` packages.
### Breaking changes
None.
### Special notes for your reviewer
This change follows the existing pattern in `before-pack.js` for
handling platform-specific native dependencies.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
fix: resolve app startup crash caused by missing @napi-rs/canvas platform binaries (DOMMatrix is not defined)
```
Signed-off-by: kangfenmao <kangfenmao@qq.com>
### What this PR does
Before this PR:
`.claude/skills/<name>/SKILL.md` files were **copied** from
`.agents/skills/<name>/SKILL.md` via `pnpm skills:sync`. A dedicated
`skills-check-windows` CI job ran on `windows-latest` to verify
cross-platform file-copy compatibility.
After this PR:
`.claude/skills/<name>` entries are **directory symlinks** pointing to
`../../.agents/skills/<name>`, following the Single Source of Truth
(SSoT) principle. The Windows-specific CI job is removed; Windows
developers are expected to enable symlink support.
### Why we need it and why it was done in this way
The following tradeoffs were made:
- Windows developers must now manually enable symlink support (Developer
Mode + `git config --global core.symlinks true`). This is acceptable
because:
1. The existing `AGENTS.md` is already a symlink, so Windows
compatibility was never fully enforced.
2. Symlinks eliminate the need for file-copy synchronization, reducing
maintenance complexity.
3. Contributors are expected to have sufficient technical capability to
configure their environments.
The following alternatives were considered:
- Keeping file-copy sync: rejected because it duplicates content and
requires extra CI to verify consistency.
### Breaking changes
Windows developers who clone without symlink support enabled will get
plain text files instead of symlinks. They must:
1. Enable Developer Mode or grant `SeCreateSymbolicLinkPrivilege`
2. Run `git config --global core.symlinks true`
3. Re-clone or run `pnpm skills:sync`
### Special notes for your reviewer
- The `.github/workflows/ci.yml` diff includes minor quote-style changes
(`'` → `"`) from the YAML formatter — these are cosmetic only.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [x] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [ ] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
NONE
```
Signed-off-by: icarus <eurfelux@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
### What this PR does
Before this PR:
Attempted to add Feishu @mention notifications in issue cards using `<at
id=...></at>` tags with various ID formats (app ID, open_id).
After this PR:
Reverted all mention-related changes. The Feishu card content is
restored to its original state without @mention tags.
### Why we need it and why it was done in this way
Testing confirmed that while the `<at>` tag with open_id displays
correctly in the card, Feishu does not provide a message receive API for
bots — so bot users cannot actually receive @mention notifications. The
feature is not feasible with the current Feishu API capabilities.
### Breaking changes
None
### Special notes for your reviewer
This PR reverts the mention feature added in #13199 and all subsequent
test commits. Net diff against `main` should only contain the revert of
#13199.
### 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: You have left the code cleaner than you found it (Boy
Scout Rule)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: N/A - no user-facing change
- [x] Self-review: I have reviewed my own code before requesting review
from others
### Release note
```release-note
NONE
```
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### What this PR does
Before this PR:
Feishu issue notification cards did not @mention any specific user, so
notifications could be easily missed.
After this PR:
The issue notification card now includes an `<at>` element that
@mentions the Feishu user `cli_a92d6e7ba3f85ced` in the card body,
ensuring they receive a direct notification for every new GitHub issue.
### Why we need it and why it was done in this way
The Feishu user needs to be actively notified when new GitHub issues are
created. By embedding the `<at id=cli_a92d6e7ba3f85ced></at>` tag
directly in the card's lark_md content, the user gets a native Feishu
@mention notification without requiring changes to the workflow or CLI
interface.
The following tradeoffs were made:
- The Feishu user ID is hardcoded in the card template rather than
passed as a CLI option. This is simpler and sufficient for the current
use case.
The following alternatives were considered:
- Adding a `--mention` CLI option: More flexible but unnecessary
complexity for a single user.
- Adding the @mention via the workflow prompt: Less reliable since it
depends on Claude's output.
### Breaking changes
None.
### Special notes for your reviewer
The TypeScript diagnostics shown for `feishu-notify.ts` (missing
`process`, `Buffer`, etc.) are pre-existing and unrelated to this change
— the script runs via `npx tsx` and is outside the project's tsconfig
scope.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
NONE
```
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### What this PR does
Before this PR: Windows code signing uses `timestamp.comodoca.com` as
the timestamp server, which is unreliable and frequently times out.
After this PR: Switches to `timestamp.digicert.com`, a more stable and
widely-used timestamp server.
### Why we need it and why it was done in this way
The Comodo timestamp server (`timestamp.comodoca.com`) has been
experiencing frequent connectivity issues, causing code signing failures
during Windows builds. DigiCert's timestamp server is industry-standard
and known for better reliability.
The following tradeoffs were made: N/A
The following alternatives were considered: N/A
### Breaking changes
None
### Special notes for your reviewer
Single-line URL change in the signing script.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
NONE
```
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### What this PR does
Before this PR:
`claude-agent-sdk` is patched via a static pnpm `.patch` file that
replaces entire minified lines. This breaks every time the SDK is
upgraded because obfuscated variable names change with each
minification.
After this PR:
A Node.js postinstall script (`scripts/patch-claude-agent-sdk.mjs`) uses
semantic regex patterns to apply the same 3 patches. Since it matches
structural patterns (not variable names), it survives SDK version bumps
as long as the code structure remains the same.
### Why we need it and why it was done in this way
The following tradeoffs were made:
- Regex-based patching is slightly less precise than a static `.patch`
file, but far more resilient to minified code changes.
- The script validates all 3 patches applied and exits with error if
patterns don't match, so SDK structure changes are caught immediately.
The following alternatives were considered:
- Keeping the pnpm patch approach — rejected because it requires manual
regeneration on every SDK upgrade.
- Using AST-based patching — rejected as overkill for 3 targeted
replacements in minified code.
### Breaking changes
None. The same 3 modifications are applied (spawn→fork, remove command
destructuring, IPC stdio), just via a different mechanism.
### Special notes for your reviewer
The 3 patches applied by the script:
1. `import{spawn as X}` → `import{fork as X}` — enables IPC channel
2. Remove `command:VAR,` from `spawnLocalProcess` destructuring
3. Rewrite spawn call to `fork(args[0], args.slice(1), ...)` with IPC
stdio, removing `windowsHide:!0`
43 unit tests cover: variable name variations, idempotency, partial
matches, and no-match detection.
### 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: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: Not required — internal build tooling change
- [x] Self-review: I have reviewed my own code before requesting review
from others
### Release note
```release-note
NONE
```
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### What this PR does
Before this PR:
- CLAUDE.md contained detailed PR workflow instructions that were loaded
in every agent session, consuming unnecessary tokens
- No unified project-level skills management mechanism; adding public
skills lacked standardization
- No automated checks to prevent non-compliant skills from being merged
- Team members had no convenient way to share skills with each other
After this PR:
- Simplified PR instructions in CLAUDE.md, now loaded on-demand via the
`gh-create-pr` skill
- Introduced project-level skills management (`.agents/skills/`
directory + `public-skills.txt` whitelist)
- Added `scripts/skills-sync.ts` and `scripts/skills-check.ts` for
automated management
- Integrated skills validation into CI to prevent non-whitelisted skills
from being merged
- **Teams can now easily share skills through the project-level
mechanism**, with `skills-sync.ts` automatically syncing skills to all
team members' local environments, streamlining onboarding and avoiding
duplicated configuration efforts
- **Optimized PR creation workflow**: `gh-create-pr` skill enforces
English PR body writing and displays the draft to users for review
before creation, ensuring quality and compliance
Fixes #
### Why we need it and why it was done in this way
The following tradeoffs were made:
- Moved PR workflow from CLAUDE.md to a skill, sacrificing immediate
visibility for token efficiency
- **Introduced whitelist mechanism (`public-skills.txt`) instead of
auto-scanning all files**: Allows developers to freely use private
project-level skills in the `.agents/skills/` directory (e.g.,
team-internal skills, personal customizations). Only skills added to the
whitelist are tracked by git and submitted. This ensures standardization
for shared skills while preserving development flexibility
- Skills exist in both `.agents/skills/` (project-level, shareable) and
`.claude/skills/` (local, private)
- **Symlink only SKILL.md files instead of entire directories**: On some
Windows/restricted filesystems, symlinks may fail or be treated as
regular files. If an entire directory is symlinked, failure results in a
regular file instead of a directory, causing complete skill failure
that's hard to diagnose. Symlinking only SKILL.md allows quick detection
when symlinks fail (file content displays directly or errors), reducing
troubleshooting costs
The following alternatives were considered:
- Keeping PR instructions in CLAUDE.md with collapsible blocks, but this
still consumes context tokens
- Using git hooks for pre-commit checks, but CI checks are more reliable
and don't block local development
Links to places where the discussion took place: N/A
### Breaking changes
None
### Special notes for your reviewer
- `gh-create-pr` skill fully implements the project's PR workflow
requirements (read template → display body → confirm → create)
- `skills-check.ts` validates: 1) tracked skills are in the whitelist;
2) whitelist skills have corresponding files
- Process for adding new public skills: 1) create skill files; 2) add to
`public-skills.txt`; 3) CI auto-validation
- `.claude/skills/` added to `.gitignore` for private skills
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
is present (link) or not required. You want a user-guide update if it's
a user facing feature.
- [ ] Documentation: A user-guide update was considered and is present
(link) or not required. You want a user-guide update if it's a user
facing feature.
### Release note
```release-note
Optimize PR workflow by moving instructions to on-demand skill; introduce project-level skills management with automated validation
```
### What this PR does
Before this PR:
- On **Windows**, `getLoginShellEnvironment()` runs `cmd.exe /c set`
which just inherits the parent (Electron) process's env — it does NOT
re-read the Windows registry. If Node.js is installed via MSI after the
app launches, the captured PATH is stale. This causes npm preinstall
scripts to fail: npm itself runs (found via `commonPaths` filesystem
fallback), but `cmd.exe /d /s /c node ./engine-requirements.js` can't
find `node` in the stale PATH. On Unix this isn't an issue because `zsh
-ilc env` sources profile files and picks up nvm/mise/fnm PATH changes.
- On **Unix**, OpenClaw fails to start/install when Node.js is installed
via nvm, mise, or fnm after Cherry Studio has launched, because the
cached shell environment is stale.
- `findExecutableInEnv` has a hidden side effect of refreshing the shell
env cache, making it unpredictable.
- `startGateway` uses stale env because `findOpenClawBinary` refreshes
the cache but the gateway spawn uses a different (stale) env.
- Install process mutates the shared cached env object, polluting all
future callers.
- Inconsistent spawn strategy: install/uninstall use `spawn()` + `shell:
true` while gateway operations use `spawnWithEnv()`.
After this PR:
- **Windows**: skip the useless `cmd.exe /c set` entirely. Instead, copy
`process.env` as the base (same result, but faster), then read the
**current** system + user PATH from the Windows registry via `reg
query`, expand `%VAR%` references, and replace the stale PATH. This
ensures newly installed tools (e.g. Node.js MSI) are found immediately.
- **Unix**: unchanged — `zsh -ilc env` still sources profile files
correctly.
- Shell env cache follows CQS (Command-Query Separation):
`getShellEnv()` is a pure query, `refreshShellEnv()` is an explicit
command.
- `findExecutableInEnv` no longer refreshes the cache — callers
explicitly call `refreshShellEnv()` when they need fresh env.
- `startGateway` refreshes env first, then passes it to both
`findOpenClawBinary` and `crossPlatformSpawn`.
- Install process clones the cached env before modifying PATH (`{
...await getShellEnv() }`).
- All spawn calls unified to `crossPlatformSpawn` (handles Windows
`.cmd` files via `cmd.exe /c`).
- OpenClaw UI now checks Node.js version (≥18) and git availability
before install, with download URL hints and automatic polling for newly
installed tools.
- Unit tests added for the new Windows registry PATH resolution logic
(10 test cases).
<img width="1019" height="765" alt="image"
src="https://github.com/user-attachments/assets/5f6a4d27-6d3e-4033-8309-0c98bf8cba4c"
/>
### Why we need it and why it was done in this way
**Why registry reads instead of `cmd.exe /c set`?**
On Windows, `cmd.exe /c set` inherits the parent process env unchanged.
Unlike Unix shells that source `~/.bashrc`/`.zshrc` on launch, `cmd.exe`
does not re-read the registry. When a user installs Node.js (via MSI,
Scoop, etc.) after Cherry Studio is already running, the new PATH
entries only exist in the registry — not in the Electron process's
inherited env. Reading `HKLM\...\Environment` (system PATH) and
`HKCU\Environment` (user PATH) directly gives us the ground-truth PATH
at the time of the call.
**Why `execFileSync` instead of `crossPlatformSpawn`/`executeCommand`?**
1. **Circular dependency**: `executeCommand` internally calls
`getShellEnv()` to obtain env. Since `queryRegValue` is called *by*
`getShellEnv` → `getLoginShellEnvironment` → `getWindowsEnvironment`,
using `executeCommand` would create an infinite recursion.
2. **Synchronous is appropriate**: `reg query` completes in
milliseconds. Keeping it synchronous allows `getWindowsEnvironment()` to
return directly via `Promise.resolve()`, simplifying the control flow.
3. **No `.cmd` shim handling needed**: `reg.exe` is a native executable
— it doesn't need the `cmd.exe /c` wrapping that `crossPlatformSpawn`
provides.
4. **Security**: `execFileSync` executes the binary directly without
shell interpolation, avoiding command injection risk.
**Why expand `%VAR%` manually?**
Windows registry stores PATH as `REG_EXPAND_SZ` with embedded references
like `%SystemRoot%\system32`. The `reg query` output returns the raw
string without expansion. We expand these references against the current
`process.env` using case-insensitive lookup to match Windows behavior.
The following tradeoffs were made:
- CQS over convenience: callers must now explicitly call
`refreshShellEnv()` before `findExecutableInEnv()` when they need fresh
env. This adds a line of code at call sites but makes the caching
behavior predictable and eliminates hidden side effects.
- Clone-on-modify over freeze: we spread-clone the env object in
`install()` rather than `Object.freeze()` the cache, because freeze
would break callers that legitimately need to add env vars (e.g.,
`OPENCLAW_CONFIG_PATH`).
The following alternatives were considered:
- Making `getShellEnv()` always return a frozen copy — rejected because
it would require all callers to spread, even those that only read.
- Extracting a shared function for install/uninstall — rejected (Rule of
Three: only 2 instances, with semantic differences in error handling and
sudo retry).
- Using PowerShell `[Environment]::GetEnvironmentVariable` instead of
`reg query` — rejected because it has a much higher startup cost (~200ms
vs ~5ms) and requires detecting PowerShell availability.
Links to places where the discussion took place: N/A
### Breaking changes
None. All changes are internal to the main process. No Redux/IndexedDB
schema changes.
### Special notes for your reviewer
- **New file**: `src/main/utils/__tests__/shell-env.test.ts` — 10 test
cases covering registry PATH resolution (stale replacement, system+user
combination, `%VAR%` expansion, REG_SZ vs REG_EXPAND_SZ, fallback
behavior, cherry bin append, no cmd.exe spawn).
- **New helpers in `shell-env.ts`**: `queryRegValue()`,
`expandWindowsEnvVars()`, `readWindowsRegistryPath()`,
`getWindowsEnvironment()` — all private, tested through the public
`refreshShellEnv()` API.
- Function renames: `spawnWithEnv` → `crossPlatformSpawn`,
`executeInEnv` → `executeCommand` — names now reflect actual
responsibility (Windows `.cmd` adaptation, not "env injection").
- `checkNodeVersion` returns a discriminated union `{ status:
'not_found' } | { status: 'version_low'; version; path } | { status:
'ok'; version; path }` instead of the previous `checkNpmAvailable`
boolean.
- i18n keys renamed from `openclaw.node_required.*` →
`openclaw.node_missing.*` / `openclaw.node_version_low.*` with
translations for all supported locales.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780096809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. You want a
user-guide update if it's a user facing feature.
### Release note
```release-note
fix(shell-env): on Windows, read PATH from registry instead of inheriting stale Electron process env; fix Node.js detection for nvm/mise/fnm-managed installations; add version check (≥18) and git availability check with download hints in OpenClaw setup UI
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dev <dev@cherry-ai.com>
Co-authored-by: kangfenmao <kangfenmao@qq.com>
* feat: add plugin install
* fix: some bug
* fix: i18n
* refactor: rename 'active-directory' to 'resource'
* feat(plugin): support remote fetch plugin
* refactor: improve error display
* feat: add cache protocol
* fix(plugin): address code review issues for PR #12426
- Fix command injection vulnerability by adding -- separator before
positional arguments in git clone and ls-remote commands
- Extract duplicate file helpers (directoryExists, fileExists, pathExists)
to shared @main/utils/file utility
- Add depth limit (MAX_PLUGIN_ROOT_DEPTH=10) to findPluginRoots to
prevent infinite recursion from symlink cycles
- Rename InstallFromZipResult to InstallFromSourceResult with type alias
for backward compatibility
- Extract duplicate loadFirstPage logic in useMarketplaceBrowser hook
- Add documentation for intentionally disabled readContent and
invalidateCache methods explaining API compatibility reasons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(plugin): add documentation for marketplace API and telemetry
- Document MARKETPLACE_API_BASE_URL with API endpoints and usage
- Add TODO for China mainland accessibility testing
- Document reportSkillInstall telemetry behavior and data transmitted
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(plugin): fix skill installation and improve UI
- Fix skill installation using v2 resolve API endpoint
- Extract base repo URL from GitHub tree/blob URLs
- Fix skill card type label (skill -> skills key mapping)
- Split plugin settings into "Available Plugins" and "Installed Plugins" tabs
- Fix refresh button styling with aspect-square
- Add card vertical spacing with pb-4
- Add unit tests for extractBaseRepoUrl and extractResolvedSkill
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(plugin): use useTimer for search debounce
Replace manual setTimeout/clearTimeout with useTimer hook for better
timer management and automatic cleanup on component unmount.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style(plugin): use explicit unknown type in catch blocks
Change all catch blocks from `catch (error)` to `catch (error: unknown)`
for better type safety and code clarity.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(plugin): only show content section for installed plugins
- Skip content fetching for marketplace plugins since readContent
always fails for remote plugins
- Only display the Content section when viewing installed plugins
- Change catch (error) to catch (error: unknown) for type safety
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(plugin): use Zod schemas for marketplace API responses
- Add PluginResolveResponseSchema for plugin resolution API
- Add ResolvedSkillSchema and SkillsResolveResponseSchema for v2 skills API
- Refactor extractRepositoryUrl to use Zod safeParse instead of manual type checking
- Refactor resolveSkillV2 to validate response with Zod and return typed array
- Update extractResolvedSkill to accept typed array directly
- Update tests to match new function signatures
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(plugin): simplify code and reduce duplication
- Merge runCommand and captureCommand into executeCommand in PluginService
- Combine URL regex patterns and use constant map for plugin directories
- Create generic response parser factory in MarketplaceService
- Extract buildSkillSourceKey helper in useMarketplaceBrowser
- Remove unused displayedEntries variable in PluginBrowser
- Consolidate category config into single object in useResourcePanel
- Extract ensureCacheData helper method in PluginCacheStore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(plugin): remove dead readContent and invalidateCache methods
Remove methods that were non-functional (always throwing or no-op):
- Remove invalidateCache() no-op method from PluginService
- Remove readContent() method that always throws
- Remove corresponding IPC handlers and preload bindings
- Remove IpcChannel enum entries for both methods
- Remove content section from PluginDetailModal (relied on readContent)
- Remove agentId prop from PluginBrowser (no longer needed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(plugin): update plugin settings and UI components
- Change default page size in useMarketplaceBrowser from 100 to 40 for improved performance.
- Add titles to the installed plugins section in multiple language files for better clarity.
- Refactor AgentSettings components to improve structure and readability, including the introduction of a new PluginsSettings component.
- Update modal widths in AgentSettingsPopup and SessionSettingsPopup for better UI consistency.
- Integrate Scrollbar component in SettingsContainer for enhanced scrolling experience.
* refactor(settings): improve Scrollbar import and enhance type safety
- Change Scrollbar import to use type-only import for ScrollbarProps.
- Update handleVirtualChange function to handle null scrollOffset for better type safety.
* fix(plugin): install only selected plugin and fix uninstall lookup
Bug fixes:
- Install only the specific requested plugin from marketplace repo
instead of installing all plugins found in the repository
- Use actual installed filename for uninstall instead of marketplace
metadata filename (which differs due to sanitization)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(plugin): support skill upload via drag-and-drop
Extended installFromSourceDir to detect and install skills:
- Check for plugin roots first (with .claude-plugin/plugin.json)
- If none found, search for skill directories (with SKILL.md)
- Install whichever type is detected
Added new methods:
- installSkillRoots: Install multiple skill directories
- installSkillFromDirectory: Install a single skill folder
Now users can drag-and-drop skill folders or ZIPs containing
skills to install them, not just plugin packages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(browser): add beforeEach to reset mock state
Add vi.clearAllMocks() in beforeEach to prevent state leakage
between tests, which could cause flaky test failures in CI.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: kangfenmao <kangfenmao@qq.com>
* fix(build): add Linux musl native dependencies for Alpine support
Add missing native dependencies for Linux musl (Alpine Linux) platform:
- @img/sharp-linuxmusl-arm64 and @img/sharp-linuxmusl-x64
- @img/sharp-libvips-linuxmusl-arm64 and @img/sharp-libvips-linuxmusl-x64
- @libsql/linux-arm64-musl and @libsql/linux-x64-musl
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(build): add support for Linux musl architecture in before-pack script
Updated the before-pack.js script to include 'linuxmusl' in the platformToArch mapping, enhancing compatibility for Alpine Linux builds.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: use pnpm install instead of manual download for prebuild packages
Replace manual tgz download with pnpm install for architecture-specific
prebuild binaries, simplifying the build process.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* delete utils
* update after pack
* udpate before pack
* use optional deps
* refactor: use js-yaml to modify pnpm-workspace.yaml for cross-platform builds
- Add all prebuild packages to optionalDependencies in package.json
- Use js-yaml to parse and modify pnpm-workspace.yaml
- Add target platform to supportedArchitectures.os and cpu
- Restore original config after pnpm install
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix version
* refactor: streamline package management and filtering logic in before… (#12370)
refactor: streamline package management and filtering logic in before-pack.js
- Consolidated architecture-specific package definitions into a single array for better maintainability.
- Simplified the logic for determining target platform and architecture.
- Enhanced the filtering process for excluding and including packages based on architecture and platform.
- Improved console logging for clarity during package installation.
This refactor aims to improve the readability and efficiency of the prebuild package handling process.
* refactor: update package filtering logic in before-pack.js to read from electron-builder.yml
- Modified the package filtering process to load configuration directly from electron-builder.yml, reducing potential errors from multiple overrides.
- Enhanced maintainability by centralizing the file configuration management.
This change aims to streamline the prebuild package handling and improve configuration clarity.
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: 亢奋猫 <kangfenmao@qq.com>
* build: add commander package as dependency
* refactor(scripts): migrate feishu-notify to TypeScript with CLI interface
- Convert JavaScript implementation to TypeScript with proper type definitions
- Add CLI interface using commander for better usability
- Improve error handling and input validation
- Add version management and subcommand support
* ci(workflows): update feishu notification command and add pnpm install step
Update the feishu notification command to use CLI tool with proper arguments instead of direct node script execution
Add pnpm install step to ensure dependencies are available before running the workflow
* docs: add feishu notification script documentation
Add Chinese and English documentation for the feishu-notify.ts CLI tool
* feat(notify): add generic send command to feishu-notify
Add a new 'send' subcommand to send simple notifications to Feishu with customizable title, description and header color. This provides a more flexible way to send notifications without being tied to specific business logic like the existing 'issue' command.
The implementation includes:
- New send command handler and options interface
- Simple card creation function
- Zod schema for header color validation
- Documentation updates in both Chinese and English
- Enhanced the logic to determine included Claude code vendors based on architecture and platform.
- Adjusted filters for excluding and including Claude code vendors to improve compatibility, particularly for Windows ARM64.
- Removed unnecessary variables and streamlined the filter application process.
* refactor: switch workflows from yarn to pnpm
Replace Yarn usage with pnpm in CI workflows to standardize package
management and leverage pnpm's store/cache behavior.
- Use pnpm/action-setup to install pnpm (v) instead of enabling corepack
and preparing Yarn.
- Retrieve pnpm store path and update cache actions to cache the pnpm
store and use pnpm-lock.yaml for cache keys and restores.
- Replace yarn commands with pnpm equivalents across workflows:
install, i18n:sync/translate, format, build:* and tsx invocation.
- Avoid committing lockfile changes by resetting pnpm-lock.yaml instead
of yarn.lock when checking for changes.
- Update install flags: use pnpm install --frozen-lockfile / --install
semantics where appropriate.
These changes unify dependency tooling, improve caching correctness,
and ensure CI uses pnpm-specific lockfile and cache paths.
* build: switch pre-commit hook to pnpm lint-staged
Update .husky/pre-commit to run pnpm lint-staged instead of yarn.
This aligns the pre-commit hook with the project's package manager
and ensures lint-staged runs using pnpm's environment and caching.
* chore(ci): remove pinned pnpm version from GH Action steps
Remove the explicit `with: version: 9` lines from multiple GitHub Actions workflows
(auto-i18n.yml, nightly-build.yml, pr-ci.yml, update-app-upgrade-config.yml,
sync-to-gitcode.yml, release.yml). The workflows still call `pnpm/action-setup@v4`
but no longer hardcode a pnpm version.
This simplifies maintenance and allows the action to resolve an appropriate pnpm
version (or use its default) without needing updates whenever the pinned
version becomes outdated. It reduces churn when bumping pnpm across CI configs
and prevents accidental pin drift between workflow files.
* build: Update pnpm to 10.27.0 and add onlyBuiltDependencies config
* Update @cherrystudio/openai to 6.15.0 and consolidate overrides
* Add @langchain/core to overrides
* Add override for openai-compatible 1.0.27
* build: optimize pnpm config and add missing dependencies
- Comment out shamefully-hoist in .npmrc for better pnpm compatibility
- Add React-related packages to optimizeDeps in electron.vite.config.ts
- Add missing peer dependencies and packages that were previously hoisted
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* build: refine pnpm configuration and dependency management
- Simplify .npmrc to only essential electron mirror config
- Move platform-specific dependencies to devDependencies
- Pin sharp version to 0.34.3 for consistency
- Update sharp-libvips versions to 1.2.4
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* reduce app size
* format
* build: remove unnecessary disableOxcRecommendation option from react plugin configuration
* docs: Replace yarn commands with pnpm in documentation and scripts
* Revert "build: optimize pnpm config and add missing dependencies"
This reverts commit acffad31f8.
* build: import dependencies from yarn.lock
* build: Add some phantom dependencies and reorganize dependencies
* build: Keep consistent by removing types of semver
It's not in the previous package.json
* build: Add some phantom dependencies
Keep same version with yarn.lock
* build: Add form-data dependency version 4.0.4
* Add chalk dependency
* build: downgrade some dependencies
Reference: .yarn-state-copy.yml. These phantom dependencies should use top-level package of that version in node_modules
* build: Add phantom dependencies
* build: pin tiptap dependencies to exact versions
Ensure consistent dependency resolution by removing caret ranges and pinning all @tiptap packages to exact version 3.2.0
* chore: pin embedjs dependencies to exact versions
* build: pin @modelcontextprotocol/sdk to exact version 1.23.0
Remove caret from version specifier to prevent automatic upgrades and ensure consistent dependencies
* chore: update @types/node dependency to 22.17.2
Update package.json and pnpm-lock.yaml to use @types/node version 22.17.2 instead of 22.19.3 to maintain consistency across dependencies
* build: move some dependencies to dev deps and pin dependency versions to exact numbers
Remove caret (^) from version ranges to ensure consistent dependency resolution across environments
* chore: move dependencies from prod to dev and update lockfile
Move @ant-design/icons, chalk, form-data, and open from dependencies to devDependencies
Update pnpm-lock.yaml to reflect dependency changes
* build: update package dependencies
- Add new dependencies: md5, @libsql/win32-x64-msvc, @strongtz/win32-arm64-msvc, bonjour-service, emoji-picker-element-data, gray-matter, js-yaml
- Remove redundant dependencies from devDependencies
* build: add cors, katex and pako dependencies
add new dependencies to support cross-origin requests, mathematical notation rendering and data compression
* move some js deps to dev deps
* test: update snapshot tests for Spinner and InputEmbeddingDimension
* chore: exclude .zed directory from biome formatting
* Update @ai-sdk/openai-compatible patch hash
* chore: update @kangfenmao/keyv-storage to version 0.1.3 in package.json and pnpm-lock.yaml
---------
Co-authored-by: icarus <eurfelux@gmail.com>
Co-authored-by: beyondkmp <beyondkmp@gmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: kangfenmao <kangfenmao@qq.com>
* feat(i18n): add Romanian localization (ro-RO)
Added the ro-ro.json file to provide Romanian language support for the Cherry Studio interface.
This commit introduces a high-quality, professional translation for the Romanian language. The localization has been carefully reviewed to ensure linguistic accuracy and terminology consistency, so no further adjustments from other contributors are required at this stage. Thank you!
* chore: move ro-ro.json to translate folder and register in index.ts
Moved the Romanian translation file to the translate directory and updated the i18n index to support the automated workflow as requested.
* Delete src/renderer/src/i18n/locales/ro-ro.json
* chore: add ro-ro.json to translate folder
Finalized the relocation of the Romanian translation file to the translate directory to support the automated i18n workflow.
* chore(i18n): remove trailing comma in index.ts
Biome formatter removed trailing comma for consistency.
* feat(i18n): add Romanian (ro-RO) to language selector
Add Romanian language option in settings with Română label and 🇷🇴 flag.
* fix(i18n): add Romanian language support
- Add ro-RO to LanguageVarious type
- Add Romanian to language selector in settings
- Add emoji picker fallback to English (no Romanian CLDR data)
* feat: Add Romanian to auto-translation language map
* fix: Add Romanian language support in main
* fix: Add Romanian (ro-RO) locale support for AntdProvider
* fix: Add Romanian language support to smooth stream segmenter
* fix: Add Romanian translations for assistant preset groups
---------
Co-authored-by: George·Dong <GeorgeDong32@qq.com>
Co-authored-by: icarus <eurfelux@gmail.com>
* refactor: rename i18n commands for better consistency
- Rename `check:i18n` to `i18n:check`
- Rename `sync:i18n` to `i18n:sync`
- Rename `update:i18n` to `i18n:translate` (clearer purpose)
- Rename `auto:i18n` to `i18n:all` (runs check, sync, and translate)
- Update lint script to use new `i18n:check` command name
This follows the common naming convention of grouping related commands
under a namespace prefix (e.g., `test:main`, `test:renderer`).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: update i18n command names and improve documentation
- Renamed i18n commands for consistency: `sync:i18n` to `i18n:sync`, `check:i18n` to `i18n:check`, and `auto:i18n` to `i18n:translate`.
- Updated relevant documentation and scripts to reflect new command names.
- Improved formatting and clarity in i18n-related guides and scripts.
This change enhances the clarity and usability of i18n commands across the project.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* chore: add gitcode release sync workflow
* fix(ci): address review feedback for gitcode sync workflow
- Use Authorization header instead of token in URL query parameter
- Add file existence check before copying signed Windows artifacts
- Remove inappropriate `|| true` from artifact listing
- Use heredoc for safe GITHUB_OUTPUT writing
- Add error context logging in upload_file function
- Add curl timeout for API requests (connect: 30s, max: 60s)
- Add cleanup step for temp files with `if: always()`
- Add env var validation for GitCode credentials
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>