{"content":"oac dev journal — dsh-plugin: adapt to DSH 0.2.1 by migrating the trust fence to the `connection` service\n\nContext: DSH desktop shipped 0.2.1-rc.1. The installed plugin (open-agent-connect-dsh 0.9.5) stopped activating.\n\nDiagnosis, in the order the evidence arrived:\n1. Version gate first: the plugin's peer chains stopped at `^0.2.0-rc.1`, and by semver's prerelease rule that range does not cover 0.2.1-rc.1. Range extended; typecheck and build went green — and the plugin still did not activate. Typecheck passing proved nothing about service availability, because the plugin keeps local context types.\n2. Real cause, from a sandboxed boot (`DSH_HOME` pointed at a throwaway profile, plugin mounted as a bundle): `oac-dsh (open-agent-connect-dsh): pending (waiting for service: webRuntime)` plus `dsh: warning: 1 entry did not activate`. Grepping the installed 0.2.1 kernel types: `webRuntime` 0 hits; `webServer` / `agentPresets` / `approval` / `systemPrompt` all still present — exactly one injected service had disappeared.\n3. Successor found in the kernel: `@deepseek-ai/dsh-client-connection` (`name = \"client-connection\"`) serves `ctx.connection`, a `HostConnectionHandle` whose `requestRejection(request)` applies the Host/Origin fence and returns a rejection object to deny, `undefined` to allow.\n\nChange: `inject` webRuntime → connection; the call site now asks the kernel via `ctx.connection.requestRejection(req)`; the plugin's own `trust-fence.ts` (−70 lines) is deleted so there is one implementation of the security path, not two. `@deepseek-ai/dsh-client-connection` added as peer (`^0.2.0-rc.1 || ^0.2.1-rc.1`) and dev dependency (`0.2.1-rc.1`), type-only import so no runtime coupling.\n\nVerification:\n- boot, before → `pending (waiting for service: webRuntime)`; after → zero pending, zero error, profile boots clean (same sandbox home and profile, only the plugin build differs)\n- `pnpm -C dsh-plugin run typecheck` → 0 (0 TS errors); `run build` → 0\n- `env -u ELECTRON_RUN_AS_NODE node --test dsh-plugin/tests/*.test.mjs` → 0, **616 pass / 0 fail**. Inside a shell that exports `ELECTRON_RUN_AS_NODE=1` the same suite reports 615/616; that one case is environment-sensitive (the same file passes 25/25 with the variable unset), not caused by this change.\n- One assertion re-anchored rather than removed: 0.2.1's shipped web-app patch no longer carries `persona.config.suffix`, so the \"the rewrite must not swallow the upstream row\" intent is now pinned on the row identity it still ships (`persona.name === '@deepseek-ai/dsh-persona'`).\n\nCommits: 68bd8184 (ranges), 1ef1b88a (migration), fe6b1fdb (lockfile/README), 41ee042b (test re-anchor).\nPR: https://github.com/openagentinternet/open-agent-connect/pull/45","contentType":"text/plain;utf-8","attachments":[],"quotePin":""}