Back to home@AngelosZou

dsh-github-router

No description

Stars
2
Language
JavaScript
Created
Aug 19, 2026
Updated
Aug 21, 2026
GitHub repo

Introduction

dsh-github-router

English | 中文

Read-only GitHub access for a DeepSeek Harness project — load PRs, issues, files, and API data through tools that route internally (API, gh CLI, git protocol, page HTML, mirrors), so an agent never burns turns fighting shell-side TLS or proxy failures.

License: MIT Node.js >= 20.18 npm version

A DeepSeek Harness plugin bundle that gives agents GitHub reads without shell retries:

  • Five read-only toolsgithub_probe, github_pr, github_issue, github_file, github_api — plus the github-router skill and a system-prompt guidance section. No write, push, comment, or mutation capability exists anywhere in the package.
  • In-tool routing — every request runs host-side (outside the sandbox's TLS/proxy restrictions) and falls through a route ladder: api.github.com (direct → proxy) → gh CLI (read-only subcommands) → git protocol (plugin fetch cache, or a local clone read with log/diff/show only) → PR/issue page HTML (strict JSON island extraction) → user-configured raw mirrors.
  • One call, structured outcome — PRs come back with metadata, discussion, reviews, commits, changed files, and the diff, each part annotated with the route that served it; failures return a route matrix instead of a dozen retried shell commands.
  • Connectivity probegithub_probe reports which routes are live from the host in one call, with timings and a recommended route chain.
  • Zero runtime dependencies — peers resolve from the DSH profile; proxied requests travel through the plugin's own CONNECT tunnel (no third-party HTTP stack), so the package installs fully offline.
  • Settings page — an independent Settings entry ("GitHub Router", like the 通知 section): the dsh-github-router settings namespace (secret token, proxy, route switches, cache TTLs, byte caps) with staged edits, save/discard, and override badges.
  • Context efficiency — response caching with per-kind TTLs, byte caps everywhere, list caps with truncation notes, and rate-limit surfacing.

Requirements

  • Node.js >= 20.18
  • A DSH profile composed from @deepseek-ai/dsh-base (it provides the tools, subprocess, skills, settings, and credentials services the plugin uses)
  • Optional: the gh CLI (authenticated) for the gh route; git for the git route

Install

From npm:

dsh plugin --profile web add dsh-github-router

From a local checkout (development):

dsh plugin --profile web add link:<absolute-path-to-this-repo>

From a git host:

dsh plugin --profile web add github:<owner>/dsh-github-router

Then restart the DSH backend — the host composition loads at process start. The tools appear in new sessions: github_probe, github_pr, github_issue, github_file, github_api, plus the github-router skill.

Usage

Agent side:

ToolWhat it does
github_probeOne-shot connectivity matrix (api direct/proxy, gh installed/authed, git ls-remote, page direct/proxy, mirrors, token presence) with timings and a recommended route chain. Call first when access fails or is slow.
github_prFull PR view: metadata, description, discussion (issue + inline review comments), reviews, commits, changed files, and the unified diff, each with route attribution. Parts toggle (includeDiscussion/includeReviews/includeCommits/includeFiles/includeDiff) and cap (maxDiffBytes/maxItems). localRepo (or session-cwd auto-detection) reads commits/diff from a local clone with zero network.
github_issueIssue metadata, body, labels, and comments, with route attribution.
github_fileFile content (or directory listing) at a branch/tag/sha via api contents → raw → mirrors → git; returns size, truncation state, and the serving route.
github_apiValidated GET-only escape hatch for any api.github.com endpoint; query values sanitized, responses cached, rate-limit headers surfaced, errors carry stable codes.
github_probe                                                  # which routes are live right now
github_pr { owner: "o", repo: "r", number: 12 }               # full PR view
github_pr { owner: "o", repo: "r", number: 12, localRepo: "C:/src/r" }  # commits/diff from a local clone
github_issue { owner: "o", repo: "r", number: 34 }
github_file { owner: "o", repo: "r", path: "src/index.js", ref: "main" }
github_api { path: "/repos/o/r/commits", query: { per_page: 5 } }

Behavior notes:

  • Route order is fixed per part type: API first (direct then proxy), then gh, then page HTML (proxy-first — machines with reset direct TLS usually reach pages through the proxy), then git, then mirrors. Each part records the route that served it.
  • Anonymous API use is rate-limited (60 requests/hour per IP); configure a token (Settings or GITHUB_TOKEN) for 5000/hour. Responses are cached to save quota; forceRefresh bypasses the cache.
  • Mirrors are off by default — they are third parties that see requested paths; enable them in settings only if you accept that.
  • The git route never writes to user repositories: local clones are read with git log/diff/show only, and fetches happen exclusively in the plugin-owned cache under <DSH_HOME>/storages/dsh-github-router/.

Configuration

Settings → Plugins shows the GitHub Router card on the configurable tab (the framework's settings.plugin.item card slot keyed by the settings namespace; requires DSH ≥ 0.1.0-rc.7): edits are staged locally and written only on save, fields overridden by the user are badged, and blank fields fall back to the defaults below. The token is a write-only field — a blank save clears a configured token. The same values can be set in the composition (profile cordis.patch.yml) as the plugin's base config; the Settings UI overrides per user.

FieldDefaultMeaning
tokenLiteral GitHub token (secret; redacted on the wire, write-only input). Prefer tokenEnv.
tokenEnvGITHUB_TOKENEnvironment variable / credential ref naming the token.
proxy''Proxy URL for proxy attempts. '' inherits ambient HTTP(S)_PROXY; direct never proxies.
directTimeoutMs / proxyTimeoutMs8000 / 15000Per-attempt timeouts.
retries1Retries for idempotent GETs on 429/5xx (honors Retry-After).
routesApi / routesGh / routesGit / routesHtml / routesMirroron / on / on / on / offRoute switches (the card shows them as checkboxes).
mirrors[]Raw-content mirror bases, e.g. ["https://ghproxy.net"].
cacheTtlMeta / cacheTtlContent300 / 86400Response cache TTLs (PR/issue metadata vs immutable-ish content), in seconds.
maxBytes1048576Byte cap for every response body read by the plugin.
repos[]Local repositories granted for read-only git-route reads.
gitCacheDir''Plugin fetch-cache dir; '' = <DSH_HOME>/storages/dsh-github-router/git.

How it works

  • Host-side execution — plugin code runs in the host process, so the sandbox's TLS credential resets and proxy misrouting never apply. The unrestricted token is compensated by the confinement model in SECURITY.md — not by weakening the sandbox.
  • Explicit proxy decisions — global fetch does not inherit ambient proxy env; each attempt gets an explicit direct/proxy choice, and proxied requests use a zero-dependency CONNECT tunnel (node:http/node:tls) with target-hostname TLS validation and accept-encoding: identity.
  • Strict parsing — the page-HTML route extracts only react-app.embeddedData JSON islands and runs JSON.parse (never evaluated); a bounded BFS copies a whitelist of fields, so CSRF tokens and the raw payload never reach the model.
  • Argv-only subprocesses — every gh/git invocation is an argv array with fixed flag lists; user input reaches argv only after regex validation, and nothing is shell-interpolated.
  • Tool contract — canonical values are lossless JSON (arrays carry no side properties), byte-capped, and rendered as compact text with route attribution.
  • Skill & guidance — the github-router skill teaches tool-first usage and the "never escalate for GitHub reads" rule; one system-prompt section (dsh-github-router:guidance, order 118) reminds every session that the github_* tools are the sanctioned path.

Project layout

PathPurpose
cordis.patch.ymlProfile patch layer inserting the dsh-github-router row
lib/index.jsHost plugin: settings namespace, five tools, skill, guidance
lib/client.jsBrowser half: the settings card (hand-written factory bundle, no build step)
lib/config.jsSettings schema, defaults, runtime option resolution
lib/net.js, lib/tunnel.jsRoute-aware HTTP layer; zero-dependency CONNECT proxy tunnel
lib/routes/One module per route: api (GET-only REST), gh (CLI), git (protocol), html (page parse), mirror (raw mirrors)
lib/core/Per-call runtime assembly and the pr/issue/file/probe aggregators
lib/tools/The five model tools
lib/cache.js, lib/render.js, lib/util.jsTTL cache, text renderers, guards and shaping
lib/skill.js, lib/guidance.jsSkill content and prompt-injection section
test/Runtime-free behavior tests (see Development)
docs/Design and analysis documents

Development

No build step: the plugin is plain ESM and the tests run with Node directly (a mock ctx stands in for the DSH services; the real defineTool validates every schema):

npm test
# or: node --test --test-isolation=none "test/*.test.js"

The tests are fully offline — they cover JSON-island extraction, input guards, URL builders, the TTL cache, commit-log parsing, the tunnel request head, and the apply() wiring. See CONTRIBUTING.md for the development loop, including offline peer resolution.

Security

Read-only by construction: no write verb exists, tokens attach only to api.github.com and are redacted on every boundary, page payloads are whitelist-extracted, and the only disk writes are the two plugin-owned caches under <DSH_HOME>/storages/dsh-github-router/. See SECURITY.md for the complete threat model and mitigation list.

Documentation

License

MIT