style(desktop): prettier + eslint pass

Repo-wide `npm run fmt` + `eslint --fix`; also drop two unused destructured
params in titlebar-overlay-width.cjs so the lint run is clean.
This commit is contained in:
Brooklyn Nicholson 2026-06-28 21:04:43 -05:00
parent 317b94871b
commit 9f02eea1d2
16 changed files with 74 additions and 64 deletions

View file

@ -2266,9 +2266,7 @@ async function handOffWindowsBootstrapRecovery(reason) {
// --repair (full venv recreate) and drove reinstall loops. The venv interpreter
// and the bootstrap-complete marker are present earlier and are better signals.
const haveRealInstall =
fileExists(venvPython) ||
fileExists(venvHermes) ||
fileExists(path.join(updateRoot, '.hermes-bootstrap-complete'))
fileExists(venvPython) || fileExists(venvHermes) || fileExists(path.join(updateRoot, '.hermes-bootstrap-complete'))
const updaterArgs = haveRealInstall ? ['--update', '--branch', branch] : ['--repair', '--branch', branch]
await releaseBackendLockForUpdate(updateRoot)

View file

@ -14,9 +14,9 @@ const OVERLAY_FALLBACK_WIDTH = 144
* the Electron overlay (Windows, WSLg, and plain Linux KDE/GNOME), so they all
* reserve the fallback width.
*
* @param {{ isWindows?: boolean, isWsl?: boolean, isMac?: boolean }} opts
* @param {{ isMac?: boolean }} opts
*/
function nativeOverlayWidth({ isWindows = false, isWsl = false, isMac = false } = {}) {
function nativeOverlayWidth({ isMac = false } = {}) {
if (isMac) return 0
return OVERLAY_FALLBACK_WIDTH
}

View file

@ -43,21 +43,13 @@ test('findOnPath tries PATHEXT extensions before the bare (empty) name on Window
test('Windows bootstrap recovery chooses --update when any real-install signal is present', () => {
const source = readMain()
assert.match(source, /const haveRealInstall =/, 'recovery must compute haveRealInstall')
assert.match(
source,
/fileExists\(venvPython\)/,
'recovery must accept the venv interpreter as a real-install signal'
)
assert.match(source, /fileExists\(venvPython\)/, 'recovery must accept the venv interpreter as a real-install signal')
assert.match(
source,
/\.hermes-bootstrap-complete/,
'recovery must accept the bootstrap-complete marker as a real-install signal'
)
assert.match(
source,
/updaterArgs = haveRealInstall \? \['--update'/,
'updaterArgs must gate on haveRealInstall'
)
assert.match(source, /updaterArgs = haveRealInstall \? \['--update'/, 'updaterArgs must gate on haveRealInstall')
// The old too-narrow check (only venv\Scripts\hermes.exe) must not return.
assert.doesNotMatch(
source,

View file

@ -1149,8 +1149,7 @@ export function ChatSidebar({
const showSessionSkeletons = sessionsLoading && sortedSessions.length === 0
const showSessionSections =
showSessionSkeletons || sortedSessions.length > 0 || projectModel.length > 0
const showSessionSections = showSessionSkeletons || sortedSessions.length > 0 || projectModel.length > 0
// Each reorderable list reports its OWN new id order; persisting is a direct,
// typed write — no id-prefix sniffing to figure out which level moved.
@ -1628,12 +1627,7 @@ function SidebarBlankState({ onNewProject }: { onNewProject: () => void }) {
<div className="flex flex-col items-center gap-2">
<Codicon className="text-(--ui-text-quaternary)" name="root-folder" size="1.25rem" />
<p className="text-xs text-(--ui-text-tertiary)">{s.noSessions}</p>
<Button
className="mt-0.5 text-(--ui-text-secondary)"
onClick={onNewProject}
size="sm"
variant="ghost"
>
<Button className="mt-0.5 text-(--ui-text-secondary)" onClick={onNewProject} size="sm" variant="ghost">
<Codicon name="add" size="0.75rem" />
{s.projects.newButton}
</Button>

View file

@ -149,10 +149,7 @@ export function ProjectDialog() {
return (
<Dialog onOpenChange={onOpenChange} open={open}>
<DialogContent
className="max-w-md"
onInteractOutside={event => event.preventDefault()}
>
<DialogContent className="max-w-md" onInteractOutside={event => event.preventDefault()}>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
{mode === 'create' && <DialogDescription>{p.createDesc}</DialogDescription>}

View file

@ -596,7 +596,6 @@ function CronJobDetail({
)
}
function formatRunTime(seconds?: null | number): string {
if (!seconds) {
return '—'

View file

@ -2,12 +2,7 @@ import type { ReactNode } from 'react'
import { Button } from '@/components/ui/button'
import { Codicon } from '@/components/ui/codicon'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { SearchField } from '@/components/ui/search-field'
import { translateNow } from '@/i18n'
import { cn } from '@/lib/utils'
@ -146,7 +141,17 @@ interface PanelListRowProps {
// A row is a container (not a <button>) so it can host both the select target
// and a kebab menu without nesting interactive elements. Hover/active bg lives
// on the wrapper so the whole row highlights as one.
export function PanelListRow({ active, dotClassName, icon, lead, menu, meta, onSelect, rowKey, title }: PanelListRowProps) {
export function PanelListRow({
active,
dotClassName,
icon,
lead,
menu,
meta,
onSelect,
rowKey,
title
}: PanelListRowProps) {
return (
<div
className={cn(
@ -162,11 +167,12 @@ export function PanelListRow({ active, dotClassName, icon, lead, menu, meta, onS
onClick={onSelect}
type="button"
>
{lead ?? (dotClassName ? (
<span aria-hidden="true" className={cn('size-1.5 shrink-0 rounded-full', dotClassName)} />
) : icon ? (
<Codicon className="shrink-0 text-muted-foreground/55" name={icon} size="0.85rem" />
) : null)}
{lead ??
(dotClassName ? (
<span aria-hidden="true" className={cn('size-1.5 shrink-0 rounded-full', dotClassName)} />
) : icon ? (
<Codicon className="shrink-0 text-muted-foreground/55" name={icon} size="0.85rem" />
) : null)}
<span className="min-w-0 flex-1 truncate font-medium text-foreground/85">{title}</span>
</button>
{meta ? <span className="shrink-0 pr-2 text-[0.62rem] tabular-nums text-muted-foreground/45">{meta}</span> : null}
@ -321,7 +327,15 @@ export function PanelPill({ children, tone = 'muted' }: { children: ReactNode; t
// Self-describing centered "+" that sits as the LAST item in a PanelList. The
// label rides aria/title only — no visible text.
export function PanelAddButton({ icon = 'add', label, onClick }: { icon?: string; label: string; onClick: () => void }) {
export function PanelAddButton({
icon = 'add',
label,
onClick
}: {
icon?: string
label: string
onClick: () => void
}) {
return (
<Button
aria-label={label}

View file

@ -295,7 +295,13 @@ function ProfileRow({
return (
<PanelListRow
active={active}
lead={<ProfileGlyph color={resolveProfileColor(profile.name, colors)} isDefault={profile.is_default} name={profile.name} />}
lead={
<ProfileGlyph
color={resolveProfileColor(profile.name, colors)}
isDefault={profile.is_default}
name={profile.name}
/>
}
menu={menu}
onSelect={onSelect}
rowKey={profile.name}
@ -313,7 +319,12 @@ function ProfileGlyph({ color, isDefault, name }: { color: null | string; isDefa
}
const hue = color ?? 'var(--ui-text-quaternary)'
const initial = name.replace(/[^a-z0-9]/gi, '').charAt(0).toUpperCase() || '?'
const initial =
name
.replace(/[^a-z0-9]/gi, '')
.charAt(0)
.toUpperCase() || '?'
return (
<span
@ -367,7 +378,6 @@ function ProfileDetail({ profile }: { profile: ProfileInfo }) {
)
}
function SoulEditor({ profileName }: { profileName: string }) {
const { t } = useI18n()
const p = t.profiles

View file

@ -685,7 +685,9 @@ export function useSessionActions({
if (warmHit) {
const cachedRuntimeId = warmHit.runtimeId
const cachedState = warmHit.state
const stored = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId)) ?? storedForProfile
const stored =
$sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId)) ?? storedForProfile
const cachedViewState =
!cachedState.model && stored?.model != null
@ -752,7 +754,10 @@ export function useSessionActions({
setSelectedStoredSessionId(storedSessionId)
selectedStoredSessionIdRef.current = storedSessionId
setSessionStartedAt(Date.now())
const stored = $sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId)) ?? storedForProfile
const stored =
$sessions.get().find(session => sessionMatchesStoredId(session, storedSessionId)) ?? storedForProfile
applyStoredSessionPreviewRuntimeInfo(stored)
if (stored) {

View file

@ -191,9 +191,7 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
// MoA reference/aggregator slots must never be the moa virtual provider —
// that would create a recursive MoA tree (the backend rejects it on save).
// Hide it from the slot selectors so it isn't offered as a dead choice.
const moaSlotProviderOptions = providerOptions.filter(
provider => (provider.slug || '').toLowerCase() !== 'moa'
)
const moaSlotProviderOptions = providerOptions.filter(provider => (provider.slug || '').toLowerCase() !== 'moa')
const selectedProviderRow = useMemo(
() => providers.find(provider => provider.slug === selectedProvider),
@ -783,6 +781,7 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
...moa,
default_preset: selectedMoaPreset || moa.default_preset
}
void saveMoa(next)
}}
size="sm"
@ -800,12 +799,14 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
const presets = { ...moa.presets }
delete presets[selectedMoaPreset]
const fallback = Object.keys(presets)[0]
const next: MoaConfigResponse = {
...moa,
presets,
default_preset: moa.default_preset === selectedMoaPreset ? fallback : moa.default_preset,
active_preset: moa.active_preset === selectedMoaPreset ? '' : moa.active_preset
}
setSelectedMoaPreset(Object.keys(moa.presets).find(name => name !== selectedMoaPreset) || '')
void saveMoa(next)
}}
@ -824,6 +825,7 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
disabled={!newMoaPresetName.trim() || !!moa.presets[newMoaPresetName.trim()] || applying}
onClick={() => {
const name = newMoaPresetName.trim()
const next: MoaConfigResponse = {
...moa,
presets: {
@ -831,6 +833,7 @@ export function ModelSettings({ onMainModelChanged }: ModelSettingsProps) {
[name]: { ...currentMoaPreset, reference_models: [...currentMoaPreset.reference_models] }
}
}
setSelectedMoaPreset(name)
setNewMoaPresetName('')
void saveMoa(next)

View file

@ -9,10 +9,7 @@ describe('withActive', () => {
const curated = ['hermes-4', 'hermes-4-mini']
it('prepends a custom model missing from the curated list', () => {
expect(withActive(curated, 'anthropic/claude-opus-4.7')).toEqual([
'anthropic/claude-opus-4.7',
...curated
])
expect(withActive(curated, 'anthropic/claude-opus-4.7')).toEqual(['anthropic/claude-opus-4.7', ...curated])
})
it('leaves the list untouched when the active model is already curated', () => {

View file

@ -235,6 +235,7 @@ export function useStatusbarItems({
const applying = backendUpdateApply.applying || backendUpdateApply.stage === 'restart'
const base = copy.backendLabel(backendVersion ?? copy.unknown)
const behindHint =
!applying && behind > 0 ? ` (+${behind})` : !applying && updateAvailable ? ` (${copy.update})` : ''

View file

@ -280,7 +280,11 @@ function ClarifyToolPending({ args }: ToolCallMessagePartProps) {
if (loading) {
return (
<ClarifyShell aria-label={copy.loadingQuestion} className="grid min-h-12 place-items-center px-2.5 py-3" role="status">
<ClarifyShell
aria-label={copy.loadingQuestion}
className="grid min-h-12 place-items-center px-2.5 py-3"
role="status"
>
<Loader2 aria-hidden className="size-4 animate-spin text-(--ui-text-tertiary)" />
</ClarifyShell>
)

View file

@ -1540,10 +1540,7 @@ function dynamicTitle(
}
const failed =
part.isError ||
result.success === false ||
result.ok === false ||
Boolean(firstStringField(result, ['error']))
part.isError || result.success === false || result.ok === false || Boolean(firstStringField(result, ['error']))
if (failed) {
const failAction = translateNow('assistant.tool.actions.failedToOpen')
@ -1556,10 +1553,7 @@ function dynamicTitle(
const action = verb(translateNow('assistant.tool.actions.opening'), translateNow('assistant.tool.actions.opened'))
return titledAction(
action,
translateNow('assistant.tool.titleTemplates.actionTarget', action, hostnameOf(url))
)
return titledAction(action, translateNow('assistant.tool.titleTemplates.actionTarget', action, hostnameOf(url)))
}
if (part.toolName === 'web_search') {

View file

@ -279,7 +279,8 @@ export const zhHant = defineLocale({
translucencyTitle: '視窗透明',
translucencyDesc: '讓整個視窗透出桌面。僅支援 macOS 與 Windows。',
embedsTitle: '內嵌預覽',
embedsDesc: '豐富預覽會從第三方網站YouTube、X 等)載入。詢問會在你允許前顯示佔位符;一律會自動載入;關閉則保留純連結。',
embedsDesc:
'豐富預覽會從第三方網站YouTube、X 等)載入。詢問會在你允許前顯示佔位符;一律會自動載入;關閉則保留純連結。',
embedsAsk: '詢問',
embedsAlways: '一律',
embedsOff: '關閉',

View file

@ -370,7 +370,8 @@ export const zh: Translations = {
translucencyTitle: '窗口透明',
translucencyDesc: '让整个窗口透出桌面。仅支持 macOS 和 Windows。',
embedsTitle: '内嵌预览',
embedsDesc: '富预览会从第三方网站YouTube、X 等)加载。询问会在你允许前显示占位符;总是会自动加载;关闭则保留纯链接。',
embedsDesc:
'富预览会从第三方网站YouTube、X 等)加载。询问会在你允许前显示占位符;总是会自动加载;关闭则保留纯链接。',
embedsAsk: '询问',
embedsAlways: '总是',
embedsOff: '关闭',