설치
npx -y @deepseek-ai/dsh plugin --profile web add github:usertianziyang/DSH-Plugin-Hub이 설치 명령은 GitHub 저장소 주소에서 생성된 확인되지 않은 시작점입니다.
README
유지 관리자가 작성한 문서 스냅샷입니다.
DSH Plugin Hub
A searchable, client-side index of public GitHub repositories tagged with dsh-plugin, ranked by stars.
English · 简体中文 · GitHub Topic
⚠️ Disclaimer — this is not an official registry, store, or marketplace. Any repository maintainer can add the
dsh-plugintopic, so inclusion here is not an endorsement and does not guarantee that a repository is safe, maintained, or installable. Data boundary: every public repository carrying the exactdsh-plugintopic that the GitHub REST Search API could return during a successful, fully-validated sync. Private repositories and repositories without the exact topic are out of scope. GitHub's search index may lag a few minutes behind reality.
✨ Features
- 🌍 Bilingual UI — English and 简体中文, with auto-detection and a persisted toggle.
- ⚡ Fully static —
dist/is a plain SPA. No server, no API calls from the browser, no tracking. - 🔍 Client-side search & pagination — NFKC-normalized, case-insensitive, AND-semantics. Searches names, owners, descriptions, languages, licenses, and topics.
- 🏷️ Curated categories — MCP, Web UI, CLI, Desktop, Vision, Memory, Agent, Security, Developer Tools, Editor Integration, Awesome List, plus a unified All / Uncategorized view.
- 🛡️ Statically validated data — every sync shard is integrity-checked end-to-end; truncated or partial data is never published.
- ⏰ Auto-refreshing — a 6-hour GitHub Actions cron keeps
plugins.jsonfresh; Vercel re-deploys on every data commit. - ♿ Responsive & accessible — sticky header, search, and footer; respects
prefers-color-schemeandprefers-reduced-motion.
📸 Screenshot
The hero view. A sticky header carries site branding and a 中文 / English language toggle. The hero section shows the eyebrow "Community-ranked · Stars Top 10", a bilingual tagline, a direct link to the GitHub topic, and the last-synced timestamp. Below it, the Top 10 most-starred dsh-plugin repositories are rendered as rich cards (owner avatar & handle, description, language, star count, forks, open issues, license, and topic tags). Everything below the fold — the Explore view, category filters, full-text search, and pagination — is loaded from the same static plugins.json and runs entirely in the browser. The browser never calls the GitHub API.
📑 Table of Contents
🏗️ Architecture
GitHub REST Search API
│ (recursive date sharding + integrity checks)
▼
public/plugins.json ← atomic, validated static snapshot
│
▼
React + TypeScript (Vite) — search & pagination entirely in the browser
scripts/sync-github.tsfetches every matching repository via the officialGET /search/repositoriesendpoint (q=topic:dsh-plugin, sorted by stars).- The result is cleaned, de-duplicated, globally sorted, and validated, then written atomically to
public/plugins.json. - The browser loads
plugins.jsonand performs all search / pagination locally. The browser never calls the GitHub API.
Why recursive date sharding
GitHub Search returns at most 100 results per page and only the first 1,000 results of any query. Looping through pages cannot go past that ceiling. To collect all repositories the sync script recursively shards the query by repository creation date:
topic:dsh-plugin created:2008-01-01..<today UTC>
Any shard whose total_count exceeds 1,000 is split at the midpoint of its date range into two adjacent, non-overlapping, gap-free closed ranges. When a range is already a single day but still exceeds 1,000 results (which happens in practice — one day can hold thousands of repos), the sync falls back to a second, orthogonal dimension and bisects by star count (stars:min..max). A single star value that still needs more than one page would make sort=stars degenerate (every repository ties), so the sync falls back to a third orthogonal dimension and bisects by creation timestamp within the day (down to the second), reducing each shard to a single page and eliminating offset-pagination drift. A single second that still exceeds the page size aborts the sync. Truncated data is never published. All shards are merged and de-duplicated by GitHub repository id, then re-sorted globally.
Integrity guarantees
A sync is only "successful" when every check passes:
- ✅ Every API response is HTTP-successful and has
incomplete_results === false. - ✅ Every shard has
total_count <= 1000, fetches exactlyMath.ceil(total_count / 100)pages, and its de-duplicated count equals its first-pagetotal_count. - ✅ The merged snapshot has no duplicate
id, every item carries the exactdsh-plugintopic, counts are non-negative integers, and items are sorted by stars desc thenfull_nameasc. - ✅ The published
meta.total_countequals the number of repositories actually collected and validated during the run (a "collection-time snapshot"). The roottotal_countis still measured before and after collection and logged, but is not used as a publish gate: the live topic grows continuously, so a strict before/after equality requirement would never be satisfiable. Each shard is still strictly integrity-checked, so no truncated shard is ever published. - ✅ The snapshot is serialized to a temp file in the same directory, re-read, re-validated, and only then atomically renamed over
public/plugins.json. Any failure cleans up the temp file and leaves the last good snapshot intact.
🚀 Quick Start
Requirements
- Node.js 20.19+ (22.12+ or 24.x recommended)
Install
npm ci
Local development
npm run dev # start the Vite dev server
npm run test # run the offline test suite (node:test + tsx)
npm run typecheck # tsc --noEmit
npm run build # produce dist/
npm run preview # preview the production build
🔄 Syncing Data
The sync script reads the token exclusively from process.env.GITHUB_TOKEN. Create a local, git-ignored .env (see .env.example) or export it inline:
GITHUB_TOKEN=ghp_xxx npm run sync
The token is used only by the sync script. It never appears in frontend code, public/plugins.json, dist/, logs, or error messages.
Without a token (or before the first sync), the repository ships a valid placeholder public/plugins.json with items: [], total_count: 0, and complete: false so local builds still work.
Snapshot schema
public/plugins.json has meta (schema version, topic, topic URL, query, fetched_at, total_count, complete) and items, where each item maps a GitHub repository to: id, name, full_name, owner, owner_avatar_url, url, homepage, description, stars, forks, open_issues, language, license (SPDX id or null), topics, fork, archived, and the three timestamps. See src/types.ts.
🧩 Frontend
| File | Purpose |
|---|---|
src/App.tsx | Page shell, async state machine (idle / loading / success / error), search input, category navigation, URL state (?q, ?cat, ?view), and the data-source region. |
src/i18n.ts | English / 简体中文 translations, language detection, and persistence. |
src/categories.ts | A curated set of representative categories mapped from repository topics (e.g. web-ui → Web UI, mcp → MCP). |
src/search.ts | Pure, NFKC-normalized, case-insensitive, AND-semantics search. |
src/main.tsx | React root. |
src/styles.css | Design tokens, responsive layout, prefers-color-scheme, prefers-reduced-motion, and a sticky header / search / footer layout. |
The header, search bar (with category filters), and footer stay pinned while the page scrolls. The language toggle switches between English and Chinese and persists the choice. Categories are derived from each repository's topics (excluding dsh-plugin); plugins are grouped by category and sorted by stars descending within each category.
The snapshot is loaded via Vite's base URL so the app works at a domain root or any sub-path:
const dataUrl = `${import.meta.env.BASE_URL}plugins.json`;
Do not hard-code a hosting sub-path. For a sub-path deployment set Vite's base at build time (no source changes needed):
VITE_BASE=/my-app/ npm run build
🚢 Deployment
dist/ is a plain static site that can be served by any static host (Vercel, Netlify, Cloudflare Pages, S3 / CDN, nginx, …). After choosing a host, configure:
- Build command:
npm run build - Output directory:
dist
This project does not use GitHub Pages, and no specific hosting provider is preconfigured. Provider-specific deployment config is added only when a target is chosen (see the Vercel guide below).
Deploying to Vercel
This project targets Vercel as its host. The site is a fully static build (no serverless functions), configured by vercel.json (SPA rewrites, caching headers, and the npm run build / dist build settings).
Why the sync stays in GitHub Actions (not on Vercel)
The topic sync (scripts/sync-github.ts) recursively shards the GitHub Search API with a 2.1 s throttle and integrity checks, issuing a large number of requests that can take minutes. Vercel serverless functions are too short-lived for this, and Vercel's build filesystem is read-only, so the sync cannot run on Vercel. Instead:
- GitHub Actions runs the sync on a
15 */6 * * *cron (every 6 hours) and on manual dispatch, usinggithub.token(no personal token stored). - After a successful sync, the workflow commits the refreshed
public/plugins.jsonback tomain; the connected Vercel project automatically redeploys from that push. - Vercel only serves the static site and never talks to the GitHub API.
One-time setup
- Import the repo in Vercel. Choose the "Vite" framework preset, or rely on the values in
vercel.json(npm run build, outputdist). Vercel rebuilds on every push tomain, including the data commit from the sync workflow. - Enable GitHub Actions write permissions. In the repository, open Settings → Actions → General → Workflow permissions and select Read and write permissions so scheduled/manual syncs can commit
public/plugins.json.
That is all. On the next scheduled (or manually dispatched) sync, the workflow will refresh the data, commit it, and Vercel will redeploy automatically. No Vercel environment variable or Deploy Hook is required.
Notes
- The
GITHUB_TOKENused by the sync is GitHub's built-in per-run token; no long-lived token needs to be stored. It only needscontents: readfor the API andcontents: writefor the data commit (granted automatically on scheduled / manual runs).
🤝 CI
.github/workflows/ci.yml runs offline tests, type-check, and build on every pull request and push. .github/workflows/sync.yml runs the full data sync on a 6-hour schedule and on manual dispatch, then commits the refreshed snapshot back to main with contents: write. A successful CI build uploads the standard dist/ directory as a dsh-plugin-hub-dist artifact.
프로젝트 파일 및 신호
표시된 항목은 디렉터리 스냅샷에서 감지된 공개 저장소 신호입니다.
저장소 정보
- 언어
- TypeScript
- 라이선스
- MIT
- 최신 릴리스
- v1.0.1
- 마지막 업데이트
- 2026. 8. 18. AM 8:19
신중하게 설치하기
소스 코드, 권한, 수명 주기 스크립트, 의존성 및 네트워크 접근을 검토하고 신뢰하지 않는 플러그인은 격리 환경에서 테스트하세요.