@rubytech/taskmaster 1.5.0 → 1.5.1

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,5 +1,5 @@
1
1
  {
2
- "version": "1.5.0",
3
- "commit": "b261680b5d87960c18d6b70c7a8ba92f5b4d3e1d",
4
- "builtAt": "2026-02-25T14:35:58.840Z"
2
+ "version": "1.5.1",
3
+ "commit": "c41ff963c35a771e2926c6229418a18568bdd3bb",
4
+ "builtAt": "2026-02-25T16:02:37.451Z"
5
5
  }
@@ -16,7 +16,7 @@ import { resolveWhatsAppAccount } from "../accounts.js";
16
16
  import { setActiveWebListener } from "../active-listener.js";
17
17
  import { monitorWebInbox } from "../inbound.js";
18
18
  import { computeBackoff, newConnectionId, resolveHeartbeatSeconds, resolveReconnectPolicy, sleepWithAbort, } from "../reconnect.js";
19
- import { formatError, getWebAuthAgeMs, readWebSelfId } from "../session.js";
19
+ import { formatError, getStatusCode, getWebAuthAgeMs, readWebSelfId } from "../session.js";
20
20
  import { DEFAULT_WEB_MEDIA_BYTES } from "./constants.js";
21
21
  import { whatsappHeartbeatLog, whatsappLog } from "./loggers.js";
22
22
  import { buildMentionConfig } from "./mentions.js";
@@ -142,24 +142,80 @@ export async function monitorWebChannel(verbose, listenerFactory = monitorWebInb
142
142
  return false;
143
143
  return !hasControlCommand(msg.body, cfg);
144
144
  };
145
- const listener = await (listenerFactory ?? monitorWebInbox)({
146
- verbose,
147
- accountId: account.accountId,
148
- authDir: account.authDir,
149
- mediaMaxMb: account.mediaMaxMb,
150
- sendReadReceipts: account.sendReadReceipts,
151
- debounceMs: inboundDebounceMs,
152
- shouldDebounce,
153
- onMessage: async (msg) => {
154
- handledMessages += 1;
155
- lastMessageAt = Date.now();
156
- status.lastMessageAt = lastMessageAt;
157
- status.lastEventAt = lastMessageAt;
158
- emitStatus();
159
- _lastInboundMsg = msg;
160
- await onMessage(msg);
161
- },
162
- });
145
+ let listener;
146
+ try {
147
+ listener = await (listenerFactory ?? monitorWebInbox)({
148
+ verbose,
149
+ accountId: account.accountId,
150
+ authDir: account.authDir,
151
+ mediaMaxMb: account.mediaMaxMb,
152
+ sendReadReceipts: account.sendReadReceipts,
153
+ debounceMs: inboundDebounceMs,
154
+ shouldDebounce,
155
+ onMessage: async (msg) => {
156
+ handledMessages += 1;
157
+ lastMessageAt = Date.now();
158
+ status.lastMessageAt = lastMessageAt;
159
+ status.lastEventAt = lastMessageAt;
160
+ emitStatus();
161
+ _lastInboundMsg = msg;
162
+ await onMessage(msg);
163
+ },
164
+ });
165
+ }
166
+ catch (setupErr) {
167
+ // Connection setup failed (e.g., 405 from WhatsApp server during handshake).
168
+ // Feed into the same retry/backoff logic as a runtime disconnect instead
169
+ // of letting the error escape the loop and kill the channel permanently.
170
+ const statusCode = getStatusCode(setupErr) ?? "unknown";
171
+ const errorStr = formatError(setupErr);
172
+ const loggedOut = statusCode === 401; // DisconnectReason.loggedOut
173
+ status.connected = false;
174
+ status.lastEventAt = Date.now();
175
+ status.lastDisconnect = {
176
+ at: status.lastEventAt,
177
+ status: typeof statusCode === "number" ? statusCode : undefined,
178
+ error: errorStr,
179
+ loggedOut,
180
+ };
181
+ status.lastError = errorStr;
182
+ status.reconnectAttempts = reconnectAttempts;
183
+ emitStatus();
184
+ reconnectLogger.info({ connectionId, status: statusCode, loggedOut, reconnectAttempts, error: errorStr }, "web reconnect: connection setup failed");
185
+ if (loggedOut) {
186
+ runtime.error(`WhatsApp session logged out. Run \`${formatCliCommand("taskmaster channels login --channel web")}\` to relink.`);
187
+ break;
188
+ }
189
+ reconnectAttempts += 1;
190
+ status.reconnectAttempts = reconnectAttempts;
191
+ emitStatus();
192
+ if (reconnectPolicy.maxAttempts > 0 && reconnectAttempts >= reconnectPolicy.maxAttempts) {
193
+ reconnectLogger.warn({
194
+ connectionId,
195
+ status: statusCode,
196
+ reconnectAttempts,
197
+ maxAttempts: reconnectPolicy.maxAttempts,
198
+ }, "web reconnect: max attempts reached after setup failures; stopping");
199
+ runtime.error(`WhatsApp Web reconnect: max attempts reached (${reconnectAttempts}/${reconnectPolicy.maxAttempts}). Stopping web monitoring.`);
200
+ break;
201
+ }
202
+ const delay = computeBackoff(reconnectPolicy, reconnectAttempts);
203
+ reconnectLogger.info({
204
+ connectionId,
205
+ status: statusCode,
206
+ reconnectAttempts,
207
+ maxAttempts: reconnectPolicy.maxAttempts || "unlimited",
208
+ delayMs: delay,
209
+ }, "web reconnect: scheduling retry after setup failure");
210
+ runtime.error(`WhatsApp Web connection setup failed (status ${statusCode}). Retry ${reconnectAttempts}/${reconnectPolicy.maxAttempts || "∞"} in ${formatDurationMs(delay)}… (${errorStr})`);
211
+ try {
212
+ await sleep(delay, abortSignal);
213
+ }
214
+ catch {
215
+ break;
216
+ }
217
+ continue;
218
+ }
163
219
  status.connected = true;
164
220
  status.lastConnectedAt = Date.now();
165
221
  status.lastEventAt = status.lastConnectedAt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"