feat(v2): add SSH management, ctx integration, themes, detached mode, auto-updater

SSH session management:
- SshSession struct + ssh_sessions SQLite table in session.rs
- CRUD Tauri commands (ssh_session_list/save/delete) in lib.rs
- SshDialog.svelte (create/edit modal), SshSessionList.svelte (sidebar)
- SSH pane routes to TerminalPane with shell=/usr/bin/ssh + args

ctx context database integration:
- ctx.rs: read-only CtxDb (SQLITE_OPEN_READ_ONLY for ~/.claude-context/context.db)
- 5 Tauri commands (ctx_list_projects/get_context/get_shared/get_summaries/search)
- ContextPane.svelte with project selector, tabs, search
- ctx-bridge.ts adapter

Catppuccin theme flavors (Latte/Frappe/Macchiato/Mocha):
- themes.ts: all 4 palette definitions + buildXtermTheme/applyCssVariables
- theme.svelte.ts: reactive store with SQLite persistence
- SettingsDialog flavor dropdown, TerminalPane theme-aware

Detached pane mode (pop-out windows):
- detach.ts: isDetachedMode/getDetachedConfig from URL params
- App.svelte: conditional rendering of single pane without chrome

Other additions:
- Shiki syntax highlighting (highlight.ts, lazy singleton, 13 languages)
- Tauri auto-updater plugin (tauri-plugin-updater + updater.ts)
- AgentPane markdown rendering with Shiki code highlighting
- New deps: shiki, @tauri-apps/plugin-updater, tauri-plugin-updater
This commit is contained in:
Hibryda 2026-03-06 14:50:00 +01:00
parent 4f2614186d
commit 4db7ccff60
28 changed files with 2992 additions and 51 deletions

254
v2/src/lib/styles/themes.ts Normal file
View file

@ -0,0 +1,254 @@
// Catppuccin theme flavors — https://catppuccin.com/palette
// Each flavor provides CSS custom properties and an xterm.js theme object.
export type CatppuccinFlavor = 'latte' | 'frappe' | 'macchiato' | 'mocha';
export interface CatppuccinPalette {
rosewater: string;
flamingo: string;
pink: string;
mauve: string;
red: string;
maroon: string;
peach: string;
yellow: string;
green: string;
teal: string;
sky: string;
sapphire: string;
blue: string;
lavender: string;
text: string;
subtext1: string;
subtext0: string;
overlay2: string;
overlay1: string;
overlay0: string;
surface2: string;
surface1: string;
surface0: string;
base: string;
mantle: string;
crust: string;
}
export interface XtermTheme {
background: string;
foreground: string;
cursor: string;
cursorAccent: string;
selectionBackground: string;
selectionForeground: string;
black: string;
red: string;
green: string;
yellow: string;
blue: string;
magenta: string;
cyan: string;
white: string;
brightBlack: string;
brightRed: string;
brightGreen: string;
brightYellow: string;
brightBlue: string;
brightMagenta: string;
brightCyan: string;
brightWhite: string;
}
const palettes: Record<CatppuccinFlavor, CatppuccinPalette> = {
latte: {
rosewater: '#dc8a78',
flamingo: '#dd7878',
pink: '#ea76cb',
mauve: '#8839ef',
red: '#d20f39',
maroon: '#e64553',
peach: '#fe640b',
yellow: '#df8e1d',
green: '#40a02b',
teal: '#179299',
sky: '#04a5e5',
sapphire: '#209fb5',
blue: '#1e66f5',
lavender: '#7287fd',
text: '#4c4f69',
subtext1: '#5c5f77',
subtext0: '#6c6f85',
overlay2: '#7c7f93',
overlay1: '#8c8fa1',
overlay0: '#9ca0b0',
surface2: '#acb0be',
surface1: '#bcc0cc',
surface0: '#ccd0da',
base: '#eff1f5',
mantle: '#e6e9ef',
crust: '#dce0e8',
},
frappe: {
rosewater: '#f2d5cf',
flamingo: '#eebebe',
pink: '#f4b8e4',
mauve: '#ca9ee6',
red: '#e78284',
maroon: '#ea999c',
peach: '#ef9f76',
yellow: '#e5c890',
green: '#a6d189',
teal: '#81c8be',
sky: '#99d1db',
sapphire: '#85c1dc',
blue: '#8caaee',
lavender: '#babbf1',
text: '#c6d0f5',
subtext1: '#b5bfe2',
subtext0: '#a5adce',
overlay2: '#949cbb',
overlay1: '#838ba7',
overlay0: '#737994',
surface2: '#626880',
surface1: '#51576d',
surface0: '#414559',
base: '#303446',
mantle: '#292c3c',
crust: '#232634',
},
macchiato: {
rosewater: '#f4dbd6',
flamingo: '#f0c6c6',
pink: '#f5bde6',
mauve: '#c6a0f6',
red: '#ed8796',
maroon: '#ee99a0',
peach: '#f5a97f',
yellow: '#eed49f',
green: '#a6da95',
teal: '#8bd5ca',
sky: '#91d7e3',
sapphire: '#7dc4e4',
blue: '#8aadf4',
lavender: '#b7bdf8',
text: '#cad3f5',
subtext1: '#b8c0e0',
subtext0: '#a5adcb',
overlay2: '#939ab7',
overlay1: '#8087a2',
overlay0: '#6e738d',
surface2: '#5b6078',
surface1: '#494d64',
surface0: '#363a4f',
base: '#24273a',
mantle: '#1e2030',
crust: '#181926',
},
mocha: {
rosewater: '#f5e0dc',
flamingo: '#f2cdcd',
pink: '#f5c2e7',
mauve: '#cba6f7',
red: '#f38ba8',
maroon: '#eba0ac',
peach: '#fab387',
yellow: '#f9e2af',
green: '#a6e3a1',
teal: '#94e2d5',
sky: '#89dceb',
sapphire: '#74c7ec',
blue: '#89b4fa',
lavender: '#b4befe',
text: '#cdd6f4',
subtext1: '#bac2de',
subtext0: '#a6adc8',
overlay2: '#9399b2',
overlay1: '#7f849c',
overlay0: '#6c7086',
surface2: '#585b70',
surface1: '#45475a',
surface0: '#313244',
base: '#1e1e2e',
mantle: '#181825',
crust: '#11111b',
},
};
export function getPalette(flavor: CatppuccinFlavor): CatppuccinPalette {
return palettes[flavor];
}
/** Build xterm.js ITheme from a Catppuccin palette */
export function buildXtermTheme(flavor: CatppuccinFlavor): XtermTheme {
const p = palettes[flavor];
return {
background: p.base,
foreground: p.text,
cursor: p.rosewater,
cursorAccent: p.base,
selectionBackground: p.surface1,
selectionForeground: p.text,
black: p.surface1,
red: p.red,
green: p.green,
yellow: p.yellow,
blue: p.blue,
magenta: p.pink,
cyan: p.teal,
white: p.subtext1,
brightBlack: p.surface2,
brightRed: p.red,
brightGreen: p.green,
brightYellow: p.yellow,
brightBlue: p.blue,
brightMagenta: p.pink,
brightCyan: p.teal,
brightWhite: p.subtext0,
};
}
/** CSS custom property names mapped to palette keys */
const CSS_VAR_MAP: [string, keyof CatppuccinPalette][] = [
['--ctp-rosewater', 'rosewater'],
['--ctp-flamingo', 'flamingo'],
['--ctp-pink', 'pink'],
['--ctp-mauve', 'mauve'],
['--ctp-red', 'red'],
['--ctp-maroon', 'maroon'],
['--ctp-peach', 'peach'],
['--ctp-yellow', 'yellow'],
['--ctp-green', 'green'],
['--ctp-teal', 'teal'],
['--ctp-sky', 'sky'],
['--ctp-sapphire', 'sapphire'],
['--ctp-blue', 'blue'],
['--ctp-lavender', 'lavender'],
['--ctp-text', 'text'],
['--ctp-subtext1', 'subtext1'],
['--ctp-subtext0', 'subtext0'],
['--ctp-overlay2', 'overlay2'],
['--ctp-overlay1', 'overlay1'],
['--ctp-overlay0', 'overlay0'],
['--ctp-surface2', 'surface2'],
['--ctp-surface1', 'surface1'],
['--ctp-surface0', 'surface0'],
['--ctp-base', 'base'],
['--ctp-mantle', 'mantle'],
['--ctp-crust', 'crust'],
];
/** Apply a Catppuccin flavor's CSS custom properties to document root */
export function applyCssVariables(flavor: CatppuccinFlavor): void {
const p = palettes[flavor];
const style = document.documentElement.style;
for (const [varName, key] of CSS_VAR_MAP) {
style.setProperty(varName, p[key]);
}
}
export const FLAVOR_LABELS: Record<CatppuccinFlavor, string> = {
latte: 'Latte (Light)',
frappe: 'Frappe',
macchiato: 'Macchiato',
mocha: 'Mocha (Default)',
};
export const ALL_FLAVORS: CatppuccinFlavor[] = ['latte', 'frappe', 'macchiato', 'mocha'];