reg.exe always echoes the full hive name, never the abbreviation it was given: query HKLM\SOFTWARE\… and every row comes back HKEY_LOCAL_MACHINE\SOFTWARE\…. regSubKeys built its match prefix from the HKLM\… string it was handed, so nothing ever matched and it returned [] — on every machine, for every key, always. Measured verbatim on .173:
Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — the same shape as the SQLite reader in 0.3.1: a total failure that every layer degrades into an empty library.
The contract was wrong too, and the hive bug hid it.regSubKeys returned whole key paths, while the GOG plugin uses each result as a bare name (const key = \${GAMES_KEY}\${id}`, and the subkey name *is* the product id that becomes external_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names — what the sole consumer, and its own doc comment, always assumed.
Parsing is split into an exported parseRegSubKeys(stdout, key) for the same reason parseRegQuery is exported: a text format that breaks quietly, and this one had no test coverage at all. Six tests added from the verbatim .173 output — names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, empty/error input. Four of the six fail against the old behaviour.
0.3.1 → 0.3.2.
2. Adopt the biome config its own plugins already use (10a0ef32)
The kit had no biome config and no lint script, while every plugin repo that consumes it has both — so its source drifted with nothing to catch it. First run reported 20 findings across 8 files.
Adds plugin-kit/biome.json mirroring the plugin repos', a check script, and @biomejs/biome pinned to the same ^2.5.2 (without the pin, bunx biome resolved 2.4.6, which rejects the 2.5 rules.preset key). Two deliberate differences: no vcs.useIgnoreFile (those are standalone repos with a .gitignore beside the config; this is a subdirectory, and biome errors without one), and !examples/**/dist rather than !ui/dist.
css.parser.tailwindDirectives is carried over and is load-bearing — without it biome can't parse @theme in src/theme.css and reports three parse errors on perfectly valid Tailwind v4.
Beyond formatting, two real findings, both fixed:
Layer (library/define.ts) and Cause (sync-engine.ts) imported and never used;
test/spike-httpapi.test.ts read (reg?.body as …).ui.secret one line after expect(reg).toBeDefined(). The optional chain undoes the assertion — had reg been undefined, .ui would throw a TypeError instead of failing the test readably.
Wired into plugin-kit-publish.yml as a Lint & format step ahead of Typecheck, so it can't rot again.
Gates
biome clean (42 files), tsc --noEmit clean, 67/67 tests, build clean — on each commit.
After merge
Tag plugin-kit-v0.3.2 to publish, then GOG needs a lockfile refresh and a 0.1.1 release (the published 0.1.0 cannot see any game), and only then can it be added to index#4.
Two commits, split so the fix is reviewable apart from the formatter churn.
## 1. `regSubKeys` could never return a subkey (`4edb662b`)
Found on hardware by the GOG plugin's own parity gate, on a box with exactly one GOG game installed:
```
HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST …)
host's built-in scanner: 1 entry
plugin: detect: absent, 0 games
parity FAILED — 1 missing, exit 1
```
**`reg.exe` always echoes the full hive name**, never the abbreviation it was given: query `HKLM\SOFTWARE\…` and every row comes back `HKEY_LOCAL_MACHINE\SOFTWARE\…`. `regSubKeys` built its match prefix from the `HKLM\…` string it was handed, so nothing ever matched and it returned `[]` — on every machine, for every key, always. Measured verbatim on `.173`:
```
reg.exe: [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102]
regSubKeys: []
```
Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — **the same shape as the SQLite reader in 0.3.1**: a total failure that every layer degrades into an empty library.
**The contract was wrong too, and the hive bug hid it.** `regSubKeys` returned whole key *paths*, while the GOG plugin uses each result as a bare *name* (`const key = \`${GAMES_KEY}\\${id}\``, and the subkey name *is* the product id that becomes `external_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names — what the sole consumer, and its own doc comment, always assumed.
Parsing is split into an exported `parseRegSubKeys(stdout, key)` for the same reason `parseRegQuery` is exported: a text format that breaks quietly, and this one had **no test coverage at all**. Six tests added from the verbatim `.173` output — names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, empty/error input. **Four of the six fail against the old behaviour.**
`0.3.1 → 0.3.2`.
## 2. Adopt the biome config its own plugins already use (`10a0ef32`)
The kit had **no biome config and no lint script**, while every plugin repo that consumes it has both — so its source drifted with nothing to catch it. First run reported 20 findings across 8 files.
Adds `plugin-kit/biome.json` mirroring the plugin repos', a `check` script, and `@biomejs/biome` pinned to the same `^2.5.2` (without the pin, `bunx biome` resolved 2.4.6, which rejects the 2.5 `rules.preset` key). Two deliberate differences: no `vcs.useIgnoreFile` (those are standalone repos with a `.gitignore` beside the config; this is a subdirectory, and biome errors without one), and `!examples/**/dist` rather than `!ui/dist`.
`css.parser.tailwindDirectives` is carried over and is load-bearing — without it biome can't parse `@theme` in `src/theme.css` and reports three parse errors on perfectly valid Tailwind v4.
Beyond formatting, **two real findings**, both fixed:
- `Layer` (`library/define.ts`) and `Cause` (`sync-engine.ts`) imported and never used;
- `test/spike-httpapi.test.ts` read `(reg?.body as …).ui.secret` one line after `expect(reg).toBeDefined()`. The optional chain undoes the assertion — had `reg` been undefined, `.ui` would throw a TypeError instead of failing the test readably.
Wired into `plugin-kit-publish.yml` as a `Lint & format` step ahead of Typecheck, so it can't rot again.
## Gates
biome clean (42 files), `tsc --noEmit` clean, **67/67 tests**, build clean — on each commit.
## After merge
Tag `plugin-kit-v0.3.2` to publish, then GOG needs a lockfile refresh and a **0.1.1** release (the published 0.1.0 cannot see any game), and only then can it be added to [index#4](https://git.unom.io/unom/punktfunk-plugin-index/pulls/4).
The kit had NO biome config and no lint script, while every plugin repo that
consumes it has both. So its source quietly drifted — unused imports, unsorted
imports, formatting — with nothing to catch any of it. Running biome here for
the first time reported 20 findings across 8 files.
Adds `plugin-kit/biome.json` mirroring the plugin repos' (tab indent, double
quotes, recommended lint preset, organizeImports), a `check` script, and
`@biomejs/biome` pinned to the same `^2.5.2` the plugins pin — without that pin
`bunx biome` resolved 2.4.6, which rejects the 2.5 `rules.preset` key.
Two deliberate differences from the plugin repos' copy:
* no `vcs.useIgnoreFile` — those are standalone repos with a .gitignore beside
the config; plugin-kit is a directory inside this one, and biome errors with
"couldn't find an ignore file". The `files.includes` exclusions cover it.
* `!examples/**/dist` instead of `!ui/dist` — the kit has examples, not a UI.
`css.parser.tailwindDirectives` is carried over and is load-bearing: without it
biome cannot parse `@theme` in src/theme.css and reports three parse errors on
CSS that is perfectly valid Tailwind v4.
Everything here is formatter/import churn except two real findings, both fixed:
* `Layer` (library/define.ts) and `Cause` (sync-engine.ts) were imported and
never used;
* test/spike-httpapi.test.ts read `(reg?.body as …).ui.secret` one line after
`expect(reg).toBeDefined()`. The optional chain undoes the assertion: had
`reg` been undefined the `.ui` access would throw a TypeError instead of
failing the test readably. Now asserted to the type system too.
Wired into plugin-kit-publish.yml as a `Lint & format` step ahead of Typecheck,
so this cannot rot again.
Gates after: biome clean (42 files), tsc clean, 67/67 tests, build clean.
Found on hardware by the GOG plugin's own parity gate, on a box with exactly one
GOG game installed:
HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST ...)
host's built-in scanner: 1 entry
plugin: detect: absent, 0 games
parity FAILED - 1 missing, exit 1
`reg.exe` ALWAYS echoes the full hive name in its output rows, never the
abbreviation it was given: query `HKLM\SOFTWARE\...` and every line comes back
`HKEY_LOCAL_MACHINE\SOFTWARE\...`. regSubKeys built its match prefix from the
`HKLM\...` string it was handed, so no line ever matched and it returned `[]` —
on every machine, for every key, always. Measured verbatim on .173:
reg.exe: [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102]
regSubKeys: []
Its only consumer is the GOG plugin, so the symptom was "GOG reports no games
installed" rather than an error — the same shape as the SQLite reader in 0.3.1:
a total failure that every layer degrades into an empty library.
The contract was wrong too, and the hive bug hid it. regSubKeys returned whole
key PATHS while the GOG plugin uses each result as a bare NAME
(`const key = \`${GAMES_KEY}\\${id}\``, and the subkey name IS the product id
that becomes `external_id`). Even with the prefix fixed, paths would have
composed nonsense keys. It now returns names, which is what the sole consumer
and its own comment always assumed.
Parsing is split into an exported `parseRegSubKeys(stdout, key)` for the same
reason `parseRegQuery` is exported — this is a text format that breaks quietly,
and it had NO test coverage at all. Six added, using the verbatim .173 output:
names not paths, multiple subkeys, grandchildren ignored, the queried key is not
its own subkey, case-insensitivity, and empty/error input. Four of the six FAIL
against the old behaviour.
0.3.1 -> 0.3.2. Gates: biome clean, tsc clean, 67/67 tests, build clean.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two commits, split so the fix is reviewable apart from the formatter churn.
1.
regSubKeyscould never return a subkey (4edb662b)Found on hardware by the GOG plugin's own parity gate, on a box with exactly one GOG game installed:
reg.exealways echoes the full hive name, never the abbreviation it was given: queryHKLM\SOFTWARE\…and every row comes backHKEY_LOCAL_MACHINE\SOFTWARE\….regSubKeysbuilt its match prefix from theHKLM\…string it was handed, so nothing ever matched and it returned[]— on every machine, for every key, always. Measured verbatim on.173:Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — the same shape as the SQLite reader in 0.3.1: a total failure that every layer degrades into an empty library.
The contract was wrong too, and the hive bug hid it.
regSubKeysreturned whole key paths, while the GOG plugin uses each result as a bare name (const key = \${GAMES_KEY}\${id}`, and the subkey name *is* the product id that becomesexternal_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names — what the sole consumer, and its own doc comment, always assumed.Parsing is split into an exported
parseRegSubKeys(stdout, key)for the same reasonparseRegQueryis exported: a text format that breaks quietly, and this one had no test coverage at all. Six tests added from the verbatim.173output — names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, empty/error input. Four of the six fail against the old behaviour.0.3.1 → 0.3.2.2. Adopt the biome config its own plugins already use (
10a0ef32)The kit had no biome config and no lint script, while every plugin repo that consumes it has both — so its source drifted with nothing to catch it. First run reported 20 findings across 8 files.
Adds
plugin-kit/biome.jsonmirroring the plugin repos', acheckscript, and@biomejs/biomepinned to the same^2.5.2(without the pin,bunx biomeresolved 2.4.6, which rejects the 2.5rules.presetkey). Two deliberate differences: novcs.useIgnoreFile(those are standalone repos with a.gitignorebeside the config; this is a subdirectory, and biome errors without one), and!examples/**/distrather than!ui/dist.css.parser.tailwindDirectivesis carried over and is load-bearing — without it biome can't parse@themeinsrc/theme.cssand reports three parse errors on perfectly valid Tailwind v4.Beyond formatting, two real findings, both fixed:
Layer(library/define.ts) andCause(sync-engine.ts) imported and never used;test/spike-httpapi.test.tsread(reg?.body as …).ui.secretone line afterexpect(reg).toBeDefined(). The optional chain undoes the assertion — hadregbeen undefined,.uiwould throw a TypeError instead of failing the test readably.Wired into
plugin-kit-publish.ymlas aLint & formatstep ahead of Typecheck, so it can't rot again.Gates
biome clean (42 files),
tsc --noEmitclean, 67/67 tests, build clean — on each commit.After merge
Tag
plugin-kit-v0.3.2to publish, then GOG needs a lockfile refresh and a 0.1.1 release (the published 0.1.0 cannot see any game), and only then can it be added to index#4.The kit had NO biome config and no lint script, while every plugin repo that consumes it has both. So its source quietly drifted — unused imports, unsorted imports, formatting — with nothing to catch any of it. Running biome here for the first time reported 20 findings across 8 files. Adds `plugin-kit/biome.json` mirroring the plugin repos' (tab indent, double quotes, recommended lint preset, organizeImports), a `check` script, and `@biomejs/biome` pinned to the same `^2.5.2` the plugins pin — without that pin `bunx biome` resolved 2.4.6, which rejects the 2.5 `rules.preset` key. Two deliberate differences from the plugin repos' copy: * no `vcs.useIgnoreFile` — those are standalone repos with a .gitignore beside the config; plugin-kit is a directory inside this one, and biome errors with "couldn't find an ignore file". The `files.includes` exclusions cover it. * `!examples/**/dist` instead of `!ui/dist` — the kit has examples, not a UI. `css.parser.tailwindDirectives` is carried over and is load-bearing: without it biome cannot parse `@theme` in src/theme.css and reports three parse errors on CSS that is perfectly valid Tailwind v4. Everything here is formatter/import churn except two real findings, both fixed: * `Layer` (library/define.ts) and `Cause` (sync-engine.ts) were imported and never used; * test/spike-httpapi.test.ts read `(reg?.body as …).ui.secret` one line after `expect(reg).toBeDefined()`. The optional chain undoes the assertion: had `reg` been undefined the `.ui` access would throw a TypeError instead of failing the test readably. Now asserted to the type system too. Wired into plugin-kit-publish.yml as a `Lint & format` step ahead of Typecheck, so this cannot rot again. Gates after: biome clean (42 files), tsc clean, 67/67 tests, build clean.Found on hardware by the GOG plugin's own parity gate, on a box with exactly one GOG game installed: HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST ...) host's built-in scanner: 1 entry plugin: detect: absent, 0 games parity FAILED - 1 missing, exit 1 `reg.exe` ALWAYS echoes the full hive name in its output rows, never the abbreviation it was given: query `HKLM\SOFTWARE\...` and every line comes back `HKEY_LOCAL_MACHINE\SOFTWARE\...`. regSubKeys built its match prefix from the `HKLM\...` string it was handed, so no line ever matched and it returned `[]` — on every machine, for every key, always. Measured verbatim on .173: reg.exe: [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102] regSubKeys: [] Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — the same shape as the SQLite reader in 0.3.1: a total failure that every layer degrades into an empty library. The contract was wrong too, and the hive bug hid it. regSubKeys returned whole key PATHS while the GOG plugin uses each result as a bare NAME (`const key = \`${GAMES_KEY}\\${id}\``, and the subkey name IS the product id that becomes `external_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names, which is what the sole consumer and its own comment always assumed. Parsing is split into an exported `parseRegSubKeys(stdout, key)` for the same reason `parseRegQuery` is exported — this is a text format that breaks quietly, and it had NO test coverage at all. Six added, using the verbatim .173 output: names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, and empty/error input. Four of the six FAIL against the old behaviour. 0.3.1 -> 0.3.2. Gates: biome clean, tsc clean, 67/67 tests, build clean.