diff --git a/packages/web/package.json b/packages/web/package.json index 499dc3ef..4ee8ae21 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -25,6 +25,7 @@ "@fontsource/ibm-plex-mono": "^5.2.7", "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", + "@octokit/rest": "^22.0.1", "@opencode-ai/sdk": "^1.1.19", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", diff --git a/packages/web/server/lib/github-auth.js b/packages/web/server/lib/github-auth.js index c75b65c6..10131e55 100644 --- a/packages/web/server/lib/github-auth.js +++ b/packages/web/server/lib/github-auth.js @@ -43,7 +43,17 @@ function readJsonFile() { function writeJsonFile(payload) { ensureStorageDir(); - fs.writeFileSync(STORAGE_FILE, JSON.stringify(payload, null, 2), 'utf8'); + + // Atomic write so multiple OpenChamber instances can safely share the same file. + const tmpFile = `${STORAGE_FILE}.${process.pid}.${Date.now()}.tmp`; + fs.writeFileSync(tmpFile, JSON.stringify(payload, null, 2), 'utf8'); + try { + fs.chmodSync(tmpFile, 0o600); + } catch { + // best-effort + } + + fs.renameSync(tmpFile, STORAGE_FILE); try { fs.chmodSync(STORAGE_FILE, 0o600); } catch {