Skip to content

feat(wallet-cli): add daemon JSON-RPC socket transport#9108

Open
sirtimid wants to merge 3 commits into
mainfrom
sirtimid/wallet-cli-daemon-transport
Open

feat(wallet-cli): add daemon JSON-RPC socket transport#9108
sirtimid wants to merge 3 commits into
mainfrom
sirtimid/wallet-cli-daemon-transport

Conversation

@sirtimid

@sirtimid sirtimid commented Jun 12, 2026

Copy link
Copy Markdown
Member

Explanation

@metamask/wallet-cli runs a background daemon that hosts a @metamask/wallet instance; the CLI talks to it over a Unix socket. This PR adds that transport layer. It is purely additive plumbing — no mm subcommand consumes it yet (commands land in a follow-up), so there is no user-visible behavior change.

  • socket-linewriteLine/readLine for newline-delimited framing over a net.Socket, with an optional read timeout and listener cleanup.
  • daemon-clientsendCommand opens a connection, writes one JSON-RPC request, reads one response, and closes; it correlates the response id with the request and retries once on transient connection errors (ECONNREFUSED/ECONNRESET). pingDaemon is a lightweight getStatus health probe that distinguishes "no daemon" (absent) from "daemon present but unreachable", classifying the latter by failure mode (refused / timeout / permission / protocol / other).
  • rpc-socket-serverstartRpcSocketServer listens on a Unix socket and dispatches one JSON-RPC request per connection to a handler map. It intercepts a built-in shutdown method, enforces one-request-per-connection, times out idle connections, and returns a close() handle.
  • daemon-spawnensureDaemon spawns a detached daemon process and polls until the socket is responsive, refusing to take over a wedged or foreign-owned socket. Resolves the entry point from dist (prod) or src via tsx (dev).
  • stop-daemonstopDaemon escalates from a graceful shutdown RPC through SIGTERM to SIGKILL, then removes the PID and socket files best-effort.
  • promptsconfirmPurge wraps the ESM-only @inquirer/confirm via dynamic import.
  • types — adds RpcHandler, RpcHandlerMap, DaemonStatusInfo, and DaemonSpawnConfig.

Adds @inquirer/confirm and @metamask/rpc-errors dependencies. Every daemon module is covered to the package's 100% coverage thresholds, plus a socket-integration.test.ts that exercises the client and server together over a real Unix socket (framing, id correlation, the one-request-per-connection invariant, and real shutdown timing).

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

🤖 Generated with Claude Code

sirtimid added a commit that referenced this pull request Jun 12, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@socket-security

socket-security Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​inquirer/​confirm@​6.0.7 ⏵ 6.1.1100 +11009895100

View full report

@sirtimid sirtimid force-pushed the sirtimid/wallet-cli-persistence branch from b9854de to fbcddc5 Compare June 16, 2026 18:04
Base automatically changed from sirtimid/wallet-cli-persistence to main June 16, 2026 18:19
sirtimid and others added 3 commits June 17, 2026 15:42
Add the daemon's IPC transport layer for `@metamask/wallet-cli`. This is
purely additive plumbing — no `mm` subcommand consumes it yet (commands
land in a later slice), so there is no user-visible behavior change.

- socket-line: newline-delimited read/write framing over a `net.Socket`.
- daemon-client: `sendCommand` (one request per connection, id-correlated,
  retries once on transient connection errors) and `pingDaemon` (a
  `getStatus` health probe that classifies unreachable daemons by failure
  mode: refused / timeout / permission / protocol / other).
- rpc-socket-server: `startRpcSocketServer` listens on a Unix socket and
  dispatches one JSON-RPC request per connection to a handler map, with a
  built-in `shutdown` method and idle-connection timeout.
- daemon-spawn: `ensureDaemon` spawns a detached daemon and polls until the
  socket is responsive, refusing to take over a wedged or foreign socket.
- stop-daemon: `stopDaemon` escalates from a graceful `shutdown` RPC through
  SIGTERM to SIGKILL, then cleans up the PID and socket files.
- prompts: `confirmPurge` wraps the ESM-only `@inquirer/confirm`.
- types: add `RpcHandler`, `RpcHandlerMap`, `DaemonStatusInfo`, and
  `DaemonSpawnConfig`.

Adds `@inquirer/confirm` and `@metamask/rpc-errors` dependencies. All daemon
modules are covered to the package's 100% thresholds, plus an end-to-end
socket integration test exercising both halves over a real Unix socket.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse duplicate @inquirer/* entries introduced by the daemon
transport dependencies to their highest resolved versions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sirtimid sirtimid force-pushed the sirtimid/wallet-cli-daemon-transport branch from 4a42757 to 57b77a3 Compare June 17, 2026 14:44
@sirtimid sirtimid marked this pull request as ready for review June 17, 2026 14:45
@sirtimid sirtimid requested review from a team as code owners June 17, 2026 14:45
@sirtimid sirtimid temporarily deployed to default-branch June 17, 2026 14:45 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant