dsh-onfail
DSH plugin: poll GitHub Actions, surface failed checks as cards, open a fix session with log context.
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 28, 2026
- Updated
- Aug 28, 2026
Introduction
dsh-onfail
CI failed. Stay in DSH. Click the card, start the fix. CI 挂了也别离开 DSH:侧栏一张失败卡,点一下带 log 开修。
DeepSeek Harness plugin: poll one GitHub repository's Actions, surface failed checks as sidebar cards (job name, SHA, log tail), and open a repair session preloaded with that failure context.
v0 is polling only. No webhooks.
Install
Requires a DSH web profile. From any directory:
dsh plugin --profile web add github:ZZZjf13960/dsh-onfail
This package ships committed JavaScript (dsh/index.js + dsh/client.js) on main, so the GitHub specifier is loadable without a prepare build or pnpm allowBuilds gate.
Then start (or restart) the web UI:
dsh --profile web
The plugin mounts as package name dsh-onfail via cordis.patch.yml. Settings, then Plugins, should show an Onfail (GitHub Actions) card. A CI control appears in the sidebar footer; failed checks also render as overlay cards.
Remove
Either form drops the profile dependency and the bundle layer:
dsh plugin --profile web remove github:ZZZjf13960/dsh-onfail
dsh plugin --profile web remove dsh-onfail
Restart the web UI so the host process unloads the routes and the browser half.
Configure
| Field | Default | Where |
|---|---|---|
repo | empty | Plugin settings card, or config.repo on the dsh-onfail loader row (owner/name) |
token | empty | Plugin settings card (never echoed back). Also DSH_ONFAIL_TOKEN then GITHUB_TOKEN |
pollIntervalMs | 60000 | Settings card or loader config (~60s) |
fixture | false | Settings checkbox, loader config, or DSH_ONFAIL_FIXTURE=1 |
logTailChars | 4000 | Loader config |
Token resolution order: plugin config, then DSH_ONFAIL_TOKEN, then GITHUB_TOKEN. Nothing is hardcoded. A teammate supplies a live token and CI later.
A classic repo PAT (or GitHub App installation token) needs Actions read on that repository. Fine-grained PATs need Actions: Read.
Loader override example ($DSH_HOME/profiles/web/cordis.patch.yml):
- id: dsh-onfail
config:
repo: your-org/your-repo
pollIntervalMs: 60000
fixture: false
Polling
Every pollIntervalMs the host half calls:
GET /repos/{owner}/{repo}/actions/runs?status=completed- For failed / timed-out runs,
GET .../actions/runs/{id}/jobs - For failed jobs,
GET .../actions/jobs/{id}/logs(log tail cached per job id)
There are no webhooks. The browser half polls GET /dsh-onfail/state every few seconds and renders cards.
Fixture mode
Tests and a live UI walkthrough can produce a card without a GitHub token:
- Settings, Onfail, enable Fixture mode, or
DSH_ONFAIL_FIXTURE=1, or- loader
config.fixture: true
This loads fixtures/failed-run.json (acme/widget, job unit-tests, SHA aaaabbb, a failing test log tail).
node --test
Acceptance checks
-
Install from GitHub on main. Manifest tests assert
dsh.bundle.patchpoints atcordis.patch.ymlthat inserts packagedsh-onfail, plusexports["./client"]anddsh.client. JS is committed onmain. Verifier still runsdsh plugin --profile web add github:ZZZjf13960/dsh-onfail. -
Failed Actions checks become sidebar cards (job, SHA, log tail). Fixture and the poll mapper produce that card shape. The client registers
sidebar.footer.actionandshell.overlay. Verifier still confirms the CI footer / overlay cards in DSH Web. -
Clicking a card opens a repair session with repo, job, SHA, and log tail. The click path is
sessions.create→sessions.open→session.prompt(..., 'queue'). A rejected prompt or failed create shows arole=statuserror on the card. Composer paste is not a session. Verifier still clicks a card in the live UI. -
Missing token: readable error, harness does not crash or hang.
apply()with no token setserrorand still registers routes; it never throws. Verifier still opens the plugin UI with empty token/repo. -
Remove drops the profile entry. Documented;
dsh plugin removereconciles bundles by installed state. Verifier still runs remove and checksdsh.profile.bundles.
Layout
dsh-onfail/
package.json # dsh.bundle + dsh.client + exports
cordis.patch.yml # insert id/name: dsh-onfail
fixtures/failed-run.json
dsh/index.js # host apply (imports @deepseek-ai/cordis + schemastery)
dsh/plugin.js # poll loop + /dsh-onfail/* routes
dsh/client.js # lazy CJS browser half
dsh/config.js poll.js cards.js http.js
test/*.test.js
License
MIT