diff --git a/README.md b/README.md index 7ab7b0d..3fbe093 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ and the lessons learned across every project — automatically. `~/.codex/hooks.json` for you. - ðŸŠķ **No runtime deps in hooks** — the hook scripts are pre-bundled with esbuild for fast cold starts. -- 🔧 **Fallback skills** — explicit `/supermemory-search`, `/supermemory-save`, and - `/supermemory-forget` commands available when hooks don't cover your use case. +- 🔧 **Fallback skills** — explicit `/supermemory-search`, `/supermemory-save`, + `/supermemory-forget`, `/supermemory-status`, and `/supermemory-logout` commands available when hooks + don't cover your use case. ## Quick start @@ -132,7 +133,10 @@ All memory skills support `--container ` to target a specific custom contai | `/supermemory-search` | `/supermemory-search [--container ] ` | Search memories manually. | | `/supermemory-save` | `/supermemory-save [--container ] ` | Save a specific memory explicitly. | | `/supermemory-forget` | `/supermemory-forget [--container ] ` | Remove a memory. | +| `/supermemory-profile` | `/supermemory-profile` | Show remembered profile facts. | +| `/supermemory-status` | `/supermemory-status` | Show connection and account status. | | `/supermemory-login` | `/supermemory-login` | Re-authenticate with Supermemory. | +| `/supermemory-logout` | `/supermemory-logout` | Remove saved local credentials. | Skills are fallback commands — the hooks handle most use cases automatically. diff --git a/build.mjs b/build.mjs index a3477dc..d59d18d 100644 --- a/build.mjs +++ b/build.mjs @@ -1,5 +1,5 @@ import * as esbuild from "esbuild"; -import { mkdirSync, writeFileSync, chmodSync, copyFileSync } from "node:fs"; +import { mkdirSync, writeFileSync, chmodSync, copyFileSync, rmSync } from "node:fs"; const sharedConfig = { bundle: true, @@ -16,12 +16,14 @@ const executableEntries = [ in: `src/hooks/${n}.ts`, out: `dist/hooks/${n}.js`, })), - ...["search-memory", "save-memory", "forget-memory", "profile-memory", "login"].map((n) => ({ + ...["search-memory", "save-memory", "forget-memory", "profile-memory", "status", "login", "logout"].map((n) => ({ in: `src/skills/${n}.ts`, out: `dist/skills/${n}.js`, })), ]; +rmSync("dist", { recursive: true, force: true }); + const libraryEntries = [ { in: "src/services/session.ts", out: "dist/services/session.js" }, { in: "src/services/tags.ts", out: "dist/services/tags.js" }, @@ -48,7 +50,7 @@ await Promise.all( ); // Copy SKILL.md files to dist -for (const skillName of ["supermemory-search", "supermemory-save", "supermemory-forget", "supermemory-profile", "supermemory-login"]) { +for (const skillName of ["supermemory-search", "supermemory-save", "supermemory-forget", "supermemory-profile", "supermemory-status", "supermemory-login", "supermemory-logout"]) { mkdirSync(`dist/skills/${skillName}`, { recursive: true }); copyFileSync( `src/skills/${skillName}/SKILL.md`, diff --git a/src/cli.ts b/src/cli.ts index e01450f..bb9b2e0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -45,8 +45,15 @@ const SKILLS = [ { name: "supermemory-search", script: "search-memory.js" }, { name: "supermemory-save", script: "save-memory.js" }, { name: "supermemory-forget", script: "forget-memory.js" }, + { name: "supermemory-status", script: "status.js" }, { name: "supermemory-profile", script: "profile-memory.js" }, { name: "supermemory-login", script: "login.js" }, + { name: "supermemory-logout", script: "logout.js" }, +] as const; + +const LEGACY_SUPERMEMORY_SCRIPTS = [ + "capture.js", + "tags.js", ] as const; const SCRIPT_DIR = getScriptDir(); @@ -267,10 +274,10 @@ function install() { copyFileSync(flushSrc, FLUSH_SCRIPT); copyFileSync(sessionStartSrc, SESSION_START_SCRIPT); - // Remove old capture.js if it exists - const oldCapture = join(SUPERMEMORY_HOOKS_DIR, "capture.js"); - if (existsSync(oldCapture)) { - rmSync(oldCapture); + // Remove script names left by older package layouts. + for (const script of LEGACY_SUPERMEMORY_SCRIPTS) { + const oldScript = join(SUPERMEMORY_HOOKS_DIR, script); + if (existsSync(oldScript)) rmSync(oldScript); } // Copy skill scripts and SKILL.md files @@ -302,7 +309,7 @@ Installation complete! You now have: â€Ē Session-start profile recall (${getRecallModeSummary()}) - â€Ē Explicit memory — supermemory-search, supermemory-save, supermemory-forget, supermemory-profile, supermemory-login + â€Ē Explicit memory — supermemory-search, supermemory-save, supermemory-forget, supermemory-profile, supermemory-status, supermemory-login, and supermemory-logout skills ${hadExistingConfig ? "Existing install: legacy per-prompt recall/capture preserved in ~/.codex/supermemory.json.\nTo opt into new defaults, set autoRecallEveryPrompt=false and captureEveryNTurns=0.\n" @@ -316,7 +323,7 @@ Next steps: /supermemory-login (inside Codex) export SUPERMEMORY_CODEX_API_KEY="sm_..." (in your shell profile) - 2. Get an API key at: https://console.supermemory.ai/keys (if needed) + 2. Get an API key at: https://app.supermemory.ai/?view=integrations (if needed) Optional: Enable debug logging: export SUPERMEMORY_DEBUG=true diff --git a/src/config.ts b/src/config.ts index dfcf5d6..8680506 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,7 +1,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { homedir } from "node:os"; -import { loadCredentials } from "./services/auth.js"; +import { loadCredentialData, loadCredentials } from "./services/auth.js"; export const CONFIG_FILE = join(homedir(), ".codex", "supermemory.json"); export const PLUGIN_VERSION = "1.0.7"; @@ -132,6 +132,15 @@ export function getApiKeyValue(): string | undefined { return SUPERMEMORY_API_KEY; } +export function getApiBaseUrl(): string { + return ( + process.env.SUPERMEMORY_API_URL || + process.env.SUPERMEMORY_BASE_URL || + loadCredentialData()?.apiBaseUrl || + "https://api.supermemory.ai" + ); +} + export function getSignalConfig(): { enabled: boolean; keywords: string[]; diff --git a/src/hooks/recall.ts b/src/hooks/recall.ts index 48bc154..bc87781 100644 --- a/src/hooks/recall.ts +++ b/src/hooks/recall.ts @@ -12,6 +12,7 @@ import { getSeenFacts, addSeenFacts } from "../services/factCache.js"; import { getSessionId } from "../services/session.js"; const AUTH_ATTEMPTED_FILE = join(homedir(), ".codex", "supermemory", ".auth-attempted"); +const LOGGED_OUT_FILE = join(homedir(), ".codex", "supermemory", ".logged-out"); interface CodexHookPayload { session_id?: string; @@ -45,6 +46,11 @@ async function main() { } if (!isConfigured()) { + if (existsSync(LOGGED_OUT_FILE)) { + log("recall: logged out marker present, skipping browser auth"); + exitWithContext(""); + } + const alreadyAttempted = existsSync(AUTH_ATTEMPTED_FILE); if (!alreadyAttempted) { diff --git a/src/services/auth.ts b/src/services/auth.ts index 9e23455..5f5a773 100644 --- a/src/services/auth.ts +++ b/src/services/auth.ts @@ -2,16 +2,21 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs"; import { join } from "node:path"; import { homedir, hostname, platform, arch } from "node:os"; -import { execFile } from "node:child_process"; import { randomBytes } from "node:crypto"; import type { AddressInfo } from "node:net"; +import { openUrl } from "./openUrl.js"; const SUPERMEMORY_DIR = join(homedir(), ".codex", "supermemory"); const CREDENTIALS_FILE = join(SUPERMEMORY_DIR, "credentials.json"); +export interface Credentials { + apiKey?: string; + apiBaseUrl?: string; + savedAt?: string; +} const AUTH_BASE_URL = - process.env.SUPERMEMORY_AUTH_URL || "https://console.supermemory.ai/auth/agent-connect"; -const AUTH_TIMEOUT = Number(process.env.SUPERMEMORY_AUTH_TIMEOUT) || 60_000; + process.env.SUPERMEMORY_AUTH_URL || "https://app.supermemory.ai/auth/agent-connect"; +const AUTH_TIMEOUT = Number(process.env.SUPERMEMORY_AUTH_TIMEOUT) || 5 * 60_000; const AUTH_SUCCESS_HTML = ` Connected - Supermemory