polygram 0.5.8 → 0.5.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.
@@ -168,6 +168,12 @@ class ProcessManager {
168
168
  * If the queue is empty, kill now; otherwise mark the entry so it kills
169
169
  * itself when the last pending resolves. Next send() respawns fresh
170
170
  * with whatever config spawnFn reads at that moment.
171
+ *
172
+ * onRespawn fires with `wasDrained=true` ONLY when we waited for an
173
+ * in-flight turn to finish before swapping. The immediate-kill case
174
+ * (queue empty at request time) calls onRespawn with `wasDrained=false`
175
+ * so callers can decide whether to post a user-visible confirmation
176
+ * (which is redundant noise when the user wasn't waiting on a turn).
171
177
  */
172
178
  requestRespawn(sessionKey, reason = 'config-change') {
173
179
  const entry = this.procs.get(sessionKey);
@@ -181,17 +187,17 @@ class ProcessManager {
181
187
  });
182
188
  if (entry.pendingQueue.length === 0) {
183
189
  // Queue empty — kill immediately, fire onRespawn after close.
184
- this._killAndNotifyRespawn(sessionKey, reason).catch(() => {});
190
+ this._killAndNotifyRespawn(sessionKey, reason, false).catch(() => {});
185
191
  return { killed: true, queued: 0 };
186
192
  }
187
193
  return { killed: false, queued: entry.pendingQueue.length };
188
194
  }
189
195
 
190
- async _killAndNotifyRespawn(sessionKey, reason) {
196
+ async _killAndNotifyRespawn(sessionKey, reason, wasDrained) {
191
197
  const entry = this.procs.get(sessionKey);
192
198
  await this.kill(sessionKey);
193
199
  if (this.onRespawn && entry) {
194
- try { this.onRespawn(sessionKey, reason, entry); }
200
+ try { this.onRespawn(sessionKey, reason, entry, wasDrained); }
195
201
  catch (err) { this.logger.error(`[pm] onRespawn: ${err.message}`); }
196
202
  }
197
203
  }
@@ -321,7 +327,10 @@ class ProcessManager {
321
327
  chat_id: entry.chatId,
322
328
  reason,
323
329
  });
324
- this._killAndNotifyRespawn(sessionKey, reason).catch(() => {});
330
+ // wasDrained=true: this path runs after the queue emptied
331
+ // naturally (an in-flight turn finished), so the user was
332
+ // waiting and the confirmation message is meaningful.
333
+ this._killAndNotifyRespawn(sessionKey, reason, true).catch(() => {});
325
334
  }
326
335
  }
327
336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.5.8",
3
+ "version": "0.5.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": {
package/polygram.js CHANGED
@@ -2174,8 +2174,13 @@ async function main() {
2174
2174
  },
2175
2175
  // Fires after a graceful /model or /effort drain has actually
2176
2176
  // swapped to the new settings. Post a confirmation back to the
2177
- // chat so the user knows the switch happened.
2178
- onRespawn: (sessionKey, reason, entry) => {
2177
+ // chat ONLY when wasDrained=true — the user actively waited for an
2178
+ // in-flight turn to finish before the switch took effect, so the
2179
+ // explicit "switched" message is meaningful. When the kill was
2180
+ // immediate (queue empty), the inline-card update + button toast
2181
+ // already convey "done", and a separate message is just noise.
2182
+ onRespawn: (sessionKey, reason, entry, wasDrained) => {
2183
+ if (!wasDrained) return;
2179
2184
  const chatId = entry.chatId;
2180
2185
  if (!chatId) return;
2181
2186
  const chatConfig = config.chats[chatId];