Files
deepseek-harness/packages/ui/permission
kingwl 95635dfa66 feat(permission): user-facing permission presets — one Permissions select over the two knobs
A preset names a bundle of the two mechanism knobs — request =
workspace-write + ask, yolo = danger-full-access + never — so the editor
shows ONE 'Permissions' select where the sandbox-mode and approval-policy
tiers stay orthogonal capabilities (the Codex /approvals shape: presets over
two dials). ctx.permission (dsh-permission) owns the config-defined table,
validates the default preset's bundle against the composed knob defaults at
load (fails loud), and writes a switch THROUGH: one log-only
permission/preset event (the audit fact reverse-mapping cannot recover —
the planned 'agent' preset shares request's knob values and differs only in
composed policy) plus each knob event via its own setter, deduped — a
net-zero switch appends nothing. Every knob consumer keeps reading its own
fold, untouched.

The current preset DERIVES from the effective knob values — the fold breaks
bundle ties, a knob state outside the table is the reserved 'custom' value
(a state, not an error: shown while it holds, switchable FROM, never a
target), and defaultPreset disappears (zero-event state reverse-maps from
the composition defaults).

The ACP bridge drops the two per-knob selects for the one preset select
(advertised only when ctx.permission is composed); pending/anchor/no-op
semantics carry over unchanged, with the no-op echo acknowledged before
vocabulary validation so a client re-pushing a derived 'custom' current
never errors. The sandbox variant example composes the
service with a workspace-write default; the permission-switching,
escalation-approved and escalation-rejected scenarios are re-recorded under
it (escalations now target an outside-workspace /tmp path under
danger-full-access, self-cleaning) and config-options is re-authored on the
single-select wire.
2026-07-13 14:38:26 +08:00
..

@deepseek-ai/dsh-permission

User-facing permission presets. Owns the ctx.permission service (PermissionService): a config-defined preset table — by default request (workspace-write + ask) and yolo (danger-full-access + never) — where each name bundles the two mechanism knobs, bash/sandbox-mode and approval/policy. The product surface (the ACP bridge's single Permissions select) advertises names and calls set(); the mechanism tiers stay orthogonal capabilities that never learn the product vocabulary.

A switch WRITES THROUGH: set(session, name) appends one log-only permission/preset event when the name differs from the session's current preset (the audit fact reverse-mapping cannot recover — two presets may share knob values and differ only in composed policy, the planned agent preset being the standing example), then each knob event through its own THE-write-path setter, skipping values the session already effectively has — a net-zero switch appends nothing. The current preset DERIVES from the effective knob values (fold ?? composition default per knob): the last-chosen preset when its bundle still matches (presets may share bundles — the fold breaks the tie), else the first matching table entry, else the reserved custom — the honest not-a-preset state, shown as the current value only while it holds, switchable FROM and never a target. Every existing knob consumer (executor stamping, the approval gate, narrators, resume) keeps reading its own fold, untouched.

Composing it requires a confining ctx.bash executor and the ctx.approval seam; a table entry named custom throws at load (the name is reserved), while composition defaults outside the table are not an error — a zero-event session simply derives custom. See the acp-agent example's sandbox variant for the composed leaf and the sandbox RFC § Per-session modes for the switching design this layers over.