Files
warp-engine-client/Makefile
T
mr.zeroandClaude Opus 5 06f3f2a3b1
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
The store engine moves into the client, and Python goes with it
Reading the catalog, choosing the release that fits this machine, unpacking it,
writing the menu entry and remembering what went where all happen in process now.
There is no interpreter to find, no child process, and no JSON-lines protocol
between the two halves — `PythonEngineProcessRunner`, the runtime locator, the two
engine mappers and the version negotiation are all gone, and with them the one
unchecked cast this codebase had (engine stdout to a typed event).

What that buys a person: on Windows and on a fresh Mac the app simply works. It
used to look for `python3`, `python` and `py -3` and draw a link to python.org
where none answered.

What lands on disk is unchanged, deliberately. `config.json` and `state.json` keep
the shell engine's snake_case shape, its `<scope>:<name>` keys and its file modes,
so a machine whose library was installed by the CLI keeps it — verified against the
Python engine on the same catalog: the same 13-title listing with zero field
differences, byte-identical payloads, identical modes and an identical Info.plist,
and a re-sync over a Python-installed home that writes nothing. Remove, prune,
prune-suppression on a named sync and the v1 state migration were each exercised.

Three things worth knowing about the new code:

  - the zip reader is ~150 lines over `node:zlib`, because Node has none and this
    application has no runtime dependencies. It restores the executable bit from
    each entry's external attributes, without which nothing installed can start,
    and it refuses zip64, unknown compression and paths that escape the
    destination rather than guessing;

  - `SUPPORTED_WARP_ENGINE_VERSIONS` names the engine versions this client is
    written against, checked against the `WarpEngine-Version` header every
    response carries. `selectCatalogDialect` switches over that list exhaustively,
    so adding a version fails the build — type checker and linter both — until
    somebody says what its catalog reads like. An absent header is read as the
    oldest version, which is what an engine before 0.4.0 is;

  - refresh and the language picker are icons at the foot of the side menu now,
    both named for a tooltip and a screen reader, the picker still a real
    `<select>` under its glyph.

The repository is free of Python as well: the Makefile, the CI check and the
release script read package.json and the forge's JSON with Node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 23:36:25 +02:00

123 lines
4.7 KiB
Makefile

# WarpEngine Client — the front door to the npm scripts.
#
# Everything here is a thin wrapper: the app is an Electron project, so npm still
# does the work. The Makefile exists so the useful sequences have names, and so
# `make release` is one command rather than a build followed by remembered tea
# invocations.
#
# make list the targets
# make setup install the dependencies
# make check typecheck, lint and both test suites
# make dist package for this machine
# make release package and publish to Gitea
#
# Publishing assumes `tea` is installed and logged in — the devarea repo has
# `make tea` for that.
SHELL := /bin/sh
SCRIPTS := scripts
NODE_MIN := 22
# The version is package.json's, so the release tag never drifts from the app. Read with
# node, which this project already requires — nothing here needs an interpreter the app
# itself no longer depends on.
VERSION := $(shell node -p 'require("./package.json").version')
TAG ?= v$(VERSION)
# Which site's store registry a packaged build reads. Empty means the default in
# package.json (ours); set it to build a client for somebody else's catalog:
#
# make dist STORES_API=https://games.example.org/api/stores
#
# It is baked into the package's own package.json, so the built app carries it. A runtime
# STORES_API still overrides it, which is for trying something out rather than shipping.
STORES_API ?=
BUILDER_ARGS := $(if $(STORES_API),-- --config.extraMetadata.warpEngine.registryUrl=$(STORES_API),)
.DEFAULT_GOAL := help
.PHONY: help setup node-check build typecheck lint lint-fix check start smoke uitest test \
dist dist-mac dist-win dist-linux release publish clean distclean version
help: ## List available targets
@echo "WarpEngine Client $(VERSION) — usage: make <target>"
@echo
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}'
@echo
@echo " Variables: TAG=$(TAG) TEA_LOGIN=ttg REPO=<owner/name> NOTES=RELEASE_NOTES.md"
node-check: ## Check the Node version Electron's installer needs
@node -e 'const [maj] = process.versions.node.split("."); \
if (Number(maj) < $(NODE_MIN)) { \
console.error("Node $(NODE_MIN)+ is needed to install Electron (found " + process.versions.node + \
"): its installer is ESM-only. The packaged app carries its own runtime."); \
process.exit(1); \
} else { console.log("node " + process.versions.node + " ok"); }'
setup: node-check ## Install the dependencies
npm install
build: ## Compile TypeScript and bundle the preload and the renderer
npm run build
typecheck: ## Type-check everything, emitting nothing
npm run typecheck
lint: ## Lint with the strict rule set
npm run lint
lint-fix: ## Lint and fix what can be fixed automatically
npm run lint:fix
# The order is deliberate: a type error explains a lint error, and both explain a
# failing test, so the cheapest check that can fail runs first.
check: typecheck lint test ## Type-check, lint, and run both test suites
start: ## Run the app against whatever store is installed
npm start
smoke: ## Drive the store bridge with no window at all
npm run smoke
uitest: ## Load the window once and report what rendered
npm run uitest
test: smoke uitest ## Both checks
dist: node-check ## Package for this machine
npm run dist $(BUILDER_ARGS)
dist-mac: node-check ## Package for macOS (ad-hoc signed, see the README)
npm run dist:mac $(BUILDER_ARGS)
dist-win: node-check ## Package for Windows
npm run dist:win $(BUILDER_ARGS)
dist-linux: node-check ## Package for Linux
npm run dist:linux $(BUILDER_ARGS)
publish: ## Upload the packages already in dist/ to the Gitea release
@TAG=$(TAG) $(SCRIPTS)/release.sh
# clean first: dist/ keeps earlier builds, and a release should be made of exactly
# what this version produced.
release: clean dist publish ## Package for this machine and publish it
clean: ## Remove the compiled output and the built packages
rm -rf build dist
distclean: clean ## Remove the packages and the dependencies
rm -rf node_modules
version: ## Show the versions involved
@echo "app $(VERSION) (tag $(TAG))"
@printf "node "; node --version 2>/dev/null || echo "missing"
@printf "npm "; npm --version 2>/dev/null || echo "missing"
@printf "electron "; node -p "require('./package.json').devDependencies.electron" 2>/dev/null || echo "missing"
@printf "typescript "; npx tsc --version 2>/dev/null || echo "missing"
@printf "eslint "; npx eslint --version 2>/dev/null || echo "missing"
@printf "tea "; tea --version 2>/dev/null | head -1 || echo "missing — devarea: make tea"
@printf "registry "; node -p 'require("./package.json").warpEngine.registryUrl'
@if [ -n "$(STORES_API)" ]; then printf " build override: %s\n" "$(STORES_API)"; fi