Closes build order items 7 (the systemd half) and 9 (D11 in deferrals.md). velox-nmhost (nmhost/src/main.cpp, 185 lines): a poll()-driven byte pump between Firefox's native-messaging framing on stdio (4-byte native-byte-order length prefix) and veloxd's own NDJSON framing on the Unix socket. Reframes each direction, no JSON parsing, no retry/backoff (the extension relaunches a fresh host on its own reconnect), exits the moment either side closes. Deliberately dependency-free — no veloxd_* library, no nlohmann_json — since it runs unconfined outside Firefox's sandbox regardless of packaging format. Two real bugs found and fixed while getting the integration test to actually pass rather than hang, both exactly the class of bug a "trivial pump" invites: 1. Never set the pumped fds non-blocking, so the "drain what's available" read loop blocked on its own second read() instead of returning to poll(). 2. stdin and stdout are two different descriptors (0 and 1), not one — an early draft polled POLLOUT on fd 0, which is opened read-only, so EOF and writability were never both observable through the same pollfd entry. packaging/nativehost/com.velox.host.json + its own README.md supersede AGENT-DAEMON.md's stale "four locations" line: spike S1 / ADR 0003 found only three manifest locations are real (~/.mozilla/native-messaging-hosts/ for BOTH deb/tarball and snap Firefox, /usr/lib/mozilla/... for deb/tarball only, the flatpak sandbox path) — the fourth, ~/snap/firefox/common/.mozilla/..., is not read by snap Firefox at all. The README spells out the per-user-manifest / postinst enumeration implication for PKG/QA (postinst runs once as root; the two ~/-relative locations are per-user) and flags that docs/07-packaging.md's own install-layout line only shows the one root-owned path. Socket activation: rpc/systemd_activation.cpp is a from-scratch sd_listen_fds() (env vars only — LISTEN_PID/LISTEN_FDS, fd 3 — no libsystemd link) that UdsServer::start() checks first, skipping its own create/bind/chmod/listen when systemd already bound the socket. packaging/systemd/velox.socket + velox.service are the unit pair, verified both by systemd-analyze verify and by an actual fork/dup2/execve simulation of the activation handshake — a real session.hello round-tripped over the handed-off fd with no bind() ever called inside the daemon for that run. velox.service deliberately skips ProtectSystem=/ProtectHome=/ReadWritePaths=: saveTo.allowedRoots is user-configurable to anywhere on the filesystem, and a sandbox here would turn a legitimately-configured save location into an opaque EROFS/EACCES instead of the daemon's own clear -32011. cli/man/velox.1 documents the CLI as it actually exists today (add/ls/pause/resume/rm, --json) — the queue/settings subcommands AGENT-DAEMON.md's build order originally sketched aren't implemented in cli/src/main.cpp yet, so the page doesn't claim they are. Checked warning-free with groff -mandoc -ww -z. Full ctest: 57/57 (excluding the pre-existing, unrelated conformance failure noted in earlier commits). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GRDjHGgpYmMoPE2UFbe7pP
130 lines
3.7 KiB
Groff
130 lines
3.7 KiB
Groff
.TH VELOX 1 "2026-09-12" "Velox" "User Commands"
|
|
.SH NAME
|
|
velox \- command-line client for veloxd, the Velox download manager daemon
|
|
.SH SYNOPSIS
|
|
.B velox
|
|
.I command
|
|
.RI [ options ]
|
|
.SH DESCRIPTION
|
|
.B velox
|
|
talks to
|
|
\fBveloxd\fR
|
|
over its Unix-domain socket and gives a scriptable, terminal-first view of the same
|
|
downloads the GUI and the Firefox extension see. It does no downloading itself \(em every
|
|
command is a thin JSON-RPC call; the daemon owns all state.
|
|
.PP
|
|
.B veloxd
|
|
must already be running (see
|
|
.B ENVIRONMENT
|
|
below for how
|
|
.B velox
|
|
finds it, and
|
|
.BR systemctl (1)
|
|
.RI ( "systemctl --user status velox" )
|
|
for whether it's up). If nothing is listening on the socket,
|
|
.B velox
|
|
exits with status 3 rather than hanging.
|
|
.SH COMMANDS
|
|
.TP
|
|
.BI "add " url " [\-\-dir " dir "] [\-\-out " name "] [\-\-segments " n ]
|
|
Add a new download. Prints the new task's id and initial state.
|
|
.RS
|
|
.TP
|
|
.BI "\-\-dir " dir
|
|
Destination directory. Must resolve inside one of the daemon's configured
|
|
.B saveTo.allowedRoots
|
|
or the call fails; omit to use the configured default download directory.
|
|
.TP
|
|
.BI "\-\-out " name
|
|
Filename to save as. Omit to derive one from the URL (or, once the daemon has probed it,
|
|
from the server's own
|
|
.BR Content-Disposition ).
|
|
.TP
|
|
.BI "\-\-segments " n
|
|
Requested connection count for this download, 1\(en32. The daemon may use fewer \(em a
|
|
per-host cap or a source that turns out not to support resuming both lower it. The
|
|
.B ls
|
|
table (and
|
|
.RI "\-\-json's " segments
|
|
field) show what was actually granted, not what was asked for.
|
|
.RE
|
|
.TP
|
|
.B ls
|
|
List every download the daemon knows about: id, state, progress, and filename. With
|
|
.BR \-\-json ", the raw " download.list " result instead of the table."
|
|
.TP
|
|
.BI "pause " id " [" id " ...]"
|
|
Pause one or more downloads by id. A download already paused, or already finished, is
|
|
left alone \(em not an error.
|
|
.TP
|
|
.BI "resume " id " [" id " ...]"
|
|
Resume one or more paused downloads.
|
|
.TP
|
|
.BI "rm " id " [" id " ...] " "[\-\-delete\-file]"
|
|
Remove one or more downloads from the list. Without
|
|
.BR \-\-delete\-file ,
|
|
any partial data on disk
|
|
.RI ( .veloxpart / .veloxpart.meta )
|
|
is discarded but a
|
|
.B completed
|
|
file is left in place. With
|
|
.BR \-\-delete\-file ,
|
|
the finished file is deleted too \(em there is deliberately no default for this flag; you
|
|
must say which you mean every time.
|
|
.SH OPTIONS
|
|
.TP
|
|
.B \-\-json
|
|
Print the raw JSON-RPC result instead of a formatted table. Works with every command;
|
|
combine with
|
|
.BR jq (1)
|
|
for scripting. On error, the JSON form is an
|
|
.B {"error": {...}}
|
|
object on stdout rather than a message on stderr.
|
|
.TP
|
|
.B \-h ", " \-\-help
|
|
Print usage and exit 0.
|
|
.SH EXIT STATUS
|
|
.TP
|
|
.B 0
|
|
Success.
|
|
.TP
|
|
.B 1
|
|
The daemon reached the call but returned a JSON-RPC error (bad task id, path outside the
|
|
allowed roots, and so on). The message is on stderr, or in the JSON error object with
|
|
.BR \-\-json .
|
|
.TP
|
|
.B 2
|
|
Usage error \(em missing argument, unknown option, or unknown command.
|
|
.TP
|
|
.B 3
|
|
Could not reach
|
|
.B veloxd
|
|
at all: not running, or its socket is missing or unreachable.
|
|
.SH ENVIRONMENT
|
|
.TP
|
|
.B XDG_RUNTIME_DIR
|
|
.B velox
|
|
connects to
|
|
.IR "$XDG_RUNTIME_DIR/velox/velox.sock" .
|
|
If unset, it falls back to
|
|
.IR /run/user/ <uid> ,
|
|
matching
|
|
\fBveloxd\fR's
|
|
own resolution \(em the two must agree for the client to find the daemon, so this is
|
|
normally left to the desktop session's default rather than set by hand.
|
|
.SH FILES
|
|
.TP
|
|
.I $XDG_RUNTIME_DIR/velox/velox.sock
|
|
The daemon's Unix-domain socket, mode 0600, same-UID only (\fBSO_PEERCRED\fR checked on
|
|
every connection \(em this is the transport's authorization, not an extra login).
|
|
.SH SEE ALSO
|
|
.BR systemctl (1),
|
|
.BR jq (1)
|
|
.PP
|
|
.I docs/01-architecture.md
|
|
and
|
|
.I docs/agents/AGENT-DAEMON.md
|
|
in the Velox source tree for the daemon's own build order and the wire protocol
|
|
.B velox
|
|
speaks.
|