feat(deskclaw): rebrand + vibe presets + chat model picker

This commit is contained in:
DeskClaw Bot
2026-04-21 13:56:26 +00:00
Unverified
parent 92144ab639
commit aa4d1fe2b2
23 changed files with 377 additions and 73 deletions

View File

@@ -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);

View File

@@ -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<void> {
// 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}`
);

View File

@@ -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;',

View File

@@ -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' },

View File

@@ -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 {

View File

@@ -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}`);
}
}

View File

@@ -681,6 +681,31 @@ export async function updateAgentModel(agentId: string, modelRef: string | null)
});
}
export async function updateDefaultModel(modelRef: string | null): Promise<AgentsSnapshot> {
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) {