metame-cli 1.4.34 → 1.5.1
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 +136 -94
- package/index.js +312 -57
- package/package.json +8 -4
- package/scripts/agent-layer.js +320 -0
- package/scripts/daemon-admin-commands.js +328 -28
- package/scripts/daemon-agent-commands.js +145 -6
- package/scripts/daemon-agent-tools.js +163 -7
- package/scripts/daemon-bridges.js +110 -20
- package/scripts/daemon-checkpoints.js +36 -7
- package/scripts/daemon-claude-engine.js +849 -358
- package/scripts/daemon-command-router.js +31 -10
- package/scripts/daemon-default.yaml +28 -4
- package/scripts/daemon-engine-runtime.js +328 -0
- package/scripts/daemon-exec-commands.js +15 -7
- package/scripts/daemon-notify.js +37 -1
- package/scripts/daemon-ops-commands.js +8 -6
- package/scripts/daemon-runtime-lifecycle.js +129 -5
- package/scripts/daemon-session-commands.js +60 -25
- package/scripts/daemon-session-store.js +121 -13
- package/scripts/daemon-task-scheduler.js +129 -49
- package/scripts/daemon-user-acl.js +35 -9
- package/scripts/daemon.js +268 -33
- package/scripts/distill.js +327 -18
- package/scripts/docs/agent-guide.md +12 -0
- package/scripts/docs/maintenance-manual.md +155 -0
- package/scripts/docs/pointer-map.md +110 -0
- package/scripts/feishu-adapter.js +42 -13
- package/scripts/hooks/stop-session-capture.js +243 -0
- package/scripts/memory-extract.js +105 -6
- package/scripts/memory-nightly-reflect.js +199 -11
- package/scripts/memory.js +134 -3
- package/scripts/mentor-engine.js +405 -0
- package/scripts/platform.js +24 -0
- package/scripts/providers.js +182 -22
- package/scripts/schema.js +12 -0
- package/scripts/session-analytics.js +245 -12
- package/scripts/skill-changelog.js +245 -0
- package/scripts/skill-evolution.js +288 -5
- package/scripts/telegram-adapter.js +12 -8
- package/scripts/usage-classifier.js +1 -1
- package/scripts/daemon-admin-commands.test.js +0 -333
- package/scripts/daemon-task-envelope.test.js +0 -59
- package/scripts/daemon-task-scheduler.test.js +0 -106
- package/scripts/reliability-core.test.js +0 -280
- package/scripts/skill-evolution.test.js +0 -113
- package/scripts/task-board.test.js +0 -83
- package/scripts/test_daemon.js +0 -1407
- package/scripts/utils.test.js +0 -192
package/scripts/utils.test.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it, beforeEach } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const {
|
|
8
|
-
parseInterval,
|
|
9
|
-
formatRelativeTime,
|
|
10
|
-
createPathMap,
|
|
11
|
-
normalizeProjectPath,
|
|
12
|
-
projectScopeFromCwd,
|
|
13
|
-
deriveProjectInfo,
|
|
14
|
-
buildTopicSignature,
|
|
15
|
-
hasTopicDrift,
|
|
16
|
-
} = require('./utils');
|
|
17
|
-
|
|
18
|
-
// ---------------------------------------------------------
|
|
19
|
-
// parseInterval
|
|
20
|
-
// ---------------------------------------------------------
|
|
21
|
-
describe('parseInterval', () => {
|
|
22
|
-
it('parses seconds', () => {
|
|
23
|
-
assert.equal(parseInterval('30s'), 30);
|
|
24
|
-
assert.equal(parseInterval('1s'), 1);
|
|
25
|
-
assert.equal(parseInterval('0s'), 0);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('parses minutes', () => {
|
|
29
|
-
assert.equal(parseInterval('5m'), 300);
|
|
30
|
-
assert.equal(parseInterval('1m'), 60);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('parses hours', () => {
|
|
34
|
-
assert.equal(parseInterval('1h'), 3600);
|
|
35
|
-
assert.equal(parseInterval('2h'), 7200);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('parses days', () => {
|
|
39
|
-
assert.equal(parseInterval('1d'), 86400);
|
|
40
|
-
assert.equal(parseInterval('7d'), 604800);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('defaults to 3600 for invalid input', () => {
|
|
44
|
-
assert.equal(parseInterval('abc'), 3600);
|
|
45
|
-
assert.equal(parseInterval(''), 3600);
|
|
46
|
-
assert.equal(parseInterval('10'), 3600);
|
|
47
|
-
assert.equal(parseInterval('10x'), 3600);
|
|
48
|
-
assert.equal(parseInterval(null), 3600);
|
|
49
|
-
assert.equal(parseInterval(undefined), 3600);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// ---------------------------------------------------------
|
|
54
|
-
// formatRelativeTime
|
|
55
|
-
// ---------------------------------------------------------
|
|
56
|
-
describe('formatRelativeTime', () => {
|
|
57
|
-
it('returns 刚刚 for times less than 1 minute ago', () => {
|
|
58
|
-
const now = new Date().toISOString();
|
|
59
|
-
assert.equal(formatRelativeTime(now), '刚刚');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('returns N分钟前 for times under 1 hour', () => {
|
|
63
|
-
const d = new Date(Date.now() - 5 * 60000).toISOString();
|
|
64
|
-
assert.equal(formatRelativeTime(d), '5分钟前');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('returns N小时前 for times under 24 hours', () => {
|
|
68
|
-
const d = new Date(Date.now() - 3 * 3600000).toISOString();
|
|
69
|
-
assert.equal(formatRelativeTime(d), '3小时前');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('returns 昨天 for 1 day ago', () => {
|
|
73
|
-
const d = new Date(Date.now() - 1.5 * 86400000).toISOString();
|
|
74
|
-
assert.equal(formatRelativeTime(d), '昨天');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('returns N天前 for 2-6 days', () => {
|
|
78
|
-
const d = new Date(Date.now() - 3 * 86400000).toISOString();
|
|
79
|
-
assert.equal(formatRelativeTime(d), '3天前');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('returns date for 7+ days', () => {
|
|
83
|
-
const d = new Date(Date.now() - 10 * 86400000).toISOString();
|
|
84
|
-
const result = formatRelativeTime(d);
|
|
85
|
-
// Should be a date string like "1/15" (month/day)
|
|
86
|
-
assert.match(result, /\d+\/\d+/);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// ---------------------------------------------------------
|
|
91
|
-
// createPathMap (shortenPath / expandPath)
|
|
92
|
-
// ---------------------------------------------------------
|
|
93
|
-
describe('createPathMap', () => {
|
|
94
|
-
let shortenPath, expandPath;
|
|
95
|
-
|
|
96
|
-
beforeEach(() => {
|
|
97
|
-
({ shortenPath, expandPath } = createPathMap());
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('shortens a path to a compact id', () => {
|
|
101
|
-
const id = shortenPath('/Users/foo/bar/baz');
|
|
102
|
-
assert.match(id, /^p\d+$/);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('expands back to original path', () => {
|
|
106
|
-
const original = '/Users/foo/bar/baz';
|
|
107
|
-
const id = shortenPath(original);
|
|
108
|
-
assert.equal(expandPath(id), original);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('returns same id for same path', () => {
|
|
112
|
-
const p = '/Users/foo/project';
|
|
113
|
-
const id1 = shortenPath(p);
|
|
114
|
-
const id2 = shortenPath(p);
|
|
115
|
-
assert.equal(id1, id2);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('returns different ids for different paths', () => {
|
|
119
|
-
const id1 = shortenPath('/a');
|
|
120
|
-
const id2 = shortenPath('/b');
|
|
121
|
-
assert.notEqual(id1, id2);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('expandPath returns input if not a known id', () => {
|
|
125
|
-
assert.equal(expandPath('/some/real/path'), '/some/real/path');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('ids are short enough for Telegram callback_data', () => {
|
|
129
|
-
// Even with 1000 paths, id should be < 10 bytes
|
|
130
|
-
for (let i = 0; i < 1000; i++) {
|
|
131
|
-
shortenPath(`/path/${i}`);
|
|
132
|
-
}
|
|
133
|
-
const id = shortenPath('/path/1000');
|
|
134
|
-
assert.ok(Buffer.byteLength(id) < 10, `id "${id}" too long`);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// ---------------------------------------------------------
|
|
139
|
-
// project scope helpers
|
|
140
|
-
// ---------------------------------------------------------
|
|
141
|
-
describe('project scope helpers', () => {
|
|
142
|
-
it('normalizes absolute paths', () => {
|
|
143
|
-
const input = path.join(os.tmpdir(), '.', 'metame', '..', 'metame');
|
|
144
|
-
const expected = path.resolve(os.tmpdir(), 'metame');
|
|
145
|
-
assert.equal(normalizeProjectPath(input), expected);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('returns deterministic scope ids for the same cwd', () => {
|
|
149
|
-
const base = path.join(os.tmpdir(), 'metame');
|
|
150
|
-
const dotted = path.join(os.tmpdir(), '.', 'metame');
|
|
151
|
-
const a = projectScopeFromCwd(base);
|
|
152
|
-
const b = projectScopeFromCwd(dotted);
|
|
153
|
-
assert.equal(a, b);
|
|
154
|
-
assert.match(a, /^proj_[a-f0-9]{16}$/);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('derives project info from cwd', () => {
|
|
158
|
-
const testPath = path.join(os.tmpdir(), 'demo-repo');
|
|
159
|
-
const info = deriveProjectInfo(testPath);
|
|
160
|
-
assert.equal(info.project, 'demo-repo');
|
|
161
|
-
assert.equal(info.project_path, path.resolve(testPath));
|
|
162
|
-
assert.match(info.project_id, /^proj_[a-f0-9]{16}$/);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// ---------------------------------------------------------
|
|
167
|
-
// topic drift helpers
|
|
168
|
-
// ---------------------------------------------------------
|
|
169
|
-
describe('topic drift helpers', () => {
|
|
170
|
-
it('extracts signature tokens for Chinese prompts', () => {
|
|
171
|
-
const sig = buildTopicSignature('修复登录超时并优化缓存策略');
|
|
172
|
-
assert.ok(sig.length >= 3, `expected >=3 tokens, got ${sig.length}`);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('extracts signature tokens for mixed Chinese/English prompts', () => {
|
|
176
|
-
const sig = buildTopicSignature('修复 daemon memory-extract timeout');
|
|
177
|
-
assert.ok(sig.includes('daemon'));
|
|
178
|
-
assert.ok(sig.some(t => /[\u4e00-\u9fff]/.test(t)));
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('detects drift when signatures diverge', () => {
|
|
182
|
-
const a = buildTopicSignature('修复登录超时和重试策略');
|
|
183
|
-
const b = buildTopicSignature('重构支付流水和对账报表');
|
|
184
|
-
assert.equal(hasTopicDrift(a, b), true);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('does not flag drift for similar topics', () => {
|
|
188
|
-
const a = buildTopicSignature('优化 memory 检索和缓存命中');
|
|
189
|
-
const b = buildTopicSignature('memory 检索改进与缓存策略');
|
|
190
|
-
assert.equal(hasTopicDrift(a, b), false);
|
|
191
|
-
});
|
|
192
|
-
});
|