Commit Graph
28 Commits
Author SHA1 Message Date
sneak 8746591889 Merge branch 'next' into header-utc-clock
check / check (push) Successful in 2m6s
2026-11-07 05:23:40 +01:00
sneak 053c00cd52 Merge pull request 'macOS: ignore on-link default routes when picking the physical uplink' (#18) from macos-onlink-default-route into next
check / check (push) Successful in 2m43s
Reviewed-on: #18
2026-11-07 05:23:30 +01:00
sneak bbceab0b24 Show UTC as the first header clock instead of hardcoded Los Angeles time
check / check (push) Successful in 2m0s
The header drew the host's local time and then America/Los_Angeles
time, so on a Mac in that zone both clocks read the same and neither
was UTC. The first clock is now UTC and the second the host's local
time, which also drops the hardcoded zone and its load-failure path.
2026-11-06 19:12:41 -08:00
sneak 6dc3b9e395 macOS: ignore on-link default routes when picking the physical uplink
check / check (push) Successful in 2m32s
A VM with NAT networking makes vmnet install a default route scoped to
its bridge (bridge100) with no gateway. The detector counted it as a
second physical default route and refused to start:

    multiple physical default-route interfaces found (bridge100, en0)

Scoped routes cannot simply be dropped: while a VPN holds the default
route, the physical interface keeps only a default route scoped to
itself. That route still names its gateway (flag G). The on-link one
does not, so a physical default route now requires a next-hop gateway.

parseNetstat records a gateway only when the G flag is set; a link#N
gateway column is the interface itself, not a next hop.
2026-11-06 19:08:12 -08:00
clawbot 7686440108 Bring TODO.md up to date with next and the tracker (closes #13)
check / check (push) Successful in 3m18s
The workflow lines now say who merges where: clawbot squash-merges
reviewed issue PRs into next, only sneak merges next into main, and a
deploy is a squash commit from main onto prod, never automatic.

Status lists what is on next today, each item linked to its issue: the
repo standards, interface detection on Linux and macOS, the macOS VPN
detection fix, the Starlink status lines, the version stamp, and CI
running script/cibuild. Next Step is the owner's merge of the milestone
PR and a first run on a real Mac.

Model: opus-5-5
2026-10-04 03:43:39 +02:00
clawbot 3578d18777 macOS: show the VPN pane only while a VPN is connected (closes #8)
check / check (push) Successful in 3m1s
A utun tunnel counted as the VPN whenever it was up with a routable
IPv4 address, so idle Tailscale or a tunnel left behind by a
disconnected client became the VPN pane and its probes failed. A
tunnel is now the VPN only while it carries the IPv4 default route in
netstat: an unscoped default row, or both 0/1 and 128.0/1 rows on it.
A default row scoped to a tunnel (flag I) does not count; on the
physical interface it still does, since a VPN holding the default
leaves the physical default scoped. Tests feed netstat text in the
macOS layout through the parser into Select. Not run on a real Mac.

Model: opus-5-5
2026-10-03 15:26:39 +02:00
clawbot 66fb8bf149 Refresh apt package lists before bootstrap installs anything (closes #12)
check / check (push) Successful in 2m23s
The CI job image ships with empty apt package lists, so the bootstrap's
`apt-get install -y golang` could not find the package and every CI run
stopped there. On the apt path the bootstrap now runs `apt-get update`
once, before the first install, and not at all when nothing needs
installing.

Model: opus-5-5
2026-10-03 15:09:39 +02:00
clawbot bce8bdbb2e Stamp the git tag or short commit into the binary (closes #10)
check / check (push) Failing after 3s
rtnetmon had no version. main.Version is now set at link time and logged
in the first startup line. `make build` and `make dev` set it from
`git describe --tags --always` unless VERSION is given. The Dockerfile
takes it from the VERSION build argument when one is given, otherwise
from `git describe --tags --always` of the .git the build context now
carries, and fails the build if the context carries .git and no version
comes out. .dockerignore follows the canonical copy: .git is sent,
.git/config, which can hold a credential, is not.

Model: opus-5-5
2026-10-02 10:21:25 +02:00
clawbot 769511dec2 Add Starlink status lines for the physical gateway pane (closes #3) (#7)
check / check (push) Failing after 5s
Detection is a TCP connect to the dish endpoint bound to the physical
interface; once a dish answers, get_status is read every 5s and two
status lines render under the physical pane, red on disconnect or
alert. No dish: nothing drawn, no RPC. Minimal vendored proto bindings
for get_status only. Independent review passed (PR 7 comment 100012).

Model: opus-4-8 (implementation and review); model: claude-fable-5
(merge)
2026-09-22 20:56:01 +02:00
clawbot 486a47397c Detect interfaces per platform; add macOS and single-interface support (closes #2)
check / check (push) Failing after 0s
Linux runs exactly as before when both bridge interfaces exist. When they do
not, the lone default-route interface is monitored, and a single interface
draws a single UI pane instead of an empty second one.

macOS is newly supported: a running VPN tunnel (utun) is monitored as the
primary pane alongside the physical default-route interface, or the physical
interface alone when no VPN is up.

Detection lives in internal/netdetect: interface/route data types, pure
selection logic keyed on OS name, and route parsers, all unit-tested on Linux
for both platforms. Only the real route query and the per-platform TCP dial
binding are build-tagged. NewMonitor now takes a list of interfaces.

Not verified on a real mac: live netstat parsing, IP_BOUND_IF dialing, Mullvad leak protection.

Model: opus-4-8 (implementation); fable-5-1 (landing commit)
2026-09-21 15:01:59 +02:00
clawbot 7dd4ac798d Adopt repo standards: scaffold, policies, lint-clean (closes #1)
check / check (push) Failing after 0s
Standard scaffold: script/ entrypoints with the Makefile as thin shims, a Dockerfile whose lint and test phases gate the build, a Gitea CI workflow running script/cibuild, REPO_POLICIES.md, TODO.md, .editorconfig, .dockerignore, LICENSE, wider .gitignore. .golangci.yml is byte-identical to the canonical copy in the prompts repo.

211 lint findings fixed in code: package globals became functions/fields and a cobra command constructor, magic numbers became named constants, ctx is threaded into the probes, monitor loops split. Tests moved to external _test packages with export_test.go. Behavior unchanged.

Readers will trip over: make lint/test/check now need a Docker daemon; the personal rsync copy/run targets are gone and make run runs locally.
Disclosure: four //nolint:gosec remain on the fixed-argv ping/curl calls and the operator-chosen log file, as the reference repo annotates the same class.
Disclosure: module path left as-is.

Model: opus-4-8 (implementation); fable-5-1 (merge)
2026-09-21 09:22:28 +02:00
sneak cf9dc39053 latest 2026-09-20 22:56:40 -07:00
sneak a8ab26752a initial 2026-01-06 10:20:34 -08:00
sneak 0e1fc6a88d latest 2025-05-21 21:34:06 -07:00
sneak 2ad2aef700 higher frame rate, PL meter 2025-05-21 21:24:20 -07:00
sneak 29b96b3405 fix import 2025-05-21 11:29:36 -07:00
sneak bf1ec22492 add library 2025-05-21 11:23:08 -07:00
sneak 3ac8e9b450 bugfix 2025-05-21 11:22:57 -07:00
sneak e5546fedd4 add aider stuff 2025-05-16 05:28:39 -07:00
sneak 9298891565 fix: remove colorization from standard deviation display in drawIface 2025-05-16 05:14:48 -07:00
sneak 67a5a0d545 fix: align columns and colorize numbers in drawIface function 2025-05-16 05:13:30 -07:00
sneak 25dca3f857 latest 2025-05-16 05:03:53 -07:00
sneak 6955b10ec6 control-c works now 2025-05-16 04:49:41 -07:00
sneak 5d6ce56406 color! 2025-05-16 04:42:41 -07:00
sneak 31936b21a2 add module 2025-05-16 04:29:55 -07:00
sneak 3d543f9c5b latest 2025-05-16 04:29:05 -07:00
sneak 26e7fd997f latest 2025-05-16 04:25:04 -07:00
sneak 9d2aa2b4de initial 2025-05-16 04:20:20 -07:00