refactor(tui): remove legacy sync context
This commit is contained in:
@@ -23,7 +23,6 @@
|
|||||||
"./context/project": "./src/context/project.tsx",
|
"./context/project": "./src/context/project.tsx",
|
||||||
"./context/runtime": "./src/context/runtime.tsx",
|
"./context/runtime": "./src/context/runtime.tsx",
|
||||||
"./context/sdk": "./src/context/sdk.tsx",
|
"./context/sdk": "./src/context/sdk.tsx",
|
||||||
"./context/sync": "./src/context/sync.tsx",
|
|
||||||
"./context/theme": "./src/context/theme.tsx",
|
"./context/theme": "./src/context/theme.tsx",
|
||||||
"./context/editor": "./src/context/editor.ts",
|
"./context/editor": "./src/context/editor.ts",
|
||||||
"./context/clipboard": "./src/context/clipboard.tsx",
|
"./context/clipboard": "./src/context/clipboard.tsx",
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import { useEvent } from "./context/event"
|
|||||||
import { SDKProvider, useSDK } from "./context/sdk"
|
import { SDKProvider, useSDK } from "./context/sdk"
|
||||||
import { StartupLoading } from "./component/startup-loading"
|
import { StartupLoading } from "./component/startup-loading"
|
||||||
import { Reconnecting } from "./component/reconnecting"
|
import { Reconnecting } from "./component/reconnecting"
|
||||||
import { SyncProvider, useSync } from "./context/sync"
|
|
||||||
import { DataProvider, useData } from "./context/data"
|
import { DataProvider, useData } from "./context/data"
|
||||||
import { LocationProvider } from "./context/location"
|
import { LocationProvider } from "./context/location"
|
||||||
import { LocalProvider, useLocal } from "./context/local"
|
import { LocalProvider, useLocal } from "./context/local"
|
||||||
@@ -345,7 +344,6 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
|
|||||||
>
|
>
|
||||||
<PermissionProvider>
|
<PermissionProvider>
|
||||||
<ProjectProvider>
|
<ProjectProvider>
|
||||||
<SyncProvider>
|
|
||||||
<DataProvider>
|
<DataProvider>
|
||||||
<ThemeProvider mode={mode}>
|
<ThemeProvider mode={mode}>
|
||||||
<LocalProvider>
|
<LocalProvider>
|
||||||
@@ -377,7 +375,6 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
|
|||||||
</LocalProvider>
|
</LocalProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</DataProvider>
|
</DataProvider>
|
||||||
</SyncProvider>
|
|
||||||
</ProjectProvider>
|
</ProjectProvider>
|
||||||
</PermissionProvider>
|
</PermissionProvider>
|
||||||
</SDKProvider>
|
</SDKProvider>
|
||||||
@@ -430,7 +427,6 @@ function App(props: {
|
|||||||
const keymap = useOpencodeKeymap()
|
const keymap = useOpencodeKeymap()
|
||||||
const event = useEvent()
|
const event = useEvent()
|
||||||
const sdk = useSDK()
|
const sdk = useSDK()
|
||||||
const sync = useSync()
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const themeState = useTheme()
|
const themeState = useTheme()
|
||||||
const { theme, mode, setMode, locked, lock, unlock } = themeState
|
const { theme, mode, setMode, locked, lock, unlock } = themeState
|
||||||
@@ -480,7 +476,7 @@ function App(props: {
|
|||||||
routes: pluginRuntime.routes,
|
routes: pluginRuntime.routes,
|
||||||
event,
|
event,
|
||||||
sdk,
|
sdk,
|
||||||
sync,
|
project,
|
||||||
data,
|
data,
|
||||||
theme: themeState,
|
theme: themeState,
|
||||||
toast,
|
toast,
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
import type {
|
|
||||||
Agent,
|
|
||||||
Command,
|
|
||||||
Config,
|
|
||||||
FormatterStatus,
|
|
||||||
LspStatus,
|
|
||||||
McpResource,
|
|
||||||
McpStatus,
|
|
||||||
Message,
|
|
||||||
Part,
|
|
||||||
PermissionRequest,
|
|
||||||
Provider,
|
|
||||||
QuestionRequest,
|
|
||||||
Session,
|
|
||||||
FileDiffInfo,
|
|
||||||
VcsInfo,
|
|
||||||
} from "@opencode-ai/sdk/v2"
|
|
||||||
import { createStore } from "solid-js/store"
|
|
||||||
import { createSimpleContext } from "./helper"
|
|
||||||
import { useProject } from "./project"
|
|
||||||
|
|
||||||
export const {
|
|
||||||
context: SyncContext,
|
|
||||||
use: useSync,
|
|
||||||
provider: SyncProvider,
|
|
||||||
} = createSimpleContext({
|
|
||||||
name: "Sync",
|
|
||||||
init: () => {
|
|
||||||
const project = useProject()
|
|
||||||
const [store, setStore] = createStore<{
|
|
||||||
status: "loading" | "partial" | "complete"
|
|
||||||
provider: Provider[]
|
|
||||||
agent: Agent[]
|
|
||||||
command: Command[]
|
|
||||||
permission: Record<string, PermissionRequest[]>
|
|
||||||
question: Record<string, QuestionRequest[]>
|
|
||||||
config: Config
|
|
||||||
session: Session[]
|
|
||||||
session_diff: Record<string, FileDiffInfo[]>
|
|
||||||
message: Record<string, Message[]>
|
|
||||||
part: Record<string, Part[]>
|
|
||||||
lsp: LspStatus[]
|
|
||||||
mcp: Record<string, McpStatus>
|
|
||||||
mcp_resource: Record<string, McpResource>
|
|
||||||
formatter: FormatterStatus[]
|
|
||||||
vcs: VcsInfo | undefined
|
|
||||||
}>({
|
|
||||||
status: "complete",
|
|
||||||
provider: [],
|
|
||||||
agent: [],
|
|
||||||
command: [],
|
|
||||||
permission: {},
|
|
||||||
question: {},
|
|
||||||
config: {},
|
|
||||||
session: [],
|
|
||||||
session_diff: {},
|
|
||||||
message: {},
|
|
||||||
part: {},
|
|
||||||
lsp: [],
|
|
||||||
mcp: {},
|
|
||||||
mcp_resource: {},
|
|
||||||
formatter: [],
|
|
||||||
vcs: undefined,
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: store,
|
|
||||||
set: setStore,
|
|
||||||
get status() {
|
|
||||||
return store.status
|
|
||||||
},
|
|
||||||
get ready() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
get path() {
|
|
||||||
return project.instance.path()
|
|
||||||
},
|
|
||||||
session: {
|
|
||||||
get(_sessionID: string) {
|
|
||||||
return undefined as Session | undefined
|
|
||||||
},
|
|
||||||
query() {
|
|
||||||
return {} as { scope?: "project"; path?: string }
|
|
||||||
},
|
|
||||||
async refresh() {},
|
|
||||||
status(_sessionID: string) {
|
|
||||||
return "idle" as const
|
|
||||||
},
|
|
||||||
async sync(_sessionID: string) {},
|
|
||||||
},
|
|
||||||
async bootstrap(_input: { fatal?: boolean } = {}) {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -3,8 +3,8 @@ import type { Config } from "../config"
|
|||||||
import type { useEvent } from "../context/event"
|
import type { useEvent } from "../context/event"
|
||||||
import type { useRoute } from "../context/route"
|
import type { useRoute } from "../context/route"
|
||||||
import type { useSDK } from "../context/sdk"
|
import type { useSDK } from "../context/sdk"
|
||||||
import type { useSync } from "../context/sync"
|
|
||||||
import type { useData } from "../context/data"
|
import type { useData } from "../context/data"
|
||||||
|
import type { useProject } from "../context/project"
|
||||||
import type { useTheme } from "../context/theme"
|
import type { useTheme } from "../context/theme"
|
||||||
import { Dialog as DialogUI, type useDialog } from "../ui/dialog"
|
import { Dialog as DialogUI, type useDialog } from "../ui/dialog"
|
||||||
import type { useOpencodeKeymap } from "../keymap"
|
import type { useOpencodeKeymap } from "../keymap"
|
||||||
@@ -29,7 +29,7 @@ type Input = {
|
|||||||
routes: PluginRoutes
|
routes: PluginRoutes
|
||||||
event: ReturnType<typeof useEvent>
|
event: ReturnType<typeof useEvent>
|
||||||
sdk: ReturnType<typeof useSDK>
|
sdk: ReturnType<typeof useSDK>
|
||||||
sync: ReturnType<typeof useSync>
|
project: ReturnType<typeof useProject>
|
||||||
data: ReturnType<typeof useData>
|
data: ReturnType<typeof useData>
|
||||||
theme: ReturnType<typeof useTheme>
|
theme: ReturnType<typeof useTheme>
|
||||||
toast: ReturnType<typeof useToast>
|
toast: ReturnType<typeof useToast>
|
||||||
@@ -95,57 +95,51 @@ function mapOptionCb<Value>(cb?: (item: TuiDialogSelectOption<Value>) => void) {
|
|||||||
return (item: SelectOption<Value>) => cb(pickOption(item))
|
return (item: SelectOption<Value>) => cb(pickOption(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateApi(sync: ReturnType<typeof useSync>, data: ReturnType<typeof useData>): TuiPluginApi["state"] {
|
function stateApi(project: ReturnType<typeof useProject>, data: ReturnType<typeof useData>): TuiPluginApi["state"] {
|
||||||
return {
|
return {
|
||||||
get ready() {
|
get ready() {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
get config() {
|
get config() {
|
||||||
return sync.data.config
|
return {}
|
||||||
},
|
},
|
||||||
get provider() {
|
get provider() {
|
||||||
return sync.data.provider
|
return []
|
||||||
},
|
},
|
||||||
get path() {
|
get path() {
|
||||||
return sync.path
|
return project.instance.path()
|
||||||
},
|
},
|
||||||
get vcs() {
|
get vcs() {
|
||||||
if (!sync.data.vcs) return
|
return undefined
|
||||||
return {
|
|
||||||
branch: sync.data.vcs.branch,
|
|
||||||
default_branch: sync.data.vcs.default_branch,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
count() {
|
count() {
|
||||||
return data.session.list().length
|
return data.session.list().length
|
||||||
},
|
},
|
||||||
get(sessionID) {
|
get(_sessionID) {
|
||||||
return sync.session.get(sessionID)
|
return undefined
|
||||||
},
|
},
|
||||||
diff(sessionID) {
|
diff(_sessionID) {
|
||||||
return (sync.data.session_diff[sessionID] ?? []).flatMap((item) =>
|
return []
|
||||||
item.file === undefined ? [] : [{ ...item, file: item.file }],
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
messages(sessionID) {
|
messages(_sessionID) {
|
||||||
return sync.data.message[sessionID] ?? []
|
return []
|
||||||
},
|
},
|
||||||
status(sessionID) {
|
status(sessionID) {
|
||||||
return data.session.status(sessionID) === "running" ? { type: "busy" } : { type: "idle" }
|
return data.session.status(sessionID) === "running" ? { type: "busy" } : { type: "idle" }
|
||||||
},
|
},
|
||||||
permission(sessionID) {
|
permission(_sessionID) {
|
||||||
return sync.data.permission[sessionID] ?? []
|
return []
|
||||||
},
|
},
|
||||||
question(sessionID) {
|
question(_sessionID) {
|
||||||
return sync.data.question[sessionID] ?? []
|
return []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
part(messageID) {
|
part(_messageID) {
|
||||||
return sync.data.part[messageID] ?? []
|
return []
|
||||||
},
|
},
|
||||||
lsp() {
|
lsp() {
|
||||||
return sync.data.lsp.map((item) => ({ id: item.id, root: item.root, status: item.status }))
|
return []
|
||||||
},
|
},
|
||||||
mcp() {
|
mcp() {
|
||||||
return (data.location.mcp.server.list() ?? [])
|
return (data.location.mcp.server.list() ?? [])
|
||||||
@@ -297,7 +291,7 @@ export function createTuiApiAdapters(input: Input): Omit<TuiPluginApi, "lifecycl
|
|||||||
set() {},
|
set() {},
|
||||||
ready: true,
|
ready: true,
|
||||||
},
|
},
|
||||||
state: stateApi(input.sync, input.data),
|
state: stateApi(input.project, input.data),
|
||||||
get client() {
|
get client() {
|
||||||
return input.sdk.client
|
return input.sdk.client
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/** @jsxImportSource @opentui/solid */
|
|
||||||
import { testRender } from "@opentui/solid"
|
|
||||||
import { onMount } from "solid-js"
|
|
||||||
import { ArgsProvider } from "../../../../src/context/args"
|
|
||||||
import { ProjectProvider, useProject } from "../../../../src/context/project"
|
|
||||||
import { SDKProvider } from "../../../../src/context/sdk"
|
|
||||||
import { SyncProvider, useSync } from "../../../../src/context/sync"
|
|
||||||
import { PermissionProvider } from "../../../../src/context/permission"
|
|
||||||
import { ExitProvider } from "../../../../src/context/exit"
|
|
||||||
import { createApi, createClient, createEventStream, createFetch, type FetchHandler } from "../../../fixture/tui-sdk"
|
|
||||||
import { TestTuiContexts } from "../../../fixture/tui-environment"
|
|
||||||
export { createEventStream, createFetch, directory, json, worktree } from "../../../fixture/tui-sdk"
|
|
||||||
|
|
||||||
export async function wait(fn: () => boolean, timeout = 2000) {
|
|
||||||
const start = Date.now()
|
|
||||||
while (!fn()) {
|
|
||||||
if (Date.now() - start > timeout) throw new Error("timed out waiting for condition")
|
|
||||||
await Bun.sleep(10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ctx = { project: ReturnType<typeof useProject>; sync: ReturnType<typeof useSync> }
|
|
||||||
|
|
||||||
export async function mount(override?: FetchHandler, state?: string) {
|
|
||||||
const events = createEventStream()
|
|
||||||
const calls = createFetch(override, events)
|
|
||||||
let sync!: ReturnType<typeof useSync>
|
|
||||||
let project!: ReturnType<typeof useProject>
|
|
||||||
let done!: () => void
|
|
||||||
const ready = new Promise<void>((resolve) => {
|
|
||||||
done = resolve
|
|
||||||
})
|
|
||||||
|
|
||||||
function Probe() {
|
|
||||||
const ctx: Ctx = { project: useProject(), sync: useSync() }
|
|
||||||
onMount(() => {
|
|
||||||
sync = ctx.sync
|
|
||||||
project = ctx.project
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
return <box />
|
|
||||||
}
|
|
||||||
|
|
||||||
const app = await testRender(() => (
|
|
||||||
<TestTuiContexts paths={state ? { state } : undefined}>
|
|
||||||
<ArgsProvider>
|
|
||||||
<SDKProvider client={createClient(calls.fetch)} api={createApi(calls.fetch)}>
|
|
||||||
<PermissionProvider>
|
|
||||||
<ProjectProvider>
|
|
||||||
<ExitProvider exit={() => {}}>
|
|
||||||
<SyncProvider>
|
|
||||||
<Probe />
|
|
||||||
</SyncProvider>
|
|
||||||
</ExitProvider>
|
|
||||||
</ProjectProvider>
|
|
||||||
</PermissionProvider>
|
|
||||||
</SDKProvider>
|
|
||||||
</ArgsProvider>
|
|
||||||
</TestTuiContexts>
|
|
||||||
))
|
|
||||||
|
|
||||||
await ready
|
|
||||||
await wait(() => sync.status === "complete")
|
|
||||||
return { app, emit: events.emit, project, sync, session: calls.session }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/** @jsxImportSource @opentui/solid */
|
|
||||||
import { expect, test } from "bun:test"
|
|
||||||
import { mount } from "./sync-fixture"
|
|
||||||
|
|
||||||
test("legacy sync is an inert compatibility context", async () => {
|
|
||||||
const { app, session, sync } = await mount()
|
|
||||||
|
|
||||||
try {
|
|
||||||
expect(sync.status).toBe("complete")
|
|
||||||
expect(sync.ready).toBe(true)
|
|
||||||
expect(sync.data.session).toEqual([])
|
|
||||||
expect(sync.data.message).toEqual({})
|
|
||||||
expect(sync.data.provider).toEqual([])
|
|
||||||
expect(sync.session.get("ses_test")).toBeUndefined()
|
|
||||||
|
|
||||||
await sync.bootstrap()
|
|
||||||
await sync.session.refresh()
|
|
||||||
await sync.session.sync("ses_test")
|
|
||||||
|
|
||||||
expect(session).toEqual([])
|
|
||||||
} finally {
|
|
||||||
app.renderer.destroy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user