polygram 0.4.9 → 0.4.10
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/.claude-plugin/plugin.json +1 -1
- package/lib/process-manager.js +21 -9
- package/package.json +1 -1
- package/polygram.js +19 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "polygram",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.10",
|
|
5
5
|
"description": "Telegram integration for Claude Code that preserves the OpenClaw per-chat session model. Migration target for OpenClaw users. Multi-bot, multi-chat, per-topic isolation; SQLite transcripts; inline-keyboard approvals. Bundles /polygram:status|logs|pair-code|approvals admin commands and a history skill.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"telegram",
|
package/lib/process-manager.js
CHANGED
|
@@ -54,11 +54,12 @@ class ProcessManager {
|
|
|
54
54
|
db = null,
|
|
55
55
|
logger = console,
|
|
56
56
|
killTimeoutMs = DEFAULT_KILL_TIMEOUT_MS,
|
|
57
|
-
onInit = null,
|
|
58
|
-
onResult = null,
|
|
59
|
-
onClose = null,
|
|
60
|
-
onStreamChunk = null
|
|
61
|
-
onToolUse = null,
|
|
57
|
+
onInit = null, // (sessionKey, event, entry) → void
|
|
58
|
+
onResult = null, // (sessionKey, event, entry, pending) → void
|
|
59
|
+
onClose = null, // (sessionKey, code, entry) → void
|
|
60
|
+
onStreamChunk = null, // (sessionKey, partialText, entry) → void — routes to pendingQueue[0]
|
|
61
|
+
onToolUse = null, // (sessionKey, toolName, entry) → void — routes to pendingQueue[0]
|
|
62
|
+
onRespawn = null, // (sessionKey, reason, entry) → void — fires after graceful drain-and-kill
|
|
62
63
|
} = {}) {
|
|
63
64
|
if (!spawnFn) throw new Error('spawnFn required');
|
|
64
65
|
this.cap = cap;
|
|
@@ -71,6 +72,7 @@ class ProcessManager {
|
|
|
71
72
|
this.onClose = onClose;
|
|
72
73
|
this.onStreamChunk = onStreamChunk;
|
|
73
74
|
this.onToolUse = onToolUse;
|
|
75
|
+
this.onRespawn = onRespawn;
|
|
74
76
|
this.procs = new Map();
|
|
75
77
|
}
|
|
76
78
|
|
|
@@ -137,13 +139,22 @@ class ProcessManager {
|
|
|
137
139
|
queued: entry.pendingQueue.length,
|
|
138
140
|
});
|
|
139
141
|
if (entry.pendingQueue.length === 0) {
|
|
140
|
-
//
|
|
141
|
-
this.
|
|
142
|
+
// Queue empty — kill immediately, fire onRespawn after close.
|
|
143
|
+
this._killAndNotifyRespawn(sessionKey, reason).catch(() => {});
|
|
142
144
|
return { killed: true, queued: 0 };
|
|
143
145
|
}
|
|
144
146
|
return { killed: false, queued: entry.pendingQueue.length };
|
|
145
147
|
}
|
|
146
148
|
|
|
149
|
+
async _killAndNotifyRespawn(sessionKey, reason) {
|
|
150
|
+
const entry = this.procs.get(sessionKey);
|
|
151
|
+
await this.kill(sessionKey);
|
|
152
|
+
if (this.onRespawn && entry) {
|
|
153
|
+
try { this.onRespawn(sessionKey, reason, entry); }
|
|
154
|
+
catch (err) { this.logger.error(`[pm] onRespawn: ${err.message}`); }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
147
158
|
async kill(sessionKey) {
|
|
148
159
|
const entry = this.procs.get(sessionKey);
|
|
149
160
|
if (!entry) return;
|
|
@@ -257,7 +268,8 @@ class ProcessManager {
|
|
|
257
268
|
} else {
|
|
258
269
|
entry.inFlight = false;
|
|
259
270
|
// Graceful drain-and-respawn: if caller asked for a respawn
|
|
260
|
-
// (e.g. /model change) and we just emptied the queue, kill now
|
|
271
|
+
// (e.g. /model change) and we just emptied the queue, kill now
|
|
272
|
+
// and fire onRespawn so the caller can post confirmation.
|
|
261
273
|
if (entry.needsRespawn) {
|
|
262
274
|
const reason = entry.needsRespawn;
|
|
263
275
|
entry.needsRespawn = null;
|
|
@@ -266,7 +278,7 @@ class ProcessManager {
|
|
|
266
278
|
chat_id: entry.chatId,
|
|
267
279
|
reason,
|
|
268
280
|
});
|
|
269
|
-
this.
|
|
281
|
+
this._killAndNotifyRespawn(sessionKey, reason).catch(() => {});
|
|
270
282
|
}
|
|
271
283
|
}
|
|
272
284
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
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
|
@@ -1904,6 +1904,25 @@ async function main() {
|
|
|
1904
1904
|
const r = head?.context?.reactor;
|
|
1905
1905
|
if (r) r.setState(classifyToolName(toolName));
|
|
1906
1906
|
},
|
|
1907
|
+
// Fires after a graceful /model or /effort drain has actually
|
|
1908
|
+
// swapped to the new settings. Post a confirmation back to the
|
|
1909
|
+
// chat so the user knows the switch happened.
|
|
1910
|
+
onRespawn: (sessionKey, reason, entry) => {
|
|
1911
|
+
const chatId = entry.chatId;
|
|
1912
|
+
if (!chatId) return;
|
|
1913
|
+
const chatConfig = config.chats[chatId];
|
|
1914
|
+
if (!chatConfig) return;
|
|
1915
|
+
const text = reason === 'model-change'
|
|
1916
|
+
? `✓ Using ${chatConfig.model} now.`
|
|
1917
|
+
: reason === 'effort-change'
|
|
1918
|
+
? `✓ Effort is ${chatConfig.effort} now.`
|
|
1919
|
+
: `✓ Ready.`;
|
|
1920
|
+
const threadId = entry.threadId || undefined;
|
|
1921
|
+
tg(bot, 'sendMessage', {
|
|
1922
|
+
chat_id: chatId, text,
|
|
1923
|
+
...(threadId && { message_thread_id: threadId }),
|
|
1924
|
+
}, { source: 'respawn-confirm', botName: BOT_NAME }).catch(() => {});
|
|
1925
|
+
},
|
|
1907
1926
|
});
|
|
1908
1927
|
|
|
1909
1928
|
console.log(`polygram (LRU cap=${cap}, SQLite source of truth)`);
|