@ts-org/jenkins-cli 3.0.5 → 3.1.0

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
@@ -7,6 +7,7 @@
7
7
  - 交互式 CLI,引导你选择分支和部署环境。
8
8
  - 智能触发,自动停止进行中的构建,并复用队列中相同的任务。
9
9
  - 灵活的参数化构建,支持在运行时传入额外参数。
10
+ - 支持全局 `--debug` 打印 Jenkins 请求信息。
10
11
  - 丰富的命令集,覆盖 Job、Builds、Queue 等常用操作。
11
12
  - 支持 `jenkins-cli.yaml` 或 `package.json` 进行项目级配置。
12
13
 
@@ -42,10 +43,12 @@ CLI 会自动加载配置,列出 Git 分支和部署环境供你选择。
42
43
  # Jenkins API 地址,格式: http(s)://username:token@host:port
43
44
  apiToken: http://user:token@jenkins.example.com
44
45
 
45
- # Jenkins Job 名称 (可被 -j 参数覆盖)
46
+ # Jenkins Job 名称 (可被 -j 参数覆盖,也可用函数引用)
46
47
  job: your-project-job
47
48
 
48
- # 部署环境列表 (将作为参数 `mode` 传入 Jenkins)
49
+ # 部署环境列表 (将作为参数 `mode` 传入 Jenkins,也可用函数引用)
50
+ # 选项要与Jenkins配置的对上
51
+ # 这里配置了Jenkins上没有的,比如prod,那么在提交mode = prod时会报500
49
52
  modes:
50
53
  - dev
51
54
  - sit
@@ -54,6 +57,29 @@ modes:
54
57
 
55
58
  建议在 `jenkins-cli.yaml` 顶部添加 `# yaml-language-server: $schema=https://cdn.jsdelivr.net/npm/@ts-org/jenkins-cli@latest/schemas/jenkins.json`,以有更好的开发体验,如示例。
56
59
 
60
+ #### 动态 job / modes
61
+
62
+ `job` 和 `modes` 支持函数引用(`path:exportName`),函数会收到 `answers` 参数,返回最终值。
63
+
64
+ 示例:
65
+
66
+ ```yaml
67
+ job: jenkins-utils.ts:dynamicJob
68
+ modes: jenkins-utils.ts:dynamicModes
69
+ ```
70
+
71
+ ```ts
72
+ export function dynamicJob(answers: Record<string, unknown>) {
73
+ return answers.isElectron ? 'remote-client-web' : 'remote-web-order'
74
+ }
75
+
76
+ export function dynamicModes(answers: Record<string, unknown>) {
77
+ return Number(answers.buildNumber) > 100
78
+ ? ['dev', 'sit', 'uat', 'prod']
79
+ : ['dev', 'sit', 'uat']
80
+ }
81
+ ```
82
+
57
83
  #### 扩展交互参数
58
84
 
59
85
  通过 `configs` 字段,你可以添加自定义的交互式提问,其结果将作为参数传递给 Jenkins。
@@ -61,12 +87,19 @@ modes:
61
87
  - `type`: 支持 `input`, `number`, `confirm`, `list`, `rawlist`, `checkbox`, `password`等类型。
62
88
  - `choices`, `default`, `validate`, `when`, `filter`, `transformer`: 支持从本地 TS/JS 文件动态加载。
63
89
  - `path:exportName`:自动判断并使用导出值;如果是函数则调用 (支持 async)。
90
+ - `offset`: 负数可调整提问顺序
91
+ - `-1`:插到 branch 后、modes 前
92
+ - `<= -2`:插到 branch 前
64
93
  - `name`: 参数名,注意不要使用 `branch`, `mode`, `modes` 等保留字。
65
94
 
66
95
  **示例:**
67
96
 
68
97
  ```yaml
69
98
  configs:
99
+ - type: number
100
+ name: buildNumber
101
+ message: '请选择构建号:'
102
+ offset: -2
70
103
  - type: input
71
104
  name: version
72
105
  message: '请输入版本号:'
@@ -77,6 +110,10 @@ configs:
77
110
  name: service
78
111
  message: '请选择服务:'
79
112
  choices: src/config.ts:getServices
113
+ - type: confirm
114
+ name: smokeTest
115
+ message: '是否开启冒烟测试?'
116
+ when: src/config.ts:whenSmokeTest
80
117
  - type: input
81
118
  name: ticket
82
119
  message: '请输入关联的工单号:'
@@ -90,20 +127,50 @@ export async function getServices() {
90
127
  return ['user-center', 'order-service']
91
128
  }
92
129
 
93
- export function filterVersion(input: string) {
130
+ export function filterVersion(input: unknown, answers: Record<string, unknown>) {
94
131
  return String(input ?? '').trim()
95
132
  }
96
133
 
97
- export function transformVersion(input: string) {
134
+ export function transformVersion(
135
+ input: unknown,
136
+ answers: Record<string, unknown>,
137
+ meta: { isFinal?: boolean },
138
+ ) {
98
139
  const value = String(input ?? '')
99
140
  return value ? `v${value}` : value
100
141
  }
101
142
 
102
- export function validateTicket(input: string) {
143
+ export function whenSmokeTest(answers: { mode?: string }) {
144
+ return answers.mode !== 'prod'
145
+ }
146
+
147
+ export function validateTicket(input: unknown, answers: Record<string, unknown>) {
103
148
  return /^(feat|fix|refactor)-[a-zA-Z0-9]+$/.test(input) || '工单号格式不正确'
104
149
  }
105
150
  ```
106
151
 
152
+ **四个函数的完整入参说明**:
153
+
154
+ - `when(answers)`
155
+ - `answers`: 当前已回答的所有答案对象(键为问题的 `name`)。
156
+ - 返回 `boolean | Promise<boolean>`,用于决定是否显示该问题。
157
+
158
+ - `validate(input, answers)`
159
+ - `input`: 用户当前输入的原始值。
160
+ - `answers`: 当前已回答的所有答案对象。
161
+ - 返回 `true` 表示通过;返回 `string` 作为错误提示;也可返回 `Promise<true | string>`。
162
+
163
+ - `filter(input, answers)`
164
+ - `input`: 用户当前输入的原始值。
165
+ - `answers`: 当前已回答的所有答案对象。
166
+ - 返回转换后的值(可同步或返回 Promise)。
167
+
168
+ - `transformer(input, answers, meta)`
169
+ - `input`: 用户当前输入的原始值。
170
+ - `answers`: 当前已回答的所有答案对象。
171
+ - `meta`: 渲染相关的元信息(例如 `isFinal`),不同版本可能略有差异。
172
+ - 返回显示用的字符串,不会修改answers的值(可同步或返回 Promise)。
173
+
107
174
  > **提示**: 配置也支持写在 `package.json` 的 `jenkins-cli` 字段里。
108
175
  >
109
176
  > **查找顺序**: `jenkins-cli.yaml` > `package.json` > 祖先目录的 `jenkins-cli.yaml`。
@@ -125,6 +192,9 @@ jenkins-cli build -b origin/develop -m dev,sit
125
192
  jenkins-cli build -b origin/develop -m dev --param version=1.2.3 --param force=true
126
193
  ```
127
194
 
195
+ 说明:默认会读取 `git config user.name` 并自动追加参数 `triggered_by`。
196
+ 如需覆盖,可显式传入 `--param triggered_by=YourName`。
197
+
128
198
  ---
129
199
 
130
200
  #### `builds` - 构建管理
@@ -259,6 +329,9 @@ jenkins-cli view add MyView my-job
259
329
  # 从视图移除 Job
260
330
  jenkins-cli view remove MyView my-job
261
331
 
332
+ # 编辑视图中的 Job(勾选/取消)
333
+ jenkins-cli view edit MyView
334
+
262
335
  # 创建视图
263
336
  jenkins-cli view create MyView
264
337
 
package/dist/cli.js CHANGED
@@ -1,42 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  import { program, CommanderError } from 'commander';
3
- import pn from 'inquirer';
4
- import w from 'chalk';
5
- import Tt from 'ora';
3
+ import oe from 'inquirer';
4
+ import y from 'chalk';
5
+ import Qt from 'ora';
6
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';
7
+ import Jn, { promisify } from 'util';
8
+ import M from 'fs-extra';
9
+ import sn from 'js-yaml';
10
+ import z from 'path';
11
+ import pn from 'axios';
12
12
  import { Buffer } from 'buffer';
13
- import an from 'jiti';
13
+ import kn from 'jiti';
14
14
  import { fileURLToPath } from 'url';
15
15
  import { promises } from 'fs';
16
16
  import { XMLParser } from 'fast-xml-parser';
17
- import xn from 'os';
17
+ import En from 'os';
18
18
 
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(`
19
+ var Ye="3.1.0",Xe="Jenkins deployment CLI";var d=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 nn(t){return t instanceof d?t:t instanceof CommanderError?new d(t.message,{hint:"Check the command usage and options.",example:"jenkins-cli --help",exitCode:t.exitCode??1}):t instanceof Error?new d(t.message,{hint:"Check your input and try again.",example:"jenkins-cli --help"}):new d("Unknown error",{example:"jenkins-cli --help"})}function q(t){let n=nn(t);if(console.error(y.red(`
20
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
+ `)),n.details&&console.error(y.gray(n.details)),n.hint&&console.error(y.yellow(`Hint: ${n.hint}`)),n.example!==""){let e=n.example??"jenkins-cli --help";console.error(y.cyan(`Example: ${e}`));}console.error(y.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=n.exitCode;}var ve=promisify(exec);async function Ze(){try{let{stdout:t}=await ve("git branch --show-current"),n=t.trim();if(!n)throw new d("Not on any branch (detached HEAD state).",{hint:"Checkout a branch before running this command.",example:"git checkout main"});return n}catch{throw new d("Failed to get current branch.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function et(){try{let{stdout:t}=await ve('git branch -r --format="%(refname:short)"');return t.split(`
22
+ `).filter(n=>n.includes("/")&&!n.includes("HEAD"))}catch{throw new d("Failed to list branches.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function ce(){try{let{stdout:t}=await ve("git config user.name"),n=t.trim();return n||void 0}catch{return}}var D="jenkins-cli.yaml",ue="package.json",le="jenkins-cli",an="jenkinsCli";function nt(t,n=process.cwd()){let e=n;for(;;){let r=z.join(e,t);if(M.existsSync(r))return r;let o=z.dirname(e);if(o===e)return null;e=o;}}function cn(t=process.cwd()){return nt(D,t)}function ln(t=process.cwd()){let n=nt(ue,t);return n?z.dirname(n):null}function un(t){let n=Array.isArray(t.modes)&&t.modes.length>0||typeof t.modes=="string";return !!(t.apiToken&&t.job&&n)}async function tt(t){let n=await M.readFile(t,"utf-8"),e=sn.load(n);if(!e||typeof e!="object")throw new d(`Invalid config in ${D}. Expected a YAML object.`,{hint:"Top-level config must be key/value pairs.",example:`${D}:
23
23
  apiToken: http://user:token@host
24
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}:
25
+ modes: [dev]`});return e}async function mn(t){let n=z.join(t,ue);if(!await M.pathExists(n))return {};let e=await M.readFile(n,"utf-8"),r=JSON.parse(e),o=r[le]??r[an];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new d(`Invalid ${ue} config: "${le}" must be an object.`,{hint:"Use an object for the config section.",example:`"${le}": { "apiToken": "http://user:token@host", "job": "my-job", "modes": ["dev"] }`});return o}async function rt(){let t=process.cwd(),n=ln(t)??t,e=z.join(n,D),r={},o=z.dirname(n),s=cn(o);s&&await M.pathExists(s)&&(r=await tt(s));let i=await mn(n);r={...r,...i};let a=await M.pathExists(e)?await tt(e):{};if(r={...r,...a},!un(r))throw new d("Config incomplete or not found.",{hint:`Tried ${D} in project root, "${le}" in ${ue}, and walking up from cwd. Required: apiToken, job, modes (non-empty array).`,example:`${D}:
26
26
  apiToken: http://user:token@host
27
27
  job: my-job
28
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(`
29
+ - dev`});return {...r,projectRoot:n}}var W={maxRedirects:0,validateStatus:t=>t>=200&&t<400};function x(t){return `job/${t.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function pe(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 ot(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 fn(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:pe(r.actions)}}function it(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 X(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 Z(t){let n=X(t);if(n!==void 0)return n;if(typeof t=="string"){let e=Date.parse(t);if(!Number.isNaN(e))return e}}function N(t){return t.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/")}function Ne(t,n){let e=t.replace(/\/+$/,""),r=n.replace(/^\/+/,"");return /^https?:\/\//i.test(e)?new URL(`${r}`,`${e}/`).toString():`${e}/${r}`}function _(t){return t.replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'")}function me(t){return t.replace(/<[^>]*>/g,"")}function dn(t){return /<!doctype\s+html|<html\b|<body\b/i.test(t)}function gn(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 _(me(s))}function hn(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)],l="",c="";for(let $ of a){let O=$[1]??"",F=_(me($[2]??"")).trim();if(!(!F||F==="..")&&!/all\s+files\s+in\s+zip/i.test(F)){l=O,c=F;break}}if(!l||!c||l==="../"||l==="..")continue;let u=/class="[^"]*folder[^"]*"/i.test(i)||l.endsWith("/")?"dir":"file",p=_(l.split("?")[0]??"").replace(/\/+$/,"")||c,m=i.match(/class="last-modified"[^>]*>([\s\S]*?)<\/td>/i),f=m?_(me(m[1]??"")).trim():"",g=f?Z(f):void 0,w=`${c}|${p}`;r.has(w)||(r.add(w),e.push({name:c,path:p,type:u,modified:g}));}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=_(me(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 l=i.endsWith("/")?"dir":"file",c=_(i.split("?")[0]??"").replace(/\/+$/,"")||a,u=`${a}|${c}`;r.has(u)||(r.add(u),e.push({name:a,path:c,type:l}));}return e}async function Ae(t,n,e){let r=Ne(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:"*/*"}}),l=a.data??new ArrayBuffer(0),c=Buffer.from(l);if(!c.length)continue;let u=a.headers?.["content-type"];return {data:c,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 Be(t,n,e){let r=Ne(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,*/*"}}),l=typeof a.data=="string"?a.data:String(a.data??"");if(!l)continue;if(dn(l)){let c=gn(l);if(c.trim())return c;continue}return l}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function We(t,n,e){let r=Ne(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 c=(await t.axios.get(a,{headers:{Accept:"application/json"}})).data;if(typeof c=="string")try{c=JSON.parse(c);}catch{continue}if(c&&typeof c=="object")return c}catch(l){if(i=l,l?.response?.status===404)continue;throw l}try{let a=await t.axios.get(o,{headers:{Accept:"text/html"}});if(typeof a.data=="string"){let l=hn(a.data);if(l.length)return {children:l}}}catch(a){i=a;}throw i||new Error("Workspace listing not found")}function bn(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 Ee(t){return bn(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,l=(()=>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")(),c=X(e?.size)??X(e?.length)??X(e?.fileSize)??X(e?.bytes)??void 0,u=Z(e?.lastModified)??Z(e?.modified)??Z(e?.mtime)??Z(e?.timestamp)??void 0,p=String(e?.href??e?.url??e?.link??"").trim()||void 0;return {name:i,path:a,url:p,size:c,modified:u,type:l}})}function st(t){let n=t.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!n)throw new d("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=pn.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return process.argv.includes("--debug")&&a.interceptors.request.use(c=>{let u=String(c.method??"get").toUpperCase(),p=new URL(String(c.url??""),c.baseURL??i).toString(),m=c.params,f=c.data;f instanceof URLSearchParams?f=Object.fromEntries(f):typeof f=="string"?String(c.headers?.["Content-Type"]??c.headers?.["content-type"]??"").includes("application/x-www-form-urlencoded")?f=Object.fromEntries(new URLSearchParams(f)):f=f.trim()?f:void 0:Buffer.isBuffer(f)&&(f=`[Buffer ${f.length} bytes]`);let g={method:u,url:p};return m&&Object.keys(m).length>0&&(g.params=m),f!=null&&f!==""&&(g.data=f),console.log(y.cyan("[Jenkins Debug] Request")),console.log(JSON.stringify(g,null,2)),c}),{baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function at(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 Ue(t){return t.crumbPromise||(t.crumbPromise=at(t,5e3)),t.crumbPromise}async function E(t){await Ue(t),t.crumbForm||(t.crumbPromise=at(t,15e3),await t.crumbPromise);}async function H(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 ee(t,n){let e=await t.axios.get(`${x(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:pe(o.actions)}))}async function fe(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:[],l=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let c of [...a,...l]){let u=c?.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 fn(t,i.url),l=ot(String(a?.url??i.url));return {...a,job:l}}))).filter(i=>i?.building)}async function te(t,n){return await E(t),await t.axios.post("queue/cancelItem",new URLSearchParams({id:n.toString()}),W),!0}async function ne(t,n,e){try{await E(t),await t.axios.post(`${x(n)}/${e}/stop/`,new URLSearchParams({}),W);}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(y.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(y.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 Fe(t,n,e){await E(t);let r=`view/${encodeURIComponent(n)}/addJobToView`;try{await t.axios.post(r,new URLSearchParams({name:e}),W);}catch(o){let s=o?.response?.status;throw s===404?new d(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new d(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function Le(t,n,e){await E(t);let r=`view/${encodeURIComponent(n)}/removeJobFromView`;try{await t.axios.post(r,new URLSearchParams({name:e}),W);}catch(o){let s=o?.response?.status;throw s===404?new d(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new d(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function ct(t,n){await E(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,W);}catch(r){let o=r?.response?.status;throw o===400?new d(`View already exists: ${n}`,{hint:'Use "jenkins-cli view list" to see existing views.'}):o===403?new d(`Forbidden to create view: ${n}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Create".'}):r}}async function lt(t,n){await E(t);let e=`view/${encodeURIComponent(n)}/doDelete`;try{await t.axios.post(e,new URLSearchParams({}),W);}catch(r){let o=r?.response?.status;throw o===404?new d(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".'}):o===403?new d(`Forbidden to delete view: ${n}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Delete".'}):r}}async function de(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([H(t,n),ee(t,n)]),l=(p,m)=>{let f=p.actions?.find(w=>w.parameters);return f?f.parameters.find(w=>w.name===m)?.value:void 0},c=e[r];if(s&&c){let p=i.find(m=>l(m,o)===s&&l(m,r)===c);if(p)return new URL(`queue/item/${p.id}/`,t.baseURL).toString()}let u=!1;if(s)for(let p of a)l(p,o)===s&&(console.log(`Stopping running build #${p.number} (mode=${s})...`),await ne(t,n,p.number),u=!0);u&&await new Promise(p=>setTimeout(p,1e3));try{return await E(t),(await t.axios.post(`${x(n)}/buildWithParameters/`,new URLSearchParams({...e}),W)).headers.location||""}catch(p){let m=p?.response?.status,f=it(p?.response?.data);if(m===400){let g=f?`Jenkins response (snippet):
31
+ ${f}`:void 0;throw new d("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:g})}if(m){let g=f?`Jenkins response (snippet):
32
+ ${f}`:void 0;throw new d(`Request failed with status code ${m}.`,{hint:"Check Jenkins job permissions and parameters.",example:"jenkins-cli me",details:g})}throw p}}async function ut(t){return (await t.axios.get("whoAmI/api/json")).data}async function L(t){return (await t.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function mt(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:[],l=[],c=[...a];for(;c.length;){let u=c.shift();if(!u)continue;let p=String(u.name??"").trim();if(p&&p===r&&u.url){let m=ot(String(u.url));m&&l.push(m);}Array.isArray(u.jobs)&&c.push(...u.jobs);}if(l.length)return l[0]}async function ge(t,n){try{let r=(await t.axios.get(`${x(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 d(`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 d(`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 d(`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 pt(t,n,e){let r=Math.max(1,e?.limit??20);return ((await t.axios.get(`${x(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:pe(i.actions)}))}async function ft(t,n,e){let r=Math.max(1,e?.limit??20);return ((await t.axios.get(`${x(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 he(t,n,e){let o=(await t.axios.get(`${x(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:pe(o.actions)}}async function dt(t,n,e){let r=await t.axios.get(`${x(n)}/${e}/consoleText`,{responseType:"text"});return String(r.data??"")}async function gt(t,n){return ((await t.axios.get(`${x(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 Te(t,n,e){let r=String(e?.path??"").trim(),o=r?`${N(r)}/`:"",s=await We(t,x(n),o);return Ee(s??{})}async function ht(t,n,e,r){let o=String(r?.path??"").trim(),s=o?`${N(o)}/`:"",i=`view/${encodeURIComponent(n)}/${x(e)}`,a=await We(t,i,s);return Ee(a??{})}async function bt(t,n,e,r){let o=String(r?.path??"").trim(),s=o?`${N(o)}/`:"",i=new URL(`${x(e)}/`,n).toString(),a=await We(t,i,s);return Ee(a??{})}async function wt(t,n,e){let r=N(String(e??"").trim());return await Be(t,x(n),r)}async function yt(t,n,e){let r=N(String(e??"").trim());return await Ae(t,x(n),r)}async function kt(t,n,e,r){let o=N(String(r??"").trim()),s=`view/${encodeURIComponent(n)}/${x(e)}`;return await Be(t,s,o)}async function xt(t,n,e,r){let o=N(String(r??"").trim()),s=`view/${encodeURIComponent(n)}/${x(e)}`;return await Ae(t,s,o)}async function jt(t,n,e,r){let o=N(String(r??"").trim()),s=new URL(`${x(e)}/`,n).toString();return await Be(t,s,o)}async function Ct(t,n,e,r){let o=N(String(r??"").trim()),s=new URL(`${x(e)}/`,n).toString();return await Ae(t,s,o)}async function St(t,n){try{return await E(t),await t.axios.post(`${x(n)}/doWipeOutWorkspace`,new URLSearchParams({}),W),!0}catch(e){let r=e?.response?.status;if(r){let o=it(e?.response?.data);throw new d(`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 Ve(t,n){let e=await t.axios.get(`${x(n)}/config.xml`,{responseType:"text"});return String(e.data??"")}async function $t(t,n,e,r){let o=`${x(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??""),l=i.headers["x-text-size"],c=i.headers["x-more-data"],u=l?Number(l):r+Buffer.byteLength(a);return {text:a,newOffset:u,hasMoreData:c==="true"}}async function re(t,n){let e=n?.raw?"views[*]":"views[name,url]";return (await t.axios.get(`api/json?tree=${e}`)).data.views??[]}async function Q(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 d(`View not found: ${n}`,{hint:'Check the view name using "jenkins-cli view list".',example:"jenkins-cli view show MyView"}):r}}async function Jt(t,n){let e=String(n??"").trim();if(!e)return;let r=e.split("/").filter(Boolean).pop()??e,o=await re(t,{raw:!1});for(let s of o){let i=String(s?.name??"").trim();if(i)try{if((await Q(t,i)).some(l=>{let c=String(l?.name??"").trim();return c===e||c===r}))return i}catch{}}}async function b(){let t=Qt("Loading configuration...").start();try{let n=await rt();t.succeed("Configuration loaded");let e=st(n.apiToken);return Ue(e),{config:n,jenkins:e}}catch(n){q(n),process.exit(1);}}var jn=kn(fileURLToPath(import.meta.url),{interopDefault:!0});async function we(t){return await Promise.resolve(t)}function Cn(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 Sn(t,n){return z.isAbsolute(n)?n:z.join(t,n)}function Rt(t){return !!t&&typeof t=="object"&&!Array.isArray(t)}async function Oe(t,n){let e=Cn(n);if(!e)return null;let r=Sn(t,e.file);if(!await M.pathExists(r))throw new d(`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=jn(r),s=Rt(o)?o:{default:o},i=e.exportName==="default"?s.default:s[e.exportName];if(i===void 0)throw new d(`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 be(t,n,e){if(typeof n!="string")return n;let r=await Oe(t,n);if(!r)return n;if(!e.allow(r.value))throw new d(e.error(n),{hint:e.hint,example:e.example});return r.value}async function Pt(t,n){if(typeof n!="string")return n;let e=await Oe(t,n);if(!e)return n;if(typeof e.value=="function"){let r=e.value();return await we(r)}return await we(e.value)}async function Ie(t,n,e){if(typeof n!="string")return n;let r=await Oe(t,n);if(!r)return n;if(typeof r.value=="function"){let o=r.value(e);return await we(o)}return await we(r.value)}async function Nt(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(!Rt(s))continue;let i={...s};if(i.choices!==void 0){i.choices=await Pt(r,i.choices);let a=String(i.type??"").toLowerCase(),l=i.choices;if((a==="list"||a==="rawlist"||a==="checkbox")&&typeof l!="function"&&!Array.isArray(l))if(l==null)i.choices=[];else if(typeof l=="string"||typeof l=="number"||typeof l=="boolean")i.choices=[String(l)];else if(typeof l[Symbol.iterator]=="function")i.choices=Array.from(l).map(u=>String(u));else throw new d(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof l}).`,{hint:"Return an array for list/rawlist/checkbox choices.",example:'export const choices = ["dev", "uat"]'})}i.default!==void 0&&(i.default=await Pt(r,i.default)),i.when!==void 0&&(i.when=await be(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 be(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 be(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 be(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 At(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 Bt(){console.log(y.bold.blue(`
34
34
  \u{1F680} Jenkins CLI - Jenkins Deployment CLI
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(`
35
+ `));let{config:t,jenkins:n}=await b(),[e,r]=await Promise.all([et(),Ze()]),o=()=>{console.log(y.yellow(`
36
+ \u{1F44B} Cancelled by user`)),process.exit(130);},s,i=t.job,a={};try{process.prependOnceListener("SIGINT",o);let f=await Nt(t.configs,{projectRoot:t.projectRoot}),g=new Set(["branch","modes","mode","triggered_by"]);for(let S of f){let I=String(S?.name??"").trim();if(g.has(I))throw new d(`configs name "${I}" is reserved.`,{hint:"Use another name in your extra prompt config.",example:"name: env"})}let w={type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:e,default:e.indexOf(r)},$=[],O=[],F=[];for(let S of f){let I=Number(S.offset);if(Number.isFinite(I)&&I<=-2){$.push(S);continue}if(I===-1){O.push(S);continue}F.push(S);}let C={};Object.assign(C,await oe.prompt($,C)),Object.assign(C,await oe.prompt([w],C)),Object.assign(C,await oe.prompt(O,C));let Qe=String(t.projectRoot??"").trim()||process.cwd(),G=await Ie(Qe,t.modes,C),K=[];if(Array.isArray(G))K=G.map(S=>String(S).trim()).filter(Boolean);else if(G!=null){let S=String(G).trim();S&&(K=[S]);}K.length===0&&Array.isArray(t.modes)&&(K=t.modes);let Zt={type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:K,validate:S=>S.length===0?"You must select at least one environment":!0};Object.assign(C,await oe.prompt([Zt],C)),Object.assign(C,await oe.prompt(F,C)),s={branch:String(C.branch??""),modes:C.modes??[]},a=At(C,["branch","modes"]);let en=await Ie(Qe,t.job,C),Ge=String(en??"").trim();Ge&&(i=Ge);}catch(f){let g=f,w=g?.message?String(g.message):String(g),$=g?.name?String(g.name):"";($==="ExitPromptError"||w.toLowerCase().includes("cancelled")||w.toLowerCase().includes("canceled"))&&(console.log(y.yellow(`
37
+ \u{1F44B} Cancelled by user`)),process.exit(0)),q(new d(`Prompt failed: ${w}`,{hint:$?`Error: ${$}`:""})),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let l=!1,c=()=>{l||(l=!0,console.log());},u=await ce();u&&!("triggered_by"in a)&&(a.triggered_by=u);let m=s.modes.map(async f=>{let g=Qt(`Triggering build for ${y.yellow(f)}...`).start();try{let w=await de(n,i,{...a,branch:s.branch,mode:f});c(),g.succeed(`${y.green(f)} - Triggered! Queue: ${w}`);}catch(w){throw c(),g.fail(`${y.red(f)} - ${w.message}`),w}});try{await Promise.all(m);}catch{console.log(y.bold.red(`
38
38
  \u274C Some builds failed. Check the output above.
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(`
39
+ `)),process.exit(1);}}function k(t,n){return (n??"").trim()||t}function A(t,n){let e=Number(t);if(!Number.isInteger(e)||e<0)throw new d(`${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 ye(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 Wt(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 b(),s=e.job?k(r.job,e.job):void 0,i=await H(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 b(),o=Array.isArray(e)?e:[String(e??"")],s=await Promise.all(o.map(async a=>{let l=A(String(a),"id");try{return await te(r,l),{id:l,ok:!0}}catch(c){return {id:l,ok:!1,message:String(c?.message??c)}}})),i=s.filter(a=>!a.ok);if(i.length===0){console.log(y.green(`Cancelled ${s.length} queue item(s).`));return}console.log(y.yellow(`Cancelled ${s.length-i.length} item(s), failed ${i.length} item(s).`));for(let a of i)console.log(y.red(`- ${a.id}: ${a.message??"Cancel failed"}`));});}function h(t){return {[Jn.inspect.custom]:()=>t}}function U(t,n){return String(t??"").padEnd(n," ")}function j(t){return Math.max(0,...t.map(n=>String(n??"").length))}function J(t,n){return h(U(t,n))}function v(t){let n=String(t??""),e=n.trim();if(!e)return h(y.gray("-"));let r=s=>h(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",l=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(a||l?y.cyanBright(n):y.hex("#4EA1FF")(n))}catch{return r(y.hex("#4EA1FF")(n))}return o.startsWith("ws://")||o.startsWith("wss://")?r(y.cyan(n)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(y.magenta(n)):o.startsWith("file://")?r(y.yellow(n)):o.startsWith("mailto:")?r(y.green(n)):o.startsWith("javascript:")||o.startsWith("data:")?r(y.red(n)):e.startsWith("/")||e.startsWith("./")||e.startsWith("../")?r(y.cyan(n)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(e)?r(y.blue(n)):r(n)}function P(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 ie(t,n){if(n===!0)return h(y.cyan("BUILDING"));let e=String(t??"").toUpperCase();return h(e?e==="SUCCESS"?y.green(e):e==="ABORTED"?y.gray(e):e==="FAILURE"?y.red(e):e==="UNSTABLE"?y.yellow(e):e==="NOT_BUILT"?y.gray(e):e:"-")}function se(t){let n=String(t??"");if(!n)return h("-");let e=n.endsWith("_anime"),r=e?n.slice(0,-6):n,o=(()=>{switch(r){case"blue":return e?y.blueBright(n):y.blue(n);case"red":return e?y.redBright(n):y.red(n);case"yellow":return e?y.yellowBright(n):y.yellow(n);case"aborted":return y.gray(n);case"disabled":case"notbuilt":case"grey":case"gray":return y.gray(n);default:return n}})();return h(o)}function Et(t){let n=Number(t);if(!Number.isFinite(n)||n<0)return h("-");if(n<1024)return h(`${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 h(`${s} ${e[o]}`)}function ke(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 Ut(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 Ft(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 b(),s=e.job??ke("builds")??ke(),i=k(r.job,s),l=(await pt(o,i,{limit:Number(e.limit)})).map(u=>({number:u.number,result:ie(u.result,u.building),building:u.building,"duration(s)":Number((Number(u.duration??0)/1e3).toFixed(3)),date:h(P(Number(u.timestamp??0))),parameters:Ut(u.parameters),url:v(String(u.url??""))})),c=j(l.map(u=>u.parameters));console.table(l.map(u=>({...u,parameters:J(u.parameters,c)})));}),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 b(),s=e.job??ke("active")??ke("builds"),a=((e.all?await fe(o):await ee(o,k(r.job,s)))??[]).map(c=>({...e.all?{job:h(String(c.job??""))}:{},number:c.number,date:h(c.timestamp?P(Number(c.timestamp)):"-"),parameters:Ut(c.parameters),url:v(String(c.url??""))})),l=j(a.map(c=>c.parameters));console.table(a.map(c=>({...c,parameters:J(c.parameters,l)})));});}function vn(t){let n=String(t?.authorEmail??"").trim(),e=n?n.split("@")[0]??"":"";return e||n}function Lt(t){let n=[];for(let e of t){let r=Number(e?.number),o=Number.isInteger(r)?`#${r}`:h("-"),s=e?.timestamp?P(Number(e.timestamp)):"-",i=e?.changeSet?.items??[];if(!i.length){n.push({build:o,date:h(s),author:h("-"),message:h("-")});continue}for(let a of i){let l=vn(a),c=String(a?.msg??"").trim();n.push({build:o,date:h(s),author:h(l||"-"),message:h(c||"-")});}}return n}function Tt(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 b(),s=k(r.job,e.job);if(n){let l=A(n,"id"),c=await he(o,s,l);if(e.raw){console.log(JSON.stringify({build:c.number,changeSet:c.changeSet??{}},null,2));return}console.table(Lt([c]));return}let i=Math.max(1,A(e.limit,"limit")),a=await ft(o,s,{limit:i});if(e.raw){console.log(JSON.stringify(a.map(l=>({build:l.number,changeSet:l.changeSet??{}})),null,2));return}console.table(Lt(a));});}function Vt(){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 Ot(t){let n=t.command("console").description("Fetch build console log"),e=async(r,o,s,i)=>{if(!i.follow){let c=await dt(r,o,s);process.stdout.write(c);return}let a=0,l=!0;for(console.log(y.blue(`--- Following log for build #${s} ---`));;)try{let{text:c,newOffset:u,hasMoreData:p}=await $t(r,o,s,a);if(c.length>0&&(process.stdout.write(c),a=u),l&&c.length>0&&(l=!1),c.length>0&&p)continue;if(!p){let f=(await he(r,o,s)).result||"UNKNOWN",g=f==="SUCCESS"?y.green:y.red;console.log(g(`
40
+ --- Build Finished: ${f} ---`));break}await new Promise(m=>setTimeout(m,1e3));}catch{await new Promise(c=>setTimeout(c,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 b(),a=o.job??Vt();if(a==="")throw new d("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console 123 -j my-job"});let l=k(s.job,a),c=A(r,"id");await e(i,l,c,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 b(),i=r.job??Vt();if(i==="")throw new d("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console last -j my-job -s success"});let a=k(o.job,i),l=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(l))throw new d(`Invalid status: ${r.status}.`,{hint:"Use success | failed | any.",example:"jenkins-cli console last -s success"});let c=await ge(s,a),u=l==="success"?c?.lastSuccessfulBuild:l==="failed"?c?.lastFailedBuild:c?.lastBuild,p=Number(u?.number);if(!p){let m=l==="success"?"successful":l==="failed"?"failed":"last";console.log(y.yellow(`No ${m} build found for job: ${a}. Try checking the job name or status filter.`));return}await e(s,a,p,r);});}function It(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 b(),s=k(r.job,e.job);if(e.ALL){let[i,a]=await Promise.all([H(o),fe(o)]),l=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),c=(a??[]).map(u=>({number:Number(u.number),job:String(u.job??"")})).filter(u=>u.job&&!Number.isNaN(u.number));for(let u of l)await te(o,u);for(let u of c)await ne(o,u.job,u.number);console.log(y.green(`Requested: cancelled ${l.length} queue item(s), stopped ${c.length} running build(s).`));return}if(e.all){let[i,a]=await Promise.all([H(o,s),ee(o,s)]),l=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),c=(a??[]).map(u=>Number(u.number)).filter(u=>!Number.isNaN(u));for(let u of l)await te(o,u);for(let u of c)await ne(o,s,u);console.log(y.green(`Requested: cancelled ${l.length} queue item(s), stopped ${c.length} running build(s).`));return}if(!n){console.log(y.red("Missing build id. Provide <id> or use -a/--all."));return}await ne(o,s,A(n,"id")),console.log(y.green("Stop requested"));});}function qt(t){t.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async n=>{let{config:e,jenkins:r}=await b(),o=k(e.job,n.job),s=await gt(r,o),i=j(s.map(a=>a?.name));console.table((s??[]).map(a=>({name:J(a?.name??"",i),type:h(String(a?.type??"")),description:h(String(a?.description??"")),default:h(a?.default===void 0?"-":String(a.default)),choices:h(Array.isArray(a?.choices)?a.choices.join(", "):a?.choices??"-")})));});}function Dt(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 b(),r=await ut(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,p)=>{let m=u.length;if(m>=p)return u;let f=p-m,g=Math.floor(f/2),w=f-g;return `${" ".repeat(g)}${u}${" ".repeat(w)}`},i=o.name??o.fullName??o.id??"",a=i==null?"":String(i),l=Math.max(20,a.length),c={};c.name=h(s(a,l));for(let u of Object.keys(o).sort((p,m)=>p.localeCompare(m,"en"))){if(u==="name")continue;let p=o[u],m=u.toLowerCase();if((m==="url"||m.endsWith("url")||m.includes("url"))&&(typeof p=="string"||typeof p=="number")){c[u]=v(String(p));continue}let g=p==null?"":typeof p=="object"?JSON.stringify(p):String(p);c[u]=h(g);}console.table([c]);});}function Mt(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 b(),s=k(r.job,e.job),i=String(e.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new d(`Invalid format: ${e.format}.`,{hint:"Use xml or json.",example:"jenkins-cli config show -f json"});let a=await Ve(o,s);if(i==="xml"){process.stdout.write(a);return}let c=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(a);console.log(JSON.stringify(c,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 b(),s=String(e.destination??"").trim();if(!s)throw new d("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 d("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 L(o):i?(await L(o)).filter(c=>ye(String(c.name??""),i)):[{name:k(r.job,e.job)}];if(a.length===0)throw new d(`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 l=[];for(let c of a){let u=String(c?.name??"").trim();if(!u)continue;let p=await Ve(o,u),m=z.join(s,u,"config.xml");await promises.mkdir(z.dirname(m),{recursive:!0}),await promises.writeFile(m,p),l.push(m);}console.log(`Backup completed. ${l.length} file(s) saved to ${z.resolve(s)}`);});}function zt(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 b(),o=await L(r),s=(e.search??"").trim(),i=s?o.filter(c=>ye(String(c.name??""),s)):o;i.sort((c,u)=>String(c?.name??"").localeCompare(String(u?.name??""),"en",{sensitivity:"base"}));let a=j(i.map(c=>c?.name)),l=j(i.map(c=>c?.url));console.table((i??[]).map(c=>({name:J(c.name??"",a),color:se(c.color),url:v(U(c.url??"",l))})));}),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 b(),s=k(r.job,e.job),i=await ge(o,s);if(e.json){console.log(JSON.stringify(i,null,2));return}let a=i?.lastBuild,l=i?.lastCompletedBuild,c=Array.isArray(i?.healthReport)?i.healthReport:[];console.table([{name:h(String(i?.name??"")),url:v(String(i?.url??"")),color:se(i?.color),buildable:i?.buildable,inQueue:i?.inQueue,nextBuildNumber:i?.nextBuildNumber,healthScore:c[0]?.score??"-",lastBuild:h(a?.number?`#${a.number}`:"-"),lastResult:ie(a?.result,a?.building),"lastDuration(s)":a?.duration===void 0?"-":Number((Number(a.duration)/1e3).toFixed(3)),lastDate:h(a?.timestamp?P(Number(a.timestamp)):"-"),lastCompleted:h(l?.number?`#${l.number}`:"-"),lastCompletedResult:ie(l?.result,!1),lastCompletedDate:h(l?.timestamp?P(Number(l.timestamp)):"-")}]);});}function Nn(t){return t.split(",").map(n=>n.trim()).filter(Boolean)}function An(t){let n=t.split("=");if(n.length<2)throw new d(`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 d(`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 _t(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(Nn(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 b(),o=k(e.job,n.job),s=String(n.branch??"").trim();if(!s)throw new d("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(f=>f.trim()).filter(Boolean),a=Array.from(new Set(i));if(a.length===0)throw new d("mode is required.",{hint:"Pass at least one -m/--mode.",example:"jenkins-cli build -b origin/develop -m dev -m uat"});let l={};for(let f of n.param??[]){let{key:g,value:w}=An(String(f));l[g]=w;}let c=await ce();c&&!("triggered_by"in l)&&(l.triggered_by=c),console.log();let u=!1,p=()=>{u||(u=!0,console.log());},m=a.map(async f=>{let g=Qt(`Triggering build for ${y.yellow(f)}...`).start();try{let w=await de(r,o,{...l,branch:s,mode:f});p(),g.succeed(`${y.green(f)} - Triggered! Queue: ${w}`);}catch(w){throw p(),g.fail(`${y.red(f)} - ${w.message}`),w}});try{await Promise.all(m);}catch{console.log(y.bold.red(`
41
41
  \u274C Some builds failed. Check the output above.
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();
42
+ `)),process.exit(1);}});}function Ht(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 b(),o=await re(r,{raw:e.raw});if(e.raw){console.log(JSON.stringify(o,null,2));return}o.sort((l,c)=>String(l?.name??"").localeCompare(String(c?.name??""),"en",{sensitivity:"base"}));let s=(o??[]).map(l=>({name:String(l?.name??""),url:String(l?.url??"")})),i=j(s.map(l=>l.name)),a=j(s.map(l=>l.url));console.table(s.map(l=>({name:J(l.name,i),url:v(U(l.url,a))})));}),n.command("show").description("Show jobs in a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await b(),o=await Q(r,e);if(!o.length){console.log("No jobs found in this view.");return}o.sort((a,l)=>String(a?.name??"").localeCompare(String(l?.name??""),"en",{sensitivity:"base"}));let s=j(o.map(a=>a?.name)),i=j(o.map(a=>a?.url));console.table(o.map(a=>({name:J(a.name??"",s),color:se(a.color),url:v(U(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 b();if((await Q(o,e)).some(i=>i.name===r)){console.log(y.yellow(`Job "${r}" is already in view "${e}".`));return}await Fe(o,e,r),console.log(y.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 b();if(!(await Q(o,e)).some(i=>i.name===r))throw new d(`Job "${r}" is not in view "${e}".`,{hint:'Use "jc view show <name>" to see jobs in this view.'});await Le(o,e,r),console.log(y.green(`Job "${r}" removed from view "${e}".`));}),n.command("edit").description("Edit jobs in a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await b(),[o,s]=await Promise.all([L(r),Q(r,e)]);if(!o.length){console.log("No jobs found.");return}o.sort((m,f)=>String(m?.name??"").localeCompare(String(f?.name??""),"en",{sensitivity:"base"}));let i=new Set(s.map(m=>String(m?.name??"").trim())),a=o.map(m=>String(m?.name??"").trim()).filter(Boolean).map(m=>({name:m,checked:i.has(m)})),l=await oe.prompt([{type:"checkbox",name:"jobs",message:`Select jobs for view "${e}"`,choices:a,pageSize:20}]),c=new Set((l.jobs??[]).map(m=>String(m).trim())),u=[...c].filter(m=>!i.has(m)),p=[...i].filter(m=>m&&!c.has(m));if(!u.length&&!p.length){console.log(y.yellow("No changes to apply."));return}for(let m of u)await Fe(r,e,m);for(let m of p)await Le(r,e,m);console.log(y.green(`View "${e}" updated.`));}),n.command("create").description("Create a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await b();await ct(r,e),console.log(y.green(`View "${e}" created.`));}),n.command("delete").alias("del").description("Delete a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await b();await lt(r,e),console.log(y.green(`View "${e}" deleted.`));});}function Fn(t){return h(t?P(t):"-")}function $e(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 ze(t,n,e){let r=n?.parent?.opts()?.job,o=$e(e)??$e(n?.name())??$e("ws")??$e("workspace");return t??r??o}function _e(t,n){if(n==="")throw new d("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli ws -j my-job"});return k(t,n)}function Gt(t){return t.replace(/^\/+/,"").replace(/\/+$/,"")}function Ln(t,n){let e=Gt(t),r=Gt(n);return e?r?r===e||r.startsWith(`${e}/`)?r:`${e}/${r}`:e:r||""}function Tn(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 R(t){try{return await t()}catch(n){if(n?.response?.status===404)return null;throw n}}async function Vn(t,n){try{return await mt(t,n)}catch{return}}async function On(t,n){try{return await Jt(t,n)}catch{return}}async function In(t){try{return await re(t,{raw:!1})}catch{return []}}async function He(t,n,e){let r=await e.direct(n);if(r!==null)return r;let o=await Vn(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 On(t,n);if(s){let a=await e.byViewName(s);if(a!==null)return a}let i=await In(t);for(let a of i){let l=String(a?.url??"").trim();if(!l)continue;let c=await e.byViewUrl(l);if(c!==null)return c}return null}async function qn(t,n,e){return await He(t,n,{direct:r=>R(()=>Te(t,r,{path:e})),byViewName:r=>R(()=>ht(t,r,n,{path:e})),byViewUrl:r=>R(()=>bt(t,r,n,{path:e})),beforeView:async()=>{if(e)return null;let r=n.split("/").pop();return r?await R(()=>Te(t,n,{path:r})):null}})}async function Dn(t,n,e){return await He(t,n,{direct:r=>R(()=>wt(t,r,e)),byViewName:r=>R(()=>kt(t,r,n,e)),byViewUrl:r=>R(()=>jt(t,r,n,e))})}async function Mn(t,n,e){return await He(t,n,{direct:r=>R(()=>yt(t,r,e)),byViewName:r=>R(()=>xt(t,r,n,e)),byViewUrl:r=>R(()=>Ct(t,r,n,e))})}function Kt(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 b(),i=ze(e.job,r,"workspace"),a=_e(o.job,i),l=String(e.path??"").trim(),c=Qt(`Loading workspace for job "${a}"...`).start(),u=await qn(s,a,l);if(!u){c.warn(`Workspace not found for job: ${a}. The job may be inside a folder, not run yet, or workspace is disabled.`);return}if(c.succeed(`Workspace loaded for job: ${a}`),!u.length){console.table([{name:"-",type:"-",size:"-",modified:"-",path:"-",url:"-"}]);return}let p=u.map(g=>({name:String(g.name??""),typeRaw:g.type,size:Et(g.size),modified:Fn(g.modified),path:Ln(l,String(g.path??g.name??""))})),m=j(p.map(g=>g.name)),f=j(p.map(g=>g.path));console.table(p.map(g=>{let w=U(String(g.name??""),m),$=String(g.typeRaw??"");return {name:$==="dir"?h(y.bold.cyan(w)):$==="file"?h(y.green(w)):h(y.gray(w)),size:g.size,modified:g.modified,path:J(String(g.path??""),f)}}));}),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 b(),a=ze(r.job,o,"cat"),l=_e(s.job,a),c=String(e??"").trim();if(!c)throw new d("Path is required.",{hint:'Provide a file path after "cat".',example:"jenkins-cli ws cat dist/index.html"});let u=String(r.out??"").trim(),p=r.open===!0;if(u||p){let f=await Mn(i,l,c);if(f===null){console.log(y.yellow(`Workspace file not found: ${c} (job: ${l}).`));return}let g=u||z.join(En.tmpdir(),z.basename(c)||"file");try{u&&await M.pathExists(u)&&(await M.stat(u)).isDirectory()&&(g=z.join(u,z.basename(c)||"file"));}catch{}await M.ensureDir(z.dirname(g)),await M.writeFile(g,f.data),p?(Tn(g),console.log(y.green(`Opened: ${g}`))):console.log(y.green(`Saved to: ${g}`));return}let m=await Dn(i,l,c);if(m===null){console.log(y.yellow(`Workspace file not found: ${c} (job: ${l}).`));return}process.stdout.write(String(m));}),n.command("wipe").description("Wipe out current workspace").option("-j, --job <job>","Specify job").action(async(e,r)=>{let{config:o,jenkins:s}=await b(),i=ze(e.job,r,"wipe"),a=_e(o.job,i);try{if(!(await oe.prompt([{type:"confirm",name:"confirm",message:`Wipe workspace for job "${a}"? This cannot be undone.`,default:!1}]))?.confirm){console.log(y.yellow("Cancelled."));return}}catch(c){let u=c?.message?String(c.message):String(c);if((c?.name?String(c.name):"")==="ExitPromptError"||u.toLowerCase().includes("cancelled")||u.toLowerCase().includes("canceled")){console.log(y.yellow("Cancelled."));return}throw c}let l=Qt(`Wiping workspace for job "${a}"...`).start();try{await St(s,a),l.succeed(`Workspace wiped for job: ${a}`);}catch(c){throw l.fail(`Failed to wipe workspace for job: ${a}`),c}});}function Yt(t){Ft(t),Tt(t),Mt(t),zt(t),Ot(t),qt(t),Wt(t),It(t),_t(t),Dt(t),Ht(t),Kt(t);}function Xt(t,n,e){let r=s=>s.options.some(i=>i.long===n||i.short===n),o=s=>{r(s)||s.option(n,e);for(let i of s.commands)o(i);};for(let s of t.commands)o(s);}program.name("jenkins-cli").description(Xe).version(Ye,"-v, --version").helpOption("-h, --help").option("--debug","Print Jenkins request params").allowExcessArguments(!1).configureHelp({sortSubcommands:!0,sortOptions:!0}).action(Bt);Yt(program);Xt(program,"--debug","Print Jenkins request params");async function zn(){try{await program.parseAsync(process.argv);}catch(t){q(t);}}zn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-org/jenkins-cli",
3
- "version": "3.0.5",
3
+ "version": "3.1.0",
4
4
  "description": "Jenkins deployment CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -7,14 +7,21 @@
7
7
  },
8
8
  "job": {
9
9
  "type": "string",
10
- "description": "Jenkins job name"
10
+ "description": "Jenkins job name (or reference string like jenkins-utils.ts:fn)"
11
11
  },
12
12
  "modes": {
13
- "type": "array",
14
- "description": "Available deployment environments, such as dev, sit, uat",
15
- "items": {
16
- "type": "string"
17
- }
13
+ "description": "Available deployment environments (array) or reference string like jenkins-utils.ts:fn",
14
+ "oneOf": [
15
+ {
16
+ "type": "array",
17
+ "items": {
18
+ "type": "string"
19
+ }
20
+ },
21
+ {
22
+ "type": "string"
23
+ }
24
+ ]
18
25
  },
19
26
  "configs": {
20
27
  "type": "array",
@@ -35,6 +42,10 @@
35
42
  "type": "string",
36
43
  "description": "Parameter message"
37
44
  },
45
+ "offset": {
46
+ "type": "number",
47
+ "description": "Negative offsets control prompt ordering (-1 between branch/modes, <=-2 before branch)"
48
+ },
38
49
  "default": {
39
50
  "description": "Parameter default value"
40
51
  },