deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:openAGFS/dsh-agfs
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
English | 中文

A file-browser web app for DeepSeek Harness — a React frontend and REST API served by the host webserver, plus a /dsh-agfs command and browse_files/read_file model tools. It rides the composing dsh web server: no separate port, no subprocess.

| 面包屑导航 Breadcrumbs | 视图切换 View switch | 侧边栏 Sidebar |
|---|---|---|
![]() |
![]() |
![]() |
| 搜索 Search | 本地打开 Local open |
|---|---|
![]() |
![]() |
/dsh-agfs command — opens the file browser in the system default browser and automatically navigates to the current session's workspace directory (session cwd); switch workspaces and it follows.browse_files / read_file model tools — the model can list or recursively search the browser root, and read text files under it, directly.strictRoot real-path checks, symlink/junction escape interception (clean 400 envelope), readOnly mode, remoteMode.X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer.dsh.bundle one-line install — activates as a profile layer.In the DeepSeek Harness web dialog, ask the agent directly, for example:
Install the file-browser plugin
dsh-agfs
Install the npm package
@open-agfs/dsh-agfs
The agent invokes a shell tool to run:
dsh plugin --profile web add @open-agfs/dsh-agfs
Then restart dsh web (or ask the agent to restart it) and run /dsh-agfs in the dialog to open the file browser.
Prerequisite: this flow needs the agent's shell tools (
bash/pwsh) enabled and permitted. The web profile disables shell tools by default — enable them under Settings → tools/permissions, or approve the command when the agent asks. Without shell tools, use Option 2.
dsh plugin --profile web add @open-agfs/dsh-agfs
After the install, restart dsh web and run /dsh-agfs in the dialog.
Upgrade to the latest version:
dsh plugin --profile web add @open-agfs/dsh-agfs@latest
From a checkout of this repository, mount the source through a --patch overlay:
- insert:
- id: dsh-agfs
name: 'file:///absolute/path/to/dsh-agfs/src/index.ts'
then dsh web --patch ./overlay.yml. Plugin code changes need a dsh restart; frontend assets are served from disk per request.
/dsh-agfs in the dialog: the system default browser opens the file browser and reports its URL; when the current session carries a workspace directory (session cwd), the browser boots directly at that workspace.openOnCommand: false the URL is only reported, the browser is not opened.readOnly).| Key | Default | Meaning |
|---|---|---|
basePath |
/dsh-agfs |
Webserver route prefix serving the app and its API; must start with / and have no trailing slash. |
fileRoot |
current working directory | File-browser root; drives stay reachable through the sidebar. |
projectRoot |
working directory | Project root shown in the sidebar. |
remoteMode |
false |
When true, the open, open_location, and copy endpoints are disabled. |
readOnly |
false |
When true, the delete, create_folder, rename, and copy endpoints answer 403; browsing stays fully readable. |
strictRoot |
false |
When true, browsing is locked inside fileRoot: absolute paths are rejected and symlink/junction escapes fail with a 400 envelope. |
roots |
{} |
Named browse roots shown in the sidebar as name -> path; entries that do not resolve to an existing directory are dropped. |
openOnCommand |
true |
Whether /dsh-agfs opens the system default browser. |
debug |
false |
When true, API calls and system-open results are logged to the dsh process stderr with a [dsh-agfs:debug] prefix. |
Config lives in the profile's user patch layer ($DSH_HOME/profiles/<name>/cordis.patch.yml):
- id: dsh-agfs
config:
fileRoot: 'D:/projects/my-project'
readOnly: true
The frontend calls the endpoint set under ${basePath}/api/file_browser/: list, read, download, open, open_location, search, info, workspace, sidebar, thumbnail, mode, debug, delete, create_folder, rename, copy, and analyze (one-click AI analysis, local mode only). Paths are confined under the browsable root. search accepts recursive=1 (also true/yes) with a 200-hit cap and a directory-depth cap of 5. Every response carries the security headers; static assets answer GET/HEAD only.
The plugin registers two model tools over the same pure core the HTTP layer uses:
browse_files (parameters path, keyword, recursive) — list a directory or search entry names (optionally recursively). Returns a canonical { items: [...] } value rendered as TYPE<TAB>SIZE<TAB>PATH text lines; a blank keyword falls back to a plain listing.read_file (parameter path) — read one UTF-8 text file (markdown, code, logs) under the browser root and return its content, so an analysis agent can inspect file contents, not only names.The parameter schemas and descriptions flow into the assembled prompt like every other registered tool.
app.js), but the toolbar icons still come from cdnjs; without network access the app works without icons.search matches entry names in one directory (200-hit cap); recursive content search is not implemented.openOnCommand spawns on the host — the browser opens on the machine running dsh, which is correct for a loopback deployment but surprising for remote clients.pnpm install
pnpm test # vitest: unit suites plus the real-Loader composition suite (94 tests)
pnpm typecheck # tsc --noEmit
pnpm lint # oxlint
pnpm build # tsc types + tsdown bundles -> lib/
pnpm run build:frontend # regenerate assets/app.js after editing assets/app.jsx
The frontend source is assets/app.jsx; its compiled form assets/app.js (classic JSX runtime, no Babel at runtime) and the vendored React/ReactDOM UMD builds under assets/vendor/ ship in the package so the app boots without a CDN.
Releases are tag-driven: pushing a v* tag triggers GitHub Actions (.github/workflows/publish.yml) to publish to npm. Tags are cut manually — the script never tags on its own:
pnpm run release # report release state only (no writes)
pnpm run release -- --do # cut a release now (patch bump): commit + tag + push
pnpm run release -- --do --version 0.2.0 # cut a release at a chosen version
pnpm run release -- --do --dry-run # preview without writing or pushing
scripts/release.mjs without flags prints the current version, the last v* tag, and the commit count since it; with --do it bumps the version, commits chore: release vX.Y.Z, creates the tag, and pushes main + the tag. The repository needs an AGFS secret (a granular npm publish token with bypass-2FA). The package declares the published @deepseek-ai/dsh-* harness packages as peers, so a published install resolves them from npm.
^22.19 || >=24; peers @deepseek-ai/dsh-* (rc.6)CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。