@ts-org/jenkins-cli 3.0.4 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +90 -35
  2. package/dist/cli.js +28 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -154,46 +154,71 @@ jenkins-cli changes -n 50
154
154
  jenkins-cli changes 1234
155
155
  ```
156
156
 
157
- #### `job` - Job 管理
157
+ #### `config` - Job 配置
158
158
 
159
159
  ```bash
160
- # 列出所有 Job (支持 glob 过滤)
161
- jenkins-cli job list --search 'project-*'
160
+ # 读取当前 Job XML 配置
161
+ jenkins-cli config show
162
162
 
163
- # 查看当前 Job 信息
164
- jenkins-cli job info
163
+ # JSON 格式输出
164
+ jenkins-cli config show -f json
165
+
166
+ # 备份当前 Job 配置
167
+ jenkins-cli config backup -d ./jenkins-backup
168
+
169
+ # 备份指定 Job 配置
170
+ jenkins-cli config backup -d ./jenkins-backup -j remote-factory-admin
171
+
172
+ # 按 glob 过滤备份多个 Job 配置
173
+ jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'
174
+
175
+ # 备份所有 Job 配置
176
+ jenkins-cli config backup -d ./jenkins-backup -a
165
177
  ```
166
178
 
167
179
  #### `console` - 查看日志
168
180
 
181
+ 支持实时日志追踪,默认开启。
182
+
169
183
  ```bash
170
- # 查看指定构建号的日志
184
+ # 查看指定构建号的日志,如果正在构建则追踪,否则直接输出日志
171
185
  jenkins-cli console 1234
172
186
 
173
- # 查看最后一次构建日志
187
+ # 查看最后一次构建日志,如果正在构建则追踪,否则直接输出日志
174
188
  jenkins-cli console last
175
189
 
190
+ # 仅输出当前日志内容,不追踪
191
+ jenkins-cli console last --no-follow
192
+
176
193
  # 查看最后一次构建成功日志
177
194
  jenkins-cli console last -s success
178
195
 
179
196
  # 查看最后一次构建失败日志
180
197
  jenkins-cli console last -s failed
198
+ ```
199
+
200
+ #### `job` - Job 管理
181
201
 
182
- # 仅输出最后 N 行
183
- jenkins-cli console 1234 -t 200
202
+ ```bash
203
+ # 列出所有 Job (支持 glob 过滤)
204
+ jenkins-cli job list --search 'project-*'
205
+
206
+ # 查看当前 Job 信息
207
+ jenkins-cli job info
184
208
  ```
185
209
 
186
- #### `stop` - 停止构建
210
+ #### `me` - 用户信息
187
211
 
188
212
  ```bash
189
- # 停止一个构建
190
- jenkins-cli stop 1234
213
+ # 验证 API Token 并查看当前用户
214
+ jenkins-cli me
215
+ ```
191
216
 
192
- # 清理当前 Job 的队列和所有运行中的构建
193
- jenkins-cli stop -a
217
+ #### `params` - Job 参数
194
218
 
195
- # 停止 Jenkins 上所有的构建和队列项 (慎用)
196
- jenkins-cli stop -A
219
+ ```bash
220
+ # 查看当前 Job 的参数定义
221
+ jenkins-cli params
197
222
  ```
198
223
 
199
224
  #### `queue` - 等待构建队列管理
@@ -206,40 +231,70 @@ jenkins-cli queue list
206
231
  jenkins-cli queue cancel 5678
207
232
  ```
208
233
 
209
- #### `params` - Job 参数
234
+ #### `stop` - 停止构建
210
235
 
211
236
  ```bash
212
- # 查看当前 Job 的参数定义
213
- jenkins-cli params
237
+ # 停止一个构建
238
+ jenkins-cli stop 1234
239
+
240
+ # 清理当前 Job 的队列和所有运行中的构建
241
+ jenkins-cli stop -a
242
+
243
+ # 停止 Jenkins 上所有的构建和队列项 (慎用)
244
+ jenkins-cli stop -A
214
245
  ```
215
246
 
216
- #### `config` - Job 配置
247
+ #### `view` - 视图管理
217
248
 
218
249
  ```bash
219
- # 读取当前 Job 的 XML 配置
220
- jenkins-cli config show
250
+ # 查看所有视图
251
+ jenkins-cli view list
221
252
 
222
- # JSON 格式输出
223
- jenkins-cli config show -f json
253
+ # 查看视图包含的 Job
254
+ jenkins-cli view show MyView
224
255
 
225
- # 备份当前 Job 配置
226
- jenkins-cli config backup -d ./jenkins-backup
256
+ # 添加 Job 到视图
257
+ jenkins-cli view add MyView my-job
227
258
 
228
- # 备份指定 Job 配置
229
- jenkins-cli config backup -d ./jenkins-backup -j remote-factory-admin
259
+ # 从视图移除 Job
260
+ jenkins-cli view remove MyView my-job
230
261
 
231
- # 按 glob 过滤备份多个 Job 配置
232
- jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'
262
+ # 创建视图
263
+ jenkins-cli view create MyView
233
264
 
234
- # 备份所有 Job 配置
235
- jenkins-cli config backup -d ./jenkins-backup -a
265
+ # 删除视图
266
+ jenkins-cli view delete MyView
236
267
  ```
237
268
 
238
- #### `me` - 用户信息
269
+ #### `workspace` - 工作区
239
270
 
240
271
  ```bash
241
- # 验证 API Token 并查看当前用户
242
- jenkins-cli me
272
+ # 查看当前 Job 的工作区(默认读取 jenkins-cli.yaml 里的 job)
273
+ jenkins-cli ws
274
+
275
+ # 查看子目录(当前 Job)
276
+ jenkins-cli ws -p dist
277
+
278
+ # 指定 Job
279
+ jenkins-cli ws -j my-job
280
+
281
+ # 查看文件内容
282
+ jenkins-cli ws cat dist/index.html
283
+
284
+ # 指定 Job 查看文件内容
285
+ jenkins-cli ws cat dist/index.html -j my-job
286
+
287
+ # 保存文件到本地
288
+ jenkins-cli ws cat dist/index.html -o ./index.html
289
+
290
+ # 下载并用默认应用打开(适合图片)
291
+ jenkins-cli ws cat public/favicon.ico --open
292
+
293
+ # 清空工作区(会提示确认)
294
+ jenkins-cli ws wipe
295
+
296
+ # 指定 Job 清空工作区
297
+ jenkins-cli ws wipe -j my-job
243
298
  ```
244
299
 
245
300
  ### ❓ FAQ
package/dist/cli.js CHANGED
@@ -1,39 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  import { program, CommanderError } from 'commander';
3
- import pt from 'inquirer';
4
- import b from 'chalk';
5
- import it from 'ora';
6
- import { exec } from 'child_process';
7
- import ft, { promisify } from 'util';
8
- import N from 'fs-extra';
9
- import Ye from 'js-yaml';
10
- import R from 'path';
11
- import tt from 'axios';
12
- import at from 'jiti';
3
+ import pn from 'inquirer';
4
+ import w from 'chalk';
5
+ import Tt from 'ora';
6
+ import { exec, spawn } from 'child_process';
7
+ import dn, { promisify } from 'util';
8
+ import U from 'fs-extra';
9
+ import Ht from 'js-yaml';
10
+ import L from 'path';
11
+ import Xt from 'axios';
12
+ import { Buffer } from 'buffer';
13
+ import an from 'jiti';
13
14
  import { fileURLToPath } from 'url';
14
15
  import { promises } from 'fs';
15
16
  import { XMLParser } from 'fast-xml-parser';
17
+ import xn from 'os';
16
18
 
17
- var se="3.0.4",ae="Jenkins deployment CLI";var p=class extends Error{hint;example;details;exitCode;constructor(e,t={}){super(e),this.name="UserError",this.hint=t.hint,this.example=t.example,this.details=t.details,this.exitCode=t.exitCode??1;}};function Ke(n){return n instanceof p?n:n instanceof CommanderError?new p(n.message,{hint:"Check the command usage and options.",example:"jenkins-cli --help",exitCode:n.exitCode??1}):n instanceof Error?new p(n.message,{hint:"Check your input and try again.",example:"jenkins-cli --help"}):new p("Unknown error",{example:"jenkins-cli --help"})}function J(n){let e=Ke(n);if(console.error(b.red(`
18
- \u274C ${e.message}
19
- `)),e.details&&console.error(b.gray(e.details)),e.hint&&console.error(b.yellow(`Hint: ${e.hint}`)),e.example!==""){let t=e.example??"jenkins-cli --help";console.error(b.cyan(`Example: ${t}`));}console.error(b.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=e.exitCode;}var ce=promisify(exec);async function le(){try{let{stdout:n}=await ce("git branch --show-current"),e=n.trim();if(!e)throw new p("Not on any branch (detached HEAD state).",{hint:"Checkout a branch before running this command.",example:"git checkout main"});return e}catch{throw new p("Failed to get current branch.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function ue(){try{let{stdout:n}=await ce('git branch -r --format="%(refname:short)"');return n.split(`
20
- `).filter(e=>e.includes("/")&&!e.includes("HEAD"))}catch{throw new p("Failed to list branches.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}var P="jenkins-cli.yaml",T="package.json",F="jenkins-cli",Ve="jenkinsCli";function pe(n,e=process.cwd()){let t=e;for(;;){let r=R.join(t,n);if(N.existsSync(r))return r;let o=R.dirname(t);if(o===t)return null;t=o;}}function ze(n=process.cwd()){return pe(P,n)}function Xe(n=process.cwd()){let e=pe(T,n);return e?R.dirname(e):null}function Ze(n){return !!(n.apiToken&&n.job&&Array.isArray(n.modes)&&n.modes.length>0)}async function me(n){let e=await N.readFile(n,"utf-8"),t=Ye.load(e);if(!t||typeof t!="object")throw new p(`Invalid config in ${P}. Expected a YAML object.`,{hint:"Top-level config must be key/value pairs.",example:`${P}:
19
+ var Be="3.0.5",Fe="Jenkins deployment CLI";var f=class extends Error{hint;example;details;exitCode;constructor(n,e={}){super(n),this.name="UserError",this.hint=e.hint,this.example=e.example,this.details=e.details,this.exitCode=e.exitCode??1;}};function Dt(t){return t instanceof f?t:t instanceof CommanderError?new f(t.message,{hint:"Check the command usage and options.",example:"jenkins-cli --help",exitCode:t.exitCode??1}):t instanceof Error?new f(t.message,{hint:"Check your input and try again.",example:"jenkins-cli --help"}):new f("Unknown error",{example:"jenkins-cli --help"})}function B(t){let n=Dt(t);if(console.error(w.red(`
20
+ \u274C ${n.message}
21
+ `)),n.details&&console.error(w.gray(n.details)),n.hint&&console.error(w.yellow(`Hint: ${n.hint}`)),n.example!==""){let e=n.example??"jenkins-cli --help";console.error(w.cyan(`Example: ${e}`));}console.error(w.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=n.exitCode;}var Ue=promisify(exec);async function Le(){try{let{stdout:t}=await Ue("git branch --show-current"),n=t.trim();if(!n)throw new f("Not on any branch (detached HEAD state).",{hint:"Checkout a branch before running this command.",example:"git checkout main"});return n}catch{throw new f("Failed to get current branch.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function Te(){try{let{stdout:t}=await Ue('git branch -r --format="%(refname:short)"');return t.split(`
22
+ `).filter(n=>n.includes("/")&&!n.includes("HEAD"))}catch{throw new f("Failed to list branches.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}var F="jenkins-cli.yaml",ne="package.json",te="jenkins-cli",Qt="jenkinsCli";function Ie(t,n=process.cwd()){let e=n;for(;;){let r=L.join(e,t);if(U.existsSync(r))return r;let o=L.dirname(e);if(o===e)return null;e=o;}}function _t(t=process.cwd()){return Ie(F,t)}function Kt(t=process.cwd()){let n=Ie(ne,t);return n?L.dirname(n):null}function Gt(t){return !!(t.apiToken&&t.job&&Array.isArray(t.modes)&&t.modes.length>0)}async function Ve(t){let n=await U.readFile(t,"utf-8"),e=Ht.load(n);if(!e||typeof e!="object")throw new f(`Invalid config in ${F}. Expected a YAML object.`,{hint:"Top-level config must be key/value pairs.",example:`${F}:
21
23
  apiToken: http://user:token@host
22
24
  job: my-job
23
- modes: [dev]`});return t}async function et(n){let e=R.join(n,T);if(!await N.pathExists(e))return {};let t=await N.readFile(e,"utf-8"),r=JSON.parse(t),o=r[F]??r[Ve];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new p(`Invalid ${T} config: "${F}" must be an object.`,{hint:"Use an object for the config section.",example:`"${F}": { "apiToken": "http://user:token@host", "job": "my-job", "modes": ["dev"] }`});return o}async function de(){let n=process.cwd(),e=Xe(n)??n,t=R.join(e,P),r={},o=R.dirname(e),s=ze(o);s&&await N.pathExists(s)&&(r=await me(s));let i=await et(e);r={...r,...i};let a=await N.pathExists(t)?await me(t):{};if(r={...r,...a},!Ze(r))throw new p("Config incomplete or not found.",{hint:`Tried ${P} in project root, "${F}" in ${T}, and walking up from cwd. Required: apiToken, job, modes (non-empty array).`,example:`${P}:
25
+ modes: [dev]`});return e}async function Yt(t){let n=L.join(t,ne);if(!await U.pathExists(n))return {};let e=await U.readFile(n,"utf-8"),r=JSON.parse(e),o=r[te]??r[Qt];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new f(`Invalid ${ne} config: "${te}" must be an object.`,{hint:"Use an object for the config section.",example:`"${te}": { "apiToken": "http://user:token@host", "job": "my-job", "modes": ["dev"] }`});return o}async function Oe(){let t=process.cwd(),n=Kt(t)??t,e=L.join(n,F),r={},o=L.dirname(n),s=_t(o);s&&await U.pathExists(s)&&(r=await Ve(s));let i=await Yt(n);r={...r,...i};let a=await U.pathExists(e)?await Ve(e):{};if(r={...r,...a},!Gt(r))throw new f("Config incomplete or not found.",{hint:`Tried ${F} in project root, "${te}" in ${ne}, and walking up from cwd. Required: apiToken, job, modes (non-empty array).`,example:`${F}:
24
26
  apiToken: http://user:token@host
25
27
  job: my-job
26
28
  modes:
27
- - dev`});return {...r,projectRoot:e}}var Y={maxRedirects:0,validateStatus:n=>n>=200&&n<400};function j(n){return `job/${n.split("/").map(t=>t.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function D(n){let e=Array.isArray(n)?n.find(o=>o?.parameters):void 0,t=Array.isArray(e?.parameters)?e.parameters:[],r={};for(let o of t)o?.name&&(r[String(o.name)]=o?.value);return r}function nt(n){try{let t=new URL(n).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<t.length-1;o++)t[o]==="job"&&t[o+1]&&r.push(decodeURIComponent(t[o+1]));return r.join("/")}catch{return ""}}async function rt(n,e){let r=(await n.axios.get(new URL("api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,actions[parameters[name,value]]",e).toString())).data??{};return {...r,parameters:D(r.actions)}}function ot(n,e=400){try{let r=(typeof n=="string"?n:JSON.stringify(n??"",null,2)).trim();return r?r.length>e?`${r.slice(0,e)}...`:r:""}catch{return ""}}function ge(n){let e=n.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!e)throw new p("Invalid apiToken format.",{hint:"Expected: http(s)://username:token@host:port",example:"http://user:token@jenkins.example.com:8080"});let[,t,r,o,s]=e,i=`${t}://${s.replace(/\/$/,"")}/`,a=tt.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return {baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function be(n,e=5e3){try{let t=await n.axios.get("crumbIssuer/api/json",{timeout:e}),{data:r}=t;r?.crumbRequestField&&r?.crumb&&(n.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,n.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=t.headers["set-cookie"];if(o){let s=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];n.axios.defaults.headers.common.Cookie=s.join("; ");}}catch{}}function V(n){return n.crumbPromise||(n.crumbPromise=be(n,5e3)),n.crumbPromise}async function z(n){await V(n),n.crumbForm||(n.crumbPromise=be(n,15e3),await n.crumbPromise);}async function A(n,e){let r=(await n.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(e){let o=e.trim(),s=o.split("/").filter(Boolean).pop();return r.filter(i=>{let a=i.task?.name;return a===o||(s?a===s:!1)})}return r}async function L(n,e){let t=await n.axios.get(`${j(e)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(t.data?.builds)?t.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:D(o.actions)}))}async function W(n){let e=await n.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),t=Array.isArray(e.data?.computer)?e.data.computer:[],r=[];for(let i of t){let a=Array.isArray(i?.executors)?i.executors:[],c=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...a,...c]){let u=l?.currentExecutable;u?.url&&r.push({number:Number(u.number),url:String(u.url)});}}let o=new Map;for(let i of r)i.url&&o.set(i.url,i);return (await Promise.all([...o.values()].map(async i=>{let a=await rt(n,i.url),c=nt(String(a?.url??i.url));return {...a,job:c}}))).filter(i=>i?.building)}async function I(n,e){return await z(n),await n.axios.post("queue/cancelItem",new URLSearchParams({id:e.toString()}),Y),!0}async function U(n,e,t){try{await z(n),await n.axios.post(`${j(e)}/${t}/stop/`,new URLSearchParams({}),Y);}catch(r){let o=r.response?.status;if(o===403){let s=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(s);console.log(b.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(b.yellow('[Hint] Confirm the current user has "Job" -> "Cancel" permission on this job.')),console.log(i?"[Hint] Jenkins returned a crumb/CSRF error. Ensure crumb + session cookie are sent, or use API token (not password).":s?`[Hint] Jenkins response: ${s}`:'[Hint] If "Job/Cancel" is already granted, also try granting "Run" -> "Update" (some versions use it for stop).');return}if(o===404||o===400||o===500){console.log(`[Info] Build #${t} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function M(n,e,t){let r="branch",o="mode",s=t[o];s&&console.log(`Checking for conflicting builds for mode: ${s}...`);let[i,a]=await Promise.all([A(n,e),L(n,e)]),c=(m,d)=>{let h=m.actions?.find(B=>B.parameters);return h?h.parameters.find(B=>B.name===d)?.value:void 0},l=t[r];if(s&&l){let m=i.find(d=>c(d,o)===s&&c(d,r)===l);if(m)return new URL(`queue/item/${m.id}/`,n.baseURL).toString()}let u=!1;if(s)for(let m of a)c(m,o)===s&&(console.log(`Stopping running build #${m.number} (mode=${s})...`),await U(n,e,m.number),u=!0);u&&await new Promise(m=>setTimeout(m,1e3));try{return await z(n),(await n.axios.post(`${j(e)}/buildWithParameters/`,new URLSearchParams({...t}),Y)).headers.location||""}catch(m){let d=m?.response?.status,h=ot(m?.response?.data);if(d===400){let w=h?`Jenkins response (snippet):
28
- ${h}`:void 0;throw new p("Jenkins rejected the request (400).",{hint:`Common causes: job is not parameterized, parameter names do not match, or the job endpoint differs (e.g. multibranch jobs). This CLI sends parameters "${r}" and "${o}".`,example:"jenkins-cli build -b origin/main -m dev",details:w})}if(d){let w=h?`Jenkins response (snippet):
29
- ${h}`:void 0;throw new p(`Request failed with status code ${d}.`,{hint:"Check Jenkins job permissions and parameters.",example:"jenkins-cli me",details:w})}throw m}}async function he(n){return (await n.axios.get("whoAmI/api/json")).data}async function q(n){return (await n.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function Q(n,e){try{let r=(await n.axios.get(`${j(e)}/api/json?tree=name,fullName,url,buildable,inQueue,nextBuildNumber,color,healthReport[description,score],lastBuild[number,url,building,result,timestamp,duration],lastCompletedBuild[number,url,result,timestamp,duration],lastSuccessfulBuild[number,url,building,result,timestamp,duration],lastFailedBuild[number,url,building,result,timestamp,duration]`)).data??{},o=typeof r?.fullName=="string"?r.fullName:"",s=typeof r?.name=="string"?r.name:"",i=String(e??"").trim();if(!o&&!s)throw new p(`Job not found: ${i}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli job show -j my-job"});if(i&&i!==o&&i!==s)throw new p(`Job not found: ${i}`,{hint:`Jenkins returned job "${o||s}".`,example:"jenkins-cli console last -j my-job -s success"});return r}catch(t){if(t?.response?.status===404){let o=String(e??"").trim();throw new p(`Job not found: ${o}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli console last -j my-job -s success"})}throw t}}async function ye(n,e,t){let r=Math.max(1,t?.limit??20);return ((await n.axios.get(`${j(e)}/api/json?tree=builds[number,url,building,result,timestamp,duration,actions[parameters[name,value]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,result:i.result,building:i.building,timestamp:i.timestamp,duration:i.duration,url:i.url,parameters:D(i.actions)}))}async function we(n,e,t){let r=Math.max(1,t?.limit??20);return ((await n.axios.get(`${j(e)}/api/json?tree=builds[number,url,timestamp,changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,timestamp:i.timestamp,url:i.url,changeSet:i.changeSet??{}}))}async function je(n,e,t){let o=(await n.axios.get(`${j(e)}/${t}/api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,description,actions[parameters[name,value]],changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]],culprits[fullName],executor[number,progress]`)).data??{};return {...o,parameters:D(o.actions)}}async function xe(n,e,t){let r=await n.axios.get(`${j(e)}/${t}/consoleText`,{responseType:"text"});return String(r.data??"")}async function ke(n,e){return ((await n.axios.get(`${j(e)}/api/json?tree=property[parameterDefinitions[name,type,description,defaultParameterValue[value],choices]]`)).data?.property??[]).flatMap(s=>s?.parameterDefinitions??[]).filter(Boolean).map(s=>({name:s.name,type:s.type,description:s.description,default:s.defaultParameterValue?.value,choices:s.choices}))}async function X(n,e){let t=await n.axios.get(`${j(e)}/config.xml`,{responseType:"text"});return String(t.data??"")}async function g(){let n=it("Loading configuration...").start();try{let e=await de();n.succeed("Configuration loaded");let t=ge(e.apiToken);return V(t),{config:e,jenkins:t}}catch(e){J(e),process.exit(1);}}var lt=at(fileURLToPath(import.meta.url),{interopDefault:!0});async function Se(n){return await Promise.resolve(n)}function ut(n){let e=String(n??"").trim();if(!e)return null;let t=e.split(":");if(t.length<2)return null;if(t.length===2){let[s,i]=t;return !s||!i?null:{file:s,exportName:i}}let r=t.at(-1);if(!r)return null;let o=t.slice(0,-2).join(":");return o?{file:o,exportName:r}:null}function mt(n,e){return R.isAbsolute(e)?e:R.join(n,e)}function ve(n){return !!n&&typeof n=="object"&&!Array.isArray(n)}async function Je(n,e){let t=ut(e);if(!t)return null;let r=mt(n,t.file);if(!await N.pathExists(r))throw new p(`configs reference not found: ${t.file}`,{hint:"Check the file path (relative to project root) and file name.",example:'configs: [{ choices: "./scripts/prompts.ts:choices" }]'});let o=lt(r),s=ve(o)?o:{default:o},i=t.exportName==="default"?s.default:s[t.exportName];if(i===void 0)throw new p(`configs reference export not found: ${e}`,{hint:"Make sure the export exists in the referenced file.",example:'export const choices = ["dev", "uat"]'});return {value:i}}async function _(n,e,t){if(typeof e!="string")return e;let r=await Je(n,e);if(!r)return e;if(!t.allow(r.value))throw new p(t.error(e),{hint:t.hint,example:t.example});return r.value}async function $e(n,e){if(typeof e!="string")return e;let t=await Je(n,e);if(!t)return e;if(typeof t.value=="function"){let r=t.value();return await Se(r)}return await Se(t.value)}async function Pe(n,e){let t=Array.isArray(n)?n:[];if(t.length===0)return [];let r=String(e.projectRoot??"").trim()||process.cwd(),o=[];for(let s of t){if(!ve(s))continue;let i={...s};if(i.choices!==void 0){i.choices=await $e(r,i.choices);let a=String(i.type??"").toLowerCase(),c=i.choices;if((a==="list"||a==="rawlist"||a==="checkbox")&&typeof c!="function"&&!Array.isArray(c))if(c==null)i.choices=[];else if(typeof c=="string"||typeof c=="number"||typeof c=="boolean")i.choices=[String(c)];else if(typeof c[Symbol.iterator]=="function")i.choices=Array.from(c).map(u=>String(u));else throw new p(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof c}).`,{hint:"Return an array for list/rawlist/checkbox choices.",example:'export const choices = ["dev", "uat"]'})}i.default!==void 0&&(i.default=await $e(r,i.default)),i.when!==void 0&&(i.when=await _(r,i.when,{allow:a=>typeof a=="function"||typeof a=="boolean",error:a=>`when reference must be a function or boolean: ${a}`,hint:"Export a function or boolean from the referenced file.",example:'export const when = (answers) => answers.env === "dev"'})),i.validate!==void 0&&(i.validate=await _(r,i.validate,{allow:a=>typeof a=="function",error:a=>`validate reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:'export const validate = (input) => !!input || "required"'})),i.filter!==void 0&&(i.filter=await _(r,i.filter,{allow:a=>typeof a=="function",error:a=>`filter reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const filter = (input) => input.trim()"})),i.transformer!==void 0&&(i.transformer=await _(r,i.transformer,{allow:a=>typeof a=="function",error:a=>`transformer reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const transformer = (input) => input.toUpperCase()"})),o.push(i);}return o}function Ne(n,e){let t=new Set(e),r={};for(let[o,s]of Object.entries(n))if(!t.has(o)&&s!==void 0){if(s===null){r[o]="";continue}if(Array.isArray(s)){r[o]=s.map(i=>String(i)).join(",");continue}if(typeof s=="object"){try{r[o]=JSON.stringify(s);}catch{r[o]=String(s);}continue}r[o]=String(s);}return r}async function Re(){console.log(b.bold.blue(`
29
+ - dev`});return {...r,projectRoot:n}}var N={maxRedirects:0,validateStatus:t=>t>=200&&t<400};function k(t){return `job/${t.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function oe(t){let n=Array.isArray(t)?t.find(o=>o?.parameters):void 0,e=Array.isArray(n?.parameters)?n.parameters:[],r={};for(let o of e)o?.name&&(r[String(o.name)]=o?.value);return r}function Me(t){try{let e=new URL(t).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<e.length-1;o++)e[o]==="job"&&e[o+1]&&r.push(decodeURIComponent(e[o+1]));return r.join("/")}catch{return ""}}async function Zt(t,n){let r=(await t.axios.get(new URL("api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,actions[parameters[name,value]]",n).toString())).data??{};return {...r,parameters:oe(r.actions)}}function ze(t,n=400){try{let r=(typeof t=="string"?t:JSON.stringify(t??"",null,2)).trim();return r?r.length>n?`${r.slice(0,n)}...`:r:""}catch{return ""}}function q(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="string"){let n=Number(t);if(Number.isFinite(n))return n}}function D(t){let n=q(t);if(n!==void 0)return n;if(typeof t=="string"){let e=Date.parse(t);if(!Number.isNaN(e))return e}}function v(t){return t.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/")}function be(t,n){let e=t.replace(/\/+$/,""),r=n.replace(/^\/+/,"");return /^https?:\/\//i.test(e)?new URL(`${r}`,`${e}/`).toString():`${e}/${r}`}function T(t){return t.replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'")}function re(t){return t.replace(/<[^>]*>/g,"")}function en(t){return /<!doctype\s+html|<html\b|<body\b/i.test(t)}function tn(t){let n=t.match(/<pre[^>]*>([\s\S]*?)<\/pre>/i),e=t.match(/<code[^>]*>([\s\S]*?)<\/code>/i),r=t.match(/<body[^>]*>([\s\S]*?)<\/body>/i),s=(n?.[1]??e?.[1]??r?.[1]??t).replace(/<br\s*\/?>/gi,`
30
+ `);return T(re(s))}function nn(t){let n=[...t.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)],e=[],r=new Set;for(let s of n){let i=s[1]??"",a=[...i.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)],c="",l="";for(let I of a){let We=I[1]??"",ee=T(re(I[2]??"")).trim();if(!(!ee||ee==="..")&&!/all\s+files\s+in\s+zip/i.test(ee)){c=We,l=ee;break}}if(!c||!l||c==="../"||c==="..")continue;let u=/class="[^"]*folder[^"]*"/i.test(i)||c.endsWith("/")?"dir":"file",m=T(c.split("?")[0]??"").replace(/\/+$/,"")||l,p=i.match(/class="last-modified"[^>]*>([\s\S]*?)<\/td>/i),b=p?T(re(p[1]??"")).trim():"",d=b?D(b):void 0,j=`${l}|${m}`;r.has(j)||(r.add(j),e.push({name:l,path:m,type:u,modified:d}));}if(e.length)return e;let o=[...t.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)];for(let s of o){let i=String(s[1]??"").trim(),a=T(re(s[2]??"")).trim();if(!a||a===".."||/all\s+files\s+in\s+zip/i.test(a)||!i||i==="../"||i===".."||/^https?:\/\//i.test(i)||i.startsWith("/")||i.startsWith("?")||i.startsWith("#")||/\/job\//i.test(i)||/\/view\//i.test(i))continue;let c=i.endsWith("/")?"dir":"file",l=T(i.split("?")[0]??"").replace(/\/+$/,"")||a,u=`${a}|${l}`;r.has(u)||(r.add(u),e.push({name:a,path:l,type:c}));}return e}async function we(t,n,e){let r=be(n,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await t.axios.get(i,{responseType:"arraybuffer",headers:{Accept:"*/*"}}),c=a.data??new ArrayBuffer(0),l=Buffer.from(c);if(!l.length)continue;let u=a.headers?.["content-type"];return {data:l,contentType:u?String(u):void 0}}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function ye(t,n,e){let r=be(n,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await t.axios.get(i,{responseType:"text",headers:{Accept:"text/plain,*/*"}}),c=typeof a.data=="string"?a.data:String(a.data??"");if(!c)continue;if(en(c)){let l=tn(c);if(l.trim())return l;continue}return c}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function ke(t,n,e){let r=be(n,`ws/${e}`),o=r.endsWith("/")?r:`${r}/`,s=[`${o}api/json?depth=1`,`${o}?format=json&depth=1`,`${o}?depth=1&format=json`,`${o}?format=json`,`${o}?depth=1`],i;for(let a of s)try{let l=(await t.axios.get(a,{headers:{Accept:"application/json"}})).data;if(typeof l=="string")try{l=JSON.parse(l);}catch{continue}if(l&&typeof l=="object")return l}catch(c){if(i=c,c?.response?.status===404)continue;throw c}try{let a=await t.axios.get(o,{headers:{Accept:"text/html"}});if(typeof a.data=="string"){let c=nn(a.data);if(c.length)return {children:c}}}catch(a){i=a;}throw i||new Error("Workspace listing not found")}function rn(t){if(Array.isArray(t))return t;let n=[t?.children,t?.files,t?.childs,t?.items,t?.entries,t?.content,t?.tree];for(let e of n){if(Array.isArray(e))return e;if(e&&Array.isArray(e.children))return e.children}return t?.children&&Array.isArray(t.children?.children)?t.children.children:[]}function xe(t){return rn(t).map(e=>{let r=String(e?.name??e?.displayName??"").trim(),o=String(e?.path??e?.relativePath??e?.filePath??e?.href??e?.url??"").trim(),s=o?o.split("/").filter(Boolean).pop()??o:"",i=r||s||"-",a=o||r||i,c=(()=>e?.directory===!0||e?.isDirectory===!0||e?.isFolder===!0||e?.type==="directory"||e?.type==="dir"||e?.kind==="directory"||e?.kind==="dir"?"dir":e?.file===!0||e?.type==="file"||e?.kind==="file"?"file":"unknown")(),l=q(e?.size)??q(e?.length)??q(e?.fileSize)??q(e?.bytes)??void 0,u=D(e?.lastModified)??D(e?.modified)??D(e?.mtime)??D(e?.timestamp)??void 0,m=String(e?.href??e?.url??e?.link??"").trim()||void 0;return {name:i,path:a,url:m,size:l,modified:u,type:c}})}function He(t){let n=t.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!n)throw new f("Invalid apiToken format.",{hint:"Expected: http(s)://username:token@host:port",example:"http://user:token@jenkins.example.com:8080"});let[,e,r,o,s]=n,i=`${e}://${s.replace(/\/$/,"")}/`,a=Xt.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return {baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function Qe(t,n=5e3){try{let e=await t.axios.get("crumbIssuer/api/json",{timeout:n}),{data:r}=e;r?.crumbRequestField&&r?.crumb&&(t.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,t.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=e.headers["set-cookie"];if(o){let s=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];t.axios.defaults.headers.common.Cookie=s.join("; ");}}catch{}}function je(t){return t.crumbPromise||(t.crumbPromise=Qe(t,5e3)),t.crumbPromise}async function A(t){await je(t),t.crumbForm||(t.crumbPromise=Qe(t,15e3),await t.crumbPromise);}async function V(t,n){let r=(await t.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(n){let o=n.trim(),s=o.split("/").filter(Boolean).pop();return r.filter(i=>{let a=i.task?.name;return a===o||(s?a===s:!1)})}return r}async function M(t,n){let e=await t.axios.get(`${k(n)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(e.data?.builds)?e.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:oe(o.actions)}))}async function ie(t){let n=await t.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),e=Array.isArray(n.data?.computer)?n.data.computer:[],r=[];for(let i of e){let a=Array.isArray(i?.executors)?i.executors:[],c=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...a,...c]){let u=l?.currentExecutable;u?.url&&r.push({number:Number(u.number),url:String(u.url)});}}let o=new Map;for(let i of r)i.url&&o.set(i.url,i);return (await Promise.all([...o.values()].map(async i=>{let a=await Zt(t,i.url),c=Me(String(a?.url??i.url));return {...a,job:c}}))).filter(i=>i?.building)}async function z(t,n){return await A(t),await t.axios.post("queue/cancelItem",new URLSearchParams({id:n.toString()}),N),!0}async function H(t,n,e){try{await A(t),await t.axios.post(`${k(n)}/${e}/stop/`,new URLSearchParams({}),N);}catch(r){let o=r.response?.status;if(o===403){let s=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(s);console.log(w.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(w.yellow('[Hint] Confirm the current user has "Job" -> "Cancel" permission on this job.')),console.log(i?"[Hint] Jenkins returned a crumb/CSRF error. Ensure crumb + session cookie are sent, or use API token (not password).":s?`[Hint] Jenkins response: ${s}`:'[Hint] If "Job/Cancel" is already granted, also try granting "Run" -> "Update" (some versions use it for stop).');return}if(o===404||o===400||o===500){console.log(`[Info] Build #${e} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function _e(t,n,e){await A(t);let r=`view/${encodeURIComponent(n)}/addJobToView`;try{await t.axios.post(r,new URLSearchParams({name:e}),N);}catch(o){let s=o?.response?.status;throw s===404?new f(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new f(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function Ke(t,n,e){await A(t);let r=`view/${encodeURIComponent(n)}/removeJobFromView`;try{await t.axios.post(r,new URLSearchParams({name:e}),N);}catch(o){let s=o?.response?.status;throw s===404?new f(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new f(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function Ge(t,n){await A(t);let e=new URLSearchParams({name:n,mode:"hudson.model.ListView",json:JSON.stringify({name:n,mode:"hudson.model.ListView"})});try{await t.axios.post("createView",e,N);}catch(r){let o=r?.response?.status;throw o===400?new f(`View already exists: ${n}`,{hint:'Use "jenkins-cli view list" to see existing views.'}):o===403?new f(`Forbidden to create view: ${n}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Create".'}):r}}async function Ye(t,n){await A(t);let e=`view/${encodeURIComponent(n)}/doDelete`;try{await t.axios.post(e,new URLSearchParams({}),N);}catch(r){let o=r?.response?.status;throw o===404?new f(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):o===403?new f(`Forbidden to delete view: ${n}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Delete".'}):r}}async function se(t,n,e){let r="branch",o="mode",s=e[o];s&&console.log(`Checking for conflicting builds for mode: ${s}...`);let[i,a]=await Promise.all([V(t,n),M(t,n)]),c=(m,p)=>{let b=m.actions?.find(j=>j.parameters);return b?b.parameters.find(j=>j.name===p)?.value:void 0},l=e[r];if(s&&l){let m=i.find(p=>c(p,o)===s&&c(p,r)===l);if(m)return new URL(`queue/item/${m.id}/`,t.baseURL).toString()}let u=!1;if(s)for(let m of a)c(m,o)===s&&(console.log(`Stopping running build #${m.number} (mode=${s})...`),await H(t,n,m.number),u=!0);u&&await new Promise(m=>setTimeout(m,1e3));try{return await A(t),(await t.axios.post(`${k(n)}/buildWithParameters/`,new URLSearchParams({...e}),N)).headers.location||""}catch(m){let p=m?.response?.status,b=ze(m?.response?.data);if(p===400){let d=b?`Jenkins response (snippet):
31
+ ${b}`:void 0;throw new f("Jenkins rejected the request (400).",{hint:`Common causes: job is not parameterized, parameter names do not match, or the job endpoint differs (e.g. multibranch jobs). This CLI sends parameters "${r}" and "${o}".`,example:"jenkins-cli build -b origin/main -m dev",details:d})}if(p){let d=b?`Jenkins response (snippet):
32
+ ${b}`:void 0;throw new f(`Request failed with status code ${p}.`,{hint:"Check Jenkins job permissions and parameters.",example:"jenkins-cli me",details:d})}throw m}}async function Xe(t){return (await t.axios.get("whoAmI/api/json")).data}async function Q(t){return (await t.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function Ze(t,n,e){let r=String(n??"").trim();if(!r)return;let o=Math.max(1,e?.depth??5),s="jobs[name,url]";for(let u=0;u<o;u+=1)s=`jobs[name,url,${s}]`;let i=await t.axios.get(`api/json?tree=${encodeURIComponent(s)}`),a=Array.isArray(i.data?.jobs)?i.data.jobs:[],c=[],l=[...a];for(;l.length;){let u=l.shift();if(!u)continue;let m=String(u.name??"").trim();if(m&&m===r&&u.url){let p=Me(String(u.url));p&&c.push(p);}Array.isArray(u.jobs)&&l.push(...u.jobs);}if(c.length)return c[0]}async function ae(t,n){try{let r=(await t.axios.get(`${k(n)}/api/json?tree=name,fullName,url,buildable,inQueue,nextBuildNumber,color,healthReport[description,score],lastBuild[number,url,building,result,timestamp,duration],lastCompletedBuild[number,url,result,timestamp,duration],lastSuccessfulBuild[number,url,building,result,timestamp,duration],lastFailedBuild[number,url,building,result,timestamp,duration]`)).data??{},o=typeof r?.fullName=="string"?r.fullName:"",s=typeof r?.name=="string"?r.name:"",i=String(n??"").trim();if(!o&&!s)throw new f(`Job not found: ${i}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli job show -j my-job"});if(i&&i!==o&&i!==s)throw new f(`Job not found: ${i}`,{hint:`Jenkins returned job "${o||s}".`,example:"jenkins-cli console last -j my-job -s success"});return r}catch(e){if(e?.response?.status===404){let o=String(n??"").trim();throw new f(`Job not found: ${o}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli console last -j my-job -s success"})}throw e}}async function et(t,n,e){let r=Math.max(1,e?.limit??20);return ((await t.axios.get(`${k(n)}/api/json?tree=builds[number,url,building,result,timestamp,duration,actions[parameters[name,value]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,result:i.result,building:i.building,timestamp:i.timestamp,duration:i.duration,url:i.url,parameters:oe(i.actions)}))}async function tt(t,n,e){let r=Math.max(1,e?.limit??20);return ((await t.axios.get(`${k(n)}/api/json?tree=builds[number,url,timestamp,changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,timestamp:i.timestamp,url:i.url,changeSet:i.changeSet??{}}))}async function ce(t,n,e){let o=(await t.axios.get(`${k(n)}/${e}/api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,description,actions[parameters[name,value]],changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]],culprits[fullName],executor[number,progress]`)).data??{};return {...o,parameters:oe(o.actions)}}async function nt(t,n,e){let r=await t.axios.get(`${k(n)}/${e}/consoleText`,{responseType:"text"});return String(r.data??"")}async function rt(t,n){return ((await t.axios.get(`${k(n)}/api/json?tree=property[parameterDefinitions[name,type,description,defaultParameterValue[value],choices]]`)).data?.property??[]).flatMap(s=>s?.parameterDefinitions??[]).filter(Boolean).map(s=>({name:s.name,type:s.type,description:s.description,default:s.defaultParameterValue?.value,choices:s.choices}))}async function Ce(t,n,e){let r=String(e?.path??"").trim(),o=r?`${v(r)}/`:"",s=await ke(t,k(n),o);return xe(s??{})}async function ot(t,n,e,r){let o=String(r?.path??"").trim(),s=o?`${v(o)}/`:"",i=`view/${encodeURIComponent(n)}/${k(e)}`,a=await ke(t,i,s);return xe(a??{})}async function it(t,n,e,r){let o=String(r?.path??"").trim(),s=o?`${v(o)}/`:"",i=new URL(`${k(e)}/`,n).toString(),a=await ke(t,i,s);return xe(a??{})}async function st(t,n,e){let r=v(String(e??"").trim());return await ye(t,k(n),r)}async function at(t,n,e){let r=v(String(e??"").trim());return await we(t,k(n),r)}async function ct(t,n,e,r){let o=v(String(r??"").trim()),s=`view/${encodeURIComponent(n)}/${k(e)}`;return await ye(t,s,o)}async function lt(t,n,e,r){let o=v(String(r??"").trim()),s=`view/${encodeURIComponent(n)}/${k(e)}`;return await we(t,s,o)}async function ut(t,n,e,r){let o=v(String(r??"").trim()),s=new URL(`${k(e)}/`,n).toString();return await ye(t,s,o)}async function mt(t,n,e,r){let o=v(String(r??"").trim()),s=new URL(`${k(e)}/`,n).toString();return await we(t,s,o)}async function pt(t,n){try{return await A(t),await t.axios.post(`${k(n)}/doWipeOutWorkspace`,new URLSearchParams({}),N),!0}catch(e){let r=e?.response?.status;if(r){let o=ze(e?.response?.data);throw new f(`Workspace wipe failed (HTTP ${r}).`,{hint:"Check Job/Workspace permission or CSRF settings.",example:"jenkins-cli workspace wipe -j my-job",details:o?`Jenkins response (snippet):
33
+ ${o}`:void 0})}throw e}}async function Se(t,n){let e=await t.axios.get(`${k(n)}/config.xml`,{responseType:"text"});return String(e.data??"")}async function ft(t,n,e,r){let o=`${k(n)}/${e}/logText/progressiveText`,s=new URLSearchParams;s.append("start",String(r));let i=await t.axios.post(o,s,{responseType:"text"}),a=String(i.data??""),c=i.headers["x-text-size"],l=i.headers["x-more-data"],u=c?Number(c):r+Buffer.byteLength(a);return {text:a,newOffset:u,hasMoreData:l==="true"}}async function _(t,n){let e=n?.raw?"views[*]":"views[name,url]";return (await t.axios.get(`api/json?tree=${e}`)).data.views??[]}async function K(t,n){let e=`view/${encodeURIComponent(n)}`;try{return (await t.axios.get(`${e}/api/json?tree=jobs[name,url,color]`)).data.jobs??[]}catch(r){throw r?.response?.status===404?new f(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".',example:"jenkins-cli view show MyView"}):r}}async function dt(t,n){let e=String(n??"").trim();if(!e)return;let r=e.split("/").filter(Boolean).pop()??e,o=await _(t,{raw:!1});for(let s of o){let i=String(s?.name??"").trim();if(i)try{if((await K(t,i)).some(c=>{let l=String(c?.name??"").trim();return l===e||l===r}))return i}catch{}}}async function h(){let t=Tt("Loading configuration...").start();try{let n=await Oe();t.succeed("Configuration loaded");let e=He(n.apiToken);return je(e),{config:n,jenkins:e}}catch(n){B(n),process.exit(1);}}var ln=an(fileURLToPath(import.meta.url),{interopDefault:!0});async function ht(t){return await Promise.resolve(t)}function un(t){let n=String(t??"").trim();if(!n)return null;let e=n.split(":");if(e.length<2)return null;if(e.length===2){let[s,i]=e;return !s||!i?null:{file:s,exportName:i}}let r=e.at(-1);if(!r)return null;let o=e.slice(0,-2).join(":");return o?{file:o,exportName:r}:null}function mn(t,n){return L.isAbsolute(n)?n:L.join(t,n)}function wt(t){return !!t&&typeof t=="object"&&!Array.isArray(t)}async function yt(t,n){let e=un(n);if(!e)return null;let r=mn(t,e.file);if(!await U.pathExists(r))throw new f(`configs reference not found: ${e.file}`,{hint:"Check the file path (relative to project root) and file name.",example:'configs: [{ choices: "./scripts/prompts.ts:choices" }]'});let o=ln(r),s=wt(o)?o:{default:o},i=e.exportName==="default"?s.default:s[e.exportName];if(i===void 0)throw new f(`configs reference export not found: ${n}`,{hint:"Make sure the export exists in the referenced file.",example:'export const choices = ["dev", "uat"]'});return {value:i}}async function le(t,n,e){if(typeof n!="string")return n;let r=await yt(t,n);if(!r)return n;if(!e.allow(r.value))throw new f(e.error(n),{hint:e.hint,example:e.example});return r.value}async function bt(t,n){if(typeof n!="string")return n;let e=await yt(t,n);if(!e)return n;if(typeof e.value=="function"){let r=e.value();return await ht(r)}return await ht(e.value)}async function kt(t,n){let e=Array.isArray(t)?t:[];if(e.length===0)return [];let r=String(n.projectRoot??"").trim()||process.cwd(),o=[];for(let s of e){if(!wt(s))continue;let i={...s};if(i.choices!==void 0){i.choices=await bt(r,i.choices);let a=String(i.type??"").toLowerCase(),c=i.choices;if((a==="list"||a==="rawlist"||a==="checkbox")&&typeof c!="function"&&!Array.isArray(c))if(c==null)i.choices=[];else if(typeof c=="string"||typeof c=="number"||typeof c=="boolean")i.choices=[String(c)];else if(typeof c[Symbol.iterator]=="function")i.choices=Array.from(c).map(u=>String(u));else throw new f(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof c}).`,{hint:"Return an array for list/rawlist/checkbox choices.",example:'export const choices = ["dev", "uat"]'})}i.default!==void 0&&(i.default=await bt(r,i.default)),i.when!==void 0&&(i.when=await le(r,i.when,{allow:a=>typeof a=="function"||typeof a=="boolean",error:a=>`when reference must be a function or boolean: ${a}`,hint:"Export a function or boolean from the referenced file.",example:'export const when = (answers) => answers.env === "dev"'})),i.validate!==void 0&&(i.validate=await le(r,i.validate,{allow:a=>typeof a=="function",error:a=>`validate reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:'export const validate = (input) => !!input || "required"'})),i.filter!==void 0&&(i.filter=await le(r,i.filter,{allow:a=>typeof a=="function",error:a=>`filter reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const filter = (input) => input.trim()"})),i.transformer!==void 0&&(i.transformer=await le(r,i.transformer,{allow:a=>typeof a=="function",error:a=>`transformer reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const transformer = (input) => input.toUpperCase()"})),o.push(i);}return o}function xt(t,n){let e=new Set(n),r={};for(let[o,s]of Object.entries(t))if(!e.has(o)&&s!==void 0){if(s===null){r[o]="";continue}if(Array.isArray(s)){r[o]=s.map(i=>String(i)).join(",");continue}if(typeof s=="object"){try{r[o]=JSON.stringify(s);}catch{r[o]=String(s);}continue}r[o]=String(s);}return r}async function jt(){console.log(w.bold.blue(`
30
34
  \u{1F680} Jenkins CLI - Jenkins Deployment CLI
31
- `));let{config:n,jenkins:e}=await g(),[t,r]=await Promise.all([ue(),le()]),o=()=>{console.log(b.yellow(`
32
- \u{1F44B} Cancelled by user`)),process.exit(130);},s,i={};try{process.prependOnceListener("SIGINT",o);let u=await Pe(n.configs,{projectRoot:n.projectRoot}),m=new Set(["branch","modes","mode"]);for(let h of u){let w=String(h?.name??"").trim();if(m.has(w))throw new p(`configs name "${w}" is reserved.`,{hint:"Use another name in your extra prompt config.",example:"name: env"})}let d=await pt.prompt([{type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:t,default:t.indexOf(r)},{type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:n.modes,validate:h=>h.length===0?"You must select at least one environment":!0},...u]);s={branch:String(d.branch??""),modes:d.modes??[]},i=Ne(d,["branch","modes"]);}catch(u){let m=u,d=m?.message?String(m.message):String(m),h=m?.name?String(m.name):"";(h==="ExitPromptError"||d.toLowerCase().includes("cancelled")||d.toLowerCase().includes("canceled"))&&(console.log(b.yellow(`
33
- \u{1F44B} Cancelled by user`)),process.exit(0)),J(new p(`Prompt failed: ${d}`,{hint:h?`Error: ${h}`:""})),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let a=!1,c=()=>{a||(a=!0,console.log());},l=s.modes.map(async u=>{let m=it(`Triggering build for ${b.yellow(u)}...`).start();try{let d=await M(e,n.job,{...i,branch:s.branch,mode:u});c(),m.succeed(`${b.green(u)} - Triggered! Queue: ${d}`);}catch(d){throw c(),m.fail(`${b.red(u)} - ${d.message}`),d}});try{await Promise.all(l);}catch{console.log(b.bold.red(`
35
+ `));let{config:t,jenkins:n}=await h(),[e,r]=await Promise.all([Te(),Le()]),o=()=>{console.log(w.yellow(`
36
+ \u{1F44B} Cancelled by user`)),process.exit(130);},s,i={};try{process.prependOnceListener("SIGINT",o);let u=await kt(t.configs,{projectRoot:t.projectRoot}),m=new Set(["branch","modes","mode"]);for(let b of u){let d=String(b?.name??"").trim();if(m.has(d))throw new f(`configs name "${d}" is reserved.`,{hint:"Use another name in your extra prompt config.",example:"name: env"})}let p=await pn.prompt([{type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:e,default:e.indexOf(r)},{type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:t.modes,validate:b=>b.length===0?"You must select at least one environment":!0},...u]);s={branch:String(p.branch??""),modes:p.modes??[]},i=xt(p,["branch","modes"]);}catch(u){let m=u,p=m?.message?String(m.message):String(m),b=m?.name?String(m.name):"";(b==="ExitPromptError"||p.toLowerCase().includes("cancelled")||p.toLowerCase().includes("canceled"))&&(console.log(w.yellow(`
37
+ \u{1F44B} Cancelled by user`)),process.exit(0)),B(new f(`Prompt failed: ${p}`,{hint:b?`Error: ${b}`:""})),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let a=!1,c=()=>{a||(a=!0,console.log());},l=s.modes.map(async u=>{let m=Tt(`Triggering build for ${w.yellow(u)}...`).start();try{let p=await se(n,t.job,{...i,branch:s.branch,mode:u});c(),m.succeed(`${w.green(u)} - Triggered! Queue: ${p}`);}catch(p){throw c(),m.fail(`${w.red(u)} - ${p.message}`),p}});try{await Promise.all(l);}catch{console.log(w.bold.red(`
34
38
  \u274C Some builds failed. Check the output above.
35
- `)),process.exit(1);}}function y(n,e){return (e??"").trim()||n}function x(n,e){let t=Number(n);if(!Number.isInteger(t)||t<0)throw new p(`${e} must be a non-negative integer.`,{hint:`Provide a valid ${e}.`,example:`jenkins-cli console ${e==="id"?"123":"last -t 100"}`});return t}function K(n,e){let t=String(e??"").trim();if(!t)return !0;if(!/[*?]/.test(t))return n.includes(t);let s=`^${t.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(s).test(n)}catch{return n.includes(t)}}function Ae(n){let e=n.command("queue").description("Operations for the build queue");e.command("list").alias("ls").description("List items waiting in the build queue").option("-j, --job <job>","Show only queue items for the specified job").action(async t=>{let{config:r,jenkins:o}=await g(),s=t.job?y(r.job,t.job):void 0,i=await A(o,s);console.table((i??[]).map(a=>({id:a.id,job:a.task?.name,why:a.why})));}),e.command("cancel").description("Cancel a queued build item").argument("<id...>","Queue id(s)").action(async t=>{let{jenkins:r}=await g(),o=Array.isArray(t)?t:[String(t??"")],s=await Promise.all(o.map(async a=>{let c=x(String(a),"id");try{return await I(r,c),{id:c,ok:!0}}catch(l){return {id:c,ok:!1,message:String(l?.message??l)}}})),i=s.filter(a=>!a.ok);if(i.length===0){console.log(b.green(`Cancelled ${s.length} queue item(s).`));return}console.log(b.yellow(`Cancelled ${s.length-i.length} item(s), failed ${i.length} item(s).`));for(let a of i)console.log(b.red(`- ${a.id}: ${a.message??"Cancel failed"}`));});}function f(n){return {[ft.inspect.custom]:()=>n}}function ee(n,e){return String(n??"").padEnd(e," ")}function k(n){return Math.max(0,...n.map(e=>String(e??"").length))}function v(n,e){return f(ee(n,e))}function C(n){let e=String(n??""),t=e.trim();if(!t)return f(b.gray("-"));let r=s=>f(s),o=t.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(t).hostname??"").toLowerCase(),a=i==="localhost"||i==="127.0.0.1"||i==="::1",c=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(a||c?b.cyanBright(e):b.hex("#4EA1FF")(e))}catch{return r(b.hex("#4EA1FF")(e))}return o.startsWith("ws://")||o.startsWith("wss://")?r(b.cyan(e)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(b.magenta(e)):o.startsWith("file://")?r(b.yellow(e)):o.startsWith("mailto:")?r(b.green(e)):o.startsWith("javascript:")||o.startsWith("data:")?r(b.red(e)):t.startsWith("/")||t.startsWith("./")||t.startsWith("../")?r(b.cyan(e)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(t)?r(b.blue(e)):r(e)}function S(n){let e=new Date(n),t=r=>String(r).padStart(2,"0");return `${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}function O(n,e){if(e===!0)return f(b.cyan("BUILDING"));let t=String(n??"").toUpperCase();return f(t?t==="SUCCESS"?b.green(t):t==="ABORTED"?b.gray(t):t==="FAILURE"?b.red(t):t==="UNSTABLE"?b.yellow(t):t==="NOT_BUILT"?b.gray(t):t:"-")}function te(n){let e=String(n??"");if(!e)return f("-");let t=e.endsWith("_anime"),r=t?e.slice(0,-6):e,o=(()=>{switch(r){case"blue":return t?b.blueBright(e):b.blue(e);case"red":return t?b.redBright(e):b.red(e);case"yellow":return t?b.yellowBright(e):b.yellow(e);case"aborted":return b.gray(e);case"disabled":case"notbuilt":case"grey":case"gray":return b.gray(e);default:return e}})();return f(o)}function Be(n){let e=Object.entries(n??{}).filter(([r])=>r);return e.length?(e.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"})),e.map(([r,o])=>{if(o===void 0)return `${r}=`;if(o===null)return `${r}=null`;if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return `${r}=${o}`;try{return `${r}=${JSON.stringify(o)}`}catch{return `${r}=${String(o)}`}}).join(", ")):"-"}function Ee(n){let e=n.command("builds").description("Build operations");e.option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),a=(await ye(o,s,{limit:Number(t.limit)})).map(l=>({number:l.number,result:O(l.result,l.building),building:l.building,"duration(s)":Number((Number(l.duration??0)/1e3).toFixed(3)),date:f(S(Number(l.timestamp??0))),parameters:Be(l.parameters),url:C(String(l.url??""))})),c=k(a.map(l=>l.parameters));console.table(a.map(l=>({...l,parameters:v(l.parameters,c)})));}),e.command("active").description("List active builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async t=>{let{config:r,jenkins:o}=await g(),i=((t.all?await W(o):await L(o,y(r.job,t.job)))??[]).map(c=>({...t.all?{job:f(String(c.job??""))}:{},number:c.number,date:f(c.timestamp?S(Number(c.timestamp)):"-"),parameters:Be(c.parameters),url:C(String(c.url??""))})),a=k(i.map(c=>c.parameters));console.table(i.map(c=>({...c,parameters:v(c.parameters,a)})));});}function gt(n){let e=String(n?.authorEmail??"").trim(),t=e?e.split("@")[0]??"":"";return t||e}function Le(n){let e=[];for(let t of n){let r=Number(t?.number),o=Number.isInteger(r)?`#${r}`:f("-"),s=t?.timestamp?S(Number(t.timestamp)):"-",i=t?.changeSet?.items??[];if(!i.length){e.push({build:o,date:f(s),author:f("-"),message:f("-")});continue}for(let a of i){let c=gt(a),l=String(a?.msg??"").trim();e.push({build:o,date:f(s),author:f(c||"-"),message:f(l||"-")});}}return e}function Ie(n){n.command("changes").description("List build changes").argument("[id]").option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").option("--raw","Output raw changeSet payload").action(async(e,t)=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job);if(e){let c=x(e,"id"),l=await je(o,s,c);if(t.raw){console.log(JSON.stringify({build:l.number,changeSet:l.changeSet??{}},null,2));return}console.table(Le([l]));return}let i=Math.max(1,x(t.limit,"limit")),a=await we(o,s,{limit:i});if(t.raw){console.log(JSON.stringify(a.map(c=>({build:c.number,changeSet:c.changeSet??{}})),null,2));return}console.table(Le(a));});}function Ue(){let n=process.argv,e=n.findIndex(r=>r==="-j"||r==="--job");if(e<0)return;let t=n[e+1];return !t||t.startsWith("-")?"":t}function qe(n){let e=n.command("console").description("Fetch build console log"),t=async(r,o,s)=>{let{jenkins:i}=await g(),a=await xe(i,r,o);if(s.tail){let c=x(s.tail,"tail"),l=a.split(`
36
- `);console.log(l.slice(Math.max(0,l.length-c)).join(`
37
- `));return}process.stdout.write(a);};e.argument("<id>","Build number").option("-j, --job <job>","Specify job").option("-t, --tail <n>","Only output the last N lines").action(async(r,o)=>{let{config:s}=await g(),i=o.job??Ue();if(i==="")throw new p("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console 123 -j my-job"});let a=y(s.job,i),c=x(r,"id");await t(a,c,o);}),e.command("last").description("Fetch the latest build log").option("-j, --job <job>","Specify job").option("-s, --status <status>","success | failed | any","any").option("-t, --tail <n>","Only output the last N lines").action(async r=>{let{config:o,jenkins:s}=await g(),i=r.job??Ue();if(i==="")throw new p("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console last -j my-job -s success"});let a=y(o.job,i),c=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(c))throw new p(`Invalid status: ${r.status}.`,{hint:"Use success | failed | any.",example:"jenkins-cli console last -s success"});let l=await Q(s,a),u=c==="success"?l?.lastSuccessfulBuild:c==="failed"?l?.lastFailedBuild:l?.lastBuild,m=Number(u?.number);if(!m){let d=c==="success"?"successful":c==="failed"?"failed":"last";throw new p(`No ${d} build found for job: ${a}`,{hint:"Check the job name or status filter.",example:"jenkins-cli console last -j my-job -s any"})}await t(a,m,r);});}function Oe(n){n.command("stop").description("Clear queued builds and stop running builds").argument("[id]","Build number").option("-j, --job <job>","Specify Jenkins job").option("-a, --all","Cancel queued items for this job and stop all running builds for it").option("-A, --ALL","Cancel all queued items and stop all running builds on Jenkins").action(async(e,t)=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job);if(t.ALL){let[i,a]=await Promise.all([A(o),W(o)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>({number:Number(u.number),job:String(u.job??"")})).filter(u=>u.job&&!Number.isNaN(u.number));for(let u of c)await I(o,u);for(let u of l)await U(o,u.job,u.number);console.log(b.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(t.all){let[i,a]=await Promise.all([A(o,s),L(o,s)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>Number(u.number)).filter(u=>!Number.isNaN(u));for(let u of c)await I(o,u);for(let u of l)await U(o,s,u);console.log(b.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!e){console.log(b.red("Missing build id. Provide <id> or use -a/--all."));return}await U(o,s,x(e,"id")),console.log(b.green("Stop requested"));});}function Fe(n){n.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async e=>{let{config:t,jenkins:r}=await g(),o=y(t.job,e.job),s=await ke(r,o),i=k(s.map(a=>a?.name));console.table((s??[]).map(a=>({name:v(a?.name??"",i),type:f(String(a?.type??"")),description:f(String(a?.description??"")),default:f(a?.default===void 0?"-":String(a.default)),choices:f(Array.isArray(a?.choices)?a.choices.join(", "):a?.choices??"-")})));});}function Te(n){n.command("me").description("Show Jenkins user info for the current token").option("--raw","Print raw response").action(async e=>{let{jenkins:t}=await g(),r=await he(t);if(e.raw){console.log(r&&typeof r=="object"?JSON.stringify(r,null,2):String(r));return}let o=r&&typeof r=="object"?r:{value:r},s=(u,m)=>{let d=u.length;if(d>=m)return u;let h=m-d,w=Math.floor(h/2),B=h-w;return `${" ".repeat(w)}${u}${" ".repeat(B)}`},i=o.name??o.fullName??o.id??"",a=i==null?"":String(i),c=Math.max(20,a.length),l={};l.name=f(s(a,c));for(let u of Object.keys(o).sort((m,d)=>m.localeCompare(d,"en"))){if(u==="name")continue;let m=o[u],d=u.toLowerCase();if((d==="url"||d.endsWith("url")||d.includes("url"))&&(typeof m=="string"||typeof m=="number")){l[u]=C(String(m));continue}let w=m==null?"":typeof m=="object"?JSON.stringify(m):String(m);l[u]=f(w);}console.table([l]);});}function De(n){let e=n.command("config").description("Show Jenkins job configuration");e.command("show").description("Show job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),i=String(t.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new p(`Invalid format: ${t.format}.`,{hint:"Use xml or json.",example:"jenkins-cli config show -f json"});let a=await X(o,s);if(i==="xml"){process.stdout.write(a);return}let l=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(a);console.log(JSON.stringify(l,null,2));}),e.command("backup").description("Backup job configuration to files").requiredOption("-d, --destination <path>","Destination folder").option("-a, --all","Backup all jobs").option("-j, --job <job>","Specify job").option("--filter <pattern>","Filter jobs by name (supports glob)").action(async t=>{let{config:r,jenkins:o}=await g(),s=String(t.destination??"").trim();if(!s)throw new p("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli config backup -d ./jenkins-backup"});if(t.all&&t.filter)throw new p("Options --all and --filter are mutually exclusive.",{hint:"Use either -a/--all or --filter, not both.",example:"jenkins-cli config backup -d ./jenkins-backup -a"});let i=String(t.filter??"").trim(),a=t.all?await q(o):i?(await q(o)).filter(l=>K(String(l.name??""),i)):[{name:y(r.job,t.job)}];if(a.length===0)throw new p(`No jobs matched filter: ${i}`,{hint:"Check the pattern or remove --filter to use the default job.",example:"jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'"});await promises.mkdir(s,{recursive:!0});let c=[];for(let l of a){let u=String(l?.name??"").trim();if(!u)continue;let m=await X(o,u),d=R.join(s,u,"config.xml");await promises.mkdir(R.dirname(d),{recursive:!0}),await promises.writeFile(d,m),c.push(d);}console.log(`Backup completed. ${c.length} file(s) saved to ${R.resolve(s)}`);});}function We(n){let e=n.command("job").description("Job operations");e.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async t=>{let{jenkins:r}=await g(),o=await q(r),s=(t.search??"").trim(),i=s?o.filter(l=>K(String(l.name??""),s)):o;i.sort((l,u)=>String(l?.name??"").localeCompare(String(u?.name??""),"en",{sensitivity:"base"}));let a=k(i.map(l=>l?.name)),c=k(i.map(l=>l?.url));console.table((i??[]).map(l=>({name:v(l.name??"",a),color:te(l.color),url:C(ee(l.url??"",c))})));}),e.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),i=await Q(o,s);if(t.json){console.log(JSON.stringify(i,null,2));return}let a=i?.lastBuild,c=i?.lastCompletedBuild,l=Array.isArray(i?.healthReport)?i.healthReport:[];console.table([{name:f(String(i?.name??"")),url:C(String(i?.url??"")),color:te(i?.color),buildable:i?.buildable,inQueue:i?.inQueue,nextBuildNumber:i?.nextBuildNumber,healthScore:l[0]?.score??"-",lastBuild:f(a?.number?`#${a.number}`:"-"),lastResult:O(a?.result,a?.building),"lastDuration(s)":a?.duration===void 0?"-":Number((Number(a.duration)/1e3).toFixed(3)),lastDate:f(a?.timestamp?S(Number(a.timestamp)):"-"),lastCompleted:f(c?.number?`#${c.number}`:"-"),lastCompletedResult:O(c?.result,!1),lastCompletedDate:f(c?.timestamp?S(Number(c.timestamp)):"-")}]);});}function yt(n){return n.split(",").map(e=>e.trim()).filter(Boolean)}function wt(n){let e=n.split("=");if(e.length<2)throw new p(`Invalid --param: "${n}".`,{hint:"Use the format key=value.",example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});let t=e[0].trim(),r=e.slice(1).join("=").trim();if(!t)throw new p(`Invalid --param: "${n}". Key is empty.`,{hint:'Provide a non-empty key before "=".',example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});return {key:t,value:r}}function Me(n){n.command("build").description("Trigger Jenkins builds non-interactively").requiredOption("-b, --branch <branch>","Branch (e.g., origin/develop)").option("-m, --mode <mode>","Deployment environment (repeatable or comma-separated: -m dev -m uat / -m dev,uat)",(e,t)=>t.concat(yt(e)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(e,t)=>t.concat(e),[]).option("-j, --job <job>","Specify job").action(async e=>{let{config:t,jenkins:r}=await g(),o=y(t.job,e.job),s=String(e.branch??"").trim();if(!s)throw new p("branch is required.",{hint:"Pass a branch with -b or --branch.",example:"jenkins-cli build -b origin/develop -m dev"});let i=(e.mode??[]).map(String).map(d=>d.trim()).filter(Boolean),a=Array.from(new Set(i));if(a.length===0)throw new p("mode is required.",{hint:"Pass at least one -m/--mode.",example:"jenkins-cli build -b origin/develop -m dev -m uat"});let c={};for(let d of e.param??[]){let{key:h,value:w}=wt(String(d));c[h]=w;}console.log();let l=!1,u=()=>{l||(l=!0,console.log());},m=a.map(async d=>{let h=it(`Triggering build for ${b.yellow(d)}...`).start();try{let w=await M(r,o,{...c,branch:s,mode:d});u(),h.succeed(`${b.green(d)} - Triggered! Queue: ${w}`);}catch(w){throw u(),h.fail(`${b.red(d)} - ${w.message}`),w}});try{await Promise.all(m);}catch{console.log(b.bold.red(`
39
+ `)),process.exit(1);}}function y(t,n){return (n??"").trim()||t}function P(t,n){let e=Number(t);if(!Number.isInteger(e)||e<0)throw new f(`${n} must be a non-negative integer.`,{hint:`Provide a valid ${n}.`,example:`jenkins-cli console ${n==="id"?"123":"last -t 100"}`});return e}function ue(t,n){let e=String(n??"").trim();if(!e)return !0;if(!/[*?]/.test(e))return t.includes(e);let s=`^${e.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(s).test(t)}catch{return t.includes(e)}}function Ct(t){let n=t.command("queue").description("Operations for the build queue");n.command("list").alias("ls").description("List items waiting in the build queue").option("-j, --job <job>","Show only queue items for the specified job").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job?y(r.job,e.job):void 0,i=await V(o,s);console.table((i??[]).map(a=>({id:a.id,job:a.task?.name,why:a.why})));}),n.command("cancel").description("Cancel a queued build item").argument("<id...>","Queue id(s)").action(async e=>{let{jenkins:r}=await h(),o=Array.isArray(e)?e:[String(e??"")],s=await Promise.all(o.map(async a=>{let c=P(String(a),"id");try{return await z(r,c),{id:c,ok:!0}}catch(l){return {id:c,ok:!1,message:String(l?.message??l)}}})),i=s.filter(a=>!a.ok);if(i.length===0){console.log(w.green(`Cancelled ${s.length} queue item(s).`));return}console.log(w.yellow(`Cancelled ${s.length-i.length} item(s), failed ${i.length} item(s).`));for(let a of i)console.log(w.red(`- ${a.id}: ${a.message??"Cancel failed"}`));});}function g(t){return {[dn.inspect.custom]:()=>t}}function W(t,n){return String(t??"").padEnd(n," ")}function x(t){return Math.max(0,...t.map(n=>String(n??"").length))}function C(t,n){return g(W(t,n))}function S(t){let n=String(t??""),e=n.trim();if(!e)return g(w.gray("-"));let r=s=>g(s),o=e.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(e).hostname??"").toLowerCase(),a=i==="localhost"||i==="127.0.0.1"||i==="::1",c=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(a||c?w.cyanBright(n):w.hex("#4EA1FF")(n))}catch{return r(w.hex("#4EA1FF")(n))}return o.startsWith("ws://")||o.startsWith("wss://")?r(w.cyan(n)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(w.magenta(n)):o.startsWith("file://")?r(w.yellow(n)):o.startsWith("mailto:")?r(w.green(n)):o.startsWith("javascript:")||o.startsWith("data:")?r(w.red(n)):e.startsWith("/")||e.startsWith("./")||e.startsWith("../")?r(w.cyan(n)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(e)?r(w.blue(n)):r(n)}function $(t){let n=new Date(t),e=r=>String(r).padStart(2,"0");return `${n.getFullYear()}-${e(n.getMonth()+1)}-${e(n.getDate())} ${e(n.getHours())}:${e(n.getMinutes())}:${e(n.getSeconds())}`}function G(t,n){if(n===!0)return g(w.cyan("BUILDING"));let e=String(t??"").toUpperCase();return g(e?e==="SUCCESS"?w.green(e):e==="ABORTED"?w.gray(e):e==="FAILURE"?w.red(e):e==="UNSTABLE"?w.yellow(e):e==="NOT_BUILT"?w.gray(e):e:"-")}function Y(t){let n=String(t??"");if(!n)return g("-");let e=n.endsWith("_anime"),r=e?n.slice(0,-6):n,o=(()=>{switch(r){case"blue":return e?w.blueBright(n):w.blue(n);case"red":return e?w.redBright(n):w.red(n);case"yellow":return e?w.yellowBright(n):w.yellow(n);case"aborted":return w.gray(n);case"disabled":case"notbuilt":case"grey":case"gray":return w.gray(n);default:return n}})();return g(o)}function St(t){let n=Number(t);if(!Number.isFinite(n)||n<0)return g("-");if(n<1024)return g(`${n} B`);let e=["KB","MB","GB","TB"],r=n,o=-1;for(;r>=1024&&o<e.length-1;)r/=1024,o+=1;let s=r>=10||o===0?r.toFixed(1):r.toFixed(2);return g(`${s} ${e[o]}`)}function me(t){let n=process.argv,e=0;if(t){let r=n.lastIndexOf(t);r>=0&&(e=r+1);}for(let r=e;r<n.length;r+=1){let o=n[r];if(o==="-j"||o==="--job"){let s=n[r+1];return !s||s.startsWith("-")?"":s}}}function $t(t){let n=Object.entries(t??{}).filter(([r])=>r);return n.length?(n.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"})),n.map(([r,o])=>{if(o===void 0)return `${r}=`;if(o===null)return `${r}=null`;if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return `${r}=${o}`;try{return `${r}=${JSON.stringify(o)}`}catch{return `${r}=${String(o)}`}}).join(", ")):"-"}function Jt(t){let n=t.command("builds").description("Build operations");n.option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job??me("builds")??me(),i=y(r.job,s),c=(await et(o,i,{limit:Number(e.limit)})).map(u=>({number:u.number,result:G(u.result,u.building),building:u.building,"duration(s)":Number((Number(u.duration??0)/1e3).toFixed(3)),date:g($(Number(u.timestamp??0))),parameters:$t(u.parameters),url:S(String(u.url??""))})),l=x(c.map(u=>u.parameters));console.table(c.map(u=>({...u,parameters:C(u.parameters,l)})));}),n.command("active").description("List active builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job??me("active")??me("builds"),a=((e.all?await ie(o):await M(o,y(r.job,s)))??[]).map(l=>({...e.all?{job:g(String(l.job??""))}:{},number:l.number,date:g(l.timestamp?$(Number(l.timestamp)):"-"),parameters:$t(l.parameters),url:S(String(l.url??""))})),c=x(a.map(l=>l.parameters));console.table(a.map(l=>({...l,parameters:C(l.parameters,c)})));});}function gn(t){let n=String(t?.authorEmail??"").trim(),e=n?n.split("@")[0]??"":"";return e||n}function vt(t){let n=[];for(let e of t){let r=Number(e?.number),o=Number.isInteger(r)?`#${r}`:g("-"),s=e?.timestamp?$(Number(e.timestamp)):"-",i=e?.changeSet?.items??[];if(!i.length){n.push({build:o,date:g(s),author:g("-"),message:g("-")});continue}for(let a of i){let c=gn(a),l=String(a?.msg??"").trim();n.push({build:o,date:g(s),author:g(c||"-"),message:g(l||"-")});}}return n}function Pt(t){t.command("changes").description("List build changes").argument("[id]").option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").option("--raw","Output raw changeSet payload").action(async(n,e)=>{let{config:r,jenkins:o}=await h(),s=y(r.job,e.job);if(n){let c=P(n,"id"),l=await ce(o,s,c);if(e.raw){console.log(JSON.stringify({build:l.number,changeSet:l.changeSet??{}},null,2));return}console.table(vt([l]));return}let i=Math.max(1,P(e.limit,"limit")),a=await tt(o,s,{limit:i});if(e.raw){console.log(JSON.stringify(a.map(c=>({build:c.number,changeSet:c.changeSet??{}})),null,2));return}console.table(vt(a));});}function Rt(){let t=process.argv,n=t.findIndex(r=>r==="-j"||r==="--job");if(n<0)return;let e=t[n+1];return !e||e.startsWith("-")?"":e}function Nt(t){let n=t.command("console").description("Fetch build console log"),e=async(r,o,s,i)=>{if(!i.follow){let l=await nt(r,o,s);process.stdout.write(l);return}let a=0,c=!0;for(console.log(w.blue(`--- Following log for build #${s} ---`));;)try{let{text:l,newOffset:u,hasMoreData:m}=await ft(r,o,s,a);if(l.length>0&&(process.stdout.write(l),a=u),c&&l.length>0&&(c=!1),l.length>0&&m)continue;if(!m){let b=(await ce(r,o,s)).result||"UNKNOWN",d=b==="SUCCESS"?w.green:w.red;console.log(d(`
40
+ --- Build Finished: ${b} ---`));break}await new Promise(p=>setTimeout(p,1e3));}catch{await new Promise(l=>setTimeout(l,2e3));}};n.argument("<id>","Build number").option("-j, --job <job>","Specify job").option("--no-follow","Do not follow the build log").action(async(r,o)=>{let{config:s,jenkins:i}=await h(),a=o.job??Rt();if(a==="")throw new f("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console 123 -j my-job"});let c=y(s.job,a),l=P(r,"id");await e(i,c,l,o);}),n.command("last").description("Fetch the latest build log").option("-j, --job <job>","Specify job").option("-s, --status <status>","success | failed | any","any").option("--no-follow","Do not follow the build log").action(async r=>{let{config:o,jenkins:s}=await h(),i=r.job??Rt();if(i==="")throw new f("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console last -j my-job -s success"});let a=y(o.job,i),c=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(c))throw new f(`Invalid status: ${r.status}.`,{hint:"Use success | failed | any.",example:"jenkins-cli console last -s success"});let l=await ae(s,a),u=c==="success"?l?.lastSuccessfulBuild:c==="failed"?l?.lastFailedBuild:l?.lastBuild,m=Number(u?.number);if(!m){let p=c==="success"?"successful":c==="failed"?"failed":"last";console.log(w.yellow(`No ${p} build found for job: ${a}. Try checking the job name or status filter.`));return}await e(s,a,m,r);});}function At(t){t.command("stop").description("Clear queued builds and stop running builds").argument("[id]","Build number").option("-j, --job <job>","Specify Jenkins job").option("-a, --all","Cancel queued items for this job and stop all running builds for it").option("-A, --ALL","Cancel all queued items and stop all running builds on Jenkins").action(async(n,e)=>{let{config:r,jenkins:o}=await h(),s=y(r.job,e.job);if(e.ALL){let[i,a]=await Promise.all([V(o),ie(o)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>({number:Number(u.number),job:String(u.job??"")})).filter(u=>u.job&&!Number.isNaN(u.number));for(let u of c)await z(o,u);for(let u of l)await H(o,u.job,u.number);console.log(w.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(e.all){let[i,a]=await Promise.all([V(o,s),M(o,s)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>Number(u.number)).filter(u=>!Number.isNaN(u));for(let u of c)await z(o,u);for(let u of l)await H(o,s,u);console.log(w.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!n){console.log(w.red("Missing build id. Provide <id> or use -a/--all."));return}await H(o,s,P(n,"id")),console.log(w.green("Stop requested"));});}function Wt(t){t.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async n=>{let{config:e,jenkins:r}=await h(),o=y(e.job,n.job),s=await rt(r,o),i=x(s.map(a=>a?.name));console.table((s??[]).map(a=>({name:C(a?.name??"",i),type:g(String(a?.type??"")),description:g(String(a?.description??"")),default:g(a?.default===void 0?"-":String(a.default)),choices:g(Array.isArray(a?.choices)?a.choices.join(", "):a?.choices??"-")})));});}function Et(t){t.command("me").description("Show Jenkins user info for the current token").option("--raw","Print raw response").action(async n=>{let{jenkins:e}=await h(),r=await Xe(e);if(n.raw){console.log(r&&typeof r=="object"?JSON.stringify(r,null,2):String(r));return}let o=r&&typeof r=="object"?r:{value:r},s=(u,m)=>{let p=u.length;if(p>=m)return u;let b=m-p,d=Math.floor(b/2),j=b-d;return `${" ".repeat(d)}${u}${" ".repeat(j)}`},i=o.name??o.fullName??o.id??"",a=i==null?"":String(i),c=Math.max(20,a.length),l={};l.name=g(s(a,c));for(let u of Object.keys(o).sort((m,p)=>m.localeCompare(p,"en"))){if(u==="name")continue;let m=o[u],p=u.toLowerCase();if((p==="url"||p.endsWith("url")||p.includes("url"))&&(typeof m=="string"||typeof m=="number")){l[u]=S(String(m));continue}let d=m==null?"":typeof m=="object"?JSON.stringify(m):String(m);l[u]=g(d);}console.table([l]);});}function Bt(t){let n=t.command("config").description("Show Jenkins job configuration");n.command("show").description("Show job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async e=>{let{config:r,jenkins:o}=await h(),s=y(r.job,e.job),i=String(e.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new f(`Invalid format: ${e.format}.`,{hint:"Use xml or json.",example:"jenkins-cli config show -f json"});let a=await Se(o,s);if(i==="xml"){process.stdout.write(a);return}let l=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(a);console.log(JSON.stringify(l,null,2));}),n.command("backup").description("Backup job configuration to files").requiredOption("-d, --destination <path>","Destination folder").option("-a, --all","Backup all jobs").option("-j, --job <job>","Specify job").option("--filter <pattern>","Filter jobs by name (supports glob)").action(async e=>{let{config:r,jenkins:o}=await h(),s=String(e.destination??"").trim();if(!s)throw new f("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli config backup -d ./jenkins-backup"});if(e.all&&e.filter)throw new f("Options --all and --filter are mutually exclusive.",{hint:"Use either -a/--all or --filter, not both.",example:"jenkins-cli config backup -d ./jenkins-backup -a"});let i=String(e.filter??"").trim(),a=e.all?await Q(o):i?(await Q(o)).filter(l=>ue(String(l.name??""),i)):[{name:y(r.job,e.job)}];if(a.length===0)throw new f(`No jobs matched filter: ${i}`,{hint:"Check the pattern or remove --filter to use the default job.",example:"jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'"});await promises.mkdir(s,{recursive:!0});let c=[];for(let l of a){let u=String(l?.name??"").trim();if(!u)continue;let m=await Se(o,u),p=L.join(s,u,"config.xml");await promises.mkdir(L.dirname(p),{recursive:!0}),await promises.writeFile(p,m),c.push(p);}console.log(`Backup completed. ${c.length} file(s) saved to ${L.resolve(s)}`);});}function Ft(t){let n=t.command("job").description("Job operations");n.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async e=>{let{jenkins:r}=await h(),o=await Q(r),s=(e.search??"").trim(),i=s?o.filter(l=>ue(String(l.name??""),s)):o;i.sort((l,u)=>String(l?.name??"").localeCompare(String(u?.name??""),"en",{sensitivity:"base"}));let a=x(i.map(l=>l?.name)),c=x(i.map(l=>l?.url));console.table((i??[]).map(l=>({name:C(l.name??"",a),color:Y(l.color),url:S(W(l.url??"",c))})));}),n.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async e=>{let{config:r,jenkins:o}=await h(),s=y(r.job,e.job),i=await ae(o,s);if(e.json){console.log(JSON.stringify(i,null,2));return}let a=i?.lastBuild,c=i?.lastCompletedBuild,l=Array.isArray(i?.healthReport)?i.healthReport:[];console.table([{name:g(String(i?.name??"")),url:S(String(i?.url??"")),color:Y(i?.color),buildable:i?.buildable,inQueue:i?.inQueue,nextBuildNumber:i?.nextBuildNumber,healthScore:l[0]?.score??"-",lastBuild:g(a?.number?`#${a.number}`:"-"),lastResult:G(a?.result,a?.building),"lastDuration(s)":a?.duration===void 0?"-":Number((Number(a.duration)/1e3).toFixed(3)),lastDate:g(a?.timestamp?$(Number(a.timestamp)):"-"),lastCompleted:g(c?.number?`#${c.number}`:"-"),lastCompletedResult:G(c?.result,!1),lastCompletedDate:g(c?.timestamp?$(Number(c.timestamp)):"-")}]);});}function wn(t){return t.split(",").map(n=>n.trim()).filter(Boolean)}function yn(t){let n=t.split("=");if(n.length<2)throw new f(`Invalid --param: "${t}".`,{hint:"Use the format key=value.",example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});let e=n[0].trim(),r=n.slice(1).join("=").trim();if(!e)throw new f(`Invalid --param: "${t}". Key is empty.`,{hint:'Provide a non-empty key before "=".',example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});return {key:e,value:r}}function Ut(t){t.command("build").description("Trigger Jenkins builds non-interactively").requiredOption("-b, --branch <branch>","Branch (e.g., origin/develop)").option("-m, --mode <mode>","Deployment environment (repeatable or comma-separated: -m dev -m uat / -m dev,uat)",(n,e)=>e.concat(wn(n)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(n,e)=>e.concat(n),[]).option("-j, --job <job>","Specify job").action(async n=>{let{config:e,jenkins:r}=await h(),o=y(e.job,n.job),s=String(n.branch??"").trim();if(!s)throw new f("branch is required.",{hint:"Pass a branch with -b or --branch.",example:"jenkins-cli build -b origin/develop -m dev"});let i=(n.mode??[]).map(String).map(p=>p.trim()).filter(Boolean),a=Array.from(new Set(i));if(a.length===0)throw new f("mode is required.",{hint:"Pass at least one -m/--mode.",example:"jenkins-cli build -b origin/develop -m dev -m uat"});let c={};for(let p of n.param??[]){let{key:b,value:d}=yn(String(p));c[b]=d;}console.log();let l=!1,u=()=>{l||(l=!0,console.log());},m=a.map(async p=>{let b=Tt(`Triggering build for ${w.yellow(p)}...`).start();try{let d=await se(r,o,{...c,branch:s,mode:p});u(),b.succeed(`${w.green(p)} - Triggered! Queue: ${d}`);}catch(d){throw u(),b.fail(`${w.red(p)} - ${d.message}`),d}});try{await Promise.all(m);}catch{console.log(w.bold.red(`
38
41
  \u274C Some builds failed. Check the output above.
39
- `)),process.exit(1);}});}function Qe(n){Ee(n),Ie(n),De(n),We(n),qe(n),Fe(n),Ae(n),Oe(n),Me(n),Te(n);}program.name("jenkins-cli").description(ae).version(se,"-v, --version").helpOption("-h, --help").allowExcessArguments(!1).configureHelp({sortSubcommands:!0,sortOptions:!0}).action(Re);Qe(program);async function jt(){try{await program.parseAsync(process.argv);}catch(n){J(n);}}jt();
42
+ `)),process.exit(1);}});}function Lt(t){let n=t.command("view").description("View operations");n.command("list").alias("ls").description("List all views").option("--raw","Output raw JSON").action(async e=>{let{jenkins:r}=await h(),o=await _(r,{raw:e.raw});if(e.raw){console.log(JSON.stringify(o,null,2));return}o.sort((c,l)=>String(c?.name??"").localeCompare(String(l?.name??""),"en",{sensitivity:"base"}));let s=(o??[]).map(c=>({name:String(c?.name??""),url:String(c?.url??"")})),i=x(s.map(c=>c.name)),a=x(s.map(c=>c.url));console.table(s.map(c=>({name:C(c.name,i),url:S(W(c.url,a))})));}),n.command("show").description("Show jobs in a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h(),o=await K(r,e);if(!o.length){console.log("No jobs found in this view.");return}o.sort((a,c)=>String(a?.name??"").localeCompare(String(c?.name??""),"en",{sensitivity:"base"}));let s=x(o.map(a=>a?.name)),i=x(o.map(a=>a?.url));console.table(o.map(a=>({name:C(a.name??"",s),color:Y(a.color),url:S(W(a.url??"",i))})));}),n.command("add").description("Add a job to a view").argument("<view>","View name").argument("<job>","Job name").action(async(e,r)=>{let{jenkins:o}=await h();if((await K(o,e)).some(i=>i.name===r)){console.log(w.yellow(`Job "${r}" is already in view "${e}".`));return}await _e(o,e,r),console.log(w.green(`Job "${r}" added to view "${e}".`));}),n.command("remove").alias("rm").description("Remove a job from a view").argument("<view>","View name").argument("<job>","Job name").action(async(e,r)=>{let{jenkins:o}=await h();if(!(await K(o,e)).some(i=>i.name===r))throw new f(`Job "${r}" is not in view "${e}".`,{hint:'Use "jc view show <name>" to see jobs in this view.'});await Ke(o,e,r),console.log(w.green(`Job "${r}" removed from view "${e}".`));}),n.command("create").description("Create a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h();await Ge(r,e),console.log(w.green(`View "${e}" created.`));}),n.command("delete").alias("del").description("Delete a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h();await Ye(r,e),console.log(w.green(`View "${e}" deleted.`));});}function Cn(t){return g(t?$(t):"-")}function he(t){let n=process.argv,e=0;if(t){let r=n.lastIndexOf(t);r>=0&&(e=r+1);}for(let r=e;r<n.length;r+=1){let o=n[r];if(o==="-j"||o==="--job"){let s=n[r+1];return !s||s.startsWith("-")?"":s}}}function Pe(t,n,e){let r=n?.parent?.opts()?.job,o=he(e)??he(n?.name())??he("ws")??he("workspace");return t??r??o}function Re(t,n){if(n==="")throw new f("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli ws -j my-job"});return y(t,n)}function Vt(t){return t.replace(/^\/+/,"").replace(/\/+$/,"")}function Sn(t,n){let e=Vt(t),r=Vt(n);return e?r?r===e||r.startsWith(`${e}/`)?r:`${e}/${r}`:e:r||""}function $n(t){let n=process.platform,e="",r=[];n==="darwin"?(e="open",r=[t]):n==="win32"?(e="cmd",r=["/c","start","",t]):(e="xdg-open",r=[t]);try{spawn(e,r,{stdio:"ignore",detached:!0}).unref();}catch{}}async function J(t){try{return await t()}catch(n){if(n?.response?.status===404)return null;throw n}}async function Jn(t,n){try{return await Ze(t,n)}catch{return}}async function vn(t,n){try{return await dt(t,n)}catch{return}}async function Pn(t){try{return await _(t,{raw:!1})}catch{return []}}async function Ne(t,n,e){let r=await e.direct(n);if(r!==null)return r;let o=await Jn(t,n);if(o&&o!==n){let a=await e.direct(o);if(a!==null)return a}if(e.beforeView){let a=await e.beforeView();if(a!==null)return a}let s=await vn(t,n);if(s){let a=await e.byViewName(s);if(a!==null)return a}let i=await Pn(t);for(let a of i){let c=String(a?.url??"").trim();if(!c)continue;let l=await e.byViewUrl(c);if(l!==null)return l}return null}async function Rn(t,n,e){return await Ne(t,n,{direct:r=>J(()=>Ce(t,r,{path:e})),byViewName:r=>J(()=>ot(t,r,n,{path:e})),byViewUrl:r=>J(()=>it(t,r,n,{path:e})),beforeView:async()=>{if(e)return null;let r=n.split("/").pop();return r?await J(()=>Ce(t,n,{path:r})):null}})}async function Nn(t,n,e){return await Ne(t,n,{direct:r=>J(()=>st(t,r,e)),byViewName:r=>J(()=>ct(t,r,n,e)),byViewUrl:r=>J(()=>ut(t,r,n,e))})}async function An(t,n,e){return await Ne(t,n,{direct:r=>J(()=>at(t,r,e)),byViewName:r=>J(()=>lt(t,r,n,e)),byViewUrl:r=>J(()=>mt(t,r,n,e))})}function It(t){let n=t.command("workspace").alias("ws").description("Workspace operations");n.option("-j, --job <job>","Specify job").option("-p, --path <path>","Workspace sub path").action(async(e,r)=>{let{config:o,jenkins:s}=await h(),i=Pe(e.job,r,"workspace"),a=Re(o.job,i),c=String(e.path??"").trim(),l=Tt(`Loading workspace for job "${a}"...`).start(),u=await Rn(s,a,c);if(!u){l.warn(`Workspace not found for job: ${a}. The job may be inside a folder, not run yet, or workspace is disabled.`);return}if(l.succeed(`Workspace loaded for job: ${a}`),!u.length){console.table([{name:"-",type:"-",size:"-",modified:"-",path:"-",url:"-"}]);return}let m=u.map(d=>({name:String(d.name??""),typeRaw:d.type,size:St(d.size),modified:Cn(d.modified),path:Sn(c,String(d.path??d.name??""))})),p=x(m.map(d=>d.name)),b=x(m.map(d=>d.path));console.table(m.map(d=>{let j=W(String(d.name??""),p),I=String(d.typeRaw??"");return {name:I==="dir"?g(w.bold.cyan(j)):I==="file"?g(w.green(j)):g(w.gray(j)),size:d.size,modified:d.modified,path:C(String(d.path??""),b)}}));}),n.command("cat").description("Show file content in workspace").argument("<path>","Workspace file path").option("-j, --job <job>","Specify job").option("-o, --out <file>","Save file to path").option("--open","Open file with default application").action(async(e,r,o)=>{let{config:s,jenkins:i}=await h(),a=Pe(r.job,o,"cat"),c=Re(s.job,a),l=String(e??"").trim();if(!l)throw new f("Path is required.",{hint:'Provide a file path after "cat".',example:"jenkins-cli ws cat dist/index.html"});let u=String(r.out??"").trim(),m=r.open===!0;if(u||m){let b=await An(i,c,l);if(b===null){console.log(w.yellow(`Workspace file not found: ${l} (job: ${c}).`));return}let d=u||L.join(xn.tmpdir(),L.basename(l)||"file");try{u&&await U.pathExists(u)&&(await U.stat(u)).isDirectory()&&(d=L.join(u,L.basename(l)||"file"));}catch{}await U.ensureDir(L.dirname(d)),await U.writeFile(d,b.data),m?($n(d),console.log(w.green(`Opened: ${d}`))):console.log(w.green(`Saved to: ${d}`));return}let p=await Nn(i,c,l);if(p===null){console.log(w.yellow(`Workspace file not found: ${l} (job: ${c}).`));return}process.stdout.write(String(p));}),n.command("wipe").description("Wipe out current workspace").option("-j, --job <job>","Specify job").action(async(e,r)=>{let{config:o,jenkins:s}=await h(),i=Pe(e.job,r,"wipe"),a=Re(o.job,i);try{if(!(await pn.prompt([{type:"confirm",name:"confirm",message:`Wipe workspace for job "${a}"? This cannot be undone.`,default:!1}]))?.confirm){console.log(w.yellow("Cancelled."));return}}catch(l){let u=l?.message?String(l.message):String(l);if((l?.name?String(l.name):"")==="ExitPromptError"||u.toLowerCase().includes("cancelled")||u.toLowerCase().includes("canceled")){console.log(w.yellow("Cancelled."));return}throw l}let c=Tt(`Wiping workspace for job "${a}"...`).start();try{await pt(s,a),c.succeed(`Workspace wiped for job: ${a}`);}catch(l){throw c.fail(`Failed to wipe workspace for job: ${a}`),l}});}function Ot(t){Jt(t),Pt(t),Bt(t),Ft(t),Nt(t),Wt(t),Ct(t),At(t),Ut(t),Et(t),Lt(t),It(t);}program.name("jenkins-cli").description(Fe).version(Be,"-v, --version").helpOption("-h, --help").allowExcessArguments(!1).configureHelp({sortSubcommands:!0,sortOptions:!0}).action(jt);Ot(program);async function Wn(){try{await program.parseAsync(process.argv);}catch(t){B(t);}}Wn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-org/jenkins-cli",
3
- "version": "3.0.4",
3
+ "version": "3.0.5",
4
4
  "description": "Jenkins deployment CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",