Skip to content
Closed
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
16 changes: 7 additions & 9 deletions apps/desktop/src/app/chat/perf-probe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,13 @@ if (typeof window !== 'undefined' && !window.__PERF_DRIVE__) {
let baseline: ReturnType<typeof $messages.get> | null = null
let activeHandle: SyntheticDriverHandle | null = null

let rightPaneBaseline:
| null
| {
activeTerminalId: null | string
cwd: string
repoStatusByCwd: ReturnType<typeof $repoStatusByCwd.get>
takeover: boolean
terminals: readonly TerminalEntry[]
} = null
let rightPaneBaseline: null | {
activeTerminalId: null | string
cwd: string
repoStatusByCwd: ReturnType<typeof $repoStatusByCwd.get>
takeover: boolean
terminals: readonly TerminalEntry[]
} = null

const stop = () => {
activeHandle = null
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/app/chat/session-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,12 @@ function TileChat({
(url: string) => addContextRefAttachment(`@url:${formatRefValue(url)}`, url),
[addContextRefAttachment]
)

const onPasteClipboardImage = useCallback(
(opts?: { silent?: boolean }) => pasteClipboardImage(opts),
[pasteClipboardImage]
)

const onPickFiles = useCallback(() => void pickContextPaths('file'), [pickContextPaths])
const onPickFolders = useCallback(() => void pickContextPaths('folder'), [pickContextPaths])
const onPickImages = useCallback(() => void pickImages(), [pickImages])
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src/app/chat/sidebar/sessions-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ export function SidebarSessionsSection({
(items: SessionInfo[]) => {
const entries = flattenSessionsWithBranches(items)

return (dateGrouped ? groupEntriesByRecency(entries) : toSessionRows(entries)).map(row => renderListRow(row, false))
return (dateGrouped ? groupEntriesByRecency(entries) : toSessionRows(entries)).map(row =>
renderListRow(row, false)
)
},
[dateGrouped, renderListRow]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ export function useMessageStream({
// stays as the fallback.
const writeCost = performance.now() - startedAt
lastFlushCostRef.current = writeCost

// At most one measurement rAF may be pending: only the newest flush's
// measurement matters (the guard below discards stale frames), and a
// hidden renderer parks rAF callbacks — without cancellation a long
Expand All @@ -295,8 +296,10 @@ export function useMessageStream({
if (measureRafRef.current !== null) {
window.cancelAnimationFrame(measureRafRef.current)
}

measureRafRef.current = window.requestAnimationFrame(frameStart => {
measureRafRef.current = null

// A newer flush already started; its own measurement wins.
if (lastFlushAtRef.current !== startedAt) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ describe('reconcileResumeMessages — structural parts on a mid-turn switch', ()

expect(assistant.parts.some(part => part.type === 'reasoning')).toBe(true)
expect(assistant.parts.some(part => part.type === 'tool-call')).toBe(true)
expect(assistant.parts.filter(part => part.type === 'text').map(part => ('text' in part ? part.text : ''))).toEqual([
'partial'
])
expect(assistant.parts.filter(part => part.type === 'text').map(part => ('text' in part ? part.text : ''))).toEqual(
['partial']
)
})

it('does not graft historical structure onto a live text-only row after compression rewrote ordinals', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,7 @@ describe('preserveLocalPendingTurnMessages', () => {
'does not duplicate the optimistic %s turn when the persisted turn carries its directive',
kind => {
const ref = `@${kind}:X`

const previous = [
msg('1-user', 'user', 'first'),
msg('2-assistant', 'assistant', 'first answer'),
Expand Down Expand Up @@ -771,6 +772,7 @@ describe('preserveLocalPendingTurnMessages', () => {

it('does not duplicate a turn with multiple CRLF directives and Unicode payloads', () => {
const refs = ['@file:`資料/über notes.md`', '@url:`https://example.com/café?q=✓`']

const previous = [
msg('1-user', 'user', 'first'),
msg('2-assistant', 'assistant', 'first answer'),
Expand Down Expand Up @@ -1153,9 +1155,9 @@ describe('appendLiveSessionProjection', () => {
expect(assistants[0].parts.some(part => part.type === 'reasoning')).toBe(true)
expect(assistants[0].parts.some(part => part.type === 'tool-call')).toBe(true)
// Answer text stays the structured row's text, not the dump.
expect(assistants[0].parts.filter(part => part.type === 'text').map(part => ('text' in part ? part.text : ''))).toEqual([
'partial'
])
expect(
assistants[0].parts.filter(part => part.type === 'text').map(part => ('text' in part ? part.text : ''))
).toEqual(['partial'])
})

it('still projects inflight when only a completed historical tool reply has structure', () => {
Expand Down
14 changes: 9 additions & 5 deletions apps/desktop/src/components/pet/floating-pet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export function FloatingPet() {

if (hasPetSpriteForMeta(current, meta)) {
const merged = mergePetInfoMeta(current, meta)

if (merged !== current) {
setPetInfo(merged)
}
Expand Down Expand Up @@ -214,11 +215,14 @@ export function FloatingPet() {
// so no timer. Legacy backend: the historical poll.
const timer = changeEventsAvailable
? null
: window.setInterval(() => {
if (document.visibilityState === 'visible') {
void pull()
}
}, active ? PET_ACTIVE_REFRESH_MS : PET_POLL_MS)
: window.setInterval(
() => {
if (document.visibilityState === 'visible') {
void pull()
}
},
active ? PET_ACTIVE_REFRESH_MS : PET_POLL_MS
)

return () => {
cancelled = true
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/components/ui/status-pulse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const beat = () => {
for (const subscriber of pulseSubscribers) {
subscriber.play()
}

sharedTimer = window.setTimeout(beat, PULSE_PERIOD_MS)
}

Expand All @@ -46,6 +47,7 @@ const handleSharedPauseChange = () => {
for (const subscriber of pulseSubscribers) {
subscriber.cancel()
}

return
}

Expand Down
6 changes: 1 addition & 5 deletions apps/desktop/src/debug/right-pane-events.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
export type RightPanePerfEvent =
| 'project-tree-render'
| 'project-tree-row-render'
| 'terminal-fit-active'
| 'terminal-fit-hidden'
| 'terminal-measure'
'project-tree-render' | 'project-tree-row-render' | 'terminal-fit-active' | 'terminal-fit-hidden' | 'terminal-measure'
Comment on lines 1 to +2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Union type collapsed onto one line exceeds the usual readability threshold

RightPanePerfEvent is now a single 120-char union line instead of the leading-pipe multi-line form. Purely cosmetic and semantically identical, but adding a sixth member will re-wrap the whole declaration, producing noisy diffs. Same shape appears in the reformatted cast at ui-tui/src/__tests__/scrollBoxRendererBounds.test.ts:385-386.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


export interface RightPanePerfSnapshot {
counts: Record<RightPanePerfEvent, number>
Expand Down
4 changes: 1 addition & 3 deletions apps/desktop/src/debug/right-pane-probe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ if (typeof window !== 'undefined' && !window.__RIGHT_PANE_PERF__) {
},
snapshot: (): RightPanePerfSnapshot => ({
counts: { ...counts },
details: Object.fromEntries(
Object.entries(details).map(([event, eventDetails]) => [event, { ...eventDetails }])
),
details: Object.fromEntries(Object.entries(details).map(([event, eventDetails]) => [event, { ...eventDetails }])),
rows: { ...rows }
}),
start: () => {
Expand Down
5 changes: 1 addition & 4 deletions apps/desktop/src/lib/inflight-turn-journal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,7 @@ describe('recoverInFlightTurnJournal', () => {
})

it('keeps journal answer text when a longer flat dump is not a strict extension (#76444)', () => {
journalEntry([
user('u1', 'do the thing'),
assistantWithTool('assistant-stream-old', 'partial', { pending: true })
])
journalEntry([user('u1', 'do the thing'), assistantWithTool('assistant-stream-old', 'partial', { pending: true })])

const base = [
user('db-u1', 'do the thing'),
Expand Down
4 changes: 4 additions & 0 deletions apps/desktop/src/store/pet-gallery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe('pet gallery pet.info sync', () => {

throw new Error(`unexpected method: ${method}`)
})

const request = requestMock as unknown as GatewayRequest

await loadPetGallery(request)
Expand Down Expand Up @@ -113,6 +114,7 @@ describe('pet gallery pet.info sync', () => {

throw new Error(`unexpected method: ${method}`)
})

const request = requestMock as unknown as GatewayRequest

await loadPetGallery(request)
Expand Down Expand Up @@ -147,6 +149,7 @@ describe('pet gallery pet.info sync', () => {

throw new Error(`unexpected method: ${method}`)
})

const request = requestMock as unknown as GatewayRequest

await loadPetGallery(request)
Expand Down Expand Up @@ -195,6 +198,7 @@ describe('pet gallery pet.info sync', () => {

throw new Error(`unexpected method: ${method}`)
})

const request = requestMock as unknown as GatewayRequest

await expect(adoptPet(request, 'boba', 'Could not adopt pet.')).resolves.toBe(true)
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/store/pet-gallery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ export function loadPetGallery(request: GatewayRequest, options: { force?: boole
$petGalleryError.set(null)
localOk = true
}

} catch (e) {
if (isMissingMethod(e)) {
$petGalleryStatus.set('stale')
Expand Down Expand Up @@ -216,6 +215,7 @@ async function syncInfo(request: GatewayRequest): Promise<void> {

if (hasPetSpriteForMeta(current, meta)) {
const merged = mergePetInfoMeta(current, meta)

if (merged !== current) {
setPetInfo(merged)
}
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/store/pet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ describe('pet info metadata cache helpers', () => {
spritesheetBase64: 'large-sprite-payload',
spritesheetRevision: '100:2048'
}

const meta = {
enabled: true,
slug: 'boba',
Expand Down Expand Up @@ -116,6 +117,7 @@ describe('pet info metadata cache helpers', () => {
spritesheetBase64: 'large-sprite-payload',
spritesheetRevision: '100:2048'
}

const meta = {
enabled: true,
slug: 'boba',
Expand Down
3 changes: 1 addition & 2 deletions ui-tui/src/__tests__/scrollBoxRendererBounds.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,7 @@ describe('ScrollBox renderer bounds', () => {
expect(nestedTextWrapper?.yogaNode).toBeDefined()

const nestedText = nestedTextWrapper!.childNodes.find(child => child.nodeName === 'ink-text') as
| DOMElement
| undefined
DOMElement | undefined

const nestedTextChild = nestedText?.childNodes[0]

Expand Down
10 changes: 5 additions & 5 deletions ui-tui/src/app/overlayStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ export const $isBlocked = computed(
export const hasFloatingPanel = (overlay: OverlayState): boolean =>
Boolean(
overlay.modelPicker ||
overlay.pager ||
overlay.petPicker ||
overlay.pluginsHub ||
overlay.sessions ||
overlay.skillsHub
overlay.pager ||
overlay.petPicker ||
overlay.pluginsHub ||
overlay.sessions ||
overlay.skillsHub
Comment on lines 122 to +127

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Deindented boolean chain in hasFloatingPanel is not prettier-idiomatic

The reformat drops the continuation indentation on the || chain inside Boolean(...), which is unusual output for Prettier (the surrounding $isBlocked computed at ui-tui/src/app/overlayStore.ts:49-66 uses the same flat style, so it is at least internally consistent). Behavior is unchanged; worth a sanity check that the TUI package's formatter config (e.g. a custom printWidth or a non-Prettier formatter) is what produced this, so the next npm run fix doesn't oscillate the file back and forth.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

)

export const $isStatusRuleOccluded = computed([$overlayState, $uiState], (overlay, ui) =>
Expand Down