@inetafrica/open-claudia 1.1.3 → 1.1.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.
Files changed (2) hide show
  1. package/bot.js +49 -1
  2. package/package.json +1 -1
package/bot.js CHANGED
@@ -98,9 +98,38 @@ const FULL_PATH = [
98
98
  "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin",
99
99
  ].filter(Boolean).join(":");
100
100
 
101
- const bot = new TelegramBot(TOKEN, { polling: true });
101
+ const bot = new TelegramBot(TOKEN, {
102
+ polling: {
103
+ autoStart: true,
104
+ params: { timeout: 30 },
105
+ },
106
+ });
102
107
  const vault = new Vault(VAULT_FILE);
103
108
 
109
+ // ── Auto-reconnect on polling errors ───────────────────────────────
110
+ let reconnectTimer = null;
111
+ bot.on("polling_error", (err) => {
112
+ const msg = err.message || "";
113
+ console.error("Polling error:", msg);
114
+ if (msg.includes("ETIMEDOUT") || msg.includes("ECONNRESET") || msg.includes("ENOTFOUND") || msg.includes("EFATAL")) {
115
+ if (reconnectTimer) return; // Already scheduled
116
+ console.log("Network lost. Reconnecting in 10s...");
117
+ reconnectTimer = setTimeout(async () => {
118
+ reconnectTimer = null;
119
+ try {
120
+ await bot.stopPolling();
121
+ await new Promise((r) => setTimeout(r, 2000));
122
+ await bot.startPolling();
123
+ console.log("Reconnected.");
124
+ } catch (e) {
125
+ console.error("Reconnect failed:", e.message);
126
+ // launchd will restart us if we exit
127
+ process.exit(1);
128
+ }
129
+ }, 10000);
130
+ }
131
+ });
132
+
104
133
  // ── Commands Menu ───────────────────────────────────────────────────
105
134
  bot.setMyCommands([
106
135
  { command: "session", description: "Pick a project to work on" },
@@ -149,6 +178,20 @@ function saveState() {
149
178
  try { fs.writeFileSync(STATE_FILE, JSON.stringify(data)); } catch (e) {}
150
179
  }
151
180
 
181
+ // ── Message deduplication ──────────────────────────────────────────
182
+ const processedMessages = new Set();
183
+ function isDuplicate(msgId) {
184
+ if (processedMessages.has(msgId)) return true;
185
+ processedMessages.add(msgId);
186
+ // Keep set from growing unbounded
187
+ if (processedMessages.size > 200) {
188
+ const arr = [...processedMessages];
189
+ processedMessages.clear();
190
+ arr.slice(-100).forEach((id) => processedMessages.add(id));
191
+ }
192
+ return false;
193
+ }
194
+
152
195
  // ── Per-project session history ────────────────────────────────────
153
196
 
154
197
  function loadSessions() {
@@ -1023,6 +1066,7 @@ bot.on("callback_query", async (q) => {
1023
1066
  // ── Media Handlers ──────────────────────────────────────────────────
1024
1067
 
1025
1068
  bot.on("voice", async (msg) => {
1069
+ if (isDuplicate(msg.message_id)) return;
1026
1070
  if (!isAuthorized(msg)) return;
1027
1071
  if (!requireSession(msg)) return;
1028
1072
  try {
@@ -1037,6 +1081,7 @@ bot.on("voice", async (msg) => {
1037
1081
  });
1038
1082
 
1039
1083
  bot.on("audio", async (msg) => {
1084
+ if (isDuplicate(msg.message_id)) return;
1040
1085
  if (!isAuthorized(msg)) return;
1041
1086
  if (!requireSession(msg)) return;
1042
1087
  try {
@@ -1051,6 +1096,7 @@ bot.on("audio", async (msg) => {
1051
1096
  });
1052
1097
 
1053
1098
  bot.on("photo", async (msg) => {
1099
+ if (isDuplicate(msg.message_id)) return;
1054
1100
  if (!isAuthorized(msg)) return;
1055
1101
  if (!requireSession(msg)) return;
1056
1102
  try {
@@ -1061,6 +1107,7 @@ bot.on("photo", async (msg) => {
1061
1107
  });
1062
1108
 
1063
1109
  bot.on("document", async (msg) => {
1110
+ if (isDuplicate(msg.message_id)) return;
1064
1111
  if (!isAuthorized(msg)) return;
1065
1112
  if (!requireSession(msg)) return;
1066
1113
  try {
@@ -1075,6 +1122,7 @@ bot.on("document", async (msg) => {
1075
1122
  // ── Text Message Handler (handles onboarding, vault password, normal messages) ──
1076
1123
 
1077
1124
  bot.on("message", async (msg) => {
1125
+ if (isDuplicate(msg.message_id)) return;
1078
1126
  if (!isAuthorized(msg)) return;
1079
1127
  if (!msg.text || msg.text.startsWith("/")) return;
1080
1128
  if (msg.voice || msg.audio || msg.photo || msg.document || msg.video || msg.sticker) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Your always-on AI coding assistant — Claude Code via Telegram",
5
5
  "main": "bot.js",
6
6
  "bin": {