A plugin whose injection list names a service nobody provides is held pending
by Cordis: the module loads, but the fiber never mounts, so its routes are
never registered and the core static handler answers in their place. That
handler allows GET and HEAD only, so every URL the plugin's own pane calls
comes back as HTTP 405. Releases from 0.2.1-alpha.2 no longer provide
`webRuntime`, which is how the sidebar's Files pane stopped previewing and
downloading anything.
lib/web-runtime.js provides that service — only when nothing else does, so a
deployment that still has the real one (or @linxin666/dsh-remote-web-ui) is
untouched. The value is read live from the trust source this harness actually
has now: `connection.trustedHosts`, plus the listener's bind address, which
the alpha.2 /api fence accepts as a separate case and a plugin carrying the
older two-argument fence cannot see at all. `provideWebRuntime` turns it off.
Verified against the installed 0.2.1-alpha.2, end to end: the same boot with
and without the plugin gives 405 and then 400 on POST /sidebar/api/fs.tree,
the 400 being the sidebar's own handler answering. 59/59 unit tests (new
test/web-runtime.test.mjs), and scripts/live-probe.mjs — extended with the
Files-API check — reports 11/11 on the fixed build and 10/11 with the 405 on
the live one, which is the user-visible regression itself.
A page served over plain HTTP from anything but localhost is not a
secure context, so crypto.randomUUID and navigator.clipboard are simply
absent. Code that assumes them fails, sometimes loudly and sometimes as
a button that does nothing — billion-context calls
navigator.clipboard.writeText unguarded today.
Fold in what lanmode was still doing for us, so two plugins are not
needed to make one page work:
- shimRandomUuid mints the UUID from crypto.getRandomValues, which is
not restricted to secure contexts
- shimClipboard falls back to a hidden textarea and execCommand
- shimPwa serves a manifest, links it, and widens the viewport
tag to viewport-fit=cover for standalone installs
All three default on. None of them touches request identity; they live
here so that reaching the harness from another machine is one plugin's
job rather than two.
test/shims.test.mjs evaluates the generated source in a node:vm context
that lacks both APIs, so it checks the delivered code rather than the
string that delivers it. live-probe.mjs now also asserts the shims and
the manifest reach the running harness.
Checks the three surfaces the plugin is responsible for against the process
actually serving a browser: the market's fence, the shell without a token,
and the Skill Center.
The Skill Center check connects to a non-loopback local address on purpose.
Its fence requires a loopback socket as well as a loopback Host, so a probe
over 127.0.0.1 can never reproduce a remote client and always appears to
pass.