From fa7bce0789d80fa99080a2be231fcc754fd2af3c Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 30 Jun 2026 02:42:07 -0500 Subject: [PATCH] refactor(desktop): colocate hook/component families into scoped folders Single-scoped helpers/sub-files were sitting flat in shared/grab-bag dirs. Fold each family into its own folder (index = the export, dir resolution keeps public import paths intact), dropping the now-redundant filename prefix: - session/hooks/use-prompt-actions.ts (+ -utils, + tests) -> use-prompt-actions/{index,utils}.ts (+ tests) - components/assistant-ui/thread* + assistant/system/user message renderers -> assistant-ui/thread/{index,content,status,message-parts,timestamp,types, list,timeline,timeline-data,assistant-message,system-message,user-message, user-edit-composer,user-message-text} (+ tests) - components/assistant-ui/tool-fallback(+model)/tool-approval -> assistant-ui/tool/{fallback,fallback-model,approval} (+ tests) Pure move + import rewrites; no behaviour change. App-wide shared primitives (markdown-text, directive-text, tooltip-icon-button, clarify-tool, ansi-text, message-render-boundary) stay flat. desktop-controller intentionally left in app/ (route root; foldering would churn ~80 relative imports for no gain). --- .../index.test.tsx} | 2 +- .../index.ts} | 4 ++-- .../utils.test.ts} | 2 +- .../utils.ts} | 0 .../src/components/assistant-ui/clarify-tool.tsx | 4 ++-- .../{ => thread}/assistant-message.tsx | 8 ++++---- .../{ => thread}/block-direction.test.tsx | 2 +- .../content.test.ts} | 2 +- .../{thread-content.ts => thread/content.ts} | 0 .../{thread.tsx => thread/index.tsx} | 16 ++++++++-------- .../{thread-list.tsx => thread/list.tsx} | 2 +- .../message-parts.tsx} | 2 +- .../{thread-status.tsx => thread/status.tsx} | 0 .../assistant-ui/{ => thread}/streaming.test.tsx | 2 +- .../assistant-ui/{ => thread}/system-message.tsx | 2 +- .../timeline-data.test.ts} | 2 +- .../timeline-data.ts} | 0 .../{thread-timeline.tsx => thread/timeline.tsx} | 2 +- .../timestamp.test.ts} | 2 +- .../{thread-timestamp.ts => thread/timestamp.ts} | 0 .../{thread-types.ts => thread/types.ts} | 0 .../{ => thread}/user-edit-composer.tsx | 2 +- .../{ => thread}/user-message-edit.test.tsx | 2 +- .../{ => thread}/user-message-text.tsx | 0 .../assistant-ui/{ => thread}/user-message.tsx | 6 +++--- .../approval-group.test.tsx} | 2 +- .../approval.test.tsx} | 4 ++-- .../{tool-approval.tsx => tool/approval.tsx} | 2 +- .../fallback-model.test.ts} | 2 +- .../fallback-model.ts} | 0 .../{tool-fallback.tsx => tool/fallback.tsx} | 4 ++-- apps/desktop/src/components/prompt-overlays.tsx | 2 +- 32 files changed, 40 insertions(+), 40 deletions(-) rename apps/desktop/src/app/session/hooks/{use-prompt-actions.test.tsx => use-prompt-actions/index.test.tsx} (99%) rename apps/desktop/src/app/session/hooks/{use-prompt-actions.ts => use-prompt-actions/index.ts} (99%) rename apps/desktop/src/app/session/hooks/{use-prompt-actions-utils.test.ts => use-prompt-actions/utils.test.ts} (99%) rename apps/desktop/src/app/session/hooks/{use-prompt-actions-utils.ts => use-prompt-actions/utils.ts} (100%) rename apps/desktop/src/components/assistant-ui/{ => thread}/assistant-message.tsx (98%) rename apps/desktop/src/components/assistant-ui/{ => thread}/block-direction.test.tsx (99%) rename apps/desktop/src/components/assistant-ui/{thread-content.test.ts => thread/content.test.ts} (99%) rename apps/desktop/src/components/assistant-ui/{thread-content.ts => thread/content.ts} (100%) rename apps/desktop/src/components/assistant-ui/{thread.tsx => thread/index.tsx} (90%) rename apps/desktop/src/components/assistant-ui/{thread-list.tsx => thread/list.tsx} (99%) rename apps/desktop/src/components/assistant-ui/{thread-message-parts.tsx => thread/message-parts.tsx} (99%) rename apps/desktop/src/components/assistant-ui/{thread-status.tsx => thread/status.tsx} (100%) rename apps/desktop/src/components/assistant-ui/{ => thread}/streaming.test.tsx (99%) rename apps/desktop/src/components/assistant-ui/{ => thread}/system-message.tsx (99%) rename apps/desktop/src/components/assistant-ui/{thread-timeline-data.test.ts => thread/timeline-data.test.ts} (97%) rename apps/desktop/src/components/assistant-ui/{thread-timeline-data.ts => thread/timeline-data.ts} (100%) rename apps/desktop/src/components/assistant-ui/{thread-timeline.tsx => thread/timeline.tsx} (99%) rename apps/desktop/src/components/assistant-ui/{thread-timestamp.test.ts => thread/timestamp.test.ts} (95%) rename apps/desktop/src/components/assistant-ui/{thread-timestamp.ts => thread/timestamp.ts} (100%) rename apps/desktop/src/components/assistant-ui/{thread-types.ts => thread/types.ts} (100%) rename apps/desktop/src/components/assistant-ui/{ => thread}/user-edit-composer.tsx (99%) rename apps/desktop/src/components/assistant-ui/{ => thread}/user-message-edit.test.tsx (99%) rename apps/desktop/src/components/assistant-ui/{ => thread}/user-message-text.tsx (100%) rename apps/desktop/src/components/assistant-ui/{ => thread}/user-message.tsx (99%) rename apps/desktop/src/components/assistant-ui/{tool-approval-group.test.tsx => tool/approval-group.test.tsx} (99%) rename apps/desktop/src/components/assistant-ui/{tool-approval.test.tsx => tool/approval.test.tsx} (98%) rename apps/desktop/src/components/assistant-ui/{tool-approval.tsx => tool/approval.tsx} (99%) rename apps/desktop/src/components/assistant-ui/{tool-fallback-model.test.ts => tool/fallback-model.test.ts} (99%) rename apps/desktop/src/components/assistant-ui/{tool-fallback-model.ts => tool/fallback-model.ts} (100%) rename apps/desktop/src/components/assistant-ui/{tool-fallback.tsx => tool/fallback.tsx} (99%) diff --git a/apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx b/apps/desktop/src/app/session/hooks/use-prompt-actions/index.test.tsx similarity index 99% rename from apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx rename to apps/desktop/src/app/session/hooks/use-prompt-actions/index.test.tsx index bd971dd52c9..2647f4dcef1 100644 --- a/apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx +++ b/apps/desktop/src/app/session/hooks/use-prompt-actions/index.test.tsx @@ -8,7 +8,7 @@ import { $composerAttachments, type ComposerAttachment } from '@/store/composer' import { $busy, $connection, $messages, $sessions, setSessions } from '@/store/session' import type { SessionInfo } from '@/types/hermes' -import { uploadComposerAttachment, usePromptActions } from './use-prompt-actions' +import { uploadComposerAttachment, usePromptActions } from '.' vi.mock('@/hermes', () => ({ getProfiles: vi.fn(async () => ({ profiles: [] })), diff --git a/apps/desktop/src/app/session/hooks/use-prompt-actions.ts b/apps/desktop/src/app/session/hooks/use-prompt-actions/index.ts similarity index 99% rename from apps/desktop/src/app/session/hooks/use-prompt-actions.ts rename to apps/desktop/src/app/session/hooks/use-prompt-actions/index.ts index b671dfdf8a6..49257094a1c 100644 --- a/apps/desktop/src/app/session/hooks/use-prompt-actions.ts +++ b/apps/desktop/src/app/session/hooks/use-prompt-actions/index.ts @@ -72,7 +72,7 @@ import type { SessionSteerResponse, SessionTitleResponse, SlashExecResponse -} from '../../types' +} from '../../../types' import { _submitInFlight, @@ -93,7 +93,7 @@ import { visibleUserIndexAtOrdinal, visibleUserOrdinal, withSessionBusyRetry -} from './use-prompt-actions-utils' +} from './utils' interface HandoffResult { ok: boolean diff --git a/apps/desktop/src/app/session/hooks/use-prompt-actions-utils.test.ts b/apps/desktop/src/app/session/hooks/use-prompt-actions/utils.test.ts similarity index 99% rename from apps/desktop/src/app/session/hooks/use-prompt-actions-utils.test.ts rename to apps/desktop/src/app/session/hooks/use-prompt-actions/utils.test.ts index d95f880bb94..1acc854aac5 100644 --- a/apps/desktop/src/app/session/hooks/use-prompt-actions-utils.test.ts +++ b/apps/desktop/src/app/session/hooks/use-prompt-actions/utils.test.ts @@ -15,7 +15,7 @@ import { slashStatusText, visibleUserIndexAtOrdinal, visibleUserOrdinal -} from './use-prompt-actions-utils' +} from './utils' describe('isSessionIdCandidate', () => { it('accepts the timestamped and hex id forms', () => { diff --git a/apps/desktop/src/app/session/hooks/use-prompt-actions-utils.ts b/apps/desktop/src/app/session/hooks/use-prompt-actions/utils.ts similarity index 100% rename from apps/desktop/src/app/session/hooks/use-prompt-actions-utils.ts rename to apps/desktop/src/app/session/hooks/use-prompt-actions/utils.ts diff --git a/apps/desktop/src/components/assistant-ui/clarify-tool.tsx b/apps/desktop/src/components/assistant-ui/clarify-tool.tsx index d5f5b0de511..898e83cd650 100644 --- a/apps/desktop/src/components/assistant-ui/clarify-tool.tsx +++ b/apps/desktop/src/components/assistant-ui/clarify-tool.tsx @@ -13,7 +13,7 @@ import { useState } from 'react' -import { ToolFallback } from '@/components/assistant-ui/tool-fallback' +import { ToolFallback } from '@/components/assistant-ui/tool/fallback' import { Button } from '@/components/ui/button' import { Kbd } from '@/components/ui/kbd' import { Textarea } from '@/components/ui/textarea' @@ -25,7 +25,7 @@ import { $clarifyRequest, clearClarifyRequest } from '@/store/clarify' import { $gateway } from '@/store/gateway' import { notifyError } from '@/store/notifications' -import { selectMessageRunning } from './tool-fallback-model' +import { selectMessageRunning } from './tool/fallback-model' interface ClarifyArgs { question?: string diff --git a/apps/desktop/src/components/assistant-ui/assistant-message.tsx b/apps/desktop/src/components/assistant-ui/thread/assistant-message.tsx similarity index 98% rename from apps/desktop/src/components/assistant-ui/assistant-message.tsx rename to apps/desktop/src/components/assistant-ui/thread/assistant-message.tsx index 15efdf3d683..5c73a80a5f7 100644 --- a/apps/desktop/src/components/assistant-ui/assistant-message.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/assistant-message.tsx @@ -13,10 +13,10 @@ import { contentHasVisibleText, messageContentText, pickPrimaryPreviewTarget -} from '@/components/assistant-ui/thread-content' -import { MESSAGE_PARTS_COMPONENTS } from '@/components/assistant-ui/thread-message-parts' -import { StreamStallIndicator } from '@/components/assistant-ui/thread-status' -import { formatMessageTimestamp } from '@/components/assistant-ui/thread-timestamp' +} from '@/components/assistant-ui/thread/content' +import { MESSAGE_PARTS_COMPONENTS } from '@/components/assistant-ui/thread/message-parts' +import { StreamStallIndicator } from '@/components/assistant-ui/thread/status' +import { formatMessageTimestamp } from '@/components/assistant-ui/thread/timestamp' import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button' import { PreviewAttachment } from '@/components/chat/preview-attachment' import { Codicon } from '@/components/ui/codicon' diff --git a/apps/desktop/src/components/assistant-ui/block-direction.test.tsx b/apps/desktop/src/components/assistant-ui/thread/block-direction.test.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/block-direction.test.tsx rename to apps/desktop/src/components/assistant-ui/thread/block-direction.test.tsx index a206e8e847d..cc63d4fbbe3 100644 --- a/apps/desktop/src/components/assistant-ui/block-direction.test.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/block-direction.test.tsx @@ -10,7 +10,7 @@ import { AssistantRuntimeProvider, type ThreadMessage, useExternalStoreRuntime } import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { Thread } from './thread' +import { Thread } from '.' const createdAt = new Date('2026-06-01T00:00:00.000Z') diff --git a/apps/desktop/src/components/assistant-ui/thread-content.test.ts b/apps/desktop/src/components/assistant-ui/thread/content.test.ts similarity index 99% rename from apps/desktop/src/components/assistant-ui/thread-content.test.ts rename to apps/desktop/src/components/assistant-ui/thread/content.test.ts index 732e8c2e3cf..060ecb3ea85 100644 --- a/apps/desktop/src/components/assistant-ui/thread-content.test.ts +++ b/apps/desktop/src/components/assistant-ui/thread/content.test.ts @@ -6,7 +6,7 @@ import { messageContentText, partText, pickPrimaryPreviewTarget -} from './thread-content' +} from './content' describe('partText', () => { it('returns plain strings as-is', () => { diff --git a/apps/desktop/src/components/assistant-ui/thread-content.ts b/apps/desktop/src/components/assistant-ui/thread/content.ts similarity index 100% rename from apps/desktop/src/components/assistant-ui/thread-content.ts rename to apps/desktop/src/components/assistant-ui/thread/content.ts diff --git a/apps/desktop/src/components/assistant-ui/thread.tsx b/apps/desktop/src/components/assistant-ui/thread/index.tsx similarity index 90% rename from apps/desktop/src/components/assistant-ui/thread.tsx rename to apps/desktop/src/components/assistant-ui/thread/index.tsx index fdf95f7e234..ff30931e3f3 100644 --- a/apps/desktop/src/components/assistant-ui/thread.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/index.tsx @@ -1,17 +1,17 @@ import { type FC, useCallback, useMemo, useState } from 'react' -import { AssistantMessage } from '@/components/assistant-ui/assistant-message' -import { SystemMessage } from '@/components/assistant-ui/system-message' -import { ThreadMessageList } from '@/components/assistant-ui/thread-list' +import { AssistantMessage } from '@/components/assistant-ui/thread/assistant-message' +import { ThreadMessageList } from '@/components/assistant-ui/thread/list' import { BackgroundResumeNotice, CenteredThreadSpinner, ResponseLoadingIndicator -} from '@/components/assistant-ui/thread-status' -import { ThreadTimeline } from '@/components/assistant-ui/thread-timeline' -import { type RestoreMessageTarget } from '@/components/assistant-ui/thread-types' -import { UserEditComposer } from '@/components/assistant-ui/user-edit-composer' -import { UserMessage } from '@/components/assistant-ui/user-message' +} from '@/components/assistant-ui/thread/status' +import { SystemMessage } from '@/components/assistant-ui/thread/system-message' +import { ThreadTimeline } from '@/components/assistant-ui/thread/timeline' +import { type RestoreMessageTarget } from '@/components/assistant-ui/thread/types' +import { UserEditComposer } from '@/components/assistant-ui/thread/user-edit-composer' +import { UserMessage } from '@/components/assistant-ui/thread/user-message' import { Intro, type IntroProps } from '@/components/chat/intro' import { ConfirmDialog } from '@/components/ui/confirm-dialog' import type { HermesGateway } from '@/hermes' diff --git a/apps/desktop/src/components/assistant-ui/thread-list.tsx b/apps/desktop/src/components/assistant-ui/thread/list.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/thread-list.tsx rename to apps/desktop/src/components/assistant-ui/thread/list.tsx index 1bdc96d6c16..8f2856e3dfa 100644 --- a/apps/desktop/src/components/assistant-ui/thread-list.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/list.tsx @@ -24,7 +24,7 @@ import { } from '@/store/thread-scroll' import { isSecondaryWindow } from '@/store/windows' -import { MessageRenderBoundary } from './message-render-boundary' +import { MessageRenderBoundary } from '../message-render-boundary' type ThreadMessageComponents = ComponentProps['components'] diff --git a/apps/desktop/src/components/assistant-ui/thread-message-parts.tsx b/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/thread-message-parts.tsx rename to apps/desktop/src/components/assistant-ui/thread/message-parts.tsx index 7d2c87e0e4d..ccd672dac9f 100644 --- a/apps/desktop/src/components/assistant-ui/thread-message-parts.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx @@ -3,7 +3,7 @@ import { type ComponentProps, type FC, type ReactNode, useEffect, useRef, useSta import { ClarifyTool } from '@/components/assistant-ui/clarify-tool' import { MarkdownText, MarkdownTextContent } from '@/components/assistant-ui/markdown-text' -import { ToolFallback, ToolGroupSlot } from '@/components/assistant-ui/tool-fallback' +import { ToolFallback, ToolGroupSlot } from '@/components/assistant-ui/tool/fallback' import { useElapsedSeconds } from '@/components/chat/activity-timer' import { ActivityTimerText } from '@/components/chat/activity-timer-text' import { DisclosureRow } from '@/components/chat/disclosure-row' diff --git a/apps/desktop/src/components/assistant-ui/thread-status.tsx b/apps/desktop/src/components/assistant-ui/thread/status.tsx similarity index 100% rename from apps/desktop/src/components/assistant-ui/thread-status.tsx rename to apps/desktop/src/components/assistant-ui/thread/status.tsx diff --git a/apps/desktop/src/components/assistant-ui/streaming.test.tsx b/apps/desktop/src/components/assistant-ui/thread/streaming.test.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/streaming.test.tsx rename to apps/desktop/src/components/assistant-ui/thread/streaming.test.tsx index d23bbb42049..3759f469e2f 100644 --- a/apps/desktop/src/components/assistant-ui/streaming.test.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/streaming.test.tsx @@ -3,7 +3,7 @@ import { act, fireEvent, render, screen, waitFor, within } from '@testing-librar import { useEffect, useState } from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { Thread } from './thread' +import { Thread } from '.' const createdAt = new Date('2026-05-01T00:00:00.000Z') diff --git a/apps/desktop/src/components/assistant-ui/system-message.tsx b/apps/desktop/src/components/assistant-ui/thread/system-message.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/system-message.tsx rename to apps/desktop/src/components/assistant-ui/thread/system-message.tsx index ce6d0a856c8..57631764f8f 100644 --- a/apps/desktop/src/components/assistant-ui/system-message.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/system-message.tsx @@ -1,7 +1,7 @@ import { MessagePrimitive, useAuiState } from '@assistant-ui/react' import { type FC } from 'react' -import { messageContentText } from '@/components/assistant-ui/thread-content' +import { messageContentText } from '@/components/assistant-ui/thread/content' import { Codicon } from '@/components/ui/codicon' import { LinkifiedText } from '@/lib/external-link' import { cn } from '@/lib/utils' diff --git a/apps/desktop/src/components/assistant-ui/thread-timeline-data.test.ts b/apps/desktop/src/components/assistant-ui/thread/timeline-data.test.ts similarity index 97% rename from apps/desktop/src/components/assistant-ui/thread-timeline-data.test.ts rename to apps/desktop/src/components/assistant-ui/thread/timeline-data.test.ts index a3cc48da56a..0c2918aea59 100644 --- a/apps/desktop/src/components/assistant-ui/thread-timeline-data.test.ts +++ b/apps/desktop/src/components/assistant-ui/thread/timeline-data.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import { activeTimelineIndex, deriveTimelineEntries, timelinePreview } from './thread-timeline-data' +import { activeTimelineIndex, deriveTimelineEntries, timelinePreview } from './timeline-data' describe('timelinePreview', () => { it('collapses whitespace to a single line', () => { diff --git a/apps/desktop/src/components/assistant-ui/thread-timeline-data.ts b/apps/desktop/src/components/assistant-ui/thread/timeline-data.ts similarity index 100% rename from apps/desktop/src/components/assistant-ui/thread-timeline-data.ts rename to apps/desktop/src/components/assistant-ui/thread/timeline-data.ts diff --git a/apps/desktop/src/components/assistant-ui/thread-timeline.tsx b/apps/desktop/src/components/assistant-ui/thread/timeline.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/thread-timeline.tsx rename to apps/desktop/src/components/assistant-ui/thread/timeline.tsx index 60f39c9de85..6c1a8380f30 100644 --- a/apps/desktop/src/components/assistant-ui/thread-timeline.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/timeline.tsx @@ -9,7 +9,7 @@ import { deriveTimelineEntries, type TimelineEntry, type TimelineSourceMessage -} from './thread-timeline-data' +} from './timeline-data' const MIN_ENTRIES = 4 const VIEWPORT = '[data-slot="aui_thread-viewport"]' diff --git a/apps/desktop/src/components/assistant-ui/thread-timestamp.test.ts b/apps/desktop/src/components/assistant-ui/thread/timestamp.test.ts similarity index 95% rename from apps/desktop/src/components/assistant-ui/thread-timestamp.test.ts rename to apps/desktop/src/components/assistant-ui/thread/timestamp.test.ts index 684456205b7..938d7de81e0 100644 --- a/apps/desktop/src/components/assistant-ui/thread-timestamp.test.ts +++ b/apps/desktop/src/components/assistant-ui/thread/timestamp.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import { formatMessageTimestamp } from './thread-timestamp' +import { formatMessageTimestamp } from './timestamp' const labels = { today: (time: string) => `Today at ${time}`, diff --git a/apps/desktop/src/components/assistant-ui/thread-timestamp.ts b/apps/desktop/src/components/assistant-ui/thread/timestamp.ts similarity index 100% rename from apps/desktop/src/components/assistant-ui/thread-timestamp.ts rename to apps/desktop/src/components/assistant-ui/thread/timestamp.ts diff --git a/apps/desktop/src/components/assistant-ui/thread-types.ts b/apps/desktop/src/components/assistant-ui/thread/types.ts similarity index 100% rename from apps/desktop/src/components/assistant-ui/thread-types.ts rename to apps/desktop/src/components/assistant-ui/thread/types.ts diff --git a/apps/desktop/src/components/assistant-ui/user-edit-composer.tsx b/apps/desktop/src/components/assistant-ui/thread/user-edit-composer.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/user-edit-composer.tsx rename to apps/desktop/src/components/assistant-ui/thread/user-edit-composer.tsx index ffc45e166d8..b292f3f90bb 100644 --- a/apps/desktop/src/components/assistant-ui/user-edit-composer.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/user-edit-composer.tsx @@ -52,7 +52,7 @@ import { USER_ACTION_ICON_BUTTON_CLASS, USER_ACTION_ICON_SIZE, USER_BUBBLE_BASE_CLASS -} from '@/components/assistant-ui/user-message' +} from '@/components/assistant-ui/thread/user-message' import { Codicon } from '@/components/ui/codicon' import type { HermesGateway } from '@/hermes' import { useI18n } from '@/i18n' diff --git a/apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx b/apps/desktop/src/components/assistant-ui/thread/user-message-edit.test.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx rename to apps/desktop/src/components/assistant-ui/thread/user-message-edit.test.tsx index ee915cf7429..914fc043b12 100644 --- a/apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/user-message-edit.test.tsx @@ -13,7 +13,7 @@ import { describe, expect, it, vi } from 'vitest' import { useIncrementalExternalStoreRuntime } from '@/lib/incremental-external-store-runtime' -import { Thread } from './thread' +import { Thread } from '.' const createdAt = new Date('2026-05-01T00:00:00.000Z') diff --git a/apps/desktop/src/components/assistant-ui/user-message-text.tsx b/apps/desktop/src/components/assistant-ui/thread/user-message-text.tsx similarity index 100% rename from apps/desktop/src/components/assistant-ui/user-message-text.tsx rename to apps/desktop/src/components/assistant-ui/thread/user-message-text.tsx diff --git a/apps/desktop/src/components/assistant-ui/user-message.tsx b/apps/desktop/src/components/assistant-ui/thread/user-message.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/user-message.tsx rename to apps/desktop/src/components/assistant-ui/thread/user-message.tsx index 89a387ee8ae..6b0a6248eb8 100644 --- a/apps/desktop/src/components/assistant-ui/user-message.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/user-message.tsx @@ -2,9 +2,9 @@ import { ActionBarPrimitive, BranchPickerPrimitive, MessagePrimitive, useAuiStat import { type FC, type ReactNode, useCallback, useRef, useState } from 'react' import { DirectiveContent } from '@/components/assistant-ui/directive-text' -import { messageAttachmentRefs, messageContentText } from '@/components/assistant-ui/thread-content' -import { type RestoreMessageTarget } from '@/components/assistant-ui/thread-types' -import { UserMessageText } from '@/components/assistant-ui/user-message-text' +import { messageAttachmentRefs, messageContentText } from '@/components/assistant-ui/thread/content' +import { type RestoreMessageTarget } from '@/components/assistant-ui/thread/types' +import { UserMessageText } from '@/components/assistant-ui/thread/user-message-text' import { Codicon } from '@/components/ui/codicon' import { useResizeObserver } from '@/hooks/use-resize-observer' import { useI18n } from '@/i18n' diff --git a/apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx b/apps/desktop/src/components/assistant-ui/tool/approval-group.test.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx rename to apps/desktop/src/components/assistant-ui/tool/approval-group.test.tsx index 79c07ea4dbf..f6201153c98 100644 --- a/apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx +++ b/apps/desktop/src/components/assistant-ui/tool/approval-group.test.tsx @@ -7,7 +7,7 @@ import { $activeSessionId } from '@/store/session' import { clearDismissedToolRows } from '@/store/tool-dismiss' import { $toolDisclosureStates } from '@/store/tool-view' -import { Thread } from './thread' +import { Thread } from '../thread' // Regression coverage for the "approval must never be buried" bug. Tools now // render as a flat list (no collapsible "N steps" group), so a pending tool's diff --git a/apps/desktop/src/components/assistant-ui/tool-approval.test.tsx b/apps/desktop/src/components/assistant-ui/tool/approval.test.tsx similarity index 98% rename from apps/desktop/src/components/assistant-ui/tool-approval.test.tsx rename to apps/desktop/src/components/assistant-ui/tool/approval.test.tsx index db8debd85c6..2955fafe8d6 100644 --- a/apps/desktop/src/components/assistant-ui/tool-approval.test.tsx +++ b/apps/desktop/src/components/assistant-ui/tool/approval.test.tsx @@ -6,8 +6,8 @@ import { $gateway } from '@/store/gateway' import { $approvalRequest, clearAllPrompts, setApprovalRequest } from '@/store/prompts' import { $activeSessionId } from '@/store/session' -import { PendingApprovalFallback, PendingToolApproval } from './tool-approval' -import type { ToolPart } from './tool-fallback-model' +import { PendingApprovalFallback, PendingToolApproval } from './approval' +import type { ToolPart } from './fallback-model' // Radix's DropdownMenu touches pointer-capture + scrollIntoView, which jsdom // doesn't implement; stub them so the menu can open in tests. diff --git a/apps/desktop/src/components/assistant-ui/tool-approval.tsx b/apps/desktop/src/components/assistant-ui/tool/approval.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/tool-approval.tsx rename to apps/desktop/src/components/assistant-ui/tool/approval.tsx index 3a0bf75af5e..3416c22727b 100644 --- a/apps/desktop/src/components/assistant-ui/tool-approval.tsx +++ b/apps/desktop/src/components/assistant-ui/tool/approval.tsx @@ -27,7 +27,7 @@ import { registerApprovalInlineAnchor } from '@/store/prompts' -import type { ToolPart } from './tool-fallback-model' +import type { ToolPart } from './fallback-model' // Inline approval control. Rendered as a compact button strip // under the pending tool row that raised the approval (the row already shows diff --git a/apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts b/apps/desktop/src/components/assistant-ui/tool/fallback-model.test.ts similarity index 99% rename from apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts rename to apps/desktop/src/components/assistant-ui/tool/fallback-model.test.ts index 6c864608c72..009abcfdf69 100644 --- a/apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts +++ b/apps/desktop/src/components/assistant-ui/tool/fallback-model.test.ts @@ -9,7 +9,7 @@ import { inlineDiffFromResult, MAX_TOOL_RENDER_CHARS, type ToolPart -} from './tool-fallback-model' +} from './fallback-model' const part = (overrides: Partial): ToolPart => ({ args: {}, diff --git a/apps/desktop/src/components/assistant-ui/tool-fallback-model.ts b/apps/desktop/src/components/assistant-ui/tool/fallback-model.ts similarity index 100% rename from apps/desktop/src/components/assistant-ui/tool-fallback-model.ts rename to apps/desktop/src/components/assistant-ui/tool/fallback-model.ts diff --git a/apps/desktop/src/components/assistant-ui/tool-fallback.tsx b/apps/desktop/src/components/assistant-ui/tool/fallback.tsx similarity index 99% rename from apps/desktop/src/components/assistant-ui/tool-fallback.tsx rename to apps/desktop/src/components/assistant-ui/tool/fallback.tsx index 5b895a7397b..a8267ce6b84 100644 --- a/apps/desktop/src/components/assistant-ui/tool-fallback.tsx +++ b/apps/desktop/src/components/assistant-ui/tool/fallback.tsx @@ -30,7 +30,7 @@ import { $toolInlineDiffs } from '@/store/tool-diffs' import { $toolRowDismissed, dismissToolRow } from '@/store/tool-dismiss' import { $toolDisclosureOpen, $toolViewMode, setToolDisclosureOpen } from '@/store/tool-view' -import { PendingToolApproval } from './tool-approval' +import { PendingToolApproval } from './approval' import { buildToolView, clampForDisplay, @@ -48,7 +48,7 @@ import { toolPartDisclosureId, type ToolStatus, type ToolTitleAction -} from './tool-fallback-model' +} from './fallback-model' // `true` when a ToolEntry is rendered inside an embedding wrapper that owns // the per-row chrome (timer / preview). The flat ToolGroupSlot sets this diff --git a/apps/desktop/src/components/prompt-overlays.tsx b/apps/desktop/src/components/prompt-overlays.tsx index 62262b2ac07..a43303e1ced 100644 --- a/apps/desktop/src/components/prompt-overlays.tsx +++ b/apps/desktop/src/components/prompt-overlays.tsx @@ -3,7 +3,7 @@ import { useStore } from '@nanostores/react' import { type FormEvent, useCallback, useEffect, useState } from 'react' -import { PendingApprovalFallback } from '@/components/assistant-ui/tool-approval' +import { PendingApprovalFallback } from '@/components/assistant-ui/tool/approval' import { Button } from '@/components/ui/button' import { Dialog,