Skip to content

Releases: fuhefei/dsh-sentinel

v0.13.2 — DSH 0.2.1 alignment, plugin-manager metadata

Choose a tag to compare

@fuhefei fuhefei released this 19 Oct 03:45

DSH 0.2.1 alignment

The deployment moved from dsh 0.2.0-rc.2 to dsh 0.2.1-rc.2 and this release is the plugin's alignment pass. No plugin source change was needed: against the real 0.2.1-rc.2 packages tsc -b --noEmit passes, all 76 tests pass, and a rebuild produces byte-identical lib/ bundles.

  • devDependencies moved to 0.2.1-rc.2 (all twelve @deepseek-ai/* pins).
  • engines.dsh declared as >=0.2.0-0 <0.3.0. Since 0.2.1-alpha.4 the host's install gate decides on engines.dsh alone whenever a manifest declares it (checked in the host's evaluatePluginCompatibility source), so this field now carries the 0.2-line admission: both the 0.2.0 rollback line and 0.2.1+ pass, and older lines are refused.

Plugin Manager display metadata

0.2-generation managers read display metadata without activating the plugin, and this release ships it: locale/en.json + locale/zh.json meta titles/descriptions plus an exported icon. The display-metadata check in dsh-plugin-guide now passes.

Fixes

  • The git-install example pinned a stale tag (#14). github:fuhefei/dsh-sentinel#v0.11.0 made copy-paste installs land on a version predating the 0.1.7/0.2 compatibility fixes — one reporter's watch fired and delivered, but the v4 session format silently rejected the wakeup. The example now pins v0.13.2 and notes that the tag tracks the latest release.
  • The README compatibility paragraph was corrected: the three harness packages are peerDependencies (one host instance; a second copy owns a different TOOL_RUNTIME_SCHEDULER symbol and breaks real tool calls) since v0.13.0, not carried dependencies.

Verification

Upgraded deployment: clean profile reinstall on dsh 0.2.1-rc.2; the plugin activates, holds the duty lease, its client bundle carries sidebar.panellist, the state route answers, 71 boot rows, zero skipped bundles. Rehearsed first against a copy of the live profile; the launcher + profile backup is retained for rollback.

v0.13.1 — client poller fix, wider 0.2 support

Choose a tag to compare

@fuhefei fuhefei released this 07 Oct 14:35

Fixes

  • The client state pollers no longer overlap or leak in-flight requests (#13). Both the per-session hook and the page-wide shared poller armed a setInterval and fired a request on every tick without looking at the previous one, so a slow server accumulated outstanding requests — the reporter's isolation produced six from five ticks — and unloading only cleared the timer, leaving work in flight to resolve into a dead component. fetch carried no AbortSignal at all, and the last global subscriber leaving did not cancel the shared request.

    Both now run on a self-scheduling poller: the next tick is armed only after the previous request settles, so at most one request is ever in flight, and every request carries a signal that aborts on teardown or on a per-request timeout. The timeout is load-bearing rather than defensive — because the loop re-arms after settlement, one request that never settled would otherwise stall polling permanently.

Improvements

  • The harness peer range now covers the 0.2 line instead of a single release. The three peers were pinned to exactly 0.2.0-rc.2, which means the plugin installs on precisely one host version and becomes uninstallable on the next — that is how the 0.1.7 → 0.2.0 step broke, and it would have repeated on every 0.2.x. They are now >=0.2.0-rc.2 <0.3.0, which still refuses anything older.

    Checked against the host's own compatibility gate rather than by inspection: 0.2.0-rc.2 and 0.2.1-alpha.1 are admitted; 0.2.0-rc.1 and 0.1.7-rc.2 are refused. Verified on a rehearsal built from a copy of the live profile running 0.2.1-alpha.1 — the plugin activates, holds the duty lease, serves its client half and answers the state route (68 boot rows).

Notes

  • Eight new unit tests cover the poller contract: non-accumulation under a hanging server, sequential re-arming, abort-on-stop, timeout recovery, abort-vs-error reporting, idempotent start and restart. They have teeth — against the previous setInterval design the non-accumulation assertion fails with 11 outstanding requests over ten intervals. Full suite: 76/76.
  • dsh-web-shell remains pinned to <0.2.0 in its own manifest, which 0.2.0-rc.2 happens to satisfy (a prerelease sorts below its release) but 0.2.1-alpha.1 does not. If you run the alpha, the terminal bundle is skipped until that is fixed upstream.

Full Changelog: v0.13.0...v0.13.1

v0.13.0 — DSH 0.2 alignment, by @WindLX

Choose a tag to compare

@fuhefei fuhefei released this 07 Oct 12:34

Breaking changes

  • This release targets the DSH 0.2 line (0.2.0-rc.2). The three harness value imports (@deepseek-ai/dsh-tools, @deepseek-ai/dsh-llm, @deepseek-ai/dsh-scope) moved from dependencies to peerDependencies, pinned to 0.2.0-rc.2. A profile therefore no longer installs its own copy of the host's core modules. That duplication was not merely wasteful: two copies meant two distinct TOOL_RUNTIME_SCHEDULER symbols, and real tool calls failed with Cannot read properties of undefined (reading 'prepare'). If you are on DSH 0.1.x, use 0.12.1.

Fixes

  • Reasoning effort was silently dropped when resuming a dormant session. currentSelection() was destructured to just { provider, model }, so the wakeup resumed with the default effort instead of the configured one. The full ModelSelection is now passed through.
  • Historic agent presets were never restored. The resume path called sessionPersistence.inspect(), which is not part of the host interface, so the optional call skipped silently and every resumed session fell back to the current default preset. It now reads the restored session's agentPreset projection and mounts that.
  • The duty lease could be released in the wrong directory. The lease path was recomputed on each use, so a DSH_HOME change between claim and teardown pointed renewal and cleanup at a different home. It is now resolved once at construction.
  • Overlapping probe rounds. Heartbeat ticks could start a second round while the first was still running, duplicating lease renewals and probes. Rounds now coalesce, and dispose() is async: it stops timers and sensors, waits for the in-flight round, then releases the lease — so teardown no longer races startup.

Internal

  • The loose structural shims around Context, ResumeAgentOptions, ModelSelection and the preset registry are replaced with the host's real types, so tsc now checks those contracts instead of accepting anything.
  • Five new end-to-end tests cover the two resume-preservation paths, preset-free composition, the lease-home fix, and in-flight teardown. Suite: 68/68 passing.

Thanks

PR #11 by @WindLX — the DSH 0.2 alignment and all four fixes above, with the reproduction and regression evidence.

Full Changelog: v0.12.1...v0.13.0

v0.12.1 — DSH 0.1.7 alignment

Choose a tag to compare

@fuhefei fuhefei released this 29 Sep 14:00

Breaking changes

  • This release targets the DSH 0.1.7 line. Under strict semver the previous dependency range (>=0.1.5-rc.2 <0.2.0) does not admit 0.1.7-rc.2 — the prerelease rule only lets a prerelease match a comparator carrying the same major.minor.patch. Left alone, a 0.1.7 host would have resolved this plugin's harness imports to 0.1.5 copies while the host ran 0.1.7, which is the same silent drift the 0.1.5 alignment removed. The ranges are now pinned to the 0.1.7 line, so 0.12.1 will not install against DSH 0.1.5 — if you are staying on 0.1.5, use 0.12.0.

Fixes

  • DSH 0.1.7 removed the shared catch-all plugin message-source kind; every producer now declares its own. Watch wakeups carry { kind: 'sentinel' }, declared by merging into MessageSourceMap — the same idiom upstream's own goal kind uses, and one that compiles against both the 0.1.5 and 0.1.7 type surfaces.
  • The end-to-end harness now asserts the wakeup's message source. It captured only message text before, so nothing caught a wrong kind.

Notes

  • No user-visible change beyond one label: a wakeup now reads "Sentinel" in the trajectory inspector where it previously read "Plugin · dsh-sentinel" (0.1.7 dropped its plugin branch, so the old kind would have degraded there anyway).
  • Transcript placement is unchanged: both kinds land in context, not steering, so wakeups still render exactly where they did.

Full Changelog: v0.12.0...v0.12.1

v0.12.0 — DSH 0.1.5 alignment

Choose a tag to compare

@fuhefei fuhefei released this 29 Sep 14:00

Breaking changes

  • The global watch view moved seats. DSH 0.1.5 removed the session-row extension holes the old surface grew under, so it disappeared silently after upgrading. The watch table now lives on the official seats: a sidebar.panellist entry (id sentinel, showing a state dot while watches are active) that selects the layout's keyed main panel. The conversation dock card and the optional better-sidebar tab are unchanged. This release requires DSH 0.1.5 or later.

Fixes

  • Declare the harness value imports (@deepseek-ai/dsh-tools, @deepseek-ai/dsh-llm, @deepseek-ai/dsh-scope) as dependencies pinned to the verified line. A profile's hoisted store could previously resolve them to 0.1.0-rc.8 copies while the host ran 0.1.5-rc.2, and the loose shims hid the mismatch from tsc.
  • Delete both loose shim files and compile the client half against the real 0.1.5 types, so pnpm typecheck now actually checks the host contracts instead of papering over them.
  • Point the client build's external table at the 0.1.5 platform seed and drop the removed dsh-client-runtime / web-react / schema-form names.

Internal

  • Drop seven unused devDependencies.
  • Retire the session-row branch path; its bundled patch is kept for pre-0.1.5 trees only.

Full Changelog: v0.11.1...v0.12.0

v0.11.1

Choose a tag to compare

@fuhefei fuhefei released this 07 Sep 14:05

What's Changed

  • fix: register bare module id + tolerate vendored-cordis inject fiber by @dracpet in #7

New Contributors

Full Changelog: v0.11.0...v0.11.1

v0.11.0

Choose a tag to compare

@fuhefei fuhefei released this 17 Aug 03:25

Published to npm under the bare name dsh-sentinel; bilingual README and a security policy.

Distribution

  • Now on npm: dsh plugin --profile web add dsh-sentinel. The package dropped the @dsh-external scope so it can live on the public registry without scope ownership, and the cordis plugin name changed with it (@dsh-external/dsh-sentinel → dsh-sentinel). Existing installs should update their profile to depend on dsh-sentinel and drop the old scoped row; watches themselves survive the switch — they live in the sidecar log, not the install.
  • The git-source install still works and now pins #v0.11.0.
  • The npm tarball ships lib/, the mount manifest, both READMEs, SECURITY.md, patches/, and the preview screenshots. A stray lib/client.js.bak build residue is excluded and now gitignored.

Docs

  • Chinese README (README.zh.md) with a language switcher on both sides.
  • SECURITY.md: the trust surfaces in scope (route fence, webhook URLs as secrets, the command sensor's trust domain) and private reporting through GitHub vulnerability reporting.

v0.10.0

Choose a tag to compare

@fuhefei fuhefei released this 14 Aug 18:05

Security hardening plus the missing observability surfaces.

Security

  • All routes now sit behind a browser-trust fence. The host fences its own /api channels against cross-site POSTs and DNS rebinding, but plugin routes under /plugins/* were outside it — a malicious webpage could form-POST to your localhost and fire the webhook route (waking a full-access agent) or cancel watches; a DNS-rebound page could read state. Browser-marked cross-site requests and Host/Origin authorities that are DNS names now get 403. Headerless clients (curl, CI jobs) are completely unaffected.

Added

  • Recent-fires table on the dashboard — time, watch, session, summary; answers "what fired while I was away".
  • Duty heartbeat in the dashboard meta line — shows the lease heartbeat age and flags a stale resident process, so a silently-dead watcher is visible.
  • Dropped-wakeup badges — wakeups dropped by the maxPendingWakeups cap (dormant session, queue full) are now counted per session, exposed in the state route and shown as a red badge instead of vanishing into the server log.
  • Wakeup stop-guardrail — the wakeup message now ends with an explicit instruction to handle this trigger and stop, so a woken agent does not wander off into open-ended investigation.

Documented

  • First-probe semantics: pattern-less watches absorb the first observation as baseline; a pattern watch whose target already matches fires on the first probe.

v0.9.0

Choose a tag to compare

@fuhefei fuhefei released this 14 Aug 17:45

Watches now have a manual kill switch, and queued wakeups are visible.

Added

  • Manual cancel everywhere. POST /plugins/dsh-sentinel/cancel?sessionId=…&id=watch-N cancels a watch through the same durable sidecar path as every other mutation (logged with reason user). The dashboard table and every dock / sidebar-branch / tab row carry a ✕ that calls it — no more resuming a dormant session (and spending a model call) just to stop a watch.
  • Pending-wakeup visibility. Watch rows now expose pendingWakeups — fires logged but not yet delivered to the session show as a badge (e.g. 0/3 待投递 1) in the dashboard and UI rows instead of sitting silently in the queue.
  • docs/invariants.md rule 7: watches outlive their session's agent; the host has no session-deleted event, so orphaned watches of deleted sessions keep probing until cancelled by hand — the ✕ is the kill switch of last resort.

This closes a real semantic gap found while testing: an orphaned watch (its session deleted) could never be cancelled at all — the only entry point was its session's agent, which no longer existed.

Fixed

  • Install line regression: the README had briefly regressed to #v0.8.2 after a stale-copy edit; it now pins #v0.9.0.

v0.8.3

Choose a tag to compare

@fuhefei fuhefei released this 14 Aug 17:06

Two correctness fixes, found by running a real agent session against a live install.

Fixed

  • Pattern watches no longer false-fire on placeholder snapshots. A watch on a missing file used to expose the placeholder <absent> to the pattern, so any-content regexes like [\s\S]+ (what an agent naturally writes for "fire when the file has content") matched on the very first probe and burned the whole budget on a file that did not exist. Placeholders (<absent>, <unreachable>, <none>, <push-only>) are never pattern-matchable now; the edge a pattern waits for is placeholder → matching content. Pattern-less watches keep firing on any snapshot change. The sentinel_watch pattern doc now names the JavaScript RegExp syntax and the placeholder rule.
  • Webhook hook URLs are scoped per session. Watch ids are allocated per session, so two sessions could hold the same watch-1 — and receive the identical hook URL ?id=watch-1; an external POST then woke whichever session loaded first. Hook URLs now carry &s=<sessionId> and the route resolves the qualifier first. URLs without s (baked into existing CI jobs) still work and deterministically resolve to the first matching webhook watch; a stray qualifier returns 404 instead of leaking across sessions.

Added

  • docs/invariants.md: the six load-bearing rules (id scope, snapshot domains, edge semantics, at-least-once delivery, duty lease, sidecar-as-truth).
  • Exhaustive property tests for the fire decision (no consecutive fires without an intervening non-match; placeholders are a non-match under every pattern) and a two-session same-id e2e regression.

Upgrade note: if a pattern of yours deliberately matched the literal placeholder text (e.g. absent), it will no longer fire; use a pattern-less watch to react to the target appearing or disappearing.