feat(deskclaw): rebrand + vibe presets + chat model picker
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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}`
|
||||
);
|
||||
|
||||
@@ -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;',
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user