Skip to content

feat(whatsapp-bridge): add phone-number pairing code support - #17907

Open
keiravoss94 wants to merge 2 commits into
NousResearch:mainfrom
pebble-tech:upstream-pr/whatsapp-pair-with-number
Open

feat(whatsapp-bridge): add phone-number pairing code support#17907
keiravoss94 wants to merge 2 commits into
NousResearch:mainfrom
pebble-tech:upstream-pr/whatsapp-pair-with-number

Conversation

@keiravoss94

@keiravoss94 keiravoss94 commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds --pair-with-number <e164> to the WhatsApp bridge for Baileys requestPairingCode() onboarding, alongside the existing --pair-only QR flow. Operators who cannot scan a QR code can link the bridge using an 8-character pairing code instead.

Related Issue

Fixes #

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • scripts/whatsapp-bridge/pairing-args.js — parse/validate --pair-with-number, format pairing codes for display
  • scripts/whatsapp-bridge/pairing-args.test.mjs — unit tests for parsing, validation, and formatting
  • scripts/whatsapp-bridge/bridge.js — request/display pairing code via sock.requestPairingCode(), avoid duplicate requests on reconnect
  • scripts/whatsapp-bridge/package.json — add npm test with explicit test file paths

How to Test

  1. cd scripts/whatsapp-bridge && npm test
  2. Run the bridge with --pair-with-number +15551234567 (use your own E.164 number) and confirm an 8-character hyphenated code is printed with linking steps
  3. Confirm --pair-only QR flow still works unchanged

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

N/A — delete this section otherwise.

Screenshots / Logs

Pairing output example:

Pairing code: ABCD-EFGH
On your phone: WhatsApp → Linked devices → Link with phone number instead → enter the code above.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/whatsapp WhatsApp Business adapter labels Apr 30, 2026
Adds a new pairing flow using Baileys' requestPairingCode() as an
alternative to QR-scan onboarding. A WhatsApp account can be linked by
passing a phone number and reading an 8-character code on the device,
avoiding QR scanning via camera or screenshare when that is awkward.

Usage:
  node bridge.js --pair-with-number "+15551234567"

Output:
  Pairing code: ABCD-EFGH

  On your phone:
    1. Open WhatsApp
    2. Settings > Linked Devices > Link a Device > "Link with phone
       number instead"
    3. Enter: ABCD-EFGH

  Waiting for pairing to complete...

The existing --pair-only (QR) flow remains intact and is the fallback
when --pair-with-number isn't provided. If both flags are passed,
phone-number flow takes precedence with a warning.

Argument parsing/validation factored into pairing-args.js with unit
tests; phone numbers are validated as E.164 and stripped to digits-only
before being passed to Baileys per requestPairingCode signature.
@vKongv
vKongv force-pushed the upstream-pr/whatsapp-pair-with-number branch from c379af0 to bdb41cb Compare May 13, 2026 07:52
@vKongv
vKongv requested a review from a team May 13, 2026 07:52
@austinpickett
austinpickett requested a review from Copilot May 19, 2026 12:15

@austinpickett austinpickett left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use .github/PULL_REQUEST_TEMPLATE.md and resolve Copilot comments

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for WhatsApp “link with phone number” onboarding in the scripts/whatsapp-bridge Node bridge by introducing a new --pair-with-number <e164> CLI flag and emitting a Baileys pairing code, alongside the existing QR-based --pair-only flow.

Changes:

  • Added --pair-with-number parsing + phone-number validation utilities (pairing-args.js) with Node test coverage.
  • Updated bridge.js to request/display a pairing code via sock.requestPairingCode() and to avoid duplicate requests across reconnects.
  • Added an npm test script for the bridge package.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
scripts/whatsapp-bridge/bridge.js Adds phone-number pairing mode, pairing-code request flow, and exit behavior for pairing runs.
scripts/whatsapp-bridge/pairing-args.js Introduces parsing/validation helpers and pairing-code display formatting.
scripts/whatsapp-bridge/pairing-args.test.mjs Adds unit tests for parsing/validation/formatting helpers.
scripts/whatsapp-bridge/package.json Adds a test script for running the bridge’s Node tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +14
/** E.164-like phone number for pairing: country code plus 10–15 digits total. */
export const E164_PAIRING_REGEX = /^\+?[1-9]\d{9,14}$/;

/**
* @param {string} raw - CLI value passed to `--pair-with-number`
* @returns {{ ok: true, digits: string } | { ok: false, error: string }}
*/
export function validateE164ForPairing(raw) {
const s = String(raw ?? '').trim();
if (!E164_PAIRING_REGEX.test(s)) {
return {
ok: false,
error: 'Invalid phone number. Use E.164 (e.g. +15551234567): country code, digits only besides an optional leading +.',
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the validation error to state the 10–15 digit requirement explicitly instead of the generic "Use E.164" wording, matching E164_PAIRING_REGEX and the file comment.

Comment thread scripts/whatsapp-bridge/package.json Outdated
"scripts": {
"start": "node bridge.js"
"start": "node bridge.js",
"test": "node --test ./*.test.mjs"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed npm test to pass explicit test file paths (pairing-args.test.mjs allowlist.test.mjs) so Node runs them without shell glob expansion.

Clarify the 10–15 digit phone requirement in validation errors and
list test files explicitly so npm test works on Windows.
@vKongv
vKongv requested a review from a team May 29, 2026 13:38
@vKongv

vKongv commented May 29, 2026

Copy link
Copy Markdown
Contributor

Addressed review feedback in 888d8f8: PR body now follows .github/PULL_REQUEST_TEMPLATE.md, Copilot threads replied to (E.164 error wording + explicit npm test paths). Please re-review when convenient.

@vKongv

vKongv commented May 29, 2026

Copy link
Copy Markdown
Contributor

@austinpickett check again

thamam pushed a commit to thamam/hermes-agent that referenced this pull request Jun 27, 2026
…uestPairingCode

Adds an opt-in --pair-phone=<E.164> flag to scripts/whatsapp-bridge/bridge.js
that switches first-time pairing from QR scan to WhatsApp phone-number
pairing code (8 chars). QR mode remains the default — no behaviour change
for existing installs.

Motivation: pairing a remote EC2-hosted Hermes agent via QR over SSH/journal
is awkward; Baileys exposes the native alternative via sock.requestPairingCode().

See PR body for full details.

# Status: requires-upstream-merge
# Tracks: NousResearch#45585
# Note: collaborator called PR NousResearch#45585 a duplicate of upstream PR NousResearch#17907;
#   either landing on upstream main causes the auto-drop probe to succeed
#   and this patch is removed from the series next cycle.
# Tests-that-must-pass-without-patch:
#   tests/scripts/whatsapp-bridge/test_pair_phone.py
thamam pushed a commit to thamam/hermes-agent that referenced this pull request Jul 6, 2026
…uestPairingCode

Adds an opt-in --pair-phone=<E.164> flag to scripts/whatsapp-bridge/bridge.js
that switches first-time pairing from QR scan to WhatsApp phone-number
pairing code (8 chars). QR mode remains the default — no behaviour change
for existing installs.

Motivation: pairing a remote EC2-hosted Hermes agent via QR over SSH/journal
is awkward; Baileys exposes the native alternative via sock.requestPairingCode().

See PR body for full details.

# Status: requires-upstream-merge
# Tracks: NousResearch#45585
# Note: collaborator called PR NousResearch#45585 a duplicate of upstream PR NousResearch#17907;
#   either landing on upstream main causes the auto-drop probe to succeed
#   and this patch is removed from the series next cycle.
# Tests-that-must-pass-without-patch:
#   tests/scripts/whatsapp-bridge/test_pair_phone.py
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the phone-number pairing implementation and for resolving the prior validation and cross-platform test-script feedback.

Problems

  • Current supported onboarding does not pass the new bridge flag: the CLI wizard invokes only --pair-only at hermes_cli/main.py:2644-2653, and dashboard onboarding invokes --pair-only --pair-json at hermes_cli/web_server.py:7038-7055. The feature therefore needs an operator-facing selection/input path rather than only a bridge-local CLI flag.
  • The PR predates 4f620a0bbc11, which added structured dashboard pairing. Current --pair-json behavior emits QR/connected events in scripts/whatsapp-bridge/bridge.js:382-465; the proposed code prints the phone pairing code but does not provide an equivalent structured event.
  • pairing-args.test.mjs covers parsing/formatting, but not the socket lifecycle or JSON protocol.

Suggested changes

  • Rework the salvage against the current bridge and onboarding paths: retain QR as default, add an explicit phone-number selection/input path, and emit a structured pairing-code event for dashboard consumers.
  • Add lifecycle tests for request timing/deduplication, QR suppression, and the structured code event.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 12, 2026

@GottZ GottZ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

Summary

Three PRs address phone-number pairing through Baileys requestPairingCode(): #17907 provides the most complete bridge-local implementation with argument validation and tests, while #20798 and #45585 implement narrower bridge.js-only variants. None completes the current CLI/dashboard onboarding path or emits the structured pairing-code event required by the dashboard protocol.

Related pull requests

  • #17907 related — (+199/-8) — retain as the consolidation base, but not merge-ready: the diff adds validated --pair-with-number parsing, pairing-code formatting, reconnect deduplication, and unit tests, directly implementing the underlying capability. The earlier CHANGES_REQUESTED review was reportedly addressed, but the later contributor keep_open review identifies still-blocking current-main gaps: no CLI/dashboard selection path, no --pair-json code event, and no lifecycle/protocol coverage.
  • #20798 [closed] duplicate — (+67/-11) — closed duplicate, still relevant as a reference implementation: it adds requestPairingCode(), health-state exposure, environment/custom-code options, and unrelated outbound JID normalization, but has no dedicated validation or tests and does not integrate phone pairing into current onboarding. Its bridge-only implementation substantially overlaps #17907, and a contributor explicitly identified it as a duplicate of #17907.
  • #45585 duplicate — (+29/-1) — close as a duplicate after preserving any useful timing evidence: despite the APPROVED non-contributor review and the contributor keep_open review on #45585, the diff's documented --pair-phone=<E.164> form cannot be parsed by getArg(), emits only plain console output rather than the dashboard's structured JSON event, and adds no regression coverage. It implements the same bridge-local requestPairingCode() path as #17907 with less validation and testing.

Duplicates

#17907, #20798, and #45585 substantially duplicate the same phone-number pairing capability; #20798 and #45585 are narrower bridge.js-only alternatives to #17907.

Suggested consolidation

Consolidate on #17907, but do not merge it until the blocking contributor review is addressed by rebasing onto current main, adding explicit CLI/dashboard phone-number selection, emitting a structured --pair-json pairing-code event, and covering the socket lifecycle and JSON protocol. Then close #45585 as a duplicate; keep already-closed #20798 linked as a duplicate/reference implementation rather than reopening it.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    subgraph Dup17907 ["PRs duplicating each other"]
        P17907["PR #17907 (open)"]
        P20798["PR #20798 (closed)"]
        P45585["PR #45585 (open)"]
    end
    class P17907 open
    class P20798 closed
    class P45585 open
    class P17907 target
    click P17907 "https://github.com/NousResearch/hermes-agent/pull/17907"
    click P20798 "https://github.com/NousResearch/hermes-agent/pull/20798"
    click P45585 "https://github.com/NousResearch/hermes-agent/pull/45585"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed or no verify verdict yet (state tag in the node label).

Cross-PR triage: Reviewed 3 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 21 kB of PR diffs, 8 kB of issue/PR text, 6 kB of discussion (10 comments), 3 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/whatsapp WhatsApp Business adapter sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants