whatsapp-pi 1.0.15 → 1.0.18

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 CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  A WhatsApp integration extension for the **[Pi Coding Agent](https://github.com/mariozechner/pi-coding-agent)**.
8
8
 
9
+ [![GitHub](https://img.shields.io/badge/github-repo-black.svg?style=flat-square&logo=github)](https://github.com/RaphaCastelloes/whatsapp-pi)
10
+
9
11
  Pi is a powerful agentic AI coding assistant that operates in your terminal. This extension allows you to chat and pair-program with your Pi agent directly through WhatsApp, featuring message filtering, allow-listing, and reliable message delivery.
10
12
 
11
13
  ## Features
@@ -40,10 +42,12 @@ pi --whatsapp
40
42
 
41
43
  ## Development / Testing
42
44
 
43
- If you are developing or testing the extension locally:
45
+ If you are developing or testing the extension locally, you can clone the repository from [GitHub](https://github.com/RaphaCastelloes/whatsapp-pi):
44
46
 
45
- 1. Install dependencies:
47
+ 1. Clone and install dependencies:
46
48
  ```bash
49
+ git clone https://github.com/RaphaCastelloes/whatsapp-pi.git
50
+ cd whatsapp-pi
47
51
  npm install
48
52
  ```
49
53
 
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "whatsapp-pi",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
4
4
  "type": "module",
5
5
  "description": "WhatsApp integration extension for Pi",
6
6
  "main": "whatsapp-pi.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/RaphaCastelloes/whatsapp-pi.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/RaphaCastelloes/whatsapp-pi/issues"
13
+ },
14
+ "homepage": "https://github.com/RaphaCastelloes/whatsapp-pi#readme",
7
15
  "files": [
8
16
  "whatsapp-pi.ts",
9
17
  "src"
@@ -21,6 +21,8 @@ export class SessionManager {
21
21
  private allowList: Contact[] = [];
22
22
  private blockList: Contact[] = [];
23
23
  private ignoredNumbers: Contact[] = [];
24
+ private openaiKey: string = '';
25
+ private visionModel: string = 'gpt-4o';
24
26
 
25
27
  public async ensureInitialized() {
26
28
  try {
@@ -54,6 +56,8 @@ export class SessionManager {
54
56
  this.blockList = (config.blockList || []).map(cleanContact).filter(Boolean) as Contact[];
55
57
  this.ignoredNumbers = (config.ignoredNumbers || []).map(cleanContact).filter(Boolean) as Contact[];
56
58
  this.status = config.status || 'logged-out';
59
+ this.openaiKey = config.openaiKey || '';
60
+ this.visionModel = config.visionModel || 'gpt-4o';
57
61
  } catch (error) {
58
62
  // File not found is fine
59
63
  }
@@ -65,7 +69,9 @@ export class SessionManager {
65
69
  allowList: this.allowList,
66
70
  blockList: this.blockList,
67
71
  ignoredNumbers: this.ignoredNumbers,
68
- status: this.status
72
+ status: this.status,
73
+ openaiKey: this.openaiKey,
74
+ visionModel: this.visionModel
69
75
  };
70
76
  await writeFile(this.configPath, JSON.stringify(config, null, 2));
71
77
  } catch (error) {
@@ -195,6 +201,24 @@ export class SessionManager {
195
201
  await this.saveConfig();
196
202
  }
197
203
 
204
+ getOpenaiKey(): string {
205
+ return this.openaiKey;
206
+ }
207
+
208
+ async setOpenaiKey(key: string) {
209
+ this.openaiKey = key;
210
+ await this.saveConfig();
211
+ }
212
+
213
+ getVisionModel(): string {
214
+ return this.visionModel;
215
+ }
216
+
217
+ async setVisionModel(model: string) {
218
+ this.visionModel = model;
219
+ await this.saveConfig();
220
+ }
221
+
198
222
  getAuthDir(): string {
199
223
  return this.authDir;
200
224
  }
package/whatsapp-pi.ts CHANGED
@@ -120,13 +120,38 @@ export default function (pi: ExtensionAPI) {
120
120
  }
121
121
 
122
122
  // Handle media types
123
+ let imageBuffer: Buffer | undefined;
124
+ let imageMimeType: string | undefined;
125
+
123
126
  if (msg.message.audioMessage) {
124
127
  console.log(`[WhatsApp-Pi] Transcribing audio from ${pushName}...`);
125
128
  const transcription = await audioService.transcribe(msg.message.audioMessage);
126
129
  text = `[Áudio Transcrito]: ${transcription}`;
130
+ } else if (msg.message.imageMessage) {
131
+ console.log(`[WhatsApp-Pi] Downloading image from ${pushName}...`);
132
+ try {
133
+ const { downloadContentFromMessage } = await import('@whiskeysockets/baileys');
134
+ const stream = await downloadContentFromMessage(msg.message.imageMessage, 'image');
135
+ let buffer = Buffer.from([]);
136
+ for await (const chunk of stream) {
137
+ buffer = Buffer.concat([buffer, chunk]);
138
+ }
139
+ imageBuffer = buffer;
140
+
141
+ // Normalize mime type for Cloud Code Assist / Gemini
142
+ let rawMime = msg.message.imageMessage.mimetype || 'image/jpeg';
143
+ imageMimeType = rawMime.toLowerCase().split(';')[0].trim();
144
+ if (imageMimeType === 'image/jpg') imageMimeType = 'image/jpeg';
145
+
146
+ console.log(`[WhatsApp-Pi] Image downloaded. MIME: ${imageMimeType} (original: ${rawMime}), Size: ${imageBuffer.length} bytes`);
147
+
148
+ text = msg.message.imageMessage.caption || "[Image]";
149
+ } catch (e) {
150
+ console.error(`[WhatsApp-Pi] Failed to download image:`, e);
151
+ text = "[Image (download failed)]";
152
+ }
127
153
  } else if (!text) {
128
- if (msg.message.imageMessage) text = "[Image]";
129
- else if (msg.message.videoMessage) text = "[Video]";
154
+ if (msg.message.videoMessage) text = "[Video]";
130
155
  else if (msg.message.stickerMessage) text = "[Sticker]";
131
156
  else if (msg.message.documentMessage) text = "[Document]";
132
157
  else if (msg.message.contactMessage || msg.message.contactsArrayMessage) text = "[Contact]";
@@ -137,6 +162,16 @@ export default function (pi: ExtensionAPI) {
137
162
  // Always log to console so it appears in the TUI log pane
138
163
  console.log(`[WhatsApp-Pi] ${pushName} (+${sender}): ${text}`);
139
164
 
165
+ // Use a standard delivery for ALL messages to ensure TUI consistency
166
+ if (imageBuffer && imageMimeType) {
167
+ pi.sendUserMessage([
168
+ { type: "text", text: `Mensagem de ${pushName} (+${sender}): ${text}` },
169
+ { type: "image", data: imageBuffer.toString('base64'), mimeType: imageMimeType }
170
+ ], { deliverAs: "followUp" });
171
+ } else {
172
+ pi.sendUserMessage(`Mensagem de ${pushName} (+${sender}): ${text}`, { deliverAs: "followUp" });
173
+ }
174
+
140
175
  // Handle commands
141
176
  if (text.trim().toLowerCase().startsWith('/compact')) {
142
177
  console.log(`[WhatsApp-Pi] Session compact requested by ${pushName}.`);
@@ -157,8 +192,7 @@ export default function (pi: ExtensionAPI) {
157
192
  return;
158
193
  }
159
194
 
160
- // Use a standard delivery for ALL messages to ensure TUI consistency
161
- pi.sendUserMessage(`Mensagem de ${pushName} (+${sender}): ${text}`, { deliverAs: "followUp" });
195
+
162
196
  });
163
197
 
164
198
  // Register commands