Bundle
dsh-jenkins
Jenkins CLI plugin (dual-face): multi-server config page, model tools, and a per-workspace Run-Jenkins-Job entry with environment tabs. Bilingual UI (zh/en), no hardcoded paths, publishable to npm / GitHub
- Source
- jsoncode
- stars
- 2 stars
- License
- MIT
- Updated
- Updated 14 hours ago
Readme
# dsh-jenkins
<p align="center">
<img src="assets/preview/1.png" alt="dsh-jenkins preview" width="800" />
</p>
**dsh-jenkins** is a Jenkins management plugin built on the DeepSeek Harness (DSH)
host, centralizing multiple servers and jobs for fast build publishing.
- **Multi-server / multi-job management** — configure and manage multiple Jenkins
servers and jobs in one place
- **One-click publishing** — trigger parameterized builds, track
queue → building → result in real time
- **Logs & operations** — view build logs, stop or cancel builds at any time
- **Bilingual UI** — follows the host interface language (中文 / English)
Available from the Settings page, a per-workspace entry, and model tools.
[中文文档](README.zh.md)
## Preview
Screenshots of the Settings page, workspace entry and run/history modals: see [preview.md](preview.md).
## Features
- **Settings → Jenkins Config** page (`settings.section`): add / edit / delete
multiple servers (URL, username, Token), test connections, skip TLS verification.
Only **Server URL** and **Token** are required (username defaults to `admin`).
- **Workspace entry** (`sidebar.footer.action`): a footer group with the **Jenkins
logo button** (opens the Run Jenkins Job modal) and a **History button** (clock
icon, publish history of the last 50 runs across all workspaces, filterable by
workspace — defaults to All) appears when the current workspace root contains a
`dsh-jenkins.{json,js,ts}` config file.
The modal has **searchable dropdowns** for server / job, a parameter form
pre-filled from the config, build triggering, and status polling (queued →
building → result, with a 10-minute timeout). The server dropdown shows the
**intersection of the servers referenced by the config and the servers configured
in the plugin**; selecting a server auto-selects the configured job and echoes its
parameters. The last submitted **server / job / parameters** are remembered per
workspace and auto-echoed the next time the modal opens (browser `localStorage`).
A missing or invalid config file is treated as "not configured" — no entry is shown.
- **Entry visibility**: the sidebar entry follows a **Show in menu** preference
(default on), toggled from **Settings → Jenkins Config** or the top of the
modal's **Config** tab. When off the entry renders nothing; the host settings
page keeps an **Open Jenkins Config** button so the modal stays reachable
(both places share one preference source and stay in sync).
- **Model tools** (docs/develop/basic/tool): `dsh_jenkins_build`, `dsh_jenkins_status`.
- **Config** (docs/develop/basic/config): Schemastery `Config` + a plugin data file
`$DSH_HOME/dsh-jenkins.json` (server tokens encrypted with the machine-bound key
`$DSH_HOME/dsh-jenkins.key`, cache in plaintext; on first run any legacy
`dsh-jenkins` namespace in `settings.yaml` is migrated once and cleared).
- **Packaging** (docs/develop/basic/publish): `dsh.bundle` + `dsh.client`(web) manifests.
## Structure
```
├── src/host/*.ts # Host half source: index.ts (entry), jenkins.ts (curl core), ops.ts (op dispatch), workspace-config.ts, types.ts
├── src/client/*.tsx # Browser half source (React TSX components): Settings page, footer entry, run-job modal, history modal
├── lib/index.js # Host half build artifact (tsdown, ESM), committed for git installs
├── lib/client.js # Browser half build artifact (tsdown → __ModuleLoader__ factory), committed
├── lib/types/ # Type declarations (generated by tsc -b)
├── scripts/ # verify-client.mjs (host-seed simulation check)
├── tsdown.config.ts # tsdown build config (node half + client bundle banner wrapper)
├── tsconfig.json # solution: references tsconfig.host.json / tsconfig.client.json
├── cordis.patch.yml # Bundle patch: plugin row referenced by package name (no paths)
├── package.json # dsh.bundle + dsh.client(web) manifests + peerDependencies
├── README.md # This file (English)
├── README.zh.md # 中文文档
└── preview.md # Screenshot preview (references assets/preview/*.png)
```
## Workspace config file (`dsh-jenkins.json` / `.js` / `.ts`)
Place it in the **workspace root**. It is an **array**; each element is one deploy
target (job + server + environments params). `.json` is parsed directly; `.js` / `.ts`
are evaluated with node (CJS `module.exports` or ESM `export default`):
```json
[
{
"job": "build-app",
"server": "http://uat.example.com",
"environments": { "BRANCH": "main", "DEPLOY": false }
},
{
"job": "build-app",
"server": "http://prod.example.com",
"environments": { "BRANCH": "release-1.0", "DEPLOY": true }
}
]
```
- Every element requires `job` (Jenkins job path, e.g. `build-app` or
`folder/build-app`) and `server` (the server name / id / URL as configured in
Settings → Jenkins).
- `environments` (optional): the parameter map for this target (booleans render as
checkboxes, everything else as text fields).
- The modal's server dropdown shows the **intersection** of the servers referenced
by the config and the servers configured in the plugin; selecting a server
auto-selects the matching `job` (left empty when absent from the Jenkins job list,
letting the user choose) and echoes its parameters. If the intersection is empty,
the dropdown degrades to all servers with a hint. A missing or invalid config is
treated as "not configured" — the entry is hidden.
## Installation
```sh
# Local development
dsh plugin --profile web add ./dsh-jenkins
# Published: npm / tarball / GitHub
dsh plugin --profile web add dsh-jenkins
dsh plugin --profile web add ./dsh-jenkins-0.1.4.tgz
dsh plugin --profile web add github:you/dsh-jenkins#<sha>
dsh --profile web --dump-config # verify the layer
dsh --profile web # start (restart required for the host half to reload)
```
> **Local development dependencies**: the host loads `index.js` through native Node ESM, so
> `@deepseek-ai/schemastery`, `@deepseek-ai/dsh-tools` and `@deepseek-ai/dsh-settings` must be
> resolvable from the plugin directory (`node_modules` is gitignored). Either:
> 1. run `pnpm install` inside the plugin directory (these three are declared as
> devDependencies); or
> 2. junction the host's flat fallback copies, e.g.:
> ```powershell
> New-Item -ItemType Directory "$PWD\node_modules\@deepseek-ai" -Force
> foreach ($p in 'schemastery','dsh-tools','dsh-settings') {
> New-Item -ItemType Junction "$PWD\node_modules\@deepseek-ai\$p" -Target "$env:DSH_HOME\profiles\node_modules\@deepseek-ai\$p"
> }
> ```
Static server defaults can also be set in the profile's `cordis.patch.yml`:
```yaml
- insert:
- id: dsh-jenkins
name: dsh-jenkins
config:
servers:
- id: prod
name: 生产环境
baseUrl: https://jenkins.example.com
username: admin
token: <API Token or password>
insecure: false
```
## Publish
The build toolchain is **tsc + tsdown** (same as `@lemcae/dsh-balance` and other
similar plugins — no vite): `tsc -b` type-checks and emits declarations, while
`tsdown` (Rolldown core) bundles the host half (`lib/index.js`, ESM) and the
browser half (`lib/client.js`, single-file CJS `__ModuleLoader__` factory with
auto banner wrapping). Dependency management uses **pnpm 10** (Node 26; the
`pnpm-lock.yaml` is committed and CI installs with `--frozen-lockfile`):
```sh
pnpm install # install per pnpm-lock.yaml
pnpm run build # clean lib → tsc -b (types + declarations) → tsdown (both halves)
pnpm run verify # simulate the host module table to check lib/client.js (optional)
pnpm publish # or pnpm pack / git push origin main (lib/ is committed; git installs need no build)
```
### Automated publishing (GitHub Actions)
Pushing a `v*` tag (`pnpm run release` bumps the patch version, rebuilds the
artifact, and tags it automatically) triggers
[`.github/workflows/publish.yml`](.github/workflows/publish.yml):
- **release job**: Setup Node 26 → `pnpm install --frozen-lockfile` →
`pnpm run check` (tsc -b) → `pnpm run build` (tsc -b && tsdown) →
`pnpm pack` → creates a GitHub Release (auto-generated changelog, tarball
attached);
- **publish-npm job**: publishes to npm — requires the `NPM_TOKEN` repository
secret (Settings → Secrets and variables → Actions); fails fast with a hint
when it is missing.
## Development
Requirements: **Node ≥ 26 + pnpm 10** (the `packageManager` field in
`package.json` pins the pnpm version).
```sh
pnpm install # devDependencies: typescript, tsdown, @types/react, @deepseek-ai/* type packages, etc.
pnpm run check # whole-tree TypeScript type check (tsc -b)
pnpm run build # rebuild both halves after editing source (tsc -b && tsdown)
pnpm run watch # tsdown watch mode (rebuild on src/client changes)
pnpm run verify # simulate the host seed table to check lib/client.js loads
```
- Host half lives in `src/host/`; browser half in `src/client/` (build entry
`src/client/index.ts`, exporting `{ name, inject, apply }` directly);
- The `window.__ModuleLoader__.load` factory wrapper of `lib/client.js` is
generated by tsdown's banner/intro/footer options (no hand-written wrap
script);
- External dependencies in the artifact (`react`,
`@deepseek-ai/dsh-client-ui-primitives`, ...) stay external and resolve from
the host module table (seed) at runtime.
## Implementation notes
- Jenkins REST via `curl.exe` through the host `shell` service: Basic auth + CSRF crumb
+ `--data-binary @-` (form body over stdin, UTF-8 without BOM); `-D -` parses status
and the `Location` header.
- Browser ↔ host transport: `ctx.remote.commands.execute(sessionId, '/dsh-jenkins <json>')`,
host errors carry a `code` that the client localizes (fallback to the raw message).
- Peer dependencies (`@deepseek-ai/cordis`, `dsh-tools`, `schemastery`, `dsh-settings`,
`dsh-commands`, `dsh-session`, `dsh-api-remotes`, client runtime/ui-slots/ui-settings/
cordis-client-runner, `react`) are resolved by the host at install time.
- The official `deepseek-harness` project is **not modified**; all features use existing
slots (`sidebar.footer.action`, `settings.section`, `shell.overlay`) and the command
transport.
- **Style isolation**: every rule in the injected stylesheet is scoped to `.dshj-*`
with one deliberate exception — `:where(div:has(> [data-slot="sidebar.footer.action"] > .dshj-footer-group)){flex-direction:column}`,
which stacks the host footer container (the host lays it out as a flex **row**, so
several plugin entries would squeeze onto one line). It can only match a container
that already holds **this plugin's own entry**, and `:where()` drops its specificity
to 0 so the host can always override it. Keyframe names are `dshj-`-prefixed and the
style tag is marked `data-plugin-css="dsh-jenkins/settings.css"`; no other global
selector, no `:root`/`body`/`*` rule, no body-style mutation.
- **Dialog palette**: the modals follow dsh-get-balance — a `rgba(0,0,0,.32)` scrim
with `blur(12px) saturate(1.2)`, a `color-mix(bg-layer-1 78%)` glass panel with a
`border-l2` hairline and 14px radius, `border-l1` header/footer dividers, solid
`button-primary-fill` primary buttons and active tabs (translucent fills washed the
host's monochrome `#0f1115` / `#f9fafb` primary into grey), `bg-base` inputs and
dropdown panels, `bg-layer-2` cards, and `state-*` tokens for status colours.
Install
dsh plugin --profile web add github:jsoncode/dsh-jenkins
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-jenkins from the hub
- 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.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.