-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
567 lines (506 loc) · 26.7 KB
/
Copy pathMakefile
File metadata and controls
567 lines (506 loc) · 26.7 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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
# Decky Proton Pulse — Makefile
#
# Remote vs local mode:
# When DECK_IP is set, device targets (deploy, logs, get-logs, etc.) run
# against the remote Deck over SSH. When unset, they run locally.
#
# Setting DECK_IP (pick one):
# DECK_IP=192.168.1.x make deploy (one-off)
# echo '192.168.1.x' > ~/.deckip (persistent via file)
# export DECK_IP=192.168.1.x (persistent via shell env)
#
# Switching back to local mode:
# unset DECK_IP (current shell)
# rm ~/.deckip (remove persistent file)
# DECK_IP=local make <target> (force local for one command)
ifneq ($(wildcard $(HOME)/.deckip),)
DECK_IP ?= $(shell cat $(HOME)/.deckip)
endif
DECK_IP ?= steamdeck
DECK_USER ?= deck
# DECK_IP=local is a shortcut to force local mode
ifeq ($(DECK_IP),local)
override DECK_IP :=
endif
DECK_HOST ?= $(DECK_IP)
TARGET ?= stable
_DRY_RUN_FLAG := $(if $(filter false,$(DRY_RUN)),--no-dry-run,--dry-run)
DRY_RUN ?= true
IS_TERMUX := $(if $(findstring com.termux,$(PREFIX)),1,)
ifeq ($(IS_TERMUX),1)
UV_CACHE_DIR ?= $(if $(TMPDIR),$(TMPDIR)/uv-cache,$(HOME)/.cache/uv)
# Termux: uv cant download managed Python builds for Android/bionic,
# so force it to find the pkg-installed python3 on PATH
UV_PYTHON_PREFERENCE ?= system
export UV_PYTHON_PREFERENCE
else
UV_CACHE_DIR ?= /tmp/uv-cache
endif
export UV_CACHE_DIR
PROTONDB_REPO_URL ?= https://github.com/bdefore/protondb-data
PROTONDB_PROJECT_REPO_DIR := $(abspath ../protondb-data)
PROTONDB_REPO_DIR ?= $(if $(wildcard $(PROTONDB_PROJECT_REPO_DIR)/.git),$(PROTONDB_PROJECT_REPO_DIR),$(HOME)/src/protondb-data)
PROTONDB_LOCAL_OUTPUT ?= /tmp/proton-pulse-protondb-data
APP_ID ?=
SCREENSHOT_BASE ?=
SCREENSHOT_GROUP ?=
SCREENSHOT_KEY ?=
SCREENSHOT_TITLE ?=
SCREENSHOT_CAPTION ?=
SCREENSHOT_MATCH ?=
SCREENSHOT_MANIFEST ?= config/ui_screenshot_manifest.json
SCREENSHOT_TARGET ?=
SCREENSHOT_DIR ?= $(HOME)/storage/screenshots
# find pnpm: check mise path, then PATH, then npx fallback
PNPM ?= $(shell command -v pnpm 2>/dev/null || echo "npx pnpm")
# On old-glibc systems (e.g. AL2 with glibc 2.26), official Node 24 binaries
# require glibc >= 2.28. When Linuxbrew's node@24 is present, prepend it to
# PATH so every recipe shell picks it up automatically.
BREW_NODE := /home/linuxbrew/.linuxbrew/opt/node@24/bin
ifneq ($(wildcard $(BREW_NODE)/node),)
export PATH := $(BREW_NODE):$(PATH)
PNPM := $(shell command -v pnpm 2>/dev/null || echo "npx pnpm")
endif
.PHONY: default help build install watch test coverage coverage-diff test-ts test-py typecheck check-translations check-ui-strings translate setup setup-termux-ssh ensure-mise setup-remote-dev deploy deploy-local deploy-reload deploy-reload-local build-and-deploy build-and-deploy-local clean \
logs get-logs get-cef-capture take-screenshot take-video publish-screenshots-wiki take-screenshot-wiki \
package release github-release github-pre-release github-dev-release \
capture-project-screenshots \
fetch-protondb check-protondb-data logs-loader reload reload-local cef-debug-enable live-reload-enable
default: build
help:
@echo "================ usage ================ "
@echo "Usage: make <target>"
@echo " DECK_IP=192.168.1.x make deploy (remote Deck)"
@echo " DECK_IP=local make get-logs (force local mode)"
@echo ""
@echo "DECK_IP controls remote vs local mode."
@echo "When set, device targets run against the remote Deck over SSH."
@echo ""
@echo "Set DECK_IP persistently (pick one):"
@echo " echo '192.168.1.x' > ~/.deckip"
@echo " export DECK_IP=192.168.1.x"
@echo ""
@echo "Switch back to local: unset DECK_IP, rm ~/.deckip, or pass DECK_IP=local"
@echo ""
@echo "============= main targets ============= "
@printf " %-27s %s\n" "build" "Clean, test, then build frontend"
@printf " %-27s %s\n" "install" "Install plugin files into a local Decky plugin directory"
@printf " %-27s %s\n" "watch" "Watch frontend for changes (pnpm watch)"
@printf " %-27s %s\n" "test" "Run all tests, print a per-language coverage table, and enforce minimums"
@printf " %-27s %s\n" "coverage" "Run both coverage suites and fail below the enforced minimums"
@printf " %-27s %s\n" "coverage-diff" "Fail if changed lines drop below the diff coverage minimum"
@printf " %-27s %s\n" "check-translations" "Enforce translation coverage and refresh coverage metrics"
@printf " %-27s %s\n" "check-ui-strings" "Scan UI sources for likely hardcoded English strings"
@printf " %-27s %s\n" "translate" "Alias for check-translations"
@printf " %-27s %s\n" "typecheck" "Run strict pyright type checking on all Python code"
@printf " %-27s %s\n" "test-ts" "Run TypeScript tests only (vitest)"
@printf " %-27s %s\n" "test-py" "Run Python tests only (pytest via uv)"
@printf " %-27s %s\n" "setup" "Install mise (if missing), runtime toolchains, and dependencies"
@printf " %-27s %s\n" "" "Termux: uses pkg for base tools and keeps uv cache out of /tmp"
@printf " %-27s %s\n" "setup-termux-ssh" "Install and start sshd on Termux (port 8022)"
@printf " %-27s %s\n" "" "Sets password, generates host keys, prints connect instructions"
@printf " %-27s %s\n" "setup-remote-dev" "Bootstrap Deck sudoers + CEF/live-reload helpers over SSH"
@printf " %-27s %s\n" "deploy" "Build and deploy to Steam Deck (requires DECK_IP)"
@printf " %-27s %s\n" "deploy-local" "Force a local deploy without using DECK_IP/default remote host"
@printf " %-27s %s\n" "deploy-reload" "Build, deploy, then restart plugin_loader (requires DECK_IP)"
@printf " %-27s %s\n" "deploy-reload-local" "Force a local deploy, then local plugin_loader restart"
@printf " %-27s %s\n" "build-and-deploy" "Clean, test, build, and deploy (requires DECK_IP)"
@printf " %-27s %s\n" "build-and-deploy-local" "Force a local clean/test/build/deploy flow"
@printf " %-27s %s\n" "package" "Build and create the local release zip for the current VERSION"
@printf " %-27s %s\n" "release" "Build, package, and prepare a GitHub release using CHANGELOG.md notes"
@printf " %-27s %s\n" "" "Safe by default: pass DRY_RUN=false to apply live changes"
@printf " %-27s %s\n" "github-release" "GitHub-only release flow (no Decky database submission)"
@printf " %-27s %s\n" "" "Safe by default: pass DRY_RUN=false to apply live changes"
@printf " %-27s %s\n" "github-pre-release" "GitHub-only pre-release flow (no Decky database submission)"
@printf " %-27s %s\n" "" "Safe by default: pass DRY_RUN=false to apply live changes"
@printf " %-27s %s\n" "github-dev-release" "Refresh the rolling 'developer' tag + release with the current HEAD zip"
@printf " %-27s %s\n" "" "Runs every time you push plugin code so the Deck Developer channel can pull"
@printf " %-27s %s\n" "" "Safe by default: pass DRY_RUN=false to apply live changes"
@printf " %-27s %s\n" "clean" "Remove build output (dist/) and generated release archives"
@echo ""
@echo "============= device targets ============= "
@echo "On-device debugging (require DECK_IP):"
@printf " %-27s %s\n" "logs" "Follow plugin app log in real time"
@printf " %-27s %s\n" "get-logs" "Sync plugin logs from the Steam Deck into the project root"
@printf " %-27s %s\n" "get-cef-capture" "Save a local CEF debug snapshot pack from port 8081"
@printf " %-27s %s\n" "take-screenshot" "Capture the current Steam UI into \$$HOME/storage/screenshots/"
@printf " %-27s %s\n" "" "Optional: SCREENSHOT_BASE=my-name make take-screenshot"
@printf " %-27s %s\n" "" "Optional: PAGE=/library/app/1145350 make take-screenshot"
@printf " %-27s %s\n" "" "Optional: STORE_URL=https://store.steampowered.com/app/848480 make take-screenshot"
@printf " %-27s %s\n" "" "Optional: DPAD=up,a make take-screenshot (send dpad before capture)"
@printf " %-27s %s\n" "" "Optional catalog metadata: SCREENSHOT_GROUP=manage-game SCREENSHOT_KEY=default"
@printf " %-27s %s\n" "" "Optional language gallery: LANG=cn (also supports SCREENSHOT_LANGUAGE=...)"
@printf " %-27s %s\n" "take-screenshot-wiki" "Capture and register a grouped wiki screenshot"
@printf " %-27s %s\n" "" "Required: SCREENSHOT_GROUP=... SCREENSHOT_KEY=..."
@printf " %-27s %s\n" "" "Optional: SCREENSHOT_TITLE='Manage Game default' SCREENSHOT_CAPTION='...'"
@printf " %-27s %s\n" "capture-project-screenshots" "Zero-prompt batch capture for the screenshot manifest"
@printf " %-27s %s\n" "" "Uses --auto and captures each manifest step without prompting"
@printf " %-27s %s\n" "" "Optional: SCREENSHOT_MATCH=manage-game to limit the run"
@printf " %-27s %s\n" "" "Optional language gallery: LANG=cn or LANG=all (also supports SCREENSHOT_LANGUAGE=...)"
@printf " %-27s %s\n" "" "Optional review target: SCREENSHOT_TARGET=../screenshots/review or SCREENSHOT_TARGET=gist"
@printf " %-27s %s\n" "publish-screenshots-wiki" "Copy catalogued screenshots into ../decky-proton-pulse.wiki"
@printf " %-27s %s\n" "" "Also copies the saved PNG to the local clipboard when supported."
@printf " %-27s %s\n" "" "Linux tip: install wl-clipboard for Wayland clipboard copy."
@printf " %-27s %s\n" "" "Warning: this may capture private on-screen content such as account, chat, or store UI."
@printf " %-27s %s\n" "take-video" "Record the current Steam UI into ../videos/ until Ctrl+C"
@printf " %-27s %s\n" "" "Optional: SCREENSHOT_BASE=my-name make take-video"
@printf " %-27s %s\n" "" "Note: press Enter to stop and finalize cleanly."
@printf " %-27s %s\n" "fetch-protondb" "Clone or update upstream protondb-data for local inspection"
@printf " %-27s %s\n" "" "Prefers ../protondb-data when present, otherwise uses ~/src/protondb-data"
@printf " %-27s %s\n" "check-protondb-data" "Run the proton-pulse-web splitter against the local upstream repo into /tmp"
@printf " %-27s %s\n" "" "Optional: APP_ID=1145350 make check-protondb-data"
@printf " %-27s %s\n" "logs-loader" "Follow plugin_loader journal in real time"
@printf " %-27s %s\n" "reload" "Restart plugin_loader locally, or on the Deck when DECK_IP is set"
@printf " %-27s %s\n" "reload-local" "Force a local plugin_loader restart without using DECK_IP/default remote host"
@printf " %-27s %s\n" "cef-debug-enable" "Enable remote CEF debugging (React DevTools on port 8081)"
@printf " %-27s %s\n" "live-reload-enable" "Configure LIVE_RELOAD=1 on plugin_loader service"
build: clean test check-scoring-sync
@COMMIT=$$(git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
UNCOMMITTED=$$(git diff --quiet 2>/dev/null && git diff --cached --quiet 2>/dev/null || echo "+uncommitted"); \
echo "$${COMMIT}$${UNCOMMITTED}" > .build-commit
$(PNPM) build
# Sync the shared scoring module from proton-pulse-web. Run this any time
# the canonical source at ../proton-pulse-web/js/lib/scoring/ changes -- CI
# (check-scoring-sync) will fail the plugin build until you do.
sync-scoring:
node scripts/sync-scoring.mjs
# CI guard: verifies src/lib/gameStats/_synced/ hasn't been edited locally
# and (if proton-pulse-web is checked out next door) warns when upstream
# has new content that hasn't been synced yet
check-scoring-sync:
node scripts/check-scoring-sync.mjs
@echo ""
@echo "Build complete."
@echo "Next steps:"
@echo " Local install: make install"
@echo " Deck deploy: DECK_IP=192.168.1.x make deploy"
install: build
@REAL_HOME="$$(cd ~ && pwd -P)"; \
LOCAL_DIR="$${LOCAL_DECKY_PLUGIN_DIR:-$$REAL_HOME/homebrew/plugins}"; \
TARGET_DIR="$${LOCAL_DIR}/decky-proton-pulse"; \
USE_SUDO=""; \
if [ ! -d "$$LOCAL_DIR" ]; then \
echo "Decky Loader plugin directory not found: $$LOCAL_DIR"; \
echo "Install Decky Loader first, or set LOCAL_DECKY_PLUGIN_DIR to your plugin path."; \
echo ""; \
echo "Stable install command:"; \
echo " curl -L https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/install_release.sh | sh"; \
echo ""; \
echo "Pre-release install command:"; \
echo " curl -L https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/install_prerelease.sh | sh"; \
exit 1; \
fi; \
if { [ ! -w "$$LOCAL_DIR" ] && [ ! -d "$$TARGET_DIR" ]; } || { [ -d "$$TARGET_DIR" ] && [ ! -w "$$TARGET_DIR" ]; }; then \
if ! command -v sudo >/dev/null 2>&1; then \
echo "Decky Loader plugin directory needs elevated permissions, but sudo is not available."; \
echo "Plugin root: $$LOCAL_DIR"; \
echo "Target dir: $$TARGET_DIR"; \
exit 1; \
fi; \
USE_SUDO="sudo"; \
echo "Installing into root-owned Decky plugin directory with sudo: $$TARGET_DIR"; \
fi; \
echo "Installing plugin into $$TARGET_DIR"; \
$$USE_SUDO mkdir -p "$$TARGET_DIR/dist"; \
$$USE_SUDO cp dist/index.js "$$TARGET_DIR/dist/"; \
$$USE_SUDO cp main.py plugin.json package.json LICENSE "$$TARGET_DIR/"; \
$$USE_SUDO rsync -a --delete --exclude='__pycache__' lib/ "$$TARGET_DIR/lib/"
@echo "Installed. Restart Decky/plugin_loader if needed."
watch:
$(PNPM) watch
test: coverage
coverage: node_modules
$(PNPM) run coverage:check
$(PNPM) run coverage:summary
$(PNPM) run coverage:badges
coverage-diff: node_modules
$(PNPM) run coverage:check
$(PNPM) run coverage:diff
check-translations: node_modules
$(PNPM) run sync-version
$(PNPM) run check-translations
check-ui-strings: node_modules
$(PNPM) run check-ui-strings
translate: check-translations
node_modules: package.json
CI=true $(PNPM) i
test-ts: node_modules
$(PNPM) test
typecheck:
npx pyright
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run --group dev python -m mypy
test-py:
npx pyright
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run --group dev python -m mypy
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run --group dev python -m pylint main.py lib/
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run --group dev python -m pytest tests/ -v
ensure-mise:
@bash scripts/setup-toolchain.sh
setup: ensure-mise
@mkdir -p "$(UV_CACHE_DIR)"
@echo "Using UV_CACHE_DIR=$(UV_CACHE_DIR)"
$(PNPM) i
UV_CACHE_DIR=$(UV_CACHE_DIR) uv sync --group dev
# Set up SSH server on Termux so you can connect from a desktop/laptop.
# Termux sshd runs on port 8022 (not 22) since Android doesn't allow
# binding to privileged ports without root.
# Ref: https://wiki.termux.com/wiki/Remote_Access
setup-termux-ssh:
@if [ -z "$(IS_TERMUX)" ]; then \
echo "This target is only for Termux. Skipping."; \
exit 0; \
fi
@echo "=== Termux SSH setup ==="
pkg install -y openssh
@# generate host keys if they dont exist yet
@if [ ! -f "$$PREFIX/etc/ssh/ssh_host_rsa_key" ]; then \
echo "Generating SSH host keys ..."; \
ssh-keygen -A; \
else \
echo "Host keys already exist, skipping keygen."; \
fi
@# set a password so password auth works (Termux has no default password)
@echo ""
@echo "Set a login password for sshd (you'll need this to connect):"
@passwd
@echo ""
@echo "Starting sshd on port 8022 ..."
@sshd
@echo ""
@# grab the local IP and username so the user knows where to connect
@TERM_IP=$$(ip -4 addr show wlan0 2>/dev/null | grep -oP 'inet \K[\d.]+' || echo "<unknown>"); \
TERM_USER=$$(whoami); \
echo "=== SSH is running ==="; \
echo ""; \
echo "Your Termux username is: $$TERM_USER"; \
echo " (This is auto-generated by Android and cant be changed.)"; \
echo ""; \
echo "Connect from your desktop/laptop with:"; \
echo " ssh -p 8022 $$TERM_USER@$$TERM_IP"; \
echo ""; \
echo "To copy your public key (no password prompts after this):"; \
echo " ssh-copy-id -p 8022 $$TERM_USER@$$TERM_IP"; \
echo ""; \
echo "Tip: add this to ~/.ssh/config on your desktop to avoid"; \
echo "typing the username and port every time:"; \
echo ""; \
echo " Host termux"; \
echo " HostName $$TERM_IP"; \
echo " User $$TERM_USER"; \
echo " Port 8022"; \
echo ""; \
echo "Then just: ssh termux"; \
echo ""; \
echo "To stop sshd later: pkill sshd"; \
echo "To auto-start on Termux boot, add 'sshd' to ~/.bashrc"
deploy: build
bash scripts/deploy.sh --skip-build --target $(TARGET) $(if $(DECK_IP),--deck-ip $(DECK_IP),) --deck-user $(DECK_USER)
deploy-local:
@$(MAKE) deploy DECK_IP=local
deploy-reload: deploy reload
deploy-reload-local:
@$(MAKE) deploy-reload DECK_IP=local
build-and-deploy: clean test build
bash scripts/deploy.sh --skip-build --target $(TARGET) $(if $(DECK_IP),--deck-ip $(DECK_IP),) --deck-user $(DECK_USER)
build-and-deploy-local:
@$(MAKE) build-and-deploy DECK_IP=local
package: build
bash scripts/deploy.sh --skip-build
$(RELEASE_NOTES_FILE): CHANGELOG.md VERSION scripts/release-notes.mjs
node scripts/release-notes.mjs > $(RELEASE_NOTES_FILE)
release: package
bash scripts/deploy.sh --skip-build --release $(_DRY_RUN_FLAG)
github-release: package
bash scripts/deploy.sh --skip-build --github-release $(_DRY_RUN_FLAG)
github-pre-release: package
bash scripts/deploy.sh --skip-build --github-prerelease $(_DRY_RUN_FLAG)
# Rolling "developer" channel. Builds the current HEAD, deletes the existing
# "developer" tag + release, then recreates both with the freshly built zip
# attached. The Steam Deck plugin's "Developer (rolling)" update channel
# polls this release. We always force --no-dry-run since it's idempotent
# and there is nothing to confirm versus the versioned release flow
github-dev-release: package
bash scripts/deploy.sh --skip-build --github-dev-release --no-dry-run
clean:
rm -rf dist/
rm -f ./*.zip ./*.tar.gz
# ─── On-device debugging ───────────────────────────────────────────────────────
define require_deck_ip
$(if $(DECK_IP),,$(error DECK_IP is required: DECK_IP=192.168.1.x make $@))
endef
# print which mode we're running in so it's obvious in the output
define show_mode
@if [ -n "$(DECK_IP)" ]; then \
echo "[remote] DECK_IP=$(DECK_IP) DECK_USER=$(DECK_USER)"; \
else \
echo "[local] no DECK_IP set, running locally (pass DECK_IP=x.x.x.x for remote)"; \
fi
endef
REMOTE_SSH = ssh $(DECK_USER)@$(DECK_IP)
REMOTE_SSH_TTY = ssh -tt $(DECK_USER)@$(DECK_IP)
define remote_setup_hint
echo "Run: make setup-remote-dev DECK_IP=$(DECK_IP)"; \
exit 1;
endef
define remote_sudo_failure
echo "Remote sudo is not passwordless for $(1)."; \
$(call remote_setup_hint)
endef
logs:
$(call show_mode)
@if [ -n "$(DECK_IP)" ]; then \
$(REMOTE_SSH) "tail -f ~/homebrew/logs/decky-proton-pulse/plugin.log"; \
else \
tail -f $$HOME/homebrew/logs/decky-proton-pulse/plugin.log; \
fi
LOGS_DIR := $(abspath ../logs/decky-proton-pulse)
get-logs:
$(call show_mode)
@mkdir -p $(LOGS_DIR)
@if [ -n "$(DECK_IP)" ]; then \
rsync -rav $(DECK_USER)@$(DECK_HOST):~/homebrew/logs/decky-proton-pulse/ $(LOGS_DIR)/; \
else \
rsync -rav $$HOME/homebrew/logs/decky-proton-pulse/ $(LOGS_DIR)/; \
fi
@cd $(LOGS_DIR) && ls -1t *.log 2>/dev/null | grep -v '^plugin-debug\.log$$' | tail -n +20 | xargs -r rm -f
@echo ""
@echo "Logs synced to: $(LOGS_DIR)"
@ls -1t $(LOGS_DIR)/*.log 2>/dev/null | head -5 | sed 's/^/ /' || true
get-cef-capture:
$(call show_mode)
@mkdir -p ../cef-captures
@python3 scripts/get_cef_capture.py $(if $(DECK_IP),--deck-ip $(DECK_IP),) --output-dir ../cef-captures
take-screenshot:
@echo "Capturing the current Steam UI via CEF remote debugging..."
@echo "This may include private on-screen content visible on the Steam UI."
@mkdir -p $(SCREENSHOT_DIR)
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run python scripts/take_cef_screenshot.py $(if $(DECK_IP),--deck-ip $(DECK_IP) --deck-user $(DECK_USER),) --output-dir $(SCREENSHOT_DIR) $(if $(SCREENSHOT_LANGUAGE),--language $(SCREENSHOT_LANGUAGE),) $(if $(SCREENSHOT_BASE),--filename-base $(SCREENSHOT_BASE),) $(if $(SCREENSHOT_GROUP),--group $(SCREENSHOT_GROUP),) $(if $(SCREENSHOT_KEY),--shot-key $(SCREENSHOT_KEY),) $(if $(SCREENSHOT_TITLE),--title "$(SCREENSHOT_TITLE)",) $(if $(SCREENSHOT_CAPTION),--caption "$(SCREENSHOT_CAPTION)",) $(if $(STORE_URL),--store-url "$(STORE_URL)",$(if $(WEB_URL),--prepare-action-json "{\"webUrl\": \"$(WEB_URL)\"}",$(if $(PAGE),--prepare-action-json "{\"steamRoute\": \"$(PAGE)\"}",))) $(if $(DPAD),--dpad-sequence "$(DPAD)",)
take-screenshot-wiki:
$(call require_deck_ip)
ifndef SCREENSHOT_GROUP
$(error SCREENSHOT_GROUP is required: SCREENSHOT_GROUP=manage-game make take-screenshot-wiki)
endif
ifndef SCREENSHOT_KEY
$(error SCREENSHOT_KEY is required: SCREENSHOT_KEY=default make take-screenshot-wiki)
endif
@$(MAKE) take-screenshot SCREENSHOT_GROUP="$(SCREENSHOT_GROUP)" SCREENSHOT_KEY="$(SCREENSHOT_KEY)" SCREENSHOT_TITLE="$(SCREENSHOT_TITLE)" SCREENSHOT_CAPTION="$(SCREENSHOT_CAPTION)" SCREENSHOT_BASE="$(if $(SCREENSHOT_BASE),$(SCREENSHOT_BASE),$(SCREENSHOT_KEY))"
@$(MAKE) publish-screenshots-wiki
capture-project-screenshots:
@mkdir -p $(SCREENSHOT_DIR) $(SCREENSHOT_DIR)/review
@if [ -n "$(DECK_IP)" ]; then \
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run python scripts/capture_project_screenshots.py --deck-ip $(DECK_IP) --deck-user $(DECK_USER) --manifest $(SCREENSHOT_MANIFEST) --match "$(SCREENSHOT_MATCH)" --auto --output-dir $(SCREENSHOT_DIR) --wiki-dir ../decky-proton-pulse.wiki --language $(if $(SCREENSHOT_LANGUAGE),$(SCREENSHOT_LANGUAGE),$(if $(LANG),$(LANG),en)) $(if $(SCREENSHOT_TARGET),--target "$(SCREENSHOT_TARGET)",); \
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run python scripts/push_wiki_screenshots.py --wiki-dir ../decky-proton-pulse.wiki; \
else \
echo "No DECK_IP set; capturing local review screenshots"; \
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run python scripts/capture_project_screenshots.py --manifest $(SCREENSHOT_MANIFEST) --match "$(SCREENSHOT_MATCH)" --auto --output-dir $(SCREENSHOT_DIR)/review --skip-publish --language $(if $(SCREENSHOT_LANGUAGE),$(SCREENSHOT_LANGUAGE),$(if $(LANG),$(LANG),en)) $(if $(SCREENSHOT_TARGET),--target "$(SCREENSHOT_TARGET)",); \
fi
publish-screenshots-wiki:
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run python scripts/publish_screenshots_to_wiki.py --screenshots-dir $(SCREENSHOT_DIR) --wiki-dir ../decky-proton-pulse.wiki
take-video:
@echo "Recording the current Steam UI via the Deck's native gamescope video source..."
@echo "This may include private on-screen content visible on the Steam UI."
@echo "Press Enter in this terminal to stop and process the video cleanly."
@echo "Ctrl+C may interrupt make before the video finalizes."
UV_CACHE_DIR=$(UV_CACHE_DIR) uv run --with aiohttp python scripts/take_cef_video.py $(if $(DECK_IP),--deck-ip $(DECK_IP) --deck-user $(DECK_USER),) --output-dir ../videos $(if $(SCREENSHOT_BASE),--filename-base $(SCREENSHOT_BASE),)
fetch-protondb:
bash scripts/fetch-protondb.sh "$(PROTONDB_REPO_URL)" "$(PROTONDB_REPO_DIR)"
check-protondb-data: fetch-protondb
bash scripts/check-protondb-data.sh "$(PROTONDB_REPO_DIR)" "$(PROTONDB_LOCAL_OUTPUT)" "$(UV_CACHE_DIR)" "$(APP_ID)"
reload:
$(call show_mode)
@echo "Reloading Decky plugin service..."
@sleep 2
@if [ -n "$(DECK_IP)" ]; then \
echo "Reloading remote plugin_loader on $(DECK_USER)@$(DECK_IP)"; \
if $(REMOTE_SSH_TTY) "sudo -n /usr/bin/systemctl restart plugin_loader"; then \
echo "Remote plugin_loader restarted."; \
else \
echo "Remote sudo is not passwordless for plugin_loader restart."; \
echo "Recommended Deck sudoers entry:"; \
echo " $(DECK_USER) ALL=(root) NOPASSWD: /usr/bin/systemctl restart plugin_loader, /usr/bin/systemctl status plugin_loader"; \
echo "Or restart plugin_loader manually on the Deck."; \
exit 1; \
fi; \
elif systemctl list-unit-files plugin_loader.service >/dev/null 2>&1; then \
echo "Reloading local plugin_loader service"; \
if systemctl is-active --quiet plugin_loader.service 2>/dev/null || systemctl status plugin_loader.service >/dev/null 2>&1; then \
if systemctl restart plugin_loader.service >/dev/null 2>&1; then \
echo "Local plugin_loader restarted."; \
elif command -v sudo >/dev/null 2>&1; then \
sudo systemctl restart plugin_loader.service; \
echo "Local plugin_loader restarted with sudo."; \
else \
echo "plugin_loader.service exists locally but requires elevated permissions to restart."; \
exit 1; \
fi; \
else \
echo "plugin_loader.service exists locally but does not appear to be available to restart."; \
exit 1; \
fi; \
else \
echo "No local plugin_loader.service found and DECK_IP is not set."; \
echo "Use make reload DECK_IP=192.168.1.x for a remote Deck reload."; \
exit 1; \
fi
reload-local:
@$(MAKE) reload DECK_IP=local
logs-loader:
@if [ -n "$(DECK_IP)" ]; then \
$(REMOTE_SSH) "journalctl -u plugin_loader -f"; \
else \
journalctl -u plugin_loader -f; \
fi
setup-remote-dev:
@DECK_IP="$(DECK_IP)" DECK_USER="$(DECK_USER)" bash scripts/setup_remote_dev.sh
# Enable remote CEF debugging so React DevTools can connect.
# After running: open http://$(DECK_IP):8081 in a Chromium browser on your dev machine,
# or use chrome://inspect → Configure → add $(DECK_IP):8081
cef-debug-enable:
@if [ -n "$(DECK_IP)" ]; then \
$(REMOTE_SSH) "touch ~/.steam/steam/.cef-enable-remote-debugging"; \
if $(REMOTE_SSH) "ss -ltn | grep -q ':8081'"; then \
echo "CEF debugging enabled. Connect at http://$(DECK_IP):8081 in a Chromium browser."; \
else \
echo "CEF debug marker written, but port 8081 is not listening yet."; \
echo "Steam may need to be restarted manually from Game Mode or Desktop Mode."; \
exit 1; \
fi; \
else \
touch $$HOME/.steam/steam/.cef-enable-remote-debugging; \
if systemctl restart steam >/dev/null 2>&1; then \
echo "CEF debugging enabled locally. Connect at http://localhost:8081 in a Chromium browser."; \
else \
sudo systemctl restart steam; \
echo "CEF debugging enabled locally. Connect at http://localhost:8081 in a Chromium browser."; \
fi; \
fi
# Enable LIVE_RELOAD=1 on the plugin_loader service so redeploying dist/index.js
# triggers an automatic frontend reload (close the plugin panel first, then deploy).
live-reload-enable:
@if [ -n "$(DECK_IP)" ]; then \
$(REMOTE_SSH) "printf '[Service]\nEnvironment=LIVE_RELOAD=1\n' > /tmp/proton-pulse-live-reload.conf"; \
if $(REMOTE_SSH_TTY) \
"sudo -n mkdir -p /etc/systemd/system/plugin_loader.service.d && \
sudo -n install -D -m 644 /tmp/proton-pulse-live-reload.conf /etc/systemd/system/plugin_loader.service.d/live-reload.conf && \
sudo -n /usr/bin/systemctl daemon-reload && \
sudo -n /usr/bin/systemctl restart plugin_loader"; then \
echo "Live reload enabled. Close the plugin panel, then: make deploy && (plugin auto-reloads)"; \
else \
$(call remote_sudo_failure,live reload setup) \
fi; \
else \
if systemctl daemon-reload >/dev/null 2>&1; then \
sudo mkdir -p /etc/systemd/system/plugin_loader.service.d; \
printf '[Service]\nEnvironment=LIVE_RELOAD=1\n' | sudo tee /etc/systemd/system/plugin_loader.service.d/live-reload.conf >/dev/null; \
sudo systemctl daemon-reload; \
sudo systemctl restart plugin_loader; \
else \
sudo mkdir -p /etc/systemd/system/plugin_loader.service.d; \
printf '[Service]\nEnvironment=LIVE_RELOAD=1\n' | sudo tee /etc/systemd/system/plugin_loader.service.d/live-reload.conf >/dev/null; \
sudo systemctl daemon-reload; \
sudo systemctl restart plugin_loader; \
fi; \
fi
@if [ -z "$(DECK_IP)" ]; then \
echo "Live reload enabled. Close the plugin panel, then: make deploy && (plugin auto-reloads)"; \
fi