feat(wallet-cli): Add wallet CLI with daemon support#8446
Open
rekmarks wants to merge 21 commits intofeat/wallet-libraryfrom
Open
feat(wallet-cli): Add wallet CLI with daemon support#8446rekmarks wants to merge 21 commits intofeat/wallet-libraryfrom
rekmarks wants to merge 21 commits intofeat/wallet-libraryfrom
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This comment was marked as resolved.
This comment was marked as resolved.
Base automatically changed from
rekm/wallet-library-tweaks
to
feat/wallet-library
April 14, 2026 10:50
…rocess Adds a daemon that runs a Wallet instance as a detached background process, communicating over JSON-RPC via Unix domain sockets. This mirrors the architecture of kernel-cli's daemon. Infrastructure (src/daemon/): - socket-line: newline-delimited socket I/O - rpc-socket-server: generic Unix socket JSON-RPC server - daemon-client: one-shot JSON-RPC client with retry - daemon-entry: standalone entry point for the spawned process - daemon-spawn: spawns daemon-entry as detached child - stop-daemon: shared stop logic with escalation - wallet-factory: creates configured Wallet from config - utils, paths, types: process utilities and path resolution Commands (src/commands/daemon/): - start: start daemon (--infura-project-id or INFURA_PROJECT_ID env) - stop: stop daemon (RPC shutdown -> SIGTERM -> SIGKILL) - status: check daemon status - purge: stop daemon and delete all state files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9 test files covering all daemon infrastructure: paths, socket-line, utils, rpc-socket-server, daemon-client, stop-daemon, wallet-factory, daemon-entry, and daemon-spawn. 96 tests total. Config changes: - jest.config.js: exclude commands/ from coverage (not yet tested) - eslint.config.mjs: disable n/no-process-env and n/no-sync for wallet-cli test files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire sendSignal into stopDaemon so EPERM errors from process.kill are not silently treated as successful stops. Remove unused withTimeout utility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thread wallet password and secret recovery phrase through the daemon startup chain so the wallet is initialized with an imported SRP. - Export importSecretRecoveryPhrase from @metamask/wallet - Add --password and --srp required flags to `daemon start` - Pass MM_WALLET_PASSWORD / MM_WALLET_SRP env vars to spawned daemon - Make createWallet async; call importSecretRecoveryPhrase after init Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a `daemon call` CLI command that forwards arbitrary messenger action calls to the running wallet daemon over JSON-RPC. The daemon registers a `call` RPC handler that invokes `wallet.messenger.call()` with the provided action name and arguments. Usage: wallet-cli daemon call AccountsController:listAccounts wallet-cli daemon call NetworkController:getState --timeout 10000 Also fixes lint errors in wallet-factory.ts (missing return types). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove placeholder index.ts and library exports (CLI-only package) - Add yarn constraints exception for wallet-cli exports - Document intentional `as any` messenger dispatch in daemon-entry - Remove duplicate socketPath param from ensureDaemon - Remove unused logPath from DaemonSpawnConfig - Add 30s server-side socket read timeout in rpc-socket-server - Handle sendCommand throwing in status command - Have purge remove entire data directory - Tighten isRpcError to require both code and message - Fix waitFor to return false on timeout instead of re-checking - Clarify multi-request rejection test assertions - Document password/srp CLI flags as testing-only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Destructuring null params (when a request omits the params field) would throw a confusing TypeError. Add a runtime check that params is a non-empty array before destructuring. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98a9392 to
1c1a4bf
Compare
Member
Author
|
@SocketSecurity ignore npm/jake@10.9.4 Transitive via |
… typedoc and JSDoc - Await rm calls in shutdown finally block via Promise.all and in error cleanup path so callers know cleanup is complete - Use rpcErrors.parse() (-32700) for JSON.parse failures per JSON-RPC spec - Update typedoc.json entry points after index.ts removal - Move CONNECTION_TIMEOUT_MS above JSDoc so doc attaches to the function Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reject params where the first element is not a string, preventing confusing downstream errors from messenger.call. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5951891. Configure here.
- Log errors in catch blocks instead of silently swallowing them across
daemon-entry, stop-daemon, and rpc-socket-server
- Make shutdown cleanup independent: handle.close(), wallet.destroy(),
and file removal each run in their own try/catch so one failure
doesn't skip the others
- Add default 30s timeout to sendCommand to prevent indefinite hangs
- Use JsonRpcResponse from @metamask/utils as handleRequest return type
- Add shared DaemonStatusInfo type for the getStatus RPC contract
- Change RpcHandler to allow void return, document null params
- Filter expected socket errors (EPIPE/ECONNRESET), log unexpected ones
- Only suppress ENOENT in socket unlink, re-throw other errors
- Clean up socket file (not just PID file) when stopDaemon succeeds
- Add child.on('error') handler in daemon-spawn for spawn failures
- Switch makeLogger from sync appendFileSync to async appendFile
- Remove socketPath from DaemonSpawnConfig, derive from dataDir
- Include error details in status command catch block
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the required --force flag with an interactive y/N confirmation prompt using @inquirer/confirm. The --force flag now skips the prompt instead of being mandatory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Introduces an
oclifCLI for@metamask/wallet. It is more or less a port of the Ocap Kernel equivalent.Usage
First,
cd packages/wallet-cli.Then, to start the daemon:
Try calling an available controller action:
Actions params must be specified as a stringified JSON array:
When done, stop the daemon and clean up:
Summary
wallet-clipackage scaffolded with oclif (mmbinary)@metamask/walletinstance as a detached background process, communicating over JSON-RPC via Unix domain socketsstart,stop,status,purge,callcallcommand dispatches arbitrary messenger actions to the running daemon (e.g.mm daemon call AccountsController:listAccounts)Note
High Risk
Adds a new CLI/daemon that starts a wallet instance and exposes arbitrary messenger actions over a local Unix socket, plus lifecycle management (spawn/stop/purge); mistakes here could impact key handling and local security expectations.
Overview
Introduces a new
@metamask/wallet-clipackage (Oclifmmbinary) that can spawn and manage a detached wallet daemon and communicate with it over newline-delimited JSON-RPC on a Unix domain socket.Implements daemon lifecycle and RPC plumbing: a socket server with
getStatus,shutdown, and a genericcallmethod that forwards arbitrary messenger action names/args, along with CLI commandsdaemon start|stop|status|purge|calland supporting utilities/tests.Wires the package into the monorepo (TypeScript refs, ESLint overrides, README dependency graph, CODEOWNERS/
teams.json, Yarn workspace rules/lockfile), and exportsimportSecretRecoveryPhrasefrom@metamask/walletfor daemon initialization.Reviewed by Cursor Bugbot for commit f69d1cc. Bugbot is set up for automated code reviews on this repo. Configure here.