# Changelog ## [0.2.26] - 2026-10-20 ### Fixed - **Tools Result Payload Forwarding (#125, gh-1)**: Fixed tool outcome tracking in `lib/index.js` where `tools/result` event listener only captured the first argument (`execution`), losing the actual result payload passed as the second argument (`result`) by the DSH runtime (`dsh-tools`). Updated `tools/result` to capture `(execution, result)` and forward `{ ...execution, result }` to `state.recordResult()`. Updated `outcomeFromExecution` and `recordResult` in `lib/guard-state.js` to accept `maybeResult` and extract result payload, properly recognizing successful tool executions as productive progress (`productive: true`), advancing `progressEpoch`, and clearing `exactGroups`. Resolves false-positive `LOOP_GUARD_DUPLICATE` blocks on legitimate retries and eliminates catastrophic lockouts into `answerOnly` mode. ## [0.2.25] - 2026-10-19 ### Fixed - **Stop Command Detection & History Isolation (#120)**: Hardened `hasStopRequest` in `lib/guard-state.js` to inspect only the latest user message (`source.kind === 'user'` or `role === 'user'`), eliminating cross-turn leakage where a past stop command in turn 1 permanently locked tools in subsequent turns. Removed broad keywords `answer` and `回答` from default stop patterns, and introduced `isDefaultStopRequest` to require explicit standalone or imperative stop commands ("stop", "halt", "cancel", "abort", "terminate", "please stop", "停止", "暂停", "取消", "终止", "死循环"), eliminating false-positive blocks on regular user requests ("answer in Russian", "please answer using files", "stop the service and fix it"). - **Bounded Streaming Output Buffer (#121)**: Bounded `state.pending` buffer in `AssistantOutputGuardState.observeText` to `maxAssistantBlockChars` and parsed newlines incrementally via `indexOf('\n')` instead of `split(/\n/gu)`, preventing unbounded memory growth and O(N^2) CPU stalls during long streaming outputs without line breaks (such as minified JSON or base64 payloads). - **Issue Label Deduplication (#122)**: Reassigned affected issues to canonical project labels and cleaned up duplicate labels in Gitea repository. ## [0.2.24] - 2026-10-15 ### Fixed - **Supply-Chain Guard Compliance (#116)**: Removed `--config.minimumReleaseAge=0` override in plugin updater (`lib/plugin-updater.js`), enforcing compliance with pnpm global supply-chain quarantine and release age delay policies across fleet environments. - **Client Slots Cleanup (#116)**: Removed deprecated dead slot `settings.plugin.item` from `src/client/60-slots.js` and unified configuration card rendering across `plugins.row.config` and `plugins.item`, reducing bundle size and keeping `lib/client.js` at 582 lines (under the 600 line limit). ## [0.2.23] - 2026-10-11 ### Fixed - **Desktop Updater Fallback (#113)**: Detected DSH Desktop profile via `isDesktopProfile` and located bundled desktop CLI binary via `findDesktopCliEntry`. Added `isDesktop` and `canAutoUpdate` flags to updater status endpoint. Added `shell: true` option when spawning Windows `.cmd` binaries in `installExact`. Replaced "Update Now" button in settings card with localized hint (`Update in Plugins page` / `请在插件页面更新`) when running in DSH Desktop or when automatic updates cannot be performed. Preserved standard "Update Now" flow in headless/web server profiles. ## [0.2.22] - 2026-10-09 ### Fixed - **Telemetry Route Security Boundary (#102)**: Integrated `getConnection(ctx)` and delegated request verification to DSH core service `connection.requestRejection(request)`. Enforced loopback and mandatory `sec-fetch-site` (`same-origin` or `none`) fallback when connection service is absent. Enforced `x-dsh-loop-guard: '1'` header and origin/host verification on POST telemetry reset, preventing unauthorized access or state reset from loopback/LAN bridges. - **Persistent Release Packaging & Clean Isolation (#101)**: Relocated production web profile tarball dependency to external persistent directory `/home/vadim/.dsh/artifacts/`. Replaced indiscriminate `rm -f *.tgz` in `clean` script with `scripts/clean-pack.mjs` to safeguard release tarballs from local repository cleanup. Added `scripts/pack-release.mjs` (`npm run pack:release`) to build, pack into persistent artifacts directory, and generate `.sha256` checksums. ## [0.2.21] - 2026-10-09 ### Fixed - **Canonical Design Tokens (#100)**: Replaced 38 occurrences of non-existent theme tokens (`--dsw-alias-accent-primary`, `status-success`, `status-danger`, `status-warning`, `bg-hover`, `bg-layer-hover`) in `src/client/10-styles.js` and `src/client/50-settings-card.js` with canonical DSH theme tokens (`brand-primary`, `state-success-primary`, `state-error-primary`, `state-warn-primary`, `interactive-bg-hover`), restoring native styling, status coloring, and updater button appearance across themes. - **Theme Token Validation Guard (#104)**: Extended `test/theme-guard.test.js` to extract all `--dsw-alias-*` tokens from `lib/client.js` and assert adherence to the canonical 79-token design system of `@deepseek-ai/dsh-client-ui-theme`, preventing regression on unknown tokens. ## [0.2.20] - 2026-10-09 ### Fixed - **Streamed Text Memory Cap (#97)**: Capped `streamedText` buffer in `AssistantOutputGuardState` to `maxAssistantBlockChars` to prevent unbounded memory growth during long streaming assistant turns. - **Volatile Config Reload Subscription (#98)**: Subscribed to Cordis `loader/volatile-update` event alongside `app-boot/config-reload` and `internal/update` for instant volatile settings reload without requiring manual refresh. - **Settings Loader Fallback Cleanup (#99)**: Removed dead `typeof sctx.settings.get === 'function'` fallback from live config reader. - **Language Independence & Configurable Stop Patterns (#103)**: Removed Cyrillic regex in engine core `lib/guard-state.js`, added balanced standard `en` and `zh` default patterns, and added configurable `stopPatterns` in `Config` (with `.volatile()`) and `hasStopRequest()`. ## [0.2.19] - 2026-10-08 ### Fixed - **Settings Contract & Snapshot Reader (#90)**: Replaced non-existent with synchronous , unpacked settings values from ( contract) instead of , and bound reactive updates through . - **Locale Resolution & Reactivity (#40)**: Read active locale identifier from in with fallback to and , ensuring settings card respects the host language selection over browser . - **Volatile Schema Verification (#89)**: Verified and tested that all 13 user-facing schema fields carry (), ensuring live configuration registration under DSH 0.2.0. ## [0.2.18] - 2026-09-30 ### Fixed - **Cordis Volatile Unwrapping (#93)**: Unwrapped Volatile settings references recursively via `plainConfig()` and `resolveConfig()` before and after Schemastery `Config(...)` validation, preventing `ValidationError: $.maxToolAttemptsPerTurn expected number but got [object Object]` during plugin activation under DSH 0.2.0-rc.2. - **Strict Validation Integrity**: Preserved strict error throwing on invalid user types (e.g. non-numeric volatile values or arbitrary non-volatile objects) without silent coercion. ## [0.2.17] - 2026-09-29 ### Fixed - **Settings Form ID Binding (#92)**: Keyed form presentation under the entry ID for DSH 0.1.7-rc.2 and 0.2.0 hosts. ## 0.2.16 ### Fixed - **Peer gate on DSH 0.2.0-rc.1** (#58): DSH skips a profile bundle whose `peerDependencies` exclude the running version, so this plugin was absent from the profile with no error in the UI. Every `@deepseek-ai/dsh-*` peer now names both the 0.1.7-rc.2 and 0.2.0-rc.1 lines, because semver does not admit a prerelease of the next minor into a range that does not name it. All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.2.15] - 2026-09-25 ### Fixed - **SettingsForms API Migration**: Replaced legacy, removed `sctx.settings.register()` call with modern DSH 0.1.7-rc.1 `SettingsForms` lifecycle integration (#85). - **Presentation Policy**: Configured `sctx.settings.configure({ auto: false }, ctx.fiber)` to register page policy with proper disposer in `sctx.effect`. - **Live Settings Resolution**: Resolved live configuration via `sctx.settings.describe()` and subscribed to `settings/document-updated` event. - **Config Reload Contract**: Supported `app-boot/config-reload` and `internal/update` events for runtime guard limit re-synchronization. - **Optional Dependency**: Removed `settings` from top-level required `inject` array, enabling the plugin to run cleanly in headless or minimal environments. ## [0.2.14] - 2026-09-24 ### Added - **Streaming Assistant Block Hashing**: Incremental SHA-256 hashing for assistant output blocks exceeding 16,384 characters, preventing false positive loop rejections caused by truncated suffixes (#79). - **Large Payload Fingerprints**: SHA-256 fingerprint hashing for tool arguments and results larger than 256 bytes, drastically lowering memory usage and serialization overhead in long turns (#70, #66). - **Client Modular Architecture**: Extracted monolithic client source into clean submodules under `src/client/` (`00-header.js`, `10-styles.js`, `20-locales.js`, `50-settings-card.js`, `60-slots.js`, `90-footer.js`) with automated build via `scripts/build-client.mjs`, reducing final client bundle below the 600-line preflight threshold (#74). - **Repository Clean Script**: Added standard `clean` npm script (`rm -f *.tgz`) (#67). ### Fixed - **Immediate Duplicate Tool Call Blocking**: `blockExactDuplicates: true` now rejects identical duplicate tool calls immediately on the first recurrence (`exactCount >= 1`), while `blockExactDuplicates: false` allows iterations up to `maxCallsPerRepeatGroup` (#76). - **Memory Leak in Session State**: `LoopGuardState.byAgent` now removes agent session entries when `session/disposed` fires, preventing memory growth in persistent daemon processes (#69, #65). - **Group Counter Rollback**: Releasing uncommitted or canceled tool calls in `recordResult` properly decrements `repeatGroups` and `exactGroups` counters (#78). - **Assistant Message Fallback Key**: Normalized message text is now used as fallback key when message ID is absent, replacing unreliable string length comparison (#77). - **Telemetry Violation Accuracy**: Preserved primary violation code (`blockReason`) during `answerOnly` mode, eliminating false spikes of `LOOP_GUARD_STOP` in telemetry when agents attempt subsequent tools (#73). - **LAN Origin Authorization**: Permitted same-origin update and telemetry requests from local network host headers matching the server socket address (#72). - **Bare Mode UI Activation**: Enabled automatic telemetry polling and updater checks when rendering bare settings on `plugins.item` and `plugins.row.config` seats without manual header clicks (#64). ### Performance - Replaced array-copy reversal (`[...calls].reverse().find`) with native `Array.prototype.findLast` in `findCall` (#71). ### Documentation - Updated `docs/design/DESIGN.md` to document dual-seat integration (`plugins.row.config` and `plugins.item`), justify runtime functional Cyrillic stop word heuristics, and refresh npm packaging metrics (#68). ## 0.2.13 ### Fixed - Settings no longer wait on the removed settingsScope service. The client uses configForms (#75). ## [0.2.12] - 2026-09-19 - **Settings reachable again on the plugin's own page**: the current DSH core (0.1.6-alpha.2) renders a plugin's configuration page only for entries registered in the plugin-list seat `plugins.item` — that is how `dsh-agentrouter` and `dsh-agent-orchestrator` show their settings, while the row seat and the legacy card alone leave the page without the form. `PluginItem` is now registered there too (`id: '@goodandready/dsh-agent-loop-guard'`, order 10, static label), with both older seats kept as fallbacks. - The seat-composition test now expects the list seat and asserts its `id`, static `label` and component. ## [0.2.11] - 2026-09-18 - **Settings reachable again**: the settings card registered into `settings.plugin.item`, a slot the current DSH core no longer renders, so the guard's settings were unreachable. The surface now registers into the Plugins page row seat `plugins.row.config`, keyed `@goodandready/dsh-agent-loop-guard#@goodandready/dsh-agent-loop-guard` (row id as `cordis.patch.yml` declares it): the plugin's row gains a configure control whose page is the settings form (`view: 'page'`, rendered bare — `PluginCard` accepts a `bare` prop and drops the card chrome because the host page draws the title, icon, crumb and padding) plus a one-line state under the title (`view: 'summary'`). The legacy seat stays registered as a fallback for older cores. - **Row-seat guard** (`test/row-config-seat.test.js`): checks the row key against `package.json` and `cordis.patch.yml`, the seat order (row seat first) and the bare page render. ## [0.2.10] - 2026-09-18 - **Documentation & Packaging Architecture**: - Migrated cumulative version changelogs from all three README files (`README.md`, `README.ru.md`, `README.zh.md`) to canonical root `CHANGELOG.md` adhering to Keep a Changelog standard (#56). - Explicitly added `CHANGELOG.md` to `files` whitelist in `package.json` for npm distribution. - Expanded thematic feature sections across all three language documentations with dedicated coverage of Native WebUI Settings Card, Protection Telemetry, and One-Click In-Place Updater. - Synchronized automated test count to 51 tests across Russian and Chinese documentations. - Updated design contract status and documentation standards in `docs/design/DESIGN.md`. ## [0.2.9] - 2026-09-18 - **Theme Guard & Token Integrity**: eliminated 100% of hardcoded hex and rgba colors from `lib/client.js` in both CSS styles and JSX inline markup, switching entirely to DSH design tokens (`var(--dsw-alias-*)`) and `color-mix(in srgb, ...)`; added automated regression test `test/theme-guard.test.js` enforcing zero hex/rgba literals (#53, #39). - **Updater Resilience**: hardened `currentVersion` and status endpoint against corrupted, non-JSON or missing manifests, returning safe fallback status without throwing unhandled exceptions (#47). - **Distribution & Package Hygiene**: removed internal `docs` directory from npm distribution package `files` whitelist; added diagnostic warning with `bestEffort` annotation to client primitives loader; pruned stale branches and worktrees (#54). - **Test Suite**: expanded to 51 automated tests covering theme token compliance and manifest corruption handling. ## [0.2.8] - 2026-09-18 - **Host & Security Engine Hardening**: - Expanded stop keyword detector with Russian keyword `'стоп'` for multilingual interrupt safety (#43). - Enforced loopback and same-origin validation on `/telemetry` endpoint (#37). - Eliminated dead `if(true)` branch and unused `releaseCall` method in core guard engine (#44). - Deprecated legacy alias `maxCallsPerToolPerTurn` in configuration schema per standard (#48). - Replaced empty catch blocks with structured debug logging via `ctx.logger('loop-guard')` (#49). - **WebUI Client & Design System Alignment**: - Aligned settings card with DSH standard CSS variables `--dsw-alias-*` and primitive chevron icon with smooth 180° rotation (#39). - Removed emoji headers (`🛑`, `📊`) for a clean, professional interface (#39). - Fixed localization reactivity by resolving locale from `ctx.locale.getLocale()` and registering within `ctx.effect` lifecycle (#40, #41). - Removed hardcoded version strings; version is dynamically verified from updater endpoint (#42). - Enhanced accessibility: all form controls now link `