File size: 9,097 Bytes
38be44d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | #!/usr/bin/env node
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Seeds the auto-memory inbox with REALISTIC patches for manual end-to-end
* testing of `/memory inbox`. Mirrors what one extraction-agent run would
* produce in practice: a single canonical `extraction.patch` per kind,
* containing multiple hunks (MEMORY.md update + sibling creation, etc.).
*
* Run AFTER `npm run build` from the project root:
* node scripts/seed-test-inbox.js
*
* The script will:
* 1. Initialize Storage for the current working directory.
* 2. Compute <projectMemoryDir> = ~/.gemini/tmp/<projectId>/memory/.
* 3. Seed `MEMORY.md` and TWO canonical inbox patches:
* - .inbox/private/extraction.patch (multi-hunk: update MEMORY.md
* + create verify-workflow.md + add MEMORY.md pointer to it)
* - .inbox/global/extraction.patch (creates ~/.gemini/GEMINI.md)
* 4. Print a verification checklist + the launch command.
*
* To clean up later, delete `<projectMemoryDir>/.inbox/` and the seeded
* MEMORY.md / GEMINI.md files.
*/
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import * as os from 'node:os';
import { fileURLToPath } from 'node:url';
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(SCRIPT_DIR, '..');
const corePath = path.join(REPO_ROOT, 'packages/core/dist/src/index.js');
try {
await fs.access(corePath);
} catch {
console.error(
`Cannot find built core at ${corePath}. Run \`npm run build\` first.`,
);
process.exit(1);
}
const { Storage } = await import(corePath);
const cwd = process.cwd();
const storage = new Storage(cwd);
await storage.initialize();
const memoryDir = storage.getProjectMemoryTempDir();
const inboxPrivate = path.join(memoryDir, '.inbox', 'private');
const inboxGlobal = path.join(memoryDir, '.inbox', 'global');
const homeDir = os.homedir();
const globalGeminiMd = path.join(homeDir, '.gemini', 'GEMINI.md');
console.log(`\nπ§ Seeding inbox for cwd: ${cwd}`);
console.log(` memoryDir = ${memoryDir}\n`);
await fs.mkdir(inboxPrivate, { recursive: true });
await fs.mkdir(inboxGlobal, { recursive: true });
const seeded = [];
async function seed(filePath, content, label) {
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, content, 'utf-8');
seeded.push({ filePath, label });
}
// --- 1. Pre-existing private MEMORY.md so the update hunk has something to modify ---
const memoryMd = path.join(memoryDir, 'MEMORY.md');
await seed(
memoryMd,
'# Project Memory\n\n- old fact about this project\n',
'pre-existing active MEMORY.md',
);
// --- 2. Canonical PRIVATE extraction.patch ---
// One file, multi-hunk: update MEMORY.md AND create verify-workflow.md
// AND add a pointer line for the sibling. This is what one extraction
// agent run typically produces.
const verifyWorkflowMd = path.join(memoryDir, 'verify-workflow.md');
await fs.rm(verifyWorkflowMd, { force: true });
await seed(
path.join(inboxPrivate, 'extraction.patch'),
[
// Hunk 1: replace the existing fact and append a sibling pointer.
`--- ${memoryMd}`,
`+++ ${memoryMd}`,
`@@ -1,3 +1,4 @@`,
` # Project Memory`,
` `,
`-- old fact about this project`,
`+- new fact extracted from session analysis`,
`+- See ${verifyWorkflowMd} for the project's verification commands.`,
// Hunk 2: create the verify-workflow.md sibling.
`--- /dev/null`,
`+++ ${verifyWorkflowMd}`,
`@@ -0,0 +1,5 @@`,
`+# Verify Workflow`,
`+`,
`+- Run \`npm run typecheck\` after editing any *.ts file.`,
`+- Run \`npm run build --workspace @google/gemini-cli-core\` before testing CLI changes.`,
`+- Inbox patches are guarded by /memory inbox.`,
``,
].join('\n'),
'canonical PRIVATE extraction.patch (2 hunks: MEMORY.md update + sibling create)',
);
// --- 3. Canonical GLOBAL extraction.patch ---
// Creates ~/.gemini/GEMINI.md. Backs up any existing one first.
let existingGlobalGemini = null;
try {
existingGlobalGemini = await fs.readFile(globalGeminiMd, 'utf-8');
} catch {
// Doesn't exist yet β fine.
}
if (existingGlobalGemini !== null) {
const backupPath = `${globalGeminiMd}.seed-test-backup-${Date.now()}`;
await fs.copyFile(globalGeminiMd, backupPath);
console.log(
` βΉοΈ Backed up existing ${globalGeminiMd} β ${backupPath}\n` +
` (restore manually after testing if you wish.)\n`,
);
await fs.rm(globalGeminiMd, { force: true });
}
await seed(
path.join(inboxGlobal, 'extraction.patch'),
[
`--- /dev/null`,
`+++ ${globalGeminiMd}`,
`@@ -0,0 +1,3 @@`,
`+# Global Personal Preferences`,
`+`,
`+- Prefer concise architecture summaries.`,
``,
].join('\n'),
'canonical GLOBAL extraction.patch (creates ~/.gemini/GEMINI.md)',
);
// --- Summary ---
console.log('Seeded files:');
for (const { filePath, label } of seeded) {
console.log(` β ${path.relative(cwd, filePath)}`);
console.log(` ${label}\n`);
}
console.log('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log('NEXT STEPS');
console.log('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log(`
1. Enable autoMemory in your settings (the inbox command requires it):
~/.gemini/settings.json should contain:
{
"experimental": { "autoMemory": true }
}
Or run this to set it:
node -e "const fs=require('fs'),p=require('os').homedir()+'/.gemini/settings.json';let s={};try{s=JSON.parse(fs.readFileSync(p,'utf-8'))}catch{}s.experimental=s.experimental||{};s.experimental.autoMemory=true;fs.mkdirSync(require('path').dirname(p),{recursive:true});fs.writeFileSync(p,JSON.stringify(s,null,2))"
2. Launch the just-built CLI from THIS REPO ONLY. Do NOT use any globally
installed "gemini" binary β it will be a stale build that doesn't know
about memory patches and will silently show only skills.
npm run start
(or, equivalently: node ${path.relative(cwd, REPO_ROOT)}/bundle/gemini.js)
Sanity check before launching:
node ${path.relative(cwd, path.join(REPO_ROOT, 'scripts/check-inbox.js'))}
should report 2 memory patches (Private memory + Global memory).
3. In the CLI, run:
/memory inbox
You should see exactly 2 entries in the "Memory Updates" group:
- Private memory 2 hunks from 1 source patch
- Global memory 1 hunk from 1 source patch
4. Test focus preservation: arrow-down to "Global memory" β Enter β Esc β
cursor MUST still be on "Global memory" (not row 0).
5. Open "Private memory" preview. You'll see TWO target sections (no
duplicates), since both hunks come from one source patch:
${memoryMd}
- new fact extracted from session analysis
- See ${verifyWorkflowMd} for the project's verification commands.
${verifyWorkflowMd} (new file)
# Verify Workflow
...
6. Apply each entry:
ββββββββββββββββββββ¬βββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β Item β Action β Expected outcome β
ββββββββββββββββββββΌβββββββββββΌββββββββββββββββββββββββββββββββββββββββ€
β Private memory β Apply β "Applied all 1 private memory patch." β
β β β MEMORY.md updated; verify-workflow.md β
β β β created. β
β Global memory β Apply β "Applied all 1 global memory patch." β
β β β ~/.gemini/GEMINI.md created. β
ββββββββββββββββββββ΄βββββββββββ΄ββββββββββββββββββββββββββββββββββββββββ
7. Verify final state on disk:
cat ${path.relative(cwd, memoryMd)} # should show new fact + pointer line
cat ${path.relative(cwd, verifyWorkflowMd)} # should exist
cat ${globalGeminiMd} # should show "Prefer concise..."
ls ${path.relative(cwd, inboxPrivate)} # should be empty
ls ${path.relative(cwd, inboxGlobal)} # should be empty
8. Cleanup:
rm -rf ${path.relative(cwd, path.join(memoryDir, '.inbox'))}
rm -f ${path.relative(cwd, memoryMd)}
rm -f ${path.relative(cwd, verifyWorkflowMd)}
rm -f ${globalGeminiMd}
`);
|