polygram 0.12.0-rc.24 → 0.12.0-rc.26
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/handlers/dispatcher.js +40 -0
- package/lib/process/cli-process.js +14 -7
- package/package.json +1 -1
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
const CONCURRENT_WARN_THRESHOLD_DEFAULT = 20;
|
|
26
26
|
|
|
27
|
+
// Startup auto-retry (option a, 2026-06-04): a short breath before silently
|
|
28
|
+
// re-dispatching a message whose first attempt died in the dev-channels startup
|
|
29
|
+
// gate (TMUX_SESSION_GONE). Long enough that a host under momentary load isn't
|
|
30
|
+
// hammered with a back-to-back respawn, short enough that a transient flake
|
|
31
|
+
// still recovers fast enough to feel instant to the user.
|
|
32
|
+
const STARTUP_RETRY_DELAY_MS = 1500;
|
|
33
|
+
|
|
27
34
|
function createDispatcher({
|
|
28
35
|
config,
|
|
29
36
|
db,
|
|
@@ -48,6 +55,9 @@ function createDispatcher({
|
|
|
48
55
|
// the historic 4096 for back-compat in synthetic test runs that pass
|
|
49
56
|
// pre-formatted text.
|
|
50
57
|
chunkBudget = 4096,
|
|
58
|
+
// Delay before a silent startup auto-retry re-dispatches (TMUX_SESSION_GONE).
|
|
59
|
+
// Injected so tests can drive it to 0; production uses STARTUP_RETRY_DELAY_MS.
|
|
60
|
+
startupRetryDelayMs = STARTUP_RETRY_DELAY_MS,
|
|
51
61
|
// State accessors (need late binding because polygram.js mutates):
|
|
52
62
|
getIsShuttingDown, // () → boolean
|
|
53
63
|
logger = console,
|
|
@@ -217,6 +227,35 @@ function createDispatcher({
|
|
|
217
227
|
// - shutting down ("Process killed" isn't a real error),
|
|
218
228
|
// - user just /stop'd (already saw their abort ack).
|
|
219
229
|
if (!wasAborted && !isReplay && !isShuttingDown) {
|
|
230
|
+
// Startup auto-retry (option a, 2026-06-04). TMUX_SESSION_GONE = claude
|
|
231
|
+
// exited INSIDE the startup gate, before the dev-channels channel went
|
|
232
|
+
// live — so the user's message was NEVER delivered to claude. That makes
|
|
233
|
+
// a re-send idempotent BY CONSTRUCTION (unlike a mid-turn drop, where
|
|
234
|
+
// claude might still be slowly processing). The session_id was just
|
|
235
|
+
// poison-cleared above, so re-dispatching the SAME message spawns a FRESH
|
|
236
|
+
// session and delivers it. Silent: a transient startup flake (recurs
|
|
237
|
+
// ~once/9h on the channels backend) never reaches the user — instead of
|
|
238
|
+
// the "🔄 reset it, resend" papercut, polygram just retries. One-shot
|
|
239
|
+
// (_startupRetried) so a host that genuinely can't start claude surfaces
|
|
240
|
+
// the friendly reset reply (below) after EXACTLY one retry, never a loop.
|
|
241
|
+
// Scoped to TMUX_SESSION_GONE only: CHANNELS_DIALOG_TIMEOUT is a real
|
|
242
|
+
// blocking dialog (usage-limit / permission) a retry would just re-hit,
|
|
243
|
+
// so it keeps its "please resend" copy.
|
|
244
|
+
if (err.code === 'TMUX_SESSION_GONE' && !msg._startupRetried) {
|
|
245
|
+
logEvent('startup-auto-retry', {
|
|
246
|
+
chat_id: chatId, session_key: sessionKey, msg_id: msg?.message_id,
|
|
247
|
+
});
|
|
248
|
+
// Re-dispatch a COPY carrying the one-shot marker — never mutate the
|
|
249
|
+
// caller's msg (the boot-replay path shares/re-reads it). unref the
|
|
250
|
+
// best-effort timer so a pending retry can't pin the daemon alive
|
|
251
|
+
// (the Telegram long-poll already keeps the loop running).
|
|
252
|
+
const retryMsg = { ...msg, _startupRetried: true };
|
|
253
|
+
setTimeout(
|
|
254
|
+
() => dispatchHandleMessage(sessionKey, chatId, retryMsg, bot),
|
|
255
|
+
startupRetryDelayMs,
|
|
256
|
+
).unref?.();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
220
259
|
// rc.54: auto-resume on 300s no-activity timeout. The
|
|
221
260
|
// resume turn itself runs through sendToProcess directly
|
|
222
261
|
// (not handleMessage), so its errors don't re-enter this
|
|
@@ -309,4 +348,5 @@ function createDispatcher({
|
|
|
309
348
|
module.exports = {
|
|
310
349
|
createDispatcher,
|
|
311
350
|
CONCURRENT_WARN_THRESHOLD_DEFAULT,
|
|
351
|
+
STARTUP_RETRY_DELAY_MS,
|
|
312
352
|
};
|
|
@@ -115,13 +115,20 @@ const STREAMING_HINT_RE = /esc to interrupt/i;
|
|
|
115
115
|
|
|
116
116
|
// 0.12.0 background-work lifecycle: claude's TUI mode line shows a live
|
|
117
117
|
// background-shell COUNT while a `run_in_background:true` Bash outlives its turn,
|
|
118
|
-
// e.g. `⏵⏵
|
|
119
|
-
// claude 2.1.158 (P0 spike — docs/0.12.0-background-work-lifecycle-
|
|
120
|
-
// count is always-present in the viewport mode line while shells run
|
|
121
|
-
// IN-PLACE within ~3s when they exit (no stale scrollback).
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
118
|
+
// e.g. `⏵⏵ bypass permissions on · 1 shell · ← for agents · ↓ to manage`.
|
|
119
|
+
// Confirmed on claude 2.1.158 (P0 spike — docs/0.12.0-background-work-lifecycle-
|
|
120
|
+
// plan.md): the count is always-present in the viewport mode line while shells run
|
|
121
|
+
// and clears IN-PLACE within ~3s when they exit (no stale scrollback).
|
|
122
|
+
//
|
|
123
|
+
// MODE-INDEPENDENT (prod regression fix, 2026-06-04): the original regex anchored
|
|
124
|
+
// on "auto mode on", but EVERY shumorobot session runs "⏵⏵ bypass permissions on"
|
|
125
|
+
// — the spike happened to be captured in auto mode. So the detector never matched
|
|
126
|
+
// in prod and bg-work-status fired zero times. Anchor instead on the `⏵⏵` mode-
|
|
127
|
+
// line glyph (present in auto / bypass / accept-edits modes alike); only the mode
|
|
128
|
+
// label between it and `· N shell` varies. Still matched only against the captured
|
|
129
|
+
// TAIL so a scrolled-off history line never trips it. R1: re-validate on each
|
|
130
|
+
// pinned-claude bump (glyph + `N shell` wording).
|
|
131
|
+
const BACKGROUND_SHELL_RE = /⏵⏵[^\n]*·\s*(\d+)\s+shells?\b/i;
|
|
125
132
|
// How long a detached background shell may run AFTER its turn resolved (claude
|
|
126
133
|
// idle) before the stall-watchdog fires one read-only self-check. Override via
|
|
127
134
|
// the constructor (tests use a small value).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.12.0-rc.
|
|
3
|
+
"version": "0.12.0-rc.26",
|
|
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": {
|