dsh-jenkins A DeepSeek Harness plugin (dual-face: host + browser) for managing multiple Jenkins servers and triggering jobs — from a Settings page, from model tools, and from a per-workspace "Run Jenkins Job" entry. No hardcoded paths, TypeScript throughout, publishable to npm / GitHub. UI copy is bilingual (Chinese / English, following the host UI language). 中文文档 ## 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. - Model tools (docs/develop/basic/tool): dsh_jenkins_build, dsh_jenkins_status. - Config (docs/develop/basic/config): Schemastery Config + a settings namespace that persists UI edits to $DSH_HOME/settings.yaml (server list stored as JSON text to avoid frozen-array pitfalls). - 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 # 中文文档 ## 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

ode_modules@deepseek-ai" -Force > foreach ($p in 'schemastery','dsh-tools','dsh-settings') { > New-Item -ItemType Junction "$PWD
ode_modules@deepseek-ai$p" -Target "$env:DSH_HOME\profiles
ode_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: 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): sh npm run build # clean lib → tsc -b (types + declarations) → tsdown (both halves) npm run verify # simulate the host module table to check lib/client.js (optional) npm publish # or npm pack / git push origin main (lib/ is committed; git installs need no build) ### Automated publishing (GitHub Actions) Pushing a `v*` tag (`npm run release` bumps the patch version, rebuilds the artifact, and tags it automatically) triggers [`.github/workflows/publish.yml`](.github/workflows/publish.yml): - **release job**: `npm ci` → `npm run check` (tsc -b) → `npm run build` (tsc -b && tsdown) → `npm 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 sh npm install # devDependencies: typescript, tsdown, @types/react, @deepseek-ai/* type packages, etc. npm run check # whole-tree TypeScript type check (tsc -b) npm run build # rebuild both halves after editing source (tsc -b && tsdown) npm run watch # tsdown watch mode (rebuild on src/client changes) npm 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.