task-pipeliner 0.2.18 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 조건 기반 작업 파이프라인 실행기로 아름다운 CLI 출력을 제공합니다
4
4
 
5
- **버전:** 0.2.18
5
+ **버전:** 0.3.0
6
6
 
7
7
  ![fox2](https://github.com/user-attachments/assets/fdf8d786-6a91-4d2d-9dc1-72be6f3ccd98)
8
8
 
@@ -73,7 +73,8 @@ tp history remove-all # 모든 히스토리 삭제
73
73
 
74
74
  **워크플로우 스케줄링:**
75
75
  ```bash
76
- tp schedule # 모든 스케줄 보기
76
+ tp schedule # 모든 스케줄 보기 (tp schedule list와 동일)
77
+ tp schedule list # 스케줄 목록 및 데몬 상태 보기
77
78
  tp schedule add schedules.yaml # 스케줄 파일에서 스케줄 추가
78
79
  tp schedule remove # 스케줄 삭제
79
80
  tp schedule remove-all # 모든 스케줄 삭제
@@ -81,9 +82,15 @@ tp schedule toggle # 스케줄 활성화/비활성화
81
82
  tp schedule start # 포그라운드 모드로 스케줄러 시작
82
83
  tp schedule start -d # 백그라운드 데몬 모드로 스케줄러 시작
83
84
  tp schedule stop # 스케줄러 데몬 종료
84
- tp schedule status # 데몬 상태 확인 (실시간 모드, Ctrl+C 종료)
85
+ tp schedule status # 데몬·스케줄 상태 확인 (실시간 모드; Ctrl+C 화면만 종료, 데몬은 계속 실행)
85
86
  ```
86
87
 
88
+ **데이터 및 업그레이드:**
89
+ ```bash
90
+ tp clean # ~/.pipeliner 전체 삭제 (스케줄, 데몬 상태, 워크플로우 히스토리)
91
+ ```
92
+ 버전 업그레이드 후 호환이 맞지 않을 때(스케줄/데몬 오류 등)는 `tp clean`으로 로컬 데이터를 초기화하면 됩니다. 실행 중인 데몬이 있으면 먼저 종료된 뒤 삭제됩니다.
93
+
87
94
  ## 🚀 빠른 시작
88
95
 
89
96
  ### 설치
@@ -116,6 +123,8 @@ brew update
116
123
  brew upgrade task-pipeliner
117
124
  ```
118
125
 
126
+ 업그레이드 후 호환 문제(스케줄/데몬 오류 등)가 있으면 `tp clean`으로 `~/.pipeliner` 데이터(스케줄, 데몬 상태, 히스토리)를 초기화하세요.
127
+
119
128
  #### Scoop (Windows)
120
129
 
121
130
  Windows에서 Scoop을 사용하여 설치:
@@ -140,6 +149,8 @@ tp run workflow.yaml
140
149
  scoop update task-pipeliner
141
150
  ```
142
151
 
152
+ 업그레이드 후 문제가 있으면 `tp clean`으로 `~/.pipeliner` 데이터를 초기화하세요.
153
+
143
154
  #### 전역 설치 (npm)
144
155
 
145
156
  npm을 사용하여 전역으로 설치하면 `task-pipeliner` 또는 `tp` 명령을 직접 사용할 수 있습니다:
@@ -1362,6 +1373,11 @@ schedules:
1362
1373
  cron: "0 * * * *"
1363
1374
  workflow: simple.yaml
1364
1375
  baseDir: /path/to/workflows # 선택사항: 워크플로우 경로의 기준 디렉토리
1376
+
1377
+ - name: Daily UTC
1378
+ cron: "0 9 * * *"
1379
+ workflow: ./daily.yaml
1380
+ timezone: 0 # 선택사항: UTC 오프셋(시간). +9, -5, 0. 생략 시 시스템 로컬
1365
1381
  ```
1366
1382
 
1367
1383
  **필드 설명:**
@@ -1369,6 +1385,7 @@ schedules:
1369
1385
  - `cron`: 실행 시간 (cron 표현식)
1370
1386
  - `workflow`: 워크플로우 파일 경로 (스케줄 파일 또는 `baseDir` 기준 상대 경로, 또는 절대 경로)
1371
1387
  - `baseDir`: (선택사항) 워크플로우 경로의 기준 디렉토리 (기본값: 스케줄 파일 디렉토리)
1388
+ - `timezone`: (선택사항) UTC 오프셋(시간). 숫자 또는 문자열 (예: `+9`, `-5`, `0`). 생략 시 시스템 로컬
1372
1389
  - `silent`: (선택사항) 무음 모드로 실행 (콘솔 출력 억제)
1373
1390
  - `profile`: (선택사항) 사용할 프로필 이름 (프로필이 있는 워크플로우용)
1374
1391
 
@@ -1475,17 +1492,12 @@ tp schedule start -d
1475
1492
 
1476
1493
  **데몬 상태 확인:**
1477
1494
  ```bash
1478
- tp schedule status
1479
- ```
1480
- - systemctl 스타일의 실시간 데몬 상태를 표시합니다
1481
- - 다음 정보를 표시합니다:
1482
- - 데몬 상태 (active/inactive)
1483
- - 프로세스 ID (PID)
1484
- - 시작 시간 및 업타임
1485
- - 모든 스케줄과 상태 (active/inactive)
1486
- - 각 스케줄의 마지막 실행 시간
1487
- - 1초마다 자동으로 업데이트됩니다
1488
- - `Ctrl+C`를 눌러 종료합니다 (데몬은 계속 실행됩니다)
1495
+ tp schedule status # 실시간 보기 (1초마다 갱신); Ctrl+C는 화면만 종료, 데몬은 유지
1496
+ tp schedule status -n # 한 번만 표시 후 종료 (갱신 없음)
1497
+ ```
1498
+ - 데몬·스케줄 상태를 `tp schedule list`, `tp schedule start`와 동일한 카드 레이아웃으로 표시
1499
+ - 표시 내용: 데몬 상태(active/inactive), PID, 시작 시각·업타임, 각 스케줄의 Enabled/Cron/Timezone/Workflow/Profile/Last run/Next run
1500
+ - `Ctrl+C`로 상태 화면만 종료 (데몬은 `tp schedule start -d`로 띄웠다면 계속 실행됨)
1489
1501
 
1490
1502
  스케줄러는:
1491
1503
  - 예약된 시간에 워크플로우를 실행합니다
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.18
5
+ **Version:** 0.3.0
6
6
 
7
7
  ![fox2](https://github.com/user-attachments/assets/fdf8d786-6a91-4d2d-9dc1-72be6f3ccd98)
8
8
 
@@ -73,7 +73,8 @@ tp history remove-all # Remove all histories
73
73
 
74
74
  **Workflow Scheduling:**
75
75
  ```bash
76
- tp schedule # View all schedules
76
+ tp schedule # View all schedules (same as tp schedule list)
77
+ tp schedule list # List schedules with daemon status
77
78
  tp schedule add schedules.yaml # Add schedules from a schedule file
78
79
  tp schedule remove # Remove a schedule
79
80
  tp schedule remove-all # Remove all schedules
@@ -81,9 +82,15 @@ tp schedule toggle # Enable/disable a schedule
81
82
  tp schedule start # Start scheduler in foreground mode
82
83
  tp schedule start -d # Start scheduler daemon in background
83
84
  tp schedule stop # Stop the scheduler daemon
84
- tp schedule status # Check daemon status (real-time mode, press Ctrl+C to exit)
85
+ tp schedule status # Check daemon status (real-time mode; Ctrl+C exits the view only, daemon keeps running)
85
86
  ```
86
87
 
88
+ **Data & upgrades:**
89
+ ```bash
90
+ tp clean # Remove all data in ~/.pipeliner (schedules, daemon state, workflow history)
91
+ ```
92
+ After upgrading to a new version, if you see compatibility issues (e.g. schedules or daemon not working), run `tp clean` to reset local data. The daemon is stopped first if it is running.
93
+
87
94
  ## 🚀 Quick Start
88
95
 
89
96
  ### Installation
@@ -116,6 +123,8 @@ brew update
116
123
  brew upgrade task-pipeliner
117
124
  ```
118
125
 
126
+ If you see compatibility issues after an upgrade (e.g. schedules or daemon), run `tp clean` to reset `~/.pipeliner` data (schedules, daemon state, history).
127
+
119
128
  #### Scoop (Windows)
120
129
 
121
130
  Install using Scoop on Windows:
@@ -140,6 +149,8 @@ tp run workflow.yaml
140
149
  scoop update task-pipeliner
141
150
  ```
142
151
 
152
+ If you see compatibility issues after an upgrade, run `tp clean` to reset `~/.pipeliner` data.
153
+
143
154
  #### Global Installation (npm)
144
155
 
145
156
  Install globally using npm to use `task-pipeliner` or `tp` commands directly:
@@ -1363,6 +1374,11 @@ schedules:
1363
1374
  cron: "0 * * * *"
1364
1375
  workflow: simple.yaml
1365
1376
  baseDir: /path/to/workflows # Optional: base directory for workflow path
1377
+
1378
+ - name: Daily UTC
1379
+ cron: "0 9 * * *"
1380
+ workflow: ./daily.yaml
1381
+ timezone: 0 # Optional: UTC offset (hours). +9, -5, 0. Omit = system local
1366
1382
  ```
1367
1383
 
1368
1384
  **Field Descriptions:**
@@ -1370,6 +1386,7 @@ schedules:
1370
1386
  - `cron`: Execution time (cron expression)
1371
1387
  - `workflow`: Path to workflow file (relative to schedule file or `baseDir`, or absolute)
1372
1388
  - `baseDir`: (Optional) Base directory for workflow path (defaults to schedule file's directory)
1389
+ - `timezone`: (Optional) UTC offset in hours: number or string (e.g. `+9`, `-5`, `0`). Omit = system local
1373
1390
  - `silent`: (Optional) Run in silent mode, suppressing console output
1374
1391
  - `profile`: (Optional) Profile name to use (for workflows with profiles)
1375
1392
 
@@ -1476,17 +1493,12 @@ tp schedule start -d
1476
1493
 
1477
1494
  **Checking Daemon Status:**
1478
1495
  ```bash
1479
- tp schedule status
1480
- ```
1481
- - Shows real-time daemon status with systemctl-style display
1482
- - Displays:
1483
- - Daemon state (active/inactive)
1484
- - Process ID (PID)
1485
- - Start time and uptime
1486
- - All schedules with their status (active/inactive)
1487
- - Last run time for each schedule
1488
- - Updates every second automatically
1489
- - Press `Ctrl+C` to exit (daemon continues running)
1496
+ tp schedule status # Live view (updates every second); Ctrl+C exits the view only, daemon keeps running
1497
+ tp schedule status -n # Show status once and exit (no live refresh)
1498
+ ```
1499
+ - Shows daemon and schedule status in a unified card layout (same as `tp schedule list` and `tp schedule start`)
1500
+ - Displays: daemon state (active/inactive), PID, start time and uptime, all schedules with Enabled/Cron/Timezone/Workflow/Profile/Last run/Next run
1501
+ - Press `Ctrl+C` to exit the status view (daemon continues running if it was started with `tp schedule start -d`)
1490
1502
 
1491
1503
  The scheduler will:
1492
1504
  - Execute workflows at their scheduled times
package/dist/index.cjs CHANGED
@@ -1,24 +1,26 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var Dt=Object.create;var Se=Object.defineProperty;var Mt=Object.getOwnPropertyDescriptor;var It=Object.getOwnPropertyNames;var jt=Object.getPrototypeOf,Tt=Object.prototype.hasOwnProperty;var Nt=(r,e)=>()=>(r&&(e=r(r=0)),e);var At=(r,e)=>{for(var t in e)Se(r,t,{get:e[t],enumerable:!0})},Ft=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of It(e))!Tt.call(r,s)&&s!==t&&Se(r,s,{get:()=>e[s],enumerable:!(o=Mt(e,s))||o.enumerable});return r};var b=(r,e,t)=>(t=r!=null?Dt(jt(r)):{},Ft(e||!r||!r.__esModule?Se(t,"default",{value:r,enumerable:!0}):t,r));var rt={};At(rt,{DAEMON_DIR:()=>he,getDaemonPid:()=>Me,getDaemonStartTime:()=>ot,getDaemonStatus:()=>P,isDaemonRunning:()=>W,removeDaemonPid:()=>ne,saveDaemonPid:()=>Xt});function Gt(r){try{return process.kill(r,0),!0}catch{return!1}}async function Me(){try{if(!(0,Z.existsSync)(j))return null;let r=await(0,k.readFile)(j,"utf-8"),e=parseInt(r.trim(),10);return isNaN(e)?(await(0,k.unlink)(j),null):Gt(e)?e:(await(0,k.unlink)(j),null)}catch(r){if(r instanceof Error&&"code"in r&&r.code==="ENOENT")return null;throw r}}async function W(){return await Me()!==null}async function Xt(){await(0,k.mkdir)(he,{recursive:!0}),await(0,k.writeFile)(j,process.pid.toString(),"utf-8");let r=new Date().toISOString();await(0,k.writeFile)(re,r,"utf-8")}async function ne(){try{(0,Z.existsSync)(j)&&await(0,k.unlink)(j),(0,Z.existsSync)(re)&&await(0,k.unlink)(re)}catch{}}async function ot(){try{if((0,Z.existsSync)(re)){let e=(await(0,k.readFile)(re,"utf-8")).trim();if(e)return e}if((0,Z.existsSync)(j)){let r=await(0,k.stat)(j);return new Date(r.mtime).toISOString()}return null}catch{return null}}async function P(){let r=await Me(),e=r?await ot():null;return{running:r!==null,pid:r,startTime:e}}var Z,k,tt,me,he,j,re,ge=Nt(()=>{"use strict";Z=require("fs"),k=require("fs/promises"),tt=require("os"),me=require("path"),he=(0,me.join)((0,tt.homedir)(),".pipeliner","daemon"),j=(0,me.join)(he,"scheduler.pid"),re=(0,me.join)(he,"scheduler.started")});var $t=require("child_process"),Fe=require("fs"),Rt=require("fs/promises"),Q=require("path"),Pt=require("util"),Le=b(require("boxen"),1),p=b(require("chalk"),1),Et=require("commander"),Ct=b(require("dayjs"),1);var B=require("path"),Je=b(require("chalk"),1),de=b(require("log-update"),1);var Be=b(require("readline"),1),R=b(require("chalk"),1),ve=b(require("inquirer"),1),Oe=15,L=class{searchable;constructor(e=!1){this.searchable=e}async prompt(e,t){if(this.searchable)return this.promptWithSearch(e,t);let{choice:o}=await ve.default.prompt([{type:"list",name:"choice",message:R.default.cyan(e),choices:t.map(n=>({name:n.label,value:n.id})),pageSize:Oe}]),s=t.find(n=>n.id===o);if(!s)throw new Error(`Invalid choice: ${o}`);return s}async promptWithSearch(e,t){return new Promise(o=>{let s="",n=0,a=[...t],i=Be.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(R.default.cyan(`? ${e}`));let m=s?R.default.gray(` Filter: ${s}`)+R.default.gray(` (${a.length}/${t.length})`):R.default.gray(" Type to filter, \u2191\u2193 to navigate, Enter to select");console.log(m),console.log();let d=Oe,w=0,S=a.length;if(a.length>d){let v=Math.floor(d/2);w=Math.max(0,n-v),S=Math.min(a.length,w+d),S===a.length&&(w=Math.max(0,S-d))}if(a.length===0)console.log(R.default.yellow(" No matches found"));else{w>0&&console.log(R.default.gray(` \u2191 ${w} more above`));for(let v=w;v<S;v++){let $=a[v];console.log(v===n?R.default.cyan(`\u276F ${$.label}`):R.default.white(` ${$.label}`))}S<a.length&&console.log(R.default.gray(` \u2193 ${a.length-S} more below`))}},c=()=>{let m=s.toLowerCase();a=m?t.filter(d=>d.label.toLowerCase().includes(m)):[...t],n>=a.length&&(n=Math.max(0,a.length-1))},f=m=>{let d=m.toString();if(d===""&&(g(),process.exit(0)),d==="\r"||d===`
3
- `){a.length>0&&(g(),o(a[n]));return}if(d==="\x1B"&&m.length===1){s&&(s="",c(),l());return}if(d==="\x1B[A"){a.length>0&&(n=n>0?n-1:a.length-1,l());return}if(d==="\x1B[B"){a.length>0&&(n=n<a.length-1?n+1:0,l());return}if(d==="\x7F"||d==="\b"){s.length>0&&(s=s.slice(0,-1),c(),l());return}d.length===1&&d>=" "&&d<="~"&&(s+=d,c(),l())},g=()=>{process.stdin.removeListener("data",f),process.stdin.isTTY&&process.stdin.setRawMode(!1),i.close(),process.stdout.write("\x1B[?25h"),process.stdout.write("\x1B[?1049l")};l(),process.stdin.on("data",f)})}},ie=class{async prompt(e,t){let{value:o}=await ve.default.prompt([{type:"input",name:"value",message:R.default.cyan(e),default:t}]);return o}};var ae=b(require("boxen"),1),V=b(require("chalk"),1);function ke(r,e,t,o={}){let{borderColor:s="cyan",isNested:n=!1}=o,a;e!==void 0&&(t?a=`line ${e} in ${t}`:a=`line ${e}`);let i=n?`\u2502 ${r}`:`> ${r}`;return(0,ae.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:s})}function H(r,e=!1,t){let o=r?"\u2713 Completed":"\u2717 Failed",s=r?V.default.green(o):V.default.red(o);if(t!==void 0){let n=Y(t);return`${s} ${V.default.gray(`(${n})`)}`}return s}function te(r){return(0,ae.default)(`\u2717 ${r}`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"red"})}function We(r){return(0,ae.default)(`> Starting parallel execution (${r} branches)`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"yellow"})}function _e(r){let e=r?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return r?V.default.green(e):V.default.red(e)}function xe(r,e=!1){return`${e?"| \u2502 ":"\u2502 "}${r}`}function Y(r){return`${(r/1e3).toFixed(3)}s`}var Ve=require("fs"),He=require("path"),U=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[o,s]of Object.entries(e.var)){let n=this.workspace.getVariable(o),a=this.workspace.getFact(o),i=n??(a!==void 0?a.toString():void 0);if(i===void 0||i!==s)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(),o=(0,He.resolve)(process.cwd(),t);return(0,Ve.existsSync)(o)}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 E=require("fs/promises"),Ye=require("os"),O=require("path"),Ue=b(require("dayjs"),1),J=(0,O.join)((0,Ye.homedir)(),".pipeliner","workflow-history"),z=class{constructor(){}async saveHistory(e){await(0,E.mkdir)(J,{recursive:!0});let t=(0,Ue.default)().format("YYYY-MM-DD_HH-mm-ss"),o=Math.random().toString(36).slice(2,6),s=(0,O.join)(J,`workflow-${t}-${o}.json`);return await(0,E.writeFile)(s,JSON.stringify(e,null,2),{encoding:"utf8"}),s}async clearAllHistories(){await(0,E.rm)(J,{recursive:!0,force:!0})}async removeHistory(e){await(0,E.rm)((0,O.join)(J,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,E.readdir)(J)).map(o=>(0,O.basename)(o));return t.sort((o,s)=>{let n=l=>{let c=l.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},a=n(o),i=n(s);return a===i?s.localeCompare(o):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,E.readFile)((0,O.join)(J,e),{encoding:"utf8"});return JSON.parse(t)}};var le=class{records=[];initialTimestamp=Date.now();recordStartTimestamp=Date.now();constructor(){this.records=[]}recordStart(){this.recordStartTimestamp=Date.now()}recordEnd(e,t,o,s){let n=this.getDuration();return this.records.push({step:e,context:t,output:o,duration:n,status:s}),n}reset(){this.records=[],this.initialTimestamp=Date.now()}async save(){let e=new z,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var $e=require("child_process");var ce=class{async run(e,t,o,s,n=!1,a=!1,i,l,c,f,g){return n?this.runBuffered(e,c,f,g):this.runRealtime(e,o||e,a,i,l,c,f,g)}async runBuffered(e,t,o,s){return new Promise((n,a)=>{let i=this.spawnWithShell(e,t,s),l=[],c=[],f="",g="",m=null;o&&o>0&&(m=setTimeout(()=>{i.kill("SIGTERM");let d=`Command timed out after ${o} seconds`;c.push(d),n({success:!1,stdout:l,stderr:c})},o*1e3)),i.stdout?.on("data",d=>{let w=d.toString(),{lines:S,remaining:v}=this.processStreamBuffer(w,f);l.push(...S),f=v}),i.stderr?.on("data",d=>{let w=d.toString(),{lines:S,remaining:v}=this.processStreamBuffer(w,g);c.push(...S),g=v}),i.on("close",d=>{m&&clearTimeout(m),f.trim()&&l.push(f),g.trim()&&c.push(g),n({success:d===0,stdout:l,stderr:c})}),i.on("error",d=>{m&&clearTimeout(m);let w=`Error: ${d.message}`;n({success:!1,stdout:l,stderr:[...c,w]})})})}async runRealtime(e,t,o,s,n,a,i,l){let f=ke(t,s,n,{borderColor:o?"green":"cyan"});console.log(f);let g=Date.now();return new Promise(m=>{let d=this.spawnWithShell(e,a,l),w="",S="",v=null;i&&i>0&&(v=setTimeout(()=>{d.kill("SIGTERM");let $=`Command timed out after ${i} seconds`,D=te($);console.error(D);let A=Date.now()-g,F=H(!1,!1,A);console.log(F),m(!1)},i*1e3)),d.stdout?.on("data",$=>{let D=$.toString(),{lines:A,remaining:F}=this.processStreamBuffer(D,w);A.forEach(be=>process.stdout.write(`\u2502 ${be}
4
- `)),w=F}),d.stderr?.on("data",$=>{let D=$.toString(),{lines:A,remaining:F}=this.processStreamBuffer(D,S);A.forEach(be=>process.stderr.write(`\u2502 ${be}
5
- `)),S=F}),d.on("close",$=>{v&&clearTimeout(v),w.trim()&&process.stdout.write(`\u2502 ${w}
6
- `),S.trim()&&process.stderr.write(`\u2502 ${S}
7
- `);let D=$===0,A=Date.now()-g,F=H(D,!1,A);console.log(F),m(D)}),d.on("error",$=>{v&&clearTimeout(v);let D=te(`Error: ${$.message}`);console.error(D),m(!1)})})}createSpawnOptions(e){let t={stdio:["inherit","pipe","pipe"],shell:!0};return e&&(t.cwd=e),t}spawnWithShell(e,t,o){if(o&&o.length>0){let s=o[0],n=[...o.slice(1),e],a={stdio:["inherit","pipe","pipe"]};return t&&(a.cwd=t),(0,$e.spawn)(s,n,a)}else{let s=process.env.SHELL||(process.platform==="win32"?"cmd.exe":"/bin/sh"),n=process.platform==="win32"?"/c":"-c",a={stdio:["inherit","pipe","pipe"]};return t&&(a.cwd=t),(0,$e.spawn)(s,[n,e],a)}}processStreamBuffer(e,t){let o=t+e,s=[],n=o;for(;n.includes(`
8
- `);){let a=n.indexOf(`
9
- `),i=n.substring(0,a);n=n.substring(a+1),s.push(i)}return{lines:s,remaining:n}}formatNestedOutput(e,t){t?e.split(`
10
- `).forEach(o=>{o.trim()&&console.log(`| ${o}`)}):console.log(e)}displayBufferedOutput(e,t,o=!1,s,n){let a=ke(t,s,n,{borderColor:"cyan",isNested:o});this.formatNestedOutput(a,o),e.stdout.forEach(l=>{let c=xe(l,o);process.stdout.write(`${c}
11
- `)}),e.stderr.forEach(l=>{let c=xe(l,o);process.stderr.write(`${c}
12
- `)});let i=H(e.success,o);console.log(i)}};function Lt(r,e,t){if(e.hasVariable(r)){let o=e.getVariable(r);return o??t}if(e.hasFact(r)){let o=e.getFact(r);return typeof o=="string"?o:String(o)}if(e.hasChoice(r)){let o=e.getChoice(r);return o??t}return t}function ue(r,e){let t=/\{\{\s*(\w+)\s*\}\}/g;return r.replace(t,(o,s)=>Lt(s,e,o))}var pe=class r{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,o){this.state.stepResults.set(e,{success:t,exitCode:o}),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 r;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 q=class r{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;globalShell;constructor(){this.workspace=new pe,this.taskRunner=new ce,this.choicePrompt=new L,this.textPrompt=new ie}resolveBaseDir(e){if(e.baseDir)if((0,B.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,B.dirname)(e._filePath);this.baseDir=(0,B.resolve)(t,e.baseDir)}else this.baseDir=(0,B.resolve)(process.cwd(),e.baseDir)}createStepContext(e,t){let o={workspace:this.workspace,stepIndex:e};return t._lineNumbers&&(o.lineNumber=t._lineNumbers.get(e)),t._fileName&&(o.fileName=t._fileName),o}evaluateStepCondition(e){return e.when?new U(this.workspace).evaluate(e.when):!0}calculateBaseStepIndex(e){return e.branchIndex===void 0?e.stepIndex:Math.floor(e.stepIndex/r.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 o=new le,s=Date.now();for(let i=0;i<e.steps.length;i++){let l=e.steps[i],c=this.createStepContext(i,e),f=!!l.when;if(this.evaluateStepCondition(l)){o.recordStart();try{let g=await this.executeStep(l,c,!1,f);this.handleStepResult(l,c,i,g,o)}catch(g){throw this.handleStepError(l,c,i,g,o),g}}}let n=Date.now()-s,a=Y(n);console.log(Je.default.cyan(`
13
- Total execution time: ${a}`)),await o.save(),o.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,o,s,n){let a=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(o);return c?c.success:!0})():this.isStepSuccessful(s,e),i=a?"success":"failure",l=n.recordEnd(e,t,s,i);if(!this.isRunStep(e)){let c=H(a,!1,l);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",f=a?`Step ${o}${c} completed, but workflow stopped due to continue: false`:`Step ${o}${c} failed`;throw new Error(f)}if(!a&&e.continue!==!0){let c=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${o}${c} failed`)}}}handleStepError(e,t,o,s,n){this.workspace.setStepResult(o,!1);let a=s instanceof Error?s.message:String(s),i={success:!1,stdout:[],stderr:[a]};n.recordEnd(e,t,i,"failure")}fixMalformedStep(e){let o=e;return"choose"in e&&o.choose===null&&"message"in e&&"options"in e?{choose:{message:o.message,options:o.options,as:o.as},when:o.when}:"prompt"in e&&o.prompt===null&&"message"in e&&"as"in e?{prompt:{message:o.message,as:o.as,default:o.default},when:o.when}:e}async executeStep(e,t,o=!1,s=!1){if(e=this.fixMalformedStep(e),"run"in e){let n=await this.executeRunStep(e,t,o,s);return o&&typeof n=="object"&&"stdout"in n,n}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,o=!1,s=!1){let n=this.calculateBaseStepIndex(t),a=ue(e.run,this.workspace),i=e.shell||this.globalShell,l=e.retry??0,c=e.timeout,f=!1,g=0;for(;g<=l;){let m=await this.taskRunner.run(a,n,a,t.branchIndex,o,s,t.lineNumber,t.fileName,this.baseDir,c,i),d=typeof m=="boolean"?m:m.success;if(f=m,d||g>=l)break;if(g++,g<=l){let w=Math.min(1e3*Math.pow(2,g-1),1e4);await new Promise(S=>setTimeout(S,w))}}return f}async executeRunStep(e,t,o=!1,s=!1){let n=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:e.shell},t,o,s),a=typeof n=="boolean"?n:n.success;if(this.workspace.setStepResult(t.stepIndex,a),a||!e.onError)return n;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,o,s)}async executeRunChain(e,t,o,s){let n=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:void 0},t,o,s);return(typeof n=="boolean"?n:n.success)||!e.onError?n:this.executeRunChain(e.onError,t,o,s)}async executeChooseStep(e,t){let o=e.choose.as,s=e.choose.options.map(i=>i.id);if(o&&this.workspace.hasVariable(o)){let i=this.workspace.getVariable(o)??"";if(s.includes(i)){this.workspace.setChoice(i,i),this.workspace.setStepResult(t.stepIndex,!0);return}}let n=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!n?.id)throw new Error(`Invalid choice result: ${JSON.stringify(n)}`);let a=o??n.id;this.workspace.setChoice(n.id,n.id),this.workspace.setVariable(a,n.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let o=e.prompt.as;if(this.workspace.hasVariable(o)){let i=this.workspace.getVariable(o)??"";this.workspace.setFact(o,i),this.workspace.setStepResult(t.stepIndex,!0);return}let s=ue(e.prompt.message,this.workspace),n=e.prompt.default?ue(e.prompt.default,this.workspace):void 0,a=await this.textPrompt.prompt(s,n);this.workspace.setVariable(o,a),this.workspace.setFact(o,a),this.workspace.setStepResult(t.stepIndex,!0)}createParallelContexts(e,t){return e.parallel.map((o,s)=>({workspace:this.workspace.clone(),stepIndex:t.stepIndex*r.PARALLEL_STEP_INDEX_MULTIPLIER+s,branchIndex:s,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 o=[],s=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],n=0;for(let c=0;c<e.length;c++){let f=e[c],g=t[c];if(f.when&&!new U(g.workspace).evaluate(f.when))continue;let m=this.getBranchDisplayName(f,c);o.push({index:c,name:m,status:"pending"})}let a=setInterval(()=>{n=(n+1)%s.length,this.updateParallelBranchesDisplay(o,s[n])},100),i=o.map(async c=>{let{index:f}=c,g=e[f],m=t[f];c.status="running";try{let d=await this.executeStep(g,m,!0);return c.status="success",this.updateParallelBranchesDisplay(o,s[n]),{index:f,result:d,context:m}}catch(d){m.workspace.setStepResult(m.stepIndex,!1);let w=d instanceof Error?d.message:String(d);return c.status="failed",c.error=w,this.updateParallelBranchesDisplay(o,s[n]),{index:f,error:d,context:m}}}),l=await Promise.all(i);return clearInterval(a),this.updateParallelBranchesDisplay(o,"",!0),de.default.done(),l}updateParallelBranchesDisplay(e,t,o=!1){let s=e.map(n=>{let a=n.index+1,i="",l="";switch(n.status){case"pending":i="\u25CB",l=`Branch ${a}: ${n.name} - Pending`;break;case"running":i=t,l=`Branch ${a}: ${n.name} - Running...`;break;case"success":i="\u2713",l=`Branch ${a}: ${n.name} - Completed`;break;case"failed":i="\u2717",l=`Branch ${a}: ${n.name} - Failed${n.error?`: ${n.error}`:""}`;break}return`${i} ${l}`});o?(0,de.default)(s.join(`
14
- `)):(0,de.default)(s.join(`
15
- `))}displayParallelResults(e,t,o){let s=!0,n=!1;console.log("");for(let i of e){if(!i)continue;n=!0;let{index:l,result:c,error:f,context:g}=i;if(f){s=!1;let m=`Branch ${l+1} failed: ${f instanceof Error?f.message:String(f)}`,d=te(m);console.error(d)}else if(c&&typeof c=="object"&&"stdout"in c){let m=c;if(s=s&&m.success,m.stdout.length>0||m.stderr.length>0||!m.success){let d=t[l],w=this.getBranchDisplayName(d,l);this.taskRunner.displayBufferedOutput(m,w,!1,g.lineNumber,g.fileName)}}}n||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let a=_e(s);return console.log(a),s}mergeParallelResults(e){for(let t of e){let o=t.workspace.getAllFacts(),s=t.workspace.getAllVariables();for(let[n,a]of o)this.workspace.setFact(n,a);for(let[n,a]of s)this.workspace.setVariable(n,a)}}countExecutableBranches(e,t){let o=0;for(let s=0;s<e.length;s++){let n=e[s],a=t[s];n.when&&!new U(a.workspace).evaluate(n.when)||o++}return o}async executeParallelStep(e,t){let o=this.createParallelContexts(e,t),s=this.countExecutableBranches(e.parallel,o),n=We(s);console.log(n);let a=await this.executeParallelBranches(e.parallel,o),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(o)}async executeFailStep(e,t){let o=new Error(e.fail.message);throw o.stack=void 0,o}};var Xe=require("yaml"),Ce=require("zod");var u=require("zod"),Ot=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()}),Wt=u.z.object({status:u.z.object({fact:u.z.string(),is:u.z.enum(["ready","failed","pending"])})}),_t=u.z.object({step:u.z.object({success:u.z.boolean()}).optional(),last_step:u.z.enum(["success","failure"]).optional()}),Vt=u.z.object({choice:u.z.string()}),Ht=u.z.union([Ot,Vt,Bt,Wt,_t]),M=u.z.lazy(()=>u.z.union([Ht,u.z.object({all:u.z.array(M)}),u.z.object({any:u.z.array(M)}),u.z.object({not:M})])),ze=u.z.lazy(()=>u.z.object({run:u.z.string(),timeout:u.z.number().optional(),retry:u.z.number().optional(),onError:ze.optional()})),qe=u.z.object({run:u.z.string(),when:M.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:ze.optional()}),Yt=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:M.optional()}),Ut=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:M.optional()});function Ze(r){if(!r||typeof r!="object")return{found:!1};let e=r;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 o=Ze(t);if(o.found)return o}return{found:!1}}var Ge=u.z.lazy(()=>u.z.union([qe,u.z.object({parallel:u.z.array(u.z.lazy(()=>Ge)),when:M.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:M.optional()})]).superRefine((r,e)=>{let t=Ze(r);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)`})})),Jt=u.z.lazy(()=>u.z.union([qe,Yt,Ut,u.z.object({parallel:u.z.array(Ge),when:M.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:M.optional()})])),zt=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))}),qt=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(zt).optional(),steps:u.z.array(Jt).min(1,"Workflow must have at least one step")});function Re(r){return qt.parse(r)}function Ke(r,e){let t=r.path;if(r.code==="custom"){let s=Pe(t);return` - ${r.message}${s}`}if(r.message==="Invalid input"){let s=Pe(t),n=Zt(t,e);return n?` - ${n}${s}`:` - Invalid step type${s}`}let o=Pe(t);return` - ${r.message}${o}`}function Pe(r){if(r.length===0)return"";let e=[];for(let t=0;t<r.length;t++){let o=r[t],s=r[t+1];o==="steps"&&typeof s=="number"?(e.push(`step ${s+1}`),t++):o==="parallel"&&typeof s=="number"?(e.push(`parallel branch ${s+1}`),t++):typeof o=="string"&&o!=="steps"&&o!=="parallel"&&e.push(o)}return e.length>0?` (${e.join(" \u2192 ")})`:""}function y(r,e,t){let o=t?`
2
+ "use strict";var Ut=Object.create;var De=Object.defineProperty;var Jt=Object.getOwnPropertyDescriptor;var qt=Object.getOwnPropertyNames;var Gt=Object.getPrototypeOf,Zt=Object.prototype.hasOwnProperty;var Xt=(r,e)=>()=>(r&&(e=r(r=0)),e);var Kt=(r,e)=>{for(var t in e)De(r,t,{get:e[t],enumerable:!0})},Qt=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of qt(e))!Zt.call(r,n)&&n!==t&&De(r,n,{get:()=>e[n],enumerable:!(o=Jt(e,n))||o.enumerable});return r};var y=(r,e,t)=>(t=r!=null?Ut(Gt(r)):{},Qt(e||!r||!r.__esModule?De(t,"default",{value:r,enumerable:!0}):t,r));var et={};Kt(et,{DAEMON_DIR:()=>q,getDaemonErrorLogPath:()=>Me,getDaemonPid:()=>Te,getDaemonStartTime:()=>Qe,getDaemonStatus:()=>$,isDaemonRunning:()=>A,readDaemonErrorLog:()=>je,removeDaemonPid:()=>se,saveDaemonPid:()=>to,writeDaemonError:()=>Ie});function eo(r){try{return process.kill(r,0),!0}catch{return!1}}async function Te(){try{if(!(0,V.existsSync)(N))return null;let r=await(0,x.readFile)(N,"utf-8"),e=parseInt(r.trim(),10);return isNaN(e)?(await(0,x.unlink)(N),null):eo(e)?e:(await(0,x.unlink)(N),null)}catch(r){if(r instanceof Error&&"code"in r&&r.code==="ENOENT")return null;throw r}}async function A(){return await Te()!==null}async function to(){await(0,x.mkdir)(q,{recursive:!0}),await(0,x.writeFile)(N,process.pid.toString(),"utf-8");let r=new Date().toISOString();await(0,x.writeFile)(re,r,"utf-8")}async function Ie(r){try{await(0,x.mkdir)(q,{recursive:!0});let e=`${new Date().toISOString()} ${r.message}
3
+ ${r.stack??""}
4
+ `;await(0,x.writeFile)(de,e,"utf-8")}catch{}}async function se(){try{(0,V.existsSync)(N)&&await(0,x.unlink)(N),(0,V.existsSync)(re)&&await(0,x.unlink)(re)}catch{}}async function Qe(){try{if((0,V.existsSync)(re)){let e=(await(0,x.readFile)(re,"utf-8")).trim();if(e)return e}if((0,V.existsSync)(N)){let r=await(0,x.stat)(N);return new Date(r.mtime).toISOString()}return null}catch{return null}}function Me(){return de}async function je(){try{return(0,V.existsSync)(de)&&(await(0,x.readFile)(de,"utf-8")).trim()||null}catch{return null}}async function $(){let r=await Te(),e=r?await Qe():null;return{running:r!==null,pid:r,startTime:e}}var V,x,Ke,ne,q,N,re,de,ie=Xt(()=>{"use strict";V=require("fs"),x=require("fs/promises"),Ke=require("os"),ne=require("path"),q=(0,ne.join)((0,Ke.homedir)(),".pipeliner","daemon"),N=(0,ne.join)(q,"scheduler.pid"),re=(0,ne.join)(q,"scheduler.started");de=(0,ne.join)(q,"error.log")});var _t=require("child_process"),pe=require("fs"),Pe=require("fs/promises"),Vt=require("os"),U=require("path"),Ht=require("util"),Xe=y(require("boxen"),1),p=y(require("chalk"),1),zt=require("commander"),Yt=y(require("dayjs"),1);ie();var z=require("path"),ct=y(require("chalk"),1),be=y(require("log-update"),1);var ot=y(require("readline"),1),C=y(require("chalk"),1),Ne=y(require("inquirer"),1),tt=15,L=class{searchable;constructor(e=!1){this.searchable=e}async prompt(e,t){if(this.searchable)return this.promptWithSearch(e,t);let{choice:o}=await Ne.default.prompt([{type:"list",name:"choice",message:C.default.cyan(e),choices:t.map(s=>({name:s.label,value:s.id})),pageSize:tt}]),n=t.find(s=>s.id===o);if(!n)throw new Error(`Invalid choice: ${o}`);return n}async promptWithSearch(e,t){return new Promise(o=>{let n="",s=0,i=[...t],a=ot.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(C.default.cyan(`? ${e}`));let m=n?C.default.gray(` Filter: ${n}`)+C.default.gray(` (${i.length}/${t.length})`):C.default.gray(" Type to filter, \u2191\u2193 to navigate, Enter to select");console.log(m),console.log();let d=tt,w=0,v=i.length;if(i.length>d){let k=Math.floor(d/2);w=Math.max(0,s-k),v=Math.min(i.length,w+d),v===i.length&&(w=Math.max(0,v-d))}if(i.length===0)console.log(C.default.yellow(" No matches found"));else{w>0&&console.log(C.default.gray(` \u2191 ${w} more above`));for(let k=w;k<v;k++){let R=i[k];console.log(k===s?C.default.cyan(`\u276F ${R.label}`):C.default.white(` ${R.label}`))}v<i.length&&console.log(C.default.gray(` \u2193 ${i.length-v} more below`))}},c=()=>{let m=n.toLowerCase();i=m?t.filter(d=>d.label.toLowerCase().includes(m)):[...t],s>=i.length&&(s=Math.max(0,i.length-1))},f=m=>{let d=m.toString();if(d===""&&(g(),process.exit(0)),d==="\r"||d===`
5
+ `){i.length>0&&(g(),o(i[s]));return}if(d==="\x1B"&&m.length===1){n&&(n="",c(),l());return}if(d==="\x1B[A"){i.length>0&&(s=s>0?s-1:i.length-1,l());return}if(d==="\x1B[B"){i.length>0&&(s=s<i.length-1?s+1:0,l());return}if(d==="\x7F"||d==="\b"){n.length>0&&(n=n.slice(0,-1),c(),l());return}d.length===1&&d>=" "&&d<="~"&&(n+=d,c(),l())},g=()=>{process.stdin.removeListener("data",f),process.stdin.isTTY&&process.stdin.setRawMode(!1),a.close(),process.stdout.write("\x1B[?25h"),process.stdout.write("\x1B[?1049l")};l(),process.stdin.on("data",f)})}},fe=class{async prompt(e,t){let{value:o}=await Ne.default.prompt([{type:"input",name:"value",message:C.default.cyan(e),default:t}]);return o}};var me=y(require("boxen"),1),G=y(require("chalk"),1);function Ae(r,e,t,o={}){let{borderColor:n="cyan",isNested:s=!1}=o,i;e!==void 0&&(t?i=`line ${e} in ${t}`:i=`line ${e}`);let a=s?`\u2502 ${r}`:`> ${r}`;return(0,me.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 Z(r,e=!1,t){let o=r?"\u2713 Completed":"\u2717 Failed",n=r?G.default.green(o):G.default.red(o);if(t!==void 0){let s=X(t);return`${n} ${G.default.gray(`(${s})`)}`}return n}function ae(r){return(0,me.default)(`\u2717 ${r}`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"red"})}function rt(r){return(0,me.default)(`> Starting parallel execution (${r} branches)`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"yellow"})}function nt(r){let e=r?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return r?G.default.green(e):G.default.red(e)}function Oe(r,e=!1){return`${e?"| \u2502 ":"\u2502 "}${r}`}function X(r){return`${(r/1e3).toFixed(3)}s`}var st=require("fs"),it=require("path"),K=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[o,n]of Object.entries(e.var)){let s=this.workspace.getVariable(o),i=this.workspace.getFact(o),a=s??(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(),o=(0,it.resolve)(process.cwd(),t);return(0,st.existsSync)(o)}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 D=require("fs/promises"),at=require("os"),H=require("path"),lt=y(require("dayjs"),1),Q=(0,H.join)((0,at.homedir)(),".pipeliner","workflow-history"),ee=class{constructor(){}async saveHistory(e){await(0,D.mkdir)(Q,{recursive:!0});let t=(0,lt.default)().format("YYYY-MM-DD_HH-mm-ss"),o=Math.random().toString(36).slice(2,6),n=(0,H.join)(Q,`workflow-${t}-${o}.json`);return await(0,D.writeFile)(n,JSON.stringify(e,null,2),{encoding:"utf8"}),n}async clearAllHistories(){await(0,D.rm)(Q,{recursive:!0,force:!0})}async removeHistory(e){await(0,D.rm)((0,H.join)(Q,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,D.readdir)(Q)).map(o=>(0,H.basename)(o));return t.sort((o,n)=>{let s=l=>{let c=l.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},i=s(o),a=s(n);return i===a?n.localeCompare(o):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,D.readFile)((0,H.join)(Q,e),{encoding:"utf8"});return JSON.parse(t)}};var he=class{records=[];initialTimestamp=Date.now();recordStartTimestamp=Date.now();constructor(){this.records=[]}recordStart(){this.recordStartTimestamp=Date.now()}recordEnd(e,t,o,n){let s=this.getDuration();return this.records.push({step:e,context:t,output:o,duration:s,status:n}),s}reset(){this.records=[],this.initialTimestamp=Date.now()}async save(){let e=new ee,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var Fe=require("child_process");var ge=class{async run(e,t,o,n,s=!1,i=!1,a,l,c,f,g){return s?this.runBuffered(e,c,f,g):this.runRealtime(e,o||e,i,a,l,c,f,g)}async runBuffered(e,t,o,n){return new Promise((s,i)=>{let a=this.spawnWithShell(e,t,n),l=[],c=[],f="",g="",m=null;o&&o>0&&(m=setTimeout(()=>{a.kill("SIGTERM");let d=`Command timed out after ${o} seconds`;c.push(d),s({success:!1,stdout:l,stderr:c})},o*1e3)),a.stdout?.on("data",d=>{let w=d.toString(),{lines:v,remaining:k}=this.processStreamBuffer(w,f);l.push(...v),f=k}),a.stderr?.on("data",d=>{let w=d.toString(),{lines:v,remaining:k}=this.processStreamBuffer(w,g);c.push(...v),g=k}),a.on("close",d=>{m&&clearTimeout(m),f.trim()&&l.push(f),g.trim()&&c.push(g),s({success:d===0,stdout:l,stderr:c})}),a.on("error",d=>{m&&clearTimeout(m);let w=`Error: ${d.message}`;s({success:!1,stdout:l,stderr:[...c,w]})})})}async runRealtime(e,t,o,n,s,i,a,l){let f=Ae(t,n,s,{borderColor:o?"green":"cyan"});console.log(f);let g=Date.now();return new Promise(m=>{let d=this.spawnWithShell(e,i,l),w="",v="",k=null;a&&a>0&&(k=setTimeout(()=>{d.kill("SIGTERM");let R=`Command timed out after ${a} seconds`,I=ae(R);console.error(I);let W=Date.now()-g,_=Z(!1,!1,W);console.log(_),m(!1)},a*1e3)),d.stdout?.on("data",R=>{let I=R.toString(),{lines:W,remaining:_}=this.processStreamBuffer(I,w);W.forEach(Ce=>process.stdout.write(`\u2502 ${Ce}
6
+ `)),w=_}),d.stderr?.on("data",R=>{let I=R.toString(),{lines:W,remaining:_}=this.processStreamBuffer(I,v);W.forEach(Ce=>process.stderr.write(`\u2502 ${Ce}
7
+ `)),v=_}),d.on("close",R=>{k&&clearTimeout(k),w.trim()&&process.stdout.write(`\u2502 ${w}
8
+ `),v.trim()&&process.stderr.write(`\u2502 ${v}
9
+ `);let I=R===0,W=Date.now()-g,_=Z(I,!1,W);console.log(_),m(I)}),d.on("error",R=>{k&&clearTimeout(k);let I=ae(`Error: ${R.message}`);console.error(I),m(!1)})})}createSpawnOptions(e){let t={stdio:["inherit","pipe","pipe"],shell:!0};return e&&(t.cwd=e),t}spawnWithShell(e,t,o){if(o&&o.length>0){let n=o[0],s=[...o.slice(1),e],i={stdio:["inherit","pipe","pipe"]};return t&&(i.cwd=t),(0,Fe.spawn)(n,s,i)}else{let n=process.env.SHELL||(process.platform==="win32"?"cmd.exe":"/bin/sh"),s=process.platform==="win32"?"/c":"-c",i={stdio:["inherit","pipe","pipe"]};return t&&(i.cwd=t),(0,Fe.spawn)(n,[s,e],i)}}processStreamBuffer(e,t){let o=t+e,n=[],s=o;for(;s.includes(`
10
+ `);){let i=s.indexOf(`
11
+ `),a=s.substring(0,i);s=s.substring(i+1),n.push(a)}return{lines:n,remaining:s}}formatNestedOutput(e,t){t?e.split(`
12
+ `).forEach(o=>{o.trim()&&console.log(`| ${o}`)}):console.log(e)}displayBufferedOutput(e,t,o=!1,n,s){let i=Ae(t,n,s,{borderColor:"cyan",isNested:o});this.formatNestedOutput(i,o),e.stdout.forEach(l=>{let c=Oe(l,o);process.stdout.write(`${c}
13
+ `)}),e.stderr.forEach(l=>{let c=Oe(l,o);process.stderr.write(`${c}
14
+ `)});let a=Z(e.success,o);console.log(a)}};function oo(r,e,t){if(e.hasVariable(r)){let o=e.getVariable(r);return o??t}if(e.hasFact(r)){let o=e.getFact(r);return typeof o=="string"?o:String(o)}if(e.hasChoice(r)){let o=e.getChoice(r);return o??t}return t}function we(r,e){let t=/\{\{\s*(\w+)\s*\}\}/g;return r.replace(t,(o,n)=>oo(n,e,o))}var ye=class r{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,o){this.state.stepResults.set(e,{success:t,exitCode:o}),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 r;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 te=class r{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;globalShell;constructor(){this.workspace=new ye,this.taskRunner=new ge,this.choicePrompt=new L,this.textPrompt=new fe}resolveBaseDir(e){if(e.baseDir)if((0,z.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,z.dirname)(e._filePath);this.baseDir=(0,z.resolve)(t,e.baseDir)}else this.baseDir=(0,z.resolve)(process.cwd(),e.baseDir)}createStepContext(e,t){let o={workspace:this.workspace,stepIndex:e};return t._lineNumbers&&(o.lineNumber=t._lineNumbers.get(e)),t._fileName&&(o.fileName=t._fileName),o}evaluateStepCondition(e){return e.when?new K(this.workspace).evaluate(e.when):!0}calculateBaseStepIndex(e){return e.branchIndex===void 0?e.stepIndex:Math.floor(e.stepIndex/r.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,l]of Object.entries(t.profileVars))this.workspace.setVariable(a,l);this.resolveBaseDir(e),this.globalShell=e.shell;let o=new he,n=Date.now();for(let a=0;a<e.steps.length;a++){let l=e.steps[a],c=this.createStepContext(a,e),f=!!l.when;if(this.evaluateStepCondition(l)){o.recordStart();try{let g=await this.executeStep(l,c,!1,f);this.handleStepResult(l,c,a,g,o)}catch(g){throw this.handleStepError(l,c,a,g,o),g}}}let s=Date.now()-n,i=X(s);console.log(ct.default.cyan(`
15
+ Total execution time: ${i}`)),await o.save(),o.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,o,n,s){let i=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(o);return c?c.success:!0})():this.isStepSuccessful(n,e),a=i?"success":"failure",l=s.recordEnd(e,t,n,a);if(!this.isRunStep(e)){let c=Z(i,!1,l);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",f=i?`Step ${o}${c} completed, but workflow stopped due to continue: false`:`Step ${o}${c} failed`;throw new Error(f)}if(!i&&e.continue!==!0){let c=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${o}${c} failed`)}}}handleStepError(e,t,o,n,s){this.workspace.setStepResult(o,!1);let i=n instanceof Error?n.message:String(n),a={success:!1,stdout:[],stderr:[i]};s.recordEnd(e,t,a,"failure")}fixMalformedStep(e){let o=e;return"choose"in e&&o.choose===null&&"message"in e&&"options"in e?{choose:{message:o.message,options:o.options,as:o.as},when:o.when}:"prompt"in e&&o.prompt===null&&"message"in e&&"as"in e?{prompt:{message:o.message,as:o.as,default:o.default},when:o.when}:e}async executeStep(e,t,o=!1,n=!1){if(e=this.fixMalformedStep(e),"run"in e){let s=await this.executeRunStep(e,t,o,n);return o&&typeof s=="object"&&"stdout"in s,s}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,o=!1,n=!1){let s=this.calculateBaseStepIndex(t),i=we(e.run,this.workspace),a=e.shell||this.globalShell,l=e.retry??0,c=e.timeout,f=!1,g=0;for(;g<=l;){let m=await this.taskRunner.run(i,s,i,t.branchIndex,o,n,t.lineNumber,t.fileName,this.baseDir,c,a),d=typeof m=="boolean"?m:m.success;if(f=m,d||g>=l)break;if(g++,g<=l){let w=Math.min(1e3*Math.pow(2,g-1),1e4);await new Promise(v=>setTimeout(v,w))}}return f}async executeRunStep(e,t,o=!1,n=!1){let s=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:e.shell},t,o,n),i=typeof s=="boolean"?s:s.success;if(this.workspace.setStepResult(t.stepIndex,i),i||!e.onError)return s;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,o,n)}async executeRunChain(e,t,o,n){let s=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry,shell:void 0},t,o,n);return(typeof s=="boolean"?s:s.success)||!e.onError?s:this.executeRunChain(e.onError,t,o,n)}async executeChooseStep(e,t){let o=e.choose.as,n=e.choose.options.map(a=>a.id);if(o&&this.workspace.hasVariable(o)){let a=this.workspace.getVariable(o)??"";if(n.includes(a)){this.workspace.setChoice(a,a),this.workspace.setStepResult(t.stepIndex,!0);return}}let s=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!s?.id)throw new Error(`Invalid choice result: ${JSON.stringify(s)}`);let i=o??s.id;this.workspace.setChoice(s.id,s.id),this.workspace.setVariable(i,s.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let o=e.prompt.as;if(this.workspace.hasVariable(o)){let a=this.workspace.getVariable(o)??"";this.workspace.setFact(o,a),this.workspace.setStepResult(t.stepIndex,!0);return}let n=we(e.prompt.message,this.workspace),s=e.prompt.default?we(e.prompt.default,this.workspace):void 0,i=await this.textPrompt.prompt(n,s);this.workspace.setVariable(o,i),this.workspace.setFact(o,i),this.workspace.setStepResult(t.stepIndex,!0)}createParallelContexts(e,t){return e.parallel.map((o,n)=>({workspace:this.workspace.clone(),stepIndex:t.stepIndex*r.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 o=[],n=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],s=0;for(let c=0;c<e.length;c++){let f=e[c],g=t[c];if(f.when&&!new K(g.workspace).evaluate(f.when))continue;let m=this.getBranchDisplayName(f,c);o.push({index:c,name:m,status:"pending"})}let i=setInterval(()=>{s=(s+1)%n.length,this.updateParallelBranchesDisplay(o,n[s])},100),a=o.map(async c=>{let{index:f}=c,g=e[f],m=t[f];c.status="running";try{let d=await this.executeStep(g,m,!0);return c.status="success",this.updateParallelBranchesDisplay(o,n[s]),{index:f,result:d,context:m}}catch(d){m.workspace.setStepResult(m.stepIndex,!1);let w=d instanceof Error?d.message:String(d);return c.status="failed",c.error=w,this.updateParallelBranchesDisplay(o,n[s]),{index:f,error:d,context:m}}}),l=await Promise.all(a);return clearInterval(i),this.updateParallelBranchesDisplay(o,"",!0),be.default.done(),l}updateParallelBranchesDisplay(e,t,o=!1){let n=e.map(s=>{let i=s.index+1,a="",l="";switch(s.status){case"pending":a="\u25CB",l=`Branch ${i}: ${s.name} - Pending`;break;case"running":a=t,l=`Branch ${i}: ${s.name} - Running...`;break;case"success":a="\u2713",l=`Branch ${i}: ${s.name} - Completed`;break;case"failed":a="\u2717",l=`Branch ${i}: ${s.name} - Failed${s.error?`: ${s.error}`:""}`;break}return`${a} ${l}`});o?(0,be.default)(n.join(`
16
+ `)):(0,be.default)(n.join(`
17
+ `))}displayParallelResults(e,t,o){let n=!0,s=!1;console.log("");for(let a of e){if(!a)continue;s=!0;let{index:l,result:c,error:f,context:g}=a;if(f){n=!1;let m=`Branch ${l+1} failed: ${f instanceof Error?f.message:String(f)}`,d=ae(m);console.error(d)}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 d=t[l],w=this.getBranchDisplayName(d,l);this.taskRunner.displayBufferedOutput(m,w,!1,g.lineNumber,g.fileName)}}}s||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let i=nt(n);return console.log(i),n}mergeParallelResults(e){for(let t of e){let o=t.workspace.getAllFacts(),n=t.workspace.getAllVariables();for(let[s,i]of o)this.workspace.setFact(s,i);for(let[s,i]of n)this.workspace.setVariable(s,i)}}countExecutableBranches(e,t){let o=0;for(let n=0;n<e.length;n++){let s=e[n],i=t[n];s.when&&!new K(i.workspace).evaluate(s.when)||o++}return o}async executeParallelStep(e,t){let o=this.createParallelContexts(e,t),n=this.countExecutableBranches(e.parallel,o),s=rt(n);console.log(s);let i=await this.executeParallelBranches(e.parallel,o),a=this.displayParallelResults(i,e.parallel,t);if(this.workspace.setStepResult(t.stepIndex,a),!a){let l=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Parallel step ${t.stepIndex}${l} failed: one or more branches failed`)}this.mergeParallelResults(o)}async executeFailStep(e,t){let o=new Error(e.fail.message);throw o.stack=void 0,o}};var mt=require("yaml"),_e=require("zod");var u=require("zod"),ro=u.z.object({file:u.z.string()}),no=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()}),so=u.z.object({status:u.z.object({fact:u.z.string(),is:u.z.enum(["ready","failed","pending"])})}),io=u.z.object({step:u.z.object({success:u.z.boolean()}).optional(),last_step:u.z.enum(["success","failure"]).optional()}),ao=u.z.object({choice:u.z.string()}),lo=u.z.union([ro,ao,no,so,io]),M=u.z.lazy(()=>u.z.union([lo,u.z.object({all:u.z.array(M)}),u.z.object({any:u.z.array(M)}),u.z.object({not:M})])),ut=u.z.lazy(()=>u.z.object({run:u.z.string(),timeout:u.z.number().optional(),retry:u.z.number().optional(),onError:ut.optional()})),pt=u.z.object({run:u.z.string(),when:M.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:ut.optional()}),co=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:M.optional()}),uo=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:M.optional()});function dt(r){if(!r||typeof r!="object")return{found:!1};let e=r;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 o=dt(t);if(o.found)return o}return{found:!1}}var ft=u.z.lazy(()=>u.z.union([pt,u.z.object({parallel:u.z.array(u.z.lazy(()=>ft)),when:M.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:M.optional()})]).superRefine((r,e)=>{let t=dt(r);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)`})})),po=u.z.lazy(()=>u.z.union([pt,co,uo,u.z.object({parallel:u.z.array(ft),when:M.optional()}),u.z.object({fail:u.z.object({message:u.z.string()}),when:M.optional()})])),fo=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))}),mo=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(fo).optional(),steps:u.z.array(po).min(1,"Workflow must have at least one step")});function Le(r){return mo.parse(r)}function ht(r,e){let t=r.path;if(r.code==="custom"){let n=Be(t);return` - ${r.message}${n}`}if(r.message==="Invalid input"){let n=Be(t),s=ho(t,e);return s?` - ${s}${n}`:` - Invalid step type${n}`}let o=Be(t);return` - ${r.message}${o}`}function Be(r){if(r.length===0)return"";let e=[];for(let t=0;t<r.length;t++){let o=r[t],n=r[t+1];o==="steps"&&typeof n=="number"?(e.push(`step ${n+1}`),t++):o==="parallel"&&typeof n=="number"?(e.push(`parallel branch ${n+1}`),t++):typeof o=="string"&&o!=="steps"&&o!=="parallel"&&e.push(o)}return e.length>0?` (${e.join(" \u2192 ")})`:""}function b(r,e,t){let o=t?`
16
18
  Reason: ${t}`:"";throw new Error(`Invalid workflow structure:
17
- - ${e} (step ${r+1})${o}`)}function Qe(r,e,t=!1,o=[]){let s=["run","choose","prompt","parallel","fail"],n=s.find(a=>a in r);if(!n){let a=Object.keys(r).filter(i=>i!=="when");y(e,`Unknown step type. Found keys: [${a.join(", ")}]. Valid types: ${s.join(", ")}`)}if(n==="run"){let a=r.run;if(typeof a!="string"&&y(e,"'run' must be a string command"),a===""&&y(e,"'run' command cannot be empty"),"shell"in r&&r.shell!==void 0){Array.isArray(r.shell)||y(e,"'shell' must be an array");let i=r.shell;i.length===0&&y(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"&&y(e,`'shell[${l}]' must be a string`)}}if(n==="choose"){if(t){let l=o.join(" \u2192 ");throw new Error(`Invalid workflow structure:
19
+ - ${e} (step ${r+1})${o}`)}function gt(r,e,t=!1,o=[]){let n=["run","choose","prompt","parallel","fail"],s=n.find(i=>i in r);if(!s){let i=Object.keys(r).filter(a=>a!=="when");b(e,`Unknown step type. Found keys: [${i.join(", ")}]. Valid types: ${n.join(", ")}`)}if(s==="run"){let i=r.run;if(typeof i!="string"&&b(e,"'run' must be a string command"),i===""&&b(e,"'run' command cannot be empty"),"shell"in r&&r.shell!==void 0){Array.isArray(r.shell)||b(e,"'shell' must be an array");let a=r.shell;a.length===0&&b(e,"'shell' cannot be empty","Shell configuration must have at least one element (program name)");for(let l=0;l<a.length;l++)typeof a[l]!="string"&&b(e,`'shell[${l}]' must be a string`)}}if(s==="choose"){if(t){let l=o.join(" \u2192 ");throw new Error(`Invalid workflow structure:
18
20
  - 'choose' step is not allowed inside 'parallel' block (step ${e+1}, ${l})
19
- Reason: User input prompts cannot run in parallel`)}let a=r.choose;(!a||typeof a!="object")&&y(e,"'choose' must be an object with 'message' and 'options'");let i=a;(!i.message||typeof i.message!="string")&&y(e,"'choose.message' is required and must be a string"),Array.isArray(i.options)||y(e,"'choose.options' is required and must be an array"),i.options.length===0&&y(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")&&y(e,`'choose.options[${l}]' must be an object with 'id' and 'label'`),(!c.id||typeof c.id!="string")&&y(e,`'choose.options[${l}].id' is required and must be a string`),(!c.label||typeof c.label!="string")&&y(e,`'choose.options[${l}].label' is required and must be a string`)}}if(n==="prompt"){if(t){let l=o.join(" \u2192 ");throw new Error(`Invalid workflow structure:
21
+ Reason: User input prompts cannot run in parallel`)}let i=r.choose;(!i||typeof i!="object")&&b(e,"'choose' must be an object with 'message' and 'options'");let a=i;(!a.message||typeof a.message!="string")&&b(e,"'choose.message' is required and must be a string"),Array.isArray(a.options)||b(e,"'choose.options' is required and must be an array"),a.options.length===0&&b(e,"'choose.options' cannot be empty","At least one option is required");for(let l=0;l<a.options.length;l++){let c=a.options[l];(!c||typeof c!="object")&&b(e,`'choose.options[${l}]' must be an object with 'id' and 'label'`),(!c.id||typeof c.id!="string")&&b(e,`'choose.options[${l}].id' is required and must be a string`),(!c.label||typeof c.label!="string")&&b(e,`'choose.options[${l}].label' is required and must be a string`)}}if(s==="prompt"){if(t){let l=o.join(" \u2192 ");throw new Error(`Invalid workflow structure:
20
22
  - 'prompt' step is not allowed inside 'parallel' block (step ${e+1}, ${l})
21
- Reason: User input prompts cannot run in parallel`)}let a=r.prompt;(!a||typeof a!="object")&&y(e,"'prompt' must be an object with 'message' and 'as'");let i=a;(!i.message||typeof i.message!="string")&&y(e,"'prompt.message' is required and must be a string"),(!i.as||typeof i.as!="string")&&y(e,"'prompt.as' is required and must be a string","The 'as' field specifies the variable name to store the user's input")}if(n==="parallel"){let a=r.parallel;Array.isArray(a)||y(e,"'parallel' must be an array of steps"),a.length===0&&y(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")&&y(e,`'parallel[${i}]' must be a valid step object`);let c=[...o,`branch ${i+1}`];Qe(l,e,!0,c)}}if(n==="fail"){let a=r.fail;(!a||typeof a!="object")&&y(e,"'fail' must be an object with 'message'");let i=a;(!i.message||typeof i.message!="string")&&y(e,"'fail.message' is required and must be a string")}}function et(r){if(!r||typeof r!="object")throw new Error(`Invalid workflow structure:
23
+ Reason: User input prompts cannot run in parallel`)}let i=r.prompt;(!i||typeof i!="object")&&b(e,"'prompt' must be an object with 'message' and 'as'");let a=i;(!a.message||typeof a.message!="string")&&b(e,"'prompt.message' is required and must be a string"),(!a.as||typeof a.as!="string")&&b(e,"'prompt.as' is required and must be a string","The 'as' field specifies the variable name to store the user's input")}if(s==="parallel"){let i=r.parallel;Array.isArray(i)||b(e,"'parallel' must be an array of steps"),i.length===0&&b(e,"'parallel' cannot be empty","At least one step is required");for(let a=0;a<i.length;a++){let l=i[a];(!l||typeof l!="object")&&b(e,`'parallel[${a}]' must be a valid step object`);let c=[...o,`branch ${a+1}`];gt(l,e,!0,c)}}if(s==="fail"){let i=r.fail;(!i||typeof i!="object")&&b(e,"'fail' must be an object with 'message'");let a=i;(!a.message||typeof a.message!="string")&&b(e,"'fail.message' is required and must be a string")}}function wt(r){if(!r||typeof r!="object")throw new Error(`Invalid workflow structure:
22
24
  - Workflow must be an object`);let e=r;if("name"in e&&e.name!==void 0&&typeof e.name!="string")throw new Error(`Invalid workflow structure:
23
25
  - '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
26
  - 'shell' must be an array`);if(e.shell.length===0)throw new Error(`Invalid workflow structure:
@@ -29,46 +31,53 @@ Total execution time: ${a}`)),await o.save(),o.reset()}isStepSuccessful(e,t){ret
29
31
  - 'steps' must be an array`);if(e.steps.length===0)throw new Error(`Invalid workflow structure:
30
32
  - 'steps' cannot be empty
31
33
  Reason: Workflow must have at least one step`);for(let t=0;t<e.steps.length;t++){let o=e.steps[t];if(!o||typeof o!="object")throw new Error(`Invalid workflow structure:
32
- - Step ${t+1} must be an object`);Qe(o,t)}}function Zt(r,e){try{let t=e;for(let n of r)if(typeof n!="symbol")if(t&&typeof t=="object")t=t[n];else return null;if(!t||typeof t!="object")return null;let s=Object.keys(t);if(s.length>0){let n=["run","choose","prompt","parallel","fail"];if(!s.some(i=>n.includes(i)))return`Unknown step type. Found keys: [${s.join(", ")}]. Valid types: run, choose, prompt, parallel, fail`}return null}catch{return null}}function De(r){let e=r;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=>De(t))}:r}var fe=class{parse(e){let t;try{t=(0,Xe.parse)(e)}catch(o){throw new Error(`Invalid YAML format: ${o instanceof Error?o.message:String(o)}`)}if(t&&typeof t=="object"&&"steps"in t){let o=t;Array.isArray(o.steps)&&(o.steps=o.steps.map(s=>De(s)))}et(t);try{return Re(t)}catch(o){if(o instanceof Ce.ZodError){let s=o.issues.map(n=>Ke(n,t)).filter(n=>n!==null).join(`
34
+ - Step ${t+1} must be an object`);gt(o,t)}}function ho(r,e){try{let t=e;for(let s of r)if(typeof s!="symbol")if(t&&typeof t=="object")t=t[s];else return null;if(!t||typeof t!="object")return null;let n=Object.keys(t);if(n.length>0){let s=["run","choose","prompt","parallel","fail"];if(!n.some(a=>s.includes(a)))return`Unknown step type. Found keys: [${n.join(", ")}]. Valid types: run, choose, prompt, parallel, fail`}return null}catch{return null}}function Ve(r){let e=r;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=>Ve(t))}:r}var Se=class{parse(e){let t;try{t=(0,mt.parse)(e)}catch(o){throw new Error(`Invalid YAML format: ${o instanceof Error?o.message:String(o)}`)}if(t&&typeof t=="object"&&"steps"in t){let o=t;Array.isArray(o.steps)&&(o.steps=o.steps.map(n=>Ve(n)))}wt(t);try{return Le(t)}catch(o){if(o instanceof _e.ZodError){let n=o.issues.map(s=>ht(s,t)).filter(s=>s!==null).join(`
33
35
  `);throw new Error(`Invalid workflow structure:
34
- ${s}`)}throw o}}extractStepLineNumbers(e){let t=new Map,o=e.split(`
35
- `),s=0,n=!1;for(let a=0;a<o.length;a++){let i=o[a].trim();if(i==="steps:"||i.startsWith("steps:")){n=!0;continue}n&&i.startsWith("-")&&t.set(s++,a+1)}return t}},Ee=class{parse(e){let t;try{t=JSON.parse(e)}catch(o){throw new Error(`Invalid JSON format: ${o instanceof Error?o.message:String(o)}`)}if(t&&typeof t=="object"&&"steps"in t){let o=t;Array.isArray(o.steps)&&(o.steps=o.steps.map(s=>De(s)))}et(t);try{return Re(t)}catch(o){if(o instanceof Ce.ZodError){let s=o.issues.map(n=>Ke(n,t)).filter(n=>n!==null).join(`
36
+ ${n}`)}throw o}}extractStepLineNumbers(e){let t=new Map,o=e.split(`
37
+ `),n=0,s=!1;for(let i=0;i<o.length;i++){let a=o[i].trim();if(a==="steps:"||a.startsWith("steps:")){s=!0;continue}s&&a.startsWith("-")&&t.set(n++,i+1)}return t}},We=class{parse(e){let t;try{t=JSON.parse(e)}catch(o){throw new Error(`Invalid JSON format: ${o instanceof Error?o.message:String(o)}`)}if(t&&typeof t=="object"&&"steps"in t){let o=t;Array.isArray(o.steps)&&(o.steps=o.steps.map(n=>Ve(n)))}wt(t);try{return Le(t)}catch(o){if(o instanceof _e.ZodError){let n=o.issues.map(s=>ht(s,t)).filter(s=>s!==null).join(`
36
38
  `);throw new Error(`Invalid workflow structure:
37
- ${s}`)}throw o}}extractStepLineNumbers(e){let t=new Map,o=e.split(`
38
- `),s=0,n=!1,a=!1;for(let i=0;i<o.length;i++){let c=o[i].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){n=!0,c.includes("[")&&(a=!0);continue}if(n&&c==="["){a=!0;continue}if(a&&c==="]"){a=!1,n=!1;continue}a&&c.startsWith("{")&&t.set(s++,i+1)}return t}};function oe(r){switch(r.toLowerCase().split(".").pop()){case"yaml":case"yml":return new fe;case"json":return new Ee;default:return new fe}}var gt=require("child_process"),we=require("fs"),T=require("path"),ye=b(require("boxen"),1),h=b(require("chalk"),1),wt=require("commander"),K=b(require("dayjs"),1),_=b(require("inquirer"),1),se=b(require("log-update"),1),yt=b(require("node-cron"),1);ge();var st=require("fs/promises"),it=require("path"),at=require("yaml"),lt=require("zod");var I=require("zod"),Kt=I.z.object({name:I.z.string().min(1,"Schedule name must be non-empty"),cron:I.z.string().min(1,"Cron expression is required"),workflow:I.z.string().min(1,"Workflow path is required"),baseDir:I.z.string().optional(),silent:I.z.boolean().optional(),profile:I.z.string().optional()}),Qt=I.z.object({schedules:I.z.array(Kt).min(1,"Schedule file must have at least one schedule")});function nt(r){return Qt.parse(r)}async function ct(r){let e=await(0,st.readFile)(r,"utf-8"),t=(0,it.extname)(r).toLowerCase(),o;try{if(t===".yaml"||t===".yml")o=(0,at.parse)(e);else if(t===".json")o=JSON.parse(e);else throw new Error(`Unsupported file format: ${t}. Use .yaml, .yml, or .json`)}catch(s){if(s instanceof Error&&s.message.startsWith("Unsupported"))throw s;let n=t===".json"?"JSON":"YAML";throw new Error(`Invalid ${n} format: ${s instanceof Error?s.message:String(s)}`)}try{return nt(o)}catch(s){if(s instanceof lt.ZodError){let n=s.issues.map(a=>` - ${a.message} (${a.path.join(".")})`).join(`
39
- `);throw new Error(`Invalid schedule file structure:
40
- ${n}`)}throw s}}var G=require("fs/promises"),pt=require("os"),Ie=require("path"),dt=(0,Ie.join)((0,pt.homedir)(),".pipeliner","schedules"),ut=(0,Ie.join)(dt,"schedules.json"),C=class{async loadSchedules(){try{let e=await(0,G.readFile)(ut,"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,G.mkdir)(dt,{recursive:!0}),await(0,G.writeFile)(ut,JSON.stringify({schedules:e},null,2),"utf-8")}async addSchedule(e){let t=await this.loadSchedules(),o=Math.random().toString(36).slice(2,10),s=new Date().toISOString(),n={id:o,createdAt:s,...e};return t.push(n),await this.saveSchedules(t),n}async removeSchedule(e){let t=await this.loadSchedules(),o=t.length,s=t.filter(n=>n.id!==e);return s.length===o?!1:(await this.saveSchedules(s),!0)}async updateLastRun(e){let t=await this.loadSchedules(),o=t.find(s=>s.id===e);o&&(o.lastRun=new Date().toISOString(),await this.saveSchedules(t))}async toggleSchedule(e,t){let o=await this.loadSchedules(),s=o.find(n=>n.id===e);return s?(s.enabled=t,await this.saveSchedules(o),!0):!1}async getSchedule(e){return(await this.loadSchedules()).find(o=>o.id===e)}};var ft=require("fs/promises"),mt=require("path"),je=b(require("node-cron"),1);ge();var X=class{scheduleManager;tasks=new Map;constructor(){this.scheduleManager=new C}async start(e=!1){if(await W()){let o=await P();throw new Error(`Scheduler daemon is already running (PID: ${o.pid}). Use "tp schedule stop" to stop it first.`)}console.log(e?"\u{1F680} Starting scheduler daemon in background...":"\u{1F680} Starting workflow scheduler..."),await this.reload(),e?process.env.TP_DAEMON_MODE||(console.log(`\u2713 Scheduler daemon started (PID: ${process.pid})`),console.log(' Run "tp schedule stop" to stop the daemon'),console.log(' Run "tp schedule status" to check daemon status')):(console.log("\u2713 Scheduler is running"),console.log(" Press Ctrl+C to stop"));let t=async()=>{e||console.log(`
41
- \u23F9 Stopping scheduler...`),this.stop(),await ne(),e||process.exit(0)};process.on("SIGINT",t),process.on("SIGTERM",t),e&&process.stdin.destroy()}async reload(){this.stop();let t=(await this.scheduleManager.loadSchedules()).filter(o=>o.enabled);if(t.length===0){console.log(" No active schedules found");return}console.log(` Loading ${t.length} schedule(s)...`);for(let o of t)try{this.startSchedule(o)}catch(s){console.error(` \u2717 Failed to start schedule ${o.id}:`,s)}}startSchedule(e){if(!je.default.validate(e.cron)){console.error(` \u2717 Invalid cron expression for schedule ${e.id}: ${e.cron}`);return}let t=je.default.schedule(e.cron,async()=>{await this.executeSchedule(e)});this.tasks.set(e.id,t);let o=e.name??e.workflowPath;console.log(` \u2713 Scheduled: ${o}`),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 o=(0,mt.resolve)(e.workflowPath),s=oe(o),n=await(0,ft.readFile)(o,"utf-8"),a=s.parse(n),i=new q,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(f=>f.name===e.profile);if(!c)throw new Error(`Profile "${e.profile}" not found. Available profiles: ${a.profiles.map(f=>f.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}
39
+ ${n}`)}throw o}}extractStepLineNumbers(e){let t=new Map,o=e.split(`
40
+ `),n=0,s=!1,i=!1;for(let a=0;a<o.length;a++){let c=o[a].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){s=!0,c.includes("[")&&(i=!0);continue}if(s&&c==="["){i=!0;continue}if(i&&c==="]"){i=!1,s=!1;continue}i&&c.startsWith("{")&&t.set(n++,a+1)}return t}};function le(r){switch(r.toLowerCase().split(".").pop()){case"yaml":case"yml":return new Se;case"json":return new We;default:return new Se}}var vt=require("fs/promises"),kt=require("path"),ke=y(require("boxen"),1),j=y(require("chalk"),1),ze=y(require("node-cron"),1);ie();var oe=require("fs/promises"),bt=require("os"),He=require("path"),St=(0,He.join)((0,bt.homedir)(),".pipeliner","schedules"),yt=(0,He.join)(St,"schedules.json"),T=class{async loadSchedules(){try{let e=await(0,oe.readFile)(yt,"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,oe.mkdir)(St,{recursive:!0}),await(0,oe.writeFile)(yt,JSON.stringify({schedules:e},null,2),"utf-8")}async addSchedule(e){let t=await this.loadSchedules(),o=Math.random().toString(36).slice(2,10),n=new Date().toISOString(),s={id:o,createdAt:n,...e};return t.push(s),await this.saveSchedules(t),s}async removeSchedule(e){let t=await this.loadSchedules(),o=t.length,n=t.filter(s=>s.id!==e);return n.length===o?!1:(await this.saveSchedules(n),!0)}async updateLastRun(e){let t=await this.loadSchedules(),o=t.find(n=>n.id===e);o&&(o.lastRun=new Date().toISOString(),await this.saveSchedules(t))}async toggleSchedule(e,t){let o=await this.loadSchedules(),n=o.find(s=>s.id===e);return n?(n.enabled=t,await this.saveSchedules(o),!0):!1}async getSchedule(e){return(await this.loadSchedules()).find(o=>o.id===e)}};var go=/^([+-])?(\d{1,2})(?::(\d{2}))?$/;function wo(r){let e=r.trim();if(e===""||e==="0"||e==="+0"||e==="-0")return 0;let t=e.match(go);if(!t)return null;let o=t[1],n=parseInt(t[2],10);if(n>14)return null;let i=o==="-"?-n:n;return i<-12||i>14?null:i}function yo(r){if(r===0)return"UTC";let e=r>0?"-":"+",t=Math.abs(r);return`Etc/GMT${e}${t}`}function ve(r){if(!r?.trim())return;let e=wo(r);if(e!==null)return yo(e)}var B=class{scheduleManager;tasks=new Map;startOptions;constructor(){this.scheduleManager=new T}async start(e=!1,t){if(this.startOptions=t,!e&&await A()){let n=await $();throw new Error(`Scheduler daemon is already running (PID: ${n.pid}). Use "tp schedule stop" to stop it first.`)}if(e)console.log("\u{1F680} Starting scheduler daemon in background...");else{let n=j.default.bold("\u{1F680} Starting workflow scheduler...");console.log((0,ke.default)(n,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"cyan"}))}if(await this.reload(),e){if(!process.env.TP_DAEMON_MODE){let n=[j.default.green("\u2713 Scheduler daemon started"),"",j.default.gray(`PID: ${process.pid}`),j.default.dim(" tp schedule stop stop daemon"),j.default.dim(" tp schedule status check status")].join(`
41
+ `);console.log(`${(0,ke.default)(n,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},borderColor:"green"})}
42
+ `)}}else{let n=[j.default.green("\u2713 Scheduler is running"),j.default.dim(" Press Ctrl+C to stop")].join(`
43
+ `);console.log((0,ke.default)(n,{borderStyle:"round",padding:{top:0,bottom:0,left:2,right:2},margin:{top:0,bottom:0,left:0,right:0},borderColor:"green"}))}let o=async()=>{e||console.log(`
44
+ \u23F9 Stopping scheduler...`),this.stop(),await se(),e||process.exit(0)};process.on("SIGINT",o),process.on("SIGTERM",o),e&&process.stdin.destroy()}async reload(){this.stop();let t=(await this.scheduleManager.loadSchedules()).filter(o=>o.enabled);if(t.length===0){console.log(j.default.gray(` No enabled schedules to load.
45
+ `));return}for(let o of t)try{this.startSchedule(o)}catch(n){console.error(j.default.red(` \u2717 Failed to start schedule ${o.id}:`),n)}}startSchedule(e){if(!ze.default.validate(e.cron)){console.error(` \u2717 Invalid cron expression for schedule ${e.id}: ${e.cron}`);return}let t={},o=ve(e.timezone);o&&(t.timezone=o);let n;try{n=ze.default.schedule(e.cron,async()=>{await this.executeSchedule(e)},t)}catch(s){throw console.error(` \u2717 Cron schedule failed for ${e.id} (timezone: ${o??"local"}).`,s instanceof Error?s.message:s),s}this.tasks.set(e.id,n),this.startOptions?.onScheduleStarted?.(e)}async executeSchedule(e){let t=e.name??e.workflowPath;e.silent||(console.log(`
46
+ \u23F0 Running scheduled workflow: ${t}`),console.log(` Time: ${new Date().toISOString()}`),e.profile&&console.log(` Profile: ${e.profile}`));try{let o=(0,kt.resolve)(e.workflowPath),n=le(o),s=await(0,vt.readFile)(o,"utf-8"),i=n.parse(s),a=new te,l={};if(e.profile){if(!i.profiles)throw new Error(`Profile "${e.profile}" not found: no profiles defined in workflow`);let c=i.profiles.find(f=>f.name===e.profile);if(!c)throw new Error(`Profile "${e.profile}" not found. Available profiles: ${i.profiles.map(f=>f.name).join(", ")}`);l.profileVars=c.var}await a.execute(i,l),await this.scheduleManager.updateLastRun(e.id),e.silent||console.log(`\u2713 Scheduled workflow completed: ${t}
43
47
  `)}catch(o){e.silent||(console.error(`\u2717 Scheduled workflow failed: ${t}`),console.error(` Error: ${o instanceof Error?o.message:String(o)}
44
- `))}}stop(){for(let e of this.tasks.values())e.stop();this.tasks.clear()}async stopDaemon(){let e=await P();if(!e.running||!e.pid)return!1;let t=e.pid;try{if(process.kill(t,"SIGTERM"),await new Promise(o=>setTimeout(o,1e3)),await W()){try{process.kill(t,"SIGKILL")}catch{}await new Promise(o=>setTimeout(o,500))}return await ne(),!0}catch{return await ne(),!1}}};function bt(){let r=new wt.Command("schedule").description("Manage workflow schedules").action(async()=>{await ht()});return r.command("add [scheduleFile]").description("Add schedules from a schedule file (YAML or JSON)").action(async e=>{await eo(e)}),r.command("remove").alias("rm").description("Remove a workflow schedule").action(async()=>{await to()}),r.command("remove-all").description("Remove all workflow schedules").action(async()=>{await lo()}),r.command("list").alias("ls").description("List all workflow schedules").action(async()=>{await ht()}),r.command("start").description("Start the scheduler daemon").option("-d, --daemon","Run in background daemon mode").action(async e=>{await oo(e.daemon??!1)}),r.command("stop").description("Stop the scheduler daemon").action(async()=>{await ro()}),r.command("status").description("Check scheduler daemon status (real-time mode, press Ctrl+C to exit)").action(async()=>{await io(!0)}),r.command("toggle").description("Enable or disable a schedule").action(async()=>{await ao()}),r}function Te(r,e){let t=e.workflow;if((0,T.isAbsolute)(t))return t;let o=e.baseDir?(0,T.resolve)(e.baseDir):(0,T.dirname)(r);return(0,T.resolve)(o,t)}async function eo(r){let e=new C;if(!r){let{path:i}=await _.default.prompt([{type:"input",name:"path",message:"Schedule file path (YAML or JSON):",validate:l=>{let c=(0,T.resolve)(l);return(0,we.existsSync)(c)?!0:`File not found: ${c}`}}]);r=i}let t=(0,T.resolve)(r);(0,we.existsSync)(t)||(console.error(`\u2717 File not found: ${t}`),process.exit(1));let o;try{o=await ct(t)}catch(i){console.error(`\u2717 Failed to parse schedule file: ${i instanceof Error?i.message:String(i)}`),process.exit(1)}let s=o.schedules.filter(i=>!yt.default.validate(i.cron));if(s.length>0){console.error("\u2717 Invalid cron expression(s):");for(let i of s)console.error(` - ${i.name}: "${i.cron}"`);process.exit(1)}let n=o.schedules.filter(i=>{let l=Te(t,i);return!(0,we.existsSync)(l)});if(n.length>0){console.error("\u2717 Workflow file(s) not found:");for(let i of n){let l=Te(t,i);console.error(` - ${i.name}: ${i.workflow} (resolved: ${l})`)}process.exit(1)}console.log(`
48
+ `))}}stop(){for(let e of this.tasks.values())e.stop();this.tasks.clear()}async stopDaemon(){let e=await $();if(!e.running||!e.pid)return!1;let t=e.pid;try{if(process.kill(t,"SIGTERM"),await new Promise(o=>setTimeout(o,1e3)),await A()){try{process.kill(t,"SIGKILL")}catch{}await new Promise(o=>setTimeout(o,500))}return await se(),!0}catch{return await se(),!1}}};var jt=require("child_process"),$e=require("fs"),O=require("path"),Re=y(require("boxen"),1),h=y(require("chalk"),1),Nt=require("commander"),Ee=y(require("dayjs"),1),Y=y(require("inquirer"),1),ce=y(require("log-update"),1),At=y(require("node-cron"),1);ie();var $t=require("fs/promises"),Rt=require("path"),Et=require("yaml"),Pt=require("zod");var P=require("zod"),bo=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(),timezone:P.z.union([P.z.string(),P.z.number()]).transform(String).optional(),silent:P.z.boolean().optional(),profile:P.z.string().optional()}),So=P.z.object({schedules:P.z.array(bo).min(1,"Schedule file must have at least one schedule")});function xt(r){return So.parse(r)}async function Ct(r){let e=await(0,$t.readFile)(r,"utf-8"),t=(0,Rt.extname)(r).toLowerCase(),o;try{if(t===".yaml"||t===".yml")o=(0,Et.parse)(e);else if(t===".json")o=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 s=t===".json"?"JSON":"YAML";throw new Error(`Invalid ${s} format: ${n instanceof Error?n.message:String(n)}`)}try{return xt(o)}catch(n){if(n instanceof Pt.ZodError){let s=n.issues.map(i=>` - ${i.message} (${i.path.join(".")})`).join(`
49
+ `);throw new Error(`Invalid schedule file structure:
50
+ ${s}`)}throw n}}var Dt=y(require("boxen"),1),S=y(require("chalk"),1),Tt=y(require("cronstrue"),1),Ye=y(require("dayjs"),1),Ue=y(require("node-cron"),1);function Je(r){try{return Tt.default.toString(r)}catch{return null}}function vo(r){if(!Ue.default.validate(r.cron))return null;try{let e={},t=ve(r.timezone);t&&(e.timezone=t);let o=Ue.default.createTask(r.cron,()=>{},e),n=o.getNextRun();return o.destroy(),n}catch{return null}}function xe(r,e){let t=r,{daemonRunning:o}=e,n=t.enabled?S.default.green("enabled"):S.default.gray("disabled"),s=o&&t.enabled,i=s?S.default.green("\u25CF active"):S.default.gray("\u25CB inactive"),a=S.default.bold(t.name??t.workflowPath),l=vo(t),c=l?(0,Ye.default)(l).format("YYYY-MM-DD HH:mm:ss"):S.default.dim("\u2014"),f=t.lastRun?(0,Ye.default)(t.lastRun).format("YYYY-MM-DD HH:mm:ss"):S.default.dim("never"),g=Je(t.cron),m=t.timezone?t.timezone.startsWith("+")||t.timezone.startsWith("-")?`UTC${t.timezone}`:`UTC+${t.timezone}`:null,d=[[S.default.gray("Enabled"),n],[S.default.gray("Cron"),t.cron],...g?[[S.default.gray(""),S.default.dim(`\u2192 ${g}`)]]:[],...m?[[S.default.gray("Timezone"),m]]:[],[S.default.gray("Workflow"),t.workflowPath],...t.profile?[[S.default.gray("Profile"),S.default.cyan(t.profile)]]:[],...t.silent?[[S.default.gray("Silent"),S.default.yellow("yes")]]:[],[S.default.gray("Last run"),f],[S.default.gray("Next run"),c]],w=[`${a} ${i}`,...d.map(([k,R])=>` ${k.padEnd(10)} ${R}`)].join(`
51
+ `);return(0,Dt.default)(w,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:s?"green":"gray"})}function Ot(){let r=new Nt.Command("schedule").description("Manage workflow schedules").action(async()=>{await It()});return r.command("add [scheduleFile]").description("Add schedules from a schedule file (YAML or JSON)").action(async e=>{await ko(e)}),r.command("remove").alias("rm").description("Remove a workflow schedule").action(async()=>{await xo()}),r.command("remove-all").description("Remove all workflow schedules").action(async()=>{await To()}),r.command("list").alias("ls").description("List all workflow schedules").action(async()=>{await It()}),r.command("start").description("Start the scheduler daemon").option("-d, --daemon","Run in background daemon mode").action(async e=>{await $o(e.daemon??!1)}),r.command("stop").description("Stop the scheduler daemon").action(async()=>{await Ro()}),r.command("status").description('View daemon and schedule status (does not start the daemon). In live mode, Ctrl+C only exits the status view; the daemon keeps running if it was started with "tp schedule start -d".').option("-n, --no-follow","Show status once and exit (no live refresh)").action(async e=>{let t=e.follow!==!1;await Co(t)}),r.command("toggle").description("Enable or disable a schedule").action(async()=>{await Do()}),r}function qe(r,e){let t=e.workflow;if((0,O.isAbsolute)(t))return t;let o=e.baseDir?(0,O.resolve)(e.baseDir):(0,O.dirname)(r);return(0,O.resolve)(o,t)}async function ko(r){let e=new T;if(!r){let{path:a}=await Y.default.prompt([{type:"input",name:"path",message:"Schedule file path (YAML or JSON):",validate:l=>{let c=(0,O.resolve)(l);return(0,$e.existsSync)(c)?!0:`File not found: ${c}`}}]);r=a}let t=(0,O.resolve)(r);(0,$e.existsSync)(t)||(console.error(`\u2717 File not found: ${t}`),process.exit(1));let o;try{o=await Ct(t)}catch(a){console.error(`\u2717 Failed to parse schedule file: ${a instanceof Error?a.message:String(a)}`),process.exit(1)}let n=o.schedules.filter(a=>!At.default.validate(a.cron));if(n.length>0){console.error("\u2717 Invalid cron expression(s):");for(let a of n)console.error(` - ${a.name}: "${a.cron}"`);process.exit(1)}let s=o.schedules.filter(a=>{let l=qe(t,a);return!(0,$e.existsSync)(l)});if(s.length>0){console.error("\u2717 Workflow file(s) not found:");for(let a of s){let l=qe(t,a);console.error(` - ${a.name}: ${a.workflow} (resolved: ${l})`)}process.exit(1)}console.log(`
45
52
  Found ${o.schedules.length} schedule(s) in file.
46
- `);let a=[];for(let i of o.schedules){let{alias:l}=await _.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:Te(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 to(){let r=new C,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await _.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to remove:",choices:e.map(n=>({name:`${n.name??n.workflowPath} (${n.cron}) ${n.enabled?"\u2713":"\u2717"}`,value:n.id}))}]),{confirm:o}=await _.default.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to remove this schedule?",default:!1}]);if(!o){console.log("Cancelled");return}let s=await r.removeSchedule(t);console.log(s?"\u2713 Schedule removed successfully":"\u2717 Schedule not found")}async function ht(){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 o=t.enabled?"\u2713 Enabled":"\u2717 Disabled",s=t.name??t.workflowPath,n=t.lastRun?(0,K.default)(t.lastRun).format("YYYY-MM-DD HH:mm:ss"):"Never";console.log(` ${o} ${s}`),console.log(` ID: ${t.id}`),console.log(` Cron: ${t.cron}`),console.log(` Workflow: ${t.workflowPath}`),console.log(` Last run: ${n}`),console.log()}}async function oo(r){if(await W()){let e=await P();console.error(`\u2717 Scheduler daemon is already running (PID: ${e.pid})`),console.error(' Run "tp schedule stop" to stop it first'),process.exit(1)}if(r)if(process.env.TP_DAEMON_MODE==="true"){let{saveDaemonPid:e}=await Promise.resolve().then(()=>(ge(),rt));await e(),await new X().start(!0),await new Promise(()=>{})}else{let e=process.argv.slice(1);if((0,gt.spawn)(process.argv[0],e,{detached:!0,stdio:"ignore",env:{...process.env,TP_DAEMON_MODE:"true"}}).unref(),await new Promise(o=>setTimeout(o,1e3)),await W()){let o=await P();console.log(`\u2713 Scheduler daemon started in background (PID: ${o.pid})`),console.log(' Run "tp schedule stop" to stop the daemon'),console.log(' Run "tp schedule status" to check daemon status')}else console.error("\u2717 Failed to start scheduler daemon"),process.exit(1);process.exit(0)}else await new X().start(!1),await new Promise(()=>{})}async function ro(){let r=await P();if(!r.running){console.log("Scheduler daemon is not running");return}console.log(`Stopping scheduler daemon (PID: ${r.pid})...`);let t=await new X().stopDaemon();console.log(t?"\u2713 Scheduler daemon stopped":"\u2717 Failed to stop scheduler daemon (process may have already exited)")}function no(r){if(!r)return"Unknown";let e=(0,K.default)(r),o=(0,K.default)().diff(e,"second"),s=Math.floor(o/86400),n=Math.floor(o%86400/3600),a=Math.floor(o%3600/60),i=o%60,l=[];return s>0&&l.push(`${s}d`),n>0&&l.push(`${n}h`),a>0&&l.push(`${a}m`),(i>0||l.length===0)&&l.push(`${i}s`),l.join(" ")}function so(r){let e=r.name??r.workflowPath,t=r.enabled?h.default.green("\u25CF active"):h.default.gray("\u25CB inactive"),o=r.lastRun?(0,K.default)(r.lastRun).format("YYYY-MM-DD HH:mm:ss"):h.default.gray("never"),s=r.profile?h.default.cyan(` [profile: ${r.profile}]`):"",n=r.silent?h.default.gray(" [silent]"):"",a=[`${t} ${h.default.bold(e)}${s}${n}`,`${h.default.gray("Cron:")} ${r.cron}`,`${h.default.gray("Last run:")} ${o}`].join(`
52
- `);return(0,ye.default)(a,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:1,left:0,right:0},borderColor:r.enabled?"green":"gray"})}async function Ne(){let r=await P(),t=await new C().loadSchedules(),o=[],s;if(r.running&&r.pid){let a=no(r.startTime),i=r.startTime?(0,K.default)(r.startTime).format("YYYY-MM-DD HH:mm:ss"):"Unknown";s=[`${h.default.green("\u25CF")} ${h.default.green("active")} ${h.default.gray("(running)")}`,"",`${h.default.gray("Loaded:")} ${h.default.white(i)}`,`${h.default.gray("Active:")} ${h.default.green("active (running)")} since ${h.default.white(i)}`,`${h.default.gray("PID:")} ${h.default.white(r.pid.toString())}`,`${h.default.gray("Uptime:")} ${h.default.white(a)}`].join(`
53
- `)}else s=[`${h.default.red("\u25CF")} ${h.default.red("inactive")} ${h.default.gray("(dead)")}`,"",`${h.default.gray("Loaded:")} ${h.default.gray("not found")}`,`${h.default.gray("Active:")} ${h.default.red("inactive (dead)")}`].join(`
54
- `);let n=(0,ye.default)(s,{title:h.default.bold("task-pipeliner-scheduler.service"),titleAlignment:"left",borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:r.running?"green":"red"});if(o.push(n),t.length>0){let a=t.filter(l=>l.enabled).length,i=h.default.bold(`Schedules: ${a}/${t.length} active`);o.push(i),o.push("");for(let l of t)o.push(so(l))}else{let a=(0,ye.default)(h.default.gray("No schedules configured"),{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"gray"});o.push(a)}return o.join(`
55
- `)}async function io(r){if(r){let e=!0,t=()=>{e=!1,se.default.done(),process.exit(0)};process.on("SIGINT",t),process.on("SIGTERM",t);let o=setInterval(async()=>{if(!e){clearInterval(o);return}try{let i=await Ne(),c=(await P()).running?h.default.gray(`
56
- Press Ctrl+C to exit (daemon will continue running)`):h.default.gray(`
57
- Run "tp schedule start -d" to start the daemon`);(0,se.default)(`${i}${c}`)}catch(i){se.default.done(),console.error("Error updating status:",i),clearInterval(o),process.exit(1)}},1e3),s=await Ne(),a=(await P()).running?h.default.gray(`
58
- Press Ctrl+C to exit (daemon will continue running)`):h.default.gray(`
59
- Run "tp schedule start -d" to start the daemon`);(0,se.default)(`${s}${a}`),await new Promise(()=>{})}else{let e=await Ne(),o=(await P()).running?"":h.default.gray(`
60
- Run "tp schedule start -d" to start the daemon`);console.log(`
61
- ${e}${o}
62
- `)}}async function ao(){let r=new C,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await _.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to toggle:",choices:e.map(n=>({name:`${n.name??n.workflowPath} (${n.cron}) ${n.enabled?"\u2713":"\u2717"}`,value:n.id}))}]),o=e.find(n=>n.id===t);if(!o){console.log("\u2717 Schedule not found");return}let s=!o.enabled;await r.toggleSchedule(t,s),console.log(`\u2713 Schedule ${s?"enabled":"disabled"}: ${o.name??o.workflowPath}`)}async function lo(){let r=new C,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{confirm:t}=await _.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 r.saveSchedules([]),console.log(`\u2713 Removed all ${e.length} schedule(s)`)}var N=require("fs"),x=require("path"),Ae=require("url"),St={};function vt(){console.log=()=>{},console.error=()=>{},console.warn=()=>{},console.info=()=>{},process.stdout.write=()=>!0,process.stderr.write=()=>!0}function kt(){return"0.2.18"}function xt(r){let e=r?(0,x.resolve)(r):process.cwd(),t=50,o=0;for(;o<t;){let s=(0,x.resolve)(e,"tp");try{if((0,N.existsSync)(s)&&(0,N.statSync)(s).isDirectory())return s}catch{}let n=(0,x.dirname)(e);if(n===e)break;e=n,o++}return null}var co=(0,Pt.promisify)($t.exec),ee=new Et.Command;ee.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
53
+ `);let i=[];for(let a of o.schedules){let{alias:l}=await Y.default.prompt([{type:"input",name:"alias",message:`Alias for "${a.name}" (press Enter to use as-is):`,default:a.name}]),c=await e.addSchedule({name:l,workflowPath:qe(t,a),cron:a.cron,enabled:!0,timezone:a.timezone,silent:a.silent,profile:a.profile});i.push(c)}console.log(`
54
+ \u2713 Added ${i.length} schedule(s) successfully
55
+ `);for(let a of i){let l=Je(a.cron);console.log(` - ${a.name??"N/A"}`),console.log(` Cron: ${a.cron}`),l&&console.log(` ${h.default.dim(`\u2192 ${l}`)}`),a.timezone&&console.log(` Timezone: ${a.timezone}`),console.log(` Workflow: ${a.workflowPath}`),a.silent&&console.log(" Silent: Yes"),a.profile&&console.log(` Profile: ${a.profile}`),console.log(` Status: ${a.enabled?"Enabled":"Disabled"}`),console.log()}console.log('Run "tp schedule start" to start the scheduler daemon')}async function xo(){let r=new T,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await Y.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to remove:",choices:e.map(s=>({name:`${s.name??s.workflowPath} (${s.cron}) ${s.enabled?"\u2713":"\u2717"}`,value:s.id}))}]),{confirm:o}=await Y.default.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to remove this schedule?",default:!1}]);if(!o){console.log("Cancelled");return}let n=await r.removeSchedule(t);console.log(n?"\u2713 Schedule removed successfully":"\u2717 Schedule not found")}async function It(){let e=await new T().loadSchedules();if(e.length===0){let i=[h.default.gray("No schedules registered."),"",h.default.dim(" tp schedule add <schedule.yaml> add from a schedule file")].join(`
56
+ `);console.log(`
57
+ ${(0,Re.default)(i,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0,left:0,right:0},borderColor:"gray"})}
58
+ `);return}let t=await $(),o=t.running?h.default.green("\u25CF running"):h.default.gray("\u25CB stopped"),n=e.filter(i=>i.enabled).length,s=h.default.bold("\u{1F4C5} Workflow Schedules");console.log(s),console.log([h.default.gray(" Daemon: "),o,h.default.gray(` \xB7 Schedules: ${n}/${e.length} enabled`)].join(""));for(let i of e)console.log(xe(i,{daemonRunning:t.running}));console.log(h.default.dim(" Tip: tp schedule start \u2014 run scheduler daemon; tp schedule status \u2014 view live status"))}async function $o(r){if(await A()){let e=await $();console.error(`\u2717 Scheduler daemon is already running (PID: ${e.pid})`),console.error(' Run "tp schedule stop" to stop it first'),process.exit(1)}if(r)if(process.env.TP_DAEMON_MODE==="true")try{let{saveDaemonPid:e}=await Promise.resolve().then(()=>(ie(),et));await e(),await new B().start(!0),await new Promise(()=>{})}catch(e){await Ie(e instanceof Error?e:new Error(String(e))),process.exit(1)}else{let e=process.argv.slice(1);(0,jt.spawn)(process.argv[0],e,{detached:!0,stdio:"ignore",env:{...process.env,TP_DAEMON_MODE:"true"}}).unref();let o=3,n=800,s=!1;for(let i=0;i<o;i++)if(await new Promise(a=>setTimeout(a,n)),await A()){s=!0;break}if(s){let i=await $();console.log(`\u2713 Scheduler daemon started in background (PID: ${i.pid})`),console.log(' Run "tp schedule stop" to stop the daemon'),console.log(' Run "tp schedule status" to check daemon status')}else{console.error("\u2717 Failed to start scheduler daemon");let i=await je();i?(console.error(h.default.dim(" Last error from daemon:")),console.error(h.default.red(i.split(`
59
+ `).map(a=>` ${a}`).join(`
60
+ `)))):console.error(h.default.dim(` Check ${Me()} for details`)),process.exit(1)}process.exit(0)}else await new B().start(!1,{onScheduleStarted:t=>console.log(xe(t,{daemonRunning:!0}))}),await new Promise(()=>{})}async function Ro(){let r=await $();if(!r.running){console.log("Scheduler daemon is not running");return}console.log(`Stopping scheduler daemon (PID: ${r.pid})...`);let t=await new B().stopDaemon();console.log(t?"\u2713 Scheduler daemon stopped":"\u2717 Failed to stop scheduler daemon (process may have already exited)")}function Eo(r){if(!r)return"Unknown";let e=(0,Ee.default)(r),o=(0,Ee.default)().diff(e,"second"),n=Math.floor(o/86400),s=Math.floor(o%86400/3600),i=Math.floor(o%3600/60),a=o%60,l=[];return n>0&&l.push(`${n}d`),s>0&&l.push(`${s}h`),i>0&&l.push(`${i}m`),(a>0||l.length===0)&&l.push(`${a}s`),l.join(" ")}function Po(r,e){return xe(r,{daemonRunning:e})}async function Ge(){let r=await $(),t=await new T().loadSchedules(),o=[],n;if(r.running&&r.pid){let i=Eo(r.startTime),a=r.startTime?(0,Ee.default)(r.startTime).format("YYYY-MM-DD HH:mm:ss"):"Unknown";n=[`${h.default.green("\u25CF")} ${h.default.green("active")} ${h.default.gray("(running)")}`,"",`${h.default.gray("Loaded:")} ${h.default.white(a)}`,`${h.default.gray("Active:")} ${h.default.green("active (running)")} since ${h.default.white(a)}`,`${h.default.gray("PID:")} ${h.default.white(r.pid.toString())}`,`${h.default.gray("Uptime:")} ${h.default.white(i)}`].join(`
61
+ `)}else n=[`${h.default.red("\u25CF")} ${h.default.red("inactive")} ${h.default.gray("(dead)")}`,"",`${h.default.gray("Loaded:")} ${h.default.gray("not found")}`,`${h.default.gray("Active:")} ${h.default.red("inactive (dead)")}`].join(`
62
+ `);let s=(0,Re.default)(n,{title:h.default.bold("task-pipeliner-scheduler.service"),titleAlignment:"left",borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0,left:0,right:0},borderColor:r.running?"green":"red"});if(o.push(s),t.length>0){let i=t.filter(l=>l.enabled).length,a=h.default.bold(`Schedules: ${i}/${t.length} enabled`);o.push(a);for(let l of t)o.push(Po(l,r.running))}else{let i=(0,Re.default)(h.default.gray("No schedules configured"),{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0,left:0,right:0},borderColor:"gray"});o.push(i)}return o.join(`
63
+ `)}function Mt(){process.stdout.write("\x1B[2J\x1B[H")}async function Co(r){if(r){let e=!0,t=()=>{e=!1,ce.default.done(),process.exit(0)};process.on("SIGINT",t),process.on("SIGTERM",t);let o=setInterval(async()=>{if(!e){clearInterval(o);return}try{let a=await Ge(),c=(await $()).running?h.default.gray(`
64
+ Press Ctrl+C to exit this view (daemon keeps running in background)`):h.default.gray(`
65
+ Tip: To start the daemon, run: tp schedule start -d. Press Ctrl+C to exit this view.`);(0,ce.default)(`${a}${c}`)}catch(a){ce.default.done(),console.error("Error updating status:",a),clearInterval(o),process.exit(1)}},1e3);Mt();let n=await Ge(),i=(await $()).running?h.default.gray(`
66
+ Press Ctrl+C to exit this view (daemon keeps running in background)`):h.default.gray(`
67
+ Tip: To start the daemon, run: tp schedule start -d. Press Ctrl+C to exit this view.`);(0,ce.default)(`${n}${i}`),await new Promise(()=>{})}else{Mt();let e=await Ge(),o=(await $()).running?"":h.default.gray(`
68
+ Tip: To start the daemon, run: tp schedule start -d`);console.log(`${e}${o}
69
+ `)}}async function Do(){let r=new T,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{scheduleId:t}=await Y.default.prompt([{type:"list",name:"scheduleId",message:"Select schedule to toggle:",choices:e.map(s=>({name:`${s.name??s.workflowPath} (${s.cron}) ${s.enabled?"\u2713":"\u2717"}`,value:s.id}))}]),o=e.find(s=>s.id===t);if(!o){console.log("\u2717 Schedule not found");return}let n=!o.enabled;await r.toggleSchedule(t,n),console.log(`\u2713 Schedule ${n?"enabled":"disabled"}: ${o.name??o.workflowPath}`)}async function To(){let r=new T,e=await r.loadSchedules();if(e.length===0){console.log("No schedules found");return}let{confirm:t}=await Y.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 r.saveSchedules([]),console.log(`\u2713 Removed all ${e.length} schedule(s)`)}var F=require("fs"),E=require("path"),Ze=require("url"),Ft={};function Lt(){console.log=()=>{},console.error=()=>{},console.warn=()=>{},console.info=()=>{},process.stdout.write=()=>!0,process.stderr.write=()=>!0}function Bt(){return"0.3.0"}function Wt(r){let e=r?(0,E.resolve)(r):process.cwd(),t=50,o=0;for(;o<t;){let n=(0,E.resolve)(e,"tp");try{if((0,F.existsSync)(n)&&(0,F.statSync)(n).isDirectory())return n}catch{}let s=(0,E.dirname)(e);if(s===e)break;e=s,o++}return null}var ue=(0,U.join)((0,Vt.homedir)(),".pipeliner"),Io=(0,Ht.promisify)(_t.exec),J=new zt.Command;J.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
63
70
 
64
71
  Define workflows in YAML or JSON files with conditional execution, parallel tasks,
65
- interactive prompts, and variable substitution.
72
+ interactive prompts, variable substitution, and cron-based scheduling.
66
73
 
67
74
  Features:
68
75
  \u2022 Condition-based execution (file checks, variable comparisons)
69
76
  \u2022 Parallel task execution
70
77
  \u2022 Interactive prompts and choices
71
78
  \u2022 Variable substitution with {{variables}}
79
+ \u2022 Profiles: run the same workflow with different variable sets (--profile)
80
+ \u2022 Schedule: run workflows on a cron schedule (tp schedule add/list/start/status)
72
81
  \u2022 Beautiful terminal output
73
82
  \u2022 Supports both YAML (.yaml, .yml) and JSON (.json) formats
74
83
 
@@ -97,20 +106,40 @@ Quick Start:
97
106
  tp history remove # Remove a specific history
98
107
  tp history remove-all # Remove all histories
99
108
 
100
- `).version(kt()).addHelpText("after",`
109
+ 4. Schedule workflows (cron):
110
+ tp schedule add schedule.yaml # Add schedules from a file
111
+ tp schedule list # List schedules
112
+ tp schedule start -d # Start daemon in background
113
+ tp schedule status # View daemon and schedule status
114
+
115
+ 5. Other commands:
116
+ tp open docs # Open documentation in browser
117
+ tp open generator # Open visual workflow generator
118
+ tp clean # Remove ~/.pipeliner data (schedules, daemon, history)
119
+
120
+ Note: After upgrading to a new version, if you see compatibility issues (e.g. schedules or daemon), run "tp clean" to reset ~/.pipeliner data.
121
+
122
+ `).version(Bt()).addHelpText("after",`
101
123
  Examples:
102
124
  $ tp run workflow.yaml
103
- $ tp run examples/simple-project/workflow.yaml
104
- $ tp open docs # Open documentation
105
- $ tp open generator # Open visual generator
106
- $ tp history # View workflow execution history
107
- $ tp history show # Select and view a specific history
125
+ $ tp run workflow.yaml --profile Production
126
+ $ tp schedule add schedule.yaml
127
+ $ tp schedule list
128
+ $ tp schedule start -d
129
+ $ tp schedule status
130
+ $ tp open docs
131
+ $ tp open generator
132
+ $ tp history
133
+ $ tp history show
134
+ $ tp clean
135
+
136
+ After upgrading: if schedules or daemon misbehave, run "tp clean" to reset ~/.pipeliner.
108
137
 
109
138
  Resources:
110
139
  \u{1F4DA} Documentation: https://task-pipeliner.racgoo.com/
111
140
  \u{1F3A8} Visual Generator: https://task-pipeliner-generator.racgoo.com/
112
141
 
113
- See README.md for complete DSL reference.`);ee.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",`
142
+ See README.md for complete DSL reference.`);J.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",`
114
143
  Examples:
115
144
  $ tp run workflow.yaml
116
145
  $ tp run workflow.json
@@ -135,11 +164,11 @@ Workflow File Structure:
135
164
  \u2022 all/any/not: Combine conditions
136
165
 
137
166
  Supported formats: YAML (.yaml, .yml) and JSON (.json)
138
- See README.md for complete DSL documentation.`).action(async(r,e)=>{try{let t=r??await po()??null;t||(console.error(p.default.red(`
139
- \u2717 No workflow file found`)),process.exit(1)),e.silent&&vt();let o=oe(t);console.log(p.default.blue(`Loading workflow from ${t}...`));let s=(0,Fe.readFileSync)(t,"utf-8"),n=o.parse(s);if(!n.steps||!Array.isArray(n.steps))throw new Error("Invalid workflow: steps array is required");let a;if(e.profile){let l=e.profile.trim();if(!n.profiles?.length)throw new Error(`Profile "${l}" requested but workflow has no "profiles" defined. Add a "profiles" section to your workflow file.`);let c=n.profiles.find(f=>f.name===l);if(!c){let f=n.profiles.map(g=>g.name).join(", ");throw new Error(`Profile "${l}" not found. Available profile(s): ${f}`)}a=c.var}n._lineNumbers=o.extractStepLineNumbers(s),n._fileName=fo(t),n._filePath=(0,Q.resolve)(t),console.log(p.default.green(`Starting workflow execution...
140
- `)),await new q().execute(n,a?{profileVars:a}:void 0),console.log(p.default.green(`
167
+ See README.md for complete DSL documentation.`).action(async(r,e)=>{try{let t=r??await jo()??null;t||(console.error(p.default.red(`
168
+ \u2717 No workflow file found`)),process.exit(1)),e.silent&&Lt();let o=le(t);console.log(p.default.blue(`Loading workflow from ${t}...`));let n=(0,pe.readFileSync)(t,"utf-8"),s=o.parse(n);if(!s.steps||!Array.isArray(s.steps))throw new Error("Invalid workflow: steps array is required");let i;if(e.profile){let l=e.profile.trim();if(!s.profiles?.length)throw new Error(`Profile "${l}" requested but workflow has no "profiles" defined. Add a "profiles" section to your workflow file.`);let c=s.profiles.find(f=>f.name===l);if(!c){let f=s.profiles.map(g=>g.name).join(", ");throw new Error(`Profile "${l}" not found. Available profile(s): ${f}`)}i=c.var}s._lineNumbers=o.extractStepLineNumbers(n),s._fileName=No(t),s._filePath=(0,U.resolve)(t),console.log(p.default.green(`Starting workflow execution...
169
+ `)),await new te().execute(s,i?{profileVars:i}:void 0),console.log(p.default.green(`
141
170
  \u2713 Workflow completed successfully`))}catch(t){let o=t instanceof Error?t.message:String(t);console.error(p.default.red(`
142
- \u2717 Workflow failed: ${o}`)),process.exit(1)}});ee.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
171
+ \u2717 Workflow failed: ${o}`)),process.exit(1)}});J.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
143
172
  Examples:
144
173
  $ tp open generator
145
174
  $ tp open docs
@@ -148,27 +177,31 @@ Targets:
148
177
  generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
149
178
  docs Open the documentation site (https://task-pipeliner.racgoo.com/)`).action(async r=>{let t={generator:"https://task-pipeliner-generator.racgoo.com/",docs:"https://task-pipeliner.racgoo.com/"}[r.toLowerCase()];t||(console.error(p.default.red(`
150
179
  \u2717 Invalid target: ${r}`)),console.log(p.default.yellow(`
151
- 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 o=process.platform,s;o==="darwin"?s=`open "${t}"`:o==="win32"?s=`start "${t}"`:s=`xdg-open "${t}"`,await co(s),console.log(p.default.green(`
152
- \u2713 Opening ${r==="generator"?"generator":"documentation"} in browser...`)),console.log(p.default.blue(` ${t}`))}catch(o){let s=o instanceof Error?o.message:String(o);console.error(p.default.red(`
153
- \u2717 Failed to open browser: ${s}`)),console.log(p.default.yellow(`
154
- Please visit manually: ${t}`)),process.exit(1)}});ee.addCommand(bt());var uo=ee.command("history").description("Manage workflow execution history");uo.action(async()=>{let r=new L,e=await r.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(`
155
- \u2717 Invalid choice`)),process.exit(1));let t=new z;switch(e.id){case"show":{let o=await t.getHistoryNames();if(o.length===0){console.log(p.default.yellow(`
156
- \u26A0 No history found`));return}let s=await r.prompt("Select a history to view",o.map(n=>({id:n,label:n})));s?.id||(console.error(p.default.red(`
157
- \u2717 Invalid choice`)),process.exit(1));try{let n=await t.getHistory(s.id);mo(n,s.id)}catch(n){let a=n instanceof Error?n.message:String(n);console.error(p.default.red(`
158
- \u2717 Failed to load history: ${a}`)),process.exit(1)}break}case"remove":{let o=await t.getHistoryNames();if(o.length===0){console.log(p.default.yellow(`
159
- \u26A0 No history found`));return}let s=await r.prompt("Select a history to remove",o.map(n=>({id:n,label:n})));s?.id||(console.error(p.default.red(`
160
- \u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(s.id),console.log(p.default.green(`
161
- \u2713 Removed history: ${s.id}`))}catch(n){let a=n instanceof Error?n.message:String(n);console.error(p.default.red(`
162
- \u2717 Failed to remove history: ${a}`)),process.exit(1)}break}case"remove-all":{if((await r.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(`
180
+ 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 o=process.platform,n;o==="darwin"?n=`open "${t}"`:o==="win32"?n=`start "${t}"`:n=`xdg-open "${t}"`,await Io(n),console.log(p.default.green(`
181
+ \u2713 Opening ${r==="generator"?"generator":"documentation"} in browser...`)),console.log(p.default.blue(` ${t}`))}catch(o){let n=o instanceof Error?o.message:String(o);console.error(p.default.red(`
182
+ \u2717 Failed to open browser: ${n}`)),console.log(p.default.yellow(`
183
+ Please visit manually: ${t}`)),process.exit(1)}});J.addCommand(Ot());var Mo=J.command("history").description("Manage workflow execution history");Mo.action(async()=>{let r=new L,e=await r.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(`
184
+ \u2717 Invalid choice`)),process.exit(1));let t=new ee;switch(e.id){case"show":{let o=await t.getHistoryNames();if(o.length===0){console.log(p.default.yellow(`
185
+ \u26A0 No history found`));return}let n=await r.prompt("Select a history to view",o.map(s=>({id:s,label:s})));n?.id||(console.error(p.default.red(`
186
+ \u2717 Invalid choice`)),process.exit(1));try{let s=await t.getHistory(n.id);Ao(s,n.id)}catch(s){let i=s instanceof Error?s.message:String(s);console.error(p.default.red(`
187
+ \u2717 Failed to load history: ${i}`)),process.exit(1)}break}case"remove":{let o=await t.getHistoryNames();if(o.length===0){console.log(p.default.yellow(`
188
+ \u26A0 No history found`));return}let n=await r.prompt("Select a history to remove",o.map(s=>({id:s,label:s})));n?.id||(console.error(p.default.red(`
189
+ \u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(n.id),console.log(p.default.green(`
190
+ \u2713 Removed history: ${n.id}`))}catch(s){let i=s instanceof Error?s.message:String(s);console.error(p.default.red(`
191
+ \u2717 Failed to remove history: ${i}`)),process.exit(1)}break}case"remove-all":{if((await r.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(`
163
192
  \u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(p.default.green(`
164
- \u2713 All histories removed`))}catch(s){let n=s instanceof Error?s.message:String(s);console.error(p.default.red(`
165
- \u2717 Failed to remove histories: ${n}`)),process.exit(1)}break}default:console.error(p.default.red(`
166
- \u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function po(){let r=xt();if(!r)return console.error(p.default.red(`
167
- \u2717 No tp directory found`)),null;try{let t=(await(0,Rt.readdir)(r)).filter(a=>{let i=(0,Q.extname)(a).toLowerCase();return[".yaml",".yml",".json"].includes(i)});if(t.length===0)return console.error(p.default.red(`
168
- \u2717 No workflow files found in ${r}`)),null;let o=await Promise.all(t.map(async a=>{let i=(0,Q.join)(r,a);try{let l=oe(i),c=(0,Fe.readFileSync)(i,"utf-8"),g=l.parse(c).name??"Untitled";return{id:i,label:`${a} - ${g}`}}catch{return{id:i,label:a}}}));return(await new L(!0).prompt("Select a workflow to run",o)).id}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(p.default.red(`
169
- \u2717 Failed to read tp directory: ${t}`)),null}}function fo(r){return r.split("/").pop()??r}function mo(r,e){console.log(`
170
- `);let t=r.records.reduce((c,f)=>c+f.duration,0),o=r.records.filter(c=>c.status==="success").length,s=r.records.filter(c=>c.status==="failure").length,n=(0,Ct.default)(r.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),i=Y(t),l=[p.default.bold("Workflow Execution History"),"",`${p.default.cyan("File:")} ${e}`,`${p.default.cyan("Started:")} ${n}`,`${p.default.cyan("Total Duration:")} ${i}`,`${p.default.cyan("Total Steps:")} ${r.records.length}`,`${p.default.green("\u2713 Successful:")} ${o}`,s>0?`${p.default.red("\u2717 Failed:")} ${s}`:""].filter(Boolean).join(`
171
- `);console.log((0,Le.default)(l,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:"cyan"})),r.records.forEach((c,f)=>{ho(c,f+1,r.records.length)}),console.log("")}function ho(r,e,t){let o=go(r.step),s=wo(r.step),n=r.status==="success"?p.default.green("\u2713"):p.default.red("\u2717"),a=r.status==="success"?p.default.green("Success"):p.default.red("Failed"),i=Y(r.duration),l=[`${n} ${p.default.bold(`Step ${e}/${t}`)} - ${p.default.cyan(o)}`,`${p.default.gray("Duration:")} ${i} | ${p.default.gray("Status:")} ${a}`,"",p.default.white(s)].join(`
172
- `);console.log((0,Le.default)(l,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:r.status==="success"?"green":"red"})),yo(r.output)&&bo(r.output)}function go(r){return"run"in r?"Run":"choose"in r?"Choose":"prompt"in r?"Prompt":"parallel"in r?"Parallel":"fail"in r?"Fail":"Unknown"}function wo(r){return"run"in r?`Command: ${p.default.yellow(r.run)}`:"choose"in r?`Message: ${p.default.yellow(r.choose.message)}`:"prompt"in r?`Message: ${p.default.yellow(r.prompt.message)} | Variable: ${p.default.cyan(r.prompt.as)}`:"parallel"in r?`Parallel execution with ${r.parallel.length} branches`:"fail"in r?`Error: ${p.default.red(r.fail.message)}`:"Unknown step type"}function yo(r){return typeof r=="object"&&r!==null&&"success"in r&&"stdout"in r&&"stderr"in r}function bo(r){if(r.stdout.length>0){let e=r.stdout.map(t=>p.default.gray(` ${t}`)).join(`
193
+ \u2713 All histories removed`))}catch(n){let s=n instanceof Error?n.message:String(n);console.error(p.default.red(`
194
+ \u2717 Failed to remove histories: ${s}`)),process.exit(1)}break}default:console.error(p.default.red(`
195
+ \u2717 Unknown action: ${e.id}`)),process.exit(1)}});async function jo(){let r=Wt();if(!r)return console.error(p.default.red(`
196
+ \u2717 No tp directory found`)),null;try{let t=(await(0,Pe.readdir)(r)).filter(i=>{let a=(0,U.extname)(i).toLowerCase();return[".yaml",".yml",".json"].includes(a)});if(t.length===0)return console.error(p.default.red(`
197
+ \u2717 No workflow files found in ${r}`)),null;let o=await Promise.all(t.map(async i=>{let a=(0,U.join)(r,i);try{let l=le(a),c=(0,pe.readFileSync)(a,"utf-8"),g=l.parse(c).name??"Untitled";return{id:a,label:`${i} - ${g}`}}catch{return{id:a,label:i}}}));return(await new L(!0).prompt("Select a workflow to run",o)).id}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(p.default.red(`
198
+ \u2717 Failed to read tp directory: ${t}`)),null}}function No(r){return r.split("/").pop()??r}function Ao(r,e){console.log(`
199
+ `);let t=r.records.reduce((c,f)=>c+f.duration,0),o=r.records.filter(c=>c.status==="success").length,n=r.records.filter(c=>c.status==="failure").length,s=(0,Yt.default)(r.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),a=X(t),l=[p.default.bold("Workflow Execution History"),"",`${p.default.cyan("File:")} ${e}`,`${p.default.cyan("Started:")} ${s}`,`${p.default.cyan("Total Duration:")} ${a}`,`${p.default.cyan("Total Steps:")} ${r.records.length}`,`${p.default.green("\u2713 Successful:")} ${o}`,n>0?`${p.default.red("\u2717 Failed:")} ${n}`:""].filter(Boolean).join(`
200
+ `);console.log((0,Xe.default)(l,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:"cyan"})),r.records.forEach((c,f)=>{Oo(c,f+1,r.records.length)}),console.log("")}function Oo(r,e,t){let o=Fo(r.step),n=Lo(r.step),s=r.status==="success"?p.default.green("\u2713"):p.default.red("\u2717"),i=r.status==="success"?p.default.green("Success"):p.default.red("Failed"),a=X(r.duration),l=[`${s} ${p.default.bold(`Step ${e}/${t}`)} - ${p.default.cyan(o)}`,`${p.default.gray("Duration:")} ${a} | ${p.default.gray("Status:")} ${i}`,"",p.default.white(n)].join(`
201
+ `);console.log((0,Xe.default)(l,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1,left:0,right:0},borderColor:r.status==="success"?"green":"red"})),Bo(r.output)&&Wo(r.output)}function Fo(r){return"run"in r?"Run":"choose"in r?"Choose":"prompt"in r?"Prompt":"parallel"in r?"Parallel":"fail"in r?"Fail":"Unknown"}function Lo(r){return"run"in r?`Command: ${p.default.yellow(r.run)}`:"choose"in r?`Message: ${p.default.yellow(r.choose.message)}`:"prompt"in r?`Message: ${p.default.yellow(r.prompt.message)} | Variable: ${p.default.cyan(r.prompt.as)}`:"parallel"in r?`Parallel execution with ${r.parallel.length} branches`:"fail"in r?`Error: ${p.default.red(r.fail.message)}`:"Unknown step type"}function Bo(r){return typeof r=="object"&&r!==null&&"success"in r&&"stdout"in r&&"stderr"in r}function Wo(r){if(r.stdout.length>0){let e=r.stdout.map(t=>p.default.gray(` ${t}`)).join(`
173
202
  `);console.log(p.default.green(" Output:")),console.log(e)}if(r.stderr.length>0){let e=r.stderr.map(t=>p.default.gray(` ${t}`)).join(`
174
- `);console.log(p.default.red(" Errors:")),console.log(e)}}ee.parse();
203
+ `);console.log(p.default.red(" Errors:")),console.log(e)}}J.command("clean").description("Remove all data in ~/.pipeliner (schedules, daemon state, workflow history). Use after upgrades if data is incompatible.").action(async()=>{if((await new L().prompt(`This will remove all data in ${p.default.yellow(ue)} (schedules, daemon PID, workflow history). Continue?`,[{id:"yes",label:"Yes, remove all"},{id:"no",label:"No, cancel"}]))?.id!=="yes"){console.log(p.default.yellow(`
204
+ \u2717 Cancelled`));return}try{if(await A()){let t=await $();console.log(p.default.gray(`Stopping scheduler daemon (PID: ${t.pid})...`)),await new B().stopDaemon(),console.log(p.default.gray(" Daemon stopped"))}(0,pe.existsSync)(ue)?(await(0,Pe.rm)(ue,{recursive:!0}),console.log(p.default.green(`
205
+ \u2713 Removed ${ue}`))):console.log(p.default.gray(`
206
+ ${ue} does not exist (already clean)`))}catch(t){let o=t instanceof Error?t.message:String(t);console.error(p.default.red(`
207
+ \u2717 Clean failed: ${o}`)),process.exit(1)}});J.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-pipeliner",
3
- "version": "0.2.18",
3
+ "version": "0.3.0",
4
4
  "description": "A task pipeline runner with condition-based workflow execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -32,6 +32,7 @@
32
32
  "boxen": "^5.1.2",
33
33
  "chalk": "^4.1.2",
34
34
  "commander": "^11.1.0",
35
+ "cronstrue": "^3.11.0",
35
36
  "dayjs": "^1.11.19",
36
37
  "inquirer": "^8.2.6",
37
38
  "log-update": "^4.0.0",