polygram 0.6.0 → 0.6.2

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/lib/db.js CHANGED
@@ -8,7 +8,7 @@ const fs = require('fs');
8
8
  const path = require('path');
9
9
  const Database = require('better-sqlite3');
10
10
 
11
- const SCHEMA_VERSION = 7;
11
+ const SCHEMA_VERSION = 8;
12
12
 
13
13
  function open(dbPath) {
14
14
  const db = new Database(dbPath);
@@ -56,14 +56,16 @@ function runMigrations(db, migrationsDir) {
56
56
  }
57
57
 
58
58
  function wrap(db) {
59
+ // 0.6.1: attachments_json column dropped (migration 008). All attachment
60
+ // data lives in the per-attachment table now (see attachments stmts below).
59
61
  const insertMessageStmt = db.prepare(`
60
62
  INSERT INTO messages (
61
63
  chat_id, thread_id, msg_id, user, user_id, text, reply_to_id,
62
- direction, source, bot_name, attachments_json, session_id,
64
+ direction, source, bot_name, session_id,
63
65
  model, effort, turn_id, status, error, cost_usd, ts
64
66
  ) VALUES (
65
67
  @chat_id, @thread_id, @msg_id, @user, @user_id, @text, @reply_to_id,
66
- @direction, @source, @bot_name, @attachments_json, @session_id,
68
+ @direction, @source, @bot_name, @session_id,
67
69
  @model, @effort, @turn_id, @status, @error, @cost_usd, @ts
68
70
  )
69
71
  ON CONFLICT(chat_id, msg_id) DO UPDATE SET
@@ -121,8 +123,7 @@ function wrap(db) {
121
123
 
122
124
  const setMessageTextStmt = db.prepare(`
123
125
  UPDATE messages
124
- SET text = @text,
125
- attachments_json = COALESCE(@attachments_json, attachments_json)
126
+ SET text = @text
126
127
  WHERE chat_id = @chat_id AND msg_id = @msg_id
127
128
  `);
128
129
 
@@ -174,7 +175,6 @@ function wrap(db) {
174
175
  direction: row.direction || 'in',
175
176
  source: row.source || 'polygram',
176
177
  bot_name: row.bot_name || null,
177
- attachments_json: row.attachments_json || null,
178
178
  session_id: row.session_id || null,
179
179
  model: row.model || null,
180
180
  effort: row.effort || null,
@@ -240,12 +240,11 @@ function wrap(db) {
240
240
  return getMessageStmt.get(String(chatId), msgId);
241
241
  },
242
242
 
243
- setMessageText({ chat_id, msg_id, text, attachments_json = null }) {
243
+ setMessageText({ chat_id, msg_id, text }) {
244
244
  return setMessageTextStmt.run({
245
245
  chat_id: String(chat_id),
246
246
  msg_id,
247
247
  text: text ?? '',
248
- attachments_json,
249
248
  });
250
249
  },
251
250
 
@@ -324,7 +323,7 @@ function wrap(db) {
324
323
  const placeholders = chatIds.map(() => '?').join(',');
325
324
  return db.prepare(`
326
325
  SELECT id, chat_id, thread_id, msg_id, user, user_id, text, reply_to_id,
327
- attachments_json, ts, handler_status
326
+ ts, handler_status
328
327
  FROM messages
329
328
  WHERE direction = 'in'
330
329
  AND handler_status IN ('dispatched', 'processing', 'replay-pending')
@@ -0,0 +1,12 @@
1
+ -- Drop the legacy messages.attachments_json column. 0.6.0's migration 007
2
+ -- created the per-attachment table and backfilled from this column; the
3
+ -- column was kept for one minor as a safety net. polygram 0.6.1 reads
4
+ -- exclusively from the attachments table now, so the column is dead code
5
+ -- on the schema side and can go.
6
+ --
7
+ -- SQLite supports ALTER TABLE DROP COLUMN since 3.35 (well below
8
+ -- better-sqlite3's bundled SQLite). The op rewrites the table in place,
9
+ -- which is fine — `messages` is small enough that a one-time rewrite at
10
+ -- migration time is cheaper than carrying the column around forever.
11
+
12
+ ALTER TABLE messages DROP COLUMN attachments_json;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Telegram daemon for Claude Code that preserves the OpenClaw per-chat session model. Migration path for OpenClaw users moving to Claude Code.",
5
5
  "main": "lib/ipc-client.js",
6
6
  "bin": {
package/polygram.js CHANGED
@@ -220,10 +220,6 @@ function recordInbound(msg) {
220
220
  direction: 'in',
221
221
  source: 'polygram',
222
222
  bot_name: BOT_NAME,
223
- // attachments_json kept temporarily as a fallback during the 0.6.0
224
- // migration window; per-attachment rows below are the source of
225
- // truth. Will be dropped in a follow-up minor.
226
- attachments_json: attachments.length ? JSON.stringify(attachments) : null,
227
223
  model: chatConfig?.model || null,
228
224
  effort: chatConfig?.effort || null,
229
225
  ts,
@@ -380,9 +376,7 @@ async function transcribeVoiceAttachments(downloaded, { chatId, msgId, label, bo
380
376
  // parses it back when building the prompt.
381
377
  // - Message-level: setMessageText updates messages.text with the
382
378
  // combined transcript so FTS finds "what Maria said" via the
383
- // normal chat search path. attachments_json is left as-is (will
384
- // be dropped in a future minor; per-attachment row is the source
385
- // of truth).
379
+ // normal chat search path.
386
380
  const successful = targets.filter((a) => a.transcription?.text);
387
381
  if (!successful.length) return;
388
382
  for (const a of successful) {
@@ -393,8 +387,7 @@ async function transcribeVoiceAttachments(downloaded, { chatId, msgId, label, bo
393
387
  }
394
388
  const combinedText = successful.map((a) => a.transcription.text).join(' ').trim();
395
389
  dbWrite(() => db.setMessageText({
396
- chat_id: chatId, msg_id: msgId,
397
- text: combinedText, attachments_json: null,
390
+ chat_id: chatId, msg_id: msgId, text: combinedText,
398
391
  }), 'persist voice transcription');
399
392
  }
400
393
 
@@ -2434,18 +2427,12 @@ async function main() {
2434
2427
  // Attach already-recorded attachments via the media-group shortcut
2435
2428
  // field so extractAttachments picks them up without re-parsing
2436
2429
  // grammy fields that don't exist on this reconstructed object.
2437
- // 0.6.0: read from the per-attachment table; fall back to the
2438
- // legacy attachments_json blob for rows inserted before migration
2439
- // 007 ran (covers the small window during the upgrade).
2440
2430
  const attRows = db.getAttachmentsByMessage(row.id);
2441
2431
  if (attRows.length) {
2442
2432
  reconstructed._mergedAttachments = attRows.map((a) => ({
2443
2433
  kind: a.kind, name: a.name, mime_type: a.mime_type,
2444
2434
  size: a.size_bytes, file_id: a.file_id, file_unique_id: a.file_unique_id,
2445
2435
  }));
2446
- } else if (row.attachments_json) {
2447
- try { reconstructed._mergedAttachments = JSON.parse(row.attachments_json); }
2448
- catch {}
2449
2436
  }
2450
2437
  const chatConfig = config.chats[row.chat_id];
2451
2438
  if (!chatConfig) { skipped += 1; continue; }
@@ -148,18 +148,39 @@ function copy(src, dst, bot, chatToBot) {
148
148
  const rows = src.raw.prepare(
149
149
  `SELECT * FROM messages WHERE chat_id IN (${ph(chatIds.length)}) OR bot_name = ?`,
150
150
  ).all(...chatIds, bot);
151
+ // 0.6.1: messages.attachments_json column was dropped (migration 008).
152
+ // Per-attachment rows live in the `attachments` table now and are
153
+ // copied separately below.
151
154
  const ins = dst.raw.prepare(`
152
155
  INSERT OR IGNORE INTO messages
153
156
  (id, chat_id, thread_id, msg_id, user, user_id, text, reply_to_id,
154
- direction, source, bot_name, attachments_json, session_id,
157
+ direction, source, bot_name, session_id,
155
158
  model, effort, turn_id, status, error, cost_usd, ts, edited_ts)
156
159
  VALUES
157
160
  (@id, @chat_id, @thread_id, @msg_id, @user, @user_id, @text, @reply_to_id,
158
- @direction, @source, @bot_name, @attachments_json, @session_id,
161
+ @direction, @source, @bot_name, @session_id,
159
162
  @model, @effort, @turn_id, @status, @error, @cost_usd, @ts, @edited_ts)
160
163
  `);
161
164
  for (const r of rows) { if (ins.run(r).changes) stats.messages++; }
162
165
 
166
+ // Copy per-attachment rows for the messages we just copied. FK target
167
+ // exists since messages were inserted in the same transaction.
168
+ const arows = src.raw.prepare(
169
+ `SELECT * FROM attachments WHERE chat_id IN (${ph(chatIds.length)})`,
170
+ ).all(...chatIds);
171
+ const aIns = dst.raw.prepare(`
172
+ INSERT OR IGNORE INTO attachments
173
+ (id, message_id, chat_id, msg_id, thread_id, bot_name,
174
+ file_id, file_unique_id, kind, name, mime_type, size_bytes,
175
+ local_path, download_status, download_error, transcription, ts)
176
+ VALUES
177
+ (@id, @message_id, @chat_id, @msg_id, @thread_id, @bot_name,
178
+ @file_id, @file_unique_id, @kind, @name, @mime_type, @size_bytes,
179
+ @local_path, @download_status, @download_error, @transcription, @ts)
180
+ `);
181
+ stats.attachments = 0;
182
+ for (const r of arows) { if (aIns.run(r).changes) stats.attachments++; }
183
+
163
184
  const srows = src.raw.prepare(`SELECT * FROM sessions WHERE chat_id IN (${ph(chatIds.length)})`).all(...chatIds);
164
185
  const sins = dst.raw.prepare(`
165
186
  INSERT OR REPLACE INTO sessions