Skip to content

dsh-pr-watch

Verified

dsh-pr-watch · v1.0.0 · MIT · Web UI

PR status window for the DeepSeek Harness Web GUI — floating pull-request chips with CI check tallies, review/mergeability badges, auto-discovery of your open PRs, and per-session branch scoping. Uses your existing gh CLI auth.

Install

dsh plugin add dsh-pr-watch

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Tags

Creators

Readme

dsh-pr-watch

A pull-request status window for the DeepSeek Harness Web GUI — a stack of small floating chips, one per watched PR, pinned to the corner of the chat: live CI check-tallies (5✓ 1✗ …), draft / mergeable / review-decision badges, and a click-to-expand panel listing every check with a link to its CI run.

Everything flows through the gh CLI that's already signed in on your machine, so private and SSO-gated repos work with zero token setup.

npm

Features

  • Per-session scoping — the chips attach to the chat session you're actually viewing. Each session's window shows only the PRs whose head branch matches the workspace checked out for that session; home, settings and sessions with no open PR show nothing. No more overlay spam across tabs.
  • Auto-discovery — every poll re-runs gh pr list --author @me, so a PR you open (or close/merge) appears and disappears on its own. Pinned PRs can be added alongside.
  • Multi-PR — one chip per pull request (capped at 12 to protect the corner), click any chip to see its checks.
  • Truthful staleness — if the host bridge blinks, the chips keep your last good data and say it's stale instead of flicking to "offline".
  • Honest failure surface — failed lookups render as a small ⚠ n chip instead of failing silently.
  • Self-authenticating — the status endpoint only answers same-machine callers, or callers holding the app's own auth cookie. It picks up no tokens and stores nothing.

Requirements

  • DeepSeek Harness desktop app with the Web GUI (plugins ecosystem),
  • GitHub CLI (gh) installed and authenticated (gh auth login) — that's the only credential the plugin uses.

Install

# in ~/.dsh/profiles/<your-profile>
npm install dsh-pr-watch
pnpm install            # profiles are pnpm workspaces

Then add the package name to dsh.profile.bundles in that profile's package.json (bundle order = apply order; anywhere near the end is fine), and restart the app. The plugin activates itself through its own bundle patch — no hand-editing of cordis.patch.yml (the app regenerates that file on boot and would wipe any row you add there).

Configuration

The plugin ships with a minimal default config. Put your own preferences in ~/.dsh/pr-watch.config.json — it overrides the shipped defaults, and it is re-read on every poll so edits take effect without restarting the app:

{
  "repo": "owner/repo",          // optional: derived from `dir`'s git remote when omitted
  "dir": "~/code/my-repo",       // a local checkout gh runs in
  "pollSeconds": 120,            // host refresh cadence (min 60)
  "autoDetect": "mine",          // "mine" | "branch" | "off"
  "prs": [                       // optional pins, always watched
    { "repo": "owner/repo", "number": 123, "dir": "~/code/my-repo" }
  ]
}
Field Default Notes
repo derived from dir's remote GitHub owner/name used for discovery and pinning
dir ~ Any local path; needed for repo derivation and branch scoping to be useful
pollSeconds 120 Min 60 enforced
autoDetect "mine" when a repo is known, else "off" "mine": every open PR by the gh user (appears/vanishes within one poll). "branch": the PR of the current branch in dir. "off": pins only
prs [] Pinned targets, deduped against discovery; total target cap is 12

Zero-config mode

If your chat sessions run in worktrees/checkouts of the repos you care about, you can leave everything defaulted: the session-scoped request already carries the session's workspace dir, and the host answers with the PRs that match its branch.

How it works

┌──────── Desktop app host ────────┐        ┌──────── Web GUI client ────────┐
│ poll every N s:                  │        │ visible session:               │
│  gh pr list/view + gh pr checks  │  GET   │  uiSession → sessions store    │
│  ─ branch filter per ?dir=       │◀───────│  cwd → ?dir=<cwd>              │
│  auth: loopback or app cookie    │  JSON  │  chip per PR, panel per click  │
└──────────────────────────────────┘        └────────────────────────────────┘
  • The host half (lib/index.js) is a cordis plugin: it polls gh for the pinned + discovered targets and serves the snapshot at /plugins/pr-watch/status.json. gh pr checks exits non-zero when a check fails — its TSV is read from the rejection's stdout (gh 2.42-era CLIs have no --json for checks).
  • The client half (lib/client.js) figures out which chat session is on screen (uiSession service → active conversation wrapper → largest visible conversation), resolves that session's workspace dir via the sessions store, and asks the host for the branch-scoped snapshot. Sessions whose branch has no open PR simply display nothing.

Security

Named webserver routes are not behind the app's browser-cookie gate, so this plugin trusts only loopback callers, plus remote callers that satisfy the app's own browserAuth.isAuthenticated(req). The branch probe runs git -C <dir> branch --show-current through execFile argument arrays (no shell), and check rows are rendered with textContent only.

Development

node --test            # parse/tally unit tests

License

MIT — see LICENSE.