-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskfile.yml
More file actions
236 lines (219 loc) · 11.9 KB
/
Copy pathTaskfile.yml
File metadata and controls
236 lines (219 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
version: '3'
vars:
APP_NAME: "mill"
BIN_DIR: "bin"
PACKAGE_MANAGER: '{{.PACKAGE_MANAGER | default "npm"}}'
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
# Target OS for build/package/run. Defaults to the host OS, and is overridden
# by `wails3 build GOOS=...` (or the GOOS env var) for cross-compilation. The
# tasks below dispatch to the matching platform Taskfile via this variable.
GOOS: '{{.GOOS | default OS}}'
includes:
common: ./build/Taskfile.yml
windows: ./build/windows/Taskfile.yml
darwin: ./build/darwin/Taskfile.yml
linux: ./build/linux/Taskfile.yml
ios: ./build/ios/Taskfile.yml
android: ./build/android/Taskfile.yml
tasks:
regen:
summary: Regenerates every committed derived artifact after a schema/docs/seed change
desc: |
One command instead of three failed-commit round trips (goal
0134): the contract document (schema changes), the generated
user docs (userdocs/docsgen changes), the seed-fingerprint
record (deliberate golden changes -- the SeedRevision bump in
the constructor is still yours to author), and the Wails
bindings (bound-method/type changes). Idempotent; run it before
committing anything that touches those surfaces.
cmds:
- go generate ./internal/contract/...
- go generate ./internal/docsgen
- go test ./internal/services/seeding/ -run TestSeedFingerprints_MatchCommittedRecord -update
- PATH="$HOME/go/bin:$PATH" wails3 generate bindings -clean=true -ts -i
clean:
summary: Removes every build artifact from BIN_DIR
desc: |
bin/ accumulates one artifact per build shape (bin/mill, the raw
intermediate binary; bin/mill.app / bin/mill.dev.app, the packaged
bundles; bin/mill-server, server mode) and nothing ever clears
them out on its own -- across enough dev/build/package runs it
stops being obvious which one is actually current. dev/build/
build:server all depend on this so a fresh `task dev` or
`task build` is always a clean rebuild, never a stale binary
sitting next to a new one. Safe to run standalone too.
cmds:
- rm -rf {{.BIN_DIR}}
build:
summary: Builds the application
deps: [clean]
cmds:
- task: "{{.GOOS}}:build"
# Plain quotes, never backticks: backticks in a sh string are
# command substitution -- the previous wording executed
# 'task package' and 'task run' (launching the real app) just to
# print this message.
- 'echo "Built raw binary: {{.BIN_DIR}}/{{.APP_NAME}}{{exeExt}} -- this is NOT a launchable app bundle. Run ''task package'' to produce one, or ''task run'' to build and launch in one step."'
package:
summary: Packages a production build of the application
cmds:
- task: "{{.GOOS}}:package"
- '{{if eq .GOOS "darwin"}}echo "Packaged app: {{.BIN_DIR}}/{{.APP_NAME}}.app -- launch with: open {{.BIN_DIR}}/{{.APP_NAME}}.app"{{else if eq .GOOS "windows"}}echo "Packaged app: {{.BIN_DIR}}/{{.APP_NAME}}.exe"{{else}}echo "Packaged app: see {{.BIN_DIR}}/ for output"{{end}}'
install:app:
summary: Build a fully-fresh production app and install it to /Applications (macOS)
desc: |
The correct one-command reinstall -- fixes the manual-reinstall
footguns that bit repeatedly during live testing:
1. Stale frontend bundle: `task package` reuses frontend/dist,
so a Go-only change ships an old JS bundle and the app's own
build-staleness badge (correctly) flags app-commit !=
frontend-commit. This rebuilds the frontend first.
2. Stale bundle timestamp / straggler files: `ditto` MERGES into
an existing bundle rather than replacing it, so the bundle
dir mtime never refreshes and a removed-in-a-later-build file
can linger. This wipes bin/mill.app AND /Applications/Mill.app
first, then does a clean copy.
3. Wrong embedded commit: packaging before committing bakes the
old HEAD into vcs.revision. This verifies the installed
binary's embedded commit equals HEAD and warns loudly if not.
Prefer `task dev` for iterating (hot reload, no install). Use this
only when you need the real installed .app (Accessibility-gated
hotkeys, the native menu, launch/Spotlight behaviour).
cmds:
- '{{if ne .GOOS "darwin"}}echo "install:app is macOS-only"; exit 1{{end}}'
- cd frontend && {{.PACKAGE_MANAGER}} run build
- rm -rf {{.BIN_DIR}}/{{.APP_NAME}}.app
- task: package
- pkill -x {{.APP_NAME}} || true
- rm -rf /Applications/Mill.app
- ditto {{.BIN_DIR}}/{{.APP_NAME}}.app /Applications/Mill.app
- |
HEAD=$(git rev-parse HEAD)
GOT=$(go version -m /Applications/Mill.app/Contents/MacOS/{{.APP_NAME}} | sed -n 's/.*vcs.revision=//p')
if [ "$HEAD" = "$GOT" ]; then
echo "✅ Installed Mill.app @ ${GOT} (matches HEAD; no stale-build badge expected)"
else
echo "⚠️ MISMATCH: installed ${GOT} != HEAD ${HEAD} -- did you commit before installing?"
fi
run:
summary: Runs the application
cmds:
- task: "{{.GOOS}}:run"
dev:
summary: Runs the application in development mode (hot reload)
env:
# The dev app must never contend for the LaunchAgent server's MCP
# listener: both binaries fall back to 127.0.0.1:8090 when
# MILL_MCP_ADDR is unset (main.go), so a dev relaunch that wins
# the 8090 race locks the KeepAlive'd com.alicoding.mill-server
# into an EX_CONFIG respawn loop until the dev app exits. Pinning
# dev to 8091 keeps the two MCP planes disjoint by construction;
# external MCP clients keep 8090 = the managed server, 8091 = the
# dev/desktop instance.
MILL_MCP_ADDR: 127.0.0.1:8091
desc: |
Deliberately does NOT depend on `clean` (unlike build/package):
wiping bin/ on every `task dev` throws away the linked binary and
forces a from-scratch relink each start, buying nothing for the dev
loop -- Go's own compile cache and Task's binding-generation
fingerprints (frontend/bindings tracked against Go sources) are what
actually keep restarts fast, and `task clean` doesn't clear either
of those, so cleaning here just adds a slow relink. The
stale-binary confusion the clean-before-build rule guards against is
already covered for dev by the app's own build-staleness badge
(SPEC §3.8) and by dev using bin/mill.dev.app specifically. Run
`task clean` by hand, or use `task build`/`package`/`install:app`
(which still clean), when you want a guaranteed-fresh artifact.
The dev loop, so it's not re-paid needlessly: START THIS ONCE and
LEAVE IT RUNNING. Frontend edits (frontend/src/**) are instant Vite
HMR in the live window -- no rebuild, no binding regen, no reinstall.
Only a Go change restarts the app, and even then the ~20s
`wails3 generate bindings` step is SKIPPED automatically whenever Go
sources are unchanged: Task fingerprints that step against the Go
files (build/Taskfile.yml `generate:bindings` sources ->
frontend/bindings/**), so it only re-runs after a real Go change.
`wails3 dev` has no `-skipbindings` passthrough (checked directly:
its only flags are -config/-port/-nocolour/-s), so there's no
manual override -- the fingerprint IS the mechanism, which is why
not wiping bin/ (above) matters.
A second concurrent `task dev` REFUSES to start (internal/devguard,
docs/goals/BACKLOG.md Standing #8b), naming the already-running
PID instead of silently killing the first session's own vite/app.
build/config.yml's dev_mode.executes also reaps any leftover
mill.dev.app before each Go-rebuild relaunch WITHIN one session
-- the one residual, CI-unprovable gap (a real live wedge/rebuild
timing under an actually-running watcher) is named explicitly in
the manual-only registry (.claude/skills/run-mill/SKILL.md), not
silently assumed fixed.
cmds:
# Concurrent-start guard (docs/goals/BACKLOG.md Standing #8b,
# owner-hit 2026-08-12 evening: THREE concurrent mill.dev.app
# instances, a real crash risk on a 16GB machine). Runs BEFORE the
# destructive sweep below: a second `task dev` invoked while a
# first is already live must REFUSE to start, not silently kill
# the first session's own vite/app the way the sweep would --
# internal/devguard checks for an already-running `wails3 dev`
# process for this repo and exits non-zero naming its PID, which
# aborts this whole task before the sweep steps ever run (Task's
# own default: stop on the first failing cmd).
- go run ./internal/devguard -port {{.VITE_PORT}}
# Defensive orphan sweep (researched root cause, SPEC §3.8): the
# `wails3 dev` supervisor only traps SIGINT+SIGTERM, not SIGHUP, so
# closing the terminal tab (rather than Ctrl-C) kills the supervisor
# without running refresh's own cleanup -- the child mill.dev.app
# process lives on in its own process group, orphaned, and the NEXT
# `task dev` has no memory of it and launches a SECOND window. This
# kills any such leftover before starting, so a fresh `task dev`
# always begins from exactly one live instance. `|| true`: a clean
# start (no orphan) is the normal case, not an error. Only reached
# once the guard above has already confirmed no LIVE `wails3 dev`
# is running, so anything found here is safely presumed a genuine
# orphan, never a second session's own live process.
- pkill -f "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS/{{.APP_NAME}}" || true
# Same failure mode, the vite side (goal 0029, hit live tonight):
# a supervisor killed via SIGHUP can leave the vite dev server
# itself still bound to VITE_PORT (strictPort: true in
# vite.config.ts), so the NEXT `wails3 dev` fails to bind instead
# of just starting -- kill whatever's still listening first.
- lsof -ti :{{.VITE_PORT}} | xargs kill -9 2>/dev/null || true
# Disk-space warning (goal 0029, hit live tonight): a Go rebuild
# can fail or wedge SILENTLY when the disk fills up mid-link, and
# the build-identity badge has no way to tell "wedged" apart from
# "idle" from the outside -- so warn loudly up front instead.
# Non-blocking by design (never refuse to start the dev loop over
# this) -- df -Pk's portable single-line-per-filesystem format
# avoids the wrapped-output parsing footgun plain `df` has on
# long device paths.
- |
FREE_KB=$(df -Pk . | awk 'NR==2 {print $4}')
if [ -n "$FREE_KB" ] && [ "$FREE_KB" -lt 2097152 ] 2>/dev/null; then
FREE_GB=$(( FREE_KB / 1024 / 1024 ))
echo "⚠️ Disk space low (~${FREE_GB}GB free) -- Go rebuilds can fail or wedge silently, and BuildIdentityBadge's go-stale detection can't tell that apart from a healthy idle watcher. Run 'go clean -cache' to free space."
fi
- wails3 dev -config ./build/config.yml -port {{.VITE_PORT}}
setup:docker:
summary: Builds Docker image for cross-compilation (~800MB download)
cmds:
- task: common:setup:docker
setup:hooks:
summary: Installs Lefthook's git hooks (run once after cloning)
cmds:
- lefthook install
build:server:
summary: Builds the application in server mode (no GUI, HTTP server only)
deps: [clean]
cmds:
- task: common:build:server
- 'echo "Built server binary: {{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}} -- run with: ./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}"'
run:server:
summary: Runs the application in server mode
cmds:
- task: common:run:server
build:docker:
summary: Builds a Docker image for server mode deployment
cmds:
- task: common:build:docker
run:docker:
summary: Builds and runs the Docker image
cmds:
- task: common:run:docker