polygram 0.8.0-rc.64 β 0.8.0-rc.66
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/db.js +18 -2
- package/package.json +1 -1
- package/polygram.js +76 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "polygram",
|
|
4
|
-
"version": "0.8.0-rc.
|
|
4
|
+
"version": "0.8.0-rc.66",
|
|
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 plus history (transcript queries) and polygram-send (out-of-turn IPC sends with file-upload validation) skills.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"telegram",
|
package/lib/db.js
CHANGED
|
@@ -360,7 +360,8 @@ function wrap(db) {
|
|
|
360
360
|
json_extract(detail_json, '$.session_key') AS session_key,
|
|
361
361
|
json_extract(detail_json, '$.user') AS user,
|
|
362
362
|
json_extract(detail_json, '$.user_id') AS user_id,
|
|
363
|
-
json_extract(detail_json, '$.text_len') AS text_len
|
|
363
|
+
json_extract(detail_json, '$.text_len') AS text_len,
|
|
364
|
+
json_extract(detail_json, '$.text') AS text
|
|
364
365
|
FROM events
|
|
365
366
|
WHERE kind = 'compact-command'
|
|
366
367
|
AND ts > ?
|
|
@@ -380,7 +381,22 @@ function wrap(db) {
|
|
|
380
381
|
AND json_extract(detail_json, '$.session_key') = ?
|
|
381
382
|
LIMIT 1
|
|
382
383
|
`).get(c.id, c.session_key);
|
|
383
|
-
if (
|
|
384
|
+
if (boundary) continue;
|
|
385
|
+
// rc.66: also skip if a previous boot has already handled
|
|
386
|
+
// this orphan (silent replay via compact-replay event, OR
|
|
387
|
+
// surface-fallback via compact-failed-restart event). Both
|
|
388
|
+
// of those record `original_ts` in their detail_json
|
|
389
|
+
// matching the original compact-command's ts. Without this
|
|
390
|
+
// dedupe, every subsequent deploy re-surfaces / re-replays
|
|
391
|
+
// the same orphan (annoying noise).
|
|
392
|
+
const handled = db.prepare(`
|
|
393
|
+
SELECT id FROM events
|
|
394
|
+
WHERE kind IN ('compact-replay', 'compact-failed-restart')
|
|
395
|
+
AND json_extract(detail_json, '$.original_ts') = ?
|
|
396
|
+
LIMIT 1
|
|
397
|
+
`).get(c.ts);
|
|
398
|
+
if (handled) continue;
|
|
399
|
+
orphans.push(c);
|
|
384
400
|
}
|
|
385
401
|
return orphans;
|
|
386
402
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.8.0-rc.
|
|
3
|
+
"version": "0.8.0-rc.66",
|
|
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
|
@@ -2220,6 +2220,12 @@ async function handleMessage(sessionKey, chatId, msg, bot) {
|
|
|
2220
2220
|
logEvent('compact-command', {
|
|
2221
2221
|
chat_id: chatId, thread_id: threadIdStr, session_key: sessionKey,
|
|
2222
2222
|
text_len: text.length,
|
|
2223
|
+
// rc.65: store the full /compact text so boot-time orphan
|
|
2224
|
+
// recovery can silently re-push it after a deploy
|
|
2225
|
+
// interrupted compaction. Agent-supplied hints (e.g.
|
|
2226
|
+
// "/compact keep the Q3 commission decisions") need to be
|
|
2227
|
+
// preserved verbatim for the retry to summarize correctly.
|
|
2228
|
+
text,
|
|
2223
2229
|
user: cmdUser, user_id: cmdUserId,
|
|
2224
2230
|
});
|
|
2225
2231
|
const hasHint = text.length > '/compact'.length + 1;
|
|
@@ -4420,28 +4426,77 @@ async function main() {
|
|
|
4420
4426
|
console.error(`[replay] boot replay failed: ${err.message}`);
|
|
4421
4427
|
}
|
|
4422
4428
|
|
|
4423
|
-
// rc.61:
|
|
4424
|
-
// a compact-boundary (
|
|
4425
|
-
//
|
|
4426
|
-
//
|
|
4427
|
-
//
|
|
4428
|
-
//
|
|
4429
|
-
//
|
|
4430
|
-
// them context was still full. Now: detect orphaned compact-command
|
|
4431
|
-
// events on boot, post a "compaction was interrupted" message to
|
|
4432
|
-
// the chat so the user knows to re-run.
|
|
4429
|
+
// rc.61 + rc.65: handle compact-command events that were never
|
|
4430
|
+
// paired with a compact-boundary (deploy / crash interrupted them
|
|
4431
|
+
// before the SDK processed). rc.65 changes behaviour from
|
|
4432
|
+
// "post a 'please retry' message and ask the user" to
|
|
4433
|
+
// "silently retry by re-pushing the same /compact text to a
|
|
4434
|
+
// freshly-spawned (resumed) Query." Same pattern as boot-replay
|
|
4435
|
+
// for inbound messages β recovery should be invisible.
|
|
4433
4436
|
//
|
|
4434
|
-
//
|
|
4435
|
-
//
|
|
4436
|
-
//
|
|
4437
|
+
// Requirements for a silent retry:
|
|
4438
|
+
// 1. The compact-command event was logged with full `text`
|
|
4439
|
+
// (rc.65+ does this; pre-rc.65 events have only text_len β
|
|
4440
|
+
// we fall back to the old "please retry" message for those).
|
|
4441
|
+
// 2. The chat is still configured (config.chats[chat_id] exists).
|
|
4442
|
+
// 3. The session has a saved claude_session_id we can resume.
|
|
4443
|
+
//
|
|
4444
|
+
// Dedupe: if multiple orphans for the same session_key (e.g. user
|
|
4445
|
+
// ran /compact twice in quick succession before a deploy), retry
|
|
4446
|
+
// only the MOST RECENT β older ones are obsolete.
|
|
4447
|
+
//
|
|
4448
|
+
// Scan window matches replayWindowMs β anything older than the
|
|
4449
|
+
// bot's expected long-turn ceiling is stale.
|
|
4437
4450
|
try {
|
|
4438
|
-
const
|
|
4451
|
+
const orphansAll = db.findOrphanedCompactCommands({
|
|
4439
4452
|
olderThanMs: resolveReplayWindowMs(config) ?? 30 * 60 * 1000,
|
|
4440
4453
|
});
|
|
4441
|
-
|
|
4454
|
+
// Dedupe per-session_key, keep the most recent (highest ts).
|
|
4455
|
+
const orphansLatest = new Map();
|
|
4456
|
+
for (const o of orphansAll) {
|
|
4457
|
+
orphansLatest.set(o.session_key, o);
|
|
4458
|
+
}
|
|
4459
|
+
let replayed = 0;
|
|
4460
|
+
let surfacedFallback = 0;
|
|
4461
|
+
for (const o of orphansLatest.values()) {
|
|
4442
4462
|
const chatCfg = config.chats[o.chat_id];
|
|
4443
|
-
if (!chatCfg) continue;
|
|
4463
|
+
if (!chatCfg) continue;
|
|
4444
4464
|
const threadId = o.thread_id ? Number(o.thread_id) : null;
|
|
4465
|
+
const savedSessionId = getClaudeSessionId(db, o.session_key);
|
|
4466
|
+
|
|
4467
|
+
// Silent retry path: only when we have BOTH the original text
|
|
4468
|
+
// (rc.65+) AND a session_id to resume into.
|
|
4469
|
+
if (o.text && savedSessionId) {
|
|
4470
|
+
try {
|
|
4471
|
+
const entry = await pm.getOrSpawn(o.session_key, buildSpawnContext(o.session_key));
|
|
4472
|
+
if (!entry?.inputController?.push) {
|
|
4473
|
+
throw new Error('input controller not ready post-spawn');
|
|
4474
|
+
}
|
|
4475
|
+
entry.inputController.push({
|
|
4476
|
+
type: 'user',
|
|
4477
|
+
message: { role: 'user', content: o.text },
|
|
4478
|
+
parent_tool_use_id: null,
|
|
4479
|
+
});
|
|
4480
|
+
logEvent('compact-replay', {
|
|
4481
|
+
chat_id: o.chat_id,
|
|
4482
|
+
thread_id: o.thread_id,
|
|
4483
|
+
session_key: o.session_key,
|
|
4484
|
+
original_ts: o.ts,
|
|
4485
|
+
text_len: o.text.length,
|
|
4486
|
+
user: o.user,
|
|
4487
|
+
user_id: o.user_id,
|
|
4488
|
+
});
|
|
4489
|
+
replayed += 1;
|
|
4490
|
+
continue;
|
|
4491
|
+
} catch (err) {
|
|
4492
|
+
console.error(`[compact-replay] ${o.session_key}: ${err.message} β falling back to surface`);
|
|
4493
|
+
// fall through to surface fallback below
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
// Fallback: surface the legacy "please retry" message. Only
|
|
4498
|
+
// happens for pre-rc.65 events (no `text` field) or when
|
|
4499
|
+
// the silent-retry spawn failed.
|
|
4445
4500
|
try {
|
|
4446
4501
|
await tg(bot, 'sendMessage', {
|
|
4447
4502
|
chat_id: o.chat_id,
|
|
@@ -4455,16 +4510,18 @@ async function main() {
|
|
|
4455
4510
|
original_ts: o.ts,
|
|
4456
4511
|
user: o.user,
|
|
4457
4512
|
user_id: o.user_id,
|
|
4513
|
+
reason: o.text ? 'spawn-failed' : 'pre-rc65-event-no-text',
|
|
4458
4514
|
});
|
|
4515
|
+
surfacedFallback += 1;
|
|
4459
4516
|
} catch (err) {
|
|
4460
4517
|
console.error(`[compact-orphan-surface] ${o.session_key}: ${err.message}`);
|
|
4461
4518
|
}
|
|
4462
4519
|
}
|
|
4463
|
-
if (
|
|
4464
|
-
console.log(`[compact-orphan] surfaced
|
|
4520
|
+
if (replayed + surfacedFallback > 0) {
|
|
4521
|
+
console.log(`[compact-orphan] silent-replayed=${replayed}, surfaced-fallback=${surfacedFallback}`);
|
|
4465
4522
|
}
|
|
4466
4523
|
} catch (err) {
|
|
4467
|
-
console.error(`[compact-orphan-
|
|
4524
|
+
console.error(`[compact-orphan-handler] failed: ${err.message}`);
|
|
4468
4525
|
}
|
|
4469
4526
|
|
|
4470
4527
|
console.log(`[${BOT_NAME}] Starting...`);
|