memoir-cli 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/memoir.js +6 -29
- package/package.json +1 -1
- package/src/commands/push.js +15 -8
- package/src/commands/restore.js +14 -8
- package/src/config.js +45 -0
package/bin/memoir.js
CHANGED
|
@@ -53,41 +53,18 @@ async function checkForUpdate() {
|
|
|
53
53
|
} catch {}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
//
|
|
56
|
+
// When run with no args: auto-push (zero-config)
|
|
57
57
|
if (process.argv.length <= 2) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
chalk.gray(' Your AI remembers everything.') + '\n\n' +
|
|
61
|
-
chalk.white.bold('Quick Start:') + '\n' +
|
|
62
|
-
chalk.cyan(' memoir init ') + chalk.gray('— first-time setup') + '\n' +
|
|
63
|
-
chalk.cyan(' memoir push ') + chalk.gray('— back up your AI memory') + '\n' +
|
|
64
|
-
chalk.cyan(' memoir restore ') + chalk.gray('— restore on a new machine') + '\n' +
|
|
65
|
-
chalk.cyan(' memoir snapshot ') + chalk.gray('— capture your current session') + '\n' +
|
|
66
|
-
chalk.cyan(' memoir resume ') + chalk.gray('— pick up where you left off') + '\n' +
|
|
67
|
-
chalk.cyan(' memoir status ') + chalk.gray('— see detected AI tools') + '\n' +
|
|
68
|
-
chalk.cyan(' memoir profile ') + chalk.gray('— manage profiles (personal/work)') + '\n' +
|
|
69
|
-
chalk.cyan(' memoir projects ') + chalk.gray('— see all your projects at a glance') + '\n' +
|
|
70
|
-
chalk.cyan(' memoir activate ') + chalk.gray('— enable auto-recall in this project') + '\n' +
|
|
71
|
-
chalk.cyan(' memoir encrypt ') + chalk.gray('— toggle E2E encryption') + '\n' +
|
|
72
|
-
chalk.cyan(' memoir update ') + chalk.gray('— update to latest version') + '\n' +
|
|
73
|
-
chalk.cyan(' memoir upgrade ') + chalk.gray('— view plans & upgrade') + '\n\n' +
|
|
74
|
-
chalk.white.bold('Cloud (Pro):') + '\n' +
|
|
75
|
-
chalk.cyan(' memoir login ') + chalk.gray('— sign in to memoir cloud') + '\n' +
|
|
76
|
-
chalk.cyan(' memoir cloud push ') + chalk.gray('— back up to the cloud') + '\n' +
|
|
77
|
-
chalk.cyan(' memoir cloud restore ') + chalk.gray('— restore from cloud') + '\n' +
|
|
78
|
-
chalk.cyan(' memoir share ') + chalk.gray('— share memory via secure link') + '\n' +
|
|
79
|
-
chalk.cyan(' memoir history ') + chalk.gray('— view backup versions') + '\n\n' +
|
|
80
|
-
chalk.gray(' Tip: use --profile work to sync a specific profile') + '\n\n' +
|
|
81
|
-
chalk.gray(`v${VERSION}`),
|
|
82
|
-
{ padding: 1, borderStyle: 'round', borderColor: 'cyan', dimBorder: true }
|
|
83
|
-
) + '\n');
|
|
84
|
-
process.exit(0);
|
|
58
|
+
// Pass 'push' as the command so Commander routes to pushCommand
|
|
59
|
+
process.argv.push('push');
|
|
85
60
|
}
|
|
86
61
|
|
|
87
62
|
// Custom help banner
|
|
88
63
|
program.addHelpText('beforeAll', '\n' + boxen(
|
|
89
64
|
gradient.pastel.multiline(' memoir ') + '\n' +
|
|
90
|
-
chalk.gray(' Your AI remembers everything.')
|
|
65
|
+
chalk.gray(' Your AI remembers everything.') + '\n\n' +
|
|
66
|
+
chalk.white.bold('Zero-config:') + ' just run ' + chalk.cyan('memoir') + ' or ' + chalk.cyan('npx memoir-cli') + '\n' +
|
|
67
|
+
chalk.gray('Auto-detects your GitHub, creates a private repo, and backs up.'),
|
|
91
68
|
{ padding: { top: 0, bottom: 0, left: 1, right: 1 }, borderStyle: 'round', borderColor: 'cyan', dimBorder: true }
|
|
92
69
|
) + '\n');
|
|
93
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memoir-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"mcpName": "io.github.camgitt/memoir",
|
|
5
5
|
"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.",
|
|
6
6
|
"main": "src/index.js",
|
package/src/commands/push.js
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'os';
|
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
import boxen from 'boxen';
|
|
7
7
|
import gradient from 'gradient-string';
|
|
8
|
-
import { getConfig } from '../config.js';
|
|
8
|
+
import { getConfig, autoSetup } from '../config.js';
|
|
9
9
|
import { extractMemories, adapters } from '../adapters/index.js';
|
|
10
10
|
import { syncToLocal, syncToGit } from '../providers/index.js';
|
|
11
11
|
import inquirer from 'inquirer';
|
|
@@ -17,15 +17,22 @@ import { scanWorkspace } from '../workspace/tracker.js';
|
|
|
17
17
|
import { promptActivate } from './activate.js';
|
|
18
18
|
|
|
19
19
|
export async function pushCommand(options = {}) {
|
|
20
|
-
|
|
20
|
+
let config = await getConfig(options.profile);
|
|
21
21
|
|
|
22
22
|
if (!config) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// Zero-config: auto-detect GitHub user, create repo, save config
|
|
24
|
+
const setupSpinner = ora({ text: chalk.gray('Setting up memoir automatically...'), spinner: 'dots' }).start();
|
|
25
|
+
config = await autoSetup();
|
|
26
|
+
if (config) {
|
|
27
|
+
setupSpinner.succeed(chalk.green('Auto-configured') + chalk.gray(` → ${config.gitRepo}`));
|
|
28
|
+
} else {
|
|
29
|
+
setupSpinner.fail(chalk.red('Could not detect GitHub username'));
|
|
30
|
+
console.log('\n' + boxen(
|
|
31
|
+
chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to set up manually.'),
|
|
32
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'yellow' }
|
|
33
|
+
) + '\n');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
console.log();
|
package/src/commands/restore.js
CHANGED
|
@@ -6,7 +6,7 @@ import ora from 'ora';
|
|
|
6
6
|
import boxen from 'boxen';
|
|
7
7
|
import gradient from 'gradient-string';
|
|
8
8
|
import inquirer from 'inquirer';
|
|
9
|
-
import { getConfig } from '../config.js';
|
|
9
|
+
import { getConfig, autoSetup } from '../config.js';
|
|
10
10
|
import { fetchFromLocal, fetchFromGit } from '../providers/restore.js';
|
|
11
11
|
import { decryptDirectory, verifyPassphrase } from '../security/encryption.js';
|
|
12
12
|
import { detectLocalHomeKey } from '../adapters/restore.js';
|
|
@@ -23,15 +23,21 @@ export async function restoreCommand(options = {}) {
|
|
|
23
23
|
return restoreFromShare(options);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
let config = await getConfig(options.profile);
|
|
27
27
|
|
|
28
28
|
if (!config) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const setupSpinner = ora({ text: chalk.gray('Setting up memoir automatically...'), spinner: 'dots' }).start();
|
|
30
|
+
config = await autoSetup();
|
|
31
|
+
if (config) {
|
|
32
|
+
setupSpinner.succeed(chalk.green('Auto-configured') + chalk.gray(` → ${config.gitRepo}`));
|
|
33
|
+
} else {
|
|
34
|
+
setupSpinner.fail(chalk.red('Could not detect GitHub username'));
|
|
35
|
+
console.log('\n' + boxen(
|
|
36
|
+
chalk.white('Run ') + chalk.cyan.bold('memoir init') + chalk.white(' to set up manually.'),
|
|
37
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'yellow' }
|
|
38
|
+
) + '\n');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
console.log();
|
package/src/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import { execFileSync } from 'child_process';
|
|
4
5
|
|
|
5
6
|
const CONFIG_DIR = process.platform === 'win32'
|
|
6
7
|
? path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'memoir')
|
|
@@ -114,6 +115,50 @@ export async function deleteProfile(name) {
|
|
|
114
115
|
await saveConfig(raw);
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
// Zero-config auto-setup: detect GitHub user, create repo, save config, return it
|
|
119
|
+
export async function autoSetup() {
|
|
120
|
+
// Try gh CLI first, then git config
|
|
121
|
+
let username = '';
|
|
122
|
+
try {
|
|
123
|
+
username = execFileSync('gh', ['api', 'user', '--jq', '.login'], { encoding: 'utf8', timeout: 5000 }).trim();
|
|
124
|
+
} catch {
|
|
125
|
+
try {
|
|
126
|
+
username = execFileSync('git', ['config', '--global', 'user.name'], { encoding: 'utf8' }).trim();
|
|
127
|
+
} catch {}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!username) return null; // Can't auto-setup without a username
|
|
131
|
+
|
|
132
|
+
const repo = 'ai-memory';
|
|
133
|
+
const gitRepo = `https://github.com/${username}/${repo}.git`;
|
|
134
|
+
|
|
135
|
+
// Try to create the repo if it doesn't exist (best-effort)
|
|
136
|
+
try {
|
|
137
|
+
execFileSync('gh', ['repo', 'view', `${username}/${repo}`], { stdio: 'ignore', timeout: 5000 });
|
|
138
|
+
} catch {
|
|
139
|
+
try {
|
|
140
|
+
execFileSync('gh', ['repo', 'create', `${username}/${repo}`, '--private', '--description', 'AI memory backup (memoir-cli)'], { stdio: 'ignore', timeout: 10000 });
|
|
141
|
+
} catch {
|
|
142
|
+
// If gh isn't available, user will need to create repo manually — that's fine, syncToGit will handle it
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const config = {
|
|
147
|
+
version: 2,
|
|
148
|
+
activeProfile: 'default',
|
|
149
|
+
profiles: {
|
|
150
|
+
default: {
|
|
151
|
+
provider: 'git',
|
|
152
|
+
gitRepo,
|
|
153
|
+
encrypt: false // Skip encryption for zero-config — user can enable later with `memoir encrypt`
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await saveConfig(config);
|
|
159
|
+
return config.profiles.default;
|
|
160
|
+
}
|
|
161
|
+
|
|
117
162
|
export async function getGeminiApiKey() {
|
|
118
163
|
const raw = await getRawConfig();
|
|
119
164
|
return raw?.geminiApiKey || process.env.GEMINI_API_KEY || null;
|