diff --git a/packages/opencode/src/cli/cmd/serve.ts b/packages/opencode/src/cli/cmd/serve.ts index 654150d8fa5..bee2c8f711f 100644 --- a/packages/opencode/src/cli/cmd/serve.ts +++ b/packages/opencode/src/cli/cmd/serve.ts @@ -13,8 +13,7 @@ export const ServeCommand = cmd({ } const opts = await resolveNetworkOptions(args) const server = Server.listen(opts) - const displayUrl = opts.rootPath ? new URL(opts.rootPath, `http://${server.hostname}:${server.port}`).toString() : `http://${server.hostname}:${server.port}` - console.log(`opencode server listening on ${displayUrl}`) + console.log(`opencode server listening on http://${server.hostname}:${server.port}`) await new Promise(() => {}) await server.stop() }, diff --git a/packages/opencode/src/cli/cmd/web.ts b/packages/opencode/src/cli/cmd/web.ts index 72ca1fcbbca..5fa2bb42640 100644 --- a/packages/opencode/src/cli/cmd/web.ts +++ b/packages/opencode/src/cli/cmd/web.ts @@ -44,18 +44,17 @@ export const WebCommand = cmd({ if (opts.hostname === "0.0.0.0") { // Show localhost for local access - const baseUrl = opts.rootPath ? new URL(opts.rootPath, `http://localhost:${server.port}`).toString() : `http://localhost:${server.port}` - UI.println(UI.Style.TEXT_INFO_BOLD + " Local access: ", UI.Style.TEXT_NORMAL, baseUrl) + const localhostUrl = `http://localhost:${server.port}` + UI.println(UI.Style.TEXT_INFO_BOLD + " Local access: ", UI.Style.TEXT_NORMAL, localhostUrl) // Show network IPs for remote access const networkIPs = getNetworkIPs() if (networkIPs.length > 0) { for (const ip of networkIPs) { - const networkUrl = opts.rootPath ? new URL(opts.rootPath, `http://${ip}:${server.port}`).toString() : `http://${ip}:${server.port}` UI.println( UI.Style.TEXT_INFO_BOLD + " Network access: ", UI.Style.TEXT_NORMAL, - networkUrl, + `http://${ip}:${server.port}`, ) } } @@ -69,7 +68,7 @@ export const WebCommand = cmd({ } // Open localhost in browser - open(baseUrl.toString()).catch(() => {}) + open(localhostUrl.toString()).catch(() => {}) } else { const displayUrl = server.url.toString() UI.println(UI.Style.TEXT_INFO_BOLD + " Web interface: ", UI.Style.TEXT_NORMAL, displayUrl) diff --git a/packages/opencode/src/cli/network.ts b/packages/opencode/src/cli/network.ts index 5df16f68fa7..fe5731d0713 100644 --- a/packages/opencode/src/cli/network.ts +++ b/packages/opencode/src/cli/network.ts @@ -23,11 +23,6 @@ const options = { describe: "additional domains to allow for CORS", default: [] as string[], }, - rootPath: { - type: "string" as const, - describe: "base path for reverse proxy", - default: "", - }, } export type NetworkOptions = InferredOptionTypes @@ -42,7 +37,6 @@ export async function resolveNetworkOptions(args: NetworkOptions) { const hostnameExplicitlySet = process.argv.includes("--hostname") const mdnsExplicitlySet = process.argv.includes("--mdns") const corsExplicitlySet = process.argv.includes("--cors") - const rootPathExplicitlySet = process.argv.includes("--root-path") const mdns = mdnsExplicitlySet ? args.mdns : (config?.server?.mdns ?? args.mdns) const port = portExplicitlySet ? args.port : (config?.server?.port ?? args.port) @@ -54,11 +48,6 @@ export async function resolveNetworkOptions(args: NetworkOptions) { const configCors = config?.server?.cors ?? [] const argsCors = Array.isArray(args.cors) ? args.cors : args.cors ? [args.cors] : [] const cors = [...configCors, ...argsCors] - const rootPath = rootPathExplicitlySet ? args.rootPath : (config?.server?.rootPath ?? args.rootPath) - - if (rootPath && !rootPath.startsWith("/")) { - throw new Error(`rootPath must start with '/' if provided (got: '${rootPath}')`) - } - return { hostname, port, mdns, cors, rootPath } + return { hostname, port, mdns, cors } } diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 472799c0204..98970ba392d 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -854,7 +854,6 @@ export namespace Config { hostname: z.string().optional().describe("Hostname to listen on"), mdns: z.boolean().optional().describe("Enable mDNS service discovery"), cors: z.array(z.string()).optional().describe("Additional domains to allow for CORS"), - rootPath: z.string().optional().describe("Base path for reverse proxy"), }) .strict() .meta({ diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index a318dfbb830..f6dd0d122f8 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -563,17 +563,13 @@ export namespace Server { return result } - export function listen(opts: { port: number; hostname: string; mdns?: boolean; cors?: string[]; rootPath?: string }) { + export function listen(opts: { port: number; hostname: string; mdns?: boolean; cors?: string[] }) { _corsWhitelist = opts.cors ?? [] - // When rootPath is provided (for reverse proxy support), wrap the main app with a base path prefix. - // Hono's basePath() automatically prefixes all routes, including WebSocket upgrades. - const baseApp = opts.rootPath ? new Hono().basePath(opts.rootPath).route("/", App()) : App() - const args = { hostname: opts.hostname, idleTimeout: 0, - fetch: baseApp.fetch, + fetch: App().fetch, websocket: websocket, } as const const tryServe = (port: number) => { @@ -586,7 +582,7 @@ export namespace Server { const server = opts.port === 0 ? (tryServe(4096) ?? tryServe(0)) : tryServe(opts.port) if (!server) throw new Error(`Failed to start server on port ${opts.port}`) - _url = opts.rootPath ? new URL(opts.rootPath, server.url) : server.url + _url = server.url const shouldPublishMDNS = opts.mdns && diff --git a/packages/opencode/test/server/rootpath.test.ts b/packages/opencode/test/server/rootpath.test.ts deleted file mode 100644 index fadc0b16bfc..00000000000 --- a/packages/opencode/test/server/rootpath.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { Server } from "../../src/server/server" - -describe("rootPath support", () => { - test("server accepts rootPath option", () => { - // Test that listen function accepts rootPath parameter - const listenFn = Server.listen - expect(listenFn).toBeDefined() - - // This will test that the function signature is correct - // We can't actually start the server in tests, but we can verify the types - }) - - test("URL construction with rootPath", () => { - // Test URL construction logic - const testCases = [ - { rootPath: "", expected: "http://localhost:4096" }, - { rootPath: "/proxy", expected: "http://localhost:4096/proxy" }, - { rootPath: "/jupyter/proxy/opencode", expected: "http://192.168.1.100:4096/jupyter/proxy/opencode" }, - ] - - for (const { rootPath, expected } of testCases) { - const hostname = expected.includes("192.168") ? "192.168.1.100" : "localhost" - const port = 4096 - - const url = rootPath - ? new URL(rootPath, `http://${hostname}:${port}`).toString() - : `http://${hostname}:${port}` - - expect(url).toBe(expected) - } - }) - - test("rootPath validation", () => { - // Test that rootPath must start with / - const invalidPaths = ["proxy", "test/path", "no-slash"] - const validPaths = ["/proxy", "/test/path", "/jupyter/proxy/opencode"] - - for (const path of invalidPaths) { - if (path && !path.startsWith("/")) { - // This should throw an error - expect(path.startsWith("/")).toBe(false) - } - } - - for (const path of validPaths) { - expect(path.startsWith("/")).toBe(true) - } - }) - - test("server URL with rootPath", () => { - // Simulate server.url construction - const serverUrl = new URL("http://localhost:4096") - - // Test with rootPath - const rootPath = "/proxy" - const finalUrl = rootPath ? new URL(rootPath, serverUrl) : serverUrl - - expect(finalUrl.toString()).toBe("http://localhost:4096/proxy") - - // Test without rootPath - const noRootPath = "" - const finalUrl2 = noRootPath ? new URL(noRootPath, serverUrl) : serverUrl - - expect(finalUrl2.toString()).toBe("http://localhost:4096/") - }) -}) diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 96786d3f6a6..7fb948f5054 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -368,7 +368,6 @@ This starts an HTTP server that provides API access to opencode functionality wi | `--hostname` | Hostname to listen on | | `--mdns` | Enable mDNS discovery | | `--cors` | Additional browser origin(s) to allow CORS | -| `--root-path` | Base path for reverse proxy | --- @@ -465,7 +464,6 @@ This starts an HTTP server and opens a web browser to access OpenCode through a | `--hostname` | Hostname to listen on | | `--mdns` | Enable mDNS discovery | | `--cors` | Additional browser origin(s) to allow CORS | -| `--root-path` | Base path for reverse proxy | --- diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index 13ce9f32775..1474cb91558 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -190,8 +190,7 @@ You can configure server settings for the `opencode serve` and `opencode web` co "port": 4096, "hostname": "0.0.0.0", "mdns": true, - "cors": ["http://localhost:5173"], - "rootPath": "/proxy" + "cors": ["http://localhost:5173"] } } ``` @@ -202,7 +201,6 @@ Available options: - `hostname` - Hostname to listen on. When `mdns` is enabled and no hostname is set, defaults to `0.0.0.0`. - `mdns` - Enable mDNS service discovery. This allows other devices on the network to discover your OpenCode server. - `cors` - Additional origins to allow for CORS when using the HTTP server from a browser-based client. Values must be full origins (scheme + host + optional port), eg `https://app.example.com`. -- `rootPath` - Base path for reverse proxy. All routes will be prefixed with this path. [Learn more about the server here](/docs/server). diff --git a/packages/web/src/content/docs/server.mdx b/packages/web/src/content/docs/server.mdx index 92510c214c0..7229e09b22f 100644 --- a/packages/web/src/content/docs/server.mdx +++ b/packages/web/src/content/docs/server.mdx @@ -13,7 +13,7 @@ The `opencode serve` command runs a headless HTTP server that exposes an OpenAPI ### Usage ```bash -opencode serve [--port ] [--hostname ] [--cors ] [--root-path ] +opencode serve [--port ] [--hostname ] [--cors ] ``` #### Options @@ -24,7 +24,6 @@ opencode serve [--port ] [--hostname ] [--cors ] [--root | `--hostname` | Hostname to listen on | `127.0.0.1` | | `--mdns` | Enable mDNS discovery | `false` | | `--cors` | Additional browser origins to allow | `[]` | -| `--root-path` | Base path for reverse proxy | (empty) | `--cors` can be passed multiple times: @@ -32,12 +31,6 @@ opencode serve [--port ] [--hostname ] [--cors ] [--root opencode serve --cors http://localhost:5173 --cors https://app.example.com ``` -Use `--root-path` when running behind a reverse proxy: - -```bash -opencode serve --root-path /jupyter/proxy/opencode -``` - --- ### Authentication