fix(build): put wails3 on PATH for the Taskfile supervisors

`make sandbox`, `make dev`, `make build-dev` and `make build-prod` all
died with "/bin/sh: wails3: command not found". `wails3 dev` and
`wails3 task` are supervisors: they run the scaffold's Taskfile tree,
which invokes `wails3` by bare name in 54 places across four files. The
CLI is a vendored Go tool by design (plan 009, D3 — a global install
would be this build's first undeclared dependency), so that name did
not exist.

scripts/toolbin/wails3 execs `go tool wails3`, and the Makefile
prepends that directory only for the targets that start a supervisor.
Rewriting 54 scaffold call sites would be churn to redo on every
scaffold refresh; nothing global is installed either way.

The shim does not cd. The first version did, to be sure `go tool` found
the module — it does not need to — and that silently discarded the
`dir:` a task had set, so generate:icons failed with "open
appicon.png: no such file or directory" against a file that was there.

Three things the build path needed once it got that far:

- `frontend/package.json` gains `build:dev`, which build:frontend runs
  under DEV=true and which did not exist.
- Vite binds 127.0.0.1. It defaulted to `localhost`, which resolves to
  `[::1]` only here, while wails3 dev's asset proxy dials IPv4 — so the
  first request for the dev server was refused and the first paint
  raced a retry. Zero proxy errors after.
- The icons and the .desktop file are generated on every build.
  icons.icns/icon.ico are deterministic from our appicon.png (verified
  by regenerating), so the regenerated pair is committed and the churn
  ends; .task/ and the .desktop file are ignored.

Also corrects a claim: build-prod strips and trims but does **not**
UPX-compress — that was v2's `-upx` flag. Phase 1 recorded UPX as
still working, but neither build target had been run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
This commit is contained in:
2026-08-14 22:49:16 -04:00
co-authored by Claude Opus 5
parent 84963e38bd
commit 453d5df0da
10 changed files with 70 additions and 8 deletions
+8
View File
@@ -54,3 +54,11 @@ coverage/
.cache/
tmp/
bin/
# Task's checksum cache, written by every `wails3 task` run.
.task/
# Generated by build/linux/Taskfile.yml's generate:dotdesktop from
# build/config.yml on every build, and consumed by the deb/rpm/AppImage
# packaging tasks that depend on it. A derived file with one source.
build/linux/yellowjacket.desktop
@@ -294,6 +294,14 @@ Taskfile tree — a genuinely larger and more visible build surface.
`make build-prod` still strips and UPX-compresses; `make skill-check`
passes; `grep -r webkit2_41` returns nothing.
> **Corrected after the fact.** `make build-prod` strips and trims
> (`-trimpath -ldflags="-w -s"`, 28.8 MB against the dev build's
> 38 MB) but **does not UPX-compress**: that was v2's `wails build
> -upx` flag, and v3's Taskfile has no equivalent. Neither `make
> build-dev` nor `make build-prod` was actually run when Phase 1 was
> recorded — both were broken until the shim below. Whether to
> reintroduce UPX is a packaging decision for Phase 7, not a port.
**Est.** Half a session. Low risk, high churn.
### Phase 1 — what actually landed
+1 -1
View File
@@ -32,7 +32,7 @@ make sandbox-seed-bulk # Same, from the bulk library (minutes; it is a real scan
make perf LABEL=<n> # Measure a running app; writes .dev/perf/<n>.json
make perf-compare BEFORE=<a> AFTER=<b> # Print the before/after table
make build-dev # Debug build with symbols
make build-prod # Production build (stripped, UPX-compressed)
make build-prod # Production build (stripped and trimmed; no UPX)
make generate # Run code generators (sqlc + templ via go generate)
make e2e # Playwright smoke suite against a running dev-headless app
make e2e-setup # Install the e2e runner + its browser (once)
+13 -6
View File
@@ -7,11 +7,18 @@ LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)'
# point elsewhere (or unset it there to share the real user dirs).
DEV_YJ_HOME ?= $(HOME)/.local/share/yellowjacket-dev
# `wails3 dev` and `wails3 task` run the scaffold's Taskfile tree, which
# invokes `wails3` by bare name. The CLI is a vendored Go tool, so the
# name only exists on PATH via this shim -- see scripts/toolbin/wails3.
# Without it every supervisor target dies with
# "/bin/sh: wails3: command not found" at its first sub-task.
TOOLBIN := $(CURDIR)/scripts/toolbin
dev: setup generate clean
if [ -f .env ]; then set -a; . ./.env; set +a; fi; : "$${YJ_HOME:=$(DEV_YJ_HOME)}"; export YJ_HOME; go tool wails3 dev -config ./build/config.yml
if [ -f .env ]; then set -a; . ./.env; set +a; fi; : "$${YJ_HOME:=$(DEV_YJ_HOME)}"; export YJ_HOME; PATH="$(TOOLBIN):$$PATH" go tool wails3 dev -config ./build/config.yml
dev-debug: setup generate clean
if [ -f .env ]; then set -a; . ./.env; set +a; fi; : "$${YJ_HOME:=$(DEV_YJ_HOME)}"; export YJ_HOME; YJ_LOG_LEVEL=debug go tool wails3 dev -config ./build/config.yml
if [ -f .env ]; then set -a; . ./.env; set +a; fi; : "$${YJ_HOME:=$(DEV_YJ_HOME)}"; export YJ_HOME; YJ_LOG_LEVEL=debug PATH="$(TOOLBIN):$$PATH" go tool wails3 dev -config ./build/config.yml
# ── Headless harness (plan 005) ──────────────────────────────────────
# The same dev server `make dev` runs, minus the blocking GTK window:
@@ -162,7 +169,7 @@ fresh-install: setup generate clean
case "$$(findmnt -no FSTYPE -T "$$YJ_HOME" 2>/dev/null)" in \
tmpfs|ramfs) echo "==> WARNING: $$YJ_HOME is RAM-backed; the search index import needs ~6GB of real disk. Set FRESH_HOME_BASE to a disk-backed path." ;; \
esac; \
go tool wails3 dev -config ./build/config.yml
PATH="$(TOOLBIN):$$PATH" go tool wails3 dev -config ./build/config.yml
# Named, persistent sandboxes: `make sandbox foo` runs dev against
# $(FRESH_HOME_BASE)/yellowjacket-sandbox-foo, creating it on first use
@@ -222,7 +229,7 @@ sandbox-%: setup generate clean
case "$$(findmnt -no FSTYPE -T "$$YJ_HOME" 2>/dev/null)" in \
tmpfs|ramfs) echo "==> WARNING: $$YJ_HOME is RAM-backed; the search index import needs ~6GB of real disk. Set FRESH_HOME_BASE to a disk-backed path." ;; \
esac; \
go tool wails3 dev -config ./build/config.yml
PATH="$(TOOLBIN):$$PATH" go tool wails3 dev -config ./build/config.yml
sandboxes: ## List existing named sandboxes
@ls -d "$(SANDBOX_DIR)"-* 2>/dev/null \
@@ -232,10 +239,10 @@ sandboxes: ## List existing named sandboxes
.PHONY: sandbox sandbox-rm sandboxes
build-dev: generate
go tool wails3 task build DEV=true
PATH="$(TOOLBIN):$$PATH" go tool wails3 task build DEV=true
build-prod: generate
go tool wails3 task build
PATH="$(TOOLBIN):$$PATH" go tool wails3 task build
build-frontend:
cd frontend && pnpm install && pnpm build
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 11 KiB

+1
View File
@@ -2,6 +2,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"build:dev": "vite build --mode development",
"preview": "vite preview"
},
"dependencies": {
+6
View File
@@ -33,6 +33,12 @@ export default defineConfig({
},
},
server: {
// IPv4, explicitly. Vite's default binds `localhost`, which on
// this machine resolves to `[::1]` *only* — and wails3 dev's
// asset proxy dials 127.0.0.1, so the app's first request for
// the dev server was answered with "connection refused" and the
// first paint raced a retry.
host: '127.0.0.1',
hmr: {
host: 'localhost',
protocol: 'ws',
-1
View File
@@ -406,7 +406,6 @@ require (
mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect
)
tool (
github.com/a-h/templ/cmd/templ
github.com/evilmartians/lefthook
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# `wails3`, for the Taskfiles that shell out to it by bare name.
#
# The CLI is a vendored Go tool (go.mod's `tool` block), invoked as
# `go tool wails3` — deliberately, so the build declares its own
# dependencies rather than assuming a global install (plan 009, D3).
# But `wails3 dev` and `wails3 task` are supervisors: they run the
# scaffold's Taskfile tree, which invokes `wails3` by name in 54 places
# across build/Taskfile.yml and the three per-platform ones. Those are
# scaffold files, and rewriting every call site is churn that would
# have to be redone whenever they are refreshed from a newer scaffold.
#
# So the name is put on PATH instead, pointing back at the vendored
# tool. The Makefile prepends this directory for the targets that
# start a supervisor; nothing else needs it, and nothing global is
# installed.
#
# Two details are load-bearing.
#
# `exec` rather than a call, so signals and the exit status reach the
# real tool: `make dev` is stopped with Ctrl-C, and a wrapper that ate
# SIGINT would leave the app running.
#
# And the working directory is left alone. An earlier version cd'd to
# the repo root to be sure `go tool` found the module -- it does not
# need that, `go tool` resolves from anywhere inside it -- and the cd
# silently discarded the `dir:` a task had set, so `generate:icons`
# (dir: build) failed with "open appicon.png: no such file or
# directory" against a file that was right there.
set -euo pipefail
exec go tool wails3 "$@"