wazzup-cli 1.0.0
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/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.js +20 -0
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.js +47 -0
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +10 -0
- package/dist/commands/send.d.ts +4 -0
- package/dist/commands/send.js +76 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +31 -0
- package/dist/lib/auth.d.ts +2 -0
- package/dist/lib/auth.js +7 -0
- package/dist/lib/config.d.ts +5 -0
- package/dist/lib/config.js +16 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jensblond
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# wazzup-cli
|
|
2
|
+
|
|
3
|
+
Send WhatsApp messages from the terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g wazzup-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Log in
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
wazzup login
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Scan the QR code with WhatsApp on your phone (Linked Devices → Link a Device).
|
|
20
|
+
|
|
21
|
+
### 2. Send a message
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
wazzup send --to "+491234567890" --message "Hello from the terminal!"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. Pipe messages via stdin
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
echo "Server is down!" | wazzup send --to "+491234567890"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
### `wazzup login`
|
|
36
|
+
|
|
37
|
+
Connect to WhatsApp by scanning a QR code. Session is saved locally so you only need to do this once.
|
|
38
|
+
|
|
39
|
+
### `wazzup logout`
|
|
40
|
+
|
|
41
|
+
Delete stored session credentials.
|
|
42
|
+
|
|
43
|
+
### `wazzup send`
|
|
44
|
+
|
|
45
|
+
Send a message to a phone number.
|
|
46
|
+
|
|
47
|
+
| Option | Description |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `--to <number>` | Recipient phone number with country code (e.g. `+491234567890`) |
|
|
50
|
+
| `--message <text>` | Message text. If omitted, reads from stdin. |
|
|
51
|
+
|
|
52
|
+
### `wazzup config`
|
|
53
|
+
|
|
54
|
+
View or update configuration.
|
|
55
|
+
|
|
56
|
+
| Option | Description |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `--default-number <number>` | Set a default recipient so you can skip `--to` |
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Set a default number
|
|
62
|
+
wazzup config --default-number "+491234567890"
|
|
63
|
+
|
|
64
|
+
# Then just
|
|
65
|
+
wazzup send --message "Quick message"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## How It Works
|
|
69
|
+
|
|
70
|
+
wazzup-cli uses [Baileys](https://github.com/WhiskeySockets/Baileys), an open-source WhatsApp Web API library. It connects as a linked device to your WhatsApp account — no separate phone number or WhatsApp Business account needed.
|
|
71
|
+
|
|
72
|
+
Session credentials are stored in `~/.whatsapp-cli/auth/`.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
2
|
+
export function configCommand(options) {
|
|
3
|
+
const config = loadConfig();
|
|
4
|
+
if (options.defaultNumber) {
|
|
5
|
+
config.defaultNumber = options.defaultNumber;
|
|
6
|
+
saveConfig(config);
|
|
7
|
+
console.log(`✅ Default number set to ${options.defaultNumber}`);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
// No flags — show current config
|
|
11
|
+
if (Object.keys(config).length === 0) {
|
|
12
|
+
console.log("No configuration set yet.");
|
|
13
|
+
console.log(' wazzup config --default-number "+491234567"');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
console.log("Current configuration:");
|
|
17
|
+
if (config.defaultNumber) {
|
|
18
|
+
console.log(` Default number: ${config.defaultNumber}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loginCommand(): Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import makeWASocket, { useMultiFileAuthState, DisconnectReason, } from "@whiskeysockets/baileys";
|
|
2
|
+
import { AUTH_DIR } from "../lib/auth.js";
|
|
3
|
+
import qrcode from "qrcode-terminal";
|
|
4
|
+
import { mkdirSync } from "fs";
|
|
5
|
+
import P from "pino";
|
|
6
|
+
const logger = P({ level: "silent" });
|
|
7
|
+
async function startLogin() {
|
|
8
|
+
mkdirSync(AUTH_DIR, { recursive: true });
|
|
9
|
+
const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
|
|
10
|
+
const sock = makeWASocket({
|
|
11
|
+
auth: state,
|
|
12
|
+
logger,
|
|
13
|
+
});
|
|
14
|
+
sock.ev.on("creds.update", saveCreds);
|
|
15
|
+
sock.ev.on("connection.update", (update) => {
|
|
16
|
+
const { connection, lastDisconnect, qr } = update;
|
|
17
|
+
if (qr) {
|
|
18
|
+
console.log("\nScan this QR code with WhatsApp on your phone:\n");
|
|
19
|
+
qrcode.generate(qr, { small: true });
|
|
20
|
+
}
|
|
21
|
+
if (connection === "close") {
|
|
22
|
+
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
23
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
24
|
+
console.error("Logged out. Please run 'wazzup login' again.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
if (statusCode === DisconnectReason.restartRequired) {
|
|
28
|
+
// Retry connection after restart-required signal
|
|
29
|
+
startLogin();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const msg = lastDisconnect?.error?.message || "unknown error";
|
|
33
|
+
console.error(`Connection failed (status ${statusCode}): ${msg}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (connection === "open") {
|
|
38
|
+
console.log("✅ Successfully logged in! Session saved.");
|
|
39
|
+
console.log("You can now use 'wazzup send' to send messages.");
|
|
40
|
+
setTimeout(() => process.exit(0), 1000);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export async function loginCommand() {
|
|
45
|
+
console.log("Connecting to WhatsApp...");
|
|
46
|
+
await startLogin();
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function logoutCommand(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { rmSync, existsSync } from "fs";
|
|
2
|
+
import { AUTH_DIR } from "../lib/auth.js";
|
|
3
|
+
export function logoutCommand() {
|
|
4
|
+
if (!existsSync(AUTH_DIR)) {
|
|
5
|
+
console.log("No active session found. Already logged out.");
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
rmSync(AUTH_DIR, { recursive: true, force: true });
|
|
9
|
+
console.log("✅ Logged out. Session credentials deleted.");
|
|
10
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import makeWASocket, { useMultiFileAuthState, DisconnectReason, } from "@whiskeysockets/baileys";
|
|
2
|
+
import { AUTH_DIR, isAuthenticated } from "../lib/auth.js";
|
|
3
|
+
import { loadConfig } from "../lib/config.js";
|
|
4
|
+
import P from "pino";
|
|
5
|
+
const logger = P({ level: "silent" });
|
|
6
|
+
function formatPhoneNumber(phone) {
|
|
7
|
+
// Remove +, spaces, dashes -> append @s.whatsapp.net
|
|
8
|
+
const cleaned = phone.replace(/[\s\-+]/g, "");
|
|
9
|
+
return `${cleaned}@s.whatsapp.net`;
|
|
10
|
+
}
|
|
11
|
+
async function readStdin() {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
if (process.stdin.isTTY) {
|
|
14
|
+
resolve("");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let data = "";
|
|
18
|
+
process.stdin.setEncoding("utf-8");
|
|
19
|
+
process.stdin.on("data", (chunk) => (data += chunk));
|
|
20
|
+
process.stdin.on("end", () => resolve(data.trim()));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export async function sendCommand(options) {
|
|
24
|
+
// Resolve recipient
|
|
25
|
+
const config = loadConfig();
|
|
26
|
+
const recipient = options.to || config.defaultNumber;
|
|
27
|
+
if (!recipient) {
|
|
28
|
+
console.error("Error: No recipient specified. Use --to or set a default number:");
|
|
29
|
+
console.error(' wazzup config --default-number "+491234567"');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
// Resolve message (flag or stdin)
|
|
33
|
+
let message = options.message;
|
|
34
|
+
if (!message) {
|
|
35
|
+
message = await readStdin();
|
|
36
|
+
}
|
|
37
|
+
if (!message) {
|
|
38
|
+
console.error("Error: No message specified. Use --message or pipe via stdin.");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
// Check auth
|
|
42
|
+
if (!isAuthenticated()) {
|
|
43
|
+
console.error("Error: Not logged in. Run 'wazzup login' first.");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
|
|
47
|
+
const sock = makeWASocket({
|
|
48
|
+
auth: state,
|
|
49
|
+
logger,
|
|
50
|
+
});
|
|
51
|
+
sock.ev.on("creds.update", saveCreds);
|
|
52
|
+
const jid = formatPhoneNumber(recipient);
|
|
53
|
+
sock.ev.on("connection.update", async (update) => {
|
|
54
|
+
const { connection, lastDisconnect } = update;
|
|
55
|
+
if (connection === "close") {
|
|
56
|
+
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
57
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
58
|
+
console.error("Session expired. Please run 'wazzup login' again.");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
console.error("Connection closed unexpectedly.");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (connection === "open") {
|
|
65
|
+
try {
|
|
66
|
+
await sock.sendMessage(jid, { text: message });
|
|
67
|
+
console.log(`✅ Message sent to ${recipient}`);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error("Failed to send message:", err);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
setTimeout(() => process.exit(0), 1000);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { loginCommand } from "./commands/login.js";
|
|
4
|
+
import { logoutCommand } from "./commands/logout.js";
|
|
5
|
+
import { sendCommand } from "./commands/send.js";
|
|
6
|
+
import { configCommand } from "./commands/config.js";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("wazzup")
|
|
10
|
+
.description("Send WhatsApp messages from the terminal")
|
|
11
|
+
.version("1.0.0");
|
|
12
|
+
program
|
|
13
|
+
.command("login")
|
|
14
|
+
.description("Log in by scanning a QR code")
|
|
15
|
+
.action(loginCommand);
|
|
16
|
+
program
|
|
17
|
+
.command("logout")
|
|
18
|
+
.description("Log out and delete stored session")
|
|
19
|
+
.action(logoutCommand);
|
|
20
|
+
program
|
|
21
|
+
.command("send")
|
|
22
|
+
.description("Send a message")
|
|
23
|
+
.option("--to <number>", "Recipient phone number (with country code, e.g. +491234567)")
|
|
24
|
+
.option("--message <text>", "Message text (or pipe via stdin)")
|
|
25
|
+
.action(sendCommand);
|
|
26
|
+
program
|
|
27
|
+
.command("config")
|
|
28
|
+
.description("View or set configuration")
|
|
29
|
+
.option("--default-number <number>", "Set default recipient number")
|
|
30
|
+
.action(configCommand);
|
|
31
|
+
program.parse();
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
export const AUTH_DIR = join(homedir(), ".whatsapp-cli", "auth");
|
|
5
|
+
export function isAuthenticated() {
|
|
6
|
+
return existsSync(AUTH_DIR) && existsSync(join(AUTH_DIR, "creds.json"));
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".whatsapp-cli");
|
|
5
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
6
|
+
export function loadConfig() {
|
|
7
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
export function saveConfig(config) {
|
|
14
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
15
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
16
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wazzup-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Send WhatsApp messages from the terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "jensblond",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/jensblond/wazzup-cli.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/jensblond/wazzup-cli/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/jensblond/wazzup-cli#readme",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"whatsapp",
|
|
18
|
+
"cli",
|
|
19
|
+
"terminal",
|
|
20
|
+
"messaging",
|
|
21
|
+
"send"
|
|
22
|
+
],
|
|
23
|
+
"bin": {
|
|
24
|
+
"wazzup": "dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"dev": "tsx src/index.ts",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@whiskeysockets/baileys": "^7.0.0-rc.9",
|
|
36
|
+
"commander": "^13.1.0",
|
|
37
|
+
"pino": "^10.3.1",
|
|
38
|
+
"qrcode-terminal": "^0.12.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.13.1",
|
|
42
|
+
"tsx": "^4.19.2",
|
|
43
|
+
"typescript": "^5.7.3"
|
|
44
|
+
}
|
|
45
|
+
}
|