# Changelog Notable changes to `@dsh-external/dsh-auto-review-jev`. Each version matches a [git tag](https://github.com/sperictao/dsh-auto-review-jev/tags) and a GitHub Release carrying a prebuilt tarball. ## 0.2.9 - **Adapted to DeepSeek Harness 0.2.0-rc.1.** The harness checks a plugin's declared `@deepseek-ai/dsh-*` peers against its own runtime version, at install and at profile startup, so the `^0.1.7-alpha.1` ranges would have this bundle refused as incompatible. Every DSH peer and dev range now reads `^0.2.0-rc.1`, and the Cordis floor moves from `^4.0.3` to `~4.0.4` — the range every package in the 0.2.0-rc.1 family declares. - No source change was needed: the 0.2.0 family's changes do not reach this plugin. `dsh-agent`, `dsh-typert-protocol`, `dsh-client-ui-slots`, the settings / user-approval / authorization contracts, the client bundle handoff (`window.__ModuleLoader__.load`) and the `dsh.bundle.patch` / `dsh.client` manifest schema are unchanged, and the changes in `dsh-llm`, `dsh-tools`, `dsh-session` and `dsh-subagent` are additive (tool-update projection, `ToolCallRecovery`, `projectContent`, a localized `ask` reason). - Everything the plugin actually consumes is unchanged in 0.2.0-rc.1: the session event vocabulary it folds, the `MessageSource` discriminants, the `permissionPresets` face (`registerAuto`, `AUTO_PRESET`), the `configForms` save contract, the `userQuestions` reprieve seam and the `settings` namespace registration. The version bump alone needed no test change. - **Coexistence with DSH's shipped auto review is exact.** The teardown migration now runs only while this plugin actually owns the `auto` slot: unloading or reloading it while `@deepseek-ai/dsh-experimental-auto-review` holds Auto (or while this plugin is bound to a named preset) no longer moves that integration's live sessions to `danger-full-access`. The conflict warning names the built-in package, its `auto-review` row and the Plugins-page toggle, and both READMEs state the built-in's fixed slot bundle (Full access with the `ask` approval policy) next to this plugin's deliberate `never` pairing. - Both READMEs gained a screenshots walkthrough (the settings page, the reprieve dialog, a denial in the transcript) and a companion-UI section for the Jev-branded permission-preset fork; the captured images ship under `docs/screenshots/`. The fork needs no change for 0.2.0-rc.1 — upstream's client code is byte-identical there. - Both READMEs state the new supported matrix. ## 0.2.8 - **The reprieve dialog follows the Web UI language and shows the review's own findings.** A denial used to ask in Chinese and English at once, quoting one line of raw denial text: it said what happened, not what was judged. The dialog now asks in the language the Web UI is rendering in and states the verdict, the dimensions that fired with their scores, the tool, and the call about to run. - The language comes from the browser half, which reports it over a new `jev/locale` Remote. The Host cannot work it out alone: an unset `locale` preference in the Host settings document deliberately delegates to the browser, so the common case — a browser-derived UI nobody configured — is invisible Host-side. Anything that is not a Chinese locale falls back to English, the same fallback DSH uses for non-browser runs and for a browser that names no registered language. - Option labels are the answer encoding, so they are written per language and matched against the language that was actually asked. - **A verdict is cached against the request that produced it, not the review state alone.** `endpoint` and `model` are live-editable from the settings page and the key is re-resolved on every call, so a state-only key replayed a decision taken against a previous endpoint, model or account for up to one TTL after the change. Expired entries are also reclaimed on insert now, so a long session no longer accumulates every distinct state it ever reviewed. - **Endpoints must be `https`.** Every request carries the API key as a Bearer credential, so a plaintext destination is a credential leak rather than a misconfiguration. Plain `http` is still accepted for loopback hosts (`localhost`, `127.0.0.1`, `[::1]`), so a local proxy stays usable. - The rule lives in one predicate (`src/endpoint.ts`) instead of three copies of "is it an absolute URL", and it is enforced at boot, at the settings write, in the settings page's field state, and at the request itself — the last gate before the key is attached. - **Behavior change:** an `http://` endpoint outside loopback now fails at boot or at the settings save. It used to be accepted and then fail every review closed. - **The Cordis peer floor is `^4.0.3`**, matching what every package in the `0.1.7-alpha.1` family declares; the previous `^4.0.2` admitted a Cordis the harness itself considers out of range. Both READMEs state the supported matrix now instead of leaving it to be inferred from peer ranges. - **The authorization lifecycle and the release assets are covered by tests.** `tests/lifecycle.test.ts` drives the `tools/pre-execute` listener through a fake Cordis context: the engagement gate, the fail-closed denials, the human reprieve, teardown, cache reuse and key rotation had no coverage at all before — every suite tested a leaf module. `tests/release-assets.test.ts` makes `pnpm test` fail when the version, the newest changelog section and the published file list disagree, so a release can no longer be packed before its notes exist. ## 0.2.7 - **Adapted to DeepSeek Harness 0.1.7-alpha.1.** Two breaking upstream changes reach this plugin, one per half. - The message-source vocabulary lost its catch-all `plugin` kind, so a compaction summary is now identified by the `compact-checkpoint` source kind rather than `kind: 'plugin'` + `plugin: 'compact'`. The check reads that discriminant structurally: the kind is declared in the compaction plugin's own module, which this plugin deliberately does not depend on. - The browser settings service was renamed. `ctx.settingsScope.bind({ … })` is now `ctx.configForms.get(namespace)`, and the injected key `settingsScope` is now `configForms`. - **A refused settings write now fails the save.** `ConfigForm.set` / `unset` answer the Host's acceptance — `false` when the namespace's own validation refuses the value — where the old scope settled silently. `save()` treats a refusal as a failure, so the page raises its error banner instead of reporting success for a value that never landed. - **Peer ranges are now `^0.1.7-alpha.1` alone.** The previous ranges reached back to `0.1.2-rc.1`; the browser half cannot load without `configForms` and the host half no longer recognises a 0.1.6 checkpoint source, so keeping them would have advertised support that no longer exists. - The dual-generation Remote codec went with them. `wire-shared.ts` used to carry both `schema` (read by engines up to 0.1.6) and `create: () => TypertSchema` (read by 0.1.7) so one descriptor could serve either engine; with 0.1.7 the only generation still in range, the legacy member and the explanation that propped it up are deleted. - The new `developer/message` events (tool-registry changes) stay out of the review state: they are session bookkeeping, never authorization, and a 0.1.6 session had no equivalent — so what Jev receives is unchanged. - The host half no longer filters `tool-result` blocks out of user messages: 0.1.7 gave tool results their own message role, so those blocks no longer appear in a user message's content and the two filters were type errors against the narrowed `ContentBlock` union. - `tests/settings.test.ts` pins the new save contract: a write the Host refused fails the save and keeps the draft, an accepted one clears it, and a draft whose trimmed text already matches the stored value is never written. ## 0.2.6 - **Fix: the reprieve path could replace a clean denial with a raw service error.** The seam accessor used `ctx.userQuestions`, which Cordis guards behind an inject — outside an injected scope that property access throws `cannot get property "userQuestions" without inject`. With `askOnDeny` on (the default), every denied call hit that throw instead of the question card or the self-explaining denial, so denied commands (an install, a push) died with an internal error and no output — which reads as "the install did nothing". The accessor now uses the supported soft lookup (`ctx.get('userQuestions')`, yielding `undefined` when the service is absent), and the ask is wrapped so it can never escape or reject: every failure — a guarded accessor, a missing service, a malformed answer payload — degrades to the fail-closed denial with the reason in its suffix. - Two regression tests pin the property: the asker resolves an error result (never rejects) when the seam accessor throws or the answerer returns a malformed payload. 72 tests total. ## 0.2.5 - **A denial now asks the human before it becomes final.** On any denial — a risk verdict (`risk: …`) or a failure of the review itself (`review_error: …`) — the plugin asks through DSH's user-questions seam (`ctx.userQuestions`, the seam behind the model's `ask_user_question` tool), shows the original denial text verbatim, and offers **允许本次执行 (Allow once)** / **保持拒绝 (Keep denied)**. An allow lifts the denial for that one call only and is never remembered; every other outcome (no answerer mounted, a subagent's call, an aborted call, an unrecognised answer) keeps the denial, and the denial suffix records which of those it was. - New `src/ask-on-deny.ts` and `tests/ask-on-deny.test.ts` (17 assertions, covering the question copy, the answer vocabulary, per-session prompt serialization, and every fail-closed path). - New `Config.askOnDeny` (default `true`); set it to `false` for a reviewer that never asks. - Why not the platform's own `{ kind: 'ask' }` decision: it routes through `ctx.approval`, whose `decide()` answers `'rejected'` immediately while the session policy is `never` — exactly the policy the Auto preset pairs with Full access. The reprieve therefore asks the user-questions seam directly. The deviation is deliberate and narrow: the human may override a denial, the model never may. ## 0.2.4 - **The usage panel moved into the settings page.** It now renders inline at the top of the "Auto Review Jev" page, directly above the API key: account snapshot, quota bars, this host's counters, a manual refresh and an "Updated" timestamp. Its copy follows the UI language — bound to the `panel.jev` namespace through a new `panelText` seat, because a `settings.section` entry declares only one locale namespace. - **The settings page is called `Auto Review Jev` in every locale.** The page name is a product name and is deliberately untranslated: the English and Chinese copy dictionaries carry the same literal for `nav` and `title`. - **The sidebar quota card is gone.** Removed along with it: the `sidebar.footer.action` registration, the keyed `main` dashboard cell, `JevFooterEntry`, the quota ring, the open/close plumbing, the card-only CSS and copy, and the slot-map module that declared those two slots. The plugin now mounts a single `settings.section` surface, so the sidebar, the composer and the layout service are no longer touched. - The card-only `headline` projection was dropped from the panel view model; the two tests that asserted it now assert the same facts through `creditBar`. ## 0.2.3 - **Denial reasons are visible.** A fail-closed denial (unreachable endpoint, invalid key) and a genuine risk verdict used to look identical in the UI, because the reason only lived in a structured field: an HTTP 401 surfaced as a wall of unexplained denials. The detail is now appended to the copy DSH renders — `Jev Auto review rejected tool "bash"; its body was not executed — review_error: HTTP 401 (missing or invalid API key)` — with the key still redacted. - New `src/denial.ts` (`rejectionReason()` / `denial()`) and `tests/denial.test.ts` (6 assertions, including a 401 regression guard). Behaviour and public API are unchanged (`lib/index.d.ts` still 15630 bytes). ## 0.2.2 - Keep the settings locale namespace slash-free, and single-source the constants shared by the host and browser halves. ## 0.2.1 - Renamed the package to `@dsh-external/dsh-auto-review-jev` (the previous unscoped name is no longer used; existing configs must be updated). ## 0.2.0 - Account usage reporting (`jev/report` Remote, host-side accumulator and the optional account-quota poll), the API-key settings UI, and coexistence with the official auto review through a dedicated `preset: auto-jev`. ## 0.1.0 - First standalone release: Jev-backed per-tool-call authorization review for DSH's Auto permission preset.