DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-jenkins

d

dsh-jenkins

Manifest valid

Manages multiple Jenkins servers and triggers jobs from a Settings page, model tools, or a per-workspace "Run Jenkins Job" entry, with a bilingual host + browser UI.

UI (client)hasBundlePatch

dsh-jenkins

dsh-jenkins preview

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.

中文文档

Preview

Screenshots of the Settings page, workspace entry and run/history modals: see 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).
  • Project Config ($DSH_HOME/dsh-jenkins-map.json): every project's publish targets in one file — project name → target array, with elements identical to a workspace config file ({ name?, job, server, environments }). Each env can carry a name display label (e.g. uat环境 / prod灰度 / prod环境) and the number of envs is unlimited (an empty name falls back to UAT / Prod / Env N). A dsh-jenkins.json/js/ts in a project root is discovered automatically (folder name as the project name, missing-only — nothing you edited is overwritten), so there is usually nothing to maintain by hand; to edit, click Edit map on the Project Config row of the Config tab (form / JSON). See Project config.
  • Workspace entry (sidebar.footer.action): a footer group with the Jenkins logo button (opens the unified modal) and a History button (clock icon, publish history of the last 50 runs across all workspaces, filterable by workspace — defaults to All). The Publish tab has just three rows — project → server → job — then the parameter form, build triggering and status polling (queued → building → result, 10-minute timeout). The env has no row of its own: each env in a project config is a server, so env selection lives in the Server dropdown — whose labels show only the plugin's server name (never a mix of the config's env name and the server name), and picking one switches the job / params to that env. Config server refs are matched against configured servers by name → id → full URL → domain (the domain level ignores scheme, port and context path). The dropdown shows the intersection of the servers referenced by the project config and the servers configured in the plugin; the last parameters are remembered per project and auto-echoed next time.
  • 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); the project config is its own file $DSH_HOME/dsh-jenkins-map.json (plaintext, hand-editable). On first run any legacy dsh-jenkins namespace in settings.yaml is migrated once and cleared; a legacy projects field inside dsh-jenkins.json is migrated into the new file (missing-only).
  • Packaging (docs/develop/basic/publish): dsh.bundle + dsh.client(web) manifests.

Structure

├── src/host/*.ts       # Host half: index.ts (entry), jenkins.ts (curl core), ops.ts (op dispatch), project-map.ts (project config file), projects.ts (normalize/merge), workspace-config.ts, types.ts
├── src/client/*.tsx    # Browser half (React TSX): settings page, footer entry, publish modal, project config 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) + isolated tests
├── examples/           # sample configs: dsh-jenkins.json (workspace array), dsh-jenkins-map.json (central map)
├── 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):

[
  {
    "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).
  • Such a file is now a discovery source: the plugin reads it into Project Config under the workspace folder name (missing-only — existing projects are never overwritten). Just pick the project on the Publish tab; server / job / params come from the current env.

Project config (dsh-jenkins-map.json)

One config for every project: project name → target array. Each env may carry a name display label (e.g. uat环境 / prod灰度 / prod环境) and the number of envs is unlimited (env 1 is the default, usually UAT); when the name is empty the UI falls back to UAT / Prod / Env N. Elements are identical to a workspace config file, so they can be moved back and forth:

{
  "health-check-ui": [
    {
      "name": "uat环境",
      "job": "system3_Front_docker3",
      "server": "https://dev-jenkins-tx.whale-plus.com",
      "environments": {
        "project": "health-check-ui",
        "branch": "uat5",
        "NodeVersion": "v24.12.0",
        "INSTALL_COMMAND_ACTIVE": "pnpm i --registry=https://repo.huaweicloud.com/repository/npm/",
        "BUILD_COMMAND_ACTIVE": "pnpm build:uat"
      }
    },
    {
      "name": "prod灰度",
      "job": "pro_system3_Front_docker3_gray",
      "server": "https://jenkins-tx.whale-plus.com",
      "environments": {
        "project": "health-check-ui",
        "branch": "release/gray",
        "NodeVersion": "v24.12.0",
        "BUILD_COMMAND_ACTIVE": "pnpm build:gray"
      }
    },
    {
      "name": "prod环境",
      "job": "pro_system3_Front_docker3",
      "server": "https://jenkins-tx.whale-plus.com",
      "environments": {
        "project": "health-check-ui",
        "branch": "master5",
        "NodeVersion": "v24.12.0",
        "BUILD_COMMAND_ACTIVE": "pnpm build:prod"
      }
    }
  ]
}
  • Where it lives: its own file $DSH_HOME/dsh-jenkins-map.json (a bare map, no wrapper, plaintext; a missing file loads as {}, a corrupt one is backed up to .bak and treated as empty). A legacy projects field inside dsh-jenkins.json is migrated into this file on first startup (missing-only).
  • name (env display label): optional; an empty string is dropped (no "name": "" is written). It shows up in the Server dropdown label and in Local Records, so a build's env is obvious at a glance.
  • Unlimited envs: a project may have any number of targets (UAT / gray / prod / overseas…); array order is display order and item 1 is the default.
  • Discovery: opening the Config / Publish tab scans every open workspace root for dsh-jenkins.json/js/ts and merges it under the folder namemissing-only by default, so hand-edited projects are never clobbered. To pull in updated workspace configs, tick Overwrite same-name projects and hit Rediscover in the modal footer.
  • Editing: on the Config tab, the Project Config row (dsh-jenkins-map.json · N projects) → Edit map:
    • Form: project list; each env row is env name (optional, placeholder shows the fallback) + job + server + N params (expands that env's key/value editor, values text / number / boolean) + a per-row remove button; Add env has no cap, and projects / envs / params can all be added or removed;
    • JSON: the whole map as JSON — paste your own config wholesale, then Apply JSON to write it back into the form.
  • server refs may be a server name / id / full URL / bare domain; they are matched against configured servers by name → id → full URL (trailing slash ignored) → domain, where the domain level ignores scheme, port and context path (http://jenkins-tx.example.com:8080/jenkins equals the configured https://jenkins-tx.example.com). When nothing matches, the Publish tab shows a hint under the server row and the dropdown falls back to all servers.
  • One-click publish: the Project dropdown on the Publish tab lists the map's projects; the env is switched straight from the Server dropdown (its labels are just the plugin's server names — the config's env name is not mixed in), which brings that env's job and params with it — then hit Submit. Records are grouped as "Project Config: " on the Local Records tab (filterable / clearable per project, and each record shows the env name).
  • Hand editing: the file is the map — edit it in any editor; the next read picks it up (the file is re-parsed on every load).

Installation

# 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.:
    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:

- 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):

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:

  • release job: Setup Node 26 → pnpm install --frozen-lockfilepnpm 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).

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
pnpm run test          # isolated tests: curl dump parsing + failure log + param parsing + centralized project config
pnpm run test:params   # param parsing: built-in types / uno-choice / Extended Choice / build-page fallback
pnpm run test:store    # data-file round-trip: token encryption / migration / keep-token semantics
  • 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.

Job parameter recognition

The Publish tab renders its parameter form from the server-side definitions:

| Server-side type | Control | | --- | --- | | StringParameterDefinition / uno-choice dynamic reference | single-line text | | TextParameterDefinition | textarea | | BooleanParameterDefinition | checkbox | | PasswordParameterDefinition / CredentialsParameterDefinition / FileParameterDefinition | password / text field | | ChoiceParameterDefinition, uno-choice ChoiceParameter / CascadeChoiceParameter, Extended Choice single | searchable dropdown | | Extended Choice multi-select / uno-choice MultiSelectParameter | checkbox list (submitted joined by the delimiter) |

  • Script-generated options (Active Choices / uno-choice ChoiceParameter, CascadeChoiceParameter) expose only _class + default in REST /api/json — the option list is computed by Groovy at render time. Those params automatically fall back to the build page HTML (job/<path>/build) and are parsed from its <select> options, so a project dropdown lists every project. When it still cannot be resolved the field degrades to a text input with an inline hint instead of showing an empty dropdown.
  • Defaults come from either defaultValue (built-ins) or defaultParameterValue.value (plugin types such as uno-choice), so project=boss_backend is pre-filled correctly.
  • Separator rows: uno-choice DynamicReferenceParameter entries (empty name) never become empty fields — dash-only ones are dropped, ones with text render as a dashed divider note.
  • Duplicate parameter names keep the first definition; unknown types fall back to text.

Troubleshooting (failure log)

Every failed request (job list / job detail / build history / trigger / status / build log / connection test …) is appended to $DSH_HOME/dsh-jenkins.log (same directory as dsh-jenkins.json; on Windows C:\Users\<you>\.dsh\dsh-jenkins.log) as JSONL — one line per failure:

{"time":"2026-09-14T07:02:19.949Z","level":"error","op":"jobs","code":"http-401",
 "message":"auth failed (HTTP 401)","server":"UAT <https://jenkins.example.com>","user":"jason",
 "request":"GET /api/json?tree=jobs[...]","httpStatus":401,"httpStatuses":[200,401],
 "curlExit":0,"curlStderr":"","bodySnippet":"<html>...Error 401 Unauthorized...</html>"}
  • Fields: op, error code, message, server (name + URL), request line, HTTP status, all response block statuses, curl exit code and stderr, response body snippet, session id;
  • httpStatuses like [200, 401] means curl went through an HTTP proxy: the proxy's CONNECT tunnel block (200 Connection Established) is printed first, then the real response block — the last entry is the real status;
  • Redaction: no token, no Basic credentials, no credentials embedded in a URL, no Jenkins crumb; body snippets are flattened and capped at 600 characters;
  • The file rotates to dsh-jenkins.log.1 above 2MB (one generation kept); logging never breaks the main flow.

Common causes of "Failed to load jobs"

| Symptom (log field / UI text) | Cause | | --- | --- | | code=parse-failed with a bodySnippet starting with HTTP/1.1 | HTTPS through an HTTP proxy (https_proxy): curl's -D - prints the proxy's 200 Connection Established tunnel block first; the old code split at the first blank line and swallowed the real headers into the body. Fixed by block-aware parsing (parseCurlDump) | | code=auth-failed (HTTP 401) | Wrong or expired username/Token (re-run Test connection in settings) | | code=forbidden (HTTP 403) | Token lacks permission / CSRF missing / reverse proxy blocking | | code=network-failed with curlExit=7/28/35/60 | DNS, connection refused (7), timeout (28, 40s cap), TLS handshake (35), self-signed cert (60 — enable "ignore certificate") | | code=redirect | URL is not the final one (http://https://, missing context path); redirects are not followed, the log carries Location | | code=response-too-large | Response exceeded the host's 8MB collection cap (tail kept); narrow the request | | code=empty-response | No response header block: proxy ate the response, connection cut, or output truncated | | code=server-missing | The client's cached server id no longer exists in the config (pick a server again) | | code=curl-unavailable | Host subprocess service unavailable / curl cannot start | | stage=route-guard | Request was rejected by the /dsh-jenkins/api trust fence (non-loopback Host, cross-site marker) — it never reached plugin logic | | Empty job list but no failure | Folders deeper than the 3-level tree are returned as folder placeholders and filtered out by the UI; the instance nests jobs too deeply |

Implementation notes

  • Jenkins REST via curl.exe spawned directly through the host subprocess service: Basic auth
    • CSRF crumb + --data-binary @- (form body over stdin, UTF-8 without BOM); the -D - output is parsed per response block (parseCurlDump: skip the proxy CONNECT / 1xx blocks, take the last real block for status and Location), so a tunnel block's 200 no longer masks the real status.
  • Failures are logged to $DSH_HOME/dsh-jenkins.log (see above): jenkins.ts records the HTTP / curl evidence, index.ts records op-level failures at all three entry points (route, command, model tool).
  • Browser ↔ host transport: by default the /dsh-jenkins/api route registered on webServer (fetch POST JSON → { ok, value } envelope, behind a trust fence); older hosts fall back to the command channel 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.

Compatibility

DSH 0.1.5-rc.2: errorDSH 0.1.6-alpha.1: errorDSH 0.1.5-rc.1: errorDSH 0.1.5-alpha.2: errorDSH 0.1.5-alpha.1: errorDSH 0.1.3-alpha.2: errorDSH 0.1.2-rc.1: errorDSH 0.1.2-alpha.5: errorDSH 0.1.2-alpha.4: errorDSH 0.1.2-alpha.3: errorDSH 0.1.2-alpha.2: error

Versions

Latest versionPublishedSize
0.1.31
0.1.32
0.1.34
0.1.35
0.1.38
0.1.39
0.1.40
0.1.41
0.1.42
0.1.43
0.1.44
0.1.45
0.1.46
0.1.47
0.1.48
0.1.49
0.1.50
0.1.51
0.1.52
0.1.53

Similar plugins

dsh-bgjobs

Runs commands as background jobs that keep executing when DSH exits, with an optional sandbox to constrain file effects, plus a live web panel and offline CLI/GUI management. Windows only for now.

Tools & CapabilitiesManifest valid

0

dsh plugin --profile web add bgjobs

Adds session, project, and global controls in the DSH WebUI for skills, MCP servers, tools, prompt injections, approval escalation, and safety guards; enforcement is scoped to the current agent.

Tools & CapabilitiesManifest valid

0

dsh plugin --profile web add dsh-capability-toggle-plugin

Cron scheduler for agent tasks: create jobs by natural language or a sidebar UI, inject a user message into a new or fixed session on schedule to trigger a full agent turn, with run history, manual tr

Workflow & AutomationManifest valid

0

956/wk

dsh plugin --profile web add dsh-plugin-cron-scheduler

by squirrel20

Unattended scheduled jobs for the DeepSeek Harness (dsh): agent/command tasks on cron schedules

Workflow & AutomationManifest valid

3

54/wk

MIT

JavaScript

Sep 15, 2026

dsh plugin --profile web add dsh-cron

Kubernetes ops for the agent: get resources with structured JSON output, describe, logs, exec, apply/delete (user-confirmed) and port-forward.

Development & InfrastructureManifest valid

0

dsh plugin --profile web add dsh-kubectl

by Failing-coachman563

Manage and organize DSH skills via a web interface with one-click enable/disable, batch migration, and workspace-based grouping.

Manifest valid

0

MIT

JavaScript

Sep 12, 2026

dsh plugin --profile web add dsh-skill-viewer