memoir-cli 2.0.2 → 2.1.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 CHANGED
@@ -17,6 +17,27 @@ import { createRequire } from 'module';
17
17
  const require = createRequire(import.meta.url);
18
18
  const { version: VERSION } = require('../package.json');
19
19
 
20
+ // Check for updates (non-blocking)
21
+ async function checkForUpdate() {
22
+ try {
23
+ const controller = new AbortController();
24
+ const timeout = setTimeout(() => controller.abort(), 2000);
25
+ const res = await fetch('https://registry.npmjs.org/memoir-cli/latest', { signal: controller.signal });
26
+ clearTimeout(timeout);
27
+ const data = await res.json();
28
+ const latest = data.version;
29
+ if (latest && latest !== VERSION) {
30
+ console.log(
31
+ '\n' + boxen(
32
+ chalk.yellow(`Update available: ${VERSION} → ${chalk.green.bold(latest)}`) + '\n' +
33
+ chalk.gray('Run: ') + chalk.cyan('npm install -g memoir-cli'),
34
+ { padding: { top: 0, bottom: 0, left: 1, right: 1 }, borderStyle: 'round', borderColor: 'yellow', dimBorder: true }
35
+ )
36
+ );
37
+ }
38
+ } catch {}
39
+ }
40
+
20
41
  // Show quick start when run with no args
21
42
  if (process.argv.length <= 2) {
22
43
  console.log('\n' + boxen(
@@ -171,4 +192,8 @@ program
171
192
  }
172
193
  });
173
194
 
195
+ program.hook('postAction', async () => {
196
+ await checkForUpdate();
197
+ });
198
+
174
199
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoir-cli",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Sync AI memory across devices. Back up and restore Claude, Gemini, Codex, Cursor, Copilot, Windsurf configs. Snapshot coding sessions and resume on another machine. Migrate instructions between AI assistants.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -219,6 +219,86 @@ export async function extractMemories(stagingDir, spinner, onlyFilter = null) {
219
219
  }
220
220
  }
221
221
 
222
+ // Scan for per-project AI config files
223
+ if (!onlyFilter || onlyFilter.some(f => 'projects'.includes(f))) {
224
+ spinner.text = `📁 Scanning for project-level AI configs...`;
225
+
226
+ const projectFiles = [
227
+ 'CLAUDE.md', 'GEMINI.md', 'AGENTS.md', '.cursorrules',
228
+ '.github/copilot-instructions.md', '.windsurfrules',
229
+ '.aider.conf.yml', '.clinerules'
230
+ ];
231
+
232
+ const skipDirs = new Set([
233
+ 'node_modules', '.git', '.next', '.vercel', 'dist', 'build',
234
+ '__pycache__', '.venv', 'venv', '.cache', '.npm', '.bun',
235
+ 'Library', '.Trash', 'Applications', 'Pictures', 'Music',
236
+ 'Movies', 'Public', 'Downloads', '.local', '.cargo', '.rustup'
237
+ ]);
238
+
239
+ const projectsDest = path.join(stagingDir, 'projects');
240
+ let projectCount = 0;
241
+ let projectFileCount = 0;
242
+ const projectNames = [];
243
+
244
+ // Walk home dir up to 3 levels deep looking for project markers
245
+ const scanDir = async (dir, depth = 0) => {
246
+ if (depth > 3) return;
247
+ let entries;
248
+ try {
249
+ entries = await fs.readdir(dir, { withFileTypes: true });
250
+ } catch { return; }
251
+
252
+ // Check if this dir has any AI config files
253
+ const foundFiles = [];
254
+ for (const file of projectFiles) {
255
+ const filePath = path.join(dir, file);
256
+ if (await fs.pathExists(filePath)) {
257
+ foundFiles.push(file);
258
+ }
259
+ }
260
+
261
+ if (foundFiles.length > 0 && dir !== home) {
262
+ // This is a project with AI configs
263
+ const projectName = path.basename(dir);
264
+ const projectDestDir = path.join(projectsDest, projectName);
265
+ await fs.ensureDir(projectDestDir);
266
+
267
+ for (const file of foundFiles) {
268
+ const src = path.join(dir, file);
269
+ const dest = path.join(projectDestDir, file);
270
+ await fs.ensureDir(path.dirname(dest));
271
+ await fs.copy(src, dest);
272
+ projectFileCount++;
273
+ }
274
+
275
+ projectCount++;
276
+ projectNames.push(projectName);
277
+ }
278
+
279
+ // Recurse into subdirectories
280
+ for (const entry of entries) {
281
+ if (!entry.isDirectory()) continue;
282
+ if (entry.name.startsWith('.') && entry.name !== '.github') continue;
283
+ if (skipDirs.has(entry.name)) continue;
284
+ await scanDir(path.join(dir, entry.name), depth + 1);
285
+ }
286
+ };
287
+
288
+ await scanDir(home);
289
+
290
+ if (projectCount > 0) {
291
+ const size = await dirSize(projectsDest);
292
+ foundAny = true;
293
+ results.push({
294
+ adapter: { name: `Projects (${projectCount})`, icon: '📁' },
295
+ fileCount: projectFileCount,
296
+ size
297
+ });
298
+ spinner.text = `📁 ${chalk.green(`${projectCount} projects`)} ${chalk.gray(`(${projectFileCount} files, ${formatSize(size)})`)}`;
299
+ }
300
+ }
301
+
222
302
  // Print tree after scanning
223
303
  if (results.length > 0) {
224
304
  spinner.stop();
@@ -168,6 +168,106 @@ export async function restoreMemories(sourceDir, spinner, onlyFilter = null, aut
168
168
  }
169
169
  }
170
170
 
171
+ // Restore per-project AI configs
172
+ const projectsDir = path.join(sourceDir, 'projects');
173
+ if (await fs.pathExists(projectsDir)) {
174
+ const projectEntries = await fs.readdir(projectsDir, { withFileTypes: true });
175
+ const projectDirs = projectEntries.filter(e => e.isDirectory() && e.name !== '.git');
176
+
177
+ if (projectDirs.length > 0) {
178
+ spinner.stop();
179
+ console.log('\n' + chalk.cyan(`📁 Found ${chalk.bold(projectDirs.length + ' project(s)')} with AI configs`));
180
+
181
+ // Try to find matching local project dirs
182
+ const home = os.homedir();
183
+ let totalRestored = 0;
184
+
185
+ for (const proj of projectDirs) {
186
+ const backupProjDir = path.join(projectsDir, proj.name);
187
+ const files = await fs.readdir(backupProjDir);
188
+
189
+ // Search for project on local machine (up to 3 levels deep)
190
+ let localProjDir = null;
191
+ const searchDirs = [home];
192
+ for (const searchDir of searchDirs) {
193
+ const candidate = path.join(searchDir, proj.name);
194
+ if (await fs.pathExists(candidate)) {
195
+ localProjDir = candidate;
196
+ break;
197
+ }
198
+ // Check one level deeper
199
+ try {
200
+ const entries = await fs.readdir(searchDir, { withFileTypes: true });
201
+ for (const e of entries) {
202
+ if (!e.isDirectory() || e.name.startsWith('.')) continue;
203
+ const deeper = path.join(searchDir, e.name, proj.name);
204
+ if (await fs.pathExists(deeper)) {
205
+ localProjDir = deeper;
206
+ break;
207
+ }
208
+ }
209
+ } catch {}
210
+ if (localProjDir) break;
211
+ }
212
+
213
+ if (!localProjDir) {
214
+ console.log(chalk.gray(` ○ ${proj.name} — not found on this machine, skipping`));
215
+ continue;
216
+ }
217
+
218
+ console.log(chalk.white(` 📁 ${proj.name}`) + chalk.gray(` → ${localProjDir}`));
219
+
220
+ let confirm = true;
221
+ if (!autoYes) {
222
+ const answer = await inquirer.prompt([
223
+ {
224
+ type: 'confirm',
225
+ name: 'confirm',
226
+ message: `Restore AI configs to ${proj.name}?`,
227
+ default: true
228
+ }
229
+ ]);
230
+ confirm = answer.confirm;
231
+ }
232
+
233
+ if (confirm) {
234
+ for (const file of files) {
235
+ const src = path.join(backupProjDir, file);
236
+ const dest = path.join(localProjDir, file);
237
+ const stat = await fs.stat(src);
238
+
239
+ if (stat.isDirectory()) {
240
+ await fs.ensureDir(dest);
241
+ await syncFiles(src, dest, { added: [], updated: [], skipped: [] });
242
+ } else {
243
+ if (await fs.pathExists(dest)) {
244
+ const srcStat = await fs.stat(src);
245
+ const destStat = await fs.stat(dest);
246
+ if (srcStat.mtimeMs > destStat.mtimeMs) {
247
+ await fs.copy(src, dest);
248
+ console.log(chalk.yellow(` ↻ ${file}`) + chalk.gray(` (updated)`));
249
+ } else {
250
+ console.log(chalk.gray(` = ${file} (up to date)`));
251
+ }
252
+ } else {
253
+ await fs.ensureDir(path.dirname(dest));
254
+ await fs.copy(src, dest);
255
+ console.log(chalk.green(` + ${file}`) + chalk.gray(` (new)`));
256
+ }
257
+ totalRestored++;
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ if (totalRestored > 0) {
264
+ allResults.push({ name: `Projects (${projectDirs.length})`, icon: '📁', dest: 'various', added: totalRestored, updated: 0 });
265
+ restoredAny = true;
266
+ }
267
+ spinner.start();
268
+ }
269
+ }
270
+
171
271
  // Final recap
172
272
  if (allResults.length > 0) {
173
273
  spinner.stop();
package/SHOW_HN.md DELETED
@@ -1,23 +0,0 @@
1
- Title: Show HN: Memoir – Sync your AI CLI memory across devices and tools
2
-
3
- URL: https://github.com/camgitt/memoir
4
-
5
- Text:
6
-
7
- I got tired of losing my AI setup every time I switched machines. My Claude Code rules, Gemini instructions, Cursor settings — all trapped in hidden dotfiles on one laptop.
8
-
9
- Memoir is a CLI that backs up, restores, and translates your AI memory across devices and tools. It works with Claude Code, Gemini CLI, OpenAI Codex, Cursor, Copilot, Windsurf, and Aider.
10
-
11
- Three commands:
12
-
13
- memoir push # back up AI configs to GitHub or local folder
14
- memoir restore # restore on a new machine
15
- memoir migrate --from claude --to gemini # translate between tools
16
-
17
- The migrate command uses Gemini to intelligently rewrite your instructions — not copy-paste, but actual translation that follows each tool's conventions.
18
-
19
- It only syncs config and instruction files (settings.json, CLAUDE.md, GEMINI.md, etc). Never touches credentials, auth tokens, or .env files.
20
-
21
- npm install -g memoir-cli
22
-
23
- Built with Node.js. MIT licensed. Would love feedback on what tools or workflows to support next.
package/demo.cast DELETED
@@ -1,269 +0,0 @@
1
- {"version":3,"term":{"cols":44,"rows":24,"type":"xterm-256color","theme":{"fg":"#ffffff","bg":"#1e1e1e","palette":"#000000:#990000:#00a600:#999900:#0000b3:#b300b3:#00a6b3:#bfbfbf:#666666:#e60000:#00d900:#e6e600:#0000ff:#e600e6:#00e6e6:#e6e6e6"}},"timestamp":1772934225,"command":"bash demo.sh","env":{"SHELL":"/bin/zsh"}}
2
- [0.036, "o", "\u001b[3J\u001b[H\u001b[2J"]
3
- [0.000, "o", "\r\n"]
4
- [0.000, "o", "\u001b[1;36m memoir — Your AI remembers everything. Sync it everywhere.\u001b[0m\r\n\u001b[0;90m https://github.com/camgitt/memoir\u001b[0m\r\n"]
5
- [2.008, "o", "\r\n\u001b[1;33m# See what AI tools are on this machine\u001b[0m\r\n"]
6
- [1.012, "o", "\r\n\u001b[1;32m❯\u001b[0m "]
7
- [0.000, "o", "n"]
8
- [0.051, "o", "o"]
9
- [0.051, "o", "d"]
10
- [0.051, "o", "e"]
11
- [0.050, "o", " "]
12
- [0.050, "o", "/"]
13
- [0.049, "o", "U"]
14
- [0.050, "o", "s"]
15
- [0.048, "o", "e"]
16
- [0.049, "o", "r"]
17
- [0.048, "o", "s"]
18
- [0.049, "o", "/"]
19
- [0.049, "o", "c"]
20
- [0.050, "o", "a"]
21
- [0.051, "o", "m"]
22
- [0.050, "o", "a"]
23
- [0.049, "o", "r"]
24
- [0.048, "o", "t"]
25
- [0.047, "o", "h"]
26
- [0.050, "o", "u"]
27
- [0.049, "o", "r"]
28
- [0.050, "o", "/"]
29
- [0.050, "o", "m"]
30
- [0.049, "o", "e"]
31
- [0.050, "o", "m"]
32
- [0.052, "o", "o"]
33
- [0.049, "o", "i"]
34
- [0.051, "o", "r"]
35
- [0.050, "o", "/"]
36
- [0.050, "o", "b"]
37
- [0.047, "o", "i"]
38
- [0.050, "o", "n"]
39
- [0.043, "o", "/"]
40
- [0.049, "o", "m"]
41
- [0.049, "o", "e"]
42
- [0.048, "o", "m"]
43
- [0.049, "o", "o"]
44
- [0.050, "o", "i"]
45
- [0.048, "o", "r"]
46
- [0.050, "o", "."]
47
- [0.049, "o", "j"]
48
- [0.049, "o", "s"]
49
- [0.050, "o", " "]
50
- [0.051, "o", "s"]
51
- [0.050, "o", "t"]
52
- [0.049, "o", "a"]
53
- [0.049, "o", "t"]
54
- [0.046, "o", "u"]
55
- [0.049, "o", "s"]
56
- [0.049, "o", "\r\n"]
57
- [0.528, "o", "\r\n"]
58
- [0.002, "o", "\u001b[2m\u001b[36m╭──────────────────────────────────────────╮\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[38;2;116;235;213mm\u001b[39m\u001b[38;2;116;192;235me\u001b[39m\u001b[38;2;116;127;235mm\u001b[39m\u001b[38;2;170;116;235mo\u001b[39m\u001b[38;2;235;116;235mi\u001b[39m\u001b[38;2;235;116;171mr\u001b[39m \u001b[38;2;236;126;116ms\u001b[39m\u001b[38;2;236;191;116mt\u001b[39m\u001b[38;2;215;236;116ma\u001b[39m\u001b[38;2;150;236;116mt\u001b[39m\u001b[38;2;116;236;148mu\u001b[39m\u001b[38;2;116;236;213ms\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[32m✔ Connected\u001b[39m\u001b[90m → \u001b[39m\u001b[36m/var/folders/hz/21xm5f\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[36mzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0E\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[36mpmHHv/memoir-backup\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b"]
59
- [0.000, "o", "[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[1m\u001b[37mAI Tools\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[32m✔ \u001b[39m\u001b[37mGemini CLI\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[32m✔ \u001b[39m\u001b[37mClaude CLI\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[32m✔ \u001b[39m\u001b[37mOpenAI Codex\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[90m○ Cursor\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[90m○ GitHub Copilot\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[90m○ Windsurf\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[32m✔ \u001b[39m\u001b[37mAider\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b["]
60
- [0.000, "o", "2m\u001b[36m│\u001b[39m\u001b[22m \u001b[90m──────────────────────────────\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[37m4 tools ready to sync\u001b[39m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m│\u001b[39m\u001b[22m \u001b[2m\u001b[36m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[36m╰──────────────────────────────────────────╯\u001b[39m\u001b[22m\r\n\r\n"]
61
- [1.510, "o", "\r\n\u001b[1;33m# Back up all AI memory in one command\u001b[0m\r\n"]
62
- [1.010, "o", "\r\n\u001b[1;32m❯\u001b[0m n"]
63
- [0.050, "o", "o"]
64
- [0.049, "o", "d"]
65
- [0.050, "o", "e"]
66
- [0.049, "o", " "]
67
- [0.047, "o", "/"]
68
- [0.050, "o", "U"]
69
- [0.049, "o", "s"]
70
- [0.047, "o", "e"]
71
- [0.049, "o", "r"]
72
- [0.046, "o", "s"]
73
- [0.050, "o", "/"]
74
- [0.049, "o", "c"]
75
- [0.048, "o", "a"]
76
- [0.048, "o", "m"]
77
- [0.048, "o", "a"]
78
- [0.050, "o", "r"]
79
- [0.046, "o", "t"]
80
- [0.050, "o", "h"]
81
- [0.047, "o", "u"]
82
- [0.045, "o", "r"]
83
- [0.046, "o", "/"]
84
- [0.051, "o", "m"]
85
- [0.049, "o", "e"]
86
- [0.048, "o", "m"]
87
- [0.048, "o", "o"]
88
- [0.047, "o", "i"]
89
- [0.047, "o", "r"]
90
- [0.047, "o", "/"]
91
- [0.048, "o", "b"]
92
- [0.049, "o", "i"]
93
- [0.049, "o", "n"]
94
- [0.047, "o", "/"]
95
- [0.050, "o", "m"]
96
- [0.049, "o", "e"]
97
- [0.049, "o", "m"]
98
- [0.050, "o", "o"]
99
- [0.046, "o", "i"]
100
- [0.047, "o", "r"]
101
- [0.049, "o", "."]
102
- [0.047, "o", "j"]
103
- [0.050, "o", "s"]
104
- [0.047, "o", " "]
105
- [0.049, "o", "p"]
106
- [0.049, "o", "u"]
107
- [0.047, "o", "s"]
108
- [0.049, "o", "h"]
109
- [0.050, "o", "\r\n"]
110
- [0.441, "o", "\r\n"]
111
- [0.007, "o", "\u001b[?25l"]
112
- [0.000, "o", "\u001b[1G"]
113
- [0.000, "o", "\u001b[1G"]
114
- [0.000, "o", "\u001b[36m⠋\u001b[39m \u001b[90mScanning for AI tools...\u001b[39m"]
115
- [0.008, "o", "\u001b[1G"]
116
- [0.000, "o", "\u001b[0K"]
117
- [0.000, "o", "\u001b[?25h"]
118
- [0.000, "o", "\r\n"]
119
- [0.000, "o", "\u001b[37m\u001b[1m Detected AI tools:\u001b[22m\u001b[39m\r\n\u001b[37m\u001b[1m\u001b[22m\u001b[39m\r\n ├─ 🔵 \u001b[36mGemini CLI\u001b[39m\u001b[90m 3 files, 237B\u001b[39m\r\n"]
120
- [0.000, "o", " ├─ 🟣 \u001b[36mClaude CLI\u001b[39m\u001b[90m 3 files, 334B\u001b[39m\r\n ├─ 🟢 \u001b[36mOpenAI Codex\u001b[39m\u001b[90m 2 files, 90B\u001b[39m\r\n └─ 🔧 \u001b[36mAider\u001b[39m\u001b[90m 1 files, 49B\u001b[39m\r\n\r\n"]
121
- [0.000, "o", "\u001b[?25l"]
122
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m \u001b[90mUploading...\u001b[39m"]
123
- [0.002, "o", "\u001b[1G\u001b[0K"]
124
- [0.000, "o", "\u001b[?25h"]
125
- [0.000, "o", "\u001b[32m✔\u001b[39m \u001b[32mSync complete! \u001b[39m\u001b[90m(Saved to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/memoir-backup)\u001b[39m\r\n\u001b[1G"]
126
- [0.000, "o", "\u001b[?25h"]
127
- [0.002, "o", "\r\n\u001b[2m\u001b[32m╭──────────────────────────────────────────╮\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[38;2;116;235;213mB\u001b[39m\u001b[38;2;116;168;235ma\u001b[39m\u001b[38;2;153;116;235mc\u001b[39m\u001b[38;2;235;116;228mk\u001b[39m\u001b[38;2;235;116;138me\u001b[39m\u001b[38;2;236;183;116md\u001b[39m \u001b[38;2;199;236;116mu\u001b[39m\u001b[38;2;116;236;123mp\u001b[39m\u001b[38;2;116;236;213m!\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[36m✔ Gemini CLI\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[36m✔ Claude CLI\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[36m✔ OpenAI Codex\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[36m✔ Aider\u001b[39m \u001b[2m\u001b[32m│\u001b"]
128
- [0.000, "o", "[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[37m9 files from 4 tools\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90m→ /var/folders/hz/21xm5fzj4b93bbv25b\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90m7jnjyr0000gn/T/tmp.GvJ0EpmHHv/memoir\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90m-backup\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90mRestore on another machine with:\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90m\u001b[39m\u001b[36mmemoir restore\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m╰──────────────────────────────────────────╯\u001b[39m\u001b[2"]
129
- [0.000, "o", "2m\r\n\r\n"]
130
- [0.002, "o", "\u001b[?25h"]
131
- [1.509, "o", "\r\n\u001b[1;33m# Now simulate switching to a new machine...\u001b[0m\r\n"]
132
- [2.034, "o", "\u001b[1;31m [wiped all AI configs]\u001b[0m\r\n"]
133
- [1.509, "o", "\r\n\u001b[1;33m# Restore everything on the new machine\u001b[0m\r\n"]
134
- [1.010, "o", "\r\n\u001b[1;32m❯\u001b[0m "]
135
- [0.000, "o", "n"]
136
- [0.047, "o", "o"]
137
- [0.047, "o", "d"]
138
- [0.048, "o", "e"]
139
- [0.049, "o", " "]
140
- [0.050, "o", "/"]
141
- [0.047, "o", "U"]
142
- [0.050, "o", "s"]
143
- [0.049, "o", "e"]
144
- [0.046, "o", "r"]
145
- [0.049, "o", "s"]
146
- [0.050, "o", "/"]
147
- [0.045, "o", "c"]
148
- [0.050, "o", "a"]
149
- [0.049, "o", "m"]
150
- [0.048, "o", "a"]
151
- [0.047, "o", "r"]
152
- [0.047, "o", "t"]
153
- [0.047, "o", "h"]
154
- [0.047, "o", "u"]
155
- [0.048, "o", "r"]
156
- [0.046, "o", "/"]
157
- [0.050, "o", "m"]
158
- [0.049, "o", "e"]
159
- [0.049, "o", "m"]
160
- [0.047, "o", "o"]
161
- [0.049, "o", "i"]
162
- [0.045, "o", "r"]
163
- [0.049, "o", "/"]
164
- [0.046, "o", "b"]
165
- [0.049, "o", "i"]
166
- [0.050, "o", "n"]
167
- [0.049, "o", "/"]
168
- [0.050, "o", "m"]
169
- [0.050, "o", "e"]
170
- [0.049, "o", "m"]
171
- [0.049, "o", "o"]
172
- [0.049, "o", "i"]
173
- [0.049, "o", "r"]
174
- [0.050, "o", "."]
175
- [0.048, "o", "j"]
176
- [0.049, "o", "s"]
177
- [0.049, "o", " "]
178
- [0.051, "o", "r"]
179
- [0.046, "o", "e"]
180
- [0.050, "o", "s"]
181
- [0.048, "o", "t"]
182
- [0.050, "o", "o"]
183
- [0.049, "o", "r"]
184
- [0.050, "o", "e"]
185
- [0.049, "o", " "]
186
- [0.049, "o", "-"]
187
- [0.049, "o", "-"]
188
- [0.049, "o", "y"]
189
- [0.048, "o", "e"]
190
- [0.049, "o", "s"]
191
- [0.044, "o", "\r\n"]
192
- [0.446, "o", "\r\n"]
193
- [0.007, "o", "\u001b[?25l"]
194
- [0.000, "o", "\u001b[1G"]
195
- [0.000, "o", "\u001b[1G"]
196
- [0.001, "o", "\u001b[36m⠋\u001b[39m \u001b[90mFetching memories from local storage...\u001b[39m"]
197
- [0.005, "o", "\u001b[1G"]
198
- [0.000, "o", "\u001b[0K"]
199
- [0.000, "o", "\u001b[?25h"]
200
- [0.000, "o", "\r\n\u001b[36m🔵 Found backup for \u001b[1mGemini CLI\u001b[22m\u001b[39m\r\n"]
201
- [0.000, "o", "\u001b[90m Will restore to: /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini\u001b[39m\r\n"]
202
- [0.000, "o", "\u001b[32m Auto-restoring Gemini CLI...\u001b[39m\r\n\u001b[?25l"]
203
- [0.000, "o", "\u001b[1G"]
204
- [0.000, "o", "\u001b[36m⠋\u001b[39m Fetching data from local directory: \u001b[36m/var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/memoir-backup\u001b[39m"]
205
- [0.001, "o", "\u001b[1G\u001b[0K"]
206
- [0.000, "o", "\u001b[1A\u001b[0K\u001b[1A\u001b[0K\u001b[?25h"]
207
- [0.000, "o", "\u001b[32m\u001b[1m\u001b[22m\u001b[39m\r\n\u001b[32m\u001b[1m 🔵 Gemini CLI — 3 file(s) restored to \u001b[4m/var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini\u001b[24m\u001b[22m\u001b[39m\r\n"]
208
- [0.000, "o", "\u001b[32m + GEMINI.md\u001b[39m\u001b[90m (new)\u001b[39m\r\n"]
209
- [0.000, "o", "\u001b[32m + projects.json\u001b[39m\u001b[90m (new)\u001b[39m\r\n"]
210
- [0.000, "o", "\u001b[32m + settings.json\u001b[39m\u001b[90m (new)\u001b[39m\r\n\u001b[?25l"]
211
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mGemini CLI\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini..."]
212
- [0.000, "o", "\u001b[1G\u001b[0K\u001b[1A\u001b[0K\u001b[1A"]
213
- [0.000, "o", "\u001b[0K\u001b[?25h"]
214
- [0.000, "o", "\r\n\u001b[36m🟣 Found backup for \u001b[1mClaude CLI\u001b[22m\u001b[39m\r\n\u001b[90m Will restore to: /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.claude\u001b[39m\r\n"]
215
- [0.000, "o", "\u001b[32m Auto-restoring Claude CLI...\u001b[39m\r\n"]
216
- [0.000, "o", "\u001b[?25l"]
217
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mGemini CLI\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini..."]
218
- [0.001, "o", "\u001b[1G\u001b[0K\u001b[1A\u001b[0K\u001b[1A"]
219
- [0.000, "o", "\u001b[0K"]
220
- [0.000, "o", "\u001b[?25h"]
221
- [0.000, "o", "\u001b[90m Remapping project path: -Users-dev → -var-folders-hz-21xm5fzj4b93bbv25b7jnjyr0000gn-T-tmp.GvJ0EpmHHv\u001b[39m\r\n\u001b[?25l"]
222
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mGemini CLI\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini..."]
223
- [0.001, "o", "\u001b[1G\u001b[0K\u001b[1A"]
224
- [0.000, "o", "\u001b[0K\u001b[1A\u001b[0K"]
225
- [0.000, "o", "\u001b[?25h"]
226
- [0.001, "o", "\u001b[32m\u001b[1m\u001b[22m\u001b[39m\r\n\u001b[32m\u001b[1m 🟣 Claude CLI — 3 file(s) restored to \u001b[4m/var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.claude\u001b[24m\u001b[22m\u001b[39m\r\n\u001b[32m + projects/-var-folders-hz-21xm5fzj4b93bbv25b7jnjyr0000gn-T-tmp.GvJ0EpmHHv/webapp/CLAUDE.md\u001b[39m\u001b[90m (new)\u001b[39m\r\n\u001b[32m + projects/-var-folders-hz-21xm5fzj4b93bbv25b7jnjyr0000gn-T-tmp.GvJ0EpmHHv/webapp/memory/MEMORY.md\u001b[39m\u001b[90m (new)\u001b[39m\r\n\u001b[32m + settings.json\u001b[39m\u001b[90m (new)\u001b[39m\r\n\u001b[?25l\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mClaude CLI\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.claude..."]
227
- [0.000, "o", "\u001b[1G\u001b[0K\u001b[1A\u001b[0K\u001b[1A\u001b[0K\u001b[?25h"]
228
- [0.000, "o", "\r\n\u001b[36m🟢 Found backup for \u001b[1mOpenAI Codex\u001b[22m\u001b[39m\r\n\u001b[90m Will restore to: /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex\u001b[39m\r\n"]
229
- [0.000, "o", "\u001b[32m Auto-restoring OpenAI Codex...\u001b[39m\r\n"]
230
- [0.000, "o", "\u001b[?25l"]
231
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mClaude CLI\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.claude..."]
232
- [0.000, "o", "\u001b[1G\u001b[0K\u001b[1A\u001b[0K\u001b[1A\u001b[0K\u001b[?25h"]
233
- [0.000, "o", "\u001b[32m\u001b[1m\u001b[22m\u001b[39m\r\n\u001b[32m\u001b[1m 🟢 OpenAI Codex — 2 file(s) restored to \u001b[4m/var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex\u001b[24m\u001b[22m\u001b[39m\r\n\u001b[32m + config.json\u001b[39m\u001b[90m (new)\u001b[39m\r\n"]
234
- [0.000, "o", "\u001b[32m + instructions.md\u001b[39m\u001b[90m (new)\u001b[39m\r\n\u001b[?25l"]
235
- [0.001, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mOpenAI Codex\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex..."]
236
- [0.000, "o", "\u001b[1G\u001b[0K"]
237
- [0.000, "o", "\u001b[1A\u001b[0K\u001b[1A"]
238
- [0.000, "o", "\u001b[0K"]
239
- [0.000, "o", "\u001b[?25h"]
240
- [0.000, "o", "\r\n\u001b[36m🔧 Found backup for \u001b[1mAider\u001b[22m\u001b[39m\r\n\u001b[90m Will restore to: /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv\u001b[39m\r\n"]
241
- [0.000, "o", "\u001b[32m Auto-restoring Aider...\u001b[39m\r\n"]
242
- [0.000, "o", "\u001b[?25l"]
243
- [0.000, "o", "\u001b[1G\u001b[36m⠋\u001b[39m Restoring \u001b[36mOpenAI Codex\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex..."]
244
- [0.000, "o", "\u001b[1G\u001b[0K\u001b[1A\u001b[0K\u001b[1A"]
245
- [0.000, "o", "\u001b[0K\u001b[?25h"]
246
- [0.000, "o", "\u001b[32m\u001b[1m\u001b[22m\u001b[39m\r\n\u001b[32m\u001b[1m 🔧 Aider — 1 file(s) restored to \u001b[4m/var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv\u001b[24m\u001b[22m\u001b[39m\r\n"]
247
- [0.000, "o", "\u001b[32m + .aider.conf.yml\u001b[39m\u001b[90m (new)\u001b[39m\r\n"]
248
- [0.000, "o", "\u001b[?25l"]
249
- [0.000, "o", "\u001b[1G"]
250
- [0.000, "o", "\u001b[36m⠋\u001b[39m Restoring \u001b[36mOpenAI Codex\u001b[39m to /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex..."]
251
- [0.000, "o", "\u001b[1G\u001b[0K\u001b[1A"]
252
- [0.000, "o", "\u001b[0K\u001b[1A\u001b[0K"]
253
- [0.000, "o", "\u001b[?25h"]
254
- [0.000, "o", "\r\n\u001b[90m────────────────────────────────────────\u001b[39m\r\n"]
255
- [0.000, "o", "\u001b[1m\u001b[37m\u001b[39m\u001b[22m\r\n\u001b[1m\u001b[37m Restore Summary:\u001b[39m\u001b[22m\r\n\u001b[1m\u001b[37m\u001b[39m\u001b[22m\r\n"]
256
- [0.000, "o", " 🔵 \u001b[37mGemini CLI\u001b[39m\r\n\u001b[90m 3 file(s) → /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.gemini\u001b[39m\r\n"]
257
- [0.000, "o", " 🟣 \u001b[37mClaude CLI\u001b[39m\r\n"]
258
- [0.000, "o", "\u001b[90m 3 file(s) → /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.claude\u001b[39m\r\n"]
259
- [0.000, "o", " 🟢 \u001b[37mOpenAI Codex\u001b[39m\r\n"]
260
- [0.000, "o", "\u001b[90m 2 file(s) → /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv/.codex\u001b[39m\r\n 🔧 \u001b[37mAider\u001b[39m\r\n\u001b[90m 1 file(s) → /var/folders/hz/21xm5fzj4b93bbv25b7jnjyr0000gn/T/tmp.GvJ0EpmHHv\u001b[39m\r\n"]
261
- [0.000, "o", "\r\n\u001b[1G"]
262
- [0.000, "o", "\u001b[?25h"]
263
- [0.001, "o", "\u001b[2m\u001b[32m╭──────────────────────────────────────────╮\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[38;2;116;235;213mD\u001b[39m\u001b[38;2;153;116;235mo\u001b[39m\u001b[38;2;235;116;138mn\u001b[39m\u001b[38;2;199;236;116me\u001b[39m\u001b[38;2;116;236;213m!\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[37mYour AI tools have their memories\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[37mback.\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90mRestart your AI tools to pick up the\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[90mchanges.\u001b[39m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[32m│\u001b[39m\u001b[22m \u001b[2m\u001b[32m│\u001b[39m\u001b[22m\r\n\u001b[2m\u001b[3"]
264
- [0.000, "o", "2m╰──────────────────────────────────────────╯\u001b[39m\u001b[22m\r\n\r\n"]
265
- [0.001, "o", "\u001b[?25h"]
266
- [1.508, "o", "\r\n\u001b[1;33m# All done. 11 files restored across 4 tools in seconds.\u001b[0m\r\n"]
267
- [2.015, "o", "\r\n\u001b[1;32m npm install -g memoir-cli\u001b[0m\r\n"]
268
- [0.000, "o", "\u001b[0;90m Works with Claude, Gemini, Codex, Cursor, Copilot, Windsurf, and Aider.\u001b[0m\r\n\r\n"]
269
- [3.025, "x", "0"]
package/demo.gif DELETED
Binary file
package/demo.sh DELETED
@@ -1,99 +0,0 @@
1
- #!/bin/bash
2
- # Scripted demo for asciinema recording
3
- # Usage: asciinema rec demo.cast -c "bash demo.sh"
4
-
5
- # Simulate typing with a delay
6
- type_cmd() {
7
- local cmd="$1"
8
- echo ""
9
- echo -ne "\033[1;32m❯\033[0m "
10
- for ((i=0; i<${#cmd}; i++)); do
11
- echo -n "${cmd:$i:1}"
12
- sleep 0.04
13
- done
14
- echo ""
15
- sleep 0.3
16
- eval "$cmd"
17
- sleep 1.5
18
- }
19
-
20
- narrate() {
21
- echo ""
22
- echo -e "\033[1;33m# $1\033[0m"
23
- sleep 1
24
- }
25
-
26
- export FAKE_HOME=$(mktemp -d)
27
- export BACKUP_DIR="$FAKE_HOME/memoir-backup"
28
- MEMOIR_BIN="$(cd "$(dirname "$0")" && pwd)/bin/memoir.js"
29
-
30
- # Pre-setup: create mock configs and memoir config silently
31
- mkdir -p "$FAKE_HOME/.gemini"
32
- echo '{ "theme": "dark", "model": "gemini-2.5-pro" }' > "$FAKE_HOME/.gemini/settings.json"
33
- cat > "$FAKE_HOME/.gemini/GEMINI.md" << 'EOF'
34
- # My Gemini Instructions
35
- Always use TypeScript. Prefer functional patterns. Keep responses concise.
36
- Never use `any` type. Always handle errors explicitly.
37
- EOF
38
- echo '{ "recent": ["/home/dev/webapp"] }' > "$FAKE_HOME/.gemini/projects.json"
39
-
40
- mkdir -p "$FAKE_HOME/.claude/projects/-Users-dev/webapp/memory"
41
- echo '{ "permissions": { "allow": ["Read", "Write", "Bash"] } }' > "$FAKE_HOME/.claude/settings.json"
42
- cat > "$FAKE_HOME/.claude/projects/-Users-dev/webapp/CLAUDE.md" << 'EOF'
43
- # Project: webapp
44
- Next.js 15 app with Supabase backend. Always use server components.
45
- Database schema is in /supabase/migrations. Run tests before committing.
46
- EOF
47
- cat > "$FAKE_HOME/.claude/projects/-Users-dev/webapp/memory/MEMORY.md" << 'EOF'
48
- # Memory
49
- - User prefers Tailwind CSS v4
50
- - Auth is handled by Supabase Auth with Google OAuth
51
- - Deploy target: Vercel
52
- EOF
53
-
54
- mkdir -p "$FAKE_HOME/.codex"
55
- echo '{ "model": "codex-1", "approval": "auto" }' > "$FAKE_HOME/.codex/config.json"
56
- echo 'Use Python 3.12. Follow PEP 8. Prefer pathlib.' > "$FAKE_HOME/.codex/instructions.md"
57
-
58
- cat > "$FAKE_HOME/.aider.conf.yml" << 'EOF'
59
- model: claude-opus-4-20250514
60
- auto-commits: true
61
- EOF
62
-
63
- mkdir -p "$FAKE_HOME/.config/memoir"
64
- echo "{ \"provider\": \"local\", \"localPath\": \"$BACKUP_DIR\" }" > "$FAKE_HOME/.config/memoir/config.json"
65
- mkdir -p "$BACKUP_DIR"
66
-
67
- export HOME="$FAKE_HOME"
68
-
69
- clear
70
- echo ""
71
- echo -e "\033[1;36m memoir — Your AI remembers everything. Sync it everywhere.\033[0m"
72
- echo -e "\033[0;90m https://github.com/camgitt/memoir\033[0m"
73
- sleep 2
74
-
75
- narrate "See what AI tools are on this machine"
76
- type_cmd "node $MEMOIR_BIN status"
77
-
78
- narrate "Back up all AI memory in one command"
79
- type_cmd "node $MEMOIR_BIN push"
80
-
81
- narrate "Now simulate switching to a new machine..."
82
- sleep 1
83
- rm -rf "$FAKE_HOME/.gemini" "$FAKE_HOME/.claude" "$FAKE_HOME/.codex"
84
- rm -f "$FAKE_HOME/.aider.conf.yml"
85
- echo -e "\033[1;31m [wiped all AI configs]\033[0m"
86
- sleep 1.5
87
-
88
- narrate "Restore everything on the new machine"
89
- type_cmd "node $MEMOIR_BIN restore --yes"
90
-
91
- narrate "All done. 11 files restored across 4 tools in seconds."
92
- sleep 1
93
- echo ""
94
- echo -e "\033[1;32m npm install -g memoir-cli\033[0m"
95
- echo -e "\033[0;90m Works with Claude, Gemini, Codex, Cursor, Copilot, Windsurf, and Aider.\033[0m"
96
- echo ""
97
- sleep 3
98
-
99
- rm -rf "$FAKE_HOME"