@brianluby/agent-brain 1.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.
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, renameSync, unlinkSync } from 'fs';
3
+ import { relative, basename, dirname, resolve, isAbsolute, sep } from 'path';
4
+ import { execSync } from 'child_process';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ function defaultPlatformRelativePath(platform) {
8
+ const normalizedPlatform = platform.trim().toLowerCase();
9
+ const safePlatform = normalizedPlatform.replace(/[^a-z0-9_-]/g, "-").replace(/^-+|-+$/g, "") || "unknown";
10
+ return `.agent-brain/mind-${safePlatform}.mv2`;
11
+ }
12
+ function resolveInsideProject(projectDir, candidatePath) {
13
+ if (isAbsolute(candidatePath)) {
14
+ return resolve(candidatePath);
15
+ }
16
+ const root = resolve(projectDir);
17
+ const resolved = resolve(root, candidatePath);
18
+ const rel = relative(root, resolved);
19
+ if (rel === ".." || rel.startsWith(`..${sep}`)) {
20
+ throw new Error("Resolved memory path must stay inside projectDir");
21
+ }
22
+ return resolved;
23
+ }
24
+ function resolveMemoryPathPolicy(input) {
25
+ const mode = input.platformOptIn ? "platform_opt_in" : "legacy_first";
26
+ const canonicalRelativePath = input.platformOptIn ? input.platformRelativePath || defaultPlatformRelativePath(input.platform) : input.defaultRelativePath;
27
+ const canonicalPath = resolveInsideProject(input.projectDir, canonicalRelativePath);
28
+ if (existsSync(canonicalPath)) {
29
+ return {
30
+ mode,
31
+ memoryPath: canonicalPath,
32
+ canonicalPath
33
+ };
34
+ }
35
+ const fallbackPaths = (input.legacyRelativePaths || []).map((relativePath) => resolveInsideProject(input.projectDir, relativePath));
36
+ for (const fallbackPath of fallbackPaths) {
37
+ if (existsSync(fallbackPath)) {
38
+ return {
39
+ mode,
40
+ memoryPath: fallbackPath,
41
+ canonicalPath,
42
+ migrationSuggestion: {
43
+ fromPath: fallbackPath,
44
+ toPath: canonicalPath
45
+ }
46
+ };
47
+ }
48
+ }
49
+ if (input.platformOptIn) {
50
+ return {
51
+ mode: "platform_opt_in",
52
+ memoryPath: canonicalPath,
53
+ canonicalPath
54
+ };
55
+ }
56
+ return {
57
+ mode: "legacy_first",
58
+ memoryPath: canonicalPath,
59
+ canonicalPath
60
+ };
61
+ }
62
+
63
+ // src/platforms/platform-detector.ts
64
+ function normalizePlatform(value) {
65
+ if (!value) return void 0;
66
+ const normalized = value.trim().toLowerCase();
67
+ return normalized.length > 0 ? normalized : void 0;
68
+ }
69
+ function detectPlatformFromEnv() {
70
+ const explicitFromEnv = normalizePlatform(process.env.MEMVID_PLATFORM);
71
+ if (explicitFromEnv) {
72
+ return explicitFromEnv;
73
+ }
74
+ if (process.env.OPENCODE === "1") {
75
+ return "opencode";
76
+ }
77
+ return "claude";
78
+ }
79
+
80
+ // src/scripts/utils.ts
81
+ async function createFreshMemory(memoryPath, create) {
82
+ const memoryDir = dirname(memoryPath);
83
+ mkdirSync(memoryDir, { recursive: true });
84
+ await create(memoryPath, "basic");
85
+ }
86
+ function isCorruptedMemoryError(error) {
87
+ const errorMessage = error instanceof Error ? error.message : String(error);
88
+ return errorMessage.includes("Deserialization") || errorMessage.includes("UnexpectedVariant") || errorMessage.includes("Invalid") || errorMessage.includes("corrupt") || errorMessage.includes("version mismatch") || errorMessage.includes("validation failed") || errorMessage.includes("unable to recover") || errorMessage.includes("table of contents");
89
+ }
90
+ async function handleCorruptedMemory(memoryPath, create) {
91
+ console.log(
92
+ "\u26A0\uFE0F Memory file is corrupted or incompatible. Creating fresh memory..."
93
+ );
94
+ const backupPath = `${memoryPath}.backup-${Date.now()}`;
95
+ try {
96
+ renameSync(memoryPath, backupPath);
97
+ console.log(` Old file backed up to: ${backupPath}`);
98
+ } catch {
99
+ try {
100
+ unlinkSync(memoryPath);
101
+ } catch {
102
+ }
103
+ }
104
+ await createFreshMemory(memoryPath, create);
105
+ }
106
+ async function openMemorySafely(memoryPath, use, create) {
107
+ if (!existsSync(memoryPath)) {
108
+ console.log("No memory file found. Creating new memory at:", memoryPath);
109
+ await createFreshMemory(memoryPath, create);
110
+ return { memvid: null, isNew: true };
111
+ }
112
+ try {
113
+ const memvid = await use("basic", memoryPath);
114
+ return { memvid, isNew: false };
115
+ } catch (openError) {
116
+ if (isCorruptedMemoryError(openError)) {
117
+ await handleCorruptedMemory(memoryPath, create);
118
+ return { memvid: null, isNew: true };
119
+ }
120
+ throw openError;
121
+ }
122
+ }
123
+ function resolveScriptMemoryPath(projectDir) {
124
+ const pathPolicy = resolveMemoryPathPolicy({
125
+ projectDir,
126
+ platform: detectPlatformFromEnv(),
127
+ defaultRelativePath: ".agent-brain/mind.mv2",
128
+ legacyRelativePaths: [".claude/mind.mv2"],
129
+ platformRelativePath: process.env.MEMVID_PLATFORM_MEMORY_PATH,
130
+ platformOptIn: process.env.MEMVID_PLATFORM_PATH_OPT_IN === "1"
131
+ });
132
+ if (!pathPolicy.migrationSuggestion) {
133
+ return { memoryPath: pathPolicy.memoryPath };
134
+ }
135
+ const fromDisplay = relative(projectDir, pathPolicy.migrationSuggestion.fromPath) || basename(pathPolicy.migrationSuggestion.fromPath);
136
+ const toDisplay = relative(projectDir, pathPolicy.migrationSuggestion.toPath) || basename(pathPolicy.migrationSuggestion.toPath);
137
+ return {
138
+ memoryPath: pathPolicy.memoryPath,
139
+ migrationPrompt: `mkdir -p "${dirname(toDisplay)}" && mv "${fromDisplay}" "${toDisplay}"`
140
+ };
141
+ }
142
+
143
+ // src/scripts/timeline.ts
144
+ async function ensureDeps() {
145
+ const __dirname = dirname(fileURLToPath(import.meta.url));
146
+ const pluginRoot = resolve(__dirname, "../..");
147
+ const sdkPath = resolve(pluginRoot, "node_modules/@memvid/sdk");
148
+ if (!existsSync(sdkPath)) {
149
+ console.log("Installing dependencies...");
150
+ try {
151
+ execSync("npm install --production --no-fund --no-audit", {
152
+ cwd: pluginRoot,
153
+ stdio: "inherit",
154
+ timeout: 12e4
155
+ });
156
+ } catch {
157
+ console.error("Failed to install dependencies. Please run: npm install");
158
+ process.exit(1);
159
+ }
160
+ }
161
+ }
162
+ async function loadSDK() {
163
+ await ensureDeps();
164
+ return await import('@memvid/sdk');
165
+ }
166
+ async function main() {
167
+ const args = process.argv.slice(2);
168
+ const limit = parseInt(args[0] || "10", 10);
169
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.OPENCODE_PROJECT_DIR || process.cwd();
170
+ const { memoryPath, migrationPrompt } = resolveScriptMemoryPath(projectDir);
171
+ if (migrationPrompt) {
172
+ console.log("Legacy memory detected at .claude/mind.mv2.");
173
+ console.log(`Move it to .agent-brain/mind.mv2? Run: ${migrationPrompt}
174
+ `);
175
+ }
176
+ const { use, create } = await loadSDK();
177
+ const { memvid, isNew } = await openMemorySafely(memoryPath, use, create);
178
+ if (isNew || !memvid) {
179
+ console.log("\u2705 Memory initialized! No memories to show yet.\n");
180
+ process.exit(0);
181
+ }
182
+ try {
183
+ const mv = memvid;
184
+ const timeline = await mv.timeline({ limit, reverse: true });
185
+ const frames = Array.isArray(timeline) ? timeline : timeline.frames || [];
186
+ if (frames.length === 0) {
187
+ console.log("No memories yet. Start using Claude to build your memory!");
188
+ process.exit(0);
189
+ }
190
+ console.log(`Recent ${frames.length} memories:
191
+ `);
192
+ for (let i = 0; i < frames.length; i++) {
193
+ const frame = frames[i];
194
+ const preview = frame.preview || "";
195
+ const uri = frame.uri || `frame/${frame.frame_id}`;
196
+ const timestamp = frame.timestamp ? new Date(frame.timestamp * 1e3).toLocaleString() : "Unknown time";
197
+ const snippet = preview.slice(0, 100).replace(/\n/g, " ");
198
+ console.log(`#${i + 1} ${uri}`);
199
+ console.log(` \u{1F4C5} ${timestamp}`);
200
+ console.log(` ${snippet}${snippet.length >= 100 ? "..." : ""}`);
201
+ console.log();
202
+ }
203
+ } catch (error) {
204
+ console.error("Error reading timeline:", error);
205
+ process.exit(1);
206
+ }
207
+ }
208
+ main();
209
+ //# sourceMappingURL=timeline.js.map
210
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/platforms/path-policy.ts","../../src/platforms/platform-detector.ts","../../src/scripts/utils.ts","../../src/scripts/timeline.ts"],"names":["pathRelative","existsSync","dirname","resolve"],"mappings":"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","file":"timeline.js","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { isAbsolute, relative as pathRelative, resolve, sep } from \"node:path\";\n\nexport type MemoryPathMode = \"legacy_first\" | \"platform_opt_in\";\n\nexport interface MemoryPathPolicyInput {\n projectDir: string;\n platform: string;\n defaultRelativePath: string;\n platformRelativePath?: string;\n platformOptIn?: boolean;\n legacyRelativePaths?: string[];\n}\n\nexport interface MemoryMigrationSuggestion {\n fromPath: string;\n toPath: string;\n}\n\nexport interface MemoryPathPolicyResult {\n mode: MemoryPathMode;\n memoryPath: string;\n canonicalPath: string;\n migrationSuggestion?: MemoryMigrationSuggestion;\n}\n\nfunction defaultPlatformRelativePath(platform: string): string {\n const normalizedPlatform = platform.trim().toLowerCase();\n const safePlatform = normalizedPlatform\n .replace(/[^a-z0-9_-]/g, \"-\")\n .replace(/^-+|-+$/g, \"\") || \"unknown\";\n return `.agent-brain/mind-${safePlatform}.mv2`;\n}\n\nfunction resolveInsideProject(projectDir: string, candidatePath: string): string {\n if (isAbsolute(candidatePath)) {\n return resolve(candidatePath);\n }\n const root = resolve(projectDir);\n const resolved = resolve(root, candidatePath);\n const rel = pathRelative(root, resolved);\n if (rel === \"..\" || rel.startsWith(`..${sep}`)) {\n throw new Error(\"Resolved memory path must stay inside projectDir\");\n }\n return resolved;\n}\n\nexport function resolveMemoryPathPolicy(input: MemoryPathPolicyInput): MemoryPathPolicyResult {\n const mode: MemoryPathMode = input.platformOptIn ? \"platform_opt_in\" : \"legacy_first\";\n const canonicalRelativePath = input.platformOptIn\n ? input.platformRelativePath || defaultPlatformRelativePath(input.platform)\n : input.defaultRelativePath;\n const canonicalPath = resolveInsideProject(input.projectDir, canonicalRelativePath);\n\n if (existsSync(canonicalPath)) {\n return {\n mode,\n memoryPath: canonicalPath,\n canonicalPath,\n };\n }\n\n const fallbackPaths = (input.legacyRelativePaths || [])\n .map((relativePath) => resolveInsideProject(input.projectDir, relativePath));\n\n for (const fallbackPath of fallbackPaths) {\n if (existsSync(fallbackPath)) {\n return {\n mode,\n memoryPath: fallbackPath,\n canonicalPath,\n migrationSuggestion: {\n fromPath: fallbackPath,\n toPath: canonicalPath,\n },\n };\n }\n }\n\n if (input.platformOptIn) {\n return {\n mode: \"platform_opt_in\",\n memoryPath: canonicalPath,\n canonicalPath,\n };\n }\n\n return {\n mode: \"legacy_first\",\n memoryPath: canonicalPath,\n canonicalPath,\n };\n}\n","import type { HookInput } from \"../types.js\";\n\nfunction normalizePlatform(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const normalized = value.trim().toLowerCase();\n return normalized.length > 0 ? normalized : undefined;\n}\n\nexport function detectPlatformFromEnv(): string {\n const explicitFromEnv = normalizePlatform(process.env.MEMVID_PLATFORM);\n if (explicitFromEnv) {\n return explicitFromEnv;\n }\n\n if (process.env.OPENCODE === \"1\") {\n return \"opencode\";\n }\n\n return \"claude\";\n}\n\nexport function detectPlatform(input: HookInput): string {\n const explicitFromHook = normalizePlatform(input.platform);\n if (explicitFromHook) {\n return explicitFromHook;\n }\n\n return detectPlatformFromEnv();\n}\n","/**\n * Shared utilities for Memvid Mind scripts\n */\n\nimport { existsSync, mkdirSync, unlinkSync, renameSync } from \"node:fs\";\nimport { basename, dirname, relative } from \"node:path\";\nimport { resolveMemoryPathPolicy } from \"../platforms/path-policy.js\";\nimport { detectPlatformFromEnv } from \"../platforms/platform-detector.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype CreateFn = (path: string, kind: any) => Promise<any>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype UseFn = (kind: any, path: string) => Promise<any>;\n\n/**\n * Create a fresh memory file at the given path\n */\nexport async function createFreshMemory(\n memoryPath: string,\n create: CreateFn\n): Promise<void> {\n const memoryDir = dirname(memoryPath);\n mkdirSync(memoryDir, { recursive: true });\n await create(memoryPath, \"basic\");\n}\n\n/**\n * Check if an error indicates a corrupted or incompatible memory file\n */\nexport function isCorruptedMemoryError(error: unknown): boolean {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return (\n errorMessage.includes(\"Deserialization\") ||\n errorMessage.includes(\"UnexpectedVariant\") ||\n errorMessage.includes(\"Invalid\") ||\n errorMessage.includes(\"corrupt\") ||\n errorMessage.includes(\"version mismatch\") ||\n errorMessage.includes(\"validation failed\") ||\n errorMessage.includes(\"unable to recover\") ||\n errorMessage.includes(\"table of contents\")\n );\n}\n\n/**\n * Handle corrupted memory file by backing it up and creating a fresh one\n */\nexport async function handleCorruptedMemory(\n memoryPath: string,\n create: CreateFn\n): Promise<void> {\n console.log(\n \"⚠️ Memory file is corrupted or incompatible. Creating fresh memory...\"\n );\n // Backup corrupted file\n const backupPath = `${memoryPath}.backup-${Date.now()}`;\n try {\n renameSync(memoryPath, backupPath);\n console.log(` Old file backed up to: ${backupPath}`);\n } catch {\n try {\n unlinkSync(memoryPath);\n } catch {\n // Ignore unlink errors\n }\n }\n await createFreshMemory(memoryPath, create);\n}\n\n/**\n * Open a memory file, handling corruption by creating fresh memory if needed\n * Returns the opened memvid instance, or null if memory was recreated (caller should exit)\n */\nexport async function openMemorySafely(\n memoryPath: string,\n use: UseFn,\n create: CreateFn\n): Promise<{ memvid: unknown; isNew: boolean }> {\n // Auto-create if doesn't exist\n if (!existsSync(memoryPath)) {\n console.log(\"No memory file found. Creating new memory at:\", memoryPath);\n await createFreshMemory(memoryPath, create);\n return { memvid: null, isNew: true };\n }\n\n // Try to open, handle corrupted files\n try {\n const memvid = await use(\"basic\", memoryPath);\n return { memvid, isNew: false };\n } catch (openError: unknown) {\n if (isCorruptedMemoryError(openError)) {\n await handleCorruptedMemory(memoryPath, create);\n return { memvid: null, isNew: true };\n }\n // Re-throw other errors\n throw openError;\n }\n}\n\nexport interface ScriptMemoryPathResult {\n memoryPath: string;\n migrationPrompt?: string;\n}\n\nexport function resolveScriptMemoryPath(projectDir: string): ScriptMemoryPathResult {\n const pathPolicy = resolveMemoryPathPolicy({\n projectDir,\n platform: detectPlatformFromEnv(),\n defaultRelativePath: \".agent-brain/mind.mv2\",\n legacyRelativePaths: [\".claude/mind.mv2\"],\n platformRelativePath: process.env.MEMVID_PLATFORM_MEMORY_PATH,\n platformOptIn: process.env.MEMVID_PLATFORM_PATH_OPT_IN === \"1\",\n });\n\n if (!pathPolicy.migrationSuggestion) {\n return { memoryPath: pathPolicy.memoryPath };\n }\n\n const fromDisplay = relative(projectDir, pathPolicy.migrationSuggestion.fromPath) || basename(pathPolicy.migrationSuggestion.fromPath);\n const toDisplay = relative(projectDir, pathPolicy.migrationSuggestion.toPath) || basename(pathPolicy.migrationSuggestion.toPath);\n return {\n memoryPath: pathPolicy.memoryPath,\n migrationPrompt: `mkdir -p \"${dirname(toDisplay)}\" && mv \"${fromDisplay}\" \"${toDisplay}\"`,\n };\n}\n","#!/usr/bin/env node\n/**\n * Memvid Mind - Timeline Script\n *\n * View recent memories using the SDK (no CLI dependency)\n */\n\nimport { existsSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { openMemorySafely, resolveScriptMemoryPath } from \"./utils.js\";\n\n// Ensure dependencies are installed before importing SDK\nasync function ensureDeps() {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pluginRoot = resolve(__dirname, \"../..\");\n const sdkPath = resolve(pluginRoot, \"node_modules/@memvid/sdk\");\n\n if (!existsSync(sdkPath)) {\n console.log(\"Installing dependencies...\");\n try {\n execSync(\"npm install --production --no-fund --no-audit\", {\n cwd: pluginRoot,\n stdio: \"inherit\",\n timeout: 120000,\n });\n } catch {\n console.error(\"Failed to install dependencies. Please run: npm install\");\n process.exit(1);\n }\n }\n}\n\n// Dynamic import for SDK\nasync function loadSDK() {\n await ensureDeps();\n return await import(\"@memvid/sdk\");\n}\n\nasync function main() {\n const args = process.argv.slice(2);\n const limit = parseInt(args[0] || \"10\", 10);\n\n // Get memory file path\n const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.OPENCODE_PROJECT_DIR || process.cwd();\n const { memoryPath, migrationPrompt } = resolveScriptMemoryPath(projectDir);\n\n if (migrationPrompt) {\n console.log(\"Legacy memory detected at .claude/mind.mv2.\");\n console.log(`Move it to .agent-brain/mind.mv2? Run: ${migrationPrompt}\\n`);\n }\n\n // Load SDK dynamically\n const { use, create } = await loadSDK();\n\n // Open memory safely (handles corrupted files)\n const { memvid, isNew } = await openMemorySafely(memoryPath, use, create);\n\n if (isNew || !memvid) {\n console.log(\"✅ Memory initialized! No memories to show yet.\\n\");\n process.exit(0);\n }\n\n try {\n const mv = memvid as any;\n const timeline = await mv.timeline({ limit, reverse: true });\n\n // SDK returns array directly or { frames: [...] }\n const frames = Array.isArray(timeline) ? timeline : timeline.frames || [];\n\n if (frames.length === 0) {\n console.log(\"No memories yet. Start using Claude to build your memory!\");\n process.exit(0);\n }\n\n console.log(`Recent ${frames.length} memories:\\n`);\n\n for (let i = 0; i < frames.length; i++) {\n const frame = frames[i];\n const preview = frame.preview || \"\";\n const uri = frame.uri || `frame/${frame.frame_id}`;\n const timestamp = frame.timestamp\n ? new Date(frame.timestamp * 1000).toLocaleString()\n : \"Unknown time\";\n const snippet = preview.slice(0, 100).replace(/\\n/g, \" \");\n\n console.log(`#${i + 1} ${uri}`);\n console.log(` 📅 ${timestamp}`);\n console.log(` ${snippet}${snippet.length >= 100 ? \"...\" : \"\"}`);\n console.log();\n }\n } catch (error) {\n console.error(\"Error reading timeline:\", error);\n process.exit(1);\n }\n}\n\nmain();\n"]}
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@brianluby/agent-brain",
3
+ "version": "1.1.0",
4
+ "description": "Give Claude Code photographic memory in ONE portable file",
5
+ "type": "module",
6
+ "main": "dist/opencode/plugin.js",
7
+ "types": "dist/opencode/plugin.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/opencode/plugin.d.ts",
11
+ "default": "./dist/opencode/plugin.js"
12
+ },
13
+ "./mind": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "./opencode": {
18
+ "types": "./dist/opencode/plugin.d.ts",
19
+ "default": "./dist/opencode/plugin.js"
20
+ }
21
+ },
22
+ "opencode": {
23
+ "type": "plugin",
24
+ "hooks": [
25
+ "chat.message",
26
+ "tool.execute.after",
27
+ "event"
28
+ ]
29
+ },
30
+ "scripts": {
31
+ "build": "tsup && cp src/hooks/hooks.json dist/hooks/",
32
+ "dev": "tsup --watch",
33
+ "lint": "eslint src/",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "prepublishOnly": "npm run build"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "skills",
41
+ "commands",
42
+ ".claude-plugin"
43
+ ],
44
+ "keywords": [
45
+ "claude",
46
+ "claude-code",
47
+ "claude-code-plugin",
48
+ "anthropic",
49
+ "opencode",
50
+ "opencode-plugin",
51
+ "memory",
52
+ "ai-memory",
53
+ "context-persistence",
54
+ "memvid",
55
+ "portable-memory",
56
+ "persistent-memory",
57
+ "llm-memory",
58
+ "ai-assistant"
59
+ ],
60
+ "author": "Memvid <hello@memvid.com>",
61
+ "license": "MIT",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/brianluby/Agent-brain.git"
65
+ },
66
+ "homepage": "https://memvid.com",
67
+ "bugs": {
68
+ "url": "https://github.com/brianluby/Agent-brain/issues"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public"
72
+ },
73
+ "dependencies": {
74
+ "@opencode-ai/plugin": "^1.2.10",
75
+ "@memvid/sdk": "^2.0.149",
76
+ "proper-lockfile": "^4.1.2"
77
+ },
78
+ "devDependencies": {
79
+ "@eslint/js": "^9.39.2",
80
+ "@types/node": "^22.0.0",
81
+ "@types/proper-lockfile": "^4.1.4",
82
+ "eslint": "^9.0.0",
83
+ "tsup": "^8.0.0",
84
+ "typescript": "^5.7.0",
85
+ "typescript-eslint": "^8.50.0",
86
+ "vitest": "^3.0.0"
87
+ },
88
+ "engines": {
89
+ "node": ">=18.0.0"
90
+ }
91
+ }
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: memory
3
+ description: Claude Mind - Search and manage Claude's persistent memory stored in a single portable .mv2 file
4
+ ---
5
+
6
+ # Claude Mind
7
+
8
+ You have access to a persistent memory system powered by Claude Mind. All your observations, discoveries, and learnings are stored in a single `.agent-brain/mind.mv2` file.
9
+
10
+ ## How to Execute Memory Commands
11
+
12
+ Use the bundled SDK scripts via Node.js (NOT the CLI). The scripts are at `${CLAUDE_PLUGIN_ROOT}/dist/scripts/`.
13
+
14
+ ### Search Memories
15
+ ```bash
16
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "<query>" [limit]
17
+ ```
18
+
19
+ Examples:
20
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "authentication" 5`
21
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "database schema" 10`
22
+
23
+ ### Ask Questions
24
+ ```bash
25
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "<question>"
26
+ ```
27
+
28
+ Examples:
29
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "Why did we choose React?"`
30
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "What was the CORS solution?"`
31
+
32
+ ### View Statistics
33
+ ```bash
34
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/stats.js"
35
+ ```
36
+
37
+ ### View Recent Memories
38
+ ```bash
39
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/timeline.js" [count]
40
+ ```
41
+
42
+ ## Memory Types
43
+
44
+ Memories are automatically classified into these types:
45
+ - **discovery** - New information discovered
46
+ - **decision** - Important decisions made
47
+ - **problem** - Problems or errors encountered
48
+ - **solution** - Solutions implemented
49
+ - **pattern** - Patterns recognized in code/data
50
+ - **warning** - Warnings or concerns noted
51
+ - **success** - Successful outcomes
52
+ - **refactor** - Code refactoring done
53
+ - **bugfix** - Bugs fixed
54
+ - **feature** - Features added
55
+
56
+ ## File Location
57
+
58
+ Your memory is stored at: `.agent-brain/mind.mv2`
59
+
60
+ This file is:
61
+ - **Portable** - Copy it anywhere, share with teammates
62
+ - **Git-friendly** - Commit to version control
63
+ - **Self-contained** - Everything in ONE file
64
+ - **Searchable** - Instant semantic search
65
+
66
+ ## Usage Tips
67
+
68
+ 1. **Start of session**: Recent memories are automatically injected as context
69
+ 2. **During coding**: Observations are captured automatically from tool use
70
+ 3. **Searching**: Use natural language queries to find relevant past context
71
+ 4. **Sharing**: Send the `.mind.mv2` file to teammates for instant onboarding
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: mind
3
+ description: Claude Mind - Search and manage Claude's persistent memory stored in a single portable .mv2 file
4
+ ---
5
+
6
+ # Claude Mind
7
+
8
+ You have access to a persistent memory system powered by Claude Mind. All your observations, discoveries, and learnings are stored in a single `.agent-brain/mind.mv2` file.
9
+
10
+ ## How to Execute Memory Commands
11
+
12
+ Use the bundled SDK scripts via Node.js (NOT the CLI). The scripts are at `${CLAUDE_PLUGIN_ROOT}/dist/scripts/`.
13
+
14
+ ### Search Memories
15
+ ```bash
16
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "<query>" [limit]
17
+ ```
18
+
19
+ Examples:
20
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "authentication" 5`
21
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/find.js" "database schema" 10`
22
+
23
+ ### Ask Questions
24
+ ```bash
25
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "<question>"
26
+ ```
27
+
28
+ Examples:
29
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "Why did we choose React?"`
30
+ - `node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/ask.js" "What was the CORS solution?"`
31
+
32
+ ### View Statistics
33
+ ```bash
34
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/stats.js"
35
+ ```
36
+
37
+ ### View Recent Memories
38
+ ```bash
39
+ node "${CLAUDE_PLUGIN_ROOT}/dist/scripts/timeline.js" [count]
40
+ ```
41
+
42
+ ## Memory Types
43
+
44
+ Memories are automatically classified into these types:
45
+ - **discovery** - New information discovered
46
+ - **decision** - Important decisions made
47
+ - **problem** - Problems or errors encountered
48
+ - **solution** - Solutions implemented
49
+ - **pattern** - Patterns recognized in code/data
50
+ - **warning** - Warnings or concerns noted
51
+ - **success** - Successful outcomes
52
+ - **refactor** - Code refactoring done
53
+ - **bugfix** - Bugs fixed
54
+ - **feature** - Features added
55
+
56
+ ## File Location
57
+
58
+ Your memory is stored at: `.agent-brain/mind.mv2`
59
+
60
+ This file is:
61
+ - **Portable** - Copy it anywhere, share with teammates
62
+ - **Git-friendly** - Commit to version control
63
+ - **Self-contained** - Everything in ONE file
64
+ - **Searchable** - Instant semantic search
65
+
66
+ ## Usage Tips
67
+
68
+ 1. **Start of session**: Recent memories are automatically injected as context
69
+ 2. **During coding**: Observations are captured automatically from tool use
70
+ 3. **Searching**: Use natural language queries to find relevant past context
71
+ 4. **Sharing**: Send the `.mind.mv2` file to teammates for instant onboarding