aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/cli
Commit message (Collapse)AuthorAgeFilesLines
* feat(packaging): the Store package declares what the NSIS scripts doChristophe Besson40 hours1-0/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A test-signed install of the MSIX build, in the WindowsApps folder a Store install uses, showed that every script-made piece of the NSIS model breaks there, because each names the install folder and every update deletes it: the firewall rules went stale, the PATH entries piled up pointing at deleted folders, and the Startup-folder .vbs was refused ("Permission denied") right after sign-in. The network capabilities the manifest declared covered nothing: they make rules for sandboxed apps only, and a listener in the package still got the Windows firewall prompt. The package's own startup task was on by default, started the node whatever mode the Node page said, and ran the console executable, whose window stopped the node when closed. The package now declares what Windows then creates at install, carries across updates and removes with the app, all without an administrator prompt (each measured on the real install, through an update and a reboot): - firewall rules for the node, in a custom manifest template, since only a package-level element can hold them; - the startup task, off by default, running meshbay-nodew.exe, a new build of the daemon without a console; - an execution alias for meshbay-node.exe, so the app adds no PATH entry. The node's CLI switches the startup task (platform.startup_task, ctypes over the WinRT ABI): Windows gives the package's identity to the executables in it, not to a powershell.exe the app starts, which got "Element not found". `meshbay-node autostart install | remove | status` therefore works in the Store package from the app and a terminal alike; the app caches the answer, since the Node page polls. Starting at boot stays the .exe installer's: the Store package offers no service mode, and the CLI refuses `service install` there. Process listings count both image names. The Node page's status poll cleared the message of a refused action within five seconds; the two errors are kept apart now (all Windows builds). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: set the Windows node up at sign-in, and stop it for realChristophe Besson4 days1-7/+50
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Found by the first Windows beta tester, then reproduced on a clean install. After a service-mode install nothing set the node up for the account that signed in: the boot task started a node that quit ("hub.username not set"), and the sidebar showed Node / Create group only once the hub held a node key. The only way to the wizard that provisions was the home page's welcome card, which an account already in a group never sees. The way out was `meshbay-node init` and the key pasted on the profile page -- which is also what PACKAGING-GUIDE.md told people to do. - main.js `node:ensure`, called by app.js at sign-in: provisions, starts and links the node this build ships (Windows, bundled node only). A node set up for another account, or an account linked to another node, is left alone. node:start waits for it, so the two never race. - The sidebar shows the Node section when a node exists on this machine. - The Node page's status is the node's: its control API and the process list, not the service task's state (a node started from a terminal ran while the page said Stopped). Stop says Stopped only once no meshbay-node.exe is left, and stays offered for a process that answers nothing. - CLI stop kills the pid that answered when a graceful stop does not finish, and fails with the reason when a node process is still there. - The daemon ends its process 3s after _shutdown(): Python's exit waited for a busy indexer thread, with the control API already closed. Armed by main() only, never by a daemon run inside a test. - node.toml is read as utf-8-sig (PowerShell 5.1 writes a BOM), and a config that cannot be read is logged instead of dying silently in service mode. - "Pair this browser" queues the code for the next group of this node to open instead of saying "Paired successfully"; no banner before a group. - test_e2e_windows_app.py (opt-in, MESHBAY_WIN_E2E=1) drives the installed app against a throwaway hub: fresh account to linked node, Stop, Start, Restart, checked against the real processes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): print "running" once in meshbay-node statusChristophe Besson7 days1-1/+2
| | | | | | | | The daemon line repeated the state the daemon reports ("running — running"). The state is now appended only when it says something more than "running", such as waiting_for_hub. The QUICKSTART example is updated to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): how a hosted group admits people is the operator's, not the hub'sChristophe Besson11 days2-2/+12
| | | | | | | | | | | attach_group no longer copies join_policy and visibility from the hub's answer: they come with the operator's request (the desktop creation form, `group add --open`) and default to invite/private; the CLI says when the hub lists the group otherwise. Every string written into node.toml is escaped (toml_string) and read back through tomllib, so a group or folder name cannot write lines of its own (F-17). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: only the owner decides who hosts a group, and nobody is made a member ↵Christophe Besson12 days1-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | unasked - hub: a node may host a group only if its account owns it or the owner approved that node (new `group_hosts`). Membership was the ceiling, and every member holds the group key, so any member's node could register as a host and be the one clients kept. A node claiming a group it may not host is recorded as a request; the owner is notified once and approves or refuses it (GET/POST/DELETE /v1/groups/{id}/hosts[/{node_id}]), which takes effect on a connected node at once. - hub: an owner adding a username creates an invitation (new `group_invitations`), accepted or declined by the invitee (/v1/groups/invitations, /{id}/invitation/accept|decline). Until then the group is not listed, not dialled, not searched and not in any token. Invitation links, open joins and group creation still make members directly: they are the account's own act. - hub: the MNP token names only the group it is minted for (group_id is now required), so a node operator no longer learns a member's other groups. - SPA: invitations on the home page; invited people and host requests in the group's settings; the transport sends group_id. Ten catalogues. - Browser probes for both screens, run in Chrome and Firefox. - Design §5.2, §7.2, §7.3, AV32, AV33; protocol §6.3; user guide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): a Windows daemon that stops properly, starts honestly and runs onceChristophe Besson2026-09-272-33/+148
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Found by installing the builds and driving every startup mode live: - Stop through the node's own control API first (POST /api/shutdown, loopback and per-run token): the one channel that reaches a daemon in any session without elevation -- a service node runs in session 0 -- and the one that runs its shutdown. Then Task Scheduler, then a forced stop. Nine stops in a row used to log no shutdown at all: each was a TerminateProcess. - The forced stop spares the command running it. The frozen meshbay-node.exe is the daemon and every CLI verb, so `taskkill /IM meshbay-node.exe` killed `autostart stop` and `restart-daemon` themselves: exit 1, no output, and no node after a restart. It excludes its own pid and its parent's, and /T takes a venv launcher's python child and a daemon's ffmpeg children with it. - Start and restart report the version that answered, never "started" about a node nobody asked; `service start` says so when no node answered, and where the log is. - A second instance fails before it touches anything. The daemon wrote ui-token, then failed to bind inside uvicorn's task and exited with the reason on a hidden console; the node still running then refused every stop and status, its token file naming a dead process. The control port is now bound first (exclusively on Windows, where SO_REUSEADDR would share it), and a refusal is logged and exits 2. Linux had the same order. - The daemon logs to %LOCALAPPDATA%\meshbay\state\node.log: Task Scheduler discards its stderr. Only the daemon run opens it, never a CLI verb. - Hub sign-in waits are interruptible, a stop requested before the node is up is honoured, and a hub that answers 429 or restarts leaves the node in waiting_for_hub rather than looking dead. - operator_paired is null until the roster is read, instead of a false that showed "No operator paired" about a node whose pairing was intact. The node test conftest also points HOME, USERPROFILE, LOCALAPPDATA and APPDATA at a throwaway directory for every test, and keeps log_file() away from the developer's own node: redirecting HOME alone isolates nothing on Windows, and the CLI tests had been writing invite and pairing codes into the real profile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): read the packaged TMDB token in placeChristophe Besson2026-09-261-5/+0
| | | | | | | | A node onboarded by the desktop client never ran `init`, so default.env was never copied to node.env; and default.env was 0600 root, unreadable to a per-user node anyway. The daemon now loads it beneath node.env, 0644. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: invitation links no longer bound to an e-mail addressChristophe Besson2026-09-252-16/+17
| | | | | | | | A link is redeemable by whoever opens it first, so it can be sent by any messaging app. The address is optional (mail + label only); a link lives 7 days, fixed. Adds a Share button; see MESHBAY_DESIGN.md §3.4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(node): move the CLI out of daemon.py into cli/Christophe Besson2026-09-2411-0/+1540
Each `if args.command == ...` branch of main() becomes a function in cli/ (one module per family of verbs); the parser, the process setup and a VERBS table go to cli/parser.py and cli/dispatch.py. daemon.main runs the verb or starts the daemon. Tests patch the CLI through conftest.patch_cli; the CLI golden is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>