opencode-telegram-mirror 0.4.2 → 0.4.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-telegram-mirror",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Standalone bot that mirrors OpenCode sessions to Telegram topics",
5
5
  "type": "module",
6
6
  "main": "src/main.ts",
package/src/main.ts CHANGED
@@ -836,11 +836,13 @@ async function handleTelegramMessage(
836
836
  > = []
837
837
 
838
838
  if (msg.photo && msg.photo.length > 0) {
839
+ const stopTyping = state.telegram.startTyping()
839
840
  const bestPhoto = msg.photo[msg.photo.length - 1]
840
841
  const dataUrlResult = await state.telegram.downloadFileAsDataUrl(
841
842
  bestPhoto.file_id,
842
843
  "image/jpeg"
843
844
  )
845
+ stopTyping()
844
846
  if (dataUrlResult.status === "ok") {
845
847
  parts.push({
846
848
  type: "file",
@@ -862,6 +864,8 @@ async function handleTelegramMessage(
862
864
  return
863
865
  }
864
866
 
867
+ const stopTyping = state.telegram.startTyping()
868
+
865
869
  log("info", "Processing voice message", {
866
870
  duration: msg.voice.duration,
867
871
  fileId: msg.voice.file_id,
@@ -869,6 +873,7 @@ async function handleTelegramMessage(
869
873
 
870
874
  const fileUrlResult = await state.telegram.getFileUrl(msg.voice.file_id)
871
875
  if (fileUrlResult.status === "error") {
876
+ stopTyping()
872
877
  log("error", "Failed to get voice file URL", {
873
878
  error: fileUrlResult.error.message,
874
879
  })
@@ -878,6 +883,7 @@ async function handleTelegramMessage(
878
883
 
879
884
  const audioResponse = await fetch(fileUrlResult.value)
880
885
  if (!audioResponse.ok) {
886
+ stopTyping()
881
887
  log("error", "Failed to download voice file", { status: audioResponse.status })
882
888
  await state.telegram.sendMessage("Failed to download voice message.")
883
889
  return
@@ -885,6 +891,7 @@ async function handleTelegramMessage(
885
891
 
886
892
  const audioBuffer = await audioResponse.arrayBuffer()
887
893
  const transcriptionResult = await transcribeVoice(audioBuffer, log)
894
+ stopTyping()
888
895
 
889
896
  if (transcriptionResult.status === "error") {
890
897
  log("error", "Voice transcription failed", {
@@ -1071,6 +1078,23 @@ async function handleOpenCodeEvent(state: BotState, ev: OpenCodeEvent) {
1071
1078
 
1072
1079
  if (!sessionId || sessionId !== state.sessionId) return
1073
1080
 
1081
+ // Stop typing when session becomes idle
1082
+ if (ev.type === "session.idle") {
1083
+ for (const [key, entry] of state.typingIndicators) {
1084
+ if (key.startsWith(`${sessionId}:`)) {
1085
+ if (entry.timeout) clearTimeout(entry.timeout)
1086
+ entry.stop()
1087
+ state.typingIndicators.delete(key)
1088
+ }
1089
+ }
1090
+ return
1091
+ }
1092
+
1093
+ // Send typing action on every session event to keep indicator active during long operations
1094
+ if (ev.type !== "session.error") {
1095
+ state.telegram.sendTypingAction()
1096
+ }
1097
+
1074
1098
  if (sessionTitle && state.threadId) {
1075
1099
  const trimmedTitle = sessionTitle.trim()
1076
1100
  const shouldUpdate = trimmedTitle && trimmedTitle !== state.threadTitle
@@ -1140,7 +1164,7 @@ async function handleOpenCodeEvent(state: BotState, ev: OpenCodeEvent) {
1140
1164
  existing.stop()
1141
1165
  }
1142
1166
 
1143
- const stop = state.telegram.startTyping(mode === "tool" ? 2000 : 4000)
1167
+ const stop = state.telegram.startTyping(mode === "tool" ? 1500 : 2500)
1144
1168
  state.typingIndicators.set(targetKey, { stop, timeout: null, mode })
1145
1169
  }
1146
1170
 
package/src/telegram.ts CHANGED
@@ -505,11 +505,12 @@ export class TelegramClient {
505
505
  * Send typing indicator to show the bot is working
506
506
  * Returns a stop function to cancel the typing indicator
507
507
  */
508
- startTyping(intervalMs = 4000): () => void {
508
+ startTyping(intervalMs = 2500): () => void {
509
509
  // Send immediately
510
510
  this.sendTypingAction()
511
511
 
512
- // Telegram typing indicator lasts ~5 seconds, so refresh every 4 seconds
512
+ // Telegram typing indicator lasts ~5 seconds, so refresh every 2.5 seconds by default
513
+ // to ensure continuous typing even with network delays
513
514
  const interval = setInterval(() => {
514
515
  this.sendTypingAction()
515
516
  }, intervalMs)