migration to postgres

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 17:42:59 +00:00
co-authored by Claude Opus 4.6
parent 7f04ecd644
commit 500a70910e
54 changed files with 4016 additions and 264 deletions
+30 -8
View File
@@ -5,7 +5,7 @@ import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { getHomeDir, getGlobalSkillsDir, getGlobalToolsDir, getGlobalExtensionsDir, getUserSkillsDir, getUserToolsDir, DATA_PATH, SERVER_CONFIG_DIR } from '@@/data-path';
import { syncUserPiConfig } from '@@/api/server-settings/sync-user-pi-config';
import { getUsers } from 'officerdb';
import { getUsers, getServerIntegration, getUserIntegration } from 'officerdb';
type WSData = { userId: number; email: string; username: string; role: string; sandboxed: boolean; sessionId?: string; cwd?: string; cols?: number; rows?: number };
type ShellInfo = { command: string; args: string[]; name: string };
@@ -113,10 +113,10 @@ const containerHasExpectedMounts = (dockerId: string): boolean => {
});
if (result.exitCode !== 0) return false;
const mounts = result.stdout.toString();
return mounts.includes(getGlobalSkillsDir()) && mounts.includes('google-oauth.json');
return mounts.includes(getGlobalSkillsDir());
};
const startDockerSidecar = (port: number, homeDir: string, userId: number, username: string, email: string): { dockerId: string } => {
const startDockerSidecar = async (port: number, homeDir: string, userId: number, username: string, email: string): Promise<{ dockerId: string }> => {
ensureDockerImage();
const dockerPath = Bun.which('docker') ?? 'docker';
const dockerId = `officer-terminal-${userId}`;
@@ -138,10 +138,32 @@ const startDockerSidecar = (port: number, homeDir: string, userId: number, usern
}
const containerHome = `/home/${username}`;
// Write google-oauth config from DB to files for Docker mount
const googleConfigHost = join(SERVER_CONFIG_DIR, 'google-oauth.json');
const googleMounts: string[] = existsSync(googleConfigHost)
? ['-v', `${googleConfigHost}:/officer/google-oauth.json:ro`]
: [];
let googleMounts: string[] = [];
try {
const googleIntegration = await getServerIntegration('google');
if (googleIntegration?.config) {
mkdirSync(SERVER_CONFIG_DIR, { recursive: true });
writeFileSync(googleConfigHost, JSON.stringify(googleIntegration.config, null, 2));
googleMounts = ['-v', `${googleConfigHost}:/officer/google-oauth.json:ro`];
}
} catch {
// No google config — skip mount
}
// Write per-user google token from DB for Docker mount
const userIntegrationsDir = join(DATA_PATH, email, 'integrations');
try {
const userGoogle = await getUserIntegration(userId, 'google');
if (userGoogle?.config) {
mkdirSync(userIntegrationsDir, { recursive: true });
writeFileSync(join(userIntegrationsDir, 'google.json'), JSON.stringify(userGoogle.config, null, 2));
}
} catch {
// No user google integration — skip
}
const run = Bun.spawnSync({
cmd: [
@@ -273,7 +295,7 @@ export const ensureDockerContainer = async (email: string, userId: number, homeD
}
const port = existing?.port ?? getAvailablePort(map, userId);
const docker = startDockerSidecar(port, homeDir, userId, username, email);
const docker = await startDockerSidecar(port, homeDir, userId, username, email);
const next = { userId, email, dockerId: docker.dockerId, port };
map[email] = next;
await saveContainerMap(map);
@@ -321,7 +343,7 @@ const startHostSidecar = async () => {
export const initTerminalSidecars = async () => {
await startHostSidecar();
ensureDockerImage();
const users = getUsers();
const users = await getUsers();
for (const user of users) {
const homeDir = getHomeDir(user.email);
mkdirSync(dirname(homeDir), { recursive: true });