···88make run-app # Build and launch Debug app
99make install-dev-build # Build and copy to /Applications (Debug)
1010make install-release # Build Release, sign locally, install to /Applications
1111-make format # Run swift-format only
1212-make lint # Run swiftlint only (fix + lint)
1313-make check # Run both format and lint
1111+make format-changed # Run swift-format on changed Swift files only
1212+make format # Run full-tree swift-format cleanup
1313+make lint # Run swiftlint only
1414+make check # Run changed-file format, swift-format lint, and swiftlint
1415make test # Run all tests
1516make log-stream # Stream app logs (subsystem: com.onevcat.prowl)
1617make build-cli # Build CLI (prowl) via SwiftPM
···103104- `swift-format` is the source of truth for trailing commas: multi-element collection literals keep trailing commas, while single-element collection literals may have them removed.
104105- SwiftLint runs in strict mode; never disable lint rules without permission
105106- Custom SwiftLint rule: `store_state_mutation_in_views` — do not mutate `store.*` directly in view files; send actions instead
106106-- Before creating a PR, run `make lint`.
107107+- Before creating a PR, run `make check`. Use `make format` only for intentional full-tree formatting cleanup.
107108108109## UX Standards
109110
+22-3
Makefile
···1919VERSION ?=
2020BUILD ?=
2121XCODEBUILD_FLAGS ?=
2222+FORMAT_BASE_REF ?= origin/main
22232324# Release-only analytics/crash credentials. Included from Config/Secrets.env if present,
2425# or overridable from the environment (e.g. CI). Debug builds skip SDK init regardless.
···2829PROWL_POSTHOG_HOST ?=
29303031.DEFAULT_GOAL := help
3131-.PHONY: build-ghostty-xcframework ensure-ghostty sync-ghostty _check-ghostty-hash _record-ghostty-hash build-app build-cli build-cli-release embed-cli-debug embed-cli run-app install-dev-build install-release archive export-archive format lint check test test-cli-smoke test-cli-integration bump-version bump-and-release log-stream
3232+.PHONY: build-ghostty-xcframework ensure-ghostty sync-ghostty _check-ghostty-hash _record-ghostty-hash build-app build-cli build-cli-release embed-cli-debug embed-cli run-app install-dev-build install-release archive export-archive format format-changed format-lint lint check test test-cli-smoke test-cli-integration bump-version bump-and-release log-stream
32333334help: # Display this help.
3435 @-+echo "Run make with one of the following targets:"
···303304test-cli-integration: # Run CLI integration tests via SwiftPM
304305 swift test --filter ProwlCLIIntegrationTests
305306306306-format: # Format code with swift-format (local only)
307307+format: # Format all Swift code with swift-format (full-tree cleanup)
307308 swift-format -p --in-place --recursive --configuration ./.swift-format.json supacode supacodeTests
308309310310+format-changed: # Format Swift files changed from FORMAT_BASE_REF (default: origin/main)
311311+ @base="$$(git merge-base HEAD "$(FORMAT_BASE_REF)" 2>/dev/null || git rev-parse HEAD)"; \
312312+ mapfile -t files < <( \
313313+ { \
314314+ git diff --name-only --diff-filter=ACMR "$$base" -- supacode supacodeTests; \
315315+ git ls-files --others --exclude-standard -- supacode supacodeTests; \
316316+ } | awk '/\.swift$$/' | sort -u \
317317+ ); \
318318+ if [ "$${#files[@]}" -eq 0 ]; then \
319319+ echo "No changed Swift files to format."; \
320320+ else \
321321+ printf 'Formatting %s changed Swift file(s) from %s\n' "$${#files[@]}" "$$base"; \
322322+ swift-format -p --in-place --configuration ./.swift-format.json "$${files[@]}"; \
323323+ fi
324324+325325+format-lint: # Check Swift formatting without rewriting files
326326+ swift-format lint --strict --recursive --configuration ./.swift-format.json supacode supacodeTests
327327+309328lint: # Lint code with swiftlint
310329 mise exec -- swiftlint lint --quiet --config .swiftlint.yml
311330312312-check: format lint # Format and lint
331331+check: format-changed format-lint lint # Format changed Swift files, then run swift-format lint and SwiftLint
313332314333log-stream: # Stream logs from the app via log stream
315334 log stream --predicate 'subsystem == "com.onevcat.prowl"' --style compact --color always
+4-3
README.md
···105105### Develop & test
106106107107```bash
108108-make check # swift-format + swiftlint
109109-make format # Format only
110110-make lint # Lint only
108108+make check # Format changed Swift files, then run swift-format lint + SwiftLint
109109+make format-changed # Format changed Swift files only
110110+make format # Full-tree Swift format cleanup
111111+make lint # SwiftLint only
111112make test # Run app/unit tests
112113make log-stream # Stream app logs (subsystem: com.onevcat.prowl)
113114```