task-pipeliner 0.2.15 → 0.2.16
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.ko.md +35 -1
- package/README.md +35 -1
- package/dist/index.cjs +30 -30
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 조건 기반 작업 파이프라인 실행기로 아름다운 CLI 출력을 제공합니다
|
|
4
4
|
|
|
5
|
-
**버전:** 0.2.
|
|
5
|
+
**버전:** 0.2.16
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
- **변수 치환** - 워크플로우 전반에서 `{{variables}}` 사용
|
|
27
27
|
|
|
28
|
+
- **프로필** - 미리 정의한 변수로 비대화형 실행 (`tp run --profile <name>`); 프로필에 설정된 변수에 대해서는 choose/prompt 단계 생략
|
|
29
|
+
|
|
28
30
|
- **실행 히스토리** - 상세한 단계별 기록으로 과거 워크플로우 실행 추적 및 검토
|
|
29
31
|
|
|
30
32
|
## 리소스
|
|
@@ -47,6 +49,8 @@
|
|
|
47
49
|
```bash
|
|
48
50
|
tp run workflow.yaml # 워크플로우 실행
|
|
49
51
|
tp run # 가장 가까운 tp 디렉토리에서 워크플로우 선택하여 실행
|
|
52
|
+
tp run workflow.yaml --profile Test # 프로필로 실행 (프로필에 설정된 변수는 choose/prompt 생략)
|
|
53
|
+
tp run workflow.yaml -p Test # 프로필 짧은 형식
|
|
50
54
|
tp run workflow.yaml --silent # 사일런트 모드로 실행 (모든 콘솔 출력 억제)
|
|
51
55
|
tp run workflow.yaml -s # 사일런트 모드 짧은 형식
|
|
52
56
|
```
|
|
@@ -297,6 +301,11 @@ shell: # 선택사항: 모든 run 명령의 전
|
|
|
297
301
|
- bash # - 첫 번째 요소: 쉘 프로그램 (bash, zsh, sh 등)
|
|
298
302
|
- -lc # - 나머지: 쉘 인자 (-c, -lc 등)
|
|
299
303
|
# - 생략 시: 플랫폼 기본 쉘 사용
|
|
304
|
+
profiles: # 선택사항: tp run --profile <name>용 미리 설정된 변수
|
|
305
|
+
- name: Test # - name: 프로필 이름
|
|
306
|
+
var: # - var: 키-값 맵 ({{variable}} 치환 및 choose/prompt 생략에 사용)
|
|
307
|
+
mode: "dev"
|
|
308
|
+
label: "test-label"
|
|
300
309
|
|
|
301
310
|
steps: # 필수: 실행할 단계 배열
|
|
302
311
|
- some-step-1
|
|
@@ -317,6 +326,9 @@ steps: # 필수: 실행할 단계 배열
|
|
|
317
326
|
// - 첫 번째 요소: 쉘 프로그램
|
|
318
327
|
// - 나머지: 쉘 인자
|
|
319
328
|
// - 생략 시: 플랫폼 기본 쉘 사용
|
|
329
|
+
"profiles": [ // 선택사항: tp run --profile <name>용 미리 설정된 변수
|
|
330
|
+
{ "name": "Test", "var": { "mode": "dev", "label": "test-label" } }
|
|
331
|
+
],
|
|
320
332
|
"steps": [ // 필수: 실행할 단계 배열
|
|
321
333
|
{ /* some-step-1 */ },
|
|
322
334
|
{ /* some-step-2 */ }
|
|
@@ -369,6 +381,26 @@ steps: # 필수: 실행할 단계 배열
|
|
|
369
381
|
- **Git Bash (Windows)**: `[bash, -c]`
|
|
370
382
|
- **WSL**: `[wsl, bash, -c]` 또는 `wsl` 명령 직접 사용
|
|
371
383
|
|
|
384
|
+
#### `profiles` (선택)
|
|
385
|
+
- **타입**: `{ name: string, var: Record<string, string> }` 의 `array`
|
|
386
|
+
- **설명**: 비대화형 실행을 위한 이름 붙은 변수 세트. `tp run --profile <name>` 과 함께 사용.
|
|
387
|
+
- **동작**: 프로필을 사용하면, 프로필에 이미 설정된 변수에 값을 저장하는 **choose** 또는 **prompt** 단계는 생략되고, 프로필 값이 `{{variable}}` 치환 및 조건에 사용됩니다.
|
|
388
|
+
- **예제**:
|
|
389
|
+
```yaml
|
|
390
|
+
profiles:
|
|
391
|
+
- name: Test
|
|
392
|
+
var:
|
|
393
|
+
mode: "dev"
|
|
394
|
+
label: "test-label"
|
|
395
|
+
- name: Prod
|
|
396
|
+
var:
|
|
397
|
+
mode: "prod"
|
|
398
|
+
label: "prod-label"
|
|
399
|
+
```
|
|
400
|
+
```bash
|
|
401
|
+
tp run workflow.yaml --profile Test # Test 프로필 변수 사용; mode, label에 대한 choose/prompt 생략
|
|
402
|
+
```
|
|
403
|
+
|
|
372
404
|
#### `steps` (필수)
|
|
373
405
|
- **타입**: `Step` 객체의 `array`
|
|
374
406
|
- **설명**: 순차적으로 실행할 단계 목록
|
|
@@ -1307,6 +1339,7 @@ tp history remove-all -y # 확인 건너뛰기
|
|
|
1307
1339
|
- **`file-checks.yaml`** - 파일 존재 확인
|
|
1308
1340
|
- **`prompt.yaml`** - 사용자 입력 프롬프트
|
|
1309
1341
|
- **`variables.yaml`** - 변수 치환 예제
|
|
1342
|
+
- **`profiles-example.yaml`** - 비대화형 실행용 프로필 (`tp run --profile <name>`)
|
|
1310
1343
|
|
|
1311
1344
|
### JSON 예제
|
|
1312
1345
|
|
|
@@ -1318,6 +1351,7 @@ tp history remove-all -y # 확인 건너뛰기
|
|
|
1318
1351
|
- **`conditions.json`** - 조건 평가 예제
|
|
1319
1352
|
- **`prompt.json`** - 사용자 입력 프롬프트
|
|
1320
1353
|
- **`variables.json`** - 변수 치환 예제
|
|
1354
|
+
- **`profiles-example.json`** - 비대화형 실행용 프로필 (`tp run --profile <name>`)
|
|
1321
1355
|
|
|
1322
1356
|
**참고:** YAML과 JSON 형식 모두 완전히 지원됩니다. 선호하는 형식을 선택하세요 - 가독성을 위해 YAML, 프로그래밍 방식 생성을 위해 JSON.
|
|
1323
1357
|
- **`variables.yaml`** - 변수 사용 예제
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A powerful, condition-based task pipeline runner with beautiful CLI output
|
|
4
4
|
|
|
5
|
-
**Version:** 0.2.
|
|
5
|
+
**Version:** 0.2.16
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
- **Variable substitution** - Use `{{variables}}` throughout your workflows
|
|
27
27
|
|
|
28
|
+
- **Profiles** - Run workflows non-interactively with pre-set variables (`tp run --profile <name>`); choose/prompt steps are skipped when the variable is set in the profile
|
|
29
|
+
|
|
28
30
|
- **Execution history** - Track and review past workflow executions with detailed step-by-step records
|
|
29
31
|
|
|
30
32
|
## 🔗 Resources
|
|
@@ -47,6 +49,8 @@
|
|
|
47
49
|
```bash
|
|
48
50
|
tp run workflow.yaml # Run a workflow
|
|
49
51
|
tp run # Select and run a workflow from nearest tp directory
|
|
52
|
+
tp run workflow.yaml --profile Test # Run with profile (skip choose/prompt for variables set in profile)
|
|
53
|
+
tp run workflow.yaml -p Test # Short form for profile
|
|
50
54
|
tp run workflow.yaml --silent # Run in silent mode (suppress all console output)
|
|
51
55
|
tp run workflow.yaml -s # Short form for silent mode
|
|
52
56
|
```
|
|
@@ -297,6 +301,11 @@ shell: # Optional: Global shell configuration fo
|
|
|
297
301
|
- bash # - First element: shell program (bash, zsh, sh, etc.)
|
|
298
302
|
- -lc # - Rest: shell arguments (-c, -lc, etc.)
|
|
299
303
|
# - If omitted: uses platform default shell
|
|
304
|
+
profiles: # Optional: Pre-set variables for tp run --profile <name>
|
|
305
|
+
- name: Test # - name: profile name
|
|
306
|
+
var: # - var: key-value map (used for {{variable}} and to skip choose/prompt)
|
|
307
|
+
mode: "dev"
|
|
308
|
+
label: "test-label"
|
|
300
309
|
|
|
301
310
|
steps: # Required: Array of steps to execute
|
|
302
311
|
- some-step-1
|
|
@@ -317,6 +326,9 @@ steps: # Required: Array of steps to execute
|
|
|
317
326
|
// - First element: shell program
|
|
318
327
|
// - Rest: shell arguments
|
|
319
328
|
// - If omitted: uses platform default shell
|
|
329
|
+
"profiles": [ // Optional: Pre-set variables for tp run --profile <name>
|
|
330
|
+
{ "name": "Test", "var": { "mode": "dev", "label": "test-label" } }
|
|
331
|
+
],
|
|
320
332
|
"steps": [ // Required: Array of steps to execute
|
|
321
333
|
{ /* some-step-1 */ },
|
|
322
334
|
{ /* some-step-2 */ }
|
|
@@ -369,6 +381,26 @@ steps: # Required: Array of steps to execute
|
|
|
369
381
|
- **Git Bash (Windows)**: `[bash, -c]`
|
|
370
382
|
- **WSL**: `[wsl, bash, -c]` or use `wsl` command directly
|
|
371
383
|
|
|
384
|
+
#### `profiles` (optional)
|
|
385
|
+
- **Type**: `array` of `{ name: string, var: Record<string, string> }`
|
|
386
|
+
- **Description**: Named sets of variables for non-interactive runs. Use with `tp run --profile <name>`.
|
|
387
|
+
- **Behavior**: When a profile is used, any **choose** or **prompt** step that stores into a variable already set in the profile is skipped; the profile value is used for `{{variable}}` substitution and conditions.
|
|
388
|
+
- **Example**:
|
|
389
|
+
```yaml
|
|
390
|
+
profiles:
|
|
391
|
+
- name: Test
|
|
392
|
+
var:
|
|
393
|
+
mode: "dev"
|
|
394
|
+
label: "test-label"
|
|
395
|
+
- name: Prod
|
|
396
|
+
var:
|
|
397
|
+
mode: "prod"
|
|
398
|
+
label: "prod-label"
|
|
399
|
+
```
|
|
400
|
+
```bash
|
|
401
|
+
tp run workflow.yaml --profile Test # Uses Test profile variables; choose/prompt for mode, label are skipped
|
|
402
|
+
```
|
|
403
|
+
|
|
372
404
|
#### `steps` (required)
|
|
373
405
|
- **Type**: `array` of `Step` objects
|
|
374
406
|
- **Description**: List of steps to execute sequentially
|
|
@@ -1308,6 +1340,7 @@ Check out `examples/yaml-examples/` for YAML workflow examples:
|
|
|
1308
1340
|
- **`file-checks.yaml`** - File existence checks
|
|
1309
1341
|
- **`prompt.yaml`** - User input prompts
|
|
1310
1342
|
- **`variables.yaml`** - Variable substitution examples
|
|
1343
|
+
- **`profiles-example.yaml`** - Profiles for non-interactive runs (`tp run --profile <name>`)
|
|
1311
1344
|
|
|
1312
1345
|
### JSON Examples
|
|
1313
1346
|
|
|
@@ -1319,6 +1352,7 @@ Check out `examples/json-examples/` for JSON workflow examples (equivalent to YA
|
|
|
1319
1352
|
- **`conditions.json`** - Condition evaluation examples
|
|
1320
1353
|
- **`prompt.json`** - User input prompts
|
|
1321
1354
|
- **`variables.json`** - Variable substitution examples
|
|
1355
|
+
- **`profiles-example.json`** - Profiles for non-interactive runs (`tp run --profile <name>`)
|
|
1322
1356
|
|
|
1323
1357
|
**Note:** Both YAML and JSON formats are fully supported. Choose the format that fits your preference - YAML for readability, JSON for programmatic generation.
|
|
1324
1358
|
- **`variables.yaml`** - Variable usage examples
|
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var Fe=Object.create;var pe=Object.defineProperty;var
|
|
3
|
-
`){i.length>0&&(h(),r(i[o]));return}if(f==="\x1B"&&d.length===1){n&&(n="",
|
|
2
|
+
"use strict";var Fe=Object.create;var pe=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,_e=Object.prototype.hasOwnProperty;var He=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of We(e))!_e.call(s,n)&&n!==t&&pe(s,n,{get:()=>e[n],enumerable:!(r=Ve(e,n))||r.enumerable});return s};var x=(s,e,t)=>(t=s!=null?Fe(Oe(s)):{},He(e||!s||!s.__esModule?pe(t,"default",{value:s,enumerable:!0}):t,s));var Ae=require("child_process"),ce=require("fs"),Ie=require("fs/promises"),V=require("path"),Be=require("util"),ue=x(require("boxen"),1),p=x(require("chalk"),1),De=require("commander"),Le=x(require("dayjs"),1);var T=require("path"),Se=x(require("chalk"),1),q=x(require("log-update"),1);var me=x(require("readline"),1),v=x(require("chalk"),1),K=x(require("inquirer"),1),fe=15,M=class{searchable;constructor(e=!1){this.searchable=e}async prompt(e,t){if(this.searchable)return this.promptWithSearch(e,t);let{choice:r}=await K.default.prompt([{type:"list",name:"choice",message:v.default.cyan(e),choices:t.map(o=>({name:o.label,value:o.id})),pageSize:fe}]),n=t.find(o=>o.id===r);if(!n)throw new Error(`Invalid choice: ${r}`);return n}async promptWithSearch(e,t){return new Promise(r=>{let n="",o=0,i=[...t],a=me.createInterface({input:process.stdin,output:process.stdout,terminal:!1});process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdout.write("\x1B[?1049h"),process.stdout.write("\x1B[?25l");let u=()=>{process.stdout.write("\x1B[H\x1B[2J"),console.log(v.default.cyan(`? ${e}`));let d=n?v.default.gray(` Filter: ${n}`)+v.default.gray(` (${i.length}/${t.length})`):v.default.gray(" Type to filter, \u2191\u2193 to navigate, Enter to select");console.log(d),console.log();let f=fe,g=0,b=i.length;if(i.length>f){let y=Math.floor(f/2);g=Math.max(0,o-y),b=Math.min(i.length,g+f),b===i.length&&(g=Math.max(0,b-f))}if(i.length===0)console.log(v.default.yellow(" No matches found"));else{g>0&&console.log(v.default.gray(` \u2191 ${g} more above`));for(let y=g;y<b;y++){let k=i[y];console.log(y===o?v.default.cyan(`\u276F ${k.label}`):v.default.white(` ${k.label}`))}b<i.length&&console.log(v.default.gray(` \u2193 ${i.length-b} more below`))}},c=()=>{let d=n.toLowerCase();i=d?t.filter(f=>f.label.toLowerCase().includes(d)):[...t],o>=i.length&&(o=Math.max(0,i.length-1))},m=d=>{let f=d.toString();if(f===""&&(h(),process.exit(0)),f==="\r"||f===`
|
|
3
|
+
`){i.length>0&&(h(),r(i[o]));return}if(f==="\x1B"&&d.length===1){n&&(n="",c(),u());return}if(f==="\x1B[A"){i.length>0&&(o=o>0?o-1:i.length-1,u());return}if(f==="\x1B[B"){i.length>0&&(o=o<i.length-1?o+1:0,u());return}if(f==="\x7F"||f==="\b"){n.length>0&&(n=n.slice(0,-1),c(),u());return}f.length===1&&f>=" "&&f<="~"&&(n+=f,c(),u())},h=()=>{process.stdin.removeListener("data",m),process.stdin.isTTY&&process.stdin.setRawMode(!1),a.close(),process.stdout.write("\x1B[?25h"),process.stdout.write("\x1B[?1049l")};u(),process.stdin.on("data",m)})}},_=class{async prompt(e,t){let{value:r}=await K.default.prompt([{type:"input",name:"value",message:v.default.cyan(e),default:t}]);return r}};var H=x(require("boxen"),1),A=x(require("chalk"),1);function Q(s,e,t,r={}){let{borderColor:n="cyan",isNested:o=!1}=r,i;e!==void 0&&(t?i=`line ${e} in ${t}`:i=`line ${e}`);let a=o?`\u2502 ${s}`:`> ${s}`;return(0,H.default)(a,{title:i,borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:n})}function I(s,e=!1,t){let r=s?"\u2713 Completed":"\u2717 Failed",n=s?A.default.green(r):A.default.red(r);if(t!==void 0){let o=B(t);return`${n} ${A.default.gray(`(${o})`)}`}return n}function W(s){return(0,H.default)(`\u2717 ${s}`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"red"})}function de(s){return(0,H.default)(`> Starting parallel execution (${s} branches)`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"yellow"})}function he(s){let e=s?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return s?A.default.green(e):A.default.red(e)}function ee(s,e=!1){return`${e?"| \u2502 ":"\u2502 "}${s}`}function B(s){return`${(s/1e3).toFixed(3)}s`}var ge=require("fs"),we=require("path"),D=class{constructor(e){this.workspace=e}evaluate(e){return"var"in e||"has"in e?this.evaluateVarExists(e):"file"in e?this.evaluateFileExists(e):"choice"in e?this.evaluateChoice(e):"all"in e?this.evaluateAll(e):"any"in e?this.evaluateAny(e):"not"in e?this.evaluateNot(e):!1}evaluateVarExists(e){if(e.has)return this.workspace.hasVariable(e.has)||this.workspace.hasFact(e.has);if(!e.var)return!1;if(typeof e.var=="object"){for(let[r,n]of Object.entries(e.var)){let o=this.workspace.getVariable(r),i=this.workspace.getFact(r),a=o??(i!==void 0?i.toString():void 0);if(a===void 0||a!==n)return!1}return!0}let t=e.var;return this.workspace.hasVariable(t)||this.workspace.hasFact(t)}evaluateFileExists(e){try{let t=e.file.trim(),r=(0,we.resolve)(process.cwd(),t);return(0,ge.existsSync)(r)}catch{return!1}}evaluateChoice(e){return this.workspace.hasChoice(e.choice)}evaluateAll(e){return e.all.every(t=>this.evaluate(t))}evaluateAny(e){return e.any.some(t=>this.evaluate(t))}evaluateNot(e){return!this.evaluate(e.not)}};var R=require("fs/promises"),be=require("os"),N=require("path"),ye=x(require("dayjs"),1),L=(0,N.join)((0,be.homedir)(),".pipeliner","workflow-history"),F=class{constructor(){}async saveHistory(e){await(0,R.mkdir)(L,{recursive:!0});let t=(0,ye.default)().format("YYYY-MM-DD_HH-mm-ss"),r=Math.random().toString(36).slice(2,6),n=(0,N.join)(L,`workflow-${t}-${r}.json`);return await(0,R.writeFile)(n,JSON.stringify(e,null,2),{encoding:"utf8"}),n}async clearAllHistories(){await(0,R.rm)(L,{recursive:!0,force:!0})}async removeHistory(e){await(0,R.rm)((0,N.join)(L,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,R.readdir)(L)).map(r=>(0,N.basename)(r));return t.sort((r,n)=>{let o=u=>{let c=u.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},i=o(r),a=o(n);return i===a?n.localeCompare(r):a.localeCompare(i)}),t}catch(e){if(e instanceof Error&&"code"in e&&e.code==="ENOENT")return[];throw e}}async getHistory(e){let t=await(0,R.readFile)((0,N.join)(L,e),{encoding:"utf8"});return JSON.parse(t)}};var J=class{records=[];initialTimestamp=Date.now();recordStartTimestamp=Date.now();constructor(){this.records=[]}recordStart(){this.recordStartTimestamp=Date.now()}recordEnd(e,t,r,n){let o=this.getDuration();return this.records.push({step:e,context:t,output:r,duration:o,status:n}),o}reset(){this.records=[],this.initialTimestamp=Date.now()}async save(){let e=new F,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var te=require("child_process");var U=class{async run(e,t,r,n,o=!1,i=!1,a,u,c,m,h){return o?this.runBuffered(e,c,m,h):this.runRealtime(e,r||e,i,a,u,c,m,h)}async runBuffered(e,t,r,n){return new Promise((o,i)=>{let a=this.spawnWithShell(e,t,n),u=[],c=[],m="",h="",d=null;r&&r>0&&(d=setTimeout(()=>{a.kill("SIGTERM");let f=`Command timed out after ${r} seconds`;c.push(f),o({success:!1,stdout:u,stderr:c})},r*1e3)),a.stdout?.on("data",f=>{let g=f.toString(),{lines:b,remaining:y}=this.processStreamBuffer(g,m);u.push(...b),m=y}),a.stderr?.on("data",f=>{let g=f.toString(),{lines:b,remaining:y}=this.processStreamBuffer(g,h);c.push(...b),h=y}),a.on("close",f=>{d&&clearTimeout(d),m.trim()&&u.push(m),h.trim()&&c.push(h),o({success:f===0,stdout:u,stderr:c})}),a.on("error",f=>{d&&clearTimeout(d);let g=`Error: ${f.message}`;o({success:!1,stdout:u,stderr:[...c,g]})})})}async runRealtime(e,t,r,n,o,i,a,u){let m=Q(t,n,o,{borderColor:r?"green":"cyan"});console.log(m);let h=Date.now();return new Promise(d=>{let f=this.spawnWithShell(e,i,u),g="",b="",y=null;a&&a>0&&(y=setTimeout(()=>{f.kill("SIGTERM");let k=`Command timed out after ${a} seconds`,$=W(k);console.error($);let P=Date.now()-h,j=I(!1,!1,P);console.log(j),d(!1)},a*1e3)),f.stdout?.on("data",k=>{let $=k.toString(),{lines:P,remaining:j}=this.processStreamBuffer($,g);P.forEach(X=>process.stdout.write(`\u2502 ${X}
|
|
4
4
|
`)),g=j}),f.stderr?.on("data",k=>{let $=k.toString(),{lines:P,remaining:j}=this.processStreamBuffer($,b);P.forEach(X=>process.stderr.write(`\u2502 ${X}
|
|
5
5
|
`)),b=j}),f.on("close",k=>{y&&clearTimeout(y),g.trim()&&process.stdout.write(`\u2502 ${g}
|
|
6
6
|
`),b.trim()&&process.stderr.write(`\u2502 ${b}
|
|
7
|
-
`);let $=k===0,P=Date.now()-h,j=
|
|
7
|
+
`);let $=k===0,P=Date.now()-h,j=I($,!1,P);console.log(j),d($)}),f.on("error",k=>{y&&clearTimeout(y);let $=W(`Error: ${k.message}`);console.error($),d(!1)})})}createSpawnOptions(e){let t={stdio:["inherit","pipe","pipe"],shell:!0};return e&&(t.cwd=e),t}spawnWithShell(e,t,r){if(r&&r.length>0){let n=r[0],o=[...r.slice(1),e],i={stdio:["inherit","pipe","pipe"]};return t&&(i.cwd=t),(0,te.spawn)(n,o,i)}else{let n=process.env.SHELL||(process.platform==="win32"?"cmd.exe":"/bin/sh"),o=process.platform==="win32"?"/c":"-c",i={stdio:["inherit","pipe","pipe"]};return t&&(i.cwd=t),(0,te.spawn)(n,[o,e],i)}}processStreamBuffer(e,t){let r=t+e,n=[],o=r;for(;o.includes(`
|
|
8
8
|
`);){let i=o.indexOf(`
|
|
9
9
|
`),a=o.substring(0,i);o=o.substring(i+1),n.push(a)}return{lines:n,remaining:o}}formatNestedOutput(e,t){t?e.split(`
|
|
10
|
-
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,n,o){let i=Q(t,n,o,{borderColor:"cyan",isNested:r});this.formatNestedOutput(i,r),e.stdout.forEach(u=>{let
|
|
11
|
-
`)}),e.stderr.forEach(u=>{let
|
|
12
|
-
`)});let a=
|
|
13
|
-
Total execution time: ${
|
|
10
|
+
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,n,o){let i=Q(t,n,o,{borderColor:"cyan",isNested:r});this.formatNestedOutput(i,r),e.stdout.forEach(u=>{let c=ee(u,r);process.stdout.write(`${c}
|
|
11
|
+
`)}),e.stderr.forEach(u=>{let c=ee(u,r);process.stderr.write(`${c}
|
|
12
|
+
`)});let a=I(e.success,r);console.log(a)}};function Je(s,e,t){if(e.hasVariable(s)){let r=e.getVariable(s);return r??t}if(e.hasFact(s)){let r=e.getFact(s);return typeof r=="string"?r:String(r)}if(e.hasChoice(s)){let r=e.getChoice(s);return r??t}return t}function Y(s,e){let t=/\{\{\s*(\w+)\s*\}\}/g;return s.replace(t,(r,n)=>Je(n,e,r))}var z=class s{state;constructor(){this.state={facts:new Map,choices:new Map,variables:new Map,stepResults:new Map,lastStepIndex:-1}}hasFact(e){return this.state.facts.has(e)}getFact(e){return this.state.facts.get(e)}setFact(e,t){this.state.facts.set(e,t)}getFactStatus(e){if(!this.hasFact(e))return"pending";let t=this.getFact(e);return t===!1||t==="failed"?"failed":"ready"}getAllFacts(){return new Map(this.state.facts)}hasChoice(e){return this.state.choices.has(e)}getChoice(e){return this.state.choices.get(e)}setChoice(e,t){this.state.choices.set(e,t)}hasVariable(e){return this.state.variables.has(e)}getVariable(e){return this.state.variables.get(e)}setVariable(e,t){this.state.variables.set(e,t)}getAllVariables(){return new Map(this.state.variables)}setStepResult(e,t,r){this.state.stepResults.set(e,{success:t,exitCode:r}),this.state.lastStepIndex=e}getStepResult(e){return this.state.stepResults.get(e)}getLastStepResult(){if(this.state.lastStepIndex!==-1)return this.state.stepResults.get(this.state.lastStepIndex)}clone(){let e=new s;return e.state.facts=new Map(this.state.facts),e.state.choices=new Map(this.state.choices),e.state.variables=new Map(this.state.variables),e.state.stepResults=new Map(this.state.stepResults),e.state.lastStepIndex=this.state.lastStepIndex,e}};var Z=class s{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;globalShell;constructor(){this.workspace=new z,this.taskRunner=new U,this.choicePrompt=new M,this.textPrompt=new _}resolveBaseDir(e){if(e.baseDir)if((0,T.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,T.dirname)(e._filePath);this.baseDir=(0,T.resolve)(t,e.baseDir)}else this.baseDir=(0,T.resolve)(process.cwd(),e.baseDir)}createStepContext(e,t){let r={workspace:this.workspace,stepIndex:e};return t._lineNumbers&&(r.lineNumber=t._lineNumbers.get(e)),t._fileName&&(r.fileName=t._fileName),r}evaluateStepCondition(e){return e.when?new D(this.workspace).evaluate(e.when):!0}calculateBaseStepIndex(e){return e.branchIndex===void 0?e.stepIndex:Math.floor(e.stepIndex/s.PARALLEL_STEP_INDEX_MULTIPLIER)}isRunStep(e){return"run"in e}async execute(e,t){if(t?.profileVars&&Object.keys(t.profileVars).length>0)for(let[a,u]of Object.entries(t.profileVars))this.workspace.setVariable(a,u);this.resolveBaseDir(e),this.globalShell=e.shell;let r=new J,n=Date.now();for(let a=0;a<e.steps.length;a++){let u=e.steps[a],c=this.createStepContext(a,e),m=!!u.when;if(this.evaluateStepCondition(u)){r.recordStart();try{let h=await this.executeStep(u,c,!1,m);this.handleStepResult(u,c,a,h,r)}catch(h){throw this.handleStepError(u,c,a,h,r),h}}}let o=Date.now()-n,i=B(o);console.log(Se.default.cyan(`
|
|
13
|
+
Total execution time: ${i}`)),await r.save(),r.reset()}isStepSuccessful(e,t){return"run"in t?typeof e=="boolean"?e:e&&typeof e=="object"&&"success"in e?e.success:!1:!0}handleStepResult(e,t,r,n,o){let i=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(r);return c?c.success:!0})():this.isStepSuccessful(n,e),a=i?"success":"failure",u=o.recordEnd(e,t,n,a);if(!this.isRunStep(e)){let c=I(i,!1,u);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",m=i?`Step ${r}${c} completed, but workflow stopped due to continue: false`:`Step ${r}${c} failed`;throw new Error(m)}if(!i&&e.continue!==!0){let c=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${r}${c} failed`)}}}handleStepError(e,t,r,n,o){this.workspace.setStepResult(r,!1);let i=n instanceof Error?n.message:String(n),a={success:!1,stdout:[],stderr:[i]};o.recordEnd(e,t,a,"failure")}fixMalformedStep(e){let r=e;return"choose"in e&&r.choose===null&&"message"in e&&"options"in e?{choose:{message:r.message,options:r.options,as:r.as},when:r.when}:"prompt"in e&&r.prompt===null&&"message"in e&&"as"in e?{prompt:{message:r.message,as:r.as,default:r.default},when:r.when}:e}async executeStep(e,t,r=!1,n=!1){if(e=this.fixMalformedStep(e),"run"in e){let o=await this.executeRunStep(e,t,r,n);return r&&typeof o=="object"&&"stdout"in o,o}if("choose"in e){await this.executeChooseStep(e,t);return}if("prompt"in e){await this.executePromptStep(e,t);return}if("parallel"in e){await this.executeParallelStep(e,t);return}if("fail"in e){await this.executeFailStep(e,t);return}}async executeSingleRun(e,t,r=!1,n=!1){let o=this.calculateBaseStepIndex(t),i=Y(e.run,this.workspace),a=e.shell||this.globalShell,u=e.retry??0,c=e.timeout,m=!1,h=0;for(;h<=u;){let d=await this.taskRunner.run(i,o,i,t.branchIndex,r,n,t.lineNumber,t.fileName,this.baseDir,c,a),f=typeof d=="boolean"?d:d.success;if(m=d,f||h>=u)break;if(h++,h<=u){let g=Math.min(1e3*Math.pow(2,h-1),1e4);await new Promise(b=>setTimeout(b,g))}}return m}async executeRunStep(e,t,r=!1,n=!1){let o=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:e.shell},t,r,n),i=typeof o=="boolean"?o:o.success;if(this.workspace.setStepResult(t.stepIndex,i),i||!e.onError)return o;let a={run:e.onError.run,timeout:e.onError.timeout,retry:e.onError.retry,onError:e.onError.onError??void 0};return await this.executeRunChain(a,t,r,n)}async executeRunChain(e,t,r,n){let o=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:void 0},t,r,n);return(typeof o=="boolean"?o:o.success)||!e.onError?o:this.executeRunChain(e.onError,t,r,n)}async executeChooseStep(e,t){let r=e.choose.as,n=e.choose.options.map(a=>a.id);if(r&&this.workspace.hasVariable(r)){let a=this.workspace.getVariable(r)??"";if(n.includes(a)){this.workspace.setChoice(a,a),this.workspace.setStepResult(t.stepIndex,!0);return}}let o=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!o?.id)throw new Error(`Invalid choice result: ${JSON.stringify(o)}`);let i=r??o.id;this.workspace.setChoice(o.id,o.id),this.workspace.setVariable(i,o.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let r=e.prompt.as;if(this.workspace.hasVariable(r)){let a=this.workspace.getVariable(r)??"";this.workspace.setFact(r,a),this.workspace.setStepResult(t.stepIndex,!0);return}let n=Y(e.prompt.message,this.workspace),o=e.prompt.default?Y(e.prompt.default,this.workspace):void 0,i=await this.textPrompt.prompt(n,o);this.workspace.setVariable(r,i),this.workspace.setFact(r,i),this.workspace.setStepResult(t.stepIndex,!0)}createParallelContexts(e,t){return e.parallel.map((r,n)=>({workspace:this.workspace.clone(),stepIndex:t.stepIndex*s.PARALLEL_STEP_INDEX_MULTIPLIER+n,branchIndex:n,lineNumber:t.lineNumber,fileName:t.fileName}))}getBranchDisplayName(e,t){return"run"in e?e.run:"choose"in e?`Choose: ${e.choose.message}`:"prompt"in e?`Prompt: ${e.prompt.message}`:"fail"in e?`Fail: ${e.fail.message}`:`Branch ${t+1}`}async executeParallelBranches(e,t){let r=[],n=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],o=0;for(let c=0;c<e.length;c++){let m=e[c],h=t[c];if(m.when&&!new D(h.workspace).evaluate(m.when))continue;let d=this.getBranchDisplayName(m,c);r.push({index:c,name:d,status:"pending"})}let i=setInterval(()=>{o=(o+1)%n.length,this.updateParallelBranchesDisplay(r,n[o])},100),a=r.map(async c=>{let{index:m}=c,h=e[m],d=t[m];c.status="running";try{let f=await this.executeStep(h,d,!0);return c.status="success",this.updateParallelBranchesDisplay(r,n[o]),{index:m,result:f,context:d}}catch(f){d.workspace.setStepResult(d.stepIndex,!1);let g=f instanceof Error?f.message:String(f);return c.status="failed",c.error=g,this.updateParallelBranchesDisplay(r,n[o]),{index:m,error:f,context:d}}}),u=await Promise.all(a);return clearInterval(i),this.updateParallelBranchesDisplay(r,"",!0),q.default.done(),u}updateParallelBranchesDisplay(e,t,r=!1){let n=e.map(o=>{let i=o.index+1,a="",u="";switch(o.status){case"pending":a="\u25CB",u=`Branch ${i}: ${o.name} - Pending`;break;case"running":a=t,u=`Branch ${i}: ${o.name} - Running...`;break;case"success":a="\u2713",u=`Branch ${i}: ${o.name} - Completed`;break;case"failed":a="\u2717",u=`Branch ${i}: ${o.name} - Failed${o.error?`: ${o.error}`:""}`;break}return`${a} ${u}`});r?(0,q.default)(n.join(`
|
|
14
14
|
`)):(0,q.default)(n.join(`
|
|
15
|
-
`))}displayParallelResults(e,t,r){let n=!0,o=!1;console.log("");for(let a of e){if(!a)continue;o=!0;let{index:u,result:
|
|
15
|
+
`))}displayParallelResults(e,t,r){let n=!0,o=!1;console.log("");for(let a of e){if(!a)continue;o=!0;let{index:u,result:c,error:m,context:h}=a;if(m){n=!1;let d=`Branch ${u+1} failed: ${m instanceof Error?m.message:String(m)}`,f=W(d);console.error(f)}else if(c&&typeof c=="object"&&"stdout"in c){let d=c;if(n=n&&d.success,d.stdout.length>0||d.stderr.length>0||!d.success){let f=t[u],g=this.getBranchDisplayName(f,u);this.taskRunner.displayBufferedOutput(d,g,!1,h.lineNumber,h.fileName)}}}o||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let i=he(n);return console.log(i),n}mergeParallelResults(e){for(let t of e){let r=t.workspace.getAllFacts(),n=t.workspace.getAllVariables();for(let[o,i]of r)this.workspace.setFact(o,i);for(let[o,i]of n)this.workspace.setVariable(o,i)}}countExecutableBranches(e,t){let r=0;for(let n=0;n<e.length;n++){let o=e[n],i=t[n];o.when&&!new D(i.workspace).evaluate(o.when)||r++}return r}async executeParallelStep(e,t){let r=this.createParallelContexts(e,t),n=this.countExecutableBranches(e.parallel,r),o=de(n);console.log(o);let i=await this.executeParallelBranches(e.parallel,r),a=this.displayParallelResults(i,e.parallel,t);if(this.workspace.setStepResult(t.stepIndex,a),!a){let u=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Parallel step ${t.stepIndex}${u} failed: one or more branches failed`)}this.mergeParallelResults(r)}async executeFailStep(e,t){let r=new Error(e.fail.message);throw r.stack=void 0,r}};var $e=require("yaml"),se=require("zod");var l=require("zod"),Ue=l.z.object({file:l.z.string()}),Ye=l.z.object({var:l.z.union([l.z.string(),l.z.record(l.z.string(),l.z.string())]).optional(),has:l.z.string().optional()}),ze=l.z.object({status:l.z.object({fact:l.z.string(),is:l.z.enum(["ready","failed","pending"])})}),qe=l.z.object({step:l.z.object({success:l.z.boolean()}).optional(),last_step:l.z.enum(["success","failure"]).optional()}),Ze=l.z.object({choice:l.z.string()}),Ge=l.z.union([Ue,Ze,Ye,ze,qe]),E=l.z.lazy(()=>l.z.union([Ge,l.z.object({all:l.z.array(E)}),l.z.object({any:l.z.array(E)}),l.z.object({not:E})])),ke=l.z.lazy(()=>l.z.object({run:l.z.string(),timeout:l.z.number().optional(),retry:l.z.number().optional(),onError:ke.optional()})),ve=l.z.object({run:l.z.string(),when:E.optional(),timeout:l.z.number().optional(),retry:l.z.number().optional(),shell:l.z.array(l.z.string()).min(1,"shell must have at least one element").optional(),continue:l.z.boolean().optional(),onError:ke.optional()}),Xe=l.z.object({choose:l.z.object({message:l.z.string(),options:l.z.array(l.z.object({id:l.z.string(),label:l.z.string()})),as:l.z.string().optional()}),when:E.optional()}),Ke=l.z.object({prompt:l.z.object({message:l.z.string(),as:l.z.string(),default:l.z.string().optional(),validate:l.z.string().optional()}),when:E.optional()});function xe(s){if(!s||typeof s!="object")return{found:!1};let e=s;if("choose"in e)return{found:!0,type:"choose"};if("prompt"in e)return{found:!0,type:"prompt"};if("parallel"in e&&Array.isArray(e.parallel))for(let t of e.parallel){let r=xe(t);if(r.found)return r}return{found:!1}}var Re=l.z.lazy(()=>l.z.union([ve,l.z.object({parallel:l.z.array(l.z.lazy(()=>Re)),when:E.optional()}),l.z.object({fail:l.z.object({message:l.z.string()}),when:E.optional()})]).superRefine((s,e)=>{let t=xe(s);t.found&&e.addIssue({code:l.z.ZodIssueCode.custom,message:`'${t.type}' step is not allowed inside 'parallel' block (user input cannot run in parallel)`})})),Qe=l.z.lazy(()=>l.z.union([ve,Xe,Ke,l.z.object({parallel:l.z.array(Re),when:E.optional()}),l.z.object({fail:l.z.object({message:l.z.string()}),when:E.optional()})])),et=l.z.object({name:l.z.string().min(1,"Profile name must be non-empty"),var:l.z.record(l.z.string(),l.z.union([l.z.string(),l.z.number(),l.z.boolean()]).transform(String))}),tt=l.z.object({name:l.z.string().optional(),baseDir:l.z.string().optional(),shell:l.z.array(l.z.string()).min(1,"shell must have at least one element").optional(),profiles:l.z.array(et).optional(),steps:l.z.array(Qe).min(1,"Workflow must have at least one step")});function re(s){return tt.parse(s)}function Ee(s,e){let t=s.path;if(s.code==="custom"){let n=oe(t);return` - ${s.message}${n}`}if(s.message==="Invalid input"){let n=oe(t),o=rt(t,e);return o?` - ${o}${n}`:` - Invalid step type${n}`}let r=oe(t);return` - ${s.message}${r}`}function oe(s){if(s.length===0)return"";let e=[];for(let t=0;t<s.length;t++){let r=s[t],n=s[t+1];r==="steps"&&typeof n=="number"?(e.push(`step ${n+1}`),t++):r==="parallel"&&typeof n=="number"?(e.push(`parallel branch ${n+1}`),t++):typeof r=="string"&&r!=="steps"&&r!=="parallel"&&e.push(r)}return e.length>0?` (${e.join(" \u2192 ")})`:""}function w(s,e,t){let r=t?`
|
|
16
16
|
Reason: ${t}`:"";throw new Error(`Invalid workflow structure:
|
|
17
17
|
- ${e} (step ${s+1})${r}`)}function Ce(s,e,t=!1,r=[]){let n=["run","choose","prompt","parallel","fail"],o=n.find(i=>i in s);if(!o){let i=Object.keys(s).filter(a=>a!=="when");w(e,`Unknown step type. Found keys: [${i.join(", ")}]. Valid types: ${n.join(", ")}`)}if(o==="run"){let i=s.run;if(typeof i!="string"&&w(e,"'run' must be a string command"),i===""&&w(e,"'run' command cannot be empty"),"shell"in s&&s.shell!==void 0){Array.isArray(s.shell)||w(e,"'shell' must be an array");let a=s.shell;a.length===0&&w(e,"'shell' cannot be empty","Shell configuration must have at least one element (program name)");for(let u=0;u<a.length;u++)typeof a[u]!="string"&&w(e,`'shell[${u}]' must be a string`)}}if(o==="choose"){if(t){let u=r.join(" \u2192 ");throw new Error(`Invalid workflow structure:
|
|
18
18
|
- 'choose' step is not allowed inside 'parallel' block (step ${e+1}, ${u})
|
|
19
|
-
Reason: User input prompts cannot run in parallel`)}let i=s.choose;(!i||typeof i!="object")&&w(e,"'choose' must be an object with 'message' and 'options'");let a=i;(!a.message||typeof a.message!="string")&&w(e,"'choose.message' is required and must be a string"),Array.isArray(a.options)||w(e,"'choose.options' is required and must be an array"),a.options.length===0&&w(e,"'choose.options' cannot be empty","At least one option is required");for(let u=0;u<a.options.length;u++){let
|
|
19
|
+
Reason: User input prompts cannot run in parallel`)}let i=s.choose;(!i||typeof i!="object")&&w(e,"'choose' must be an object with 'message' and 'options'");let a=i;(!a.message||typeof a.message!="string")&&w(e,"'choose.message' is required and must be a string"),Array.isArray(a.options)||w(e,"'choose.options' is required and must be an array"),a.options.length===0&&w(e,"'choose.options' cannot be empty","At least one option is required");for(let u=0;u<a.options.length;u++){let c=a.options[u];(!c||typeof c!="object")&&w(e,`'choose.options[${u}]' must be an object with 'id' and 'label'`),(!c.id||typeof c.id!="string")&&w(e,`'choose.options[${u}].id' is required and must be a string`),(!c.label||typeof c.label!="string")&&w(e,`'choose.options[${u}].label' is required and must be a string`)}}if(o==="prompt"){if(t){let u=r.join(" \u2192 ");throw new Error(`Invalid workflow structure:
|
|
20
20
|
- 'prompt' step is not allowed inside 'parallel' block (step ${e+1}, ${u})
|
|
21
|
-
Reason: User input prompts cannot run in parallel`)}let i=s.prompt;(!i||typeof i!="object")&&w(e,"'prompt' must be an object with 'message' and 'as'");let a=i;(!a.message||typeof a.message!="string")&&w(e,"'prompt.message' is required and must be a string"),(!a.as||typeof a.as!="string")&&w(e,"'prompt.as' is required and must be a string","The 'as' field specifies the variable name to store the user's input")}if(o==="parallel"){let i=s.parallel;Array.isArray(i)||w(e,"'parallel' must be an array of steps"),i.length===0&&w(e,"'parallel' cannot be empty","At least one step is required");for(let a=0;a<i.length;a++){let u=i[a];(!u||typeof u!="object")&&w(e,`'parallel[${a}]' must be a valid step object`);let
|
|
21
|
+
Reason: User input prompts cannot run in parallel`)}let i=s.prompt;(!i||typeof i!="object")&&w(e,"'prompt' must be an object with 'message' and 'as'");let a=i;(!a.message||typeof a.message!="string")&&w(e,"'prompt.message' is required and must be a string"),(!a.as||typeof a.as!="string")&&w(e,"'prompt.as' is required and must be a string","The 'as' field specifies the variable name to store the user's input")}if(o==="parallel"){let i=s.parallel;Array.isArray(i)||w(e,"'parallel' must be an array of steps"),i.length===0&&w(e,"'parallel' cannot be empty","At least one step is required");for(let a=0;a<i.length;a++){let u=i[a];(!u||typeof u!="object")&&w(e,`'parallel[${a}]' must be a valid step object`);let c=[...r,`branch ${a+1}`];Ce(u,e,!0,c)}}if(o==="fail"){let i=s.fail;(!i||typeof i!="object")&&w(e,"'fail' must be an object with 'message'");let a=i;(!a.message||typeof a.message!="string")&&w(e,"'fail.message' is required and must be a string")}}function Pe(s){if(!s||typeof s!="object")throw new Error(`Invalid workflow structure:
|
|
22
22
|
- Workflow must be an object`);let e=s;if("name"in e&&e.name!==void 0&&typeof e.name!="string")throw new Error(`Invalid workflow structure:
|
|
23
23
|
- 'name' must be a string`);if("shell"in e&&e.shell!==void 0){if(!Array.isArray(e.shell))throw new Error(`Invalid workflow structure:
|
|
24
24
|
- 'shell' must be an array`);if(e.shell.length===0)throw new Error(`Invalid workflow structure:
|
|
@@ -29,13 +29,13 @@ Total execution time: ${o}`)),await t.save(),t.reset()}isStepSuccessful(e,t){ret
|
|
|
29
29
|
- 'steps' must be an array`);if(e.steps.length===0)throw new Error(`Invalid workflow structure:
|
|
30
30
|
- 'steps' cannot be empty
|
|
31
31
|
Reason: Workflow must have at least one step`);for(let t=0;t<e.steps.length;t++){let r=e.steps[t];if(!r||typeof r!="object")throw new Error(`Invalid workflow structure:
|
|
32
|
-
- Step ${t+1} must be an object`);Ce(r,t)}}function
|
|
32
|
+
- Step ${t+1} must be an object`);Ce(r,t)}}function rt(s,e){try{let t=e;for(let o of s)if(typeof o!="symbol")if(t&&typeof t=="object")t=t[o];else return null;if(!t||typeof t!="object")return null;let n=Object.keys(t);if(n.length>0){let o=["run","choose","prompt","parallel","fail"];if(!n.some(a=>o.includes(a)))return`Unknown step type. Found keys: [${n.join(", ")}]. Valid types: run, choose, prompt, parallel, fail`}return null}catch{return null}}function ie(s){let e=s;return"choose"in e&&(e.choose===null||e.choose===void 0)&&"message"in e&&"options"in e?{choose:{message:e.message,options:e.options,as:e.as},when:e.when}:"prompt"in e&&(e.prompt===null||e.prompt===void 0)&&"message"in e&&"as"in e?{prompt:{message:e.message,as:e.as,default:e.default,validate:e.validate},when:e.when}:"parallel"in e&&Array.isArray(e.parallel)?{...e,parallel:e.parallel.map(t=>ie(t))}:s}var G=class{parse(e){let t;try{t=(0,$e.parse)(e)}catch(r){throw new Error(`Invalid YAML format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(n=>ie(n)))}Pe(t);try{return re(t)}catch(r){if(r instanceof se.ZodError){let n=r.issues.map(o=>Ee(o,t)).filter(o=>o!==null).join(`
|
|
33
33
|
`);throw new Error(`Invalid workflow structure:
|
|
34
34
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
35
|
-
`),n=0,o=!1;for(let i=0;i<r.length;i++){let a=r[i].trim();if(a==="steps:"||a.startsWith("steps:")){o=!0;continue}o&&a.startsWith("-")&&t.set(n++,i+1)}return t}},
|
|
35
|
+
`),n=0,o=!1;for(let i=0;i<r.length;i++){let a=r[i].trim();if(a==="steps:"||a.startsWith("steps:")){o=!0;continue}o&&a.startsWith("-")&&t.set(n++,i+1)}return t}},ne=class{parse(e){let t;try{t=JSON.parse(e)}catch(r){throw new Error(`Invalid JSON format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(n=>ie(n)))}Pe(t);try{return re(t)}catch(r){if(r instanceof se.ZodError){let n=r.issues.map(o=>Ee(o,t)).filter(o=>o!==null).join(`
|
|
36
36
|
`);throw new Error(`Invalid workflow structure:
|
|
37
37
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
38
|
-
`),n=0,o=!1,i=!1;for(let a=0;a<r.length;a++){let
|
|
38
|
+
`),n=0,o=!1,i=!1;for(let a=0;a<r.length;a++){let c=r[a].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){o=!0,c.includes("[")&&(i=!0);continue}if(o&&c==="["){i=!0;continue}if(i&&c==="]"){i=!1,o=!1;continue}i&&c.startsWith("{")&&t.set(n++,a+1)}return t}};function ae(s){switch(s.toLowerCase().split(".").pop()){case"yaml":case"yml":return new G;case"json":return new ne;default:return new G}}var C=require("fs"),S=require("path"),le=require("url"),je={};function Me(){console.log=()=>{},console.error=()=>{},console.warn=()=>{},console.info=()=>{},process.stdout.write=()=>!0,process.stderr.write=()=>!0}function Ne(){return"0.2.16"}function Te(s){let e=s?(0,S.resolve)(s):process.cwd(),t=50,r=0;for(;r<t;){let n=(0,S.resolve)(e,"tp");try{if((0,C.existsSync)(n)&&(0,C.statSync)(n).isDirectory())return n}catch{}let o=(0,S.dirname)(e);if(o===e)break;e=o,r++}return null}var ot=(0,Be.promisify)(Ae.exec),O=new De.Command;O.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
|
|
39
39
|
|
|
40
40
|
Define workflows in YAML or JSON files with conditional execution, parallel tasks,
|
|
41
41
|
interactive prompts, and variable substitution.
|
|
@@ -73,7 +73,7 @@ Quick Start:
|
|
|
73
73
|
tp history remove # Remove a specific history
|
|
74
74
|
tp history remove-all # Remove all histories
|
|
75
75
|
|
|
76
|
-
`).version(
|
|
76
|
+
`).version(Ne()).addHelpText("after",`
|
|
77
77
|
Examples:
|
|
78
78
|
$ tp run workflow.yaml
|
|
79
79
|
$ tp run examples/simple-project/workflow.yaml
|
|
@@ -86,7 +86,7 @@ Resources:
|
|
|
86
86
|
\u{1F4DA} Documentation: https://task-pipeliner.racgoo.com/
|
|
87
87
|
\u{1F3A8} Visual Generator: https://task-pipeliner-generator.racgoo.com/
|
|
88
88
|
|
|
89
|
-
See README.md for complete DSL reference.`);
|
|
89
|
+
See README.md for complete DSL reference.`);O.command("run").description("Run a workflow from a YAML or JSON file").argument("[file]","Path to the workflow file (YAML or JSON, relative or absolute). If omitted, will search for workflows in the nearest tp directory.").option("-s, --silent","Run in silent mode (suppress console output)").option("-p, --profile <name>","Run in profile mode (use profile name)").addHelpText("after",`
|
|
90
90
|
Examples:
|
|
91
91
|
$ tp run workflow.yaml
|
|
92
92
|
$ tp run workflow.json
|
|
@@ -111,11 +111,11 @@ Workflow File Structure:
|
|
|
111
111
|
\u2022 all/any/not: Combine conditions
|
|
112
112
|
|
|
113
113
|
Supported formats: YAML (.yaml, .yml) and JSON (.json)
|
|
114
|
-
See README.md for complete DSL documentation.`).action(async(s,e)=>{try{let t=s??await
|
|
115
|
-
\u2717 No workflow file found`)),process.exit(1)),e.silent&&Me();let r=ae(t);console.log(p.default.blue(`Loading workflow from ${t}...`));let n=(0,ce.readFileSync)(t,"utf-8"),o=r.parse(n);if(!o.steps||!Array.isArray(o.steps))throw new Error("Invalid workflow: steps array is required");o._lineNumbers=r.extractStepLineNumbers(n),o._fileName=
|
|
116
|
-
`)),await new Z().execute(o),console.log(p.default.green(`
|
|
114
|
+
See README.md for complete DSL documentation.`).action(async(s,e)=>{try{let t=s??await st()??null;t||(console.error(p.default.red(`
|
|
115
|
+
\u2717 No workflow file found`)),process.exit(1)),e.silent&&Me();let r=ae(t);console.log(p.default.blue(`Loading workflow from ${t}...`));let n=(0,ce.readFileSync)(t,"utf-8"),o=r.parse(n);if(!o.steps||!Array.isArray(o.steps))throw new Error("Invalid workflow: steps array is required");let i;if(e.profile){let u=e.profile.trim();if(!o.profiles?.length)throw new Error(`Profile "${u}" requested but workflow has no "profiles" defined. Add a "profiles" section to your workflow file.`);let c=o.profiles.find(m=>m.name===u);if(!c){let m=o.profiles.map(h=>h.name).join(", ");throw new Error(`Profile "${u}" not found. Available profile(s): ${m}`)}i=c.var}o._lineNumbers=r.extractStepLineNumbers(n),o._fileName=it(t),o._filePath=(0,V.resolve)(t),console.log(p.default.green(`Starting workflow execution...
|
|
116
|
+
`)),await new Z().execute(o,i?{profileVars:i}:void 0),console.log(p.default.green(`
|
|
117
117
|
\u2713 Workflow completed successfully`))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(p.default.red(`
|
|
118
|
-
\u2717 Workflow failed: ${r}`)),process.exit(1)}});
|
|
118
|
+
\u2717 Workflow failed: ${r}`)),process.exit(1)}});O.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
|
|
119
119
|
Examples:
|
|
120
120
|
$ tp open generator
|
|
121
121
|
$ tp open docs
|
|
@@ -124,13 +124,13 @@ Targets:
|
|
|
124
124
|
generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
|
|
125
125
|
docs Open the documentation site (https://task-pipeliner.racgoo.com/)`).action(async s=>{let t={generator:"https://task-pipeliner-generator.racgoo.com/",docs:"https://task-pipeliner.racgoo.com/"}[s.toLowerCase()];t||(console.error(p.default.red(`
|
|
126
126
|
\u2717 Invalid target: ${s}`)),console.log(p.default.yellow(`
|
|
127
|
-
Valid targets:`)),console.log(p.default.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(p.default.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,n;r==="darwin"?n=`open "${t}"`:r==="win32"?n=`start "${t}"`:n=`xdg-open "${t}"`,await
|
|
127
|
+
Valid targets:`)),console.log(p.default.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(p.default.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,n;r==="darwin"?n=`open "${t}"`:r==="win32"?n=`start "${t}"`:n=`xdg-open "${t}"`,await ot(n),console.log(p.default.green(`
|
|
128
128
|
\u2713 Opening ${s==="generator"?"generator":"documentation"} in browser...`)),console.log(p.default.blue(` ${t}`))}catch(r){let n=r instanceof Error?r.message:String(r);console.error(p.default.red(`
|
|
129
129
|
\u2717 Failed to open browser: ${n}`)),console.log(p.default.yellow(`
|
|
130
|
-
Please visit manually: ${t}`)),process.exit(1)}});var nt=
|
|
130
|
+
Please visit manually: ${t}`)),process.exit(1)}});var nt=O.command("history").description("Manage workflow execution history");nt.action(async()=>{let s=new M,e=await s.prompt("Select an action",[{id:"show",label:"Show - View and select a history to view"},{id:"remove",label:"Remove - Delete a specific history file"},{id:"remove-all",label:"Remove All - Delete all history files"}]);e?.id||(console.error(p.default.red(`
|
|
131
131
|
\u2717 Invalid choice`)),process.exit(1));let t=new F;switch(e.id){case"show":{let r=await t.getHistoryNames();if(r.length===0){console.log(p.default.yellow(`
|
|
132
132
|
\u26A0 No history found`));return}let n=await s.prompt("Select a history to view",r.map(o=>({id:o,label:o})));n?.id||(console.error(p.default.red(`
|
|
133
|
-
\u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);
|
|
133
|
+
\u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);at(o,n.id)}catch(o){let i=o instanceof Error?o.message:String(o);console.error(p.default.red(`
|
|
134
134
|
\u2717 Failed to load history: ${i}`)),process.exit(1)}break}case"remove":{let r=await t.getHistoryNames();if(r.length===0){console.log(p.default.yellow(`
|
|
135
135
|
\u26A0 No history found`));return}let n=await s.prompt("Select a history to remove",r.map(o=>({id:o,label:o})));n?.id||(console.error(p.default.red(`
|
|
136
136
|
\u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(n.id),console.log(p.default.green(`
|
|
@@ -139,12 +139,12 @@ Please visit manually: ${t}`)),process.exit(1)}});var nt=_.command("history").de
|
|
|
139
139
|
\u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(p.default.green(`
|
|
140
140
|
\u2713 All histories removed`))}catch(n){let o=n instanceof Error?n.message:String(n);console.error(p.default.red(`
|
|
141
141
|
\u2717 Failed to remove histories: ${o}`)),process.exit(1)}break}default:console.error(p.default.red(`
|
|
142
|
-
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function
|
|
143
|
-
\u2717 No tp directory found`)),null;try{let t=(await(0,
|
|
144
|
-
\u2717 No workflow files found in ${s}`)),null;let r=await Promise.all(t.map(async i=>{let a=(0,
|
|
145
|
-
\u2717 Failed to read tp directory: ${t}`)),null}}function
|
|
146
|
-
`);let t=s.records.reduce((
|
|
147
|
-
`);console.log((0,ue.default)(u,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:"cyan"})),s.records.forEach((
|
|
148
|
-
`);console.log((0,ue.default)(u,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:s.status==="success"?"green":"red"})),
|
|
142
|
+
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function st(){let s=Te();if(!s)return console.error(p.default.red(`
|
|
143
|
+
\u2717 No tp directory found`)),null;try{let t=(await(0,Ie.readdir)(s)).filter(i=>{let a=(0,V.extname)(i).toLowerCase();return[".yaml",".yml",".json"].includes(a)});if(t.length===0)return console.error(p.default.red(`
|
|
144
|
+
\u2717 No workflow files found in ${s}`)),null;let r=await Promise.all(t.map(async i=>{let a=(0,V.join)(s,i);try{let u=ae(a),c=(0,ce.readFileSync)(a,"utf-8"),h=u.parse(c).name??"Untitled";return{id:a,label:`${i} - ${h}`}}catch{return{id:a,label:i}}}));return(await new M(!0).prompt("Select a workflow to run",r)).id}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(p.default.red(`
|
|
145
|
+
\u2717 Failed to read tp directory: ${t}`)),null}}function it(s){return s.split("/").pop()??s}function at(s,e){console.log(`
|
|
146
|
+
`);let t=s.records.reduce((c,m)=>c+m.duration,0),r=s.records.filter(c=>c.status==="success").length,n=s.records.filter(c=>c.status==="failure").length,o=(0,Le.default)(s.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),a=B(t),u=[p.default.bold("Workflow Execution History"),"",`${p.default.cyan("File:")} ${e}`,`${p.default.cyan("Started:")} ${o}`,`${p.default.cyan("Total Duration:")} ${a}`,`${p.default.cyan("Total Steps:")} ${s.records.length}`,`${p.default.green("\u2713 Successful:")} ${r}`,n>0?`${p.default.red("\u2717 Failed:")} ${n}`:""].filter(Boolean).join(`
|
|
147
|
+
`);console.log((0,ue.default)(u,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:"cyan"})),s.records.forEach((c,m)=>{lt(c,m+1,s.records.length)}),console.log("")}function lt(s,e,t){let r=ct(s.step),n=ut(s.step),o=s.status==="success"?p.default.green("\u2713"):p.default.red("\u2717"),i=s.status==="success"?p.default.green("Success"):p.default.red("Failed"),a=B(s.duration),u=[`${o} ${p.default.bold(`Step ${e}/${t}`)} - ${p.default.cyan(r)}`,`${p.default.gray("Duration:")} ${a} | ${p.default.gray("Status:")} ${i}`,"",p.default.white(n)].join(`
|
|
148
|
+
`);console.log((0,ue.default)(u,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:s.status==="success"?"green":"red"})),pt(s.output)&&ft(s.output)}function ct(s){return"run"in s?"Run":"choose"in s?"Choose":"prompt"in s?"Prompt":"parallel"in s?"Parallel":"fail"in s?"Fail":"Unknown"}function ut(s){return"run"in s?`Command: ${p.default.yellow(s.run)}`:"choose"in s?`Message: ${p.default.yellow(s.choose.message)}`:"prompt"in s?`Message: ${p.default.yellow(s.prompt.message)} | Variable: ${p.default.cyan(s.prompt.as)}`:"parallel"in s?`Parallel execution with ${s.parallel.length} branches`:"fail"in s?`Error: ${p.default.red(s.fail.message)}`:"Unknown step type"}function pt(s){return typeof s=="object"&&s!==null&&"success"in s&&"stdout"in s&&"stderr"in s}function ft(s){if(s.stdout.length>0){let e=s.stdout.map(t=>p.default.gray(` ${t}`)).join(`
|
|
149
149
|
`);console.log(p.default.green(" Output:")),console.log(e)}if(s.stderr.length>0){let e=s.stderr.map(t=>p.default.gray(` ${t}`)).join(`
|
|
150
|
-
`);console.log(p.default.red(" Errors:")),console.log(e)}}
|
|
150
|
+
`);console.log(p.default.red(" Errors:")),console.log(e)}}O.parse();
|