/** * @file tool-profiles.js * @description `/api/tool-profiles` — the login profiles of the AI tools other * than Claude Code (server/lib/tool-profiles.js; Claude's stay under * `/api/cc-config/profiles`, and Settings → AI tools → Profiles shows both). * `GET /` lists every covered tool (`supported: false` + `reason` for one that * cannot be switched); `POST /:tool` saves the live login, `PATCH /:tool` * renames, `POST /:tool/activate` switches, `DELETE /:tool` deletes — the * profile name always in the body. Identity metadata only, never a token. The * writes change the HOST's own login, so `/tool-profiles` is in * ADMIN_WRITE_PREFIXES and STAFF_ONLY_PREFIXES like `/cc-config`. * @author Nguyễn Ngọc Trí Vĩ */ const { Router } = require("express"); const profiles = require("../lib/tool-profiles"); const { sameOriginGuard } = require("../lib/same-origin"); const router = Router(); // Every write swaps a live login: never from a cross-site form. router.use((req, res, next) => (req.method === "GET" ? next() : sameOriginGuard(req, res, next))); const STATUS = { EBADNAME: 400, EBADLABEL: 400, EBADTOOL: 404, ENOTFOUND: 404, EUNSUPPORTED: 409, ENOTINSTALLED: 409, EBADJSON: 409, EACTIVE: 409, EUNSAVED: 409, ENOAUTH: 409, EDUPLICATE: 409, ELABELTAKEN: 409, EOMP: 502, }; const handle = (fn) => async (req, res) => { try { res.json(await fn(req)); } catch (e) { res .status(STATUS[e.code] || 500) .json({ error: { code: e.code || "EINTERNAL", message: e.message } }); } }; router.get( "/", handle(() => ({ tools: profiles.tools().map((t) => { if (!t.supported) return { ...t, items: [], active: null }; try { return { ...t, ...profiles.listProfiles(t.tool), error: null }; } catch (e) { // One tool's failure (omp not installed) never hides the others. return { ...t, items: [], active: null, error: { code: e.code, message: e.message } }; } }), })) ); const name = (req) => (req.body || {}).name; router.post( "/:tool", handle((req) => profiles.saveProfile(req.params.tool, name(req))) ); router.patch( "/:tool", handle((req) => profiles.renameProfile(req.params.tool, name(req), (req.body || {}).label)) ); router.post( "/:tool/activate", handle((req) => profiles.activateProfile(req.params.tool, name(req))) ); router.delete( "/:tool", handle((req) => profiles.deleteProfile(req.params.tool, name(req))) ); module.exports = router;