task-pipeliner 0.1.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.
Files changed (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +1034 -0
  3. package/README.md +1031 -0
  4. package/dist/cli/index.d.ts +19 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +147 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/cli/prompts.d.ts +48 -0
  9. package/dist/cli/prompts.d.ts.map +1 -0
  10. package/dist/cli/prompts.js +75 -0
  11. package/dist/cli/prompts.js.map +1 -0
  12. package/dist/cli/ui.d.ts +39 -0
  13. package/dist/cli/ui.d.ts.map +1 -0
  14. package/dist/cli/ui.js +84 -0
  15. package/dist/cli/ui.js.map +1 -0
  16. package/dist/core/__tests__/actual-execution.test.d.ts +2 -0
  17. package/dist/core/__tests__/actual-execution.test.d.ts.map +1 -0
  18. package/dist/core/__tests__/actual-execution.test.js +140 -0
  19. package/dist/core/__tests__/actual-execution.test.js.map +1 -0
  20. package/dist/core/__tests__/base-dir.test.d.ts +2 -0
  21. package/dist/core/__tests__/base-dir.test.d.ts.map +1 -0
  22. package/dist/core/__tests__/base-dir.test.js +146 -0
  23. package/dist/core/__tests__/base-dir.test.js.map +1 -0
  24. package/dist/core/__tests__/built-code-execution.test.d.ts +2 -0
  25. package/dist/core/__tests__/built-code-execution.test.d.ts.map +1 -0
  26. package/dist/core/__tests__/built-code-execution.test.js +48 -0
  27. package/dist/core/__tests__/built-code-execution.test.js.map +1 -0
  28. package/dist/core/__tests__/choose-as-var-condition.test.d.ts +2 -0
  29. package/dist/core/__tests__/choose-as-var-condition.test.d.ts.map +1 -0
  30. package/dist/core/__tests__/choose-as-var-condition.test.js +308 -0
  31. package/dist/core/__tests__/choose-as-var-condition.test.js.map +1 -0
  32. package/dist/core/__tests__/cli-integration.test.d.ts +2 -0
  33. package/dist/core/__tests__/cli-integration.test.d.ts.map +1 -0
  34. package/dist/core/__tests__/cli-integration.test.js +83 -0
  35. package/dist/core/__tests__/cli-integration.test.js.map +1 -0
  36. package/dist/core/__tests__/comprehensive-basic-yaml.test.d.ts +2 -0
  37. package/dist/core/__tests__/comprehensive-basic-yaml.test.d.ts.map +1 -0
  38. package/dist/core/__tests__/comprehensive-basic-yaml.test.js +111 -0
  39. package/dist/core/__tests__/comprehensive-basic-yaml.test.js.map +1 -0
  40. package/dist/core/__tests__/condition-evaluator.test.d.ts +2 -0
  41. package/dist/core/__tests__/condition-evaluator.test.d.ts.map +1 -0
  42. package/dist/core/__tests__/condition-evaluator.test.js +170 -0
  43. package/dist/core/__tests__/condition-evaluator.test.js.map +1 -0
  44. package/dist/core/__tests__/debug-basic-yaml.test.d.ts +2 -0
  45. package/dist/core/__tests__/debug-basic-yaml.test.d.ts.map +1 -0
  46. package/dist/core/__tests__/debug-basic-yaml.test.js +128 -0
  47. package/dist/core/__tests__/debug-basic-yaml.test.js.map +1 -0
  48. package/dist/core/__tests__/example-files.test.d.ts +2 -0
  49. package/dist/core/__tests__/example-files.test.d.ts.map +1 -0
  50. package/dist/core/__tests__/example-files.test.js +200 -0
  51. package/dist/core/__tests__/example-files.test.js.map +1 -0
  52. package/dist/core/__tests__/executor-choice-integration.test.d.ts +2 -0
  53. package/dist/core/__tests__/executor-choice-integration.test.d.ts.map +1 -0
  54. package/dist/core/__tests__/executor-choice-integration.test.js +171 -0
  55. package/dist/core/__tests__/executor-choice-integration.test.js.map +1 -0
  56. package/dist/core/__tests__/executor-choice.test.d.ts +2 -0
  57. package/dist/core/__tests__/executor-choice.test.d.ts.map +1 -0
  58. package/dist/core/__tests__/executor-choice.test.js +174 -0
  59. package/dist/core/__tests__/executor-choice.test.js.map +1 -0
  60. package/dist/core/__tests__/executor-parallel.test.d.ts +2 -0
  61. package/dist/core/__tests__/executor-parallel.test.d.ts.map +1 -0
  62. package/dist/core/__tests__/executor-parallel.test.js +136 -0
  63. package/dist/core/__tests__/executor-parallel.test.js.map +1 -0
  64. package/dist/core/__tests__/executor-prompt.test.d.ts +2 -0
  65. package/dist/core/__tests__/executor-prompt.test.d.ts.map +1 -0
  66. package/dist/core/__tests__/executor-prompt.test.js +149 -0
  67. package/dist/core/__tests__/executor-prompt.test.js.map +1 -0
  68. package/dist/core/__tests__/executor-real-scenario.test.d.ts +2 -0
  69. package/dist/core/__tests__/executor-real-scenario.test.d.ts.map +1 -0
  70. package/dist/core/__tests__/executor-real-scenario.test.js +169 -0
  71. package/dist/core/__tests__/executor-real-scenario.test.js.map +1 -0
  72. package/dist/core/__tests__/file-condition.test.d.ts +2 -0
  73. package/dist/core/__tests__/file-condition.test.d.ts.map +1 -0
  74. package/dist/core/__tests__/file-condition.test.js +182 -0
  75. package/dist/core/__tests__/file-condition.test.js.map +1 -0
  76. package/dist/core/__tests__/final-verification.test.d.ts +2 -0
  77. package/dist/core/__tests__/final-verification.test.d.ts.map +1 -0
  78. package/dist/core/__tests__/final-verification.test.js +59 -0
  79. package/dist/core/__tests__/final-verification.test.js.map +1 -0
  80. package/dist/core/__tests__/parallel-when-condition.test.d.ts +2 -0
  81. package/dist/core/__tests__/parallel-when-condition.test.d.ts.map +1 -0
  82. package/dist/core/__tests__/parallel-when-condition.test.js +155 -0
  83. package/dist/core/__tests__/parallel-when-condition.test.js.map +1 -0
  84. package/dist/core/__tests__/parser.test.d.ts +2 -0
  85. package/dist/core/__tests__/parser.test.d.ts.map +1 -0
  86. package/dist/core/__tests__/parser.test.js +94 -0
  87. package/dist/core/__tests__/parser.test.js.map +1 -0
  88. package/dist/core/__tests__/real-inquirer-test.test.d.ts +2 -0
  89. package/dist/core/__tests__/real-inquirer-test.test.d.ts.map +1 -0
  90. package/dist/core/__tests__/real-inquirer-test.test.js +20 -0
  91. package/dist/core/__tests__/real-inquirer-test.test.js.map +1 -0
  92. package/dist/core/__tests__/reproduce-bug.test.d.ts +2 -0
  93. package/dist/core/__tests__/reproduce-bug.test.d.ts.map +1 -0
  94. package/dist/core/__tests__/reproduce-bug.test.js +84 -0
  95. package/dist/core/__tests__/reproduce-bug.test.js.map +1 -0
  96. package/dist/core/__tests__/timeout-retry.test.d.ts +2 -0
  97. package/dist/core/__tests__/timeout-retry.test.d.ts.map +1 -0
  98. package/dist/core/__tests__/timeout-retry.test.js +184 -0
  99. package/dist/core/__tests__/timeout-retry.test.js.map +1 -0
  100. package/dist/core/__tests__/workflow-validation.test.d.ts +2 -0
  101. package/dist/core/__tests__/workflow-validation.test.d.ts.map +1 -0
  102. package/dist/core/__tests__/workflow-validation.test.js +120 -0
  103. package/dist/core/__tests__/workflow-validation.test.js.map +1 -0
  104. package/dist/core/__tests__/workspace.test.d.ts +2 -0
  105. package/dist/core/__tests__/workspace.test.d.ts.map +1 -0
  106. package/dist/core/__tests__/workspace.test.js +29 -0
  107. package/dist/core/__tests__/workspace.test.js.map +1 -0
  108. package/dist/core/__tests__/yaml-integration.test.d.ts +2 -0
  109. package/dist/core/__tests__/yaml-integration.test.d.ts.map +1 -0
  110. package/dist/core/__tests__/yaml-integration.test.js +114 -0
  111. package/dist/core/__tests__/yaml-integration.test.js.map +1 -0
  112. package/dist/core/__tests__/yaml-scenarios.test.d.ts +2 -0
  113. package/dist/core/__tests__/yaml-scenarios.test.d.ts.map +1 -0
  114. package/dist/core/__tests__/yaml-scenarios.test.js +199 -0
  115. package/dist/core/__tests__/yaml-scenarios.test.js.map +1 -0
  116. package/dist/core/condition-evaluator.d.ts +44 -0
  117. package/dist/core/condition-evaluator.d.ts.map +1 -0
  118. package/dist/core/condition-evaluator.js +121 -0
  119. package/dist/core/condition-evaluator.js.map +1 -0
  120. package/dist/core/executor.d.ts +172 -0
  121. package/dist/core/executor.d.ts.map +1 -0
  122. package/dist/core/executor.js +579 -0
  123. package/dist/core/executor.js.map +1 -0
  124. package/dist/core/parser.d.ts +41 -0
  125. package/dist/core/parser.d.ts.map +1 -0
  126. package/dist/core/parser.js +202 -0
  127. package/dist/core/parser.js.map +1 -0
  128. package/dist/core/rust-task-runner.d.ts +14 -0
  129. package/dist/core/rust-task-runner.d.ts.map +1 -0
  130. package/dist/core/rust-task-runner.js +34 -0
  131. package/dist/core/rust-task-runner.js.map +1 -0
  132. package/dist/core/task-runner.d.ts +63 -0
  133. package/dist/core/task-runner.d.ts.map +1 -0
  134. package/dist/core/task-runner.js +252 -0
  135. package/dist/core/task-runner.js.map +1 -0
  136. package/dist/core/template.d.ts +11 -0
  137. package/dist/core/template.d.ts.map +1 -0
  138. package/dist/core/template.js +36 -0
  139. package/dist/core/template.js.map +1 -0
  140. package/dist/core/workflow-schema.d.ts +31 -0
  141. package/dist/core/workflow-schema.d.ts.map +1 -0
  142. package/dist/core/workflow-schema.js +125 -0
  143. package/dist/core/workflow-schema.js.map +1 -0
  144. package/dist/core/workspace.d.ts +90 -0
  145. package/dist/core/workspace.d.ts.map +1 -0
  146. package/dist/core/workspace.js +143 -0
  147. package/dist/core/workspace.js.map +1 -0
  148. package/dist/index.d.ts +10 -0
  149. package/dist/index.d.ts.map +1 -0
  150. package/dist/index.js +10 -0
  151. package/dist/index.js.map +1 -0
  152. package/dist/task-pipeliner-rs.node +0 -0
  153. package/dist/types/condition.d.ts +62 -0
  154. package/dist/types/condition.d.ts.map +1 -0
  155. package/dist/types/condition.js +6 -0
  156. package/dist/types/condition.js.map +1 -0
  157. package/dist/types/workflow.d.ts +69 -0
  158. package/dist/types/workflow.d.ts.map +1 -0
  159. package/dist/types/workflow.js +2 -0
  160. package/dist/types/workflow.js.map +1 -0
  161. package/package.json +67 -0
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Workflow Parser
3
+ *
4
+ * Supports both YAML and JSON format workflow files.
5
+ * Uses polymorphism to handle different file formats.
6
+ * Validates parsed data using Zod schemas for type safety.
7
+ */
8
+ import { parse } from 'yaml';
9
+ import { ZodError } from 'zod';
10
+ import { validateWorkflow } from './workflow-schema.js';
11
+ /**
12
+ * Fix malformed step (YAML indentation issue)
13
+ * When choose/prompt is null but properties exist at step level
14
+ * This happens when YAML is incorrectly indented
15
+ */
16
+ function fixMalformedStep(step) {
17
+ const stepAsRecord = step;
18
+ // Fix malformed choose structure
19
+ if ('choose' in stepAsRecord &&
20
+ (stepAsRecord.choose === null || stepAsRecord.choose === undefined) &&
21
+ 'message' in stepAsRecord &&
22
+ 'options' in stepAsRecord) {
23
+ return {
24
+ choose: {
25
+ message: stepAsRecord.message,
26
+ options: stepAsRecord.options,
27
+ as: stepAsRecord.as,
28
+ },
29
+ when: stepAsRecord.when,
30
+ };
31
+ }
32
+ // Fix malformed prompt structure
33
+ if ('prompt' in stepAsRecord &&
34
+ (stepAsRecord.prompt === null || stepAsRecord.prompt === undefined) &&
35
+ 'message' in stepAsRecord &&
36
+ 'as' in stepAsRecord) {
37
+ return {
38
+ prompt: {
39
+ message: stepAsRecord.message,
40
+ as: stepAsRecord.as,
41
+ default: stepAsRecord.default,
42
+ validate: stepAsRecord.validate,
43
+ },
44
+ when: stepAsRecord.when,
45
+ };
46
+ }
47
+ // Fix malformed parallel steps
48
+ if ('parallel' in stepAsRecord && Array.isArray(stepAsRecord.parallel)) {
49
+ return {
50
+ ...stepAsRecord,
51
+ parallel: stepAsRecord.parallel.map((subStep) => fixMalformedStep(subStep)),
52
+ };
53
+ }
54
+ return step;
55
+ }
56
+ /**
57
+ * YAML Parser
58
+ */
59
+ export class YAMLParser {
60
+ parse(content) {
61
+ let parsed;
62
+ try {
63
+ parsed = parse(content);
64
+ }
65
+ catch (error) {
66
+ throw new Error(`Invalid YAML format: ${error instanceof Error ? error.message : String(error)}`);
67
+ }
68
+ // Fix malformed steps before validation
69
+ if (parsed && typeof parsed === 'object' && 'steps' in parsed) {
70
+ const workflow = parsed;
71
+ if (Array.isArray(workflow.steps)) {
72
+ workflow.steps = workflow.steps.map(step => fixMalformedStep(step));
73
+ }
74
+ }
75
+ // Validate using Zod schema
76
+ try {
77
+ const validated = validateWorkflow(parsed);
78
+ return validated;
79
+ }
80
+ catch (error) {
81
+ if (error instanceof ZodError) {
82
+ // Zod validation error
83
+ const issues = error.issues.map((issue) => {
84
+ const path = issue.path.length > 0 ? ` at ${issue.path.join('.')}` : '';
85
+ return ` - ${issue.message}${path}`;
86
+ }).join('\n');
87
+ throw new Error(`Invalid workflow structure:\n${issues}`);
88
+ }
89
+ throw error;
90
+ }
91
+ }
92
+ extractStepLineNumbers(content) {
93
+ const lineNumbers = new Map();
94
+ const lines = content.split('\n');
95
+ let stepIndex = 0;
96
+ let inSteps = false; // Track if we're inside the "steps:" section
97
+ for (let i = 0; i < lines.length; i++) {
98
+ const trimmed = lines[i].trim();
99
+ // Found the "steps:" section
100
+ if (trimmed === 'steps:' || trimmed.startsWith('steps:')) {
101
+ inSteps = true;
102
+ continue;
103
+ }
104
+ // Found a step (line starting with "-")
105
+ if (inSteps && trimmed.startsWith('-')) {
106
+ lineNumbers.set(stepIndex++, i + 1); // i+1 because line numbers are 1-based
107
+ }
108
+ }
109
+ return lineNumbers;
110
+ }
111
+ }
112
+ /**
113
+ * JSON Parser
114
+ */
115
+ export class JSONParser {
116
+ parse(content) {
117
+ let parsed;
118
+ try {
119
+ parsed = JSON.parse(content);
120
+ }
121
+ catch (error) {
122
+ throw new Error(`Invalid JSON format: ${error instanceof Error ? error.message : String(error)}`);
123
+ }
124
+ // Fix malformed steps before validation
125
+ if (parsed && typeof parsed === 'object' && 'steps' in parsed) {
126
+ const workflow = parsed;
127
+ if (Array.isArray(workflow.steps)) {
128
+ workflow.steps = workflow.steps.map(step => fixMalformedStep(step));
129
+ }
130
+ }
131
+ // Validate using Zod schema
132
+ try {
133
+ const validated = validateWorkflow(parsed);
134
+ return validated;
135
+ }
136
+ catch (error) {
137
+ if (error instanceof ZodError) {
138
+ // Zod validation error
139
+ const issues = error.issues.map((issue) => {
140
+ const path = issue.path.length > 0 ? ` at ${issue.path.join('.')}` : '';
141
+ return ` - ${issue.message}${path}`;
142
+ }).join('\n');
143
+ throw new Error(`Invalid workflow structure:\n${issues}`);
144
+ }
145
+ throw error;
146
+ }
147
+ }
148
+ extractStepLineNumbers(content) {
149
+ const lineNumbers = new Map();
150
+ const lines = content.split('\n');
151
+ let stepIndex = 0;
152
+ let inSteps = false;
153
+ let inStepsArray = false;
154
+ for (let i = 0; i < lines.length; i++) {
155
+ const line = lines[i];
156
+ const trimmed = line.trim();
157
+ // Found "steps" property
158
+ if (trimmed.startsWith('"steps"') || trimmed.startsWith("'steps'")) {
159
+ inSteps = true;
160
+ // Check if it's an array start on the same line
161
+ if (trimmed.includes('[')) {
162
+ inStepsArray = true;
163
+ }
164
+ continue;
165
+ }
166
+ // Found array start after "steps"
167
+ if (inSteps && trimmed === '[') {
168
+ inStepsArray = true;
169
+ continue;
170
+ }
171
+ // Found array end
172
+ if (inStepsArray && trimmed === ']') {
173
+ inStepsArray = false;
174
+ inSteps = false;
175
+ continue;
176
+ }
177
+ // Found a step object (starts with "{" and we're in steps array)
178
+ if (inStepsArray && trimmed.startsWith('{')) {
179
+ lineNumbers.set(stepIndex++, i + 1);
180
+ }
181
+ }
182
+ return lineNumbers;
183
+ }
184
+ }
185
+ /**
186
+ * Get appropriate parser based on file extension
187
+ */
188
+ export function getParser(filePath) {
189
+ const ext = filePath.toLowerCase().split('.').pop();
190
+ switch (ext) {
191
+ case 'yaml':
192
+ case 'yml':
193
+ return new YAMLParser();
194
+ case 'json':
195
+ return new JSONParser();
196
+ default:
197
+ // Default to YAML if extension is not recognized
198
+ // This maintains backward compatibility
199
+ return new YAMLParser();
200
+ }
201
+ }
202
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Rust Task Runner Module
3
+ * Directly imports Rust NAPI module (auto-generated by @napi-rs/cli)
4
+ */
5
+ interface RustTaskRunnerModule {
6
+ runTask(command: string): Promise<boolean>;
7
+ runTaskSync(command: string): boolean;
8
+ }
9
+ /**
10
+ * Load Rust module (dynamically require .node file in ESM)
11
+ */
12
+ export declare function loadRustModule(): Promise<RustTaskRunnerModule | null>;
13
+ export {};
14
+ //# sourceMappingURL=rust-task-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rust-task-runner.d.ts","sourceRoot":"","sources":["../../src/core/rust-task-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,UAAU,oBAAoB;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACvC;AAID;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA4B3E"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Rust Task Runner Module
3
+ * Directly imports Rust NAPI module (auto-generated by @napi-rs/cli)
4
+ */
5
+ let rustModule = null;
6
+ /**
7
+ * Load Rust module (dynamically require .node file in ESM)
8
+ */
9
+ export async function loadRustModule() {
10
+ if (rustModule) {
11
+ return rustModule;
12
+ }
13
+ try {
14
+ const path = await import('path');
15
+ const { fileURLToPath } = await import('url');
16
+ const { createRequire } = await import('module');
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+ const nodePath = path.resolve(__dirname, '../task-pipeliner-rs.node');
20
+ // Use require to load .node file in ESM
21
+ const require = createRequire(import.meta.url);
22
+ const module = require(nodePath);
23
+ if (module && 'runTask' in module) {
24
+ rustModule = module;
25
+ return rustModule;
26
+ }
27
+ }
28
+ catch (_error) {
29
+ // Return null if Rust module not found (use fallback)
30
+ return null;
31
+ }
32
+ return null;
33
+ }
34
+ //# sourceMappingURL=rust-task-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rust-task-runner.js","sourceRoot":"","sources":["../../src/core/rust-task-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,IAAI,UAAU,GAAgC,IAAI,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEjD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,2BAA2B,CAAC,CAAC;QAEtE,wCAAwC;QACxC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEjC,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;YAClC,UAAU,GAAG,MAA8B,CAAC;YAC5C,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,sDAAsD;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,63 @@
1
+ export interface TaskRunResult {
2
+ success: boolean;
3
+ stdout: string[];
4
+ stderr: string[];
5
+ }
6
+ export declare class TaskRunner {
7
+ /**
8
+ * Run a task command with box-style output streaming
9
+ *
10
+ * @param command - Shell command to execute
11
+ * @param stepIndex - Step index in workflow (for tracking)
12
+ * @param stepName - Display name for the step
13
+ * @param branchIndex - Branch index for parallel execution
14
+ * @param bufferOutput - If true, collect output instead of displaying immediately
15
+ * @param hasCondition - If true, step has a condition (affects border color)
16
+ * @param lineNumber - Line number in YAML file (for error reporting)
17
+ * @param fileName - YAML file name (for error reporting)
18
+ * @param cwd - Working directory for command execution
19
+ * @param timeout - Timeout in seconds (optional)
20
+ */
21
+ run(command: string, stepIndex?: number, stepName?: string, branchIndex?: number, bufferOutput?: boolean, hasCondition?: boolean, lineNumber?: number, fileName?: string, cwd?: string, timeout?: number): Promise<boolean | TaskRunResult>;
22
+ /**
23
+ * Run command in buffered mode (collect all output for later display)
24
+ * Used for parallel execution where we need to collect output first
25
+ */
26
+ private runBuffered;
27
+ /**
28
+ * Run command in real-time mode (output immediately as it happens)
29
+ */
30
+ private runRealtime;
31
+ /**
32
+ * Parse command string into command and arguments
33
+ */
34
+ private parseCommand;
35
+ /**
36
+ * Create spawn options with optional working directory
37
+ */
38
+ private createSpawnOptions;
39
+ /**
40
+ * Process stream buffer and extract complete lines
41
+ *
42
+ * Command output comes in chunks, not necessarily line-by-line.
43
+ * This function:
44
+ * 1. Combines new chunk with existing buffer
45
+ * 2. Extracts all complete lines (ending with \n)
46
+ * 3. Keeps incomplete line in buffer for next chunk
47
+ *
48
+ * Example:
49
+ * - Buffer: "Hello "
50
+ * - Chunk: "World\nHow are"
51
+ * - Result: lines=["Hello World"], remaining="How are"
52
+ */
53
+ private processStreamBuffer;
54
+ /**
55
+ * Format nested output (add | prefix for nested display)
56
+ */
57
+ private formatNestedOutput;
58
+ /**
59
+ * Display buffered output in box format (for parallel execution, nested display)
60
+ */
61
+ displayBufferedOutput(result: TaskRunResult, stepName: string, isNested?: boolean, lineNumber?: number, fileName?: string): void;
62
+ }
63
+ //# sourceMappingURL=task-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-runner.d.ts","sourceRoot":"","sources":["../../src/core/task-runner.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAQD,qBAAa,UAAU;IACrB;;;;;;;;;;;;;OAaG;IACG,GAAG,CACP,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,GAAE,OAAe,EAC7B,YAAY,GAAE,OAAe,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,EACjB,GAAG,CAAC,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,GAAG,aAAa,CAAC;IAWnC;;;OAGG;YACW,WAAW;IAgEzB;;OAEG;YACW,WAAW;IAkFzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,qBAAqB,CACnB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAe,EACzB,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI;CAgBR"}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Task Runner
3
+ *
4
+ * Executes shell commands and displays output in a nice box format.
5
+ *
6
+ * Two modes:
7
+ * 1. Real-time mode: Output appears immediately as command runs (normal execution)
8
+ * 2. Buffered mode: Collect all output first, display later (parallel execution)
9
+ *
10
+ * Features:
11
+ * - Box-style output with borders
12
+ * - Line-by-line streaming
13
+ * - Error handling
14
+ * - Working directory support (baseDir)
15
+ */
16
+ import { createStepHeaderBox, createStepFooterMessage, createErrorBox, formatNestedLine, } from '../cli/ui.js';
17
+ export class TaskRunner {
18
+ /**
19
+ * Run a task command with box-style output streaming
20
+ *
21
+ * @param command - Shell command to execute
22
+ * @param stepIndex - Step index in workflow (for tracking)
23
+ * @param stepName - Display name for the step
24
+ * @param branchIndex - Branch index for parallel execution
25
+ * @param bufferOutput - If true, collect output instead of displaying immediately
26
+ * @param hasCondition - If true, step has a condition (affects border color)
27
+ * @param lineNumber - Line number in YAML file (for error reporting)
28
+ * @param fileName - YAML file name (for error reporting)
29
+ * @param cwd - Working directory for command execution
30
+ * @param timeout - Timeout in seconds (optional)
31
+ */
32
+ async run(command, stepIndex, stepName, branchIndex, bufferOutput = false, hasCondition = false, lineNumber, fileName, cwd, timeout) {
33
+ // Choose mode based on bufferOutput flag
34
+ if (bufferOutput) {
35
+ // Collect output for later display (parallel execution)
36
+ return this.runBuffered(command, cwd, timeout);
37
+ }
38
+ else {
39
+ // Display output immediately (normal execution)
40
+ return this.runRealtime(command, stepName || command, hasCondition, lineNumber, fileName, cwd, timeout);
41
+ }
42
+ }
43
+ /**
44
+ * Run command in buffered mode (collect all output for later display)
45
+ * Used for parallel execution where we need to collect output first
46
+ */
47
+ async runBuffered(command, workingDirectory, timeoutSeconds) {
48
+ const { spawn } = await import('child_process');
49
+ const [commandName, ...commandArgs] = this.parseCommand(command);
50
+ const spawnOptions = this.createSpawnOptions(workingDirectory);
51
+ return new Promise((resolve, _reject) => {
52
+ const child = spawn(commandName, commandArgs, spawnOptions);
53
+ const allStdoutLines = [];
54
+ const allStderrLines = [];
55
+ let incompleteStdoutLine = '';
56
+ let incompleteStderrLine = '';
57
+ let timeoutId = null;
58
+ // Set up timeout if specified
59
+ if (timeoutSeconds && timeoutSeconds > 0) {
60
+ timeoutId = setTimeout(() => {
61
+ child.kill('SIGTERM');
62
+ const timeoutMessage = `Command timed out after ${timeoutSeconds} seconds`;
63
+ allStderrLines.push(timeoutMessage);
64
+ resolve({ success: false, stdout: allStdoutLines, stderr: allStderrLines });
65
+ }, timeoutSeconds * 1000);
66
+ }
67
+ // Collect stdout lines
68
+ child.stdout?.on('data', (data) => {
69
+ const dataChunk = data.toString();
70
+ const { lines: completeLines, remaining: incompleteLine } = this.processStreamBuffer(dataChunk, incompleteStdoutLine);
71
+ allStdoutLines.push(...completeLines);
72
+ incompleteStdoutLine = incompleteLine;
73
+ });
74
+ // Collect stderr lines
75
+ child.stderr?.on('data', (data) => {
76
+ const dataChunk = data.toString();
77
+ const { lines: completeLines, remaining: incompleteLine } = this.processStreamBuffer(dataChunk, incompleteStderrLine);
78
+ allStderrLines.push(...completeLines);
79
+ incompleteStderrLine = incompleteLine;
80
+ });
81
+ // When process finishes, add any remaining incomplete lines
82
+ child.on('close', (exitCode) => {
83
+ if (timeoutId) {
84
+ clearTimeout(timeoutId);
85
+ }
86
+ if (incompleteStdoutLine.trim()) {
87
+ allStdoutLines.push(incompleteStdoutLine);
88
+ }
89
+ if (incompleteStderrLine.trim()) {
90
+ allStderrLines.push(incompleteStderrLine);
91
+ }
92
+ const success = exitCode === 0;
93
+ resolve({ success, stdout: allStdoutLines, stderr: allStderrLines });
94
+ });
95
+ child.on('error', (error) => {
96
+ if (timeoutId) {
97
+ clearTimeout(timeoutId);
98
+ }
99
+ const errorMessage = `Error: ${error.message}`;
100
+ resolve({ success: false, stdout: allStdoutLines, stderr: [...allStderrLines, errorMessage] });
101
+ });
102
+ });
103
+ }
104
+ /**
105
+ * Run command in real-time mode (output immediately as it happens)
106
+ */
107
+ async runRealtime(command, displayName, hasWhenCondition, lineNumber, fileName, workingDirectory, timeoutSeconds) {
108
+ const { spawn } = await import('child_process');
109
+ const [commandName, ...commandArgs] = this.parseCommand(command);
110
+ const spawnOptions = this.createSpawnOptions(workingDirectory);
111
+ // Green border if step has condition, cyan otherwise
112
+ const borderColor = hasWhenCondition ? 'green' : 'cyan';
113
+ const headerBox = createStepHeaderBox(displayName, lineNumber, fileName, { borderColor });
114
+ console.log(headerBox);
115
+ return new Promise((resolve) => {
116
+ const child = spawn(commandName, commandArgs, spawnOptions);
117
+ let incompleteStdoutLine = '';
118
+ let incompleteStderrLine = '';
119
+ let timeoutId = null;
120
+ // Set up timeout if specified
121
+ if (timeoutSeconds && timeoutSeconds > 0) {
122
+ timeoutId = setTimeout(() => {
123
+ child.kill('SIGTERM');
124
+ const timeoutMessage = `Command timed out after ${timeoutSeconds} seconds`;
125
+ const errorBox = createErrorBox(timeoutMessage);
126
+ console.error(errorBox);
127
+ const footerMessage = createStepFooterMessage(false);
128
+ console.log(footerMessage);
129
+ resolve(false);
130
+ }, timeoutSeconds * 1000);
131
+ }
132
+ // Process stdout: output complete lines immediately
133
+ child.stdout?.on('data', (data) => {
134
+ const dataChunk = data.toString();
135
+ const { lines: completeLines, remaining: incompleteLine } = this.processStreamBuffer(dataChunk, incompleteStdoutLine);
136
+ completeLines.forEach(line => process.stdout.write(`│ ${line}\n`));
137
+ incompleteStdoutLine = incompleteLine;
138
+ });
139
+ // Process stderr: output complete lines immediately
140
+ child.stderr?.on('data', (data) => {
141
+ const dataChunk = data.toString();
142
+ const { lines: completeLines, remaining: incompleteLine } = this.processStreamBuffer(dataChunk, incompleteStderrLine);
143
+ completeLines.forEach(line => process.stderr.write(`│ ${line}\n`));
144
+ incompleteStderrLine = incompleteLine;
145
+ });
146
+ // When process finishes, output any remaining incomplete lines
147
+ child.on('close', (exitCode) => {
148
+ if (timeoutId) {
149
+ clearTimeout(timeoutId);
150
+ }
151
+ if (incompleteStdoutLine.trim()) {
152
+ process.stdout.write(`│ ${incompleteStdoutLine}\n`);
153
+ }
154
+ if (incompleteStderrLine.trim()) {
155
+ process.stderr.write(`│ ${incompleteStderrLine}\n`);
156
+ }
157
+ const success = exitCode === 0;
158
+ const footerMessage = createStepFooterMessage(success);
159
+ console.log(footerMessage);
160
+ resolve(success);
161
+ });
162
+ child.on('error', (error) => {
163
+ if (timeoutId) {
164
+ clearTimeout(timeoutId);
165
+ }
166
+ const errorBox = createErrorBox(`Error: ${error.message}`);
167
+ console.error(errorBox);
168
+ resolve(false);
169
+ });
170
+ });
171
+ }
172
+ /**
173
+ * Parse command string into command and arguments
174
+ */
175
+ parseCommand(command) {
176
+ const parts = command.split(' ');
177
+ return [parts[0], ...parts.slice(1)];
178
+ }
179
+ /**
180
+ * Create spawn options with optional working directory
181
+ */
182
+ createSpawnOptions(workingDirectory) {
183
+ const options = {
184
+ stdio: ['inherit', 'pipe', 'pipe'],
185
+ shell: true,
186
+ };
187
+ if (workingDirectory) {
188
+ options.cwd = workingDirectory;
189
+ }
190
+ return options;
191
+ }
192
+ /**
193
+ * Process stream buffer and extract complete lines
194
+ *
195
+ * Command output comes in chunks, not necessarily line-by-line.
196
+ * This function:
197
+ * 1. Combines new chunk with existing buffer
198
+ * 2. Extracts all complete lines (ending with \n)
199
+ * 3. Keeps incomplete line in buffer for next chunk
200
+ *
201
+ * Example:
202
+ * - Buffer: "Hello "
203
+ * - Chunk: "World\nHow are"
204
+ * - Result: lines=["Hello World"], remaining="How are"
205
+ */
206
+ processStreamBuffer(chunk, buffer) {
207
+ const newBuffer = buffer + chunk;
208
+ const lines = [];
209
+ let remaining = newBuffer;
210
+ // Extract all complete lines (ending with \n)
211
+ while (remaining.includes('\n')) {
212
+ const newlineIndex = remaining.indexOf('\n');
213
+ const line = remaining.substring(0, newlineIndex);
214
+ remaining = remaining.substring(newlineIndex + 1);
215
+ lines.push(line);
216
+ }
217
+ return { lines, remaining };
218
+ }
219
+ /**
220
+ * Format nested output (add | prefix for nested display)
221
+ */
222
+ formatNestedOutput(content, isNested) {
223
+ if (isNested) {
224
+ content.split('\n').forEach(line => {
225
+ if (line.trim()) {
226
+ console.log(`| ${line}`);
227
+ }
228
+ });
229
+ }
230
+ else {
231
+ console.log(content);
232
+ }
233
+ }
234
+ /**
235
+ * Display buffered output in box format (for parallel execution, nested display)
236
+ */
237
+ displayBufferedOutput(result, stepName, isNested = false, lineNumber, fileName) {
238
+ const headerBox = createStepHeaderBox(stepName, lineNumber, fileName, { borderColor: 'cyan', isNested });
239
+ this.formatNestedOutput(headerBox, isNested);
240
+ result.stdout.forEach(line => {
241
+ const formattedLine = formatNestedLine(line, isNested);
242
+ process.stdout.write(`${formattedLine}\n`);
243
+ });
244
+ result.stderr.forEach(line => {
245
+ const formattedLine = formatNestedLine(line, isNested);
246
+ process.stderr.write(`${formattedLine}\n`);
247
+ });
248
+ const footerMessage = createStepFooterMessage(result.success, isNested);
249
+ console.log(footerMessage);
250
+ }
251
+ }
252
+ //# sourceMappingURL=task-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-runner.js","sourceRoot":"","sources":["../../src/core/task-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Template Variable Substitution
3
+ * Replaces {{variable}} with actual values from workspace
4
+ */
5
+ import type { Workspace } from './workspace.js';
6
+ /**
7
+ * Substitute {{variable}} template variables in string with actual values
8
+ * Example: "Hello {{name}}" becomes "Hello John" if name variable is "John"
9
+ */
10
+ export declare function substituteVariables(template: string, workspace: Workspace): string;
11
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/core/template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AA2BhD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,GACnB,MAAM,CAMR"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Template Variable Substitution
3
+ * Replaces {{variable}} with actual values from workspace
4
+ */
5
+ /**
6
+ * Find variable value from workspace
7
+ * Checks variables, facts, and choices in that order
8
+ */
9
+ function findVariableValue(variableName, workspace, defaultValue) {
10
+ // First, check variables
11
+ if (workspace.hasVariable(variableName)) {
12
+ return workspace.getVariable(variableName) || defaultValue;
13
+ }
14
+ // Second, check facts
15
+ if (workspace.hasFact(variableName)) {
16
+ const factValue = workspace.getFact(variableName);
17
+ return typeof factValue === 'string' ? factValue : String(factValue);
18
+ }
19
+ // Third, check choices
20
+ if (workspace.hasChoice(variableName)) {
21
+ return workspace.getChoice(variableName) || defaultValue;
22
+ }
23
+ // If not found, return the original template text
24
+ return defaultValue;
25
+ }
26
+ /**
27
+ * Substitute {{variable}} template variables in string with actual values
28
+ * Example: "Hello {{name}}" becomes "Hello John" if name variable is "John"
29
+ */
30
+ export function substituteVariables(template, workspace) {
31
+ const variablePattern = /\{\{(\w+)\}\}/g;
32
+ return template.replace(variablePattern, (originalMatch, variableName) => {
33
+ return findVariableValue(variableName, workspace, originalMatch);
34
+ });
35
+ }
36
+ //# sourceMappingURL=template.js.map