metame-cli 1.4.17 → 1.4.19

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
@@ -14,25 +14,31 @@
14
14
  <a href="./README.md">English</a> | <a href="./README中文版.md">中文</a>
15
15
  </p>
16
16
 
17
- > **Claude Code that knows you — and works from your phone.**
17
+ > **Your digital twin. Lives on your Mac.**
18
18
 
19
- MetaMe turns Claude Code into a persistent AI that remembers how you think, runs on your Mac 24/7, and takes commands from your phone via Telegram or Feishu.
19
+ MetaMe is an AI that lives on your machine remembers how you think, stays online 24/7, and takes commands from your phone via Telegram or Feishu. Not in the cloud. In your computer.
20
20
 
21
- One command. No cloud. Your machine, your data.
21
+ No cloud. Your machine, your data.
22
22
 
23
+ **macOS / Linux / Windows WSL — same command:**
24
+ ```bash
25
+ curl -fsSL https://raw.githubusercontent.com/Yaron9/MetaMe/main/install.sh | bash
26
+ ```
27
+
28
+ **Already have Node.js ≥ 18:**
23
29
  ```bash
24
30
  npm install -g metame-cli && metame
25
31
  ```
26
32
 
27
33
  ---
28
34
 
29
- > ### 🚀 v1.4.0Layered Memory Architecture
35
+ > ### 🚀 v1.4.18Multi-User ACL + Session Context Preview
30
36
  >
31
- > MetaMe now has a **three-layer memory system** that works completely in the background:
32
- > - **Long-term facts** extracted from every session, recalled semantically on demand
33
- > - **Session summary cache** when you resume after a 2h+ gap, MetaMe injects what you were last working on
34
- > - **Automatic session tagging** every conversation is indexed by topic, enabling future session routing
35
- > - **Unix Socket IPC** dispatch latency dropped from ~60s to <100ms
37
+ > - **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.
38
+ > - **Session context preview**: `/resume` and `/sessions` now show the last message snippet so you know exactly what to pick up.
39
+ > - **Team Task protocol**: multi-agent task board for cross-agent collaboration. Agents can dispatch and track tasks across workspaces.
40
+ > - **Layered Memory Architecture**: three-layer memory (long-term facts, session summaries, session index) all automatic.
41
+ > - **Unix Socket IPC**: dispatch latency <100ms.
36
42
  >
37
43
  > Zero configuration. It just works.
38
44
 
@@ -64,7 +70,7 @@ Claude: ✏️ Edit: api/login.ts
64
70
  ✅ Fixed. 3 tests passing.
65
71
  ```
66
72
 
67
- Start on your laptop, continue on the train. `/stop` to interrupt, `/undo` to rollback, `/sh ls` for raw shell access when everything else breaks.
73
+ Start on your laptop, continue on the train. `/stop` to interrupt, `/undo` to rollback, `/mac check` for macOS automation diagnostics, and `/sh ls` for raw shell access when everything else breaks.
68
74
 
69
75
  ### 3. Layered Memory That Works While You Sleep
70
76
 
@@ -124,7 +130,8 @@ projects:
124
130
  heartbeat_tasks:
125
131
  - name: "daily-draft"
126
132
  prompt: "Research top AI news and write an article"
127
- interval: "24h"
133
+ at: "09:30"
134
+ days: "weekdays"
128
135
  model: "sonnet"
129
136
  notify: true
130
137
 
@@ -132,7 +139,7 @@ heartbeat:
132
139
  tasks:
133
140
  - name: "morning-brief"
134
141
  prompt: "Summarize my git activity from yesterday"
135
- interval: "24h"
142
+ at: "09:00"
136
143
  notify: true
137
144
  ```
138
145
 
@@ -150,7 +157,21 @@ Chain skills into multi-step workflows — research → write → publish — fu
150
157
  prompt: "Publish it"
151
158
  ```
152
159
 
153
- Task options: `require_idle` (defer when you're active, retry on next heartbeat tick), `precondition` (shell guard — skip if false, zero tokens), `notify` (push result to phone), `model`, `cwd`, `allowedTools`, `timeout`.
160
+ **Task options:**
161
+
162
+ | Option | Description |
163
+ |--------|-------------|
164
+ | `at` | Fixed-time trigger, e.g. `"09:30"` (local time) |
165
+ | `days` | Day filter, e.g. `"weekdays"`, `[mon, wed, fri]` |
166
+ | `interval` | Interval trigger, e.g. `"4h"`, `"30m"` |
167
+ | `require_idle` | Skip if you're active; retry on next heartbeat tick |
168
+ | `precondition` | Shell guard — skip task if command returns non-zero (zero tokens consumed) |
169
+ | `notify` | Push result to phone when done |
170
+ | `model` | Override model, e.g. `"sonnet"`, `"haiku"` |
171
+ | `cwd` | Working directory for the task |
172
+ | `timeout` | Max run time |
173
+
174
+ > **Scheduled tasks require system registration.** Run `metame daemon install-launchd` and tasks fire on schedule even with the screen locked or the lid closed — as long as the Mac is on.
154
175
 
155
176
  ### 5. Skills That Evolve Themselves
156
177
 
@@ -172,6 +193,13 @@ Task fails → skill-scout finds a skill → installs → retries → succeeds
172
193
 
173
194
  ## Quick Start
174
195
 
196
+ **macOS / Linux / Windows WSL:**
197
+ ```bash
198
+ curl -fsSL https://raw.githubusercontent.com/Yaron9/MetaMe/main/install.sh | bash
199
+ ```
200
+ > Same command everywhere. The script detects your OS and uses Homebrew (macOS) or apt/dnf/pacman (Linux/WSL) to install Node.js automatically.
201
+
202
+ **Already have Node.js ≥ 18:**
175
203
  ```bash
176
204
  npm install -g metame-cli && metame
177
205
  ```
@@ -183,7 +211,35 @@ npm install -g metame-cli && metame
183
211
  | 1. Install & profile | `metame` | First run: cognitive interview → builds `~/.claude_profile.yaml` |
184
212
  | 2. Connect phone | Follow the setup wizard | Bot token + app credentials → `~/.metame/daemon.yaml` |
185
213
  | 3. Start daemon | `metame start` | Background daemon launches, bot goes online |
186
- | 4. Auto-start | `metame daemon install-launchd` | Survives reboot + crash recovery |
214
+ | 4. Register with system | macOS: `metame daemon install-launchd` · WSL/Linux: see below | Always-on, crash recovery |
215
+
216
+ > **What does system registration mean?**
217
+ > Once registered, MetaMe runs in the background automatically — screen locked, lid closed, woken from sleep — as long as the machine is on. Scheduled tasks fire on time. No terminal window needed.
218
+
219
+ **WSL2 / Linux — register with systemd:**
220
+
221
+ ```bash
222
+ cat > ~/.config/systemd/user/metame.service << 'EOF'
223
+ [Unit]
224
+ Description=MetaMe Daemon
225
+ After=network.target
226
+
227
+ [Service]
228
+ ExecStart=/usr/bin/env metame start
229
+ Restart=on-failure
230
+ RestartSec=5
231
+
232
+ [Install]
233
+ WantedBy=default.target
234
+ EOF
235
+
236
+ systemctl --user enable metame
237
+ systemctl --user start metame
238
+ ```
239
+
240
+ > WSL2 requires systemd enabled first: add `[boot]\nsystemd=true` to `/etc/wsl.conf`, then restart WSL.
241
+
242
+ > **WSL limitation:** `/mac` commands (macOS AppleScript/JXA automation) are not available.
187
243
 
188
244
  **Create your first Agent:**
189
245
 
@@ -208,15 +264,46 @@ npm install -g metame-cli && metame
208
264
  | **Browser Automation** | Built-in Playwright MCP. Browser control out of the box for every user. |
209
265
  | **Provider Relay** | Route through any Anthropic-compatible API. Use GPT-4, DeepSeek, Gemini — zero config file mutation. |
210
266
  | **Metacognition** | Detects behavioral patterns (decision style, comfort zones, goal drift) and injects mirror observations. Zero extra API cost. |
211
- | **Emergency Tools** | `/doctor` diagnostics, `/sh` raw shell, `/fix` config restore, `/undo` git-based rollback. |
267
+ | **Multi-User ACL** | Role-based permission system (admin / member / stranger). Share bots with teammates safely. Dynamic user management via `/user` commands with hot-reload config. |
268
+ | **Team Task** | Multi-agent task board for cross-agent collaboration. Agents can create, assign, and track tasks across workspaces. N-agent session scoping for parallel team workflows. |
269
+ | **Emergency Tools** | `/doctor` diagnostics, `/mac` macOS control helpers, `/sh` raw shell, `/fix` config restore, `/undo` git-based rollback. |
212
270
 
213
271
  ## Defining Your Agents
214
272
 
215
- Agent configs live in `~/.metame/daemon.yaml` local only, never uploaded to npm or Git.
273
+ MetaMe's design philosophy: **one folder = one agent.**
274
+
275
+ Give an agent a directory, drop a `CLAUDE.md` inside describing its role, and you're done. The folder is the agent — it can be a code project, a blog repo, any workspace you already have.
276
+
277
+ ### Option 1: Just say it (fastest)
278
+
279
+ No commands needed. Tell the bot what you want in plain language — MetaMe understands intent and acts:
280
+
281
+ ```
282
+ You: Create an agent for this group, directory ~/projects/assistant
283
+ Bot: ✅ Agent created and bound
284
+ Name: assistant
285
+ Dir: ~/projects/assistant
286
+
287
+ You: Change this agent's role to: a writing and content creation assistant
288
+ Bot: ✅ Role definition updated in CLAUDE.md
289
+
290
+ You: Bind an agent to ~/AGI/MyProject
291
+ Bot: ✅ Agent bound
292
+ Name: MyProject
293
+ Dir: ~/AGI/MyProject
294
+
295
+ You: List all agents
296
+ Bot: 📋 Agent list
297
+ 🤖 assistant ◀ current
298
+ Dir: ~/projects/assistant
299
+ ...
300
+ ```
301
+
302
+ Supported intents: create, bind, unbind, edit role, list — just say it naturally.
216
303
 
217
- ### From your phone (recommended)
304
+ ### Option 2: Wizard commands
218
305
 
219
- The easiest way. Open any Telegram/Feishu group and use the `/agent` wizard:
306
+ Use `/agent` commands in any Telegram/Feishu group:
220
307
 
221
308
  | Command | What it does |
222
309
  |---------|-------------|
@@ -226,21 +313,7 @@ The easiest way. Open any Telegram/Feishu group and use the `/agent` wizard:
226
313
  | `/agent edit` | Update the current agent's role description (rewrites its `CLAUDE.md` section). |
227
314
  | `/agent reset` | Remove the current agent's role section. |
228
315
 
229
- Example flow:
230
- ```
231
- You: /agent new
232
- Bot: Please select a working directory:
233
- 📁 ~/AGI 📁 ~/projects 📁 ~/Desktop
234
- You: ~/AGI/MyProject/NewDir
235
- Bot: ✅ 已新建目录:~/AGI/MyProject/NewDir
236
- What should we name this agent?
237
- You: 小美
238
- Bot: Describe 小美's role and responsibilities:
239
- You: Personal assistant. Manages my calendar, drafts messages, and tracks todos.
240
- Bot: ✅ Agent「小美」created. CLAUDE.md updated with role definition.
241
- ```
242
-
243
- You can tap a button to pick an existing directory, or type any path directly in chat. If the path doesn't exist, it's created automatically. All entry points (`/agent new` wizard and `/agent bind`) validate that the directory is real before saving.
316
+ You can tap a button to pick an existing directory, or type any path directly in chat. If the path doesn't exist, it's created automatically.
244
317
 
245
318
  ### From config file (for power users)
246
319
 
@@ -263,7 +336,8 @@ projects:
263
336
  heartbeat_tasks:
264
337
  - name: "daily-review"
265
338
  prompt: "Review yesterday's commits and flag any issues"
266
- interval: "24h"
339
+ at: "20:30"
340
+ days: [mon, tue, wed, thu, fri]
267
341
  notify: true
268
342
 
269
343
  feishu:
@@ -294,10 +368,20 @@ All agents share your cognitive profile (`~/.claude_profile.yaml`) — they all
294
368
  | `/list` | Browse & download project files |
295
369
  | `/model` | Switch model (sonnet/opus/haiku) |
296
370
  | `/agent bind <name> [dir]` | Register group as dedicated agent |
371
+ | `/mac` | macOS control helper: permissions check/open + AppleScript/JXA execution |
297
372
  | `/sh <cmd>` | Raw shell — bypasses Claude |
298
373
  | `/memory` | Memory stats: fact count, session tags, DB size |
299
374
  | `/memory <keyword>` | Search long-term facts by keyword |
300
375
  | `/doctor` | Interactive diagnostics |
376
+ | `/user add <open_id>` | Add a user (admin only) |
377
+ | `/user role <open_id> <admin\|member>` | Set user role |
378
+ | `/user list` | List all configured users |
379
+ | `/user remove <open_id>` | Remove a user |
380
+ | `/sessions` | Browse recent sessions with last message preview |
381
+ | `/teamtask create <agent> <goal>` | Create a cross-agent collaboration task |
382
+ | `/teamtask` | List recent TeamTasks (last 10) |
383
+ | `/teamtask <task_id>` | View task detail |
384
+ | `/teamtask resume <task_id>` | Resume a task |
301
385
 
302
386
  ## How It Works
303
387
 
package/index.js CHANGED
@@ -30,7 +30,7 @@ if (!fs.existsSync(METAME_DIR)) {
30
30
  // Auto-deploy bundled scripts to ~/.metame/
31
31
  // IMPORTANT: daemon.yaml is USER CONFIG — never overwrite it. Only daemon-default.yaml (template) is synced.
32
32
  const scriptsDir = path.join(__dirname, 'scripts');
33
- const BUNDLED_BASE_SCRIPTS = ['signal-capture.js', 'distill.js', 'schema.js', 'pending-traits.js', 'migrate-v2.js', 'daemon.js', 'telegram-adapter.js', 'feishu-adapter.js', 'daemon-default.yaml', 'providers.js', 'session-analytics.js', 'resolve-yaml.js', 'utils.js', 'skill-evolution.js', 'memory.js', 'memory-extract.js', 'qmd-client.js', 'session-summarize.js'];
33
+ const BUNDLED_BASE_SCRIPTS = ['signal-capture.js', 'distill.js', 'schema.js', 'pending-traits.js', 'migrate-v2.js', 'daemon.js', 'telegram-adapter.js', 'feishu-adapter.js', 'daemon-default.yaml', 'providers.js', 'session-analytics.js', 'resolve-yaml.js', 'utils.js', 'skill-evolution.js', 'memory.js', 'memory-extract.js', 'memory-search.js', 'qmd-client.js', 'session-summarize.js', 'check-macos-control-capabilities.sh', 'usage-classifier.js', 'task-board.js'];
34
34
  const DAEMON_MODULE_SCRIPTS = (() => {
35
35
  try {
36
36
  return fs.readdirSync(scriptsDir).filter((f) => /^daemon-[\w-]+\.js$/.test(f));
@@ -1755,15 +1755,22 @@ if (!isKnownUser) {
1755
1755
  // RAG: inject relevant facts based on current project (desktop-side equivalent of daemon RAG)
1756
1756
  try {
1757
1757
  const memory = require(path.join(__dirname, 'scripts', 'memory.js'));
1758
- // Derive project key from git repo name or cwd basename
1759
- let projectQuery = path.basename(process.cwd());
1758
+ const { projectScopeFromCwd } = require(path.join(__dirname, 'scripts', 'utils.js'));
1759
+ // Keep cwd basename as authoritative project filter for legacy rows (scope IS NULL).
1760
+ const cwdProject = path.basename(process.cwd());
1761
+ let repoProject = cwdProject;
1760
1762
  try {
1761
1763
  const { execSync } = require('child_process');
1762
1764
  const remote = execSync('git remote get-url origin 2>/dev/null || true', { encoding: 'utf8', stdio: 'pipe' }).trim();
1763
- if (remote) projectQuery = path.basename(remote, '.git');
1765
+ if (remote) repoProject = path.basename(remote, '.git');
1764
1766
  } catch { /* not a git repo, use dirname */ }
1765
1767
 
1766
- const facts = memory.searchFacts(projectQuery, { limit: 5 });
1768
+ const factQuery = repoProject === cwdProject ? cwdProject : `${repoProject} ${cwdProject}`;
1769
+ const facts = memory.searchFacts(factQuery, {
1770
+ limit: 5,
1771
+ project: cwdProject || undefined,
1772
+ scope: projectScopeFromCwd(process.cwd()) || undefined,
1773
+ });
1767
1774
  if (facts.length > 0) {
1768
1775
  const factBlock = facts.map(f => `- [${f.relation}] ${f.value}`).join('\n');
1769
1776
  launchArgs.push(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metame-cli",
3
- "version": "1.4.17",
3
+ "version": "1.4.19",
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": {
@@ -13,7 +13,7 @@
13
13
  "scripts": {
14
14
  "test": "node --test scripts/*.test.js",
15
15
  "start": "node index.js",
16
- "sync:plugin": "cp scripts/schema.js scripts/pending-traits.js scripts/signal-capture.js scripts/distill.js scripts/daemon.js scripts/daemon-agent-commands.js scripts/daemon-session-commands.js scripts/daemon-admin-commands.js scripts/daemon-exec-commands.js scripts/daemon-ops-commands.js scripts/daemon-session-store.js scripts/daemon-checkpoints.js scripts/daemon-bridges.js scripts/daemon-file-browser.js scripts/daemon-runtime-lifecycle.js scripts/daemon-notify.js scripts/daemon-claude-engine.js scripts/daemon-command-router.js scripts/daemon-agent-tools.js scripts/daemon-task-scheduler.js scripts/telegram-adapter.js scripts/feishu-adapter.js scripts/daemon-default.yaml scripts/providers.js scripts/utils.js scripts/resolve-yaml.js scripts/memory.js scripts/memory-extract.js scripts/qmd-client.js scripts/session-summarize.js scripts/session-analytics.js scripts/skill-evolution.js plugin/scripts/ && echo '✅ Plugin scripts synced'",
16
+ "sync:plugin": "cp scripts/schema.js scripts/pending-traits.js scripts/signal-capture.js scripts/distill.js scripts/daemon.js scripts/daemon-agent-commands.js scripts/daemon-session-commands.js scripts/daemon-admin-commands.js scripts/daemon-exec-commands.js scripts/daemon-ops-commands.js scripts/daemon-session-store.js scripts/daemon-checkpoints.js scripts/daemon-bridges.js scripts/daemon-file-browser.js scripts/daemon-runtime-lifecycle.js scripts/daemon-notify.js scripts/daemon-claude-engine.js scripts/daemon-command-router.js scripts/daemon-user-acl.js scripts/daemon-agent-tools.js scripts/daemon-task-scheduler.js scripts/daemon-task-envelope.js scripts/task-board.js scripts/telegram-adapter.js scripts/feishu-adapter.js scripts/daemon-default.yaml scripts/providers.js scripts/utils.js scripts/usage-classifier.js scripts/resolve-yaml.js scripts/memory.js scripts/memory-extract.js scripts/qmd-client.js scripts/session-summarize.js scripts/session-analytics.js scripts/skill-evolution.js scripts/check-macos-control-capabilities.sh plugin/scripts/ && echo '✅ Plugin scripts synced'",
17
17
  "restart:daemon": "node index.js stop 2>/dev/null; sleep 1; node index.js start 2>/dev/null || echo '⚠️ Daemon not running or restart failed'",
18
18
  "precommit": "npm run sync:plugin && npm run restart:daemon"
19
19
  },
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bash
2
+ set -u
3
+ set -o pipefail
4
+
5
+ PASS=0
6
+ FAIL=0
7
+ WARN=0
8
+
9
+ print_line() {
10
+ printf '%s\n' "$1"
11
+ }
12
+
13
+ run_check() {
14
+ local name="$1"
15
+ local mode="$2"
16
+ local cmd="$3"
17
+
18
+ local output
19
+ output="$(bash -o pipefail -lc "$cmd" 2>&1)"
20
+ local code=$?
21
+
22
+ if [ "$mode" = "pass_on_zero" ]; then
23
+ if [ $code -eq 0 ]; then
24
+ PASS=$((PASS + 1))
25
+ print_line "[PASS] $name"
26
+ [ -n "$output" ] && print_line " $output"
27
+ else
28
+ FAIL=$((FAIL + 1))
29
+ print_line "[FAIL] $name"
30
+ [ -n "$output" ] && print_line " $output"
31
+ fi
32
+ return
33
+ fi
34
+
35
+ if [ "$mode" = "warn_on_nonzero" ]; then
36
+ if [ $code -eq 0 ]; then
37
+ PASS=$((PASS + 1))
38
+ print_line "[PASS] $name"
39
+ [ -n "$output" ] && print_line " $output"
40
+ else
41
+ WARN=$((WARN + 1))
42
+ print_line "[WARN] $name"
43
+ [ -n "$output" ] && print_line " $output"
44
+ fi
45
+ return
46
+ fi
47
+
48
+ FAIL=$((FAIL + 1))
49
+ print_line "[FAIL] $name"
50
+ print_line " invalid mode: $mode"
51
+ }
52
+
53
+ print_line "MetaMe macOS control capability check"
54
+ print_line "Timestamp: $(date '+%Y-%m-%d %H:%M:%S %z')"
55
+ print_line ""
56
+
57
+ run_check "osascript binary available" "pass_on_zero" "which osascript"
58
+ run_check "AppleScript baseline" "pass_on_zero" "osascript -e 'return \"ok\"'"
59
+ run_check "Finder automation" "pass_on_zero" "osascript -e 'tell application \"Finder\" to get name of startup disk'"
60
+ run_check "System Events accessibility" "pass_on_zero" "osascript -e 'tell application \"System Events\" to get UI elements enabled'"
61
+ run_check "GUI app launch/control (Calculator)" "pass_on_zero" "open -a Calculator >/dev/null 2>&1; sleep 1; osascript -e 'tell application \"System Events\" to tell process \"Calculator\" to return {frontmost, (count of windows)}'; osascript -e 'tell application \"Calculator\" to quit' >/dev/null 2>&1"
62
+
63
+ SHOT_PATH="/tmp/metame_gui_test_$$.png"
64
+ run_check "Screenshot capability (screencapture)" "pass_on_zero" "screencapture -x '$SHOT_PATH' && ls -lh '$SHOT_PATH'"
65
+ rm -f "$SHOT_PATH" >/dev/null 2>&1
66
+
67
+ run_check "Full Disk probe: read ~/Library/Mail" "warn_on_nonzero" "ls '$HOME/Library/Mail' | head -n 3"
68
+ run_check "Full Disk probe: query Safari History.db" "warn_on_nonzero" "sqlite3 '$HOME/Library/Safari/History.db' 'select count(*) from history_items;'"
69
+
70
+ print_line ""
71
+ print_line "Summary: pass=$PASS warn=$WARN fail=$FAIL"
72
+
73
+ if [ $FAIL -gt 0 ]; then
74
+ exit 1
75
+ fi
76
+
77
+ exit 0