polygram 0.17.7 → 0.17.8

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.
@@ -2040,12 +2040,32 @@ class CliProcess extends Process {
2040
2040
  * sibling's text; otherwise leave the status (nothing more to send).
2041
2041
  */
2042
2042
  _resolveTurnDelivery(pending, turnId) {
2043
+ const out = this._computeTurnDelivery(pending, turnId);
2044
+ // 0.17.8 characterize-first: the channels double-delivery (shumorobot Music,
2045
+ // 2026-06-28 — reply tool sent #2147, then the daemon re-sent result.text as
2046
+ // #2149) is a turn that resolved with alreadyDelivered=false despite a reply tool
2047
+ // delivery. Log the chosen branch + counts so the next occurrence pins WHY (the
2048
+ // leading hypothesis: an interrupted turn loses its recorded reply → the
2049
+ // zero-reply Stop-fallback re-delivers last_assistant_message).
2050
+ this._logEvent('cli-resolve-delivery', {
2051
+ turn_id: turnId, session_key: this.sessionKey, backend: this.backend,
2052
+ branch: out.branch,
2053
+ already_delivered: out.alreadyDelivered,
2054
+ reply_count: pending.replies.length,
2055
+ interim_count: pending._interimReplyCount || 0,
2056
+ has_stop_data: !!pending._stopHookData,
2057
+ text_len: (out.text || '').length,
2058
+ });
2059
+ return { text: out.text, alreadyDelivered: out.alreadyDelivered };
2060
+ }
2061
+
2062
+ _computeTurnDelivery(pending, turnId) {
2043
2063
  const norm = (s) => (s || '').trim();
2044
2064
  const interimText = pending.replies.join('\n\n');
2045
2065
  const fallbackText = pending._stopHookData?.lastAssistantMessage || '';
2046
2066
 
2047
2067
  if (this._turnHasFinalReply(pending)) {
2048
- return { text: interimText, alreadyDelivered: true };
2068
+ return { text: interimText, alreadyDelivered: true, branch: 'final-reply' };
2049
2069
  }
2050
2070
  if (pending.replies.length === 0) {
2051
2071
  // 0.12 Phase 1.7 fallback: no reply tool call landed — use the Stop hook's
@@ -2068,7 +2088,7 @@ class CliProcess extends Process {
2068
2088
  rescued_len: text.length, ack_len: norm(pending._consumedByText).length,
2069
2089
  });
2070
2090
  }
2071
- return { text, alreadyDelivered };
2091
+ return { text, alreadyDelivered, branch: 'zero-reply' };
2072
2092
  }
2073
2093
  // Interim-only: the turn delivered ONLY status/progress promises ("give me a
2074
2094
  // couple min") and never a final reply. If claude produced a substantive final
@@ -2084,9 +2104,9 @@ class CliProcess extends Process {
2084
2104
  turn_id: turnId, session_key: this.sessionKey, backend: this.backend,
2085
2105
  rescued_len: fallbackText.length, interim_count: pending.replies.length,
2086
2106
  });
2087
- return { text: fallbackText, alreadyDelivered: false };
2107
+ return { text: fallbackText, alreadyDelivered: false, branch: 'interim-rescue' };
2088
2108
  }
2089
- return { text: interimText, alreadyDelivered: true };
2109
+ return { text: interimText, alreadyDelivered: true, branch: 'interim-noop' };
2090
2110
  }
2091
2111
 
2092
2112
  _finalizeTurn(turnId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.17.7",
3
+ "version": "0.17.8",
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": {