- Go 63.3%
- Shell 18.3%
- Python 16.4%
- Dockerfile 0.9%
- CSS 0.6%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
## What this does Replaces the fake, CSS-dressed macOS/Windows tray screenshots with genuine captures, per platform issue [#648](Grey.ooo/Someones.Computer#648). | Platform | Scene | Before | After | |---|---|---|---| | macOS | `menu`, `running`, `built`, `failed` | Linux GTK menu tinted blue | **Genuine** — captured via `tart` on Apple silicon | | Windows | `menu` | Linux GTK menu tinted blue | **Genuine** — captured via an unattended Windows Server install on Proxmox | | Windows | `running`, `built`, `failed` | Linux GTK menu tinted blue | **Not captured this round** — old fakes deleted rather than left mislabelled | `themes/macos.css` and `themes/windows.css` are deleted; the dressing pipeline (`run.sh`'s `DRESSED`/`HERO`) is retired entirely rather than kept half-alive to paper over the Windows gap. `docs/manual.md`'s "dressed for other platforms" section is rewritten to show what's actually genuine per platform instead of the retired disclaimer. ## A real bug this surfaced Windows never showed a tray icon at all, silently — `Shell_NotifyIcon`'s `LoadImage` call rejects the embedded PNG (it wants a real `.ico` container) and fails in a way that logs a misleading "operation completed successfully". Nobody had run genuine Windows before to notice. Fixed with a platform-specific `icon.ico`, embedded only on Windows (`internal/tray/icon_windows.go` / `icon_other.go`), rendered from the same solo-mark SVG by `hack/icons/render.sh`. ## What's still open (partial completion, by design) This issue explicitly anticipated a partial hand-back being fine. What's left, tracked back on #648: - **Windows `running`/`built`/`failed`.** The top-level tray menu opens and photographs cleanly (see the screenshot below), but driving *into* a submenu (`shop · #12` → a deployment row) never expanded it, keyboard-only, on this Windows Server 2022 build — see `hack/tray-vm-capture/README.md` for exactly what was tried. A session with real mouse access to the guest (Proxmox's `vncproxy` refused every connection attempt this session, for reasons unresolved) should just click it. - **rrru is down.** The Proxmox mule the issue's plan was written around is unreachable — confirmed dead at the network layer (ARP failure from the bastion on its own LAN segment), not a sandboxing artifact. With the repo owner's go-ahead, macOS ran on the operator's own Apple-silicon Mac via `tart` instead, and Windows ran on `grey-area` (production) instead of the mule — both one-offs, not standing runners. - **No Packer template, no nightly runner yet.** Both platforms were driven by hand this session (documented step by step in `hack/tray-vm-capture/README.md`) rather than by the one-command automation the issue's "Shape of the run" describes. The Windows `autounattend.xml` committed here is "what it should do", not "what ran" — a two-CD-ROM confusion in Windows Setup's own media detection meant most of the actual install was driven by hand; see the README for the workaround that wasn't fully proven either. ## Evidence **macOS — all four states, genuine:** .
Status: v1, menu-only
| Works today | Stubbed, and what it waits on |
|---|---|
| Tray icon + menu on Linux (D-Bus SNI) and Windows; macOS builds locally (cgo) | — |
| Application list and per-deployment status, resynced every 10 s | Device-flow login — platform /cli/auth/*; today it reads sc login's credential store or $SC_TOKEN |
| Per-deployment toggles — Activate, and a confirming second click to stop; each row offers only the gesture the platform will accept | Rich windows — the runway chart, schedule editor and log viewer are v2, in Fyne |
| Follows an activation to running/failed and raises one desktop notification (macOS, Linux) | Press-and-hold to stop, with an animation: needs a real window, so it lands with v2 |
| A refused activation surfaces a Top up credit… row pointing at the org's billing page | |
| Says who it is signed in as, and against which endpoint | |
| An icon that follows the OS theme — the brand's solo mark as a macOS template image, redrawn black-on-light and white-on-dark by the menu bar itself | Per-state icons — animated while deploying, badged on failure, dimmed when signed out |
| Applications grouped under their organization, whose heading carries the balance, a block-element sparkline of the day's spend, and the runway | |
| An unread-notification row, shown only when there is something unread | |
Shared auth with sc via scclient |
Run it
go build ./cmd/sc-tray
SC_ENDPOINT=https://someones.computer ./sc-tray # token from `sc login`, or $SC_TOKEN
Linux needs a StatusNotifierItem host (KDE, MATE/XFCE trays, GNOME with the AppIndicator extension).
The menu's shape is drawn once from the first fetch: every later poll updates titles and shows or hides the two gestures, but an application or deployment that appears afterwards asks for a restart on the status line rather than half-drawing. Rows can be shown, hidden and retitled in place, which is all a toggle needs; rebuilding the tree as it changes is a v2 concern, alongside the Fyne rich windows.
A Linux capture — the manual has the same menu on macOS and Windows too, taken off real hardware/VMs rather than dressed up. The manual is the tour of every state, generated from the capture run below.
Switching off asks twice. A running deployment's row holds a
Confirm stop <name> entry rather than stopping on the click that opens it —
teardown removes a live stack, and a tray row is easier to fat-finger than a
page button. Switching on is a single Activate <name>: its failure mode is a
deploy, not an outage. Only the gesture the platform would accept is shown, so
a click never comes back 409.
Policy: every feature is proved by a picture, and the pictures are the manual
A tray app is only ever seen as a menu, so a menu nobody has looked at is an untested app. Go tests here can check the labels a function returns; they cannot tell you the applications ended up underneath Quit, which is exactly what the first capture found. So:
- Every feature carries a capture — one scene per state a user meets.
hack/screenshotruns the real binary against a fixed scene on a headless desktop and photographs the menu at each step. There is a scene for being signed out, for an unreachable platform, for the empty case, for each state a deployment can be in, for a refused activation, for one in flight, and for an application appearing or disappearing under a menu whose shape is already fixed. A change that alters what the menu shows, offers or hides re-runs the suite and commits the result — the diff indocs/images/is the review. - The captures are read for defects, not just attached. They exist to be looked at. Anything that reads wrong in a shot — order, wording, a gesture offered when it shouldn't be — is a bug found before a user found it. What the current suite found on its way in is filed as platform #838, #839, #841 and #844.
- What a machine can check, it checks.
cmd/menudumpprints the tree the running binary exported over DBus, andcheck.shdiffs each scene's dumps against that scene's golden — labels, order, nesting, and which rows are disabled or hidden. The same program routes the walk:menudump --toturns a named row into the keystrokes that reach it, so a row that moved is re-reached and a row that is gone fails the run. Counting keypresses instead is how two committed captures came to show rows they did not claim to. - The captures compose into the user manual. docs/manual.md is every state, in the order a person meets it, illustrated by the capture that state produced and quoting the menu that walk recorded. It is generated from the same run, so it cannot drift from the app: a stale screenshot in it means a stale run, and re-running fixes both. CI fails a manual that is not what the scenes and captures produce.
- A shot claiming to be a platform has to come off that platform. The
suite captures every state in Linux, undressed. macOS and Windows are
captured for real too — off a Mac and off a Windows VM, one scene at a
time by hand rather than by the automated Linux harness — shown together
at the end of the manual. Neither is complete yet: macOS has all four
applicationsstates, Windows has one (#648 tracks the rest). What never happens again is dressing a Linux capture in another platform's colours to stand in for the real thing — see hack/screenshot/README.md and hack/tray-vm-capture/.
Gates
Same shape as the platform repo's, in Go terms — one definition each, so a laptop and CI cannot drift:
| Check | Command | Is |
|---|---|---|
| Static analysis | hack/lint.sh |
golangci-lint from a pinned image: staticcheck, govet, errcheck, unused, plus bodyclose, errorlint, gosec, gocritic, misspell. Configured in .golangci.yaml, no baseline — the gate is "no findings" |
| Coverage | hack/coverage.sh |
a ratchet: every package's figure is recorded in coverage.floor, and a drop fails. --bump raises them |
| Captures | hack/screenshot/run.sh |
every scene, photographed, then asserted, then assembled into the manual — see the policy above. --bless accepts a changed menu. Runs in CI too, against the current binary rather than the committed captures |
| Menu | hack/screenshot/check.sh |
the same menus as text, one golden per scene under hack/screenshot/scenes/. The half a machine can check, so a row moving fails the build rather than waiting to be spotted in a PNG |
| Manual | hack/screenshot/manual.py check |
that docs/manual.md is what the scenes and their captures produce, and that no capture is unclaimed and no claimed capture missing — the discipline the platform repo's make lint-screenshots applies to its user guide |
| Icons | hack/icons/render.sh |
rasterises hack/icons/*.svg into the two PNGs the binary embeds. Run it when the mark moves; the SVG geometry is copied from the platform repo's templates/_mark.html.twig |
Those first three files are duplicated verbatim in someones.computer_scclient
and someones.computer_agent, and are meant to stay identical.
The figure is low here on purpose, and the ratchet is why it can be. Most of this package is menu callbacks the OS drives and systray mutation that needs a display; a line-coverage target would be met by testing the wrong things. The capture suite is what actually exercises those paths, and the ratchet stops the number rotting downwards while that suite grows to replace it — it started at 17% and the org tree brought it to 27.7%, which is the ratchet doing its job in the direction it is supposed to turn.
Shared code
The /cli client and the credential store come from the
scclient module —
the wire contract shared with sc, vendored here so CI builds offline (the
module is private and the Actions token is repo-scoped). Inside the platform
repo's checkout, its go.work resolves scclient by path instead, so contract
changes are developed against both consumers at once.
