@ts-org/jenkins-cli 3.0.3 → 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.
package/README.md CHANGED
@@ -51,6 +51,7 @@ modes:
51
51
  - sit
52
52
  - uat
53
53
  ```
54
+
54
55
  建议在 `jenkins-cli.yaml` 顶部添加 `# yaml-language-server: $schema=https://cdn.jsdelivr.net/npm/@ts-org/jenkins-cli@latest/schemas/jenkins.json`,以有更好的开发体验,如示例。
55
56
 
56
57
  #### 扩展交互参数
@@ -109,19 +110,19 @@ export function validateTicket(input: string) {
109
110
 
110
111
  ### 🤖 命令参考
111
112
 
112
- #### `trigger` (非交互式触发)
113
+ #### `build` (非交互式触发)
113
114
 
114
115
  适用于 CI 或其他脚本化场景。
115
116
 
116
117
  ```bash
117
118
  # 触发 dev 环境构建
118
- jenkins-cli trigger -b origin/develop -m dev
119
+ jenkins-cli build -b origin/develop -m dev
119
120
 
120
121
  # 同时触发多个环境
121
- jenkins-cli trigger -b origin/develop -m dev,sit
122
+ jenkins-cli build -b origin/develop -m dev,sit
122
123
 
123
124
  # 传入额外参数
124
- jenkins-cli trigger -b origin/develop -m dev --param version=1.2.3 --param force=true
125
+ jenkins-cli build -b origin/develop -m dev --param version=1.2.3 --param force=true
125
126
  ```
126
127
 
127
128
  ---
@@ -130,13 +131,70 @@ jenkins-cli trigger -b origin/develop -m dev --param version=1.2.3 --param force
130
131
 
131
132
  ```bash
132
133
  # 查看最近 20 次构建
133
- jenkins-cli builds list
134
+ jenkins-cli builds
134
135
 
135
136
  # 查看运行中的构建
136
- jenkins-cli builds running
137
+ jenkins-cli builds active
137
138
 
138
139
  # 查看 Jenkins 上所有运行中的构建
139
- jenkins-cli builds running -a
140
+ jenkins-cli builds active -a
141
+
142
+ ```
143
+
144
+ #### `changes` - 变更记录
145
+
146
+ ```bash
147
+ # 查看最近 20 次构建的变更记录
148
+ jenkins-cli changes
149
+
150
+ # 查看最近 50 次构建的变更记录
151
+ jenkins-cli changes -n 50
152
+
153
+ # 查看指定构建的变更记录
154
+ jenkins-cli changes 1234
155
+ ```
156
+
157
+ #### `config` - Job 配置
158
+
159
+ ```bash
160
+ # 读取当前 Job 的 XML 配置
161
+ jenkins-cli config show
162
+
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
177
+ ```
178
+
179
+ #### `console` - 查看日志
180
+
181
+ 支持实时日志追踪,默认开启。
182
+
183
+ ```bash
184
+ # 查看指定构建号的日志,如果正在构建则追踪,否则直接输出日志
185
+ jenkins-cli console 1234
186
+
187
+ # 查看最后一次构建日志,如果正在构建则追踪,否则直接输出日志
188
+ jenkins-cli console last
189
+
190
+ # 仅输出当前日志内容,不追踪
191
+ jenkins-cli console last --no-follow
192
+
193
+ # 查看最后一次构建成功日志
194
+ jenkins-cli console last -s success
195
+
196
+ # 查看最后一次构建失败日志
197
+ jenkins-cli console last -s failed
140
198
  ```
141
199
 
142
200
  #### `job` - Job 管理
@@ -149,23 +207,28 @@ jenkins-cli job list --search 'project-*'
149
207
  jenkins-cli job info
150
208
  ```
151
209
 
152
- #### `log` - 查看日志
210
+ #### `me` - 用户信息
153
211
 
154
212
  ```bash
155
- # 查看指定构建号的日志
156
- jenkins-cli log 1234
213
+ # 验证 API Token 并查看当前用户
214
+ jenkins-cli me
215
+ ```
157
216
 
158
- # 查看最后一次构建日志
159
- jenkins-cli log last
217
+ #### `params` - Job 参数
160
218
 
161
- # 查看最后一次构建成功日志
162
- jenkins-cli log last -s success
219
+ ```bash
220
+ # 查看当前 Job 的参数定义
221
+ jenkins-cli params
222
+ ```
163
223
 
164
- # 查看最后一次构建失败日志
165
- jenkins-cli log last -s failed
224
+ #### `queue` - 等待构建队列管理
225
+
226
+ ```bash
227
+ # 查看等待构建的队列
228
+ jenkins-cli queue list
166
229
 
167
- # 仅输出最后 N 行
168
- jenkins-cli log 1234 -t 200
230
+ # 取消一个等待构建队列项
231
+ jenkins-cli queue cancel 5678
169
232
  ```
170
233
 
171
234
  #### `stop` - 停止构建
@@ -181,38 +244,57 @@ jenkins-cli stop -a
181
244
  jenkins-cli stop -A
182
245
  ```
183
246
 
184
- #### `queue` - 等待构建队列管理
247
+ #### `view` - 视图管理
185
248
 
186
249
  ```bash
187
- # 查看等待构建的队列
188
- jenkins-cli queue list
250
+ # 查看所有视图
251
+ jenkins-cli view list
189
252
 
190
- # 取消一个等待构建队列项
191
- jenkins-cli queue cancel 5678
192
- ```
253
+ # 查看视图包含的 Job
254
+ jenkins-cli view show MyView
193
255
 
194
- #### `params` - Job 参数
256
+ # 添加 Job 到视图
257
+ jenkins-cli view add MyView my-job
195
258
 
196
- ```bash
197
- # 查看当前 Job 的参数定义
198
- jenkins-cli params
259
+ # 从视图移除 Job
260
+ jenkins-cli view remove MyView my-job
261
+
262
+ # 创建视图
263
+ jenkins-cli view create MyView
264
+
265
+ # 删除视图
266
+ jenkins-cli view delete MyView
199
267
  ```
200
268
 
201
- #### `config` - Job 配置
269
+ #### `workspace` - 工作区
202
270
 
203
271
  ```bash
204
- # 读取当前 Job XML 配置
205
- jenkins-cli config read
272
+ # 查看当前 Job 的工作区(默认读取 jenkins-cli.yaml 里的 job)
273
+ jenkins-cli ws
206
274
 
207
- # JSON 格式输出
208
- jenkins-cli config read -f json
209
- ```
275
+ # 查看子目录(当前 Job)
276
+ jenkins-cli ws -p dist
210
277
 
211
- #### `whoami` - 用户信息
278
+ # 指定 Job
279
+ jenkins-cli ws -j my-job
212
280
 
213
- ```bash
214
- # 验证 API Token 并查看当前用户
215
- jenkins-cli whoami
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
216
298
  ```
217
299
 
218
300
  ### ❓ FAQ
package/dist/cli.d.ts CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -1,36 +1,42 @@
1
1
  #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import Ye from 'inquirer';
4
- import g from 'chalk';
5
- import We from 'ora';
6
- import { exec } from 'child_process';
7
- import ze, { promisify } from 'util';
8
- import C from 'fs-extra';
9
- import Ne from 'js-yaml';
10
- import S from 'path';
11
- import Fe from 'axios';
12
- import _e from 'jiti';
2
+ import { program, CommanderError } from 'commander';
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';
15
+ import { promises } from 'fs';
14
16
  import { XMLParser } from 'fast-xml-parser';
17
+ import xn from 'os';
15
18
 
16
- var H="3.0.3",Y="Jenkins deployment CLI";var V=promisify(exec);async function z(){try{let{stdout:e}=await V("git branch --show-current"),t=e.trim();if(!t)throw new Error("Not on any branch (detached HEAD state)");return t}catch{throw new Error("Failed to get current branch. Are you in a git repository?")}}async function X(){try{let{stdout:e}=await V('git branch -r --format="%(refname:short)"');return e.split(`
17
- `).filter(t=>t.includes("/")&&!t.includes("HEAD"))}catch{throw new Error("Failed to list branches. Are you in a git repository?")}}var B="jenkins-cli.yaml",T="package.json",U="jenkins-cli",Ee="jenkinsCli";function ee(e,t=process.cwd()){let n=t;for(;;){let r=S.join(n,e);if(C.existsSync(r))return r;let o=S.dirname(n);if(o===n)return null;n=o;}}function Be(e=process.cwd()){return ee(B,e)}function Le(e=process.cwd()){let t=ee(T,e);return t?S.dirname(t):null}function Ie(e){return !!(e.apiToken&&e.job&&Array.isArray(e.modes)&&e.modes.length>0)}async function Z(e){let t=await C.readFile(e,"utf-8"),n=Ne.load(t);if(!n||typeof n!="object")throw new Error(`Invalid config in ${B}: expected a YAML object`);return n}async function qe(e){let t=S.join(e,T);if(!await C.pathExists(t))return {};let n=await C.readFile(t,"utf-8"),r=JSON.parse(n),o=r[U]??r[Ee];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new Error(`Invalid ${T} config: "${U}" must be an object`);return o}async function te(){let e=process.cwd(),t=Le(e)??e,n=S.join(t,B),r={},o=S.dirname(t),a=Be(o);a&&await C.pathExists(a)&&(r=await Z(a));let i=await qe(t);r={...r,...i};let s=await C.pathExists(n)?await Z(n):{};if(r={...r,...s},!Ie(r))throw new Error(`Config incomplete or not found: tried ${B} in project root, "${U}" in $
18
- {PACKAGE_JSON}, and walking up from cwd. Required: apiToken, job, modes (non-empty array)`);return {...r,projectRoot:t}}var D={maxRedirects:0,validateStatus:e=>e>=200&&e<400};function w(e){return `job/${e.split("/").map(n=>n.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function W(e){let t=Array.isArray(e)?e.find(o=>o?.parameters):void 0,n=Array.isArray(t?.parameters)?t.parameters:[],r={};for(let o of n)o?.name&&(r[String(o.name)]=o?.value);return r}function Oe(e){try{let n=new URL(e).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<n.length-1;o++)n[o]==="job"&&n[o+1]&&r.push(decodeURIComponent(n[o+1]));return r.join("/")}catch{return ""}}async function Te(e,t){let r=(await e.axios.get(new URL("api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,actions[parameters[name,value]]",t).toString())).data??{};return {...r,parameters:W(r.actions)}}function Ue(e,t=400){try{let r=(typeof e=="string"?e:JSON.stringify(e??"",null,2)).trim();return r?r.length>t?`${r.slice(0,t)}...`:r:""}catch{return ""}}function re(e){let t=e.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!t)throw new Error("Invalid apiToken format. Expected: http(s)://username:token@host:port");let[,n,r,o,a]=t,i=`${n}://${a.replace(/\/$/,"")}/`,s=Fe.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return {baseURL:i,auth:{username:r,password:o},axios:s,crumbForm:void 0}}async function oe(e,t=5e3){try{let n=await e.axios.get("crumbIssuer/api/json",{timeout:t}),{data:r}=n;r?.crumbRequestField&&r?.crumb&&(e.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,e.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=n.headers["set-cookie"];if(o){let a=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];e.axios.defaults.headers.common.Cookie=a.join("; ");}}catch{}}function M(e){return e.crumbPromise||(e.crumbPromise=oe(e,5e3)),e.crumbPromise}async function _(e){await M(e),e.crumbForm||(e.crumbPromise=oe(e,15e3),await e.crumbPromise);}async function $(e,t){let r=(await e.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(t){let o=t.trim(),a=o.split("/").filter(Boolean).pop();return r.filter(i=>{let s=i.task?.name;return s===o||(a?s===a:!1)})}return r}async function v(e,t){let n=await e.axios.get(`${w(t)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(n.data?.builds)?n.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:W(o.actions)}))}async function L(e){let t=await e.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),n=Array.isArray(t.data?.computer)?t.data.computer:[],r=[];for(let i of n){let s=Array.isArray(i?.executors)?i.executors:[],u=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...s,...u]){let c=l?.currentExecutable;c?.url&&r.push({number:Number(c.number),url:String(c.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 s=await Te(e,i.url),u=Oe(String(s?.url??i.url));return {...s,job:u}}))).filter(i=>i?.building)}async function P(e,t){return await _(e),await e.axios.post("queue/cancelItem",new URLSearchParams({id:t.toString()}),D),!0}async function A(e,t,n){try{await _(e),await e.axios.post(`${w(t)}/${n}/stop/`,new URLSearchParams({}),D);}catch(r){let o=r.response?.status;if(o===403){let a=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(a);console.log(g.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(g.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).":a?`[Hint] Jenkins response: ${a}`:'[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 #${n} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function I(e,t,n){let r="branch",o="mode",a=n[o];a&&console.log(`Checking for conflicting builds for mode: ${a}...`);let[i,s]=await Promise.all([$(e,t),v(e,t)]),u=(m,f)=>{let b=m.actions?.find(R=>R.parameters);return b?b.parameters.find(R=>R.name===f)?.value:void 0},l=n[r];if(a&&l){let m=i.find(f=>u(f,o)===a&&u(f,r)===l);if(m)return new URL(`queue/item/${m.id}/`,e.baseURL).toString()}let c=!1;if(a)for(let m of s)u(m,o)===a&&(console.log(`Stopping running build #${m.number} (mode=${a})...`),await A(e,t,m.number),c=!0);c&&await new Promise(m=>setTimeout(m,1e3));try{return await _(e),(await e.axios.post(`${w(t)}/buildWithParameters/`,new URLSearchParams({...n}),D)).headers.location||""}catch(m){let f=m?.response?.status,b=Ue(m?.response?.data);if(f===400){let y=[];y.push("Hint: Jenkins returned 400. Common causes: job is not parameterized, parameter names do not match, or the job endpoint differs (e.g. multibranch jobs)."),y.push(`Hint: This CLI sends parameters "${r}" and "${o}". Ensure your Jenkins Job has matching parameter names.`);let R=b?`
19
- Jenkins response (snippet):
20
- ${b}`:"";throw new Error(`Request failed with status code 400.${R}
21
- ${y.join(`
22
- `)}`)}if(f){let y=b?`
23
- Jenkins response (snippet):
24
- ${b}`:"";throw new Error(`Request failed with status code ${f}.${y}`)}throw m}}async function ie(e){return (await e.axios.get("whoAmI/api/json")).data}async function se(e){return (await e.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function q(e,t){return (await e.axios.get(`${w(t)}/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}async function ae(e,t,n){let r=Math.max(1,n?.limit??20);return ((await e.axios.get(`${w(t)}/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:W(i.actions)}))}async function ce(e,t,n){let r=await e.axios.get(`${w(t)}/${n}/consoleText`,{responseType:"text"});return String(r.data??"")}async function ue(e,t){return ((await e.axios.get(`${w(t)}/api/json?tree=property[parameterDefinitions[name,type,description,defaultParameterValue[value],choices]]`)).data?.property??[]).flatMap(a=>a?.parameterDefinitions??[]).filter(Boolean).map(a=>({name:a.name,type:a.type,description:a.description,default:a.defaultParameterValue?.value,choices:a.choices}))}async function le(e,t){let n=await e.axios.get(`${w(t)}/config.xml`,{responseType:"text"});return String(n.data??"")}async function p(){let e=We("Loading configuration...").start();try{let t=await te();e.succeed("Configuration loaded");let n=re(t.apiToken);return M(n),{config:t,jenkins:n}}catch(t){e.fail(g.red(t.message)),process.exit(1);}}var Ge=_e(fileURLToPath(import.meta.url),{interopDefault:!0});async function fe(e){return await Promise.resolve(e)}function Ke(e){let t=String(e??"").trim();if(!t)return null;let n=t.split(":");if(n.length<2)return null;if(n.length===2){let[a,i]=n;return !a||!i?null:{file:a,exportName:i}}let r=n.at(-1);if(!r)return null;let o=n.slice(0,-2).join(":");return o?{file:o,exportName:r}:null}function He(e,t){return S.isAbsolute(t)?t:S.join(e,t)}function pe(e){return !!e&&typeof e=="object"&&!Array.isArray(e)}async function N(e,t){let n=Ke(t);if(!n)return null;let r=He(e,n.file);if(!await C.pathExists(r))throw new Error(`configs reference not found: ${n.file}`);let o=Ge(r),a=pe(o)?o:{default:o},i=n.exportName==="default"?a.default:a[n.exportName];if(i===void 0)throw new Error(`configs reference export not found: ${t}`);return {value:i}}async function de(e,t){if(typeof t!="string")return t;let n=await N(e,t);if(!n)return t;if(typeof n.value=="function"){let r=n.value();return await fe(r)}return await fe(n.value)}async function ge(e,t){let n=Array.isArray(e)?e:[];if(n.length===0)return [];let r=String(t.projectRoot??"").trim()||process.cwd(),o=[];for(let a of n){if(!pe(a))continue;let i={...a};if(i.choices!==void 0){i.choices=await de(r,i.choices);let s=String(i.type??"").toLowerCase(),u=i.choices;if((s==="list"||s==="rawlist"||s==="checkbox")&&typeof u!="function"&&!Array.isArray(u))if(u==null)i.choices=[];else if(typeof u=="string"||typeof u=="number"||typeof u=="boolean")i.choices=[String(u)];else if(typeof u[Symbol.iterator]=="function")i.choices=Array.from(u).map(c=>String(c));else throw new Error(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof u})`)}if(i.default!==void 0&&(i.default=await de(r,i.default)),i.when!==void 0){let s=i.when;if(typeof s=="string"){let u=await N(r,s);if(!u)i.when=s;else {if(typeof u.value!="function"&&typeof u.value!="boolean")throw new Error(`when reference must be a function or boolean: ${s}`);i.when=u.value;}}else (typeof s=="function"||typeof s=="boolean")&&(i.when=s);}if(i.validate!==void 0){let s=i.validate;if(typeof s=="string"){let u=await N(r,s);if(!u)i.validate=s;else {if(typeof u.value!="function")throw new Error(`validate reference must be a function: ${s}`);i.validate=u.value;}}else typeof s=="function"&&(i.validate=s);}if(i.filter!==void 0){let s=i.filter;if(typeof s=="string"){let u=await N(r,s);if(!u)i.filter=s;else {if(typeof u.value!="function")throw new Error(`filter reference must be a function: ${s}`);i.filter=u.value;}}else typeof s=="function"&&(i.filter=s);}if(i.transformer!==void 0){let s=i.transformer;if(typeof s=="string"){let u=await N(r,s);if(!u)i.transformer=s;else {if(typeof u.value!="function")throw new Error(`transformer reference must be a function: ${s}`);i.transformer=u.value;}}else typeof s=="function"&&(i.transformer=s);}o.push(i);}return o}function be(e,t){let n=new Set(t),r={};for(let[o,a]of Object.entries(e))if(!n.has(o)&&a!==void 0){if(a===null){r[o]="";continue}if(Array.isArray(a)){r[o]=a.map(i=>String(i)).join(",");continue}if(typeof a=="object"){try{r[o]=JSON.stringify(a);}catch{r[o]=String(a);}continue}r[o]=String(a);}return r}async function ye(){console.log(g.bold.blue(`
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}:
23
+ apiToken: http://user:token@host
24
+ job: my-job
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}:
26
+ apiToken: http://user:token@host
27
+ job: my-job
28
+ modes:
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(`
25
34
  \u{1F680} Jenkins CLI - Jenkins Deployment CLI
26
- `));let{config:e,jenkins:t}=await p(),[n,r]=await Promise.all([X(),z()]),o=()=>{console.log(g.yellow(`
27
- \u{1F44B} Cancelled by user`)),process.exit(130);},a,i={};try{process.prependOnceListener("SIGINT",o);let c=await ge(e.configs,{projectRoot:e.projectRoot}),m=new Set(["branch","modes","mode"]);for(let b of c){let y=String(b?.name??"").trim();if(m.has(y))throw new Error(`configs name "${y}" is reserved. Use another name.`)}let f=await Ye.prompt([{type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:n,default:n.indexOf(r)},{type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:e.modes,validate:b=>b.length===0?"You must select at least one environment":!0},...c]);a={branch:String(f.branch??""),modes:f.modes??[]},i=be(f,["branch","modes"]);}catch(c){let m=c,f=m?.message?String(m.message):String(m);((m?.name?String(m.name):"")==="ExitPromptError"||f.toLowerCase().includes("cancelled")||f.toLowerCase().includes("canceled"))&&(console.log(g.yellow(`
28
- \u{1F44B} Cancelled by user`)),process.exit(0)),console.log(g.red(`
29
- \u274C Prompt failed: ${f}
30
- `)),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let s=!1,u=()=>{s||(s=!0,console.log());},l=a.modes.map(async c=>{let m=We(`Triggering build for ${g.yellow(c)}...`).start();try{let f=await I(t,e.job,{...i,branch:a.branch,mode:c});u(),m.succeed(`${g.green(c)} - Triggered! Queue: ${f}`);}catch(f){throw u(),m.fail(`${g.red(c)} - ${f.message}`),f}});try{await Promise.all(l);}catch{console.log(g.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(`
31
38
  \u274C Some builds failed. Check the output above.
32
- `)),process.exit(1);}}function h(e,t){return (t??"").trim()||e}function x(e,t){let n=Number(e);if(!Number.isInteger(n)||n<0)throw new Error(`${t} must be a non-negative integer`);return n}function we(e){let t=e.command("queue").description("Operations for the build queue");t.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 n=>{let{config:r,jenkins:o}=await p(),a=n.job?h(r.job,n.job):void 0,i=await $(o,a);console.table((i??[]).map(s=>({id:s.id,job:s.task?.name,why:s.why})));}),t.command("cancel").description("Cancel a queued build item").argument("<id>").action(async n=>{let{jenkins:r}=await p(),o=await P(r,x(n,"id"));console.log(o?g.green("Cancelled"):g.red("Cancel failed"));});}function d(e){return {[ze.inspect.custom]:()=>e}}function k(e){let t=String(e??""),n=t.trim();if(!n)return d(g.gray("-"));let r=a=>d(a),o=n.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(n).hostname??"").toLowerCase(),s=i==="localhost"||i==="127.0.0.1"||i==="::1",u=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(s||u?g.cyanBright(t):g.hex("#4EA1FF")(t))}catch{return r(g.hex("#4EA1FF")(t))}return o.startsWith("ws://")||o.startsWith("wss://")?r(g.cyan(t)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(g.magenta(t)):o.startsWith("file://")?r(g.yellow(t)):o.startsWith("mailto:")?r(g.green(t)):o.startsWith("javascript:")||o.startsWith("data:")?r(g.red(t)):n.startsWith("/")||n.startsWith("./")||n.startsWith("../")?r(g.cyan(t)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(n)?r(g.blue(t)):r(t)}function J(e){let t=new Date(e),n=r=>String(r).padStart(2,"0");return `${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}function E(e,t){if(t===!0)return d(g.cyan("BUILDING"));let n=String(e??"").toUpperCase();return d(n?n==="SUCCESS"?g.green(n):n==="ABORTED"?g.gray(n):n==="FAILURE"?g.red(n):n==="UNSTABLE"?g.yellow(n):n==="NOT_BUILT"?g.gray(n):n:"-")}function Q(e){let t=String(e??"");if(!t)return d("-");let n=t.endsWith("_anime"),r=n?t.slice(0,-6):t,o=(()=>{switch(r){case"blue":return n?g.blueBright(t):g.blue(t);case"red":return n?g.redBright(t):g.red(t);case"yellow":return n?g.yellowBright(t):g.yellow(t);case"aborted":return g.gray(t);case"disabled":case"notbuilt":case"grey":case"gray":return g.gray(t);default:return t}})();return d(o)}function Xe(e){let t=Object.entries(e??{}).filter(([r])=>r);if(!t.length)return d("-");t.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"}));let n=t.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(", ");return d(n)}function je(e){let t=e.command("builds").description("Build operations");t.command("list").alias("ls").description("List builds").option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async n=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job),i=await ae(o,a,{limit:Number(n.limit)});console.table(i.map(s=>({number:s.number,result:E(s.result,s.building),building:s.building,durationS:Number((Number(s.duration??0)/1e3).toFixed(3)),date:d(J(Number(s.timestamp??0)))})));}),t.command("running").description("List running builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async n=>{let{config:r,jenkins:o}=await p(),a=n.all?await L(o):await v(o,h(r.job,n.job));console.table((a??[]).map(i=>({...n.all?{job:d(String(i.job??""))}:{},number:i.number,date:d(i.timestamp?J(Number(i.timestamp)):"-"),parameters:Xe(i.parameters),url:k(String(i.url??""))})));});}function xe(e){let t=e.command("log").description("Fetch build console log"),n=async(r,o,a)=>{let{jenkins:i}=await p(),s=await ce(i,r,o);if(a.tail){let u=x(a.tail,"tail"),l=s.split(`
33
- `);console.log(l.slice(Math.max(0,l.length-u)).join(`
34
- `));return}process.stdout.write(s);};t.argument("<id>").option("-j, --job <job>","Specify job").option("-t, --tail <n>","Only output the last N lines").action(async(r,o)=>{let{config:a}=await p(),i=h(a.job,o.job),s=x(r,"id");await n(i,s,o);}),t.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:a}=await p(),i=h(o.job,r.job),s=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(s))throw new Error(`Invalid status: ${r.status}. Use success | failed | any.`);let u=await q(a,i),l=s==="success"?u?.lastSuccessfulBuild:s==="failed"?u?.lastFailedBuild:u?.lastBuild,c=Number(l?.number);if(!c){let m=s==="success"?"successful":s==="failed"?"failed":"last";throw new Error(`No ${m} build found for job: ${i}`)}await n(i,c,r);});}function ke(e){e.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(t,n)=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job);if(n.ALL){let[i,s]=await Promise.all([$(o),L(o)]),u=(i??[]).map(c=>Number(c.id)).filter(c=>!Number.isNaN(c)),l=(s??[]).map(c=>({number:Number(c.number),job:String(c.job??"")})).filter(c=>c.job&&!Number.isNaN(c.number));for(let c of u)await P(o,c);for(let c of l)await A(o,c.job,c.number);console.log(g.green(`Requested: cancelled ${u.length} queue item(s), stopped ${l.length} running build(s).`));return}if(n.all){let[i,s]=await Promise.all([$(o,a),v(o,a)]),u=(i??[]).map(c=>Number(c.id)).filter(c=>!Number.isNaN(c)),l=(s??[]).map(c=>Number(c.number)).filter(c=>!Number.isNaN(c));for(let c of u)await P(o,c);for(let c of l)await A(o,a,c);console.log(g.green(`Requested: cancelled ${u.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!t){console.log(g.red("Missing build id. Provide <id> or use -a/--all."));return}await A(o,a,x(t,"id")),console.log(g.green("Stop requested"));});}function Ce(e){e.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async t=>{let{config:n,jenkins:r}=await p(),o=h(n.job,t.job),a=await ue(r,o),i=Math.max(0,...a.map(s=>String(s?.name??"").length));console.table((a??[]).map(s=>({name:d(String(s?.name??"").padEnd(i," ")),type:d(String(s?.type??"")),description:d(String(s?.description??"")),default:d(s?.default===void 0?"-":String(s.default)),choices:d(Array.isArray(s?.choices)?s.choices.join(", "):s?.choices??"-")})));});}function Se(e){e.command("whoami").description("Show Jenkins user info for the current token").action(async()=>{let{jenkins:t}=await p(),n=await ie(t),r=n&&typeof n=="object"?n:{value:n},o=(l,c)=>{let m=l.length;if(m>=c)return l;let f=c-m,b=Math.floor(f/2),y=f-b;return `${" ".repeat(b)}${l}${" ".repeat(y)}`},a=r.name??r.fullName??r.id??"",i=a==null?"":String(a),s=Math.max(20,i.length),u={};u.name=d(o(i,s));for(let l of Object.keys(r).sort((c,m)=>c.localeCompare(m,"en"))){if(l==="name")continue;let c=r[l],m=l.toLowerCase();if((m==="url"||m.endsWith("url")||m.includes("url"))&&(typeof c=="string"||typeof c=="number")){u[l]=k(String(c));continue}let b=c==null?"":typeof c=="object"?JSON.stringify(c):String(c);u[l]=d(b);}console.table([u]);});}function $e(e){e.command("config").description("Read Jenkins job configuration").command("read").description("Read job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async n=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job),i=String(n.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new Error(`Invalid format: ${n.format}. Expected: xml or json`);let s=await le(o,a);if(i==="xml"){process.stdout.write(s);return}let l=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(s);console.log(JSON.stringify(l,null,2));});}function Je(e){let t=e.command("job").description("Job operations"),n=(r,o)=>{let a=String(o??"").trim();if(!a)return !0;if(!/[*?]/.test(a))return r.includes(a);let u=`^${a.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(u).test(r)}catch{return r.includes(a)}};t.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async r=>{let{jenkins:o}=await p(),a=await se(o),i=(r.search??"").trim(),s=i?a.filter(c=>n(String(c.name??""),i)):a;s.sort((c,m)=>String(c?.name??"").localeCompare(String(m?.name??""),"en",{sensitivity:"base"}));let u=Math.max(0,...s.map(c=>String(c?.name??"").length)),l=Math.max(0,...s.map(c=>String(c?.url??"").length));console.table((s??[]).map(c=>({name:d(String(c.name??"").padEnd(u," ")),color:Q(c.color),url:k(String(c.url??"").padEnd(l," "))})));}),t.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async r=>{let{config:o,jenkins:a}=await p(),i=h(o.job,r.job),s=await q(a,i);if(r.json){console.log(JSON.stringify(s,null,2));return}let u=s?.lastBuild,l=s?.lastCompletedBuild,c=Array.isArray(s?.healthReport)?s.healthReport:[];console.table([{name:d(String(s?.name??"")),url:k(String(s?.url??"")),color:Q(s?.color),buildable:s?.buildable,inQueue:s?.inQueue,nextBuildNumber:s?.nextBuildNumber,healthScore:c[0]?.score??"-",lastBuild:d(u?.number?`#${u.number}`:"-"),lastResult:E(u?.result,u?.building),lastDurationS:u?.duration===void 0?"-":Number((Number(u.duration)/1e3).toFixed(3)),lastDate:d(u?.timestamp?J(Number(u.timestamp)):"-"),lastCompleted:d(l?.number?`#${l.number}`:"-"),lastCompletedResult:E(l?.result,!1),lastCompletedDate:d(l?.timestamp?J(Number(l.timestamp)):"-")}]);});}function tt(e){return e.split(",").map(t=>t.trim()).filter(Boolean)}function nt(e){let t=e.indexOf("=");if(t<=0)throw new Error(`Invalid --param: "${e}". Expected: key=value`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n)throw new Error(`Invalid --param: "${e}". Key is empty`);return {key:n,value:r}}function Re(e){e.command("trigger").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)",(t,n)=>n.concat(tt(t)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(t,n)=>n.concat(t),[]).option("-j, --job <job>","Specify job").action(async t=>{let{config:n,jenkins:r}=await p(),o=h(n.job,t.job),a=String(t.branch??"").trim();if(!a)throw new Error("branch is required");let i=(t.mode??[]).map(String).map(f=>f.trim()).filter(Boolean),s=Array.from(new Set(i));if(s.length===0)throw new Error("mode is required. Example: jenkins-cli trigger -b origin/develop -m dev -m uat");let u={};for(let f of t.param??[]){let{key:b,value:y}=nt(String(f));u[b]=y;}console.log();let l=!1,c=()=>{l||(l=!0,console.log());},m=s.map(async f=>{let b=We(`Triggering build for ${g.yellow(f)}...`).start();try{let y=await I(r,o,{...u,branch:a,mode:f});c(),b.succeed(`${g.green(f)} - Triggered! Queue: ${y}`);}catch(y){throw c(),b.fail(`${g.red(f)} - ${y.message}`),y}});try{await Promise.all(m);}catch{console.log(g.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(`
35
41
  \u274C Some builds failed. Check the output above.
36
- `)),process.exit(1);}});}function ve(e){je(e),$e(e),Je(e),xe(e),Ce(e),we(e),ke(e),Re(e),Se(e);}program.name("jenkins-cli").description(Y).version(H,"-v, --version").helpOption("-h, --help").configureHelp({sortSubcommands:!0,sortOptions:!0}).action(ye);ve(program);program.parse();
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.3",
3
+ "version": "3.0.5",
4
4
  "description": "Jenkins deployment CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -8,13 +8,6 @@
8
8
  "jenkins-cli": "dist/cli.js",
9
9
  "jc": "dist/cli.js"
10
10
  },
11
- "scripts": {
12
- "build": "tsup",
13
- "dev": "NODE_ENV=development tsup --watch",
14
- "prepublishOnly": "npm run build",
15
- "link:test": "npm run build && npm link",
16
- "format": "eslint . --fix && prettier . --write"
17
- },
18
11
  "keywords": [
19
12
  "jenkins",
20
13
  "cli",
@@ -66,5 +59,11 @@
66
59
  "directories": {
67
60
  "doc": "docs"
68
61
  },
69
- "types": "./dist/index.d.ts"
70
- }
62
+ "types": "./dist/index.d.ts",
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "dev": "NODE_ENV=development tsup --watch",
66
+ "link:test": "npm run build && npm link",
67
+ "format": "eslint . --fix && prettier . --write"
68
+ }
69
+ }
@@ -63,4 +63,4 @@
63
63
  },
64
64
  "required": ["apiToken", "job", "modes"],
65
65
  "additionalProperties": false
66
- }
66
+ }