parallelclaw 1.0.0
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/CHANGELOG.md +204 -0
- package/HELP.md +600 -0
- package/LICENSE +21 -0
- package/MULTI_MACHINE.md +152 -0
- package/README.md +417 -0
- package/README.ru.md +740 -0
- package/SYNC.md +844 -0
- package/bot/README.md +173 -0
- package/bot/config.js +66 -0
- package/bot/inbox.js +153 -0
- package/bot/index.js +294 -0
- package/bot/nexara.js +61 -0
- package/bot/poll.js +304 -0
- package/bot/search.js +155 -0
- package/bot/telegram.js +96 -0
- package/ingest.js +2712 -0
- package/lib/cli/index.js +1987 -0
- package/lib/config.js +220 -0
- package/lib/db-init.js +158 -0
- package/lib/hook/install.js +268 -0
- package/lib/import-telegram.js +158 -0
- package/lib/ingest-file.js +779 -0
- package/lib/notify-click-action.js +281 -0
- package/lib/openclaw-channel.js +643 -0
- package/lib/parse-cursor.js +172 -0
- package/lib/parse-obsidian.js +256 -0
- package/lib/parse-telegram-html.js +384 -0
- package/lib/parse.js +175 -0
- package/lib/render-markdown.js +0 -0
- package/lib/store-doc/canonicalize.js +116 -0
- package/lib/store-doc/detect.js +209 -0
- package/lib/store-doc/extract-title.js +162 -0
- package/lib/sync/auth.js +80 -0
- package/lib/sync/cert.js +144 -0
- package/lib/sync/cli.js +906 -0
- package/lib/sync/client.js +138 -0
- package/lib/sync/config.js +130 -0
- package/lib/sync/pair.js +145 -0
- package/lib/sync/pull.js +158 -0
- package/lib/sync/push.js +305 -0
- package/lib/sync/replicate.js +335 -0
- package/lib/sync/server.js +224 -0
- package/lib/sync/service.js +726 -0
- package/lib/tasks.js +215 -0
- package/lib/telegram-decisions.js +165 -0
- package/lib/telegram-discovery.js +373 -0
- package/lib/telegram-notify.js +272 -0
- package/lib/telegram-pending.js +200 -0
- package/lib/web/index.js +265 -0
- package/lib/web/routes/conversation.js +193 -0
- package/lib/web/routes/conversations.js +180 -0
- package/lib/web/routes/dashboard.js +175 -0
- package/lib/web/routes/pending.js +277 -0
- package/lib/web/routes/settings.js +226 -0
- package/lib/web/static/style.css +393 -0
- package/lib/web/templates.js +234 -0
- package/package.json +84 -0
- package/server.js +3816 -0
- package/skills/install-memex/README.md +109 -0
- package/skills/install-memex/SKILL.md +342 -0
- package/skills/install-memex/examples.md +294 -0
- package/skills/install-memex-claw/SKILL.md +423 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Telegram-importer logic — used by both server.js (live, via inbox
|
|
3
|
+
* watcher) and the CLI (`memex telegram import` direct write).
|
|
4
|
+
*
|
|
5
|
+
* Takes a better-sqlite3 Database connection (write mode) and a parsed
|
|
6
|
+
* Telegram object (the shape produced by Telegram Desktop JSON export OR
|
|
7
|
+
* lib/parse-telegram-html.js).
|
|
8
|
+
*
|
|
9
|
+
* Returns:
|
|
10
|
+
* {
|
|
11
|
+
* totalImported: <int>, // messages inserted across all chats
|
|
12
|
+
* chats: [{
|
|
13
|
+
* conversation_id, title, msg_count, first_ts, last_ts
|
|
14
|
+
* }, ...]
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* UNIQUE(source, conversation_id, msg_id) handles dedupe — re-importing the
|
|
18
|
+
* same chat (e.g. a fresh export with newer messages) only adds the delta.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
import { getOrigin } from './config.js';
|
|
23
|
+
|
|
24
|
+
export function importTelegramRaw(db, raw) {
|
|
25
|
+
if (typeof raw === 'string') {
|
|
26
|
+
raw = JSON.parse(readFileSync(raw, 'utf-8'));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const insertMessage = db.prepare(`
|
|
30
|
+
INSERT INTO messages (source, conversation_id, msg_id, role, sender, text, ts, metadata, edited_at, uuid, origin)
|
|
31
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '${getOrigin()}')
|
|
32
|
+
ON CONFLICT(source, conversation_id, msg_id) DO UPDATE SET
|
|
33
|
+
text = CASE
|
|
34
|
+
WHEN excluded.edited_at IS NOT NULL
|
|
35
|
+
AND (messages.edited_at IS NULL OR excluded.edited_at > messages.edited_at)
|
|
36
|
+
THEN excluded.text ELSE messages.text END,
|
|
37
|
+
edited_at = CASE
|
|
38
|
+
WHEN excluded.edited_at IS NOT NULL
|
|
39
|
+
AND (messages.edited_at IS NULL OR excluded.edited_at > messages.edited_at)
|
|
40
|
+
THEN excluded.edited_at ELSE messages.edited_at END,
|
|
41
|
+
uuid = COALESCE(messages.uuid, excluded.uuid),
|
|
42
|
+
origin = COALESCE(messages.origin, excluded.origin)
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
const upsertConversation = db.prepare(`
|
|
46
|
+
INSERT INTO conversations (conversation_id, source, title, first_ts, last_ts, message_count, parent_conversation_id, project_path)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
48
|
+
ON CONFLICT(conversation_id) DO UPDATE SET
|
|
49
|
+
title = excluded.title,
|
|
50
|
+
first_ts = MIN(first_ts, excluded.first_ts),
|
|
51
|
+
last_ts = MAX(last_ts, excluded.last_ts),
|
|
52
|
+
parent_conversation_id = COALESCE(excluded.parent_conversation_id, parent_conversation_id),
|
|
53
|
+
project_path = COALESCE(excluded.project_path, project_path),
|
|
54
|
+
message_count = (
|
|
55
|
+
SELECT COUNT(*) FROM messages
|
|
56
|
+
WHERE messages.conversation_id = conversations.conversation_id
|
|
57
|
+
)
|
|
58
|
+
`);
|
|
59
|
+
|
|
60
|
+
const chats = Array.isArray(raw.chats?.list)
|
|
61
|
+
? raw.chats.list
|
|
62
|
+
: Array.isArray(raw.list)
|
|
63
|
+
? raw.list
|
|
64
|
+
: raw.messages
|
|
65
|
+
? [raw]
|
|
66
|
+
: [];
|
|
67
|
+
|
|
68
|
+
const myUserId = String(raw?.personal_information?.user_id || raw?.user_id || '');
|
|
69
|
+
let totalImported = 0;
|
|
70
|
+
const chatSummaries = [];
|
|
71
|
+
|
|
72
|
+
const tx = db.transaction((chatList) => {
|
|
73
|
+
for (const chat of chatList) {
|
|
74
|
+
if (!Array.isArray(chat.messages)) continue;
|
|
75
|
+
|
|
76
|
+
const conversationId = `tg-${chat.id ?? chat.name ?? 'unknown'}`;
|
|
77
|
+
const title =
|
|
78
|
+
chat.name ||
|
|
79
|
+
(chat.type === 'saved_messages' ? 'Saved Messages' : `Telegram chat ${chat.id}`);
|
|
80
|
+
|
|
81
|
+
let first_ts = Infinity;
|
|
82
|
+
let last_ts = 0;
|
|
83
|
+
let chatMsgs = 0;
|
|
84
|
+
|
|
85
|
+
for (const msg of chat.messages) {
|
|
86
|
+
if (msg.type !== 'message') continue;
|
|
87
|
+
|
|
88
|
+
let text = '';
|
|
89
|
+
if (typeof msg.text === 'string') {
|
|
90
|
+
text = msg.text;
|
|
91
|
+
} else if (Array.isArray(msg.text)) {
|
|
92
|
+
text = msg.text
|
|
93
|
+
.map((f) => (typeof f === 'string' ? f : f.text || ''))
|
|
94
|
+
.join('');
|
|
95
|
+
}
|
|
96
|
+
if (!text || !text.trim()) continue;
|
|
97
|
+
|
|
98
|
+
const ts = parseInt(msg.date_unixtime || '0', 10);
|
|
99
|
+
if (ts) {
|
|
100
|
+
first_ts = Math.min(first_ts, ts);
|
|
101
|
+
last_ts = Math.max(last_ts, ts);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const editedAt = msg.edited_unixtime
|
|
105
|
+
? parseInt(msg.edited_unixtime, 10) || null
|
|
106
|
+
: null;
|
|
107
|
+
|
|
108
|
+
const fromId = String(msg.from_id || '');
|
|
109
|
+
const isMe =
|
|
110
|
+
(myUserId && fromId === `user${myUserId}`) ||
|
|
111
|
+
(myUserId && fromId === myUserId);
|
|
112
|
+
const role = isMe ? 'user' : 'assistant';
|
|
113
|
+
|
|
114
|
+
insertMessage.run(
|
|
115
|
+
'telegram',
|
|
116
|
+
conversationId,
|
|
117
|
+
String(msg.id),
|
|
118
|
+
role,
|
|
119
|
+
msg.from || (isMe ? 'me' : 'bot'),
|
|
120
|
+
text,
|
|
121
|
+
ts,
|
|
122
|
+
JSON.stringify({
|
|
123
|
+
chat_name: chat.name,
|
|
124
|
+
chat_type: chat.type,
|
|
125
|
+
reply_to: msg.reply_to_message_id || null,
|
|
126
|
+
}),
|
|
127
|
+
editedAt,
|
|
128
|
+
null
|
|
129
|
+
);
|
|
130
|
+
chatMsgs += 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (chatMsgs > 0) {
|
|
134
|
+
upsertConversation.run(
|
|
135
|
+
conversationId,
|
|
136
|
+
'telegram',
|
|
137
|
+
title,
|
|
138
|
+
isFinite(first_ts) ? first_ts : null,
|
|
139
|
+
last_ts || null,
|
|
140
|
+
chatMsgs,
|
|
141
|
+
null,
|
|
142
|
+
null
|
|
143
|
+
);
|
|
144
|
+
totalImported += chatMsgs;
|
|
145
|
+
chatSummaries.push({
|
|
146
|
+
conversation_id: conversationId,
|
|
147
|
+
title,
|
|
148
|
+
msg_count: chatMsgs,
|
|
149
|
+
first_ts: isFinite(first_ts) ? first_ts : null,
|
|
150
|
+
last_ts: last_ts || null,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
tx(chats);
|
|
157
|
+
return { totalImported, chats: chatSummaries };
|
|
158
|
+
}
|