metame-cli 1.5.19 → 1.5.21
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 +157 -80
- package/package.json +2 -2
- package/scripts/bin/bootstrap-worktree.sh +20 -0
- package/scripts/core/audit.js +190 -0
- package/scripts/core/handoff.js +780 -0
- package/scripts/core/handoff.test.js +1074 -0
- package/scripts/core/memory-model.js +183 -0
- package/scripts/core/memory-model.test.js +486 -0
- package/scripts/core/reactive-paths.js +44 -0
- package/scripts/core/reactive-paths.test.js +35 -0
- package/scripts/core/reactive-prompt.js +51 -0
- package/scripts/core/reactive-prompt.test.js +88 -0
- package/scripts/core/reactive-signal.js +40 -0
- package/scripts/core/reactive-signal.test.js +88 -0
- package/scripts/core/thread-chat-id.js +52 -0
- package/scripts/core/thread-chat-id.test.js +113 -0
- package/scripts/daemon-bridges.js +92 -38
- package/scripts/daemon-claude-engine.js +373 -444
- package/scripts/daemon-command-router.js +82 -8
- package/scripts/daemon-engine-runtime.js +7 -10
- package/scripts/daemon-reactive-lifecycle.js +100 -33
- package/scripts/daemon-session-commands.js +133 -43
- package/scripts/daemon-session-store.js +300 -82
- package/scripts/daemon-team-dispatch.js +16 -16
- package/scripts/daemon.js +21 -175
- package/scripts/deploy-manifest.js +90 -0
- package/scripts/docs/maintenance-manual.md +14 -11
- package/scripts/docs/pointer-map.md +13 -4
- package/scripts/feishu-adapter.js +31 -27
- package/scripts/hooks/intent-engine.js +6 -3
- package/scripts/hooks/intent-memory-recall.js +1 -0
- package/scripts/hooks/intent-perpetual.js +1 -1
- package/scripts/memory-extract.js +5 -97
- package/scripts/memory-gc.js +35 -90
- package/scripts/memory-migrate-v2.js +304 -0
- package/scripts/memory-nightly-reflect.js +40 -41
- package/scripts/memory.js +340 -859
- package/scripts/migrate-reactive-paths.js +122 -0
- package/scripts/signal-capture.js +4 -0
- package/scripts/sync-plugin.js +56 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const { resolveReactivePaths, resolveLegacyPaths } = require('./core/reactive-paths');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Discover all project keys that have legacy reactive files.
|
|
10
|
+
* Scans memory/now/ for *_memory.md, *.md (state), and events/ for *.jsonl.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} metameDir
|
|
13
|
+
* @returns {string[]} unique project keys
|
|
14
|
+
*/
|
|
15
|
+
function discoverLegacyKeys(metameDir) {
|
|
16
|
+
const keys = new Set();
|
|
17
|
+
|
|
18
|
+
// Scan memory/now/ for <key>_memory.md and <key>.md (state files)
|
|
19
|
+
const nowDir = path.join(metameDir, 'memory', 'now');
|
|
20
|
+
if (fs.existsSync(nowDir)) {
|
|
21
|
+
for (const file of fs.readdirSync(nowDir)) {
|
|
22
|
+
if (file === 'shared.md') continue; // skip shared.md
|
|
23
|
+
const memMatch = file.match(/^(.+)_memory\.md$/);
|
|
24
|
+
if (memMatch) { keys.add(memMatch[1]); continue; }
|
|
25
|
+
const l2Match = file.match(/^(.+)_l2cache\.md$/);
|
|
26
|
+
if (l2Match) { keys.add(l2Match[1]); continue; }
|
|
27
|
+
// State files: <key>.md (but not <key>_memory.md or <key>_l2cache.md)
|
|
28
|
+
if (file.endsWith('.md') && !file.endsWith('_memory.md') && !file.endsWith('_l2cache.md')) {
|
|
29
|
+
keys.add(file.replace(/\.md$/, ''));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Scan events/ for <key>.jsonl
|
|
35
|
+
const evDir = path.join(metameDir, 'events');
|
|
36
|
+
if (fs.existsSync(evDir)) {
|
|
37
|
+
for (const file of fs.readdirSync(evDir)) {
|
|
38
|
+
if (file.endsWith('.jsonl')) {
|
|
39
|
+
keys.add(file.replace(/\.jsonl$/, ''));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Scan memory/agents/ for <key>_latest.md
|
|
45
|
+
const agentsDir = path.join(metameDir, 'memory', 'agents');
|
|
46
|
+
if (fs.existsSync(agentsDir)) {
|
|
47
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
48
|
+
const latestMatch = file.match(/^(.+)_latest\.md$/);
|
|
49
|
+
if (latestMatch) keys.add(latestMatch[1]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return [...keys];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Migrate legacy flat reactive files to per-project directory structure.
|
|
58
|
+
* Idempotent: skips files that already exist at the destination.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} [metameDir] - defaults to ~/.metame
|
|
61
|
+
* @returns {{ migrated: string[], skipped: string[], errors: string[] }}
|
|
62
|
+
*/
|
|
63
|
+
function migrate(metameDir) {
|
|
64
|
+
metameDir = metameDir || path.join(os.homedir(), '.metame');
|
|
65
|
+
const report = { migrated: [], skipped: [], errors: [] };
|
|
66
|
+
|
|
67
|
+
const keys = discoverLegacyKeys(metameDir);
|
|
68
|
+
if (keys.length === 0) return report;
|
|
69
|
+
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
const legacy = resolveLegacyPaths(key, metameDir);
|
|
72
|
+
const target = resolveReactivePaths(key, metameDir);
|
|
73
|
+
|
|
74
|
+
// Create target directory
|
|
75
|
+
fs.mkdirSync(target.dir, { recursive: true });
|
|
76
|
+
|
|
77
|
+
const fileMap = [
|
|
78
|
+
{ src: legacy.memory, dst: target.memory, label: 'memory' },
|
|
79
|
+
{ src: legacy.l2cache, dst: target.l2cache, label: 'l2cache' },
|
|
80
|
+
{ src: legacy.state, dst: target.state, label: 'state' },
|
|
81
|
+
{ src: legacy.events, dst: target.events, label: 'events' },
|
|
82
|
+
{ src: legacy.latest, dst: target.latest, label: 'latest' },
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const { src, dst, label } of fileMap) {
|
|
86
|
+
if (!fs.existsSync(src)) continue;
|
|
87
|
+
if (fs.existsSync(dst)) {
|
|
88
|
+
report.skipped.push(`${key}/${label} (target exists)`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
fs.copyFileSync(src, dst);
|
|
93
|
+
fs.unlinkSync(src);
|
|
94
|
+
report.migrated.push(`${key}/${label}`);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
report.errors.push(`${key}/${label}: ${e.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return report;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// CLI mode
|
|
105
|
+
if (require.main === module) {
|
|
106
|
+
const metameDir = process.argv[2] || path.join(os.homedir(), '.metame');
|
|
107
|
+
console.log(`Migrating reactive paths in ${metameDir}...`);
|
|
108
|
+
const report = migrate(metameDir);
|
|
109
|
+
console.log(`Migrated: ${report.migrated.length}`);
|
|
110
|
+
for (const m of report.migrated) console.log(` + ${m}`);
|
|
111
|
+
if (report.skipped.length) {
|
|
112
|
+
console.log(`Skipped: ${report.skipped.length}`);
|
|
113
|
+
for (const s of report.skipped) console.log(` ~ ${s}`);
|
|
114
|
+
}
|
|
115
|
+
if (report.errors.length) {
|
|
116
|
+
console.log(`Errors: ${report.errors.length}`);
|
|
117
|
+
for (const e of report.errors) console.log(` ! ${e}`);
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = { migrate, discoverLegacyKeys };
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* persistent preferences/identity signals, appends to buffer.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
// Global safety net: hooks must NEVER crash or exit non-zero
|
|
12
|
+
process.on('uncaughtException', () => process.exit(0));
|
|
13
|
+
process.on('unhandledRejection', () => process.exit(0));
|
|
14
|
+
|
|
11
15
|
const fs = require('fs');
|
|
12
16
|
const path = require('path');
|
|
13
17
|
const os = require('os');
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const { collectDeployGroups } = require('./deploy-manifest');
|
|
7
|
+
|
|
8
|
+
function syncDirFiles(srcDir, destDir, { fileList, chmod } = {}) {
|
|
9
|
+
if (!fs.existsSync(srcDir)) return false;
|
|
10
|
+
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
11
|
+
let updated = false;
|
|
12
|
+
const files = fileList || fs.readdirSync(srcDir).filter((f) => fs.statSync(path.join(srcDir, f)).isFile());
|
|
13
|
+
for (const file of files) {
|
|
14
|
+
const src = path.join(srcDir, file);
|
|
15
|
+
const dest = path.join(destDir, file);
|
|
16
|
+
if (!fs.existsSync(src)) continue;
|
|
17
|
+
const srcContent = fs.readFileSync(src, 'utf8');
|
|
18
|
+
const destContent = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : '';
|
|
19
|
+
if (srcContent !== destContent) {
|
|
20
|
+
fs.writeFileSync(dest, srcContent, 'utf8');
|
|
21
|
+
if (chmod) {
|
|
22
|
+
try { fs.chmodSync(dest, chmod); } catch { /* ignore */ }
|
|
23
|
+
}
|
|
24
|
+
updated = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return updated;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function syncPluginScripts(projectRoot = process.cwd()) {
|
|
31
|
+
const scriptsDir = path.join(projectRoot, 'scripts');
|
|
32
|
+
const pluginScriptsDir = path.join(projectRoot, 'plugin', 'scripts');
|
|
33
|
+
const deployGroups = collectDeployGroups(fs, path, scriptsDir, {
|
|
34
|
+
excludedScripts: new Set(['sync-readme.js', 'test_daemon.js', 'daemon.yaml']),
|
|
35
|
+
includeNestedDirs: ['core'],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let updated = false;
|
|
39
|
+
for (const group of deployGroups) {
|
|
40
|
+
const destDir = group.destSubdir ? path.join(pluginScriptsDir, group.destSubdir) : pluginScriptsDir;
|
|
41
|
+
updated = syncDirFiles(group.srcDir, destDir, { fileList: group.fileList }) || updated;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
updated = syncDirFiles(path.join(scriptsDir, 'hooks'), path.join(pluginScriptsDir, 'hooks')) || updated;
|
|
45
|
+
return updated;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (require.main === module) {
|
|
49
|
+
syncPluginScripts(process.cwd());
|
|
50
|
+
console.log('Plugin scripts synced');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
syncPluginScripts,
|
|
55
|
+
syncDirFiles,
|
|
56
|
+
};
|