fix(whatsapp): render compact pairing QR and split gateway diagnostics#4607
Conversation
In-sandbox WhatsApp pairing delegated QR rendering to the upstream
@openclaw/whatsapp plugin, which draws the Linked-Devices QR at full size
via qrcode-terminal. On DGX Spark terminals the code filled 50-80+ rows and
hundreds of columns, so it could not be captured in one phone-camera frame.
The reported "1008 abnormal closure" then surfaced as raw gateway text with
no separation from the QR problem.
NemoClaw owns the user-facing pairing workflow, so wrap the supported path:
- Add a NemoClaw-owned preload (whatsapp-qr-compact.js) that forces
qrcode-terminal into the same `{ small: true }` half-block mode the
host-side WeChat QR path already uses, quartering the rendered area
without changing the payload. It hooks Module._load so the plugin's
nested copy is patched, and is idempotent.
- Install it only when WhatsApp is configured and inject it for the single
`openclaw channels login --channel whatsapp` invocation via the sandbox
guard — the gateway never renders the QR, so it stays off global
NODE_OPTIONS. Validate it under validate_tmp_permissions (root:444).
- Validate OPENCLAW_GATEWAY_URL before pairing and, on a non-zero login
exit, print retry/diagnostic guidance that distinguishes a gateway close
(e.g. 1008) from a QR-size issue.
Add a unit test for the renderer (forces small, bounds lines, idempotent)
and the guard branch (gateway preflight, preload injection, close
diagnostics), plus a live e2e check that the preload + guard wiring land in
the sandbox. Carries a documented removal criterion for when upstream
renders a scan-friendly QR by default.
Fixes NVIDIA#4522
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds a Node.js preload to force compact WhatsApp QR rendering, installs and optionally injects the preload into the openclaw login guard, updates sandbox help text, and adds unit/e2e tests validating rendering, idempotency, and guard wiring. ChangesWhatsApp Compact QR Pairing
Sequence DiagramsequenceDiagram
participant Startup as NemoClaw Startup
participant InstallFunc as install_whatsapp_qr_compact()
participant TmpPreload as /tmp/nemoclaw-whatsapp-qr-compact.js
participant OpenClawGuard as openclaw channels login guard
participant NodeRuntime as spawned openclaw process (NODE_OPTIONS)
participant QRLibrary as qrcode-terminal
Startup->>InstallFunc: call during service init
InstallFunc->>TmpPreload: create preload file in /tmp
OpenClawGuard->>OpenClawGuard: validate OPENCLAW_GATEWAY_URL
OpenClawGuard->>NodeRuntime: set NODE_OPTIONS --require /tmp/...
NodeRuntime->>QRLibrary: require('qrcode-terminal') (preload intercepts)
QRLibrary->>NodeRuntime: generate() enforced with small:true
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/e2e/test-messaging-providers.sh`:
- Around line 919-924: The current check uses whatsapp_qr_guard_wiring and only
greps for 'nemoclaw-whatsapp-qr-compact.js' which can miss whether NODE_OPTIONS
actually injects it; update the assertion to grep for the exact require flag
pattern (e.g., "--require $_whatsapp_qr_compact" or the resolved value of
_whatsapp_qr_compact) via sandbox_exec so the test verifies the actual --require
injection string, adjust the variable used (whatsapp_qr_guard_wiring) and the
subsequent conditional message to reflect the check for the --require injection
rather than just the filename.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c228f084-608a-4055-b508-f89bfb45772f
📒 Files selected for processing (5)
nemoclaw-blueprint/scripts/whatsapp-qr-compact.jsscripts/nemoclaw-start.shsrc/lib/sandbox/channels.tstest/e2e/test-messaging-providers.shtest/whatsapp-qr-compact.test.ts
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
CodeRabbit flagged that the M-WA6c guard-wiring check grepped only for the preload filename, which also appears in the install banner and the literal path assignment — so it would pass even if the NODE_OPTIONS `--require` injection regressed. Grep the emitted proxy-env file for the literal `--require $_whatsapp_qr_compact` token so the test pins the actual injection. Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 1991-1999: The current guard only checks OPENCLAW_GATEWAY_URL is
non-empty; add a validation step before calling openclaw (where openclaw
channels login is used) to reject malformed or local gateway URLs. After the
existing empty check, validate OPENCLAW_GATEWAY_URL with a shell-safe regex
(e.g. require a scheme like http:// or https:// and a non-local host), and also
reject localhost/127.0.0.1 variants; on failure print a clear error (same style
as existing messages) and return 1 so openclaw is never invoked with a bad URL.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: ef067405-7d5d-4b8e-bfbb-9a9ee7e3ad0e
📒 Files selected for processing (5)
nemoclaw-blueprint/scripts/whatsapp-qr-compact.jsscripts/nemoclaw-start.shsrc/lib/sandbox/channels.tstest/e2e/test-messaging-providers.shtest/whatsapp-qr-compact.test.ts
CodeRabbit noted the gateway preflight only checked OPENCLAW_GATEWAY_URL for non-emptiness, so a clobbered value (e.g. `foo` or an `http://` typo) would still reach `openclaw channels login` and fail inside the login as the same ambiguous close this guard exists to separate from QR rendering. Validate the scheme up front: the OpenClaw gateway is a WebSocket endpoint (set to ws://127.0.0.1:<port> at boot), so accept only ws:// and wss:// and reject anything else with a gateway/env diagnostic. (CodeRabbit's literal suggestion to require http(s):// and reject 127.0.0.1 would have rejected the real local ws:// gateway URL, so the scheme check is adapted to this stack.) Add parametrized guard tests covering rejected and accepted schemes. Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary - Adds the v0.0.56 release notes section with links to the deeper docs pages for installer, status, inference, messaging, policy, and lifecycle changes. - Updates source docs for the remaining release-prep gaps around `uv` in the PyPI preset, compact WhatsApp pairing guidance, and `nemoclaw inference set` command boundaries. - Refreshes generated `nemoclaw-user-*` skills and removes skipped experimental command terms from generated skill surfaces. ## Source summary - #4613 -> `docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Documents that public installs and `nemoclaw update` follow the maintained `lkg` tag by default. - #4419 -> `docs/about/release-notes.mdx`: Notes that non-interactive Linux installs can reactivate Docker group membership and continue in one installer run when `sg docker` is available. - #4550 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Captures live sandbox agent-version probing for status, connect, and upgrade checks. - #4609 -> `docs/inference/use-local-inference.mdx`, `docs/about/release-notes.mdx`: Captures the GPU Docker-driver host-network local-inference reachability gate. - #4607 -> `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Documents compact WhatsApp QR pairing guidance and gateway/session diagnostics. - #4582 -> `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Reflects Slack credential validation before enabling the channel. - #4554 -> `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/troubleshooting.mdx`, `docs/about/release-notes.mdx`: Keeps Telegram allowlist alias guidance in the generated user skills and release notes. - #4563 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Includes the new `nemoclaw <name> skill remove <skill>` command in command docs and release notes. - #4566 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Documents the `nemoclaw inference set` redirect boundary when `--provider` or `--model` is missing. - #4323 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Captures per-sandbox status JSON support. - #4506 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Captures debug command sandbox-name validation and safer tarball writing. - #4569 -> `docs/network-policy/integration-policy-examples.mdx`, `docs/about/release-notes.mdx`: Documents that the `pypi` preset allows `/usr/local/bin/uv`. - #4579 -> `docs/network-policy/integration-policy-examples.mdx`, `docs/about/release-notes.mdx`: Captures observable Jira preset validation guidance. - #4229 -> `docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Documents user-data preservation defaults for uninstall. - #4399 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Captures CPU-only sandbox intent preservation across rebuilds. - #4058 -> `docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Captures safer snapshot restore behavior around existing destinations. - #4155 and #4460 -> skipped by `docs/.docs-skip`: Removed skipped experimental command terms from source docs and generated skill evals instead of documenting those features. ## Verification - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx` - `npm run docs` (passes; Fern reports the pre-existing light-mode accent contrast warning) - `rg "permissive mode|shields down|shields up|shields status|config rotate-token|rotate-token" .agents/skills` (no matches) - `npm run build:cli` (run to refresh local CLI artifacts for the pre-push TypeScript hook) - Commit hooks passed, including `NEMOCLAW_* env-var documentation gate`, `Verify docs-to-skills output`, `markdownlint-cli2`, `gitleaks`, and `Test (skills YAML)`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Expanded Model Router setup with YAML examples, flow diagrams, and credential handling; strengthened agent-config immutability and integrity guidance; messaging channels updated (Telegram aliases, WhatsApp pairing/diagnostics); CLI docs revised (GPU detection, inference set behavior, uninstall/rebuild preservation); overview rebranded to NemoClaw and added v0.0.56 release notes. * **New Features** * Added `nemoclaw <name> channels status` (messaging diagnostics, JSON); added `nemoclaw <name> skill remove`; Hermes no longer marked experimental; DGX Spark quickstart sandbox-name note. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
NemoClaw delegated in-sandbox WhatsApp QR pairing to the upstream
@openclaw/whatsappplugin, which renders the Linked-Devices QR at full size — on DGX Spark terminals it filled 50–80+ rows and hundreds of columns and could not be scanned in one phone-camera frame, and the reported1008 abnormal closuresurfaced as raw gateway text with no separation from the QR problem. This PR makes the NemoClaw-supported pairing path render a compact QR and diagnose gateway close/error conditions separately from QR rendering.Related Issue
Fixes #4522
Changes
nemoclaw-blueprint/scripts/whatsapp-qr-compact.js) that forcesqrcode-terminalinto the same{ small: true }half-block mode the host-side WeChat QR path already uses (src/ext/wechat/login.ts), roughly quartering the rendered area without changing the QR payload. It hooksModule._loadso the plugin's nested copy is patched and is idempotent.openclaw channels login --channel whatsappinvocation via the sandboxopenclaw()guard — the gateway never renders the pairing QR, so it stays off globalNODE_OPTIONS. The preload is validated undervalidate_tmp_permissions(root:444) so the sandbox user cannot tamper with aNODE_OPTIONS-injected file.OPENCLAW_GATEWAY_URLbefore pairing, and on a non-zero login exit print retry/diagnostic guidance that distinguishes a gateway close (e.g.1008) from a QR-size issue.M-WA6b/M-WA6c) that the preload + guard wiring land in the sandbox.Type of Change
Verification
npm testpasses (cli + plugin projects; the only failures were pre-existing 5000ms timeouts intest/e2e-scenario/framework-tests/*that spawn real bash and flake under parallel load — they pass in isolation and are unrelated to this change)test/whatsapp-qr-compact.test.ts,src/lib/sandbox/channels.test.ts,src/lib/sandbox/whatsapp-diagnostics.test.ts,test/nemoclaw-start.test.ts,npm run typecheck:cli— all greenLive note: no live WhatsApp sandbox/account was available, so the compact-QR rendering and gateway diagnostics are validated by hermetic tests around the renderer and the sandbox guard; the live
channels login --channel whatsappscan was not exercised end-to-end. The compact renderer assumes the bundled plugin usesqrcode-terminal(the dominant renderer, same lib as the WeChat path); the gateway validation/diagnostics apply regardless.Signed-off-by: Yimo Jiang yimoj@nvidia.com
Summary by CodeRabbit
New Features
Documentation
Tests