@marktoflow/core 2.0.0-alpha.12 → 2.0.0-alpha.14

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 (53) hide show
  1. package/README.md +147 -4
  2. package/dist/built-in-operations.d.ts +140 -0
  3. package/dist/built-in-operations.d.ts.map +1 -0
  4. package/dist/built-in-operations.js +414 -0
  5. package/dist/built-in-operations.js.map +1 -0
  6. package/dist/engine.d.ts +11 -1
  7. package/dist/engine.d.ts.map +1 -1
  8. package/dist/engine.js +76 -42
  9. package/dist/engine.js.map +1 -1
  10. package/dist/file-operations.d.ts +86 -0
  11. package/dist/file-operations.d.ts.map +1 -0
  12. package/dist/file-operations.js +363 -0
  13. package/dist/file-operations.js.map +1 -0
  14. package/dist/index.d.ts +6 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +29 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/logging.d.ts +40 -2
  19. package/dist/logging.d.ts.map +1 -1
  20. package/dist/logging.js +166 -13
  21. package/dist/logging.js.map +1 -1
  22. package/dist/models.d.ts +144 -8
  23. package/dist/models.d.ts.map +1 -1
  24. package/dist/models.js +15 -1
  25. package/dist/models.js.map +1 -1
  26. package/dist/nunjucks-filters.d.ts +271 -0
  27. package/dist/nunjucks-filters.d.ts.map +1 -0
  28. package/dist/nunjucks-filters.js +648 -0
  29. package/dist/nunjucks-filters.js.map +1 -0
  30. package/dist/parser.d.ts.map +1 -1
  31. package/dist/parser.js +16 -2
  32. package/dist/parser.js.map +1 -1
  33. package/dist/prompt-loader.d.ts +8 -2
  34. package/dist/prompt-loader.d.ts.map +1 -1
  35. package/dist/prompt-loader.js +26 -89
  36. package/dist/prompt-loader.js.map +1 -1
  37. package/dist/scheduler.d.ts +22 -3
  38. package/dist/scheduler.d.ts.map +1 -1
  39. package/dist/scheduler.js +72 -73
  40. package/dist/scheduler.js.map +1 -1
  41. package/dist/script-executor.d.ts +65 -0
  42. package/dist/script-executor.d.ts.map +1 -0
  43. package/dist/script-executor.js +261 -0
  44. package/dist/script-executor.js.map +1 -0
  45. package/dist/template-engine.d.ts +51 -0
  46. package/dist/template-engine.d.ts.map +1 -0
  47. package/dist/template-engine.js +227 -0
  48. package/dist/template-engine.js.map +1 -0
  49. package/dist/templates.d.ts +10 -0
  50. package/dist/templates.d.ts.map +1 -1
  51. package/dist/templates.js +21 -17
  52. package/dist/templates.js.map +1 -1
  53. package/package.json +16 -2
package/README.md CHANGED
@@ -128,7 +128,9 @@ await registry.register({
128
128
 
129
129
  ## Workflow Format
130
130
 
131
- Workflows are written in markdown with YAML frontmatter:
131
+ Workflows are written in markdown with YAML frontmatter. See the [examples/](https://github.com/marktoflow/marktoflow/tree/main/examples) directory for production-ready workflow templates.
132
+
133
+ ### Basic Example
132
134
 
133
135
  ```markdown
134
136
  ---
@@ -165,12 +167,88 @@ This workflow posts a message to Slack.
165
167
  \`\`\`yaml
166
168
  action: slack.chat.postMessage
167
169
  inputs:
168
- channel: '#general'
169
- text: '{{ inputs.message }}'
170
+ channel: '#general'
171
+ text: '{{ inputs.message }}'
170
172
  output_variable: result
171
173
  \`\`\`
172
174
  ```
173
175
 
176
+ ### Real-World Examples
177
+
178
+ See these production workflows in the `examples/` directory:
179
+
180
+ - **[daily-standup](https://github.com/marktoflow/marktoflow/tree/main/examples/daily-standup)** - Jira + Slack integration with AI-generated summaries
181
+ - **[code-review](https://github.com/marktoflow/marktoflow/tree/main/examples/code-review)** - Automated GitHub PR reviews with security analysis
182
+ - **[incident-response](https://github.com/marktoflow/marktoflow/tree/main/examples/incident-response)** - PagerDuty + Slack + Jira coordination
183
+ - **[gmail-notification](https://github.com/marktoflow/marktoflow/tree/main/examples/gmail-notification)** - Email automation with Gmail API
184
+ - **[web-automation](https://github.com/marktoflow/marktoflow/tree/main/examples/web-automation)** - Browser automation with Playwright
185
+
186
+ ### Advanced Features
187
+
188
+ The core engine supports sophisticated workflow patterns:
189
+
190
+ #### Control Flow
191
+
192
+ ```yaml
193
+ # Conditional execution
194
+ - action: jira.issues.getIssue
195
+ inputs:
196
+ issueKey: 'PROJ-123'
197
+ output_variable: issue
198
+
199
+ - action: slack.chat.postMessage
200
+ condition: '{{ issue.fields.priority.name == "Critical" }}'
201
+ inputs:
202
+ channel: '#urgent'
203
+ text: 'Critical issue found!'
204
+ ```
205
+
206
+ #### Loops and Iteration
207
+
208
+ ```yaml
209
+ # Process multiple items
210
+ - action: github.pulls.list
211
+ inputs:
212
+ owner: marktoflow
213
+ repo: marktoflow
214
+ output_variable: prs
215
+
216
+ - action: code_review
217
+ for_each: '{{ prs.data }}'
218
+ inputs:
219
+ pr: '{{ item }}'
220
+ ```
221
+
222
+ #### Error Handling and Retry
223
+
224
+ ```yaml
225
+ - action: external_api.call
226
+ retry:
227
+ max_attempts: 3
228
+ backoff: exponential
229
+ initial_delay: 1000
230
+ on_error: continue
231
+ fallback:
232
+ - action: slack.chat.postMessage
233
+ inputs:
234
+ channel: '#alerts'
235
+ text: 'API call failed after retries'
236
+ ```
237
+
238
+ #### Circuit Breaker Pattern
239
+
240
+ ```yaml
241
+ tools:
242
+ external_api:
243
+ sdk: 'custom-api-client'
244
+ circuit_breaker:
245
+ failure_threshold: 5
246
+ timeout: 30000
247
+ reset_timeout: 60000
248
+ ```
249
+
250
+ See [examples/tests/control-flow/](https://github.com/marktoflow/marktoflow/tree/main/examples/tests/control-flow) for more advanced patterns.
251
+
174
252
  ## Architecture
175
253
 
176
254
  ### Core Components
@@ -291,8 +369,73 @@ class Scheduler {
291
369
 
292
370
  ## Testing
293
371
 
372
+ The core package includes comprehensive unit and integration tests.
373
+
374
+ ### Running Tests
375
+
294
376
  ```bash
295
- npm test
377
+ # Run all tests (unit + integration)
378
+ pnpm test
379
+
380
+ # Run only unit tests
381
+ pnpm test:unit
382
+
383
+ # Run only integration tests
384
+ pnpm test:integration
385
+
386
+ # Run specific test file
387
+ pnpm test path/to/test.ts
388
+
389
+ # Run tests matching a pattern
390
+ pnpm test:integration -t "transform"
391
+
392
+ # Watch mode
393
+ pnpm test --watch
394
+ ```
395
+
396
+ ### Test Structure
397
+
398
+ - **Unit Tests** (`tests/`) - Fast, isolated tests for individual functions and classes
399
+ - **Integration Tests** (`integration-tests/`) - End-to-end workflow execution tests organized by feature:
400
+ - `suites/built-in-operations.integration.test.ts` - Transform, filter, reduce, etc.
401
+ - `suites/control-flow.integration.test.ts` - If/else, loops, parallel execution
402
+ - `suites/error-handling.integration.test.ts` - Retry, circuit breaker, error recovery
403
+ - `suites/nunjucks-filters.integration.test.ts` - Template engine filters
404
+ - `suites/script-execution.integration.test.ts` - JavaScript script execution
405
+ - `suites/variable-resolution.integration.test.ts` - Template variables and context
406
+
407
+ ### Writing Integration Tests
408
+
409
+ Integration tests use real workflow definitions and the full execution engine:
410
+
411
+ ```typescript
412
+ import { loadInline, createSmartExecutor } from '../helpers/test-utils.js';
413
+ import { WorkflowEngine } from '../../src/engine.js';
414
+
415
+ const engine = new WorkflowEngine();
416
+
417
+ it('should execute workflow', async () => {
418
+ const { workflow } = loadInline(`
419
+ ---
420
+ workflow:
421
+ id: test-workflow
422
+ name: Test Workflow
423
+ steps:
424
+ - id: step1
425
+ type: action
426
+ action: core.set
427
+ inputs:
428
+ value: "Hello"
429
+ output_variable: result
430
+ ---
431
+ `);
432
+
433
+ const { executor, registry } = createSmartExecutor();
434
+ const result = await engine.execute(workflow, {}, registry, executor);
435
+
436
+ expect(result.status).toBe(WorkflowStatus.COMPLETED);
437
+ expect(result.output.result).toBe('Hello');
438
+ });
296
439
  ```
297
440
 
298
441
  ## Links
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Built-in Operations for marktoflow
3
+ *
4
+ * Provides common operations that eliminate the need for verbose script blocks:
5
+ * - core.set: Simple variable assignment
6
+ * - core.transform: Map/filter/reduce transformations
7
+ * - core.extract: Nested path access
8
+ * - core.format: Date/number/string formatting
9
+ * - file.read: Read files with format conversion (docx, pdf, xlsx)
10
+ * - file.write: Write files (text or binary)
11
+ */
12
+ import { ExecutionContext } from './models.js';
13
+ export interface SetOperationInputs {
14
+ [key: string]: unknown;
15
+ }
16
+ export interface TransformOperationInputs {
17
+ input: unknown[];
18
+ operation: 'map' | 'filter' | 'reduce' | 'find' | 'group_by' | 'unique' | 'sort';
19
+ expression?: string;
20
+ condition?: string;
21
+ initialValue?: unknown;
22
+ key?: string;
23
+ reverse?: boolean;
24
+ }
25
+ export interface ExtractOperationInputs {
26
+ input: unknown;
27
+ path: string;
28
+ default?: unknown;
29
+ }
30
+ export interface FormatOperationInputs {
31
+ value: unknown;
32
+ type: 'date' | 'number' | 'string' | 'currency' | 'json';
33
+ format?: string;
34
+ locale?: string;
35
+ currency?: string;
36
+ precision?: number;
37
+ }
38
+ /**
39
+ * Set multiple variables at once with expression resolution.
40
+ *
41
+ * Example:
42
+ * ```yaml
43
+ * action: core.set
44
+ * inputs:
45
+ * owner: "{{ inputs.repo =~ /^([^\/]+)\// }}"
46
+ * repo_name: "{{ inputs.repo =~ /\/(.+)$/ }}"
47
+ * timestamp: "{{ now() }}"
48
+ * ```
49
+ */
50
+ export declare function executeSet(inputs: SetOperationInputs, context: ExecutionContext): Record<string, unknown>;
51
+ /**
52
+ * Transform arrays using common operations like map, filter, reduce.
53
+ *
54
+ * Examples:
55
+ *
56
+ * Map:
57
+ * ```yaml
58
+ * action: core.transform
59
+ * inputs:
60
+ * input: "{{ oncall_response.data.oncalls }}"
61
+ * operation: map
62
+ * expression: "@{{ item.user.name }}"
63
+ * ```
64
+ *
65
+ * Filter:
66
+ * ```yaml
67
+ * action: core.transform
68
+ * inputs:
69
+ * input: "{{ issues }}"
70
+ * operation: filter
71
+ * condition: "item.priority == 'high'"
72
+ * ```
73
+ *
74
+ * Reduce:
75
+ * ```yaml
76
+ * action: core.transform
77
+ * inputs:
78
+ * input: "{{ numbers }}"
79
+ * operation: reduce
80
+ * expression: "{{ accumulator + item }}"
81
+ * initialValue: 0
82
+ * ```
83
+ */
84
+ export declare function executeTransform(rawInputs: TransformOperationInputs, resolvedInputs: Record<string, unknown>, context: ExecutionContext): unknown;
85
+ /**
86
+ * Extract values from nested objects safely.
87
+ *
88
+ * Example:
89
+ * ```yaml
90
+ * action: core.extract
91
+ * inputs:
92
+ * input: "{{ api_response }}"
93
+ * path: "data.users[0].email"
94
+ * default: "unknown@example.com"
95
+ * ```
96
+ */
97
+ export declare function executeExtract(inputs: ExtractOperationInputs, context: ExecutionContext): unknown;
98
+ /**
99
+ * Format values for display (dates, numbers, strings, currency).
100
+ *
101
+ * Examples:
102
+ *
103
+ * Date:
104
+ * ```yaml
105
+ * action: core.format
106
+ * inputs:
107
+ * value: "{{ now() }}"
108
+ * type: date
109
+ * format: "YYYY-MM-DD HH:mm:ss"
110
+ * ```
111
+ *
112
+ * Number:
113
+ * ```yaml
114
+ * action: core.format
115
+ * inputs:
116
+ * value: 1234.56
117
+ * type: number
118
+ * precision: 2
119
+ * ```
120
+ *
121
+ * Currency:
122
+ * ```yaml
123
+ * action: core.format
124
+ * inputs:
125
+ * value: 1234.56
126
+ * type: currency
127
+ * currency: USD
128
+ * locale: en-US
129
+ * ```
130
+ */
131
+ export declare function executeFormat(inputs: FormatOperationInputs, context: ExecutionContext): string;
132
+ /**
133
+ * Execute a built-in operation based on action name
134
+ */
135
+ export declare function executeBuiltInOperation(action: string, rawInputs: Record<string, unknown>, resolvedInputs: Record<string, unknown>, context: ExecutionContext): unknown | Promise<unknown>;
136
+ /**
137
+ * Check if an action is a built-in operation
138
+ */
139
+ export declare function isBuiltInOperation(action: string): boolean;
140
+ //# sourceMappingURL=built-in-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"built-in-operations.d.ts","sourceRoot":"","sources":["../src/built-in-operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQ/C,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,wBAAwB,EACnC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA4CT;AAsKD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAkBT;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAsBR;AAiHD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,EAAE,gBAAgB,GACxB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAsB5B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAG1D"}