metame-cli 1.4.12 → 1.4.13
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/index.js +205 -57
- package/package.json +2 -2
- package/scripts/daemon-admin-commands.js +365 -0
- package/scripts/daemon-agent-commands.js +467 -0
- package/scripts/daemon-agent-tools.js +256 -0
- package/scripts/daemon-bridges.js +236 -0
- package/scripts/daemon-checkpoints.js +89 -0
- package/scripts/daemon-claude-engine.js +808 -0
- package/scripts/daemon-command-router.js +395 -0
- package/scripts/daemon-default.yaml +2 -2
- package/scripts/daemon-exec-commands.js +290 -0
- package/scripts/daemon-file-browser.js +219 -0
- package/scripts/daemon-notify.js +64 -0
- package/scripts/daemon-ops-commands.js +275 -0
- package/scripts/daemon-runtime-lifecycle.js +133 -0
- package/scripts/daemon-session-commands.js +436 -0
- package/scripts/daemon-session-store.js +423 -0
- package/scripts/daemon-task-scheduler.js +539 -0
- package/scripts/daemon.js +543 -4308
- package/scripts/memory-extract.js +15 -9
- package/scripts/session-analytics.js +116 -0
- package/scripts/test_daemon.js +1407 -0
package/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const os = require('os');
|
|
6
|
-
const { spawn } = require('child_process');
|
|
6
|
+
const { spawn, execSync } = require('child_process');
|
|
7
7
|
|
|
8
8
|
// ---------------------------------------------------------
|
|
9
9
|
// 1. CONFIGURATION
|
|
@@ -29,8 +29,16 @@ if (!fs.existsSync(METAME_DIR)) {
|
|
|
29
29
|
|
|
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
|
-
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', 'skill-evolution.js', 'memory.js', 'memory-extract.js', 'qmd-client.js', 'session-summarize.js'];
|
|
33
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'];
|
|
34
|
+
const DAEMON_MODULE_SCRIPTS = (() => {
|
|
35
|
+
try {
|
|
36
|
+
return fs.readdirSync(scriptsDir).filter((f) => /^daemon-[\w-]+\.js$/.test(f));
|
|
37
|
+
} catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
const BUNDLED_SCRIPTS = [...new Set([...BUNDLED_BASE_SCRIPTS, ...DAEMON_MODULE_SCRIPTS])];
|
|
34
42
|
|
|
35
43
|
// Protect daemon.yaml: create backup before any sync operation
|
|
36
44
|
const DAEMON_YAML_BACKUP = path.join(METAME_DIR, 'daemon.yaml.bak');
|
|
@@ -213,15 +221,12 @@ function spawnDistillBackground() {
|
|
|
213
221
|
|
|
214
222
|
if (!hasSignals && !bootstrap) return;
|
|
215
223
|
|
|
216
|
-
|
|
217
|
-
const bufferFile = path.join(METAME_DIR, 'raw_signals.jsonl');
|
|
218
|
-
const lines = fs.readFileSync(bufferFile, 'utf8').trim().split('\n').filter(l => l.trim());
|
|
219
|
-
console.log(`🧠 MetaMe: Distilling ${lines.length} moment${lines.length > 1 ? 's' : ''} in background...`);
|
|
220
|
-
}
|
|
224
|
+
// Note: status display is handled separately in startup output — no log here
|
|
221
225
|
if (bootstrap) {
|
|
222
|
-
|
|
226
|
+
// Background bootstrap — silent, no need to inform user
|
|
223
227
|
}
|
|
224
228
|
|
|
229
|
+
|
|
225
230
|
// Spawn as detached background process — won't block Claude launch
|
|
226
231
|
// Remove CLAUDECODE env var so distill.js can call `claude -p` without nested-session rejection
|
|
227
232
|
const distillEnvClean = { ...process.env };
|
|
@@ -609,41 +614,72 @@ try {
|
|
|
609
614
|
// Non-fatal
|
|
610
615
|
}
|
|
611
616
|
|
|
612
|
-
//
|
|
613
|
-
|
|
617
|
+
// Project-level CLAUDE.md: KERNEL has moved to global ~/.claude/CLAUDE.md.
|
|
618
|
+
// Only inject dynamic per-session observations (mirror / reflection).
|
|
619
|
+
// If nothing dynamic, write the cleaned file with no METAME block at all.
|
|
620
|
+
const dynamicContent = mirrorLine + reflectionLine;
|
|
621
|
+
const newContent = dynamicContent.trim()
|
|
622
|
+
? METAME_START + '\n' + dynamicContent + METAME_END + '\n' + fileContent
|
|
623
|
+
: fileContent;
|
|
614
624
|
fs.writeFileSync(PROJECT_FILE, newContent, 'utf8');
|
|
615
625
|
|
|
616
626
|
// ---------------------------------------------------------
|
|
617
|
-
// 4.7 GLOBAL CLAUDE.MD INJECTION (
|
|
627
|
+
// 4.7 GLOBAL CLAUDE.MD INJECTION (Full Kernel + Capabilities)
|
|
618
628
|
// ---------------------------------------------------------
|
|
619
|
-
// Inject MetaMe
|
|
620
|
-
//
|
|
629
|
+
// Inject the full MetaMe KERNEL into ~/.claude/CLAUDE.md.
|
|
630
|
+
// This file is read by ALL Claude Code sessions regardless of working directory,
|
|
631
|
+
// so every project (小美, 3D, MetaMe, etc.) gets the system automatically.
|
|
632
|
+
// Project-level CLAUDE.md only needs role definitions — no kernel duplication.
|
|
621
633
|
const GLOBAL_CLAUDE_MD = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
622
634
|
const GLOBAL_MARKER_START = '<!-- METAME-GLOBAL:START -->';
|
|
623
635
|
const GLOBAL_MARKER_END = '<!-- METAME-GLOBAL:END -->';
|
|
624
636
|
|
|
625
|
-
//
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
637
|
+
// Build dynamic Agent dispatch table from daemon.yaml projects.
|
|
638
|
+
// Only include agents whose cwd actually exists on disk — test/stale agents
|
|
639
|
+
// with deleted paths are automatically excluded, no manual cleanup needed.
|
|
640
|
+
let dispatchTable = '';
|
|
641
|
+
try {
|
|
642
|
+
const daemonYamlPath = path.join(os.homedir(), '.metame', 'daemon.yaml');
|
|
643
|
+
if (fs.existsSync(daemonYamlPath)) {
|
|
644
|
+
const daemonCfg = yaml.load(fs.readFileSync(daemonYamlPath, 'utf8')) || {};
|
|
645
|
+
const projects = daemonCfg.projects || {};
|
|
646
|
+
const rows = Object.entries(projects)
|
|
647
|
+
.filter(([, p]) => {
|
|
648
|
+
if (!p || !p.name || !p.cwd) return false;
|
|
649
|
+
// Expand ~ to home directory
|
|
650
|
+
const expandedCwd = String(p.cwd).replace(/^~/, os.homedir());
|
|
651
|
+
return fs.existsSync(expandedCwd);
|
|
652
|
+
})
|
|
653
|
+
.map(([key, p]) => `| \`${key}\` | ${p.name} |`);
|
|
654
|
+
if (rows.length > 0) {
|
|
655
|
+
dispatchTable = '\n\n| project_key | 昵称 |\n|-------------|------|\n' + rows.join('\n') + '\n\n`--new` 强制新建会话(用户说"新开会话"时加此参数)。';
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
} catch { /* daemon.yaml missing or invalid — skip dispatch table */ }
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
// Full kernel body: reuse PROTOCOL_NORMAL, strip project-level marker
|
|
662
|
+
const KERNEL_BODY = PROTOCOL_NORMAL
|
|
663
|
+
.replace(/^<!-- METAME:START -->\n/, '') // remove project-level marker
|
|
664
|
+
.trimEnd();
|
|
665
|
+
|
|
666
|
+
const CAPABILITY_SECTIONS = [
|
|
667
|
+
'## Agent Dispatch',
|
|
668
|
+
`"告诉X/让X" → \`~/.metame/bin/dispatch_to <project_key> "内容"\`,手机端 \`/dispatch to <key> <消息>\`。` + dispatchTable,
|
|
669
|
+
'新增 Agent:`/agent bind <名称> <工作目录>`',
|
|
670
|
+
'',
|
|
671
|
+
'## 跨会话记忆',
|
|
672
|
+
'用户提"上次/之前"时搜索:`node ~/.metame/memory-search.js "关键词1" "keyword2"`',
|
|
673
|
+
'一次传 3-4 个关键词(中文+英文+函数名),`--facts` 只搜事实,`--sessions` 只搜会话。',
|
|
674
|
+
'',
|
|
675
|
+
'## Skills',
|
|
676
|
+
'能力不足/工具缺失/任务失败 → 先查 `cat ~/.claude/skills/skill-manager/SKILL.md`,不要自己猜。',
|
|
677
|
+
'',
|
|
678
|
+
'## 手机端文件交互',
|
|
679
|
+
'**收**:用户发图片/文件自动存到 `upload/`,用 Read 查看。',
|
|
680
|
+
'**发**:回复末尾加 `[[FILE:/absolute/path]]`,daemon 自动发手机。不要读内容再复述。',
|
|
681
|
+
|
|
682
|
+
].join('\n');
|
|
647
683
|
|
|
648
684
|
try {
|
|
649
685
|
const globalDir = path.join(os.homedir(), '.claude');
|
|
@@ -652,34 +688,32 @@ try {
|
|
|
652
688
|
let globalContent = '';
|
|
653
689
|
if (fs.existsSync(GLOBAL_CLAUDE_MD)) {
|
|
654
690
|
globalContent = fs.readFileSync(GLOBAL_CLAUDE_MD, 'utf8');
|
|
655
|
-
// Remove previous injection
|
|
691
|
+
// Remove previous global injection (always replace with latest)
|
|
656
692
|
globalContent = globalContent.replace(new RegExp(
|
|
657
|
-
GLOBAL_MARKER_START.replace(/[.*+?^${}()|[
|
|
693
|
+
GLOBAL_MARKER_START.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&') +
|
|
658
694
|
'[\\s\\S]*?' +
|
|
659
|
-
GLOBAL_MARKER_END.replace(/[.*+?^${}()|[
|
|
695
|
+
GLOBAL_MARKER_END.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&') + '\\n?'
|
|
660
696
|
), '');
|
|
661
697
|
}
|
|
662
698
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
699
|
+
const injection =
|
|
700
|
+
GLOBAL_MARKER_START + '\n' +
|
|
701
|
+
KERNEL_BODY + '\n\n' +
|
|
702
|
+
'# MetaMe 能力注入(自动生成,勿手动编辑)\n\n' +
|
|
703
|
+
CAPABILITY_SECTIONS + '\n\n' +
|
|
704
|
+
GLOBAL_MARKER_END;
|
|
666
705
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
needed.map(s => s.text.join('\n')).join('\n\n') + '\n\n' + GLOBAL_MARKER_END;
|
|
670
|
-
const finalGlobal = globalContent.trimEnd() + '\n\n' + injection + '\n';
|
|
671
|
-
fs.writeFileSync(GLOBAL_CLAUDE_MD, finalGlobal, 'utf8');
|
|
672
|
-
} else {
|
|
673
|
-
// All sections already present, just clean up stale marker block
|
|
674
|
-
fs.writeFileSync(GLOBAL_CLAUDE_MD, globalContent.trimEnd() + '\n', 'utf8');
|
|
675
|
-
}
|
|
706
|
+
const finalGlobal = globalContent.trimEnd() + (globalContent.trim() ? '\n\n' : '') + injection + '\n';
|
|
707
|
+
fs.writeFileSync(GLOBAL_CLAUDE_MD, finalGlobal, 'utf8');
|
|
676
708
|
} catch (e) {
|
|
677
709
|
// Non-fatal: global CLAUDE.md injection is best-effort
|
|
678
710
|
console.error(`⚠️ Failed to inject global CLAUDE.md: ${e.message}`);
|
|
679
711
|
}
|
|
680
712
|
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
|
|
681
716
|
console.log("🔮 MetaMe: Link Established.");
|
|
682
|
-
console.log("🧬 Protocol: Dynamic Handshake Active");
|
|
683
717
|
|
|
684
718
|
// Memory system status — show live stats without blocking launch
|
|
685
719
|
try {
|
|
@@ -699,6 +733,39 @@ try {
|
|
|
699
733
|
}
|
|
700
734
|
} catch { /* non-fatal */ }
|
|
701
735
|
|
|
736
|
+
// Cognitive distillation status — always show so user knows the system's state
|
|
737
|
+
try {
|
|
738
|
+
const bufferFile = path.join(METAME_DIR, 'raw_signals.jsonl');
|
|
739
|
+
const pendingCount = fs.existsSync(bufferFile)
|
|
740
|
+
? fs.readFileSync(bufferFile, 'utf8').trim().split('\n').filter(l => l.trim()).length
|
|
741
|
+
: 0;
|
|
742
|
+
|
|
743
|
+
if (pendingCount > 0) {
|
|
744
|
+
console.log(`🧬 Cognition: ${pendingCount} moment${pendingCount > 1 ? 's' : ''} pending distillation`);
|
|
745
|
+
} else {
|
|
746
|
+
// Show last distill time
|
|
747
|
+
let lastDistillStr = '从未';
|
|
748
|
+
try {
|
|
749
|
+
const profilePath = path.join(process.env.HOME || '', '.claude_profile.yaml');
|
|
750
|
+
if (fs.existsSync(profilePath)) {
|
|
751
|
+
const _yaml = require('js-yaml');
|
|
752
|
+
const profile = _yaml.load(fs.readFileSync(profilePath, 'utf8'));
|
|
753
|
+
const distillLog = profile && profile.evolution && profile.evolution.auto_distill;
|
|
754
|
+
if (Array.isArray(distillLog) && distillLog.length > 0) {
|
|
755
|
+
const lastTs = new Date(distillLog[distillLog.length - 1].ts).getTime();
|
|
756
|
+
const diffMs = Date.now() - lastTs;
|
|
757
|
+
const diffH = Math.floor(diffMs / 3600000);
|
|
758
|
+
const diffM = Math.floor((diffMs % 3600000) / 60000);
|
|
759
|
+
lastDistillStr = diffH > 0 ? `${diffH}h${diffM}m 前` : `${diffM}m 前`;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
} catch { /* non-fatal */ }
|
|
763
|
+
console.log(`🧬 Cognition: 无新信号 · 上次蒸馏 ${lastDistillStr}`);
|
|
764
|
+
}
|
|
765
|
+
} catch { /* non-fatal */ }
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
702
769
|
// ---------------------------------------------------------
|
|
703
770
|
// 4.9 AUTO-UPDATE CHECK (non-blocking)
|
|
704
771
|
// ---------------------------------------------------------
|
|
@@ -715,7 +782,7 @@ const CURRENT_VERSION = require('./package.json').version;
|
|
|
715
782
|
res.on('end', () => {
|
|
716
783
|
try { resolve(JSON.parse(data).version); } catch { reject(); }
|
|
717
784
|
});
|
|
718
|
-
}).on('error', reject).on('timeout', function() { this.destroy(); reject(); });
|
|
785
|
+
}).on('error', reject).on('timeout', function () { this.destroy(); reject(); });
|
|
719
786
|
});
|
|
720
787
|
|
|
721
788
|
if (latest && latest !== CURRENT_VERSION) {
|
|
@@ -731,6 +798,71 @@ const CURRENT_VERSION = require('./package.json').version;
|
|
|
731
798
|
} catch { /* network unavailable, skip silently */ }
|
|
732
799
|
})();
|
|
733
800
|
|
|
801
|
+
// ---------------------------------------------------------
|
|
802
|
+
// 4.95 QMD OPTIONAL INSTALL PROMPT (one-time)
|
|
803
|
+
// ---------------------------------------------------------
|
|
804
|
+
// Only prompt when: TTY environment + QMD not installed + never asked before.
|
|
805
|
+
// Uses synchronous fs.readSync on stdin — no async/readline complexity.
|
|
806
|
+
// Writes a flag file after asking so this prompt never appears again.
|
|
807
|
+
(function maybeOfferQmd() {
|
|
808
|
+
const QMD_OFFERED_FILE = path.join(METAME_DIR, '.qmd_offered');
|
|
809
|
+
const isTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
810
|
+
if (!isTTY) return; // non-interactive env: CI, pipe, etc.
|
|
811
|
+
if (fs.existsSync(QMD_OFFERED_FILE)) return; // already offered before
|
|
812
|
+
|
|
813
|
+
// Check if QMD already installed
|
|
814
|
+
try { execSync('which qmd', { stdio: 'pipe', timeout: 2000 }); return; } catch { }
|
|
815
|
+
|
|
816
|
+
// Mark as offered NOW — so crash/ctrl-c won't re-ask
|
|
817
|
+
try { fs.writeFileSync(QMD_OFFERED_FILE, new Date().toISOString(), 'utf8'); } catch { }
|
|
818
|
+
|
|
819
|
+
// Check bun availability
|
|
820
|
+
let bunAvailable = false;
|
|
821
|
+
try { execSync('which bun', { stdio: 'pipe', timeout: 2000 }); bunAvailable = true; } catch { }
|
|
822
|
+
|
|
823
|
+
console.log('');
|
|
824
|
+
console.log('┌─ 🔍 记忆搜索增强(可选,免费)');
|
|
825
|
+
console.log('│');
|
|
826
|
+
console.log('│ 当前模式:基础全文搜索(FTS5)');
|
|
827
|
+
console.log('│ 安装 QMD 后:BM25 + 向量语义 + 重排序 混合搜索');
|
|
828
|
+
console.log('│ 效果:召回质量约 5x,模糊描述也能精准命中历史记忆');
|
|
829
|
+
if (!bunAvailable) {
|
|
830
|
+
console.log('│');
|
|
831
|
+
console.log('│ ⚠️ 未检测到 bun,无法自动安装。');
|
|
832
|
+
console.log('│ 手动安装:curl -fsSL https://bun.sh/install | bash');
|
|
833
|
+
console.log('│ bun install -g github:tobi/qmd');
|
|
834
|
+
console.log('└────────────────────────────────────────────────');
|
|
835
|
+
console.log('');
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
console.log('│ 耗时:约 30 秒');
|
|
839
|
+
console.log('│');
|
|
840
|
+
|
|
841
|
+
// Synchronous prompt — read one character from stdin
|
|
842
|
+
try {
|
|
843
|
+
process.stdout.write('└─ 立即安装?(y/N) › ');
|
|
844
|
+
const buf = Buffer.alloc(8);
|
|
845
|
+
const n = fs.readSync(0, buf, 0, 8);
|
|
846
|
+
const answer = buf.slice(0, n).toString().trim().toLowerCase();
|
|
847
|
+
process.stdout.write('\n');
|
|
848
|
+
|
|
849
|
+
if (answer === 'y' || answer === 'yes') {
|
|
850
|
+
console.log(' ⬇️ 正在安装 QMD...');
|
|
851
|
+
try {
|
|
852
|
+
execSync('bun install -g github:tobi/qmd', { stdio: 'inherit', timeout: 120000 });
|
|
853
|
+
console.log(' ✅ QMD 已安装,下次记忆搜索自动启用向量模式。');
|
|
854
|
+
} catch {
|
|
855
|
+
console.log(' ⚠️ 安装失败,可手动执行:bun install -g github:tobi/qmd');
|
|
856
|
+
}
|
|
857
|
+
} else {
|
|
858
|
+
console.log(' 跳过。如需日后安装:bun install -g github:tobi/qmd');
|
|
859
|
+
}
|
|
860
|
+
console.log('');
|
|
861
|
+
} catch {
|
|
862
|
+
// stdin not readable (edge case) — silent skip
|
|
863
|
+
}
|
|
864
|
+
})();
|
|
865
|
+
|
|
734
866
|
// ---------------------------------------------------------
|
|
735
867
|
// 5. LAUNCH CLAUDE (OR HOT RELOAD)
|
|
736
868
|
// ---------------------------------------------------------
|
|
@@ -1231,8 +1363,8 @@ if (isDaemon) {
|
|
|
1231
1363
|
cfg.feishu.app_secret = feishuSecret;
|
|
1232
1364
|
if (!cfg.feishu.allowed_chat_ids) cfg.feishu.allowed_chat_ids = [];
|
|
1233
1365
|
console.log(" ✅ Feishu configured!");
|
|
1234
|
-
console.log(" Note: allowed_chat_ids is empty =
|
|
1235
|
-
console.log("
|
|
1366
|
+
console.log(" Note: allowed_chat_ids is empty = deny all users.");
|
|
1367
|
+
console.log(" Add chat IDs to daemon.yaml or use /agent bind from target chat.\n");
|
|
1236
1368
|
}
|
|
1237
1369
|
} else {
|
|
1238
1370
|
console.log(" Skipped.\n");
|
|
@@ -1463,13 +1595,29 @@ WantedBy=default.target
|
|
|
1463
1595
|
|
|
1464
1596
|
// Tasks
|
|
1465
1597
|
const tasks = state.tasks || {};
|
|
1466
|
-
|
|
1598
|
+
const configuredTaskNames = new Set();
|
|
1599
|
+
for (const t of ((config.heartbeat && config.heartbeat.tasks) || [])) {
|
|
1600
|
+
if (t && t.name) configuredTaskNames.add(t.name);
|
|
1601
|
+
}
|
|
1602
|
+
for (const proj of Object.values(config.projects || {})) {
|
|
1603
|
+
for (const t of ((proj && proj.heartbeat_tasks) || [])) {
|
|
1604
|
+
if (t && t.name) configuredTaskNames.add(t.name);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
const taskEntries = Object.entries(tasks).filter(([name]) =>
|
|
1608
|
+
configuredTaskNames.size === 0 || configuredTaskNames.has(name)
|
|
1609
|
+
);
|
|
1610
|
+
if (taskEntries.length > 0) {
|
|
1467
1611
|
console.log(" Recent tasks:");
|
|
1468
|
-
for (const [name, info] of
|
|
1612
|
+
for (const [name, info] of taskEntries) {
|
|
1469
1613
|
const icon = info.status === 'success' ? '✅' : '❌';
|
|
1470
1614
|
console.log(` ${icon} ${name}: ${info.last_run || 'unknown'}`);
|
|
1471
1615
|
if (info.output_preview) console.log(` ${info.output_preview.slice(0, 80)}...`);
|
|
1472
1616
|
}
|
|
1617
|
+
const hiddenStale = Object.keys(tasks).length - taskEntries.length;
|
|
1618
|
+
if (hiddenStale > 0) {
|
|
1619
|
+
console.log(` … ${hiddenStale} stale task record(s) hidden`);
|
|
1620
|
+
}
|
|
1473
1621
|
}
|
|
1474
1622
|
process.exit(0);
|
|
1475
1623
|
}
|
|
@@ -1641,4 +1789,4 @@ child.on('error', () => {
|
|
|
1641
1789
|
child.on('close', (code) => process.exit(code || 0));
|
|
1642
1790
|
|
|
1643
1791
|
// Launch background distillation AFTER Claude starts — no blocking
|
|
1644
|
-
spawnDistillBackground();
|
|
1792
|
+
spawnDistillBackground();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metame-cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.13",
|
|
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/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-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'",
|
|
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
|
},
|