task-pipeliner 0.2.13 → 0.2.15
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 +88 -15
- package/README.md +89 -15
- package/dist/index.cjs +62 -45
- package/dist/index.d.ts +2 -2
- package/dist/task-pipeliner-rs.node +0 -0
- 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.15
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -293,6 +293,10 @@ baseDir: ./ # 선택사항: 명령 실행 기본 디
|
|
|
293
293
|
# - 상대 경로: YAML 파일 위치 기준으로 해석
|
|
294
294
|
# - 절대 경로: 그대로 사용
|
|
295
295
|
# - 생략 시: 현재 작업 디렉토리 사용
|
|
296
|
+
shell: # 선택사항: 모든 run 명령의 전역 쉘 설정
|
|
297
|
+
- bash # - 첫 번째 요소: 쉘 프로그램 (bash, zsh, sh 등)
|
|
298
|
+
- -lc # - 나머지: 쉘 인자 (-c, -lc 등)
|
|
299
|
+
# - 생략 시: 플랫폼 기본 쉘 사용
|
|
296
300
|
|
|
297
301
|
steps: # 필수: 실행할 단계 배열
|
|
298
302
|
- some-step-1
|
|
@@ -309,6 +313,10 @@ steps: # 필수: 실행할 단계 배열
|
|
|
309
313
|
// - 상대 경로: JSON 파일 위치 기준으로 해석
|
|
310
314
|
// - 절대 경로: 그대로 사용
|
|
311
315
|
// - 생략 시: 현재 작업 디렉토리 사용
|
|
316
|
+
"shell": ["bash", "-lc"], // 선택사항: 모든 run 명령의 전역 쉘 설정
|
|
317
|
+
// - 첫 번째 요소: 쉘 프로그램
|
|
318
|
+
// - 나머지: 쉘 인자
|
|
319
|
+
// - 생략 시: 플랫폼 기본 쉘 사용
|
|
312
320
|
"steps": [ // 필수: 실행할 단계 배열
|
|
313
321
|
{ /* some-step-1 */ },
|
|
314
322
|
{ /* some-step-2 */ }
|
|
@@ -334,6 +342,33 @@ steps: # 필수: 실행할 단계 배열
|
|
|
334
342
|
baseDir: /app/frontend # 절대 경로
|
|
335
343
|
```
|
|
336
344
|
|
|
345
|
+
#### `shell` (선택)
|
|
346
|
+
- **타입**: `string`의 `array`
|
|
347
|
+
- **설명**: 워크플로우 내 모든 `run` 명령에 대한 전역 쉘 설정
|
|
348
|
+
- **형식**: `[프로그램, ...인자]` - 첫 번째 요소는 쉘 프로그램, 나머지는 인자
|
|
349
|
+
- **우선순위**: 스텝별 `shell` > 워크플로우 `shell` > 사용자의 현재 쉘
|
|
350
|
+
- **사용자의 현재 쉘** (생략 시):
|
|
351
|
+
- **Linux/macOS**: `$SHELL` 환경변수 사용 (예: `/bin/zsh`, `/bin/bash`)
|
|
352
|
+
- **Windows**: `%COMSPEC%` 사용 (일반적으로 `cmd.exe`)
|
|
353
|
+
- **동작**: `tp run`을 실행한 쉘 환경과 동일한 환경에서 명령 실행
|
|
354
|
+
- **예제**:
|
|
355
|
+
```yaml
|
|
356
|
+
# Unix/Linux/macOS
|
|
357
|
+
shell: [bash, -lc] # bash 로그인 쉘 사용
|
|
358
|
+
shell: [zsh, -c] # zsh 사용
|
|
359
|
+
shell: [sh, -c] # sh 사용 (POSIX)
|
|
360
|
+
|
|
361
|
+
# Windows
|
|
362
|
+
shell: [cmd, /c] # 명령 프롬프트
|
|
363
|
+
shell: [powershell, -Command] # Windows PowerShell
|
|
364
|
+
shell: [pwsh, -Command] # PowerShell Core
|
|
365
|
+
```
|
|
366
|
+
- **크로스 플랫폼 예시**:
|
|
367
|
+
- **Linux/macOS**: `[bash, -lc]`, `[zsh, -c]`, `[/bin/bash, -c]`
|
|
368
|
+
- **Windows**: `[cmd, /c]`, `[powershell, -Command]`, `[pwsh, -Command]`
|
|
369
|
+
- **Git Bash (Windows)**: `[bash, -c]`
|
|
370
|
+
- **WSL**: `[wsl, bash, -c]` 또는 `wsl` 명령 직접 사용
|
|
371
|
+
|
|
337
372
|
#### `steps` (필수)
|
|
338
373
|
- **타입**: `Step` 객체의 `array`
|
|
339
374
|
- **설명**: 순차적으로 실행할 단계 목록
|
|
@@ -355,6 +390,7 @@ steps: # 필수: 실행할 단계 배열
|
|
|
355
390
|
when?: <condition> # 선택: 조건이 충족될 때만 실행
|
|
356
391
|
timeout?: <number> # 선택: 타임아웃 (초 단위)
|
|
357
392
|
retry?: <number> # 선택: 실패 시 재시도 횟수 (기본값: 0)
|
|
393
|
+
shell?: <array> # 선택: 쉘 설정 (workflow.shell 오버라이드)
|
|
358
394
|
continue?: <bool> # 선택: 이 스텝 이후 다음 스텝으로 진행할지 여부 (성공/실패 무관)
|
|
359
395
|
onError?: # 선택: 에러 처리 동작
|
|
360
396
|
run: <command> # 메인 run 명령이 실패했을 때 실행할 대체 명령 (사이드 이펙트)
|
|
@@ -368,6 +404,7 @@ steps: # 필수: 실행할 단계 배열
|
|
|
368
404
|
- `when` (선택): `Condition` - 실행 전 확인할 조건
|
|
369
405
|
- `timeout` (선택): `number` - 최대 실행 시간 (초 단위). 이 시간을 초과하면 명령이 종료됩니다.
|
|
370
406
|
- `retry` (선택): `number` - 실패 시 재시도 횟수 (기본값: 0, 재시도 없음)
|
|
407
|
+
- `shell` (선택): `string`의 `array` - 이 스텝의 쉘 설정. 워크플로우의 전역 `shell`을 오버라이드합니다. 형식: `[프로그램, ...인자]`. 예: `[bash, -lc]`, `[zsh, -c]`.
|
|
371
408
|
- `continue` (선택): `boolean` - 이 스텝 완료 후 다음 스텝으로 진행할지 여부를 제어합니다 (성공/실패와 무관).
|
|
372
409
|
- `continue: true` - 항상 다음 스텝으로 진행 (이 스텝이 실패해도)
|
|
373
410
|
- `continue: false` - 항상 워크플로우 중단 (이 스텝이 성공해도)
|
|
@@ -432,6 +469,18 @@ steps:
|
|
|
432
469
|
continue: true
|
|
433
470
|
onError:
|
|
434
471
|
run: echo "Type check failed, but continuing..."
|
|
472
|
+
|
|
473
|
+
# 커스텀 쉘 사용 (스텝별)
|
|
474
|
+
- run: echo $SHELL
|
|
475
|
+
shell:
|
|
476
|
+
- zsh
|
|
477
|
+
- -c
|
|
478
|
+
|
|
479
|
+
# bash 로그인 쉘 사용
|
|
480
|
+
- run: source ~/.bashrc && echo "프로필 로드됨"
|
|
481
|
+
shell:
|
|
482
|
+
- bash
|
|
483
|
+
- -lc
|
|
435
484
|
```
|
|
436
485
|
|
|
437
486
|
**동작:**
|
|
@@ -609,9 +658,11 @@ steps:
|
|
|
609
658
|
```
|
|
610
659
|
|
|
611
660
|
**속성:**
|
|
612
|
-
- `parallel` (필수):
|
|
661
|
+
- `parallel` (필수): 단계들의 `array` - 병렬로 실행할 단계. **`run`, 중첩 `parallel`, `fail` 스텝만 허용됩니다.** `choose`와 `prompt`(사용자 입력 스텝)는 `parallel` **안에서 사용할 수 없습니다**—사용자 입력은 병렬로 실행되지 않습니다.
|
|
613
662
|
- `when` (선택): `Condition` - 조건이 충족될 때만 병렬 블록 실행
|
|
614
663
|
|
|
664
|
+
**제한:** `parallel` 내부의 스텝은 `run`, 중첩 `parallel`, `fail`만 사용할 수 있습니다. `parallel` 안에서 `choose`나 `prompt`를 사용하면 안 되며, 워크플로우 검증 시 에러가 발생합니다 (예: `'choose' step is not allowed inside 'parallel' block`).
|
|
665
|
+
|
|
615
666
|
**예제:**
|
|
616
667
|
```yaml
|
|
617
668
|
# 기본 병렬 실행
|
|
@@ -640,20 +691,12 @@ steps:
|
|
|
640
691
|
- run: npm run test
|
|
641
692
|
- run: npm run lint
|
|
642
693
|
|
|
643
|
-
# parallel
|
|
694
|
+
# 중첩 parallel (허용); parallel 내부에는 run / parallel / fail만 사용
|
|
644
695
|
- parallel:
|
|
645
696
|
- run: npm run test
|
|
646
|
-
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
- id: yes
|
|
650
|
-
label: "예"
|
|
651
|
-
- id: no
|
|
652
|
-
label: "아니오"
|
|
653
|
-
as: runLint
|
|
654
|
-
- prompt:
|
|
655
|
-
message: "버전을 입력하세요:"
|
|
656
|
-
as: version
|
|
697
|
+
- parallel:
|
|
698
|
+
- run: npm run lint
|
|
699
|
+
- run: npm run typecheck
|
|
657
700
|
```
|
|
658
701
|
|
|
659
702
|
**동작:**
|
|
@@ -661,6 +704,7 @@ steps:
|
|
|
661
704
|
- 워크플로우는 모든 병렬 단계가 완료될 때까지 기다립니다
|
|
662
705
|
- 어떤 단계라도 실패하면 워크플로우가 중지됩니다
|
|
663
706
|
- 각 병렬 브랜치는 자체 격리된 워크스페이스 상태를 가집니다 (복제됨)
|
|
707
|
+
- **`choose`와 `prompt`는 `parallel` 안에서 사용할 수 없습니다** (사용자 입력은 병렬로 실행되지 않음; `parallel` 블록 앞뒤의 순차 스텝에서만 사용하세요)
|
|
664
708
|
|
|
665
709
|
---
|
|
666
710
|
|
|
@@ -989,11 +1033,36 @@ when:
|
|
|
989
1033
|
|
|
990
1034
|
### 변수 치환
|
|
991
1035
|
|
|
992
|
-
변수는 `{{variable}}` 문법을 사용하여 명령에서 사용할 수 있습니다.
|
|
1036
|
+
변수는 `{{variable}}` 문법을 사용하여 명령에서 사용할 수 있습니다. 선택적으로 공백을 사용할 수 있습니다: `{{var}}`, `{{ var }}`, `{{ var }}` 모두 작동합니다.
|
|
993
1037
|
|
|
994
1038
|
**문법:**
|
|
995
1039
|
```yaml
|
|
996
1040
|
run: echo "{{variableName}}"
|
|
1041
|
+
# 또는 선택적으로 공백 사용
|
|
1042
|
+
run: echo "{{ variableName }}"
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
**⚠️ 중요: YAML 문법 규칙**
|
|
1046
|
+
|
|
1047
|
+
명령어에서 `{{variable}}`을 사용할 때, 파싱 오류를 방지하기 위해 다음 규칙을 따르세요:
|
|
1048
|
+
|
|
1049
|
+
✅ **안전한 패턴:**
|
|
1050
|
+
```yaml
|
|
1051
|
+
# 단어로 시작 (따옴표 불필요)
|
|
1052
|
+
- run: echo "Building {{version}}..."
|
|
1053
|
+
- run: npm run build --version={{version}}
|
|
1054
|
+
|
|
1055
|
+
# 전체 명령어를 작은따옴표로 감싸기
|
|
1056
|
+
- run: 'echo "Selected: {{mode}}"'
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
❌ **문제가 되는 패턴:**
|
|
1060
|
+
```yaml
|
|
1061
|
+
# 금지: 따옴표 + 변수 앞 콜론
|
|
1062
|
+
- run: echo "mode: {{mode}}" # ❌ YAML 파싱 에러!
|
|
1063
|
+
|
|
1064
|
+
# 해결: 전체 명령어를 작은따옴표로 감싸기
|
|
1065
|
+
- run: 'echo "mode: {{mode}}"' # ✅ 정상 작동
|
|
997
1066
|
```
|
|
998
1067
|
|
|
999
1068
|
**예제:**
|
|
@@ -1082,6 +1151,10 @@ steps:
|
|
|
1082
1151
|
- run: npm run test:integration
|
|
1083
1152
|
- run: npm run lint
|
|
1084
1153
|
|
|
1154
|
+
# 6.5. 스텝별 쉘 오버라이드
|
|
1155
|
+
- run: echo "zsh로 실행"
|
|
1156
|
+
shell: [zsh, -c] # 이 스텝만 워크플로우 쉘 오버라이드
|
|
1157
|
+
|
|
1085
1158
|
# 7. 파일 존재 확인
|
|
1086
1159
|
- when:
|
|
1087
1160
|
file: ./test-results
|
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.15
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -293,6 +293,10 @@ baseDir: ./ # Optional: Base directory for command ex
|
|
|
293
293
|
# - Relative path: resolved from YAML file location
|
|
294
294
|
# - Absolute path: used as-is
|
|
295
295
|
# - If omitted: uses current working directory
|
|
296
|
+
shell: # Optional: Global shell configuration for all run commands
|
|
297
|
+
- bash # - First element: shell program (bash, zsh, sh, etc.)
|
|
298
|
+
- -lc # - Rest: shell arguments (-c, -lc, etc.)
|
|
299
|
+
# - If omitted: uses platform default shell
|
|
296
300
|
|
|
297
301
|
steps: # Required: Array of steps to execute
|
|
298
302
|
- some-step-1
|
|
@@ -309,6 +313,10 @@ steps: # Required: Array of steps to execute
|
|
|
309
313
|
// - Relative path: resolved from JSON file location
|
|
310
314
|
// - Absolute path: used as-is
|
|
311
315
|
// - If omitted: uses current working directory
|
|
316
|
+
"shell": ["bash", "-lc"], // Optional: Global shell configuration for all run commands
|
|
317
|
+
// - First element: shell program
|
|
318
|
+
// - Rest: shell arguments
|
|
319
|
+
// - If omitted: uses platform default shell
|
|
312
320
|
"steps": [ // Required: Array of steps to execute
|
|
313
321
|
{ /* some-step-1 */ },
|
|
314
322
|
{ /* some-step-2 */ }
|
|
@@ -334,6 +342,33 @@ steps: # Required: Array of steps to execute
|
|
|
334
342
|
baseDir: /app/frontend # Absolute path
|
|
335
343
|
```
|
|
336
344
|
|
|
345
|
+
#### `shell` (optional)
|
|
346
|
+
- **Type**: `array` of `string`
|
|
347
|
+
- **Description**: Global shell configuration for all `run` commands in the workflow
|
|
348
|
+
- **Format**: `[program, ...args]` - First element is the shell program, rest are arguments
|
|
349
|
+
- **Priority**: Step-level `shell` > Workflow-level `shell` > User's current shell
|
|
350
|
+
- **User's current shell** (when omitted):
|
|
351
|
+
- **Linux/macOS**: Uses `$SHELL` environment variable (e.g., `/bin/zsh`, `/bin/bash`)
|
|
352
|
+
- **Windows**: Uses `%COMSPEC%` (typically `cmd.exe`)
|
|
353
|
+
- **Behavior**: Commands run in the same shell environment as where you execute `tp run`
|
|
354
|
+
- **Example**:
|
|
355
|
+
```yaml
|
|
356
|
+
# Unix/Linux/macOS
|
|
357
|
+
shell: [bash, -lc] # Use bash login shell
|
|
358
|
+
shell: [zsh, -c] # Use zsh
|
|
359
|
+
shell: [sh, -c] # Use sh (POSIX)
|
|
360
|
+
|
|
361
|
+
# Windows
|
|
362
|
+
shell: [cmd, /c] # Command Prompt
|
|
363
|
+
shell: [powershell, -Command] # Windows PowerShell
|
|
364
|
+
shell: [pwsh, -Command] # PowerShell Core
|
|
365
|
+
```
|
|
366
|
+
- **Cross-platform examples**:
|
|
367
|
+
- **Linux/macOS**: `[bash, -lc]`, `[zsh, -c]`, `[/bin/bash, -c]`
|
|
368
|
+
- **Windows**: `[cmd, /c]`, `[powershell, -Command]`, `[pwsh, -Command]`
|
|
369
|
+
- **Git Bash (Windows)**: `[bash, -c]`
|
|
370
|
+
- **WSL**: `[wsl, bash, -c]` or use `wsl` command directly
|
|
371
|
+
|
|
337
372
|
#### `steps` (required)
|
|
338
373
|
- **Type**: `array` of `Step` objects
|
|
339
374
|
- **Description**: List of steps to execute sequentially
|
|
@@ -355,6 +390,7 @@ Execute a shell command.
|
|
|
355
390
|
when?: <condition> # Optional: Execute only if condition is met
|
|
356
391
|
timeout?: <number> # Optional: Timeout in seconds
|
|
357
392
|
retry?: <number> # Optional: Number of retries on failure (default: 0)
|
|
393
|
+
shell?: <array> # Optional: Shell configuration (overrides workflow.shell)
|
|
358
394
|
continue?: <bool> # Optional: Continue to next step after this step completes (regardless of success/failure)
|
|
359
395
|
onError?: # Optional: Error handling behavior
|
|
360
396
|
run: <command> # Fallback command when main run command fails (side effect)
|
|
@@ -368,6 +404,7 @@ Execute a shell command.
|
|
|
368
404
|
- `when` (optional): `Condition` - Condition to check before execution
|
|
369
405
|
- `timeout` (optional): `number` - Maximum execution time in seconds. Command will be killed if it exceeds this time.
|
|
370
406
|
- `retry` (optional): `number` - Number of retry attempts if command fails (default: 0, meaning no retry)
|
|
407
|
+
- `shell` (optional): `array` of `string` - Shell configuration for this step. Overrides workflow's global `shell`. Format: `[program, ...args]`. Example: `[bash, -lc]`, `[zsh, -c]`.
|
|
371
408
|
- `continue` (optional): `boolean` - Controls whether to proceed to the next step after this step completes, regardless of success or failure.
|
|
372
409
|
- `continue: true` - Always proceed to the next step (even if this step fails)
|
|
373
410
|
- `continue: false` - Always stop the workflow after this step (even if this step succeeds)
|
|
@@ -432,6 +469,18 @@ steps:
|
|
|
432
469
|
continue: true
|
|
433
470
|
onError:
|
|
434
471
|
run: echo "Type check failed, but continuing..."
|
|
472
|
+
|
|
473
|
+
# Command with custom shell (step-level)
|
|
474
|
+
- run: echo $SHELL
|
|
475
|
+
shell:
|
|
476
|
+
- zsh
|
|
477
|
+
- -c
|
|
478
|
+
|
|
479
|
+
# Command with bash login shell
|
|
480
|
+
- run: source ~/.bashrc && echo "Loaded profile"
|
|
481
|
+
shell:
|
|
482
|
+
- bash
|
|
483
|
+
- -lc
|
|
435
484
|
```
|
|
436
485
|
|
|
437
486
|
**Behavior:**
|
|
@@ -609,9 +658,11 @@ Execute multiple steps simultaneously. Like `steps`, `parallel` contains an arra
|
|
|
609
658
|
```
|
|
610
659
|
|
|
611
660
|
**Properties:**
|
|
612
|
-
- `parallel` (required): `array` of
|
|
661
|
+
- `parallel` (required): `array` of steps - Steps to execute in parallel. **Only `run`, nested `parallel`, and `fail` steps are allowed.** `choose` and `prompt` (user input steps) are **not allowed** inside `parallel`—user input cannot run in parallel.
|
|
613
662
|
- `when` (optional): `Condition` - Execute parallel block only if condition is met
|
|
614
663
|
|
|
664
|
+
**Restriction:** Steps inside `parallel` may only be `run`, nested `parallel`, or `fail`. Do **not** use `choose` or `prompt` inside `parallel`; the workflow validator will reject it and report an error (e.g. `'choose' step is not allowed inside 'parallel' block`).
|
|
665
|
+
|
|
615
666
|
**Examples:**
|
|
616
667
|
```yaml
|
|
617
668
|
# Basic parallel execution
|
|
@@ -640,20 +691,12 @@ Execute multiple steps simultaneously. Like `steps`, `parallel` contains an arra
|
|
|
640
691
|
- run: npm run test
|
|
641
692
|
- run: npm run lint
|
|
642
693
|
|
|
643
|
-
# parallel
|
|
694
|
+
# Nested parallel (allowed); only run / parallel / fail inside parallel
|
|
644
695
|
- parallel:
|
|
645
696
|
- run: npm run test
|
|
646
|
-
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
- id: yes
|
|
650
|
-
label: "Yes"
|
|
651
|
-
- id: no
|
|
652
|
-
label: "No"
|
|
653
|
-
as: runLint
|
|
654
|
-
- prompt:
|
|
655
|
-
message: "Enter version:"
|
|
656
|
-
as: version
|
|
697
|
+
- parallel:
|
|
698
|
+
- run: npm run lint
|
|
699
|
+
- run: npm run typecheck
|
|
657
700
|
```
|
|
658
701
|
|
|
659
702
|
**Behavior:**
|
|
@@ -661,6 +704,7 @@ Execute multiple steps simultaneously. Like `steps`, `parallel` contains an arra
|
|
|
661
704
|
- Workflow waits for all parallel steps to complete before continuing
|
|
662
705
|
- If any step fails, the workflow stops
|
|
663
706
|
- Each parallel branch has its own isolated workspace state (cloned)
|
|
707
|
+
- **`choose` and `prompt` are not allowed inside `parallel`** (user input cannot run in parallel; use them in sequential steps before or after a `parallel` block)
|
|
664
708
|
|
|
665
709
|
---
|
|
666
710
|
|
|
@@ -989,11 +1033,36 @@ Nest conditions to create complex logic.
|
|
|
989
1033
|
|
|
990
1034
|
### Variable Substitution
|
|
991
1035
|
|
|
992
|
-
Variables can be used in commands using the `{{variable}}` syntax.
|
|
1036
|
+
Variables can be used in commands using the `{{variable}}` syntax. Optional whitespace is supported: `{{var}}`, `{{ var }}`, `{{ var }}` all work.
|
|
993
1037
|
|
|
994
1038
|
**Syntax:**
|
|
995
1039
|
```yaml
|
|
996
1040
|
run: echo "{{variableName}}"
|
|
1041
|
+
# or with optional spaces
|
|
1042
|
+
run: echo "{{ variableName }}"
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
**⚠️ Important YAML Syntax Rules:**
|
|
1046
|
+
|
|
1047
|
+
When using `{{variable}}` in commands, follow these rules to avoid parsing errors:
|
|
1048
|
+
|
|
1049
|
+
✅ **Safe patterns:**
|
|
1050
|
+
```yaml
|
|
1051
|
+
# Start with a word (no quotes needed)
|
|
1052
|
+
- run: echo "Building {{version}}..."
|
|
1053
|
+
- run: npm run build --version={{version}}
|
|
1054
|
+
|
|
1055
|
+
# Wrap entire command in single quotes
|
|
1056
|
+
- run: 'echo "Selected: {{mode}}"'
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
❌ **Problematic patterns:**
|
|
1060
|
+
```yaml
|
|
1061
|
+
# DO NOT: quotes + colons before variables
|
|
1062
|
+
- run: echo "mode: {{mode}}" # ❌ YAML parsing error!
|
|
1063
|
+
|
|
1064
|
+
# FIX: Wrap entire command in single quotes
|
|
1065
|
+
- run: 'echo "mode: {{mode}}"' # ✅ Works correctly
|
|
997
1066
|
```
|
|
998
1067
|
|
|
999
1068
|
**Examples:**
|
|
@@ -1031,6 +1100,7 @@ A complete example demonstrating all features:
|
|
|
1031
1100
|
```yaml
|
|
1032
1101
|
name: Complete Workflow Example
|
|
1033
1102
|
baseDir: ./
|
|
1103
|
+
shell: [bash, -c] # Optional: Use bash for all steps (default: user's current shell)
|
|
1034
1104
|
|
|
1035
1105
|
steps:
|
|
1036
1106
|
# 1. Simple command
|
|
@@ -1082,6 +1152,10 @@ steps:
|
|
|
1082
1152
|
- run: npm run test:integration
|
|
1083
1153
|
- run: npm run lint
|
|
1084
1154
|
|
|
1155
|
+
# 6.5. Step-level shell override
|
|
1156
|
+
- run: echo "Running with zsh"
|
|
1157
|
+
shell: [zsh, -c] # Override workflow shell for this step only
|
|
1158
|
+
|
|
1085
1159
|
# 7. File existence check
|
|
1086
1160
|
- when:
|
|
1087
1161
|
file: ./test-results
|
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
`){i.length>0&&(
|
|
4
|
-
`)),g=
|
|
5
|
-
`)),
|
|
6
|
-
`),
|
|
7
|
-
`);let
|
|
2
|
+
"use strict";var Fe=Object.create;var pe=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var Oe=Object.getOwnPropertyNames;var _e=Object.getPrototypeOf,Ve=Object.prototype.hasOwnProperty;var He=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Oe(e))!Ve.call(s,n)&&n!==t&&pe(s,n,{get:()=>e[n],enumerable:!(r=We(e,n))||r.enumerable});return s};var x=(s,e,t)=>(t=s!=null?Fe(_e(s)):{},He(e||!s||!s.__esModule?pe(t,"default",{value:s,enumerable:!0}):t,s));var Ae=require("child_process"),ce=require("fs"),Be=require("fs/promises"),W=require("path"),Ie=require("util"),ue=x(require("boxen"),1),p=x(require("chalk"),1),De=require("commander"),Le=x(require("dayjs"),1);var N=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`))}},l=()=>{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="",l(),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),l(),u());return}f.length===1&&f>=" "&&f<="~"&&(n+=f,l(),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)})}},V=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 B(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=I(t);return`${n} ${A.default.gray(`(${o})`)}`}return n}function O(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 I(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"),T=require("path"),ye=x(require("dayjs"),1),L=(0,T.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,T.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,T.join)(L,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,R.readdir)(L)).map(r=>(0,T.basename)(r));return t.sort((r,n)=>{let o=u=>{let l=u.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return l?l[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,T.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,l,m,h){return o?this.runBuffered(e,l,m,h):this.runRealtime(e,r||e,i,a,u,l,m,h)}async runBuffered(e,t,r,n){return new Promise((o,i)=>{let a=this.spawnWithShell(e,t,n),u=[],l=[],m="",h="",d=null;r&&r>0&&(d=setTimeout(()=>{a.kill("SIGTERM");let f=`Command timed out after ${r} seconds`;l.push(f),o({success:!1,stdout:u,stderr:l})},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);l.push(...b),h=y}),a.on("close",f=>{d&&clearTimeout(d),m.trim()&&u.push(m),h.trim()&&l.push(h),o({success:f===0,stdout:u,stderr:l})}),a.on("error",f=>{d&&clearTimeout(d);let g=`Error: ${f.message}`;o({success:!1,stdout:u,stderr:[...l,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`,$=O(k);console.error($);let P=Date.now()-h,j=B(!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
|
+
`)),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
|
+
`)),b=j}),f.on("close",k=>{y&&clearTimeout(y),g.trim()&&process.stdout.write(`\u2502 ${g}
|
|
6
|
+
`),b.trim()&&process.stderr.write(`\u2502 ${b}
|
|
7
|
+
`);let $=k===0,P=Date.now()-h,j=B($,!1,P);console.log(j),d($)}),f.on("error",k=>{y&&clearTimeout(y);let $=O(`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=
|
|
11
|
-
`)}),e.stderr.forEach(
|
|
12
|
-
`)});let a=
|
|
13
|
-
Total execution time: ${o}`)),await t.save(),t.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 l=this.workspace.getStepResult(r);return l?l.success:!0})():this.isStepSuccessful(n,e),a=i?"success":"failure",
|
|
14
|
-
`)):(0,
|
|
15
|
-
`))}displayParallelResults(e,t,r){let n=!0,o=!1;console.log("");for(let a of e){if(!a)continue;o=!0;let{index:
|
|
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 l=ee(u,r);process.stdout.write(`${l}
|
|
11
|
+
`)}),e.stderr.forEach(u=>{let l=ee(u,r);process.stderr.write(`${l}
|
|
12
|
+
`)});let a=B(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 V}resolveBaseDir(e){if(e.baseDir)if((0,N.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,N.dirname)(e._filePath);this.baseDir=(0,N.resolve)(t,e.baseDir)}else this.baseDir=(0,N.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){this.resolveBaseDir(e),this.globalShell=e.shell;let t=new J,r=Date.now();for(let i=0;i<e.steps.length;i++){let a=e.steps[i],u=this.createStepContext(i,e),l=!!a.when;if(this.evaluateStepCondition(a)){t.recordStart();try{let m=await this.executeStep(a,u,!1,l);this.handleStepResult(a,u,i,m,t)}catch(m){throw this.handleStepError(a,u,i,m,t),m}}}let n=Date.now()-r,o=I(n);console.log(Se.default.cyan(`
|
|
13
|
+
Total execution time: ${o}`)),await t.save(),t.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 l=this.workspace.getStepResult(r);return l?l.success:!0})():this.isStepSuccessful(n,e),a=i?"success":"failure",u=o.recordEnd(e,t,n,a);if(!this.isRunStep(e)){let l=B(i,!1,u);console.log(l)}if(this.isRunStep(e)){if(e.continue===!1){let l=t.lineNumber?` (line ${t.lineNumber})`:"",m=i?`Step ${r}${l} completed, but workflow stopped due to continue: false`:`Step ${r}${l} failed`;throw new Error(m)}if(!i&&e.continue!==!0){let l=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${r}${l} 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,l=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,l,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=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!r?.id)throw new Error(`Invalid choice result: ${JSON.stringify(r)}`);let n=e.choose.as??r.id;this.workspace.setChoice(r.id,r.id),this.workspace.setVariable(n,r.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let r=Y(e.prompt.message,this.workspace),n=e.prompt.default?Y(e.prompt.default,this.workspace):void 0,o=await this.textPrompt.prompt(r,n);this.workspace.setVariable(e.prompt.as,o),this.workspace.setFact(e.prompt.as,o),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 l=0;l<e.length;l++){let m=e[l],h=t[l];if(m.when&&!new D(h.workspace).evaluate(m.when))continue;let d=this.getBranchDisplayName(m,l);r.push({index:l,name:d,status:"pending"})}let i=setInterval(()=>{o=(o+1)%n.length,this.updateParallelBranchesDisplay(r,n[o])},100),a=r.map(async l=>{let{index:m}=l,h=e[m],d=t[m];l.status="running";try{let f=await this.executeStep(h,d,!0);return l.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 l.status="failed",l.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
|
+
`)):(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:l,error:m,context:h}=a;if(m){n=!1;let d=`Branch ${u+1} failed: ${m instanceof Error?m.message:String(m)}`,f=O(d);console.error(f)}else if(l&&typeof l=="object"&&"stdout"in l){let d=l;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 c=require("zod"),Ue=c.z.object({file:c.z.string()}),Ye=c.z.object({var:c.z.union([c.z.string(),c.z.record(c.z.string(),c.z.string())]).optional(),has:c.z.string().optional()}),ze=c.z.object({status:c.z.object({fact:c.z.string(),is:c.z.enum(["ready","failed","pending"])})}),qe=c.z.object({step:c.z.object({success:c.z.boolean()}).optional(),last_step:c.z.enum(["success","failure"]).optional()}),Ze=c.z.object({choice:c.z.string()}),Ge=c.z.union([Ue,Ze,Ye,ze,qe]),E=c.z.lazy(()=>c.z.union([Ge,c.z.object({all:c.z.array(E)}),c.z.object({any:c.z.array(E)}),c.z.object({not:E})])),ke=c.z.lazy(()=>c.z.object({run:c.z.string(),timeout:c.z.number().optional(),retry:c.z.number().optional(),onError:ke.optional()})),ve=c.z.object({run:c.z.string(),when:E.optional(),timeout:c.z.number().optional(),retry:c.z.number().optional(),shell:c.z.array(c.z.string()).min(1,"shell must have at least one element").optional(),continue:c.z.boolean().optional(),onError:ke.optional()}),Xe=c.z.object({choose:c.z.object({message:c.z.string(),options:c.z.array(c.z.object({id:c.z.string(),label:c.z.string()})),as:c.z.string().optional()}),when:E.optional()}),Ke=c.z.object({prompt:c.z.object({message:c.z.string(),as:c.z.string(),default:c.z.string().optional(),validate:c.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=c.z.lazy(()=>c.z.union([ve,c.z.object({parallel:c.z.array(c.z.lazy(()=>Re)),when:E.optional()}),c.z.object({fail:c.z.object({message:c.z.string()}),when:E.optional()})]).superRefine((s,e)=>{let t=xe(s);t.found&&e.addIssue({code:c.z.ZodIssueCode.custom,message:`'${t.type}' step is not allowed inside 'parallel' block (user input cannot run in parallel)`})})),Qe=c.z.lazy(()=>c.z.union([ve,Xe,Ke,c.z.object({parallel:c.z.array(Re),when:E.optional()}),c.z.object({fail:c.z.object({message:c.z.string()}),when:E.optional()})])),et=c.z.object({name:c.z.string().optional(),baseDir:c.z.string().optional(),shell:c.z.array(c.z.string()).min(1,"shell must have at least one element").optional(),steps:c.z.array(Qe).min(1,"Workflow must have at least one step")});function re(s){return et.parse(s)}function Ee(s,e){let t=s.path;if(s.code==="custom"){let n=ne(t);return` - ${s.message}${n}`}if(s.message==="Invalid input"){let n=ne(t),o=tt(t,e);return o?` - ${o}${n}`:` - Invalid step type${n}`}let r=ne(t);return` - ${s.message}${r}`}function ne(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
|
+
Reason: ${t}`:"";throw new Error(`Invalid workflow structure:
|
|
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
|
+
- '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 l=a.options[u];(!l||typeof l!="object")&&w(e,`'choose.options[${u}]' must be an object with 'id' and 'label'`),(!l.id||typeof l.id!="string")&&w(e,`'choose.options[${u}].id' is required and must be a string`),(!l.label||typeof l.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
|
+
- '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 l=[...r,`branch ${a+1}`];Ce(u,e,!0,l)}}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
|
+
- 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
|
+
- '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
|
+
- 'shell' must be an array`);if(e.shell.length===0)throw new Error(`Invalid workflow structure:
|
|
25
|
+
- 'shell' cannot be empty
|
|
26
|
+
Reason: Shell configuration must have at least one element (program name)`);for(let t=0;t<e.shell.length;t++)if(typeof e.shell[t]!="string")throw new Error(`Invalid workflow structure:
|
|
27
|
+
- 'shell[${t}]' must be a string`)}if(!("steps"in e))throw new Error(`Invalid workflow structure:
|
|
28
|
+
- 'steps' is required`);if(!Array.isArray(e.steps))throw new Error(`Invalid workflow structure:
|
|
29
|
+
- 'steps' must be an array`);if(e.steps.length===0)throw new Error(`Invalid workflow structure:
|
|
30
|
+
- 'steps' cannot be empty
|
|
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 tt(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(`
|
|
16
33
|
`);throw new Error(`Invalid workflow structure:
|
|
17
34
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
18
|
-
`),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}},oe=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(`
|
|
19
36
|
`);throw new Error(`Invalid workflow structure:
|
|
20
37
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
21
|
-
`),n=0,o=!1,i=!1;for(let a=0;a<r.length;a++){let l=r[a].trim();if(l.startsWith('"steps"')||l.startsWith("'steps'")){o=!0,l.includes("[")&&(i=!0);continue}if(o&&l==="["){i=!0;continue}if(i&&l==="]"){i=!1,o=!1;continue}i&&l.startsWith("{")&&t.set(n++,a+1)}return t}};function
|
|
38
|
+
`),n=0,o=!1,i=!1;for(let a=0;a<r.length;a++){let l=r[a].trim();if(l.startsWith('"steps"')||l.startsWith("'steps'")){o=!0,l.includes("[")&&(i=!0);continue}if(o&&l==="["){i=!0;continue}if(i&&l==="]"){i=!1,o=!1;continue}i&&l.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 oe;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 Te(){return"0.2.15"}function Ne(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 rt=(0,Ie.promisify)(Ae.exec),_=new De.Command;_.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
|
|
22
39
|
|
|
23
40
|
Define workflows in YAML or JSON files with conditional execution, parallel tasks,
|
|
24
41
|
interactive prompts, and variable substitution.
|
|
@@ -56,7 +73,7 @@ Quick Start:
|
|
|
56
73
|
tp history remove # Remove a specific history
|
|
57
74
|
tp history remove-all # Remove all histories
|
|
58
75
|
|
|
59
|
-
`).version(
|
|
76
|
+
`).version(Te()).addHelpText("after",`
|
|
60
77
|
Examples:
|
|
61
78
|
$ tp run workflow.yaml
|
|
62
79
|
$ tp run examples/simple-project/workflow.yaml
|
|
@@ -94,10 +111,10 @@ Workflow File Structure:
|
|
|
94
111
|
\u2022 all/any/not: Combine conditions
|
|
95
112
|
|
|
96
113
|
Supported formats: YAML (.yaml, .yml) and JSON (.json)
|
|
97
|
-
See README.md for complete DSL documentation.`).action(async(s,e)=>{try{let t=s??await
|
|
98
|
-
\u2717 No workflow file found`)),process.exit(1)),e.silent&&
|
|
99
|
-
`)),await new Z().execute(o),console.log(
|
|
100
|
-
\u2713 Workflow completed successfully`))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(
|
|
114
|
+
See README.md for complete DSL documentation.`).action(async(s,e)=>{try{let t=s??await ot()??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");o._lineNumbers=r.extractStepLineNumbers(n),o._fileName=st(t),o._filePath=(0,W.resolve)(t),console.log(p.default.green(`Starting workflow execution...
|
|
116
|
+
`)),await new Z().execute(o),console.log(p.default.green(`
|
|
117
|
+
\u2713 Workflow completed successfully`))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(p.default.red(`
|
|
101
118
|
\u2717 Workflow failed: ${r}`)),process.exit(1)}});_.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
|
|
102
119
|
Examples:
|
|
103
120
|
$ tp open generator
|
|
@@ -105,29 +122,29 @@ Examples:
|
|
|
105
122
|
|
|
106
123
|
Targets:
|
|
107
124
|
generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
|
|
108
|
-
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(
|
|
109
|
-
\u2717 Invalid target: ${s}`)),console.log(
|
|
110
|
-
Valid targets:`)),console.log(
|
|
111
|
-
\u2713 Opening ${s==="generator"?"generator":"documentation"} in browser...`)),console.log(
|
|
112
|
-
\u2717 Failed to open browser: ${n}`)),console.log(
|
|
113
|
-
Please visit manually: ${t}`)),process.exit(1)}});var
|
|
114
|
-
\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(
|
|
115
|
-
\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(
|
|
116
|
-
\u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);
|
|
117
|
-
\u2717 Failed to load history: ${i}`)),process.exit(1)}break}case"remove":{let r=await t.getHistoryNames();if(r.length===0){console.log(
|
|
118
|
-
\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(
|
|
119
|
-
\u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(n.id),console.log(
|
|
120
|
-
\u2713 Removed history: ${n.id}`))}catch(o){let i=o instanceof Error?o.message:String(o);console.error(
|
|
121
|
-
\u2717 Failed to remove history: ${i}`)),process.exit(1)}break}case"remove-all":{if((await s.prompt("Are you sure you want to remove all histories?",[{id:"yes",label:"Yes, remove all"},{id:"no",label:"No, cancel"}]))?.id!=="yes"){console.log(
|
|
122
|
-
\u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(
|
|
123
|
-
\u2713 All histories removed`))}catch(n){let o=n instanceof Error?n.message:String(n);console.error(
|
|
124
|
-
\u2717 Failed to remove histories: ${o}`)),process.exit(1)}break}default:console.error(
|
|
125
|
-
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function
|
|
126
|
-
\u2717 No tp directory found`)),null;try{let t=(await(0,
|
|
127
|
-
\u2717 No workflow files found in ${s}`)),null;let r=await Promise.all(t.map(async i=>{let a=(0,
|
|
128
|
-
\u2717 Failed to read tp directory: ${t}`)),null}}function
|
|
129
|
-
`);let t=s.records.reduce((l,
|
|
130
|
-
`);console.log((0,
|
|
131
|
-
`);console.log((0,
|
|
132
|
-
`);console.log(
|
|
133
|
-
`);console.log(
|
|
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
|
+
\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 rt(n),console.log(p.default.green(`
|
|
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
|
+
\u2717 Failed to open browser: ${n}`)),console.log(p.default.yellow(`
|
|
130
|
+
Please visit manually: ${t}`)),process.exit(1)}});var nt=_.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
|
+
\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
|
+
\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);it(o,n.id)}catch(o){let i=o instanceof Error?o.message:String(o);console.error(p.default.red(`
|
|
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
|
+
\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
|
+
\u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(n.id),console.log(p.default.green(`
|
|
137
|
+
\u2713 Removed history: ${n.id}`))}catch(o){let i=o instanceof Error?o.message:String(o);console.error(p.default.red(`
|
|
138
|
+
\u2717 Failed to remove history: ${i}`)),process.exit(1)}break}case"remove-all":{if((await s.prompt("Are you sure you want to remove all histories?",[{id:"yes",label:"Yes, remove all"},{id:"no",label:"No, cancel"}]))?.id!=="yes"){console.log(p.default.yellow(`
|
|
139
|
+
\u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(p.default.green(`
|
|
140
|
+
\u2713 All histories removed`))}catch(n){let o=n instanceof Error?n.message:String(n);console.error(p.default.red(`
|
|
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 ot(){let s=Ne();if(!s)return console.error(p.default.red(`
|
|
143
|
+
\u2717 No tp directory found`)),null;try{let t=(await(0,Be.readdir)(s)).filter(i=>{let a=(0,W.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,W.join)(s,i);try{let u=ae(a),l=(0,ce.readFileSync)(a,"utf-8"),h=u.parse(l).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 st(s){return s.split("/").pop()??s}function it(s,e){console.log(`
|
|
146
|
+
`);let t=s.records.reduce((l,m)=>l+m.duration,0),r=s.records.filter(l=>l.status==="success").length,n=s.records.filter(l=>l.status==="failure").length,o=(0,Le.default)(s.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),a=I(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((l,m)=>{at(l,m+1,s.records.length)}),console.log("")}function at(s,e,t){let r=lt(s.step),n=ct(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=I(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"})),ut(s.output)&&pt(s.output)}function lt(s){return"run"in s?"Run":"choose"in s?"Choose":"prompt"in s?"Prompt":"parallel"in s?"Parallel":"fail"in s?"Fail":"Unknown"}function ct(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 ut(s){return typeof s=="object"&&s!==null&&"success"in s&&"stdout"in s&&"stderr"in s}function pt(s){if(s.stdout.length>0){let e=s.stdout.map(t=>p.default.gray(` ${t}`)).join(`
|
|
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)}}_.parse();
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
|
|
4
4
|
/* auto-generated by NAPI-RS */
|
|
5
5
|
|
|
6
|
-
export declare function runTask(command: string): Promise<boolean>
|
|
7
|
-
export declare function runTaskSync(command: string): boolean
|
|
6
|
+
export declare function runTask(command: string, shell?: Array<string> | undefined | null): Promise<boolean>
|
|
7
|
+
export declare function runTaskSync(command: string, shell?: Array<string> | undefined | null): boolean
|
|
Binary file
|