diff --git a/packages/opencode/src/control-plane/workspace-context.ts b/packages/opencode/src/control-plane/workspace-context.ts index 3d4fa5baef..85ef596e7a 100644 --- a/packages/opencode/src/control-plane/workspace-context.ts +++ b/packages/opencode/src/control-plane/workspace-context.ts @@ -2,13 +2,13 @@ import { LocalContext } from "../util" import type { WorkspaceID } from "../control-plane/schema" export interface WorkspaceContext { - workspaceID: WorkspaceID + workspaceID: WorkspaceID | undefined } const context = LocalContext.create("instance") export const WorkspaceContext = { - async provide(input: { workspaceID: WorkspaceID; fn: () => R }): Promise { + async provide(input: { workspaceID?: WorkspaceID; fn: () => R }): Promise { return context.provide({ workspaceID: input.workspaceID }, () => input.fn()) }, diff --git a/packages/opencode/src/server/control/index.ts b/packages/opencode/src/server/routes/control/index.ts similarity index 96% rename from packages/opencode/src/server/control/index.ts rename to packages/opencode/src/server/routes/control/index.ts index 737f958d6b..3fd60636ff 100644 --- a/packages/opencode/src/server/control/index.ts +++ b/packages/opencode/src/server/routes/control/index.ts @@ -6,13 +6,12 @@ import { ProviderID } from "@/provider/schema" import { Hono } from "hono" import { describeRoute, resolver, validator, openAPIRouteHandler } from "hono-openapi" import z from "zod" -import { errors } from "../error" -import { GlobalRoutes } from "../instance/global" +import { errors } from "../../error" +import { WorkspaceRoutes } from "./workspace" export function ControlPlaneRoutes(): Hono { const app = new Hono() return app - .route("/global", GlobalRoutes()) .put( "/auth/:providerID", describeRoute({ @@ -159,4 +158,5 @@ export function ControlPlaneRoutes(): Hono { return c.json(true) }, ) + .route("/experimental/workspace", WorkspaceRoutes()) } diff --git a/packages/opencode/src/server/instance/workspace.ts b/packages/opencode/src/server/routes/control/workspace.ts similarity index 95% rename from packages/opencode/src/server/instance/workspace.ts rename to packages/opencode/src/server/routes/control/workspace.ts index 59369ef8e7..9ff747b68a 100644 --- a/packages/opencode/src/server/instance/workspace.ts +++ b/packages/opencode/src/server/routes/control/workspace.ts @@ -1,11 +1,11 @@ import { Hono } from "hono" import { describeRoute, resolver, validator } from "hono-openapi" import z from "zod" -import { listAdaptors } from "../../control-plane/adaptors" -import { Workspace } from "../../control-plane/workspace" -import { Instance } from "../../project/instance" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { listAdaptors } from "@/control-plane/adaptors" +import { Workspace } from "@/control-plane/workspace" +import { Instance } from "@/project/instance" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" import { Log } from "@/util" import { errorData } from "@/util/error" diff --git a/packages/opencode/src/server/instance/global.ts b/packages/opencode/src/server/routes/global.ts similarity index 100% rename from packages/opencode/src/server/instance/global.ts rename to packages/opencode/src/server/routes/global.ts diff --git a/packages/opencode/src/server/instance/config.ts b/packages/opencode/src/server/routes/instance/config.ts similarity index 92% rename from packages/opencode/src/server/instance/config.ts rename to packages/opencode/src/server/routes/instance/config.ts index 15c393fe5a..235f5682e2 100644 --- a/packages/opencode/src/server/instance/config.ts +++ b/packages/opencode/src/server/routes/instance/config.ts @@ -1,11 +1,11 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" -import { Config } from "../../config" -import { Provider } from "../../provider" -import { errors } from "../error" -import { lazy } from "../../util/lazy" -import { AppRuntime } from "../../effect/app-runtime" +import { Config } from "@/config" +import { Provider } from "@/provider" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" +import { AppRuntime } from "@/effect/app-runtime" import { jsonRequest } from "./trace" export const ConfigRoutes = lazy(() => diff --git a/packages/opencode/src/server/instance/event.ts b/packages/opencode/src/server/routes/instance/event.ts similarity index 97% rename from packages/opencode/src/server/instance/event.ts rename to packages/opencode/src/server/routes/instance/event.ts index 103d3d7cfb..1d883bd883 100644 --- a/packages/opencode/src/server/instance/event.ts +++ b/packages/opencode/src/server/routes/instance/event.ts @@ -5,7 +5,7 @@ import { streamSSE } from "hono/streaming" import { Log } from "@/util" import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" -import { AsyncQueue } from "../../util/queue" +import { AsyncQueue } from "@/util/queue" const log = Log.create({ service: "server" }) diff --git a/packages/opencode/src/server/instance/experimental.ts b/packages/opencode/src/server/routes/instance/experimental.ts similarity index 94% rename from packages/opencode/src/server/instance/experimental.ts rename to packages/opencode/src/server/routes/instance/experimental.ts index 6fe99a8c3b..f7ecc8255b 100644 --- a/packages/opencode/src/server/instance/experimental.ts +++ b/packages/opencode/src/server/routes/instance/experimental.ts @@ -1,22 +1,21 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" -import { ProviderID, ModelID } from "../../provider/schema" -import { ToolRegistry } from "../../tool" -import { Worktree } from "../../worktree" -import { Instance } from "../../project/instance" -import { Project } from "../../project" -import { MCP } from "../../mcp" -import { Session } from "../../session" -import { Config } from "../../config" -import { ConsoleState } from "../../config/console-state" -import { Account } from "../../account/account" -import { AccountID, OrgID } from "../../account/schema" -import { AppRuntime } from "../../effect/app-runtime" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { ProviderID, ModelID } from "@/provider/schema" +import { ToolRegistry } from "@/tool" +import { Worktree } from "@/worktree" +import { Instance } from "@/project/instance" +import { Project } from "@/project" +import { MCP } from "@/mcp" +import { Session } from "@/session" +import { Config } from "@/config" +import { ConsoleState } from "@/config/console-state" +import { Account } from "@/account/account" +import { AccountID, OrgID } from "@/account/schema" +import { AppRuntime } from "@/effect/app-runtime" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" import { Effect, Option } from "effect" -import { WorkspaceRoutes } from "./workspace" import { Agent } from "@/agent/agent" const ConsoleOrgOption = z.object({ @@ -231,7 +230,6 @@ export const ExperimentalRoutes = lazy(() => ) }, ) - .route("/workspace", WorkspaceRoutes()) .post( "/worktree", describeRoute({ diff --git a/packages/opencode/src/server/instance/file.ts b/packages/opencode/src/server/routes/instance/file.ts similarity index 95% rename from packages/opencode/src/server/instance/file.ts rename to packages/opencode/src/server/routes/instance/file.ts index db5e227770..a82e5687d8 100644 --- a/packages/opencode/src/server/instance/file.ts +++ b/packages/opencode/src/server/routes/instance/file.ts @@ -2,12 +2,12 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import { Effect } from "effect" import z from "zod" -import { AppRuntime } from "../../effect/app-runtime" -import { File } from "../../file" -import { Ripgrep } from "../../file/ripgrep" -import { LSP } from "../../lsp" -import { Instance } from "../../project/instance" -import { lazy } from "../../util/lazy" +import { AppRuntime } from "@/effect/app-runtime" +import { File } from "@/file" +import { Ripgrep } from "@/file/ripgrep" +import { LSP } from "@/lsp" +import { Instance } from "@/project/instance" +import { lazy } from "@/util/lazy" export const FileRoutes = lazy(() => new Hono() diff --git a/packages/opencode/src/server/instance/httpapi/config.ts b/packages/opencode/src/server/routes/instance/httpapi/config.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/config.ts rename to packages/opencode/src/server/routes/instance/httpapi/config.ts diff --git a/packages/opencode/src/server/instance/httpapi/permission.ts b/packages/opencode/src/server/routes/instance/httpapi/permission.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/permission.ts rename to packages/opencode/src/server/routes/instance/httpapi/permission.ts diff --git a/packages/opencode/src/server/instance/httpapi/project.ts b/packages/opencode/src/server/routes/instance/httpapi/project.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/project.ts rename to packages/opencode/src/server/routes/instance/httpapi/project.ts diff --git a/packages/opencode/src/server/instance/httpapi/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/provider.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/provider.ts rename to packages/opencode/src/server/routes/instance/httpapi/provider.ts diff --git a/packages/opencode/src/server/instance/httpapi/question.ts b/packages/opencode/src/server/routes/instance/httpapi/question.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/question.ts rename to packages/opencode/src/server/routes/instance/httpapi/question.ts diff --git a/packages/opencode/src/server/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts similarity index 100% rename from packages/opencode/src/server/instance/httpapi/server.ts rename to packages/opencode/src/server/routes/instance/httpapi/server.ts diff --git a/packages/opencode/src/server/instance/index.ts b/packages/opencode/src/server/routes/instance/index.ts similarity index 95% rename from packages/opencode/src/server/instance/index.ts rename to packages/opencode/src/server/routes/instance/index.ts index cfcaffc596..017541b8fc 100644 --- a/packages/opencode/src/server/instance/index.ts +++ b/packages/opencode/src/server/routes/instance/index.ts @@ -3,15 +3,15 @@ import { Hono } from "hono" import type { UpgradeWebSocket } from "hono/ws" import { Context, Effect } from "effect" import z from "zod" -import { Format } from "../../format" +import { Format } from "@/format" import { TuiRoutes } from "./tui" -import { Instance } from "../../project/instance" -import { Vcs } from "../../project" -import { Agent } from "../../agent/agent" -import { Skill } from "../../skill" -import { Global } from "../../global" -import { LSP } from "../../lsp" -import { Command } from "../../command" +import { Instance } from "@/project/instance" +import { Vcs } from "@/project" +import { Agent } from "@/agent/agent" +import { Skill } from "@/skill" +import { Global } from "@/global" +import { LSP } from "@/lsp" +import { Command } from "@/command" import { QuestionRoutes } from "./question" import { PermissionRoutes } from "./permission" import { Flag } from "@/flag/flag" @@ -26,11 +26,10 @@ import { ExperimentalRoutes } from "./experimental" import { ProviderRoutes } from "./provider" import { EventRoutes } from "./event" import { SyncRoutes } from "./sync" -import { WorkspaceRouterMiddleware } from "./middleware" import { AppRuntime } from "@/effect/app-runtime" export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => { - const app = new Hono().use(WorkspaceRouterMiddleware(upgrade)) + const app = new Hono() if (Flag.OPENCODE_EXPERIMENTAL_HTTPAPI) { const handler = ExperimentalHttpApiServer.webHandler().handler diff --git a/packages/opencode/src/server/instance/mcp.ts b/packages/opencode/src/server/routes/instance/mcp.ts similarity index 96% rename from packages/opencode/src/server/instance/mcp.ts rename to packages/opencode/src/server/routes/instance/mcp.ts index f6e6f1eddb..197185bde0 100644 --- a/packages/opencode/src/server/instance/mcp.ts +++ b/packages/opencode/src/server/routes/instance/mcp.ts @@ -1,12 +1,12 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" -import { MCP } from "../../mcp" -import { Config } from "../../config" -import { ConfigMCP } from "../../config/mcp" -import { AppRuntime } from "../../effect/app-runtime" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { MCP } from "@/mcp" +import { Config } from "@/config" +import { ConfigMCP } from "@/config/mcp" +import { AppRuntime } from "@/effect/app-runtime" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" import { Effect } from "effect" export const McpRoutes = lazy(() => diff --git a/packages/opencode/src/server/instance/permission.ts b/packages/opencode/src/server/routes/instance/permission.ts similarity index 96% rename from packages/opencode/src/server/instance/permission.ts rename to packages/opencode/src/server/routes/instance/permission.ts index b8c2244140..c3f9c82011 100644 --- a/packages/opencode/src/server/instance/permission.ts +++ b/packages/opencode/src/server/routes/instance/permission.ts @@ -4,8 +4,8 @@ import z from "zod" import { AppRuntime } from "@/effect/app-runtime" import { Permission } from "@/permission" import { PermissionID } from "@/permission/schema" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" export const PermissionRoutes = lazy(() => new Hono() diff --git a/packages/opencode/src/server/instance/project.ts b/packages/opencode/src/server/routes/instance/project.ts similarity index 92% rename from packages/opencode/src/server/instance/project.ts rename to packages/opencode/src/server/routes/instance/project.ts index 95b5862fd5..060542c4b4 100644 --- a/packages/opencode/src/server/instance/project.ts +++ b/packages/opencode/src/server/routes/instance/project.ts @@ -1,13 +1,13 @@ import { Hono } from "hono" import { describeRoute, validator } from "hono-openapi" import { resolver } from "hono-openapi" -import { Instance } from "../../project/instance" -import { Project } from "../../project" +import { Instance } from "@/project/instance" +import { Project } from "@/project" import z from "zod" -import { ProjectID } from "../../project/schema" -import { errors } from "../error" -import { lazy } from "../../util/lazy" -import { InstanceBootstrap } from "../../project/bootstrap" +import { ProjectID } from "@/project/schema" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" +import { InstanceBootstrap } from "@/project/bootstrap" import { AppRuntime } from "@/effect/app-runtime" export const ProjectRoutes = lazy(() => diff --git a/packages/opencode/src/server/instance/provider.ts b/packages/opencode/src/server/routes/instance/provider.ts similarity index 93% rename from packages/opencode/src/server/instance/provider.ts rename to packages/opencode/src/server/routes/instance/provider.ts index a81ae00d59..57aa895e3d 100644 --- a/packages/opencode/src/server/instance/provider.ts +++ b/packages/opencode/src/server/routes/instance/provider.ts @@ -1,15 +1,15 @@ import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" -import { Config } from "../../config" -import { Provider } from "../../provider" -import { ModelsDev } from "../../provider" -import { ProviderAuth } from "../../provider" -import { ProviderID } from "../../provider/schema" -import { AppRuntime } from "../../effect/app-runtime" +import { Config } from "@/config" +import { Provider } from "@/provider" +import { ModelsDev } from "@/provider" +import { ProviderAuth } from "@/provider" +import { ProviderID } from "@/provider/schema" +import { AppRuntime } from "@/effect/app-runtime" import { mapValues } from "remeda" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" import { Effect } from "effect" export const ProviderRoutes = lazy(() => diff --git a/packages/opencode/src/server/instance/pty.ts b/packages/opencode/src/server/routes/instance/pty.ts similarity index 98% rename from packages/opencode/src/server/instance/pty.ts rename to packages/opencode/src/server/routes/instance/pty.ts index 7943725120..b3f71c235c 100644 --- a/packages/opencode/src/server/instance/pty.ts +++ b/packages/opencode/src/server/routes/instance/pty.ts @@ -6,8 +6,8 @@ import z from "zod" import { AppRuntime } from "@/effect/app-runtime" import { Pty } from "@/pty" import { PtyID } from "@/pty/schema" -import { NotFoundError } from "../../storage" -import { errors } from "../error" +import { NotFoundError } from "@/storage" +import { errors } from "../../error" export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) { return new Hono() diff --git a/packages/opencode/src/server/instance/question.ts b/packages/opencode/src/server/routes/instance/question.ts similarity index 96% rename from packages/opencode/src/server/instance/question.ts rename to packages/opencode/src/server/routes/instance/question.ts index 0f61a18672..9b8f461e39 100644 --- a/packages/opencode/src/server/instance/question.ts +++ b/packages/opencode/src/server/routes/instance/question.ts @@ -2,11 +2,11 @@ import { Hono } from "hono" import { describeRoute, validator } from "hono-openapi" import { resolver } from "hono-openapi" import { QuestionID } from "@/question/schema" -import { Question } from "../../question" +import { Question } from "@/question" import { AppRuntime } from "@/effect/app-runtime" import z from "zod" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" const Reply = z.object({ answers: Question.Answer.zod diff --git a/packages/opencode/src/server/instance/session.ts b/packages/opencode/src/server/routes/instance/session.ts similarity index 98% rename from packages/opencode/src/server/instance/session.ts rename to packages/opencode/src/server/routes/instance/session.ts index 1511e99e8d..ae6185abb8 100644 --- a/packages/opencode/src/server/instance/session.ts +++ b/packages/opencode/src/server/routes/instance/session.ts @@ -3,28 +3,28 @@ import { stream } from "hono/streaming" import { describeRoute, validator, resolver } from "hono-openapi" import { SessionID, MessageID, PartID } from "@/session/schema" import z from "zod" -import { Session } from "../../session" -import { MessageV2 } from "../../session/message-v2" -import { SessionPrompt } from "../../session/prompt" +import { Session } from "@/session" +import { MessageV2 } from "@/session/message-v2" +import { SessionPrompt } from "@/session/prompt" import { SessionRunState } from "@/session/run-state" -import { SessionCompaction } from "../../session/compaction" -import { SessionRevert } from "../../session/revert" +import { SessionCompaction } from "@/session/compaction" +import { SessionRevert } from "@/session/revert" import { SessionShare } from "@/share" import { SessionStatus } from "@/session/status" import { SessionSummary } from "@/session/summary" -import { Todo } from "../../session/todo" +import { Todo } from "@/session/todo" import { Effect } from "effect" -import { AppRuntime } from "../../effect/app-runtime" -import { Agent } from "../../agent/agent" +import { AppRuntime } from "@/effect/app-runtime" +import { Agent } from "@/agent/agent" import { Snapshot } from "@/snapshot" -import { Command } from "../../command" -import { Log } from "../../util" +import { Command } from "@/command" +import { Log } from "@/util" import { Permission } from "@/permission" import { PermissionID } from "@/permission/schema" import { ModelID, ProviderID } from "@/provider/schema" -import { errors } from "../error" -import { lazy } from "../../util/lazy" -import { Bus } from "../../bus" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" +import { Bus } from "@/bus" import { NamedError } from "@opencode-ai/shared/util/error" import { jsonRequest } from "./trace" diff --git a/packages/opencode/src/server/instance/sync.ts b/packages/opencode/src/server/routes/instance/sync.ts similarity index 98% rename from packages/opencode/src/server/instance/sync.ts rename to packages/opencode/src/server/routes/instance/sync.ts index ac43b638eb..c6a067997b 100644 --- a/packages/opencode/src/server/instance/sync.ts +++ b/packages/opencode/src/server/routes/instance/sync.ts @@ -6,7 +6,7 @@ import { Database, asc, and, not, or, lte, eq } from "@/storage" import { EventTable } from "@/sync/event.sql" import { lazy } from "@/util/lazy" import { Log } from "@/util" -import { errors } from "../error" +import { errors } from "../../error" const ReplayEvent = z.object({ id: z.string(), diff --git a/packages/opencode/src/server/instance/trace.ts b/packages/opencode/src/server/routes/instance/trace.ts similarity index 93% rename from packages/opencode/src/server/instance/trace.ts rename to packages/opencode/src/server/routes/instance/trace.ts index b3adbb4c80..3e1f72d8b2 100644 --- a/packages/opencode/src/server/instance/trace.ts +++ b/packages/opencode/src/server/routes/instance/trace.ts @@ -1,6 +1,6 @@ import type { Context } from "hono" import { Effect } from "effect" -import { AppRuntime } from "../../effect/app-runtime" +import { AppRuntime } from "@/effect/app-runtime" type AppEnv = Parameters[0] extends Effect.Effect ? R : never diff --git a/packages/opencode/src/server/instance/tui.ts b/packages/opencode/src/server/routes/instance/tui.ts similarity index 98% rename from packages/opencode/src/server/instance/tui.ts rename to packages/opencode/src/server/routes/instance/tui.ts index 0073ef98c9..2f856c3488 100644 --- a/packages/opencode/src/server/instance/tui.ts +++ b/packages/opencode/src/server/routes/instance/tui.ts @@ -1,13 +1,13 @@ import { Hono, type Context } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import z from "zod" -import { Bus } from "../../bus" -import { Session } from "../../session" +import { Bus } from "@/bus" +import { Session } from "@/session" import { TuiEvent } from "@/cli/cmd/tui/event" import { AppRuntime } from "@/effect/app-runtime" -import { AsyncQueue } from "../../util/queue" -import { errors } from "../error" -import { lazy } from "../../util/lazy" +import { AsyncQueue } from "@/util/queue" +import { errors } from "../../error" +import { lazy } from "@/util/lazy" const TuiRequest = z.object({ path: z.string(), diff --git a/packages/opencode/src/server/ui/index.ts b/packages/opencode/src/server/routes/ui.ts similarity index 100% rename from packages/opencode/src/server/ui/index.ts rename to packages/opencode/src/server/routes/ui.ts diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 892a99a77c..2201c75b4c 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -1,16 +1,25 @@ import { generateSpecs } from "hono-openapi" import { Hono } from "hono" +import type { MiddlewareHandler } from "hono" import { adapter } from "#hono" -import { MDNS } from "./mdns" import { lazy } from "@/util/lazy" -import { AuthMiddleware, CompressionMiddleware, CorsMiddleware, ErrorMiddleware, LoggerMiddleware } from "./middleware" -import { FenceMiddleware } from "./fence" -import { InstanceRoutes } from "./instance" -import { initProjectors } from "./projectors" import { Log } from "@/util" import { Flag } from "@/flag/flag" -import { ControlPlaneRoutes } from "./control" -import { UIRoutes } from "./ui" +import { Instance } from "@/project/instance" +import { InstanceBootstrap } from "@/project/bootstrap" +import { AppRuntime } from "@/effect/app-runtime" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" +import { WorkspaceID } from "@/control-plane/schema" +import { WorkspaceContext } from "@/control-plane/workspace-context" +import { MDNS } from "./mdns" +import { AuthMiddleware, CompressionMiddleware, CorsMiddleware, ErrorMiddleware, LoggerMiddleware } from "./middleware" +import { FenceMiddleware } from "./fence" +import { initProjectors } from "./projectors" +import { InstanceRoutes } from "./routes/instance" +import { ControlPlaneRoutes } from "./routes/control" +import { UIRoutes } from "./routes/ui" +import { GlobalRoutes } from "./routes/global" +import { WorkspaceRouterMiddleware } from "./workspace" // @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85 globalThis.AI_SDK_LOG_WARNINGS = false @@ -30,18 +39,48 @@ export const Default = lazy(() => create({})) function create(opts: { cors?: string[] }) { const app = new Hono() + .onError(ErrorMiddleware) + .use(AuthMiddleware) + .use(LoggerMiddleware) + .use(CompressionMiddleware) + .use(CorsMiddleware(opts)) + .route("/global", GlobalRoutes()) + const runtime = adapter.create(app) + function InstanceMiddleware(workspaceID?: WorkspaceID): MiddlewareHandler { + return async (c, next) => { + const raw = c.req.query("directory") || c.req.header("x-opencode-directory") || process.cwd() + const directory = AppFileSystem.resolve( + (() => { + try { + return decodeURIComponent(raw) + } catch { + return raw + } + })(), + ) + + return WorkspaceContext.provide({ + workspaceID, + async fn() { + return Instance.provide({ + directory, + init: () => AppRuntime.runPromise(InstanceBootstrap), + async fn() { + return next() + }, + }) + }, + }) + } + } + if (Flag.OPENCODE_WORKSPACE_ID) { return { app: app - .onError(ErrorMiddleware) - .use(AuthMiddleware) - .use(LoggerMiddleware) - .use(CompressionMiddleware) - .use(CorsMiddleware(opts)) + .use(InstanceMiddleware(Flag.OPENCODE_WORKSPACE_ID ? WorkspaceID.make(Flag.OPENCODE_WORKSPACE_ID) : undefined)) .use(FenceMiddleware) - .route("/", ControlPlaneRoutes()) .route("/", InstanceRoutes(runtime.upgradeWebSocket)), runtime, } @@ -49,12 +88,9 @@ function create(opts: { cors?: string[] }) { return { app: app - .onError(ErrorMiddleware) - .use(AuthMiddleware) - .use(LoggerMiddleware) - .use(CompressionMiddleware) - .use(CorsMiddleware(opts)) + .use(InstanceMiddleware()) .route("/", ControlPlaneRoutes()) + .use(WorkspaceRouterMiddleware(runtime.upgradeWebSocket)) .route("/", InstanceRoutes(runtime.upgradeWebSocket)) .route("/", UIRoutes()), runtime, diff --git a/packages/opencode/src/server/instance/middleware.ts b/packages/opencode/src/server/workspace.ts similarity index 79% rename from packages/opencode/src/server/instance/middleware.ts rename to packages/opencode/src/server/workspace.ts index 7b66072c23..c141d10956 100644 --- a/packages/opencode/src/server/instance/middleware.ts +++ b/packages/opencode/src/server/workspace.ts @@ -2,17 +2,16 @@ import type { MiddlewareHandler } from "hono" import type { UpgradeWebSocket } from "hono/ws" import { getAdaptor } from "@/control-plane/adaptors" import { WorkspaceID } from "@/control-plane/schema" +import { WorkspaceContext } from "@/control-plane/workspace-context" import { Workspace } from "@/control-plane/workspace" -import { ServerProxy } from "../proxy" -import { Instance } from "@/project/instance" -import { InstanceBootstrap } from "@/project/bootstrap" import { Flag } from "@/flag/flag" +import { InstanceBootstrap } from "@/project/bootstrap" +import { Instance } from "@/project/instance" import { Session } from "@/session" import { SessionID } from "@/session/schema" -import { WorkspaceContext } from "@/control-plane/workspace-context" import { AppRuntime } from "@/effect/app-runtime" import { Log } from "@/util" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" +import { ServerProxy } from "./proxy" type Rule = { method?: string; path: string; exact?: boolean; action: "local" | "forward" } @@ -51,45 +50,13 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware const log = Log.create({ service: "workspace-router" }) return async (c, next) => { - const raw = c.req.query("directory") || c.req.header("x-opencode-directory") || process.cwd() - const directory = AppFileSystem.resolve( - (() => { - try { - return decodeURIComponent(raw) - } catch { - return raw - } - })(), - ) - const url = new URL(c.req.url) const sessionWorkspaceID = await getSessionWorkspace(url) const workspaceID = sessionWorkspaceID || url.searchParams.get("workspace") if (!workspaceID || url.pathname.startsWith("/console") || Flag.OPENCODE_WORKSPACE_ID) { - if (Flag.OPENCODE_WORKSPACE_ID) { - return WorkspaceContext.provide({ - workspaceID: WorkspaceID.make(Flag.OPENCODE_WORKSPACE_ID), - async fn() { - return Instance.provide({ - directory, - init: () => AppRuntime.runPromise(InstanceBootstrap), - async fn() { - return next() - }, - }) - }, - }) - } - - return Instance.provide({ - directory, - init: () => AppRuntime.runPromise(InstanceBootstrap), - async fn() { - return next() - }, - }) + return next() } const workspace = await Workspace.get(WorkspaceID.make(workspaceID)) diff --git a/packages/opencode/test/server/session-messages.test.ts b/packages/opencode/test/server/session-messages.test.ts index 50b7658969..23e8b50145 100644 --- a/packages/opencode/test/server/session-messages.test.ts +++ b/packages/opencode/test/server/session-messages.test.ts @@ -165,16 +165,3 @@ describe("session messages endpoint", () => { ) }) }) - -describe("session.prompt_async error handling", () => { - test("prompt_async route has error handler for detached prompt call", async () => { - const src = await Bun.file(new URL("../../src/server/instance/session.ts", import.meta.url)).text() - const start = src.indexOf('"/:sessionID/prompt_async"') - const end = src.indexOf('"/:sessionID/command"', start) - expect(start).toBeGreaterThan(-1) - expect(end).toBeGreaterThan(start) - const route = src.slice(start, end) - expect(route).toContain(".catch(") - expect(route).toContain("Bus.publish(Session.Event.Error") - }) -}) diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index d7bf43f506..f484147a40 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -510,6 +510,430 @@ export class App extends HeyApiClient { } } +export class Adaptor extends HeyApiClient { + /** + * List workspace adaptors + * + * List all available workspace adaptors for the current project. + */ + public list( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/workspace/adaptor", + ...options, + ...params, + }) + } +} + +export class Workspace extends HeyApiClient { + /** + * List workspaces + * + * List all workspaces. + */ + public list( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/workspace", + ...options, + ...params, + }) + } + + /** + * Create workspace + * + * Create a workspace for the current project. + */ + public create( + parameters?: { + directory?: string + workspace?: string + id?: string + type?: string + branch?: string | null + extra?: unknown | null + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "body", key: "id" }, + { in: "body", key: "type" }, + { in: "body", key: "branch" }, + { in: "body", key: "extra" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post< + ExperimentalWorkspaceCreateResponses, + ExperimentalWorkspaceCreateErrors, + ThrowOnError + >({ + url: "/experimental/workspace", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } + + /** + * Workspace status + * + * Get connection status for workspaces in the current project. + */ + public status( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/workspace/status", + ...options, + ...params, + }) + } + + /** + * Remove workspace + * + * Remove an existing workspace. + */ + public remove( + parameters: { + id: string + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "path", key: "id" }, + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).delete< + ExperimentalWorkspaceRemoveResponses, + ExperimentalWorkspaceRemoveErrors, + ThrowOnError + >({ + url: "/experimental/workspace/{id}", + ...options, + ...params, + }) + } + + /** + * Restore session into workspace + * + * Replay a session's sync events into the target workspace in batches. + */ + public sessionRestore( + parameters: { + id: string + directory?: string + workspace?: string + sessionID?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "path", key: "id" }, + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "body", key: "sessionID" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post< + ExperimentalWorkspaceSessionRestoreResponses, + ExperimentalWorkspaceSessionRestoreErrors, + ThrowOnError + >({ + url: "/experimental/workspace/{id}/session-restore", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } + + private _adaptor?: Adaptor + get adaptor(): Adaptor { + return (this._adaptor ??= new Adaptor({ client: this.client })) + } +} + +export class Console extends HeyApiClient { + /** + * Get active Console provider metadata + * + * Get the active Console org name and the set of provider IDs managed by that Console org. + */ + public get( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/console", + ...options, + ...params, + }) + } + + /** + * List switchable Console orgs + * + * Get the available Console orgs across logged-in accounts, including the current active org. + */ + public listOrgs( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/console/orgs", + ...options, + ...params, + }) + } + + /** + * Switch active Console org + * + * Persist a new active Console account/org selection for the current local OpenCode state. + */ + public switchOrg( + parameters?: { + directory?: string + workspace?: string + accountID?: string + orgID?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "body", key: "accountID" }, + { in: "body", key: "orgID" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post({ + url: "/experimental/console/switch", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } +} + +export class Session extends HeyApiClient { + /** + * List sessions + * + * Get a list of all OpenCode sessions across projects, sorted by most recently updated. Archived sessions are excluded by default. + */ + public list( + parameters?: { + directory?: string + workspace?: string + roots?: boolean + start?: number + cursor?: number + search?: string + limit?: number + archived?: boolean + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "query", key: "roots" }, + { in: "query", key: "start" }, + { in: "query", key: "cursor" }, + { in: "query", key: "search" }, + { in: "query", key: "limit" }, + { in: "query", key: "archived" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/session", + ...options, + ...params, + }) + } +} + +export class Resource extends HeyApiClient { + /** + * Get MCP resources + * + * Get all available MCP resources from connected servers. Optionally filter by name. + */ + public list( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/experimental/resource", + ...options, + ...params, + }) + } +} + +export class Experimental extends HeyApiClient { + private _workspace?: Workspace + get workspace(): Workspace { + return (this._workspace ??= new Workspace({ client: this.client })) + } + + private _console?: Console + get console(): Console { + return (this._console ??= new Console({ client: this.client })) + } + + private _session?: Session + get session(): Session { + return (this._session ??= new Session({ client: this.client })) + } + + private _resource?: Resource + get resource(): Resource { + return (this._resource ??= new Resource({ client: this.client })) + } +} + export class Project extends HeyApiClient { /** * List all projects @@ -972,430 +1396,6 @@ export class Config2 extends HeyApiClient { } } -export class Console extends HeyApiClient { - /** - * Get active Console provider metadata - * - * Get the active Console org name and the set of provider IDs managed by that Console org. - */ - public get( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/console", - ...options, - ...params, - }) - } - - /** - * List switchable Console orgs - * - * Get the available Console orgs across logged-in accounts, including the current active org. - */ - public listOrgs( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/console/orgs", - ...options, - ...params, - }) - } - - /** - * Switch active Console org - * - * Persist a new active Console account/org selection for the current local OpenCode state. - */ - public switchOrg( - parameters?: { - directory?: string - workspace?: string - accountID?: string - orgID?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - { in: "body", key: "accountID" }, - { in: "body", key: "orgID" }, - ], - }, - ], - ) - return (options?.client ?? this.client).post({ - url: "/experimental/console/switch", - ...options, - ...params, - headers: { - "Content-Type": "application/json", - ...options?.headers, - ...params.headers, - }, - }) - } -} - -export class Adaptor extends HeyApiClient { - /** - * List workspace adaptors - * - * List all available workspace adaptors for the current project. - */ - public list( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/workspace/adaptor", - ...options, - ...params, - }) - } -} - -export class Workspace extends HeyApiClient { - /** - * List workspaces - * - * List all workspaces. - */ - public list( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/workspace", - ...options, - ...params, - }) - } - - /** - * Create workspace - * - * Create a workspace for the current project. - */ - public create( - parameters?: { - directory?: string - workspace?: string - id?: string - type?: string - branch?: string | null - extra?: unknown | null - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - { in: "body", key: "id" }, - { in: "body", key: "type" }, - { in: "body", key: "branch" }, - { in: "body", key: "extra" }, - ], - }, - ], - ) - return (options?.client ?? this.client).post< - ExperimentalWorkspaceCreateResponses, - ExperimentalWorkspaceCreateErrors, - ThrowOnError - >({ - url: "/experimental/workspace", - ...options, - ...params, - headers: { - "Content-Type": "application/json", - ...options?.headers, - ...params.headers, - }, - }) - } - - /** - * Workspace status - * - * Get connection status for workspaces in the current project. - */ - public status( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/workspace/status", - ...options, - ...params, - }) - } - - /** - * Remove workspace - * - * Remove an existing workspace. - */ - public remove( - parameters: { - id: string - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "path", key: "id" }, - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).delete< - ExperimentalWorkspaceRemoveResponses, - ExperimentalWorkspaceRemoveErrors, - ThrowOnError - >({ - url: "/experimental/workspace/{id}", - ...options, - ...params, - }) - } - - /** - * Restore session into workspace - * - * Replay a session's sync events into the target workspace in batches. - */ - public sessionRestore( - parameters: { - id: string - directory?: string - workspace?: string - sessionID?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "path", key: "id" }, - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - { in: "body", key: "sessionID" }, - ], - }, - ], - ) - return (options?.client ?? this.client).post< - ExperimentalWorkspaceSessionRestoreResponses, - ExperimentalWorkspaceSessionRestoreErrors, - ThrowOnError - >({ - url: "/experimental/workspace/{id}/session-restore", - ...options, - ...params, - headers: { - "Content-Type": "application/json", - ...options?.headers, - ...params.headers, - }, - }) - } - - private _adaptor?: Adaptor - get adaptor(): Adaptor { - return (this._adaptor ??= new Adaptor({ client: this.client })) - } -} - -export class Session extends HeyApiClient { - /** - * List sessions - * - * Get a list of all OpenCode sessions across projects, sorted by most recently updated. Archived sessions are excluded by default. - */ - public list( - parameters?: { - directory?: string - workspace?: string - roots?: boolean - start?: number - cursor?: number - search?: string - limit?: number - archived?: boolean - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - { in: "query", key: "roots" }, - { in: "query", key: "start" }, - { in: "query", key: "cursor" }, - { in: "query", key: "search" }, - { in: "query", key: "limit" }, - { in: "query", key: "archived" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/session", - ...options, - ...params, - }) - } -} - -export class Resource extends HeyApiClient { - /** - * Get MCP resources - * - * Get all available MCP resources from connected servers. Optionally filter by name. - */ - public list( - parameters?: { - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/experimental/resource", - ...options, - ...params, - }) - } -} - -export class Experimental extends HeyApiClient { - private _console?: Console - get console(): Console { - return (this._console ??= new Console({ client: this.client })) - } - - private _workspace?: Workspace - get workspace(): Workspace { - return (this._workspace ??= new Workspace({ client: this.client })) - } - - private _session?: Session - get session(): Session { - return (this._session ??= new Session({ client: this.client })) - } - - private _resource?: Resource - get resource(): Resource { - return (this._resource ??= new Resource({ client: this.client })) - } -} - export class Tool extends HeyApiClient { /** * List tool IDs @@ -4314,6 +4314,11 @@ export class OpencodeClient extends HeyApiClient { return (this._app ??= new App({ client: this.client })) } + private _experimental?: Experimental + get experimental(): Experimental { + return (this._experimental ??= new Experimental({ client: this.client })) + } + private _project?: Project get project(): Project { return (this._project ??= new Project({ client: this.client })) @@ -4329,11 +4334,6 @@ export class OpencodeClient extends HeyApiClient { return (this._config ??= new Config2({ client: this.client })) } - private _experimental?: Experimental - get experimental(): Experimental { - return (this._experimental ??= new Experimental({ client: this.client })) - } - private _tool?: Tool get tool(): Tool { return (this._tool ??= new Tool({ client: this.client })) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 25c3cfa669..839dae8b22 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1706,6 +1706,16 @@ export type WellKnownAuth = { export type Auth = OAuth | ApiAuth | WellKnownAuth +export type Workspace = { + id: string + type: string + name: string + branch: string | null + directory: string | null + extra: unknown | null + projectID: string +} + export type NotFoundError = { name: "NotFoundError" data: { @@ -1808,16 +1818,6 @@ export type ToolListItem = { export type ToolList = Array -export type Workspace = { - id: string - type: string - name: string - branch: string | null - directory: string | null - extra: unknown | null - projectID: string -} - export type Worktree = { name: string branch: string @@ -2394,6 +2394,177 @@ export type AppLogResponses = { export type AppLogResponse = AppLogResponses[keyof AppLogResponses] +export type ExperimentalWorkspaceAdaptorListData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace/adaptor" +} + +export type ExperimentalWorkspaceAdaptorListResponses = { + /** + * Workspace adaptors + */ + 200: Array<{ + type: string + name: string + description: string + }> +} + +export type ExperimentalWorkspaceAdaptorListResponse = + ExperimentalWorkspaceAdaptorListResponses[keyof ExperimentalWorkspaceAdaptorListResponses] + +export type ExperimentalWorkspaceListData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace" +} + +export type ExperimentalWorkspaceListResponses = { + /** + * Workspaces + */ + 200: Array +} + +export type ExperimentalWorkspaceListResponse = + ExperimentalWorkspaceListResponses[keyof ExperimentalWorkspaceListResponses] + +export type ExperimentalWorkspaceCreateData = { + body?: { + id?: string + type: string + branch: string | null + extra: unknown | null + } + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace" +} + +export type ExperimentalWorkspaceCreateErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type ExperimentalWorkspaceCreateError = + ExperimentalWorkspaceCreateErrors[keyof ExperimentalWorkspaceCreateErrors] + +export type ExperimentalWorkspaceCreateResponses = { + /** + * Workspace created + */ + 200: Workspace +} + +export type ExperimentalWorkspaceCreateResponse = + ExperimentalWorkspaceCreateResponses[keyof ExperimentalWorkspaceCreateResponses] + +export type ExperimentalWorkspaceStatusData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace/status" +} + +export type ExperimentalWorkspaceStatusResponses = { + /** + * Workspace status + */ + 200: Array<{ + workspaceID: string + status: "connected" | "connecting" | "disconnected" | "error" + error?: string + }> +} + +export type ExperimentalWorkspaceStatusResponse = + ExperimentalWorkspaceStatusResponses[keyof ExperimentalWorkspaceStatusResponses] + +export type ExperimentalWorkspaceRemoveData = { + body?: never + path: { + id: string + } + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace/{id}" +} + +export type ExperimentalWorkspaceRemoveErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type ExperimentalWorkspaceRemoveError = + ExperimentalWorkspaceRemoveErrors[keyof ExperimentalWorkspaceRemoveErrors] + +export type ExperimentalWorkspaceRemoveResponses = { + /** + * Workspace removed + */ + 200: Workspace +} + +export type ExperimentalWorkspaceRemoveResponse = + ExperimentalWorkspaceRemoveResponses[keyof ExperimentalWorkspaceRemoveResponses] + +export type ExperimentalWorkspaceSessionRestoreData = { + body?: { + sessionID: string + } + path: { + id: string + } + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace/{id}/session-restore" +} + +export type ExperimentalWorkspaceSessionRestoreErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type ExperimentalWorkspaceSessionRestoreError = + ExperimentalWorkspaceSessionRestoreErrors[keyof ExperimentalWorkspaceSessionRestoreErrors] + +export type ExperimentalWorkspaceSessionRestoreResponses = { + /** + * Session replay started + */ + 200: { + total: number + } +} + +export type ExperimentalWorkspaceSessionRestoreResponse = + ExperimentalWorkspaceSessionRestoreResponses[keyof ExperimentalWorkspaceSessionRestoreResponses] + export type ProjectListData = { body?: never path?: never @@ -2883,177 +3054,6 @@ export type ToolListResponses = { export type ToolListResponse = ToolListResponses[keyof ToolListResponses] -export type ExperimentalWorkspaceAdaptorListData = { - body?: never - path?: never - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace/adaptor" -} - -export type ExperimentalWorkspaceAdaptorListResponses = { - /** - * Workspace adaptors - */ - 200: Array<{ - type: string - name: string - description: string - }> -} - -export type ExperimentalWorkspaceAdaptorListResponse = - ExperimentalWorkspaceAdaptorListResponses[keyof ExperimentalWorkspaceAdaptorListResponses] - -export type ExperimentalWorkspaceListData = { - body?: never - path?: never - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace" -} - -export type ExperimentalWorkspaceListResponses = { - /** - * Workspaces - */ - 200: Array -} - -export type ExperimentalWorkspaceListResponse = - ExperimentalWorkspaceListResponses[keyof ExperimentalWorkspaceListResponses] - -export type ExperimentalWorkspaceCreateData = { - body?: { - id?: string - type: string - branch: string | null - extra: unknown | null - } - path?: never - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace" -} - -export type ExperimentalWorkspaceCreateErrors = { - /** - * Bad request - */ - 400: BadRequestError -} - -export type ExperimentalWorkspaceCreateError = - ExperimentalWorkspaceCreateErrors[keyof ExperimentalWorkspaceCreateErrors] - -export type ExperimentalWorkspaceCreateResponses = { - /** - * Workspace created - */ - 200: Workspace -} - -export type ExperimentalWorkspaceCreateResponse = - ExperimentalWorkspaceCreateResponses[keyof ExperimentalWorkspaceCreateResponses] - -export type ExperimentalWorkspaceStatusData = { - body?: never - path?: never - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace/status" -} - -export type ExperimentalWorkspaceStatusResponses = { - /** - * Workspace status - */ - 200: Array<{ - workspaceID: string - status: "connected" | "connecting" | "disconnected" | "error" - error?: string - }> -} - -export type ExperimentalWorkspaceStatusResponse = - ExperimentalWorkspaceStatusResponses[keyof ExperimentalWorkspaceStatusResponses] - -export type ExperimentalWorkspaceRemoveData = { - body?: never - path: { - id: string - } - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace/{id}" -} - -export type ExperimentalWorkspaceRemoveErrors = { - /** - * Bad request - */ - 400: BadRequestError -} - -export type ExperimentalWorkspaceRemoveError = - ExperimentalWorkspaceRemoveErrors[keyof ExperimentalWorkspaceRemoveErrors] - -export type ExperimentalWorkspaceRemoveResponses = { - /** - * Workspace removed - */ - 200: Workspace -} - -export type ExperimentalWorkspaceRemoveResponse = - ExperimentalWorkspaceRemoveResponses[keyof ExperimentalWorkspaceRemoveResponses] - -export type ExperimentalWorkspaceSessionRestoreData = { - body?: { - sessionID: string - } - path: { - id: string - } - query?: { - directory?: string - workspace?: string - } - url: "/experimental/workspace/{id}/session-restore" -} - -export type ExperimentalWorkspaceSessionRestoreErrors = { - /** - * Bad request - */ - 400: BadRequestError -} - -export type ExperimentalWorkspaceSessionRestoreError = - ExperimentalWorkspaceSessionRestoreErrors[keyof ExperimentalWorkspaceSessionRestoreErrors] - -export type ExperimentalWorkspaceSessionRestoreResponses = { - /** - * Session replay started - */ - 200: { - total: number - } -} - -export type ExperimentalWorkspaceSessionRestoreResponse = - ExperimentalWorkspaceSessionRestoreResponses[keyof ExperimentalWorkspaceSessionRestoreResponses] - export type WorktreeRemoveData = { body?: WorktreeRemoveInput path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 9193b11ad9..cf14026eae 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -415,6 +415,394 @@ ] } }, + "/experimental/workspace/adaptor": { + "get": { + "operationId": "experimental.workspace.adaptor.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "List workspace adaptors", + "description": "List all available workspace adaptors for the current project.", + "responses": { + "200": { + "description": "Workspace adaptors", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": ["type", "name", "description"] + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.adaptor.list({\n ...\n})" + } + ] + } + }, + "/experimental/workspace": { + "post": { + "operationId": "experimental.workspace.create", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "Create workspace", + "description": "Create a workspace for the current project.", + "responses": { + "200": { + "description": "Workspace created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^wrk.*" + }, + "type": { + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "extra": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + } + }, + "required": ["type", "branch", "extra"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.create({\n ...\n})" + } + ] + }, + "get": { + "operationId": "experimental.workspace.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "List workspaces", + "description": "List all workspaces.", + "responses": { + "200": { + "description": "Workspaces", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Workspace" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.list({\n ...\n})" + } + ] + } + }, + "/experimental/workspace/status": { + "get": { + "operationId": "experimental.workspace.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "Workspace status", + "description": "Get connection status for workspaces in the current project.", + "responses": { + "200": { + "description": "Workspace status", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "workspaceID": { + "type": "string", + "pattern": "^wrk.*" + }, + "status": { + "type": "string", + "enum": ["connected", "connecting", "disconnected", "error"] + }, + "error": { + "type": "string" + } + }, + "required": ["workspaceID", "status"] + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.status({\n ...\n})" + } + ] + } + }, + "/experimental/workspace/{id}": { + "delete": { + "operationId": "experimental.workspace.remove", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string", + "pattern": "^wrk.*" + }, + "required": true + } + ], + "summary": "Remove workspace", + "description": "Remove an existing workspace.", + "responses": { + "200": { + "description": "Workspace removed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.remove({\n ...\n})" + } + ] + } + }, + "/experimental/workspace/{id}/session-restore": { + "post": { + "operationId": "experimental.workspace.sessionRestore", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string", + "pattern": "^wrk.*" + }, + "required": true + } + ], + "summary": "Restore session into workspace", + "description": "Replay a session's sync events into the target workspace in batches.", + "responses": { + "200": { + "description": "Session replay started", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["total"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses.*" + } + }, + "required": ["sessionID"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.sessionRestore({\n ...\n})" + } + ] + } + }, "/project": { "get": { "operationId": "project.list", @@ -1501,394 +1889,6 @@ ] } }, - "/experimental/workspace/adaptor": { - "get": { - "operationId": "experimental.workspace.adaptor.list", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - } - ], - "summary": "List workspace adaptors", - "description": "List all available workspace adaptors for the current project.", - "responses": { - "200": { - "description": "Workspace adaptors", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": ["type", "name", "description"] - } - } - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.adaptor.list({\n ...\n})" - } - ] - } - }, - "/experimental/workspace": { - "post": { - "operationId": "experimental.workspace.create", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - } - ], - "summary": "Create workspace", - "description": "Create a workspace for the current project.", - "responses": { - "200": { - "description": "Workspace created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Workspace" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BadRequestError" - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^wrk.*" - }, - "type": { - "type": "string" - }, - "branch": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "extra": { - "anyOf": [ - {}, - { - "type": "null" - } - ] - } - }, - "required": ["type", "branch", "extra"] - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.create({\n ...\n})" - } - ] - }, - "get": { - "operationId": "experimental.workspace.list", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - } - ], - "summary": "List workspaces", - "description": "List all workspaces.", - "responses": { - "200": { - "description": "Workspaces", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Workspace" - } - } - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.list({\n ...\n})" - } - ] - } - }, - "/experimental/workspace/status": { - "get": { - "operationId": "experimental.workspace.status", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - } - ], - "summary": "Workspace status", - "description": "Get connection status for workspaces in the current project.", - "responses": { - "200": { - "description": "Workspace status", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "workspaceID": { - "type": "string", - "pattern": "^wrk.*" - }, - "status": { - "type": "string", - "enum": ["connected", "connecting", "disconnected", "error"] - }, - "error": { - "type": "string" - } - }, - "required": ["workspaceID", "status"] - } - } - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.status({\n ...\n})" - } - ] - } - }, - "/experimental/workspace/{id}": { - "delete": { - "operationId": "experimental.workspace.remove", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "id", - "schema": { - "type": "string", - "pattern": "^wrk.*" - }, - "required": true - } - ], - "summary": "Remove workspace", - "description": "Remove an existing workspace.", - "responses": { - "200": { - "description": "Workspace removed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Workspace" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BadRequestError" - } - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.remove({\n ...\n})" - } - ] - } - }, - "/experimental/workspace/{id}/session-restore": { - "post": { - "operationId": "experimental.workspace.sessionRestore", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "workspace", - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "id", - "schema": { - "type": "string", - "pattern": "^wrk.*" - }, - "required": true - } - ], - "summary": "Restore session into workspace", - "description": "Replay a session's sync events into the target workspace in batches.", - "responses": { - "200": { - "description": "Session replay started", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - } - }, - "required": ["total"] - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BadRequestError" - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "pattern": "^ses.*" - } - }, - "required": ["sessionID"] - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.sessionRestore({\n ...\n})" - } - ] - } - }, "/experimental/worktree": { "post": { "operationId": "worktree.create", @@ -12003,6 +12003,53 @@ } ] }, + "Workspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^wrk.*" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "extra": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "projectID": { + "type": "string" + } + }, + "required": ["id", "type", "name", "branch", "directory", "extra", "projectID"] + }, "NotFoundError": { "type": "object", "properties": { @@ -12309,53 +12356,6 @@ "$ref": "#/components/schemas/ToolListItem" } }, - "Workspace": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^wrk.*" - }, - "type": { - "type": "string" - }, - "name": { - "type": "string" - }, - "branch": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "directory": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "extra": { - "anyOf": [ - {}, - { - "type": "null" - } - ] - }, - "projectID": { - "type": "string" - } - }, - "required": ["id", "type", "name", "branch", "directory", "extra", "projectID"] - }, "Worktree": { "type": "object", "properties": {