From 36c7b1f3fdfa9a66d6a3bff44a06e7d7f282a815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Tue, 4 Aug 2026 03:19:37 +0000 Subject: [PATCH] delete api routes with no consumers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from a full audit of all 179 route definitions under src/servers/api, tracing consumers through useClient, raw fetch, EventSource, the capabilities repo and the mobile monorepo. only routes with zero consumers anywhere are removed. server-settings/applications.ts whole file — an app install/update registry with no settings section to drive it server-settings/claude-code.ts whole file — the ai settings screen talks to chat-providers/* exclusively GET browser/extension-download superseded by a static asset; BrowserRelay links at /browser-relay-extension.zip GET integrations/ a stub returning [] GET chat-providers/auth /api-keys says the same thing with more detail GET desktop/vnc-status and with it the vnc:status command and reply, which existed only to serve this route. docs/sidecar-audit-2026-07.md called this one dead months ago deliberately KEPT, because "no caller" turned out not to mean "dead": POST activity/announce not orphaned — it is the missing PRODUCER for the detached[] list GET activity/tasks already returns and ActivityScreen already renders. an unbuilt feature, not dead code, and finishing or dropping it is a product decision. GET agents/runs three days old. part of agent grounds, still being built. "not yet consumed" is not "dead". PUT/GET vault/unlock-key six days old, storage half of a feature whose client half is unwritten. the vault is off limits. DELETE integrations/google/connection caller exists but is deliberately commented out of the tree. dormant on purpose. vnc-manager's getSession is now orphaned too, but it is sidecar-internal and was not in scope; noted rather than chased. Co-Authored-By: Claude Opus 5 --- src/servers/api/browser/router.ts | 27 +-- src/servers/api/desktop/rest.ts | 11 +- src/servers/api/integrations/integrations.ts | 4 +- .../api/server-settings/applications.ts | 211 ------------------ .../api/server-settings/chat-providers.ts | 7 +- .../api/server-settings/claude-code.ts | 80 ------- .../api/server-settings/server-settings.ts | 4 - src/servers/sidecar-registry.ts | 7 - src/servers/sidecar/protocol.ts | 4 +- src/servers/sidecar/vnc/index.ts | 6 - 10 files changed, 14 insertions(+), 347 deletions(-) delete mode 100644 src/servers/api/server-settings/applications.ts delete mode 100644 src/servers/api/server-settings/claude-code.ts diff --git a/src/servers/api/browser/router.ts b/src/servers/api/browser/router.ts index e632981a..148958c1 100644 --- a/src/servers/api/browser/router.ts +++ b/src/servers/api/browser/router.ts @@ -1,5 +1,4 @@ import { randomUUID } from 'node:crypto'; -import { join } from 'node:path'; import { createRouter } from '@@/create-router'; import * as errors from '@@/custom-errors'; import { getUserIntegration, upsertUserIntegration, deleteUserIntegration } from 'officerdb'; @@ -9,8 +8,6 @@ import { captureScreenshot, evaluateJS, navigateTo } from './cdp'; export const browserRouter = createRouter(); -const EXTENSION_DIR = join(import.meta.dir, '../../../extensions/browser-relay'); - async function getOpts(userId: number) { const port = getRelayPort(); const integration = await getUserIntegration(userId, 'browser-relay'); @@ -22,22 +19,8 @@ async function getOpts(userId: number) { return { relayPort: port, userToken: token }; } -browserRouter.get('/extension-download', async (ctx) => { - const proc = Bun.spawn(['zip', '-r', '-', '.'], { - cwd: EXTENSION_DIR, - stdout: 'pipe', - stderr: 'pipe', - }); - const blob = await new Response(proc.stdout).blob(); - await proc.exited; - if (proc.exitCode !== 0) throw errors.INTERNAL_SERVER_ERROR('Failed to create zip'); - return new Response(blob, { - headers: { - 'Content-Type': 'application/zip', - 'Content-Disposition': 'attachment; filename="officer-browser-relay.zip"', - }, - }); -}); +// GET /extension-download used to zip the extension directory on the fly, shelling out to `zip`. It had +// no caller: BrowserRelay.tsx links straight at /browser-relay-extension.zip, a real file in public/. browserRouter.get('/status', async (ctx) => { const user = ctx.get('user'); @@ -51,7 +34,11 @@ browserRouter.get('/relay-token', async (ctx) => { let integration = await getUserIntegration(user.id, 'browser-relay'); if (!integration) { const salt = randomUUID(); - integration = await upsertUserIntegration({ userId: user.id, provider: 'browser-relay', config: { tokenSalt: salt } }); + integration = await upsertUserIntegration({ + userId: user.id, + provider: 'browser-relay', + config: { tokenSalt: salt }, + }); } const salt = (integration.config as { tokenSalt: string }).tokenSalt; const token = registerUserToken(user.id, port, salt); diff --git a/src/servers/api/desktop/rest.ts b/src/servers/api/desktop/rest.ts index 671b06a3..15ff05de 100644 --- a/src/servers/api/desktop/rest.ts +++ b/src/servers/api/desktop/rest.ts @@ -28,11 +28,6 @@ desktopRouter.get('/vnc-password', async (ctx) => { } }); -desktopRouter.get('/vnc-status', async (ctx) => { - const user = ctx.get('user'); - if (!sidecar.isVncConnected()) { - return ctx.json({ connected: false, session: null }); - } - const session = await sidecar.getVncStatus(user.email); - return ctx.json({ connected: true, session }); -}); +// GET /vnc-status is gone. It was never called — DesktopView asks only for /vnc-password — and it was +// the sole reason the `vnc:status` command existed on the sidecar wire protocol at all. Noted as dead +// by docs/sidecar-audit-2026-07.md months ago. diff --git a/src/servers/api/integrations/integrations.ts b/src/servers/api/integrations/integrations.ts index 33f5da5c..4c636846 100644 --- a/src/servers/api/integrations/integrations.ts +++ b/src/servers/api/integrations/integrations.ts @@ -30,9 +30,7 @@ export const readGoogleConfig = async (): Promise => { export const integrationsRouter = createRouter(); -integrationsRouter.get('/', async (ctx) => { - return ctx.json([]); -}); +// GET / was a stub that returned []. Never wired to anything, in either direction. // --- Apify config --- diff --git a/src/servers/api/server-settings/applications.ts b/src/servers/api/server-settings/applications.ts deleted file mode 100644 index 6024dfa2..00000000 --- a/src/servers/api/server-settings/applications.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { createRouter } from '../../create-router'; - -type AppSpec = { - id: string; - name: string; - description: string; - versionCommand: string[]; - versionParser: (output: string) => string | null; - installCommand?: string[]; - updateCommand?: string[]; - manualInstallCommand?: string; - manualUpdateCommand?: string; - processName?: string; -}; - -type AppStatus = { - id: string; - name: string; - description: string; - installed: boolean; - version: string | null; - running: boolean | null; - hasInstall: boolean; - hasUpdate: boolean; - manualInstallCommand: string | null; - manualUpdateCommand: string | null; -}; - -const detectPackageManager = (): 'pacman' | 'apt' | 'brew' | null => { - for (const [cmd, name] of [ - ['pacman', 'pacman'], - ['apt', 'apt'], - ['brew', 'brew'], - ] as const) { - try { - const proc = Bun.spawnSync(['which', cmd], { stdout: 'pipe', stderr: 'pipe' }); - if (proc.exitCode === 0) return name; - } catch { - // continue - } - } - return null; -}; - -type FfmpegCommands = { - installCommand?: string[]; - updateCommand?: string[]; - manualInstallCommand?: string; - manualUpdateCommand?: string; -}; - -const getFfmpegCommands = (): FfmpegCommands => { - const pm = detectPackageManager(); - if (pm === 'pacman') - return { - manualInstallCommand: 'sudo pacman -S ffmpeg', - manualUpdateCommand: 'sudo pacman -Syu ffmpeg', - }; - if (pm === 'apt') - return { - manualInstallCommand: 'sudo apt install ffmpeg', - manualUpdateCommand: 'sudo apt install --only-upgrade ffmpeg', - }; - if (pm === 'brew') - return { - installCommand: ['brew', 'install', 'ffmpeg'], - updateCommand: ['brew', 'upgrade', 'ffmpeg'], - }; - return {}; -}; - -const ffmpegCmds = getFfmpegCommands(); - -const apps: AppSpec[] = [ - { - id: 'ffmpeg', - name: 'FFmpeg', - description: 'Audio and video processing toolkit', - versionCommand: ['ffmpeg', '-version'], - versionParser: (output) => { - const match = output.match(/ffmpeg version (\S+)/); - return match?.[1] ?? null; - }, - installCommand: ffmpegCmds.installCommand, - updateCommand: ffmpegCmds.updateCommand, - manualInstallCommand: ffmpegCmds.manualInstallCommand, - manualUpdateCommand: ffmpegCmds.manualUpdateCommand, - }, - { - id: 'sharp', - name: 'Sharp', - description: 'High-performance image processing library', - versionCommand: ['bun', '--eval', "console.log(require('sharp').versions.sharp)"], - versionParser: (output) => output.trim() || null, - installCommand: ['bun', 'add', 'sharp'], - updateCommand: ['bun', 'add', 'sharp@latest'], - }, - { - id: 'whisper-cpp', - name: 'Whisper.cpp', - description: 'Speech-to-text inference engine', - versionCommand: ['whisper-cpp', '--version'], - versionParser: (output) => output.trim() || null, - installCommand: detectPackageManager() === 'brew' ? ['brew', 'install', 'whisper-cpp'] : undefined, - processName: 'whisper-server', - }, - { - id: 'mlx-audio', - name: 'MLX Audio', - description: 'Audio processing with Apple MLX framework', - versionCommand: ['pip', 'show', 'mlx-audio'], - versionParser: (output) => { - const match = output.match(/Version:\s*(\S+)/); - return match?.[1] ?? null; - }, - installCommand: ['pip', 'install', 'mlx-audio'], - updateCommand: ['pip', 'install', '--upgrade', 'mlx-audio'], - }, -]; - -const COMMAND_TIMEOUT_MS = 30_000; - -const runCommand = async (command: string[]): Promise<{ exitCode: number; stdout: string; stderr: string }> => { - try { - const proc = Bun.spawn(command, { stdout: 'pipe', stderr: 'pipe' }); - const timeout = new Promise((_, reject) => - setTimeout(() => { - proc.kill(); - reject(new Error('Command timed out')); - }, COMMAND_TIMEOUT_MS), - ); - const result = Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]); - const [stdout, stderr] = await Promise.race([result, timeout]); - return { exitCode: proc.exitCode ?? 1, stdout, stderr }; - } catch (err) { - const message = err instanceof Error ? err.message : 'Command not found or failed to execute'; - return { exitCode: 1, stdout: '', stderr: message }; - } -}; - -const checkVersion = async (app: AppSpec): Promise => { - const result = await runCommand(app.versionCommand); - if (result.exitCode !== 0) return null; - return app.versionParser(result.stdout); -}; - -const checkRunning = async (processName: string): Promise => { - const result = await runCommand(['pgrep', '-x', processName]); - return result.exitCode === 0; -}; - -const getAppStatus = async (app: AppSpec): Promise => { - const version = await checkVersion(app); - const running = app.processName ? await checkRunning(app.processName) : null; - return { - id: app.id, - name: app.name, - description: app.description, - installed: version !== null, - version, - running, - hasInstall: !!(app.installCommand || app.manualInstallCommand), - hasUpdate: !!(app.updateCommand ?? app.installCommand ?? app.manualUpdateCommand ?? app.manualInstallCommand), - manualInstallCommand: app.manualInstallCommand ?? null, - manualUpdateCommand: app.manualUpdateCommand ?? null, - }; -}; - -export const applicationsRouter = createRouter(); - -applicationsRouter.get('/', async (ctx) => { - const statuses = await Promise.all(apps.map(getAppStatus)); - return ctx.json(statuses); -}); - -applicationsRouter.get('/:id', async (ctx) => { - const app = apps.find((a) => a.id === ctx.req.param('id')); - if (!app) return ctx.json({ error: 'Application not found' }, 404); - const status = await getAppStatus(app); - return ctx.json(status); -}); - -applicationsRouter.post('/:id/install', async (ctx) => { - const app = apps.find((a) => a.id === ctx.req.param('id')); - if (!app) return ctx.json({ error: 'Application not found' }, 404); - if (!app.installCommand) return ctx.json({ error: 'No install command available for this platform' }, 400); - - const result = await runCommand(app.installCommand); - if (result.exitCode !== 0) { - return ctx.json({ error: result.stderr.trim() || 'Installation failed' }, 500); - } - - const status = await getAppStatus(app); - return ctx.json(status); -}); - -applicationsRouter.post('/:id/update', async (ctx) => { - const app = apps.find((a) => a.id === ctx.req.param('id')); - if (!app) return ctx.json({ error: 'Application not found' }, 404); - - const command = app.updateCommand ?? app.installCommand; - if (!command) return ctx.json({ error: 'No update command available for this platform' }, 400); - - const result = await runCommand(command); - if (result.exitCode !== 0) { - return ctx.json({ error: result.stderr.trim() || 'Update failed' }, 500); - } - - const status = await getAppStatus(app); - return ctx.json(status); -}); diff --git a/src/servers/api/server-settings/chat-providers.ts b/src/servers/api/server-settings/chat-providers.ts index 4ed234c3..c6b7755b 100644 --- a/src/servers/api/server-settings/chat-providers.ts +++ b/src/servers/api/server-settings/chat-providers.ts @@ -370,11 +370,8 @@ chatProvidersRouter.get('/providers', async (ctx) => { return ctx.json(PROVIDERS); }); -chatProvidersRouter.get('/auth', async (ctx) => { - const auth = await readAuthJson(); - const providers = PROVIDERS.filter((p) => auth[p.providerId]?.key?.trim()).map((p) => p.key); - return ctx.json({ authenticated: providers.length > 0, providers }); -}); +// GET /auth reported which providers had a key set. No caller — AIHarnessesSection reads /api-keys and +// /api-keys/health instead, which say the same thing with more detail. const maskValue = (value: string) => { if (value.length <= 8) return '***'; diff --git a/src/servers/api/server-settings/claude-code.ts b/src/servers/api/server-settings/claude-code.ts deleted file mode 100644 index 8f4afc65..00000000 --- a/src/servers/api/server-settings/claude-code.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { createRouter } from '../../create-router'; - -export const claudeCodeRouter = createRouter(); - -const GLOBAL_DIRS = ['/usr/local/bin', '/usr/bin']; - -const getPaths = async () => { - try { - const proc = Bun.spawn(['which', '-a', 'claude'], { stdout: 'pipe', stderr: 'pipe' }); - const output = await new Response(proc.stdout).text(); - await proc.exited; - if (proc.exitCode !== 0) return { path: null, globalPath: null }; - const paths = [...new Set(output.trim().split('\n'))]; - const path = paths[0] ?? null; - const globalPath = paths.find((p) => GLOBAL_DIRS.some((dir) => p.startsWith(dir))) ?? null; - return { path, globalPath }; - } catch { - return { path: null, globalPath: null }; - } -}; - -claudeCodeRouter.post('/install', async (ctx) => { - try { - const proc = Bun.spawn(['bash', '-c', 'curl -fsSL https://claude.ai/install.sh | bash'], { - stdout: 'pipe', - stderr: 'pipe', - }); - await proc.exited; - if (proc.exitCode !== 0) { - const stderr = await new Response(proc.stderr).text(); - return ctx.json({ version: null, path: null, globalPath: null, error: stderr.trim() }, 500); - } - const versionProc = Bun.spawn(['claude', '--version'], { stdout: 'pipe', stderr: 'pipe' }); - const output = await new Response(versionProc.stdout).text(); - await versionProc.exited; - const { path, globalPath } = await getPaths(); - return ctx.json({ version: output.trim(), path, globalPath }); - } catch { - return ctx.json({ version: null, path: null, globalPath: null, error: 'Installation failed' }, 500); - } -}); - -claudeCodeRouter.post('/auth/login', async (ctx) => { - try { - const env = { ...process.env }; - delete env.CLAUDECODE; - Bun.spawn(['claude', 'auth', 'login'], { stdout: 'ignore', stderr: 'ignore', env }); - return ctx.json({ started: true }); - } catch { - return ctx.json({ started: false, error: 'Failed to start login' }, 500); - } -}); - -claudeCodeRouter.get('/auth', async (ctx) => { - try { - const proc = Bun.spawn(['claude', 'auth', 'status'], { stdout: 'pipe', stderr: 'pipe' }); - const output = await new Response(proc.stdout).text(); - await proc.exited; - if (proc.exitCode === 0) { - const status = JSON.parse(output.trim()); - if (status.loggedIn) return ctx.json({ authenticated: true, ...status }); - } - return ctx.json({ authenticated: false }); - } catch { - return ctx.json({ authenticated: false }); - } -}); - -claudeCodeRouter.get('/version', async (ctx) => { - try { - const proc = Bun.spawn(['claude', '--version'], { stdout: 'pipe', stderr: 'pipe' }); - const output = await new Response(proc.stdout).text(); - await proc.exited; - if (proc.exitCode !== 0) return ctx.json({ version: null, path: null, globalPath: null }); - const { path, globalPath } = await getPaths(); - return ctx.json({ version: output.trim(), path, globalPath }); - } catch { - return ctx.json({ version: null, path: null, globalPath: null }); - } -}); diff --git a/src/servers/api/server-settings/server-settings.ts b/src/servers/api/server-settings/server-settings.ts index 173a39fb..aa09fd18 100644 --- a/src/servers/api/server-settings/server-settings.ts +++ b/src/servers/api/server-settings/server-settings.ts @@ -2,9 +2,7 @@ import { createRouter } from '../../create-router'; import { readdirSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { readServerSettings, writeServerSettings } from 'officerdb'; -import { claudeCodeRouter } from './claude-code'; import { chatProvidersRouter } from './chat-providers'; -import { applicationsRouter } from './applications'; import { smtpRouter } from './smtp'; import { ttsRouter } from './tts'; import { sttRouter } from './stt'; @@ -12,9 +10,7 @@ import { ocrRouter } from './ocr'; export const serverSettingsRouter = createRouter(); -serverSettingsRouter.route('/claude-code', claudeCodeRouter); serverSettingsRouter.route('/chat-providers', chatProvidersRouter); -serverSettingsRouter.route('/applications', applicationsRouter); serverSettingsRouter.route('/smtp', smtpRouter); serverSettingsRouter.route('/tts', ttsRouter); serverSettingsRouter.route('/stt', sttRouter); diff --git a/src/servers/sidecar-registry.ts b/src/servers/sidecar-registry.ts index 27286141..beef8d53 100644 --- a/src/servers/sidecar-registry.ts +++ b/src/servers/sidecar-registry.ts @@ -8,7 +8,6 @@ import type { ClaudeCodeResult, OpenCodeRunParams, VncStartParams, - VncSessionInfo, } from './sidecar/protocol'; import type { SidecarRegistration } from './sidecar/registration-protocol'; import type { TurnMessage } from './api/chat/types'; @@ -348,12 +347,6 @@ export function stopVnc(email: string): void { sendFire('vnc', { type: 'vnc:stop', id: nextId(), email }); } -export async function getVncStatus(email: string): Promise { - const res = await sendCommand('vnc', { type: 'vnc:status', id: nextId(), email }); - if (res.type === 'vnc:status') return res.session; - throw new Error('Unexpected response'); -} - export function isVncConnected(): boolean { return findSidecarByCapability('vnc') !== undefined; } diff --git a/src/servers/sidecar/protocol.ts b/src/servers/sidecar/protocol.ts index 964b73ef..271e1bdb 100644 --- a/src/servers/sidecar/protocol.ts +++ b/src/servers/sidecar/protocol.ts @@ -24,8 +24,7 @@ export type SidecarCommand = | { type: 'vnc:start'; id: string; params: VncStartParams } // Provision the VNC password without starting a server — the UI needs it before it can connect | { type: 'vnc:ensure-password'; id: string; email: string } - | { type: 'vnc:stop'; id: string; email: string } - | { type: 'vnc:status'; id: string; email: string }; + | { type: 'vnc:stop'; id: string; email: string }; // ── Responses/Events (sidecar → API server) ── @@ -48,7 +47,6 @@ export type SidecarEvent = | { type: 'vnc:started'; id: string; port: number; display: number } | { type: 'vnc:password'; id: string; password: string } | { type: 'vnc:stopped'; id: string } - | { type: 'vnc:status'; id: string; session: VncSessionInfo | null } | { type: 'vnc:error'; id: string; error: string } // Email — new mail no longer crosses this socket; the sidecar owns the SSE stream and pushes directly // OpenCode — the sidecar reports where its `opencode serve` is listening (random port) on connect diff --git a/src/servers/sidecar/vnc/index.ts b/src/servers/sidecar/vnc/index.ts index b8af5611..9a7eca10 100644 --- a/src/servers/sidecar/vnc/index.ts +++ b/src/servers/sidecar/vnc/index.ts @@ -40,12 +40,6 @@ async function handleCommand(cmd: SidecarCommand, reply: ReplyFn) { reply({ type: 'vnc:stopped', id: cmd.id }); break; - case 'vnc:status': { - const session = vncManager.getSession(cmd.email); - reply({ type: 'vnc:status', id: cmd.id, session }); - break; - } - default: reply({ type: 'error',