feat(server,ui): allow OpenCode directory override via proxy path

This commit is contained in:
Shantur Rathore
2026-02-18 09:43:30 +00:00
parent 859312ba3b
commit 127a1f628d
3 changed files with 168 additions and 18 deletions

View File

@@ -4,12 +4,12 @@ import { CODENOMAD_API_BASE } from "./api-client"
class SDKManager {
private clients = new Map<string, OpencodeClient>()
private key(instanceId: string, worktreeSlug: string): string {
return `${instanceId}:${worktreeSlug || "root"}`
private key(instanceId: string, proxyPath: string): string {
return `${instanceId}:${normalizeProxyPath(proxyPath)}`
}
createClient(instanceId: string, proxyPath: string, worktreeSlug = "root"): OpencodeClient {
const key = this.key(instanceId, worktreeSlug)
createClient(instanceId: string, proxyPath: string, _worktreeSlug = "root"): OpencodeClient {
const key = this.key(instanceId, proxyPath)
const existing = this.clients.get(key)
if (existing) {
return existing
@@ -23,12 +23,12 @@ class SDKManager {
return client
}
getClient(instanceId: string, worktreeSlug = "root"): OpencodeClient | null {
return this.clients.get(this.key(instanceId, worktreeSlug)) ?? null
getClient(instanceId: string, proxyPath: string): OpencodeClient | null {
return this.clients.get(this.key(instanceId, proxyPath)) ?? null
}
destroyClient(instanceId: string, worktreeSlug = "root"): void {
this.clients.delete(this.key(instanceId, worktreeSlug))
destroyClient(instanceId: string, proxyPath: string): void {
this.clients.delete(this.key(instanceId, proxyPath))
}
destroyClientsForInstance(instanceId: string): void {

View File

@@ -329,12 +329,38 @@ function buildWorktreeProxyPath(instanceId: string, slug: string): string {
return `/workspaces/${encodeURIComponent(instanceId)}/worktrees/${encodeURIComponent(normalizedSlug)}/instance`
}
function encodeBase64UrlUtf8(input: string): string {
const bytes = new TextEncoder().encode(input)
// Convert bytes -> base64 (btoa expects a binary string)
let binary = ""
const chunkSize = 0x8000
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.subarray(i, i + chunkSize)
binary += String.fromCharCode(...chunk)
}
const base64 = btoa(binary)
// base64 -> base64url (strip padding)
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "")
}
function buildWorktreeProxyPathWithDirectoryOverride(instanceId: string, slug: string, directory: string): string {
const base = buildWorktreeProxyPath(instanceId, slug)
const encoded = encodeBase64UrlUtf8(directory)
return `${base}/__dir/${encoded}`
}
function getOrCreateWorktreeClient(instanceId: string, slug: string): OpencodeClient {
const normalized = normalizeWorktreeSlug(instanceId, slug || "root")
const proxyPath = buildWorktreeProxyPath(instanceId, normalized)
return sdkManager.createClient(instanceId, proxyPath, normalized)
}
function getOrCreateWorktreeClientWithDirectoryOverride(instanceId: string, slug: string, directory: string): OpencodeClient {
const normalized = normalizeWorktreeSlug(instanceId, slug || "root")
const proxyPath = buildWorktreeProxyPathWithDirectoryOverride(instanceId, normalized, directory)
return sdkManager.createClient(instanceId, proxyPath, normalized)
}
function getRootClient(instanceId: string): OpencodeClient {
return getOrCreateWorktreeClient(instanceId, "root")
}
@@ -359,7 +385,9 @@ export {
removeParentSessionMapping,
getWorktreeSlugForDirectory,
buildWorktreeProxyPath,
buildWorktreeProxyPathWithDirectoryOverride,
getOrCreateWorktreeClient,
getOrCreateWorktreeClientWithDirectoryOverride,
getRootClient,
createWorktree,
deleteWorktree,