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/scripts/distill.js
CHANGED
|
@@ -159,6 +159,7 @@ RULES:
|
|
|
159
159
|
5. Episodic exceptions: context.anti_patterns (max 5, cross-project lessons only), context.milestones (max 3).
|
|
160
160
|
6. Strong directives (以后一律/always/never/from now on) → _confidence: high. Otherwise: normal.
|
|
161
161
|
7. Add _confidence and _source blocks mapping field keys to confidence level and triggering quote.
|
|
162
|
+
8. NEVER extract agent identity or role definitions. Messages like "你是贾维斯/你的角色是.../you are Jarvis" define the AGENT, not the USER. The profile is about the USER's cognition only.
|
|
162
163
|
|
|
163
164
|
BIAS PREVENTION:
|
|
164
165
|
- Single observation = STATE, not TRAIT. T3 cognition needs 3+ observations.
|
|
@@ -38,7 +38,7 @@ function createBot(config) {
|
|
|
38
38
|
* Send a plain text message
|
|
39
39
|
*/
|
|
40
40
|
async sendMessage(chatId, text) {
|
|
41
|
-
await client.im.message.create({
|
|
41
|
+
const res = await client.im.message.create({
|
|
42
42
|
params: { receive_id_type: 'chat_id' },
|
|
43
43
|
data: {
|
|
44
44
|
receive_id: chatId,
|
|
@@ -46,20 +46,155 @@ function createBot(config) {
|
|
|
46
46
|
content: JSON.stringify({ text }),
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
|
+
// Return Telegram-compatible shape so daemon can edit it later
|
|
50
|
+
const msgId = res?.data?.message_id;
|
|
51
|
+
return msgId ? { message_id: msgId } : null;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
_editBroken: false, // Set to true if patch API consistently fails
|
|
55
|
+
async editMessage(chatId, messageId, text) {
|
|
56
|
+
if (this._editBroken) return false;
|
|
57
|
+
try {
|
|
58
|
+
await client.im.message.patch({
|
|
59
|
+
path: { message_id: messageId },
|
|
60
|
+
data: { content: JSON.stringify({ text }) },
|
|
61
|
+
});
|
|
62
|
+
return true;
|
|
63
|
+
} catch (e) {
|
|
64
|
+
const code = e?.code || e?.response?.data?.code;
|
|
65
|
+
if (code === 230001 || code === 230002 || /permission|forbidden/i.test(String(e))) {
|
|
66
|
+
this._editBroken = true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
49
70
|
},
|
|
50
71
|
|
|
51
72
|
/**
|
|
52
|
-
* Send markdown
|
|
73
|
+
* Send markdown as Feishu interactive card (lark_md renders bold, lists, code, links)
|
|
53
74
|
*/
|
|
54
75
|
async sendMarkdown(chatId, markdown) {
|
|
55
|
-
|
|
76
|
+
// Convert standard markdown → lark_md compatible format
|
|
77
|
+
let content = markdown
|
|
78
|
+
.replace(/^(#{1,3})\s+(.+)$/gm, '**$2**') // headers → bold
|
|
79
|
+
.replace(/^---+$/gm, '─────────────────────'); // hr → unicode line
|
|
80
|
+
|
|
81
|
+
// Split into chunks if too long (element limit ~4000 chars)
|
|
82
|
+
const MAX_CHUNK = 3800;
|
|
83
|
+
const chunks = [];
|
|
84
|
+
if (content.length <= MAX_CHUNK) {
|
|
85
|
+
chunks.push(content);
|
|
86
|
+
} else {
|
|
87
|
+
const paragraphs = content.split(/\n\n/);
|
|
88
|
+
let buf = '';
|
|
89
|
+
for (const p of paragraphs) {
|
|
90
|
+
if (buf.length + p.length + 2 > MAX_CHUNK && buf) {
|
|
91
|
+
chunks.push(buf);
|
|
92
|
+
buf = p;
|
|
93
|
+
} else {
|
|
94
|
+
buf = buf ? buf + '\n\n' + p : p;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (buf) chunks.push(buf);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// V2 schema: markdown element with normal text size
|
|
101
|
+
const elements = chunks.map(c => ({
|
|
102
|
+
tag: 'markdown',
|
|
103
|
+
content: c,
|
|
104
|
+
text_size: 'x-large',
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const card = {
|
|
108
|
+
schema: '2.0',
|
|
109
|
+
body: { elements },
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const res = await client.im.message.create({
|
|
56
113
|
params: { receive_id_type: 'chat_id' },
|
|
57
114
|
data: {
|
|
58
115
|
receive_id: chatId,
|
|
59
|
-
msg_type: '
|
|
60
|
-
content: JSON.stringify(
|
|
116
|
+
msg_type: 'interactive',
|
|
117
|
+
content: JSON.stringify(card),
|
|
61
118
|
},
|
|
62
119
|
});
|
|
120
|
+
const msgId = res?.data?.message_id;
|
|
121
|
+
return msgId ? { message_id: msgId } : null;
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Send a colored interactive card (for project-tagged notifications)
|
|
126
|
+
* @param {string} chatId
|
|
127
|
+
* @param {string} title - card header text
|
|
128
|
+
* @param {string} body - card body (lark markdown)
|
|
129
|
+
* @param {string} color - header color: blue|orange|green|red|grey|purple|turquoise
|
|
130
|
+
*/
|
|
131
|
+
async sendCard(chatId, { title, body, color = 'blue' }) {
|
|
132
|
+
// Use card schema V2 for better text sizing
|
|
133
|
+
if (!body) {
|
|
134
|
+
const card = {
|
|
135
|
+
schema: '2.0',
|
|
136
|
+
header: { title: { tag: 'plain_text', content: title }, template: color },
|
|
137
|
+
body: { elements: [] },
|
|
138
|
+
};
|
|
139
|
+
const res = await client.im.message.create({
|
|
140
|
+
params: { receive_id_type: 'chat_id' },
|
|
141
|
+
data: { receive_id: chatId, msg_type: 'interactive', content: JSON.stringify(card) },
|
|
142
|
+
});
|
|
143
|
+
const msgId = res?.data?.message_id;
|
|
144
|
+
return msgId ? { message_id: msgId } : null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Convert standard markdown → lark_md
|
|
148
|
+
let content = body
|
|
149
|
+
.replace(/^(#{1,3})\s+(.+)$/gm, '**$2**')
|
|
150
|
+
.replace(/^---+$/gm, '─────────────────────');
|
|
151
|
+
|
|
152
|
+
// Split into chunks (lark_md element limit ~4000 chars)
|
|
153
|
+
const MAX_CHUNK = 3800;
|
|
154
|
+
const chunks = [];
|
|
155
|
+
if (content.length <= MAX_CHUNK) {
|
|
156
|
+
chunks.push(content);
|
|
157
|
+
} else {
|
|
158
|
+
const paragraphs = content.split(/\n\n/);
|
|
159
|
+
let buf = '';
|
|
160
|
+
for (const p of paragraphs) {
|
|
161
|
+
if (buf.length + p.length + 2 > MAX_CHUNK && buf) {
|
|
162
|
+
chunks.push(buf);
|
|
163
|
+
buf = p;
|
|
164
|
+
} else {
|
|
165
|
+
buf = buf ? buf + '\n\n' + p : p;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (buf) chunks.push(buf);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// V2: use markdown element with text_size for readable font
|
|
172
|
+
const elements = chunks.map(c => ({
|
|
173
|
+
tag: 'markdown',
|
|
174
|
+
content: c,
|
|
175
|
+
text_size: 'x-large',
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
const card = {
|
|
179
|
+
schema: '2.0',
|
|
180
|
+
header: { title: { tag: 'plain_text', content: title }, template: color },
|
|
181
|
+
body: { elements },
|
|
182
|
+
};
|
|
183
|
+
const res = await client.im.message.create({
|
|
184
|
+
params: { receive_id_type: 'chat_id' },
|
|
185
|
+
data: { receive_id: chatId, msg_type: 'interactive', content: JSON.stringify(card) },
|
|
186
|
+
});
|
|
187
|
+
const msgId = res?.data?.message_id;
|
|
188
|
+
return msgId ? { message_id: msgId } : null;
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Delete a message by ID
|
|
193
|
+
*/
|
|
194
|
+
async deleteMessage(chatId, messageId) {
|
|
195
|
+
try {
|
|
196
|
+
await client.im.message.delete({ path: { message_id: messageId } });
|
|
197
|
+
} catch { /* non-fatal — message may already be deleted or expired */ }
|
|
63
198
|
},
|
|
64
199
|
|
|
65
200
|
/**
|
|
@@ -271,6 +406,7 @@ function createBot(config) {
|
|
|
271
406
|
if (isDuplicate(msg.message_id)) return;
|
|
272
407
|
|
|
273
408
|
const chatId = msg.chat_id;
|
|
409
|
+
const senderId = data.sender && data.sender.sender_id && data.sender.sender_id.open_id || null;
|
|
274
410
|
let text = '';
|
|
275
411
|
let fileInfo = null;
|
|
276
412
|
|
|
@@ -299,7 +435,7 @@ function createBot(config) {
|
|
|
299
435
|
|
|
300
436
|
if (text || fileInfo) {
|
|
301
437
|
// Fire-and-forget: don't block the event loop (SDK needs fast ack)
|
|
302
|
-
Promise.resolve().then(() => onMessage(chatId, text, data, fileInfo)).catch(() => {});
|
|
438
|
+
Promise.resolve().then(() => onMessage(chatId, text, data, fileInfo, senderId)).catch(() => {});
|
|
303
439
|
}
|
|
304
440
|
} catch (e) {
|
|
305
441
|
// Non-fatal
|
package/scripts/schema.js
CHANGED
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
const SCHEMA = {
|
|
19
|
-
// === T1: Identity ===
|
|
20
|
-
'identity.nickname': { tier: 'T1', type: 'string', locked: true },
|
|
19
|
+
// === T1: Identity (USER's identity, not agent's) ===
|
|
21
20
|
'identity.role': { tier: 'T1', type: 'string', locked: false },
|
|
22
21
|
'identity.locale': { tier: 'T1', type: 'string', locked: true },
|
|
23
22
|
|
|
@@ -13,7 +13,6 @@ const path = require('path');
|
|
|
13
13
|
const os = require('os');
|
|
14
14
|
|
|
15
15
|
const BUFFER_FILE = path.join(os.homedir(), '.metame', 'raw_signals.jsonl');
|
|
16
|
-
const MAX_BUFFER_LINES = 50; // Safety cap to avoid unbounded growth
|
|
17
16
|
|
|
18
17
|
// === CONFIDENCE PATTERNS ===
|
|
19
18
|
|
|
@@ -66,6 +65,11 @@ process.stdin.on('end', () => {
|
|
|
66
65
|
process.exit(0);
|
|
67
66
|
}
|
|
68
67
|
|
|
68
|
+
// Skip agent identity definitions (these belong in project CLAUDE.md, not user profile)
|
|
69
|
+
if (/^(你是|你叫|你的(角色|身份|职责|任务)|你负责|你现在是|from now on you are|you are now|your role is)/i.test(prompt)) {
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
// Skip pasted error logs / stack traces
|
|
70
74
|
if (/^(Error|TypeError|SyntaxError|ReferenceError|at\s+\w+|Traceback|FATAL|WARN|ERR!)/i.test(prompt)) {
|
|
71
75
|
process.exit(0);
|
|
@@ -110,11 +114,6 @@ process.stdin.on('end', () => {
|
|
|
110
114
|
|
|
111
115
|
existingLines.push(JSON.stringify(entry));
|
|
112
116
|
|
|
113
|
-
// Keep only the most recent entries (drop oldest)
|
|
114
|
-
if (existingLines.length > MAX_BUFFER_LINES) {
|
|
115
|
-
existingLines = existingLines.slice(-MAX_BUFFER_LINES);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
117
|
fs.writeFileSync(BUFFER_FILE, existingLines.join('\n') + '\n');
|
|
119
118
|
|
|
120
119
|
} catch {
|