refactor(client): full Claude→Heicode rebrand across desktop runtime

Beyond the i18n strings rebrand (b55d103) this pass cleans up everything
that still surfaced "Claude" in the built artifact:

Theme tokens (cc-haha/desktop/src/theme/globals.css)
- light-mode text-selection-bg rgba(197,165,114,*) → rgba(123,107,227,*)
  (selecting ANY text in light mode used to paint a gold highlight)
- dark + light diff-highlight-bg / -gutter switched from gold to brand
  violet rgba(123,107,227,*) — keeps semantic "highlight" without leaving
  the brand

Sidecar binary rename: claude-sidecar → heicode-sidecar
- desktop/sidecars/claude-sidecar.ts renamed (git mv)
- internal log prefix strings (12 occurrences) updated
- desktop/scripts/build-sidecars.ts: entrypoint / outfileBase / productName
  ('Heicode Sidecar') / publisher ('Heicode') — these last two are embedded
  in the .exe metadata you see in File Properties
- src-tauri/capabilities/default.json: 9 binaries/claude-sidecar references
  rewritten + description "Default capabilities for Heicode Desktop"
- src-tauri/src/lib.rs: 2 .sidecar("claude-sidecar") + 3 packaged sidecar
  exe filename strings + 1 doc comment
- desktop/sidecars/launcherRouting{,.test}.ts

After this rebuild, Task Manager shows heicode-sidecar-*.exe child
processes (was claude-sidecar-*.exe) and right-click → Properties on
that binary shows "Heicode Sidecar" / "Heicode" instead of "Claude Code".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 15:56:03 +08:00
co-authored by Claude Opus 4.7
parent b6607c9a3e
commit 3a358ba5e1
7 changed files with 39 additions and 39 deletions
+5 -5
View File
@@ -28,11 +28,11 @@ await mkdir(binariesDir, { recursive: true })
// 单一合并 sidecar:server / cli 共享一份 bun runtime + 共享依赖代码。 // 单一合并 sidecar:server / cli 共享一份 bun runtime + 共享依赖代码。
// 调用方(Tauri lib.rs / conversationService)通过第一个 positional 参数 // 调用方(Tauri lib.rs / conversationService)通过第一个 positional 参数
// 选择 'server' 或 'cli' 模式,详见 desktop/sidecars/claude-sidecar.ts。 // 选择 'server' 或 'cli' 模式,详见 desktop/sidecars/heicode-sidecar.ts。
await compileExecutable({ await compileExecutable({
entrypoint: path.join(desktopRoot, 'sidecars/claude-sidecar.ts'), entrypoint: path.join(desktopRoot, 'sidecars/heicode-sidecar.ts'),
outfileBase: path.join(binariesDir, `claude-sidecar-${targetTriple}`), outfileBase: path.join(binariesDir, `heicode-sidecar-${targetTriple}`),
productName: 'Claude Code Sidecar', productName: 'Heicode Sidecar',
bunTarget, bunTarget,
}) })
@@ -142,7 +142,7 @@ async function compileExecutable({
autoloadPackageJson: true, autoloadPackageJson: true,
windows: { windows: {
title: productName, title: productName,
publisher: 'Claude Code', publisher: 'Heicode',
description: productName, description: productName,
hideConsole: true, hideConsole: true,
}, },
@@ -6,9 +6,9 @@
* 把所有运行模式合并到同一个二进制里,runtime 只保留一份;调用方通过 * 把所有运行模式合并到同一个二进制里,runtime 只保留一份;调用方通过
* 第一个 positional 参数选择模式: * 第一个 positional 参数选择模式:
* *
* claude-sidecar server --app-root <path> --host 127.0.0.1 --port 12345 * heicode-sidecar server --app-root <path> --host 127.0.0.1 --port 12345
* claude-sidecar cli --app-root <path> [其它 CLI 参数...] * heicode-sidecar cli --app-root <path> [其它 CLI 参数...]
* claude-sidecar adapters --app-root <path> [--feishu] [--telegram] * heicode-sidecar adapters --app-root <path> [--feishu] [--telegram]
* *
* 任何模式都必须先做 process.env / process.argv 设置,再 await 进入相应的 * 任何模式都必须先做 process.env / process.argv 设置,再 await 进入相应的
* 子模块树。原因:src/server/index.ts、src/entrypoints/cli.tsx、以及 * 子模块树。原因:src/server/index.ts、src/entrypoints/cli.tsx、以及
@@ -22,7 +22,7 @@ import { parseLauncherArgs, resolveSidecarInvocation } from './launcherRouting'
const rawArgs = process.argv.slice(2) const rawArgs = process.argv.slice(2)
const invocation = resolveSidecarInvocation(rawArgs) const invocation = resolveSidecarInvocation(rawArgs)
if (!invocation.mode) { if (!invocation.mode) {
console.error('claude-sidecar: missing mode argument (expected "server", "cli" or "adapters")') console.error('heicode-sidecar: missing mode argument (expected "server", "cli" or "adapters")')
process.exit(2) process.exit(2)
} }
const mode = invocation.mode const mode = invocation.mode
@@ -45,7 +45,7 @@ if (mode === 'adapters') {
} else if (mode === 'cli') { } else if (mode === 'cli') {
await import('../../src/entrypoints/cli.tsx') await import('../../src/entrypoints/cli.tsx')
} else { } else {
console.error(`claude-sidecar: unknown mode "${mode}" (expected "server", "cli" or "adapters")`) console.error(`heicode-sidecar: unknown mode "${mode}" (expected "server", "cli" or "adapters")`)
process.exit(2) process.exit(2)
} }
} }
@@ -73,12 +73,12 @@ async function runAdapters(rawArgs: string[]): Promise<void> {
enableTelegram = true enableTelegram = true
continue continue
} }
console.warn(`claude-sidecar adapters: ignoring unknown arg "${arg}"`) console.warn(`heicode-sidecar adapters: ignoring unknown arg "${arg}"`)
} }
if (!enableFeishu && !enableTelegram) { if (!enableFeishu && !enableTelegram) {
console.error( console.error(
'claude-sidecar adapters: must enable at least one of --feishu / --telegram', 'heicode-sidecar adapters: must enable at least one of --feishu / --telegram',
) )
process.exit(2) process.exit(2)
} }
@@ -102,10 +102,10 @@ async function runAdapters(rawArgs: string[]): Promise<void> {
if (enableFeishu) { if (enableFeishu) {
if (!config.feishu.appId || !config.feishu.appSecret) { if (!config.feishu.appId || !config.feishu.appSecret) {
console.warn( console.warn(
'[claude-sidecar] --feishu requested but FEISHU_APP_ID / FEISHU_APP_SECRET missing in env or ~/.claude/adapters.json — skipping', '[heicode-sidecar] --feishu requested but FEISHU_APP_ID / FEISHU_APP_SECRET missing in env or ~/.claude/adapters.json — skipping',
) )
} else { } else {
console.log('[claude-sidecar] starting Feishu adapter') console.log('[heicode-sidecar] starting Feishu adapter')
// 副作用 import:feishu/index.ts 顶层会自动 new WSClient + start() // 副作用 import:feishu/index.ts 顶层会自动 new WSClient + start()
await import('../../adapters/feishu/index.ts') await import('../../adapters/feishu/index.ts')
started += 1 started += 1
@@ -115,10 +115,10 @@ async function runAdapters(rawArgs: string[]): Promise<void> {
if (enableTelegram) { if (enableTelegram) {
if (!config.telegram.botToken) { if (!config.telegram.botToken) {
console.warn( console.warn(
'[claude-sidecar] --telegram requested but TELEGRAM_BOT_TOKEN missing in env or ~/.claude/adapters.json — skipping', '[heicode-sidecar] --telegram requested but TELEGRAM_BOT_TOKEN missing in env or ~/.claude/adapters.json — skipping',
) )
} else { } else {
console.log('[claude-sidecar] starting Telegram adapter') console.log('[heicode-sidecar] starting Telegram adapter')
// 副作用 import:telegram/index.ts 顶层会自动 bot.start() // 副作用 import:telegram/index.ts 顶层会自动 bot.start()
await import('../../adapters/telegram/index.ts') await import('../../adapters/telegram/index.ts')
started += 1 started += 1
@@ -127,7 +127,7 @@ async function runAdapters(rawArgs: string[]): Promise<void> {
if (started === 0) { if (started === 0) {
console.error( console.error(
'[claude-sidecar] no adapter could be started — check credentials in env or ~/.claude/adapters.json', '[heicode-sidecar] no adapter could be started — check credentials in env or ~/.claude/adapters.json',
) )
process.exit(1) process.exit(1)
} }
@@ -7,7 +7,7 @@ describe('resolveSidecarInvocation', () => {
expect( expect(
resolveSidecarInvocation( resolveSidecarInvocation(
['server', '--host', '127.0.0.1'], ['server', '--host', '127.0.0.1'],
'/tmp/claude-sidecar', '/tmp/heicode-sidecar',
), ),
).toEqual({ ).toEqual({
mode: 'server', mode: 'server',
+1 -1
View File
@@ -57,7 +57,7 @@ export function parseLauncherArgs(
} }
if (!appRoot) { if (!appRoot) {
throw new Error('Missing --app-root for claude-sidecar') throw new Error('Missing --app-root for heicode-sidecar')
} }
return { appRoot, args: nextArgs } return { appRoot, args: nextArgs }
@@ -20,7 +20,7 @@
"server", "server",
{ "validator": "regex", "value": "^(--port|--host|--config)=.+$" } { "validator": "regex", "value": "^(--port|--host|--config)=.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -28,7 +28,7 @@
"adapters", "adapters",
{ "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" } { "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -36,7 +36,7 @@
"cli", "cli",
{ "validator": "regex", "value": "^.+$" } { "validator": "regex", "value": "^.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
} }
] ]
@@ -49,7 +49,7 @@
"server", "server",
{ "validator": "regex", "value": "^(--port|--host|--config)=.+$" } { "validator": "regex", "value": "^(--port|--host|--config)=.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -57,7 +57,7 @@
"adapters", "adapters",
{ "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" } { "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -65,7 +65,7 @@
"cli", "cli",
{ "validator": "regex", "value": "^.+$" } { "validator": "regex", "value": "^.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
} }
] ]
@@ -78,7 +78,7 @@
"server", "server",
{ "validator": "regex", "value": "^(--port|--host|--config)=.+$" } { "validator": "regex", "value": "^(--port|--host|--config)=.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -86,7 +86,7 @@
"adapters", "adapters",
{ "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" } { "validator": "regex", "value": "^(feishu|telegram|lark|slack)(:.+)?$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
}, },
{ {
@@ -94,7 +94,7 @@
"cli", "cli",
{ "validator": "regex", "value": "^.+$" } { "validator": "regex", "value": "^.+$" }
], ],
"name": "binaries/claude-sidecar", "name": "binaries/heicode-sidecar",
"sidecar": true "sidecar": true
} }
] ]
+6 -6
View File
@@ -50,7 +50,7 @@ struct AppExitState {
/// 与 ServerState 平级的 adapter 子进程状态。 /// 与 ServerState 平级的 adapter 子进程状态。
/// ///
/// adapter sidecar(claude-sidecar adapters --feishu --telegram)的生命周期 /// adapter sidecar(heicode-sidecar adapters --feishu --telegram)的生命周期
/// 跟 server 不同:它没有 HTTP 端口可探活,没配凭据时会自己干净退出, /// 跟 server 不同:它没有 HTTP 端口可探活,没配凭据时会自己干净退出,
/// 而且需要支持运行时热重启 —— 用户在设置页保存飞书 / Telegram 凭据后, /// 而且需要支持运行时热重启 —— 用户在设置页保存飞书 / Telegram 凭据后,
/// 前端会通过 invoke('restart_adapters_sidecar') 来重启它,让新凭据生效。 /// 前端会通过 invoke('restart_adapters_sidecar') 来重启它,让新凭据生效。
@@ -679,7 +679,7 @@ fn start_server_sidecar(app: &AppHandle) -> Result<ServerRuntime, String> {
// 单一合并 sidecar:第一个参数选 server / cli / adapters 模式。 // 单一合并 sidecar:第一个参数选 server / cli / adapters 模式。
let mut sidecar = app let mut sidecar = app
.shell() .shell()
.sidecar("claude-sidecar") .sidecar("heicode-sidecar")
.map_err(|err| format!("resolve sidecar: {err}"))?; .map_err(|err| format!("resolve sidecar: {err}"))?;
for (key, value) in terminal_environment(&default_shell()) { for (key, value) in terminal_environment(&default_shell()) {
sidecar = sidecar.env(key, value); sidecar = sidecar.env(key, value);
@@ -786,7 +786,7 @@ fn start_adapters_sidecar(app: &AppHandle) -> Result<CommandChild, String> {
let mut sidecar = app let mut sidecar = app
.shell() .shell()
.sidecar("claude-sidecar") .sidecar("heicode-sidecar")
.map_err(|err| format!("resolve sidecar: {err}"))?; .map_err(|err| format!("resolve sidecar: {err}"))?;
for (key, value) in terminal_environment(&default_shell()) { for (key, value) in terminal_environment(&default_shell()) {
sidecar = sidecar.env(key, value); sidecar = sidecar.env(key, value);
@@ -865,9 +865,9 @@ fn stop_adapters_sidecar(app: &AppHandle) {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn kill_windows_sidecars() { fn kill_windows_sidecars() {
for image_name in [ for image_name in [
"claude-sidecar-x86_64-pc-windows-msvc.exe", "heicode-sidecar-x86_64-pc-windows-msvc.exe",
"claude-sidecar-aarch64-pc-windows-msvc.exe", "heicode-sidecar-aarch64-pc-windows-msvc.exe",
"claude-sidecar.exe", "heicode-sidecar.exe",
] { ] {
let _ = StdCommand::new("taskkill") let _ = StdCommand::new("taskkill")
.args(["/F", "/T", "/IM", image_name]) .args(["/F", "/T", "/IM", image_name])
+5 -5
View File
@@ -278,8 +278,8 @@
--color-diff-removed-word: rgba(229, 72, 77, 0.22); --color-diff-removed-word: rgba(229, 72, 77, 0.22);
--color-diff-removed-gutter: rgba(229, 72, 77, 0.16); --color-diff-removed-gutter: rgba(229, 72, 77, 0.16);
--color-diff-removed-text: #E5848A; --color-diff-removed-text: #E5848A;
--color-diff-highlight-bg: rgba(197, 165, 114, 0.10); --color-diff-highlight-bg: rgba(123, 107, 227, 0.10);
--color-diff-highlight-gutter: rgba(197, 165, 114, 0.16); --color-diff-highlight-gutter: rgba(123, 107, 227, 0.18);
--color-diff-title-bg: var(--color-surface-container-low); --color-diff-title-bg: var(--color-surface-container-low);
--color-diff-title-color: var(--color-text-tertiary); --color-diff-title-color: var(--color-text-tertiary);
--color-diff-title-border: rgba(255, 255, 255, 0.06); --color-diff-title-border: rgba(255, 255, 255, 0.06);
@@ -439,8 +439,8 @@
--color-diff-removed-word: #F5B8B4; --color-diff-removed-word: #F5B8B4;
--color-diff-removed-gutter: #F9D4D0; --color-diff-removed-gutter: #F9D4D0;
--color-diff-removed-text: #C92A30; --color-diff-removed-text: #C92A30;
--color-diff-highlight-bg: #FFF5D6; --color-diff-highlight-bg: rgba(123, 107, 227, 0.08);
--color-diff-highlight-gutter: #FFECB3; --color-diff-highlight-gutter: rgba(123, 107, 227, 0.16);
--color-diff-title-bg: var(--color-surface-container-low); --color-diff-title-bg: var(--color-surface-container-low);
--color-diff-title-color: var(--color-text-tertiary); --color-diff-title-color: var(--color-text-tertiary);
--color-diff-title-border: rgba(0, 0, 0, 0.06); --color-diff-title-border: rgba(0, 0, 0, 0.06);
@@ -455,7 +455,7 @@
--color-terminal-warning: #FEBC2E; --color-terminal-warning: #FEBC2E;
--color-window-close-hover: #E81123; --color-window-close-hover: #E81123;
--color-selection-bg: rgba(197, 165, 114, 0.30); --color-selection-bg: rgba(123, 107, 227, 0.28);
--color-selection-fg: #1B1B1F; --color-selection-fg: #1B1B1F;
} }