dsh-cache-guard

DSH PLUGIN记忆与知识

仓库 loonylabs/dsh-cache-guard

记忆与知识 L5 · 运行验证通过 安全审查:低风险 可信度:金 可安装插件
安装这个插件

dsh-cache-guard 是 loonylabs 维护的 记忆与知识 类 DSH 可安装插件, 仓库为 loonylabs/dsh-cache-guard,许可证 MIT。 下面按「装什么、怎么装、验没验过、跑起来要注意什么」逐项列出。

一句话选型结论

按资料字段整理

dsh-cache-guard 是记忆与知识类的 DSH 可安装插件,验证等级 L5 · 运行验证通过,安全审查为低风险,有可直接复制的安装命令。验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么;涉及密钥或系统权限的,建议先在隔离环境试装。

分类记忆与知识 收录类型可安装插件 验证等级L5 · 运行验证通过 安全审查低风险
验证等级 L5 L5 · 运行验证通过
GitHub 星标 0 复刻 未标注 · 未关闭 issue 未标注
最近更新 2026-09-19 创建于 未标注
README 20.9 KB 正文体量,越大说明说明书写得越细

安装

可安装插件
在 DSH 里执行,装完用 dsh plugin list 确认已挂上;标了 L4 / L5 的命令已在沙盒里真实跑通
dsh plugin --profile web add github:loonylabs/dsh-cache-guard
  1. 1
    确认版本与运行环境

    仓库没有标注兼容版本与 Node.js 要求,先确认你的 DSH 版本能装,再继续。

  2. 2
    执行安装命令

    在 DSH 里执行上面的命令;多包仓库要注意区分具体子包名,别装错包。

  3. 3
    确认已挂载

    用 dsh plugin list 查看列表里是否出现这个插件,出现即挂载成功。

  4. 4
    试跑并检查权限

    加载后跑一个最小用例,确认它能正常工作;同时看它申请了哪些文件、命令或网络权限。

兼容 DSH 版本未标注版本不匹配时安装会报错
Node.js 要求未标注来自仓库 package.json 的 engines 字段
前置依赖无需要同时安装的同级依赖
npm 包名未发布到 npm可用 npm view 查看包信息

能做什么

记忆与知识
字段来自项目仓库与公开索引,中文说明由本站标注

适用场景

记忆

验证等级与安全审查

L5 · 运行验证通过
自动化流程结论,不是人工审核
验证等级L5 · 运行验证通过在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来
安全审查低风险静态分析结论,未标注不代表已通过审查
仓库健康度稳定按仓库活跃度与最近更新时间给出
可信度金综合仓库活跃度与验证结果

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 验证等级 L5:安装和运行都在沙盒里跑通过,装完能直接用的概率高。
  • 静态安全审查为低风险,没有发现明显可疑行为。
  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有声明 Node.js 版本要求,版本不匹配可能装不上。
  • 验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么。

更适合

  • 需要在记忆与知识场景里给 DSH 补能力的人。
  • 想装完就能用、不想自己排依赖的人。
  • 能接受在本地装依赖、愿意自己确认权限的人。

不太适合

  • 只使用 DSH 官方内置能力、不接受第三方插件的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
插件验证等级安全审查星标兼容版本安装命令
dsh-cache-guard当前 L5 · 运行验证通过 低风险 0 未标注 有
ruflo L3 · 安装规范通过 低风险 7.4 万 未标注 无
OpenViking L3 · 安装规范通过 低风险 3.9 万 未标注 无
WeKnora L4 · 沙盒安装通过 低风险 3.3 万 未标注 有
distilly L4 · 沙盒安装通过 低风险 2.5 万 未标注 有
EverOS L4 · 沙盒安装通过 低风险 1.3 万 未标注 有

仓库档案

记忆与知识
字段来自项目仓库与公开索引,中文说明由本站标注
作者 / 维护方loonylabs仓库 dsh-cache-guard · 默认分支 未标注
分类记忆与知识memory
收录类型可安装插件声明了 dsh.bundle、可用 dsh plugin add 安装的条目
开发语言未标注仓库主语言
许可证MIT商用或二次分发前请确认条款原文
星标 / 复刻 / issue0 / 未标注 / 未标注收录时的数值,非实时
创建 / 更新未标注 · 2026-09-19最后推送 未标注
本站收录2026-10-30首次进入本站目录的时间

README 全文

20.9 KB
作者原文,中文版优先;只做安全转义,不改内容

🧊 dsh-cache-guard

Host- and agent-layer DeepSeek Harness (DSH) plugin that prices every automatic context rewrite before it lands, asks the human by default, and reports what the provider had to re-read cold.

<!-- Horizontal Badge Navigation Bar -->




<!-- Table of Contents -->
📋 Table of Contents

  • What It Prevents
  • What It Shows
  • Where It Is Active
  • How It Intercepts
  • Guarantees
  • Installation
  • Profiles
  • Configuration
  • Verification & Testing
  • Known Limitations
  • 🤝 Contributing
  • 🔗 Links
  • License

What It Prevents

A provider reuses its cached request prefix only up to the last unchanged token. Two automatic operations rewrite the model-visible surface, and both therefore re-bill the retained context at full price — without anyone being asked:

Operation What it rewrites Why it is expensive
Tool-result pruning (dsh-compaction-tool-result-pruner) Oversized tool results, in place It starts at the oldest candidate, so everything after it becomes a cache miss
Summarization (dsh-compaction-basic) An older span, replaced by one checkpoint The checkpoint invalidates from the replaced position, and the summary itself is a full-prefix model call

Measured on a real session (deepseek-v4.1-flash, 1M window): the pruner rewrote 28 tool results at once, freed 93k tokens, and the very next request re-read 720,764 tokens at full price instead of 16,768 — $0.11 for one request, three steps before that session ended.

dsh-cache-guard sits in front of both operations, prices them first, and asks.

What It Shows

A dialog before the change, with the numbers that decide it:

Context rewrite
An automatic context rewrite is ready. Allow it?
Context: 839k of 1.05M (rewrite at 839k)
Prunes 28 old tool results: 93k freed
Then summarizes: ~4k checkpoint (estimated) instead of 746k
Breaks the cache at position 0: 255k re-read in full (95% of the request)
[ Allow once ]  [ Not now ]  [ Always allow (this session) ]

And a chip in the composer's tool row — inside the input card, right after the access-mode chip, built with the same geometry as its siblings (28px pill, design-system glyph, chevron that rotates while open). It carries the state; clicking it opens a small menu with the numbers. The label has four values: Cache: ask, Cache: auto, Cache: off, and Cache: not armed — the last one for a process where no compaction engine is being guarded, which is the state that let a rewrite break a cache unanswered. The glyph follows the mode — a question mark while the guard asks, a check while it runs unprompted or is off — and the label collapses to glyph + chevron in a narrow composer, exactly as the neighbouring chips do.

[ (?) Cache: ask ⌄ ]    ╭────────────────────────────────────────────╮
│ Context 837k of 1.05M · rewrite at 839k    │
│ last rewrite: 28 tool results pruned ·     │
│ 724k re-read in full (declined, nothing    │
│ changed)                                   │
│ ────────────────────────────────────────── │
│ (?) Ask before every rewrite           ✓   │
│     Pruning and summarizing wait for your  │
│     approval.                              │
│ (✓) Allow automatically                    │
│     Runs without asking; its cost shows up │
│     here afterwards.                       │
│ (✓) Guard off                              │
│     The engine compacts as shipped:        │
│     nothing is priced, asked, or blocked.  │
╰────────────────────────────────────────────╯

Its menu rows follow the harness Menu: a leading 16px glyph, the label with its hint, and a trailing check for the selected row — the selection is a check, never a colour fill, exactly as in the neighbouring menus.

The menu floats above every column: it is portaled to the document body and placed in viewport coordinates from the chip, so a studio's wider columns can neither clip it nor cover it. Opening and closing follow the same rule as the model chooser — the chip's chevron toggles it, and a click anywhere outside the menu closes it.

The long sentence also sits in the chip's tooltip, so hovering shows it without opening the menu. The host keeps the chosen mode per session.

Where It Is Active

Installing the plugin is the whole opt-in: the host half guards every session, on every preset, with nothing to pick.

Part Lives in Reach
host half the profile bundle every session: the gate on each preset realm's engine, the pill, its menu, and the mode endpoints
engine half (optional) an agent preset, inside the compaction group that preset only — a fallback for a deployment whose profile cannot carry the host half

An agent's engine is created inside its preset: the shipped compaction group isolates compaction and toolResultPruner, so the profile's own layer cannot reach the instance. A plain internal/service listener does not hear the registration either — the event carries a scope filter that drops every listener outside the providing realm. The host half listens with { global: true }, which bypasses exactly that filter, and wraps each engine the moment its realm announces it. That is the same seam the harness's own preset invariant uses to observe realm registrations.

Because the gate is armed from the host plane, a session composed on the shipped standard preset — the case that produced the measurement in What It Prevents — is guarded like any other. Opting out is explicit, in three sizes: the session mode off in the pill, mode: off as a profile's or preset's configuration default, and removing the bundle.

How It Intercepts

Both operations run through one method — compactIfNeeded on the live compaction engine. Pruning is the first phase inside that call, summarization the second, and the provider-overflow recovery path enters the same method. compaction-basic registers its listeners with this bound to the engine instance and calls this.compactIfNeeded(...) internally, so replacing that one instance method intercepts both paths. Wrapping the compaction service would not, and neither would a listener that only sees the host plane's services.

The announced value is a traced read, so its ctx answers with the reading context. The gate therefore takes the instance behind it (cordis exposes it under the global-registry symbol cordis.original) and prices through that instance's own context, which resolves the realm's pruner and meter. Pricing through the host plane would plan no pruning at all and understate the cold re-read.

The guard therefore:

  1. prices the pending plan before anything is touched — which tool results are over the pruner's budget (the real pruner's own pruneContent decides, without mutating), which span a summarization would replace, and how many tokens break the cache at which surface position;
  2. asks (manual mode) or reports (auto mode);
  3. runs the operation itself on accept: the engine's public compactRegion transaction first, then the pruner. On decline — or when there is nothing to decide — it returns null, which the engine reads as nothing to compact.

The guard never calls the original method. That is what keeps the engine from running its own two-phase pass behind the guard's back, and it is why the phases can be paired: the checkpoint lands at the oldest replaced position, so every pruning rewrite that follows sits behind that cache break and adds nothing to it. The reverse order would pay the break twice whenever the summary lands anyway, and would leave a pruned surface behind if the range were rejected. The engine's transaction is atomic, so a rejected range throws before anything is written.

Nothing is imported from the compaction packages and no engine code is changed: the guard reads the engine's public config, calls its public compactRegion, and restores the original method when it unloads. Everything the harness owns around the operation — the transaction, the event lifecycle, the persistence, and the retry accounting in the calling listeners — stays the harness's.

Pruning and summarizing are one operation

The engine's own pass tries the model-free phase first and summarizes only if the surface is still too large. A pass that stops there has a bad price: pruning rewrites in place, so the surface stays almost as large (measured: 839k → 737k) and the next request pays the cache break at nearly full size — 720,764 tokens re-read cold, for a pass that freed 93k and needed 186.

The guard always plans both. The same session, priced with the span the guard would replace, comes to 255k cold: the surface drops to the retention tail plus a checkpoint, and the cache break is paid once.

Guarantees

  • A guard bug never blocks the engine. If pricing throws, the original call runs and the failure is logged. A guard that cannot price an operation must not decide it: treating its own failure as a decline would silently stop compaction in every session it guards.
  • The pill never promises protection the host cannot back. It reads how many engines the process actually guards; with none, it says Cache: not armed instead of "waiting for your approval".
  • Fail closed on silence. With the mode set to manual and no question provider registered, the automatic rewrite is declined and the log says how to allow it (mode: auto).
  • No repeat nagging. A decline mutes the guard for the rest of the current turn instead of asking at every step.
  • One wrapper per engine, whoever gets there first. The host half marks the wrapper function through a global-registry symbol, so a preset row arriving second recognizes the work and stays inert, even when the two halves are separate copies of this package.
  • No new session event types. The bundle adds no SessionEventMap member: an event type this build does not know would make the session log unreadable to the very build that wrote it. The client surface derives everything from existing events and the guard's own state.
  • Zero runtime dependencies. The package imports nothing outside itself, so it cannot bind to a second copy of a harness class. It reads two global-registry symbols (cordis.original) instead of importing cordis.

Installation

dsh plugin --profile web add file:C:/path/to/plugins/dsh-cache-guard

That is the whole installation: the bundle patch mounts the host half, and the host half guards every preset realm's engine. The log shows dsh-cache-guard: guarded a compaction engine of a preset realm (1 in this process, mode manual) as soon as a session's realm appears, and dsh-cache-guard: host ready (default mode manual) at startup.

A preset row is only needed where the host half cannot be installed — a deployment that composes its profile without bundle patches. It must sit inside the preset's compaction group, because that group isolates the compaction and toolResultPruner services. The installer writes a preset that includes the shipped composition and patches that one row in:

node tools/install-profile.mjs --profile web --preset cache-guard
# ~/.dsh/.agent-presets/cache-guard/agent.cordis.yml
- id: base
name: &#x27;cordis:include&#x27;
config:
path: &#x27;file:////config/agent-presets/standard/agent.cordis.yml&#x27;
patches:
- id: compaction
insert:
- id: cache-guard
name: &#x27;file:////.dsh/profiles/web/node_modules/dsh-cache-guard/engine.js&#x27;
config:
mode: manual

cordis:include applies patches to the entries it reads, and an insert patch carrying an id pushes its rows into that group's child list. The preset is therefore the shipped composition plus one row, not a copy: a harness update to the shipped preset applies here too. The same file shape works for code, cordis, or a preset of your own — change --source.

A preset is chosen when a session starts, so a running session keeps the composition it began with — which is why the host half, not a preset row, is what makes the guard cover every session. When a row is used, its log line is dsh-cache-guard: engine guarded (mode manual), and in a profile that also carries the host half the row reports already guarded by the host plane.

Profiles

The preset roots and the settings document belong to the harness home, not to one profile, so:

  • The host half guards every session of the profile it is installed in — one install per profile, and that profile needs no preset.
  • A preset row, when used, is available to every profile on that machine: the engine half is self-contained (it resolves every dependency from its own directory), so one installed copy serves all of them.
  • The pill and its mode menu need the host half in that profile. Without it nothing on screen can switch modes — and without it, nothing guards anything either.
  • --set-default writes the machine-wide agent-presets.default. It is only meaningful for a row-based installation; with the host half installed, sessions are already guarded whatever preset they run, so leave the profile's own default alone.
  • A profile without a question provider (headless, automation) has nothing to ask: in manual mode the guard then declines every automatic rewrite, and the session eventually hits its window. Set mode: auto for such a profile's host row (cordis.patch.yml) or turn the guard off there.

For plugin development, install it as a link so edits apply without reinstalling (file: entries are copies that pnpm does not refresh):

dsh plugin --profile web add link:C:/path/to/plugins/dsh-cache-guard

Configuration

The host row governs. A preset row's config applies only where the host half is absent — an engine is wrapped once, by whoever gets there first, and the host plane always announces before a preset row applies.

Key Default Meaning
mode manual manual asks before an automatic surface change; auto only reports it; off leaves the operation to the engine as shipped
pricePerMTokens unset full-price input rate per million tokens; adds a currency amount to the dialog and the pill
estimatedSummaryTokens 4000 assumed checkpoint size used when pricing a planned summarization

The trigger threshold belongs to the engine, not to the guard: it is the compaction-basic row's thresholdRatio (default 0.8, i.e. compact once 80% of the routed window is in use). The installer can set it — it patches that row's config in the generated preset, which is the whole of that row's config because a patch replaces rather than merges:

node tools/install-profile.mjs --threshold 0.9

Verification & Testing

npm test                                   # unit and contract tests
node tools/simulate-session.mjs 02abdc01   # price a real session&#x27;s first automatic rewrite
node tools/install-profile.mjs --dry-run   # show what the installer would change
node tools/verify-preset.mjs ~/.dsh/.agent-presets/cache-guard/agent.cordis.yml
dsh web --dump-config | Select-String cache-guard

tools/simulate-session.mjs truncates a real session log to the moment before its first automatic rewrite, rebuilds a real Session, prices the pending plan through the real token meter and the real pruner, and compares the prediction with the provider usage the log recorded afterwards. On the session above it predicted 28 rewrites, the first change at surface position 8, and 724,447 cold tokens — against 28 rewrites and 720,764 actual full-price tokens: 0.5 % off.

tools/verify-preset.mjs composes a preset file through a real Loader and prints what it contains — every row, the compaction group's children, and the config the engine row carries. It answers the question a config change raises and a file read does not: does the threshold this profile defaults to actually reach compaction-basic, and is the engine row still inside the group. Rows mount as stubs, so it needs no service, no model, and no running server.

Known Limitations

  • The cold split is calibrated, not guaranteed. The request total comes from the harness's own pressure number (provider-anchored where the session has provider usage); the fixed part is read from the session's cheapest real request. A very large opening message makes the fixed part slightly high and the cold estimate slightly low.
  • The checkpoint size is an estimate — a planned summarization is priced with estimatedSummaryTokens, because the real summary does not exist before it runs. Prune numbers are exact, and the plan states which of the two it is.
  • The per-session mode is process-local. "Allow automatically for this session" lasts until the harness restarts; a durable record would need a session event type this build knows, which an out-of-repo plugin cannot add.
  • A declined overflow still ends the turn. At a provider-confirmed context overflow the window is already exhausted, so declining preserves the original provider error.
  • The plan mirrors the engine's resolution. The trigger ratio, the retention budget, the routed provider/model (from the durable request/header the engine itself reads), and the safe-cut rule are recomputed here from the public engine config and the session surface — because the guard selects the range it replaces. A change upstream must be followed here; a range the engine rejects leaves the surface untouched and logs the failure.
  • A profile without the host half is not guarded at all. The gate is installed by the bundle's host row; a profile that composes without it (or disables it) has no veto, no dialog, and no pill. The preset row covers that case, one preset at a time.
  • The pill's reassurance is derived, not promised. Cache: ask means the process guards at least one engine; a fresh session confirms it after its first step, when the live context line appears. Cache: not armed is the honest answer when nothing is guarded.
  • A pricing failure spends rather than strands. If the guard cannot price an operation it hands the operation to the engine and says so in the log. That is the same cache cost the session would have paid without the plugin — deliberately chosen over declining every rewrite in every session.
  • A profile with no question provider blocks rather than spends. With mode: manual and nothing to ask, the guard declines and logs it; the session then runs to its window limit. Use mode: auto for a headless profile's row.
  • Everything but the harness vocabulary is English. Code, comments, docs, dialog copy, and the pill are English; only the harness terms the guard reports (compaction/prune, thresholdRatio, retainRatio) keep their upstream spelling.

🤝 Contributing

Keep the layout: one module per concern under lib/, one test file per module under test/, every claimed measurement traceable to a real session. Run npm test before and after a change.

🔗 Links

  • 📚 DeepSeek Harness
  • 🐛 Issues
  • 📦 NPM Package

License

MIT © loonylabs-dev


Maintained by loonylabs-dev

常见问题

5 问
答案由本站依据条目字段整理,不引用上游原文
dsh-cache-guard 怎么安装?

在 DSH 里执行 `dsh plugin --profile web add github:loonylabs/dsh-cache-guard` 即可。

dsh-cache-guard 的验证等级是什么意思?

L5 · 运行验证通过。在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来

dsh-cache-guard 安全吗?

低风险。

dsh-cache-guard 装之前要先确认什么?

先看它会读写哪些文件、执行哪些命令、连接哪些网络地址;验证等级只说明装得上、跑得起来,不等于安全。涉及密钥或系统权限的,建议先在隔离环境试装。

dsh-cache-guard 用的是什么许可证?

上游标注为 MIT。商用或二次分发前请到仓库确认许可证原文。

同名或近似条目

2 条
不同作者的仓库分开列,请确认你要装的是哪一个
记忆与知识
按星标排序,可作替代方案

ruflo

ruflo

L3 · 安装规范通过 7.4 万 星

OpenViking

OpenViking

面向 DeepSeek Harness 的 OpenViking 记忆与上下文插件:pre-step 自动召回与画像注入、会话捕获、`vik

L3 · 安装规范通过 3.9 万 星

WeKnora

WeKnora

把 WeKnora 知识库接入 dsh 的四个只读工具:列出知识库、混合检索原文片段、按顺序还原单篇文档,以及直接取用 WeKnora 自己

L4 · 沙盒安装通过 3.3 万 星

distilly

distilly

Distilly — Distill how they think into reusable Skills for any Agent o

L4 · 沙盒安装通过 2.5 万 星

EverOS

EverOS

L4 · 沙盒安装通过 1.3 万 星

MemOS

MemOS

L4 · 沙盒安装通过 1.2 万 星

插件的元信息来自作者仓库;分类、验证等级与安全结论的中文说明为中文整理,最近核验 —。