memoir-cli 3.1.0 → 3.1.1

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/README.md CHANGED
@@ -2,43 +2,59 @@
2
2
 
3
3
  # memoir
4
4
 
5
- **Sync your AI memory across every device and every tool.**
5
+ **Your AI remembers everything. On every machine.**
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/memoir-cli.svg?style=flat-square&color=7c6ef0)](https://npmjs.org/package/memoir-cli)
8
8
  [![npm downloads](https://img.shields.io/npm/dm/memoir-cli.svg?style=flat-square&color=7c6ef0)](https://npmjs.org/package/memoir-cli)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
10
10
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](https://nodejs.org)
11
11
 
12
- Your AI tools forget you on every new machine. memoir fixes that.
12
+ Close your laptop. Open another one. **Your AI picks up exactly where you left off.**
13
13
 
14
14
  [Website](https://memoir.sh) • [npm](https://npmjs.org/package/memoir-cli) • [Blog](https://memoir.sh/blog)
15
15
 
16
16
  <br />
17
17
 
18
- ![memoir demo](demo.gif)
19
-
20
18
  </div>
21
19
 
22
- ## Why memoir
20
+ ## The Problem
23
21
 
24
- You spend weeks teaching your AI tools how you code. Your CLAUDE.md is dialed in. Your .cursorrules are perfect. Your ChatGPT custom instructions know your stack.
22
+ You spend weeks teaching Claude how you code. Your projects are dialed in. Your AI knows your stack, your decisions, your preferences.
25
23
 
26
- Then you get a new laptop. **Everything is gone.**
24
+ Then you switch machines. **Everything is gone.** Your AI has amnesia. Your projects aren't there. You start from zero.
27
25
 
28
- memoir backs up, restores, and **translates** your AI memory across any machine and any tool. One command to save. One command to restore.
26
+ ## The Fix
29
27
 
30
28
  ```bash
29
+ # On your main machine
30
+ memoir push
31
+
32
+ # On any other machine
31
33
  npm install -g memoir-cli
34
+ memoir restore -y
35
+
36
+ # Done. Everything's back:
37
+ # ✔ AI memory restored (Claude, Gemini, Cursor, 11 tools)
38
+ # ✔ 44 projects cloned & unpacked
39
+ # ✔ Uncommitted changes applied
40
+ # ✔ Session context injected — AI picks up mid-conversation
32
41
  ```
33
42
 
34
- ## Supported Tools (11)
43
+ One command to save. One command to restore. That's it.
44
+
45
+ ## What Gets Synced
46
+
47
+ memoir syncs three layers that no other tool connects:
48
+
49
+ ### Layer 1: AI Memory
50
+ Your AI tool configs, preferences, and project knowledge across 11 tools.
35
51
 
36
52
  | Tool | What gets synced |
37
53
  |------|-----------------|
38
- | **ChatGPT** | CHATGPT.md custom instructions |
39
54
  | **Claude Code** | ~/.claude/ settings, memory, CLAUDE.md files |
40
55
  | **Gemini CLI** | ~/.gemini/ config, GEMINI.md files |
41
- | **OpenAI Codex** | ~/.codex/ config, AGENTS.md, codex.md |
56
+ | **ChatGPT** | CHATGPT.md custom instructions |
57
+ | **OpenAI Codex** | ~/.codex/ config, AGENTS.md |
42
58
  | **Cursor** | Settings, keybindings, .cursorrules |
43
59
  | **GitHub Copilot** | Config, copilot-instructions.md |
44
60
  | **Windsurf** | Settings, keybindings, .windsurfrules |
@@ -47,7 +63,37 @@ npm install -g memoir-cli
47
63
  | **Continue.dev** | Config, .continuerules |
48
64
  | **Aider** | .aider.conf.yml, system prompt |
49
65
 
50
- Plus **per-project configs** memoir scans your filesystem for CLAUDE.md, GEMINI.md, CHATGPT.md, .cursorrules, and AGENTS.md across all your projects.
66
+ ### Layer 2: Session State
67
+ What you were **doing** — not just what your AI knows, but the active context.
68
+
69
+ - Last coding session captured automatically
70
+ - What files you changed, what errors you hit, what decisions you made
71
+ - Injected into your AI on restore so it picks up mid-conversation
72
+ - Secrets auto-redacted (API keys, tokens, passwords stripped before sync)
73
+
74
+ ### Layer 3: Workspace (NEW in v3.1)
75
+ Your actual projects — code, files, everything.
76
+
77
+ - **Git projects:** Remote URLs saved, auto-cloned on restore
78
+ - **Non-git projects:** Bundled as compressed archives, unpacked on restore
79
+ - **Uncommitted work:** Saved as patches, applied after clone
80
+ - **Zero git commands needed** — memoir handles it all
81
+
82
+ ```
83
+ memoir push on Mac:
84
+ ✔ AI memory backed up
85
+ ✔ Session context captured
86
+ ✔ Workspace: 44 projects (17 git, 23 bundled)
87
+ 🔒 E2E encrypted
88
+
89
+ memoir restore on Windows:
90
+ ✔ AI memory restored
91
+ ✔ stock-market-book → C:\Users\You\stock-market-book (cloned)
92
+ ✔ socialslink → C:\Users\You\socialslink (cloned)
93
+ ✔ btc-trader → C:\Users\You\btc-trader (unpacked)
94
+ ✔ 41 more projects restored
95
+ 📋 Session context injected — Claude picks up where you left off
96
+ ```
51
97
 
52
98
  ## Quick Start
53
99
 
@@ -55,41 +101,52 @@ Plus **per-project configs** — memoir scans your filesystem for CLAUDE.md, GEM
55
101
  # Install
56
102
  npm install -g memoir-cli
57
103
 
58
- # First-time setup (GitHub repo or local)
104
+ # First-time setup
59
105
  memoir init
60
106
 
61
- # Back up all your AI configs
107
+ # Back up everything
62
108
  memoir push
63
109
 
64
- # Restore on a new machine
110
+ # Restore on any machine
65
111
  memoir restore
66
112
  ```
67
113
 
68
- That's it. Every AI tool gets its memory back.
69
-
70
114
  ## Key Features
71
115
 
72
- ### Translate between AI tools
116
+ ### Workspace sync
73
117
  ```bash
74
- memoir migrate --from chatgpt --to claude
75
- # AI-powered rewrites conventions, not copy-paste
118
+ memoir push # scans all projects, saves git URLs + bundles non-git projects
119
+ memoir restore # auto-clones repos, unpacks bundles, applies uncommitted patches
76
120
  ```
77
121
 
78
- Works between any combination: ChatGPT, Claude, Gemini, Cursor, Copilot, Codex, Windsurf, Aider, and more. Translate to one tool or all at once:
122
+ No manual git commands. memoir detects your projects, tracks their remotes, and restores them anywhere.
79
123
 
124
+ ### Translate between AI tools
80
125
  ```bash
126
+ memoir migrate --from chatgpt --to claude
127
+ # AI-powered — rewrites conventions, not copy-paste
128
+
81
129
  memoir migrate --from chatgpt --to all
130
+ # Translate to every tool at once
82
131
  ```
83
132
 
84
133
  ### Session handoff
85
134
  ```bash
86
- # Laptop dying? Capture your session
135
+ # Capture your session (automatic on push, or manual)
87
136
  memoir snapshot
88
137
 
89
138
  # Pick up on another machine
90
139
  memoir resume --inject --to claude
91
140
  ```
92
141
 
142
+ ### E2E Encryption
143
+ ```bash
144
+ memoir encrypt # toggle encryption on/off
145
+ memoir push # prompted for passphrase, AES-256-GCM encrypted
146
+ ```
147
+
148
+ Your backup is encrypted before it leaves your machine. Even if your storage is compromised, your data is safe. Secret scanning auto-redacts API keys, tokens, and passwords.
149
+
93
150
  ### Profiles (personal / work)
94
151
  ```bash
95
152
  memoir profile create work
@@ -107,23 +164,24 @@ memoir cloud restore # restore from any version
107
164
  memoir history # view all backup versions
108
165
  ```
109
166
 
110
- Free tier: 3 cloud backups. Pro ($5/mo): unlimited + version history.
111
-
112
- ### Security
167
+ ### Cross-platform (Mac / Windows / Linux)
113
168
  ```bash
114
- memoir doctor
115
- # Scans for secrets, API keys, .env files before pushing
169
+ # Push from Mac
170
+ memoir push
171
+
172
+ # Restore on Windows — paths remap automatically
173
+ memoir restore
116
174
  ```
117
175
 
118
- memoir **never** syncs credentials, API keys, .env files, or auth tokens.
176
+ Claude's memory paths are automatically remapped between platforms. Projects are cloned to the right locations. It just works.
119
177
 
120
178
  ## All Commands
121
179
 
122
180
  | Command | What it does |
123
181
  |---------|-------------|
124
182
  | `memoir init` | Setup wizard — GitHub or local storage |
125
- | `memoir push` | Back up all AI configs |
126
- | `memoir restore` | Restore on a new machine |
183
+ | `memoir push` | Back up AI memory + workspace + session |
184
+ | `memoir restore` | Restore everything on a new machine |
127
185
  | `memoir status` | Show detected AI tools |
128
186
  | `memoir doctor` | Diagnose issues, scan for secrets |
129
187
  | `memoir view` | Preview what's in your backup |
@@ -131,6 +189,7 @@ memoir **never** syncs credentials, API keys, .env files, or auth tokens.
131
189
  | `memoir migrate` | Translate memory between tools via AI |
132
190
  | `memoir snapshot` | Capture current coding session |
133
191
  | `memoir resume` | Pick up where you left off |
192
+ | `memoir encrypt` | Toggle E2E encryption |
134
193
  | `memoir profile` | Manage profiles (personal/work) |
135
194
  | `memoir cloud push` | Back up to memoir cloud |
136
195
  | `memoir cloud restore` | Restore from memoir cloud |
@@ -140,57 +199,65 @@ memoir **never** syncs credentials, API keys, .env files, or auth tokens.
140
199
 
141
200
  ## How memoir compares
142
201
 
143
- | Feature | memoir | skillshare | ai-rulez | memories.sh |
144
- |---------|--------|-----------|----------|-------------|
145
- | Cross-device sync | **Yes** | Yes (git) | No | Yes |
202
+ | Feature | memoir | dotfiles managers | ai-rulez | memories.sh |
203
+ |---------|--------|-------------------|----------|-------------|
204
+ | AI memory sync | **11 tools** | No | 18 tools | 3 tools |
205
+ | Workspace sync | **Yes** | No | No | No |
206
+ | Session handoff | **Yes** | No | No | No |
146
207
  | AI-powered translation | **Yes** | No | No | No |
147
- | Tools supported | **11** | 40+ | 18 | 3 |
208
+ | E2E encryption | **Yes** | No | No | No |
209
+ | Secret scanning | **Yes** | Some | No | No |
210
+ | Cross-platform remap | **Yes** | Some | No | No |
211
+ | Uncommitted work patches | **Yes** | No | No | No |
148
212
  | Cloud backup | **Yes** | No | No | Yes ($15/mo) |
149
- | Version history | **Yes** | No | No | No |
150
- | Session handoff | **Yes** | No | No | No |
151
213
  | Profiles | **Yes** | No | No | No |
152
- | Secret scanning | **Yes** | Yes | No | No |
153
214
  | Free & open source | **Yes** | Yes | Yes | No |
154
215
 
155
- memoir is free and open source. Cloud sync starts at $0 (3 backups free).
156
-
157
216
  ## Common Workflows
158
217
 
159
- ### New laptop setup
218
+ ### New machine setup
160
219
  ```bash
161
220
  # Old machine
162
221
  memoir push
163
222
 
164
- # New machine
165
- npm install -g memoir-cli
166
- memoir init # connect to same repo
167
- memoir restore # all configs restored in seconds
223
+ # New machine — one command, everything's back
224
+ npm install -g memoir-cli && memoir init && memoir restore -y
168
225
  ```
169
226
 
170
- ### Switching from ChatGPT to Claude
227
+ ### Daily sync between machines
171
228
  ```bash
172
- memoir migrate --from chatgpt --to claude
173
- # Your custom instructions become a proper CLAUDE.md
229
+ memoir push # end of day on laptop
230
+ memoir restore # next morning on desktop AI knows what you were doing
174
231
  ```
175
232
 
176
- ### Daily sync between machines
233
+ ### Switching AI tools
177
234
  ```bash
178
- memoir push # end of day on laptop
179
- memoir restore # next morning on desktop
235
+ memoir migrate --from chatgpt --to claude
236
+ # Your custom instructions become a proper CLAUDE.md
180
237
  ```
181
238
 
182
- ### Cross-platform (Mac ↔ Windows ↔ Linux)
239
+ ### Team onboarding
183
240
  ```bash
184
- # Push from Mac
185
- memoir push
241
+ # Senior dev pushes team config
242
+ memoir push --profile team
186
243
 
187
- # Restore on Windows paths remap automatically
188
- memoir restore
244
+ # New hire runs one command
245
+ memoir restore --profile team
246
+ # Every project cloned. Every AI tool configured. Day one productive.
189
247
  ```
190
248
 
249
+ ## Security
250
+
251
+ - **E2E encryption** — AES-256-GCM with scrypt key derivation
252
+ - **Secret scanning** — 20+ patterns detect API keys, tokens, passwords, connection strings
253
+ - **Auto-redaction** — secrets stripped from session handoffs before sync
254
+ - **No credentials synced** — .env files, auth tokens, and API keys are never included
255
+ - **Passphrase verified** — wrong passphrase caught before decrypt attempt
256
+
191
257
  ## Requirements
192
258
 
193
259
  - Node.js >= 18
260
+ - Git (for workspace sync)
194
261
  - Works on macOS, Windows, Linux
195
262
 
196
263
  ## Contributing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoir-cli",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
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",
@@ -9,7 +9,7 @@ import { getConfig } 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';
12
- import { findClaudeSessions, parseSession, generateContextHandoff, shouldIgnoreProject } from '../context/capture.js';
12
+ import { findClaudeSessions, parseSession, generateContextHandoff, shouldIgnoreProject, persistDecisions } from '../context/capture.js';
13
13
  import { scanForSecrets, printSecurityReport } from '../security/scanner.js';
14
14
  import { encryptDirectory, createVerifyToken } from '../security/encryption.js';
15
15
  import { getRawConfig, saveConfig, migrateConfigToV2 } from '../config.js';
@@ -77,10 +77,19 @@ export async function pushCommand(options = {}) {
77
77
  await fs.writeFile(path.join(localHandoffDir, `${timestamp}-claude.md`), clean);
78
78
  await fs.writeFile(path.join(localHandoffDir, 'latest.md'), clean);
79
79
 
80
+ // Persist decisions to Claude's memory so they survive across sessions
81
+ let decisionCount = 0;
82
+ if (parsed.decisions.length > 0) {
83
+ try {
84
+ decisionCount = persistDecisions(parsed.decisions);
85
+ } catch {}
86
+ }
87
+
80
88
  contextCaptured = true;
81
89
  sessionInfo = {
82
90
  slug: parsed.slug,
83
91
  filesModified: parsed.filesWritten.length,
92
+ decisions: decisionCount,
84
93
  duration: parsed.firstTimestamp && parsed.lastTimestamp
85
94
  ? (() => {
86
95
  const ms = new Date(parsed.lastTimestamp) - new Date(parsed.firstTimestamp);
@@ -226,6 +235,9 @@ export async function pushCommand(options = {}) {
226
235
  if (sessionInfo.duration) parts.push(sessionInfo.duration);
227
236
  if (sessionInfo.filesModified) parts.push(`${sessionInfo.filesModified} files changed`);
228
237
  contextLine = '\n' + chalk.green(' ✔ Session Context') + chalk.gray(` (${parts.join(', ')})`) + '\n';
238
+ if (sessionInfo.decisions > 0) {
239
+ contextLine += chalk.green(` ✔ ${sessionInfo.decisions} decision(s) saved to persistent memory`) + '\n';
240
+ }
229
241
  if (sessionInfo.secretsRedacted > 0) {
230
242
  contextLine += chalk.yellow(` 🔒 ${sessionInfo.secretsRedacted} secret(s) auto-redacted`) + '\n';
231
243
  }
@@ -61,6 +61,7 @@ export function parseSession(sessionPath, maxSizeMB = 10) {
61
61
  }
62
62
 
63
63
  function parseLines(lines) {
64
+ const assistantTexts = [];
64
65
  const result = {
65
66
  sessionId: null,
66
67
  slug: null,
@@ -95,9 +96,14 @@ function parseLines(lines) {
95
96
  }
96
97
  }
97
98
 
98
- // Tool uses from assistant
99
+ // Tool uses and text from assistant
99
100
  if (obj.type === 'assistant' && Array.isArray(obj.message?.content)) {
100
101
  for (const block of obj.message.content) {
102
+ if (block.type === 'text' && block.text) {
103
+ // Capture assistant text for decision extraction (limit size)
104
+ if (block.text.length < 2000) assistantTexts.push(block.text);
105
+ continue;
106
+ }
101
107
  if (block.type !== 'tool_use') continue;
102
108
  const name = block.name;
103
109
  const input = block.input || {};
@@ -139,9 +145,148 @@ function parseLines(lines) {
139
145
  result.filesRead = [...result.filesRead];
140
146
  result.errors = [...new Set(result.errors)].slice(0, 10);
141
147
 
148
+ // Extract decisions from user + assistant messages
149
+ result.decisions = extractDecisions(result.userMessages, assistantTexts);
150
+
142
151
  return result;
143
152
  }
144
153
 
154
+ /**
155
+ * Extract durable decisions from session conversation.
156
+ * These are things like renames, tech choices, preferences — stuff that should persist.
157
+ */
158
+ function extractDecisions(userMessages, assistantTexts) {
159
+ const decisions = [];
160
+ const allText = [...userMessages, ...assistantTexts].join('\n');
161
+
162
+ // Patterns that indicate a decision was made
163
+ const patterns = [
164
+ // Renames / naming
165
+ { regex: /(?:rename|call|name)\s+(?:it|this|the (?:project|app|tool|product))\s+(?:to\s+)?["']?([A-Z][a-zA-Z0-9_-]+)["']?/gi, type: 'rename' },
166
+ { regex: /(?:the\s+)?(?:new\s+)?name\s+(?:is|will be|should be)\s+["']?([A-Z][a-zA-Z0-9_-]+)["']?/gi, type: 'rename' },
167
+ { regex: /(?:rebrand|rebranding)\s+(?:to|as)\s+["']?([A-Z][a-zA-Z0-9_-]+)["']?/gi, type: 'rename' },
168
+ // Tech choices
169
+ { regex: /(?:let'?s|we(?:'ll| will| should)?|going to|decided to)\s+use\s+([A-Z][a-zA-Z0-9_./-]+)\s+(?:for|instead|as|to)/gi, type: 'tech' },
170
+ { regex: /(?:switch|migrate|move)\s+(?:from\s+\S+\s+)?to\s+([A-Z][a-zA-Z0-9_./-]+)/gi, type: 'tech' },
171
+ // Architecture / design
172
+ { regex: /(?:let'?s|we(?:'ll| will| should)?)\s+(?:go with|pick|choose)\s+(.{5,60}?)(?:\.|$|,|\n)/gi, type: 'design' },
173
+ // Stack choices
174
+ { regex: /(?:stack|framework|database|backend|frontend)\s+(?:is|will be|should be)\s+(.{5,60}?)(?:\.|$|,|\n)/gi, type: 'stack' },
175
+ ];
176
+
177
+ for (const { regex, type } of patterns) {
178
+ let match;
179
+ while ((match = regex.exec(allText)) !== null) {
180
+ const value = match[1].trim().replace(/["']+$/, '');
181
+ if (value.length > 2 && value.length < 80) {
182
+ // Avoid duplicates
183
+ const existing = decisions.find(d => d.value.toLowerCase() === value.toLowerCase());
184
+ if (!existing) {
185
+ decisions.push({ type, value, context: match[0].trim().slice(0, 120) });
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ // Look for explicit "remember this" instructions from the user
192
+ for (const msg of userMessages) {
193
+ // Only match when user is clearly asking to remember something
194
+ const rememberMatch = msg.match(/(?:remember (?:that|this)|note that|keep in mind that|from now on)[:\s]+(.{10,150})/i);
195
+ if (rememberMatch) {
196
+ decisions.push({ type: 'user-note', value: rememberMatch[1].trim(), context: msg.slice(0, 120) });
197
+ }
198
+ }
199
+
200
+ return decisions.slice(0, 20); // Cap at 20 decisions per session
201
+ }
202
+
203
+ /**
204
+ * Write extracted decisions to Claude's persistent memory.
205
+ * This ensures decisions survive across sessions and machines.
206
+ */
207
+ export function persistDecisions(decisions, claudeSource) {
208
+ if (!decisions || decisions.length === 0) return 0;
209
+
210
+ const claudeDir = claudeSource || path.join(home, '.claude');
211
+ const projectsDir = path.join(claudeDir, 'projects');
212
+ if (!fs.existsSync(projectsDir)) return 0;
213
+
214
+ // Find the HOME-level memory dir (not project-specific)
215
+ // This is the dir that matches the user's home path encoding
216
+ let homeKey;
217
+ if (process.platform === 'win32') {
218
+ homeKey = home.replace(/\\/g, '-').replace(/:/g, '-');
219
+ } else {
220
+ homeKey = '-' + home.replace(/^\//, '').replace(/\//g, '-');
221
+ }
222
+
223
+ // Try exact match first, then detect from existing dirs
224
+ let memDir = path.join(projectsDir, homeKey, 'memory');
225
+ if (!fs.existsSync(memDir)) {
226
+ // Fallback: find dirs with memory/ subfolder, pick shortest name (likely home-level)
227
+ const entries = fs.readdirSync(projectsDir, { withFileTypes: true })
228
+ .filter(e => e.isDirectory() && fs.existsSync(path.join(projectsDir, e.name, 'memory')));
229
+ if (entries.length === 0) return 0;
230
+ // Shortest dir name is most likely the home key (not a sub-project)
231
+ const homeEntry = entries.sort((a, b) => a.name.length - b.name.length)[0];
232
+ memDir = path.join(projectsDir, homeEntry.name, 'memory');
233
+ }
234
+
235
+ fs.mkdirSync(memDir, { recursive: true });
236
+ const decisionsFile = path.join(memDir, 'session-decisions.md');
237
+ const memoryMdPath = path.join(memDir, 'MEMORY.md');
238
+
239
+ // Read existing decisions file or create new
240
+ let existing = '';
241
+ if (fs.existsSync(decisionsFile)) {
242
+ existing = fs.readFileSync(decisionsFile, 'utf8');
243
+ }
244
+
245
+ // Format new decisions
246
+ const date = new Date().toISOString().split('T')[0];
247
+ const newEntries = decisions.map(d => {
248
+ if (d.type === 'rename') return `- **Renamed:** ${d.context}`;
249
+ if (d.type === 'tech') return `- **Tech choice:** ${d.context}`;
250
+ if (d.type === 'design') return `- **Decision:** ${d.context}`;
251
+ if (d.type === 'stack') return `- **Stack:** ${d.context}`;
252
+ if (d.type === 'user-note') return `- **Note:** ${d.value}`;
253
+ return `- ${d.context}`;
254
+ });
255
+
256
+ // Check for duplicates against existing content
257
+ const fresh = newEntries.filter(entry => !existing.includes(entry));
258
+ if (fresh.length === 0) return 0;
259
+
260
+ const section = `\n### ${date}\n${fresh.join('\n')}\n`;
261
+
262
+ if (!existing) {
263
+ // Create new file with frontmatter
264
+ const content = `---
265
+ name: Session Decisions
266
+ description: Project decisions extracted from coding sessions — renames, tech choices, architecture
267
+ type: project
268
+ ---
269
+
270
+ # Decisions from coding sessions
271
+ ${section}`;
272
+ fs.writeFileSync(decisionsFile, content);
273
+ } else {
274
+ // Append to existing
275
+ fs.writeFileSync(decisionsFile, existing.trimEnd() + '\n' + section);
276
+ }
277
+
278
+ // Ensure MEMORY.md references the decisions file
279
+ if (fs.existsSync(memoryMdPath)) {
280
+ const memoryMd = fs.readFileSync(memoryMdPath, 'utf8');
281
+ if (!memoryMd.includes('session-decisions.md')) {
282
+ const addition = `\n- [Session Decisions](session-decisions.md) — project renames, tech choices, architecture decisions from coding sessions\n`;
283
+ fs.writeFileSync(memoryMdPath, memoryMd.trimEnd() + addition);
284
+ }
285
+ }
286
+
287
+ return fresh.length;
288
+ }
289
+
145
290
  /**
146
291
  * Generate a concise handoff markdown from parsed session
147
292
  * This is what gets injected into the AI tool on the other machine