From 43e171ad5df9ce4383ac0c2ead9851ed2fc284eb Mon Sep 17 00:00:00 2001 From: Taylor Addison Date: Thu, 15 Oct 2026 16:52:19 -0400 Subject: [PATCH] Release 0.8.0 Version 0.8.0 everywhere, the changelog section, and docs brought up to date: releases exist, the container image and the systemd backend are run by CI, the desktop Rust and the Roku channel compile. README and the docs home gain the agent CLI, MCP and skill; CONTRIBUTING gains the release steps. Co-authored-by: Cursor --- .github/workflows/release.yml | 9 +++--- CHANGELOG.md | 46 ++++++++++++++++++++++++++++- CONTRIBUTING.md | 24 +++++++++++++++ README.md | 30 +++++++++++++++++-- VERSION | 2 +- collector/dash/package.json | 2 +- collector/openapi.json | 2 +- collector/package.json | 2 +- collector/runner-web/index.html | 2 +- collector/src/version.ts | 2 +- desktop/README.md | 19 +++++++----- docs/deploy/headless.md | 8 ++--- docs/deploy/index.md | 16 ++++++---- docs/getting-started.md | 15 ++++++---- docs/index.md | 12 ++++++-- docs/install/devices.md | 7 +++-- docs/install/docker.md | 25 ++++++++-------- docs/install/index.md | 4 +-- docs/install/linux.md | 43 ++++++++++++++++----------- docs/install/macos.md | 26 ++++++++-------- docs/install/windows.md | 22 +++++++------- docs/platforms.md | 26 ++++++++-------- fleet/Dockerfile | 9 +++--- fleet/README.md | 17 ++++++++--- fleet/package.json | 2 +- fleet/src/version.ts | 2 +- install.ps1 | 8 ++--- install.sh | 2 +- runner-android/app/build.gradle.kts | 2 +- runner-ios/project.yml | 6 ++-- runner-machine/package.json | 2 +- runner-machine/src/descriptor.ts | 2 +- runner-roku/README.md | 8 +++-- runner-roku/manifest | 2 +- 34 files changed, 269 insertions(+), 137 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f2bdea..607557a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,11 +30,10 @@ name: release # # ## What has not been proved # -# This file has never run. There is no published release of Fleet Runner, so -# neither installer has ever been pointed at a real one, and the container image -# has never been built at all -- docs/platforms.md has said so since the -# Dockerfile was written. Everything below is a first attempt with the reasoning -# written down, not a proven pipeline. +# It has published every release since v0.5.0. install.sh has been run against +# those archives on macOS (arm64 and Intel); install.ps1 never has. The amd64 +# image is started by `container smoke` in fleet.yml on every pull request; the +# arm64 image is built here and has never been started. on: push: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ddd984..3c9d5fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ a CI job fails when they disagree. ## [Unreleased] +## [0.8.0] — 2026-10-15 + +The fleet as something a program or an AI agent can drive: a versioned control +API, a CLI and MCP tools that are thin wrappers over it, an optional OAuth +gateway for chat tools, and a skill that tells an agent how to use them. See +[AI agents and automation](docs/agents.md). + ### Added - **A versioned control API, `/api/v1`.** Devices, workloads, jobs, results, @@ -72,6 +79,42 @@ a CI job fails when they disagree. - **The container image could not start on a fresh volume.** `VOLUME` named a directory the image never created, so Docker made it root-owned and the non-root `fleet` user died on `mkdir`. The image now creates it first. +- **The desktop app's build script failed before compiling anything.** The + bundled resource directory was named `fleet`, the same name the sidecar is + copied to in `target/debug`, so the copy failed with "Not a directory". The + resource is now `fleet-tree`, and the sidecar shim also looks beside itself, + where a dev build puts it. + +### Now verified + +Four items from earlier "Not verified" lists, each now checked by CI on every +pull request that touches them: + +- **The container image runs.** `fleet / container smoke` builds + `fleet/Dockerfile`, starts it, and waits for its own agent to register and + answer `fleet devices`, `fleet workloads` and `fleet whoami`. It found the + volume bug above on its first run. linux/amd64 only; the arm64 image is still + built and not run. +- **`fleet service install` on systemd.** `fleet / systemd smoke` installs the + user unit on a real systemd, checks it with `systemd-analyze verify`, waits + for the collector it starts to answer, then uninstalls and checks nothing is + left answering. launchd and the Windows scheduled task are still unrun. +- **The desktop app's Rust compiles.** `desktop / cargo check` stages the + sidecar and runs `cargo check --all-targets` on macOS. It found the resource + bug above; once that was fixed the Rust compiled with no errors. Compiling is + all it proves: the app has still never been launched. +- **The Roku channel compiles.** `runner-roku / brighterscript` runs `bsc` + over the channel. It has still never run on a Roku. + +### Not verified + +- **The MCP gateway has not met a real identity provider.** Its tests use a + local fake that signs tokens the way Entra ID and Okta do; no tenant has an app + registration for it yet, and it is not on any company's approved-connector + list. [Authentication and the MCP gateway](docs/deploy/auth.md) has the setup. +- **The dashboard does not use the generated client yet.** It still calls the + unversioned routes with hand-written types + ([#83](https://github.com/addisdev/fleet-runner/issues/83)). ## [0.7.2] — 2026-09-30 @@ -994,7 +1037,8 @@ The first public release, when the project was still four repositories. that starts a throwaway collector on a spare port so it never touches a live fleet's history. -[Unreleased]: https://github.com/addisdev/fleet-runner/compare/v0.7.2...HEAD +[Unreleased]: https://github.com/addisdev/fleet-runner/compare/v0.8.0...HEAD +[0.8.0]: https://github.com/addisdev/fleet-runner/compare/v0.7.2...v0.8.0 [0.7.2]: https://github.com/addisdev/fleet-runner/compare/v0.7.1...v0.7.2 [0.7.1]: https://github.com/addisdev/fleet-runner/compare/v0.7.0...v0.7.1 [0.7.0]: https://github.com/addisdev/fleet-runner/compare/v0.6.2...v0.7.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 183d2a9..f5e7d56 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -157,6 +157,30 @@ this is the first rule rather than a nice sentiment. component suite is green **or skipped** — a change to one runner does not build the others. +## Cutting a release + +One version covers every component, so a release is one number everywhere. + +1. On a branch from `develop`, run `node scripts/version.mjs set X.Y.Z`. It + writes `VERSION` and every component's own version. Then run + `npm --prefix collector run gen:api`, because `openapi.json` carries the + version and CI fails when it is stale. Android's `versionCode` is not + derived from it; bump that by hand if the Play Store build needs it. +2. In `CHANGELOG.md`, rename `## [Unreleased]` to `## [X.Y.Z] — YYYY-MM-DD`, + add a fresh empty `## [Unreleased]` above it, and update the compare links + at the bottom. +3. Merge that into `develop`, then open a `develop` → `main` pull request named + `Release X.Y.Z` and merge it once `ci-ok` passes. +4. Tag the merge commit on `main` and push the tag: + `git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z`. + +The tag runs `release.yml`. Its first job refuses to publish anything unless +the tag, `VERSION` and every component agree. Then it builds the six +platform archives and `SHASUMS256.txt`, pushes the container image, and creates +the GitHub Release, which `install.sh` and `install.ps1` read. A version with a +suffix (`0.9.0-rc.1`) is published as a pre-release and leaves `latest` alone. +Pushing to `main` also publishes the docs site. + ## Dependencies **Dependabot is deliberately limited to security alerts and security fixes.** diff --git a/README.md b/README.md index 0ff3adf..9ab2b35 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,31 @@ curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install. > **[docs/install/](https://addisdev.github.io/fleet-runner/install/)** is honest > per platform. +## Drive it from a script or an AI agent + +``` +fleetr run benchmark --pool phones && deploy +``` + +Devices, workloads, jobs, results, artifacts, schedules and alerts are one +versioned control API, +[`/api/v1`](https://addisdev.github.io/fleet-runner/api/#control-api-apiv1), +with an OpenAPI document and a generated client. Three wrappers sit on that +client and nothing else: + +- **A CLI** (`fleetr`, the same program as `fleet`) whose exit code is the + verdict and whose `--json` is the API's answer, for scripts, CI and coding + agents. +- **An MCP server**, `fleet mcp`, for agents that prefer tools to shell + commands, and a remote one, `fleet mcp --http`, that sits behind your + company's sign-in (OAuth 2.1, Entra ID or Okta) for chat tools. +- **A skill**, installed with `fleet skill install`: a short file telling an + agent which commands to run in what order and what not to do, with tables + generated from the code so it cannot drift from the binary. + +Authentication is opt-in: `FLEET_AUTH=tokens` turns on scoped tokens and an +audit log; a fleet on a LAN or tailnet works as before without it. + ## Documentation **[addisdev.github.io/fleet-runner](https://addisdev.github.io/fleet-runner/)** @@ -78,6 +103,7 @@ curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install. | **[Get started](https://addisdev.github.io/fleet-runner/getting-started/)** | `fleet up`, a real job, and a result on the dashboard. Needs Node 22.13 and nothing else -- no Xcode, no NDK, no phone. | | **[Exploratory QA](https://addisdev.github.io/fleet-runner/explore/)** | A vision model explores tonight's build on phones, simulators and TVs, and files only the bugs that reproduce on a clean install. | | **[Wire in your own app](https://addisdev.github.io/fleet-runner/integration/)** | Publish builds on merge, run a nightly on your own devices, and block a pull request on the verdict. | +| **[AI agents and automation](https://addisdev.github.io/fleet-runner/agents/)** | The CLI, the skill, MCP over stdio, and the remote MCP gateway with company sign-in. | | **[The protocol](https://addisdev.github.io/fleet-runner/protocol/)** | Register, long-poll, claim, beacon, report. Enough to write a runner in a language none of these are in. | ## How it fits together @@ -140,14 +166,14 @@ languages, sharing not one line | **[runner-ios/](runner-ios)** | Swift. SwiftUI, with llama.cpp and Core ML backends. The same sources build the tvOS and visionOS targets -- two conditions rather than a fork. | | **[runner-machine/](runner-machine)** | TypeScript. A Node process that makes a laptop, desktop, board or NAS a fleet device, so a phone's tok/s and a laptop's land in the same table. | | **[collector/runner-web/](collector/runner-web)** | JavaScript, one HTML file the collector serves at `/runner`: opening it enrols the browser that opened it. A smart TV, a console, a Chromebook -- anything with no way to install a signed app. | -| **[runner-roku/](runner-roku)** | BrightScript, because it is the only language a Roku will run. A SceneGraph channel, so a streaming player or a Roku TV is a fleet device. It has never been run on a Roku, and it has never been *compiled* -- there is no emulator -- so read its README before you read a number from it. | +| **[runner-roku/](runner-roku)** | BrightScript, because it is the only language a Roku will run. A SceneGraph channel, so a streaming player or a Roku TV is a fleet device. It has never been run on a Roku -- there is no emulator -- and CI compiling it with brighterscript is all that is checked, so read its README before you read a number from it. | **The front doors** | | What it is | |---|---| | **[fleet/](fleet)** | The CLI. `fleet up` runs this machine's components under a supervisor that backs off and gives up loudly rather than restarting a broken component forever; `fleet doctor` says what the machine can run and why not; `fleet service install` keeps it up. It wraps the three programs above and reimplements none of them. | -| **[desktop/](desktop)** | A Tauri menu-bar app around that CLI: a tray menu, role switches, the dashboard in a window, and a notification when a component gives up. It exists to test one hypothesis about macOS local-network permissions, and **none of its Rust has ever been compiled** -- read its README before believing anything in it. | +| **[desktop/](desktop)** | A Tauri menu-bar app around that CLI: a tray menu, role switches, the dashboard in a window, and a notification when a component gives up. It exists to test one hypothesis about macOS local-network permissions, and **it has never been launched**: CI compiles its Rust and that is all -- read its README before believing anything in it. | Each directory has its own README, its own tests and its own CI job, filtered by path so a change to a phone runner does not build the dashboard. diff --git a/VERSION b/VERSION index 7486fdb..a3df0a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.2 +0.8.0 diff --git a/collector/dash/package.json b/collector/dash/package.json index 0419a63..ec9d68d 100644 --- a/collector/dash/package.json +++ b/collector/dash/package.json @@ -1,6 +1,6 @@ { "name": "fleet-dash", - "version": "0.7.2", + "version": "0.8.0", "private": true, "type": "module", "description": "Fleet Runner dashboard SPA. Built to dash/dist and served by the collector at /dash.", diff --git a/collector/openapi.json b/collector/openapi.json index 88d17a4..d245a68 100644 --- a/collector/openapi.json +++ b/collector/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Fleet Runner", - "version": "0.7.2", + "version": "0.8.0", "description": "The Fleet Runner control API.\n\nEvery list is `{items, page, per_page, total, pages}`. Every failure is\n`{error: {code, message, hint?}}`; branch on `code`. Timestamps are ISO 8601 UTC.\n\nThe usual sequence for running something: listWorkloads (pick one, copy its\nexample), validateJob (fix what it says), createJob, waitJob until\n`finished`, then read `verdict`. `skipped` means nothing ran; it is not a pass.\n\nAuth is off unless the collector runs with FLEET_AUTH=tokens. Then send\n`Authorization: Bearer `; scopes are read, run (implies read), admin\n(implies run), agent (the runner protocol) and delegate (a gateway naming the\nperson it acts for in X-Fleet-Actor). Each operation's `x-fleet-scope` says\nwhich it needs. Send `X-Fleet-Source` (mcp, cli, ci...) so jobs record where\nthey came from.", "license": { "name": "MIT" diff --git a/collector/package.json b/collector/package.json index 251d33f..57ba697 100644 --- a/collector/package.json +++ b/collector/package.json @@ -1,6 +1,6 @@ { "name": "fleet-collector", - "version": "0.7.2", + "version": "0.8.0", "private": true, "type": "module", "engines": { diff --git a/collector/runner-web/index.html b/collector/runner-web/index.html index 04e6ce5..9ff5aeb 100644 --- a/collector/runner-web/index.html +++ b/collector/runner-web/index.html @@ -144,7 +144,7 @@

Fleet Runner

* shelf forever as an offline device nobody can find. */ -const APP_VER = "0.7.2"; +const APP_VER = "0.8.0"; const SCHEMA = 1; const BLOCK_SIZE = 4096; const ROUNDS_PER_TOKEN = 1000; diff --git a/collector/src/version.ts b/collector/src/version.ts index df318c3..4316bad 100644 --- a/collector/src/version.ts +++ b/collector/src/version.ts @@ -10,4 +10,4 @@ * which CI runs on every push. See its header for why one number across four * components is the rule. */ -export const APP_VERSION = "0.7.2"; +export const APP_VERSION = "0.8.0"; diff --git a/desktop/README.md b/desktop/README.md index 31c6bfd..5dc157d 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -217,12 +217,18 @@ the first `codesign` invocation. ## Status -Be suspicious of this whole directory. **None of the Rust has ever been -compiled**, on this machine or any other — there is no Rust toolchain here -(`cargo` and `rustc` are both absent), so `cargo check` was never run. +Be suspicious of this whole directory. **The Rust compiles, and that is all +that is known about it.** There is no Rust toolchain on the machine it was +written on, so CI does the compiling: `desktop / cargo check` stages the +sidecar and runs `cargo check --all-targets` on macOS for every pull request +that touches `desktop/`. What **has** actually been checked: +- **`cargo check` passes.** Its first run failed in the build script, before + any Rust was compiled, because the bundled resource and the sidecar were + both named `fleet` in `target/debug`. With the resource renamed `fleet-tree` + the Rust compiled without errors on the first try, Tauri 2 APIs included. - Every JSON file validates (`python3 -m json.tool`), and both plists lint (`plutil -lint`). - `ui/app.js` parses (`node --check`), and every element id it reaches for @@ -239,10 +245,9 @@ What **has** actually been checked: What has **not**: - **It has never run.** Not the tray, not the settings window, not the sidecar - under Tauri, not a notification, not the dashboard window. Assume the first - `cargo check` produces a list of errors; the Tauri 2 APIs most likely to have - moved are `App::on_menu_event`, `TrayIcon::set_menu`, and - `tauri::async_runtime::spawn_blocking`. The Cargo package is `fleet-desktop` + under Tauri, not a notification, not the dashboard window. Compiling says + the Tauri 2 calls exist with those signatures, not that they do what the + code assumes. The Cargo package is `fleet-desktop` and `productName` is `Fleet`; if the bundler cannot find its binary, that mismatch is why, and `mainBinaryName` in `tauri.conf.json` is the knob. - **The Local Network hypothesis.** See The bet, above. Everything this app is diff --git a/docs/deploy/headless.md b/docs/deploy/headless.md index 06044af..8b6a06a 100644 --- a/docs/deploy/headless.md +++ b/docs/deploy/headless.md @@ -17,10 +17,10 @@ a Mac collector reachable at all. one unit running `fleet up` instead of one unit per component. They ship one more release and are then removed. - They are documented here rather than deleted because of an awkward fact: - **`fleet service install` has never been run on any platform**, and these - have. Until somebody has watched the new path start at login, the old path - is the one with mileage on it. + They are documented here rather than deleted because they have more + mileage: `fleet service install` now runs a real fleet's brain under launchd + and passes a systemd smoke test in CI, but nobody has watched its systemd or + Windows backends start a machine at boot, and these have. ## The plists are templates, and that is not tidiness diff --git a/docs/deploy/index.md b/docs/deploy/index.md index e33b531..e9feb26 100644 --- a/docs/deploy/index.md +++ b/docs/deploy/index.md @@ -51,14 +51,18 @@ depends on the machine: | Linux | a systemd **user** unit | `~/.config/systemd/user/fleet.service` | | Windows | a `schtasks` task that runs at logon | the task scheduler | -!!! danger "`fleet service install` has never been run, on any platform" +!!! warning "How much each backend has been run" - Not launchd, not systemd, not the Windows task. Every path it writes is - resolved absolutely -- launchd expands no `~` and reads no login `PATH`, - systemd is the same and Windows is worse -- and none of it has been watched - start at login. The code is written and reviewed; that is all. + - **launchd:** a real fleet's brain runs under it, on macOS 12. + - **systemd:** a CI smoke test installs the user unit on Ubuntu, checks it + with `systemd-analyze verify`, waits for the collector it starts to + answer, and uninstalls it. Nobody has watched it come back after a reboot. + - **Windows task:** never run. - What *has* been run, on macOS, are the older per-component plists in + Every path it writes is resolved absolutely -- launchd expands no `~` and + reads no login `PATH`, systemd is the same and Windows is worse. + + Also run, on macOS, are the older per-component plists in `collector/deploy/` and `runner-machine/deploy/`. Those are what the reference deployment actually uses today, and they are documented in [headless hosts](headless.md). They are deprecated -- they ship one more diff --git a/docs/getting-started.md b/docs/getting-started.md index 410ae7e..5e961c1 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -17,10 +17,13 @@ seen the loop work. curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install.sh | sh ``` -!!! warning "No release has been published yet, so that line does not work" +That downloads the latest [release](https://github.com/addisdev/fleet-runner/releases), +refuses it unless its checksum matches, and unpacks it into `~/.fleet`. It +prints the `PATH` line to add if `~/.fleet/bin` is not already on it. On +Windows the command is +`irm https://raw.githubusercontent.com/addisdev/fleet-runner/main/install.ps1 | iex`. - There are no tags and no archives, so the installer asks GitHub for the - latest release, finds nothing, and stops. **Build from a checkout instead:** +??? note "Or build from a checkout" ```bash git clone https://github.com/addisdev/fleet-runner @@ -36,8 +39,8 @@ curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install. `PATH`, or type the whole thing -- the rest of this page says `fleet` either way. - [Install](install/index.md) has the same thing per platform, and is honest - about which of them anyone has actually run. macOS/arm64 is the answer. +[Install](install/index.md) has the details per platform, and is honest about +which of them anyone has actually run. macOS is the answer. ## 2. `fleet up` @@ -46,7 +49,7 @@ fleet up ``` ``` -fleet 0.5.0-dev +fleet 0.8.0 home /Users/you/.fleet roles brain, agent brain http://127.0.0.1:8788 (bind 0.0.0.0) diff --git a/docs/index.md b/docs/index.md index f219b44..713bb7e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -65,6 +65,13 @@ fleet on. The answer is macOS; the suites run on all three. Publish builds on merge, run a nightly on your own devices, block a pull request on the verdict. +- __[AI agents and automation](agents.md)__ + + --- + + `fleetr` for scripts and coding agents, a skill that tells an agent how to + use it, and MCP tools, locally or behind your company's sign-in. + - __[Deploy](deploy/index.md)__ --- @@ -115,13 +122,14 @@ Five runners, in five languages, sharing not one line: [`collector/runner-web/`](https://github.com/addisdev/fleet-runner/tree/main/collector/runner-web) (JavaScript) and [`runner-roku/`](https://github.com/addisdev/fleet-runner/tree/main/runner-roku) -(BrightScript, and never compiled -- see [platforms](platforms.md)). +(BrightScript, compiled in CI and never run on a Roku -- see [platforms](platforms.md)). And two front doors: [`fleet/`](https://github.com/addisdev/fleet-runner/tree/main/fleet), the CLI behind `fleet up`, and [`desktop/`](https://github.com/addisdev/fleet-runner/tree/main/desktop), a -menu-bar app around it whose Rust has never been compiled. +menu-bar app around it whose Rust compiles in CI and which has never been +launched. [The history section](history/index.md) keeps the original architecture plan and the design journals as they were written. They are not maintained, and they are diff --git a/docs/install/devices.md b/docs/install/devices.md index 2afb728..946a55f 100644 --- a/docs/install/devices.md +++ b/docs/install/devices.md @@ -135,9 +135,10 @@ Two things to know before you read a number off a Roku: interpreted folds. On a phone that is seconds; on a Roku nobody has measured one, and it could be many minutes per iteration. -**None of this has ever run.** The channel has never been compiled either -- -BrightScript's only compiler is inside a television and no emulator exists. -[Roku: the one that could not be compiled](../platforms.md#roku-the-one-that-could-not-be-compiled) +**None of this has ever run.** No Roku emulator exists. CI compiles the channel +with brighterscript's `bsc`, which catches syntax errors off the television; +the firmware's own compiler has never seen it. +[Roku: the one that has never run](../platforms.md#roku-the-one-that-has-never-run) and [`runner-roku/README.md`](https://github.com/addisdev/fleet-runner/tree/main/runner-roku) are the two places that say exactly which claims are untested. diff --git a/docs/install/docker.md b/docs/install/docker.md index c77f209..eb6d5cf 100644 --- a/docs/install/docker.md +++ b/docs/install/docker.md @@ -6,18 +6,19 @@ docker run -d --restart unless-stopped -p 8788:8788 \ ghcr.io/addisdev/fleet up --role brain,agent ``` -!!! warning "Built, never run" - - `ghcr.io/addisdev/fleet` exists: the release workflow built and pushed it for - linux/amd64 and linux/arm64 at v0.5.0, tagged `0.5.0` and `latest`. So the - Dockerfile is at least correct enough to assemble, which is more than could - be said of it before that tag. - - **No container has been started from it.** Docker was not available on the - machine that wrote it, and the build succeeding in CI says nothing about - whether `fleet up` comes up inside one -- the entrypoint, the volume, the - health check and the non-root user are all untested. If you run it and it - works, or does not, that is worth an issue either way. +!!! note "Run by CI on every pull request, on amd64" + + Every release builds and pushes `ghcr.io/addisdev/fleet` for linux/amd64 and + linux/arm64, tagged with the version and `latest`. + + `container smoke` in CI builds the same Dockerfile on linux/amd64, starts it + with `up --role brain,agent` on a fresh volume, waits for `/api/health`, + then waits for the container's own + machine agent to register and checks `fleet devices`, `fleet workloads` and + `fleet whoami` against it. Its first run found that the image could not + start on a fresh volume (the directory was created root-owned), fixed in + 0.8.0. The arm64 image is built and has not been started. If you run it on + a NAS or a board, an issue saying how it went is welcome either way. `runner-machine/Dockerfile`, the agent-only image, is still **not built at all**: nothing publishes it and nobody has run `docker build` on it. diff --git a/docs/install/index.md b/docs/install/index.md index 3ce67da..e1cf6a1 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -27,8 +27,8 @@ can type it. |---|---|---| | **[macOS](macos.md)** | `curl -fsSL …/install.sh \| sh` | Installed from a real release on **arm64 and Intel**, checksum verified, and upgraded in place from 0.5.0 to 0.6.0. **A real fleet's brain runs here under `fleet service`** — one launchd unit, three components, on macOS 12 | | **[Windows](windows.md)** | `irm …/install.ps1 \| iex` | `install.ps1` has never been parsed by PowerShell. The CLI's own suite -- supervisor, config, `fleet up` end to end -- passes on `windows-latest` in CI, but **nobody has stood a fleet up on a Windows machine**, and the service backend is untested | -| **[Linux](linux.md)** | `curl -fsSL …/install.sh \| sh` | The installer is the same script macOS runs against the real release; it has not been run on Linux. The collector's and the CLI's suites pass on x64 and arm64 Linux in CI. **Nobody has stood a fleet up on one**, and the systemd service backend is unexercised | -| **[Docker](docker.md)** | `docker run ghcr.io/addisdev/fleet` | Published for linux/amd64 and linux/arm64 at v0.5.0, so it builds. **No container has been started from it** | +| **[Linux](linux.md)** | `curl -fsSL …/install.sh \| sh` | The installer is the same script macOS runs against the real release; it has not been run on Linux. The collector's and the CLI's suites pass on x64 and arm64 Linux in CI. **Nobody has stood a fleet up on one.** The systemd service backend is installed, started and uninstalled by a CI smoke test on Ubuntu, and has not been watched survive a reboot | +| **[Docker](docker.md)** | `docker run ghcr.io/addisdev/fleet` | Published for linux/amd64 and linux/arm64 with every release. CI starts the amd64 image on every pull request and waits for its agent to register; the arm64 image has not been started | | **[Devices](devices.md)** | -- | How a phone, a television, a Roku or a browser joins a fleet that is already up | ## What the installers do, and what they refuse to do diff --git a/docs/install/linux.md b/docs/install/linux.md index 64487c6..39e4885 100644 --- a/docs/install/linux.md +++ b/docs/install/linux.md @@ -4,24 +4,28 @@ curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install.sh | sh ``` -!!! danger "Two separate things are untested here" - - **No release has been published**, so there is no archive to download and no - `SHASUMS256.txt` to check it against. The script asks `api.github.com` for - the latest release, finds nothing, and stops. Use [from a - checkout](#from-a-checkout) or [Docker](docker.md). - - **And the `fleet` CLI has never been run on Linux.** Not the CLI, not the - supervisor, not the bundle, not the systemd service backend. The paths, the - process handling and the service code are written and untested. +!!! warning "What has been run on Linux, and what has not" + + **`install.sh` has not been run against a release on Linux.** Releases + publish `linux-x64` and `linux-arm64` archives with `SHASUMS256.txt`, and the + script has been run against a real release on macOS; the Linux branch of it + has not been watched. + + **The `fleet` CLI has been run on Linux only by CI.** Every pull request + that touches it runs the CLI's suite on `ubuntu-latest`, including the + supervised `fleet up` end to end. Two smoke jobs go further: + `systemd smoke` installs the built bundle as a systemd user service, waits + for its collector to answer, and uninstalls it; `container smoke` starts the + [Docker image](docker.md) and waits for its machine agent to register. That + is a real result, and it is not the same as somebody running a fleet on a + Linux machine for a week. What *has* been exercised on Linux is [the machine agent](../platforms.md#what-a-cloud-runner-actually-reports): its own suite runs on x64 and arm64 Linux in CI, and the arm64 descriptor comes back near enough complete -- only `soc` is missing, because `/proc/cpuinfo` on - arm64 has no `model name` line. That is a real result about the agent and - says nothing about `fleet`. **No board has ever registered against a real - collector.** + arm64 has no `model name` line. **No board has ever registered against a + real collector.** **You need Node 22.13 or newer on `PATH`.** The release carries no runtime, and your distribution's `nodejs` package is very often older than 22.13 -- Debian @@ -128,12 +132,15 @@ lingering for the account (`loginctl enable-linger `). A headless Pi that reboots unattended and is never logged into will otherwise sit there running nothing. -**`fleet service install` has never been run on Linux.** It has now been run -on macOS, where it runs a real fleet's brain -- so the command works and the -systemd backend specifically does not have that behind it. Every path it writes +**`fleet service install` on systemd is checked by CI, not by a deployment.** +On macOS it runs a real fleet's brain. On Linux, `systemd smoke` installs the +user unit on GitHub's Ubuntu runner, checks it with `systemd-analyze verify`, +waits for the collector it starts to answer, and uninstalls it. What that does +not cover is a reboot: the job enables lingering and starts the unit, and +nobody has watched it come back at boot on a real machine. Every path it writes is resolved absolutely, because systemd expands no `~` and reads no login -`PATH`, and none of it has been watched start here. [Headless -hosts](../deploy/headless.md) has the older, actually-deployed alternative. +`PATH`. [Headless hosts](../deploy/headless.md) has the older, +actually-deployed alternative. ## Next diff --git a/docs/install/macos.md b/docs/install/macos.md index 05dc607..59d29a1 100644 --- a/docs/install/macos.md +++ b/docs/install/macos.md @@ -4,19 +4,16 @@ curl -fsSL https://raw.githubusercontent.com/addisdev/fleet-runner/main/install.sh | sh ``` -!!! warning "This cannot work yet" +!!! note "What has been run" - **No release has been published**, so there is no archive for that script to - download and no `SHASUMS256.txt` to check it against. It will ask - `api.github.com` for the latest release, find nothing, and stop. Skip to - [from a checkout](#from-a-checkout) below, which is the path that has - actually been run on this platform. - - The script itself has been exercised against locally built archives -- - checksum verified, a tampered archive refused, a re-install leaving - `config.json` and `data/` intact. It has since been run against the real - v0.5.0 release on macOS/arm64: the checksum verified and the installed - binary reported its version. + The script downloads the latest [release](https://github.com/addisdev/fleet-runner/releases) + and refuses it unless it matches `SHASUMS256.txt`. It has been exercised + against locally built archives -- checksum verified, a tampered archive + refused, a re-install leaving `config.json` and `data/` intact -- and run + against real releases on arm64 and Intel, where the checksum verified, the + installed binary reported its version, and an install upgraded in place from + 0.5.0 to 0.6.0. Set `FLEET_VERSION` to pin a release instead of taking the + latest. **You need Node 22.13 or newer on `PATH`.** The release carries no runtime, by decision rather than oversight -- see [why](index.md#what-the-installers-do-and-what-they-refuse-to-do). @@ -29,8 +26,9 @@ line to add and the file to add it to, and leaves that to you. ## From a checkout -This is the supported path today, and on macOS/arm64 it is the one that has been -watched to work end to end. +For working on Fleet Runner itself, or running something newer than the latest +release. On macOS/arm64 this is the path that has been watched to work end to +end. ```bash git clone https://github.com/addisdev/fleet-runner diff --git a/docs/install/windows.md b/docs/install/windows.md index 550020e..9f60cc0 100644 --- a/docs/install/windows.md +++ b/docs/install/windows.md @@ -6,15 +6,15 @@ irm https://raw.githubusercontent.com/addisdev/fleet-runner/main/install.ps1 | i !!! danger "Two separate things are untested here, and the second one matters more" - **No release has been published**, so there is nothing for that line to - download. It will ask `api.github.com` for the latest release, fail, and - stop with a message naming the releases page and `$env:FLEET_VERSION`. + **`install.ps1` has never been run.** Releases publish `win32-x64` and + `win32-arm64` zips with `SHASUMS256.txt`, so there is something for that + line to download, but nobody has pointed PowerShell at it. - **And the `fleet` CLI has never been run on Windows at all.** Not the CLI, - not the supervisor, not the bundle, not the scheduled-task service backend. - The paths, the process handling and the service code are written and - untested. `fleet.yml` declares a three-platform matrix that has never - executed. + **And nobody has run a fleet on Windows.** CI runs the `fleet` CLI's suite + on `windows-latest` on every pull request that touches it, including the + supervised `fleet up` end to end, and it passes. That is the whole of it: + the bundle from an archive, `fleet service install`'s scheduled-task + backend, and a fleet left running on a Windows machine are all unwatched. What *has* been exercised on Windows is [the machine agent](../platforms.md#what-a-cloud-runner-actually-reports): its own suite @@ -53,9 +53,9 @@ Three details the script gets right that are easy to get wrong by hand: ## From a checkout -Until a release exists, this is the only path. It has never been run on Windows -either, but it has no archive to download and no `PATH` registry entry to write, -so there is less of it to be wrong. +This is what CI runs on `windows-latest`, so of the two it is the one with +something behind it. It has no archive to download and no `PATH` registry entry +to write, so there is less of it to be wrong. ```powershell git clone https://github.com/addisdev/fleet-runner diff --git a/docs/platforms.md b/docs/platforms.md index a8c7ae5..8d20453 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -14,7 +14,7 @@ that says which ones somebody has watched register is worth something. | Android phone, tablet | `runner-android` | `adb install`, or sideload | **yes** — the original shelf | | iPhone, iPad | `runner-ios` | Xcode, TestFlight internal | **yes** | | iOS simulator | `runner-ios` | `simctl install` | **yes** | -| macOS, Linux, Windows | `runner-machine` | `fleet up`, or `npm start`, or a LaunchAgent / systemd unit | **macOS yes, on both architectures** — an Apple M1 Pro and a 2016 Intel i7 both registered, passed `npm run conformance`, and produce comparable synthetic numbers with matching digests; both run under `fleet service`. Linux and Windows run their suite in CI on x64 and arm64, and neither has registered against a real collector — see [what each one reports](#what-a-cloud-runner-actually-reports) | +| macOS, Linux, Windows | `runner-machine` | `fleet up`, or `npm start`, or a LaunchAgent / systemd unit | **macOS yes, on both architectures** — an Apple M1 Pro and a 2016 Intel i7 both registered, passed `npm run conformance`, and produce comparable synthetic numbers with matching digests; both run under `fleet service`. Linux and Windows run their suite in CI on x64 and arm64. On Linux x64 the agent also registers, inside the Docker image in CI, against the collector beside it; Windows has never registered against a real collector — see [what each one reports](#what-a-cloud-runner-actually-reports) | | Android emulator | `runner-android` | `adb install` to the emulator | **yes** | ## What Wave 5 added @@ -28,13 +28,13 @@ that says which ones somebody has watched register is worth something. | **Apple TV (tvOS)** | `runner-ios`, `FleetRunnerTV` target | `devicectl` or `simctl` | **builds** — `xcodebuild -scheme FleetRunnerTV` succeeds. No Apple TV has run it | | **Vision Pro (visionOS)** | `runner-ios`, `FleetRunnerVision` target | `devicectl` or `simctl` | **no** — the target is written and has never been compiled; the visionOS platform is not installed on the machine it was written on | | **Raspberry Pi, Jetson, Steam Deck** | `runner-machine` | `install-agent.sh`, or the Docker image | **no** — but arm64 Linux in CI reports a nearly complete descriptor, so a board should register cleanly. No board has | -| **Anything with Docker** | `fleet/Dockerfile` | `docker run ghcr.io/addisdev/fleet` | **builds** — CI built and published the image for linux/amd64 and linux/arm64 at v0.5.0. **No container has been run**: Docker was not available on the machine that wrote it, so the image assembling is all that is known | +| **Anything with Docker** | `fleet/Dockerfile` | `docker run ghcr.io/addisdev/fleet` | **in CI** — every release publishes linux/amd64 and linux/arm64. CI starts the amd64 image on every pull request that touches it and waits for its own machine agent to register; the arm64 image has not been started | ## What Wave 6 added | Platform | Runner | How it joins | Verified | |---|---|---|---| -| **Roku player, Roku TV** | `runner-roku` | `build.sh --install `, then an ECP launch | **no** -- and less verified than anything above it. No Roku was available and no Roku emulator exists, so the channel has never been *compiled*, let alone run: BrightScript's only compiler is inside a television. See [Roku: the one that could not be compiled](#roku-the-one-that-could-not-be-compiled) | +| **Roku player, Roku TV** | `runner-roku` | `build.sh --install `, then an ECP launch | **no** -- and less verified than anything above it. No Roku was available and no Roku emulator exists, so the channel has never run. CI compiles it with brighterscript's `bsc` on every pull request that touches it; the firmware's own compiler has never seen it. See [Roku: the one that has never run](#roku-the-one-that-has-never-run) | | **Roku, from the executor** | `collector/src/drivers/roku.ts` | SSDP discovery on the LAN | **partly** -- the SSDP and device-info parsers are checked against recorded response shapes in `drivers.test.ts`; the UDP socket path is exercised by nothing, and no Roku has answered it | ## Android: one APK, every shape @@ -129,7 +129,7 @@ hidden in that window would be measured through the throttle. It registers with a TTL, so a tab that is *closed* leaves the shelf instead of sitting there forever as an offline device nobody can find. -## Roku: the one that could not be compiled +## Roku: the one that has never run A Roku is the cheapest always-on ARM box in most houses, it is mains-powered, and it never moves. On paper it is an ideal shelf device. @@ -137,14 +137,16 @@ and it never moves. On paper it is an ideal shelf device. is a SceneGraph channel that speaks the protocol: it registers, long-polls, runs the fold, beacons and reports. -**None of it has been run, and none of it has been compiled.** Roku has never -shipped an emulator and BrightScript exists only on the device, so there is no -`bsc`, no linter and no parse step available anywhere off a television. Every -other "no" in the tables above is a runner that at least builds. This one is a -careful hand review and nothing more, and the first syntax error in it will be -discovered by a sideload page. That is worth stating plainly here rather than -only in its README, because this page exists so that a row's last column can be -trusted. +**None of it has been run.** Roku has never shipped an emulator and +BrightScript runs only on the device. What CI does have is +[brighterscript](https://github.com/rokucommunity/brighterscript)'s `bsc`, the +community compiler: `runner-roku / brighterscript` parses and validates every +`.brs` and SceneGraph `.xml` file in the channel on each pull request that +touches it, so syntax errors and calls to functions that do not exist are +caught off the television. Whether the firmware's own compiler agrees, and +whether any of it behaves as written, is still for the first sideload to find +out. That is worth stating plainly here rather than only in its README, because +this page exists so that a row's last column can be trusted. ### It names its backend `roevp`, for the browser's reason diff --git a/fleet/Dockerfile b/fleet/Dockerfile index c4c92a5..de794c2 100644 --- a/fleet/Dockerfile +++ b/fleet/Dockerfile @@ -33,11 +33,10 @@ # fails to start without it, and `fleet doctor` says so in a sentence. An image # that needs them should install them in a layer of its own. # -# STATUS: built, never run. The release workflow built and pushed it for -# linux/amd64 and linux/arm64 at v0.5.0, so the file is at least correct enough -# to assemble. Nothing has started a container from it -- Docker was not -# available on the machine that wrote it -- so whether `fleet up` actually comes -# up inside one is unknown. +# STATUS: run in CI. Every release pushes it for linux/amd64 and linux/arm64, +# and `container smoke` in .github/workflows/fleet.yml builds it on amd64, +# starts `fleet up` in it, and waits for its own machine agent to register. The +# arm64 image is built and has not been started. # --- build the bundle ------------------------------------------------------ FROM node:22-bookworm-slim AS build diff --git a/fleet/README.md b/fleet/README.md index d36778b..1afbaa0 100644 --- a/fleet/README.md +++ b/fleet/README.md @@ -223,12 +223,21 @@ the collector under it. Two things cost an outage each on the way and are fixed `PATH` from the shell that ran the install, which is how an executor ends up unable to find `adb`. +Since 0.8.0, two CI smoke jobs in `fleet.yml` run what had only been built: + +- **systemd.** `systemd smoke` installs the built bundle as a systemd user unit on Ubuntu, + checks it with `systemd-analyze verify`, waits for its collector to answer, and uninstalls + it. +- **A container.** `container smoke` builds `fleet/Dockerfile`, starts `fleet up` in it, and + waits for its machine agent to register. Its first run found the image could not start on + a fresh volume. + What has still not been run: -- **`fleet service install` on systemd or on Windows.** The launchd backend is the one with a - real deployment behind it; the other two are written, typechecked, and unexercised. -- **A container.** `fleet/Dockerfile` is built and published by the release workflow for - linux/amd64 and linux/arm64, so it assembles; nothing has started a container from it. +- **`fleet service install` on Windows**, and the systemd unit surviving a reboot on a real + machine. +- **The arm64 container image.** The release workflow builds and publishes it; nothing has + started it. - **`install.ps1`.** No PowerShell was available to parse it, let alone run it. `install.sh` *has* been run against the real v0.5.0 release on macOS/arm64: checksum verified, binary installed and reporting its version. diff --git a/fleet/package.json b/fleet/package.json index 70084f0..7cc2a04 100644 --- a/fleet/package.json +++ b/fleet/package.json @@ -1,6 +1,6 @@ { "name": "fleet-cli", - "version": "0.7.2", + "version": "0.8.0", "private": true, "type": "module", "description": "Fleet Runner's front door: one command that runs a brain, a runner, or both.", diff --git a/fleet/src/version.ts b/fleet/src/version.ts index ab3fb71..afad63e 100644 --- a/fleet/src/version.ts +++ b/fleet/src/version.ts @@ -6,4 +6,4 @@ * it. `scripts/version.mjs` keeps it honest with the other seven places -- * see its header for why the number matters at all. */ -export const VERSION = "0.7.2"; +export const VERSION = "0.8.0"; diff --git a/install.ps1 b/install.ps1 index 0616b23..3c1cbfe 100644 --- a/install.ps1 +++ b/install.ps1 @@ -29,9 +29,9 @@ # # ## What has not been checked # -# This has never been run against a published release, because there is no -# published release yet, and the fleet CLI itself has never been run on Windows -# at all -- see fleet/README.md's Status section. Treat every line below as +# This has never been run, against a published release or anything else. The +# fleet CLI's suite passes on windows-latest in CI, but nobody has run a fleet +# on a Windows machine -- see docs/install/windows.md. Treat every line below as # untested against the real thing. $ErrorActionPreference = 'Stop' @@ -128,7 +128,7 @@ function Resolve-FleetVersion { $latest = Invoke-RestMethod -Uri $api -UseBasicParsing -Headers @{ 'User-Agent' = 'fleet-install' } } catch { Die "could not work out the latest version from $api ($($_.Exception.Message)). - Either there is no published release yet, or this address is rate limited. + Either GitHub could not be reached, or this address is rate limited. Pick one from $Releases and set `$env:FLEET_VERSION = ''." } if (-not $latest.tag_name) { diff --git a/install.sh b/install.sh index 2a77c92..49480d5 100755 --- a/install.sh +++ b/install.sh @@ -199,7 +199,7 @@ resolve_version() { head -n 1)" if [ -z "$tag" ]; then die "could not work out the latest version from ${api}. - Either there is no published release yet, or this address is rate limited. + Either GitHub could not be reached, or this address is rate limited. Pick one from ${RELEASES} and set FLEET_VERSION=." fi printf '%s' "${tag#v}" diff --git a/runner-android/app/build.gradle.kts b/runner-android/app/build.gradle.kts index fd398cb..3db81fa 100644 --- a/runner-android/app/build.gradle.kts +++ b/runner-android/app/build.gradle.kts @@ -27,7 +27,7 @@ android { minSdk = 24 targetSdk = 35 versionCode = 2 - versionName = "0.7.2" + versionName = "0.8.0" ndk { // The fleet's LLM-capable devices are all arm64; 32-bit devices diff --git a/runner-ios/project.yml b/runner-ios/project.yml index 371d2c4..7aac600 100644 --- a/runner-ios/project.yml +++ b/runner-ios/project.yml @@ -33,7 +33,7 @@ targets: settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.taylab.fleetrunner - MARKETING_VERSION: "0.7.2" + MARKETING_VERSION: "0.8.0" GENERATE_INFOPLIST_FILE: YES ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon INFOPLIST_KEY_UILaunchScreen_Generation: YES @@ -106,7 +106,7 @@ targets: settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.taylab.fleetrunner.tv - MARKETING_VERSION: "0.7.2" + MARKETING_VERSION: "0.8.0" SWIFT_VERSION: "5.9" TARGETED_DEVICE_FAMILY: "3" CODE_SIGN_IDENTITY: "" @@ -164,7 +164,7 @@ targets: settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.taylab.fleetrunner.vision - MARKETING_VERSION: "0.7.2" + MARKETING_VERSION: "0.8.0" SWIFT_VERSION: "5.9" CODE_SIGN_IDENTITY: "" CODE_SIGNING_REQUIRED: NO diff --git a/runner-machine/package.json b/runner-machine/package.json index d93d734..9c02e1c 100644 --- a/runner-machine/package.json +++ b/runner-machine/package.json @@ -1,6 +1,6 @@ { "name": "fleet-runner-machine", - "version": "0.7.2", + "version": "0.8.0", "private": true, "type": "module", "description": "Fleet Runner machine agent: turns a laptop or desktop into a device the collector can send work to.", diff --git a/runner-machine/src/descriptor.ts b/runner-machine/src/descriptor.ts index 9b7f575..61ec232 100644 --- a/runner-machine/src/descriptor.ts +++ b/runner-machine/src/descriptor.ts @@ -16,7 +16,7 @@ import { existsSync } from "node:fs"; import { out, readText, orNull, firstMatch, finite, run } from "./probe.js"; import type { Descriptor } from "./protocol.js"; -export const APP_VER = "0.7.2"; +export const APP_VER = "0.8.0"; const MB = 1024 * 1024; diff --git a/runner-roku/README.md b/runner-roku/README.md index 1cae2d8..e33dd1e 100644 --- a/runner-roku/README.md +++ b/runner-roku/README.md @@ -10,8 +10,10 @@ and reports results. > **This has never run on a Roku.** No Roku hardware was available and no Roku > emulator exists -- Roku has never shipped one, and BrightScript only runs on > the device. Everything here was written against Roku's published API -> documentation. It has not been compiled, because the only BrightScript -> compiler is the one inside a television. [What is not +> documentation. CI compiles it with +> [brighterscript](https://github.com/rokucommunity/brighterscript)'s `bsc` on +> every pull request that touches it, which catches syntax errors; the +> firmware's own compiler has never seen it. [What is not > verified](#what-is-not-verified) lists the specific claims, and the last > column of [docs/platforms.md](../docs/platforms.md) says the same thing in the > table where somebody comparing platforms would look. @@ -235,7 +237,7 @@ deciding whether to trust a number needs the list, not the footnotes. | Claim | Why it is uncertain | |---|---| -| **The channel compiles at all** | BrightScript's only compiler is on the device. There is no linter, no `bsc` and no emulator here; the code was reviewed by hand line by line and never parsed. A first sideload may well report a syntax error. | +| **The firmware compiles it** | CI parses and validates the channel with brighterscript's `bsc`, a separate implementation of the language. The compiler on the device has never seen it, and the two can disagree, so a first sideload could still report an error `bsc` accepted. | | **`roEVPDigest.Process()` reinitialises** | Roku documents it as a one-shot over the whole input but does not say whether it resets the context first. The code calls `Reset()` before every `Process()` so it is correct either way, at the cost of one interpreted call per round. | | **`Process()` returns lowercase hex** | Undocumented. The result is passed through `LCase()` before comparison, so a device that returns uppercase still agrees with the fleet. | | **`FormatJSON` writes `invalid` as `null`** | Three descriptor fields are deliberately `invalid`. If a firmware refuses to serialise them, `FormatJSON` returns `""` and the agent reports "cannot serialise the request body" rather than POSTing an empty body -- so the failure is legible, but it has not been seen either way. | diff --git a/runner-roku/manifest b/runner-roku/manifest index 865dfb4..d4022f5 100644 --- a/runner-roku/manifest +++ b/runner-roku/manifest @@ -23,7 +23,7 @@ build_version=0 # table next to a released one's. Arbitrary manifest keys are readable at # runtime, so the descriptor's version and the repo's version are one string in # one place rather than a constant in the code that drifts from the manifest. -app_ver=0.7.2 +app_ver=0.8.0 # Channel art. Roku draws the focus icon in the home grid and the splash while # the channel boots; a manifest line pointing at a file that is not in the zip