Repository navigation
Expand file tree
/
Copy pathTaskfile.yml
More file actions
253 lines (233 loc) · 12.4 KB
/
Copy pathTaskfile.yml
File metadata and controls
253 lines (233 loc) · 12.4 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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
version: '3'
# lich is a pure-Go binary (no CGO) serving its embedded frontend to a Chromium
# --app window — see docs/chromium-shell.md. That window is lich's own, an
# embedded Chromium built out of shell/ (Rust, CEF) and launched like a
# browser, on Linux, Windows and Apple Silicon; an Intel Mac still opens the
# system browser. Linux first; Windows and macOS supported.
vars:
APP_NAME: "lich"
BIN_DIR: "bin"
VITE_PORT: '{{.LICH_VITE_PORT | default 9245}}'
# Package version follows the git tag (env VERSION overrides) — no manual bump.
# The tag is trimmed in the template, not with sed: Task's shell is mvdan/sh
# on every OS, and a plain Windows box has no sed on PATH — the pipeline would
# fail silently and stamp an empty version into the binary.
RAW_VERSION:
sh: echo "${VERSION:-$(git describe --tags --always 2>/dev/null)}"
VERSION: '{{trimPrefix "v" .RAW_VERSION}}'
# -X main.version stamps the git tag into the binary so the in-app update
# check knows what it is running (dev builds via `go run` stay "dev").
LDFLAGS: '-s -w -X main.version={{.VERSION}}'
GO_BUILD_FLAGS: '-trimpath -ldflags "{{.LDFLAGS}}"'
tasks:
build:frontend:
desc: Build frontend/dist (embedded by the Go binary)
cmds:
- cmd: cd frontend && pnpm install --frozen-lockfile && pnpm run build
build:shell:
desc: Build the window (embedded Chromium) into bin/shell/
# Skipped while bin/shell is up to date with the crate: the window changes
# far less often than the Go side, and `task dev` should not wait on cargo
# for it.
sources:
- shell/src/**/*
- shell/Cargo.toml
- shell/Cargo.lock
- shell/.cargo/config.toml
- shell/build.rs
- build/cef.sh
- build/linux/shell/assemble.sh
- build/windows/shell/assemble.sh
- build/darwin/shell/assemble.sh
- build/windows/shell/lich-shell.exe.manifest
- build/windows/lich.ico
generates:
- "{{.BIN_DIR}}/shell/lich-shell{{exeExt}}"
- "{{.BIN_DIR}}/shell/{{if eq OS \"windows\"}}libcef.dll{{else if eq OS \"darwin\"}}Chromium Embedded Framework.framework{{else}}cef/libcef.so{{end}}"
vars:
# Where build/cef.sh puts the CEF distribution: CEF_DIR when set (CI
# points it at .cef, and caches it), else a per-user cache shared by
# every worktree on the same CEF version. kurogane links nothing of CEF:
# the window loads libcef when it starts, so the distribution is only
# what assemble.sh ships beside the binary.
CEF_DIR:
sh: bash build/cef.sh --dir
cmds:
# The Go binary stays pure and static; the window is a separate Rust
# binary on CEF, found beside it at run time (internal/chromium/shell.go).
# assemble.sh strips libcef.so and keeps only the runtime files lich
# needs — the 1.4 GB distribution becomes ~300 MB.
- cmd: cd shell && cargo build --release
# Through bash on purpose: Task's own shell runs the command line, but a
# script file needs a real sh, and git-bash is the one every Windows
# machine with git has.
- cmd: bash build/cef.sh "{{.CEF_DIR}}"
- cmd: build/linux/shell/assemble.sh shell/target/release "{{.CEF_DIR}}" {{.BIN_DIR}}/shell
platforms: [linux]
- cmd: bash build/windows/shell/assemble.sh shell/target/release "{{.CEF_DIR}}" {{.BIN_DIR}}/shell
platforms: [windows]
- cmd: build/darwin/shell/assemble.sh shell/target/release "{{.CEF_DIR}}" {{.BIN_DIR}}/shell
platforms: [darwin]
build:
desc: Build the static binary into bin/ (with the window beside it)
deps: [build:frontend, build:shell]
cmds:
# {{exeExt}}: `go build -o bin/lich` writes exactly that name — no .exe —
# and Windows then refuses to exec it (PATHEXT resolution needs the
# extension), so `task run` fails on the binary `task build` just made.
- cmd: CGO_ENABLED=0 go build {{.GO_BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}{{exeExt}} .
build:native:
desc: Build the native window into bin/lich-native (cgo; libghostty-vt on PKG_CONFIG_PATH, native/slice.sh)
# Its own module and binary, built with cgo (docs/native-window.md); it
# never reaches the lich binary's build. The packages ship it beside lich,
# where `lich native` and Settings › Window look for it.
dir: native
cmds:
- cmd: CGO_ENABLED=1 go build -trimpath -ldflags "-s -w" -o ../{{.BIN_DIR}}/lich-native ./cmd/lich-native
build:native:windows:
desc: Cross-build bin/lich-native.exe from Linux with Zig (native/build-windows.sh)
cmds:
- cmd: sh native/build-windows.sh ../{{.BIN_DIR}}/lich-native.exe
icons:windows:
desc: Regenerate rsrc_windows_amd64.syso from build/windows/lich.ico
cmds:
# The .syso is the resource the Windows executable links, and it is the
# only source of the exe's icon: the Start Menu shortcut and the native
# file picker (an in-process COM dialog) both draw it. Nothing rebuilds
# it automatically, so a new lich.ico that skips this task ships an
# executable still wearing the previous mark. lich.ico itself comes out
# of build/appicon.py, with appicon.png and appicon-256.png.
- cmd: go run github.com/akavel/rsrc@v0.10.2 -ico build/windows/lich.ico -arch amd64 -o rsrc_windows_amd64.syso
build:windows:
desc: Cross-compile the Windows binary
deps: [build:frontend]
cmds:
# GUI subsystem: no console window rides along. stdout/stderr go
# nowhere — the persistent lich.log is the diagnostic surface.
- cmd: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags "{{.LDFLAGS}} -H=windowsgui" -o {{.BIN_DIR}}/{{.APP_NAME}}.exe .
build:mac:
desc: Cross-compile the macOS binaries
deps: [build:frontend]
cmds:
# Both arches: Apple Silicon (arm64) and Intel (amd64). Pure Go, so both
# cross-compile from any host. Unsigned — Gatekeeper quarantines until
# notarization ships (INSTALL.md says what a user has to do about it).
- cmd: CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build {{.GO_BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-darwin-arm64 .
- cmd: CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build {{.GO_BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-darwin-amd64 .
bundle:mac:
desc: Wrap the macOS binary and both windows in bin/Lich.app (macOS host only)
deps: [build:mac, build:shell]
# The native window builds apart (cgo, libghostty-vt), as for package.
preconditions:
- sh: test -x {{.BIN_DIR}}/lich-native
msg: "bin/lich-native is missing: task build:native puts it there"
cmds:
# The binary cross-compiles from anywhere; the bundle needs Apple's sips
# and iconutil for the icon, so this task only runs on a Mac.
- cmd: build/darwin/bundle.sh {{.BIN_DIR}}/{{.APP_NAME}}-darwin-{{ARCH}} {{.VERSION}} {{.BIN_DIR}} {{.BIN_DIR}}/shell {{.BIN_DIR}}/lich-native
run:
desc: Build and run
deps: [build]
cmds:
- cmd: ./{{.BIN_DIR}}/{{.APP_NAME}}{{exeExt}}
dev:
desc: Dev mode — Vite HMR, isolated DB, port and Chromium profile
deps: [build:shell]
cmds:
# frontend/dist must exist for go:embed to compile, even though the
# window loads the Vite server; build it once, then serve with HMR.
# Dev isolation: separate DB (LICH_DEV, store.databasePath), separate
# listener port and Chromium profile (LICH_DEV_URL side effect), so a
# daily-driver lich keeps running untouched.
- cmd: |
set -e
# Ctrl+C reaches the whole process group and takes Vite with it;
# closing the window instead leaves it, and the dev backend, running (Task's shell has no
# kill and its `$!` is not a pid). The next run's Vite then dies on
# strictPort in the background, unseen, while the window loads the
# survivor, which serves whatever checkout it was started from. So
# the port is proved free before anything else, and a taken one stops
# the run here.
node -e "const s = require('net').createServer(); s.once('error', () => { console.error('task dev: port {{.VITE_PORT}} on 127.0.0.1 is taken, most likely by the Vite of an earlier task dev whose window was closed. That Vite serves its own checkout, not this one. Stop it (ss -ltnp \'sport = :{{.VITE_PORT}}\' on Linux, lsof -i :{{.VITE_PORT}} on macOS) or set LICH_VITE_PORT to another port.'); process.exit(1) }); s.listen({{.VITE_PORT}}, '127.0.0.1', () => s.close())"
(cd frontend && pnpm install --frozen-lockfile && pnpm run build)
(cd frontend && pnpm run dev) &
# node, not `sleep`: Task interprets every command with its own shell
# (mvdan/sh) on every OS, where sleep is no builtin — a plain Windows
# box has no such binary on PATH and `task dev` dies right here. node
# is already required by the pnpm line above.
node -e "setTimeout(() => {}, 1500)"
# go run leaves the binary in a temp dir, where the bundled-window
# lookup finds nothing; the pin names the window build:shell made.
# The build reports "dev" unless VERSION is set: `VERSION=Unreleased
# task dev` is how the What's new dialog is smoked against the
# [Unreleased] changelog section, `VERSION=v0.44.0` against a release.
LICH_DEV=1 LICH_DEV_URL="http://127.0.0.1:{{.VITE_PORT}}" LICH_LISTEN_PORT=47822 LICH_SHELL="{{.ROOT_DIR}}/{{.BIN_DIR}}/shell/lich-shell{{exeExt}}" go run {{if env "VERSION"}}-ldflags "-X main.version={{.VERSION}}" {{end}}.
test:shell:
desc: Run the window crate's suite (Linux, macOS)
platforms: [linux, darwin]
cmds:
# --release shares cargo's CEF download and C++ wrapper build with
# build:shell; a debug profile would fetch and build both again.
- cmd: cd shell && cargo test --release
test:
desc: Run the backend, frontend and window suites
cmds:
- cmd: go test ./...
- cmd: cd frontend && pnpm test
- task: test:shell
pricing:refresh:
desc: Reprice internal/pricing/prices.json from LiteLLM — run it when cutting a release
cmds:
# The baked floor is what an offline install prices with, so it drifts from
# the day it ships. This only reprices the ids already in the file; which
# models the floor carries stays a hand-picked list.
- cmd: go run internal/pricing/genfloor.go
mutation:
desc: Mutation tests via gremlins — .gremlins.yaml, scope with -- ./internal/pkg/
preconditions:
- sh: command -v gremlins
msg: "gremlins is required: go install github.com/go-gremlins/gremlins/cmd/gremlins@latest"
cmds:
# No path → whole module (slow: single-worker, terminal spawns real PTYs).
# Scope a run with: task mutation -- ./internal/store/
- cmd: gremlins unleash {{.CLI_ARGS}}
package:
desc: Build the Linux packages (deb, rpm, archlinux)
deps: [build]
# The native window builds apart (cgo), in CI on an older glibc than a
# developer's machine: it is put in bin/ first, not rebuilt here.
preconditions:
- sh: test -x {{.BIN_DIR}}/lich-native
msg: "bin/lich-native is missing: task build:native puts it there"
cmds:
- task: package:nfpm
vars: { FORMAT: deb, TARGET: '{{.APP_NAME}}.deb' }
- task: package:nfpm
vars: { FORMAT: rpm, TARGET: '{{.APP_NAME}}.rpm' }
- task: package:nfpm
vars: { FORMAT: archlinux, TARGET: '{{.APP_NAME}}.pkg.tar.zst' }
package:windows:
desc: Build bin/lich-setup.exe with the window inside (needs Inno Setup 6, on Windows)
# The window only builds on Windows itself (MSVC, CEF's wrapper), which
# is also the only place iscc runs; build:windows alone still
# cross-compiles the bare exe from anywhere.
deps: [build:windows, build:shell]
preconditions:
- sh: command -v iscc
msg: "iscc (Inno Setup 6) is required — on Windows: choco install innosetup"
- sh: test -f {{.BIN_DIR}}/lich-native.exe
msg: "bin/lich-native.exe is missing: task build:native:windows cross-builds it from Linux"
env:
VERSION: '{{.VERSION}}'
cmds:
- cmd: iscc build/windows/lich.iss
package:nfpm:
internal: true
preconditions:
- sh: command -v nfpm
msg: "nfpm is required: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest"
env:
VERSION: '{{.VERSION}}'
GOARCH: amd64
cmds:
- cmd: nfpm package -f build/linux/nfpm/nfpm.yaml -p {{.FORMAT}} -t {{.BIN_DIR}}/{{.TARGET}}