metame-cli 1.4.33 → 1.4.34

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
@@ -24,7 +24,7 @@ No cloud. Your machine, your data.
24
24
  curl -fsSL https://raw.githubusercontent.com/Yaron9/MetaMe/main/install.sh | bash
25
25
  ```
26
26
 
27
- **Already have Node.js ≥ 18:**
27
+ **Already have Node.js ≥ 22.5:**
28
28
  ```bash
29
29
  npm install -g metame-cli
30
30
  metame
@@ -38,13 +38,15 @@ metame
38
38
 
39
39
  ---
40
40
 
41
- > ### 🚀 v1.4.19Multi-User ACL + Session Context Preview
41
+ > ### 🚀 v1.4.336-Dimension Soul Schema + Nightly Reflection + Auto-Provisioning
42
42
  >
43
- > - **Multi-user permission system**: role-based ACL (admin / member / stranger) share your bots with teammates without giving them full access. Manage users with `/user` commands.
44
- > - **Session context preview**: `/resume` and `/sessions` now show the last message snippet so you know exactly what to pick up.
45
- > - **Team Task protocol**: multi-agent task board for cross-agent collaboration. Agents can dispatch and track tasks across workspaces.
46
- > - **Layered Memory Architecture**: three-layer memory (long-term facts, session summaries, session index)all automatic.
47
- > - **Unix Socket IPC**: dispatch latency <100ms.
43
+ > - **6-dimension soul schema**: cognitive profile upgraded from key-value pairs to a structured 67-field model covering Values, Drive, Cognition Style, Stress & Shadow, Relational, and Identity Narrative with tier-based lock protection.
44
+ > - **Nightly reflection**: every night, hot-zone facts are distilled into searchable decision logs and lessons learned.
45
+ > - **Memory index**: auto-generated global index of all memory documents for instant retrieval.
46
+ > - **Auto-provisioning**: first run automatically deploys default CLAUDE.md, docs, and `dispatch_to`zero manual setup.
47
+ > - **Token budget tracking**: daily token usage monitoring with per-category breakdown and 80% warning threshold.
48
+ > - **Multi-user ACL**: role-based permissions (admin / member / stranger) with binding protection.
49
+ > - **Windows native support**: cross-platform path handling, Named Pipes IPC, GBK-safe encoding.
48
50
  >
49
51
  > Zero configuration. It just works.
50
52
 
@@ -56,7 +58,9 @@ metame
56
58
 
57
59
  Claude Code forgets you every time you switch folders. MetaMe doesn't.
58
60
 
59
- A cognitive profile (`~/.claude_profile.yaml`) follows you everywhere — not just facts like "user prefers TypeScript", but *how you think*: your decision style, cognitive load preferences, communication patterns. It learns silently from your conversations via background distillation, no effort required.
61
+ A cognitive profile (`~/.claude_profile.yaml`) follows you everywhere — not just facts like "user prefers TypeScript", but *how you think*. The profile is built on a **6-dimension soul schema**: Values, Drive, Cognition Style, Stress & Shadow, Relational, and Identity Narrative — 67 fields organized into 4 tiers (T1 locked identity → T5 system-managed evolution). First-time users go through a **Genesis Interview**: a structured deep conversation that builds your cognitive fingerprint from scratch.
62
+
63
+ Once established, the profile updates silently from your conversations via background distillation — no effort required.
60
64
 
61
65
  ```
62
66
  $ metame
@@ -80,7 +84,7 @@ Start on your laptop, continue on the train. `/stop` to interrupt, `/undo` to ro
80
84
 
81
85
  ### 3. Layered Memory That Works While You Sleep
82
86
 
83
- MetaMe's memory system runs automatically in the background — no prompts, no manual saves.
87
+ MetaMe's memory system runs automatically in the background — no prompts, no manual saves. Five layers, fully autonomous.
84
88
 
85
89
  **Layer 1 — Long-term Facts**
86
90
  When you go idle, MetaMe runs memory consolidation: extracts key decisions, patterns, and knowledge from your sessions into a persistent facts store. These are semantically recalled on every session start.
@@ -91,12 +95,20 @@ Resuming a conversation after 2+ hours? MetaMe injects a brief summary of what y
91
95
  **Layer 3 — Session Index**
92
96
  Every session gets tagged with topics and intent. This powers future session routing: when you reference "that thing we worked on last week", MetaMe knows where to look.
93
97
 
98
+ **Layer 4 — Nightly Reflection**
99
+ Every night at 01:00, MetaMe reviews your most-accessed facts from the past week and distills them into high-level decision logs and operational lessons — searchable documents that grow your personal knowledge base over time.
100
+
101
+ **Layer 5 — Memory Index**
102
+ At 01:30, an auto-generated global index (`INDEX.md`) maps every memory document across all categories. This serves as a fast lookup table so MetaMe always knows where to find relevant context.
103
+
94
104
  ```
95
105
  [Background, while you sleep]
96
106
  idle 30min → memory consolidation triggered
97
107
  → session_tags.json updated (topics indexed)
98
108
  → facts extracted → ~/.metame/memory.db
99
109
  → session summary cached → daemon_state.json
110
+ 01:00 → nightly reflection: hot facts → decisions + lessons
111
+ 01:30 → memory index regenerated
100
112
 
101
113
  [Next morning, when you resume]
102
114
  "continue from yesterday" →
@@ -117,12 +129,14 @@ Built into the daemon. Runs every 60 seconds regardless of what's in your config
117
129
  - Detects when you go idle → generates session continuity summaries
118
130
 
119
131
  **Layer 1 — System Evolution (built-in defaults)**
120
- Three tasks shipped out of the box. They are precondition-gated and run only when useful:
132
+ Five tasks shipped out of the box. They are precondition-gated and run only when useful:
121
133
 
122
134
  ```yaml
123
135
  - cognitive-distill # 4h · has signals? → distill preferences into profile
124
136
  - memory-extract # 4h · scan sessions → extract long-term facts + topic tags
125
137
  - skill-evolve # 6h · has signals? → evolve skills from task outcomes
138
+ - nightly-reflect # 01:00 daily · hot facts → decision logs + lessons learned
139
+ - memory-index # 01:30 daily · regenerate global memory index
126
140
  ```
127
141
 
128
142
  `precondition` guards mean zero tokens burned when there's nothing to process.
@@ -203,19 +217,21 @@ Task fails → skill-scout finds a skill → installs → retries → succeeds
203
217
  curl -fsSL https://raw.githubusercontent.com/Yaron9/MetaMe/main/install.sh | bash
204
218
  ```
205
219
 
206
- **Already have Node.js ≥ 18:**
220
+ **Already have Node.js ≥ 22.5:**
207
221
  ```bash
208
222
  npm install -g metame-cli
209
223
  metame
210
224
  ```
211
225
 
226
+ > **First run auto-provisioning:** MetaMe automatically deploys a default `CLAUDE.md`, documentation files, and the `dispatch_to` tool to `~/.metame/`. No manual setup needed.
227
+
212
228
  **Setup guide (3 minutes):**
213
229
 
214
230
  | Step | What to do | What happens |
215
231
  |------|-----------|-------------|
216
232
  | 1. Log in to Claude | Run `claude` and complete the login (Anthropic account or API key) | Claude Code is ready to use |
217
233
  | 2. Launch MetaMe | Run `metame` | Opens a Claude session with MetaMe loaded |
218
- | 3. Cognitive interview | Just chat — MetaMe will automatically start a deep interview on first run | Builds `~/.claude_profile.yaml` (your digital twin's brain) |
234
+ | 3. Genesis Interview | Just chat — MetaMe will automatically start a deep soul interview on first run | Builds `~/.claude_profile.yaml` (6-dimension cognitive profile) |
219
235
  | 4. Connect phone | Say "help me set up mobile access" or "connect my phone" | Interactive wizard for Telegram/Feishu bot setup → `~/.metame/daemon.yaml` |
220
236
  | 5. Start daemon | `metame start` | Background daemon launches, bot goes online |
221
237
  | 6. Register with system | macOS: `metame daemon install-launchd` · Windows: `metame daemon install-task-scheduler` · Linux: see below | Always-on, crash recovery |
@@ -281,11 +297,13 @@ systemctl --user start metame
281
297
 
282
298
  | Capability | What It Does |
283
299
  |-----------|-------------|
284
- | **Cognitive Profile** | Learns how you think across sessions. Schema-enforced, 800-token budget, auto-distilled via Haiku. Lock any value with `# [LOCKED]`. |
285
- | **Layered Memory** | Three-tier memory: long-term facts (semantic recall), session summaries (continuity bridge), session index (topic tags). All automatic. |
300
+ | **Cognitive Profile** | 6-dimension soul schema (Values, Drive, Cognition Style, Stress & Shadow, Relational, Identity Narrative). 67 fields, tier-locked, 800-token budget. First-time Genesis Interview builds your profile from scratch. |
301
+ | **Layered Memory** | Five-tier memory: long-term facts (semantic recall), session summaries (continuity bridge), session index (topic tags), nightly reflection (decision/lesson distillation), memory index (global lookup). All automatic. |
286
302
  | **Mobile Bridge** | Full Claude Code via Telegram/Feishu. Stateful sessions, file transfer both ways, real-time streaming status. |
287
303
  | **Skill Evolution** | Self-healing skill system. Auto-discovers missing skills, learns from browser recordings, evolves after every task. Skills get smarter over time. |
288
- | **Heartbeat System** | Three-layer programmable nervous system. Layer 0 kernel always-on (zero config). Layer 1 system evolution built-in (distill + memory + skills). Layer 2 your custom scheduled tasks with `require_idle`, `precondition`, `notify`, workflows. |
304
+ | **Token Budget** | Daily token usage tracking with per-category breakdown. Configurable daily limit, automatic 80% warning threshold, usage history with rollover. |
305
+ | **Auto-Provisioning** | First run deploys default CLAUDE.md, documentation, and `dispatch_to` to `~/.metame/`. Subsequent runs sync scripts without overwriting user config. |
306
+ | **Heartbeat System** | Three-layer programmable nervous system. Layer 0 kernel always-on (zero config). Layer 1 system evolution built-in (5 tasks: distill + memory + skills + nightly reflection + memory index). Layer 2 your custom scheduled tasks with `require_idle`, `precondition`, `notify`, workflows. |
289
307
  | **Multi-Agent** | Multiple projects with dedicated chat groups. `/agent bind` for one-tap setup. True parallel execution. |
290
308
  | **Browser Automation** | Built-in Playwright MCP. Browser control out of the box for every user. |
291
309
  | **Cross-Platform** | Native support for macOS and Windows. Platform abstraction layer handles spawn, IPC, process management, and terminal encoding automatically. |
@@ -429,27 +447,34 @@ All agents share your cognitive profile (`~/.claude_profile.yaml`) — they all
429
447
  │ └──────────────┘ │
430
448
  │ │
431
449
  │ ~/.claude_profile │
432
- │ (cognitive layer)
450
+ │ (6-dim soul schema)
433
451
  │ │
434
452
  │ ~/.metame/memory.db │
435
453
  │ session_tags.json │
436
- │ (memory layer) ← NEW
454
+ │ (5-layer memory)
455
+ │ │
456
+ │ dispatch_to (auto-deployed)│
437
457
  └──────────────────────────────┘
438
458
 
439
- idle mode → summaries + background memory tasks
440
- (automatic, precondition-gated)
459
+ idle → summaries + memory tasks
460
+ 01:00 → nightly reflection
461
+ 01:30 → memory index rebuild
441
462
  ```
442
463
 
443
- - **Profile** (`~/.claude_profile.yaml`): Your cognitive fingerprint. Injected into every Claude session via `CLAUDE.md`.
444
- - **Daemon** (`scripts/daemon.js`): Background process handling Telegram/Feishu messages, heartbeat tasks, Unix socket dispatch, and idle/sleep transitions.
445
- - **Distillation** (`scripts/distill.js`): Heartbeat task (default 4h, signal-gated) that updates your profile.
446
- - **Memory Extract** (`scripts/memory-extract.js`): Heartbeat task (default 4h, idle-gated) that extracts long-term facts and session topic tags.
447
- - **Session Summarize** (`scripts/session-summarize.js`): Generates a 2-4 sentence summary for idle sessions. Injected as context when resuming after a 2h+ gap.
464
+ - **Profile** (`~/.claude_profile.yaml`): 6-dimension soul schema. Injected into every Claude session via `CLAUDE.md`.
465
+ - **Daemon**: Background process handling Telegram/Feishu messages, heartbeat tasks, Unix socket dispatch, and idle/sleep transitions.
466
+ - **Distillation**: Heartbeat task (4h, signal-gated) that updates your cognitive profile.
467
+ - **Memory Extract**: Heartbeat task (4h, idle-gated) that extracts long-term facts and session topic tags.
468
+ - **Nightly Reflection**: Daily at 01:00. Distills hot-zone facts into decision logs and operational lessons.
469
+ - **Memory Index**: Daily at 01:30. Regenerates the global memory index for fast retrieval.
470
+ - **Session Summarize**: Generates a brief summary for idle sessions. Injected as context when resuming after a 2h+ gap.
448
471
 
449
472
  ## Security
450
473
 
451
474
  - All data stays on your machine. No cloud, no telemetry.
452
475
  - `allowed_chat_ids` whitelist — new groups get a smart prompt: if a pending agent activation exists, they're guided to send `/activate`; otherwise they receive setup instructions.
476
+ - **Multi-user ACL**: role-based permissions (admin / member / stranger). Admins manage access via `/user` commands with hot-reload config.
477
+ - **Binding protection**: each group can only be bound to one agent. Existing bindings cannot be overwritten without explicit `force:true`.
453
478
  - `operator_ids` for shared groups — non-operators get read-only mode.
454
479
  - `~/.metame/` directory is mode 700.
455
480
  - Bot tokens stored locally, never transmitted.
@@ -460,7 +485,7 @@ All agents share your cognitive profile (`~/.claude_profile.yaml`) — they all
460
485
  |--------|-------|
461
486
  | Daemon memory (idle) | ~100 MB RSS — standard Node.js process baseline |
462
487
  | Daemon CPU (idle, between heartbeats) | ~0% — event-loop sleeping |
463
- | Cognitive profile injection | ~600 tokens/session (0.3% of 200k context) |
488
+ | Cognitive profile injection | ~800 tokens/session (0.4% of 200k context) |
464
489
  | Dispatch latency (Unix socket) | <100ms |
465
490
  | Memory consolidation (per session) | ~1,500–2,000 tokens input + ~50–300 tokens output (Haiku) |
466
491
  | Session summary (per session) | ~400–900 tokens input + ≤250 tokens output (Haiku) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metame-cli",
3
- "version": "1.4.33",
3
+ "version": "1.4.34",
4
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": {
@@ -653,41 +653,18 @@ Reply with ONLY the name, nothing else. Examples: 插件开发, API重构, Bug
653
653
  }
654
654
 
655
655
  // Skill routing: detect skill first, then decide session
656
- // BUT: if agent was explicitly addressed by nickname, don't let skill routing hijack the session
657
- const skill = agentMatch ? null : routeSkill(prompt);
656
+ // BUT: skip skill routing if agent addressed by nickname OR chat already has an active session
657
+ // (active conversation should never be hijacked by keyword-based skill matching)
658
+ let session = getSession(chatId);
659
+ const hasActiveSession = session && session.started;
660
+ const skill = (agentMatch || hasActiveSession) ? null : routeSkill(prompt);
658
661
  const chatIdStr = String(chatId);
659
662
  const chatAgentMap = { ...(config.telegram ? config.telegram.chat_agent_map : {}), ...(config.feishu ? config.feishu.chat_agent_map : {}) };
660
663
  const boundProjectKey = chatAgentMap[chatIdStr] || projectKeyFromVirtualChatId(chatIdStr);
661
664
  const boundProject = boundProjectKey && config.projects ? config.projects[boundProjectKey] : null;
662
665
  const boundCwd = (boundProject && boundProject.cwd) ? normalizeCwd(boundProject.cwd) : null;
663
666
 
664
- // Skills with dedicated pinned sessions (reused across days, no re-injection needed)
665
- const PINNED_SKILL_SESSIONS = new Set(['skill-manager']);
666
- const usePinnedSkillSession = !!(skill && PINNED_SKILL_SESSIONS.has(skill));
667
-
668
- let session = getSession(chatId);
669
-
670
- if (usePinnedSkillSession) {
671
- // Use a dedicated long-lived session per skill
672
- const state = loadState();
673
- if (!state.pinned_sessions) state.pinned_sessions = {};
674
- const pinned = state.pinned_sessions[skill];
675
- if (pinned) {
676
- // Reuse existing pinned session
677
- state.sessions[chatId] = { id: pinned.id, cwd: pinned.cwd, started: true };
678
- saveState(state);
679
- session = state.sessions[chatId];
680
- log('INFO', `Pinned session reused for skill ${skill}: ${pinned.id.slice(0, 8)}`);
681
- } else {
682
- // First time — create session and pin it
683
- session = createSession(chatId, HOME, skill);
684
- const st2 = loadState();
685
- if (!st2.pinned_sessions) st2.pinned_sessions = {};
686
- st2.pinned_sessions[skill] = { id: session.id, cwd: session.cwd };
687
- saveState(st2);
688
- log('INFO', `Pinned session created for skill ${skill}: ${session.id.slice(0, 8)}`);
689
- }
690
- } else if (!session) {
667
+ if (!session) {
691
668
  if (boundCwd) {
692
669
  // Agent-bound chats must stay in their own workspace: never attach to another project's session.
693
670
  const recentInBound = listRecentSessions(1, boundCwd);
@@ -95,6 +95,23 @@ function nextClockRunAfter(schedule, fromMs) {
95
95
  return baseMs + 24 * 60 * 60 * 1000;
96
96
  }
97
97
 
98
+ // Map short aliases and full model IDs to what Claude CLI accepts.
99
+ // Claude CLI 2.x accepts both 'sonnet' and 'claude-sonnet-4-6'.
100
+ // This normalization keeps daemon.yaml configs forward-compatible.
101
+ const MODEL_ALIASES = {
102
+ haiku: 'claude-haiku-4-5-20251001',
103
+ sonnet: 'claude-sonnet-4-6',
104
+ opus: 'claude-opus-4-6',
105
+ };
106
+
107
+ function normalizeModel(raw) {
108
+ if (!raw || typeof raw !== 'string') return MODEL_ALIASES.haiku;
109
+ const lower = raw.trim().toLowerCase();
110
+ if (Object.prototype.hasOwnProperty.call(MODEL_ALIASES, lower)) return MODEL_ALIASES[lower];
111
+ // Already a full model ID (e.g. 'claude-sonnet-4-6') — pass through
112
+ return raw.trim();
113
+ }
114
+
98
115
  function buildTaskSchedule(task, parseInterval) {
99
116
  const atRaw = typeof task.at === 'string' ? task.at.trim() : '';
100
117
  if (atRaw) {
@@ -358,7 +375,7 @@ function createTaskScheduler(deps) {
358
375
  }
359
376
 
360
377
  const preamble = buildProfilePreamble();
361
- const model = task.model || 'haiku';
378
+ const model = normalizeModel(task.model || 'haiku');
362
379
  // If precondition returned context data, append it to the prompt
363
380
  let taskPrompt = task.prompt;
364
381
  if (precheck.context) {
@@ -533,7 +550,7 @@ function createTaskScheduler(deps) {
533
550
  const steps = task.steps || [];
534
551
  if (steps.length === 0) return { success: false, error: 'No steps defined', output: '' };
535
552
 
536
- const model = task.model || 'sonnet';
553
+ const model = normalizeModel(task.model || 'sonnet');
537
554
  const cwd = task.cwd ? task.cwd.replace(/^~/, HOME) : HOME;
538
555
  const sessionId = crypto.randomUUID();
539
556
  const outputs = [];
@@ -686,12 +703,24 @@ function createTaskScheduler(deps) {
686
703
 
687
704
  if (runningTasks.has(task.name)) {
688
705
  // Task is still running; skip this cycle and keep full interval cadence.
689
- nextRun[task.name] = nextRunAfter(schedule, currentTime);
706
+ try {
707
+ nextRun[task.name] = nextRunAfter(schedule, currentTime);
708
+ } catch (schedErr) {
709
+ nextRun[task.name] = currentTime + checkIntervalSec * 2 * 1000;
710
+ log('ERROR', `nextRunAfter (running guard) failed for "${task.name}": ${schedErr.message}`);
711
+ }
690
712
  log('WARN', `Task ${task.name} still running — skipping this interval`);
691
713
  continue;
692
714
  }
693
715
 
694
- nextRun[task.name] = nextRunAfter(schedule, currentTime);
716
+ try {
717
+ nextRun[task.name] = nextRunAfter(schedule, currentTime);
718
+ } catch (schedErr) {
719
+ // If next-run calculation fails, back off by at least 2 ticks to prevent infinite loop
720
+ nextRun[task.name] = currentTime + checkIntervalSec * 2 * 1000;
721
+ log('ERROR', `nextRunAfter failed for "${task.name}": ${schedErr.message} — backing off`);
722
+ continue;
723
+ }
695
724
  runningTasks.add(task.name);
696
725
  // executeTask now returns a Promise (async, non-blocking, process-group kill)
697
726
  Promise.resolve(executeTask(task, config))