From aa4d1fe2b2ce35bc1be323ab369c3fb60db4232e Mon Sep 17 00:00:00 2001 From: DeskClaw Bot Date: Tue, 21 Apr 2026 13:56:26 +0000 Subject: [PATCH] feat(deskclaw): rebrand + vibe presets + chat model picker --- DESKCLAW_FEATURES.md | 47 +++++++++ electron-builder.yml | 20 ++-- electron/api/routes/agents.ts | 18 ++++ electron/main/index.ts | 8 +- electron/main/launch-at-startup.ts | 6 +- electron/main/menu.ts | 4 +- electron/main/process-instance-lock.ts | 2 +- electron/main/tray.ts | 8 +- electron/utils/agent-config.ts | 25 +++++ package.json | 6 +- src/i18n/locales/en/chat.json | 4 +- src/i18n/locales/en/settings.json | 16 +-- src/i18n/locales/en/setup.json | 10 +- src/i18n/locales/ja/chat.json | 4 +- src/i18n/locales/ja/settings.json | 14 +-- src/i18n/locales/ja/setup.json | 8 +- src/i18n/locales/zh/chat.json | 4 +- src/i18n/locales/zh/settings.json | 16 +-- src/i18n/locales/zh/setup.json | 8 +- src/pages/Chat/ChatInput.tsx | 68 ++++++++++++- src/pages/Chat/ChatToolbar.tsx | 132 +++++++++++++++++++++++++ src/pages/Settings/index.tsx | 4 +- src/stores/agents.ts | 18 ++++ 23 files changed, 377 insertions(+), 73 deletions(-) create mode 100644 DESKCLAW_FEATURES.md diff --git a/DESKCLAW_FEATURES.md b/DESKCLAW_FEATURES.md new file mode 100644 index 000000000..c25bc5af9 --- /dev/null +++ b/DESKCLAW_FEATURES.md @@ -0,0 +1,47 @@ +# DeskClaw (ClawX fork) — Feature Map + +This fork targets “AutoClaw-class” desktop agent UX while staying fully provider-agnostic (BYOK keys, OpenClaw runtime). + +## Core + +- Chat UI with streaming, markdown, images, tool cards: present (ClawX) +- Thinking visibility: present (Thinking blocks + Execution Graph) +- Vibe coding presets: added (Chat composer chips) +- Live model selection in chat UI: + - Default model selector: added (writes OpenClaw config defaults) + - Per-agent override selector: added + +## Agents / Sessions + +- Multi-agent management + per-agent workspace: present (ClawX) +- Session list + labels + history: present (ClawX) +- Sub-agent transcript viewing: present (ClawX) + +## Skills / Tools + +- Preinstalled skills bundling: present (ClawX resources/skills + bundling scripts) +- Skill marketplace + enable/disable: present (ClawX) + +## Channels + +- Multi-channel bot integrations (Feishu/Lark, Telegram, Discord, WhatsApp, etc.): present (ClawX) +- Multi-account per channel + binding to agents: present (ClawX) + +## Automation + +- Cron job scheduling + delivery routing: present (ClawX) + +## Providers + +- Multi-provider UI + secure key storage: present (ClawX) +- Custom OpenAI-compatible endpoints + validation: present (ClawX) + +## System / Packaging + +- Updater integration (electron-updater): present (ClawX) +- Windows NSIS / macOS dmg / Linux AppImage+deb+rpm packaging: present (ClawX) + +## Notes + +- “Android” is not supported by Electron. A mobile DeskClaw companion would be a separate project (React Native / Flutter) talking to a remote OpenClaw gateway. + diff --git a/electron-builder.yml b/electron-builder.yml index f80ba206c..4487829f5 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -1,6 +1,6 @@ -appId: app.clawx.desktop -productName: ClawX -copyright: Copyright © 2026 ClawX +appId: app.deskclaw.desktop +productName: DeskClaw +copyright: Copyright © 2026 DeskClaw compression: maximum artifactName: ${productName}-${version}-${os}-${arch}.${ext} @@ -59,7 +59,7 @@ publish: useMultipleRangeRequest: false - provider: github owner: ValueCell-ai - repo: ClawX + repo: DeskClaw # macOS Configuration mac: @@ -133,8 +133,8 @@ nsis: differentialPackage: true createDesktopShortcut: true createStartMenuShortcut: true - shortcutName: ClawX - uninstallDisplayName: ClawX + shortcutName: DeskClaw + uninstallDisplayName: DeskClaw license: LICENSE include: scripts/installer.nsh installerIcon: resources/icons/icon.ico @@ -161,17 +161,17 @@ linux: arch: - x64 category: Utility - maintainer: ClawX Team - vendor: ClawX + maintainer: DeskClaw Team + vendor: DeskClaw synopsis: AI Assistant powered by OpenClaw description: ClawX is a graphical AI assistant application that integrates with OpenClaw Gateway to provide intelligent automation and assistance across multiple messaging platforms. desktop: entry: - Name: ClawX + Name: DeskClaw Comment: AI Assistant powered by OpenClaw Categories: Utility;Network; Keywords: ai;assistant;automation;chat; - StartupWMClass: clawx + StartupWMClass: deskclaw appImage: license: LICENSE diff --git a/electron/api/routes/agents.ts b/electron/api/routes/agents.ts index be2b9dfad..61037754c 100644 --- a/electron/api/routes/agents.ts +++ b/electron/api/routes/agents.ts @@ -8,6 +8,7 @@ import { removeAgentWorkspaceDirectory, resolveAccountIdForAgent, updateAgentModel, + updateDefaultModel, updateAgentName, } from '../../utils/agent-config'; import { deleteChannelAccountConfig } from '../../utils/channel-config'; @@ -135,6 +136,23 @@ export async function handleAgentRoutes( return true; } + if (url.pathname === '/api/agents/default-model' && req.method === 'PUT') { + try { + const body = await parseJsonBody<{ modelRef?: string | null }>(req); + const snapshot = await updateDefaultModel(body.modelRef ?? null); + try { + await syncAllProviderAuthToRuntime(); + } catch (syncError) { + console.warn('[agents] Failed to sync runtime after updating default model:', syncError); + } + scheduleGatewayReload(ctx, 'update-default-model'); + sendJson(res, 200, { success: true, ...snapshot }); + } catch (error) { + sendJson(res, 500, { success: false, error: String(error) }); + } + return true; + } + if (url.pathname.startsWith('/api/agents/') && req.method === 'PUT') { const suffix = url.pathname.slice('/api/agents/'.length); const parts = suffix.split('/').filter(Boolean); diff --git a/electron/main/index.ts b/electron/main/index.ts index 299e64784..49550b44d 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -48,7 +48,7 @@ import { browserOAuthManager } from '../utils/browser-oauth'; import { whatsAppLoginManager } from '../utils/whatsapp-login'; import { syncAllProviderAuthToRuntime } from '../services/providers/provider-runtime-sync'; -const WINDOWS_APP_USER_MODEL_ID = 'app.clawx.desktop'; +const WINDOWS_APP_USER_MODEL_ID = 'app.deskclaw.desktop'; const isE2EMode = process.env.CLAWX_E2E === '1'; const requestedUserDataDir = process.env.CLAWX_USER_DATA_DIR?.trim(); @@ -77,7 +77,7 @@ app.disableHardwareAcceleration(); // on X11 it supplements the StartupWMClass matching. // Must be called before app.whenReady() / before any window is created. if (process.platform === 'linux') { - app.setDesktopName('clawx.desktop'); + app.setDesktopName('deskclaw.desktop'); } // Prevent multiple instances of the app from running simultaneously. @@ -96,7 +96,7 @@ if (gotElectronLock && !isE2EMode) { try { const fileLock = acquireProcessInstanceFileLock({ userDataDir: app.getPath('userData'), - lockName: 'clawx', + lockName: 'deskclaw', force: true, // Electron lock already guarantees exclusivity; force-clean orphan/recycled-PID locks }); gotFileLock = fileLock.acquired; @@ -281,7 +281,7 @@ function createMainWindow(): BrowserWindow { async function initialize(): Promise { // Initialize logger first logger.init(); - logger.info('=== ClawX Application Starting ==='); + logger.info('=== DeskClaw Application Starting ==='); logger.debug( `Runtime: platform=${process.platform}/${process.arch}, electron=${process.versions.electron}, node=${process.versions.node}, packaged=${app.isPackaged}, pid=${process.pid}, ppid=${process.ppid}` ); diff --git a/electron/main/launch-at-startup.ts b/electron/main/launch-at-startup.ts index bccc68599..f7ca32579 100644 --- a/electron/main/launch-at-startup.ts +++ b/electron/main/launch-at-startup.ts @@ -4,7 +4,7 @@ import { dirname, join } from 'node:path'; import { logger } from '../utils/logger'; import { getSetting } from '../utils/store'; -const LINUX_AUTOSTART_FILE = join('.config', 'autostart', 'clawx.desktop'); +const LINUX_AUTOSTART_FILE = join('.config', 'autostart', 'deskclaw.desktop'); function quoteDesktopArg(value: string): string { if (!value) return '""'; @@ -30,8 +30,8 @@ function getLinuxDesktopEntry(): string { '[Desktop Entry]', 'Type=Application', 'Version=1.0', - 'Name=ClawX', - 'Comment=ClawX - AI Assistant', + 'Name=DeskClaw', + 'Comment=DeskClaw - AI Assistant', `Exec=${getLinuxExecCommand()}`, 'Terminal=false', 'Categories=Utility;', diff --git a/electron/main/menu.ts b/electron/main/menu.ts index f2edb3d51..0441ae923 100644 --- a/electron/main/menu.ts +++ b/electron/main/menu.ts @@ -176,13 +176,13 @@ export function createMenu(): void { { label: 'Documentation', click: async () => { - await shell.openExternal('https://claw-x.com'); + await shell.openExternal('https://github.rommark.dev/admin/DeskClaw'); }, }, { label: 'Report Issue', click: async () => { - await shell.openExternal('https://github.com/ValueCell-ai/ClawX/issues'); + await shell.openExternal('https://github.rommark.dev/admin/DeskClaw/issues'); }, }, { type: 'separator' }, diff --git a/electron/main/process-instance-lock.ts b/electron/main/process-instance-lock.ts index 2929424c5..ab1400766 100644 --- a/electron/main/process-instance-lock.ts +++ b/electron/main/process-instance-lock.ts @@ -1,7 +1,7 @@ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; -const LOCK_SCHEMA = 'clawx-instance-lock'; +const LOCK_SCHEMA = 'deskclaw-instance-lock'; const LOCK_VERSION = 1; export interface ProcessInstanceFileLock { diff --git a/electron/main/tray.ts b/electron/main/tray.ts index 0dc9c9534..4beb9eb8a 100644 --- a/electron/main/tray.ts +++ b/electron/main/tray.ts @@ -57,7 +57,7 @@ export function createTray(mainWindow: BrowserWindow): Tray { tray = new Tray(icon); // Set tooltip - tray.setToolTip('ClawX - AI Assistant'); + tray.setToolTip('DeskClaw - AI Assistant'); const showWindow = () => { if (mainWindow.isDestroyed()) return; @@ -68,7 +68,7 @@ export function createTray(mainWindow: BrowserWindow): Tray { // Create context menu const contextMenu = Menu.buildFromTemplate([ { - label: 'Show ClawX', + label: 'Show DeskClaw', click: showWindow, }, { @@ -122,7 +122,7 @@ export function createTray(mainWindow: BrowserWindow): Tray { type: 'separator', }, { - label: 'Quit ClawX', + label: 'Quit DeskClaw', click: () => { app.quit(); }, @@ -157,7 +157,7 @@ export function createTray(mainWindow: BrowserWindow): Tray { */ export function updateTrayStatus(status: string): void { if (tray) { - tray.setToolTip(`ClawX - ${status}`); + tray.setToolTip(`DeskClaw - ${status}`); } } diff --git a/electron/utils/agent-config.ts b/electron/utils/agent-config.ts index 525a5d3c6..2c3e68add 100644 --- a/electron/utils/agent-config.ts +++ b/electron/utils/agent-config.ts @@ -681,6 +681,31 @@ export async function updateAgentModel(agentId: string, modelRef: string | null) }); } +export async function updateDefaultModel(modelRef: string | null): Promise { + return withConfigLock(async () => { + const config = await readOpenClawConfig() as AgentConfigDocument; + const { agentsConfig } = normalizeAgentsConfig(config); + const normalizedModelRef = typeof modelRef === 'string' ? modelRef.trim() : ''; + const nextAgentsConfig: AgentsConfig = { ...(agentsConfig || {}) }; + const nextDefaults: AgentDefaultsConfig = { ...(nextAgentsConfig.defaults || {}) }; + + if (!normalizedModelRef) { + delete nextDefaults.model; + } else { + if (!isValidModelRef(normalizedModelRef)) { + throw new Error('modelRef must be in "provider/model" format'); + } + nextDefaults.model = { primary: normalizedModelRef }; + } + + nextAgentsConfig.defaults = nextDefaults; + config.agents = nextAgentsConfig; + await writeOpenClawConfig(config); + logger.info('Updated default model', { modelRef: normalizedModelRef || null }); + return buildSnapshotFromConfig(config); + }); +} + export async function deleteAgentConfig(agentId: string): Promise<{ snapshot: AgentsSnapshot; removedEntry: AgentListEntry }> { return withConfigLock(async () => { if (agentId === MAIN_AGENT_ID) { diff --git a/package.json b/package.json index 176f8fab7..9c39b4fea 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "clawx", + "name": "deskclaw", "version": "0.3.10", "pnpm": { "onlyBuiltDependencies": [ @@ -26,9 +26,9 @@ ] } }, - "description": "ClawX - Graphical AI Assistant based on OpenClaw", + "description": "DeskClaw - Graphical AI Assistant based on OpenClaw", "main": "dist-electron/main/index.js", - "author": "ClawX Team", + "author": "DeskClaw Team", "license": "MIT", "private": true, "scripts": { diff --git a/src/i18n/locales/en/chat.json b/src/i18n/locales/en/chat.json index 437dc0d1d..332b45570 100644 --- a/src/i18n/locales/en/chat.json +++ b/src/i18n/locales/en/chat.json @@ -2,7 +2,7 @@ "gatewayNotRunning": "Gateway Not Running", "gatewayRequired": "The OpenClaw Gateway needs to be running to use chat. It will start automatically, or you can start it from Settings.", "welcome": { - "title": "ClawX Chat", + "title": "DeskClaw Chat", "subtitle": "What can I do for you?", "askQuestions": "Handle Tasks", "askQuestionsDesc": "Work on task-oriented requests", @@ -19,7 +19,7 @@ "eyebrow": "Run View", "title": "Task Outline", "emptyTitle": "No structured steps yet", - "emptyBody": "Once a run starts, ClawX will surface thinking, tool calls, and handoff states here.", + "emptyBody": "Once a run starts, DeskClaw will surface thinking, tool calls, and handoff states here.", "status": { "idle": "Idle", "running_one": "1 active step", diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index 252ab9fdc..cfeb776f8 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -1,6 +1,6 @@ { "title": "Settings", - "subtitle": "Configure your ClawX experience", + "subtitle": "Configure your DeskClaw experience", "appearance": { "title": "General", "description": "Customize the look and feel", @@ -10,7 +10,7 @@ "system": "System", "language": "Language", "launchAtStartup": "Launch at system startup", - "launchAtStartupDesc": "Automatically launch ClawX when you log in" + "launchAtStartupDesc": "Automatically launch DeskClaw when you log in" }, "aiProviders": { "title": "AI Providers", @@ -37,7 +37,7 @@ "notRequired": "Not required", "empty": { "title": "No providers configured", - "desc": "Add an AI provider to start using ClawX", + "desc": "Add an AI provider to start using DeskClaw", "cta": "Add Your First Provider" }, "dialog": { @@ -60,7 +60,7 @@ "protocol": "Protocol", "advancedConfig": "Advanced configuration", "userAgent": "User-Agent", - "userAgentPlaceholder": "ClawX/1.0", + "userAgentPlaceholder": "DeskClaw/1.0", "fallbackModels": "Fallback Models", "fallbackProviders": "Fallback Providers", "fallbackModelIds": "Fallback Model IDs", @@ -134,7 +134,7 @@ "appLogs": "Application Logs", "openFolder": "Open Folder", "autoStart": "Auto-start Gateway", - "autoStartDesc": "Start Gateway when ClawX launches", + "autoStartDesc": "Start Gateway when DeskClaw launches", "proxyTitle": "Proxy", "proxyDesc": "Route Electron and Gateway traffic through your local proxy client.", "proxyServer": "Proxy Server", @@ -155,7 +155,7 @@ }, "updates": { "title": "Updates", - "description": "Keep ClawX up to date", + "description": "Keep DeskClaw up to date", "autoCheck": "Auto-check for updates", "autoCheckDesc": "Check for updates on startup", "autoDownload": "Auto-update", @@ -209,7 +209,7 @@ "devMode": "Developer Mode", "devModeDesc": "Show developer tools and shortcuts", "telemetry": "Anonymous Usage Data", - "telemetryDesc": "Allow providing anonymous basic usage data to improve ClawX" + "telemetryDesc": "Allow providing anonymous basic usage data to improve DeskClaw" }, "developer": { "title": "Developer", @@ -271,7 +271,7 @@ }, "about": { "title": "About", - "appName": "ClawX", + "appName": "DeskClaw", "tagline": "Graphical AI Assistant", "basedOn": "Based on OpenClaw", "version": "Version {{version}}", diff --git a/src/i18n/locales/en/setup.json b/src/i18n/locales/en/setup.json index ed674c299..87439e7b2 100644 --- a/src/i18n/locales/en/setup.json +++ b/src/i18n/locales/en/setup.json @@ -1,7 +1,7 @@ { "steps": { "welcome": { - "title": "Welcome to ClawX", + "title": "Welcome to DeskClaw", "description": "Your AI assistant is ready to be configured" }, "runtime": { @@ -22,12 +22,12 @@ }, "complete": { "title": "All Set!", - "description": "ClawX is ready to use" + "description": "DeskClaw is ready to use" } }, "welcome": { - "title": "Welcome to ClawX", - "description": "ClawX is a graphical interface for OpenClaw, making it easy to use AI assistants across your favorite messaging platforms.", + "title": "Welcome to DeskClaw", + "description": "DeskClaw is a graphical interface for OpenClaw, making it easy to use AI assistants across your favorite messaging platforms.", "features": { "noCommand": "Zero command-line required", "modernUI": "Modern, beautiful interface", @@ -113,7 +113,7 @@ }, "complete": { "title": "Setup Complete!", - "subtitle": "ClawX is configured and ready to use. You can now start chatting with your AI assistant.", + "subtitle": "DeskClaw is configured and ready to use. You can now start chatting with your AI assistant.", "provider": "AI Provider", "components": "Components", "gateway": "Gateway", diff --git a/src/i18n/locales/ja/chat.json b/src/i18n/locales/ja/chat.json index d6f01557e..11be5e21f 100644 --- a/src/i18n/locales/ja/chat.json +++ b/src/i18n/locales/ja/chat.json @@ -2,7 +2,7 @@ "gatewayNotRunning": "ゲートウェイが停止中", "gatewayRequired": "チャットを利用するには OpenClaw ゲートウェイが実行されている必要があります。自動的に起動するか、設定から起動できます。", "welcome": { - "title": "ClawX チャット", + "title": "DeskClaw チャット", "subtitle": "お手伝いできることはありますか?", "askQuestions": "タスク対応", "askQuestionsDesc": "タスク指向の依頼に対応します", @@ -19,7 +19,7 @@ "eyebrow": "実行ビュー", "title": "タスクの流れ", "emptyTitle": "まだ構造化されたステップはありません", - "emptyBody": "実行が始まると、ClawX は思考・ツール呼び出し・最終化の状態をここに表示します。", + "emptyBody": "実行が始まると、DeskClaw は思考・ツール呼び出し・最終化の状態をここに表示します。", "status": { "idle": "待機中", "running_one": "進行中 1 件", diff --git a/src/i18n/locales/ja/settings.json b/src/i18n/locales/ja/settings.json index a73136292..4d7deb19b 100644 --- a/src/i18n/locales/ja/settings.json +++ b/src/i18n/locales/ja/settings.json @@ -1,6 +1,6 @@ { "title": "設定", - "subtitle": "ClawX の体験をカスタマイズ", + "subtitle": "DeskClaw の体験をカスタマイズ", "appearance": { "title": "通用", "description": "外観とスタイルをカスタマイズ", @@ -10,7 +10,7 @@ "system": "システム", "language": "言語", "launchAtStartup": "システム起動時に自動起動", - "launchAtStartupDesc": "ログイン時に ClawX を自動的に起動します" + "launchAtStartupDesc": "ログイン時に DeskClaw を自動的に起動します" }, "aiProviders": { "title": "AI プロバイダー", @@ -37,7 +37,7 @@ "notRequired": "不要", "empty": { "title": "プロバイダーが構成されていません", - "desc": "ClawX の使用を開始するには AI プロバイダーを追加してください", + "desc": "DeskClaw の使用を開始するには AI プロバイダーを追加してください", "cta": "最初のプロバイダーを追加" }, "dialog": { @@ -60,7 +60,7 @@ "protocol": "プロトコル", "advancedConfig": "詳細設定", "userAgent": "User-Agent", - "userAgentPlaceholder": "ClawX/1.0", + "userAgentPlaceholder": "DeskClaw/1.0", "fallbackModels": "フォールバックモデル", "fallbackProviders": "別プロバイダーへのフォールバック", "fallbackModelIds": "同一プロバイダーのフォールバックモデル ID", @@ -133,7 +133,7 @@ "appLogs": "アプリケーションログ", "openFolder": "フォルダーを開く", "autoStart": "ゲートウェイ自動起動", - "autoStartDesc": "ClawX 起動時にゲートウェイを自動起動", + "autoStartDesc": "DeskClaw 起動時にゲートウェイを自動起動", "proxyTitle": "プロキシ", "proxyDesc": "Electron と Gateway の通信をローカルプロキシ経由にします。", "proxyServer": "プロキシサーバー", @@ -154,7 +154,7 @@ }, "updates": { "title": "アップデート", - "description": "ClawX を最新に保つ", + "description": "DeskClaw を最新に保つ", "autoCheck": "自動更新チェック", "autoCheckDesc": "起動時に更新を確認", "autoDownload": "自動アップデート", @@ -268,7 +268,7 @@ }, "about": { "title": "バージョン情報", - "appName": "ClawX", + "appName": "DeskClaw", "tagline": "グラフィカル AI アシスタント", "basedOn": "OpenClaw ベース", "version": "バージョン {{version}}", diff --git a/src/i18n/locales/ja/setup.json b/src/i18n/locales/ja/setup.json index 1c5c119e0..dc0cbc70e 100644 --- a/src/i18n/locales/ja/setup.json +++ b/src/i18n/locales/ja/setup.json @@ -1,7 +1,7 @@ { "steps": { "welcome": { - "title": "ClawXへようこそ", + "title": "DeskClawへようこそ", "description": "AIアシスタントの設定準備が整いました" }, "runtime": { @@ -22,12 +22,12 @@ }, "complete": { "title": "完了!", - "description": "ClawXを使用する準備が整いました" + "description": "DeskClawを使用する準備が整いました" } }, "welcome": { - "title": "ClawXへようこそ", - "description": "ClawXはOpenClawのグラフィカルインターフェースで、お気に入りのメッセージングプラットフォームでAIアシスタントを簡単に使用できます。", + "title": "DeskClawへようこそ", + "description": "DeskClawはOpenClawのグラフィカルインターフェースで、お気に入りのメッセージングプラットフォームでAIアシスタントを簡単に使用できます。", "features": { "noCommand": "コマンドライン不要", "modernUI": "モダンで美しいインターフェース", diff --git a/src/i18n/locales/zh/chat.json b/src/i18n/locales/zh/chat.json index 88ea7f963..2cfeeb844 100644 --- a/src/i18n/locales/zh/chat.json +++ b/src/i18n/locales/zh/chat.json @@ -2,7 +2,7 @@ "gatewayNotRunning": "网关未运行", "gatewayRequired": "OpenClaw 网关需要运行才能使用聊天。它将自动启动,或者您可以从设置中启动。", "welcome": { - "title": "ClawX 聊天", + "title": "DeskClaw 聊天", "subtitle": "我能为你做些什么?", "askQuestions": "处理任务", "askQuestionsDesc": "处理面向任务的请求", @@ -19,7 +19,7 @@ "eyebrow": "运行视图", "title": "任务脉络", "emptyTitle": "还没有结构化步骤", - "emptyBody": "当一次运行开始后,ClawX 会在这里展示思考、工具调用和收尾状态。", + "emptyBody": "当一次运行开始后,DeskClaw 会在这里展示思考、工具调用和收尾状态。", "status": { "idle": "空闲", "running_one": "1 个活动步骤", diff --git a/src/i18n/locales/zh/settings.json b/src/i18n/locales/zh/settings.json index 80655295c..036cd9420 100644 --- a/src/i18n/locales/zh/settings.json +++ b/src/i18n/locales/zh/settings.json @@ -1,6 +1,6 @@ { "title": "设置", - "subtitle": "配置您的 ClawX 体验", + "subtitle": "配置您的 DeskClaw 体验", "appearance": { "title": "通用", "description": "自定义外观和风格", @@ -10,7 +10,7 @@ "system": "跟随系统", "language": "语言", "launchAtStartup": "开机自动启动", - "launchAtStartupDesc": "登录系统后自动启动 ClawX" + "launchAtStartupDesc": "登录系统后自动启动 DeskClaw" }, "aiProviders": { "title": "AI 模型提供商", @@ -37,7 +37,7 @@ "notRequired": "非必填", "empty": { "title": "未配置提供商", - "desc": "添加 AI 提供商以开始使用 ClawX", + "desc": "添加 AI 提供商以开始使用 DeskClaw", "cta": "添加您的第一个提供商" }, "dialog": { @@ -60,7 +60,7 @@ "protocol": "协议", "advancedConfig": "高级配置", "userAgent": "User-Agent", - "userAgentPlaceholder": "ClawX/1.0", + "userAgentPlaceholder": "DeskClaw/1.0", "fallbackModels": "回退模型", "fallbackProviders": "跨 Provider 回退", "fallbackModelIds": "同 Provider 回退模型 ID", @@ -134,7 +134,7 @@ "appLogs": "应用日志", "openFolder": "打开文件夹", "autoStart": "自动启动网关", - "autoStartDesc": "ClawX 启动时自动启动网关", + "autoStartDesc": "DeskClaw 启动时自动启动网关", "proxyTitle": "代理", "proxyDesc": "让 Electron 和 Gateway 的网络请求都走本地代理客户端。", "proxyServer": "代理服务器", @@ -155,7 +155,7 @@ }, "updates": { "title": "更新", - "description": "保持 ClawX 最新", + "description": "保持 DeskClaw 最新", "autoCheck": "自动检查更新", "autoCheckDesc": "启动时检查更新", "autoDownload": "自动更新", @@ -209,7 +209,7 @@ "devMode": "开发者模式", "devModeDesc": "显示开发者工具和快捷方式", "telemetry": "匿名使用数据", - "telemetryDesc": "允许提供匿名的基础使用数据,用于改进 ClawX" + "telemetryDesc": "允许提供匿名的基础使用数据,用于改进 DeskClaw" }, "developer": { "title": "开发者", @@ -271,7 +271,7 @@ }, "about": { "title": "关于", - "appName": "ClawX", + "appName": "DeskClaw", "tagline": "图形化 AI 助手", "basedOn": "基于 OpenClaw", "version": "版本 {{version}}", diff --git a/src/i18n/locales/zh/setup.json b/src/i18n/locales/zh/setup.json index 8d00945be..597cf9513 100644 --- a/src/i18n/locales/zh/setup.json +++ b/src/i18n/locales/zh/setup.json @@ -1,7 +1,7 @@ { "steps": { "welcome": { - "title": "欢迎使用 ClawX", + "title": "欢迎使用 DeskClaw", "description": "您的 AI 助手已准备好进行配置" }, "runtime": { @@ -22,12 +22,12 @@ }, "complete": { "title": "准备就绪!", - "description": "ClawX 已准备好使用" + "description": "DeskClaw 已准备好使用" } }, "welcome": { - "title": "欢迎使用 ClawX", - "description": "ClawX 是 OpenClaw 的图形界面,让您可以在喜爱的消息平台上轻松使用 AI 助手。", + "title": "欢迎使用 DeskClaw", + "description": "DeskClaw 是 OpenClaw 的图形界面,让您可以在喜爱的消息平台上轻松使用 AI 助手。", "features": { "noCommand": "无需命令行", "modernUI": "现代美观的界面", diff --git a/src/pages/Chat/ChatInput.tsx b/src/pages/Chat/ChatInput.tsx index c1a479d81..388618831 100644 --- a/src/pages/Chat/ChatInput.tsx +++ b/src/pages/Chat/ChatInput.tsx @@ -87,6 +87,7 @@ function readFileAsBase64(file: globalThis.File): Promise { export function ChatInput({ onSend, onStop, disabled = false, sending = false, isEmpty = false }: ChatInputProps) { const { t } = useTranslation('chat'); const [input, setInput] = useState(''); + const [vibeMode, setVibeMode] = useState(''); const [attachments, setAttachments] = useState([]); const [targetAgentId, setTargetAgentId] = useState(null); const [pickerOpen, setPickerOpen] = useState(false); @@ -109,6 +110,31 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i [agents, targetAgentId], ); const showAgentPicker = mentionableAgents.length > 0; + const vibePresets = useMemo( + () => [ + { + key: 'plan', + label: 'Plan', + text: 'Mode: Plan.\nAsk missing questions first. Then propose a step-by-step plan and a short checklist. Wait for confirmation before implementing.', + }, + { + key: 'build', + label: 'Build', + text: 'Mode: Build.\nImplement the requested change. Keep it minimal, production-grade, and include verification steps.', + }, + { + key: 'debug', + label: 'Debug', + text: 'Mode: Debug.\nList hypotheses, propose the smallest reproduction, add instrumentation, then fix the root cause.', + }, + { + key: 'review', + label: 'Review', + text: 'Mode: Review.\nReview for correctness, security, and edge cases. Propose concrete fixes.', + }, + ], + [], + ); // Auto-resize textarea useEffect(() => { @@ -293,7 +319,11 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i const readyAttachments = attachments.filter(a => a.status === 'ready'); // Capture values before clearing — clear input immediately for snappy UX, // but keep attachments available for the async send - const textToSend = input.trim(); + let textToSend = input.trim(); + const preset = vibeMode ? vibePresets.find((p) => p.key === vibeMode) : null; + if (preset) { + textToSend = textToSend ? `${preset.text}\n\n---\n\n${textToSend}` : preset.text; + } const attachmentsToSend = readyAttachments.length > 0 ? readyAttachments : undefined; console.log(`[handleSend] text="${textToSend.substring(0, 50)}", attachments=${attachments.length}, ready=${readyAttachments.length}, sending=${!!attachmentsToSend}`); if (attachmentsToSend) { @@ -310,7 +340,7 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i onSend(textToSend, attachmentsToSend, targetAgentId); setTargetAgentId(null); setPickerOpen(false); - }, [input, attachments, canSend, onSend, targetAgentId]); + }, [input, attachments, canSend, onSend, targetAgentId, vibeMode, vibePresets]); const handleStop = useCallback(() => { if (!canStop) return; @@ -423,6 +453,40 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i )} + {!disabled && ( +
+ + {vibePresets.map((preset) => ( + + ))} +
+ )} + {/* Text Row — flush-left */}