Files
punktfunk/scripts/windows/scripting-run.cmd
enricobuehler c7c9500e89 fix(windows/scripting): the runner task writes a log file, so a runner that can't reach the host is no longer silent
Field report 2026-08-18, Windows host on 0.30: PunktfunkScripting task Running, Playnite and
Steam plugins installed, library empty, and "no logs at all for plugins" — nowhere on the box.

That is by construction, not by accident. The runner's only log door is the log shipper, which
tees console output to `POST /plugins/logs` over the mgmt API; the scheduled task itself had no
console and no file. So every failure that stops the runner reaching the host — LocalService
lost its read grant on plugin-token / native-cert.pem, a moved mgmt bind, a TLS pin miss, a
401 — is exactly the failure the shipper cannot report, and it leaves the same picture:
task Running, plugins never registering, an empty grid, and nothing to send when asked for logs.

`scripting-run.cmd` now redirects the runner's stdout+stderr to
`%ProgramData%\punktfunk\plugin-state\runner.log`, keeping the previous run as `runner.log.1`.
plugin-state is the one directory `plugins enable` makes writable for LocalService, and it
inherits Users-read from the config dir, so the operator can `type` it from any prompt.
Writability is probed with `copy /y nul` first; if the dir is not writable (the task was started
by the installer before `plugins enable` ever ran) the runner starts unlogged as before rather
than not at all. No `goto`: the file is stored LF and cmd's label scan is unreliable there.

The console's empty-Plugins hint (en/de) and the plugin docs now name the file; the log-ship
header no longer claims the task writes no file. Verified by reading only — no Windows box
reachable from here; the cmd semantics used (`copy nul` as a write probe, `if defined` blocks,
leading redirect on `echo`) are the boring ones.
2026-08-18 22:26:08 +02:00

48 lines
2.4 KiB
Batchfile

@echo off
rem punktfunk plugin/script runner launcher - the action the PunktfunkScripting scheduled task runs.
rem
rem OPT-IN: the installer registers that task DISABLED (the runner is inert until you add automation).
rem Enable it once you have scripts/plugins: Enable-ScheduledTask -TaskName PunktfunkScripting
rem
rem Lays out next to the installed payload: {app}\scripting\scripting-run.cmd + runner-cli.js and
rem {app}\bun\bun.exe (so %~dp0 = {app}\scripting\). The runner discovers the operator's units under
rem %ProgramData%\punktfunk\{scripts,plugins}; a plugin's connect() auto-wires to the host's SCOPED
rem plugin-token + identity cert in %ProgramData%\punktfunk\ (written by the host's `serve`). The
rem task runs as NT AUTHORITY\LocalService - `plugins enable` grants it read on exactly those two
rem files. No env editing.
setlocal EnableExtensions
set "BUN=%~dp0..\bun\bun.exe"
set "RUNNER=%~dp0runner-cli.js"
if not exist "%RUNNER%" (
echo [punktfunk-scripting] runner bundle missing at "%RUNNER%".
exit /b 1
)
if not exist "%BUN%" (
echo [punktfunk-scripting] bundled bun missing at "%BUN%".
exit /b 1
)
rem The runner import()s the operator's .ts plugin files, so it runs on the bundled bun. SIGTERM (task
rem End) interrupts the whole unit tree structurally so plugin finalizers run before exit.
rem
rem Its stdout/stderr go to a file: a scheduled task has no console, and the runner's other log door
rem (shipping lines to the host's Logs page) needs the very connection whose failure is what you'd
rem be trying to read about - a runner that can't reach the host was silent everywhere (field report
rem 2026-08-18: task Running, plugins installed, "no logs at all"). plugin-state is the one dir
rem `plugins enable` makes writable for LocalService; the file inherits Users-read from the config
rem dir, so `type` it from any prompt. One previous run is kept as runner.log.1. If the dir isn't
rem writable (task started before `plugins enable` ever ran), start unlogged rather than not at all.
rem ponytail: no size cap within one run - rotate on size if a chatty plugin ever fills a disk.
set "LOG=%ProgramData%\punktfunk\plugin-state\runner.log"
set "LOGGED="
if exist "%LOG%" move /y "%LOG%" "%LOG%.1" >nul 2>&1
copy /y nul "%LOG%" >nul 2>&1 && set "LOGGED=1"
if defined LOGGED (
>> "%LOG%" echo [punktfunk-scripting] %DATE% %TIME% starting "%BUN%" "%RUNNER%" as %USERNAME%
"%BUN%" "%RUNNER%" >> "%LOG%" 2>&1
) else (
"%BUN%" "%RUNNER%"
)