@output.ai/cli 0.3.1-dev.pr156.0 → 0.4.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 (48) hide show
  1. package/README.md +2 -28
  2. package/dist/api/generated/api.d.ts +35 -59
  3. package/dist/api/generated/api.js +4 -13
  4. package/dist/assets/docker/docker-compose-dev.yml +2 -2
  5. package/dist/commands/workflow/debug.d.ts +2 -8
  6. package/dist/commands/workflow/debug.js +24 -164
  7. package/dist/commands/workflow/debug.spec.js +36 -0
  8. package/dist/commands/workflow/generate.js +3 -10
  9. package/dist/commands/workflow/generate.spec.js +6 -4
  10. package/dist/commands/workflow/{output.d.ts → result.d.ts} +1 -1
  11. package/dist/commands/workflow/{output.js → result.js} +8 -8
  12. package/dist/commands/workflow/result.test.js +23 -0
  13. package/dist/commands/workflow/start.js +1 -1
  14. package/dist/services/coding_agents.js +30 -0
  15. package/dist/services/coding_agents.spec.js +36 -61
  16. package/dist/services/messages.d.ts +1 -0
  17. package/dist/services/messages.js +65 -1
  18. package/dist/services/trace_reader.d.ts +14 -0
  19. package/dist/services/trace_reader.js +67 -0
  20. package/dist/services/trace_reader.spec.d.ts +1 -0
  21. package/dist/services/trace_reader.spec.js +164 -0
  22. package/dist/services/workflow_generator.spec.d.ts +1 -0
  23. package/dist/services/workflow_generator.spec.js +77 -0
  24. package/dist/templates/agent_instructions/AGENTS.md.template +209 -19
  25. package/dist/templates/agent_instructions/agents/context_fetcher.md.template +82 -0
  26. package/dist/templates/agent_instructions/agents/prompt_writer.md.template +595 -0
  27. package/dist/templates/agent_instructions/agents/workflow_planner.md.template +13 -4
  28. package/dist/templates/agent_instructions/agents/workflow_quality.md.template +244 -0
  29. package/dist/templates/agent_instructions/commands/build_workflow.md.template +52 -9
  30. package/dist/templates/agent_instructions/commands/plan_workflow.md.template +4 -4
  31. package/dist/templates/project/package.json.template +2 -2
  32. package/dist/templates/project/src/simple/scenarios/question_ada_lovelace.json.template +3 -0
  33. package/dist/templates/workflow/scenarios/test_input.json.template +7 -0
  34. package/dist/types/trace.d.ts +161 -0
  35. package/dist/types/trace.js +18 -0
  36. package/dist/utils/date_formatter.d.ts +8 -0
  37. package/dist/utils/date_formatter.js +19 -0
  38. package/dist/utils/template.spec.js +6 -0
  39. package/dist/utils/trace_formatter.d.ts +11 -61
  40. package/dist/utils/trace_formatter.js +384 -239
  41. package/package.json +2 -2
  42. package/dist/commands/workflow/debug.test.js +0 -107
  43. package/dist/commands/workflow/output.test.js +0 -23
  44. package/dist/utils/s3_downloader.d.ts +0 -49
  45. package/dist/utils/s3_downloader.js +0 -154
  46. /package/dist/commands/workflow/{debug.test.d.ts → debug.spec.d.ts} +0 -0
  47. /package/dist/commands/workflow/{output.test.d.ts → result.test.d.ts} +0 -0
  48. /package/dist/templates/workflow/{prompt@v1.prompt.template → prompts/prompt@v1.prompt.template} +0 -0
@@ -0,0 +1,244 @@
1
+ ---
2
+ name: workflow-quality
3
+ description: Use this agent when you need expert guidance on Output SDK implementation patterns, code quality, and best practices. Invoke when writing or reviewing workflow code, troubleshooting implementation issues, or ensuring code follows SDK conventions.
4
+ model: sonnet
5
+ color: green
6
+ ---
7
+
8
+ # Output SDK Best Practices Agent
9
+
10
+ ## Identity
11
+
12
+ You are an Output SDK implementation expert who ensures workflow code follows best practices, avoids common pitfalls, and adheres to SDK conventions. You focus on code quality, correctness, and maintainability.
13
+
14
+ ## Context Retrieval
15
+
16
+ Use the `context-fetcher` subagent to efficiently retrieve:
17
+ - **Existing Patterns**: Find similar implementations in `src/workflows/*/`
18
+ - **Project Conventions**: Check `.outputai/AGENTS.md` for project-specific rules
19
+
20
+ Use the `prompt-writer` subagent for:
21
+ - Creating new `.prompt` files
22
+ - Reviewing or debugging prompt template syntax
23
+ - Understanding Liquid.js syntax and YAML frontmatter
24
+
25
+ ## Core Expertise
26
+
27
+ - **Workflow Implementation**: Correct patterns for workflow definitions and orchestration
28
+ - **Step Design**: Proper step boundaries, I/O schemas, and retry policies
29
+ - **LLM Integration**: Prompt file format, generation functions, template syntax
30
+ - **HTTP Client**: Traced HTTP requests with proper error handling
31
+ - **Type Safety**: Zod schemas and TypeScript integration
32
+ - **Error Handling**: ValidationError, FatalError, and retry strategies
33
+
34
+ ## Critical Rules
35
+
36
+ ### Import Conventions
37
+
38
+ **CRITICAL**: Always import `z` from `@output.ai/core`, NEVER from `zod` directly:
39
+ ```typescript
40
+ // Wrong
41
+ import { z } from 'zod';
42
+
43
+ // Correct
44
+ import { z } from '@output.ai/core';
45
+ ```
46
+
47
+ ### Workflow Determinism
48
+
49
+ Workflows must be deterministic. They can ONLY:
50
+ - Call steps and evaluators
51
+ - Use control flow (if/else, loops)
52
+ - Access input parameters
53
+
54
+ Workflows must NOT contain:
55
+ - Direct HTTP/API calls (wrap in steps)
56
+ - `Math.random()`, `Date.now()`, `crypto.randomUUID()`
57
+ - Dynamic imports
58
+ - File system operations
59
+
60
+ ### Step Boundaries
61
+
62
+ All I/O operations must be wrapped in steps:
63
+ ```typescript
64
+ // Wrong - I/O in workflow
65
+ export default workflow({
66
+ fn: async (input) => {
67
+ const data = await fetch('https://api.example.com'); // ❌
68
+ return { data };
69
+ }
70
+ });
71
+
72
+ // Correct - I/O in step
73
+ export const fetchData = step({
74
+ name: 'fetchData',
75
+ fn: async (input) => {
76
+ const client = httpClient({ prefixUrl: 'https://api.example.com' });
77
+ return client.get('endpoint').json();
78
+ }
79
+ });
80
+ ```
81
+
82
+ ### No Try-Catch Wrapping
83
+
84
+ Don't wrap step calls in try-catch blocks. Allow failures to propagate:
85
+ ```typescript
86
+ // Wrong
87
+ fn: async (input) => {
88
+ try {
89
+ const result = await myStep(input);
90
+ return result;
91
+ } catch (error) {
92
+ throw new FatalError(error.message);
93
+ }
94
+ }
95
+
96
+ // Correct
97
+ fn: async (input) => {
98
+ const result = await myStep(input);
99
+ return result;
100
+ }
101
+ ```
102
+
103
+ ### HTTP Client Usage
104
+
105
+ Never use axios directly. Use `@output.ai/http`:
106
+ ```typescript
107
+ import { httpClient } from '@output.ai/http';
108
+
109
+ const client = httpClient({
110
+ prefixUrl: 'https://api.example.com',
111
+ timeout: 30000,
112
+ retry: { limit: 3 }
113
+ });
114
+
115
+ // GET request
116
+ const data = await client.get('endpoint').json();
117
+
118
+ // POST request
119
+ const result = await client.post('endpoint', { json: payload }).json();
120
+ ```
121
+
122
+ ### LLM Integration
123
+
124
+ Never call LLM APIs directly. Use `@output.ai/llm`:
125
+ ```typescript
126
+ import { generateText, generateObject, generateArray, generateEnum } from '@output.ai/llm';
127
+
128
+ // Text generation
129
+ const text = await generateText({
130
+ prompt: 'prompts/my_prompt@v1',
131
+ variables: { topic: 'AI' }
132
+ });
133
+
134
+ // Structured output
135
+ const data = await generateObject({
136
+ prompt: 'prompts/extract@v1',
137
+ variables: { text },
138
+ schema: z.object({ title: z.string(), summary: z.string() })
139
+ });
140
+ ```
141
+
142
+ ### Schema Definitions
143
+
144
+ Define input/output schemas with Zod:
145
+ ```typescript
146
+ import { step, z } from '@output.ai/core';
147
+
148
+ export const processData = step({
149
+ name: 'processData',
150
+ inputSchema: z.object({
151
+ id: z.string(),
152
+ count: z.number().optional()
153
+ }),
154
+ outputSchema: z.object({
155
+ result: z.string(),
156
+ processed: z.boolean()
157
+ }),
158
+ fn: async (input) => {
159
+ // input is typed as { id: string, count?: number }
160
+ return { result: input.id, processed: true };
161
+ }
162
+ });
163
+ ```
164
+
165
+ ### Retry Policies
166
+
167
+ Configure retry policies in step options:
168
+ ```typescript
169
+ export const riskyStep = step({
170
+ name: 'riskyStep',
171
+ fn: async (input) => { /* ... */ },
172
+ options: {
173
+ retry: {
174
+ maximumAttempts: 3,
175
+ initialInterval: '1s',
176
+ maximumInterval: '10s',
177
+ backoffCoefficient: 2
178
+ },
179
+ startToCloseTimeout: '30s'
180
+ }
181
+ });
182
+ ```
183
+
184
+ ### Error Types
185
+
186
+ Use appropriate error types:
187
+ ```typescript
188
+ import { FatalError, ValidationError } from '@output.ai/core';
189
+
190
+ // Non-retryable error (workflow fails immediately)
191
+ throw new FatalError('Critical failure - do not retry');
192
+
193
+ // Validation error (schema/input validation)
194
+ throw new ValidationError('Invalid input format');
195
+ ```
196
+
197
+ ## File Structure
198
+
199
+ ```
200
+ src/workflows/{name}/
201
+ workflow.ts # Workflow definition (orchestration only)
202
+ steps.ts # Step definitions (all I/O here)
203
+ evaluators.ts # Evaluators (optional)
204
+ types.ts # Shared types and schemas (optional)
205
+ prompts/ # Prompt files directory
206
+ name@v1.prompt # Versioned prompt templates
207
+ scenarios/ # Test scenarios directory
208
+ basic.json # Common run case examples
209
+ edge_cases.json # Edge case scenarios
210
+ ```
211
+
212
+ ### Allowed Imports in Workflows
213
+
214
+ Workflows can only import from:
215
+ - `steps.ts`, `evaluators.ts`, `shared_steps.ts`
216
+ - Whitelisted: `types.ts`, `consts.ts`, `utils.ts`, `variables.ts`, `tools.ts`
217
+
218
+ ## Common Pitfalls
219
+
220
+ ### 1. Zod Import Source
221
+ Always import `z` from `@output.ai/core`, never from `zod` directly. Different `z` instances create incompatible schemas.
222
+
223
+ ### 2. Direct API Calls
224
+ Never make HTTP/LLM calls directly in workflows. Always wrap in steps.
225
+
226
+ ### 3. Non-Deterministic Operations
227
+ No `Math.random()`, `Date.now()`, or `crypto` in workflows.
228
+
229
+ ### 4. Try-Catch Blocks
230
+ Don't wrap step calls in try-catch. Let failures propagate for proper retry handling.
231
+
232
+ ### 5. Missing Schemas
233
+ Always define inputSchema and outputSchema for type safety and validation.
234
+
235
+ ## Example Interaction
236
+
237
+ **User**: "My workflow is failing with a type error on the schema"
238
+ **Agent**: Check that you're importing `z` from `@output.ai/core`, not `zod`. Different `z` instances create incompatible schemas.
239
+
240
+ **User**: "How do I make an HTTP request in my workflow?"
241
+ **Agent**: Create a step that uses `@output.ai/http`. Never make HTTP calls directly in the workflow function.
242
+
243
+ ---
244
+ *This agent specializes in Output SDK implementation best practices and code quality.*
@@ -25,7 +25,7 @@ Implement the workflow described in the plan document, following Output SDK patt
25
25
 
26
26
  <process_flow>
27
27
 
28
- <step number="1" name="plan_analysis">
28
+ <step number="1" name="plan_analysis" subagent="context-fetcher">
29
29
 
30
30
  ### Step 1: Plan Analysis
31
31
 
@@ -40,7 +40,7 @@ Read and understand the plan document.
40
40
 
41
41
  </step>
42
42
 
43
- <step number="2" name="workflow_implementation">
43
+ <step number="2" name="workflow_implementation" subagent="workflow-quality">
44
44
 
45
45
  ### Step 2: Workflow Implementation
46
46
 
@@ -85,7 +85,7 @@ export default workflow( {
85
85
 
86
86
  </step>
87
87
 
88
- <step number="3" name="steps_implementation">
88
+ <step number="3" name="steps_implementation" subagent="workflow-quality">
89
89
 
90
90
  ### Step 3: Steps Implementation
91
91
 
@@ -122,7 +122,7 @@ export const stepName = step( {
122
122
 
123
123
  </step>
124
124
 
125
- <step number="4" name="prompt_templates">
125
+ <step number="4" name="prompt_templates" subagent="prompt-writer">
126
126
 
127
127
  ### Step 4: Prompt Templates (if needed)
128
128
 
@@ -133,7 +133,7 @@ If the plan includes LLM-based steps, create prompt templates in `$3/prompts/`.
133
133
  CREATE prompt_templates
134
134
  UPDATE steps.ts to use loadPrompt and generateText
135
135
  ELSE:
136
- SKIP to step 5
136
+ SKIP to step 6
137
137
  </decision_tree>
138
138
 
139
139
  <llm_step_template>
@@ -197,9 +197,51 @@ Update `$3/README.md` with workflow-specific documentation.
197
197
 
198
198
  </step>
199
199
 
200
- <step number="6" name="validation">
200
+ <step number="6" name="scenario_creation">
201
201
 
202
- ### Step 6: Implementation Validation
202
+ ### Step 6: Scenario File Creation
203
+
204
+ Create at least one scenario file in `$3/scenarios/` for testing the workflow.
205
+
206
+ <scenario_requirements>
207
+ - Create `scenarios/` directory if it doesn't exist
208
+ - Create `test_input.json` with valid example input matching the inputSchema
209
+ - Input values should be realistic and demonstrate the workflow's purpose
210
+ - JSON must be valid and parseable
211
+ </scenario_requirements>
212
+
213
+ <scenario_template>
214
+ ```json
215
+ {
216
+ // Populate with example values matching inputSchema
217
+ // Use realistic test data that demonstrates the workflow
218
+ }
219
+ ```
220
+ </scenario_template>
221
+
222
+ <example>
223
+ For a workflow with inputSchema:
224
+ ```typescript
225
+ z.object({
226
+ topic: z.string(),
227
+ maxLength: z.number().optional()
228
+ })
229
+ ```
230
+
231
+ Create `scenarios/test_input.json`:
232
+ ```json
233
+ {
234
+ "topic": "The history of artificial intelligence",
235
+ "maxLength": 500
236
+ }
237
+ ```
238
+ </example>
239
+
240
+ </step>
241
+
242
+ <step number="7" name="validation" subagent="workflow-quality">
243
+
244
+ ### Step 7: Implementation Validation
203
245
 
204
246
  Verify the implementation is complete and correct.
205
247
 
@@ -212,13 +254,14 @@ Verify the implementation is complete and correct.
212
254
  - README is updated with accurate information
213
255
  - Code follows Output SDK patterns
214
256
  - TypeScript types are properly defined
257
+ - Scenario file exists with valid example input
215
258
  </validation_checklist>
216
259
 
217
260
  </step>
218
261
 
219
- <step number="7" name="post_flight_check">
262
+ <step number="8" name="post_flight_check">
220
263
 
221
- ### Step 7: Post-Flight Check
264
+ ### Step 8: Post-Flight Check
222
265
 
223
266
  Verify the implementation is ready for use.
224
267
 
@@ -25,7 +25,7 @@ Generate detailed specifications for implementation of a new workflow.
25
25
 
26
26
  <process_flow>
27
27
 
28
- <step number="1" name="context_gathering">
28
+ <step number="1" name="context_gathering" subagent="context-fetcher">
29
29
 
30
30
  ### Step 1: Context Gathering
31
31
 
@@ -63,7 +63,7 @@ Clarify scope boundaries and technical considerations by asking numbered questio
63
63
  </decision_tree>
64
64
  </step>
65
65
 
66
- <step number="3" name="workflow_design">
66
+ <step number="3" name="workflow_design" subagent="workflow-quality">
67
67
 
68
68
  ### Step 3: Workflow Design
69
69
 
@@ -109,7 +109,7 @@ export default workflow( {
109
109
  ```
110
110
  </workflow_template>
111
111
 
112
- <step number="4" name="step_design">
112
+ <step number="4" name="step_design" subagent="workflow-quality">
113
113
  ### Step 4: Step Design
114
114
 
115
115
  Design the steps with clear boundaries.
@@ -130,7 +130,7 @@ export const sumValues = step( {
130
130
 
131
131
  </step>
132
132
 
133
- <step number="5" name="prompt_engineering">
133
+ <step number="5" name="prompt_engineering" subagent="prompt-writer">
134
134
 
135
135
  ### Step 5: Prompt Engineering
136
136
 
@@ -12,12 +12,12 @@
12
12
  "dependencies": {
13
13
  "@output.ai/core": "^{{coreVersion}}",
14
14
  "@output.ai/llm": "^{{llmVersion}}",
15
- "@output.ai/http": "^{{httpVersion}}",
16
- "copyfiles": "^{{cliVersion}}"
15
+ "@output.ai/http": "^{{httpVersion}}"
17
16
  },
18
17
  "devDependencies": {
19
18
  "@output.ai/cli": "latest",
20
19
  "@types/node": "^22.0.0",
20
+ "copyfiles": "^1.0.0",
21
21
  "typescript": "^5.7.0"
22
22
  },
23
23
  "engines": {
@@ -0,0 +1,3 @@
1
+ {
2
+ "question": "who really is ada lovelace?"
3
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "prompt": "Tell me about the history of computing",
3
+ "data": {
4
+ "value": 42,
5
+ "type": "example"
6
+ }
7
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Trace types for workflow execution data.
3
+ *
4
+ * These types represent the structure of trace files generated during workflow execution,
5
+ * used for debugging, visualization, and analysis of workflow runs.
6
+ */
7
+ /** Node kind values for trace events */
8
+ export type NodeKind = 'workflow' | 'activity' | 'step' | 'internal_step' | string;
9
+ /** Phase of a trace event lifecycle */
10
+ export type NodePhase = 'start' | 'end' | 'error' | string;
11
+ /** Execution status of a node */
12
+ export type NodeStatus = 'completed' | 'failed' | 'running' | string;
13
+ /**
14
+ * Details associated with a trace event.
15
+ * Contains input/output data and identifying information for the event.
16
+ */
17
+ export interface TraceDetails {
18
+ /** Input data passed to the step/activity */
19
+ input?: unknown;
20
+ /** Output data returned from the step/activity */
21
+ output?: unknown;
22
+ /** Name of the activity (for activity events) */
23
+ activityName?: string;
24
+ /** Name of the step (for step events) */
25
+ stepName?: string;
26
+ /** Generic name field */
27
+ name?: string;
28
+ }
29
+ /**
30
+ * A trace event representing a point in workflow execution.
31
+ * Used for timeline display and event-based analysis.
32
+ */
33
+ export interface TraceEvent {
34
+ /** The type of event (workflow, activity, step, etc.) */
35
+ kind: NodeKind;
36
+ /** The lifecycle phase of the event */
37
+ phase: NodePhase;
38
+ /** Unix timestamp when the event occurred */
39
+ timestamp: number;
40
+ /** Unique identifier for the workflow run */
41
+ workflowId: string;
42
+ /** Name of the workflow being executed */
43
+ workflowName: string;
44
+ /** Additional event details including input/output */
45
+ details?: TraceDetails;
46
+ /** Child events for nested executions */
47
+ children?: TraceEvent[];
48
+ /** Error information if the event represents a failure */
49
+ error?: unknown;
50
+ /** Duration of the event in milliseconds */
51
+ duration?: number;
52
+ }
53
+ /**
54
+ * A node in the debug tree representation of workflow execution.
55
+ * Contains more detailed timing and state information than TraceEvent.
56
+ */
57
+ export interface DebugNode {
58
+ /** The type of node (workflow, activity, step, internal_step) */
59
+ kind?: NodeKind;
60
+ /** Alternative type field */
61
+ type?: string;
62
+ /** The name of the step or activity */
63
+ name?: string;
64
+ /** Name of the workflow (for workflow nodes) */
65
+ workflowName?: string;
66
+ /** Name of the step (for step nodes) */
67
+ stepName?: string;
68
+ /** Name of the activity (for activity nodes) */
69
+ activityName?: string;
70
+ /** The lifecycle phase of the node */
71
+ phase?: NodePhase;
72
+ /** Execution status (completed, failed, running) */
73
+ status?: NodeStatus;
74
+ /** Unix timestamp or ISO string when execution started */
75
+ startedAt?: number | string;
76
+ /** Unix timestamp when the event occurred */
77
+ timestamp?: number | string;
78
+ /** Unix timestamp or ISO string when execution ended */
79
+ endedAt?: number | string;
80
+ /** Unix timestamp when execution started (alternative field) */
81
+ startTime?: number;
82
+ /** Unix timestamp when execution ended (alternative field) */
83
+ endTime?: number;
84
+ /** Execution duration in milliseconds */
85
+ duration?: number;
86
+ /** Input data passed to the step/activity */
87
+ input?: unknown;
88
+ /** Output data returned from the step/activity */
89
+ output?: unknown;
90
+ /** Additional execution details */
91
+ details?: Record<string, unknown>;
92
+ /** Error information if the node failed */
93
+ error?: unknown;
94
+ /** Child nodes representing nested executions */
95
+ children?: DebugNode[];
96
+ }
97
+ /**
98
+ * Root structure of a workflow trace.
99
+ * Contains the execution tree and optional flat event list.
100
+ */
101
+ export interface TraceStructure {
102
+ /** Root node of the execution tree */
103
+ root?: TraceEvent | DebugNode;
104
+ /** Flat list of execution events for timeline display */
105
+ events?: TraceEvent[];
106
+ /** Hierarchical tree of execution nodes (alternative to root.children) */
107
+ children?: DebugNode[];
108
+ }
109
+ /**
110
+ * The structure of a workflow trace file generated by Output SDK workflow runs.
111
+ * This file is written to the local filesystem during workflow execution and contains
112
+ * the complete execution history including timing, inputs, outputs, and any errors.
113
+ */
114
+ export interface TraceData {
115
+ /** Root workflow execution information */
116
+ root: {
117
+ /** The name of the workflow that was executed */
118
+ workflowName: string;
119
+ /** Unique identifier for this workflow run */
120
+ workflowId: string;
121
+ /** Unix timestamp when the workflow started */
122
+ startTime: number;
123
+ /** Unix timestamp when the workflow ended */
124
+ endTime?: number;
125
+ /** Total workflow duration in milliseconds */
126
+ duration?: number;
127
+ /** Final workflow status */
128
+ status?: string;
129
+ /** Error information if the workflow failed */
130
+ error?: unknown;
131
+ };
132
+ /** Flat list of execution events for timeline display */
133
+ events?: Array<{
134
+ name: string;
135
+ phase: string;
136
+ timestamp: number;
137
+ details?: unknown;
138
+ }>;
139
+ /** Hierarchical tree of execution nodes */
140
+ children?: DebugNode[];
141
+ }
142
+ /**
143
+ * Extracted node information for display formatting.
144
+ * Used internally by the trace formatter.
145
+ */
146
+ export interface NodeInfo {
147
+ /** Display name for the node */
148
+ name: string;
149
+ /** Formatted phase indicator */
150
+ phase: string;
151
+ /** Formatted duration string */
152
+ duration: string;
153
+ }
154
+ /**
155
+ * Type guard to check if a node is a TraceEvent.
156
+ */
157
+ export declare const isTraceEvent: (node: TraceEvent | DebugNode) => node is TraceEvent;
158
+ /**
159
+ * Type guard to check if a value is a valid timestamp.
160
+ */
161
+ export declare const isValidTimestamp: (value: unknown) => value is number | string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Trace types for workflow execution data.
3
+ *
4
+ * These types represent the structure of trace files generated during workflow execution,
5
+ * used for debugging, visualization, and analysis of workflow runs.
6
+ */
7
+ /**
8
+ * Type guard to check if a node is a TraceEvent.
9
+ */
10
+ export const isTraceEvent = (node) => {
11
+ return 'workflowId' in node && 'timestamp' in node;
12
+ };
13
+ /**
14
+ * Type guard to check if a value is a valid timestamp.
15
+ */
16
+ export const isValidTimestamp = (value) => {
17
+ return typeof value === 'number' || typeof value === 'string';
18
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Format a duration in milliseconds to a human-readable string.
3
+ * Uses date-fns for durations >= 1 minute, custom formatting for shorter durations.
4
+ *
5
+ * @param ms - Duration in milliseconds
6
+ * @returns Formatted duration string (e.g., "150ms", "2.50s", "3 minutes 45 seconds")
7
+ */
8
+ export declare function formatDuration(ms: number): string;
@@ -0,0 +1,19 @@
1
+ import { formatDuration as formatDurationFns, intervalToDuration } from 'date-fns';
2
+ /**
3
+ * Format a duration in milliseconds to a human-readable string.
4
+ * Uses date-fns for durations >= 1 minute, custom formatting for shorter durations.
5
+ *
6
+ * @param ms - Duration in milliseconds
7
+ * @returns Formatted duration string (e.g., "150ms", "2.50s", "3 minutes 45 seconds")
8
+ */
9
+ export function formatDuration(ms) {
10
+ const duration = intervalToDuration({ start: 0, end: ms });
11
+ if (ms < 1000) {
12
+ return `${ms}ms`;
13
+ }
14
+ if (ms < 60000) {
15
+ const seconds = ms / 1000;
16
+ return `${seconds.toFixed(2)}s`;
17
+ }
18
+ return formatDurationFns(duration, { format: ['minutes', 'seconds'] });
19
+ }
@@ -53,6 +53,12 @@ describe('Template Utilities', () => {
53
53
  expect(processTemplate(template, variables))
54
54
  .toBe('myWorkflowName and MyWorkflowName');
55
55
  });
56
+ it('should preserve escaped curly braces for Liquid.js examples', () => {
57
+ const template = 'Use Liquid: \\{{ variable }} and {% if %}...{% endif %}';
58
+ const variables = {};
59
+ expect(processTemplate(template, variables))
60
+ .toBe('Use Liquid: {{ variable }} and {% if %}...{% endif %}');
61
+ });
56
62
  });
57
63
  describe('prepareTemplateVariables', () => {
58
64
  it('should prepare variables from workflow name and description', () => {