refactor(tui): remove legacy sdk client

This commit is contained in:
Dax Raad 2026-07-13 16:12:58 -04:00
commit 36f8cb7054
36 changed files with 316 additions and 510 deletions

View file

@ -8,7 +8,7 @@ import type {
import { createMemo, createSignal, onCleanup, onMount, Show } from "solid-js"
import { useClipboard } from "../context/clipboard"
import { useData } from "../context/data"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { useTheme } from "../context/theme"
import { useBindings } from "../keymap"
import { useDialog } from "../ui/dialog"
@ -102,7 +102,7 @@ function manageConnections(
) {
dialog.replace(() => {
const data = useData()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
return (
<DialogSelect
@ -121,7 +121,7 @@ function manageConnections(
title: `Disconnect ${connection.label}`,
value: connection.id,
onSelect: () => {
void sdk.api.credential
void client.api.credential
.remove({ credentialID: connection.id, location: location(data) })
.then(() => disconnected(integration.name, data, dialog, toast))
.catch(toast.error)
@ -172,7 +172,7 @@ function KeyMethod(props: {
}) {
const data = useData()
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
const { theme } = useTheme()
const [error, setError] = createSignal<string>()
@ -183,7 +183,7 @@ function KeyMethod(props: {
placeholder="API key"
onConfirm={(key) => {
if (!key) return
void sdk.api.integration
void client.api.integration
.connect.key({
integrationID: props.integration.id,
location: location(data),
@ -218,11 +218,11 @@ function OAuthStarting(props: {
}) {
const data = useData()
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
onMount(() => {
void sdk.api.integration
void client.api.integration
.connect.oauth({
integrationID: props.integration.id,
location: location(data),
@ -267,7 +267,7 @@ function OAuthAuto(props: {
}) {
const data = useData()
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
const clipboard = useClipboard()
let timer: ReturnType<typeof setTimeout> | undefined
@ -291,7 +291,7 @@ function OAuthAuto(props: {
}))
const poll = () => {
void sdk.api.integration
void client.api.integration
.attempt.status({ attemptID: props.attempt.attemptID, location: location(data) })
.then((result) => {
const status = result.data
@ -318,7 +318,7 @@ function OAuthAuto(props: {
onCleanup(() => {
if (timer) clearTimeout(timer)
if (settled) return
void sdk.api.integration.attempt.cancel({ attemptID: props.attempt.attemptID, location: location(data) })
void client.api.integration.attempt.cancel({ attemptID: props.attempt.attemptID, location: location(data) })
})
return (
@ -340,7 +340,7 @@ function OAuthCode(props: {
}) {
const data = useData()
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
const { theme } = useTheme()
const [error, setError] = createSignal<string>()
@ -348,7 +348,7 @@ function OAuthCode(props: {
onCleanup(() => {
if (settled) return
void sdk.api.integration.attempt.cancel({ attemptID: props.attempt.attemptID, location: location(data) })
void client.api.integration.attempt.cancel({ attemptID: props.attempt.attemptID, location: location(data) })
})
return (
@ -357,7 +357,7 @@ function OAuthCode(props: {
placeholder="Authorization code"
onConfirm={(code) => {
if (!code) return
void sdk.api.integration
void client.api.integration
.attempt.complete({ attemptID: props.attempt.attemptID, location: location(data), code })
.then(() => {
settled = true

View file

@ -4,7 +4,7 @@ import { createMemo, createResource, createSignal, onMount, Show } from "solid-j
import path from "path"
import { DialogSelect, type DialogSelectOption } from "../ui/dialog-select"
import { useDialog } from "../ui/dialog"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { useTheme } from "../context/theme"
import { useData } from "../context/data"
import { abbreviateHome } from "../runtime"
@ -35,7 +35,7 @@ type DialogMoveSessionProps = {
export function DialogMoveSession(props: DialogMoveSessionProps) {
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const dimensions = useTerminalDimensions()
const { theme } = useTheme()
const sessionData = useData()
@ -63,7 +63,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
const [loadedProject] = createResource(
() => (projectContext.project() === undefined ? props.projectID : undefined),
(projectID) =>
sdk.api.project
client.api.project
.current({ location: { directory: projectContext.instance.directory() || paths.cwd } })
.then((project) => (project.id === projectID ? project.directory : undefined))
.catch(() => undefined),
@ -78,11 +78,11 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
async (projectID, info): Promise<ReadonlyArray<ProjectDirectory> | undefined> => {
try {
const location = { directory: projectContext.instance.directory() || paths.cwd }
await sdk.api.projectCopy.refresh({
await client.api.projectCopy.refresh({
projectID,
location,
})
const directories = await sdk.api.project.directories({
const directories = await client.api.project.directories({
projectID,
location,
})
@ -232,7 +232,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
setToDelete(undefined)
setRemoving(selected.directory)
setWorking(true)
const error = await sdk.api.projectCopy
const error = await client.api.projectCopy
.remove({
projectID: props.projectID,
location: { directory: projectContext.instance.directory() || paths.cwd },
@ -247,7 +247,9 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
setRemoving(undefined)
setWorking(false)
if (isRecord(error) && isRecord(error.data) && error.data.forceRequired === true) {
const status = await sdk.client.vcs.status({ directory: selected.directory }).catch(() => undefined)
const status = await client.api.vcs
.status({ location: { directory: selected.directory } })
.catch(() => undefined)
const choice = await DialogWorkspaceFileChanges.show(dialog, status?.data ?? [], {
title: "Delete working copy?",
message: "This working copy has file changes. Do you want to delete it anyway?",
@ -257,7 +259,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
return
}
reopen(selected.directory)
const forcedError = await sdk.api.projectCopy
const forcedError = await client.api.projectCopy
.remove({
projectID: props.projectID,
location: { directory: projectContext.instance.directory() || paths.cwd },

View file

@ -2,7 +2,7 @@ import { TextAttributes } from "@opentui/core"
import { useTerminalDimensions } from "@opentui/solid"
import { createMemo, createResource, createSignal, For, Show } from "solid-js"
import { renderUnicodeCompact } from "uqr"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { useTheme } from "../context/theme"
import { useDialog } from "../ui/dialog"
import { errorMessage } from "../util/error"
@ -13,7 +13,7 @@ export type DialogPairCredentials = {
}
export function DialogPair(props: { credentials?: DialogPairCredentials }) {
const sdk = useSDK()
const client = useClient()
const dialog = useDialog()
const dimensions = useTerminalDimensions()
const { theme } = useTheme()
@ -25,7 +25,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
dialog.setCentered(true)
const [server] = createResource(() =>
sdk.api.server
client.api.server
.get()
.catch((error) => {
setLoadError(error)

View file

@ -8,7 +8,7 @@ import { useData } from "../context/data"
import { Locale } from "../util/locale"
import { useProject } from "../context/project"
import { useTheme } from "../context/theme"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { useLocal } from "../context/local"
import { createDebouncedSignal } from "../util/signal"
import { useToast } from "../ui/toast"
@ -23,7 +23,7 @@ export function DialogSessionList() {
const data = useData()
const project = useProject()
const { theme } = useTheme()
const sdk = useSDK()
const client = useClient()
const local = useLocal()
const toast = useToast()
const [search, setSearch] = createDebouncedSignal("", 150)
@ -36,7 +36,7 @@ export function DialogSessionList() {
if (!query) return
const location = data.location.default()
try {
const response = await sdk.api.session.list({
const response = await client.api.session.list({
search: query,
limit: 50,
order: "desc",
@ -140,7 +140,7 @@ export function DialogSessionList() {
setToDelete(option.value)
return
}
void sdk.api.session.remove({ sessionID: option.value }).catch((error) => {
void client.api.session.remove({ sessionID: option.value }).catch((error) => {
setToDelete(undefined)
toast.show({
message: `Failed to delete session: ${errorMessage(error)}`,

View file

@ -1,12 +1,12 @@
import { DialogPrompt } from "../ui/dialog-prompt"
import { type DialogContext, useDialog } from "../ui/dialog"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { useToast } from "../ui/toast"
import { errorMessage } from "../util/error"
export function DialogSessionRename(props: { sessionID: string; currentTitle?: string }) {
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
return (
@ -17,7 +17,7 @@ export function DialogSessionRename(props: { sessionID: string; currentTitle?: s
onConfirm={(value) => {
const title = value.trim()
if (!title) return
void sdk.api.session
void client.api.session
.rename({ sessionID: props.sessionID, title })
.then(() => dialog.clear())
.catch((error) =>

View file

@ -2,11 +2,11 @@ import { createMemo, createResource } from "solid-js"
import { DialogSelect } from "../ui/dialog-select"
import { useDialog } from "../ui/dialog"
import { useProject } from "../context/project"
import { useSDK } from "../context/sdk"
import { useClient } from "../context/client"
import { createStore } from "solid-js/store"
export function DialogTag(props: { onSelect?: (value: string) => void }) {
const sdk = useSDK()
const client = useClient()
const dialog = useDialog()
const project = useProject()
@ -17,7 +17,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) {
const [files] = createResource(
() => [store.filter],
async () => {
const result = await sdk.api.file
const result = await client.api.file
.find({
query: store.filter,
type: "file",

View file

@ -7,7 +7,7 @@ import { createMemo, createResource, createEffect, onMount, onCleanup, Index, Sh
import { createStore } from "solid-js/store"
import { useEditorContext } from "../../context/editor"
import { useProject } from "../../context/project"
import { useSDK } from "../../context/sdk"
import { useClient } from "../../context/client"
import { useData } from "../../context/data"
import { getScrollAcceleration } from "../../util/scroll"
import { useTuiPaths } from "../../context/runtime"
@ -84,7 +84,7 @@ export function Autocomplete(props: {
promptPartTypeId: () => number
}) {
const editor = useEditorContext()
const sdk = useSDK()
const client = useClient()
const data = useData()
const project = useProject()
const slashes = useCommandSlashes()
@ -315,7 +315,7 @@ export function Autocomplete(props: {
if (referenceMatch()) return []
const { lineRange, baseQuery } = extractLineRange(input.query ?? "")
const result = await sdk.api.file
const result = await client.api.file
.find({
query: baseQuery,
limit: 20,

View file

@ -21,7 +21,7 @@ import { EmptyBorder, SplitBorder } from "../../ui/border"
import { useTuiPaths, useTuiTerminalEnvironment } from "../../context/runtime"
import { useClipboard } from "../../context/clipboard"
import { Spinner } from "../spinner"
import { useSDK } from "../../context/sdk"
import { useClient } from "../../context/client"
import { useRoute } from "../../context/route"
import { useProject } from "../../context/project"
import { useEvent } from "../../context/event"
@ -148,7 +148,7 @@ export function Prompt(props: PromptProps) {
const paths = useTuiPaths()
const terminalEnvironment = useTuiTerminalEnvironment()
const clipboard = useClipboard()
const sdk = useSDK()
const client = useClient()
const editor = useEditorContext()
const route = useRoute()
const project = useProject()
@ -421,7 +421,7 @@ export function Prompt(props: PromptProps) {
}, 5000)
if (store.interrupt >= 2) {
void sdk.api.session.interrupt({
void client.api.session.interrupt({
sessionID: props.sessionID,
})
setStore("interrupt", 0)
@ -440,7 +440,7 @@ export function Prompt(props: PromptProps) {
if (!input.focused) return
if (!props.sessionID) return
void sdk.api.session.background({
void client.api.session.background({
sessionID: props.sessionID,
})
dialog.clear()
@ -965,7 +965,7 @@ export function Prompt(props: PromptProps) {
finishMoveProgress = Boolean(move.progress())
const location = data.location.default()
const created = await sdk.api.session
const created = await client.api.session
.create({
location: directory ? { directory } : location,
agent: agent.id,
@ -1009,7 +1009,7 @@ export function Prompt(props: PromptProps) {
if (store.mode === "shell") {
move.startSubmit()
void sdk.api.session.shell({
void client.api.session.shell({
sessionID,
command: inputText,
})
@ -1028,7 +1028,7 @@ export function Prompt(props: PromptProps) {
const restOfInput = firstLineEnd === -1 ? "" : inputText.slice(firstLineEnd + 1)
const args = firstLineArgs.join(" ") + (restOfInput ? "\n" + restOfInput : "")
void sdk.api.session
void client.api.session
.command({
sessionID,
command: command.slice(1),
@ -1048,7 +1048,7 @@ export function Prompt(props: PromptProps) {
)
) {
move.startSubmit()
void sdk.api.session.skill({
void client.api.session.skill({
sessionID,
skill: inputText.split("\n")[0].split(" ")[0].slice(1),
})
@ -1059,20 +1059,20 @@ export function Prompt(props: PromptProps) {
session = data.session.get(sessionID)
}
if (session?.agent !== agent.id) {
await sdk.api.session.switchAgent({ sessionID, agent: agent.id })
await client.api.session.switchAgent({ sessionID, agent: agent.id })
}
if (
session?.model?.providerID !== selectedModel.providerID ||
session.model.id !== selectedModel.modelID ||
session.model.variant !== variant
) {
await sdk.api.session.switchModel({
await client.api.session.switchModel({
sessionID,
model: { providerID: selectedModel.providerID, id: selectedModel.modelID, variant },
})
}
if (session?.revert) {
const error = await sdk.api.session.revert.commit({ sessionID }).then(
const error = await client.api.session.revert.commit({ sessionID }).then(
() => undefined,
(error) => error,
)
@ -1083,7 +1083,7 @@ export function Prompt(props: PromptProps) {
}
if (pendingEditorSelection) {
// Keep editor context hidden while admitting it before the corresponding user prompt.
const error = await sdk.api.session
const error = await client.api.session
.synthetic({
sessionID,
text: formatEditorContext(pendingEditorSelection),
@ -1098,7 +1098,7 @@ export function Prompt(props: PromptProps) {
return false
}
}
const error = await sdk.api.session
const error = await client.api.session
.prompt({
sessionID,
text: inputText,

View file

@ -3,7 +3,7 @@ import path from "path"
import { useTuiPaths } from "../../context/runtime"
import { errorMessage } from "../../util/error"
import { useDialog } from "../../ui/dialog"
import { useSDK } from "../../context/sdk"
import { useClient } from "../../context/client"
import { useToast } from "../../ui/toast"
import { DialogMoveSession, type MoveSessionSelection } from "../dialog-move-session"
import { DialogWorkspaceFileChanges } from "../dialog-workspace-file-changes"
@ -17,7 +17,7 @@ function moveReminderText(directory: string) {
export function usePromptMove(input: { projectID: () => string | undefined; sessionID: () => string | undefined }) {
const dialog = useDialog()
const sdk = useSDK()
const client = useClient()
const toast = useToast()
const homeDestination = useHomeSessionDestination()
const project = useProject()
@ -33,7 +33,7 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
setCreating(true)
setProgress("Creating copy")
try {
const result = await sdk.api.projectCopy.create({
const result = await client.api.projectCopy.create({
projectID,
location: { directory: project.instance.directory() || paths.cwd },
strategy: "git_worktree",
@ -44,7 +44,7 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
if (!directory) throw new Error("No project copy directory returned")
// Call a location-based route to make sure it's bootstrapped before moving on.
await sdk.api.location.get({ location: { directory } })
await client.api.location.get({ location: { directory } })
setProgress("Creating session")
return directory
@ -98,7 +98,9 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
async function moveExistingSession(sessionID: string, selection: MoveSessionSelection) {
const session = await resolveSession(sessionID)
const status = await sdk.client.vcs.status({ directory: session?.location.directory }).catch(() => undefined)
const status = await client.api.vcs
.status({ location: session?.location.directory ? { directory: session.location.directory } : undefined })
.catch(() => undefined)
const choice = status?.data?.length ? await DialogWorkspaceFileChanges.show(dialog, status.data) : "no"
if (!choice) return
dialog.clear()
@ -110,8 +112,8 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
}
setProgress("Moving session")
try {
await sdk.api.session.move({ sessionID, destination: { directory }, moveChanges: choice === "yes" })
await sdk.api.session
await client.api.session.move({ sessionID, destination: { directory }, moveChanges: choice === "yes" })
await client.api.session
.synthetic({ sessionID, text: moveReminderText(directory), resume: false })
.catch(() => undefined)
dialog.clear()
@ -129,7 +131,7 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
if (projectID) return projectID
const sessionID = input.sessionID()
if (sessionID) return (await resolveSession(sessionID))?.projectID
return sdk.api.project
return client.api.project
.current({ location: { directory: project.instance.directory() || paths.cwd } })
.then((project) => project.id)
.catch(() => undefined)