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

|
|
8
8
|
|
|
@@ -245,11 +245,11 @@ steps: # 필수: 실행할 단계 배열
|
|
|
245
245
|
when?: <condition> # 선택: 조건이 충족될 때만 실행
|
|
246
246
|
timeout?: <number> # 선택: 타임아웃 (초 단위)
|
|
247
247
|
retry?: <number> # 선택: 실패 시 재시도 횟수 (기본값: 0)
|
|
248
|
+
continue?: <bool> # 선택: 이 스텝 이후 다음 스텝으로 진행할지 여부 (성공/실패 무관)
|
|
248
249
|
onError?: # 선택: 에러 처리 동작
|
|
249
|
-
run: <command> #
|
|
250
|
+
run: <command> # 메인 run 명령이 실패했을 때 실행할 대체 명령 (사이드 이펙트)
|
|
250
251
|
timeout?: <number> # 선택: 이 fallback 명령의 타임아웃
|
|
251
252
|
retry?: <number> # 선택: 이 fallback 명령의 재시도 횟수
|
|
252
|
-
continue?: <bool> # 선택: 체인 전체가 실패해도 워크플로우를 계속 진행할지 여부
|
|
253
253
|
onError?: ... # 선택: 중첩 fallback (재귀 onError 체인)
|
|
254
254
|
```
|
|
255
255
|
|
|
@@ -258,10 +258,13 @@ steps: # 필수: 실행할 단계 배열
|
|
|
258
258
|
- `when` (선택): `Condition` - 실행 전 확인할 조건
|
|
259
259
|
- `timeout` (선택): `number` - 최대 실행 시간 (초 단위). 이 시간을 초과하면 명령이 종료됩니다.
|
|
260
260
|
- `retry` (선택): `number` - 실패 시 재시도 횟수 (기본값: 0, 재시도 없음)
|
|
261
|
-
|
|
261
|
+
- `continue` (선택): `boolean` - 이 스텝 완료 후 다음 스텝으로 진행할지 여부를 제어합니다 (성공/실패와 무관).
|
|
262
|
+
- `continue: true` - 항상 다음 스텝으로 진행 (이 스텝이 실패해도)
|
|
263
|
+
- `continue: false` - 항상 워크플로우 중단 (이 스텝이 성공해도)
|
|
264
|
+
- `continue` 미설정 (기본값) - 성공 시 진행, 실패 시 중단
|
|
265
|
+
- `onError.run` (선택): `string` - 메인 `run` 명령이 (자신의 재시도 후에도) 실패했을 때 실행할 대체 명령. **onError는 단순히 사이드 이펙트(예: 정리 작업, 롤백)를 수행하며, 스텝의 성공/실패 여부에는 영향을 주지 않습니다.** 메인 `run`이 실패하면 이 스텝은 실패로 간주됩니다.
|
|
262
266
|
- `onError.timeout` (선택): `number` - 이 fallback 명령의 타임아웃.
|
|
263
267
|
- `onError.retry` (선택): `number` - 이 fallback 명령의 재시도 횟수.
|
|
264
|
-
- `onError.continue` (선택): `boolean` - onError 체인 전체가 결국 실패해도, 이 단계를 실패로 기록만 하고 다음 단계로 계속 진행할지 여부.
|
|
265
268
|
|
|
266
269
|
**예제:**
|
|
267
270
|
```yaml
|
|
@@ -316,13 +319,18 @@ steps:
|
|
|
316
319
|
|
|
317
320
|
# 실패를 기록만 하고 워크플로우는 계속 진행
|
|
318
321
|
- run: pnpm typecheck
|
|
322
|
+
continue: true
|
|
319
323
|
onError:
|
|
320
|
-
|
|
324
|
+
run: echo "Type check failed, but continuing..."
|
|
321
325
|
```
|
|
322
326
|
|
|
323
327
|
**동작:**
|
|
324
328
|
- 명령은 `baseDir` (지정된 경우) 또는 현재 작업 디렉토리에서 실행됩니다
|
|
325
|
-
-
|
|
329
|
+
- 메인 `run` 명령의 성공/실패 여부가 이 스텝의 최종 결과를 결정합니다. `onError`는 단순히 실패 시 추가 작업(정리, 롤백 등)을 수행할 뿐이며, 스텝의 성공 여부를 변경하지 않습니다.
|
|
330
|
+
- `continue` 플래그는 이 스텝 완료 후 워크플로우 실행을 제어합니다:
|
|
331
|
+
- `continue: true` - 항상 다음 스텝으로 진행 (성공/실패 무관)
|
|
332
|
+
- `continue: false` - 항상 워크플로우 중단 (성공/실패 무관)
|
|
333
|
+
- `continue` 미설정 - 기본 동작: 성공 시 진행, 실패 시 중단
|
|
326
334
|
- 출력은 CLI 포맷팅과 함께 실시간으로 표시됩니다
|
|
327
335
|
- `timeout`이 지정되면 명령이 시간 제한을 초과하면 종료되고 단계가 실패합니다
|
|
328
336
|
- `retry`가 지정되면 성공할때 까지 retry 값 만큼 재시도됩니다
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A powerful, condition-based task pipeline runner with beautiful CLI output
|
|
4
4
|
|
|
5
|
-
**Version:** 0.2.
|
|
5
|
+
**Version:** 0.2.2
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -245,11 +245,11 @@ Execute a shell command.
|
|
|
245
245
|
when?: <condition> # Optional: Execute only if condition is met
|
|
246
246
|
timeout?: <number> # Optional: Timeout in seconds
|
|
247
247
|
retry?: <number> # Optional: Number of retries on failure (default: 0)
|
|
248
|
+
continue?: <bool> # Optional: Continue to next step after this step completes (regardless of success/failure)
|
|
248
249
|
onError?: # Optional: Error handling behavior
|
|
249
|
-
run: <command> # Fallback command when
|
|
250
|
+
run: <command> # Fallback command when main run command fails (side effect)
|
|
250
251
|
timeout?: <number> # Optional: Timeout for this fallback command
|
|
251
252
|
retry?: <number> # Optional: Retry count for this fallback command
|
|
252
|
-
continue?: <bool> # Optional: Continue workflow even if the whole chain still fails
|
|
253
253
|
onError?: ... # Optional: Nested fallback (recursive onError chain)
|
|
254
254
|
```
|
|
255
255
|
|
|
@@ -258,10 +258,13 @@ Execute a shell command.
|
|
|
258
258
|
- `when` (optional): `Condition` - Condition to check before execution
|
|
259
259
|
- `timeout` (optional): `number` - Maximum execution time in seconds. Command will be killed if it exceeds this time.
|
|
260
260
|
- `retry` (optional): `number` - Number of retry attempts if command fails (default: 0, meaning no retry)
|
|
261
|
-
|
|
261
|
+
- `continue` (optional): `boolean` - Controls whether to proceed to the next step after this step completes, regardless of success or failure.
|
|
262
|
+
- `continue: true` - Always proceed to the next step (even if this step fails)
|
|
263
|
+
- `continue: false` - Always stop the workflow after this step (even if this step succeeds)
|
|
264
|
+
- `continue` not set (default) - Proceed on success, stop on failure
|
|
265
|
+
- `onError.run` (optional): `string` - Fallback command executed when the main `run` command (after its retries) fails. **onError only performs side effects (e.g., cleanup, rollback) and does not affect the step's success/failure status.** If the main `run` fails, this step is considered failed regardless of onError execution.
|
|
262
266
|
- `onError.timeout` (optional): `number` - Timeout for this fallback command.
|
|
263
267
|
- `onError.retry` (optional): `number` - Retry count for this fallback command.
|
|
264
|
-
- `onError.continue` (optional): `boolean` - If `true` and the entire onError chain ultimately fails, record the failure but continue to the next step instead of stopping the workflow.
|
|
265
268
|
|
|
266
269
|
**Examples:**
|
|
267
270
|
```yaml
|
|
@@ -316,13 +319,18 @@ steps:
|
|
|
316
319
|
|
|
317
320
|
# Command that records failure but continues workflow
|
|
318
321
|
- run: pnpm typecheck
|
|
322
|
+
continue: true
|
|
319
323
|
onError:
|
|
320
|
-
|
|
324
|
+
run: echo "Type check failed, but continuing..."
|
|
321
325
|
```
|
|
322
326
|
|
|
323
327
|
**Behavior:**
|
|
324
328
|
- Command runs in the `baseDir` (if specified) or current working directory
|
|
325
|
-
-
|
|
329
|
+
- The main `run` command's success/failure determines the final step result. `onError` only performs additional actions (cleanup, rollback, etc.) on failure and does not change the step's success status.
|
|
330
|
+
- The `continue` flag controls workflow execution after this step completes:
|
|
331
|
+
- `continue: true` - Always proceed to the next step (regardless of success/failure)
|
|
332
|
+
- `continue: false` - Always stop the workflow (regardless of success/failure)
|
|
333
|
+
- `continue` not set - Default behavior: proceed on success, stop on failure
|
|
326
334
|
- Output is displayed in real-time with CLI formatting
|
|
327
335
|
- If `timeout` is specified and command exceeds the time limit, it will be killed and the step will fail
|
|
328
336
|
- If `retry` is specified, the command will be retried up to the retry value until it succeeds
|
package/dist/index.cjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
`)),
|
|
4
|
-
`)),
|
|
5
|
-
`),
|
|
6
|
-
`);let
|
|
2
|
+
"use strict";var ke=Object.create;var se=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var $e=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var Pe=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ce(e))!Ee.call(s,o)&&o!==t&&se(s,o,{get:()=>e[o],enumerable:!(r=Re(e,o))||r.enumerable});return s};var b=(s,e,t)=>(t=s!=null?ke($e(s)):{},Pe(e||!s||!s.__esModule?se(t,"default",{value:s,enumerable:!0}):t,s));var we=require("child_process"),be=require("fs"),ye=require("path"),Se=require("util"),ne=b(require("boxen"),1),u=b(require("chalk"),1),xe=require("commander"),ve=b(require("dayjs"),1);var N=require("path"),me=b(require("chalk"),1),z=b(require("log-update"),1);var X=b(require("chalk"),1),q=b(require("inquirer"),1),T=class{async prompt(e,t){let{choice:r}=await q.default.prompt([{type:"list",name:"choice",message:X.default.cyan(e),choices:t.map(n=>({name:n.label,value:n.id}))}]),o=t.find(n=>n.id===r);if(!o)throw new Error(`Invalid choice: ${r}`);return o}},H=class{async prompt(e,t){let{value:r}=await q.default.prompt([{type:"input",name:"value",message:X.default.cyan(e),default:t}]);return r}};var O=b(require("boxen"),1),A=b(require("chalk"),1);function K(s,e,t,r={}){let{borderColor:o="cyan",isNested:n=!1}=r,a;e!==void 0&&(t?a=`line ${e} in ${t}`:a=`line ${e}`);let i=n?`\u2502 ${s}`:`> ${s}`;return(0,O.default)(i,{title:a,borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:o})}function I(s,e=!1,t){let r=s?"\u2713 Completed":"\u2717 Failed",o=s?A.default.green(r):A.default.red(r);if(t!==void 0){let n=B(t);return`${o} ${A.default.gray(`(${n})`)}`}return o}function F(s){return(0,O.default)(`\u2717 ${s}`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:"red"})}function ae(s){return(0,O.default)(`> Starting parallel execution (${s} branches)`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:"yellow"})}function ie(s){let e=s?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return s?A.default.green(e):A.default.red(e)}function Q(s,e=!1){return`${e?"| \u2502 ":"\u2502 "}${s}`}function B(s){return`${(s/1e3).toFixed(3)}s`}var le=require("fs"),ce=require("path"),D=class{constructor(e){this.workspace=e}evaluate(e){return"var"in e||"has"in e?this.evaluateVarExists(e):"file"in e?this.evaluateFileExists(e):"choice"in e?this.evaluateChoice(e):"all"in e?this.evaluateAll(e):"any"in e?this.evaluateAny(e):"not"in e?this.evaluateNot(e):!1}evaluateVarExists(e){if(e.has)return this.workspace.hasVariable(e.has)||this.workspace.hasFact(e.has);if(!e.var)return!1;if(typeof e.var=="object"){for(let[r,o]of Object.entries(e.var)){let n=this.workspace.getVariable(r),a=this.workspace.getFact(r),i=n??(a!==void 0?a.toString():void 0);if(i===void 0||i!==o)return!1}return!0}let t=e.var;return this.workspace.hasVariable(t)||this.workspace.hasFact(t)}evaluateFileExists(e){try{let t=e.file.trim(),r=(0,ce.resolve)(process.cwd(),t);return(0,le.existsSync)(r)}catch{return!1}}evaluateChoice(e){return this.workspace.hasChoice(e.choice)}evaluateAll(e){return e.all.every(t=>this.evaluate(t))}evaluateAny(e){return e.any.some(t=>this.evaluate(t))}evaluateNot(e){return!this.evaluate(e.not)}};var S=require("fs/promises"),ue=require("os"),M=require("path"),pe=b(require("dayjs"),1),j=(0,M.join)((0,ue.homedir)(),".pipeliner","workflow-history"),L=class{constructor(){}async saveHistory(e){await(0,S.mkdir)(j,{recursive:!0});let t=(0,pe.default)().format("YYYY-MM-DD_HH-mm-ss"),r=Math.random().toString(36).slice(2,6),o=(0,M.join)(j,`workflow-${t}-${r}.json`);return await(0,S.writeFile)(o,JSON.stringify(e,null,2),{encoding:"utf8"}),o}async clearAllHistories(){await(0,S.rm)(j,{recursive:!0,force:!0})}async removeHistory(e){await(0,S.rm)((0,M.join)(j,e),{force:!0})}async getHistoryNames(){try{let t=(await(0,S.readdir)(j)).map(r=>(0,M.basename)(r));return t.sort((r,o)=>{let n=p=>{let c=p.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},a=n(r),i=n(o);return a===i?o.localeCompare(r):i.localeCompare(a)}),t}catch(e){if(e instanceof Error&&"code"in e&&e.code==="ENOENT")return[];throw e}}async getHistory(e){let t=await(0,S.readFile)((0,M.join)(j,e),{encoding:"utf8"});return JSON.parse(t)}};var V=class{records=[];initialTimestamp=Date.now();recordStartTimestamp=Date.now();constructor(){this.records=[]}recordStart(){this.recordStartTimestamp=Date.now()}recordEnd(e,t,r,o){let n=this.getDuration();return this.records.push({step:e,context:t,output:r,duration:n,status:o}),n}reset(){this.records=[],this.initialTimestamp=Date.now()}async save(){let e=new L,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var _=class{async run(e,t,r,o,n=!1,a=!1,i,p,c,m){return n?this.runBuffered(e,c,m):this.runRealtime(e,r||e,a,i,p,c,m)}async runBuffered(e,t,r){let{spawn:o}=await import("child_process"),[n,...a]=this.parseCommand(e),i=this.createSpawnOptions(t);return new Promise((p,c)=>{let m=o(n,a,i),h=[],f=[],d="",w="",v=null;r&&r>0&&(v=setTimeout(()=>{m.kill("SIGTERM");let g=`Command timed out after ${r} seconds`;f.push(g),p({success:!1,stdout:h,stderr:f})},r*1e3)),m.stdout?.on("data",g=>{let y=g.toString(),{lines:C,remaining:k}=this.processStreamBuffer(y,d);h.push(...C),d=k}),m.stderr?.on("data",g=>{let y=g.toString(),{lines:C,remaining:k}=this.processStreamBuffer(y,w);f.push(...C),w=k}),m.on("close",g=>{v&&clearTimeout(v),d.trim()&&h.push(d),w.trim()&&f.push(w),p({success:g===0,stdout:h,stderr:f})}),m.on("error",g=>{v&&clearTimeout(v);let y=`Error: ${g.message}`;p({success:!1,stdout:h,stderr:[...f,y]})})})}async runRealtime(e,t,r,o,n,a,i){let{spawn:p}=await import("child_process"),[c,...m]=this.parseCommand(e),h=this.createSpawnOptions(a),d=K(t,o,n,{borderColor:r?"green":"cyan"});console.log(d);let w=Date.now();return new Promise(v=>{let g=p(c,m,h),y="",C="",k=null;i&&i>0&&(k=setTimeout(()=>{g.kill("SIGTERM");let R=`Command timed out after ${i} seconds`,x=F(R);console.error(x);let E=Date.now()-w,P=I(!1,!1,E);console.log(P),v(!1)},i*1e3)),g.stdout?.on("data",R=>{let x=R.toString(),{lines:E,remaining:P}=this.processStreamBuffer(x,y);E.forEach(G=>process.stdout.write(`\u2502 ${G}
|
|
3
|
+
`)),y=P}),g.stderr?.on("data",R=>{let x=R.toString(),{lines:E,remaining:P}=this.processStreamBuffer(x,C);E.forEach(G=>process.stderr.write(`\u2502 ${G}
|
|
4
|
+
`)),C=P}),g.on("close",R=>{k&&clearTimeout(k),y.trim()&&process.stdout.write(`\u2502 ${y}
|
|
5
|
+
`),C.trim()&&process.stderr.write(`\u2502 ${C}
|
|
6
|
+
`);let x=R===0,E=Date.now()-w,P=I(x,!1,E);console.log(P),v(x)}),g.on("error",R=>{k&&clearTimeout(k);let x=F(`Error: ${R.message}`);console.error(x),v(!1)})})}parseCommand(e){let t=e.split(" ");return[t[0],...t.slice(1)]}createSpawnOptions(e){let t={stdio:["inherit","pipe","pipe"],shell:!0};return e&&(t.cwd=e),t}processStreamBuffer(e,t){let r=t+e,o=[],n=r;for(;n.includes(`
|
|
7
7
|
`);){let a=n.indexOf(`
|
|
8
8
|
`),i=n.substring(0,a);n=n.substring(a+1),o.push(i)}return{lines:o,remaining:n}}formatNestedOutput(e,t){t?e.split(`
|
|
9
|
-
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,o,n){let a=
|
|
10
|
-
`)}),e.stderr.forEach(p=>{let c=
|
|
11
|
-
`)});let i=
|
|
12
|
-
`)):(0,
|
|
13
|
-
`))
|
|
9
|
+
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,o,n){let a=K(t,o,n,{borderColor:"cyan",isNested:r});this.formatNestedOutput(a,r),e.stdout.forEach(p=>{let c=Q(p,r);process.stdout.write(`${c}
|
|
10
|
+
`)}),e.stderr.forEach(p=>{let c=Q(p,r);process.stderr.write(`${c}
|
|
11
|
+
`)});let i=I(e.success,r);console.log(i)}};function Me(s,e,t){if(e.hasVariable(s))return e.getVariable(s)||t;if(e.hasFact(s)){let r=e.getFact(s);return typeof r=="string"?r:String(r)}return e.hasChoice(s)&&e.getChoice(s)||t}function Y(s,e){let t=/\{\{(\w+)\}\}/g;return s.replace(t,(r,o)=>Me(o,e,r))}var J=class s{state;constructor(){this.state={facts:new Map,choices:new Map,variables:new Map,stepResults:new Map,lastStepIndex:-1}}hasFact(e){return this.state.facts.has(e)}getFact(e){return this.state.facts.get(e)}setFact(e,t){this.state.facts.set(e,t)}getFactStatus(e){if(!this.hasFact(e))return"pending";let t=this.getFact(e);return t===!1||t==="failed"?"failed":"ready"}getAllFacts(){return new Map(this.state.facts)}hasChoice(e){return this.state.choices.has(e)}getChoice(e){return this.state.choices.get(e)}setChoice(e,t){this.state.choices.set(e,t)}hasVariable(e){return this.state.variables.has(e)}getVariable(e){return this.state.variables.get(e)}setVariable(e,t){this.state.variables.set(e,t)}getAllVariables(){return new Map(this.state.variables)}setStepResult(e,t,r){this.state.stepResults.set(e,{success:t,exitCode:r}),this.state.lastStepIndex=e}getStepResult(e){return this.state.stepResults.get(e)}getLastStepResult(){if(this.state.lastStepIndex!==-1)return this.state.stepResults.get(this.state.lastStepIndex)}clone(){let e=new s;return e.state.facts=new Map(this.state.facts),e.state.choices=new Map(this.state.choices),e.state.variables=new Map(this.state.variables),e.state.stepResults=new Map(this.state.stepResults),e.state.lastStepIndex=this.state.lastStepIndex,e}};var U=class s{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;constructor(){this.workspace=new J,this.taskRunner=new _,this.choicePrompt=new T,this.textPrompt=new H}resolveBaseDir(e){if(e.baseDir)if((0,N.isAbsolute)(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=(0,N.dirname)(e._filePath);this.baseDir=(0,N.resolve)(t,e.baseDir)}else this.baseDir=(0,N.resolve)(process.cwd(),e.baseDir)}createStepContext(e,t){let r={workspace:this.workspace,stepIndex:e};return t._lineNumbers&&(r.lineNumber=t._lineNumbers.get(e)),t._fileName&&(r.fileName=t._fileName),r}evaluateStepCondition(e){return e.when?new D(this.workspace).evaluate(e.when):!0}calculateBaseStepIndex(e){return e.branchIndex===void 0?e.stepIndex:Math.floor(e.stepIndex/s.PARALLEL_STEP_INDEX_MULTIPLIER)}isRunStep(e){return"run"in e}async execute(e){this.resolveBaseDir(e);let t=new V,r=Date.now();for(let a=0;a<e.steps.length;a++){let i=e.steps[a],p=this.createStepContext(a,e),c=!!i.when;if(this.evaluateStepCondition(i)){t.recordStart();try{let m=await this.executeStep(i,p,!1,c);this.handleStepResult(i,p,a,m,t)}catch(m){throw this.handleStepError(i,p,a,m,t),m}}}let o=Date.now()-r,n=B(o);console.log(me.default.cyan(`
|
|
12
|
+
Total execution time: ${n}`)),await t.save(),t.reset()}isStepSuccessful(e,t){return"run"in t?typeof e=="boolean"?e:e&&typeof e=="object"&&"success"in e?e.success:!1:!0}handleStepResult(e,t,r,o,n){let a=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(r);return c?c.success:!0})():this.isStepSuccessful(o,e),i=a?"success":"failure",p=n.recordEnd(e,t,o,i);if(!this.isRunStep(e)){let c=I(a,!1,p);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",m=a?`Step ${r}${c} completed, but workflow stopped due to continue: false`:`Step ${r}${c} failed`;throw new Error(m)}if(!a&&e.continue!==!0){let c=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${r}${c} failed`)}}}handleStepError(e,t,r,o,n){this.workspace.setStepResult(r,!1);let a=o instanceof Error?o.message:String(o),i={success:!1,stdout:[],stderr:[a]};n.recordEnd(e,t,i,"failure")}fixMalformedStep(e){let r=e;return"choose"in e&&r.choose===null&&"message"in e&&"options"in e?{choose:{message:r.message,options:r.options,as:r.as},when:r.when}:"prompt"in e&&r.prompt===null&&"message"in e&&"as"in e?{prompt:{message:r.message,as:r.as,default:r.default},when:r.when}:e}async executeStep(e,t,r=!1,o=!1){if(e=this.fixMalformedStep(e),"run"in e){let n=await this.executeRunStep(e,t,r,o);return r&&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,r=!1,o=!1){let n=this.calculateBaseStepIndex(t),a=Y(e.run,this.workspace),i=e.retry??0,p=e.timeout,c=!1,m=0;for(;m<=i;){let h=await this.taskRunner.run(a,n,a,t.branchIndex,r,o,t.lineNumber,t.fileName,this.baseDir,p),f=typeof h=="boolean"?h:h.success;if(c=h,f||m>=i)break;if(m++,m<=i){let d=Math.min(1e3*Math.pow(2,m-1),1e4);await new Promise(w=>setTimeout(w,d))}}return c}async executeRunStep(e,t,r=!1,o=!1){let n=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry},t,r,o),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,r,o)}async executeRunChain(e,t,r,o){let n=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry},t,r,o);return(typeof n=="boolean"?n:n.success)||!e.onError?n:this.executeRunChain(e.onError,t,r,o)}async executeChooseStep(e,t){let r=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!r?.id)throw new Error(`Invalid choice result: ${JSON.stringify(r)}`);let o=e.choose.as??r.id;this.workspace.setChoice(r.id,r.id),this.workspace.setVariable(o,r.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let r=Y(e.prompt.message,this.workspace),o=e.prompt.default?Y(e.prompt.default,this.workspace):void 0,n=await this.textPrompt.prompt(r,o);this.workspace.setVariable(e.prompt.as,n),this.workspace.setFact(e.prompt.as,n),this.workspace.setStepResult(t.stepIndex,!0)}createParallelContexts(e,t){return e.parallel.map((r,o)=>({workspace:this.workspace.clone(),stepIndex:t.stepIndex*s.PARALLEL_STEP_INDEX_MULTIPLIER+o,branchIndex:o,lineNumber:t.lineNumber,fileName:t.fileName}))}getBranchDisplayName(e,t){return"run"in e?e.run:"choose"in e?`Choose: ${e.choose.message}`:"prompt"in e?`Prompt: ${e.prompt.message}`:"fail"in e?`Fail: ${e.fail.message}`:`Branch ${t+1}`}async executeParallelBranches(e,t){let r=[],o=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],n=0;for(let c=0;c<e.length;c++){let m=e[c],h=t[c];if(m.when&&!new D(h.workspace).evaluate(m.when))continue;let f=this.getBranchDisplayName(m,c);r.push({index:c,name:f,status:"pending"})}let a=setInterval(()=>{n=(n+1)%o.length,this.updateParallelBranchesDisplay(r,o[n])},100),i=r.map(async c=>{let{index:m}=c,h=e[m],f=t[m];c.status="running";try{let d=await this.executeStep(h,f,!0);return c.status="success",this.updateParallelBranchesDisplay(r,o[n]),{index:m,result:d,context:f}}catch(d){f.workspace.setStepResult(f.stepIndex,!1);let w=d instanceof Error?d.message:String(d);return c.status="failed",c.error=w,this.updateParallelBranchesDisplay(r,o[n]),{index:m,error:d,context:f}}}),p=await Promise.all(i);return clearInterval(a),this.updateParallelBranchesDisplay(r,"",!0),z.default.done(),p}updateParallelBranchesDisplay(e,t,r=!1){let o=e.map(n=>{let a=n.index+1,i="",p="";switch(n.status){case"pending":i="\u25CB",p=`Branch ${a}: ${n.name} - Pending`;break;case"running":i=t,p=`Branch ${a}: ${n.name} - Running...`;break;case"success":i="\u2713",p=`Branch ${a}: ${n.name} - Completed`;break;case"failed":i="\u2717",p=`Branch ${a}: ${n.name} - Failed${n.error?`: ${n.error}`:""}`;break}return`${i} ${p}`});r?(0,z.default)(o.join(`
|
|
13
|
+
`)):(0,z.default)(o.join(`
|
|
14
|
+
`))}displayParallelResults(e,t,r){let o=!0,n=!1;console.log("");for(let i of e){if(!i)continue;n=!0;let{index:p,result:c,error:m,context:h}=i;if(m){o=!1;let f=`Branch ${p+1} failed: ${m instanceof Error?m.message:String(m)}`,d=F(f);console.error(d)}else if(c&&typeof c=="object"&&"stdout"in c){let f=c;if(o=o&&f.success,f.stdout.length>0||f.stderr.length>0||!f.success){let d=t[p],w=this.getBranchDisplayName(d,p);this.taskRunner.displayBufferedOutput(f,w,!1,h.lineNumber,h.fileName)}}}n||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let a=ie(o);return console.log(a),o}mergeParallelResults(e){for(let t of e){let r=t.workspace.getAllFacts(),o=t.workspace.getAllVariables();for(let[n,a]of r)this.workspace.setFact(n,a);for(let[n,a]of o)this.workspace.setVariable(n,a)}}countExecutableBranches(e,t){let r=0;for(let o=0;o<e.length;o++){let n=e[o],a=t[o];n.when&&!new D(a.workspace).evaluate(n.when)||r++}return r}async executeParallelStep(e,t){let r=this.createParallelContexts(e,t),o=this.countExecutableBranches(e.parallel,r),n=ae(o);console.log(n);let a=await this.executeParallelBranches(e.parallel,r),i=this.displayParallelResults(a,e.parallel,t);if(this.workspace.setStepResult(t.stepIndex,i),!i){let p=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Parallel step ${t.stepIndex}${p} failed: one or more branches failed`)}this.mergeParallelResults(r)}async executeFailStep(e,t){let r=new Error(e.fail.message);throw r.stack=void 0,r}};var he=require("yaml"),re=require("zod");var l=require("zod"),Ne=l.z.object({file:l.z.string()}),Te=l.z.object({var:l.z.union([l.z.string(),l.z.record(l.z.string(),l.z.string())]).optional(),has:l.z.string().optional()}),Ae=l.z.object({status:l.z.object({fact:l.z.string(),is:l.z.enum(["ready","failed","pending"])})}),Ie=l.z.object({step:l.z.object({success:l.z.boolean()}).optional(),last_step:l.z.enum(["success","failure"]).optional()}),Be=l.z.object({choice:l.z.string()}),De=l.z.union([Ne,Be,Te,Ae,Ie]),$=l.z.lazy(()=>l.z.union([De,l.z.object({all:l.z.array($)}),l.z.object({any:l.z.array($)}),l.z.object({not:$})])),fe=l.z.lazy(()=>l.z.object({run:l.z.string(),timeout:l.z.number().optional(),retry:l.z.number().optional(),onError:fe.optional()})),je=l.z.object({run:l.z.string(),when:$.optional(),timeout:l.z.number().optional(),retry:l.z.number().optional(),continue:l.z.boolean().optional(),onError:fe.optional()}),Le=l.z.object({choose:l.z.object({message:l.z.string(),options:l.z.array(l.z.object({id:l.z.string(),label:l.z.string()})),as:l.z.string().optional()}),when:$.optional()}),Fe=l.z.object({prompt:l.z.object({message:l.z.string(),as:l.z.string(),default:l.z.string().optional(),validate:l.z.string().optional()}),when:$.optional()}),de=l.z.lazy(()=>l.z.union([je,Le,Fe,l.z.object({parallel:l.z.array(de),when:$.optional()}),l.z.object({fail:l.z.object({message:l.z.string()}),when:$.optional()})])),We=l.z.object({name:l.z.string().optional(),baseDir:l.z.string().optional(),steps:l.z.array(de).min(1,"Workflow must have at least one step")});function ee(s){return We.parse(s)}function oe(s){let e=s;return"choose"in e&&(e.choose===null||e.choose===void 0)&&"message"in e&&"options"in e?{choose:{message:e.message,options:e.options,as:e.as},when:e.when}:"prompt"in e&&(e.prompt===null||e.prompt===void 0)&&"message"in e&&"as"in e?{prompt:{message:e.message,as:e.as,default:e.default,validate:e.validate},when:e.when}:"parallel"in e&&Array.isArray(e.parallel)?{...e,parallel:e.parallel.map(t=>oe(t))}:s}var Z=class{parse(e){let t;try{t=(0,he.parse)(e)}catch(r){throw new Error(`Invalid YAML format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(o=>oe(o)))}try{return ee(t)}catch(r){if(r instanceof re.ZodError){let o=r.issues.map(n=>{let a=n.path.length>0?` at ${n.path.join(".")}`:"";return` - ${n.message}${a}`}).join(`
|
|
14
15
|
`);throw new Error(`Invalid workflow structure:
|
|
15
16
|
${o}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
16
|
-
`),o=0,n=!1;for(let a=0;a<r.length;a++){let i=r[a].trim();if(i==="steps:"||i.startsWith("steps:")){n=!0;continue}n&&i.startsWith("-")&&t.set(o++,a+1)}return t}},
|
|
17
|
+
`),o=0,n=!1;for(let a=0;a<r.length;a++){let i=r[a].trim();if(i==="steps:"||i.startsWith("steps:")){n=!0;continue}n&&i.startsWith("-")&&t.set(o++,a+1)}return t}},te=class{parse(e){let t;try{t=JSON.parse(e)}catch(r){throw new Error(`Invalid JSON format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(o=>oe(o)))}try{return ee(t)}catch(r){if(r instanceof re.ZodError){let o=r.issues.map(n=>{let a=n.path.length>0?` at ${n.path.join(".")}`:"";return` - ${n.message}${a}`}).join(`
|
|
17
18
|
`);throw new Error(`Invalid workflow structure:
|
|
18
19
|
${o}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
19
|
-
`),o=0,n=!1,a=!1;for(let i=0;i<r.length;i++){let c=r[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(o++,i+1)}return t}};function
|
|
20
|
+
`),o=0,n=!1,a=!1;for(let i=0;i<r.length;i++){let c=r[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(o++,i+1)}return t}};function ge(s){switch(s.toLowerCase().split(".").pop()){case"yaml":case"yml":return new Z;case"json":return new te;default:return new Z}}var He=(0,Se.promisify)(we.exec),W=new xe.Command;W.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
|
|
20
21
|
|
|
21
22
|
Define workflows in YAML or JSON files with conditional execution, parallel tasks,
|
|
22
23
|
interactive prompts, and variable substitution.
|
|
@@ -67,7 +68,7 @@ Resources:
|
|
|
67
68
|
\u{1F4DA} Documentation: https://task-pipeliner.racgoo.com/
|
|
68
69
|
\u{1F3A8} Visual Generator: https://task-pipeliner-generator.racgoo.com/
|
|
69
70
|
|
|
70
|
-
See README.md for complete DSL reference.`);
|
|
71
|
+
See README.md for complete DSL reference.`);W.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)").addHelpText("after",`
|
|
71
72
|
Examples:
|
|
72
73
|
$ tp run workflow.yaml
|
|
73
74
|
$ tp run workflow.json
|
|
@@ -89,10 +90,10 @@ Workflow File Structure:
|
|
|
89
90
|
\u2022 all/any/not: Combine conditions
|
|
90
91
|
|
|
91
92
|
Supported formats: YAML (.yaml, .yml) and JSON (.json)
|
|
92
|
-
See README.md for complete DSL documentation.`).action(async s=>{try{let e=
|
|
93
|
-
`)),await new
|
|
93
|
+
See README.md for complete DSL documentation.`).action(async s=>{try{let e=ge(s);console.log(u.default.blue(`Loading workflow from ${s}...`));let t=(0,be.readFileSync)(s,"utf-8"),r=e.parse(t);if(!r.steps||!Array.isArray(r.steps))throw new Error("Invalid workflow: steps array is required");r._lineNumbers=e.extractStepLineNumbers(t),r._fileName=Ve(s),r._filePath=(0,ye.resolve)(s),console.log(u.default.green(`Starting workflow execution...
|
|
94
|
+
`)),await new U().execute(r),console.log(u.default.green(`
|
|
94
95
|
\u2713 Workflow completed successfully`))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(u.default.red(`
|
|
95
|
-
\u2717 Workflow failed: ${t}`)),process.exit(1)}});
|
|
96
|
+
\u2717 Workflow failed: ${t}`)),process.exit(1)}});W.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
|
|
96
97
|
Examples:
|
|
97
98
|
$ tp open generator
|
|
98
99
|
$ tp open docs
|
|
@@ -101,13 +102,13 @@ Targets:
|
|
|
101
102
|
generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
|
|
102
103
|
docs Open the documentation site (https://task-pipeliner.racgoo.com/)`).action(async s=>{let t={generator:"https://task-pipeliner-generator.racgoo.com/",docs:"https://task-pipeliner.racgoo.com/"}[s.toLowerCase()];t||(console.error(u.default.red(`
|
|
103
104
|
\u2717 Invalid target: ${s}`)),console.log(u.default.yellow(`
|
|
104
|
-
Valid targets:`)),console.log(u.default.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(u.default.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,o;r==="darwin"?o=`open "${t}"`:r==="win32"?o=`start "${t}"`:o=`xdg-open "${t}"`,await
|
|
105
|
+
Valid targets:`)),console.log(u.default.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(u.default.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,o;r==="darwin"?o=`open "${t}"`:r==="win32"?o=`start "${t}"`:o=`xdg-open "${t}"`,await He(o),console.log(u.default.green(`
|
|
105
106
|
\u2713 Opening ${s==="generator"?"generator":"documentation"} in browser...`)),console.log(u.default.blue(` ${t}`))}catch(r){let o=r instanceof Error?r.message:String(r);console.error(u.default.red(`
|
|
106
107
|
\u2717 Failed to open browser: ${o}`)),console.log(u.default.yellow(`
|
|
107
|
-
Please visit manually: ${t}`)),process.exit(1)}});var
|
|
108
|
-
\u2717 Invalid choice`)),process.exit(1));let t=new
|
|
108
|
+
Please visit manually: ${t}`)),process.exit(1)}});var Oe=W.command("history").description("Manage workflow execution history");Oe.action(async()=>{let s=new T,e=await s.prompt("Select an action",[{id:"show",label:"Show - View and select a history to view"},{id:"remove",label:"Remove - Delete a specific history file"},{id:"remove-all",label:"Remove All - Delete all history files"}]);e?.id||(console.error(u.default.red(`
|
|
109
|
+
\u2717 Invalid choice`)),process.exit(1));let t=new L;switch(e.id){case"show":{let r=await t.getHistoryNames();if(r.length===0){console.log(u.default.yellow(`
|
|
109
110
|
\u26A0 No history found`));return}let o=await s.prompt("Select a history to view",r.map(n=>({id:n,label:n})));o?.id||(console.error(u.default.red(`
|
|
110
|
-
\u2717 Invalid choice`)),process.exit(1));try{let n=await t.getHistory(o.id);
|
|
111
|
+
\u2717 Invalid choice`)),process.exit(1));try{let n=await t.getHistory(o.id);_e(n,o.id)}catch(n){let a=n instanceof Error?n.message:String(n);console.error(u.default.red(`
|
|
111
112
|
\u2717 Failed to load history: ${a}`)),process.exit(1)}break}case"remove":{let r=await t.getHistoryNames();if(r.length===0){console.log(u.default.yellow(`
|
|
112
113
|
\u26A0 No history found`));return}let o=await s.prompt("Select a history to remove",r.map(n=>({id:n,label:n})));o?.id||(console.error(u.default.red(`
|
|
113
114
|
\u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(o.id),console.log(u.default.green(`
|
|
@@ -116,9 +117,9 @@ Please visit manually: ${t}`)),process.exit(1)}});var Fe=j.command("history").de
|
|
|
116
117
|
\u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(u.default.green(`
|
|
117
118
|
\u2713 All histories removed`))}catch(o){let n=o instanceof Error?o.message:String(o);console.error(u.default.red(`
|
|
118
119
|
\u2717 Failed to remove histories: ${n}`)),process.exit(1)}break}default:console.error(u.default.red(`
|
|
119
|
-
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});function
|
|
120
|
-
`);let t=s.records.reduce((c,m)=>c+m.duration,0),r=s.records.filter(c=>c.status==="success").length,o=s.records.filter(c=>c.status==="failure").length,n=(0,
|
|
121
|
-
`);console.log((0,
|
|
122
|
-
`);console.log((0,
|
|
120
|
+
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});function Ve(s){return s.split("/").pop()??s}function _e(s,e){console.log(`
|
|
121
|
+
`);let t=s.records.reduce((c,m)=>c+m.duration,0),r=s.records.filter(c=>c.status==="success").length,o=s.records.filter(c=>c.status==="failure").length,n=(0,ve.default)(s.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),i=B(t),p=[u.default.bold("Workflow Execution History"),"",`${u.default.cyan("File:")} ${e}`,`${u.default.cyan("Started:")} ${n}`,`${u.default.cyan("Total Duration:")} ${i}`,`${u.default.cyan("Total Steps:")} ${s.records.length}`,`${u.default.green("\u2713 Successful:")} ${r}`,o>0?`${u.default.red("\u2717 Failed:")} ${o}`:""].filter(Boolean).join(`
|
|
122
|
+
`);console.log((0,ne.default)(p,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderColor:"cyan"})),s.records.forEach((c,m)=>{Ye(c,m+1,s.records.length)}),console.log("")}function Ye(s,e,t){let r=Je(s.step),o=ze(s.step),n=s.status==="success"?u.default.green("\u2713"):u.default.red("\u2717"),a=s.status==="success"?u.default.green("Success"):u.default.red("Failed"),i=B(s.duration),p=[`${n} ${u.default.bold(`Step ${e}/${t}`)} - ${u.default.cyan(r)}`,`${u.default.gray("Duration:")} ${i} | ${u.default.gray("Status:")} ${a}`,"",u.default.white(o)].join(`
|
|
123
|
+
`);console.log((0,ne.default)(p,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderColor:s.status==="success"?"green":"red"})),Ue(s.output)&&Ze(s.output)}function Je(s){return"run"in s?"Run":"choose"in s?"Choose":"prompt"in s?"Prompt":"parallel"in s?"Parallel":"fail"in s?"Fail":"Unknown"}function ze(s){return"run"in s?`Command: ${u.default.yellow(s.run)}`:"choose"in s?`Message: ${u.default.yellow(s.choose.message)}`:"prompt"in s?`Message: ${u.default.yellow(s.prompt.message)} | Variable: ${u.default.cyan(s.prompt.as)}`:"parallel"in s?`Parallel execution with ${s.parallel.length} branches`:"fail"in s?`Error: ${u.default.red(s.fail.message)}`:"Unknown step type"}function Ue(s){return typeof s=="object"&&s!==null&&"success"in s&&"stdout"in s&&"stderr"in s}function Ze(s){if(s.stdout.length>0){let e=s.stdout.map(t=>u.default.gray(` ${t}`)).join(`
|
|
123
124
|
`);console.log(u.default.green(" Output:")),console.log(e)}if(s.stderr.length>0){let e=s.stderr.map(t=>u.default.gray(` ${t}`)).join(`
|
|
124
|
-
`);console.log(u.default.red(" Errors:")),console.log(e)}}
|
|
125
|
+
`);console.log(u.default.red(" Errors:")),console.log(e)}}W.parse();
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{exec as
|
|
3
|
-
`)),
|
|
4
|
-
`)),
|
|
5
|
-
`),
|
|
6
|
-
`);let
|
|
2
|
+
import{exec as Ie}from"child_process";import{readFileSync as Be}from"fs";import{resolve as De}from"path";import{promisify as je}from"util";import le from"boxen";import u from"chalk";import{Command as Le}from"commander";import Fe from"dayjs";import{resolve as oe,isAbsolute as ye,dirname as Se}from"path";import xe from"chalk";import Z from"log-update";import K from"chalk";import Q from"inquirer";var E=class{async prompt(e,t){let{choice:r}=await Q.prompt([{type:"list",name:"choice",message:K.cyan(e),choices:t.map(o=>({name:o.label,value:o.id}))}]),n=t.find(o=>o.id===r);if(!n)throw new Error(`Invalid choice: ${r}`);return n}},j=class{async prompt(e,t){let{value:r}=await Q.prompt([{type:"input",name:"value",message:K.cyan(e),default:t}]);return r}};import J from"boxen";import I from"chalk";function z(s,e,t,r={}){let{borderColor:n="cyan",isNested:o=!1}=r,a;e!==void 0&&(t?a=`line ${e} in ${t}`:a=`line ${e}`);let i=o?`\u2502 ${s}`:`> ${s}`;return J(i,{title:a,borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:n})}function P(s,e=!1,t){let r=s?"\u2713 Completed":"\u2717 Failed",n=s?I.green(r):I.red(r);if(t!==void 0){let o=M(t);return`${n} ${I.gray(`(${o})`)}`}return n}function B(s){return J(`\u2717 ${s}`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:"red"})}function ee(s){return J(`> Starting parallel execution (${s} branches)`,{borderStyle:"round",padding:{top:0,bottom:0,left:1,right:1},margin:{top:0,bottom:0},borderColor:"yellow"})}function te(s){let e=s?"\u2713 All parallel branches completed":"\u2717 Some parallel branches failed";return s?I.green(e):I.red(e)}function U(s,e=!1){return`${e?"| \u2502 ":"\u2502 "}${s}`}function M(s){return`${(s/1e3).toFixed(3)}s`}import{existsSync as ce}from"fs";import{resolve as ue}from"path";var N=class{constructor(e){this.workspace=e}evaluate(e){return"var"in e||"has"in e?this.evaluateVarExists(e):"file"in e?this.evaluateFileExists(e):"choice"in e?this.evaluateChoice(e):"all"in e?this.evaluateAll(e):"any"in e?this.evaluateAny(e):"not"in e?this.evaluateNot(e):!1}evaluateVarExists(e){if(e.has)return this.workspace.hasVariable(e.has)||this.workspace.hasFact(e.has);if(!e.var)return!1;if(typeof e.var=="object"){for(let[r,n]of Object.entries(e.var)){let o=this.workspace.getVariable(r),a=this.workspace.getFact(r),i=o??(a!==void 0?a.toString():void 0);if(i===void 0||i!==n)return!1}return!0}let t=e.var;return this.workspace.hasVariable(t)||this.workspace.hasFact(t)}evaluateFileExists(e){try{let t=e.file.trim(),r=ue(process.cwd(),t);return ce(r)}catch{return!1}}evaluateChoice(e){return this.workspace.hasChoice(e.choice)}evaluateAll(e){return e.all.every(t=>this.evaluate(t))}evaluateAny(e){return e.any.some(t=>this.evaluate(t))}evaluateNot(e){return!this.evaluate(e.not)}};import{mkdir as pe,readdir as me,readFile as fe,rm as re,writeFile as de}from"fs/promises";import{homedir as he}from"os";import{basename as ge,join as L}from"path";import we from"dayjs";var T=L(he(),".pipeliner","workflow-history"),A=class{constructor(){}async saveHistory(e){await pe(T,{recursive:!0});let t=we().format("YYYY-MM-DD_HH-mm-ss"),r=Math.random().toString(36).slice(2,6),n=L(T,`workflow-${t}-${r}.json`);return await de(n,JSON.stringify(e,null,2),{encoding:"utf8"}),n}async clearAllHistories(){await re(T,{recursive:!0,force:!0})}async removeHistory(e){await re(L(T,e),{force:!0})}async getHistoryNames(){try{let t=(await me(T)).map(r=>ge(r));return t.sort((r,n)=>{let o=p=>{let c=p.match(/workflow-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-/);return c?c[1]:""},a=o(r),i=o(n);return a===i?n.localeCompare(r):i.localeCompare(a)}),t}catch(e){if(e instanceof Error&&"code"in e&&e.code==="ENOENT")return[];throw e}}async getHistory(e){let t=await fe(L(T,e),{encoding:"utf8"});return JSON.parse(t)}};var F=class{records=[];initialTimestamp=Date.now();recordStartTimestamp=Date.now();constructor(){this.records=[]}recordStart(){this.recordStartTimestamp=Date.now()}recordEnd(e,t,r,n){let o=this.getDuration();return this.records.push({step:e,context:t,output:r,duration:o,status:n}),o}reset(){this.records=[],this.initialTimestamp=Date.now()}async save(){let e=new A,t={initialTimestamp:this.initialTimestamp,records:this.records};return await e.saveHistory(t)}getDuration(){return Date.now()-this.recordStartTimestamp}};var W=class{async run(e,t,r,n,o=!1,a=!1,i,p,c,m){return o?this.runBuffered(e,c,m):this.runRealtime(e,r||e,a,i,p,c,m)}async runBuffered(e,t,r){let{spawn:n}=await import("child_process"),[o,...a]=this.parseCommand(e),i=this.createSpawnOptions(t);return new Promise((p,c)=>{let m=n(o,a,i),h=[],f=[],d="",w="",S=null;r&&r>0&&(S=setTimeout(()=>{m.kill("SIGTERM");let g=`Command timed out after ${r} seconds`;f.push(g),p({success:!1,stdout:h,stderr:f})},r*1e3)),m.stdout?.on("data",g=>{let b=g.toString(),{lines:k,remaining:x}=this.processStreamBuffer(b,d);h.push(...k),d=x}),m.stderr?.on("data",g=>{let b=g.toString(),{lines:k,remaining:x}=this.processStreamBuffer(b,w);f.push(...k),w=x}),m.on("close",g=>{S&&clearTimeout(S),d.trim()&&h.push(d),w.trim()&&f.push(w),p({success:g===0,stdout:h,stderr:f})}),m.on("error",g=>{S&&clearTimeout(S);let b=`Error: ${g.message}`;p({success:!1,stdout:h,stderr:[...f,b]})})})}async runRealtime(e,t,r,n,o,a,i){let{spawn:p}=await import("child_process"),[c,...m]=this.parseCommand(e),h=this.createSpawnOptions(a),d=z(t,n,o,{borderColor:r?"green":"cyan"});console.log(d);let w=Date.now();return new Promise(S=>{let g=p(c,m,h),b="",k="",x=null;i&&i>0&&(x=setTimeout(()=>{g.kill("SIGTERM");let v=`Command timed out after ${i} seconds`,y=B(v);console.error(y);let C=Date.now()-w,$=P(!1,!1,C);console.log($),S(!1)},i*1e3)),g.stdout?.on("data",v=>{let y=v.toString(),{lines:C,remaining:$}=this.processStreamBuffer(y,b);C.forEach(Y=>process.stdout.write(`\u2502 ${Y}
|
|
3
|
+
`)),b=$}),g.stderr?.on("data",v=>{let y=v.toString(),{lines:C,remaining:$}=this.processStreamBuffer(y,k);C.forEach(Y=>process.stderr.write(`\u2502 ${Y}
|
|
4
|
+
`)),k=$}),g.on("close",v=>{x&&clearTimeout(x),b.trim()&&process.stdout.write(`\u2502 ${b}
|
|
5
|
+
`),k.trim()&&process.stderr.write(`\u2502 ${k}
|
|
6
|
+
`);let y=v===0,C=Date.now()-w,$=P(y,!1,C);console.log($),S(y)}),g.on("error",v=>{x&&clearTimeout(x);let y=B(`Error: ${v.message}`);console.error(y),S(!1)})})}parseCommand(e){let t=e.split(" ");return[t[0],...t.slice(1)]}createSpawnOptions(e){let t={stdio:["inherit","pipe","pipe"],shell:!0};return e&&(t.cwd=e),t}processStreamBuffer(e,t){let r=t+e,n=[],o=r;for(;o.includes(`
|
|
7
7
|
`);){let a=o.indexOf(`
|
|
8
8
|
`),i=o.substring(0,a);o=o.substring(a+1),n.push(i)}return{lines:n,remaining:o}}formatNestedOutput(e,t){t?e.split(`
|
|
9
|
-
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,n,o){let a=
|
|
10
|
-
`)}),e.stderr.forEach(p=>{let c=
|
|
11
|
-
`)});let i=
|
|
12
|
-
`)):
|
|
13
|
-
`))
|
|
9
|
+
`).forEach(r=>{r.trim()&&console.log(`| ${r}`)}):console.log(e)}displayBufferedOutput(e,t,r=!1,n,o){let a=z(t,n,o,{borderColor:"cyan",isNested:r});this.formatNestedOutput(a,r),e.stdout.forEach(p=>{let c=U(p,r);process.stdout.write(`${c}
|
|
10
|
+
`)}),e.stderr.forEach(p=>{let c=U(p,r);process.stderr.write(`${c}
|
|
11
|
+
`)});let i=P(e.success,r);console.log(i)}};function be(s,e,t){if(e.hasVariable(s))return e.getVariable(s)||t;if(e.hasFact(s)){let r=e.getFact(s);return typeof r=="string"?r:String(r)}return e.hasChoice(s)&&e.getChoice(s)||t}function H(s,e){let t=/\{\{(\w+)\}\}/g;return s.replace(t,(r,n)=>be(n,e,r))}var O=class s{state;constructor(){this.state={facts:new Map,choices:new Map,variables:new Map,stepResults:new Map,lastStepIndex:-1}}hasFact(e){return this.state.facts.has(e)}getFact(e){return this.state.facts.get(e)}setFact(e,t){this.state.facts.set(e,t)}getFactStatus(e){if(!this.hasFact(e))return"pending";let t=this.getFact(e);return t===!1||t==="failed"?"failed":"ready"}getAllFacts(){return new Map(this.state.facts)}hasChoice(e){return this.state.choices.has(e)}getChoice(e){return this.state.choices.get(e)}setChoice(e,t){this.state.choices.set(e,t)}hasVariable(e){return this.state.variables.has(e)}getVariable(e){return this.state.variables.get(e)}setVariable(e,t){this.state.variables.set(e,t)}getAllVariables(){return new Map(this.state.variables)}setStepResult(e,t,r){this.state.stepResults.set(e,{success:t,exitCode:r}),this.state.lastStepIndex=e}getStepResult(e){return this.state.stepResults.get(e)}getLastStepResult(){if(this.state.lastStepIndex!==-1)return this.state.stepResults.get(this.state.lastStepIndex)}clone(){let e=new s;return e.state.facts=new Map(this.state.facts),e.state.choices=new Map(this.state.choices),e.state.variables=new Map(this.state.variables),e.state.stepResults=new Map(this.state.stepResults),e.state.lastStepIndex=this.state.lastStepIndex,e}};var V=class s{static PARALLEL_STEP_INDEX_MULTIPLIER=1e3;workspace;taskRunner;choicePrompt;textPrompt;baseDir;constructor(){this.workspace=new O,this.taskRunner=new W,this.choicePrompt=new E,this.textPrompt=new j}resolveBaseDir(e){if(e.baseDir)if(ye(e.baseDir))this.baseDir=e.baseDir;else if(e._filePath){let t=Se(e._filePath);this.baseDir=oe(t,e.baseDir)}else this.baseDir=oe(process.cwd(),e.baseDir)}createStepContext(e,t){let r={workspace:this.workspace,stepIndex:e};return t._lineNumbers&&(r.lineNumber=t._lineNumbers.get(e)),t._fileName&&(r.fileName=t._fileName),r}evaluateStepCondition(e){return e.when?new N(this.workspace).evaluate(e.when):!0}calculateBaseStepIndex(e){return e.branchIndex===void 0?e.stepIndex:Math.floor(e.stepIndex/s.PARALLEL_STEP_INDEX_MULTIPLIER)}isRunStep(e){return"run"in e}async execute(e){this.resolveBaseDir(e);let t=new F,r=Date.now();for(let a=0;a<e.steps.length;a++){let i=e.steps[a],p=this.createStepContext(a,e),c=!!i.when;if(this.evaluateStepCondition(i)){t.recordStart();try{let m=await this.executeStep(i,p,!1,c);this.handleStepResult(i,p,a,m,t)}catch(m){throw this.handleStepError(i,p,a,m,t),m}}}let n=Date.now()-r,o=M(n);console.log(xe.cyan(`
|
|
12
|
+
Total execution time: ${o}`)),await t.save(),t.reset()}isStepSuccessful(e,t){return"run"in t?typeof e=="boolean"?e:e&&typeof e=="object"&&"success"in e?e.success:!1:!0}handleStepResult(e,t,r,n,o){let a=this.isRunStep(e)?(()=>{let c=this.workspace.getStepResult(r);return c?c.success:!0})():this.isStepSuccessful(n,e),i=a?"success":"failure",p=o.recordEnd(e,t,n,i);if(!this.isRunStep(e)){let c=P(a,!1,p);console.log(c)}if(this.isRunStep(e)){if(e.continue===!1){let c=t.lineNumber?` (line ${t.lineNumber})`:"",m=a?`Step ${r}${c} completed, but workflow stopped due to continue: false`:`Step ${r}${c} failed`;throw new Error(m)}if(!a&&e.continue!==!0){let c=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Step ${r}${c} failed`)}}}handleStepError(e,t,r,n,o){this.workspace.setStepResult(r,!1);let a=n instanceof Error?n.message:String(n),i={success:!1,stdout:[],stderr:[a]};o.recordEnd(e,t,i,"failure")}fixMalformedStep(e){let r=e;return"choose"in e&&r.choose===null&&"message"in e&&"options"in e?{choose:{message:r.message,options:r.options,as:r.as},when:r.when}:"prompt"in e&&r.prompt===null&&"message"in e&&"as"in e?{prompt:{message:r.message,as:r.as,default:r.default},when:r.when}:e}async executeStep(e,t,r=!1,n=!1){if(e=this.fixMalformedStep(e),"run"in e){let o=await this.executeRunStep(e,t,r,n);return r&&typeof o=="object"&&"stdout"in o,o}if("choose"in e){await this.executeChooseStep(e,t);return}if("prompt"in e){await this.executePromptStep(e,t);return}if("parallel"in e){await this.executeParallelStep(e,t);return}if("fail"in e){await this.executeFailStep(e,t);return}}async executeSingleRun(e,t,r=!1,n=!1){let o=this.calculateBaseStepIndex(t),a=H(e.run,this.workspace),i=e.retry??0,p=e.timeout,c=!1,m=0;for(;m<=i;){let h=await this.taskRunner.run(a,o,a,t.branchIndex,r,n,t.lineNumber,t.fileName,this.baseDir,p),f=typeof h=="boolean"?h:h.success;if(c=h,f||m>=i)break;if(m++,m<=i){let d=Math.min(1e3*Math.pow(2,m-1),1e4);await new Promise(w=>setTimeout(w,d))}}return c}async executeRunStep(e,t,r=!1,n=!1){let o=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry},t,r,n),a=typeof o=="boolean"?o:o.success;if(this.workspace.setStepResult(t.stepIndex,a),a||!e.onError)return o;let i={run:e.onError.run,timeout:e.onError.timeout,retry:e.onError.retry,onError:e.onError.onError??void 0};return await this.executeRunChain(i,t,r,n)}async executeRunChain(e,t,r,n){let o=await this.executeSingleRun({run:e.run,timeout:e.timeout,retry:e.retry},t,r,n);return(typeof o=="boolean"?o:o.success)||!e.onError?o:this.executeRunChain(e.onError,t,r,n)}async executeChooseStep(e,t){let r=await this.choicePrompt.prompt(e.choose.message,e.choose.options);if(!r?.id)throw new Error(`Invalid choice result: ${JSON.stringify(r)}`);let n=e.choose.as??r.id;this.workspace.setChoice(r.id,r.id),this.workspace.setVariable(n,r.id),this.workspace.setStepResult(t.stepIndex,!0)}async executePromptStep(e,t){let r=H(e.prompt.message,this.workspace),n=e.prompt.default?H(e.prompt.default,this.workspace):void 0,o=await this.textPrompt.prompt(r,n);this.workspace.setVariable(e.prompt.as,o),this.workspace.setFact(e.prompt.as,o),this.workspace.setStepResult(t.stepIndex,!0)}createParallelContexts(e,t){return e.parallel.map((r,n)=>({workspace:this.workspace.clone(),stepIndex:t.stepIndex*s.PARALLEL_STEP_INDEX_MULTIPLIER+n,branchIndex:n,lineNumber:t.lineNumber,fileName:t.fileName}))}getBranchDisplayName(e,t){return"run"in e?e.run:"choose"in e?`Choose: ${e.choose.message}`:"prompt"in e?`Prompt: ${e.prompt.message}`:"fail"in e?`Fail: ${e.fail.message}`:`Branch ${t+1}`}async executeParallelBranches(e,t){let r=[],n=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],o=0;for(let c=0;c<e.length;c++){let m=e[c],h=t[c];if(m.when&&!new N(h.workspace).evaluate(m.when))continue;let f=this.getBranchDisplayName(m,c);r.push({index:c,name:f,status:"pending"})}let a=setInterval(()=>{o=(o+1)%n.length,this.updateParallelBranchesDisplay(r,n[o])},100),i=r.map(async c=>{let{index:m}=c,h=e[m],f=t[m];c.status="running";try{let d=await this.executeStep(h,f,!0);return c.status="success",this.updateParallelBranchesDisplay(r,n[o]),{index:m,result:d,context:f}}catch(d){f.workspace.setStepResult(f.stepIndex,!1);let w=d instanceof Error?d.message:String(d);return c.status="failed",c.error=w,this.updateParallelBranchesDisplay(r,n[o]),{index:m,error:d,context:f}}}),p=await Promise.all(i);return clearInterval(a),this.updateParallelBranchesDisplay(r,"",!0),Z.done(),p}updateParallelBranchesDisplay(e,t,r=!1){let n=e.map(o=>{let a=o.index+1,i="",p="";switch(o.status){case"pending":i="\u25CB",p=`Branch ${a}: ${o.name} - Pending`;break;case"running":i=t,p=`Branch ${a}: ${o.name} - Running...`;break;case"success":i="\u2713",p=`Branch ${a}: ${o.name} - Completed`;break;case"failed":i="\u2717",p=`Branch ${a}: ${o.name} - Failed${o.error?`: ${o.error}`:""}`;break}return`${i} ${p}`});r?Z(n.join(`
|
|
13
|
+
`)):Z(n.join(`
|
|
14
|
+
`))}displayParallelResults(e,t,r){let n=!0,o=!1;console.log("");for(let i of e){if(!i)continue;o=!0;let{index:p,result:c,error:m,context:h}=i;if(m){n=!1;let f=`Branch ${p+1} failed: ${m instanceof Error?m.message:String(m)}`,d=B(f);console.error(d)}else if(c&&typeof c=="object"&&"stdout"in c){let f=c;if(n=n&&f.success,f.stdout.length>0||f.stderr.length>0||!f.success){let d=t[p],w=this.getBranchDisplayName(d,p);this.taskRunner.displayBufferedOutput(f,w,!1,h.lineNumber,h.fileName)}}}o||console.log("\u26A0\uFE0F All parallel branches were skipped (conditions not met)");let a=te(n);return console.log(a),n}mergeParallelResults(e){for(let t of e){let r=t.workspace.getAllFacts(),n=t.workspace.getAllVariables();for(let[o,a]of r)this.workspace.setFact(o,a);for(let[o,a]of n)this.workspace.setVariable(o,a)}}countExecutableBranches(e,t){let r=0;for(let n=0;n<e.length;n++){let o=e[n],a=t[n];o.when&&!new N(a.workspace).evaluate(o.when)||r++}return r}async executeParallelStep(e,t){let r=this.createParallelContexts(e,t),n=this.countExecutableBranches(e.parallel,r),o=ee(n);console.log(o);let a=await this.executeParallelBranches(e.parallel,r),i=this.displayParallelResults(a,e.parallel,t);if(this.workspace.setStepResult(t.stepIndex,i),!i){let p=t.lineNumber?` (line ${t.lineNumber})`:"";throw new Error(`Parallel step ${t.stepIndex}${p} failed: one or more branches failed`)}this.mergeParallelResults(r)}async executeFailStep(e,t){let r=new Error(e.fail.message);throw r.stack=void 0,r}};import{parse as Ae}from"yaml";import{ZodError as ae}from"zod";import{z as l}from"zod";var ve=l.object({file:l.string()}),ke=l.object({var:l.union([l.string(),l.record(l.string(),l.string())]).optional(),has:l.string().optional()}),Re=l.object({status:l.object({fact:l.string(),is:l.enum(["ready","failed","pending"])})}),Ce=l.object({step:l.object({success:l.boolean()}).optional(),last_step:l.enum(["success","failure"]).optional()}),$e=l.object({choice:l.string()}),Ee=l.union([ve,$e,ke,Re,Ce]),R=l.lazy(()=>l.union([Ee,l.object({all:l.array(R)}),l.object({any:l.array(R)}),l.object({not:R})])),ne=l.lazy(()=>l.object({run:l.string(),timeout:l.number().optional(),retry:l.number().optional(),onError:ne.optional()})),Pe=l.object({run:l.string(),when:R.optional(),timeout:l.number().optional(),retry:l.number().optional(),continue:l.boolean().optional(),onError:ne.optional()}),Me=l.object({choose:l.object({message:l.string(),options:l.array(l.object({id:l.string(),label:l.string()})),as:l.string().optional()}),when:R.optional()}),Ne=l.object({prompt:l.object({message:l.string(),as:l.string(),default:l.string().optional(),validate:l.string().optional()}),when:R.optional()}),se=l.lazy(()=>l.union([Pe,Me,Ne,l.object({parallel:l.array(se),when:R.optional()}),l.object({fail:l.object({message:l.string()}),when:R.optional()})])),Te=l.object({name:l.string().optional(),baseDir:l.string().optional(),steps:l.array(se).min(1,"Workflow must have at least one step")});function G(s){return Te.parse(s)}function q(s){let e=s;return"choose"in e&&(e.choose===null||e.choose===void 0)&&"message"in e&&"options"in e?{choose:{message:e.message,options:e.options,as:e.as},when:e.when}:"prompt"in e&&(e.prompt===null||e.prompt===void 0)&&"message"in e&&"as"in e?{prompt:{message:e.message,as:e.as,default:e.default,validate:e.validate},when:e.when}:"parallel"in e&&Array.isArray(e.parallel)?{...e,parallel:e.parallel.map(t=>q(t))}:s}var _=class{parse(e){let t;try{t=Ae(e)}catch(r){throw new Error(`Invalid YAML format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(n=>q(n)))}try{return G(t)}catch(r){if(r instanceof ae){let n=r.issues.map(o=>{let a=o.path.length>0?` at ${o.path.join(".")}`:"";return` - ${o.message}${a}`}).join(`
|
|
14
15
|
`);throw new Error(`Invalid workflow structure:
|
|
15
16
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
16
|
-
`),n=0,o=!1;for(let a=0;a<r.length;a++){let i=r[a].trim();if(i==="steps:"||i.startsWith("steps:")){o=!0;continue}o&&i.startsWith("-")&&t.set(n++,a+1)}return t}},
|
|
17
|
+
`),n=0,o=!1;for(let a=0;a<r.length;a++){let i=r[a].trim();if(i==="steps:"||i.startsWith("steps:")){o=!0;continue}o&&i.startsWith("-")&&t.set(n++,a+1)}return t}},X=class{parse(e){let t;try{t=JSON.parse(e)}catch(r){throw new Error(`Invalid JSON format: ${r instanceof Error?r.message:String(r)}`)}if(t&&typeof t=="object"&&"steps"in t){let r=t;Array.isArray(r.steps)&&(r.steps=r.steps.map(n=>q(n)))}try{return G(t)}catch(r){if(r instanceof ae){let n=r.issues.map(o=>{let a=o.path.length>0?` at ${o.path.join(".")}`:"";return` - ${o.message}${a}`}).join(`
|
|
17
18
|
`);throw new Error(`Invalid workflow structure:
|
|
18
19
|
${n}`)}throw r}}extractStepLineNumbers(e){let t=new Map,r=e.split(`
|
|
19
|
-
`),n=0,o=!1,a=!1;for(let i=0;i<r.length;i++){let c=r[i].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){o=!0,c.includes("[")&&(a=!0);continue}if(o&&c==="["){a=!0;continue}if(a&&c==="]"){a=!1,o=!1;continue}a&&c.startsWith("{")&&t.set(n++,i+1)}return t}};function
|
|
20
|
+
`),n=0,o=!1,a=!1;for(let i=0;i<r.length;i++){let c=r[i].trim();if(c.startsWith('"steps"')||c.startsWith("'steps'")){o=!0,c.includes("[")&&(a=!0);continue}if(o&&c==="["){a=!0;continue}if(a&&c==="]"){a=!1,o=!1;continue}a&&c.startsWith("{")&&t.set(n++,i+1)}return t}};function ie(s){switch(s.toLowerCase().split(".").pop()){case"yaml":case"yml":return new _;case"json":return new X;default:return new _}}var We=je(Ie),D=new Le;D.name("task-pipeliner").description(`A powerful task pipeline runner with condition-based workflow execution.
|
|
20
21
|
|
|
21
22
|
Define workflows in YAML or JSON files with conditional execution, parallel tasks,
|
|
22
23
|
interactive prompts, and variable substitution.
|
|
@@ -67,7 +68,7 @@ Resources:
|
|
|
67
68
|
\u{1F4DA} Documentation: https://task-pipeliner.racgoo.com/
|
|
68
69
|
\u{1F3A8} Visual Generator: https://task-pipeliner-generator.racgoo.com/
|
|
69
70
|
|
|
70
|
-
See README.md for complete DSL reference.`);
|
|
71
|
+
See README.md for complete DSL reference.`);D.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)").addHelpText("after",`
|
|
71
72
|
Examples:
|
|
72
73
|
$ tp run workflow.yaml
|
|
73
74
|
$ tp run workflow.json
|
|
@@ -89,10 +90,10 @@ Workflow File Structure:
|
|
|
89
90
|
\u2022 all/any/not: Combine conditions
|
|
90
91
|
|
|
91
92
|
Supported formats: YAML (.yaml, .yml) and JSON (.json)
|
|
92
|
-
See README.md for complete DSL documentation.`).action(async s=>{try{let e=
|
|
93
|
-
`)),await new
|
|
93
|
+
See README.md for complete DSL documentation.`).action(async s=>{try{let e=ie(s);console.log(u.blue(`Loading workflow from ${s}...`));let t=Be(s,"utf-8"),r=e.parse(t);if(!r.steps||!Array.isArray(r.steps))throw new Error("Invalid workflow: steps array is required");r._lineNumbers=e.extractStepLineNumbers(t),r._fileName=Oe(s),r._filePath=De(s),console.log(u.green(`Starting workflow execution...
|
|
94
|
+
`)),await new V().execute(r),console.log(u.green(`
|
|
94
95
|
\u2713 Workflow completed successfully`))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(u.red(`
|
|
95
|
-
\u2717 Workflow failed: ${t}`)),process.exit(1)}});
|
|
96
|
+
\u2717 Workflow failed: ${t}`)),process.exit(1)}});D.command("open").description("Open generator or docs website in browser").argument("<target>",'Target to open: "generator" or "docs"').addHelpText("after",`
|
|
96
97
|
Examples:
|
|
97
98
|
$ tp open generator
|
|
98
99
|
$ tp open docs
|
|
@@ -101,13 +102,13 @@ Targets:
|
|
|
101
102
|
generator Open the visual workflow generator (https://task-pipeliner-generator.racgoo.com/)
|
|
102
103
|
docs Open the documentation site (https://task-pipeliner.racgoo.com/)`).action(async s=>{let t={generator:"https://task-pipeliner-generator.racgoo.com/",docs:"https://task-pipeliner.racgoo.com/"}[s.toLowerCase()];t||(console.error(u.red(`
|
|
103
104
|
\u2717 Invalid target: ${s}`)),console.log(u.yellow(`
|
|
104
|
-
Valid targets:`)),console.log(u.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(u.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,n;r==="darwin"?n=`open "${t}"`:r==="win32"?n=`start "${t}"`:n=`xdg-open "${t}"`,await
|
|
105
|
+
Valid targets:`)),console.log(u.yellow(" \u2022 generator - Open the visual workflow generator")),console.log(u.yellow(" \u2022 docs - Open the documentation site")),process.exit(1));try{let r=process.platform,n;r==="darwin"?n=`open "${t}"`:r==="win32"?n=`start "${t}"`:n=`xdg-open "${t}"`,await We(n),console.log(u.green(`
|
|
105
106
|
\u2713 Opening ${s==="generator"?"generator":"documentation"} in browser...`)),console.log(u.blue(` ${t}`))}catch(r){let n=r instanceof Error?r.message:String(r);console.error(u.red(`
|
|
106
107
|
\u2717 Failed to open browser: ${n}`)),console.log(u.yellow(`
|
|
107
|
-
Please visit manually: ${t}`)),process.exit(1)}});var
|
|
108
|
-
\u2717 Invalid choice`)),process.exit(1));let t=new
|
|
108
|
+
Please visit manually: ${t}`)),process.exit(1)}});var He=D.command("history").description("Manage workflow execution history");He.action(async()=>{let s=new E,e=await s.prompt("Select an action",[{id:"show",label:"Show - View and select a history to view"},{id:"remove",label:"Remove - Delete a specific history file"},{id:"remove-all",label:"Remove All - Delete all history files"}]);e?.id||(console.error(u.red(`
|
|
109
|
+
\u2717 Invalid choice`)),process.exit(1));let t=new A;switch(e.id){case"show":{let r=await t.getHistoryNames();if(r.length===0){console.log(u.yellow(`
|
|
109
110
|
\u26A0 No history found`));return}let n=await s.prompt("Select a history to view",r.map(o=>({id:o,label:o})));n?.id||(console.error(u.red(`
|
|
110
|
-
\u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);
|
|
111
|
+
\u2717 Invalid choice`)),process.exit(1));try{let o=await t.getHistory(n.id);Ve(o,n.id)}catch(o){let a=o instanceof Error?o.message:String(o);console.error(u.red(`
|
|
111
112
|
\u2717 Failed to load history: ${a}`)),process.exit(1)}break}case"remove":{let r=await t.getHistoryNames();if(r.length===0){console.log(u.yellow(`
|
|
112
113
|
\u26A0 No history found`));return}let n=await s.prompt("Select a history to remove",r.map(o=>({id:o,label:o})));n?.id||(console.error(u.red(`
|
|
113
114
|
\u2717 Invalid choice`)),process.exit(1));try{await t.removeHistory(n.id),console.log(u.green(`
|
|
@@ -116,9 +117,9 @@ Please visit manually: ${t}`)),process.exit(1)}});var Le=N.command("history").de
|
|
|
116
117
|
\u2717 Cancelled`));return}try{await t.clearAllHistories(),console.log(u.green(`
|
|
117
118
|
\u2713 All histories removed`))}catch(n){let o=n instanceof Error?n.message:String(n);console.error(u.red(`
|
|
118
119
|
\u2717 Failed to remove histories: ${o}`)),process.exit(1)}break}default:console.error(u.red(`
|
|
119
|
-
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});function
|
|
120
|
-
`);let t=s.records.reduce((c,m)=>c+m.duration,0),r=s.records.filter(c=>c.status==="success").length,n=s.records.filter(c=>c.status==="failure").length,o=
|
|
121
|
-
`);console.log(
|
|
122
|
-
`);console.log(
|
|
120
|
+
\u2717 Unknown action: ${e.id}`)),process.exit(1)}});function Oe(s){return s.split("/").pop()??s}function Ve(s,e){console.log(`
|
|
121
|
+
`);let t=s.records.reduce((c,m)=>c+m.duration,0),r=s.records.filter(c=>c.status==="success").length,n=s.records.filter(c=>c.status==="failure").length,o=Fe(s.initialTimestamp).format("YYYY-MM-DD HH:mm:ss"),i=M(t),p=[u.bold("Workflow Execution History"),"",`${u.cyan("File:")} ${e}`,`${u.cyan("Started:")} ${o}`,`${u.cyan("Total Duration:")} ${i}`,`${u.cyan("Total Steps:")} ${s.records.length}`,`${u.green("\u2713 Successful:")} ${r}`,n>0?`${u.red("\u2717 Failed:")} ${n}`:""].filter(Boolean).join(`
|
|
122
|
+
`);console.log(le(p,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderColor:"cyan"})),s.records.forEach((c,m)=>{_e(c,m+1,s.records.length)}),console.log("")}function _e(s,e,t){let r=Ye(s.step),n=Je(s.step),o=s.status==="success"?u.green("\u2713"):u.red("\u2717"),a=s.status==="success"?u.green("Success"):u.red("Failed"),i=M(s.duration),p=[`${o} ${u.bold(`Step ${e}/${t}`)} - ${u.cyan(r)}`,`${u.gray("Duration:")} ${i} | ${u.gray("Status:")} ${a}`,"",u.white(n)].join(`
|
|
123
|
+
`);console.log(le(p,{borderStyle:"round",padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderColor:s.status==="success"?"green":"red"})),ze(s.output)&&Ue(s.output)}function Ye(s){return"run"in s?"Run":"choose"in s?"Choose":"prompt"in s?"Prompt":"parallel"in s?"Parallel":"fail"in s?"Fail":"Unknown"}function Je(s){return"run"in s?`Command: ${u.yellow(s.run)}`:"choose"in s?`Message: ${u.yellow(s.choose.message)}`:"prompt"in s?`Message: ${u.yellow(s.prompt.message)} | Variable: ${u.cyan(s.prompt.as)}`:"parallel"in s?`Parallel execution with ${s.parallel.length} branches`:"fail"in s?`Error: ${u.red(s.fail.message)}`:"Unknown step type"}function ze(s){return typeof s=="object"&&s!==null&&"success"in s&&"stdout"in s&&"stderr"in s}function Ue(s){if(s.stdout.length>0){let e=s.stdout.map(t=>u.gray(` ${t}`)).join(`
|
|
123
124
|
`);console.log(u.green(" Output:")),console.log(e)}if(s.stderr.length>0){let e=s.stderr.map(t=>u.gray(` ${t}`)).join(`
|
|
124
|
-
`);console.log(u.red(" Errors:")),console.log(e)}}
|
|
125
|
+
`);console.log(u.red(" Errors:")),console.log(e)}}D.parse();
|