Repository navigation
Releases: drscrewdriver/dsh-perm-gate
Release list
v5.3.2
v5.3.2
- hosts: 追加 0.2.1-rc.2 声明面枚举(34/34 @deepseek-ai/* 宿主 peer 逐包 npm 实测 rc.2 在版;本插件不触 ctx.web provider 与 conversation.input.model.label 槽,代码零改动,纯元数据发版;农场 rc.2 格挂账待命)
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v5.3.1
v5.3.1
Added
- Host support: DSH
0.2.1-rc.1. The supported-host enumeration (package.jsonengines.dsh,
dsh.plugin.json, every@deepseek-ai/dsh*peer and the README managed blocks) now lists
0.2.1-rc.1alongside the fifteen rc releases up the 0.2.0 line — exact per-rc enumeration,
no ranges. Behaviour is unchanged: this is a declaration-surface release so the host gate
(which since 0.2.1-alpha.4 reads engines.dsh alone) accepts the plugin on a 0.2.1-rc.1 host.
Changed
- Pinned
publishConfig.registrytohttps://registry.npmjs.org(release hygiene: a publish can
no longer drift to a mirror registry).
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v5.3.0
v5.3.0
Added
- YOLO tier (
yolo, owning thepermissive-yolopreset): never raises a human
confirmation. A dangerous ask — irreversible, unlearnable, an unreadable payload, or a
hard-risk verdict from the configured reviewer — is blocked and the reason is fed back to the
main agent as a工具审核意见user message; everything else runs. With no reviewer in seat it
does not quietly allow: the mechanical screen settles it and the event is labelled (see the
yolo-allow-no-reviewerentry below). - Degraded review (
rulesFallback): when the reviewer is not configured or returns no
verdict, the deterministic nets decide instead of parking the call on a confirmation nobody
will answer. Unchanged while a reviewer answers; it applies to the ordinary 自动审查 tiers
(permissive,permissive-full) — the three tiers that own an implementation already say who
answers, so this switch does not degrade them. - Script review (
scriptReview, on by default): the body of every script a call runs is read
(bounded, never executed) and given to the grader, the human card and the deterministic nets —
a delete that only shows up inside the file is graded on its code instead of its filename. A
fully-read script also stops being an unreadable payload; switching this off keeps file content
on the machine at the cost of sending such runs back to theU(unknown-target) tier. - User-declared protection, all additive and all hot-applied:
credentialPaths(path globs
held to the same standard as.ssh— reading one outside the workspace, or mutating one with a
file tool, is refused),denyKeywordsExtra(appends to the blacklist; the preset list stays
un-replaceable), andextraContentArgKeys/extraOperationArgKeys(which argument fields are
prose and which are operations, on top of the built-in lists). - Three unattended implementations, one switch and one permission preset each:
safenetAsk
(permissive-snet) screens with the deterministic nets and still asks a person, calling no
grader at all — the shape the gate takes when no reviewer LLM is connected, or when the tokens
are not worth spending and a human answer beats an auto-decision.safenetPass
(permissive-mech) lets the same screen take over the ask: named danger is blocked and fed
back to the main agent, everything it cannot condemn runs, with no human prompt and no model
call — the reviewed form ofapproval: never.yolo(permissive-yolo) is the model-backed
tier: the grader answers in the person's place and it never escalates. The mapping is the point:
a switch changes the behaviour of the tier named beside it and of no other, and switching an
implementation off returns that tier to the ordinary human flow rather than quietly turning it
into a different one. All five tiers ship in the plugin's own profile patch, so they are in
the permission picker on install with nothing to hand-edit;permissiveitself is untouched.
(A per-preset<preset>=<mode>table existed for two revisions and is retired — it competed with
these switches, and two controls for one posture means one of them lies.) - YOLO no longer claims a reviewer it did not get. With no grader configured, or one that
returnsunresolved, the tier still refuses to ask a person and settles on the mechanical
screen — but the event is recorded asyolo-allow-no-reviewerand the reason says so, because
an unlabelled fallback made YOLO and the mechanical tier indistinguishable in the approvals
history exactly when the model was missing. - One mechanical floor for every tier: the deterministic judge (irreversible / unlearnable /
unreadable) was hand-copied in three places — YOLO, the degraded gate and the new passthrough
tier. It is now a singlemechanicalJudge, so a tier can change only who settles the residual,
never what counts as danger. Pinned by tests: the same call is blocked under YOLO and under
passthrough alike, and neither spends a model call on it. - The settings card's booleans are now optimistic pill switches (36×20 capsule, state keyed off
aria-checked, theme tokens with fallbacks so light and dark both read correctly), and each
unattended row prints the preset it governs. They flip on click and hand the visual back to the
store when the write lands, is rejected, or is never reported. - The approvals history labels the decision paths that previously showed raw tags:
yolo-allow/
yolo-block,rules-fallback-*,safety-net-passthrough-*, plus four older ones that also
reached the feed untranslated (cleanup-safe,escalation-auto,learned-granted,network-ask). - A deterministic net for deletions aimed at the profile or a protected Windows root through a
variable or a glob ($HOME,~/.*,$env:USERPROFILE\.*,%WINDIR%,$PSHOME…): the
profile root is refused outright, other protected roots become a permanent confirmation that no
answer can be learned away. Measured: no grading prompt — not one primed with read-only-variable
knowledge — held this on a 9B reviewer, which is why it lives in code.
Fixed
- Issue #2: a document tool's prose is no longer read as an operation. One shared rule
(src/scan-text.ts) picks readable keys by tool class — a read/internal/write tool exposes only
its command, url, path and query fields, while an unfamiliar tool name is still treated as an
executor.exit_plan_modecan now describe a step it intends to ask about; previously the plan
text hit the destructive blacklist and the model learned to reword plans to get past the gate. - The same report's aside: newlines and glued
;/|/&&/||outside quotes are now
statement separators fordecomposeShellCommand, so the second statement of a multi-line
command is finally seen as a program a rule can match. This was the same root as the cross-line
delete leak; a lone&is left alone so2>&1and background jobs keep their shape. - Issue #3: an escalation the default safety screen produced reports itself
(write target outside the workspace (…)/command carries a file-write or redirect pattern)
instead of impersonating "no rule matched", and the reviewer's own sentence now reaches the
confirmation and the block wording — flattened, bracket-stripped, redacted and capped, so a
model cannot forge a[deny-rule:…]tag into the audit trail. - Issue #4: the write-pattern pre-screen no longer reads
=>or->as a redirect into a file. - Credential stores mutated through
write/edit(~/.ssh/authorized_keys,.git-credentials,
.npmrc, cloud credential files …) are refused at P0. Only deleting them was covered, so an
auto-allowed write could install an access backdoor. - The public half of a keypair (
id_ed25519.pub) is no longer caught by the whole-arguments
credential screen, which had made a hand-carried key restore impossible to appeal. deny-keywordaudit wording drops "preset" for entries the user appended.
Known gap
pathArgumentreadsfile_path/path/cwd/workdir; plural fields (paths,files,
urls) are not held to the credential-path standard.- A tool that executes a document it was given (
workflow,skill,ralph) is not read from that
body by the flattened screen; the work it delegates is gated as its own tool call.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v5.0.2
v5.0.2
chore(0.2.0): 5.0.2 — 5.0.1 tarball still carried the stale manifest; republish with corrected dsh.plugin.json
No CHANGELOG section found for this version; notes auto-derived from the tag commit message.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v5.0.1
v5.0.1
chore(0.2.0): 5.0.1 — republish with corrected dsh.plugin.json manifest
No CHANGELOG section found for this version; notes auto-derived from the tag commit message.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v2.0.0
v2.0.0
Fixed
- The gate stood down on every call under DSH 0.1.2, so the Approvals page stayed empty. The
session's permission-preset fold read the log asexec.agent.session.events. DSH 0.1.1 exposed
that array; 0.1.2 made the log private behindSession.snapshotEvents()/ownEvents()and kept
noeventsmember, so the read returnedundefined,presetOfansweredundefined, and
presetInScope(undefined, ['permissive'])madegateActivefalse for every call: no rule,
grant, deny-keyword, classifier, or P0 hard-deny decision, and no audit event — including in
sessions that had selected the gate's own tier, which is why the tab showed "本会话暂无审批记录"
rather than a failure. The fold now reads the log through every known accessor shape
(eventsarray,snapshotEvents(),ownEvents()) and degrades to "no events" only when the host
exposes none; the fold cache keys on the log's length plus its last event's identity, since a
0.1.2 snapshot is a fresh array over the same frozen events on every read.test/preset-scope.spec.ts
pins both shapes: a0.1.2-shaped session must yield a decision (and a recorded event), and a
grown log must re-fold so a preset switch takes effect on the next call.
Changed
- The
mainline's version series is now2.x, tracking the DSH line it serves.1.x
is the DSH<= 0.1.1line and2.xis the DSH0.1.2+line, so a plugin version says
which DSH it was built for;2.0.0is the first release of the new series and the
0.2.xreleases (0.2.0,0.2.1-beta.2…beta.5) are superseded by it. The majors
fence each other —^1.0.0does not resolve2.0.0and^2.0.0does not resolve
1.0.0— so an existing^0.2.1-beta.4install (which also does not resolve2.0.0)
must be bumped deliberately.engines.dshstates the same split
(>=0.1.2-alpha.1 <0.2.0-0here,>=0.1.0-rc.7 <0.1.2-alpha.1onlegacy), but DSH
never reads it: the version ranges and dist-tags are what keep an old DSH on1.x. - The permission tier is labelled 自动审查 on every surface, with no icon. The preset's
name:incordis.patch.ymlis now the Chinese product string, and the General-settings default
row, the composer picker, and the plugin's settings tab all show it. DSH 0.1.2 renders a
plugin-contributed tier'sname:verbatim and localizes only the three built-in values
(仅可查看/工作区内修改/完全权限), so the one host-supplied string is what a zh session sees;
the tier's machine value stayspermissive, which is whatgatePresetsmatches. The
permission-picker icon decoration is removed (src/client/permission-icon.tsdeleted): it existed
to match the retiredautotier's shield glyph, it applied to the settings row through the
0.1.2aria-haspopup="menu"selector, and a plugin tier draws no glyph because the composer's
glyphs are keyed to the built-in values only.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v1.0.0
v0.2.1-beta.5
v0.2.1-beta.5
fix: keep the gate active on DSH 0.1.2; label the tier 自动审查 (0.2.1-beta.5)
No CHANGELOG section found for this version; notes auto-derived from the tag commit message.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.
v0.2.1-beta.4
v0.2.1-beta.4
Added
trustEscalationstrategy in the Permissive tier (on by default while the tier is on): a
sandbox-escalation approval for a call this gate already allowed is answeredallowed-once
here instead of prompting you. The escalation is raised byapproveEscalationfrom inside
the shell / pwsh / edit tool body — aftertools/pre-executesettled — so the gate's own
allow never reached it and a call the LLM gradedsafestill asked you to approve the
widening. Only the exact call the gate cleared (matched bycallIdand tool name) skips the
prompt, and only for a recognized escalation reason namingworkspace-write/
danger-full-access; everything else delegates to the human unchanged. The auto-answer is
recorded on the event feed (verdict:"escalation-auto",mode:<target>). Turn the switch
off to keep sandbox widening human-gated.
Fixed
- The settings card now seeds the editable whitelist from the rules file.
installSettingsSection
calledscope.set('allowlist', …)on the host settings scope, which exposes only
get/watch/update/replace—set(field, value)is the client convenience wrapper
overmutate(), a different object — so the call threw and the namespace stayed unseeded.
It now usesscope.update({ allowlist: … }). - The
approval/requestlistener is registeredprependand is now an answering gate rather than
a passive observer, so it sits ahead of the remote bridge that renders the browser prompt. A
listener behind that bridge could only ever record a prompt that had already been shown. - The browser half no longer imports
@deepseek-ai/dsh-client-runtime, which DSH removed in
0.1.2-alpha.1.ClientContextnow comes from@deepseek-ai/cordis— the alias DSH 0.1.1
defined asexport type ClientContext = Context, so it names the same type on both lines — and
the settings card declares the four scope members it uses locally (SettingsScopeLike), the
same local-face pattern the host half already uses for the hostsettingsservice. The client
contract is byte-identical on both lines; only its exporting package moved.
Changed
- DSH compatibility now ships as two long-lived branches, each with its own version series,
engines.dsh, and npm dist-tag:main/0.2.x/>=0.1.2-alpha.1 <0.2.0-0/latest, and
legacy/1.x/>=0.1.0-rc.7 <0.1.2-alpha.1/legacy. This branch ismain. See
RELEASING.mdfor the branch layout and the cherry-pick flow. - On this line
ctx.slotsis declared by@deepseek-ai/dsh-client-ui-renderer/client— from
0.1.2-alpha.1on,@deepseek-ai/dsh-client-runtimeis gone — so the client entry imports it. - Client devDependency floors raised from
^0.1.0-rc.7to^0.1.5-rc.2, and
@deepseek-ai/dsh-client-ui-rendereradded. The old floor meant the build could only ever
resolve the 0.1.0-rc.8 package set, so this line was never compiled against. npm run verify:line(scripts/verify-line.mjs) installs this branch's line packages with
npm install --no-saveand runs typecheck + tests + build against them, so a build always
compiles against the packages the branch ships for.npm run verify:linesis an opt-in drift
check that builds on both lines and compares the bundles.
Release backfilled on 2026-10-22 from git tag + CHANGELOG history.