Use server naming for shared API/events

This commit is contained in:
Shantur Rathore
2025-11-21 00:04:01 +00:00
parent d6fdef68d9
commit 2ff51c1866
9 changed files with 31 additions and 31 deletions

View File

@@ -2,7 +2,7 @@ import { Component, Show, For, createSignal, createMemo, createEffect, onCleanup
import { ArrowUpLeft, Folder as FolderIcon, Loader2, X } from "lucide-solid" import { ArrowUpLeft, Folder as FolderIcon, Loader2, X } from "lucide-solid"
import type { FileSystemEntry, FileSystemListingMetadata } from "../../../server/src/api-types" import type { FileSystemEntry, FileSystemListingMetadata } from "../../../server/src/api-types"
import { WINDOWS_DRIVES_ROOT } from "../../../server/src/api-types" import { WINDOWS_DRIVES_ROOT } from "../../../server/src/api-types"
import { cliApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
function normalizePathKey(input?: string | null) { function normalizePathKey(input?: string | null) {
if (!input || input === "." || input === "./") { if (!input || input === "." || input === "./") {
@@ -144,7 +144,7 @@ const DirectoryBrowserDialog: Component<DirectoryBrowserDialogProps> = (props) =
}) })
} }
const response = await cliApi.listFileSystem(targetPath, { includeFiles: false }) const response = await serverApi.listFileSystem(targetPath, { includeFiles: false })
const canonicalKey = normalizePathKey(response.metadata.currentPath) const canonicalKey = normalizePathKey(response.metadata.currentPath)
const directories = response.entries const directories = response.entries
.filter((entry) => entry.type === "directory") .filter((entry) => entry.type === "directory")

View File

@@ -1,7 +1,7 @@
import { Component, Show, For, createSignal, createMemo, createEffect, onCleanup } from "solid-js" import { Component, Show, For, createSignal, createMemo, createEffect, onCleanup } from "solid-js"
import { Folder as FolderIcon, File as FileIcon, Loader2, Search, X, ArrowUpLeft } from "lucide-solid" import { Folder as FolderIcon, File as FileIcon, Loader2, Search, X, ArrowUpLeft } from "lucide-solid"
import type { FileSystemEntry, FileSystemListingMetadata } from "../../../server/src/api-types" import type { FileSystemEntry, FileSystemListingMetadata } from "../../../server/src/api-types"
import { cliApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
const MAX_RESULTS = 200 const MAX_RESULTS = 200
@@ -91,7 +91,7 @@ const FileSystemBrowserDialog: Component<FileSystemBrowserDialogProps> = (props)
const loadPromise = (async () => { const loadPromise = (async () => {
setLoadingPath(normalized) setLoadingPath(normalized)
const response = await cliApi.listFileSystem(normalized === "." ? "." : normalized, { const response = await serverApi.listFileSystem(normalized === "." ? "." : normalized, {
includeFiles: props.mode === "files", includeFiles: props.mode === "files",
}) })
directoryCache.set(normalized, response.entries) directoryCache.set(normalized, response.entries)

View File

@@ -1,7 +1,7 @@
import { Component, For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js" import { Component, For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { FolderOpen, Trash2, Check, AlertCircle, Loader2, Plus } from "lucide-solid" import { FolderOpen, Trash2, Check, AlertCircle, Loader2, Plus } from "lucide-solid"
import { useConfig } from "../stores/preferences" import { useConfig } from "../stores/preferences"
import { cliApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
import FileSystemBrowserDialog from "./filesystem-browser-dialog" import FileSystemBrowserDialog from "./filesystem-browser-dialog"
interface BinaryOption { interface BinaryOption {
@@ -105,7 +105,7 @@ const OpenCodeBinarySelector: Component<OpenCodeBinarySelectorProps> = (props) =
setValidating(true) setValidating(true)
setValidationError(null) setValidationError(null)
const result = await cliApi.validateBinary(path) const result = await serverApi.validateBinary(path)
if (result.valid && result.version) { if (result.valid && result.version) {
const updatedVersionInfo = new Map(versionInfo()) const updatedVersionInfo = new Map(versionInfo())

View File

@@ -1,7 +1,7 @@
import { Component, createSignal, createEffect, For, Show, onCleanup } from "solid-js" import { Component, createSignal, createEffect, For, Show, onCleanup } from "solid-js"
import type { Agent } from "../types/session" import type { Agent } from "../types/session"
import type { OpencodeClient } from "@opencode-ai/sdk/client" import type { OpencodeClient } from "@opencode-ai/sdk/client"
import { cliApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
const SEARCH_RESULT_LIMIT = 100 const SEARCH_RESULT_LIMIT = 100
const SEARCH_DEBOUNCE_MS = 200 const SEARCH_DEBOUNCE_MS = 200
@@ -115,7 +115,7 @@ const UnifiedPicker: Component<UnifiedPickerProps> = (props) => {
} }
inflightWorkspaceId = workspaceId inflightWorkspaceId = workspaceId
inflightSnapshotPromise = cliApi inflightSnapshotPromise = serverApi
.listWorkspaceFiles(workspaceId) .listWorkspaceFiles(workspaceId)
.then((entries) => mapEntriesToFileItems(entries)) .then((entries) => mapEntriesToFileItems(entries))
.then((snapshot) => { .then((snapshot) => {
@@ -169,7 +169,7 @@ const UnifiedPicker: Component<UnifiedPickerProps> = (props) => {
return return
} }
const results = await cliApi.searchWorkspaceFiles(workspaceId, normalizedQuery, { const results = await serverApi.searchWorkspaceFiles(workspaceId, normalizedQuery, {
limit: SEARCH_RESULT_LIMIT, limit: SEARCH_RESULT_LIMIT,
}) })
if (!shouldApplyResults(requestId, workspaceId)) { if (!shouldApplyResults(requestId, workspaceId)) {

View File

@@ -80,7 +80,7 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
} }
export const cliApi = { export const serverApi = {
fetchWorkspaces(): Promise<WorkspaceDescriptor[]> { fetchWorkspaces(): Promise<WorkspaceDescriptor[]> {
return request<WorkspaceDescriptor[]>("/api/workspaces") return request<WorkspaceDescriptor[]>("/api/workspaces")
}, },

View File

@@ -1,5 +1,5 @@
import type { WorkspaceEventPayload, WorkspaceEventType } from "../../../server/src/api-types" import type { WorkspaceEventPayload, WorkspaceEventType } from "../../../server/src/api-types"
import { cliApi } from "./api-client" import { serverApi } from "./api-client"
const RETRY_BASE_DELAY = 1000 const RETRY_BASE_DELAY = 1000
const RETRY_MAX_DELAY = 10000 const RETRY_MAX_DELAY = 10000
@@ -13,7 +13,7 @@ function logSse(message: string, context?: Record<string, unknown>) {
console.log(`${SSE_PREFIX} ${message}`) console.log(`${SSE_PREFIX} ${message}`)
} }
class CliEvents { class ServerEvents {
private handlers = new Map<WorkspaceEventType | "*", Set<(event: WorkspaceEventPayload) => void>>() private handlers = new Map<WorkspaceEventType | "*", Set<(event: WorkspaceEventPayload) => void>>()
private source: EventSource | null = null private source: EventSource | null = null
private retryDelay = RETRY_BASE_DELAY private retryDelay = RETRY_BASE_DELAY
@@ -27,7 +27,7 @@ class CliEvents {
this.source.close() this.source.close()
} }
logSse("Connecting to backend events stream") logSse("Connecting to backend events stream")
this.source = cliApi.connectEvents((event) => this.dispatch(event), () => this.scheduleReconnect()) this.source = serverApi.connectEvents((event) => this.dispatch(event), () => this.scheduleReconnect())
this.source.onopen = () => { this.source.onopen = () => {
logSse("Events stream connected") logSse("Events stream connected")
this.retryDelay = RETRY_BASE_DELAY this.retryDelay = RETRY_BASE_DELAY
@@ -62,4 +62,4 @@ class CliEvents {
} }
} }
export const cliEvents = new CliEvents() export const serverEvents = new ServerEvents()

View File

@@ -1,5 +1,5 @@
import type { ServerMeta } from "../../../server/src/api-types" import type { ServerMeta } from "../../../server/src/api-types"
import { cliApi } from "./api-client" import { serverApi } from "./api-client"
let cachedMeta: ServerMeta | null = null let cachedMeta: ServerMeta | null = null
let pendingMeta: Promise<ServerMeta> | null = null let pendingMeta: Promise<ServerMeta> | null = null
@@ -11,7 +11,7 @@ export async function getServerMeta(): Promise<ServerMeta> {
if (pendingMeta) { if (pendingMeta) {
return pendingMeta return pendingMeta
} }
pendingMeta = cliApi.fetchServerMeta().then((meta) => { pendingMeta = serverApi.fetchServerMeta().then((meta) => {
cachedMeta = meta cachedMeta = meta
pendingMeta = null pendingMeta = null
return meta return meta

View File

@@ -1,6 +1,6 @@
import type { AppConfig, InstanceData } from "../../../server/src/api-types" import type { AppConfig, InstanceData } from "../../../server/src/api-types"
import { cliApi } from "./api-client" import { serverApi } from "./api-client"
import { cliEvents } from "./cli-events" import { serverEvents } from "./server-events"
export type ConfigData = AppConfig export type ConfigData = AppConfig
@@ -35,12 +35,12 @@ export class ServerStorage {
private instanceLoadPromises = new Map<string, Promise<InstanceData>>() private instanceLoadPromises = new Map<string, Promise<InstanceData>>()
constructor() { constructor() {
cliEvents.on("config.appChanged", (event) => { serverEvents.on("config.appChanged", (event) => {
if (event.type !== "config.appChanged") return if (event.type !== "config.appChanged") return
this.setConfigCache(event.config) this.setConfigCache(event.config)
}) })
cliEvents.on("instance.dataChanged", (event) => { serverEvents.on("instance.dataChanged", (event) => {
if (event.type !== "instance.dataChanged") return if (event.type !== "instance.dataChanged") return
this.setInstanceDataCache(event.instanceId, event.data) this.setInstanceDataCache(event.instanceId, event.data)
}) })
@@ -52,7 +52,7 @@ export class ServerStorage {
} }
if (!this.loadPromise) { if (!this.loadPromise) {
this.loadPromise = cliApi this.loadPromise = serverApi
.fetchConfig() .fetchConfig()
.then((config) => { .then((config) => {
this.setConfigCache(config) this.setConfigCache(config)
@@ -67,7 +67,7 @@ export class ServerStorage {
} }
async updateConfig(next: ConfigData): Promise<ConfigData> { async updateConfig(next: ConfigData): Promise<ConfigData> {
const nextConfig = await cliApi.updateConfig(next) const nextConfig = await serverApi.updateConfig(next)
this.setConfigCache(nextConfig) this.setConfigCache(nextConfig)
return nextConfig return nextConfig
} }
@@ -79,7 +79,7 @@ export class ServerStorage {
} }
if (!this.instanceLoadPromises.has(instanceId)) { if (!this.instanceLoadPromises.has(instanceId)) {
const promise = cliApi const promise = serverApi
.readInstanceData(instanceId) .readInstanceData(instanceId)
.then((data) => { .then((data) => {
const normalized = this.normalizeInstanceData(data) const normalized = this.normalizeInstanceData(data)
@@ -98,12 +98,12 @@ export class ServerStorage {
async saveInstanceData(instanceId: string, data: InstanceData): Promise<void> { async saveInstanceData(instanceId: string, data: InstanceData): Promise<void> {
const normalized = this.normalizeInstanceData(data) const normalized = this.normalizeInstanceData(data)
await cliApi.writeInstanceData(instanceId, normalized) await serverApi.writeInstanceData(instanceId, normalized)
this.setInstanceDataCache(instanceId, normalized) this.setInstanceDataCache(instanceId, normalized)
} }
async deleteInstanceData(instanceId: string): Promise<void> { async deleteInstanceData(instanceId: string): Promise<void> {
await cliApi.deleteInstanceData(instanceId) await serverApi.deleteInstanceData(instanceId)
this.setInstanceDataCache(instanceId, DEFAULT_INSTANCE_DATA) this.setInstanceDataCache(instanceId, DEFAULT_INSTANCE_DATA)
} }

View File

@@ -4,8 +4,8 @@ import type { LspStatus, Permission } from "@opencode-ai/sdk"
import type { ClientPart, Message } from "../types/message" import type { ClientPart, Message } from "../types/message"
import { sdkManager } from "../lib/sdk-manager" import { sdkManager } from "../lib/sdk-manager"
import { sseManager } from "../lib/sse-manager" import { sseManager } from "../lib/sse-manager"
import { cliApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
import { cliEvents } from "../lib/cli-events" import { serverEvents } from "../lib/server-events"
import type { WorkspaceDescriptor, WorkspaceEventPayload, WorkspaceLogEntry } from "../../../server/src/api-types" import type { WorkspaceDescriptor, WorkspaceEventPayload, WorkspaceLogEntry } from "../../../server/src/api-types"
import { ensureInstanceConfigLoaded } from "./instance-config" import { ensureInstanceConfigLoaded } from "./instance-config"
import { import {
@@ -129,7 +129,7 @@ async function hydrateInstanceData(instanceId: string) {
void (async function initializeWorkspaces() { void (async function initializeWorkspaces() {
try { try {
const workspaces = await cliApi.fetchWorkspaces() const workspaces = await serverApi.fetchWorkspaces()
workspaces.forEach((workspace) => upsertWorkspace(workspace)) workspaces.forEach((workspace) => upsertWorkspace(workspace))
if (workspaces.length === 0) { if (workspaces.length === 0) {
setHasInstances(false) setHasInstances(false)
@@ -139,7 +139,7 @@ void (async function initializeWorkspaces() {
} }
})() })()
cliEvents.on("*", (event) => handleWorkspaceEvent(event)) serverEvents.on("*", (event) => handleWorkspaceEvent(event))
function handleWorkspaceEvent(event: WorkspaceEventPayload) { function handleWorkspaceEvent(event: WorkspaceEventPayload) {
switch (event.type) { switch (event.type) {
@@ -299,7 +299,7 @@ function removeInstance(id: string) {
async function createInstance(folder: string, _binaryPath?: string): Promise<string> { async function createInstance(folder: string, _binaryPath?: string): Promise<string> {
try { try {
const workspace = await cliApi.createWorkspace({ path: folder }) const workspace = await serverApi.createWorkspace({ path: folder })
upsertWorkspace(workspace) upsertWorkspace(workspace)
setActiveInstanceId(workspace.id) setActiveInstanceId(workspace.id)
return workspace.id return workspace.id
@@ -316,7 +316,7 @@ async function stopInstance(id: string) {
releaseInstanceResources(id) releaseInstanceResources(id)
try { try {
await cliApi.deleteWorkspace(id) await serverApi.deleteWorkspace(id)
} catch (error) { } catch (error) {
console.error("Failed to stop workspace", error) console.error("Failed to stop workspace", error)
} }