Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions apps/desktop/src/lib/trpc/routers/settings/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { db } from "main/lib/db";
import type { TerminalPreset } from "main/lib/db/schemas";
import { nanoid } from "nanoid";
import { DEFAULT_RINGTONE_ID, RINGTONES } from "shared/ringtones";
import { z } from "zod";
Expand All @@ -7,20 +8,67 @@ import { publicProcedure, router } from "../..";
/** Valid ringtone IDs for validation */
const VALID_RINGTONE_IDS = RINGTONES.map((r) => r.id);

/** Default presets to load when no presets exist */
const DEFAULT_PRESETS: Omit<TerminalPreset, "id">[] = [
{
name: "codex",
description: "Danger mode: All permissions auto-approved",
cwd: "",
commands: [
'codex -c model_reasoning_effort="high" --ask-for-approval never --sandbox danger-full-access -c model_reasoning_summary="detailed" -c model_supports_reasoning_summaries=true',
],
},
{
name: "claude",
description: "Danger mode: All permissions auto-approved",
cwd: "",
commands: ["claude --dangerously-skip-permissions"],
},
];
Comment thread
Kitenite marked this conversation as resolved.

export const createSettingsRouter = () => {
return router({
getLastUsedApp: publicProcedure.query(() => {
return db.data.settings.lastUsedApp ?? "cursor";
}),

getTerminalPresets: publicProcedure.query(() => {
return db.data.settings.terminalPresets ?? [];
getTerminalPresets: publicProcedure.query(async () => {
const { terminalPresets, terminalPresetsInitialized } = db.data.settings;

// Handle first-time initialization
if (!terminalPresetsInitialized) {
// If user already has presets (from before the flag existed), preserve them
if (terminalPresets && terminalPresets.length > 0) {
await db.update((data) => {
data.settings.terminalPresetsInitialized = true;
});
return terminalPresets;
}

// No existing presets - seed with defaults
const defaultPresetsWithIds: TerminalPreset[] = DEFAULT_PRESETS.map(
(preset) => ({
id: nanoid(),
...preset,
}),
);

await db.update((data) => {
data.settings.terminalPresets = defaultPresetsWithIds;
data.settings.terminalPresetsInitialized = true;
});

return defaultPresetsWithIds;
}

return terminalPresets ?? [];
}),

createTerminalPreset: publicProcedure
.input(
z.object({
name: z.string(),
description: z.string().optional(),
cwd: z.string(),
commands: z.array(z.string()),
}),
Expand All @@ -47,6 +95,7 @@ export const createSettingsRouter = () => {
id: z.string(),
patch: z.object({
name: z.string().optional(),
description: z.string().optional(),
cwd: z.string().optional(),
commands: z.array(z.string()).optional(),
}),
Expand All @@ -62,6 +111,8 @@ export const createSettingsRouter = () => {
}

if (input.patch.name !== undefined) preset.name = input.patch.name;
if (input.patch.description !== undefined)
preset.description = input.patch.description;
if (input.patch.cwd !== undefined) preset.cwd = input.patch.cwd;
if (input.patch.commands !== undefined)
preset.commands = input.patch.commands;
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/main/lib/db/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export type ExternalApp = (typeof EXTERNAL_APPS)[number];
export interface TerminalPreset {
id: string;
name: string;
description?: string;
cwd: string;
commands: string[];
}
Expand All @@ -107,6 +108,7 @@ export interface Settings {
lastActiveWorkspaceId?: string;
lastUsedApp?: ExternalApp;
terminalPresets?: TerminalPreset[];
terminalPresetsInitialized?: boolean;
selectedRingtoneId?: string;
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions apps/desktop/src/renderer/assets/app-icons/preset-icons/codex.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions apps/desktop/src/renderer/assets/app-icons/preset-icons/cursor.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions apps/desktop/src/renderer/assets/app-icons/preset-icons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useThemeStore } from "renderer/stores/theme/store";
import claudeIcon from "./claude.svg";
import codexIcon from "./codex.svg";
import codexWhiteIcon from "./codex-white.svg";
import cursorIcon from "./cursor.svg";
import geminiIcon from "./gemini.svg";

interface PresetIconSet {
light: string;
dark: string;
}

const PRESET_ICONS: Record<string, PresetIconSet> = {
claude: { light: claudeIcon, dark: claudeIcon },
codex: { light: codexIcon, dark: codexWhiteIcon },
gemini: { light: geminiIcon, dark: geminiIcon },
"cursor-agent": { light: cursorIcon, dark: cursorIcon },
};

export function getPresetIcon(
presetName: string,
isDark: boolean,
): string | undefined {
const normalizedName = presetName.toLowerCase().trim();
const iconSet = PRESET_ICONS[normalizedName];
if (!iconSet) return undefined;
return isDark ? iconSet.dark : iconSet.light;
}

export function usePresetIcon(presetName: string): string | undefined {
const activeTheme = useThemeStore((state) => state.activeTheme);
const isDark = activeTheme?.type === "dark";
return getPresetIcon(presetName, isDark);
}

export function useIsDarkTheme(): boolean {
const activeTheme = useThemeStore((state) => state.activeTheme);
return activeTheme?.type === "dark";
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function PresetCell({
return (
<Input
variant="ghost"
value={value as string}
value={(value as string) ?? ""}
onChange={(e) => onChange(rowIndex, column.key, e.target.value)}
onBlur={() => onBlur(rowIndex, column.key)}
className={`h-8 px-2 text-sm w-full min-w-0 truncate ${column.mono ? "font-mono" : ""}`}
Expand Down
Loading
Loading