DeepSeek Harness Plugin

UndeadSheep/dsh-file-preview#dsh-file-preview

Stars ★ 1 Category UI Enhancements Added 2026-08-18

Floating workspace file-preview window for the Web client: lazy file tree, CodeMirror preview and in-window edit with save, Markdown and image preview, Quick Open search, and opening paths clicked in the conversation.

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:UndeadSheep/dsh-file-preview#path:/packages/dsh-file-preview

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

Workspace file-preview host half: a Typert Remote (filePreview) that lists the workspace tree, reads/writes text files, and resolves the preview theme and config for the browser half.

The browser UI lives in a separate package: @undeadsheep/dsh-client-ui-file-preview.

Remote surface

Method Request Result
listDir { sessionId, path } Ok<FileTreeNode[]> | Rejected
readFile { sessionId, path } Ok<{ path, content }> | Rejected
readImage { sessionId, path } Ok<{ path, mimeType, data }> | Rejected
writeFile { sessionId, path, content } Ok<{ path }> | Rejected
readTheme { sessionId } Ok<{ colors, bg, fg }>
readConfig { sessionId } Ok<{ indentSize, useTabs, pollInterval, fontSize }>

Business results use the repo's { ok: true, value } | { ok: false, error: { code, ... } } convention; the generated ./remote face wraps them in the RemoteResult carrier. Wire codecs are generated from the @Remote method types by typert codegen — there is no hand-written schema file.

listDir lists a single directory (path = '' for the workspace root) and skips heavy/noise directories (node_modules, .git, .next, .ssh, …) plus sensitive filenames (.env*, id_rsa*, *.pem, *.key, …). A single listing is capped at 1000 children. Dir nodes carry empty children, which the browser half fills lazily by calling listDir again when a directory is expanded. readFile / readImage / writeFile also refuse those sensitive paths, so typing them in Quick Open does not bypass the tree filter.

Config

Key Default Meaning
maxFileBytes 2097152 Maximum UTF-8 byte length the preview will read or write
maxImageBytes 5242880 Maximum byte length of an inline image the preview will read

Workspace config files (read per Session, optional)

  • preview.config.json — indentSize, useTabs, pollInterval, fontSize (with .prettierrc / package.json#prettier fallback for indent knobs)
  • preview-theme.json — keyword, string, number, comment, tag, function, type, variable, background, foreground
  • .vscode/settings.json — editor.tokenColorCustomizations and workbench.colorCustomizations are read as a fallback theme

Known limitations

  • Preview is text-only (plus raster png/jpeg/gif/webp); binary, SVG-as-image, or oversized files return not-text / too-large. A stat with no size is refused rather than reading the whole file into memory. Writes use the same byte cap as text reads.
  • listDir returns at most 1000 children per directory.
  • Symlink following after resolve is the host ctx.fs implementation's responsibility; this plugin re-resolves search children against workspaceRoot but cannot realpath on its own.
  • Syntax highlighting is a lightweight hand-written tokenizer (not highlight.js / TextMate), and a prettier engine cannot be embedded.
  • Auto-refresh is polling (pollInterval, clamped 500–60000 ms), not a real file watcher.

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.