From 0afd8845142367110d0d75e5429c5b66f349d2ef Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Mon, 10 Aug 2026 12:56:12 -0700 Subject: [PATCH] Use /v3/session for status account info instead of probing account lifecycle endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The status command probed /v3/auth/account/memberships (and two other guessed paths) with the user's API key to scrape account info. That endpoint is session-only — every API-key request 403s with 'API keys cannot access account lifecycle endpoints' (Sentry issue SUPERMEMORY-BACKEND-108R, ~1,700 events across 765 users since June). /v3/session is the whoami endpoint that works with API-key auth (it's what the MCP server uses) and returns user email/name/id and org name directly, so the generic JSON scraper is gone too. Bumps to 2.0.12. Co-Authored-By: Claude Fable 5 --- package.json | 2 +- src/cli.ts | 44 +++++++++++++------------------------------- src/version.ts | 2 +- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 70f97e7..a4484f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-supermemory", - "version": "2.0.11", + "version": "2.0.12", "description": "OpenCode plugin that gives coding agents persistent memory using Supermemory", "type": "module", "main": "dist/index.js", diff --git a/src/cli.ts b/src/cli.ts index 031a0c8..bfad2e8 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -554,38 +554,20 @@ async function fetchJson(apiUrl: string, path: string): Promise } } -function findAccountInfo(value: unknown): { email?: string; name?: string; userId?: string; orgName?: string } { - const seen = new Set(); - const stack = [value]; - const result: { email?: string; name?: string; userId?: string; orgName?: string } = {}; - - while (stack.length > 0) { - const item = stack.pop(); - if (!item || typeof item !== "object" || seen.has(item)) continue; - seen.add(item); - - const record = item as Record; - for (const [key, raw] of Object.entries(record)) { - const lower = key.toLowerCase(); - if (!result.email && lower === "email" && typeof raw === "string") result.email = raw; - if (!result.name && lower === "name" && typeof raw === "string") result.name = raw; - if (!result.userId && (lower === "userid" || lower === "user_id") && typeof raw === "string") result.userId = raw; - if (!result.orgName && (lower === "organizationname" || lower === "orgname") && typeof raw === "string") result.orgName = raw; - - if (raw && typeof raw === "object") stack.push(raw); - } - } - - return result; -} - async function getAccountInfo(apiUrl: string): Promise<{ email?: string; name?: string; userId?: string; orgName?: string }> { - for (const path of ["/v3/auth/account/memberships", "/v3/account/memberships", "/v3/me"]) { - const data = await fetchJson(apiUrl, path); - const info = findAccountInfo(data); - if (info.email || info.name || info.userId || info.orgName) return info; - } - return {}; + const data = await fetchJson(apiUrl, "/v3/session"); + if (!data || typeof data !== "object") return {}; + + const session = data as { + user?: { email?: unknown; name?: unknown; id?: unknown }; + org?: { name?: unknown }; + }; + return { + email: typeof session.user?.email === "string" ? session.user.email : undefined, + name: typeof session.user?.name === "string" ? session.user.name : undefined, + userId: typeof session.user?.id === "string" ? session.user.id : undefined, + orgName: typeof session.org?.name === "string" ? session.org.name : undefined, + }; } async function status(): Promise { diff --git a/src/version.ts b/src/version.ts index 8c3e2a0..f987e67 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,3 +1,3 @@ // AUTO-GENERATED by scripts/sync-version.mjs — do not edit by hand. // Sourced from package.json "version" so the two cannot drift. -export const PLUGIN_VERSION = "2.0.11"; +export const PLUGIN_VERSION = "2.0.12";