@@ -4,6 +4,7 @@ import { join } from "node:path";
44import { homedir } from "node:os" ;
55import * as readline from "node:readline" ;
66import { stripJsoncComments } from "./services/jsonc.js" ;
7+ import { startAuthFlow , clearCredentials , loadCredentials } from "./services/auth.js" ;
78
89const OPENCODE_CONFIG_DIR = join ( homedir ( ) , ".config" , "opencode" ) ;
910const OPENCODE_COMMAND_DIR = join ( OPENCODE_CONFIG_DIR , "command" ) ;
@@ -162,6 +163,31 @@ Then ask: "I've initialized memory with X insights. Want me to continue refining
1621636. Summarize what was learned and ask if user wants refinement
163164` ;
164165
166+ const SUPERMEMORY_LOGIN_COMMAND = `---
167+ description: Authenticate with Supermemory via browser
168+ ---
169+
170+ # Supermemory Login
171+
172+ Run this command to authenticate the user with Supermemory:
173+
174+ \`\`\`bash
175+ bunx opencode-supermemory@latest login
176+ \`\`\`
177+
178+ This will:
179+ 1. Start a local server on port 19877
180+ 2. Open the browser to Supermemory's authentication page
181+ 3. After the user logs in, save credentials to ~/.supermemory-opencode/credentials.json
182+
183+ Wait for the command to complete, then inform the user whether authentication succeeded or failed.
184+
185+ If the user wants to log out instead, run:
186+ \`\`\`bash
187+ bunx opencode-supermemory@latest logout
188+ \`\`\`
189+ ` ;
190+
165191function createReadline ( ) : readline . Interface {
166192 return readline . createInterface ( {
167193 input : process . stdin ,
@@ -261,12 +287,17 @@ function createNewConfig(): boolean {
261287 return true ;
262288}
263289
264- function createCommand ( ) : boolean {
290+ function createCommands ( ) : boolean {
265291 mkdirSync ( OPENCODE_COMMAND_DIR , { recursive : true } ) ;
266- const commandPath = join ( OPENCODE_COMMAND_DIR , "supermemory-init.md" ) ;
267292
268- writeFileSync ( commandPath , SUPERMEMORY_INIT_COMMAND ) ;
293+ const initPath = join ( OPENCODE_COMMAND_DIR , "supermemory-init.md" ) ;
294+ writeFileSync ( initPath , SUPERMEMORY_INIT_COMMAND ) ;
269295 console . log ( `✓ Created /supermemory-init command` ) ;
296+
297+ const loginPath = join ( OPENCODE_COMMAND_DIR , "supermemory-login.md" ) ;
298+ writeFileSync ( loginPath , SUPERMEMORY_LOGIN_COMMAND ) ;
299+ console . log ( `✓ Created /supermemory-login command` ) ;
300+
270301 return true ;
271302}
272303
@@ -357,17 +388,17 @@ async function install(options: InstallOptions): Promise<number> {
357388 }
358389 }
359390
360- // Step 2: Create /supermemory-init command
361- console . log ( "\nStep 2: Create /supermemory-init command " ) ;
391+ // Step 2: Create commands
392+ console . log ( "\nStep 2: Create /supermemory-init and /supermemory-login commands " ) ;
362393 if ( options . tui ) {
363- const shouldCreate = await confirm ( rl ! , "Add / supermemory-init command ?" ) ;
394+ const shouldCreate = await confirm ( rl ! , "Add supermemory commands ?" ) ;
364395 if ( ! shouldCreate ) {
365396 console . log ( "Skipped." ) ;
366397 } else {
367- createCommand ( ) ;
398+ createCommands ( ) ;
368399 }
369400 } else {
370- createCommand ( ) ;
401+ createCommands ( ) ;
371402 }
372403
373404 // Step 3: Configure Oh My OpenCode (if installed)
@@ -394,34 +425,70 @@ async function install(options: InstallOptions): Promise<number> {
394425 }
395426 }
396427
397- // Step 4: API key instructions
428+ if ( rl ) rl . close ( ) ;
429+
430+ // Step 4: Authenticate
398431 console . log ( "\n" + "─" . repeat ( 50 ) ) ;
399- console . log ( "\n🔑 Final step: Set your API key\n" ) ;
400- console . log ( "Get your API key from: https://console.supermemory.ai" ) ;
401- console . log ( "\nThen add to your shell profile:\n" ) ;
432+ console . log ( "\n🔑 Final step: Authenticate with Supermemory\n" ) ;
433+
434+ if ( options . tui ) {
435+ return login ( ) ;
436+ }
437+
438+ // Non-interactive mode - print instructions
439+ console . log ( "Run this command to authenticate:" ) ;
440+ console . log ( " bunx opencode-supermemory@latest login" ) ;
441+ console . log ( "\nOr set your API key manually:" ) ;
402442 console . log ( ' export SUPERMEMORY_API_KEY="sm_..."' ) ;
403- console . log ( "\nOr create ~/.config/opencode/supermemory.jsonc:\n" ) ;
404- console . log ( ' { "apiKey": "sm_..." }' ) ;
405443 console . log ( "\n" + "─" . repeat ( 50 ) ) ;
406444 console . log ( "\n✓ Setup complete! Restart OpenCode to activate.\n" ) ;
407-
408- if ( rl ) rl . close ( ) ;
409445 return 0 ;
410446}
411447
448+ async function login ( ) : Promise < number > {
449+ const existing = loadCredentials ( ) ;
450+ if ( existing ) {
451+ console . log ( "Already authenticated. Use 'logout' first to re-authenticate." ) ;
452+ return 0 ;
453+ }
454+
455+ const result = await startAuthFlow ( ) ;
456+
457+ if ( result . success ) {
458+ console . log ( "\n✓ Successfully authenticated with Supermemory!" ) ;
459+ console . log ( "Restart OpenCode to activate.\n" ) ;
460+ return 0 ;
461+ } else {
462+ console . error ( `\n✗ Authentication failed: ${ result . error } ` ) ;
463+ return 1 ;
464+ }
465+ }
466+
467+ function logout ( ) : number {
468+ if ( clearCredentials ( ) ) {
469+ console . log ( "✓ Logged out. Credentials cleared." ) ;
470+ return 0 ;
471+ } else {
472+ console . log ( "No credentials found." ) ;
473+ return 0 ;
474+ }
475+ }
476+
412477function printHelp ( ) : void {
413478 console . log ( `
414479opencode-supermemory - Persistent memory for OpenCode agents
415480
416481Commands:
417- install Install and configure the plugin
418- --no-tui Run in non-interactive mode (for LLM agents)
419- --disable-context-recovery Disable Oh My OpenCode's context-window-limit-recovery hook (use with --no-tui)
482+ install Install and configure the plugin
483+ --no-tui Non-interactive mode (for LLM agents)
484+ --disable-context-recovery Disable Oh My OpenCode's context hook
485+ login Authenticate with Supermemory (opens browser)
486+ logout Clear stored credentials
420487
421488Examples:
422489 bunx opencode-supermemory@latest install
423- bunx opencode-supermemory@latest install --no-tui
424- bunx opencode-supermemory@latest install --no-tui --disable-context-recovery
490+ bunx opencode-supermemory@latest login
491+ bunx opencode-supermemory@latest logout
425492` ) ;
426493}
427494
@@ -437,11 +504,14 @@ if (args[0] === "install") {
437504 const disableAutoCompact = args . includes ( "--disable-context-recovery" ) ;
438505 install ( { tui : ! noTui , disableAutoCompact } ) . then ( ( code ) => process . exit ( code ) ) ;
439506} else if ( args [ 0 ] === "setup" ) {
440- // Backwards compatibility
441507 console . log ( "Note: 'setup' is deprecated. Use 'install' instead.\n" ) ;
442508 const noTui = args . includes ( "--no-tui" ) ;
443509 const disableAutoCompact = args . includes ( "--disable-context-recovery" ) ;
444510 install ( { tui : ! noTui , disableAutoCompact } ) . then ( ( code ) => process . exit ( code ) ) ;
511+ } else if ( args [ 0 ] === "login" ) {
512+ login ( ) . then ( ( code ) => process . exit ( code ) ) ;
513+ } else if ( args [ 0 ] === "logout" ) {
514+ process . exit ( logout ( ) ) ;
445515} else {
446516 console . error ( `Unknown command: ${ args [ 0 ] } ` ) ;
447517 printHelp ( ) ;
0 commit comments