metame-cli 1.1.3 β 1.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 +134 -25
- package/index.js +236 -3
- package/package.json +6 -2
- package/scripts/distill.js +495 -0
- package/scripts/migrate-v2.js +112 -0
- package/scripts/pending-traits.js +144 -0
- package/scripts/schema.js +186 -0
- package/scripts/signal-capture.js +125 -0
- package/README/344/270/255/346/226/207/347/211/210.md +0 -175
- package/logo.png +0 -0
package/README.md
CHANGED
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
<img src="./logo.png" alt="MetaMe Logo" width="200"/>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
> **The
|
|
7
|
+
> **The Cognitive Profile Layer for Claude Code.**
|
|
8
8
|
>
|
|
9
|
-
> *
|
|
9
|
+
> *Not a memory system β a cognitive mirror. It knows how you think, decide, and communicate, and it protects your core values.*
|
|
10
10
|
|
|
11
11
|
## π Introduction
|
|
12
12
|
|
|
13
13
|
**Claude Code** is a powerful tool, but it suffers from "Project Amnesia." Every time you switch folders, it forgets who you are, your communication style, and your specific constraints.
|
|
14
14
|
|
|
15
|
-
**MetaMe** solves this by wrapping Claude in a **
|
|
15
|
+
**MetaMe** solves this by wrapping Claude in a **Cognitive Profile Layer** . It creates a persistent "Global Brain" that travels with you across every project. Unlike ChatGPT/Claude/Gemini's built-in memory (which stores *facts* like "user lives in X"), MetaMe captures *how you think* β your decision style, cognitive load preferences, motivation patterns, and communication traits.
|
|
16
16
|
|
|
17
|
-
It is not
|
|
17
|
+
It is not a memory system; it is a **Cognitive Mirror** .
|
|
18
18
|
|
|
19
19
|
## β¨ Key Features
|
|
20
20
|
|
|
@@ -23,20 +23,16 @@ It is not just a launcher; it is a **Meta Avatar** .
|
|
|
23
23
|
* **π€ Dynamic Handshake Protocol:** The "Canary Test." MetaMe verifies its connection to your profile by addressing you by your chosen **Codename** in the very first sentence. If it doesn't, you know the link is broken.
|
|
24
24
|
* **π‘οΈ Auto-Lock Mechanism:** Mark any value in your profile with `# [LOCKED]`, and MetaMe will treat it as a constitution that cannot be overwritten.
|
|
25
25
|
* **π Smart Injection:** Automatically injects your profile context into the `CLAUDE.md` of any project you enter, ensuring seamless context switching.
|
|
26
|
+
* **π§ Passive Distillation:** MetaMe silently captures your messages via Claude Code hooks and, on next launch, uses a lightweight LLM (Haiku) to extract cognitive traits and preferences β automatically merging them into your profile with confidence-based upsert. Zero manual effort required.
|
|
27
|
+
* **π Schema-Enforced Profile:** A 41-field whitelist across 5 tiers (T1-T5) prevents profile bloat. Fields have type validation, enum constraints, and token budget limits (800 tokens max).
|
|
28
|
+
* **π― Confidence-Based Learning:** Strong directives ("always"/"δ»₯εδΈεΎ") write directly. Normal observations accumulate in a pending queue and only promote to the profile after 3 consistent observations β preventing single-session bias.
|
|
26
29
|
|
|
27
30
|
## π Prerequisites
|
|
28
31
|
|
|
29
|
-
MetaMe is a wrapper around
|
|
32
|
+
MetaMe is a wrapper around **Claude Code**. You must have Node.js and the official Claude Code tool installed first.
|
|
30
33
|
|
|
31
|
-
1. **Node.js
|
|
32
|
-
2. **Claude Code
|
|
33
|
-
**Bash**
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
npm install -g @anthropic-ai/claude-code
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
1. **Auth** : Ensure you have logged in via `claude login`.
|
|
34
|
+
1. **Node.js**: Version 14 or higher.
|
|
35
|
+
2. **Claude Code**: Ensure `claude` is available in your PATH and you are logged in.
|
|
40
36
|
|
|
41
37
|
## π¦ Installation
|
|
42
38
|
|
|
@@ -84,6 +80,53 @@ When you run MetaMe for the first time, it will detect that your profile is empt
|
|
|
84
80
|
3. Claude will start and immediately say: *"Ready, [Your Name]..."*
|
|
85
81
|
4. Start coding. MetaMe manages the context in the background.
|
|
86
82
|
|
|
83
|
+
### Global Initialization (Reset/Interview)
|
|
84
|
+
|
|
85
|
+
If you want to restart the **Genesis Interview** to update your psychological profile:
|
|
86
|
+
|
|
87
|
+
**Bash**
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
metame interview
|
|
91
|
+
```
|
|
92
|
+
(Command to be implemented in v1.3 - currently you can manually edit `~/.claude_profile.yaml` or use `set-trait`)
|
|
93
|
+
|
|
94
|
+
### Surgical Update (Manual Override)
|
|
95
|
+
|
|
96
|
+
If you need to update a specific trait without editing the file manually:
|
|
97
|
+
|
|
98
|
+
**Bash**
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
metame set-trait status.focus "Learning Rust"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Passive Distillation (Automatic)
|
|
105
|
+
|
|
106
|
+
MetaMe automatically learns your cognitive patterns from conversations β no action needed.
|
|
107
|
+
|
|
108
|
+
**How it works:**
|
|
109
|
+
|
|
110
|
+
1. A global Claude Code hook captures every message, tagging each with a **confidence level** (high for strong directives like "always"/"δ»₯εδΈεΎ", normal otherwise).
|
|
111
|
+
2. On your next `metame` launch, a background Haiku model analyzes the buffer and extracts cognitive traits and preferences.
|
|
112
|
+
3. **High-confidence** traits write directly to your profile. **Normal-confidence** traits enter a pending queue (`~/.metame/pending_traits.yaml`) and only promote after 3+ consistent observations.
|
|
113
|
+
4. All writes are validated against a **41-field schema whitelist** β unknown keys are silently dropped, enum fields are type-checked, and a **token budget** (800 max) prevents bloat.
|
|
114
|
+
5. The buffer is cleared, and Claude starts with a clean context.
|
|
115
|
+
|
|
116
|
+
**Anti-bias safeguards:**
|
|
117
|
+
- Single observations are treated as states, not traits
|
|
118
|
+
- Contradictions are tracked, not blindly overwritten
|
|
119
|
+
- Pending traits expire after 30 days without re-observation
|
|
120
|
+
- Context fields (focus, energy) auto-expire on staleness
|
|
121
|
+
|
|
122
|
+
You'll see this in the startup log:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
π§ MetaMe: Distilling 7 moments in background...
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The hook is installed automatically on first run to `~/.claude/settings.json` (global scope β works across all projects).
|
|
129
|
+
|
|
87
130
|
### Hot Reload (Refresh)
|
|
88
131
|
|
|
89
132
|
If you update your profile or need to fix a broken context **without restarting your session**:
|
|
@@ -101,25 +144,63 @@ Your profile is stored in a hidden YAML file in your home directory.
|
|
|
101
144
|
|
|
102
145
|
You can edit this file manually to update your status or lock your values.
|
|
103
146
|
|
|
104
|
-
**Example Profile:**
|
|
147
|
+
**Example Profile (v2 Schema):**
|
|
105
148
|
|
|
106
149
|
**YAML**
|
|
107
150
|
|
|
108
151
|
```
|
|
152
|
+
# === T1: Identity (LOCKED) ===
|
|
109
153
|
identity:
|
|
154
|
+
nickname: Neo # [LOCKED]
|
|
110
155
|
role: Senior Architect
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
156
|
+
locale: en-US # [LOCKED]
|
|
157
|
+
|
|
158
|
+
# === T2: Core Traits (LOCKED) ===
|
|
159
|
+
core_traits:
|
|
160
|
+
crisis_reflex: Analysis # [LOCKED]
|
|
161
|
+
flow_trigger: Debugging # [LOCKED]
|
|
162
|
+
learning_style: Hands-on # [LOCKED]
|
|
163
|
+
|
|
164
|
+
# === T3: Preferences (auto-learnable) ===
|
|
165
|
+
preferences:
|
|
166
|
+
code_style: concise
|
|
167
|
+
communication: direct
|
|
168
|
+
explanation_depth: brief_rationale
|
|
169
|
+
|
|
170
|
+
# === T3b: Cognition (auto-learnable, slow to change) ===
|
|
115
171
|
cognition:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
172
|
+
decision_style: analytical
|
|
173
|
+
info_processing:
|
|
174
|
+
entry_point: big_picture
|
|
175
|
+
preferred_format: structured
|
|
176
|
+
cognitive_load:
|
|
177
|
+
chunk_size: medium
|
|
178
|
+
preferred_response_length: moderate
|
|
179
|
+
|
|
180
|
+
# === T4: Context (auto-overwrite) ===
|
|
181
|
+
context:
|
|
182
|
+
focus: "Refactoring Legacy Code"
|
|
183
|
+
energy: high
|
|
184
|
+
|
|
185
|
+
# === T5: Evolution (system-managed) ===
|
|
186
|
+
evolution:
|
|
187
|
+
distill_count: 12
|
|
188
|
+
last_distill: "2026-01-30T10:00:00Z"
|
|
120
189
|
```
|
|
121
190
|
|
|
122
|
-
*
|
|
191
|
+
* **T1-T2 fields** marked `# [LOCKED]` are never auto-modified.
|
|
192
|
+
* **T3 fields** are auto-learned with confidence thresholds.
|
|
193
|
+
* **T4 fields** are freely overwritten as your context changes.
|
|
194
|
+
* **T5 fields** are managed by the distillation system.
|
|
195
|
+
|
|
196
|
+
### Profile Migration (v1 β v2)
|
|
197
|
+
|
|
198
|
+
If you have an existing v1 profile, run the migration script:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
node ~/.metame/migrate-v2.js --dry-run # preview changes
|
|
202
|
+
node ~/.metame/migrate-v2.js # apply migration (auto-backup created)
|
|
203
|
+
```
|
|
123
204
|
|
|
124
205
|
## ποΈ Uninstallation
|
|
125
206
|
|
|
@@ -145,7 +226,34 @@ If you want to delete your stored profile data:
|
|
|
145
226
|
rm ~/.claude_profile.yaml
|
|
146
227
|
```
|
|
147
228
|
|
|
148
|
-
### 3.
|
|
229
|
+
### 3. Remove Passive Distillation Data (Optional)
|
|
230
|
+
|
|
231
|
+
Remove the signal capture scripts:
|
|
232
|
+
|
|
233
|
+
**Bash**
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
rm -rf ~/.metame
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 4. Remove the Signal Capture Hook (Optional)
|
|
240
|
+
|
|
241
|
+
MetaMe installs a global hook in `~/.claude/settings.json`. To remove it, edit the file and delete the `UserPromptSubmit` entry under `hooks`, or run:
|
|
242
|
+
|
|
243
|
+
**Bash**
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
node -e "
|
|
247
|
+
const fs = require('fs');
|
|
248
|
+
const p = require('os').homedir() + '/.claude/settings.json';
|
|
249
|
+
const s = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
250
|
+
if (s.hooks) { delete s.hooks.UserPromptSubmit; }
|
|
251
|
+
fs.writeFileSync(p, JSON.stringify(s, null, 2));
|
|
252
|
+
console.log('Hook removed.');
|
|
253
|
+
"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 5. Cleanup Project Files (Optional)
|
|
149
257
|
|
|
150
258
|
MetaMe adds a header to `CLAUDE.md` files in your projects. To restore them to their original state (if you have many), you can use a text editor to remove the block starting with `## π§ SYSTEM KERNEL`.
|
|
151
259
|
|
|
@@ -158,6 +266,7 @@ You might worry: *"Does this eat up my context window?"*
|
|
|
158
266
|
* **Context Cost**: The entire MetaMe kernel + your profile takes up **~800-1000 tokens**.
|
|
159
267
|
* **Impact**: On a 200k context window, this is **0.5%** of the memory.
|
|
160
268
|
* **ROI**: By pre-loading your context, you avoid the "instructional drift" and repetitive correction loops that usually waste thousands of tokens at the start of every session.
|
|
269
|
+
* **Passive Distillation Cost**: The signal capture hook is a local Node.js script (zero API calls). The Haiku distillation on launch processes only a small buffer of filtered messages β typically a few hundred tokens at Haiku's very low cost.
|
|
161
270
|
|
|
162
271
|
## β FAQ
|
|
163
272
|
|
package/index.js
CHANGED
|
@@ -11,6 +11,181 @@ const { spawn } = require('child_process');
|
|
|
11
11
|
const HOME_DIR = os.homedir();
|
|
12
12
|
const BRAIN_FILE = path.join(HOME_DIR, '.claude_profile.yaml');
|
|
13
13
|
const PROJECT_FILE = path.join(process.cwd(), 'CLAUDE.md');
|
|
14
|
+
const METAME_DIR = path.join(HOME_DIR, '.metame');
|
|
15
|
+
const CLAUDE_SETTINGS = path.join(HOME_DIR, '.claude', 'settings.json');
|
|
16
|
+
const SIGNAL_CAPTURE_SCRIPT = path.join(METAME_DIR, 'signal-capture.js');
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------
|
|
19
|
+
// 1.5 ENSURE METAME DIRECTORY + DEPLOY SCRIPTS
|
|
20
|
+
// ---------------------------------------------------------
|
|
21
|
+
if (!fs.existsSync(METAME_DIR)) {
|
|
22
|
+
fs.mkdirSync(METAME_DIR, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Auto-deploy bundled scripts to ~/.metame/
|
|
26
|
+
const BUNDLED_SCRIPTS = ['signal-capture.js', 'distill.js', 'schema.js', 'pending-traits.js', 'migrate-v2.js'];
|
|
27
|
+
const scriptsDir = path.join(__dirname, 'scripts');
|
|
28
|
+
|
|
29
|
+
for (const script of BUNDLED_SCRIPTS) {
|
|
30
|
+
const src = path.join(scriptsDir, script);
|
|
31
|
+
const dest = path.join(METAME_DIR, script);
|
|
32
|
+
try {
|
|
33
|
+
if (fs.existsSync(src)) {
|
|
34
|
+
const srcContent = fs.readFileSync(src, 'utf8');
|
|
35
|
+
const destContent = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : '';
|
|
36
|
+
if (srcContent !== destContent) {
|
|
37
|
+
fs.writeFileSync(dest, srcContent, 'utf8');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// Non-fatal
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------
|
|
46
|
+
// 1.6 AUTO-INSTALL SIGNAL CAPTURE HOOK
|
|
47
|
+
// ---------------------------------------------------------
|
|
48
|
+
function ensureHookInstalled() {
|
|
49
|
+
try {
|
|
50
|
+
// Ensure ~/.claude/ exists
|
|
51
|
+
const claudeDir = path.join(HOME_DIR, '.claude');
|
|
52
|
+
if (!fs.existsSync(claudeDir)) {
|
|
53
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let settings = {};
|
|
57
|
+
if (fs.existsSync(CLAUDE_SETTINGS)) {
|
|
58
|
+
settings = JSON.parse(fs.readFileSync(CLAUDE_SETTINGS, 'utf8'));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check if our hook is already configured
|
|
62
|
+
const hookCommand = `node ${SIGNAL_CAPTURE_SCRIPT}`;
|
|
63
|
+
const existing = settings.hooks?.UserPromptSubmit || [];
|
|
64
|
+
const alreadyInstalled = existing.some(entry =>
|
|
65
|
+
entry.hooks?.some(h => h.command === hookCommand)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (!alreadyInstalled) {
|
|
69
|
+
if (!settings.hooks) settings.hooks = {};
|
|
70
|
+
if (!settings.hooks.UserPromptSubmit) settings.hooks.UserPromptSubmit = [];
|
|
71
|
+
|
|
72
|
+
settings.hooks.UserPromptSubmit.push({
|
|
73
|
+
hooks: [{
|
|
74
|
+
type: 'command',
|
|
75
|
+
command: hookCommand
|
|
76
|
+
}]
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2), 'utf8');
|
|
80
|
+
console.log("πͺ MetaMe: Signal capture hook installed.");
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
// Non-fatal: hook install failure shouldn't block launch
|
|
84
|
+
console.error("β οΈ Hook install skipped:", e.message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ensureHookInstalled();
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------
|
|
91
|
+
// 1.7 PASSIVE DISTILLATION (Background, post-launch)
|
|
92
|
+
// ---------------------------------------------------------
|
|
93
|
+
function shouldDistill() {
|
|
94
|
+
const bufferFile = path.join(METAME_DIR, 'raw_signals.jsonl');
|
|
95
|
+
if (!fs.existsSync(bufferFile)) return false;
|
|
96
|
+
const content = fs.readFileSync(bufferFile, 'utf8').trim();
|
|
97
|
+
return content.length > 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function spawnDistillBackground() {
|
|
101
|
+
const distillPath = path.join(METAME_DIR, 'distill.js');
|
|
102
|
+
if (!fs.existsSync(distillPath)) return;
|
|
103
|
+
if (!shouldDistill()) return;
|
|
104
|
+
|
|
105
|
+
const bufferFile = path.join(METAME_DIR, 'raw_signals.jsonl');
|
|
106
|
+
const lines = fs.readFileSync(bufferFile, 'utf8').trim().split('\n').filter(l => l.trim());
|
|
107
|
+
console.log(`π§ MetaMe: Distilling ${lines.length} moment${lines.length > 1 ? 's' : ''} in background...`);
|
|
108
|
+
|
|
109
|
+
// Spawn as detached background process β won't block Claude launch
|
|
110
|
+
const bg = spawn('node', [distillPath], {
|
|
111
|
+
detached: true,
|
|
112
|
+
stdio: 'ignore'
|
|
113
|
+
});
|
|
114
|
+
bg.unref();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ---------------------------------------------------------
|
|
118
|
+
// 1.8 TIME-BASED EXPIRY (Startup cleanup)
|
|
119
|
+
// ---------------------------------------------------------
|
|
120
|
+
function runExpiryCleanup() {
|
|
121
|
+
try {
|
|
122
|
+
const yaml = require('js-yaml');
|
|
123
|
+
if (!fs.existsSync(BRAIN_FILE)) return;
|
|
124
|
+
|
|
125
|
+
const rawProfile = fs.readFileSync(BRAIN_FILE, 'utf8');
|
|
126
|
+
const profile = yaml.load(rawProfile);
|
|
127
|
+
if (!profile || typeof profile !== 'object') return;
|
|
128
|
+
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
let changed = false;
|
|
131
|
+
|
|
132
|
+
// context.focus: if focus_since > 30 days, auto-clear
|
|
133
|
+
if (profile.context && profile.context.focus_since) {
|
|
134
|
+
const focusSince = new Date(profile.context.focus_since).getTime();
|
|
135
|
+
if (now - focusSince > 30 * 24 * 60 * 60 * 1000) {
|
|
136
|
+
profile.context.focus = null;
|
|
137
|
+
profile.context.focus_since = null;
|
|
138
|
+
changed = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// context.blockers: if > 14 days, auto-clear
|
|
143
|
+
// (blockers are arrays β clear entire array if stale)
|
|
144
|
+
if (profile.context && Array.isArray(profile.context.blockers) && profile.context.blockers.length > 0) {
|
|
145
|
+
// If we don't have a blockers_since timestamp, just leave them
|
|
146
|
+
// Future: add per-item timestamps
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// context.energy: reset to null on each session start
|
|
150
|
+
if (profile.context && profile.context.energy !== undefined) {
|
|
151
|
+
if (profile.context.energy !== null) {
|
|
152
|
+
profile.context.energy = null;
|
|
153
|
+
changed = true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (changed) {
|
|
158
|
+
// Preserve comments
|
|
159
|
+
const commentMatch = rawProfile.match(/^(\s*[\w_]+\s*:.+?)\s+(#.+)$/gm);
|
|
160
|
+
const dumped = yaml.dump(profile, { lineWidth: -1 });
|
|
161
|
+
fs.writeFileSync(BRAIN_FILE, dumped, 'utf8');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Expire stale pending traits
|
|
165
|
+
const pendingFile = path.join(METAME_DIR, 'pending_traits.yaml');
|
|
166
|
+
if (fs.existsSync(pendingFile)) {
|
|
167
|
+
const pending = yaml.load(fs.readFileSync(pendingFile, 'utf8')) || {};
|
|
168
|
+
const cutoff = 30 * 24 * 60 * 60 * 1000;
|
|
169
|
+
let expiredCount = 0;
|
|
170
|
+
for (const [key, meta] of Object.entries(pending)) {
|
|
171
|
+
if (meta.last_seen) {
|
|
172
|
+
const lastSeen = new Date(meta.last_seen).getTime();
|
|
173
|
+
if (now - lastSeen > cutoff) {
|
|
174
|
+
delete pending[key];
|
|
175
|
+
expiredCount++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (expiredCount > 0) {
|
|
180
|
+
fs.writeFileSync(pendingFile, yaml.dump(pending, { lineWidth: -1 }), 'utf8');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
// Non-fatal β expiry cleanup failure shouldn't block launch
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
runExpiryCleanup();
|
|
14
189
|
|
|
15
190
|
// ---------------------------------------------------------
|
|
16
191
|
// 2. BRAIN INITIALIZATION (Cold Start)
|
|
@@ -48,8 +223,10 @@ const CORE_PROTOCOL = `
|
|
|
48
223
|
|
|
49
224
|
**3. EVOLUTION MECHANISM (Manual Sync):**
|
|
50
225
|
* **PHILOSOPHY:** You respect the User's flow. You do NOT interrupt.
|
|
51
|
-
* **
|
|
52
|
-
|
|
226
|
+
* **TOOLS:**
|
|
227
|
+
1. **Log Insight:** \`!metame evolve "Insight"\` (For additive knowledge).
|
|
228
|
+
2. **Surgical Update:** \`!metame set-trait key value\` (For overwriting specific fields, e.g., \`!metame set-trait status.focus "API Design"\`).
|
|
229
|
+
* **RULE:** Only use these tools when the User **EXPLICITLY** instructs you.
|
|
53
230
|
* **REMINDER:** If the User expresses a strong persistent preference, you may gently ask *at the end of the task*: "Should I save this preference to your MetaMe profile?"
|
|
54
231
|
---
|
|
55
232
|
`;
|
|
@@ -182,6 +359,59 @@ if (isEvolve) {
|
|
|
182
359
|
process.exit(0);
|
|
183
360
|
}
|
|
184
361
|
|
|
362
|
+
// Check for "set-trait" command (Surgical Update)
|
|
363
|
+
const isSetTrait = process.argv.includes('set-trait');
|
|
364
|
+
|
|
365
|
+
if (isSetTrait) {
|
|
366
|
+
const yaml = require('js-yaml');
|
|
367
|
+
|
|
368
|
+
// Syntax: metame set-trait <key> <value>
|
|
369
|
+
// Example: metame set-trait identity.role "Engineering Manager"
|
|
370
|
+
|
|
371
|
+
const setIndex = process.argv.indexOf('set-trait');
|
|
372
|
+
const key = process.argv[setIndex + 1];
|
|
373
|
+
// Join the rest as the value (allows spaces)
|
|
374
|
+
const value = process.argv.slice(setIndex + 2).join(' ').trim();
|
|
375
|
+
|
|
376
|
+
if (!key || !value) {
|
|
377
|
+
console.error("β Error: Missing key or value.");
|
|
378
|
+
console.error(" Usage: metame set-trait identity.role \"New Role\"");
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
if (fs.existsSync(BRAIN_FILE)) {
|
|
384
|
+
const rawContent = fs.readFileSync(BRAIN_FILE, 'utf8');
|
|
385
|
+
const doc = yaml.load(rawContent) || {};
|
|
386
|
+
|
|
387
|
+
// Helper to set nested property
|
|
388
|
+
const setNested = (obj, path, val) => {
|
|
389
|
+
const keys = path.split('.');
|
|
390
|
+
let current = obj;
|
|
391
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
392
|
+
if (!current[keys[i]]) current[keys[i]] = {};
|
|
393
|
+
current = current[keys[i]];
|
|
394
|
+
}
|
|
395
|
+
current[keys[keys.length - 1]] = val;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Set the value
|
|
399
|
+
setNested(doc, key, value);
|
|
400
|
+
|
|
401
|
+
fs.writeFileSync(BRAIN_FILE, yaml.dump(doc), 'utf8');
|
|
402
|
+
|
|
403
|
+
console.log(`π§ MetaMe Brain Surgically Updated.`);
|
|
404
|
+
console.log(` Set \`${key}\` = "${value}"`);
|
|
405
|
+
console.log(" (Run 'metame refresh' to apply this to the current session)");
|
|
406
|
+
} else {
|
|
407
|
+
console.error("β Error: No profile found.");
|
|
408
|
+
}
|
|
409
|
+
} catch (e) {
|
|
410
|
+
console.error("β Error updating profile:", e.message);
|
|
411
|
+
}
|
|
412
|
+
process.exit(0);
|
|
413
|
+
}
|
|
414
|
+
|
|
185
415
|
// ---------------------------------------------------------
|
|
186
416
|
// ---------------------------------------------------------
|
|
187
417
|
// 6. SAFETY GUARD: RECURSION PREVENTION (v2)
|
|
@@ -208,4 +438,7 @@ child.on('error', (err) => {
|
|
|
208
438
|
console.error("\nβ Error: Could not launch 'claude'.");
|
|
209
439
|
console.error(" Please make sure Claude Code is installed globally:");
|
|
210
440
|
console.error(" npm install -g @anthropic-ai/claude-code");
|
|
211
|
-
});
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// Launch background distillation AFTER Claude starts β no blocking
|
|
444
|
+
spawnDistillBackground();
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metame-cli",
|
|
3
|
-
"version": "1.1
|
|
4
|
-
"description": "The
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "The Cognitive Profile Layer for Claude Code. Knows how you think, not just what you said.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"metame": "./index.js"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"scripts/"
|
|
12
|
+
],
|
|
9
13
|
"scripts": {
|
|
10
14
|
"start": "node index.js"
|
|
11
15
|
},
|