mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-22 03:23:27 +00:00
refactor(frontend): enforce package boundaries (#43177)
This commit is contained in:
parent
ea1ff90e42
commit
1f61eb5ca9
111 changed files with 579 additions and 283 deletions
6
bun.lock
6
bun.lock
|
|
@ -62,7 +62,6 @@
|
|||
"@dnd-kit/solid": "0.5.0",
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/client": "workspace:*",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@opencode-ai/session-ui": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
|
|
@ -685,9 +684,8 @@
|
|||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/client": "workspace:*",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/sdk": "file:../app/vendor/opencode-ai-sdk-1.18.8-dev.tgz",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@pierre/diffs": "catalog:",
|
||||
"@shikijs/stream": "catalog:",
|
||||
"@solid-primitives/event-listener": "2.4.5",
|
||||
|
|
@ -6369,8 +6367,6 @@
|
|||
|
||||
"@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
||||
|
||||
"@opencode-ai/session-ui/@opencode-ai/sdk": ["@opencode-ai/sdk@../app/vendor/opencode-ai-sdk-1.18.8-dev.tgz", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-C2nfk4x0sPINwE5V6DPkFSuH3PkUmKPWHPzxpXC1j+3Ui5hslLCWJbkk8WcOG1Lyt3C0+yp4ea64v/kmtYCO4w=="],
|
||||
|
||||
"@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/storybook/@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="],
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import type {
|
||||
JsonValue,
|
||||
OpenCodeEvent,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import type { JsonValue, OpenCodeEvent, SessionMessageAssistant, SessionMessageInfo } from "@opencode-ai/client/promise"
|
||||
import type { Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../../utils/mock-server"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { mockOpenCodeServer } from "../../utils/mock-server"
|
||||
import { fixture, pageMessages } from "./session-timeline-stress.fixture"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test } from "bun:test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { fixture } from "../timeline/session-timeline-stress.fixture"
|
||||
import { stressSessionHref } from "../timeline/timeline-test-helpers"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page, type Route } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { currentSession } from "../utils/mock-server"
|
||||
import { installSseTransport } from "../utils/sse-transport"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible } from "../utils/waits"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible } from "../utils/waits"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page, type Route } from "@playwright/test"
|
||||
import { installSseTransport } from "../utils/sse-transport"
|
||||
import { currentSession } from "../utils/mock-server"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page, type Route } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { currentSession } from "../utils/mock-server"
|
||||
|
||||
const serverA = "http://127.0.0.1:4096"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible, expectSessionTitle } from "../utils/waits"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible, expectSessionTitle } from "../utils/waits"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible, expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { installSseTransport } from "../utils/sse-transport"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import type { SessionMessageAssistant } from "@opencode-ai/client/promise"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import type { OpenCodeEvent, SessionMessageInfo } from "@opencode-ai/client/promise"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { currentSession, mockOpenCodeServer } from "../utils/mock-server"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page, type Route } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { currentSession } from "../utils/mock-server"
|
||||
|
||||
const server = "http://127.0.0.1:4096"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode, checksum } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode, checksum } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { fixture, pageMessages } from "./session-timeline.fixture"
|
||||
import { trackPageErrors, expectNoSmokeErrors } from "../utils/errors"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, type Locator, type Page } from "@playwright/test"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
|
||||
export const APP_READY_TIMEOUT = 30_000
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@
|
|||
"@dnd-kit/solid": "0.5.0",
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/client": "workspace:*",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@opencode-ai/session-ui": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import type { Project } from "@/types"
|
||||
import type { SessionInfo } from "@opencode-ai/client/promise"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import { ScrollView } from "@opencode-ai/ui/scroll-view"
|
||||
import { Dialog, DialogBody } from "@opencode-ai/ui/v2/dialog-v2"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { List } from "@opencode-ai/ui/list"
|
|||
import { showToast } from "@/utils/toast"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useServerSDK } from "@/context/server-sdk"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { extractPromptComments, extractPromptFromMessage } from "@/utils/prompt"
|
||||
import { useWorkspaceLocation } from "@/context/location"
|
||||
import { useServer } from "@/context/server"
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
} from "./directory-picker-domain"
|
||||
import "./dialog-select-directory-v2.css"
|
||||
import { DividerV2 } from "@opencode-ai/ui/v2/divider-v2"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
|
||||
interface DialogSelectDirectoryV2Props {
|
||||
title?: string
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { FileIcon } from "@opencode-ai/ui/file-icon"
|
|||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { Keybind } from "@opencode-ai/ui/keybind"
|
||||
import { List } from "@opencode-ai/ui/list"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { createMemo, createSignal, lazy, Match, Show, Switch } from "solid-js"
|
||||
import { formatKeybind } from "@/context/command"
|
||||
import { useServerSDK } from "@/context/server-sdk"
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ export function nativePickerPath(path: string) {
|
|||
if (/^[A-Za-z]:\//.test(value) || value.startsWith("//")) return value.replaceAll("/", "\\")
|
||||
return value
|
||||
}
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import fuzzysort from "fuzzysort"
|
||||
import { ServerSDK } from "@/context/server-sdk"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { useMutation } from "@tanstack/solid-query"
|
||||
import { normalizeProjectInfo } from "@/context/global-sync/utils"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import type { FileSelection } from "@/context/file"
|
||||
import { encodeFilePath } from "@/context/file/path"
|
||||
import type { AgentPart, FileAttachmentPart, ImageAttachmentPart, Prompt } from "@/context/prompt"
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ beforeAll(async () => {
|
|||
showToast: () => 0,
|
||||
}))
|
||||
|
||||
mock.module("@opencode-ai/core/util/encode", () => ({
|
||||
mock.module("@opencode-ai/util/encode", () => ({
|
||||
base64Decode: (value: string) => value,
|
||||
base64Encode: (value: string) => value,
|
||||
checksum: (value: string) => value,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Data } from "@opencode-ai/client/solid"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { useNavigate, useParams, useSearchParams } from "@solidjs/router"
|
||||
import { startTransition, type Accessor } from "solid-js"
|
||||
import { useTabs } from "@/context/tabs"
|
||||
|
|
@ -12,7 +12,7 @@ import { type ContextItem, type ImageAttachmentPart, type Prompt, type usePrompt
|
|||
import { useWorkspaceLocation } from "@/context/location"
|
||||
import { useServerSDK, type ServerSDK } from "@/context/server-sdk"
|
||||
import { Identifier } from "@/utils/id"
|
||||
import { getDirectory } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory } from "@opencode-ai/util/path"
|
||||
import { buildPromptRequest } from "./build-prompt-request"
|
||||
import { setCursorPosition } from "./editor-dom"
|
||||
import { formatServerError } from "@/utils/server-errors"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createMemo, createSignal, For, Show } from "solid-js"
|
|||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { Icon } from "@opencode-ai/ui/v2/icon"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { sameDirectory } from "@/utils/workspace"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { Icon } from "@opencode-ai/ui/v2/icon"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { createSignal, For, Show, type ComponentProps, type JSX } from "solid-js"
|
||||
import type { Project } from "@/types"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js"
|
||||
import type { JSX } from "solid-js"
|
||||
import { useData } from "@/context/server"
|
||||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { same } from "@/utils/same"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useLanguage } from "@/context/language"
|
|||
import { useData } from "@/context/server"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { Mark } from "@opencode-ai/ui/logo"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
|
||||
const MAIN_WORKTREE = "main"
|
||||
const CREATE_WORKTREE = "create"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Show } from "solid-js"
|
||||
import type { JSX } from "solid-js"
|
||||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
|
||||
export function FileVisual(props: { path: string; active?: boolean; temporary?: boolean }): JSX.Element {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
|
|||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useServerSDK } from "@/context/server-sdk"
|
||||
import { useData } from "@/context/server"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { useLanguage } from "@/context/language"
|
|||
import { useCommand } from "@/context/command"
|
||||
import { useTabs } from "@/context/tabs"
|
||||
import { createTabPromptState } from "@/context/prompt"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { canStartTabDrag, isTabCloseTarget } from "./titlebar-tab-gesture"
|
||||
import { adjacentTabKey, mergeVisibleTabOrder } from "./titlebar-tab-order"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { batch, createMemo, createRoot, onCleanup } from "solid-js"
|
|||
import { createStore, reconcile, type SetStoreFunction, type Store } from "solid-js/store"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import { useServerSDK } from "./server-sdk"
|
||||
import type { ServerScope } from "@/utils/server-scope"
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { createStore, produce, reconcile } from "solid-js/store"
|
|||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { useWorkspaceLocation } from "./location"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useLayout } from "@/context/layout"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { QueryClient } from "@tanstack/solid-query"
|
||||
import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
|
||||
import { loadPathQuery, loadProjectsQuery } from "./bootstrap"
|
||||
import { ServerScope } from "@/utils/server-scope"
|
||||
import type { ServerApi } from "@/utils/server"
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import type {
|
|||
ProjectListOutput,
|
||||
} from "@opencode-ai/client/promise"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { retry } from "@opencode-ai/core/util/retry"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { retry } from "@opencode-ai/util/retry"
|
||||
import { reconcile, type SetStoreFunction, type Store } from "solid-js/store"
|
||||
import type { State } from "./types"
|
||||
import { cmp, normalizeProjectInfo } from "./utils"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import type { Agent, Config, LspStatus, Path, VcsInfo } from "@/types"
|
||||
import type { Agent, Config, LspStatus, Path, ProviderListResponse, VcsInfo } from "@/types"
|
||||
import type { ReferenceInfo } from "@opencode-ai/client/promise"
|
||||
import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
|
||||
import type { CommandInfo, McpResource, McpServer } from "@opencode-ai/client/promise"
|
||||
import type { Accessor } from "solid-js"
|
||||
import type { SetStoreFunction, Store } from "solid-js/store"
|
||||
|
|
@ -25,7 +24,7 @@ export type State = {
|
|||
projectMeta: ProjectMeta | undefined
|
||||
icon: string | undefined
|
||||
provider_ready: boolean
|
||||
provider: NormalizedProviderListResponse
|
||||
provider: ProviderListResponse
|
||||
config: Config
|
||||
path: Path
|
||||
mcp_ready: boolean
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { AgentListOutput, ModelListOutput, ProviderListOutput } from "@opencode-ai/client/promise"
|
||||
import type { Agent, Project, Provider, ProviderListResponse } from "@/types"
|
||||
import type { Project as CurrentProject } from "@opencode-ai/client/promise"
|
||||
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)
|
||||
|
|
@ -33,7 +32,7 @@ export function normalizeAgentList(input: AgentListOutput["data"] | Agent[]): Ag
|
|||
export function normalizeProviderList(
|
||||
providers: ProviderListOutput["data"] | ProviderListResponse,
|
||||
models?: ModelListOutput["data"],
|
||||
): NormalizedProviderListResponse {
|
||||
): ProviderListResponse {
|
||||
if (!Array.isArray(providers)) {
|
||||
return providers
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
|||
import { usePlatform } from "@/context/platform"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import { playSoundById } from "@/utils/sound"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import type { PermissionRequest, SessionInfo } from "@opencode-ai/client/promise"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import {
|
||||
autoRespondsPermission,
|
||||
isDirectoryAutoAccepting,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
|
||||
export function acceptKey(sessionID: string, directory?: string) {
|
||||
if (!directory) return sessionID
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { batch, createMemo, type Accessor } from "solid-js"
|
||||
import { createStore, type SetStoreFunction } from "solid-js/store"
|
||||
import type { FileSelection } from "@/context/file"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { useParams, useSearchParams } from "@solidjs/router"
|
||||
import { createMemo, createResource, createRoot, getOwner, onCleanup } from "solid-js"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Config, Path, Project, ProviderAuthResponse } from "@/types"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { getOwner, onCleanup, untrack } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useLanguage } from "@/context/language"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { beforeAll, describe, expect, mock, test } from "bun:test"
|
||||
import { ServerScope } from "@/utils/server-scope"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { Persist } from "@/utils/persist"
|
||||
import type { Platform } from "./platform"
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { batch, createEffect, createMemo, createRoot, on, onCleanup } from "soli
|
|||
import { useWorkspaceLocation, type LocationContext } from "./location"
|
||||
import type { Platform } from "./platform"
|
||||
import { useServerSDK } from "./server-sdk"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { defaultTitle, titleNumber } from "./terminal-title"
|
||||
import { Persist, persisted, removePersisted } from "@/utils/persist"
|
||||
import { ScopedKey, ServerScope, type ServerScope as ServerScopeValue } from "@/utils/server-scope"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { expect, test } from "bun:test"
|
||||
import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
|
||||
import type { ProviderListResponse } from "@/types"
|
||||
import { selectProviderCatalog } from "./provider-catalog"
|
||||
|
||||
const catalog = (id: string): NormalizedProviderListResponse => ({
|
||||
const catalog = (id: string): ProviderListResponse => ({
|
||||
all: new Map([[id, { id, name: id, source: "api", env: [], options: {}, models: {} }]]),
|
||||
connected: [id],
|
||||
default: { [id]: `${id}-model` },
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
|
||||
import type { ProviderListResponse } from "@/types"
|
||||
|
||||
export const emptyProviderCatalog: NormalizedProviderListResponse = { all: new Map(), connected: [], default: {} }
|
||||
export const emptyProviderCatalog: ProviderListResponse = { all: new Map(), connected: [], default: {} }
|
||||
|
||||
type DirectoryCatalog = {
|
||||
ready: boolean
|
||||
providers: NormalizedProviderListResponse
|
||||
providers: ProviderListResponse
|
||||
}
|
||||
|
||||
type ProviderCatalogInput =
|
||||
|
|
@ -17,7 +17,7 @@ type ProviderCatalogInput =
|
|||
explicit: false
|
||||
directory?: string
|
||||
catalog?: DirectoryCatalog
|
||||
global: NormalizedProviderListResponse
|
||||
global: ProviderListResponse
|
||||
}
|
||||
|
||||
export function selectProviderCatalog(input: ProviderCatalogInput) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import type { SessionInfo } from "@opencode-ai/client/promise"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
import type { ServerConnection } from "@/context/servers"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { FilePart } from "@opencode-ai/sdk/v2"
|
||||
import type { FilePart } from "@/types"
|
||||
import type { FileDiffInfo, SessionMessageUser } from "@opencode-ai/client/promise"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { createQuery, skipToken, useMutation, useQueryClient } from "@tanstack/solid-query"
|
||||
import {
|
||||
|
|
@ -37,7 +37,7 @@ import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2"
|
|||
import { createAutoScroll } from "@opencode-ai/ui/hooks"
|
||||
import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge"
|
||||
import { showToast } from "@/utils/toast"
|
||||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { containsDirectory, isWorkspaceDirectory } from "@/utils/workspace"
|
||||
import { useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/router"
|
||||
import { NewSessionView, SessionHeader } from "@/components/session"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { useNavigate, useSearchParams } from "@solidjs/router"
|
||||
import { type Accessor, createMemo } from "solid-js"
|
||||
import type { PromptInputControls } from "@/components/prompt-input/contracts"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import type { FileSearchHandle } from "@opencode-ai/session-ui/file"
|
|||
import { useFileComponent } from "@opencode-ai/ui/context/file"
|
||||
import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge"
|
||||
import { createLineCommentControllerV2 } from "@opencode-ai/session-ui/v2/line-comment-annotations-v2"
|
||||
import { sampledChecksum } from "@opencode-ai/core/util/encode"
|
||||
import { sampledChecksum } from "@opencode-ai/util/encode"
|
||||
import { LineCommentV2OverflowIcon } from "@opencode-ai/ui/v2/line-comment-v2"
|
||||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useLayout } from "@/context/layout"
|
|||
import { SessionRouteKey, SessionStateKey } from "@/utils/server-scope"
|
||||
import { useWorkspaceLocation } from "@/context/location"
|
||||
import { useServerSDK } from "@/context/server-sdk"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
|
||||
export const useSessionKey = () => {
|
||||
const params = useParams()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
partDefaultOpen,
|
||||
type UserActions,
|
||||
} from "@opencode-ai/session-ui/message-part"
|
||||
import type { ToolPart } from "@opencode-ai/sdk/v2"
|
||||
import type { ToolPart } from "@/types"
|
||||
import {
|
||||
presentAssistantMessage,
|
||||
presentAssistantContent,
|
||||
|
|
@ -56,9 +56,7 @@ export function CurrentAssistantContent(props: {
|
|||
onContentRendered?: () => void
|
||||
}) {
|
||||
const message = createMemo(() => presentAssistantMessage(props.sessionID, props.parentID, props.message))
|
||||
const part = createMemo(() =>
|
||||
presentAssistantContent(props.sessionID, props.message, props.contentID, props.content),
|
||||
)
|
||||
const part = createMemo(() => presentAssistantContent(props.sessionID, props.message, props.contentID, props.content))
|
||||
return (
|
||||
<Show when={part()}>
|
||||
{(part) => (
|
||||
|
|
@ -113,9 +111,5 @@ export function currentPartDefaultOpen(
|
|||
shellExpanded: boolean,
|
||||
editExpanded: boolean,
|
||||
) {
|
||||
return partDefaultOpen(
|
||||
presentAssistantContent(sessionID, message, contentID, content),
|
||||
shellExpanded,
|
||||
editExpanded,
|
||||
)
|
||||
return partDefaultOpen(presentAssistantContent(sessionID, message, contentID, content), shellExpanded, editExpanded)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { isScrollKeyTarget, scrollKey, scrollKeyOwner, ScrollView } from "@openc
|
|||
import { TextReveal } from "@opencode-ai/ui/text-reveal"
|
||||
import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
|
||||
import type { Project } from "@/types"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { Popover as KobaltePopover } from "@kobalte/core/popover"
|
||||
import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture"
|
||||
import { SessionContextUsage } from "@/components/session-context-usage"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import "@opencode-ai/ui/v2/file-tree-v2.css"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { createEffect, createMemo, createSignal, For, Show } from "solid-js"
|
||||
import { kindChange, kindLabel, type Kind } from "@/components/file-tree-v2"
|
||||
import { normalizePath } from "@/pages/session/v2/review-diff-kinds"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { FileDiffInfo, ProjectListOutput, WorktreeDirectory } from "@opencode-ai/client/promise"
|
||||
import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
|
||||
|
||||
export type Project = Omit<ProjectListOutput[number], "canonical"> & {
|
||||
worktree: string
|
||||
|
|
@ -257,9 +256,83 @@ export type Agent = {
|
|||
steps?: number
|
||||
}
|
||||
|
||||
export type Provider = NormalizedProviderListResponse["all"] extends Map<string, infer Item> ? Item : never
|
||||
export type Model = Provider["models"][string]
|
||||
export type ProviderListResponse = NormalizedProviderListResponse
|
||||
export type Model = {
|
||||
id: string
|
||||
providerID: string
|
||||
api: {
|
||||
id: string
|
||||
url: string
|
||||
npm: string
|
||||
}
|
||||
name: string
|
||||
family?: string
|
||||
capabilities: {
|
||||
temperature: boolean
|
||||
reasoning: boolean
|
||||
attachment: boolean
|
||||
toolcall: boolean
|
||||
input: {
|
||||
text: boolean
|
||||
audio: boolean
|
||||
image: boolean
|
||||
video: boolean
|
||||
pdf: boolean
|
||||
}
|
||||
output: {
|
||||
text: boolean
|
||||
audio: boolean
|
||||
image: boolean
|
||||
video: boolean
|
||||
pdf: boolean
|
||||
}
|
||||
interleaved: boolean | { field: "reasoning" | "reasoning_content" | "reasoning_details" }
|
||||
}
|
||||
cost: {
|
||||
input: number
|
||||
output: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
tiers?: {
|
||||
input: number
|
||||
output: number
|
||||
cache: { read: number; write: number }
|
||||
tier: { type: "context"; size: number }
|
||||
}[]
|
||||
experimentalOver200K?: {
|
||||
input: number
|
||||
output: number
|
||||
cache: { read: number; write: number }
|
||||
}
|
||||
}
|
||||
limit: {
|
||||
context: number
|
||||
input?: number
|
||||
output: number
|
||||
}
|
||||
status: "alpha" | "beta" | "deprecated" | "active"
|
||||
options: Record<string, unknown>
|
||||
headers: Record<string, string>
|
||||
release_date: string
|
||||
variants?: Record<string, Record<string, unknown>>
|
||||
}
|
||||
|
||||
export type Provider = {
|
||||
id: string
|
||||
name: string
|
||||
source: "env" | "config" | "custom" | "api"
|
||||
env: string[]
|
||||
key?: string
|
||||
options: Record<string, unknown>
|
||||
models: Record<string, Model>
|
||||
}
|
||||
|
||||
export type ProviderListResponse = {
|
||||
all: Map<string, Provider>
|
||||
default: Record<string, string>
|
||||
connected: string[]
|
||||
}
|
||||
|
||||
export type ProviderAuthResponse = Record<string, unknown>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Decode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Decode } from "@opencode-ai/util/encode"
|
||||
|
||||
export function decode64(value: string | undefined) {
|
||||
if (value === undefined) return
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Platform, usePlatform } from "@/context/platform"
|
||||
import { makePersisted, type AsyncStorage, type SyncStorage } from "@solid-primitives/storage"
|
||||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { createResource, type Accessor } from "solid-js"
|
||||
import type { SetStoreFunction, Store } from "solid-js/store"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type {
|
|||
SessionMessageAssistantTool,
|
||||
SessionMessageUser,
|
||||
} from "@opencode-ai/client/promise"
|
||||
import type { AssistantMessage, FilePart, Part, ToolPart, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import type { AssistantMessage, FilePart, Part, ToolPart, UserMessage } from "@/types"
|
||||
import { Option, Schema } from "effect"
|
||||
import { createCommentMetadata, formatCommentNote, readPromptPresentation } from "./comment-note"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { ServerConnection } from "@/context/servers"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,5 @@
|
|||
}
|
||||
},
|
||||
"include": ["src", "package.json"],
|
||||
"exclude": ["dist", "ts-dist"],
|
||||
"references": [{ "path": "../core" }]
|
||||
"exclude": ["dist", "ts-dist"]
|
||||
}
|
||||
|
|
|
|||
BIN
packages/app/vendor/opencode-ai-sdk-1.18.8-dev.tgz
vendored
BIN
packages/app/vendor/opencode-ai-sdk-1.18.8-dev.tgz
vendored
Binary file not shown.
|
|
@ -1,41 +0,0 @@
|
|||
export namespace Binary {
|
||||
export function search<T>(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } {
|
||||
let left = 0
|
||||
let right = array.length - 1
|
||||
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midId = compare(array[mid])
|
||||
|
||||
if (midId === id) {
|
||||
return { found: true, index: mid }
|
||||
} else if (midId < id) {
|
||||
left = mid + 1
|
||||
} else {
|
||||
right = mid - 1
|
||||
}
|
||||
}
|
||||
|
||||
return { found: false, index: left }
|
||||
}
|
||||
|
||||
export function insert<T>(array: T[], item: T, compare: (item: T) => string): T[] {
|
||||
const id = compare(item)
|
||||
let left = 0
|
||||
let right = array.length
|
||||
|
||||
while (left < right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midId = compare(array[mid])
|
||||
|
||||
if (midId < id) {
|
||||
left = mid + 1
|
||||
} else {
|
||||
right = mid
|
||||
}
|
||||
}
|
||||
|
||||
array.splice(left, 0, item)
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
export interface RetryOptions {
|
||||
attempts?: number
|
||||
delay?: number
|
||||
factor?: number
|
||||
maxDelay?: number
|
||||
retryIf?: (error: unknown) => boolean
|
||||
}
|
||||
|
||||
const TRANSIENT_MESSAGES = [
|
||||
"load failed",
|
||||
"network connection was lost",
|
||||
"network request failed",
|
||||
"failed to fetch",
|
||||
"econnreset",
|
||||
"econnrefused",
|
||||
"etimedout",
|
||||
"socket hang up",
|
||||
]
|
||||
|
||||
function isTransientError(error: unknown): boolean {
|
||||
if (!error) return false
|
||||
// oxlint-disable-next-line no-base-to-string -- error is unknown, intentional coercion for message matching
|
||||
const message = String(error instanceof Error ? error.message : error).toLowerCase()
|
||||
return TRANSIENT_MESSAGES.some((m) => message.includes(m))
|
||||
}
|
||||
|
||||
export async function retry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
||||
const { attempts = 3, delay = 500, factor = 2, maxDelay = 10000, retryIf = isTransientError } = options
|
||||
|
||||
let lastError: unknown
|
||||
for (let attempt = 0; attempt < attempts; attempt++) {
|
||||
try {
|
||||
return await fn()
|
||||
} catch (error) {
|
||||
lastError = error
|
||||
if (attempt === attempts - 1 || !retryIf(error)) throw error
|
||||
const wait = Math.min(delay * Math.pow(factor, attempt), maxDelay)
|
||||
await new Promise((resolve) => setTimeout(resolve, wait))
|
||||
}
|
||||
}
|
||||
throw lastError
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import { Logo, Mark } from "@opencode-ai/ui/logo"
|
|||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
|
||||
import { iife } from "@opencode-ai/core/util/iife"
|
||||
import { Binary } from "@opencode-ai/core/util/binary"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { NamedError } from "@opencode-ai/core/util/error"
|
||||
import { DateTime } from "luxon"
|
||||
import { createStore } from "solid-js/store"
|
||||
|
|
|
|||
|
|
@ -40,9 +40,8 @@
|
|||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/client": "workspace:*",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/sdk": "file:../app/vendor/opencode-ai-sdk-1.18.8-dev.tgz",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@pierre/diffs": "catalog:",
|
||||
"@shikijs/stream": "catalog:",
|
||||
"@solid-primitives/event-listener": "2.4.5",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { FileContent } from "@opencode-ai/sdk/v2"
|
||||
import type { PresentationFileContent } from "../presentation"
|
||||
import { createEffect, createMemo, Match, on, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useI18n } from "@opencode-ai/ui/context/i18n"
|
||||
|
|
@ -18,7 +18,7 @@ export type FileMediaOptions = {
|
|||
before?: unknown
|
||||
after?: unknown
|
||||
deleted?: boolean
|
||||
readFile?: (path: string) => Promise<FileContent | undefined>
|
||||
readFile?: (path: string) => Promise<PresentationFileContent | undefined>
|
||||
onLoad?: () => void
|
||||
onError?: (ctx: { kind: "image" | "audio" | "svg" }) => void
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { sampledChecksum } from "@opencode-ai/core/util/encode"
|
||||
import { sampledChecksum } from "@opencode-ai/util/encode"
|
||||
import {
|
||||
areFilesEqual,
|
||||
areOptionsEqual,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useFilteredList } from "@opencode-ai/ui/hooks"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { createSignal, For, onMount, Show, splitProps, type JSX } from "solid-js"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import DOMPurify from "dompurify"
|
||||
import { parseMarkdown } from "./markdown-worker"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useI18n } from "@opencode-ai/ui/context/i18n"
|
||||
import morphdom from "morphdom"
|
||||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import {
|
||||
type ComponentProps,
|
||||
createEffect,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import type { FilePart } from "@opencode-ai/sdk/v2"
|
||||
import type { FilePart } from "../presentation"
|
||||
import { attached, inline, kind, typeLabel } from "./message-file"
|
||||
|
||||
function file(part: Partial<FilePart> = {}): FilePart {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { bundledLanguagesInfo } from "shiki"
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import type { FilePart } from "@opencode-ai/sdk/v2"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import type { FilePart } from "../presentation"
|
||||
|
||||
export function attached(part: FilePart) {
|
||||
return part.url.startsWith("data:") && !inline(part)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import type { UserMessage } from "../presentation"
|
||||
import { HoverCard } from "@kobalte/core/hover-card"
|
||||
import { ComponentProps, For, Match, Show, createSignal, splitProps, Switch } from "solid-js"
|
||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { createStore } from "solid-js/store"
|
||||
import stripAnsi from "strip-ansi"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
import {
|
||||
import type {
|
||||
AgentPart,
|
||||
AssistantMessage,
|
||||
FilePart,
|
||||
|
|
@ -29,7 +29,7 @@ import {
|
|||
Todo,
|
||||
QuestionAnswer,
|
||||
QuestionInfo,
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
} from "../presentation"
|
||||
import { type SessionSummary, useData } from "../context"
|
||||
import { useFileComponent } from "@opencode-ai/ui/context/file"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
|
|
@ -45,10 +45,10 @@ import { Checkbox } from "@opencode-ai/ui/checkbox"
|
|||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { Markdown } from "./markdown"
|
||||
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
||||
import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { AttachmentCardV2 } from "../v2/components/attachment-card-v2"
|
||||
import { CommentCardV2 } from "../v2/components/comment-card-v2"
|
||||
import { checksum } from "@opencode-ai/core/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
|
||||
|
|
@ -358,9 +358,9 @@ function relativizeProjectPath(path: string, directory?: string) {
|
|||
return path.slice(directory.length)
|
||||
}
|
||||
|
||||
function getDirectory(path: string | undefined) {
|
||||
function displayDirectory(path: string | undefined) {
|
||||
const data = useData()
|
||||
return relativizeProjectPath(_getDirectory(path), data.directory)
|
||||
return relativizeProjectPath(getDirectory(path), data.directory)
|
||||
}
|
||||
|
||||
import type { IconProps } from "@opencode-ai/ui/icon"
|
||||
|
|
@ -888,12 +888,12 @@ function contextToolTrigger(part: ToolPart, i18n: ReturnType<typeof useI18n>) {
|
|||
case "list":
|
||||
return {
|
||||
title: i18n.t("ui.tool.list"),
|
||||
subtitle: getDirectory(path),
|
||||
subtitle: displayDirectory(path),
|
||||
}
|
||||
case "glob":
|
||||
return {
|
||||
title: i18n.t("ui.tool.glob"),
|
||||
subtitle: getDirectory(path),
|
||||
subtitle: displayDirectory(path),
|
||||
args: [...(pattern ? ["pattern=" + pattern] : []), ...(matches ? [matches] : [])],
|
||||
}
|
||||
case "grep": {
|
||||
|
|
@ -903,7 +903,7 @@ function contextToolTrigger(part: ToolPart, i18n: ReturnType<typeof useI18n>) {
|
|||
if (matches) args.push(matches)
|
||||
return {
|
||||
title: i18n.t("ui.tool.grep"),
|
||||
subtitle: getDirectory(path),
|
||||
subtitle: displayDirectory(path),
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
|
@ -1534,7 +1534,7 @@ function ToolFileAccordion(props: { path: string; actions?: JSX.Element; childre
|
|||
<FileIcon node={{ path: props.path, type: "file" }} />
|
||||
<div data-slot="apply-patch-file-name-container">
|
||||
<Show when={props.path.includes("/")}>
|
||||
<span data-slot="apply-patch-directory">{`\u202A${getDirectory(props.path)}\u202C`}</span>
|
||||
<span data-slot="apply-patch-directory">{`\u202A${displayDirectory(props.path)}\u202C`}</span>
|
||||
</Show>
|
||||
<span data-slot="apply-patch-filename">{getFilename(props.path)}</span>
|
||||
</div>
|
||||
|
|
@ -1863,7 +1863,7 @@ ToolRegistry.register({
|
|||
<BasicTool
|
||||
{...props}
|
||||
icon="bullet-list"
|
||||
trigger={{ title: i18n.t("ui.tool.list"), subtitle: getDirectory(props.input.path || "/") }}
|
||||
trigger={{ title: i18n.t("ui.tool.list"), subtitle: displayDirectory(props.input.path || "/") }}
|
||||
>
|
||||
<Show when={props.output}>
|
||||
<div
|
||||
|
|
@ -1891,7 +1891,7 @@ ToolRegistry.register({
|
|||
icon="magnifying-glass-menu"
|
||||
trigger={{
|
||||
title: i18n.t("ui.tool.glob"),
|
||||
subtitle: getDirectory(props.input.path || "/"),
|
||||
subtitle: displayDirectory(props.input.path || "/"),
|
||||
args: props.input.pattern ? ["pattern=" + props.input.pattern] : [],
|
||||
}}
|
||||
>
|
||||
|
|
@ -1924,7 +1924,7 @@ ToolRegistry.register({
|
|||
icon="magnifying-glass-menu"
|
||||
trigger={{
|
||||
title: i18n.t("ui.tool.grep"),
|
||||
subtitle: getDirectory(props.input.path || "/"),
|
||||
subtitle: displayDirectory(props.input.path || "/"),
|
||||
args,
|
||||
}}
|
||||
>
|
||||
|
|
@ -2344,7 +2344,7 @@ ToolRegistry.register({
|
|||
</div>
|
||||
<Show when={!pending() && props.input.filePath?.includes("/")}>
|
||||
<div data-slot="message-part-path">
|
||||
<span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span>
|
||||
<span data-slot="message-part-directory">{displayDirectory(props.input.filePath!)}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
|
@ -2411,7 +2411,7 @@ ToolRegistry.register({
|
|||
</div>
|
||||
<Show when={!pending() && props.input.filePath?.includes("/")}>
|
||||
<div data-slot="message-part-path">
|
||||
<span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span>
|
||||
<span data-slot="message-part-directory">{displayDirectory(props.input.filePath!)}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
|
@ -2520,7 +2520,7 @@ ToolRegistry.register({
|
|||
<FileIcon node={{ path: file.relativePath, type: "file" }} />
|
||||
<div data-slot="apply-patch-file-name-container">
|
||||
<Show when={file.relativePath.includes("/")}>
|
||||
<span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
|
||||
<span data-slot="apply-patch-directory">{`\u202A${displayDirectory(file.relativePath)}\u202C`}</span>
|
||||
</Show>
|
||||
<span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span>
|
||||
</div>
|
||||
|
|
@ -2593,7 +2593,7 @@ ToolRegistry.register({
|
|||
</div>
|
||||
<Show when={!pending() && single()!.relativePath.includes("/")}>
|
||||
<div data-slot="message-part-path">
|
||||
<span data-slot="message-part-directory">{getDirectory(single()!.relativePath)}</span>
|
||||
<span data-slot="message-part-directory">{displayDirectory(single()!.relativePath)}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import type { Part as PartType } from "@opencode-ai/sdk/v2"
|
||||
import type { Part } from "../presentation"
|
||||
import { partDefaultOpen } from "./part-default-open"
|
||||
|
||||
describe("partDefaultOpen", () => {
|
||||
|
|
@ -77,7 +77,7 @@ describe("partDefaultOpen", () => {
|
|||
})
|
||||
})
|
||||
|
||||
function tool(name: string, metadata: Record<string, unknown>): PartType {
|
||||
function tool(name: string, metadata: Record<string, unknown>): Part {
|
||||
return {
|
||||
id: `part_${name}`,
|
||||
sessionID: "session",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Part as PartType, ToolPart } from "@opencode-ai/sdk/v2"
|
||||
import type { Part, ToolPart } from "../presentation"
|
||||
|
||||
function deletionOnly(part: ToolPart) {
|
||||
if (!("metadata" in part.state)) return false
|
||||
|
|
@ -21,7 +21,7 @@ function deletionOnly(part: ToolPart) {
|
|||
return filediff.additions === 0 && typeof filediff.deletions === "number" && filediff.deletions > 0
|
||||
}
|
||||
|
||||
export function partDefaultOpen(part: PartType, shell = false, edit = false): boolean | undefined {
|
||||
export function partDefaultOpen(part: Part, shell = false, edit = false): boolean | undefined {
|
||||
if (part.type !== "tool") return undefined
|
||||
if (part.tool === "bash" || part.tool === "shell" || part.tool === "execute") return shell
|
||||
if (part.tool === "edit" || part.tool === "write" || part.tool === "patch" || part.tool === "apply_patch") {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { parseDiffFromFile, parsePatchFiles, type FileDiffMetadata } from "@pierre/diffs"
|
||||
import { parsePatch } from "diff"
|
||||
import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import type { PresentationFileDiff } from "../presentation"
|
||||
|
||||
type LegacyDiff = {
|
||||
file: string
|
||||
|
|
@ -13,8 +13,7 @@ type LegacyDiff = {
|
|||
status?: "added" | "deleted" | "modified"
|
||||
}
|
||||
|
||||
type SnapshotDiff = SnapshotFileDiff & { file: string }
|
||||
type ReviewDiff = SnapshotDiff | FileDiffInfo | VcsFileDiff | LegacyDiff
|
||||
type ReviewDiff = (PresentationFileDiff & { file: string }) | FileDiffInfo | LegacyDiff
|
||||
export type DiffSource = Pick<LegacyDiff, "file" | "patch" | "before" | "after">
|
||||
|
||||
export type ViewDiff = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { createEffect, createMemo, createSignal, on, onCleanup, Show } from "solid-js"
|
||||
import type { SessionStatus } from "@opencode-ai/sdk/v2/client"
|
||||
import type { SessionStatus } from "@opencode-ai/client/promise"
|
||||
import { useI18n } from "@opencode-ai/ui/context/i18n"
|
||||
import { Card } from "@opencode-ai/ui/card"
|
||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ 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 { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { type FileContent, type SnapshotFileDiff, type VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import type { PresentationFileContent, PresentationFileDiff } from "../presentation"
|
||||
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||
import { type SelectedLineRange } from "@pierre/diffs"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
|
|
@ -63,10 +63,10 @@ export type SessionReviewCommentActions = {
|
|||
|
||||
export type SessionReviewFocus = { file: string; id: string }
|
||||
|
||||
type RawReviewDiff = (SnapshotFileDiff | FileDiffInfo | VcsFileDiff) & {
|
||||
type RawReviewDiff = (PresentationFileDiff | FileDiffInfo) & {
|
||||
preloaded?: PreloadMultiFileDiffResult<any>
|
||||
}
|
||||
type ReviewDiff = ((SnapshotFileDiff & { file: string }) | FileDiffInfo | VcsFileDiff) & {
|
||||
type ReviewDiff = ((PresentationFileDiff & { file: string }) | FileDiffInfo) & {
|
||||
preloaded?: PreloadMultiFileDiffResult<any>
|
||||
}
|
||||
type Item = ViewDiff & { preloaded?: PreloadMultiFileDiffResult<any> }
|
||||
|
|
@ -116,7 +116,7 @@ export interface SessionReviewProps {
|
|||
actions?: JSX.Element
|
||||
diffs: RawReviewDiff[]
|
||||
onViewFile?: (file: string) => void
|
||||
readFile?: (path: string) => Promise<FileContent | undefined>
|
||||
readFile?: (path: string) => Promise<PresentationFileContent | undefined>
|
||||
lineCommentMention?: LineCommentEditorProps["mention"]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
import {
|
||||
AssistantMessage,
|
||||
type SnapshotFileDiff,
|
||||
Message as MessageType,
|
||||
Part as PartType,
|
||||
} from "@opencode-ai/sdk/v2/client"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import type { SessionStatus } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo, SessionStatus } from "@opencode-ai/client/promise"
|
||||
import type { AssistantMessage, Message as MessageType, Part, PresentationFileDiff } from "../presentation"
|
||||
import { useData } from "../context"
|
||||
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"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { createEffect, createMemo, createSignal, For, on, ParentProps, Show } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
|
|
@ -91,15 +85,15 @@ function list<T>(value: T[] | undefined | null, fallback: T[]) {
|
|||
return fallback
|
||||
}
|
||||
|
||||
type SummaryDiff = (SnapshotFileDiff & { file: string }) | FileDiffInfo
|
||||
type SummaryDiff = (PresentationFileDiff & { file: string }) | FileDiffInfo
|
||||
|
||||
function summaryDiff(value: SnapshotFileDiff): value is SummaryDiff {
|
||||
function summaryDiff(value: PresentationFileDiff): value is SummaryDiff {
|
||||
return typeof value.file === "string"
|
||||
}
|
||||
|
||||
const hidden = new Set(["todowrite"])
|
||||
|
||||
function partState(part: PartType, showReasoningSummaries: boolean) {
|
||||
function partState(part: Part, showReasoningSummaries: boolean) {
|
||||
if (part.type === "tool") {
|
||||
if (hidden.has(part.tool)) return
|
||||
if (part.tool === "question" && (part.state.status === "pending" || part.state.status === "running")) return
|
||||
|
|
@ -174,7 +168,7 @@ export function SessionTurn(
|
|||
const fileComponent = useFileComponent()
|
||||
|
||||
const emptyMessages: MessageType[] = []
|
||||
const emptyParts: PartType[] = []
|
||||
const emptyParts: Part[] = []
|
||||
const emptyAssistant: AssistantMessage[] = []
|
||||
const emptyDiffs: SummaryDiff[] = []
|
||||
const idle = { type: "idle" as const }
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type {
|
|||
ToolPart,
|
||||
FilePart,
|
||||
AgentPart,
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
} from "../presentation"
|
||||
import { DataProvider } from "../context/data"
|
||||
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
|
||||
import { SessionTurn } from "./session-turn"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import type { Message, Part, SnapshotFileDiff, SessionStatus, Provider } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo, SessionInfo } from "@opencode-ai/client/promise"
|
||||
import type { FileDiffInfo, SessionInfo, SessionStatus } from "@opencode-ai/client/promise"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||
import type { Message, Part, PresentationFileDiff } from "../presentation"
|
||||
|
||||
export type SessionSummary = Pick<SessionInfo, "id" | "parentID" | "title" | "time">
|
||||
|
||||
export type NormalizedProviderListResponse = {
|
||||
all: Map<string, Provider>
|
||||
type ProviderCatalog = {
|
||||
all: Map<string, { models: Record<string, { name: string }> }>
|
||||
default: {
|
||||
[key: string]: string
|
||||
}
|
||||
|
|
@ -18,13 +18,13 @@ type Data = {
|
|||
name: string
|
||||
color?: string
|
||||
}[]
|
||||
provider?: NormalizedProviderListResponse
|
||||
provider?: ProviderCatalog
|
||||
session: SessionSummary[]
|
||||
session_status: {
|
||||
[sessionID: string]: SessionStatus
|
||||
}
|
||||
session_diff: {
|
||||
[sessionID: string]: (SnapshotFileDiff | FileDiffInfo)[]
|
||||
[sessionID: string]: (PresentationFileDiff | FileDiffInfo)[]
|
||||
}
|
||||
session_diff_preload?: {
|
||||
[sessionID: string]: PreloadMultiFileDiffResult<any>[]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { FileContent } from "@opencode-ai/sdk/v2"
|
||||
import type { PresentationFileContent } from "../presentation"
|
||||
|
||||
export type MediaKind = "image" | "audio" | "svg"
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ type MediaValue = unknown
|
|||
|
||||
function mediaRecord(value: unknown) {
|
||||
if (!value || typeof value !== "object") return
|
||||
return value as Partial<FileContent> & {
|
||||
return value as Partial<PresentationFileContent> & {
|
||||
content?: unknown
|
||||
encoding?: unknown
|
||||
mimeType?: unknown
|
||||
|
|
|
|||
151
packages/session-ui/src/presentation.ts
Normal file
151
packages/session-ui/src/presentation.ts
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// TODO: Delete this contract when Session UI renders current Client messages directly.
|
||||
export type PresentationFileDiff = {
|
||||
file?: string
|
||||
patch?: string
|
||||
before?: string
|
||||
after?: string
|
||||
additions: number
|
||||
deletions: number
|
||||
status?: "added" | "deleted" | "modified"
|
||||
}
|
||||
|
||||
export type PresentationFileContent = {
|
||||
type: "text" | "binary"
|
||||
content: string
|
||||
encoding?: "base64"
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
type MessageError = {
|
||||
name: string
|
||||
data?: {
|
||||
message?: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type UserMessage = {
|
||||
id: string
|
||||
sessionID: string
|
||||
role: "user"
|
||||
time: { created: number }
|
||||
agent: string
|
||||
model: { providerID: string; modelID: string }
|
||||
summary?: { title?: string; diffs: PresentationFileDiff[] }
|
||||
}
|
||||
|
||||
export type AssistantMessage = {
|
||||
id: string
|
||||
sessionID: string
|
||||
role: "assistant"
|
||||
parentID: string
|
||||
time: { created: number; completed?: number }
|
||||
providerID: string
|
||||
modelID: string
|
||||
agent: string
|
||||
error?: MessageError
|
||||
}
|
||||
|
||||
export type Message = UserMessage | AssistantMessage
|
||||
|
||||
type PartBase = {
|
||||
id: string
|
||||
sessionID: string
|
||||
messageID: string
|
||||
}
|
||||
|
||||
export type TextPart = PartBase & {
|
||||
type: "text"
|
||||
text: string
|
||||
synthetic?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type ReasoningPart = PartBase & {
|
||||
type: "reasoning"
|
||||
text: string
|
||||
metadata?: Record<string, unknown>
|
||||
time?: { start: number; end?: number }
|
||||
}
|
||||
|
||||
type FilePartSourceText = {
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
|
||||
export type FilePartSource =
|
||||
| { type: "file"; text: FilePartSourceText; path: string }
|
||||
| {
|
||||
type: "symbol"
|
||||
text: FilePartSourceText
|
||||
path: string
|
||||
range: { start: { line: number; character: number }; end: { line: number; character: number } }
|
||||
name: string
|
||||
kind: number
|
||||
}
|
||||
| { type: "resource"; text: FilePartSourceText; clientName: string; uri: string }
|
||||
|
||||
export type FilePart = PartBase & {
|
||||
type: "file"
|
||||
mime: string
|
||||
filename?: string
|
||||
url: string
|
||||
source?: FilePartSource
|
||||
}
|
||||
|
||||
export type AgentPart = PartBase & {
|
||||
type: "agent"
|
||||
name?: string
|
||||
source?: { value?: string; start: number; end: number }
|
||||
}
|
||||
|
||||
export type ToolState =
|
||||
| { status: "pending"; input: Record<string, unknown>; raw?: string }
|
||||
| {
|
||||
status: "running"
|
||||
input: Record<string, unknown>
|
||||
title?: string
|
||||
metadata?: Record<string, unknown>
|
||||
time?: { start: number }
|
||||
}
|
||||
| {
|
||||
status: "completed"
|
||||
input: Record<string, unknown>
|
||||
output: string
|
||||
title?: string
|
||||
metadata?: Record<string, unknown>
|
||||
time?: { start: number; end: number; compacted?: number }
|
||||
attachments?: FilePart[]
|
||||
}
|
||||
| {
|
||||
status: "error"
|
||||
input: Record<string, unknown>
|
||||
error: string
|
||||
output?: string
|
||||
metadata?: Record<string, unknown>
|
||||
time?: { start: number; end: number }
|
||||
}
|
||||
|
||||
export type ToolPart = PartBase & {
|
||||
type: "tool"
|
||||
callID?: string
|
||||
tool: string
|
||||
state: ToolState
|
||||
}
|
||||
|
||||
type PassivePart = PartBase & {
|
||||
type: "subtask" | "step-start" | "step-finish" | "snapshot" | "patch" | "retry" | "compaction"
|
||||
}
|
||||
|
||||
export type Part = TextPart | ReasoningPart | FilePart | AgentPart | ToolPart | PassivePart
|
||||
|
||||
export type Todo = {
|
||||
content: string
|
||||
status: string
|
||||
}
|
||||
|
||||
export type QuestionInfo = {
|
||||
question: string
|
||||
}
|
||||
|
||||
export type QuestionAnswer = string[]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { createSignal, onCleanup, onMount, Show } from "solid-js"
|
||||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import { getFilenameTruncated } from "@opencode-ai/core/util/path"
|
||||
import { getFilenameTruncated } from "@opencode-ai/util/path"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { AttachmentCardV2 } from "./attachment-card-v2"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { FilePartSource } from "@opencode-ai/sdk/v2/client"
|
||||
import type { FilePartSource } from "../../../presentation"
|
||||
|
||||
type PromptInputV2PartBase = {
|
||||
content: string
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue