feat(desktop): reconcile live tool events, polish thread chrome, harden boot
- chat-messages: match tool rows by overlapping query/context/preview values so preview-first `tool.progress` rows reliably adopt later stable-id `tool.start` payloads instead of spawning ghost rows or mis-merging parallel same-name calls; preserve prior args/result across phases. - tui_gateway: emit full args + parsed result on `tool.start` / `tool.complete`, drop redundant `tool.started` re-emit from `tool.progress`. - electron/main: prefer SOURCE_REPO_ROOT before PATH `hermes` in dev so local backend edits actually run; split hardening helpers into `electron/hardening.cjs` with tests. - thread/tool UI: one-shot enter animation keyed by stable ids, braille spinner for running rows, Cursor-like disclosure rows, drill-down + duration/count formatting via new tool-fallback-model. - composer: extract `text-utils`, drop liquid-glass overrides. - right-rail: split preview-pane into preview-console / preview-file. - runtime: incremental external-store runtime + runtime-readiness gate; onboarding store + tests; route-resume hook test. - regression tests for live tool reconciliation (parallel tools, id-less progress, preview-first rows, structured args/results).
This commit is contained in:
@@ -60,6 +60,7 @@ export function AppShell({
|
||||
const viewportFullscreen = useSyncExternalStore(subscribeWindowSize, viewportIsFullscreen, () => false)
|
||||
const isFullscreen = Boolean(connection?.isFullscreen) || viewportFullscreen
|
||||
const titlebarControls = titlebarControlsPosition(connection?.windowButtonPosition, isFullscreen)
|
||||
|
||||
const titlebarContentInset = sidebarOpen
|
||||
? 0
|
||||
: titlebarControls.left + TITLEBAR_HEIGHT + Math.round(TITLEBAR_HEIGHT / 2)
|
||||
|
||||
@@ -123,8 +123,9 @@ export function useStatusbarItems({
|
||||
const sha = updateStatus?.currentSha?.slice(0, 7) ?? null
|
||||
const behind = updateStatus?.behind ?? 0
|
||||
const applying = updateApply.applying || updateApply.stage === 'restart'
|
||||
const base = appVersion ? `v${appVersion}` : sha ?? 'unknown'
|
||||
const base = appVersion ? `v${appVersion}` : (sha ?? 'unknown')
|
||||
const behindHint = !applying && behind > 0 ? ` (+${behind})` : ''
|
||||
|
||||
const label = applying
|
||||
? updateApply.stage === 'restart'
|
||||
? `${base} · restart`
|
||||
|
||||
@@ -110,37 +110,37 @@ function StatusbarItemView({ item, navigate }: { item: StatusbarItem; navigate:
|
||||
: (item.menuItems ?? [])
|
||||
.filter(menuItem => !menuItem.hidden)
|
||||
.map(menuItem => (
|
||||
<DropdownMenuItem
|
||||
className={cn('gap-2 text-foreground focus:bg-accent [&_svg]:size-4', menuItem.className)}
|
||||
disabled={menuItem.disabled}
|
||||
key={menuItem.id}
|
||||
onSelect={() => {
|
||||
if (menuItem.to) {
|
||||
navigate(menuItem.to)
|
||||
}
|
||||
<DropdownMenuItem
|
||||
className={cn('gap-2 text-foreground focus:bg-accent [&_svg]:size-4', menuItem.className)}
|
||||
disabled={menuItem.disabled}
|
||||
key={menuItem.id}
|
||||
onSelect={() => {
|
||||
if (menuItem.to) {
|
||||
navigate(menuItem.to)
|
||||
}
|
||||
|
||||
menuItem.onSelect?.()
|
||||
}}
|
||||
>
|
||||
{menuItem.href ? (
|
||||
<a
|
||||
className="inline-flex w-full items-center gap-2"
|
||||
href={menuItem.href}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
title={menuItem.title ?? menuItem.label}
|
||||
menuItem.onSelect?.()
|
||||
}}
|
||||
>
|
||||
{menuItem.icon}
|
||||
<span className="truncate">{menuItem.label}</span>
|
||||
</a>
|
||||
) : (
|
||||
<>
|
||||
{menuItem.icon}
|
||||
<span className="truncate">{menuItem.label}</span>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{menuItem.href ? (
|
||||
<a
|
||||
className="inline-flex w-full items-center gap-2"
|
||||
href={menuItem.href}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
title={menuItem.title ?? menuItem.label}
|
||||
>
|
||||
{menuItem.icon}
|
||||
<span className="truncate">{menuItem.label}</span>
|
||||
</a>
|
||||
) : (
|
||||
<>
|
||||
{menuItem.icon}
|
||||
<span className="truncate">{menuItem.label}</span>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user