polygram 0.12.8 → 0.12.9

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.
@@ -190,13 +190,22 @@ function createStore(rawDb, now = () => Date.now()) {
190
190
  return { ok: false, reason: 'wrong-chat' };
191
191
  }
192
192
 
193
+ // Every pairing MUST be chat-scoped. A chat_id=NULL pairing bypasses
194
+ // requireMention in EVERY group the bot is in — the all-chats footgun that
195
+ // let a colleague (Lin) trigger shumabit in the UMI working group without a
196
+ // mention (2026-06-16). Scope to the code's chat if it was issued scoped,
197
+ // else to the chat where it's redeemed. If neither exists, refuse (and DON'T
198
+ // consume the code) rather than create a global pairing.
199
+ const pairChatId = row.chat_id || (chat_id != null ? String(chat_id) : null);
200
+ if (!pairChatId) return { ok: false, reason: 'no-chat-scope' };
201
+
193
202
  const tx = rawDb.transaction(() => {
194
203
  const upd = markCodeUsedStmt.run({ code: norm, user_id: claimer_user_id, ts: now() });
195
204
  if (upd.changes === 0) throw new Error('race: code claimed by another user');
196
205
  insertPairingStmt.run({
197
206
  bot_name: row.bot_name,
198
207
  user_id: claimer_user_id,
199
- chat_id: row.chat_id || null,
208
+ chat_id: pairChatId,
200
209
  granted_ts: now(),
201
210
  granted_by_user_id: row.issued_by_user_id,
202
211
  note: row.note,
@@ -211,7 +220,7 @@ function createStore(rawDb, now = () => Date.now()) {
211
220
  return {
212
221
  ok: true,
213
222
  bot_name: row.bot_name,
214
- chat_id: row.chat_id,
223
+ chat_id: pairChatId,
215
224
  scope: row.scope,
216
225
  note: row.note,
217
226
  };
@@ -286,7 +286,7 @@ function createSlashCommands({
286
286
  chat_id: out.chat_id, note: out.note,
287
287
  });
288
288
  const ttlLabel = args.ttl || '10m';
289
- const chatLabel = out.chat_id ? `chat ${out.chat_id}` : 'any chat';
289
+ const chatLabel = out.chat_id ? `chat ${out.chat_id}` : 'the chat where it is redeemed';
290
290
  await sendReply(
291
291
  `Code: ${out.code}\nexpires: ${ttlLabel}\nscope: ${out.scope} (${chatLabel})${out.note ? `\nnote: ${out.note}` : ''}\n\nShare with user:\n/pair ${out.code}`,
292
292
  );
@@ -341,7 +341,7 @@ function createSlashCommands({
341
341
  ok: res.ok, reason: res.reason,
342
342
  });
343
343
  if (res.ok) {
344
- const chatLabel = res.chat_id ? `chat ${res.chat_id}` : `every chat ${botName} is in`;
344
+ const chatLabel = res.chat_id ? `chat ${res.chat_id}` : 'this chat';
345
345
  await sendReply(`Paired. You can use me in ${chatLabel}.${res.note ? `\n(${res.note})` : ''}`);
346
346
  return true;
347
347
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.12.8",
3
+ "version": "0.12.9",
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": {