# Changelog

## 0.8.12

- **The plugin declares its own message-source kind, because DSH 0.2.0-rc.2 deleted the shared `plugin` kind.** `MessageSourceMap` is a merge-extensible union and its note now says so outright — "there is no shared catch-all `plugin` kind"; each producer names itself, the way upstream's `webhook`, `schedule` and `cordis-host-runner` do. `/mobile` therefore steers a `dsh-on-phone`-sourced `user/message` that still commits to the durable log and still carries the `notice`-form one-line summary, and the client — which projects any unknown producer as an inject row labelled by its kind — now labels the collapsed row `dsh-on-phone` instead of `plugin`.
- **The npm package and the GitHub release build from the same commit.** 0.8.11 was published to npm a few commits before it was tagged, so the two copies differed in five files; both are now packed from the tagged tree, and the tarballs hold the same 22 files with byte-identical contents. Compare the unpacked files rather than the archive hashes: the gzip envelope is not part of that guarantee, since the packer's zlib can differ between the machine that publishes and the runner that builds the release.
- **The compatibility checker asks the source that owns a contract, instead of one file name.** It pinned `data-conversation-scroll` to `ConversationRoot.tsx` and `isLoopback` to setting `connection.isLoopback` directly, so DSH moving the former to `ConversationContent.tsx` and reading the latter as `ctx.remote.$host.isLoopback` made CI red while nothing was actually broken. Both assertions now search `packages/client/ui-conversation/src` and `packages/client/ui-settings/src`. The `data-plan-review-scroll` marker upstream deleted is reported on stderr rather than failed: the plan-review panel still renders, but this plugin's mobile scroll cap no longer applies to it.
- **`npm run verify` no longer depends on the machine it runs on.** Three separate failures only ever happened on GitHub runners: Windows passed a bare `D:\...` path to `import()` and Node read the `d:` as a URL scheme, so `check:bundle` could not load the bundle; Windows could not spawn the fake tailscale CLI, which was a `#!/bin/sh` script and then a `.cmd` shim that `execFile` refuses without a shell, so five `serve` lifecycle tests read an empty call log; and one test named port 38082 outright and really did hit `EADDRINUSE` on a Linux runner. Bundles are now imported through their `file://` URL, the controller's `bin` can be an executable plus the arguments it is always spawned with (so Windows runs the fake through an interpreter), and the tests ask the host for a free port.
- **The development dependencies now match the contract this plugin declares.** They still tested against `dsh-llm`, `dsh-commands` and `dsh-host-webserver` 0.1.1-rc.2 while the peers already claimed up to 0.2.0-rc.2, so the source was never compiled against the release it says it supports — which is how the deleted source kind above went unnoticed. They move to 0.2.0-rc.2, together with cordis 4.0.4, schemastery 3.18.4, tsdown 0.23.0, TypeScript 7.0.2, vitest 5.0.3 and js-yaml 5.4.2. Two follow-on edits: the bundle-patch test is rewritten for js-yaml 5 (`defineScalarTag` and `JSON_SCHEMA.withTags` replace `new Type()` and `Schema.extend()`, and one `resolve` now both validates and constructs), with `@types/js-yaml` dropped because 5 ships its own types; and the react peer widens to `^18.2.0 || ^19.0.0` rather than moving to 19 — the client half takes react from the host, which still ships 18, so narrowing that peer would deny the version actually in use while declaring the one that is not.

Notable changes to dsh-on-phone are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.

## 0.8.11

- **The version number is aligned with the `dsh-mobile-tailscale` line this repository tracks, instead of counting on its own.** The code carries that line through 0.8.11 — the two phone fixes below are the last of it — and 0.8.11 is the next release of it, so the number now says so. `0.1.0`–`0.1.2` below were this repository's own numbering and none of them was ever published: the repository has no tags and 0.8.11 is the first version to reach npm, so nothing was ever installed under those numbers. The package name, the plugin id and the `$DSH_HOME/mobile-access/` paths are unchanged. `check:version` and `check:release-tag` read the number from `package.json`, so the release tag is now `v0.8.11`.
- **The transcript no longer rubber-bands vertically (carried from `dsh-mobile-tailscale` 0.8.10).** WebKit fires a scroll event every frame while the transcript bounces at an end, and the app answers each one — re-pinning its follow-the-tail floor, re-compensating while older pages land — so the render is repositioned at frame rate and the picture springs up and down, small but fast. The `overscroll-behavior-x` on the page frame and on `[data-conversation-scroll]` becomes the axis-free `overscroll-behavior`, so there is no bounce and no per-frame event to answer; the horizontal travel that rule was written for stays closed, and tables, code blocks and the open-files strip keep the inner scrollers granted above.
- **A long press on the settings page no longer turns the whole surface translucent (carried from 0.8.11).** The app renders that page as `div[role="dialog"][tabindex="-1"]`, an ancestor of everything the finger can land on inside it, and this plugin's own layout stretches that box to 100vw × 100dvh. A press marks the whole ancestor chain `:active`, so while the press-feedback matcher listed a bare `[tabindex]` the rule put `opacity:.72` on a full-screen box and the layer underneath showed through for the length of the press. `tabindex="-1"` is a programmatic focus target by definition and never a tap target, so it is dropped from the matcher, and `role="dialog"` joins the structural exclusions in both the global and the workbench feedback rule.
- **DSH 0.2.0-rc.2 is now a declared peer, because 0.2.0 added a gate that skipped this bundle outright.** 0.2.0-rc.2 checks every profile bundle's own DSH peers while composing the profile and *skips* an incompatible bundle that has no exemption, listing it in `skippedBundles` — the plugin stayed installed and simply never loaded, so the panel, the proxy and the client half all vanished with no error and no dialog. All five DSH peers (`dsh-client-connection`, `dsh-client-ui-sidebar`, `dsh-commands`, `dsh-host-webserver`, `dsh-llm`) now list `0.2.0-rc.2`, and `SUPPORTED_DSH_VERSIONS` carries it too, so the advisory warning no longer fires on the current runtime. Nothing else changed: the interfaces this plugin reaches for are still those of 0.2.0-rc.2 — the host still exports the prefix `webServer.register` route, `commands.register` with `handler`/`rawInput`/`steer`, and `dsh-llm/message`'s `boundContextSummary`/`createUserMessage`; the client manifest still reads `dsh.client.inject`/`platform`/`immediately`; and the desktop internals the session guard patches (`doOpen`, `openGeneration`, `openState`, `retentionSnapshot`, `openSession`, `isLoopback`, `reconnect`) all still resolve. Granting the exact-version exemption instead of upgrading works too, but neither a plugin upgrade nor a DSH upgrade inherits it, so every later prerelease would ask again.
