metame-cli 1.3.17 โ 1.3.20
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 +125 -0
- package/index.js +79 -11
- package/package.json +1 -1
- package/scripts/daemon-default.yaml +19 -0
- package/scripts/daemon.js +817 -150
- package/scripts/distill.js +1 -0
- package/scripts/feishu-adapter.js +142 -6
- package/scripts/schema.js +1 -2
- package/scripts/signal-capture.js +5 -6
package/README.md
CHANGED
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
* **๐ฅ Emergency Recovery (v1.3.13):** `/doctor` interactive diagnostics with one-tap fix buttons, `/sh` direct shell access from your phone (bypasses Claude entirely โ the lifeline when everything else is broken), automatic config backup before any setting change, `/fix` to restore last known good config. `/model` interactive model switcher with auto-backup.
|
|
55
55
|
* **๐ Browser Automation (v1.3.15):** Native Playwright MCP integration โ auto-registered on first run. Every MetaMe user gets browser control capability out of the box. Combined with Skills, enables workflows like automated podcast publishing, form filling, and web scraping.
|
|
56
56
|
* **๐ Interactive File Browser (v1.3.15):** `/list` shows clickable button cards โ folders expand inline, files download on tap. Folder buttons survive daemon restarts (absolute paths, no expiry). Zero token cost.
|
|
57
|
+
* **๐ Parallel Multi-Agent Chats (v1.3.19):** Assign each agent its own dedicated Feishu/Telegram group. Messages in different groups execute in parallel โ no waiting for each other. Route `chatId โ agent` via `chat_agent_map` in `daemon.yaml`. Create a new group, send `/bind <name>` to register it instantly.
|
|
58
|
+
* **๐ง Config Hot-Reload Fix (v1.3.19):** `allowed_chat_ids` is now read dynamically on every message โ no restart needed after editing `daemon.yaml`. `/fix` config restore now merges current `chatId` settings so manually-added groups are never lost.
|
|
59
|
+
* **๐ก๏ธ Daemon Auto-Restart via LaunchAgent (v1.3.19):** MetaMe's npm daemon is now managed by macOS launchd. Crashes or unexpected exits trigger an automatic restart after 5 seconds.
|
|
60
|
+
* **๐ฅ Operator Permissions & Read-Only Mode (v1.3.19):** Add `operator_ids` to restrict who can execute Claude commands in shared groups. Non-operators can still chat and query (read/search/web only) โ they just can't edit files, run bash, or trigger slash commands. Use `/myid` to discover any user's Feishu open_id.
|
|
57
61
|
|
|
58
62
|
## ๐ Prerequisites
|
|
59
63
|
|
|
@@ -341,6 +345,9 @@ Bot: ๅ้ๅฐๅชไธ่ฝฎ๏ผ
|
|
|
341
345
|
| `/budget` | Today's token usage |
|
|
342
346
|
| `/quiet` | Silence mirror/reflections for 48h |
|
|
343
347
|
| `/reload` | Manually reload daemon.yaml (also auto-reloads on file change) |
|
|
348
|
+
| `/bind <name>` | Register current group as a dedicated agent chat โ opens directory browser to pick working directory |
|
|
349
|
+
| `/chatid` | Show the current group's chat ID |
|
|
350
|
+
| `/myid` | Show your own Feishu sender open_id (for configuring `operator_ids`) |
|
|
344
351
|
|
|
345
352
|
**Heartbeat Tasks:**
|
|
346
353
|
|
|
@@ -395,10 +402,126 @@ Each step runs in the same Claude Code session. Step outputs automatically becom
|
|
|
395
402
|
**Security:**
|
|
396
403
|
|
|
397
404
|
* `allowed_chat_ids` whitelist โ unauthorized users silently ignored (empty = deny all)
|
|
405
|
+
* `operator_ids` โ within an allowed group, restrict command execution to specific users; non-operators get read-only chat mode
|
|
398
406
|
* `dangerously_skip_permissions` enabled by default for mobile (users can't click "allow" on phone โ security relies on the chat ID whitelist)
|
|
399
407
|
* `~/.metame/` directory set to mode 700
|
|
400
408
|
* Bot tokens stored locally, never transmitted
|
|
401
409
|
|
|
410
|
+
### Multi-Agent Projects โ Context Isolation & Nickname Routing (v1.3.18)
|
|
411
|
+
|
|
412
|
+
Organize your work into named agents, each tied to a project directory. Switch between them instantly from your phone โ no commands needed, just say their name.
|
|
413
|
+
|
|
414
|
+
**How it works:**
|
|
415
|
+
|
|
416
|
+
Each `project` entry in `daemon.yaml` defines an agent with a working directory, display name, notification color, and optional nicknames. When you send a message starting with a nickname, the daemon instantly switches to that project's last session โ no Claude call, no token cost.
|
|
417
|
+
|
|
418
|
+
**Setup via conversation:**
|
|
419
|
+
|
|
420
|
+
The easiest way to add an agent is to tell the bot:
|
|
421
|
+
|
|
422
|
+
> *"Add a project called 'work' pointing to ~/my-project, nickname is 'ๅทฅไฝ'"*
|
|
423
|
+
|
|
424
|
+
Or edit `~/.metame/daemon.yaml` directly:
|
|
425
|
+
|
|
426
|
+
```yaml
|
|
427
|
+
projects:
|
|
428
|
+
my_agent:
|
|
429
|
+
name: "My Agent" # Display name in notifications
|
|
430
|
+
icon: "๐ค" # Emoji shown in Feishu cards
|
|
431
|
+
color: "blue" # Feishu card color: blue|orange|green|purple|red|grey
|
|
432
|
+
cwd: "~/my-project" # Working directory for this agent
|
|
433
|
+
nicknames: [nickname1, nickname2] # Wake words (matched at message start)
|
|
434
|
+
heartbeat_tasks: [] # Scheduled tasks for this project (optional)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Available colors:** `blue` ยท `orange` ยท `green` ยท `purple` ยท `red` ยท `grey` ยท `turquoise`
|
|
438
|
+
|
|
439
|
+
**Phone commands:**
|
|
440
|
+
|
|
441
|
+
| Action | How |
|
|
442
|
+
|--------|-----|
|
|
443
|
+
| Switch agent | Send the nickname alone: `่ดพ็ปดๆฏ` โ `๐ค Jarvis ๅจ็บฟ` |
|
|
444
|
+
| Switch + ask | `่ดพ็ปดๆฏ, what's the status?` โ switches then asks Claude |
|
|
445
|
+
| Pick from list | `/agent` โ tap button to switch |
|
|
446
|
+
| Continue a reply | Reply to any bot message โ session auto-restored |
|
|
447
|
+
| View all tasks | `/tasks` โ grouped by project |
|
|
448
|
+
| Run a task | `/run <task-name>` |
|
|
449
|
+
|
|
450
|
+
**Nickname routing rules:**
|
|
451
|
+
- Matched at **message start only** โ mentioning a nickname mid-sentence never triggers a switch
|
|
452
|
+
- Pure nickname (no content after) โ instant switch, zero token cost, bypasses cooldown
|
|
453
|
+
- Nickname + content โ switch then send content to Claude
|
|
454
|
+
|
|
455
|
+
**Heartbeat task notifications** arrive as colored Feishu cards โ each project's color is distinct, so you can tell at a glance which agent sent the update.
|
|
456
|
+
|
|
457
|
+
### Parallel Multi-Agent Chats & `/bind` Command (v1.3.19)
|
|
458
|
+
|
|
459
|
+
Give each agent its own dedicated group chat โ messages to different groups execute simultaneously without blocking each other.
|
|
460
|
+
|
|
461
|
+
**How it works:**
|
|
462
|
+
|
|
463
|
+
Each group is mapped to a specific agent via `chat_agent_map` in `daemon.yaml`. When a message arrives in a group, the daemon looks up which agent owns that `chatId` and dispatches the Claude call to that agent's working directory โ fully parallel.
|
|
464
|
+
|
|
465
|
+
**Setup โ `/bind` command (recommended):**
|
|
466
|
+
|
|
467
|
+
1. Create a new Feishu or Telegram group and add your bot.
|
|
468
|
+
2. In the group, send `/bind <name>` (e.g., `/bind backend`).
|
|
469
|
+
3. The bot opens a Finder-style directory browser โ tap folders to navigate, tap a folder name to select it as the working directory.
|
|
470
|
+
4. Done. The bot automatically:
|
|
471
|
+
- Adds the group's `chatId` to `allowed_chat_ids`
|
|
472
|
+
- Creates a `chat_agent_map` entry routing this group to the agent
|
|
473
|
+
- Creates a `projects` entry for the agent
|
|
474
|
+
- Sends a welcome card
|
|
475
|
+
|
|
476
|
+
> **No whitelist required:** `/bind` works in any group โ the new group self-registers without needing to be pre-approved in `allowed_chat_ids`.
|
|
477
|
+
|
|
478
|
+
> **Re-binding:** Send `/bind <name>` again in the same group to overwrite the previous configuration.
|
|
479
|
+
|
|
480
|
+
**Manual setup** (`~/.metame/daemon.yaml`):
|
|
481
|
+
|
|
482
|
+
```yaml
|
|
483
|
+
chat_agent_map:
|
|
484
|
+
"oc_abc123": "backend" # chatId โ project key
|
|
485
|
+
"oc_def456": "frontend"
|
|
486
|
+
|
|
487
|
+
projects:
|
|
488
|
+
backend:
|
|
489
|
+
name: "Backend API"
|
|
490
|
+
cwd: "~/projects/api"
|
|
491
|
+
frontend:
|
|
492
|
+
name: "Frontend App"
|
|
493
|
+
cwd: "~/projects/app"
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**`/chatid` command:**
|
|
497
|
+
|
|
498
|
+
In any authorized group, send `/chatid` and the bot replies with the current group's `chatId`. Useful for manual configuration.
|
|
499
|
+
|
|
500
|
+
| Command | Description |
|
|
501
|
+
|---------|-------------|
|
|
502
|
+
| `/bind <name>` | Register current group as a dedicated agent chat โ opens directory browser to pick working directory |
|
|
503
|
+
| `/chatid` | Show the current group's chat ID |
|
|
504
|
+
| `/myid` | Show your own Feishu sender open_id |
|
|
505
|
+
|
|
506
|
+
**Operator Permissions (`operator_ids`):**
|
|
507
|
+
|
|
508
|
+
In shared groups (e.g., a group with a colleague or tester), you can restrict who can execute Claude commands. Non-operators get a read-only chat mode โ they can ask questions and search, but can't edit files, run bash, or trigger slash commands.
|
|
509
|
+
|
|
510
|
+
```yaml
|
|
511
|
+
feishu:
|
|
512
|
+
operator_ids:
|
|
513
|
+
- "ou_abc123yourid" # Only these users can execute commands
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Use `/myid` in any Feishu group to get a user's open_id. Then add it to `operator_ids` to grant full access.
|
|
517
|
+
|
|
518
|
+
| User type | Chat & query | Slash commands | Write / Edit / Bash |
|
|
519
|
+
|-----------|:---:|:---:|:---:|
|
|
520
|
+
| Operator | โ
| โ
| โ
|
|
|
521
|
+
| Non-operator | โ
| โ | โ |
|
|
522
|
+
|
|
523
|
+
> If `operator_ids` is empty, all whitelisted users have full access (default behavior).
|
|
524
|
+
|
|
402
525
|
### Provider Relay โ Third-Party Model Support (v1.3.11)
|
|
403
526
|
|
|
404
527
|
MetaMe supports any Anthropic-compatible API relay as a backend. This means you can route Claude Code through a third-party relay that maps `sonnet`/`opus`/`haiku` to any model (GPT-4, DeepSeek, Gemini, etc.) โ MetaMe passes standard model names and the relay handles translation.
|
|
@@ -602,6 +725,8 @@ A: No. Your profile stays local at `~/.claude_profile.yaml`. MetaMe simply passe
|
|
|
602
725
|
|
|
603
726
|
| Version | Highlights |
|
|
604
727
|
|---------|------------|
|
|
728
|
+
| **v1.3.19** | **Parallel multi-agent group chats** โ `chat_agent_map` routes chatId โ agent for true parallel execution; `/bind` command for one-tap group registration with Finder-style directory browser; `/chatid` to look up group ID; `allowed_chat_ids` hot-reload fix (read per message, no restart); `/fix` now merges current chatId config; daemon auto-restart via macOS LaunchAgent (5-second recovery); **operator_ids** permission layer โ non-operators get read-only chat mode (query/search, no write/execute); `/myid` command to retrieve Feishu open_id |
|
|
729
|
+
| **v1.3.18** | **Multi-agent project isolation** โ `projects` in `daemon.yaml` with per-project heartbeat tasks, Feishu colored cards per project, `/agent` picker button, nickname routing (say agent name to switch instantly), reply-to-message session restoration, fix `~` expansion in project cwd |
|
|
605
730
|
| **v1.3.17** | **Windows support** (WSL one-command installer), `install-systemd` for Linux/WSL daemon auto-start. Fix onboarding (Genesis interview was never injected, CLAUDE.md accumulated across runs). Marker-based cleanup, unified protocols, `--append-system-prompt` guarantees interview activation, Feishu auto-fetch chat ID, full mobile permissions, fix `/publish` false-success, auto-restart daemon on script update |
|
|
606
731
|
| **v1.3.16** | Git-based `/undo` (auto-checkpoint before each turn, `git reset --hard` rollback), `/nosleep` toggle (macOS caffeinate), custom provider model passthrough (`/model` accepts any name for non-anthropic providers), auto-fallback to anthropic/opus on provider failure, message queue works on Telegram (fire-and-forget poll loop), lazy background distill |
|
|
607
732
|
| **v1.3.15** | Native Playwright MCP (browser automation for all users), `/list` interactive file browser with buttons, Feishu image download fix, Skill/MCP/Agent status push, hot restart reliability (single notification, no double instance) |
|
package/index.js
CHANGED
|
@@ -28,9 +28,22 @@ if (!fs.existsSync(METAME_DIR)) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Auto-deploy bundled scripts to ~/.metame/
|
|
31
|
+
// IMPORTANT: daemon.yaml is USER CONFIG โ never overwrite it. Only daemon-default.yaml (template) is synced.
|
|
31
32
|
const BUNDLED_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'];
|
|
32
33
|
const scriptsDir = path.join(__dirname, 'scripts');
|
|
33
34
|
|
|
35
|
+
// Protect daemon.yaml: create backup before any sync operation
|
|
36
|
+
const DAEMON_YAML_BACKUP = path.join(METAME_DIR, 'daemon.yaml.bak');
|
|
37
|
+
try {
|
|
38
|
+
if (fs.existsSync(DAEMON_CONFIG_FILE)) {
|
|
39
|
+
const content = fs.readFileSync(DAEMON_CONFIG_FILE, 'utf8');
|
|
40
|
+
// Only backup if it has real config (not just the default template)
|
|
41
|
+
if (content.includes('enabled: true') || content.includes('bot_token:') && !content.includes('bot_token: null')) {
|
|
42
|
+
fs.copyFileSync(DAEMON_CONFIG_FILE, DAEMON_YAML_BACKUP);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch { /* non-fatal */ }
|
|
46
|
+
|
|
34
47
|
let scriptsUpdated = false;
|
|
35
48
|
for (const script of BUNDLED_SCRIPTS) {
|
|
36
49
|
const src = path.join(scriptsDir, script);
|
|
@@ -63,7 +76,11 @@ if (scriptsUpdated) {
|
|
|
63
76
|
}, 2000);
|
|
64
77
|
const DAEMON_SCRIPT = path.join(METAME_DIR, 'daemon.js');
|
|
65
78
|
setTimeout(() => {
|
|
66
|
-
|
|
79
|
+
// Use caffeinate on macOS to prevent sleep while daemon is running
|
|
80
|
+
const isNotWindows = process.platform !== 'win32';
|
|
81
|
+
const cmd = isNotWindows ? 'caffeinate' : process.execPath;
|
|
82
|
+
const args = isNotWindows ? ['-i', process.execPath, DAEMON_SCRIPT] : [DAEMON_SCRIPT];
|
|
83
|
+
const bg = spawn(cmd, args, {
|
|
67
84
|
detached: true,
|
|
68
85
|
stdio: 'ignore',
|
|
69
86
|
env: { ...process.env, HOME: HOME_DIR, METAME_ROOT: __dirname },
|
|
@@ -77,11 +94,27 @@ if (scriptsUpdated) {
|
|
|
77
94
|
}
|
|
78
95
|
}
|
|
79
96
|
|
|
80
|
-
//
|
|
97
|
+
// Load daemon config for local launch flags
|
|
98
|
+
let daemonCfg = {};
|
|
99
|
+
try {
|
|
100
|
+
if (fs.existsSync(DAEMON_CONFIG_FILE)) {
|
|
101
|
+
const _yaml = require(path.join(__dirname, 'node_modules', 'js-yaml'));
|
|
102
|
+
const raw = _yaml.load(fs.readFileSync(DAEMON_CONFIG_FILE, 'utf8')) || {};
|
|
103
|
+
daemonCfg = raw.daemon || {};
|
|
104
|
+
}
|
|
105
|
+
} catch { /* non-fatal */ }
|
|
106
|
+
|
|
107
|
+
// Ensure daemon.yaml exists (restore backup or copy from template)
|
|
81
108
|
if (!fs.existsSync(DAEMON_CONFIG_FILE)) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
fs.copyFileSync(
|
|
109
|
+
if (fs.existsSync(DAEMON_YAML_BACKUP)) {
|
|
110
|
+
// Restore from backup โ user had real config that was lost
|
|
111
|
+
fs.copyFileSync(DAEMON_YAML_BACKUP, DAEMON_CONFIG_FILE);
|
|
112
|
+
console.log('โ ๏ธ daemon.yaml was missing โ restored from backup.');
|
|
113
|
+
} else {
|
|
114
|
+
const daemonTemplate = path.join(scriptsDir, 'daemon-default.yaml');
|
|
115
|
+
if (fs.existsSync(daemonTemplate)) {
|
|
116
|
+
fs.copyFileSync(daemonTemplate, DAEMON_CONFIG_FILE);
|
|
117
|
+
}
|
|
85
118
|
}
|
|
86
119
|
}
|
|
87
120
|
|
|
@@ -161,6 +194,30 @@ function spawnDistillBackground() {
|
|
|
161
194
|
const distillPath = path.join(METAME_DIR, 'distill.js');
|
|
162
195
|
if (!fs.existsSync(distillPath)) return;
|
|
163
196
|
|
|
197
|
+
// Early exit if distillation already in progress (prevents duplicate spawns across terminals)
|
|
198
|
+
const lockFile = path.join(METAME_DIR, 'distill.lock');
|
|
199
|
+
if (fs.existsSync(lockFile)) {
|
|
200
|
+
try {
|
|
201
|
+
const lockAge = Date.now() - fs.statSync(lockFile).mtimeMs;
|
|
202
|
+
if (lockAge < 120000) return;
|
|
203
|
+
} catch { /* stale lock, proceed */ }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 4-hour cooldown: check last distill timestamp from profile
|
|
207
|
+
const cooldownMs = 4 * 60 * 60 * 1000;
|
|
208
|
+
try {
|
|
209
|
+
const profilePath = path.join(process.env.HOME || '', '.claude_profile.yaml');
|
|
210
|
+
if (fs.existsSync(profilePath)) {
|
|
211
|
+
const yaml = require('js-yaml');
|
|
212
|
+
const profile = yaml.load(fs.readFileSync(profilePath, 'utf8'));
|
|
213
|
+
const distillLog = profile && profile.evolution && profile.evolution.auto_distill;
|
|
214
|
+
if (Array.isArray(distillLog) && distillLog.length > 0) {
|
|
215
|
+
const lastTs = new Date(distillLog[distillLog.length - 1].ts).getTime();
|
|
216
|
+
if (Date.now() - lastTs < cooldownMs) return;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} catch { /* non-fatal, proceed */ }
|
|
220
|
+
|
|
164
221
|
const hasSignals = shouldDistill();
|
|
165
222
|
const bootstrap = needsBootstrap();
|
|
166
223
|
|
|
@@ -263,7 +320,7 @@ runExpiryCleanup();
|
|
|
263
320
|
if (!fs.existsSync(BRAIN_FILE)) {
|
|
264
321
|
const initialProfile = `identity:
|
|
265
322
|
role: Unknown
|
|
266
|
-
|
|
323
|
+
locale: null
|
|
267
324
|
status:
|
|
268
325
|
focus: Initializing
|
|
269
326
|
`;
|
|
@@ -325,12 +382,12 @@ You are entering **Calibration Mode**. You are not a chatbot; you are a Psycholo
|
|
|
325
382
|
|
|
326
383
|
5. **Shadows (Hidden Fears):** What are you avoiding? What pattern do you keep repeating? What keeps you up at night?
|
|
327
384
|
|
|
328
|
-
6. **Identity (
|
|
385
|
+
6. **Identity (Role + Locale):** Based on everything learned, propose a role summary and confirm their preferred language (locale). Ask if it resonates.
|
|
329
386
|
|
|
330
387
|
**TERMINATION:**
|
|
331
388
|
- After 5-7 exchanges, synthesize everything into \`~/.claude_profile.yaml\`.
|
|
332
389
|
- **LOCK** Core Values with \`# [LOCKED]\`.
|
|
333
|
-
- Announce: "Link Established.
|
|
390
|
+
- Announce: "Link Established. Profile calibrated."
|
|
334
391
|
- Then proceed to **Phase 2** below.
|
|
335
392
|
|
|
336
393
|
**3. SETUP WIZARD (Phase 2 โ Optional):**
|
|
@@ -398,7 +455,7 @@ let isKnownUser = false;
|
|
|
398
455
|
try {
|
|
399
456
|
if (fs.existsSync(BRAIN_FILE)) {
|
|
400
457
|
const doc = yaml.load(fs.readFileSync(BRAIN_FILE, 'utf8')) || {};
|
|
401
|
-
if (doc.identity && doc.identity.
|
|
458
|
+
if (doc.identity && doc.identity.locale && doc.identity.locale !== 'null') {
|
|
402
459
|
isKnownUser = true;
|
|
403
460
|
}
|
|
404
461
|
}
|
|
@@ -1086,6 +1143,8 @@ if (isDaemon) {
|
|
|
1086
1143
|
<string>com.metame.daemon</string>
|
|
1087
1144
|
<key>ProgramArguments</key>
|
|
1088
1145
|
<array>
|
|
1146
|
+
<string>/usr/bin/caffeinate</string>
|
|
1147
|
+
<string>-i</string>
|
|
1089
1148
|
<string>${nodePath}</string>
|
|
1090
1149
|
<string>${DAEMON_SCRIPT}</string>
|
|
1091
1150
|
</array>
|
|
@@ -1207,7 +1266,11 @@ WantedBy=default.target
|
|
|
1207
1266
|
console.error("โ daemon.js not found. Reinstall MetaMe.");
|
|
1208
1267
|
process.exit(1);
|
|
1209
1268
|
}
|
|
1210
|
-
|
|
1269
|
+
// Use caffeinate on macOS/Linux to prevent sleep while daemon is running
|
|
1270
|
+
const isNotWindows = process.platform !== 'win32';
|
|
1271
|
+
const cmd = isNotWindows ? 'caffeinate' : process.execPath;
|
|
1272
|
+
const args = isNotWindows ? ['-i', process.execPath, DAEMON_SCRIPT] : [DAEMON_SCRIPT];
|
|
1273
|
+
const bg = spawn(cmd, args, {
|
|
1211
1274
|
detached: true,
|
|
1212
1275
|
stdio: 'ignore',
|
|
1213
1276
|
env: { ...process.env, HOME: HOME_DIR, METAME_ROOT: __dirname },
|
|
@@ -1363,7 +1426,9 @@ if (isSync) {
|
|
|
1363
1426
|
|
|
1364
1427
|
console.log(`\n๐ Resuming session ${bestSession.id.slice(0, 8)}...\n`);
|
|
1365
1428
|
const providerEnv = (() => { try { return require(path.join(__dirname, 'scripts', 'providers.js')).buildActiveEnv(); } catch { return {}; } })();
|
|
1366
|
-
const
|
|
1429
|
+
const resumeArgs = ['--resume', bestSession.id];
|
|
1430
|
+
if (daemonCfg.dangerously_skip_permissions) resumeArgs.push('--dangerously-skip-permissions');
|
|
1431
|
+
const syncChild = spawn('claude', resumeArgs, {
|
|
1367
1432
|
stdio: 'inherit',
|
|
1368
1433
|
env: { ...process.env, ...providerEnv, METAME_ACTIVE_SESSION: 'true' }
|
|
1369
1434
|
});
|
|
@@ -1398,6 +1463,9 @@ if (activeProviderName !== 'anthropic') {
|
|
|
1398
1463
|
|
|
1399
1464
|
// Build launch args โ inject system prompt for new users
|
|
1400
1465
|
const launchArgs = process.argv.slice(2);
|
|
1466
|
+
if (daemonCfg.dangerously_skip_permissions && !launchArgs.includes('--dangerously-skip-permissions')) {
|
|
1467
|
+
launchArgs.push('--dangerously-skip-permissions');
|
|
1468
|
+
}
|
|
1401
1469
|
if (!isKnownUser) {
|
|
1402
1470
|
launchArgs.push(
|
|
1403
1471
|
'--append-system-prompt',
|
package/package.json
CHANGED
|
@@ -12,8 +12,27 @@ feishu:
|
|
|
12
12
|
app_secret: null
|
|
13
13
|
allowed_chat_ids: []
|
|
14
14
|
|
|
15
|
+
projects:
|
|
16
|
+
# Per-project heartbeat tasks. Each project's tasks are isolated and
|
|
17
|
+
# notifications arrive as colored Feishu cards (visually distinct).
|
|
18
|
+
#
|
|
19
|
+
# example_project:
|
|
20
|
+
# name: "My Project"
|
|
21
|
+
# icon: "๐ฌ"
|
|
22
|
+
# color: "orange" # blue|orange|green|red|grey|purple|turquoise
|
|
23
|
+
# heartbeat_tasks:
|
|
24
|
+
# - name: "daily-task"
|
|
25
|
+
# cwd: "~/AGI/MyProject"
|
|
26
|
+
# model: "sonnet"
|
|
27
|
+
# interval: "24h"
|
|
28
|
+
# notify: true
|
|
29
|
+
# enabled: true
|
|
30
|
+
# prompt: "..."
|
|
31
|
+
# allowedTools: [Read, Write, WebSearch]
|
|
32
|
+
|
|
15
33
|
heartbeat:
|
|
16
34
|
tasks: []
|
|
35
|
+
# Legacy flat tasks (no project isolation). New tasks should go under projects: above.
|
|
17
36
|
# Examples โ uncomment or add your own:
|
|
18
37
|
#
|
|
19
38
|
# Scheduled task (calls claude -p with your profile context):
|