AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

File Browser

skill-vanducng-skills-file-browser · by vanducng

Local HTTP server that renders markdown, code, text, JSON, CSV/TSV/XLSX tables, HTML, PDF, images, video, and audio in the browser. Persistent left tree sidebar with vim keybindings (j/k/h/l/gg/G/Enter/o), filter (/), theme toggle (T), and folder open/collapse persistence per tab. Markdown dispatches to a novel-theme reader (Mermaid, plan nav, ToC scroll-spy); code/text dispatches to a highlight.…

— No reviews yet
0 installs
39 views
0.0% view→install

Install

$ agentstack add skill-vanducng-skills-file-browser

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-vanducng-skills-file-browser)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of File Browser? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

file-browser

One local HTTP server, one port, one CLI — handles markdown, images, video, and audio. Dispatches by file extension at the /view route: markdown goes to the novel-theme reader; image/video/audio go to the media viewer.

Installation

cd $HOME/skills/skills/file-browser && npm install

Dependencies: marked, highlight.js, gray-matter (markdown), pdfjs-dist (PDF viewer), read-excel-file (XLSX tables). Media rendering is zero-dep — browser does the work.

npm install runs a postinstall hook that copies pdfjs-dist runtime deps (worker, cmaps, fonts, wasm helpers) from node_modules/pdfjs-dist/ into assets/pdfjs-viewer/. If you ran npm install --ignore-scripts, populate the assets manually:

node $HOME/skills/skills/file-browser/scripts/install-pdfjs-assets.cjs

Quick Start

# Single file (auto-detects markdown vs media)
node $HOME/skills/skills/file-browser/scripts/server.cjs --file ./plan.md --open
node $HOME/skills/skills/file-browser/scripts/server.cjs --file ./photo.png --open
node $HOME/skills/skills/file-browser/scripts/server.cjs --file ./demo.mp4 --open

# Folder (gallery + Documents section)
node $HOME/skills/skills/file-browser/scripts/server.cjs --dir ~/plans --open

# Background mode (returns JSON envelope on stdout)
node $HOME/skills/skills/file-browser/scripts/server.cjs --file ./README.md --background

# Stop all running file-browser servers
node $HOME/skills/skills/file-browser/scripts/server.cjs --stop

CLI Options

| Option | Description | Default | |---|---|---| | --file | Single file (markdown / image / video / audio) | - | | --dir | Folder gallery | - | | --port | Server port (auto-increments if busy) | 3556 | | --host | Bind host (0.0.0.0 for LAN) | localhost | | --open / --no-open | Auto-open browser | open by default | | --background | Detach as child, print JSON | false | | --foreground | Stay foreground (Claude Code bg tasks) | false | | --stop | Stop all file-browser servers | - |

HTTP Routes

| Route | Description | |---|---| | /view?file= | Dispatches by extension. .md/.markdown/.mdx → novel-theme markdown reader (Mermaid, plan nav, ToC). .csv/.tsv/.xlsx → tabular data view. .pdf → custom PDF.js viewer iframe. Image/video/audio → media single-view with arrow-key prev/next. Append ?raw=1 to fall through to source view. | | /browse?dir= | Gallery: folders, Documents (markdown + PDF + CSV/TSV/XLSX), Media (image/video/audio), Other files. | | /file/ | Raw byte streaming with HTTP Range support (required for video seeking and Safari audio). | | /api/tree?dir= | Lazy directory listing (one level) for the sidebar tree. Returns JSON {path, entries[]} where each entry has {name, path, kind: dir\|file, fileType?: markdown\|pdf\|table\|image\|video\|audio\|other}. | | /assets/* | Static assets (theme CSS, reader JS, sidebar JS). | | /assets/pdfjs-viewer/* | Custom PDF viewer + pdfjs-dist runtime deps (populated by postinstall). | | / | Welcome / route reference. |

Supported Formats

Documents: .md, .markdown, .mdx (rendered with marked + highlight.js + Mermaid), .csv, .tsv, .xlsx (tabular data view; XLSX renders the first worksheet), .pdf (custom minimal viewer wrapping the pdfjs-dist PDFViewer component) Images: PNG, JPEG, GIF, WebP, AVIF, SVG, BMP, ICO, HEIC/HEIF (Safari only), JPEG XL, APNG Video: MP4, WebM, MOV, M4V, MKV*, OGV Audio: MP3, M4A, AAC, OGG, Opus, WAV, FLAC

\* MKV codec support depends on browser. For codec-difficult video, fall back to IINA.

Markdown Features (inherited from markdown-render)

  • Novel-theme reader (warm cream / dark gold), Libre Baskerville headings, max 720px width
  • Mermaid v11 diagrams, theme-aware light/dark, click to expand
  • Plan navigation: detects plan.md + phase-XX-*.md siblings, builds accordion sidebar with status badges, prev/next buttons
  • Cross-file links: relative .md links re-route through /view; relative non-md paths through /file/
  • Keyboard shortcuts: ? cheatsheet, T theme, S sidebar, ←/→ phase nav, Esc close
  • Auto-hide header, progress bar, mobile FAB

Media Features

  • Gallery grid with lazy-loaded image thumbs, video first-frame previews, audio cards
  • Single-view: arrow keys (← →) for prev/next sibling, Esc back to folder
  • HTTP Range support — required for `` scrubbing and Safari audio playback
  • Mixed media in same folder, sorted alphabetically

Sidebar Tree (gallery + single-view)

A persistent left sidebar shows the directory tree anchored at the launch folder (--dir) or the file's parent (--file). Lazy-loaded — only the root level loads up front; folders fetch their children on expand.

Vim keybindings

| Key | Action | | --- | --- | | j / k | Move cursor down / up | | h | Collapse open folder, or jump to parent | | l | Expand folder under cursor | | Enter / o | Open file or folder under cursor | | O | Open in a new tab | | gg / G | Jump to first / last visible node | | / | Focus filter input (substring match on visible names) | | n / N | Next / previous filter match | | r | Reload current folder's children | | \ | Toggle sidebar visibility (state persisted in localStorage) | | ? | Toggle keybinding cheatsheet overlay | | Esc | Clear filter / close help |

Click also works — clicking a folder toggles expand, clicking a file opens it. The currently-viewed file is highlighted; on page load, the sidebar auto-expands ancestors of the active path so the file is always visible.

The markdown reader has its own ToC + plan-nav sidebar, so the file-browser sidebar is intentionally NOT injected there. Press ← Folder (or browser back) to return to the gallery and use the tree.

Root persistence

The current tree root is saved to localStorage['fb-tree-root'] on every page load. URL ?root= is the canonical setter — when present, the server validates against the allow-list and the rendered value is written to storage. When absent, the client redirects once via location.replace to the same URL with the stored root appended, so refresh keeps the tree where you left it. A stale stored root that the server rejects is automatically replaced with the rendered (safe) value, so storage self-heals. The ↑ rebase button keeps working — it updates the URL ?root=, which then flows through the same save path.

Customizing / extending

  • assets/sidebar.js — keybinding map and tree behavior. Add a binding by extending the keydown switch.
  • assets/sidebar.css — layout (CSS grid: var(--sidebar-width) 1fr), colors via --sidebar-* tokens.
  • lib/sidebar.cjs — HTML stub including filter input + cheatsheet markup.
  • lib/tree-api.cjs — server-side directory listing. Add a new file classification by extending classifyFile.

Architecture

scripts/
├── server.cjs                      # CLI entry
├── lib/
│   ├── port-finder.cjs             # 3556-3600 range
│   ├── process-mgr.cjs             # PID prefix file-browser-*
│   ├── http-server.cjs             # Routing + dispatch by extension
│   ├── markdown-page.cjs           # Composes novel-theme HTML for .md
│   ├── markdown-renderer.cjs       # marked + highlight.js + gray-matter
│   ├── plan-navigator.cjs          # Plan detection, sidebar, prev/next
│   ├── plan-table-parser.cjs       # plan.md table → phases
│   ├── media-renderer.cjs          # Gallery + single-view for images/video/audio
│   ├── sidebar.cjs                 # Sidebar HTML stub injected into gallery + single-view
│   └── tree-api.cjs                # /api/tree directory listing (lazy)
└── tests/
    └── server.test.cjs             # Smoke tests for every dispatch path

assets/
├── styles.css                      # Media gallery + single-view theme
├── sidebar.css                     # Sidebar layout + tree styling
├── sidebar.js                      # Sidebar tree + vim keybindings
├── novel-theme.css                 # Markdown theme entry (imports modules)
├── styles/                         # Modular markdown CSS (variables, base, content, mermaid, ...)
├── template.html                   # Markdown viewer template
├── reader.js                       # Markdown client-side: Mermaid, sidebar, shortcuts
└── pdfjs-viewer/                   # Custom viewer.html + viewer.js + viewer.css; pdfjs-dist
                                    # runtime deps (build/, web/, cmaps/, standard_fonts/, wasm/)
                                    # populated by `postinstall` from node_modules/pdfjs-dist

Custom PDF viewer architecture

/assets/pdfjs-viewer/viewer.html is custom — pdfjs-dist (npm) does NOT ship Mozilla's standalone web/viewer.html, only the embeddable PDFViewer component. Our viewer wraps that component with a minimal toolbar (~250 LOC across viewer.html / viewer.js / viewer.css). Settings: enableScripting: false, isEvalSupported: false (defense-in-depth against CVE-2024-4367; pdfjs-dist ≥4.2.67 already disables isEvalSupported at the component level). To extend: edit viewer.html (toolbar markup), viewer.js (component wiring), or viewer.css (styling). Component API: https://github.com/mozilla/pdf.js/wiki/Viewer-options

Upgrading pdfjs-dist

  1. Bump pdfjs-dist in package.json.
  2. Re-run npm install (postinstall repopulates assets/pdfjs-viewer/).
  3. Run tests (node scripts/tests/server.test.cjs).
  4. Re-read exports of assets/pdfjs-viewer/web/pdf_viewer.mjs — verify PDFViewer, EventBus, PDFLinkService, PDFFindController, PDFHistory, DownloadManager, parseQueryString are still present with compatible signatures vs viewer.js.
  5. Manual smoke: open a real multi-page PDF and exercise every toolbar control (prev/next, page input, zoom, search, download).
  6. Check the changelog for security advisories — pin minimum to ≥4.2.67 (CVE-2024-4367).

Integration

Hammerspoon (Hyper+V → smart route to Arc)

dotfiles/hammerspoon/.hammerspoon/init.lua already routes the clipboard:

  • .md/.markdown/.mdx → calls file-browser /view (dispatches to markdown reader)
  • image/video/audio extensions → calls file-browser /view (dispatches to media viewer)
  • code/config files → opens in nvim
  • everything else → open

The Hammerspoon URL always appends &root= (file's parent dir, or the dir itself when launched on a folder) so each fresh launch overrides any localStorage-saved root from the previous session. Without this, the persistence layer would keep the sidebar anchored at whatever path the server was first started with.

nvim

mv (in polish.lua) — open current buffer in file-browser. If the file is renderable (markdown / image / video / audio), opens single-view; otherwise opens the parent directory's gallery.

Testing

node $HOME/skills/skills/file-browser/scripts/tests/server.test.cjs

Boots on a free port, hits every dispatch path (welcome, gallery, image view, markdown view, PDF viewer iframe, raw passthrough, file streaming, Range, traversal guard, missing params, 404, tree API, sidebar injection), cleans up. 38 tests.

Security

  • All ?file= / ?dir= / /file/* paths must resolve under one of the allow-list directories ($HOME + cwd + target dir + assets dir).
  • Null-byte and .. traversal rejected.
  • Error messages sanitized to strip absolute paths.
  • Server binds to localhost by default; --host 0.0.0.0 opt-in for LAN.

Open Questions

  • HEIC works in Safari only. Should we add ImageMagick on-the-fly conversion for Chrome? (Requires native dep — breaks the zero-runtime-dep posture for media.)
  • Should the gallery prefetch markdown front matter (title, status) so plan dirs render with badges before clicking in? (Adds I/O cost per gallery hit.)
  • Worth adding a /api/files?dir= JSON endpoint so the gallery could be a SPA later? (YAGNI for now.)
  • Should we render gallery thumbnails for PDFs (page-1 canvas, client-side, lazy via PDF.js)?
  • Should we add custom vim keybindings inside the PDF viewer iframe (postMessage bridge)?
  • Should we add an outline/bookmarks panel to the PDF viewer? (PDFOutlineViewer would need to be added to the component import set.)
  • Should we re-add a thumbnails sidebar to the PDF viewer? (PDFThumbnailViewer is not exported from pdfjs-dist@5.7.0's pdf_viewer.mjs; would require re-implementing or upgrading to a future major.)

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.