Skip to content
dsh.fish
Bundle

dsh-ci-cd-bot

DSH Web UI plugin: listens to GitHub issues/PRs across the account's repositories, auto-fixes issues whose repos are checked out locally, and turns PRs / feature requests / other items into a review-and-run queue with one-click agent execution and push.

Source
bkMoon1024
stars
4 stars
License
MIT
Updated
Updated 6 days ago

Readme

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/banner-dark.svg">
    <img src="docs/banner.svg" alt="dsh-ci-cd-bot" width="720">
  </picture>
</p>

<h1 align="center">dsh-ci-cd-bot</h1>

<p align="center">
  <em>DSH Web UI plugin — watches GitHub issues/PRs across your account's repositories, auto-fixes issues whose repos are checked out locally, and turns PRs, feature requests, and other items into a review-and-run queue with one-click agent execution and push.</em>
</p>

<p align="center">
  <a href="https://github.com/bkMoon1024/dsh-ci-cd-bot/stargazers"><img src="https://img.shields.io/github/stars/bkMoon1024/dsh-ci-cd-bot?logo=github&label=Stars" alt="GitHub stars"></a>
  <a href="https://github.com/bkMoon1024/dsh-ci-cd-bot/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-65a30d?style=flat" alt="MIT license"></a>
  <br>
  <img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=fff" alt="TypeScript">
  <img src="https://img.shields.io/badge/esbuild-FFCF00?style=flat&logo=esbuild&logoColor=000" alt="esbuild">
  <img src="https://img.shields.io/badge/shipped__plugin-16a34a?style=flat" alt="shipped plugin">
</p>

<p align="center">
  <b>English</b> · <a href="README.zh.md">中文</a>
</p>

---

## What it does

| Item | Handling |
| --- | --- |
| Bug issue, repo checked out locally | **Fully automatic**: an agent fixes the issue in the local checkout and self-tests → the plugin commits and pushes (optionally opens a PR) → replies to the issue |
| Feature request | Enters the board queue → click **Run** → agent implements → push → reply to the issue |
| Other issue (question / maintenance) | Enters the board queue → implements and pushes when a local checkout exists; otherwise the agent drafts a reply and the plugin posts it as a comment |
| Pull request | Enters the board queue → click **Review** → fetch the diff → agent reviews → submits APPROVE / REQUEST_CHANGES / COMMENT according to the verdict, auto-merges on approve (configurable) |

Every run is a **real agent session** (kept in the session list so you can watch the full transcript). All git plumbing — branch, commit, push — is done by the plugin itself, deterministically; the push policy can be set to **auto** or **confirm in the board**.

---

## How it works

The host half polls GitHub every N minutes (configurable): it lists the account's repositories, fetches recently updated issues/PRs per repo with a watermark (first poll backfills only the last few days), classifies them by label rules plus title/body keywords, and matches repositories to local checkouts found under the configured scan roots and DSH workspaces. New local bug issues are auto-enqueued; everything else waits in the board for a user choice.

Agent runs use the official headless pattern — `ctx.agents.create({ meta: { cwd } })` + `followup` + `whenIdle`, with success/failure decided by the `turn/end` reason in the session log. The agent only edits code and self-tests (git is forbidden in the prompt); the plugin then runs `fetch → checkout ghbot/#<n>-<slug> → add → commit → push` and writes back to GitHub (comment, PR, review, merge).

The browser half injects a **CI/CD** sidebar entry and a center-column board (mutual-exclusion handshake with the sibling panels via `dsh-panel-activate`). Config lives in `~/.dsh/dsh-ci-cd-bot.json` (0600) — the token never leaves the host, and the GUI settings page edits it through a loopback-fenced `/api/dsh-ghbot/*` route family.

---

## Quick start

DSH plugins are installed into a **profile** (`dsh web` corresponds to the `web` profile). Requires Node.js ≥ 22 and `dsh` 0.1.0-rc.6.

The package is published on npm, so installing from npm is the recommended path; building from source is only needed for development/debugging.

Full installation guide — prerequisites, npm / source / manual install, verify, update, uninstall: **[INSTALL.md](INSTALL.md)**.

### From npm (recommended)

```bash
dsh plugin --profile web add dsh-ci-cd-bot
dsh web
```

### From source

```bash
git clone https://github.com/bkMoon1024/dsh-ci-cd-bot.git
cd dsh-ci-cd-bot
npm install --ignore-scripts   # the esbuild platform binary ships via optionalDependencies — no postinstall needed
npm run build
npm test                       # 11 headless behavior scenarios

# the package ships its own cordis.patch.yml (declared via dsh.bundle.patch),
# so the plugin row registers automatically
dsh plugin --profile web add link:$(pwd)

dsh web
```

### Manual install (no pnpm / dsh plugin)

```bash
ln -sfn "$(pwd)" ~/.dsh/profiles/node_modules/dsh-ci-cd-bot
# then append to ~/.dsh/profiles/web/cordis.patch.yml:
#   - insert:
#       - id: ci-cd-bot
#         name: 'dsh-ci-cd-bot'
dsh web
```

> Switching from a manual install to `dsh plugin add`? Remove the manually added `insert` entry first — the bundle patch registers the plugin row itself and duplicate rows conflict.

### Verify & uninstall

```bash
dsh --profile web --dump-config | grep ci-cd-bot   # confirm the config layer mounted
```

After a restart a **CI/CD** entry appears in the sidebar. First use: open the board → 设置 → paste a GitHub token (repo scope), configure scan roots if needed → save.

```bash
dsh plugin --profile web remove dsh-ci-cd-bot   # npm / repo install
# or delete the symlink + insert entry           # manual install
dsh web
```

---

## Configuration

Most parameters are editable in the board's settings page; changes apply immediately and persist to `~/.dsh/dsh-ci-cd-bot.json` (`announceToAgent` is JSON / API only). Complete reference — required fields, defaults, examples, security notes: **[CONFIG.md](CONFIG.md)**.

| Field | Default | Description |
| --- | --- | --- |
| GitHub Token | — | GitHub PAT with repo scope; kept on the host, never sent to the browser |
| Poll interval (ms) | `300000` | How often the listener polls GitHub |
| Backfill window (days) | `3` | First-poll window for open items |
| Scan roots | — | Extra local roots scanned for git checkouts (DSH workspaces are added automatically) |
| Bug labels | `bug,故障,defect` | Labels that classify an issue as a bug |
| Feature labels | `enhancement,feature,需求` | Labels that classify an issue as a feature request |
| Auto-fix local bugs | on | Bug issues whose repo is checked out locally run automatically |
| Push policy | `auto` | `auto` pushes immediately; `confirm` parks the run at a board confirmation gate |
| Open a PR after fixes | on | Push the `ghbot/…` branch and open a PR instead of merging directly |
| Reply to the issue | on | Post a summary comment after a run finishes |
| Auto-merge on approve | on | Merge a PR when the review verdict is approve |
| Run concurrency | `2` | Max concurrent agent runs |
| Run timeout (ms) | `1800000` | Hard timeout for one agent run |
| Enable listener | on | Master switch for polling + execution |
| Announce to agent | on | System-prompt section announcing the plugin to chat agents |
| Include / exclude repos | — | `owner/repo` filters (empty = all account repos) |

---

## Tech stack & structure

| Layer | Choice |
| --- | --- |
| Platform | DSH Web GUI plugin — host half + browser half (shipped form, no dsh source changes) |
| Language | TypeScript (host half runs in the ordinary Node process: node builtins, fetch, dsh SDK packages) |
| Build | esbuild platform binary invoked directly + tsc declarations (`node build.mjs`) |
| Runtime deps | Host: `@deepseek-ai/dsh-agent` / `dsh-llm` / `dsh-session` (resolved by the dsh installation); browser: `react` (platform seed word) |
| Storage | `~/.dsh/dsh-ci-cd-bot.json` (config) + `~/.dsh/dsh-ci-cd-bot-state.json` (items / watermarks) |

```
dsh-ci-cd-bot/
├── package.json            # plugin manifest (dsh.client / dsh.bundle)
├── cordis.patch.yml        # profile patch layer: registers the plugin row
├── INSTALL.md / CONFIG.md  # installation guide / configuration manual
├── build.mjs               # esbuild build (browser CJS wrap + host ESM)
├── tsconfig.json / tsconfig.build.json
├── src/
│   ├── index.ts            # host half: listener/runner/queue/routes/announcement
│   ├── gh.ts               # GitHub REST client (fetch, pagination, rate-limit backoff)
│   ├── listener.ts         # polling engine (watermarks, auto-enqueue local bugs)
│   ├── agent-run.ts        # ctx.agents.create({meta:{cwd}}) → followup → whenIdle
│   ├── runner.ts           # fix/implement/handle flows + git plumbing + push policy
│   ├── review.ts           # PR review flow (diff → agent → submit review / merge)
│   ├── routes.ts           # /api/dsh-ghbot/* (loopback-fenced)
│   └── client/
│       ├── index.ts        # browser half entry
│       ├── sidebar-entry.ts# DOM-injected sidebar entry (family-block convention)
│       ├── board-mount.tsx # center-column React root + panel mutual exclusion
│       ├── Board.tsx / settings-view.tsx / controller.ts / api.ts
│       └── locales.ts / board.css / styles.ts
├── tests/run.mjs           # 11 headless behavior scenarios
├── lib/                    # build output (committed, directly linkable)
└── docs/                   # banners + design notes
```

---

## Known limitations

- The sibling sidebar panels (task board, SSH) do not know the `ghbot` panel-activate event value; their controllers stay "open" internally while this board is visible (visual exclusivity holds, one extra click toggles back).
- Classification is rule-based (labels + keywords, both configurable); an LLM fallback is a planned option.
- A timed-out run is marked failed but the agent is not cancelled mid-flight.
- github.com only (no GitHub Enterprise yet); the board refreshes by polling, not SSE.

---

## Development

```bash
npm run typecheck   # tsc --noEmit
npm run build       # lib/client.js + lib/index.js + lib/types
npm test            # node tests/run.mjs — 11 behavior scenarios
```

Source must stay compatible with Node's strip-only TypeScript loader (used by the test runner): no parameter properties (`constructor(readonly x)`), no `enum`, no `namespace`.

---

## Publishing

```bash
npm run build
npm publish          # publishes dsh-ci-cd-bot with the bundled cordis.patch.yml
```

A tag-triggered CI pipeline (verify version tag → build + test → publish → GitHub release with artifacts) can be added the same way as sibling DSH plugins.

---

## Links

- **Repository**: [github.com/bkMoon1024/dsh-ci-cd-bot](https://github.com/bkMoon1024/dsh-ci-cd-bot)
- **Installation**: [INSTALL.md](INSTALL.md) · **Configuration**: [CONFIG.md](CONFIG.md)
- **DeepSeek Harness**: [github.com/deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness)

---

## License

[![MIT](https://img.shields.io/badge/license-MIT-65a30d)](LICENSE)

MIT © bkMoon1024

Install

dsh plugin --profile web add github:bkMoon1024/dsh-ci-cd-bot#c2f8f7b6f16780360978addf4ffea00f5c1676aa

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
Source