memoir-cli
Advanced tools
+6
-29
@@ -56,31 +56,6 @@ #!/usr/bin/env node | ||
| // Show quick start when run with no args | ||
| // When run with no args: auto-push (zero-config) | ||
| if (process.argv.length <= 2) { | ||
| console.log('\n' + boxen( | ||
| gradient.pastel.multiline(' memoir ') + '\n' + | ||
| chalk.gray(' Your AI remembers everything.') + '\n\n' + | ||
| chalk.white.bold('Quick Start:') + '\n' + | ||
| chalk.cyan(' memoir init ') + chalk.gray('— first-time setup') + '\n' + | ||
| chalk.cyan(' memoir push ') + chalk.gray('— back up your AI memory') + '\n' + | ||
| chalk.cyan(' memoir restore ') + chalk.gray('— restore on a new machine') + '\n' + | ||
| chalk.cyan(' memoir snapshot ') + chalk.gray('— capture your current session') + '\n' + | ||
| chalk.cyan(' memoir resume ') + chalk.gray('— pick up where you left off') + '\n' + | ||
| chalk.cyan(' memoir status ') + chalk.gray('— see detected AI tools') + '\n' + | ||
| chalk.cyan(' memoir profile ') + chalk.gray('— manage profiles (personal/work)') + '\n' + | ||
| chalk.cyan(' memoir projects ') + chalk.gray('— see all your projects at a glance') + '\n' + | ||
| chalk.cyan(' memoir activate ') + chalk.gray('— enable auto-recall in this project') + '\n' + | ||
| chalk.cyan(' memoir encrypt ') + chalk.gray('— toggle E2E encryption') + '\n' + | ||
| chalk.cyan(' memoir update ') + chalk.gray('— update to latest version') + '\n' + | ||
| chalk.cyan(' memoir upgrade ') + chalk.gray('— view plans & upgrade') + '\n\n' + | ||
| chalk.white.bold('Cloud (Pro):') + '\n' + | ||
| chalk.cyan(' memoir login ') + chalk.gray('— sign in to memoir cloud') + '\n' + | ||
| chalk.cyan(' memoir cloud push ') + chalk.gray('— back up to the cloud') + '\n' + | ||
| chalk.cyan(' memoir cloud restore ') + chalk.gray('— restore from cloud') + '\n' + | ||
| chalk.cyan(' memoir share ') + chalk.gray('— share memory via secure link') + '\n' + | ||
| chalk.cyan(' memoir history ') + chalk.gray('— view backup versions') + '\n\n' + | ||
| chalk.gray(' Tip: use --profile work to sync a specific profile') + '\n\n' + | ||
| chalk.gray(`v${VERSION}`), | ||
| { padding: 1, borderStyle: 'round', borderColor: 'cyan', dimBorder: true } | ||
| ) + '\n'); | ||
| process.exit(0); | ||
| // Pass 'push' as the command so Commander routes to pushCommand | ||
| process.argv.push('push'); | ||
| } | ||
@@ -91,3 +66,5 @@ | ||
| gradient.pastel.multiline(' memoir ') + '\n' + | ||
| chalk.gray(' Your AI remembers everything.'), | ||
| chalk.gray(' Your AI remembers everything.') + '\n\n' + | ||
| chalk.white.bold('Zero-config:') + ' just run ' + chalk.cyan('memoir') + ' or ' + chalk.cyan('npx memoir-cli') + '\n' + | ||
| chalk.gray('Auto-detects your GitHub, creates a private repo, and backs up.'), | ||
| { padding: { top: 0, bottom: 0, left: 1, right: 1 }, borderStyle: 'round', borderColor: 'cyan', dimBorder: true } | ||
@@ -94,0 +71,0 @@ ) + '\n'); |
+1
-1
| { | ||
| "name": "memoir-cli", | ||
| "version": "3.4.0", | ||
| "version": "3.5.0", | ||
| "mcpName": "io.github.camgitt/memoir", | ||
@@ -5,0 +5,0 @@ "description": "MCP server that gives Claude, Cursor, and Gemini long-term memory across sessions. Your AI remembers your codebase, decisions, and preferences — across tools and machines.", |
+15
-8
@@ -8,3 +8,3 @@ import chalk from 'chalk'; | ||
| import gradient from 'gradient-string'; | ||
| import { getConfig } from '../config.js'; | ||
| import { getConfig, autoSetup } from '../config.js'; | ||
| import { extractMemories, adapters } from '../adapters/index.js'; | ||
@@ -21,11 +21,18 @@ import { syncToLocal, syncToGit } from '../providers/index.js'; | ||
| export async function pushCommand(options = {}) { | ||
| const config = await getConfig(options.profile); | ||
| let config = await getConfig(options.profile); | ||
| if (!config) { | ||
| console.log('\n' + boxen( | ||
| chalk.red('✖ Not configured yet\n\n') + | ||
| chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to get started.'), | ||
| { padding: 1, borderStyle: 'round', borderColor: 'red' } | ||
| ) + '\n'); | ||
| return; | ||
| // Zero-config: auto-detect GitHub user, create repo, save config | ||
| const setupSpinner = ora({ text: chalk.gray('Setting up memoir automatically...'), spinner: 'dots' }).start(); | ||
| config = await autoSetup(); | ||
| if (config) { | ||
| setupSpinner.succeed(chalk.green('Auto-configured') + chalk.gray(` → ${config.gitRepo}`)); | ||
| } else { | ||
| setupSpinner.fail(chalk.red('Could not detect GitHub username')); | ||
| console.log('\n' + boxen( | ||
| chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to set up manually.'), | ||
| { padding: 1, borderStyle: 'round', borderColor: 'yellow' } | ||
| ) + '\n'); | ||
| return; | ||
| } | ||
| } | ||
@@ -32,0 +39,0 @@ |
@@ -9,3 +9,3 @@ import chalk from 'chalk'; | ||
| import inquirer from 'inquirer'; | ||
| import { getConfig } from '../config.js'; | ||
| import { getConfig, autoSetup } from '../config.js'; | ||
| import { fetchFromLocal, fetchFromGit } from '../providers/restore.js'; | ||
@@ -27,11 +27,17 @@ import { decryptDirectory, verifyPassphrase } from '../security/encryption.js'; | ||
| const config = await getConfig(options.profile); | ||
| let config = await getConfig(options.profile); | ||
| if (!config) { | ||
| console.log('\n' + boxen( | ||
| chalk.red('✖ Not configured yet\n\n') + | ||
| chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to get started.'), | ||
| { padding: 1, borderStyle: 'round', borderColor: 'red' } | ||
| ) + '\n'); | ||
| return; | ||
| const setupSpinner = ora({ text: chalk.gray('Setting up memoir automatically...'), spinner: 'dots' }).start(); | ||
| config = await autoSetup(); | ||
| if (config) { | ||
| setupSpinner.succeed(chalk.green('Auto-configured') + chalk.gray(` → ${config.gitRepo}`)); | ||
| } else { | ||
| setupSpinner.fail(chalk.red('Could not detect GitHub username')); | ||
| console.log('\n' + boxen( | ||
| chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to set up manually.'), | ||
| { padding: 1, borderStyle: 'round', borderColor: 'yellow' } | ||
| ) + '\n'); | ||
| return; | ||
| } | ||
| } | ||
@@ -38,0 +44,0 @@ |
+45
-0
| import fs from 'fs-extra'; | ||
| import path from 'path'; | ||
| import os from 'os'; | ||
| import { execFileSync } from 'child_process'; | ||
@@ -117,2 +118,46 @@ const CONFIG_DIR = process.platform === 'win32' | ||
| // Zero-config auto-setup: detect GitHub user, create repo, save config, return it | ||
| export async function autoSetup() { | ||
| // Try gh CLI first, then git config | ||
| let username = ''; | ||
| try { | ||
| username = execFileSync('gh', ['api', 'user', '--jq', '.login'], { encoding: 'utf8', timeout: 5000 }).trim(); | ||
| } catch { | ||
| try { | ||
| username = execFileSync('git', ['config', '--global', 'user.name'], { encoding: 'utf8' }).trim(); | ||
| } catch {} | ||
| } | ||
| if (!username) return null; // Can't auto-setup without a username | ||
| const repo = 'ai-memory'; | ||
| const gitRepo = `https://github.com/${username}/${repo}.git`; | ||
| // Try to create the repo if it doesn't exist (best-effort) | ||
| try { | ||
| execFileSync('gh', ['repo', 'view', `${username}/${repo}`], { stdio: 'ignore', timeout: 5000 }); | ||
| } catch { | ||
| try { | ||
| execFileSync('gh', ['repo', 'create', `${username}/${repo}`, '--private', '--description', 'AI memory backup (memoir-cli)'], { stdio: 'ignore', timeout: 10000 }); | ||
| } catch { | ||
| // If gh isn't available, user will need to create repo manually — that's fine, syncToGit will handle it | ||
| } | ||
| } | ||
| const config = { | ||
| version: 2, | ||
| activeProfile: 'default', | ||
| profiles: { | ||
| default: { | ||
| provider: 'git', | ||
| gitRepo, | ||
| encrypt: false // Skip encryption for zero-config — user can enable later with `memoir encrypt` | ||
| } | ||
| } | ||
| }; | ||
| await saveConfig(config); | ||
| return config.profiles.default; | ||
| } | ||
| export async function getGeminiApiKey() { | ||
@@ -119,0 +164,0 @@ const raw = await getRawConfig(); |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
297258
0.17%7081
0.41%35
2.94%