whatsapp-pi 1.0.44 → 1.0.46
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/README.md +13 -8
- package/package.json +1 -1
- package/src/models/whatsapp.types.ts +3 -0
- package/src/services/message.sender.ts +3 -3
- package/src/services/session.manager.ts +3 -2
- package/src/services/whatsapp.service.ts +47 -54
- package/src/ui/menu.handler.ts +13 -17
- package/whatsapp-pi.ts +31 -31
package/README.md
CHANGED
|
@@ -46,10 +46,10 @@ pi install npm:whatsapp-pi
|
|
|
46
46
|
pi
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
pi --whatsapp-pi-online
|
|
52
|
-
```
|
|
49
|
+
After connecting WhatsApp once from the menu and scanning the QR code, you can start Pi with auto-connect enabled:
|
|
50
|
+
```bash
|
|
51
|
+
pi --whatsapp-pi-online
|
|
52
|
+
```
|
|
53
53
|
|
|
54
54
|
3. Use the menu to connect WhatsApp and manage allowed/blocked numbers
|
|
55
55
|
|
|
@@ -69,10 +69,15 @@ npm install
|
|
|
69
69
|
pi -e whatsapp-pi.ts
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
For verbose mode (shows Baileys trace logs for debugging):
|
|
73
|
-
```bash
|
|
74
|
-
pi -e whatsapp-pi.ts --verbose
|
|
75
|
-
```
|
|
72
|
+
For verbose mode (shows Baileys trace logs for debugging):
|
|
73
|
+
```bash
|
|
74
|
+
pi -e whatsapp-pi.ts --verbose
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
To test startup auto-connect locally after you have already paired WhatsApp:
|
|
78
|
+
```bash
|
|
79
|
+
pi -e whatsapp-pi.ts --whatsapp-pi-online
|
|
80
|
+
```
|
|
76
81
|
|
|
77
82
|
## Commands
|
|
78
83
|
|
package/package.json
CHANGED
|
@@ -18,9 +18,12 @@ export interface IncomingMessage {
|
|
|
18
18
|
timestamp: number;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export type MessageOrigin = 'agent' | 'menu';
|
|
22
|
+
|
|
21
23
|
export interface MessageRequest {
|
|
22
24
|
recipientJid: string;
|
|
23
25
|
text: string;
|
|
26
|
+
origin?: MessageOrigin;
|
|
24
27
|
options?: {
|
|
25
28
|
maxRetries?: number;
|
|
26
29
|
priority?: 'high' | 'normal';
|
|
@@ -54,9 +54,9 @@ export class MessageSender {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// 3. Send the message
|
|
57
|
-
|
|
58
|
-
const response = await socket.sendMessage(request.recipientJid, {
|
|
59
|
-
text: `${request.text} π`
|
|
57
|
+
const shouldAppendPi = request.origin !== 'menu';
|
|
58
|
+
const response = await socket.sendMessage(request.recipientJid, {
|
|
59
|
+
text: shouldAppendPi ? `${request.text} π` : request.text
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
return {
|
|
@@ -136,10 +136,11 @@ export class SessionManager {
|
|
|
136
136
|
public async saveConfig() {
|
|
137
137
|
const tempPath = `${this.configPath}.${process.pid}.${Date.now()}.tmp`;
|
|
138
138
|
try {
|
|
139
|
+
this.hasAuthState = this.hasAuthState || await this.hasCredentialsFile();
|
|
139
140
|
const config = {
|
|
140
141
|
allowList: this.allowList,
|
|
141
|
-
blockList: this.blockList,
|
|
142
|
-
ignoredNumbers: this.ignoredNumbers,
|
|
142
|
+
blockList: this.blockList,
|
|
143
|
+
ignoredNumbers: this.ignoredNumbers,
|
|
143
144
|
status: this.status,
|
|
144
145
|
hasAuthState: this.hasAuthState,
|
|
145
146
|
openaiKey: this.openaiKey,
|
|
@@ -72,10 +72,14 @@ interface BoomLikeError {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export class WhatsAppService {
|
|
75
|
+
private static readonly INITIAL_RECONNECT_DELAY_MS = 5_000;
|
|
76
|
+
private static readonly MAX_RECONNECT_DELAY_MS = 120_000;
|
|
77
|
+
|
|
75
78
|
private socket?: WhatsAppSocketLike;
|
|
76
79
|
private sessionManager: SessionManager;
|
|
77
80
|
private messageSender: MessageSender;
|
|
78
81
|
private isReconnecting = false;
|
|
82
|
+
private reconnectAttempts = 0;
|
|
79
83
|
private verboseMode = false;
|
|
80
84
|
private onIncomingMessageRecorded?: (message: IncomingMessage) => void | Promise<void>;
|
|
81
85
|
private saveCreds?: () => Promise<void>;
|
|
@@ -171,6 +175,11 @@ export class WhatsAppService {
|
|
|
171
175
|
}
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
private getReconnectDelayMs(): number {
|
|
179
|
+
const delay = WhatsAppService.INITIAL_RECONNECT_DELAY_MS * (2 ** Math.max(0, this.reconnectAttempts - 1));
|
|
180
|
+
return Math.min(delay, WhatsAppService.MAX_RECONNECT_DELAY_MS);
|
|
181
|
+
}
|
|
182
|
+
|
|
174
183
|
private cleanupSocket() {
|
|
175
184
|
this.clearReconnectTimeout();
|
|
176
185
|
|
|
@@ -295,7 +304,7 @@ export class WhatsAppService {
|
|
|
295
304
|
private async handlePairingQr(qr: string) {
|
|
296
305
|
this.sessionManager.setStatus('pairing');
|
|
297
306
|
this.onQRCode?.(qr);
|
|
298
|
-
this.onStatusUpdate?.('| WhatsApp: Disconnected');
|
|
307
|
+
this.onStatusUpdate?.('| WhatsApp: Disconnected');
|
|
299
308
|
}
|
|
300
309
|
|
|
301
310
|
private async handleConnectionOpen() {
|
|
@@ -304,6 +313,7 @@ export class WhatsAppService {
|
|
|
304
313
|
}
|
|
305
314
|
|
|
306
315
|
this.isReconnecting = false;
|
|
316
|
+
this.reconnectAttempts = 0;
|
|
307
317
|
this.clearReconnectTimeout();
|
|
308
318
|
await this.saveCreds?.();
|
|
309
319
|
await this.sessionManager.markAuthStateAvailable();
|
|
@@ -339,45 +349,55 @@ export class WhatsAppService {
|
|
|
339
349
|
console.error(`Connection closed [${statusCode}]. Reconnecting: ${shouldReconnect}`);
|
|
340
350
|
}
|
|
341
351
|
|
|
342
|
-
if (shouldTreatAsLoggedOut) {
|
|
343
|
-
if (this.verboseMode) {
|
|
344
|
-
console.error(`Session rejected [${statusCode}] - preserving auth state`);
|
|
345
|
-
}
|
|
346
|
-
if (isBadMac) {
|
|
347
|
-
if (this.verboseMode) {
|
|
348
|
-
console.error('[WhatsApp-Pi] Bad MAC error detected. Your session keys are corrupted.');
|
|
349
|
-
console.error('[WhatsApp-Pi] Use Logoff (Delete Session) only if reconnect keeps failing.');
|
|
350
|
-
}
|
|
351
|
-
this.onStatusUpdate?.('| WhatsApp: Session Error (Bad MAC)');
|
|
352
|
-
} else if (isAuthRejected && allowPairingOnAuthFailure) {
|
|
353
|
-
this.onStatusUpdate?.('| WhatsApp: Session Preserved (Reconnect Failed)');
|
|
354
|
-
}
|
|
355
|
-
this.cleanupSocket();
|
|
356
|
-
this.isReconnecting = false;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
352
|
+
if (shouldTreatAsLoggedOut) {
|
|
353
|
+
if (this.verboseMode) {
|
|
354
|
+
console.error(`Session rejected [${statusCode}] - preserving auth state`);
|
|
355
|
+
}
|
|
356
|
+
if (isBadMac) {
|
|
357
|
+
if (this.verboseMode) {
|
|
358
|
+
console.error('[WhatsApp-Pi] Bad MAC error detected. Your session keys are corrupted.');
|
|
359
|
+
console.error('[WhatsApp-Pi] Use Logoff (Delete Session) only if reconnect keeps failing.');
|
|
360
|
+
}
|
|
361
|
+
this.onStatusUpdate?.('| WhatsApp: Session Error (Bad MAC)');
|
|
362
|
+
} else if (isAuthRejected && allowPairingOnAuthFailure) {
|
|
363
|
+
this.onStatusUpdate?.('| WhatsApp: Session Preserved (Reconnect Failed)');
|
|
364
|
+
}
|
|
365
|
+
this.cleanupSocket();
|
|
366
|
+
this.isReconnecting = false;
|
|
367
|
+
this.reconnectAttempts = 0;
|
|
368
|
+
await this.sessionManager.setStatus('disconnected');
|
|
369
|
+
if (!isBadMac) {
|
|
370
|
+
this.onStatusUpdate?.('| WhatsApp: Disconnected');
|
|
371
|
+
}
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
363
374
|
|
|
364
375
|
if (statusCode === DisconnectReason.connectionReplaced) {
|
|
365
376
|
if (this.verboseMode) {
|
|
366
377
|
console.error('Connection replaced - another instance connected');
|
|
367
378
|
}
|
|
379
|
+
this.cleanupSocket();
|
|
380
|
+
this.isReconnecting = false;
|
|
381
|
+
this.reconnectAttempts = 0;
|
|
382
|
+
await this.sessionManager.setStatus('disconnected');
|
|
368
383
|
this.onStatusUpdate?.('| WhatsApp: Conflict (Another Instance)');
|
|
369
384
|
return;
|
|
370
385
|
}
|
|
371
386
|
|
|
372
387
|
if (shouldReconnect && !this.isReconnecting) {
|
|
373
388
|
this.isReconnecting = true;
|
|
389
|
+
this.reconnectAttempts++;
|
|
390
|
+
const reconnectDelayMs = this.getReconnectDelayMs();
|
|
374
391
|
this.onStatusUpdate?.('| WhatsApp: Reconnecting...');
|
|
375
392
|
this.clearReconnectTimeout();
|
|
393
|
+
await this.saveCreds?.();
|
|
394
|
+
this.cleanupSocket();
|
|
376
395
|
this.reconnectTimeout = setTimeout(() => {
|
|
377
396
|
this.isReconnecting = false;
|
|
378
397
|
void this.start(options);
|
|
379
|
-
},
|
|
398
|
+
}, reconnectDelayMs);
|
|
380
399
|
} else if (!shouldReconnect) {
|
|
400
|
+
this.reconnectAttempts = 0;
|
|
381
401
|
this.sessionManager.setStatus('logged-out');
|
|
382
402
|
this.onStatusUpdate?.('| WhatsApp: Disconnected');
|
|
383
403
|
}
|
|
@@ -477,13 +497,14 @@ export class WhatsAppService {
|
|
|
477
497
|
return this.socket;
|
|
478
498
|
}
|
|
479
499
|
|
|
480
|
-
async sendMessage(jid: string, text: string) {
|
|
500
|
+
async sendMessage(jid: string, text: string, origin: 'agent' | 'menu' = 'agent') {
|
|
481
501
|
// Ensure we show the typing indicator before sending
|
|
482
502
|
await this.sendPresence(jid, 'composing');
|
|
483
503
|
|
|
484
504
|
const result = await this.messageSender.send({
|
|
485
505
|
recipientJid: jid,
|
|
486
|
-
text
|
|
506
|
+
text,
|
|
507
|
+
origin
|
|
487
508
|
});
|
|
488
509
|
|
|
489
510
|
// After sending, we can stop the typing indicator
|
|
@@ -498,35 +519,7 @@ export class WhatsAppService {
|
|
|
498
519
|
|
|
499
520
|
async sendMenuMessage(jid: string, text: string) {
|
|
500
521
|
const normalizedJid = this.normalizeRecipientJid(jid);
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (!socket) {
|
|
504
|
-
return {
|
|
505
|
-
success: false,
|
|
506
|
-
error: 'WhatsApp is not connected',
|
|
507
|
-
attempts: 0
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
try {
|
|
512
|
-
await this.sendPresence(normalizedJid, 'composing');
|
|
513
|
-
const response = await socket.sendMessage(normalizedJid, { text });
|
|
514
|
-
await this.sendPresence(normalizedJid, 'paused');
|
|
515
|
-
|
|
516
|
-
return {
|
|
517
|
-
success: true,
|
|
518
|
-
messageId: response?.key?.id,
|
|
519
|
-
attempts: 1
|
|
520
|
-
};
|
|
521
|
-
} catch (error: unknown) {
|
|
522
|
-
await this.sendPresence(normalizedJid, 'paused');
|
|
523
|
-
console.error(`Failed to send menu message to ${normalizedJid}:`, error);
|
|
524
|
-
return {
|
|
525
|
-
success: false,
|
|
526
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
527
|
-
attempts: 1
|
|
528
|
-
};
|
|
529
|
-
}
|
|
522
|
+
return this.sendMessage(normalizedJid, text, 'menu');
|
|
530
523
|
}
|
|
531
524
|
|
|
532
525
|
async sendPresence(jid: string, presence: 'composing' | 'recording' | 'paused') {
|
package/src/ui/menu.handler.ts
CHANGED
|
@@ -63,14 +63,14 @@ export class MenuHandler {
|
|
|
63
63
|
await this.whatsappService.stop();
|
|
64
64
|
ctx.ui.notify('WhatsApp Agent Disconnected', 'warning');
|
|
65
65
|
break;
|
|
66
|
-
case 'Logoff (Delete Session)': {
|
|
67
|
-
const confirmLogoff = await ctx.ui.confirm('Logoff', 'Delete all credentials?');
|
|
68
|
-
if (confirmLogoff) {
|
|
69
|
-
await this.whatsappService.logout();
|
|
70
|
-
ctx.ui.notify('Logged off and credentials deleted', 'info');
|
|
71
|
-
}
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
66
|
+
case 'Logoff (Delete Session)': {
|
|
67
|
+
const confirmLogoff = await ctx.ui.confirm('Logoff', 'Delete all credentials?');
|
|
68
|
+
if (confirmLogoff) {
|
|
69
|
+
await this.whatsappService.logout();
|
|
70
|
+
ctx.ui.notify('Logged off and credentials deleted', 'info');
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
74
|
case 'Allowed Numbers':
|
|
75
75
|
await this.manageAllowList(ctx);
|
|
76
76
|
break;
|
|
@@ -325,8 +325,7 @@ export class MenuHandler {
|
|
|
325
325
|
await this.sendPromptedMenuMessage(ctx, {
|
|
326
326
|
displayName: this.getConversationDisplayName(conversation),
|
|
327
327
|
senderNumber: conversation.senderNumber,
|
|
328
|
-
senderName: conversation.senderName
|
|
329
|
-
appendPiSuffix: false
|
|
328
|
+
senderName: conversation.senderName
|
|
330
329
|
});
|
|
331
330
|
}
|
|
332
331
|
|
|
@@ -334,8 +333,7 @@ export class MenuHandler {
|
|
|
334
333
|
await this.sendPromptedMenuMessage(ctx, {
|
|
335
334
|
displayName: this.formatAllowedContactOption(contact),
|
|
336
335
|
senderNumber: contact.number,
|
|
337
|
-
senderName: contact.name
|
|
338
|
-
appendPiSuffix: true
|
|
336
|
+
senderName: contact.name
|
|
339
337
|
});
|
|
340
338
|
}
|
|
341
339
|
|
|
@@ -345,10 +343,9 @@ export class MenuHandler {
|
|
|
345
343
|
displayName: string;
|
|
346
344
|
senderNumber: string;
|
|
347
345
|
senderName?: string;
|
|
348
|
-
appendPiSuffix: boolean;
|
|
349
346
|
}
|
|
350
347
|
) {
|
|
351
|
-
const { displayName, senderNumber, senderName
|
|
348
|
+
const { displayName, senderNumber, senderName } = options;
|
|
352
349
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
353
350
|
const inputText = (await ctx.ui.input(`Send a message to ${displayName}:`))?.trim() || '';
|
|
354
351
|
|
|
@@ -357,14 +354,13 @@ export class MenuHandler {
|
|
|
357
354
|
continue;
|
|
358
355
|
}
|
|
359
356
|
|
|
360
|
-
const
|
|
361
|
-
const result = await this.whatsappService.sendMenuMessage(this.toJid(senderNumber), messageText);
|
|
357
|
+
const result = await this.whatsappService.sendMenuMessage(this.toJid(senderNumber), inputText);
|
|
362
358
|
if (result.success) {
|
|
363
359
|
await this.recentsService.recordMessage({
|
|
364
360
|
messageId: result.messageId ?? `${Date.now()}`,
|
|
365
361
|
senderNumber,
|
|
366
362
|
senderName,
|
|
367
|
-
text:
|
|
363
|
+
text: inputText,
|
|
368
364
|
direction: 'outgoing',
|
|
369
365
|
timestamp: Date.now()
|
|
370
366
|
});
|
package/whatsapp-pi.ts
CHANGED
|
@@ -60,7 +60,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
// Initial status setup
|
|
63
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
63
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
64
64
|
_ctx = ctx;
|
|
65
65
|
// Check verbose mode
|
|
66
66
|
const isVerboseFlagSet = process.argv.includes("--verbose");
|
|
@@ -86,10 +86,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
86
86
|
await whatsappService.stop();
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
|
-
whatsappService.setIncomingMessageRecorder(async (message) => {
|
|
90
|
-
await recentsService.recordMessage({
|
|
91
|
-
messageId: message.id,
|
|
92
|
-
senderNumber: `+${message.remoteJid.split('@')[0]}`,
|
|
89
|
+
whatsappService.setIncomingMessageRecorder(async (message) => {
|
|
90
|
+
await recentsService.recordMessage({
|
|
91
|
+
messageId: message.id,
|
|
92
|
+
senderNumber: `+${message.remoteJid.split('@')[0]}`,
|
|
93
93
|
senderName: message.pushName,
|
|
94
94
|
text: message.text || '',
|
|
95
95
|
direction: 'incoming',
|
|
@@ -97,20 +97,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
const savedStateEntry = [...ctx.sessionManager.getEntries()]
|
|
101
|
-
.reverse()
|
|
102
|
-
.find(entry => entry.type === "custom" && entry.customType === "whatsapp-state");
|
|
103
|
-
const isWhatsappPiOn = pi.getFlag("whatsapp-pi-online") === true;
|
|
104
|
-
const registered = await sessionManager.isRegistered();
|
|
105
|
-
|
|
106
|
-
if (savedStateEntry) {
|
|
107
|
-
const data = (savedStateEntry as { data?: any }).data;
|
|
108
|
-
if (data.status) {
|
|
109
|
-
const restoredStatus = data.status === 'connected' && !(isWhatsappPiOn && registered)
|
|
110
|
-
? 'disconnected'
|
|
111
|
-
: data.status;
|
|
112
|
-
await sessionManager.setStatus(restoredStatus);
|
|
113
|
-
}
|
|
100
|
+
const savedStateEntry = [...ctx.sessionManager.getEntries()]
|
|
101
|
+
.reverse()
|
|
102
|
+
.find(entry => entry.type === "custom" && entry.customType === "whatsapp-state");
|
|
103
|
+
const isWhatsappPiOn = pi.getFlag("whatsapp-pi-online") === true;
|
|
104
|
+
const registered = await sessionManager.isRegistered();
|
|
105
|
+
|
|
106
|
+
if (savedStateEntry) {
|
|
107
|
+
const data = (savedStateEntry as { data?: any }).data;
|
|
108
|
+
if (data.status) {
|
|
109
|
+
const restoredStatus = data.status === 'connected' && !(isWhatsappPiOn && registered)
|
|
110
|
+
? 'disconnected'
|
|
111
|
+
: data.status;
|
|
112
|
+
await sessionManager.setStatus(restoredStatus);
|
|
113
|
+
}
|
|
114
114
|
if (Array.isArray(data.allowList)) {
|
|
115
115
|
for (const n of data.allowList) {
|
|
116
116
|
const num = typeof n === "string" ? n : n.number;
|
|
@@ -118,10 +118,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
118
118
|
await sessionManager.addNumber(num, name);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (isWhatsappPiOn && registered) {
|
|
124
|
-
ctx.ui.setStatus('whatsapp', '| WhatsApp: Auto-connecting...');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (isWhatsappPiOn && registered) {
|
|
124
|
+
ctx.ui.setStatus('whatsapp', '| WhatsApp: Auto-connecting...');
|
|
125
125
|
|
|
126
126
|
// Retry logic (max 3 attempts, 3s delay)
|
|
127
127
|
let attempts = 0;
|
|
@@ -131,7 +131,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
131
131
|
attempts++;
|
|
132
132
|
try {
|
|
133
133
|
await whatsappService.start({ allowPairingOnAuthFailure: false });
|
|
134
|
-
} catch {
|
|
134
|
+
} catch {
|
|
135
135
|
if (attempts < maxAttempts) {
|
|
136
136
|
ctx.ui.notify(`WhatsApp: Connection attempt ${attempts} failed. Retrying...`, 'warning');
|
|
137
137
|
setTimeout(tryConnect, 3000);
|
|
@@ -143,11 +143,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
143
143
|
};
|
|
144
144
|
|
|
145
145
|
await tryConnect();
|
|
146
|
-
} else if (isWhatsappPiOn) {
|
|
147
|
-
ctx.ui.notify('WhatsApp: Auto-connect requested, but no saved WhatsApp credentials were found. Use Connect WhatsApp once to scan the QR code.', 'warning');
|
|
148
|
-
} else {
|
|
149
|
-
ctx.ui.notify('WhatsApp: Use Connect / Reconnect WhatsApp. QR code will appear only if pairing is needed.', 'info');
|
|
150
|
-
}
|
|
146
|
+
} else if (isWhatsappPiOn) {
|
|
147
|
+
ctx.ui.notify('WhatsApp: Auto-connect requested, but no saved WhatsApp credentials were found. Use Connect WhatsApp once to scan the QR code.', 'warning');
|
|
148
|
+
} else {
|
|
149
|
+
ctx.ui.notify('WhatsApp: Use Connect / Reconnect WhatsApp. QR code will appear only if pairing is needed.', 'info');
|
|
150
|
+
}
|
|
151
151
|
|
|
152
152
|
ctx.ui.notify('WhatsApp: Session reset via /new is now fully supported.', 'info');
|
|
153
153
|
|
|
@@ -157,7 +157,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
157
157
|
if (code !== 0 && code !== 99) { // 99 is a common exit code for -v in some versions
|
|
158
158
|
throw new Error(`pdftotext returned code ${code}`);
|
|
159
159
|
}
|
|
160
|
-
} catch {
|
|
160
|
+
} catch {
|
|
161
161
|
ctx.ui.notify('WhatsApp: pdftotext not found. PDF document support will be limited to storage only.', 'warning');
|
|
162
162
|
logger.warn('[WhatsApp-Pi] Warning: pdftotext not found in system PATH.');
|
|
163
163
|
}
|
|
@@ -333,7 +333,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
333
333
|
} else {
|
|
334
334
|
ctx.ui.notify(`Failed to send WhatsApp reply`, 'error');
|
|
335
335
|
}
|
|
336
|
-
} catch {
|
|
336
|
+
} catch {
|
|
337
337
|
ctx.ui.notify(`Failed to send WhatsApp reply`, 'error');
|
|
338
338
|
}
|
|
339
339
|
}
|