task-pipeliner 0.2.16 → 0.2.17

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 조건 기반 작업 파이프라인 실행기로 아름다운 CLI 출력을 제공합니다
4
4
 
5
- **버전:** 0.2.16
5
+ **버전:** 0.2.17
6
6
 
7
7
  ![fox2](https://github.com/user-attachments/assets/fdf8d786-6a91-4d2d-9dc1-72be6f3ccd98)
8
8
 
@@ -29,6 +29,8 @@
29
29
 
30
30
  - **실행 히스토리** - 상세한 단계별 기록으로 과거 워크플로우 실행 추적 및 검토
31
31
 
32
+ - **워크플로우 스케줄링** - cron 표현식을 사용하여 지정된 시간에 워크플로우 자동 실행
33
+
32
34
  ## 리소스
33
35
 
34
36
  ### 문서 및 도구
@@ -69,6 +71,16 @@ tp history remove # 특정 히스토리 삭제
69
71
  tp history remove-all # 모든 히스토리 삭제
70
72
  ```
71
73
 
74
+ **워크플로우 스케줄링:**
75
+ ```bash
76
+ tp schedule # 모든 스케줄 보기
77
+ tp schedule add schedules.yaml # 스케줄 파일에서 스케줄 추가
78
+ tp schedule remove # 스케줄 삭제
79
+ tp schedule remove-all # 모든 스케줄 삭제
80
+ tp schedule toggle # 스케줄 활성화/비활성화
81
+ tp schedule start # 스케줄러 데몬 시작
82
+ ```
83
+
72
84
  ## 🚀 빠른 시작
73
85
 
74
86
  ### 설치
@@ -1318,6 +1330,154 @@ tp history remove-all -y # 확인 건너뛰기
1318
1330
 
1319
1331
  ---
1320
1332
 
1333
+ ## ⏰ 워크플로우 스케줄링
1334
+
1335
+ cron 표현식을 사용하여 지정된 시간에 워크플로우를 자동으로 실행하도록 예약할 수 있습니다.
1336
+
1337
+ ### 스케줄 추가
1338
+
1339
+ 스케줄을 정의하는 스케줄 파일(YAML 또는 JSON)을 생성하세요:
1340
+
1341
+ **YAML (`schedules.yaml`):**
1342
+ ```yaml
1343
+ schedules:
1344
+ - name: Daily Build # 스케줄 별칭 (구분용)
1345
+ cron: "0 9 * * *" # Cron 표현식
1346
+ workflow: ./build.yaml # 스케줄 파일 기준 상대 경로
1347
+
1348
+ - name: Nightly Test
1349
+ cron: "0 2 * * *"
1350
+ workflow: ./test.yaml
1351
+ silent: true # 선택사항: 무음 모드로 실행
1352
+
1353
+ - name: Production Deploy
1354
+ cron: "0 18 * * 5" # 매주 금요일 오후 6시
1355
+ workflow: ./deploy.yaml
1356
+ profile: Production # 선택사항: 특정 프로필 사용
1357
+
1358
+ - name: Hourly Check
1359
+ cron: "0 * * * *"
1360
+ workflow: simple.yaml
1361
+ baseDir: /path/to/workflows # 선택사항: 워크플로우 경로의 기준 디렉토리
1362
+ ```
1363
+
1364
+ **필드 설명:**
1365
+ - `name`: 스케줄을 구분하기 위한 별칭
1366
+ - `cron`: 실행 시간 (cron 표현식)
1367
+ - `workflow`: 워크플로우 파일 경로 (스케줄 파일 또는 `baseDir` 기준 상대 경로, 또는 절대 경로)
1368
+ - `baseDir`: (선택사항) 워크플로우 경로의 기준 디렉토리 (기본값: 스케줄 파일 디렉토리)
1369
+ - `silent`: (선택사항) 무음 모드로 실행 (콘솔 출력 억제)
1370
+ - `profile`: (선택사항) 사용할 프로필 이름 (프로필이 있는 워크플로우용)
1371
+
1372
+ **경로 해석 방식:**
1373
+ 기본적으로 상대 워크플로우 경로는 스케줄 파일의 디렉토리를 기준으로 해석됩니다. 즉, 스케줄 파일과 워크플로우가 같은 폴더에 있으면 `./workflow.yaml`만 쓰면 됩니다. 다른 기준 디렉토리가 필요하면 `baseDir`을 사용하세요.
1374
+
1375
+ **JSON (`schedules.json`):**
1376
+ ```json
1377
+ {
1378
+ "schedules": [
1379
+ {
1380
+ "name": "Daily Build",
1381
+ "cron": "0 9 * * *",
1382
+ "workflow": "./build.yaml"
1383
+ },
1384
+ {
1385
+ "name": "Nightly Test",
1386
+ "cron": "0 2 * * *",
1387
+ "workflow": "./test.yaml",
1388
+ "silent": true
1389
+ },
1390
+ {
1391
+ "name": "Production Deploy",
1392
+ "cron": "0 18 * * 5",
1393
+ "workflow": "./deploy.yaml",
1394
+ "profile": "Production"
1395
+ }
1396
+ ]
1397
+ }
1398
+ ```
1399
+
1400
+ 파일에서 모든 스케줄을 추가:
1401
+
1402
+ ```bash
1403
+ tp schedule add schedules.yaml
1404
+ ```
1405
+
1406
+ 각 스케줄에 대해 별칭을 확인하거나 변경할 수 있습니다
1407
+
1408
+ **Cron 표현식 형식:**
1409
+
1410
+ 5자리(표준) 또는 **6자리(초 포함, node-cron 확장)** 지원:
1411
+
1412
+ ```
1413
+ # 6자리 (초 선택사항)
1414
+ # ┌────────────── 초 (0-59, 선택)
1415
+ # │ ┌──────────── 분 (0-59)
1416
+ # │ │ ┌────────── 시 (0-23)
1417
+ # │ │ │ ┌──────── 일 (1-31)
1418
+ # │ │ │ │ ┌────── 월 (1-12)
1419
+ # │ │ │ │ │ ┌──── 요일 (0-7)
1420
+ # │ │ │ │ │ │
1421
+ * * * * * *
1422
+ ```
1423
+
1424
+ **일반적인 예시 (5자리):**
1425
+ - `0 9 * * *` - 매일 오전 9시
1426
+ - `0 0 * * 1` - 매주 월요일 자정
1427
+ - `*/15 * * * *` - 15분마다
1428
+ - `0 */2 * * *` - 2시간마다
1429
+
1430
+ **초 포함 (6자리):**
1431
+ - `* * * * * *` - 매초
1432
+ - `*/5 * * * * *` - 5초마다
1433
+ - `0 * * * * *` - 매분 (5자리 `* * * * *`와 동일)
1434
+ - `0 9 * * 1-5` - 평일 오전 9시
1435
+
1436
+ ### 스케줄 관리
1437
+
1438
+ ```bash
1439
+ # 모든 스케줄 목록 보기
1440
+ tp schedule list
1441
+
1442
+ # 스케줄 삭제
1443
+ tp schedule remove
1444
+
1445
+ # 모든 스케줄 삭제
1446
+ tp schedule remove-all
1447
+
1448
+ # 스케줄 활성화/비활성화
1449
+ tp schedule toggle
1450
+ ```
1451
+
1452
+ ### 스케줄러 실행
1453
+
1454
+ 예약된 시간에 워크플로우를 실행하려면 스케줄러 데몬을 시작하세요:
1455
+
1456
+ ```bash
1457
+ tp schedule start
1458
+ ```
1459
+
1460
+ 스케줄러는:
1461
+ - 데몬 프로세스로 실행됩니다 (백그라운드에서 계속 실행)
1462
+ - 예약된 시간에 워크플로우를 실행합니다
1463
+ - 모든 실행을 `~/.pipeliner/workflow-history/`에 기록합니다
1464
+ - 실시간 실행 상태를 표시합니다
1465
+
1466
+ **`Ctrl+C`를 눌러 스케줄러를 중지하세요**
1467
+
1468
+ ### 스케줄 저장
1469
+
1470
+ 스케줄은 `~/.pipeliner/schedules/schedules.json`에 저장됩니다. 각 스케줄은 다음을 포함합니다:
1471
+ - 고유 ID
1472
+ - 워크플로우 경로
1473
+ - Cron 표현식
1474
+ - 활성화/비활성화 상태
1475
+ - 마지막 실행 시간
1476
+
1477
+ 예약된 모든 워크플로우 실행은 수동 실행과 동일한 히스토리 디렉토리(`~/.pipeliner/workflow-history/`)에 기록되므로, `tp history`를 사용하여 검토할 수 있습니다.
1478
+
1479
+ ---
1480
+
1321
1481
  ## 📚 예제
1322
1482
 
1323
1483
  ### 프로젝트 예제
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.16
5
+ **Version:** 0.2.17
6
6
 
7
7
  ![fox2](https://github.com/user-attachments/assets/fdf8d786-6a91-4d2d-9dc1-72be6f3ccd98)
8
8
 
@@ -29,6 +29,8 @@
29
29
 
30
30
  - **Execution history** - Track and review past workflow executions with detailed step-by-step records
31
31
 
32
+ - **Workflow scheduling** - Schedule workflows to run automatically at specified times using cron expressions
33
+
32
34
  ## 🔗 Resources
33
35
 
34
36
  ### Documentation & Tools
@@ -69,6 +71,16 @@ tp history remove # Remove a specific history
69
71
  tp history remove-all # Remove all histories
70
72
  ```
71
73
 
74
+ **Workflow Scheduling:**
75
+ ```bash
76
+ tp schedule # View all schedules
77
+ tp schedule add schedules.yaml # Add schedules from a schedule file
78
+ tp schedule remove # Remove a schedule
79
+ tp schedule remove-all # Remove all schedules
80
+ tp schedule toggle # Enable/disable a schedule
81
+ tp schedule start # Start scheduler daemon
82
+ ```
83
+
72
84
  ## 🚀 Quick Start
73
85
 
74
86
  ### Installation
@@ -1319,6 +1331,154 @@ Each record contains:
1319
1331
 
1320
1332
  ---
1321
1333
 
1334
+ ## ⏰ Workflow Scheduling
1335
+
1336
+ Schedule workflows to run automatically at specified times using cron expressions.
1337
+
1338
+ ### Adding Schedules
1339
+
1340
+ Create a schedule file (YAML or JSON) defining your schedules:
1341
+
1342
+ **YAML (`schedules.yaml`):**
1343
+ ```yaml
1344
+ schedules:
1345
+ - name: Daily Build # Schedule alias (for identification)
1346
+ cron: "0 9 * * *" # Cron expression
1347
+ workflow: ./build.yaml # Path relative to schedule file
1348
+
1349
+ - name: Nightly Test
1350
+ cron: "0 2 * * *"
1351
+ workflow: ./test.yaml
1352
+ silent: true # Optional: run in silent mode
1353
+
1354
+ - name: Production Deploy
1355
+ cron: "0 18 * * 5" # Every Friday at 6 PM
1356
+ workflow: ./deploy.yaml
1357
+ profile: Production # Optional: use specific profile
1358
+
1359
+ - name: Hourly Check
1360
+ cron: "0 * * * *"
1361
+ workflow: simple.yaml
1362
+ baseDir: /path/to/workflows # Optional: base directory for workflow path
1363
+ ```
1364
+
1365
+ **Field Descriptions:**
1366
+ - `name`: Alias to identify the schedule
1367
+ - `cron`: Execution time (cron expression)
1368
+ - `workflow`: Path to workflow file (relative to schedule file or `baseDir`, or absolute)
1369
+ - `baseDir`: (Optional) Base directory for workflow path (defaults to schedule file's directory)
1370
+ - `silent`: (Optional) Run in silent mode, suppressing console output
1371
+ - `profile`: (Optional) Profile name to use (for workflows with profiles)
1372
+
1373
+ **Path Resolution:**
1374
+ By default, relative workflow paths are resolved from the schedule file's directory. This means if your schedule file and workflow are in the same folder, you can simply use `./workflow.yaml`. Use `baseDir` to specify a different base directory if needed.
1375
+
1376
+ **JSON (`schedules.json`):**
1377
+ ```json
1378
+ {
1379
+ "schedules": [
1380
+ {
1381
+ "name": "Daily Build",
1382
+ "cron": "0 9 * * *",
1383
+ "workflow": "./build.yaml"
1384
+ },
1385
+ {
1386
+ "name": "Nightly Test",
1387
+ "cron": "0 2 * * *",
1388
+ "workflow": "./test.yaml",
1389
+ "silent": true
1390
+ },
1391
+ {
1392
+ "name": "Production Deploy",
1393
+ "cron": "0 18 * * 5",
1394
+ "workflow": "./deploy.yaml",
1395
+ "profile": "Production"
1396
+ }
1397
+ ]
1398
+ }
1399
+ ```
1400
+
1401
+ Then add all schedules from the file:
1402
+
1403
+ ```bash
1404
+ tp schedule add schedules.yaml
1405
+ ```
1406
+
1407
+ You'll be prompted to confirm or override the alias for each schedule
1408
+
1409
+ **Cron Expression Format:**
1410
+
1411
+ 5 fields (standard) or **6 fields with seconds** (node-cron extension):
1412
+
1413
+ ```
1414
+ # 6 fields (optional seconds)
1415
+ # ┌────────────── second (0-59, optional)
1416
+ # │ ┌──────────── minute (0-59)
1417
+ # │ │ ┌────────── hour (0-23)
1418
+ # │ │ │ ┌──────── day of month (1-31)
1419
+ # │ │ │ │ ┌────── month (1-12)
1420
+ # │ │ │ │ │ ┌──── day of week (0-7)
1421
+ # │ │ │ │ │ │
1422
+ * * * * * *
1423
+ ```
1424
+
1425
+ **Common Examples (5 fields):**
1426
+ - `0 9 * * *` - Daily at 9:00 AM
1427
+ - `0 0 * * 1` - Weekly on Monday at midnight
1428
+ - `*/15 * * * *` - Every 15 minutes
1429
+ - `0 */2 * * *` - Every 2 hours
1430
+ - `0 9 * * 1-5` - Weekdays at 9:00 AM
1431
+
1432
+ **With seconds (6 fields):**
1433
+ - `* * * * * *` - Every second
1434
+ - `*/5 * * * * *` - Every 5 seconds
1435
+ - `0 * * * * *` - Every minute (same as `* * * * *`)
1436
+
1437
+ ### Managing Schedules
1438
+
1439
+ ```bash
1440
+ # List all schedules
1441
+ tp schedule list
1442
+
1443
+ # Remove a schedule
1444
+ tp schedule remove
1445
+
1446
+ # Remove all schedules
1447
+ tp schedule remove-all
1448
+
1449
+ # Enable/disable a schedule
1450
+ tp schedule toggle
1451
+ ```
1452
+
1453
+ ### Running the Scheduler
1454
+
1455
+ Start the scheduler daemon to run workflows at their scheduled times:
1456
+
1457
+ ```bash
1458
+ tp schedule start
1459
+ ```
1460
+
1461
+ The scheduler will:
1462
+ - Run as a daemon process (stays running in the background)
1463
+ - Execute workflows at their scheduled times
1464
+ - Log all executions to `~/.pipeliner/workflow-history/`
1465
+ - Display real-time execution status
1466
+
1467
+ **Press `Ctrl+C` to stop the scheduler**
1468
+
1469
+ ### Schedule Storage
1470
+
1471
+ Schedules are stored in `~/.pipeliner/schedules/schedules.json`. Each schedule includes:
1472
+ - Unique ID
1473
+ - Workflow path
1474
+ - Cron expression
1475
+ - Enabled/disabled status
1476
+ - Last execution time
1477
+
1478
+ All scheduled workflow executions are logged to the same history directory as manual runs (`~/.pipeliner/workflow-history/`), so you can review them using `tp history`.
1479
+
1480
+ ---
1481
+
1322
1482
  ## 📚 Examples
1323
1483
 
1324
1484
  ### Project 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 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
- `)),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}
2
+ "use strict";var ut=Object.create;var ke=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var dt=Object.getPrototypeOf,mt=Object.prototype.hasOwnProperty;var ht=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ft(e))!mt.call(s,n)&&n!==t&&ke(s,n,{get:()=>e[n],enumerable:!(r=pt(e,n))||r.enumerable});return s};var S=(s,e,t)=>(t=s!=null?ut(dt(s)):{},ht(e||!s||!s.__esModule?ke(t,"default",{value:s,enumerable:!0}):t,s));var st=require("child_process"),ye=require("fs"),it=require("fs/promises"),Y=require("path"),at=require("util"),Se=S(require("boxen"),1),p=S(require("chalk"),1),lt=require("commander"),ct=S(require("dayjs"),1);var D=require("path"),Me=S(require("chalk"),1),te=S(require("log-update"),1);var xe=S(require("readline"),1),x=S(require("chalk"),1),ie=S(require("inquirer"),1),ve=15,I=class{searchable;constructor(e=!1){this.searchable=e}async prompt(e,t){if(this.searchable)return this.promptWithSearch(e,t);let{choice:r}=await ie.default.prompt([{type:"list",name:"choice",message:x.default.cyan(e),choices:t.map(o=>({name:o.label,value:o.id})),pageSize:ve}]),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,a=[...t],i=xe.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 l=()=>{process.stdout.write("\x1B[H\x1B[2J"),console.log(x.default.cyan(`? ${e}`));let m=n?x.default.gray(` Filter: ${n}`)+x.default.gray(` (${a.length}/${t.length})`):x.default.gray(" Type to filter, \u2191\u2193 to navigate, Enter to select");console.log(m),console.log();let f=ve,g=0,b=a.length;if(a.length>f){let y=Math.floor(f/2);g=Math.max(0,o-y),b=Math.min(a.length,g+f),b===a.length&&(g=Math.max(0,b-f))}if(a.length===0)console.log(x.default.yellow(" No matches found"));else{g>0&&console.log(x.default.gray(` \u2191 ${g} more above`));for(let y=g;y<b;y++){let v=a[y];console.log(y===o?x.default.cyan(`\u276F ${v.label}`):x.default.white(` ${v.label}`))}b<a.length&&console.log(x.default.gray(` \u2193 ${a.length-b} more below`))}},c=()=>{let m=n.toLowerCase();a=m?t.filter(f=>f.label.toLowerCase().includes(m)):[...t],o>=a.length&&(o=Math.max(0,a.length-1))},d=m=>{let f=m.toString();if(f===""&&(h(),process.exit(0)),f==="\r"||f===`
3
+ `){a.length>0&&(h(),r(a[o]));return}if(f==="\x1B"&&m.length===1){n&&(n="",c(),l());return}if(f==="\x1B[A"){a.length>0&&(o=o>0?o-1:a.length-1,l());return}if(f==="\x1B[B"){a.length>0&&(o=o<a.length-1?o+1:0,l());return}if(f==="\x7F"||f==="\b"){n.length>0&&(n=n.slice(0,-1),c(),l());return}f.length===1&&f>=" "&&f<="~"&&(n+=f,c(),l())},h=()=>{process.stdin.removeListener("data",d),process.stdin.isTTY&&process.stdin.setRawMode(!1),i.close(),process.stdout.write("\x1B[?25h"),process.stdout.write("\x1B[?1049l")};l(),process.stdin.on("data",d)})}},Z=class{async prompt(e,t){let{value:r}=await ie.default.prompt([{type:"input",name:"value",message:x.default.cyan(e),default:t}]);return r}};var G=S(require("boxen"),1),B=S(require("chalk"),1);function ae(s,e,t,r={}){let{borderColor:n="cyan",isNested:o=!1}=r,a;e!==void 0&&(t?a=`line ${e} in ${t}`:a=`line ${e}`);let i=o?`\u2502 ${s}`:`> ${s}`;return(0,G.default)(i,{title:a,borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:n})}function L(s,e=!1,t){let r=s?"\u2713 Completed":"\u2717 Failed",n=s?B.default.green(r):B.default.red(r);if(t!==void 0){let o=O(t);return`${n} ${B.default.gray(`(${o})`)}`}return n}function z(s){return(0,G.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 $e(s){return(0,G.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 Re(s){let e=s?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return s?B.default.green(e):B.default.red(e)}function le(s,e=!1){return`${e?"| \u2502 ":"\u2502 "}${s}`}function O(s){return`${(s/1e3).toFixed(3)}s`}var Ee=require("fs"),Pe=require("path"),W=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),a=this.workspace.getFact(r),i=o??(a!==void 0?a.toString():void 0);if(i===void 0||i!==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,Pe.resolve)(process.cwd(),t);return(0,Ee.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 $=require("fs/promises"),Ce=require("os"),T=require("path"),je=S(require("dayjs"),1),V=(0,T.join)((0,Ce.homedir)(),".pipeliner","workflow-history"),_=class{constructor(){}async saveHistory(e){await(0,$.mkdir)(V,{recursive:!0});let t=(0,je.default)().format("YYYY-MM-DD_HH-mm-ss"),r=Math.random().toString(36).slice(2,6),n=(0,T.join)(V,`workflow-${t}-${r}.json`);return await(0,$.writeFile)(n,JSON.stringify(e,null,2),{encoding:"utf8"}),n}async clearAllHistories(){await(0,$.rm)(V,{recursive:!0,force:!0})}async removeHistory(e){await(0,$.rm)((0,T.join)(V,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,$.readdir)(V)).map(r=>(0,T.basename)(r));return t.sort((r,n)=>{let o=l=>{let c=l.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},a=o(r),i=o(n);return a===i?n.localeCompare(r):i.localeCompare(a)}),t}catch(e){if(e instanceof Error&&"code"in e&&e.code==="ENOENT")return[];throw e}}async getHistory(e){let t=await(0,$.readFile)((0,T.join)(V,e),{encoding:"utf8"});return JSON.parse(t)}};var X=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 _,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var ce=require("child_process");var K=class{async run(e,t,r,n,o=!1,a=!1,i,l,c,d,h){return o?this.runBuffered(e,c,d,h):this.runRealtime(e,r||e,a,i,l,c,d,h)}async runBuffered(e,t,r,n){return new Promise((o,a)=>{let i=this.spawnWithShell(e,t,n),l=[],c=[],d="",h="",m=null;r&&r>0&&(m=setTimeout(()=>{i.kill("SIGTERM");let f=`Command timed out after ${r} seconds`;c.push(f),o({success:!1,stdout:l,stderr:c})},r*1e3)),i.stdout?.on("data",f=>{let g=f.toString(),{lines:b,remaining:y}=this.processStreamBuffer(g,d);l.push(...b),d=y}),i.stderr?.on("data",f=>{let g=f.toString(),{lines:b,remaining:y}=this.processStreamBuffer(g,h);c.push(...b),h=y}),i.on("close",f=>{m&&clearTimeout(m),d.trim()&&l.push(d),h.trim()&&c.push(h),o({success:f===0,stdout:l,stderr:c})}),i.on("error",f=>{m&&clearTimeout(m);let g=`Error: ${f.message}`;o({success:!1,stdout:l,stderr:[...c,g]})})})}async runRealtime(e,t,r,n,o,a,i,l){let d=ae(t,n,o,{borderColor:r?"green":"cyan"});console.log(d);let h=Date.now();return new Promise(m=>{let f=this.spawnWithShell(e,a,l),g="",b="",y=null;i&&i>0&&(y=setTimeout(()=>{f.kill("SIGTERM");let v=`Command timed out after ${i} seconds`,R=z(v);console.error(R);let N=Date.now()-h,A=L(!1,!1,N);console.log(A),m(!1)},i*1e3)),f.stdout?.on("data",v=>{let R=v.toString(),{lines:N,remaining:A}=this.processStreamBuffer(R,g);N.forEach(se=>process.stdout.write(`\u2502 ${se}
4
+ `)),g=A}),f.stderr?.on("data",v=>{let R=v.toString(),{lines:N,remaining:A}=this.processStreamBuffer(R,b);N.forEach(se=>process.stderr.write(`\u2502 ${se}
5
+ `)),b=A}),f.on("close",v=>{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=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
- `);){let i=o.indexOf(`
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 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
- `)):(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: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?`
7
+ `);let R=v===0,N=Date.now()-h,A=L(R,!1,N);console.log(A),m(R)}),f.on("error",v=>{y&&clearTimeout(y);let R=z(`Error: ${v.message}`);console.error(R),m(!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],a={stdio:["inherit","pipe","pipe"]};return t&&(a.cwd=t),(0,ce.spawn)(n,o,a)}else{let n=process.env.SHELL||(process.platform==="win32"?"cmd.exe":"/bin/sh"),o=process.platform==="win32"?"/c":"-c",a={stdio:["inherit","pipe","pipe"]};return t&&(a.cwd=t),(0,ce.spawn)(n,[o,e],a)}}processStreamBuffer(e,t){let r=t+e,n=[],o=r;for(;o.includes(`
8
+ `);){let a=o.indexOf(`
9
+ `),i=o.substring(0,a);o=o.substring(a+1),n.push(i)}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 a=ae(t,n,o,{borderColor:"cyan",isNested:r});this.formatNestedOutput(a,r),e.stdout.forEach(l=>{let c=le(l,r);process.stdout.write(`${c}
11
+ `)}),e.stderr.forEach(l=>{let c=le(l,r);process.stderr.write(`${c}
12
+ `)});let i=L(e.success,r);console.log(i)}};function gt(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 Q(s,e){let t=/\{\{\s*(\w+)\s*\}\}/g;return s.replace(t,(r,n)=>gt(n,e,r))}var ee=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 H=class s{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;globalShell;constructor(){this.workspace=new ee,this.taskRunner=new K,this.choicePrompt=new I,this.textPrompt=new Z}resolveBaseDir(e){if(e.baseDir)if((0,D.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,D.dirname)(e._filePath);this.baseDir=(0,D.resolve)(t,e.baseDir)}else this.baseDir=(0,D.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 W(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[i,l]of Object.entries(t.profileVars))this.workspace.setVariable(i,l);this.resolveBaseDir(e),this.globalShell=e.shell;let r=new X,n=Date.now();for(let i=0;i<e.steps.length;i++){let l=e.steps[i],c=this.createStepContext(i,e),d=!!l.when;if(this.evaluateStepCondition(l)){r.recordStart();try{let h=await this.executeStep(l,c,!1,d);this.handleStepResult(l,c,i,h,r)}catch(h){throw this.handleStepError(l,c,i,h,r),h}}}let o=Date.now()-n,a=O(o);console.log(Me.default.cyan(`
13
+ Total execution time: ${a}`)),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 a=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(r);return c?c.success:!0})():this.isStepSuccessful(n,e),i=a?"success":"failure",l=o.recordEnd(e,t,n,i);if(!this.isRunStep(e)){let c=L(a,!1,l);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",d=a?`Step ${r}${c} completed, but workflow stopped due to continue: false`:`Step ${r}${c} failed`;throw new Error(d)}if(!a&&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 a=n instanceof Error?n.message:String(n),i={success:!1,stdout:[],stderr:[a]};o.recordEnd(e,t,i,"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),a=Q(e.run,this.workspace),i=e.shell||this.globalShell,l=e.retry??0,c=e.timeout,d=!1,h=0;for(;h<=l;){let m=await this.taskRunner.run(a,o,a,t.branchIndex,r,n,t.lineNumber,t.fileName,this.baseDir,c,i),f=typeof m=="boolean"?m:m.success;if(d=m,f||h>=l)break;if(h++,h<=l){let g=Math.min(1e3*Math.pow(2,h-1),1e4);await new Promise(b=>setTimeout(b,g))}}return d}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),a=typeof o=="boolean"?o:o.success;if(this.workspace.setStepResult(t.stepIndex,a),a||!e.onError)return o;let i={run:e.onError.run,timeout:e.onError.timeout,retry:e.onError.retry,onError:e.onError.onError??void 0};return await this.executeRunChain(i,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(i=>i.id);if(r&&this.workspace.hasVariable(r)){let i=this.workspace.getVariable(r)??"";if(n.includes(i)){this.workspace.setChoice(i,i),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 a=r??o.id;this.workspace.setChoice(o.id,o.id),this.workspace.setVariable(a,o.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let r=e.prompt.as;if(this.workspace.hasVariable(r)){let i=this.workspace.getVariable(r)??"";this.workspace.setFact(r,i),this.workspace.setStepResult(t.stepIndex,!0);return}let n=Q(e.prompt.message,this.workspace),o=e.prompt.default?Q(e.prompt.default,this.workspace):void 0,a=await this.textPrompt.prompt(n,o);this.workspace.setVariable(r,a),this.workspace.setFact(r,a),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 d=e[c],h=t[c];if(d.when&&!new W(h.workspace).evaluate(d.when))continue;let m=this.getBranchDisplayName(d,c);r.push({index:c,name:m,status:"pending"})}let a=setInterval(()=>{o=(o+1)%n.length,this.updateParallelBranchesDisplay(r,n[o])},100),i=r.map(async c=>{let{index:d}=c,h=e[d],m=t[d];c.status="running";try{let f=await this.executeStep(h,m,!0);return c.status="success",this.updateParallelBranchesDisplay(r,n[o]),{index:d,result:f,context:m}}catch(f){m.workspace.setStepResult(m.stepIndex,!1);let g=f instanceof Error?f.message:String(f);return c.status="failed",c.error=g,this.updateParallelBranchesDisplay(r,n[o]),{index:d,error:f,context:m}}}),l=await Promise.all(i);return clearInterval(a),this.updateParallelBranchesDisplay(r,"",!0),te.default.done(),l}updateParallelBranchesDisplay(e,t,r=!1){let n=e.map(o=>{let a=o.index+1,i="",l="";switch(o.status){case"pending":i="\u25CB",l=`Branch ${a}: ${o.name} - Pending`;break;case"running":i=t,l=`Branch ${a}: ${o.name} - Running...`;break;case"success":i="\u2713",l=`Branch ${a}: ${o.name} - Completed`;break;case"failed":i="\u2717",l=`Branch ${a}: ${o.name} - Failed${o.error?`: ${o.error}`:""}`;break}return`${i} ${l}`});r?(0,te.default)(n.join(`
14
+ `)):(0,te.default)(n.join(`
15
+ `))}displayParallelResults(e,t,r){let n=!0,o=!1;console.log("");for(let i of e){if(!i)continue;o=!0;let{index:l,result:c,error:d,context:h}=i;if(d){n=!1;let m=`Branch ${l+1} failed: ${d instanceof Error?d.message:String(d)}`,f=z(m);console.error(f)}else if(c&&typeof c=="object"&&"stdout"in c){let m=c;if(n=n&&m.success,m.stdout.length>0||m.stderr.length>0||!m.success){let f=t[l],g=this.getBranchDisplayName(f,l);this.taskRunner.displayBufferedOutput(m,g,!1,h.lineNumber,h.fileName)}}}o||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let a=Re(n);return console.log(a),n}mergeParallelResults(e){for(let t of e){let r=t.workspace.getAllFacts(),n=t.workspace.getAllVariables();for(let[o,a]of r)this.workspace.setFact(o,a);for(let[o,a]of n)this.workspace.setVariable(o,a)}}countExecutableBranches(e,t){let r=0;for(let n=0;n<e.length;n++){let o=e[n],a=t[n];o.when&&!new W(a.workspace).evaluate(o.when)||r++}return r}async executeParallelStep(e,t){let r=this.createParallelContexts(e,t),n=this.countExecutableBranches(e.parallel,r),o=$e(n);console.log(o);let a=await this.executeParallelBranches(e.parallel,r),i=this.displayParallelResults(a,e.parallel,t);if(this.workspace.setStepResult(t.stepIndex,i),!i){let l=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Parallel step ${t.stepIndex}${l} 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 De=require("yaml"),de=require("zod");var u=require("zod"),wt=u.z.object({file:u.z.string()}),bt=u.z.object({var:u.z.union([u.z.string(),u.z.record(u.z.string(),u.z.string())]).optional(),has:u.z.string().optional()}),yt=u.z.object({status:u.z.object({fact:u.z.string(),is:u.z.enum(["ready","failed","pending"])})}),St=u.z.object({step:u.z.object({success:u.z.boolean()}).optional(),last_step:u.z.enum(["success","failure"]).optional()}),kt=u.z.object({choice:u.z.string()}),vt=u.z.union([wt,kt,bt,yt,St]),E=u.z.lazy(()=>u.z.union([vt,u.z.object({all:u.z.array(E)}),u.z.object({any:u.z.array(E)}),u.z.object({not:E})])),Ne=u.z.lazy(()=>u.z.object({run:u.z.string(),timeout:u.z.number().optional(),retry:u.z.number().optional(),onError:Ne.optional()})),Ae=u.z.object({run:u.z.string(),when:E.optional(),timeout:u.z.number().optional(),retry:u.z.number().optional(),shell:u.z.array(u.z.string()).min(1,"shell must have at least one element").optional(),continue:u.z.boolean().optional(),onError:Ne.optional()}),xt=u.z.object({choose:u.z.object({message:u.z.string(),options:u.z.array(u.z.object({id:u.z.string(),label:u.z.string()})),as:u.z.string().optional()}),when:E.optional()}),$t=u.z.object({prompt:u.z.object({message:u.z.string(),as:u.z.string(),default:u.z.string().optional(),validate:u.z.string().optional()}),when:E.optional()});function Ie(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=Ie(t);if(r.found)return r}return{found:!1}}var Te=u.z.lazy(()=>u.z.union([Ae,u.z.object({parallel:u.z.array(u.z.lazy(()=>Te)),when:E.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:E.optional()})]).superRefine((s,e)=>{let t=Ie(s);t.found&&e.addIssue({code:u.z.ZodIssueCode.custom,message:`'${t.type}' step is not allowed inside 'parallel' block (user input cannot run in parallel)`})})),Rt=u.z.lazy(()=>u.z.union([Ae,xt,$t,u.z.object({parallel:u.z.array(Te),when:E.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:E.optional()})])),Et=u.z.object({name:u.z.string().min(1,"Profile name must be non-empty"),var:u.z.record(u.z.string(),u.z.union([u.z.string(),u.z.number(),u.z.boolean()]).transform(String))}),Pt=u.z.object({name:u.z.string().optional(),baseDir:u.z.string().optional(),shell:u.z.array(u.z.string()).min(1,"shell must have at least one element").optional(),profiles:u.z.array(Et).optional(),steps:u.z.array(Rt).min(1,"Workflow must have at least one step")});function ue(s){return Pt.parse(s)}function Fe(s,e){let t=s.path;if(s.code==="custom"){let n=pe(t);return` - ${s.message}${n}`}if(s.message==="Invalid input"){let n=pe(t),o=Ct(t,e);return o?` - ${o}${n}`:` - Invalid step type${n}`}let r=pe(t);return` - ${s.message}${r}`}function pe(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
- - ${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 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
- - '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 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:
17
+ - ${e} (step ${s+1})${r}`)}function Be(s,e,t=!1,r=[]){let n=["run","choose","prompt","parallel","fail"],o=n.find(a=>a in s);if(!o){let a=Object.keys(s).filter(i=>i!=="when");w(e,`Unknown step type. Found keys: [${a.join(", ")}]. Valid types: ${n.join(", ")}`)}if(o==="run"){let a=s.run;if(typeof a!="string"&&w(e,"'run' must be a string command"),a===""&&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 i=s.shell;i.length===0&&w(e,"'shell' cannot be empty","Shell configuration must have at least one element (program name)");for(let l=0;l<i.length;l++)typeof i[l]!="string"&&w(e,`'shell[${l}]' must be a string`)}}if(o==="choose"){if(t){let l=r.join(" \u2192 ");throw new Error(`Invalid workflow structure:
18
+ - 'choose' step is not allowed inside 'parallel' block (step ${e+1}, ${l})
19
+ Reason: User input prompts cannot run in parallel`)}let a=s.choose;(!a||typeof a!="object")&&w(e,"'choose' must be an object with 'message' and 'options'");let i=a;(!i.message||typeof i.message!="string")&&w(e,"'choose.message' is required and must be a string"),Array.isArray(i.options)||w(e,"'choose.options' is required and must be an array"),i.options.length===0&&w(e,"'choose.options' cannot be empty","At least one option is required");for(let l=0;l<i.options.length;l++){let c=i.options[l];(!c||typeof c!="object")&&w(e,`'choose.options[${l}]' must be an object with 'id' and 'label'`),(!c.id||typeof c.id!="string")&&w(e,`'choose.options[${l}].id' is required and must be a string`),(!c.label||typeof c.label!="string")&&w(e,`'choose.options[${l}].label' is required and must be a string`)}}if(o==="prompt"){if(t){let l=r.join(" \u2192 ");throw new Error(`Invalid workflow structure:
20
+ - 'prompt' step is not allowed inside 'parallel' block (step ${e+1}, ${l})
21
+ Reason: User input prompts cannot run in parallel`)}let a=s.prompt;(!a||typeof a!="object")&&w(e,"'prompt' must be an object with 'message' and 'as'");let i=a;(!i.message||typeof i.message!="string")&&w(e,"'prompt.message' is required and must be a string"),(!i.as||typeof i.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 a=s.parallel;Array.isArray(a)||w(e,"'parallel' must be an array of steps"),a.length===0&&w(e,"'parallel' cannot be empty","At least one step is required");for(let i=0;i<a.length;i++){let l=a[i];(!l||typeof l!="object")&&w(e,`'parallel[${i}]' must be a valid step object`);let c=[...r,`branch ${i+1}`];Be(l,e,!0,c)}}if(o==="fail"){let a=s.fail;(!a||typeof a!="object")&&w(e,"'fail' must be an object with 'message'");let i=a;(!i.message||typeof i.message!="string")&&w(e,"'fail.message' is required and must be a string")}}function Le(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,26 @@ Total execution time: ${i}`)),await r.save(),r.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 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(`
32
+ - Step ${t+1} must be an object`);Be(r,t)}}function Ct(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(i=>o.includes(i)))return`Unknown step type. Found keys: [${n.join(", ")}]. Valid types: run, choose, prompt, parallel, fail`}return null}catch{return null}}function me(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=>me(t))}:s}var re=class{parse(e){let t;try{t=(0,De.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=>me(n)))}Le(t);try{return ue(t)}catch(r){if(r instanceof de.ZodError){let n=r.issues.map(o=>Fe(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}},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(`
35
+ `),n=0,o=!1;for(let a=0;a<r.length;a++){let i=r[a].trim();if(i==="steps:"||i.startsWith("steps:")){o=!0;continue}o&&i.startsWith("-")&&t.set(n++,a+1)}return t}},fe=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=>me(n)))}Le(t);try{return ue(t)}catch(r){if(r instanceof de.ZodError){let n=r.issues.map(o=>Fe(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 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.
38
+ `),n=0,o=!1,a=!1;for(let i=0;i<r.length;i++){let c=r[i].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){o=!0,c.includes("[")&&(a=!0);continue}if(o&&c==="["){a=!0;continue}if(a&&c==="]"){a=!1,o=!1;continue}a&&c.startsWith("{")&&t.set(n++,i+1)}return t}};function q(s){switch(s.toLowerCase().split(".").pop()){case"yaml":case"yml":return new re;case"json":return new fe;default:return new re}}var ne=require("fs"),j=require("path"),Xe=require("commander"),Ke=S(require("dayjs"),1),F=S(require("inquirer"),1),Qe=S(require("node-cron"),1);var We=require("fs/promises"),Ve=require("path"),_e=require("yaml"),He=require("zod");var P=require("zod"),jt=P.z.object({name:P.z.string().min(1,"Schedule name must be non-empty"),cron:P.z.string().min(1,"Cron expression is required"),workflow:P.z.string().min(1,"Workflow path is required"),baseDir:P.z.string().optional(),silent:P.z.boolean().optional(),profile:P.z.string().optional()}),Mt=P.z.object({schedules:P.z.array(jt).min(1,"Schedule file must have at least one schedule")});function Oe(s){return Mt.parse(s)}async function Je(s){let e=await(0,We.readFile)(s,"utf-8"),t=(0,Ve.extname)(s).toLowerCase(),r;try{if(t===".yaml"||t===".yml")r=(0,_e.parse)(e);else if(t===".json")r=JSON.parse(e);else throw new Error(`Unsupported file format: ${t}. Use .yaml, .yml, or .json`)}catch(n){if(n instanceof Error&&n.message.startsWith("Unsupported"))throw n;let o=t===".json"?"JSON":"YAML";throw new Error(`Invalid ${o} format: ${n instanceof Error?n.message:String(n)}`)}try{return Oe(r)}catch(n){if(n instanceof He.ZodError){let o=n.issues.map(a=>` - ${a.message} (${a.path.join(".")})`).join(`
39
+ `);throw new Error(`Invalid schedule file structure:
40
+ ${o}`)}throw n}}var J=require("fs/promises"),Ue=require("os"),he=require("path"),ze=(0,he.join)((0,Ue.homedir)(),".pipeliner","schedules"),Ye=(0,he.join)(ze,"schedules.json"),C=class{async loadSchedules(){try{let e=await(0,J.readFile)(Ye,"utf-8");return JSON.parse(e).schedules||[]}catch(e){if(e instanceof Error&&"code"in e&&e.code==="ENOENT")return[];throw e}}async saveSchedules(e){await(0,J.mkdir)(ze,{recursive:!0}),await(0,J.writeFile)(Ye,JSON.stringify({schedules:e},null,2),"utf-8")}async addSchedule(e){let t=await this.loadSchedules(),r=Math.random().toString(36).slice(2,10),n=new Date().toISOString(),o={id:r,createdAt:n,...e};return t.push(o),await this.saveSchedules(t),o}async removeSchedule(e){let t=await this.loadSchedules(),r=t.length,n=t.filter(o=>o.id!==e);return n.length===r?!1:(await this.saveSchedules(n),!0)}async updateLastRun(e){let t=await this.loadSchedules(),r=t.find(n=>n.id===e);r&&(r.lastRun=new Date().toISOString(),await this.saveSchedules(t))}async toggleSchedule(e,t){let r=await this.loadSchedules(),n=r.find(o=>o.id===e);return n?(n.enabled=t,await this.saveSchedules(r),!0):!1}async getSchedule(e){return(await this.loadSchedules()).find(r=>r.id===e)}};var qe=require("fs/promises"),Ze=require("path"),ge=S(require("node-cron"),1);var oe=class{scheduleManager;tasks=new Map;constructor(){this.scheduleManager=new C}async start(){console.log("\u{1F680} Starting workflow scheduler..."),await this.reload(),console.log("\u2713 Scheduler is running"),console.log(" Press Ctrl+C to stop"),process.on("SIGINT",()=>{console.log(`
41
+ \u23F9 Stopping scheduler...`),this.stop(),process.exit(0)})}async reload(){this.stop();let t=(await this.scheduleManager.loadSchedules()).filter(r=>r.enabled);if(t.length===0){console.log(" No active schedules found");return}console.log(` Loading ${t.length} schedule(s)...`);for(let r of t)try{this.startSchedule(r)}catch(n){console.error(` \u2717 Failed to start schedule ${r.id}:`,n)}}startSchedule(e){if(!ge.default.validate(e.cron)){console.error(` \u2717 Invalid cron expression for schedule ${e.id}: ${e.cron}`);return}let t=ge.default.schedule(e.cron,async()=>{await this.executeSchedule(e)});this.tasks.set(e.id,t);let r=e.name??e.workflowPath;console.log(` \u2713 Scheduled: ${r}`),console.log(` Cron: ${e.cron}`),console.log(` Workflow: ${e.workflowPath}`)}async executeSchedule(e){let t=e.name??e.workflowPath;e.silent||(console.log(`
42
+ \u23F0 Running scheduled workflow: ${t}`),console.log(` Time: ${new Date().toISOString()}`),e.profile&&console.log(` Profile: ${e.profile}`));try{let r=(0,Ze.resolve)(e.workflowPath),n=q(r),o=await(0,qe.readFile)(r,"utf-8"),a=n.parse(o),i=new H,l={};if(e.profile){if(!a.profiles)throw new Error(`Profile "${e.profile}" not found: no profiles defined in workflow`);let c=a.profiles.find(d=>d.name===e.profile);if(!c)throw new Error(`Profile "${e.profile}" not found. Available profiles: ${a.profiles.map(d=>d.name).join(", ")}`);l.profileVars=c.var}await i.execute(a,l),await this.scheduleManager.updateLastRun(e.id),e.silent||console.log(`\u2713 Scheduled workflow completed: ${t}
43
+ `)}catch(r){e.silent||(console.error(`\u2717 Scheduled workflow failed: ${t}`),console.error(` Error: ${r instanceof Error?r.message:String(r)}
44
+ `))}}stop(){for(let e of this.tasks.values())e.stop();this.tasks.clear()}};function et(){let s=new Xe.Command("schedule").description("Manage workflow schedules").action(async()=>{await Ge()});return s.command("add [scheduleFile]").description("Add schedules from a schedule file (YAML or JSON)").action(async e=>{await Nt(e)}),s.command("remove").alias("rm").description("Remove a workflow schedule").action(async()=>{await At()}),s.command("remove-all").description("Remove all workflow schedules").action(async()=>{await Dt()}),s.command("list").alias("ls").description("List all workflow schedules").action(async()=>{await Ge()}),s.command("start").description("Start the scheduler daemon").action(async()=>{await It()}),s.command("toggle").description("Enable or disable a schedule").action(async()=>{await Tt()}),s}function we(s,e){let t=e.workflow;if((0,j.isAbsolute)(t))return t;let r=e.baseDir?(0,j.resolve)(e.baseDir):(0,j.dirname)(s);return(0,j.resolve)(r,t)}async function Nt(s){let e=new C;if(!s){let{path:i}=await F.default.prompt([{type:"input",name:"path",message:"Schedule file path (YAML or JSON):",validate:l=>{let c=(0,j.resolve)(l);return(0,ne.existsSync)(c)?!0:`File not found: ${c}`}}]);s=i}let t=(0,j.resolve)(s);(0,ne.existsSync)(t)||(console.error(`\u2717 File not found: ${t}`),process.exit(1));let r;try{r=await Je(t)}catch(i){console.error(`\u2717 Failed to parse schedule file: ${i instanceof Error?i.message:String(i)}`),process.exit(1)}let n=r.schedules.filter(i=>!Qe.default.validate(i.cron));if(n.length>0){console.error("\u2717 Invalid cron expression(s):");for(let i of n)console.error(` - ${i.name}: "${i.cron}"`);process.exit(1)}let o=r.schedules.filter(i=>{let l=we(t,i);return!(0,ne.existsSync)(l)});if(o.length>0){console.error("\u2717 Workflow file(s) not found:");for(let i of o){let l=we(t,i);console.error(` - ${i.name}: ${i.workflow} (resolved: ${l})`)}process.exit(1)}console.log(`
45
+ Found ${r.schedules.length} schedule(s) in file.
46
+ `);let a=[];for(let i of r.schedules){let{alias:l}=await F.default.prompt([{type:"input",name:"alias",message:`Alias for "${i.name}" (press Enter to use as-is):`,default:i.name}]),c=await e.addSchedule({name:l,workflowPath:we(t,i),cron:i.cron,enabled:!0,silent:i.silent,profile:i.profile});a.push(c)}console.log(`
47
+ \u2713 Added ${a.length} schedule(s) successfully
48
+ `);for(let i of a)console.log(` - ${i.name??"N/A"}`),console.log(` Cron: ${i.cron}`),console.log(` Workflow: ${i.workflowPath}`),i.silent&&console.log(" Silent: Yes"),i.profile&&console.log(` Profile: ${i.profile}`),console.log(` Status: ${i.enabled?"Enabled":"Disabled"}`),console.log();console.log('Run "tp schedule start" to start the scheduler daemon')}async function At(){let s=new C,e=await s.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await F.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to remove:",choices:e.map(o=>({name:`${o.name??o.workflowPath} (${o.cron}) ${o.enabled?"\u2713":"\u2717"}`,value:o.id}))}]),{confirm:r}=await F.default.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to remove this schedule?",default:!1}]);if(!r){console.log("Cancelled");return}let n=await s.removeSchedule(t);console.log(n?"\u2713 Schedule removed successfully":"\u2717 Schedule not found")}async function Ge(){let e=await new C().loadSchedules();if(e.length===0){console.log("No schedules found"),console.log(`
49
+ Run "tp schedule add" to create a new schedule`);return}console.log(`
50
+ \u{1F4C5} Workflow Schedules
51
+ `);for(let t of e){let r=t.enabled?"\u2713 Enabled":"\u2717 Disabled",n=t.name??t.workflowPath,o=t.lastRun?(0,Ke.default)(t.lastRun).format("YYYY-MM-DD HH:mm:ss"):"Never";console.log(` ${r} ${n}`),console.log(` ID: ${t.id}`),console.log(` Cron: ${t.cron}`),console.log(` Workflow: ${t.workflowPath}`),console.log(` Last run: ${o}`),console.log()}}async function It(){await new oe().start(),await new Promise(()=>{})}async function Tt(){let s=new C,e=await s.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await F.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to toggle:",choices:e.map(o=>({name:`${o.name??o.workflowPath} (${o.cron}) ${o.enabled?"\u2713":"\u2717"}`,value:o.id}))}]),r=e.find(o=>o.id===t);if(!r){console.log("\u2717 Schedule not found");return}let n=!r.enabled;await s.toggleSchedule(t,n),console.log(`\u2713 Schedule ${n?"enabled":"disabled"}: ${r.name??r.workflowPath}`)}async function Dt(){let s=new C,e=await s.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{confirm:t}=await F.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to remove all ${e.length} schedule(s)?`,default:!1}]);if(!t){console.log("Cancelled");return}await s.saveSchedules([]),console.log(`\u2713 Removed all ${e.length} schedule(s)`)}var M=require("fs"),k=require("path"),be=require("url"),tt={};function rt(){console.log=()=>{},console.error=()=>{},console.warn=()=>{},console.info=()=>{},process.stdout.write=()=>!0,process.stderr.write=()=>!0}function ot(){return"0.2.17"}function nt(s){let e=s?(0,k.resolve)(s):process.cwd(),t=50,r=0;for(;r<t;){let n=(0,k.resolve)(e,"tp");try{if((0,M.existsSync)(n)&&(0,M.statSync)(n).isDirectory())return n}catch{}let o=(0,k.dirname)(e);if(o===e)break;e=o,r++}return null}var Ft=(0,at.promisify)(st.exec),U=new lt.Command;U.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
39
52
 
40
53
  Define workflows in YAML or JSON files with conditional execution, parallel tasks,
41
54
  interactive prompts, and variable substitution.
@@ -73,7 +86,7 @@ Quick Start:
73
86
  tp history remove # Remove a specific history
74
87
  tp history remove-all # Remove all histories
75
88
 
76
- `).version(Ne()).addHelpText("after",`
89
+ `).version(ot()).addHelpText("after",`
77
90
  Examples:
78
91
  $ tp run workflow.yaml
79
92
  $ tp run examples/simple-project/workflow.yaml
@@ -86,7 +99,7 @@ Resources:
86
99
  \u{1F4DA} Documentation: https://task-pipeliner.racgoo.com/
87
100
  \u{1F3A8} Visual Generator: https://task-pipeliner-generator.racgoo.com/
88
101
 
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",`
102
+ See README.md for complete DSL reference.`);U.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
103
  Examples:
91
104
  $ tp run workflow.yaml
92
105
  $ tp run workflow.json
@@ -111,11 +124,11 @@ Workflow File Structure:
111
124
  \u2022 all/any/not: Combine conditions
112
125
 
113
126
  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 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(`
127
+ See README.md for complete DSL documentation.`).action(async(s,e)=>{try{let t=s??await Lt()??null;t||(console.error(p.default.red(`
128
+ \u2717 No workflow file found`)),process.exit(1)),e.silent&&rt();let r=q(t);console.log(p.default.blue(`Loading workflow from ${t}...`));let n=(0,ye.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 a;if(e.profile){let l=e.profile.trim();if(!o.profiles?.length)throw new Error(`Profile "${l}" requested but workflow has no "profiles" defined. Add a "profiles" section to your workflow file.`);let c=o.profiles.find(d=>d.name===l);if(!c){let d=o.profiles.map(h=>h.name).join(", ");throw new Error(`Profile "${l}" not found. Available profile(s): ${d}`)}a=c.var}o._lineNumbers=r.extractStepLineNumbers(n),o._fileName=Ot(t),o._filePath=(0,Y.resolve)(t),console.log(p.default.green(`Starting workflow execution...
129
+ `)),await new H().execute(o,a?{profileVars:a}:void 0),console.log(p.default.green(`
117
130
  \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)}});O.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
131
+ \u2717 Workflow failed: ${r}`)),process.exit(1)}});U.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
119
132
  Examples:
120
133
  $ tp open generator
121
134
  $ tp open docs
@@ -124,27 +137,27 @@ Targets:
124
137
  generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
125
138
  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
139
  \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 ot(n),console.log(p.default.green(`
140
+ 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 Ft(n),console.log(p.default.green(`
128
141
  \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
142
  \u2717 Failed to open browser: ${n}`)),console.log(p.default.yellow(`
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
- \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(`
143
+ Please visit manually: ${t}`)),process.exit(1)}});U.addCommand(et());var Bt=U.command("history").description("Manage workflow execution history");Bt.action(async()=>{let s=new I,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(`
144
+ \u2717 Invalid choice`)),process.exit(1));let t=new _;switch(e.id){case"show":{let r=await t.getHistoryNames();if(r.length===0){console.log(p.default.yellow(`
132
145
  \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);at(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(`
146
+ \u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);Wt(o,n.id)}catch(o){let a=o instanceof Error?o.message:String(o);console.error(p.default.red(`
147
+ \u2717 Failed to load history: ${a}`)),process.exit(1)}break}case"remove":{let r=await t.getHistoryNames();if(r.length===0){console.log(p.default.yellow(`
135
148
  \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
149
  \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(`
150
+ \u2713 Removed history: ${n.id}`))}catch(o){let a=o instanceof Error?o.message:String(o);console.error(p.default.red(`
151
+ \u2717 Failed to remove history: ${a}`)),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
152
  \u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(p.default.green(`
140
153
  \u2713 All histories removed`))}catch(n){let o=n instanceof Error?n.message:String(n);console.error(p.default.red(`
141
154
  \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 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(`
155
+ \u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function Lt(){let s=nt();if(!s)return console.error(p.default.red(`
156
+ \u2717 No tp directory found`)),null;try{let t=(await(0,it.readdir)(s)).filter(a=>{let i=(0,Y.extname)(a).toLowerCase();return[".yaml",".yml",".json"].includes(i)});if(t.length===0)return console.error(p.default.red(`
157
+ \u2717 No workflow files found in ${s}`)),null;let r=await Promise.all(t.map(async a=>{let i=(0,Y.join)(s,a);try{let l=q(i),c=(0,ye.readFileSync)(i,"utf-8"),h=l.parse(c).name??"Untitled";return{id:i,label:`${a} - ${h}`}}catch{return{id:i,label:a}}}));return(await new I(!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(`
158
+ \u2717 Failed to read tp directory: ${t}`)),null}}function Ot(s){return s.split("/").pop()??s}function Wt(s,e){console.log(`
159
+ `);let t=s.records.reduce((c,d)=>c+d.duration,0),r=s.records.filter(c=>c.status==="success").length,n=s.records.filter(c=>c.status==="failure").length,o=(0,ct.default)(s.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),i=O(t),l=[p.default.bold("Workflow Execution History"),"",`${p.default.cyan("File:")} ${e}`,`${p.default.cyan("Started:")} ${o}`,`${p.default.cyan("Total Duration:")} ${i}`,`${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(`
160
+ `);console.log((0,Se.default)(l,{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,d)=>{Vt(c,d+1,s.records.length)}),console.log("")}function Vt(s,e,t){let r=_t(s.step),n=Ht(s.step),o=s.status==="success"?p.default.green("\u2713"):p.default.red("\u2717"),a=s.status==="success"?p.default.green("Success"):p.default.red("Failed"),i=O(s.duration),l=[`${o} ${p.default.bold(`Step ${e}/${t}`)} - ${p.default.cyan(r)}`,`${p.default.gray("Duration:")} ${i} | ${p.default.gray("Status:")} ${a}`,"",p.default.white(n)].join(`
161
+ `);console.log((0,Se.default)(l,{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"})),Jt(s.output)&&Yt(s.output)}function _t(s){return"run"in s?"Run":"choose"in s?"Choose":"prompt"in s?"Prompt":"parallel"in s?"Parallel":"fail"in s?"Fail":"Unknown"}function Ht(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 Jt(s){return typeof s=="object"&&s!==null&&"success"in s&&"stdout"in s&&"stderr"in s}function Yt(s){if(s.stdout.length>0){let e=s.stdout.map(t=>p.default.gray(` ${t}`)).join(`
149
162
  `);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)}}O.parse();
163
+ `);console.log(p.default.red(" Errors:")),console.log(e)}}U.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-pipeliner",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "A task pipeline runner with condition-based workflow execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -35,6 +35,7 @@
35
35
  "dayjs": "^1.11.19",
36
36
  "inquirer": "^8.2.6",
37
37
  "log-update": "^4.0.0",
38
+ "node-cron": "^4.2.1",
38
39
  "ora": "^5.4.1",
39
40
  "yaml": "^2.3.4",
40
41
  "zod": "^4.3.5"
@@ -43,6 +44,7 @@
43
44
  "@napi-rs/cli": "^2.16.0",
44
45
  "@types/inquirer": "^9.0.7",
45
46
  "@types/node": "^20.10.0",
47
+ "@types/node-cron": "^3.0.11",
46
48
  "@typescript-eslint/eslint-plugin": "^8.53.1",
47
49
  "@typescript-eslint/parser": "^8.53.1",
48
50
  "eslint": "^9.39.2",