[object Object]

← back to George Gmail

Add agentabrams (theagentabrams@gmail.com) as 5th george account slot

23979b00576396015f9d96eaff1733cabfde3835 · 2026-05-18 14:21:06 -0700 · Steve Abrams

Files touched

Diff

commit 23979b00576396015f9d96eaff1733cabfde3835
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon May 18 14:21:06 2026 -0700

    Add agentabrams (theagentabrams@gmail.com) as 5th george account slot
---
 server.js | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 147 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index 6dba3af..34dbf39 100644
--- a/server.js
+++ b/server.js
@@ -65,6 +65,12 @@ const STEVESCLAUDE_REDIRECT_URI = 'http://localhost:9850/oauth2callback';
 const STEVESCLAUDE_REFRESH_TOKEN = creds.STEVESCLAUDE_REFRESH_TOKEN || process.env.STEVESCLAUDE_REFRESH_TOKEN;
 const STEVESCLAUDE_LOGIN_HINT = creds.STEVESCLAUDE_LOGIN_HINT || process.env.STEVESCLAUDE_LOGIN_HINT || 'stevesclaude@gmail.com';
 
+// ─── Agent Abrams (theagentabrams@gmail.com) Credentials ───
+// Reuses GMAIL_CLIENT_ID/SECRET. Added 2026-05-18 per Steve.
+const AGENTABRAMS_REDIRECT_URI = 'http://localhost:9850/oauth2callback';
+const AGENTABRAMS_REFRESH_TOKEN = creds.AGENTABRAMS_REFRESH_TOKEN || process.env.AGENTABRAMS_REFRESH_TOKEN;
+const AGENTABRAMS_LOGIN_HINT = creds.AGENTABRAMS_LOGIN_HINT || process.env.AGENTABRAMS_LOGIN_HINT || 'theagentabrams@gmail.com';
+
 // ─── OAuth2 Scopes ───
 // FULL_WORKSPACE_SCOPES = unified scope list for all 3 accounts.
 // Steve approved including Forms (Q3=y) so we don't have to re-OAuth later.
@@ -192,8 +198,31 @@ try {
   console.error(`[${AGENT_NAME}] StevesClaude client error: ${e.message}`);
 }
 
+// ─── Agent Abrams (theagentabrams@gmail.com) account ───
+let agentabramsOauth2Client;
+let agentabramsGmail, agentabramsTasksApi, agentabramsDrive, agentabramsDocs, agentabramsSheets, agentabramsSlides, agentabramsCalendar, agentabramsForms;
+try {
+  agentabramsOauth2Client = new google.auth.OAuth2(GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, AGENTABRAMS_REDIRECT_URI);
+  if (AGENTABRAMS_REFRESH_TOKEN) {
+    agentabramsOauth2Client.setCredentials({ refresh_token: AGENTABRAMS_REFRESH_TOKEN });
+    agentabramsGmail    = google.gmail   ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsTasksApi = google.tasks   ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsDrive    = google.drive   ({ version: 'v3', auth: agentabramsOauth2Client });
+    agentabramsDocs     = google.docs    ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsSheets   = google.sheets  ({ version: 'v4', auth: agentabramsOauth2Client });
+    agentabramsSlides   = google.slides  ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsCalendar = google.calendar({ version: 'v3', auth: agentabramsOauth2Client });
+    agentabramsForms    = google.forms   ({ version: 'v1', auth: agentabramsOauth2Client });
+    console.log(`[${AGENT_NAME}] Agent Abrams account initialized (full Workspace)`);
+  } else {
+    console.log(`[${AGENT_NAME}] Agent Abrams not configured — visit /auth/agentabrams to authorize`);
+  }
+} catch (e) {
+  console.error(`[${AGENT_NAME}] Agent Abrams client error: ${e.message}`);
+}
+
 // ─── Account resolver for per-service API endpoints ───
-// account query/body param: "steve-office" (default), "info", "steve-personal", "stevesclaude"
+// account query/body param: "steve-office" (default), "info", "steve-personal", "stevesclaude", "agentabrams"
 function resolveAccount(req) {
   const key = (req.query.account || req.body?.account || 'steve-office').toLowerCase();
   const map = {
@@ -201,6 +230,7 @@ function resolveAccount(req) {
     'info':           { label: 'info@designerwallcoverings.com',  oauth: infoOauth2Client, gmail: infoGmail, tasks: infoTasksApi, drive: infoDrive, docs: infoDocs, sheets: infoSheets, slides: infoSlides, calendar: infoCalendar, forms: infoForms, refreshToken: INFO_REFRESH_TOKEN },
     'steve-personal': { label: 'steveabramsdesigns@gmail.com',    oauth: personalOauth2Client, gmail: personalGmail, tasks: personalTasksApi, drive: personalDrive, docs: personalDocs, sheets: personalSheets, slides: personalSlides, calendar: personalCalendar, forms: personalForms, refreshToken: PERSONAL_REFRESH_TOKEN },
     'stevesclaude':   { label: STEVESCLAUDE_LOGIN_HINT,           oauth: stevesclaudeOauth2Client, gmail: stevesclaudeGmail, tasks: stevesclaudeTasksApi, drive: stevesclaudeDrive, docs: stevesclaudeDocs, sheets: stevesclaudeSheets, slides: stevesclaudeSlides, calendar: stevesclaudeCalendar, forms: stevesclaudeForms, refreshToken: STEVESCLAUDE_REFRESH_TOKEN },
+    'agentabrams':    { label: AGENTABRAMS_LOGIN_HINT,            oauth: agentabramsOauth2Client, gmail: agentabramsGmail, tasks: agentabramsTasksApi, drive: agentabramsDrive, docs: agentabramsDocs, sheets: agentabramsSheets, slides: agentabramsSlides, calendar: agentabramsCalendar, forms: agentabramsForms, refreshToken: AGENTABRAMS_REFRESH_TOKEN },
   };
   return { key, ...(map[key] || {}) };
 }
@@ -250,6 +280,7 @@ app.get('/auth', (req, res) => {
     'info':           '/auth/info',
     'steve-personal': '/auth/steve-personal',
     'stevesclaude':   '/auth/stevesclaude',
+    'agentabrams':    '/auth/agentabrams',
   };
   if (routes[acct]) return res.redirect(routes[acct]);
   // steve-office (default, or unknown account key) — full Workspace re-auth for steve@
@@ -313,6 +344,47 @@ app.get('/oauth2callback', async (req, res) => {
       return res.send(msg);
     }
 
+    // Route to agentabrams handler if state=agentabrams
+    if (state === 'agentabrams') {
+      const { tokens } = await agentabramsOauth2Client.getToken({ code, redirect_uri: AGENTABRAMS_REDIRECT_URI });
+      agentabramsOauth2Client.setCredentials(tokens);
+      agentabramsGmail    = google.gmail   ({ version: 'v1', auth: agentabramsOauth2Client });
+      agentabramsTasksApi = google.tasks   ({ version: 'v1', auth: agentabramsOauth2Client });
+      agentabramsDrive    = google.drive   ({ version: 'v3', auth: agentabramsOauth2Client });
+      agentabramsDocs     = google.docs    ({ version: 'v1', auth: agentabramsOauth2Client });
+      agentabramsSheets   = google.sheets  ({ version: 'v4', auth: agentabramsOauth2Client });
+      agentabramsSlides   = google.slides  ({ version: 'v1', auth: agentabramsOauth2Client });
+      agentabramsCalendar = google.calendar({ version: 'v3', auth: agentabramsOauth2Client });
+      agentabramsForms    = google.forms   ({ version: 'v1', auth: agentabramsOauth2Client });
+
+      let msg = '<html><body style="font-family:sans-serif;background:#0f1117;color:#e4e4e7;padding:40px">';
+      msg += '<h2 style="color:#4ade80">Agent Abrams Authorized! (Full Google Workspace)</h2>';
+      if (tokens.refresh_token) {
+        msg += `<p><strong>New Agent Abrams Refresh Token:</strong></p><code style="background:#1a1d27;padding:10px;display:block;word-break:break-all;border-radius:8px">${tokens.refresh_token}</code>`;
+        console.log(`[${AGENT_NAME}] Agent Abrams refresh token obtained: ${tokens.refresh_token.substring(0, 20)}...`);
+        try {
+          let envContent = fs.readFileSync(ENV_PATH, 'utf8');
+          if (envContent.includes('AGENTABRAMS_REFRESH_TOKEN=')) {
+            envContent = envContent.replace(/AGENTABRAMS_REFRESH_TOKEN=.*/, `AGENTABRAMS_REFRESH_TOKEN=${tokens.refresh_token}`);
+          } else {
+            envContent += `\n# Agent Abrams (theagentabrams@gmail.com) OAuth Token\nAGENTABRAMS_REFRESH_TOKEN=${tokens.refresh_token}\n`;
+          }
+          fs.writeFileSync(ENV_PATH, envContent);
+          msg += '<p style="color:#4ade80">Token auto-saved to central .env!</p>';
+          audit('agentabrams', 'oauth-authorized', { scopes: FULL_WORKSPACE_SCOPES.length });
+        } catch (e) {
+          msg += `<p style="color:#f87171">Could not auto-save: ${e.message}</p>`;
+        }
+      }
+      try {
+        const profile = await agentabramsGmail.users.getProfile({ userId: 'me' });
+        msg += `<p style="color:#60a5fa">Connected as: <strong>${profile.data.emailAddress}</strong></p>`;
+      } catch {}
+      msg += '<p style="color:#a3a3a3">You can close this tab. Restart george-gmail to load the new token persistently.</p>';
+      msg += '<p><a href="/" style="color:#60a5fa">Go to Dashboard</a></p></body></html>';
+      return res.send(msg);
+    }
+
     // Route to steve-personal handler if state=personal
     if (state === 'personal') {
       const { tokens } = await personalOauth2Client.getToken({ code, redirect_uri: PERSONAL_REDIRECT_URI });
@@ -486,6 +558,80 @@ app.get('/api/auth-url/stevesclaude', (req, res) => {
   res.json({ authUrl: url, account: STEVESCLAUDE_LOGIN_HINT, scopes: FULL_WORKSPACE_SCOPES });
 });
 
+// ─── Agent Abrams OAuth Authorization Flow ───
+app.get('/auth/agentabrams', (req, res) => {
+  if (!agentabramsOauth2Client) return res.status(500).send('Agent Abrams OAuth client not configured');
+  const url = agentabramsOauth2Client.generateAuthUrl({
+    access_type: 'offline',
+    scope: FULL_WORKSPACE_SCOPES,
+    prompt: 'consent',
+    redirect_uri: AGENTABRAMS_REDIRECT_URI,
+    login_hint: AGENTABRAMS_LOGIN_HINT,
+    state: 'agentabrams',
+  });
+  res.redirect(url);
+});
+
+app.get('/api/auth-url/agentabrams', (req, res) => {
+  if (!agentabramsOauth2Client) return res.status(500).json({ error: 'Agent Abrams OAuth client not configured' });
+  const url = agentabramsOauth2Client.generateAuthUrl({
+    access_type: 'offline',
+    scope: FULL_WORKSPACE_SCOPES,
+    prompt: 'consent',
+    redirect_uri: AGENTABRAMS_REDIRECT_URI,
+    login_hint: AGENTABRAMS_LOGIN_HINT,
+    state: 'agentabrams',
+  });
+  res.json({ authUrl: url, account: AGENTABRAMS_LOGIN_HINT, scopes: FULL_WORKSPACE_SCOPES });
+});
+
+app.get('/api/exchange-code/agentabrams', async (req, res) => {
+  try {
+    const { code } = req.query;
+    if (!code) return res.status(400).json({ error: 'code parameter required' });
+    const { tokens } = await agentabramsOauth2Client.getToken({ code, redirect_uri: AGENTABRAMS_REDIRECT_URI });
+    agentabramsOauth2Client.setCredentials(tokens);
+    agentabramsGmail    = google.gmail   ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsTasksApi = google.tasks   ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsDrive    = google.drive   ({ version: 'v3', auth: agentabramsOauth2Client });
+    agentabramsDocs     = google.docs    ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsSheets   = google.sheets  ({ version: 'v4', auth: agentabramsOauth2Client });
+    agentabramsSlides   = google.slides  ({ version: 'v1', auth: agentabramsOauth2Client });
+    agentabramsCalendar = google.calendar({ version: 'v3', auth: agentabramsOauth2Client });
+    agentabramsForms    = google.forms   ({ version: 'v1', auth: agentabramsOauth2Client });
+
+    const result = { success: true, account: 'agentabrams', hasRefreshToken: !!tokens.refresh_token };
+    if (tokens.refresh_token) {
+      result.refreshToken = tokens.refresh_token;
+      try {
+        let envContent = fs.readFileSync(ENV_PATH, 'utf8');
+        if (envContent.includes('AGENTABRAMS_REFRESH_TOKEN=')) {
+          envContent = envContent.replace(/AGENTABRAMS_REFRESH_TOKEN=.*/, `AGENTABRAMS_REFRESH_TOKEN=${tokens.refresh_token}`);
+        } else {
+          envContent += `\n# Agent Abrams (theagentabrams@gmail.com) OAuth Token\nAGENTABRAMS_REFRESH_TOKEN=${tokens.refresh_token}\n`;
+        }
+        fs.writeFileSync(ENV_PATH, envContent);
+        result.savedToEnv = true;
+        audit('agentabrams', 'oauth-authorized', { scopes: FULL_WORKSPACE_SCOPES.length });
+      } catch (e) {
+        result.savedToEnv = false;
+        result.envError = e.message;
+      }
+    }
+    try {
+      const profile = await agentabramsGmail.users.getProfile({ userId: 'me' });
+      result.email = profile.data.emailAddress;
+      result.ready = true;
+    } catch (e) {
+      result.ready = false;
+      result.testError = e.message;
+    }
+    res.json(result);
+  } catch (e) {
+    res.status(500).json({ error: e.message });
+  }
+});
+
 // ─── Steve Personal OAuth Authorization Flow ───
 app.get('/auth/steve-personal', (req, res) => {
   if (!personalOauth2Client) return res.status(500).send('Personal OAuth client not configured');

← ec801aa george /auth honors ?account= — dispatches to per-account re  ·  back to George Gmail  ·  remove bogus stevesclaude account from George — theagentabra 2cbc311 →