diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index 1e652104d6..be2e099d0e 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -9,6 +9,7 @@ on:
- "bun.lock"
- "packages/storybook/**"
- "packages/ui/**"
+ - "packages/session-ui/**"
pull_request:
branches: [dev]
paths:
@@ -17,6 +18,7 @@ on:
- "bun.lock"
- "packages/storybook/**"
- "packages/ui/**"
+ - "packages/session-ui/**"
workflow_dispatch:
concurrency:
diff --git a/bun.lock b/bun.lock
index 9dc9eed534..411c09c8ff 100644
--- a/bun.lock
+++ b/bun.lock
@@ -34,6 +34,7 @@
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@pierre/trees": "1.0.0-beta.4",
"@sentry/solid": "catalog:",
@@ -417,6 +418,7 @@
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@pierre/diffs": "catalog:",
"@solidjs/meta": "catalog:",
@@ -703,6 +705,50 @@
"@typescript/native-preview": "catalog:",
},
},
+ "packages/session-ui": {
+ "name": "@opencode-ai/session-ui",
+ "version": "1.17.9",
+ "dependencies": {
+ "@kobalte/core": "catalog:",
+ "@opencode-ai/core": "workspace:*",
+ "@opencode-ai/sdk": "workspace:*",
+ "@opencode-ai/ui": "workspace:*",
+ "@pierre/diffs": "catalog:",
+ "@shikijs/stream": "catalog:",
+ "@shikijs/transformers": "3.9.2",
+ "@solid-primitives/bounds": "0.1.3",
+ "@solid-primitives/event-listener": "2.4.5",
+ "@solid-primitives/media": "2.3.3",
+ "@solid-primitives/resize-observer": "2.1.3",
+ "@solidjs/meta": "catalog:",
+ "@solidjs/router": "catalog:",
+ "diff": "catalog:",
+ "dompurify": "3.3.1",
+ "fuzzysort": "catalog:",
+ "katex": "0.16.27",
+ "luxon": "catalog:",
+ "marked": "catalog:",
+ "marked-katex-extension": "5.1.6",
+ "marked-shiki": "catalog:",
+ "morphdom": "2.7.8",
+ "motion": "12.34.5",
+ "remeda": "catalog:",
+ "remend": "catalog:",
+ "shiki": "catalog:",
+ "solid-js": "catalog:",
+ "solid-list": "catalog:",
+ "strip-ansi": "7.1.2",
+ },
+ "devDependencies": {
+ "@tsconfig/node22": "catalog:",
+ "@types/bun": "catalog:",
+ "@types/katex": "0.16.7",
+ "@types/luxon": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "typescript": "catalog:",
+ "vite": "catalog:",
+ },
+ },
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.17.9",
@@ -789,6 +835,7 @@
"packages/storybook": {
"name": "@opencode-ai/storybook",
"devDependencies": {
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@solidjs/meta": "catalog:",
"@storybook/addon-a11y": "^10.2.13",
@@ -840,8 +887,6 @@
"version": "1.17.9",
"dependencies": {
"@kobalte/core": "catalog:",
- "@opencode-ai/core": "workspace:*",
- "@opencode-ai/sdk": "workspace:*",
"@pierre/diffs": "catalog:",
"@shikijs/stream": "catalog:",
"@shikijs/transformers": "3.9.2",
@@ -1825,6 +1870,8 @@
"@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"],
+ "@opencode-ai/session-ui": ["@opencode-ai/session-ui@workspace:packages/session-ui"],
+
"@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"],
"@opencode-ai/stats-app": ["@opencode-ai/stats-app@workspace:packages/stats/app"],
@@ -5843,6 +5890,8 @@
"@opencode-ai/llm/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
+ "@opencode-ai/session-ui/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
+
"@opencode-ai/ui/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="],
diff --git a/packages/app/package.json b/packages/app/package.json
index e4906b9ea4..b3648e3a9c 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -47,6 +47,7 @@
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@pierre/trees": "1.0.0-beta.4",
"@sentry/solid": "catalog:",
diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index 7152e7a0c9..9062b715cc 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -4,7 +4,7 @@ import { I18nProvider } from "@opencode-ai/ui/context"
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
-import { File } from "@opencode-ai/ui/file"
+import { File } from "@opencode-ai/session-ui/file"
import { Font } from "@opencode-ai/ui/font"
import { Splash } from "@opencode-ai/ui/logo"
import { ThemeProvider } from "@opencode-ai/ui/theme/context"
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx
index a601928de4..a44bfa2ec7 100644
--- a/packages/app/src/components/session/session-context-tab.tsx
+++ b/packages/app/src/components/session/session-context-tab.tsx
@@ -7,8 +7,8 @@ import { same } from "@/utils/same"
import { Icon } from "@opencode-ai/ui/icon"
import { Accordion } from "@opencode-ai/ui/accordion"
import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
-import { File } from "@opencode-ai/ui/file"
-import { Markdown } from "@opencode-ai/ui/markdown"
+import { File } from "@opencode-ai/session-ui/file"
+import { Markdown } from "@opencode-ai/session-ui/markdown"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
import type { Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client"
import { useLanguage } from "@/context/language"
diff --git a/packages/app/src/context/global-sync/bootstrap.test.ts b/packages/app/src/context/global-sync/bootstrap.test.ts
index 8393b04742..2e85f4850a 100644
--- a/packages/app/src/context/global-sync/bootstrap.test.ts
+++ b/packages/app/src/context/global-sync/bootstrap.test.ts
@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"
import { createStore } from "solid-js/store"
import { QueryClient } from "@tanstack/solid-query"
import type { Config, OpencodeClient, Project } from "@opencode-ai/sdk/v2/client"
-import type { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import { bootstrapDirectory, loadPathQuery, loadProvidersQuery } from "./bootstrap"
import type { State, VcsCache } from "./types"
import { ServerScope } from "@/utils/server-scope"
diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts
index bac9c69280..b24bdda811 100644
--- a/packages/app/src/context/global-sync/bootstrap.ts
+++ b/packages/app/src/context/global-sync/bootstrap.ts
@@ -19,7 +19,7 @@ import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
import { formatServerError } from "@/utils/server-errors"
import { QueryClient, queryOptions } from "@tanstack/solid-query"
import { loadMcpQuery } from "../server-sync"
-import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import { ScopedKey, type ServerScope } from "@/utils/server-scope"
type GlobalStore = {
diff --git a/packages/app/src/context/global-sync/child-store.test.ts b/packages/app/src/context/global-sync/child-store.test.ts
index 6d4b14e8c0..31c7519d84 100644
--- a/packages/app/src/context/global-sync/child-store.test.ts
+++ b/packages/app/src/context/global-sync/child-store.test.ts
@@ -1,7 +1,7 @@
import { beforeAll, describe, expect, mock, test } from "bun:test"
import { createRoot, getOwner, type Owner } from "solid-js"
import { createStore } from "solid-js/store"
-import type { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import type { State } from "./types"
import type { QueryOptionsApi } from "../server-sync"
import { ServerScope } from "@/utils/server-scope"
diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts
index e9ab8fa2a3..65011e8b09 100644
--- a/packages/app/src/context/global-sync/child-store.ts
+++ b/packages/app/src/context/global-sync/child-store.ts
@@ -17,7 +17,7 @@ import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
import { useQuery } from "@tanstack/solid-query"
import { QueryOptionsApi } from "../server-sync"
import { directoryKey, type DirectoryKey } from "./utils"
-import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import type { ServerScope } from "@/utils/server-scope"
export function createChildStoreManager(input: {
diff --git a/packages/app/src/context/global-sync/types.ts b/packages/app/src/context/global-sync/types.ts
index 8db24b904b..9fb86d6d35 100644
--- a/packages/app/src/context/global-sync/types.ts
+++ b/packages/app/src/context/global-sync/types.ts
@@ -15,7 +15,7 @@ import type {
Todo,
VcsInfo,
} from "@opencode-ai/sdk/v2/client"
-import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import type { Accessor } from "solid-js"
import type { SetStoreFunction, Store } from "solid-js/store"
diff --git a/packages/app/src/context/global-sync/utils.ts b/packages/app/src/context/global-sync/utils.ts
index 2515a593fb..e54bc88d4d 100644
--- a/packages/app/src/context/global-sync/utils.ts
+++ b/packages/app/src/context/global-sync/utils.ts
@@ -1,5 +1,5 @@
import type { Agent, Project, ProviderListResponse } from "@opencode-ai/sdk/v2/client"
-import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
export { pathKey as directoryKey, type PathKey as DirectoryKey } from "@/utils/path-key"
export const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0)
diff --git a/packages/app/src/context/server-sync.tsx b/packages/app/src/context/server-sync.tsx
index 7d714240f6..db1a57d2b2 100644
--- a/packages/app/src/context/server-sync.tsx
+++ b/packages/app/src/context/server-sync.tsx
@@ -29,7 +29,8 @@ import { createRefreshQueue } from "./global-sync/queue"
import { directoryKey } from "./global-sync/utils"
import { PathKey } from "@/utils/path-key"
import { createDirSyncContext } from "./directory-sync"
-import { createSimpleContext, NormalizedProviderListResponse } from "@opencode-ai/ui/context"
+import { createSimpleContext } from "@opencode-ai/ui/context"
+import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import { createRefCountMap } from "@/utils/refcount"
import { useGlobal } from "./global"
import { ServerConnection, useServer } from "./server"
diff --git a/packages/app/src/index.css b/packages/app/src/index.css
index 467f4ac81e..df7e7f44cf 100644
--- a/packages/app/src/index.css
+++ b/packages/app/src/index.css
@@ -1,4 +1,5 @@
@import "@opencode-ai/ui/styles/tailwind";
+@import "@opencode-ai/session-ui/styles";
@import "@opencode-ai/ui/v2/styles/tailwind.css";
@font-face {
diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx
index 73ed1ac273..b2704c2862 100644
--- a/packages/app/src/pages/directory-layout.tsx
+++ b/packages/app/src/pages/directory-layout.tsx
@@ -1,4 +1,4 @@
-import { DataProvider } from "@opencode-ai/ui/context"
+import { DataProvider } from "@opencode-ai/session-ui/context"
import { showToast } from "@/utils/toast"
import { base64Encode } from "@opencode-ai/core/util/encode"
import { useLocation, useNavigate, useParams } from "@solidjs/router"
diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx
index 907ea91f15..12934aebea 100644
--- a/packages/app/src/pages/home.tsx
+++ b/packages/app/src/pages/home.tsx
@@ -60,7 +60,7 @@ import { ServerHealthIndicator } from "@/components/server/server-row"
import { type ServerHealth } from "@/utils/server-health"
import { Persist, persisted } from "@/utils/persist"
import { useMarked } from "@opencode-ai/ui/context/marked"
-import { preloadMarkdown } from "@opencode-ai/ui/markdown-cache"
+import { preloadMarkdown } from "@opencode-ai/session-ui/markdown-cache"
const HOME_SESSION_LIMIT = 64
const HOME_ROW_LAYOUT =
diff --git a/packages/app/src/pages/layout/session-tab-avatar.tsx b/packages/app/src/pages/layout/session-tab-avatar.tsx
index 951bce96e2..bc816fda74 100644
--- a/packages/app/src/pages/layout/session-tab-avatar.tsx
+++ b/packages/app/src/pages/layout/session-tab-avatar.tsx
@@ -3,7 +3,7 @@ import { getProjectAvatarVariant } from "@/context/layout"
import { displayName, getProjectAvatarSource } from "@/pages/layout/helpers"
import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state"
import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2"
-import { SessionProgressIndicatorV2 } from "@opencode-ai/ui/v2/session-progress-indicator-v2"
+import { SessionProgressIndicatorV2 } from "@opencode-ai/session-ui/v2/session-progress-indicator-v2"
import { Show } from "solid-js"
export function SessionTabAvatar(props: {
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 7528534e56..6c9d1732f9 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -25,7 +25,7 @@ import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
import { Select } from "@opencode-ai/ui/select"
import { Tabs } from "@opencode-ai/ui/tabs"
import { createAutoScroll } from "@opencode-ai/ui/hooks"
-import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
+import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge"
import { Button } from "@opencode-ai/ui/button"
import { showToast } from "@/utils/toast"
import { base64Encode, checksum } from "@opencode-ai/core/util/encode"
diff --git a/packages/app/src/pages/session/composer/session-permission-dock.tsx b/packages/app/src/pages/session/composer/session-permission-dock.tsx
index 06ff4f4aa7..35a62f75cf 100644
--- a/packages/app/src/pages/session/composer/session-permission-dock.tsx
+++ b/packages/app/src/pages/session/composer/session-permission-dock.tsx
@@ -1,7 +1,7 @@
import { For, Show } from "solid-js"
import type { PermissionRequest } from "@opencode-ai/sdk/v2"
import { Button } from "@opencode-ai/ui/button"
-import { DockPrompt } from "@opencode-ai/ui/dock-prompt"
+import { DockPrompt } from "@opencode-ai/session-ui/dock-prompt"
import { Icon } from "@opencode-ai/ui/icon"
import { useLanguage } from "@/context/language"
diff --git a/packages/app/src/pages/session/composer/session-question-dock.tsx b/packages/app/src/pages/session/composer/session-question-dock.tsx
index 5fa0c97fb3..32d2bc4fe5 100644
--- a/packages/app/src/pages/session/composer/session-question-dock.tsx
+++ b/packages/app/src/pages/session/composer/session-question-dock.tsx
@@ -2,7 +2,7 @@ import { For, Show, createMemo, onCleanup, onMount, type Component } from "solid
import { createStore } from "solid-js/store"
import { useMutation } from "@tanstack/solid-query"
import { Button } from "@opencode-ai/ui/button"
-import { DockPrompt } from "@opencode-ai/ui/dock-prompt"
+import { DockPrompt } from "@opencode-ai/session-ui/dock-prompt"
import { Icon } from "@opencode-ai/ui/icon"
import { showToast } from "@/utils/toast"
import type { QuestionAnswer, QuestionRequest } from "@opencode-ai/sdk/v2"
diff --git a/packages/ui/src/components/todo-panel-motion.stories.tsx b/packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx
similarity index 100%
rename from packages/ui/src/components/todo-panel-motion.stories.tsx
rename to packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx
diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx
index 06d6637b37..7d110ee544 100644
--- a/packages/app/src/pages/session/file-tabs.tsx
+++ b/packages/app/src/pages/session/file-tabs.tsx
@@ -2,10 +2,10 @@ import { createEffect, createMemo, createSignal, Match, on, onCleanup, Switch }
import { createStore } from "solid-js/store"
import { Dynamic } from "solid-js/web"
import { makeEventListener } from "@solid-primitives/event-listener"
-import type { FileSearchHandle } from "@opencode-ai/ui/file"
+import type { FileSearchHandle } from "@opencode-ai/session-ui/file"
import { useFileComponent } from "@opencode-ai/ui/context/file"
-import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
-import { createLineCommentController } from "@opencode-ai/ui/line-comment-annotations"
+import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge"
+import { createLineCommentController } from "@opencode-ai/session-ui/line-comment-annotations"
import { sampledChecksum } from "@opencode-ai/core/util/encode"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { IconButton } from "@opencode-ai/ui/icon-button"
diff --git a/packages/app/src/pages/session/review-tab.tsx b/packages/app/src/pages/session/review-tab.tsx
index 9b5bf93cd4..3854bf0276 100644
--- a/packages/app/src/pages/session/review-tab.tsx
+++ b/packages/app/src/pages/session/review-tab.tsx
@@ -1,12 +1,12 @@
import { createEffect, onCleanup, type JSX } from "solid-js"
import { makeEventListener } from "@solid-primitives/event-listener"
import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2"
-import { SessionReview } from "@opencode-ai/ui/session-review"
+import { SessionReview } from "@opencode-ai/session-ui/session-review"
import type {
SessionReviewCommentActions,
SessionReviewCommentDelete,
SessionReviewCommentUpdate,
-} from "@opencode-ai/ui/session-review"
+} from "@opencode-ai/session-ui/session-review"
import type { SelectedLineRange } from "@/context/file"
import { useSDK } from "@/context/sdk"
import { useLayout } from "@/context/layout"
diff --git a/packages/app/src/pages/session/timeline/message-timeline.tsx b/packages/app/src/pages/session/timeline/message-timeline.tsx
index aedfa5b598..e546fedf2b 100644
--- a/packages/app/src/pages/session/timeline/message-timeline.tsx
+++ b/packages/app/src/pages/session/timeline/message-timeline.tsx
@@ -26,7 +26,7 @@ import {
Part as MessagePart,
partDefaultOpen,
type UserActions,
-} from "@opencode-ai/ui/message-part"
+} from "@opencode-ai/session-ui/message-part"
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
import { FileIcon } from "@opencode-ai/ui/file-icon"
import { Icon } from "@opencode-ai/ui/icon"
@@ -35,7 +35,7 @@ import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { Dialog } from "@opencode-ai/ui/dialog"
import { InlineInput } from "@opencode-ai/ui/inline-input"
import { Spinner } from "@opencode-ai/ui/spinner"
-import { SessionRetry } from "@opencode-ai/ui/session-retry"
+import { SessionRetry } from "@opencode-ai/session-ui/session-retry"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
import { TextField } from "@opencode-ai/ui/text-field"
@@ -51,7 +51,7 @@ import type {
import { showToast } from "@/utils/toast"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { Popover as KobaltePopover } from "@kobalte/core/popover"
-import { normalize } from "@opencode-ai/ui/session-diff"
+import { normalize } from "@opencode-ai/session-ui/session-diff"
import { useFileComponent } from "@opencode-ai/ui/context/file"
import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture"
import { SessionContextUsage } from "@/components/session-context-usage"
diff --git a/packages/app/src/pages/session/timeline/rows.ts b/packages/app/src/pages/session/timeline/rows.ts
index bc5719bdcf..5e023b83f4 100644
--- a/packages/app/src/pages/session/timeline/rows.ts
+++ b/packages/app/src/pages/session/timeline/rows.ts
@@ -1,6 +1,6 @@
import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note"
import { AssistantMessage, Part, SessionStatus, SnapshotFileDiff, UserMessage } from "@opencode-ai/sdk/v2"
-import { groupParts, PartGroup, renderable } from "@opencode-ai/ui/message-part"
+import { groupParts, PartGroup, renderable } from "@opencode-ai/session-ui/message-part"
import { Data, Equal } from "effect"
export type SummaryDiff = SnapshotFileDiff & { file: string }
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index f64c5c26ae..fa35204596 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -1,7 +1,7 @@
import { useNavigate } from "@solidjs/router"
import { useCommand, type CommandOption } from "@/context/command"
import { useDialog } from "@opencode-ai/ui/context/dialog"
-import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
+import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge"
import { useFile, selectionFromLines, type FileSelection, type SelectedLineRange } from "@/context/file"
import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout"
diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json
index 69534b07f7..0ba9259e12 100644
--- a/packages/enterprise/package.json
+++ b/packages/enterprise/package.json
@@ -14,6 +14,7 @@
},
"dependencies": {
"@opencode-ai/core": "workspace:*",
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"aws4fetch": "^1.0.20",
"@pierre/diffs": "catalog:",
diff --git a/packages/enterprise/src/app.css b/packages/enterprise/src/app.css
index 4af87bca63..1d3a4abf85 100644
--- a/packages/enterprise/src/app.css
+++ b/packages/enterprise/src/app.css
@@ -1 +1,2 @@
@import "@opencode-ai/ui/styles/tailwind";
+@import "@opencode-ai/session-ui/styles";
diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx
index 6d83fb4598..8c8ac59f7a 100644
--- a/packages/enterprise/src/routes/share/[shareID].tsx
+++ b/packages/enterprise/src/routes/share/[shareID].tsx
@@ -1,7 +1,7 @@
import { Message, Model, Part, Session, SessionStatus, SnapshotFileDiff, UserMessage } from "@opencode-ai/sdk/v2"
-import { SessionTurn } from "@opencode-ai/ui/session-turn"
-import { SessionReview } from "@opencode-ai/ui/session-review"
-import { DataProvider } from "@opencode-ai/ui/context"
+import { SessionTurn } from "@opencode-ai/session-ui/session-turn"
+import { SessionReview } from "@opencode-ai/session-ui/session-review"
+import { DataProvider } from "@opencode-ai/session-ui/context"
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
import { WorkerPoolProvider } from "@opencode-ai/ui/context/worker-pool"
import { createAsync, query, useParams } from "@solidjs/router"
@@ -17,15 +17,15 @@ import { DateTime } from "luxon"
import { createStore } from "solid-js/store"
import NotFound from "../[...404]"
import { Tabs } from "@opencode-ai/ui/tabs"
-import { MessageNav } from "@opencode-ai/ui/message-nav"
-import { FileSSR } from "@opencode-ai/ui/file-ssr"
+import { MessageNav } from "@opencode-ai/session-ui/message-nav"
+import { FileSSR } from "@opencode-ai/session-ui/file-ssr"
import { clientOnly } from "@solidjs/start"
import { Meta, Title } from "@solidjs/meta"
import { Base64 } from "js-base64"
import { getRequestEvent } from "solid-js/web"
const ClientOnlyWorkerPoolProvider = clientOnly(() =>
- import("@opencode-ai/ui/pierre/worker").then((m) => ({
+ import("@opencode-ai/session-ui/pierre/worker").then((m) => ({
default: (props: { children: any }) => (
{props.children}
),
diff --git a/packages/session-ui/package.json b/packages/session-ui/package.json
new file mode 100644
index 0000000000..e2b579b426
--- /dev/null
+++ b/packages/session-ui/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "@opencode-ai/session-ui",
+ "version": "1.17.9",
+ "private": true,
+ "type": "module",
+ "license": "MIT",
+ "exports": {
+ "./*": "./src/components/*.tsx",
+ "./session-diff": "./src/components/session-diff.ts",
+ "./message-file": "./src/components/message-file.ts",
+ "./message-part-text": "./src/components/message-part-text.ts",
+ "./markdown-stream": "./src/components/markdown-stream.ts",
+ "./markdown-cache": "./src/components/markdown-cache.tsx",
+ "./line-comment-styles": "./src/components/line-comment-styles.ts",
+ "./pierre": "./src/pierre/index.ts",
+ "./pierre/*": "./src/pierre/*.ts",
+ "./context": "./src/context/index.ts",
+ "./context/*": "./src/context/*.tsx",
+ "./styles": "./src/styles/index.css",
+ "./v2/*.css": "./src/v2/components/*.css",
+ "./v2/*": "./src/v2/components/*.tsx"
+ },
+ "scripts": {
+ "typecheck": "tsgo --noEmit",
+ "test": "bun test src --only-failures"
+ },
+ "devDependencies": {
+ "@tsconfig/node22": "catalog:",
+ "@types/bun": "catalog:",
+ "@types/katex": "0.16.7",
+ "@types/luxon": "catalog:",
+ "@typescript/native-preview": "catalog:",
+ "typescript": "catalog:",
+ "vite": "catalog:"
+ },
+ "dependencies": {
+ "@kobalte/core": "catalog:",
+ "@opencode-ai/core": "workspace:*",
+ "@opencode-ai/sdk": "workspace:*",
+ "@opencode-ai/ui": "workspace:*",
+ "@pierre/diffs": "catalog:",
+ "@shikijs/stream": "catalog:",
+ "@shikijs/transformers": "3.9.2",
+ "@solid-primitives/bounds": "0.1.3",
+ "@solid-primitives/event-listener": "2.4.5",
+ "@solid-primitives/media": "2.3.3",
+ "@solid-primitives/resize-observer": "2.1.3",
+ "@solidjs/meta": "catalog:",
+ "@solidjs/router": "catalog:",
+ "diff": "catalog:",
+ "dompurify": "3.3.1",
+ "fuzzysort": "catalog:",
+ "katex": "0.16.27",
+ "luxon": "catalog:",
+ "marked": "catalog:",
+ "marked-katex-extension": "5.1.6",
+ "marked-shiki": "catalog:",
+ "morphdom": "2.7.8",
+ "motion": "12.34.5",
+ "remeda": "catalog:",
+ "remend": "catalog:",
+ "shiki": "catalog:",
+ "solid-js": "catalog:",
+ "solid-list": "catalog:",
+ "strip-ansi": "7.1.2"
+ }
+}
diff --git a/packages/ui/src/components/apply-patch-file.test.ts b/packages/session-ui/src/components/apply-patch-file.test.ts
similarity index 100%
rename from packages/ui/src/components/apply-patch-file.test.ts
rename to packages/session-ui/src/components/apply-patch-file.test.ts
diff --git a/packages/ui/src/components/apply-patch-file.ts b/packages/session-ui/src/components/apply-patch-file.ts
similarity index 100%
rename from packages/ui/src/components/apply-patch-file.ts
rename to packages/session-ui/src/components/apply-patch-file.ts
diff --git a/packages/ui/src/components/basic-tool.css b/packages/session-ui/src/components/basic-tool.css
similarity index 100%
rename from packages/ui/src/components/basic-tool.css
rename to packages/session-ui/src/components/basic-tool.css
diff --git a/packages/ui/src/components/basic-tool.stories.tsx b/packages/session-ui/src/components/basic-tool.stories.tsx
similarity index 97%
rename from packages/ui/src/components/basic-tool.stories.tsx
rename to packages/session-ui/src/components/basic-tool.stories.tsx
index 9d9d97acfe..5fb366c016 100644
--- a/packages/ui/src/components/basic-tool.stories.tsx
+++ b/packages/session-ui/src/components/basic-tool.stories.tsx
@@ -1,7 +1,7 @@
// @ts-nocheck
import { createSignal } from "solid-js"
import * as mod from "./basic-tool"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const docs = `### Overview
Expandable tool panel with a structured trigger and optional details.
diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/session-ui/src/components/basic-tool.tsx
similarity index 97%
rename from packages/ui/src/components/basic-tool.tsx
rename to packages/session-ui/src/components/basic-tool.tsx
index 2477ff99b5..4f2a4ced6f 100644
--- a/packages/ui/src/components/basic-tool.tsx
+++ b/packages/session-ui/src/components/basic-tool.tsx
@@ -1,10 +1,10 @@
import { createEffect, For, Match, on, onCleanup, onMount, Show, Switch, type Accessor, type JSX } from "solid-js"
import { animate, type AnimationPlaybackControls } from "motion"
-import { useI18n } from "../context/i18n"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import { createStore } from "solid-js/store"
-import { Collapsible } from "./collapsible"
-import type { IconProps } from "./icon"
-import { TextShimmer } from "./text-shimmer"
+import { Collapsible } from "@opencode-ai/ui/collapsible"
+import type { IconProps } from "@opencode-ai/ui/icon"
+import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
export type TriggerTitle = {
title: string
diff --git a/packages/ui/src/components/dock-prompt.stories.tsx b/packages/session-ui/src/components/dock-prompt.stories.tsx
similarity index 95%
rename from packages/ui/src/components/dock-prompt.stories.tsx
rename to packages/session-ui/src/components/dock-prompt.stories.tsx
index de017a1ba2..f75b04bc21 100644
--- a/packages/ui/src/components/dock-prompt.stories.tsx
+++ b/packages/session-ui/src/components/dock-prompt.stories.tsx
@@ -1,6 +1,6 @@
// @ts-nocheck
import * as mod from "./dock-prompt"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const docs = `### Overview
Docked prompt layout for questions and permission requests.
diff --git a/packages/ui/src/components/dock-prompt.tsx b/packages/session-ui/src/components/dock-prompt.tsx
similarity index 91%
rename from packages/ui/src/components/dock-prompt.tsx
rename to packages/session-ui/src/components/dock-prompt.tsx
index 01f1848c84..75563e47b8 100644
--- a/packages/ui/src/components/dock-prompt.tsx
+++ b/packages/session-ui/src/components/dock-prompt.tsx
@@ -1,5 +1,5 @@
import type { JSX } from "solid-js"
-import { DockShell, DockTray } from "./dock-surface"
+import { DockShell, DockTray } from "@opencode-ai/ui/dock-surface"
export function DockPrompt(props: {
kind: "question" | "permission"
diff --git a/packages/ui/src/components/file-media.tsx b/packages/session-ui/src/components/file-media.tsx
similarity index 99%
rename from packages/ui/src/components/file-media.tsx
rename to packages/session-ui/src/components/file-media.tsx
index f066019d72..7e26853f08 100644
--- a/packages/ui/src/components/file-media.tsx
+++ b/packages/session-ui/src/components/file-media.tsx
@@ -1,6 +1,6 @@
import type { FileContent } from "@opencode-ai/sdk/v2"
import { createEffect, createMemo, createResource, Match, on, Show, Switch, type JSX } from "solid-js"
-import { useI18n } from "../context/i18n"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import {
dataUrlFromMediaValue,
hasMediaValue,
diff --git a/packages/ui/src/components/file-search.tsx b/packages/session-ui/src/components/file-search.tsx
similarity index 96%
rename from packages/ui/src/components/file-search.tsx
rename to packages/session-ui/src/components/file-search.tsx
index 244e9c2733..181ff9fea8 100644
--- a/packages/ui/src/components/file-search.tsx
+++ b/packages/session-ui/src/components/file-search.tsx
@@ -1,6 +1,6 @@
import { Portal } from "solid-js/web"
-import { useI18n } from "../context/i18n"
-import { Icon } from "./icon"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
+import { Icon } from "@opencode-ai/ui/icon"
export function FileSearchBar(props: {
pos: () => { top: number; right: number }
diff --git a/packages/ui/src/components/file-ssr.tsx b/packages/session-ui/src/components/file-ssr.tsx
similarity index 98%
rename from packages/ui/src/components/file-ssr.tsx
rename to packages/session-ui/src/components/file-ssr.tsx
index 6f11ca2433..68b5568edc 100644
--- a/packages/ui/src/components/file-ssr.tsx
+++ b/packages/session-ui/src/components/file-ssr.tsx
@@ -2,7 +2,7 @@ import { DIFFS_TAG_NAME, FileDiff, VirtualizedFileDiff } from "@pierre/diffs"
import { type PreloadFileDiffResult, type PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
import { createEffect, onCleanup, onMount, Show, splitProps } from "solid-js"
import { Dynamic, isServer } from "solid-js/web"
-import { useWorkerPool } from "../context/worker-pool"
+import { useWorkerPool } from "@opencode-ai/ui/context/worker-pool"
import { createDefaultOptions, styleVariables } from "../pierre"
import { markCommentedDiffLines } from "../pierre/commented-lines"
import { fixDiffSelection } from "../pierre/diff-selection"
diff --git a/packages/ui/src/components/file.css b/packages/session-ui/src/components/file.css
similarity index 100%
rename from packages/ui/src/components/file.css
rename to packages/session-ui/src/components/file.css
diff --git a/packages/ui/src/components/file.tsx b/packages/session-ui/src/components/file.tsx
similarity index 100%
rename from packages/ui/src/components/file.tsx
rename to packages/session-ui/src/components/file.tsx
diff --git a/packages/ui/src/components/line-comment-annotations.tsx b/packages/session-ui/src/components/line-comment-annotations.tsx
similarity index 99%
rename from packages/ui/src/components/line-comment-annotations.tsx
rename to packages/session-ui/src/components/line-comment-annotations.tsx
index c8fe70c758..edff8c00ad 100644
--- a/packages/ui/src/components/line-comment-annotations.tsx
+++ b/packages/session-ui/src/components/line-comment-annotations.tsx
@@ -2,7 +2,7 @@ import { type DiffLineAnnotation, type SelectedLineRange } from "@pierre/diffs"
import { createEffect, createMemo, createSignal, onCleanup, Show, type Accessor, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { render as renderSolid } from "solid-js/web"
-import { useI18n } from "../context/i18n"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import { createHoverCommentUtility } from "../pierre/comment-hover"
import { cloneSelectedLineRange, formatSelectedLineLabel, lineInSelectedRange } from "../pierre/selection-bridge"
import { LineComment, LineCommentEditor, type LineCommentEditorProps } from "./line-comment"
diff --git a/packages/ui/src/components/line-comment-styles.ts b/packages/session-ui/src/components/line-comment-styles.ts
similarity index 100%
rename from packages/ui/src/components/line-comment-styles.ts
rename to packages/session-ui/src/components/line-comment-styles.ts
diff --git a/packages/ui/src/components/line-comment.stories.tsx b/packages/session-ui/src/components/line-comment.stories.tsx
similarity index 100%
rename from packages/ui/src/components/line-comment.stories.tsx
rename to packages/session-ui/src/components/line-comment.stories.tsx
diff --git a/packages/ui/src/components/line-comment.tsx b/packages/session-ui/src/components/line-comment.tsx
similarity index 98%
rename from packages/ui/src/components/line-comment.tsx
rename to packages/session-ui/src/components/line-comment.tsx
index 983cf0ed10..0ad1a590e7 100644
--- a/packages/ui/src/components/line-comment.tsx
+++ b/packages/session-ui/src/components/line-comment.tsx
@@ -1,11 +1,11 @@
import { useFilteredList } from "@opencode-ai/ui/hooks"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { createSignal, For, onMount, Show, splitProps, type JSX } from "solid-js"
-import { Button } from "./button"
-import { FileIcon } from "./file-icon"
-import { Icon } from "./icon"
+import { Button } from "@opencode-ai/ui/button"
+import { FileIcon } from "@opencode-ai/ui/file-icon"
+import { Icon } from "@opencode-ai/ui/icon"
import { installLineCommentStyles } from "./line-comment-styles"
-import { useI18n } from "../context/i18n"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
installLineCommentStyles()
diff --git a/packages/ui/src/components/markdown-cache.tsx b/packages/session-ui/src/components/markdown-cache.tsx
similarity index 100%
rename from packages/ui/src/components/markdown-cache.tsx
rename to packages/session-ui/src/components/markdown-cache.tsx
diff --git a/packages/ui/src/components/markdown-code-state.test.ts b/packages/session-ui/src/components/markdown-code-state.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-code-state.test.ts
rename to packages/session-ui/src/components/markdown-code-state.test.ts
diff --git a/packages/ui/src/components/markdown-code-state.ts b/packages/session-ui/src/components/markdown-code-state.ts
similarity index 100%
rename from packages/ui/src/components/markdown-code-state.ts
rename to packages/session-ui/src/components/markdown-code-state.ts
diff --git a/packages/ui/src/components/markdown-preload.test.ts b/packages/session-ui/src/components/markdown-preload.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-preload.test.ts
rename to packages/session-ui/src/components/markdown-preload.test.ts
diff --git a/packages/ui/src/components/markdown-shiki.worker.ts b/packages/session-ui/src/components/markdown-shiki.worker.ts
similarity index 100%
rename from packages/ui/src/components/markdown-shiki.worker.ts
rename to packages/session-ui/src/components/markdown-shiki.worker.ts
diff --git a/packages/ui/src/components/markdown-stream.test.ts b/packages/session-ui/src/components/markdown-stream.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-stream.test.ts
rename to packages/session-ui/src/components/markdown-stream.test.ts
diff --git a/packages/ui/src/components/markdown-stream.ts b/packages/session-ui/src/components/markdown-stream.ts
similarity index 100%
rename from packages/ui/src/components/markdown-stream.ts
rename to packages/session-ui/src/components/markdown-stream.ts
diff --git a/packages/ui/src/components/markdown-worker-protocol.test.ts b/packages/session-ui/src/components/markdown-worker-protocol.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-protocol.test.ts
rename to packages/session-ui/src/components/markdown-worker-protocol.test.ts
diff --git a/packages/ui/src/components/markdown-worker-protocol.ts b/packages/session-ui/src/components/markdown-worker-protocol.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-protocol.ts
rename to packages/session-ui/src/components/markdown-worker-protocol.ts
diff --git a/packages/ui/src/components/markdown-worker-queue.test.ts b/packages/session-ui/src/components/markdown-worker-queue.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-queue.test.ts
rename to packages/session-ui/src/components/markdown-worker-queue.test.ts
diff --git a/packages/ui/src/components/markdown-worker-queue.ts b/packages/session-ui/src/components/markdown-worker-queue.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-queue.ts
rename to packages/session-ui/src/components/markdown-worker-queue.ts
diff --git a/packages/ui/src/components/markdown-worker-transport.test.ts b/packages/session-ui/src/components/markdown-worker-transport.test.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-transport.test.ts
rename to packages/session-ui/src/components/markdown-worker-transport.test.ts
diff --git a/packages/ui/src/components/markdown-worker-transport.ts b/packages/session-ui/src/components/markdown-worker-transport.ts
similarity index 100%
rename from packages/ui/src/components/markdown-worker-transport.ts
rename to packages/session-ui/src/components/markdown-worker-transport.ts
diff --git a/packages/ui/src/components/markdown-worker.ts b/packages/session-ui/src/components/markdown-worker.ts
similarity index 98%
rename from packages/ui/src/components/markdown-worker.ts
rename to packages/session-ui/src/components/markdown-worker.ts
index a48e98bbd0..1ca87467bb 100644
--- a/packages/ui/src/components/markdown-worker.ts
+++ b/packages/session-ui/src/components/markdown-worker.ts
@@ -1,5 +1,5 @@
import MarkdownShikiWorkerUrl from "./markdown-shiki.worker.ts?worker&url"
-import { OpenCodeTheme } from "../context/marked"
+import { OpenCodeTheme } from "@opencode-ai/ui/context/marked"
import {
applyMarkdownWorkerResponse,
shouldReleaseMarkdownWorkerState,
diff --git a/packages/ui/src/components/markdown.css b/packages/session-ui/src/components/markdown.css
similarity index 100%
rename from packages/ui/src/components/markdown.css
rename to packages/session-ui/src/components/markdown.css
diff --git a/packages/ui/src/components/markdown.stories.tsx b/packages/session-ui/src/components/markdown.stories.tsx
similarity index 89%
rename from packages/ui/src/components/markdown.stories.tsx
rename to packages/session-ui/src/components/markdown.stories.tsx
index cae4294869..c4f99dc2f1 100644
--- a/packages/ui/src/components/markdown.stories.tsx
+++ b/packages/session-ui/src/components/markdown.stories.tsx
@@ -1,7 +1,7 @@
// @ts-nocheck
import * as mod from "./markdown"
-import { create } from "../storybook/scaffold"
-import { markdown } from "../storybook/fixtures"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
+import { markdown } from "@opencode-ai/ui/storybook/fixtures"
const docs = `### Overview
Render sanitized Markdown with code blocks, inline code, and safe links.
diff --git a/packages/ui/src/components/markdown.tsx b/packages/session-ui/src/components/markdown.tsx
similarity index 99%
rename from packages/ui/src/components/markdown.tsx
rename to packages/session-ui/src/components/markdown.tsx
index ee21803851..97dc9e1062 100644
--- a/packages/ui/src/components/markdown.tsx
+++ b/packages/session-ui/src/components/markdown.tsx
@@ -1,5 +1,5 @@
-import { useMarked } from "../context/marked"
-import { useI18n } from "../context/i18n"
+import { useMarked } from "@opencode-ai/ui/context/marked"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import morphdom from "morphdom"
import { checksum } from "@opencode-ai/core/util/encode"
import {
diff --git a/packages/ui/src/components/message-file.test.ts b/packages/session-ui/src/components/message-file.test.ts
similarity index 100%
rename from packages/ui/src/components/message-file.test.ts
rename to packages/session-ui/src/components/message-file.test.ts
diff --git a/packages/ui/src/components/message-file.ts b/packages/session-ui/src/components/message-file.ts
similarity index 100%
rename from packages/ui/src/components/message-file.ts
rename to packages/session-ui/src/components/message-file.ts
diff --git a/packages/ui/src/components/message-nav.css b/packages/session-ui/src/components/message-nav.css
similarity index 100%
rename from packages/ui/src/components/message-nav.css
rename to packages/session-ui/src/components/message-nav.css
diff --git a/packages/ui/src/components/message-nav.stories.tsx b/packages/session-ui/src/components/message-nav.stories.tsx
similarity index 80%
rename from packages/ui/src/components/message-nav.stories.tsx
rename to packages/session-ui/src/components/message-nav.stories.tsx
index 7ce31a7bed..2bd4532506 100644
--- a/packages/ui/src/components/message-nav.stories.tsx
+++ b/packages/session-ui/src/components/message-nav.stories.tsx
@@ -1,6 +1,6 @@
// @ts-nocheck
import * as mod from "./message-nav"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const story = create({ title: "UI/MessageNav", mod })
export default { title: "UI/MessageNav", id: "components-message-nav", component: story.meta.component }
diff --git a/packages/ui/src/components/message-nav.tsx b/packages/session-ui/src/components/message-nav.tsx
similarity index 96%
rename from packages/ui/src/components/message-nav.tsx
rename to packages/session-ui/src/components/message-nav.tsx
index 4a061c90a6..85db1e1bcd 100644
--- a/packages/ui/src/components/message-nav.tsx
+++ b/packages/session-ui/src/components/message-nav.tsx
@@ -1,8 +1,8 @@
import { UserMessage } from "@opencode-ai/sdk/v2"
import { HoverCard } from "@kobalte/core/hover-card"
import { ComponentProps, For, Match, Show, createSignal, splitProps, Switch } from "solid-js"
-import { DiffChanges } from "./diff-changes"
-import { useI18n } from "../context/i18n"
+import { DiffChanges } from "@opencode-ai/ui/diff-changes"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
export function MessageNav(
props: ComponentProps<"ul"> & {
diff --git a/packages/ui/src/components/message-part-text.ts b/packages/session-ui/src/components/message-part-text.ts
similarity index 100%
rename from packages/ui/src/components/message-part-text.ts
rename to packages/session-ui/src/components/message-part-text.ts
diff --git a/packages/ui/src/components/message-part.css b/packages/session-ui/src/components/message-part.css
similarity index 100%
rename from packages/ui/src/components/message-part.css
rename to packages/session-ui/src/components/message-part.css
diff --git a/packages/ui/src/components/message-part.stories.tsx b/packages/session-ui/src/components/message-part.stories.tsx
similarity index 80%
rename from packages/ui/src/components/message-part.stories.tsx
rename to packages/session-ui/src/components/message-part.stories.tsx
index 28489dc7b1..f32f8b281f 100644
--- a/packages/ui/src/components/message-part.stories.tsx
+++ b/packages/session-ui/src/components/message-part.stories.tsx
@@ -1,6 +1,6 @@
// @ts-nocheck
import * as mod from "./message-part"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const story = create({ title: "UI/MessagePart", mod })
export default { title: "UI/MessagePart", id: "components-message-part", component: story.meta.component }
diff --git a/packages/ui/src/components/message-part.test.ts b/packages/session-ui/src/components/message-part.test.ts
similarity index 100%
rename from packages/ui/src/components/message-part.test.ts
rename to packages/session-ui/src/components/message-part.test.ts
diff --git a/packages/ui/src/components/message-part.tsx b/packages/session-ui/src/components/message-part.tsx
similarity index 98%
rename from packages/ui/src/components/message-part.tsx
rename to packages/session-ui/src/components/message-part.tsx
index 47ae745e4c..4af05c2584 100644
--- a/packages/ui/src/components/message-part.tsx
+++ b/packages/session-ui/src/components/message-part.tsx
@@ -31,26 +31,26 @@ import {
QuestionInfo,
} from "@opencode-ai/sdk/v2"
import { useData } from "../context"
-import { useFileComponent } from "../context/file"
-import { useDialog } from "../context/dialog"
-import { type UiI18n, useI18n } from "../context/i18n"
+import { useFileComponent } from "@opencode-ai/ui/context/file"
+import { useDialog } from "@opencode-ai/ui/context/dialog"
+import { type UiI18n, useI18n } from "@opencode-ai/ui/context/i18n"
import { BasicTool, GenericTool } from "./basic-tool"
-import { Accordion } from "./accordion"
-import { StickyAccordionHeader } from "./sticky-accordion-header"
-import { Collapsible } from "./collapsible"
-import { FileIcon } from "./file-icon"
-import { Icon } from "./icon"
+import { Accordion } from "@opencode-ai/ui/accordion"
+import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
+import { Collapsible } from "@opencode-ai/ui/collapsible"
+import { FileIcon } from "@opencode-ai/ui/file-icon"
+import { Icon } from "@opencode-ai/ui/icon"
import { ToolErrorCard } from "./tool-error-card"
-import { Checkbox } from "./checkbox"
-import { DiffChanges } from "./diff-changes"
+import { Checkbox } from "@opencode-ai/ui/checkbox"
+import { DiffChanges } from "@opencode-ai/ui/diff-changes"
import { Markdown } from "./markdown"
-import { ImagePreview } from "./image-preview"
+import { ImagePreview } from "@opencode-ai/ui/image-preview"
import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { checksum } from "@opencode-ai/core/util/encode"
-import { Tooltip } from "./tooltip"
-import { IconButton } from "./icon-button"
-import { Spinner } from "./spinner"
-import { TextShimmer } from "./text-shimmer"
+import { Tooltip } from "@opencode-ai/ui/tooltip"
+import { IconButton } from "@opencode-ai/ui/icon-button"
+import { Spinner } from "@opencode-ai/ui/spinner"
+import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
import { AnimatedCountList } from "./tool-count-summary"
import { ToolStatusTitle } from "./tool-status-title"
import { patchFiles } from "./apply-patch-file"
@@ -303,7 +303,7 @@ function getDirectory(path: string | undefined) {
return relativizeProjectPath(_getDirectory(path), data.directory)
}
-import type { IconProps } from "./icon"
+import type { IconProps } from "@opencode-ai/ui/icon"
import { normalize, resolveFileDiff } from "./session-diff"
export type ToolInfo = {
diff --git a/packages/ui/src/components/session-diff.test.ts b/packages/session-ui/src/components/session-diff.test.ts
similarity index 100%
rename from packages/ui/src/components/session-diff.test.ts
rename to packages/session-ui/src/components/session-diff.test.ts
diff --git a/packages/ui/src/components/session-diff.ts b/packages/session-ui/src/components/session-diff.ts
similarity index 100%
rename from packages/ui/src/components/session-diff.ts
rename to packages/session-ui/src/components/session-diff.ts
diff --git a/packages/ui/src/components/session-retry.tsx b/packages/session-ui/src/components/session-retry.tsx
similarity index 93%
rename from packages/ui/src/components/session-retry.tsx
rename to packages/session-ui/src/components/session-retry.tsx
index ac0eb035d9..cf2d6c9459 100644
--- a/packages/ui/src/components/session-retry.tsx
+++ b/packages/session-ui/src/components/session-retry.tsx
@@ -1,9 +1,9 @@
import { createEffect, createMemo, createSignal, on, onCleanup, Show } from "solid-js"
import type { SessionStatus } from "@opencode-ai/sdk/v2/client"
-import { useI18n } from "../context/i18n"
-import { Card } from "./card"
-import { Tooltip } from "./tooltip"
-import { Spinner } from "./spinner"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
+import { Card } from "@opencode-ai/ui/card"
+import { Tooltip } from "@opencode-ai/ui/tooltip"
+import { Spinner } from "@opencode-ai/ui/spinner"
export function SessionRetry(props: { status: SessionStatus; show?: boolean }) {
const i18n = useI18n()
diff --git a/packages/ui/src/components/session-review.css b/packages/session-ui/src/components/session-review.css
similarity index 100%
rename from packages/ui/src/components/session-review.css
rename to packages/session-ui/src/components/session-review.css
diff --git a/packages/ui/src/components/session-review.stories.tsx b/packages/session-ui/src/components/session-review.stories.tsx
similarity index 81%
rename from packages/ui/src/components/session-review.stories.tsx
rename to packages/session-ui/src/components/session-review.stories.tsx
index 7ab1eb2038..c09717384c 100644
--- a/packages/ui/src/components/session-review.stories.tsx
+++ b/packages/session-ui/src/components/session-review.stories.tsx
@@ -1,6 +1,6 @@
// @ts-nocheck
import * as mod from "./session-review"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const story = create({ title: "UI/SessionReview", mod })
export default { title: "UI/SessionReview", id: "components-session-review", component: story.meta.component }
diff --git a/packages/ui/src/components/session-review.tsx b/packages/session-ui/src/components/session-review.tsx
similarity index 97%
rename from packages/ui/src/components/session-review.tsx
rename to packages/session-ui/src/components/session-review.tsx
index 7aad942c5d..8db21f025b 100644
--- a/packages/ui/src/components/session-review.tsx
+++ b/packages/session-ui/src/components/session-review.tsx
@@ -1,16 +1,16 @@
-import { Accordion } from "./accordion"
-import { Button } from "./button"
-import { DropdownMenu } from "./dropdown-menu"
-import { RadioGroup } from "./radio-group"
-import { DiffChanges } from "./diff-changes"
-import { FileIcon } from "./file-icon"
-import { Icon } from "./icon"
-import { IconButton } from "./icon-button"
-import { StickyAccordionHeader } from "./sticky-accordion-header"
-import { Tooltip } from "./tooltip"
-import { ScrollView } from "./scroll-view"
-import { useFileComponent } from "../context/file"
-import { useI18n } from "../context/i18n"
+import { Accordion } from "@opencode-ai/ui/accordion"
+import { Button } from "@opencode-ai/ui/button"
+import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
+import { RadioGroup } from "@opencode-ai/ui/radio-group"
+import { DiffChanges } from "@opencode-ai/ui/diff-changes"
+import { FileIcon } from "@opencode-ai/ui/file-icon"
+import { Icon } from "@opencode-ai/ui/icon"
+import { IconButton } from "@opencode-ai/ui/icon-button"
+import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
+import { Tooltip } from "@opencode-ai/ui/tooltip"
+import { ScrollView } from "@opencode-ai/ui/scroll-view"
+import { useFileComponent } from "@opencode-ai/ui/context/file"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { checksum } from "@opencode-ai/core/util/encode"
import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
diff --git a/packages/ui/src/components/session-turn.css b/packages/session-ui/src/components/session-turn.css
similarity index 100%
rename from packages/ui/src/components/session-turn.css
rename to packages/session-ui/src/components/session-turn.css
diff --git a/packages/ui/src/components/session-turn.stories.tsx b/packages/session-ui/src/components/session-turn.stories.tsx
similarity index 80%
rename from packages/ui/src/components/session-turn.stories.tsx
rename to packages/session-ui/src/components/session-turn.stories.tsx
index 927402c8db..4b43fd20d0 100644
--- a/packages/ui/src/components/session-turn.stories.tsx
+++ b/packages/session-ui/src/components/session-turn.stories.tsx
@@ -1,6 +1,6 @@
// @ts-nocheck
import * as mod from "./session-turn"
-import { create } from "../storybook/scaffold"
+import { create } from "@opencode-ai/ui/storybook/scaffold"
const story = create({ title: "UI/SessionTurn", mod })
export default { title: "UI/SessionTurn", id: "components-session-turn", component: story.meta.component }
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/session-ui/src/components/session-turn.tsx
similarity index 97%
rename from packages/ui/src/components/session-turn.tsx
rename to packages/session-ui/src/components/session-turn.tsx
index a39b9a7f64..4ebf6459b1 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/session-ui/src/components/session-turn.tsx
@@ -6,7 +6,7 @@ import {
} from "@opencode-ai/sdk/v2/client"
import type { SessionStatus } from "@opencode-ai/sdk/v2"
import { useData } from "../context"
-import { useFileComponent } from "../context/file"
+import { useFileComponent } from "@opencode-ai/ui/context/file"
import { Binary } from "@opencode-ai/core/util/binary"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
@@ -14,16 +14,16 @@ import { createEffect, createMemo, createSignal, For, on, ParentProps, Show } fr
import { createStore } from "solid-js/store"
import { Dynamic } from "solid-js/web"
import { AssistantParts, Message, MessageDivider, PART_MAPPING, type UserActions } from "./message-part"
-import { Card } from "./card"
-import { Accordion } from "./accordion"
-import { StickyAccordionHeader } from "./sticky-accordion-header"
-import { DiffChanges } from "./diff-changes"
-import { Icon } from "./icon"
-import { TextShimmer } from "./text-shimmer"
+import { Card } from "@opencode-ai/ui/card"
+import { Accordion } from "@opencode-ai/ui/accordion"
+import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
+import { DiffChanges } from "@opencode-ai/ui/diff-changes"
+import { Icon } from "@opencode-ai/ui/icon"
+import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
import { SessionRetry } from "./session-retry"
-import { TextReveal } from "./text-reveal"
-import { createAutoScroll } from "../hooks"
-import { useI18n } from "../context/i18n"
+import { TextReveal } from "@opencode-ai/ui/text-reveal"
+import { createAutoScroll } from "@opencode-ai/ui/hooks"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
import { normalize } from "./session-diff"
function record(value: unknown): value is Record {
diff --git a/packages/ui/src/components/shell-submessage-motion.stories.tsx b/packages/session-ui/src/components/shell-submessage-motion.stories.tsx
similarity index 100%
rename from packages/ui/src/components/shell-submessage-motion.stories.tsx
rename to packages/session-ui/src/components/shell-submessage-motion.stories.tsx
diff --git a/packages/ui/src/components/shell-submessage.css b/packages/session-ui/src/components/shell-submessage.css
similarity index 100%
rename from packages/ui/src/components/shell-submessage.css
rename to packages/session-ui/src/components/shell-submessage.css
diff --git a/packages/ui/src/components/timeline-playground.stories.tsx b/packages/session-ui/src/components/timeline-playground.stories.tsx
similarity index 99%
rename from packages/ui/src/components/timeline-playground.stories.tsx
rename to packages/session-ui/src/components/timeline-playground.stories.tsx
index a189e3d0f3..491ba2063c 100644
--- a/packages/ui/src/components/timeline-playground.stories.tsx
+++ b/packages/session-ui/src/components/timeline-playground.stories.tsx
@@ -13,7 +13,7 @@ import type {
AgentPart,
} from "@opencode-ai/sdk/v2"
import { DataProvider } from "../context/data"
-import { FileComponentProvider } from "../context/file"
+import { FileComponentProvider } from "@opencode-ai/ui/context/file"
import { SessionTurn } from "./session-turn"
// ---------------------------------------------------------------------------
@@ -558,7 +558,7 @@ function toolPart(sample: (typeof TOOL_SAMPLES)[keyof typeof TOOL_SAMPLES], stat
// CSS Controls definition
// ---------------------------------------------------------------------------
-// Source file basenames inside packages/ui/src/components/
+// Source file basenames inside the UI component packages.
const MD = "markdown.css"
const MP = "message-part.css"
const ST = "session-turn.css"
diff --git a/packages/ui/src/components/tool-count-label.css b/packages/session-ui/src/components/tool-count-label.css
similarity index 100%
rename from packages/ui/src/components/tool-count-label.css
rename to packages/session-ui/src/components/tool-count-label.css
diff --git a/packages/ui/src/components/tool-count-label.tsx b/packages/session-ui/src/components/tool-count-label.tsx
similarity index 97%
rename from packages/ui/src/components/tool-count-label.tsx
rename to packages/session-ui/src/components/tool-count-label.tsx
index 67e861cdcb..715f37ef0a 100644
--- a/packages/ui/src/components/tool-count-label.tsx
+++ b/packages/session-ui/src/components/tool-count-label.tsx
@@ -1,5 +1,5 @@
import { createMemo } from "solid-js"
-import { AnimatedNumber } from "./animated-number"
+import { AnimatedNumber } from "@opencode-ai/ui/animated-number"
function split(text: string) {
const match = /{{\s*count\s*}}/.exec(text)
diff --git a/packages/ui/src/components/tool-count-summary.css b/packages/session-ui/src/components/tool-count-summary.css
similarity index 100%
rename from packages/ui/src/components/tool-count-summary.css
rename to packages/session-ui/src/components/tool-count-summary.css
diff --git a/packages/ui/src/components/tool-count-summary.stories.tsx b/packages/session-ui/src/components/tool-count-summary.stories.tsx
similarity index 100%
rename from packages/ui/src/components/tool-count-summary.stories.tsx
rename to packages/session-ui/src/components/tool-count-summary.stories.tsx
diff --git a/packages/ui/src/components/tool-count-summary.tsx b/packages/session-ui/src/components/tool-count-summary.tsx
similarity index 100%
rename from packages/ui/src/components/tool-count-summary.tsx
rename to packages/session-ui/src/components/tool-count-summary.tsx
diff --git a/packages/ui/src/components/tool-error-card.css b/packages/session-ui/src/components/tool-error-card.css
similarity index 100%
rename from packages/ui/src/components/tool-error-card.css
rename to packages/session-ui/src/components/tool-error-card.css
diff --git a/packages/ui/src/components/tool-error-card.stories.tsx b/packages/session-ui/src/components/tool-error-card.stories.tsx
similarity index 100%
rename from packages/ui/src/components/tool-error-card.stories.tsx
rename to packages/session-ui/src/components/tool-error-card.stories.tsx
diff --git a/packages/ui/src/components/tool-error-card.tsx b/packages/session-ui/src/components/tool-error-card.tsx
similarity index 94%
rename from packages/ui/src/components/tool-error-card.tsx
rename to packages/session-ui/src/components/tool-error-card.tsx
index ade7cc4b01..35720a2753 100644
--- a/packages/ui/src/components/tool-error-card.tsx
+++ b/packages/session-ui/src/components/tool-error-card.tsx
@@ -1,11 +1,11 @@
import { type ComponentProps, createMemo, Show, splitProps } from "solid-js"
import { createStore } from "solid-js/store"
-import { Card, CardDescription } from "./card"
-import { Collapsible } from "./collapsible"
-import { Icon } from "./icon"
-import { IconButton } from "./icon-button"
-import { Tooltip } from "./tooltip"
-import { useI18n } from "../context/i18n"
+import { Card, CardDescription } from "@opencode-ai/ui/card"
+import { Collapsible } from "@opencode-ai/ui/collapsible"
+import { Icon } from "@opencode-ai/ui/icon"
+import { IconButton } from "@opencode-ai/ui/icon-button"
+import { Tooltip } from "@opencode-ai/ui/tooltip"
+import { useI18n } from "@opencode-ai/ui/context/i18n"
export interface ToolErrorCardProps extends Omit, "children" | "variant"> {
tool: string
diff --git a/packages/ui/src/components/tool-status-title.css b/packages/session-ui/src/components/tool-status-title.css
similarity index 100%
rename from packages/ui/src/components/tool-status-title.css
rename to packages/session-ui/src/components/tool-status-title.css
diff --git a/packages/ui/src/components/tool-status-title.tsx b/packages/session-ui/src/components/tool-status-title.tsx
similarity index 98%
rename from packages/ui/src/components/tool-status-title.tsx
rename to packages/session-ui/src/components/tool-status-title.tsx
index 5c46593f71..589effc1f0 100644
--- a/packages/ui/src/components/tool-status-title.tsx
+++ b/packages/session-ui/src/components/tool-status-title.tsx
@@ -1,6 +1,6 @@
import { Show, createEffect, createMemo, on, onCleanup } from "solid-js"
import { createStore } from "solid-js/store"
-import { TextShimmer } from "./text-shimmer"
+import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
function common(active: string, done: string) {
const a = Array.from(active)
diff --git a/packages/ui/src/context/data.tsx b/packages/session-ui/src/context/data.tsx
similarity index 95%
rename from packages/ui/src/context/data.tsx
rename to packages/session-ui/src/context/data.tsx
index cf776c5104..999ff510d5 100644
--- a/packages/ui/src/context/data.tsx
+++ b/packages/session-ui/src/context/data.tsx
@@ -1,5 +1,5 @@
import type { Message, Session, Part, SnapshotFileDiff, SessionStatus, Provider } from "@opencode-ai/sdk/v2"
-import { createSimpleContext } from "./helper"
+import { createSimpleContext } from "@opencode-ai/ui/context"
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
export type NormalizedProviderListResponse = {
diff --git a/packages/session-ui/src/context/index.ts b/packages/session-ui/src/context/index.ts
new file mode 100644
index 0000000000..b07252ef84
--- /dev/null
+++ b/packages/session-ui/src/context/index.ts
@@ -0,0 +1 @@
+export * from "./data"
diff --git a/packages/ui/src/pierre/comment-hover.ts b/packages/session-ui/src/pierre/comment-hover.ts
similarity index 100%
rename from packages/ui/src/pierre/comment-hover.ts
rename to packages/session-ui/src/pierre/comment-hover.ts
diff --git a/packages/ui/src/pierre/commented-lines.ts b/packages/session-ui/src/pierre/commented-lines.ts
similarity index 100%
rename from packages/ui/src/pierre/commented-lines.ts
rename to packages/session-ui/src/pierre/commented-lines.ts
diff --git a/packages/ui/src/pierre/diff-selection.ts b/packages/session-ui/src/pierre/diff-selection.ts
similarity index 100%
rename from packages/ui/src/pierre/diff-selection.ts
rename to packages/session-ui/src/pierre/diff-selection.ts
diff --git a/packages/ui/src/pierre/file-find.ts b/packages/session-ui/src/pierre/file-find.ts
similarity index 100%
rename from packages/ui/src/pierre/file-find.ts
rename to packages/session-ui/src/pierre/file-find.ts
diff --git a/packages/ui/src/pierre/file-runtime.ts b/packages/session-ui/src/pierre/file-runtime.ts
similarity index 100%
rename from packages/ui/src/pierre/file-runtime.ts
rename to packages/session-ui/src/pierre/file-runtime.ts
diff --git a/packages/ui/src/pierre/file-selection.ts b/packages/session-ui/src/pierre/file-selection.ts
similarity index 100%
rename from packages/ui/src/pierre/file-selection.ts
rename to packages/session-ui/src/pierre/file-selection.ts
diff --git a/packages/ui/src/pierre/index.ts b/packages/session-ui/src/pierre/index.ts
similarity index 100%
rename from packages/ui/src/pierre/index.ts
rename to packages/session-ui/src/pierre/index.ts
diff --git a/packages/ui/src/pierre/media.ts b/packages/session-ui/src/pierre/media.ts
similarity index 100%
rename from packages/ui/src/pierre/media.ts
rename to packages/session-ui/src/pierre/media.ts
diff --git a/packages/ui/src/pierre/selection-bridge.ts b/packages/session-ui/src/pierre/selection-bridge.ts
similarity index 100%
rename from packages/ui/src/pierre/selection-bridge.ts
rename to packages/session-ui/src/pierre/selection-bridge.ts
diff --git a/packages/ui/src/pierre/virtualizer.ts b/packages/session-ui/src/pierre/virtualizer.ts
similarity index 100%
rename from packages/ui/src/pierre/virtualizer.ts
rename to packages/session-ui/src/pierre/virtualizer.ts
diff --git a/packages/ui/src/pierre/worker.ts b/packages/session-ui/src/pierre/worker.ts
similarity index 100%
rename from packages/ui/src/pierre/worker.ts
rename to packages/session-ui/src/pierre/worker.ts
diff --git a/packages/session-ui/src/styles/index.css b/packages/session-ui/src/styles/index.css
new file mode 100644
index 0000000000..24f78feb73
--- /dev/null
+++ b/packages/session-ui/src/styles/index.css
@@ -0,0 +1,14 @@
+@layer theme, base, components, utilities;
+
+@import "../components/basic-tool.css" layer(components);
+@import "../components/file.css" layer(components);
+@import "../components/markdown.css" layer(components);
+@import "../components/message-part.css" layer(components);
+@import "../components/message-nav.css" layer(components);
+@import "../components/session-review.css" layer(components);
+@import "../components/session-turn.css" layer(components);
+@import "../components/shell-submessage.css" layer(components);
+@import "../components/tool-count-label.css" layer(components);
+@import "../components/tool-count-summary.css" layer(components);
+@import "../components/tool-error-card.css" layer(components);
+@import "../components/tool-status-title.css" layer(components);
diff --git a/packages/ui/src/v2/components/basic-tool-v2.css b/packages/session-ui/src/v2/components/basic-tool-v2.css
similarity index 100%
rename from packages/ui/src/v2/components/basic-tool-v2.css
rename to packages/session-ui/src/v2/components/basic-tool-v2.css
diff --git a/packages/ui/src/v2/components/basic-tool-v2.stories.tsx b/packages/session-ui/src/v2/components/basic-tool-v2.stories.tsx
similarity index 100%
rename from packages/ui/src/v2/components/basic-tool-v2.stories.tsx
rename to packages/session-ui/src/v2/components/basic-tool-v2.stories.tsx
diff --git a/packages/ui/src/v2/components/basic-tool-v2.tsx b/packages/session-ui/src/v2/components/basic-tool-v2.tsx
similarity index 97%
rename from packages/ui/src/v2/components/basic-tool-v2.tsx
rename to packages/session-ui/src/v2/components/basic-tool-v2.tsx
index cf9d771b02..70bb87cce7 100644
--- a/packages/ui/src/v2/components/basic-tool-v2.tsx
+++ b/packages/session-ui/src/v2/components/basic-tool-v2.tsx
@@ -1,7 +1,7 @@
import { Collapsible } from "@kobalte/core/collapsible"
import { type ComponentProps, type JSX, For, Show, createMemo, splitProps } from "solid-js"
-import { DiffChanges } from "./diff-changes-v2"
-import { TextShimmerV2 } from "./text-shimmer-v2"
+import { DiffChanges } from "@opencode-ai/ui/v2/diff-changes-v2"
+import { TextShimmerV2 } from "@opencode-ai/ui/v2/text-shimmer-v2"
import "./basic-tool-v2.css"
function ChevronIcon() {
diff --git a/packages/ui/src/v2/components/session-progress-indicator-v2.css b/packages/session-ui/src/v2/components/session-progress-indicator-v2.css
similarity index 100%
rename from packages/ui/src/v2/components/session-progress-indicator-v2.css
rename to packages/session-ui/src/v2/components/session-progress-indicator-v2.css
diff --git a/packages/ui/src/v2/components/session-progress-indicator-v2.stories.tsx b/packages/session-ui/src/v2/components/session-progress-indicator-v2.stories.tsx
similarity index 100%
rename from packages/ui/src/v2/components/session-progress-indicator-v2.stories.tsx
rename to packages/session-ui/src/v2/components/session-progress-indicator-v2.stories.tsx
diff --git a/packages/ui/src/v2/components/session-progress-indicator-v2.tsx b/packages/session-ui/src/v2/components/session-progress-indicator-v2.tsx
similarity index 100%
rename from packages/ui/src/v2/components/session-progress-indicator-v2.tsx
rename to packages/session-ui/src/v2/components/session-progress-indicator-v2.tsx
diff --git a/packages/ui/src/v2/components/tool-error-card-v2.css b/packages/session-ui/src/v2/components/tool-error-card-v2.css
similarity index 100%
rename from packages/ui/src/v2/components/tool-error-card-v2.css
rename to packages/session-ui/src/v2/components/tool-error-card-v2.css
diff --git a/packages/ui/src/v2/components/tool-error-card-v2.stories.tsx b/packages/session-ui/src/v2/components/tool-error-card-v2.stories.tsx
similarity index 97%
rename from packages/ui/src/v2/components/tool-error-card-v2.stories.tsx
rename to packages/session-ui/src/v2/components/tool-error-card-v2.stories.tsx
index ae5c62bfdf..1642e53a81 100644
--- a/packages/ui/src/v2/components/tool-error-card-v2.stories.tsx
+++ b/packages/session-ui/src/v2/components/tool-error-card-v2.stories.tsx
@@ -1,5 +1,5 @@
import { createSignal } from "solid-js"
-import { ButtonV2 } from "./button-v2"
+import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2"
import { ToolErrorCardV2, type ToolErrorCardV2Props } from "./tool-error-card-v2"
const docs = `### Overview
diff --git a/packages/ui/src/v2/components/tool-error-card-v2.tsx b/packages/session-ui/src/v2/components/tool-error-card-v2.tsx
similarity index 100%
rename from packages/ui/src/v2/components/tool-error-card-v2.tsx
rename to packages/session-ui/src/v2/components/tool-error-card-v2.tsx
diff --git a/packages/session-ui/tsconfig.json b/packages/session-ui/tsconfig.json
new file mode 100644
index 0000000000..b234c74822
--- /dev/null
+++ b/packages/session-ui/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "@tsconfig/node22/tsconfig.json",
+ "compilerOptions": {
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js",
+ "target": "ESNext",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "isolatedModules": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "noEmit": true,
+ "lib": ["es2023", "dom", "dom.iterable"],
+ "strict": true,
+ "types": ["vite/client", "bun"]
+ },
+ "exclude": ["**/*.stories.*", "**/*.mdx"]
+}
diff --git a/packages/storybook/.storybook/main.ts b/packages/storybook/.storybook/main.ts
index 7b42abd67c..f592863e56 100644
--- a/packages/storybook/.storybook/main.ts
+++ b/packages/storybook/.storybook/main.ts
@@ -6,6 +6,7 @@ import { playgroundCss } from "./playground-css-plugin"
const here = path.dirname(fileURLToPath(import.meta.url))
const ui = path.resolve(here, "../../ui")
+const sessionUi = path.resolve(here, "../../session-ui")
const app = path.resolve(here, "../../app/src")
const mocks = path.resolve(here, "./mocks")
@@ -21,7 +22,11 @@ export default defineMain({
"@storybook/addon-a11y",
"@storybook/addon-vitest",
],
- stories: ["../../ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)", "../../app/src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+ stories: [
+ "../../ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../../session-ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../../app/src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ ],
async viteFinal(config) {
const { mergeConfig, searchForWorkspaceRoot } = await import("vite")
return mergeConfig(config, {
@@ -59,7 +64,7 @@ export default defineMain({
},
server: {
fs: {
- allow: [searchForWorkspaceRoot(process.cwd()), ui, app, mocks],
+ allow: [searchForWorkspaceRoot(process.cwd()), ui, sessionUi, app, mocks],
},
},
})
diff --git a/packages/storybook/.storybook/playground-css-plugin.ts b/packages/storybook/.storybook/playground-css-plugin.ts
index 23bb20b7dd..567ea9a5fc 100644
--- a/packages/storybook/.storybook/playground-css-plugin.ts
+++ b/packages/storybook/.storybook/playground-css-plugin.ts
@@ -7,7 +7,7 @@
*
* For each edit the plugin finds `anchor` in the file, then locates the
* next `prop: ;` after it and replaces the value portion.
- * `file` is a basename resolved relative to packages/ui/src/components/.
+ * `file` is a basename resolved against the UI component packages.
*/
import type { Plugin } from "vite"
import type { IncomingMessage, ServerResponse } from "node:http"
@@ -16,7 +16,7 @@ import path from "node:path"
import { fileURLToPath } from "node:url"
const here = path.dirname(fileURLToPath(import.meta.url))
-const root = path.resolve(here, "../../ui/src/components")
+const roots = [path.resolve(here, "../../session-ui/src/components"), path.resolve(here, "../../ui/src/components")]
const ENDPOINT = "/__playground/apply-css"
@@ -97,8 +97,8 @@ export function playgroundCss(): Plugin {
const grouped = new Map()
for (const edit of payload.edits) {
if (!edit.file || !edit.anchor || !edit.prop || edit.value === undefined) continue
- const abs = path.resolve(root, edit.file)
- if (!abs.startsWith(root)) continue
+ const abs = roots.map((root) => path.resolve(root, edit.file)).find((file) => fs.existsSync(file))
+ if (!abs || !roots.some((root) => abs.startsWith(root))) continue
const key = abs
if (!grouped.has(key)) grouped.set(key, [])
grouped.get(key)!.push(edit)
diff --git a/packages/storybook/.storybook/preview.tsx b/packages/storybook/.storybook/preview.tsx
index 7b892f7683..76fb3abec9 100644
--- a/packages/storybook/.storybook/preview.tsx
+++ b/packages/storybook/.storybook/preview.tsx
@@ -1,4 +1,5 @@
import "@opencode-ai/ui/styles/tailwind"
+import "@opencode-ai/session-ui/styles"
import "@opencode-ai/ui/v2/styles/tailwind.css"
import { createEffect, onCleanup, onMount } from "solid-js"
diff --git a/packages/storybook/package.json b/packages/storybook/package.json
index b1dae1c956..f7089bafa3 100644
--- a/packages/storybook/package.json
+++ b/packages/storybook/package.json
@@ -9,6 +9,7 @@
},
"devDependencies": {
"@tailwindcss/vite": "catalog:",
+ "@opencode-ai/session-ui": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@solidjs/meta": "catalog:",
"@storybook/addon-a11y": "^10.2.13",
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 489396ad49..3ec943187e 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -6,13 +6,12 @@
"exports": {
"./package.json": "./package.json",
"./*": "./src/components/*.tsx",
- "./session-diff": "./src/components/session-diff.ts",
"./i18n/*": "./src/i18n/*.ts",
- "./pierre": "./src/pierre/index.ts",
- "./pierre/*": "./src/pierre/*.ts",
"./hooks": "./src/hooks/index.ts",
"./context": "./src/context/index.ts",
"./context/*": "./src/context/*.tsx",
+ "./storybook/scaffold": "./src/storybook/scaffold.tsx",
+ "./storybook/fixtures": "./src/storybook/fixtures.ts",
"./styles": "./src/styles/index.css",
"./styles/tailwind": "./src/styles/tailwind/index.css",
"./theme": "./src/theme/index.ts",
@@ -49,8 +48,6 @@
},
"dependencies": {
"@kobalte/core": "catalog:",
- "@opencode-ai/core": "workspace:*",
- "@opencode-ai/sdk": "workspace:*",
"@pierre/diffs": "catalog:",
"@shikijs/transformers": "3.9.2",
"@solid-primitives/bounds": "0.1.3",
diff --git a/packages/ui/src/context/index.ts b/packages/ui/src/context/index.ts
index 2db004985f..7cbf02c4ee 100644
--- a/packages/ui/src/context/index.ts
+++ b/packages/ui/src/context/index.ts
@@ -1,5 +1,4 @@
export * from "./helper"
-export * from "./data"
export * from "./file"
export * from "./dialog"
export * from "./i18n"
diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css
index 1b17f6c2b7..729e19cd33 100644
--- a/packages/ui/src/styles/index.css
+++ b/packages/ui/src/styles/index.css
@@ -10,12 +10,9 @@
@import "../components/animated-number.css" layer(components);
@import "../components/app-icon.css" layer(components);
@import "../components/avatar.css" layer(components);
-@import "../components/basic-tool.css" layer(components);
@import "../components/button.css" layer(components);
@import "../components/card.css" layer(components);
-@import "../components/tool-error-card.css" layer(components);
@import "../components/checkbox.css" layer(components);
-@import "../components/file.css" layer(components);
@import "../components/collapsible.css" layer(components);
@import "../components/diff-changes.css" layer(components);
@import "../components/context-menu.css" layer(components);
@@ -33,9 +30,6 @@
@import "../components/inline-input.css" layer(components);
@import "../components/list.css" layer(components);
@import "../components/logo.css" layer(components);
-@import "../components/markdown.css" layer(components);
-@import "../components/message-part.css" layer(components);
-@import "../components/message-nav.css" layer(components);
@import "../components/popover.css" layer(components);
@import "../components/progress.css" layer(components);
@import "../components/progress-circle.css" layer(components);
@@ -45,18 +39,12 @@
@import "../components/spinner.css" layer(components);
@import "../components/switch.css" layer(components);
@import "../components/scroll-view.css" layer(components);
-@import "../components/session-review.css" layer(components);
-@import "../components/session-turn.css" layer(components);
-@import "../components/shell-submessage.css" layer(components);
@import "../components/sticky-accordion-header.css" layer(components);
@import "../components/tabs.css" layer(components);
@import "../components/tag.css" layer(components);
@import "../components/text-reveal.css" layer(components);
@import "../components/text-strikethrough.css" layer(components);
@import "../components/text-shimmer.css" layer(components);
-@import "../components/tool-count-label.css" layer(components);
-@import "../components/tool-count-summary.css" layer(components);
-@import "../components/tool-status-title.css" layer(components);
@import "../components/toast.css" layer(components);
@import "../components/tooltip.css" layer(components);
@import "../components/typewriter.css" layer(components);
diff --git a/turbo.json b/turbo.json
index c9255902c5..5e93640b1f 100644
--- a/turbo.json
+++ b/turbo.json
@@ -24,6 +24,10 @@
"@opencode-ai/ui#test": {
"dependsOn": ["^build"],
"outputs": []
+ },
+ "@opencode-ai/session-ui#test": {
+ "dependsOn": ["^build"],
+ "outputs": []
}
}
}