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 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,3 @@
1
+ export declare function configCommand(options: {
2
+ defaultNumber?: string;
3
+ }): void;
@@ -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,4 @@
1
+ export declare function sendCommand(options: {
2
+ to?: string;
3
+ message?: string;
4
+ }): Promise<void>;
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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();
@@ -0,0 +1,2 @@
1
+ export declare const AUTH_DIR: string;
2
+ export declare function isAuthenticated(): boolean;
@@ -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,5 @@
1
+ export interface AppConfig {
2
+ defaultNumber?: string;
3
+ }
4
+ export declare function loadConfig(): AppConfig;
5
+ export declare function saveConfig(config: AppConfig): void;
@@ -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
+ }