mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-07 13:02:07 +00:00
Bring apps/desktop and ui-tui to a clean state for typecheck, eslint,
and prettier:
- Run prettier across both trees (printWidth/wrap drift; prettier is not
CI-enforced for these JS projects, so main had accumulated drift).
- Apply eslint --fix for padding-line-between-statements and perfectionist
import/export sorting.
- Manual fixes for non-auto-fixable rules:
- remove unused node:net import in electron/main.cjs (uses Electron net)
- replace inline `typeof import(...)` annotations with top-level
`import type * as EnvModule` in two ui-tui test files
- scoped eslint-disable no-control-regex on intentional sentinel/ANSI
regexes (mathUnicode.ts, text.ts)
- resolve react-hooks/exhaustive-deps per-case: correct swapped/missing
deps, collapse redundant session.* members, and justified disables on
settings mount-only data-load effects to preserve run-once behavior
No behavior changes; test pass/fail counts are unchanged from the main
baseline.
92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
/**
|
|
* Install desktop themes from external sources.
|
|
*
|
|
* The heavy lifting (network + .vsix unzip) lives in the Electron main process
|
|
* (`electron/vscode-marketplace.cjs`), reached via `window.hermesDesktop.themes`.
|
|
* Main hands back the raw theme JSON; we parse + convert + persist here so the
|
|
* conversion stays in one unit-testable place.
|
|
*/
|
|
|
|
import type { DesktopMarketplaceThemeResult } from '@/global'
|
|
|
|
import type { DesktopTheme } from './types'
|
|
import { installUserTheme } from './user-themes'
|
|
import { convertVscodeColorTheme, parseVscodeTheme, vscodeThemeSlug } from './vscode'
|
|
|
|
/** A `publisher.extension` id, e.g. `dracula-theme.theme-dracula`. */
|
|
export const MARKETPLACE_ID_RE = /^[\w-]+\.[\w-]+$/
|
|
|
|
/** Parse + convert + persist a pasted VS Code theme JSON. */
|
|
export function installVscodeThemeFromText(text: string, opts?: { label?: string; source?: string }): DesktopTheme {
|
|
const raw = parseVscodeTheme(text)
|
|
const { theme } = convertVscodeColorTheme(raw, opts)
|
|
|
|
return installUserTheme(theme)
|
|
}
|
|
|
|
/**
|
|
* Fold every color theme an extension contributes into ONE desktop theme family.
|
|
*
|
|
* Many extensions ship a light *and* a dark variant (GitHub, Solarized, Winter
|
|
* is Coming…). Rather than install them as separate flat entries — which made
|
|
* the light/dark toggle a no-op and let "install in dark mode" land on the light
|
|
* variant — we map the first light variant onto `colors` and the first dark
|
|
* variant onto `darkColors`. The result is a single picker entry whose light/dark
|
|
* toggle switches between the real variants. A single-variant extension fills
|
|
* both slots with its one palette (the toggle is a no-op, as it must be).
|
|
*/
|
|
export function buildThemeFromMarketplace(result: DesktopMarketplaceThemeResult): DesktopTheme {
|
|
if (!result.themes.length) {
|
|
throw new Error(`"${result.extensionId}" does not contribute any color themes.`)
|
|
}
|
|
|
|
const variants = result.themes.map(file => {
|
|
const raw = parseVscodeTheme(file.contents)
|
|
const label = file.label || raw.name || result.displayName
|
|
const { mode, theme } = convertVscodeColorTheme(raw, { label, source: result.extensionId })
|
|
|
|
return { mode, palette: theme.colors, terminal: theme.terminal }
|
|
})
|
|
|
|
const fallback = variants[0]
|
|
const light = variants.find(variant => variant.mode === 'light') ?? fallback
|
|
const dark = variants.find(variant => variant.mode === 'dark') ?? fallback
|
|
|
|
// The terminal ANSI palette tracks the painted variant the same way colors do
|
|
// (light → terminal, dark → darkTerminal); each falls back to the other so a
|
|
// single-variant import still themes the terminal in both modes.
|
|
const terminal = light.terminal ?? dark.terminal
|
|
const darkTerminal = dark.terminal ?? light.terminal
|
|
|
|
return {
|
|
name: vscodeThemeSlug(result.displayName),
|
|
label: result.displayName,
|
|
description: `VS Code · ${result.extensionId}`,
|
|
colors: light.palette,
|
|
darkColors: dark.palette,
|
|
...(terminal ? { terminal } : {}),
|
|
...(darkTerminal ? { darkTerminal } : {})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Download a Marketplace extension and install the theme family it contributes
|
|
* (see `buildThemeFromMarketplace`). Returns the single installed theme.
|
|
*/
|
|
export async function installVscodeThemeFromMarketplace(id: string): Promise<DesktopTheme> {
|
|
const trimmed = id.trim()
|
|
|
|
if (!MARKETPLACE_ID_RE.test(trimmed)) {
|
|
throw new Error('Expected a Marketplace id like "publisher.extension".')
|
|
}
|
|
|
|
const api = window.hermesDesktop?.themes
|
|
|
|
if (!api?.fetchMarketplace) {
|
|
throw new Error('Marketplace install is only available in the desktop app.')
|
|
}
|
|
|
|
const result = await api.fetchMarketplace(trimmed)
|
|
|
|
return installUserTheme(buildThemeFromMarketplace(result))
|
|
}
|