cc-brain 0.1.9 → 0.2.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
@@ -17,7 +17,7 @@
17
17
  <a href="#installation">Installation</a> -
18
18
  <a href="#how-it-works">How It Works</a> -
19
19
  <a href="#architecture">Architecture</a> -
20
- <a href="#commands">Commands</a> -
20
+ <a href="#skills">Skills</a> -
21
21
  <a href="#cli">CLI</a>
22
22
  </p>
23
23
 
@@ -39,15 +39,15 @@ cc-brain creates a persistent memory layer that:
39
39
 
40
40
  ## Installation
41
41
 
42
- ### npm (recommended)
42
+ ### npx (quickest)
43
43
  ```bash
44
- npm install -g cc-brain
45
- cc-brain install
44
+ npx cc-brain install
46
45
  ```
47
46
 
48
- ### npx (one-liner)
47
+ ### npm (global)
49
48
  ```bash
50
- npx cc-brain install
49
+ npm install -g cc-brain
50
+ cc-brain install
51
51
  ```
52
52
 
53
53
  ### bun
@@ -64,8 +64,7 @@ cc-brain install
64
64
 
65
65
  ### Upgrade
66
66
  ```bash
67
- npm install -g cc-brain@latest
68
- cc-brain install
67
+ npx cc-brain@latest install
69
68
  ```
70
69
 
71
70
  ---
@@ -202,6 +201,7 @@ src/
202
201
  recall.js Scored archive search with safe regex and color detection
203
202
  archive.js Archive management (list, prune, stats)
204
203
  project-id.js Stable project identity (.brain-id)
204
+ saver-prompt.md Instructions for saving
205
205
  bin/
206
206
  cc-brain.js CLI entry point with fast runtime detection
207
207
  hooks/
@@ -213,6 +213,7 @@ skills/
213
213
  scripts/
214
214
  install.js Install hooks + skills to ~/.claude/
215
215
  uninstall.js Remove hooks + skills (--purge for full removal)
216
+ plugin.json Plugin manifest
216
217
  ```
217
218
 
218
219
  ---
package/hooks/hooks.json CHANGED
@@ -1,27 +1,27 @@
1
- {
2
- "SessionStart": [
3
- {
4
- "matcher": "startup|resume|compact",
5
- "hooks": [
6
- {
7
- "type": "command",
8
- "command": "npx cc-brain load",
9
- "timeout": 10,
10
- "statusMessage": "Loading brain..."
11
- }
12
- ]
13
- }
14
- ],
15
- "PreCompact": [
16
- {
17
- "hooks": [
18
- {
19
- "type": "agent",
20
- "prompt": "Context is being compacted. Save important information using the structured saver.\n\nANALYZE this session for:\n- New user insights (T1 - rare)\n- New preferences (T1 - rare)\n- Project decisions + rationale (T2)\n- Current focus/state (T2)\n- Session summary (T3 - if significant)\n\nBUILD JSON payload:\n```json\n{\n \"t2\": {\n \"what\": \"Project description\",\n \"focus\": [\"current tasks\"],\n \"decisions\": {\"decision\": \"rationale\"}\n },\n \"t3\": \"Session summary if significant work done.\"\n}\n```\n\nSAVE using:\n```bash\nnpx cc-brain save --json '<payload>'\n```\n\nRules:\n- Only include tiers with new info\n- T2 updates are common, T1 updates are rare\n- Decisions need rationale\n- Keep it concise",
21
- "timeout": 120,
22
- "statusMessage": "Saving to brain..."
23
- }
24
- ]
25
- }
26
- ]
27
- }
1
+ {
2
+ "SessionStart": [
3
+ {
4
+ "matcher": "startup|resume|compact",
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "npx cc-brain load",
9
+ "timeout": 10,
10
+ "statusMessage": "Loading brain..."
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "PreCompact": [
16
+ {
17
+ "hooks": [
18
+ {
19
+ "type": "agent",
20
+ "prompt": "Context is being compacted. Save important information using the structured saver.\n\nANALYZE this session for:\n- New user insights (T1 - rare)\n- New preferences (T1 - rare)\n- Project decisions + rationale (T2)\n- Current focus/state (T2)\n- Session summary (T3 - if significant)\n\nBUILD JSON payload:\n```json\n{\n \"t2\": {\n \"what\": \"Project description\",\n \"focus\": [\"current tasks\"],\n \"decisions\": {\"decision\": \"rationale\"}\n },\n \"t3\": \"Session summary if significant work done.\"\n}\n```\n\nSAVE using:\n```bash\nnpx cc-brain save --json '<payload>'\n```\n\nRules:\n- Only include tiers with new info\n- T2 updates are common, T1 updates are rare\n- Decisions need rationale\n- Keep it concise",
21
+ "timeout": 120,
22
+ "statusMessage": "Saving to brain..."
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-brain",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
4
4
  "description": "Persistent memory system for Claude Code - remembers context across sessions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,136 +1,137 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Install cc-brain
5
- * Sets up brain directory and hooks
6
- */
7
-
8
- import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync, realpathSync } from 'fs';
9
- import { join, dirname } from 'path';
10
- import { homedir } from 'os';
11
- import { fileURLToPath } from 'url';
12
-
13
- const HOME = homedir();
14
- const CLAUDE_DIR = join(HOME, '.claude');
15
- const BRAIN_DIR = join(CLAUDE_DIR, 'brain');
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const PROJECT_ROOT = join(__dirname, '..');
18
-
19
- console.log('Installing cc-brain...\n');
20
-
21
- // Create brain directory structure
22
- const dirs = [
23
- BRAIN_DIR,
24
- join(BRAIN_DIR, 'projects')
25
- ];
26
-
27
- for (const dir of dirs) {
28
- if (!existsSync(dir)) {
29
- mkdirSync(dir, { recursive: true });
30
- console.log(`Created: ${dir}`);
31
- }
32
- }
33
-
34
- // Clean up legacy files from previous versions
35
- const legacyFiles = [
36
- join(BRAIN_DIR, 'load-brain.sh'),
37
- ];
38
-
39
- for (const file of legacyFiles) {
40
- if (existsSync(file)) {
41
- unlinkSync(file);
42
- console.log(`Removed: ${file} (legacy)`);
43
- }
44
- }
45
-
46
- // Copy template brain files if they don't exist
47
- const templates = ['user.md', 'preferences.md'];
48
- for (const file of templates) {
49
- const dest = join(BRAIN_DIR, file);
50
- if (!existsSync(dest)) {
51
- copyFileSync(join(PROJECT_ROOT, 'brain', file), dest);
52
- console.log(`Created: ${dest}`);
53
- } else {
54
- console.log(`Exists: ${dest} (skipped)`);
55
- }
56
- }
57
-
58
- // Add hooks to settings.json
59
- const settingsPath = join(CLAUDE_DIR, 'settings.json');
60
- let settings = {};
61
-
62
- if (existsSync(settingsPath)) {
63
- settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
64
- }
65
-
66
- // Read our hooks config
67
- const hooks = JSON.parse(readFileSync(join(PROJECT_ROOT, 'hooks', 'hooks.json'), 'utf-8'));
68
-
69
- // Resolve absolute paths — avoids PATH issues on macOS with nvm/fnm/volta
70
- // Hook subprocesses don't source shell profiles, so npx/node may not be on PATH
71
- let nodePath;
72
- try {
73
- nodePath = realpathSync(process.execPath);
74
- } catch {
75
- nodePath = process.execPath;
76
- }
77
- const loaderScript = join(PROJECT_ROOT, 'src', 'loader.js');
78
- hooks.SessionStart[0].hooks[0].command = `"${nodePath}" "${loaderScript}"`;
79
-
80
- // Merge hooks — preserve user's other hooks, replace/append ours
81
- function isCcBrainHook(entry) {
82
- if (!entry || !entry.hooks) return false;
83
- return entry.hooks.some(h =>
84
- (h.command && (h.command.includes('cc-brain') || h.command.includes('loader.js'))) ||
85
- (h.prompt && h.prompt.includes('structured saver'))
86
- );
87
- }
88
-
89
- function mergeHookArray(existing, ours) {
90
- if (!existing) return ours;
91
- // Filter out old cc-brain hooks, then append ours
92
- const filtered = existing.filter(entry => !isCcBrainHook(entry));
93
- return [...filtered, ...ours];
94
- }
95
-
96
- settings.hooks = settings.hooks || {};
97
- settings.hooks.SessionStart = mergeHookArray(settings.hooks.SessionStart, hooks.SessionStart);
98
- settings.hooks.PreCompact = mergeHookArray(settings.hooks.PreCompact, hooks.PreCompact);
99
-
100
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
101
- console.log(`\nUpdated: ${settingsPath}`);
102
-
103
- // --- Install Skills to ~/.claude/skills/ ---
104
- const SKILLS_DIR = join(CLAUDE_DIR, 'skills');
105
- const skillNames = ['save', 'recall', 'brain'];
106
-
107
- for (const name of skillNames) {
108
- const skillDir = join(SKILLS_DIR, name);
109
- mkdirSync(skillDir, { recursive: true });
110
- copyFileSync(
111
- join(PROJECT_ROOT, 'skills', `${name}.md`),
112
- join(skillDir, 'SKILL.md')
113
- );
114
- }
115
-
116
- console.log(`\nInstalled skills to: ${SKILLS_DIR}`);
117
- console.log(' /save, /recall, /brain');
118
-
119
- console.log(`
120
- cc-brain installed!
121
-
122
- Brain location: ${BRAIN_DIR}
123
-
124
- Memory tiers:
125
- T1 (always): user.md, preferences.md
126
- T2 (project): projects/{name}/context.md
127
- T3 (archive): projects/{name}/archive/
128
-
129
- Hooks installed:
130
- SessionStart → loads T1 + T2 into context
131
- PreCompact saves important bits before compaction
132
-
133
- Edit your brain:
134
- ${BRAIN_DIR}/user.md
135
- ${BRAIN_DIR}/preferences.md
136
- `);
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Install cc-brain
5
+ * Sets up brain directory and hooks
6
+ */
7
+
8
+ import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync, realpathSync } from 'fs';
9
+ import { join, dirname } from 'path';
10
+ import { homedir } from 'os';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const HOME = homedir();
14
+ const CLAUDE_DIR = join(HOME, '.claude');
15
+ const BRAIN_DIR = join(CLAUDE_DIR, 'brain');
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const PROJECT_ROOT = join(__dirname, '..');
18
+
19
+ console.log('Installing cc-brain...\n');
20
+
21
+ // Create brain directory structure
22
+ const dirs = [
23
+ BRAIN_DIR,
24
+ join(BRAIN_DIR, 'projects')
25
+ ];
26
+
27
+ for (const dir of dirs) {
28
+ if (!existsSync(dir)) {
29
+ mkdirSync(dir, { recursive: true });
30
+ console.log(`Created: ${dir}`);
31
+ }
32
+ }
33
+
34
+ // Clean up legacy files from previous versions
35
+ const legacyFiles = [
36
+ join(BRAIN_DIR, 'load-brain.sh'),
37
+ ];
38
+
39
+ for (const file of legacyFiles) {
40
+ if (existsSync(file)) {
41
+ unlinkSync(file);
42
+ console.log(`Removed: ${file} (legacy)`);
43
+ }
44
+ }
45
+
46
+ // Copy template brain files if they don't exist
47
+ const templates = ['user.md', 'preferences.md'];
48
+ for (const file of templates) {
49
+ const dest = join(BRAIN_DIR, file);
50
+ if (!existsSync(dest)) {
51
+ copyFileSync(join(PROJECT_ROOT, 'brain', file), dest);
52
+ console.log(`Created: ${dest}`);
53
+ } else {
54
+ console.log(`Exists: ${dest} (skipped)`);
55
+ }
56
+ }
57
+
58
+ // Add hooks to settings.json
59
+ const settingsPath = join(CLAUDE_DIR, 'settings.json');
60
+ let settings = {};
61
+
62
+ if (existsSync(settingsPath)) {
63
+ settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
64
+ }
65
+
66
+ // Read our hooks config
67
+ const hooks = JSON.parse(readFileSync(join(PROJECT_ROOT, 'hooks', 'hooks.json'), 'utf-8'));
68
+
69
+ // Resolve absolute paths — avoids PATH issues on macOS with nvm/fnm/volta
70
+ // Hook subprocesses don't source shell profiles, so npx/node may not be on PATH
71
+ let nodePath;
72
+ try {
73
+ nodePath = realpathSync(process.execPath);
74
+ } catch {
75
+ nodePath = process.execPath;
76
+ }
77
+ const loaderScript = join(PROJECT_ROOT, 'src', 'loader.js');
78
+ hooks.SessionStart[0].hooks[0].command = `"${nodePath}" "${loaderScript}"`;
79
+
80
+ // Merge hooks — preserve user's other hooks, replace/append ours
81
+ function isCcBrainHook(entry) {
82
+ if (!entry || !entry.hooks) return false;
83
+ return entry.hooks.some(h =>
84
+ (h.command && (h.command.includes('cc-brain') || h.command.includes('loader.js'))) ||
85
+ (h.prompt && h.prompt.includes('structured saver')) ||
86
+ (h.statusMessage && h.statusMessage.includes('brain'))
87
+ );
88
+ }
89
+
90
+ function mergeHookArray(existing, ours) {
91
+ if (!existing) return ours;
92
+ // Filter out old cc-brain hooks, then append ours
93
+ const filtered = existing.filter(entry => !isCcBrainHook(entry));
94
+ return [...filtered, ...ours];
95
+ }
96
+
97
+ settings.hooks = settings.hooks || {};
98
+ settings.hooks.SessionStart = mergeHookArray(settings.hooks.SessionStart, hooks.SessionStart);
99
+ settings.hooks.PreCompact = mergeHookArray(settings.hooks.PreCompact, hooks.PreCompact);
100
+
101
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
102
+ console.log(`\nUpdated: ${settingsPath}`);
103
+
104
+ // --- Install Skills to ~/.claude/skills/ ---
105
+ const SKILLS_DIR = join(CLAUDE_DIR, 'skills');
106
+ const skillNames = ['save', 'recall', 'brain'];
107
+
108
+ for (const name of skillNames) {
109
+ const skillDir = join(SKILLS_DIR, name);
110
+ mkdirSync(skillDir, { recursive: true });
111
+ copyFileSync(
112
+ join(PROJECT_ROOT, 'skills', `${name}.md`),
113
+ join(skillDir, 'SKILL.md')
114
+ );
115
+ }
116
+
117
+ console.log(`\nInstalled skills to: ${SKILLS_DIR}`);
118
+ console.log(' /save, /recall, /brain');
119
+
120
+ console.log(`
121
+ cc-brain installed!
122
+
123
+ Brain location: ${BRAIN_DIR}
124
+
125
+ Memory tiers:
126
+ T1 (always): user.md, preferences.md
127
+ T2 (project): projects/{name}/context.md
128
+ T3 (archive): projects/{name}/archive/
129
+
130
+ Hooks installed:
131
+ SessionStart loads T1 + T2 into context
132
+ PreCompact → saves important bits before compaction
133
+
134
+ Edit your brain:
135
+ ${BRAIN_DIR}/user.md
136
+ ${BRAIN_DIR}/preferences.md
137
+ `);
@@ -24,7 +24,8 @@ function isCcBrainHook(entry) {
24
24
  if (!entry || !entry.hooks) return false;
25
25
  return entry.hooks.some(h =>
26
26
  (h.command && (h.command.includes('cc-brain') || h.command.includes('loader.js'))) ||
27
- (h.prompt && h.prompt.includes('structured saver'))
27
+ (h.prompt && h.prompt.includes('structured saver')) ||
28
+ (h.statusMessage && h.statusMessage.includes('brain'))
28
29
  );
29
30
  }
30
31