This commit is contained in:
2026-02-16 19:34:35 +00:00
commit 9ab0940ca4
784 changed files with 41710 additions and 0 deletions
@@ -0,0 +1,211 @@
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<never>((_, 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<string | null> => {
const result = await runCommand(app.versionCommand);
if (result.exitCode !== 0) return null;
return app.versionParser(result.stdout);
};
const checkRunning = async (processName: string): Promise<boolean> => {
const result = await runCommand(['pgrep', '-x', processName]);
return result.exitCode === 0;
};
const getAppStatus = async (app: AppSpec): Promise<AppStatus> => {
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);
});
@@ -0,0 +1,78 @@
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) return ctx.json({ authenticated: false });
const status = JSON.parse(output.trim());
return ctx.json({ authenticated: status.loggedIn ?? false, ...status });
} 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 });
}
});
@@ -0,0 +1,76 @@
import { createRouter } from '../../create-router';
export const opencodeRouter = createRouter();
const GLOBAL_DIRS = ['/usr/local/bin', '/usr/bin'];
const getPaths = async () => {
try {
const proc = Bun.spawn(['which', '-a', 'opencode'], { 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 };
}
};
opencodeRouter.post('/auth/login', async (ctx) => {
try {
Bun.spawn(['opencode', 'auth', 'login'], { stdout: 'ignore', stderr: 'ignore' });
return ctx.json({ started: true });
} catch {
return ctx.json({ started: false, error: 'Failed to start login' }, 500);
}
});
opencodeRouter.get('/auth', async (ctx) => {
try {
const authPath = `${process.env.HOME}/.local/share/opencode/auth.json`;
const file = Bun.file(authPath);
if (!(await file.exists())) return ctx.json({ authenticated: false, providers: [] });
const auth = await file.json();
const providers = Object.keys(auth);
return ctx.json({ authenticated: providers.length > 0, providers });
} catch {
return ctx.json({ authenticated: false, providers: [] });
}
});
opencodeRouter.post('/install', async (ctx) => {
try {
const proc = Bun.spawn(['bash', '-c', 'curl -fsSL https://opencode.ai/install | 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(['opencode', '--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);
}
});
opencodeRouter.get('/version', async (ctx) => {
try {
const proc = Bun.spawn(['opencode', '--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 });
}
});
@@ -0,0 +1,82 @@
import { createRouter } from '../../create-router';
import { homedir } from 'node:os';
import { mkdir } from 'node:fs/promises';
import { readdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { officerdb, count, Users } from 'officerdb';
import { claudeCodeRouter } from './claude-code';
import { opencodeRouter } from './opencode';
import { applicationsRouter } from './applications';
const configDir = `${homedir()}/.config/officer.dev`;
export const settingsPath = `${configDir}/server-settings.json`;
const settingsFile = Bun.file(settingsPath);
if (!(await settingsFile.exists())) {
await mkdir(configDir, { recursive: true });
await Bun.write(settingsPath, '{}');
}
export const serverSettingsRouter = createRouter();
serverSettingsRouter.route('/claude-code', claudeCodeRouter);
serverSettingsRouter.route('/opencode', opencodeRouter);
serverSettingsRouter.route('/applications', applicationsRouter);
serverSettingsRouter.get('/', async (ctx) => {
const result = await officerdb.select({ count: count() }).from(Users);
const userCount = result[0]?.count ?? 0;
return ctx.json({ registrationOpen: userCount === 0 });
});
serverSettingsRouter.get('/settings', async (ctx) => {
const settings = await Bun.file(settingsPath).json();
return ctx.json(settings);
});
serverSettingsRouter.get('/onboarding-complete', async (ctx) => {
const settings = await Bun.file(settingsPath).json();
return ctx.json({ onboardingComplete: !!settings.onboardingComplete });
});
serverSettingsRouter.put('/', async (ctx) => {
const body = await ctx.req.json();
const settings = await Bun.file(settingsPath).json();
const updated = { ...settings, ...body };
await Bun.write(settingsPath, JSON.stringify(updated, null, 2));
return ctx.json(updated);
});
serverSettingsRouter.get('/plugins', async (ctx) => {
const pluginsDir = join(import.meta.dir, '../../../workspaces/plugins');
const settings = await Bun.file(settingsPath)
.json()
.catch(() => ({}));
const pluginSettings: Record<string, boolean> = settings.plugins ?? {};
const plugins: { id: string; name: string; description: string; enabled: boolean }[] = [];
if (!existsSync(pluginsDir)) return ctx.json(plugins);
const dirs = readdirSync(pluginsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
for (const dir of dirs) {
const hasServer = existsSync(join(pluginsDir, dir.name, 'server', 'index.ts'));
const hasClient = existsSync(join(pluginsDir, dir.name, 'client', 'index.ts'));
if (!hasServer && !hasClient) continue;
const mainIndex = join(pluginsDir, dir.name, 'index.ts');
if (!existsSync(mainIndex)) continue;
const mod = await import(mainIndex);
const meta = mod.plugin ?? { id: dir.name, name: dir.name, description: '' };
plugins.push({
id: meta.id,
name: meta.name,
description: meta.description,
enabled: pluginSettings[meta.id] !== false,
});
}
return ctx.json(plugins);
});