diff --git a/.project/handoffs/20260609_parallel-completion-plan.md b/.project/handoffs/20260609_parallel-completion-plan.md index 9441092..93fdcf8 100644 --- a/.project/handoffs/20260609_parallel-completion-plan.md +++ b/.project/handoffs/20260609_parallel-completion-plan.md @@ -27,3 +27,33 @@ Discord planes. Completion criteria: all four modules merged, CLI wired (`fleet repin|daemon|serve|probe`), full `bun test` + typecheck green, docs (operations/roadmap/fleet README) updated, results appended here. + +--- + +## Result — COMPLETE (same evening) + +All four agents delivered; integration done by the coordinating session. + +- **Tests:** 131 pass / 0 fail across 9 files (was 45/5 before the team); + `bunx tsc --noEmit` clean. New: actuate 35, daemon 13, serve 16, probe 22. +- **CLI wired:** `fleet repin [--apply]`, `fleet probe`, `fleet daemon + [--apply-nudges] [--interval-min=N]`, `fleet serve [--port=N] [--token=T]`; + `status`/`custody`/`repin` now use probed capacity (`withProbedCapacity`); + `gatherHoldings` merges recorded re-pin holdings (`fleet-holdings.json`). +- **Live-verified:** `fleet probe` → black reachable, 50.7 GB free, EWMA + scores persisted; `fleet status` shows capacity lines; `fleet repin` + dry-run → 254 plans with honest skip reasons (no surviving copy / target + lacks ssh); `fleet serve --token` → /health open, /registry 401 without → + 200 with bearer token; server killed cleanly (no orphan, port closed). +- **Agent notes worth keeping:** repin runs rsync ON the target pulling from + the source (`ssh target rsync -a -s --partial --inplace source:path/ dest/`), + `--append-verify` excluded and asserted absent in tests; mcp search shape is + `bun run src/cli.ts search "" [limit]` (JSON array of + {filename,source,size,seeders,leechers,magnet}); probe merge rule = probe + wins over registry for disk AND uptime (documented in probe.ts); serve + returns 405 for non-GET (deliberate deviation from "404 for everything"). +- **To make repin executable for real:** give targets `ssh` + `mediaRoot` via + fleet.json (apricot advertises transmission but has no `user@host` service + detail today — add one, or an object-form override). +- Docs updated: operations (full subcommand table + state files), roadmap + (stage 1 fully shipped; serve noted on stage 3), fleet/README. diff --git a/docs/operations.md b/docs/operations.md index c7ccfc2..839432c 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -130,8 +130,20 @@ report carries the sha256 of the helper script it runs (`helper_sha`), and the app compares it against the repo's vendored copy (`mcp/src/blacktv/black-tv.sh`) — a mismatch (or a pre-stamp helper that reports nothing) means the app may be speaking verbs the device doesn't know. -Redeploy per `mcp/README.md` to clear it. No badge appears when freshness -can't be judged (device unreachable, unknown helper, or no repo checkout). +No badge appears when freshness can't be judged (device unreachable, unknown +helper, or no repo checkout). + +**Update & restart service** (menu + expanded summary) is the in-app fix: the +app base64-pushes the vendored script over the device's own SSH channel, +installs it atop the deployed bin (`sudo install` — atomic), verifies the +landed sha256, then restarts the player service through the fresh script. The +manual `mcp/README.md` deploy step remains for hosts the app can't reach. + +Each row expands (chevron) into a **summary section**: backend + endpoints, +role/fleet class + services, live connection/playback line, host load +(1/5/15-min + mpv decode CPU), and the helper-deployment line (deployed vs +repo hash, judged) — with the Restart / Update & restart buttons inline, so +diagnosing and fixing a wedged device happens in one place. ## governor (`portable-net-tv`) diff --git a/docs/roadmap.md b/docs/roadmap.md index c82e700..b4a698d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -98,6 +98,34 @@ infrastructure: a provisioned seedbox, friends' fleets for F2F, private-tracker credentials, Discord bots/servers. None of this is code in this repo until those exist. +### `blackd` — black as a real service (no ssh on the control path) — planned milestone + +ssh-as-transport is the app's load-bearing design debt: player control is a +fresh `ssh → sudo socat → /tmp/mpv.sock` pipeline per command (`MpvTarget`), +the library index is `ssh cat`, launch/stats/releases/restart are ssh-invoked +`black-tv` verbs (whose deploy drift required the `helper_sha` badge), and the +offline cache rsyncs over ssh. Consequences: every keyless client needs a proxy +(the iOS app exists only via the plum `:8787` bridge; a Roku/web client can't +ssh at all), every capable client reimplements ssh plumbing, and the `sudo +socat` hack exists purely because the far socket is root-owned. The +counter-examples are already in the stack: transmission (HTTP RPC :9091) and +the Roku's ECP are the robust integrations. + +**Design:** one daemon on black — HTTP on LAN + WG overlay, bearer token: +- `/player/*` + WebSocket events — local unix-socket access to mpv (root + problem dissolves; no per-command process spawn) +- `/library/index` — replaces `ssh cat` +- `/media/` (HTTP range now, on-demand HLS remux later) — the SAME media + plane the Roku channel / web client milestone needs; one investment +- `/launch`, `/stats`, `/releases`, `/restart` — the `black-tv` verbs +- `/version` — replaces helper_sha drift detection + +**Migration (each phase shippable):** 1) daemon wraps the existing pieces +(systemd unit; deploy via the existing helper mechanism); 2) `BlackdTarget` +(PlayerTarget/MediaLaunchable over HTTP, like VLC's) preferred with ssh +fallback; 3) retire ssh paths + the plum iOS bridge (iOS talks to black +directly). ssh remains for deploys/admin only. + ### Roku dev channel — planned milestone The living-room display has a Roku Streaming Stick 4K (`10.0.0.233`, ECP) diff --git a/site/screenshots/downloads.png b/site/screenshots/downloads.png index f696813..d12f105 100644 Binary files a/site/screenshots/downloads.png and b/site/screenshots/downloads.png differ diff --git a/site/screenshots/logs.png b/site/screenshots/logs.png index f696813..cc4fab2 100644 Binary files a/site/screenshots/logs.png and b/site/screenshots/logs.png differ diff --git a/site/screenshots/settings.png b/site/screenshots/settings.png index f696813..ab480b3 100644 Binary files a/site/screenshots/settings.png and b/site/screenshots/settings.png differ