polygram 0.10.0-rc.3 → 0.10.0-rc.5
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "polygram",
|
|
4
|
-
"version": "0.10.0-rc.
|
|
4
|
+
"version": "0.10.0-rc.5",
|
|
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",
|
|
@@ -62,23 +62,40 @@ const STREAMING_HINT_RE = /esc to interrupt/;
|
|
|
62
62
|
//
|
|
63
63
|
// ⏺ Bash(rm foo.txt)
|
|
64
64
|
// ⎿ Do you want to do this?
|
|
65
|
-
//
|
|
65
|
+
// ❯ 1. Yes
|
|
66
66
|
// 2. Yes, allow always for similar commands
|
|
67
67
|
// 3. No, and tell Claude what to do differently
|
|
68
68
|
//
|
|
69
|
+
// The TUI renders a `❯` selection cursor inline before the
|
|
70
|
+
// highlighted option (always option 1 at first paint). Earlier
|
|
71
|
+
// rc.1-rc.4 regex assumed no inline cursor and silently failed to
|
|
72
|
+
// match every approval-gated tool call in production, hanging the
|
|
73
|
+
// session in the TUI until orphan-sweep killed it (see
|
|
74
|
+
// tests/tmux-process-approval.test.js inline-cursor regression).
|
|
75
|
+
//
|
|
69
76
|
// SECURITY (audit H1 fix): require BOTH the question text AND a
|
|
70
77
|
// following numbered menu line ("1. ...") so a malicious assistant
|
|
71
78
|
// message text like "Do you want to proceed?" can't trigger a fake
|
|
72
79
|
// approval card by itself. The menu is part of the TUI's pause
|
|
73
80
|
// state; the assistant can't render it without actually being paused.
|
|
74
|
-
|
|
81
|
+
// The optional `❯` cursor in [^\S\n]*(?:❯[^\S\n]+)?1\. is still
|
|
82
|
+
// bounded to the line containing `1.`, so the security property
|
|
83
|
+
// holds — only a real menu line satisfies it.
|
|
84
|
+
const APPROVAL_PROMPT_RE = /Do you want to (?:proceed|do this|continue)\??[\s\S]{0,400}?(?:^|\n)[^\S\n]*(?:❯[^\S\n]+)?1\.\s+/im;
|
|
75
85
|
// Pull the tool name + raw arg snippet from the line preceding the
|
|
76
86
|
// approval prompt. Capture-pane preserves the ⏺ marker.
|
|
77
87
|
const TOOL_INVOCATION_RE = /⏺\s+([A-Za-z_]\w*)\s*\((.*?)\)\s*$/m;
|
|
78
88
|
|
|
79
89
|
// ─── Defaults — overridable per construction for tests ───────────────
|
|
80
90
|
|
|
81
|
-
|
|
91
|
+
// Cold-spawn budget for claude TUI to reach "? for shortcuts" / "accept
|
|
92
|
+
// edits on" state. 30s was enough in dev (interactive shell, warm
|
|
93
|
+
// keychain) but consistently timed out under launchd in production:
|
|
94
|
+
// MCP server starts each have a 30s connection timeout, and the
|
|
95
|
+
// keychain/Aqua context warm-up is slower outside an attached terminal.
|
|
96
|
+
// 120s is generous; the only cost is waiting longer when something is
|
|
97
|
+
// genuinely stuck (we kill + retry in that case anyway).
|
|
98
|
+
const DEFAULT_READY_TIMEOUT_MS = 120_000;
|
|
82
99
|
const DEFAULT_TURN_TIMEOUT_MS = 5 * 60_000;
|
|
83
100
|
const DEFAULT_POLL_MS = 250;
|
|
84
101
|
const DEFAULT_QUIESCE_MS = 500; // require READY for this long before declaring done
|
|
@@ -624,22 +641,32 @@ class TmuxProcess extends Process {
|
|
|
624
641
|
|
|
625
642
|
async _waitForReady() {
|
|
626
643
|
const deadline = this._now() + this.readyTimeoutMs;
|
|
644
|
+
let lastBuf = '';
|
|
627
645
|
if (this.pollScheduler) this.pollScheduler.acquire();
|
|
628
646
|
try {
|
|
629
647
|
while (this._now() < deadline) {
|
|
630
648
|
// OPTIMIZATION: ready hint lives in the bottom ~5 lines of the
|
|
631
649
|
// pane. Polling 1000 lines each tick is wasteful — cap at 80
|
|
632
650
|
// for a ~12× cheaper tmux subprocess.
|
|
633
|
-
|
|
634
|
-
if (READY_HINTS_RE.test(
|
|
651
|
+
lastBuf = await this.runner.captureWide(this.tmuxName, { lines: 80 });
|
|
652
|
+
if (READY_HINTS_RE.test(lastBuf)) return;
|
|
635
653
|
await this._waitForNextTick();
|
|
636
654
|
}
|
|
637
655
|
} finally {
|
|
638
656
|
if (this.pollScheduler) this.pollScheduler.release();
|
|
639
657
|
}
|
|
658
|
+
// On timeout, surface what the TUI was actually showing so the
|
|
659
|
+
// operator can diagnose whether it was hung, on a setup prompt,
|
|
660
|
+
// or just slow to render the ready hint. capture the last ~40
|
|
661
|
+
// lines for the error event payload + log.
|
|
662
|
+
const tail = lastBuf.split('\n').slice(-40).join('\n');
|
|
663
|
+
this.logger.warn?.(
|
|
664
|
+
`[${this.label}] TUI did not signal ready in ${this.readyTimeoutMs}ms; last pane tail:\n${tail}`,
|
|
665
|
+
);
|
|
640
666
|
throw Object.assign(new Error('TmuxProcess: TUI did not signal ready'), {
|
|
641
667
|
code: 'TMUX_READY_TIMEOUT',
|
|
642
668
|
tmuxName: this.tmuxName,
|
|
669
|
+
paneTail: tail,
|
|
643
670
|
});
|
|
644
671
|
}
|
|
645
672
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.10.0-rc.
|
|
3
|
+
"version": "0.10.0-rc.5",
|
|
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": {
|