0x7a76/dsh-extra-paths ↗★ 0

dsh-extra-paths

配置一组额外可写根:fs 工具与受限 shell 首次尝试即可写、无需审批,带 Web 设置页与按目录结构锚定的路径模式。 · DSH plugin: configured extra writable roots for the fs tools and the sandboxed shell, with a Web settings page and structure-anchored path patterns. 适合需要免审批直接读写特定工作目录的开发或自动化任务。

패키지
dsh-extra-paths
호환성
미검증
Harness peer 범위
>=0.1.5-0 <0.1.6-0 || >=0.2.0-0 <0.2.2-0
Cordis peer 범위
^4.0.2
버전
0.1.1
라이선스
MIT
최근 업데이트
2026. 10. 15.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:0x7a76/dsh-extra-paths

Configuration

Write it into the extra-paths section of the settings document ~/.dsh/settings.yaml, or just use the settings page (saving takes effect immediately, no restart needed). `` below is a placeholder for the directory that holds your projects (an absolute path, or one starting with ~/) — replace it with a path of your own:

extra-paths:
  paths:
    - /notes/home                   # default scope/surfaces
    - path: ../../notes/home                   # relative paths resolve against the session workspace
      scope: always-write
    - path: /some-repo
      scope: write
      surfaces: [fs]                           # only the write/edit tools may write here
scopesession read-onlysession workspace-write
write (default)deniedwritable
always-writewritablewritable

surfaces: fs = the write/edit/str-replace tools; shell = bash subprocesses. Reads and execution are not sandboxed to begin with.

How relative paths resolve

Relative paths resolve against each session's own workspace (the settings page has a "base workspace" field so you can preview this):

SpellingResolves toNotes
..``the parent of the workspace; that directory and all of its siblings become writable
../some-repo/some-repogrants exactly one sibling repository (more precise than .., recommended)
../../notes/home/notes/homego up a few levels and into another tree
~/notes/homeunder your homeindependent of the workspace; ~user is not expanded (same as the host)

Patterns: anchor a grant to directory structure (no hard-coded paths)

A path can use wildcards to describe a group of directories, turning "a certain directory exists somewhere in this path" into a condition:

SpellingMatches (the granted root)
/**/.worktrees/..every repository root that contains .worktrees (the parent of .worktrees)
/**/.worktrees/*each individual worktree (.git and the main checkout are never touched)
//.worktrees/*every worktree of one repository (zero traversal cost, recommended)
/*/notesthe notes directory under every repository/project

Syntax: * = exactly one level, ** = at most 3 levels (only directories that actually exist match, so ".worktrees must exist" comes for free); a trailing .. moves up after matching (so …/.worktrees/.. is "the parent of .worktrees", rather than something lexical collapsing eats away).

Safety bounds (hard constraints, not advice):

  • the wildcard needs a literal anchor before it, at least two segments long, absolute or starting with ~/ — /**, ~/**, /srv/** are refused outright
  • traversal never enters node_modules or .git, and ** never enters hidden directories (.worktrees is a literal, so it still matches at its own level)
  • bounded: ** covers at most 3 levels, and more than 4096 directories or more than 256 matches makes the whole pattern inert (fail closed — never a partial, unpredictable grant); the reason is reported as a warning
  • expansions are cached for 30 seconds, so a newly created worktree is picked up within 30 seconds

The settings page shows the resolved absolute path live for every row (symlinks follow the host's canonical preview) and, for a pattern row, the match count as [active ×N] plus each concrete root below it; zero matches and blocked patterns are both spelled out — so there is no need to "save first and then check whether it resolved".