@output.ai/cli 0.3.1-dev.pr156.0 → 0.4.1

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 (50) hide show
  1. package/README.md +36 -197
  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/.gitignore.template +0 -3
  32. package/dist/templates/project/README.md.template +2 -2
  33. package/dist/templates/project/package.json.template +2 -2
  34. package/dist/templates/project/src/simple/scenarios/question_ada_lovelace.json.template +3 -0
  35. package/dist/templates/workflow/scenarios/test_input.json.template +7 -0
  36. package/dist/types/trace.d.ts +161 -0
  37. package/dist/types/trace.js +18 -0
  38. package/dist/utils/date_formatter.d.ts +8 -0
  39. package/dist/utils/date_formatter.js +19 -0
  40. package/dist/utils/template.spec.js +6 -0
  41. package/dist/utils/trace_formatter.d.ts +11 -61
  42. package/dist/utils/trace_formatter.js +384 -239
  43. package/package.json +6 -3
  44. package/dist/commands/workflow/debug.test.js +0 -107
  45. package/dist/commands/workflow/output.test.js +0 -23
  46. package/dist/utils/s3_downloader.d.ts +0 -49
  47. package/dist/utils/s3_downloader.js +0 -154
  48. /package/dist/commands/workflow/{debug.test.d.ts → debug.spec.d.ts} +0 -0
  49. /package/dist/commands/workflow/{output.test.d.ts → result.test.d.ts} +0 -0
  50. /package/dist/templates/workflow/{prompt@v1.prompt.template → prompts/prompt@v1.prompt.template} +0 -0
package/README.md CHANGED
@@ -1,220 +1,59 @@
1
1
  # @output.ai/cli
2
2
 
3
- CLI tool for generating Output workflows.
3
+ Command-line interface for creating and running Output Framework workflows.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@output.ai/cli)](https://www.npmjs.com/package/@output.ai/cli)
6
+ [![Documentation](https://img.shields.io/badge/docs-docs.output.ai-blue)](https://docs.output.ai/packages/cli)
4
7
 
5
8
  ## Installation
6
9
 
7
10
  ```bash
8
- # Install globally from the CLI package
9
- cd sdk/cli && npm link
10
-
11
- # Or run directly from the monorepo
12
- npx @output.ai/cli
11
+ npm install -g @output.ai/cli
13
12
  ```
14
13
 
15
- ## Usage
16
-
17
- ### Initialize a New Project
14
+ ## Quick Start
18
15
 
19
16
  ```bash
20
- # Create a new Output SDK project
17
+ # Create a new project
21
18
  output init my-project
22
- ```
23
-
24
- #### What It Does
19
+ cd my-project
25
20
 
26
- Creates a complete Output SDK project structure with:
27
- - Example workflows demonstrating SDK features
28
- - TypeScript project configuration
29
- - Agent configuration files
30
-
31
- ### Start Development Services
32
-
33
- ```bash
34
- # Start with automatic file watching (default)
21
+ # Start development services
35
22
  output dev
36
23
 
37
- # Start without file watching
38
- output dev --no-watch
39
- ```
40
-
41
- #### What It Does
42
-
43
- The `dev` command orchestrates your entire development environment:
44
- 1. Starts Docker services (Temporal, Redis, PostgreSQL)
45
- 2. Launches the API server for workflow execution
46
- 3. Starts the worker to process workflows
47
- 4. Opens Temporal UI for workflow monitoring
48
- 5. Automatically restarts the worker when source files change
49
- 6. Provides a unified log view of all services
50
-
51
- This is the primary command for local development - it handles all the complexity of running multiple services and keeps them synchronized.
52
-
53
- #### Automatic File Watching
54
-
55
- By default, the worker container automatically restarts when you modify files in:
56
- - `src/` - Your workflow source files and implementations
57
- - `package.json` - When dependencies change
58
-
59
- This feature uses Docker Compose's native watch functionality (requires Docker Compose v2.22+).
60
-
61
- #### Command Options
62
-
63
- - `--no-watch` - Disable automatic container restart on file changes
64
-
65
- ### List Workflows
66
-
67
- ```bash
68
- # List all available workflows (simple list, default)
69
- output workflow list
70
-
71
- # List workflows with custom API URL
72
- API_URL=http://localhost:3001 output workflow list
73
-
74
- # List workflows with authentication
75
- API_AUTH_TOKEN=your-token output workflow list
76
-
77
- # Show detailed table view with all information
78
- output workflow list --format table
79
-
80
- # Show detailed table with expanded parameter info
81
- output workflow list --format table --detailed
82
-
83
- # List workflows in JSON format
84
- output workflow list --format json
85
-
86
- # Filter workflows by name (partial match)
87
- output workflow list --filter simple
24
+ # Run a workflow
25
+ output workflow run simple --input '{"question": "who is ada lovelace?"}'
88
26
  ```
89
27
 
90
- #### Command Options
91
-
92
- - `--format, -f` - Output format: `list` (default, simple column), `table`, or `json`
93
- - `--detailed, -d` - Show detailed parameter information in table view
94
- - `--filter` - Filter workflows by name (case-insensitive partial match)
95
-
96
- The list command connects to the API server and retrieves all available workflows. By default, it displays a simple list of workflow names (like `ls`). Use `--format table` for detailed information.
97
-
98
- ### Debug a Workflow Execution
99
-
100
- ```bash
101
- # Display trace information for a workflow run
102
- output workflow debug <workflowId>
103
-
104
- # Display trace in JSON format
105
- output workflow debug <workflowId> --format json
106
-
107
- # Prefer remote (S3) trace over local
108
- output workflow debug <workflowId> --remote
109
-
110
- # Save trace to a custom directory
111
- output workflow debug <workflowId> --download-dir ./my-traces
112
-
113
- # Force re-download of remote traces (bypass cache)
114
- output workflow debug <workflowId> --remote --force-download
115
- ```
116
-
117
- #### What It Does
118
-
119
- The `debug` command retrieves and displays detailed execution traces for debugging workflow runs. It shows:
120
- - Complete execution timeline with all events
121
- - Hierarchical execution tree showing workflow structure
122
- - Step and activity inputs/outputs
123
- - Error details and stack traces
124
- - Performance metrics and durations
125
-
126
- #### Trace Sources
127
-
128
- The command automatically handles both local and remote traces:
129
- - **Local traces**: Stored on your machine when `TRACE_LOCAL_ON=true`
130
- - **Remote traces**: Stored in S3 when `TRACE_REMOTE_ON=true` (requires AWS credentials)
131
-
132
- By default, it tries local traces first for faster access, then falls back to remote if needed.
133
-
134
- #### Command Options
135
-
136
- - `--format, -f` - Output format: `text` (default, human-readable) or `json` (raw trace data)
137
- - `--remote, -r` - Prefer remote S3 trace even if local exists
138
- - `--download-dir, -d` - Directory for saving downloaded traces (default: `.output/traces`)
139
- - `--open, -o` - Save trace to file for viewing in external JSON viewer
140
- - `--force-download` - Force re-download from S3, bypassing local cache
141
-
142
- #### AWS Configuration
143
-
144
- For remote traces, configure AWS credentials:
145
- ```bash
146
- export AWS_ACCESS_KEY_ID=your-access-key
147
- export AWS_SECRET_ACCESS_KEY=your-secret-key
148
- export AWS_REGION=us-east-1 # or your region
149
- ```
150
-
151
- ### Generate a Workflow
152
-
153
- ```bash
154
- # Generate a complete workflow with example steps
155
- output workflow generate my-workflow --description "My awesome workflow"
156
-
157
- # Generate a minimal skeleton workflow
158
- output workflow generate my-workflow --skeleton
159
-
160
- # Generate in a specific directory
161
- output workflow generate my-workflow --output-dir ./src/workflows
162
-
163
- # Force overwrite existing workflow
164
- output workflow generate my-workflow --force
165
- ```
166
-
167
- #### Command Options
168
-
169
- - `--description, -d` - Description of the workflow
170
- - `--skeleton, -s` - Generate minimal skeleton without example steps
171
- - `--output-dir, -o` - Output directory (default: `src/`)
172
- - `--force, -f` - Overwrite existing directory
173
-
174
- #### Generated Structure
175
-
176
- The CLI creates a complete workflow structure:
177
-
178
- ```
179
- my-workflow/
180
- ├── workflow.ts # Main workflow definition
181
- ├── steps.ts # Activity/step implementations
182
- ├── prompt@v1.prompt # LLM prompt template (if not skeleton)
183
- └── README.md # Workflow documentation
184
- ```
185
-
186
- ### Initialize Agent Configuration
187
-
188
- ```bash
189
- # Initialize agent configuration for your coding agent
190
- output-cli agents init
191
-
192
- # Specify your agent provider (default: claude-code)
193
- output-cli agents init --agent-provider claude-code
194
-
195
- # Force overwrite existing configuration
196
- output-cli agents init --force
197
- ```
198
-
199
- #### What It Does
200
-
201
- Sets up your coding agent of choice with context files, sub-agents, and slash commands for working with the Output SDK effectively. It creates a `.outputai/` directory and wires up your coding agent to the context files.
202
-
203
- **Note:** Currently this only works for [Claude Code](https://claude.ai/code), but we plan to add support for other coding agents over time.
204
-
205
- #### Command Options
28
+ ## Command Reference
206
29
 
207
- - `--agent-provider` - Specify the coding agent provider (default: `claude-code`)
208
- - `--force, -f` - Overwrite existing agent configuration files
30
+ | Command | Description |
31
+ |---------|-------------|
32
+ | `output init` | Initialize a new project |
33
+ | `output dev` | Start development services (Temporal, API, Worker) |
34
+ | `output agents init` | Initialize AI agent configurations |
35
+ | `output workflow plan` | Generate a workflow plan from description |
36
+ | `output workflow generate` | Generate a workflow from plan |
37
+ | `output workflow list` | List available workflows |
38
+ | `output workflow run` | Execute a workflow synchronously |
39
+ | `output workflow start` | Start a workflow asynchronously |
40
+ | `output workflow status` | Get workflow execution status |
41
+ | `output workflow result` | Get workflow execution result |
42
+ | `output workflow stop` | Stop a workflow execution |
209
43
 
210
- #### Output Agent Commands
44
+ ## Development Services
211
45
 
212
- **`/plan_workflow`** - Guides you through structured workflow planning to create comprehensive implementation blueprints before writing code.
46
+ Running `output dev` starts:
213
47
 
214
- #### Output Sub-Agents
48
+ | Service | URL | Description |
49
+ |---------|-----|-------------|
50
+ | Temporal UI | http://localhost:8080 | Monitor and debug workflows |
51
+ | API Server | http://localhost:3001 | REST API for workflow execution |
52
+ | Worker | — | Processes workflows with auto-reload |
215
53
 
216
- **`workflow_planner`** - A specialized AI agent that helps with workflow architecture and planning, including requirements analysis, schema design, and testing strategy definition.
54
+ ## Documentation
217
55
 
218
- ## About
56
+ For comprehensive documentation, visit:
219
57
 
220
- Built with [OCLIF](https://oclif.io) - see their documentation for advanced CLI features, plugins, and configuration options.
58
+ - [CLI Reference](https://docs.output.ai/packages/cli)
59
+ - [Getting Started](https://docs.output.ai/quickstart)
@@ -32,6 +32,28 @@ export interface Workflow {
32
32
  inputSchema?: JSONSchema;
33
33
  outputSchema?: JSONSchema;
34
34
  }
35
+ /**
36
+ * File destinations for trace data
37
+ */
38
+ export type TraceInfoDestinations = {
39
+ /**
40
+ * Absolute path to local trace file, or null if not saved locally
41
+ * @nullable
42
+ */
43
+ local: string | null;
44
+ /**
45
+ * Remote trace location (e.g., S3 URI), or null if not saved remotely
46
+ * @nullable
47
+ */
48
+ remote: string | null;
49
+ };
50
+ /**
51
+ * An object with information about the trace generated by the execution
52
+ */
53
+ export interface TraceInfo {
54
+ /** File destinations for trace data */
55
+ destinations?: TraceInfoDestinations;
56
+ }
35
57
  export type PostWorkflowRunBody = {
36
58
  /** The name of the workflow to execute */
37
59
  workflowName: string;
@@ -42,19 +64,12 @@ export type PostWorkflowRunBody = {
42
64
  /** The name of the task queue to send the workflow to */
43
65
  taskQueue?: string;
44
66
  };
45
- /**
46
- * An object with information about the trace generated by the execution
47
- */
48
- export type PostWorkflowRun200Trace = {
49
- [key: string]: unknown;
50
- };
51
67
  export type PostWorkflowRun200 = {
52
68
  /** The workflow execution id */
53
69
  workflowId?: string;
54
70
  /** The output of the workflow */
55
71
  output?: unknown;
56
- /** An object with information about the trace generated by the execution */
57
- trace?: PostWorkflowRun200Trace;
72
+ trace?: TraceInfo;
58
73
  };
59
74
  export type PostWorkflowStartBody = {
60
75
  /** The name of the workflow to execute */
@@ -94,31 +109,12 @@ export type GetWorkflowIdStatus200 = {
94
109
  /** An epoch timestamp representing when the workflow ended */
95
110
  completedAt?: number;
96
111
  };
97
- /**
98
- * An object with information about the trace generated by the execution
99
- */
100
- export type GetWorkflowIdOutput200Trace = {
101
- [key: string]: unknown;
102
- };
103
- export type GetWorkflowIdOutput200 = {
112
+ export type GetWorkflowIdResult200 = {
104
113
  /** The workflow execution id */
105
114
  workflowId?: string;
106
- /** The output of workflow */
115
+ /** The result of workflow */
107
116
  output?: unknown;
108
- /** An object with information about the trace generated by the execution */
109
- trace?: GetWorkflowIdOutput200Trace;
110
- };
111
- /**
112
- * The trace tree object containing execution details
113
- */
114
- export type GetWorkflowIdTraceLog200 = {
115
- [key: string]: unknown;
116
- };
117
- export type GetWorkflowIdTraceLog404 = {
118
- /** Error type */
119
- error?: string;
120
- /** Detailed error message */
121
- message?: string;
117
+ trace?: TraceInfo;
122
118
  };
123
119
  export type GetWorkflowCatalogId200 = {
124
120
  /** Each workflow available in this catalog */
@@ -213,45 +209,25 @@ export type patchWorkflowIdStopResponse = (patchWorkflowIdStopResponseSuccess |
213
209
  export declare const getPatchWorkflowIdStopUrl: (id: string) => string;
214
210
  export declare const patchWorkflowIdStop: (id: string, options?: ApiRequestOptions) => Promise<patchWorkflowIdStopResponse>;
215
211
  /**
216
- * @summary Return the output of a workflow
212
+ * @summary Return the result of a workflow
217
213
  */
218
- export type getWorkflowIdOutputResponse200 = {
219
- data: GetWorkflowIdOutput200;
214
+ export type getWorkflowIdResultResponse200 = {
215
+ data: GetWorkflowIdResult200;
220
216
  status: 200;
221
217
  };
222
- export type getWorkflowIdOutputResponse404 = {
218
+ export type getWorkflowIdResultResponse404 = {
223
219
  data: void;
224
220
  status: 404;
225
221
  };
226
- export type getWorkflowIdOutputResponseSuccess = (getWorkflowIdOutputResponse200) & {
227
- headers: Headers;
228
- };
229
- export type getWorkflowIdOutputResponseError = (getWorkflowIdOutputResponse404) & {
230
- headers: Headers;
231
- };
232
- export type getWorkflowIdOutputResponse = (getWorkflowIdOutputResponseSuccess | getWorkflowIdOutputResponseError);
233
- export declare const getGetWorkflowIdOutputUrl: (id: string) => string;
234
- export declare const getWorkflowIdOutput: (id: string, options?: ApiRequestOptions) => Promise<getWorkflowIdOutputResponse>;
235
- /**
236
- * @summary Get the trace log contents from a workflow execution
237
- */
238
- export type getWorkflowIdTraceLogResponse200 = {
239
- data: GetWorkflowIdTraceLog200;
240
- status: 200;
241
- };
242
- export type getWorkflowIdTraceLogResponse404 = {
243
- data: GetWorkflowIdTraceLog404;
244
- status: 404;
245
- };
246
- export type getWorkflowIdTraceLogResponseSuccess = (getWorkflowIdTraceLogResponse200) & {
222
+ export type getWorkflowIdResultResponseSuccess = (getWorkflowIdResultResponse200) & {
247
223
  headers: Headers;
248
224
  };
249
- export type getWorkflowIdTraceLogResponseError = (getWorkflowIdTraceLogResponse404) & {
225
+ export type getWorkflowIdResultResponseError = (getWorkflowIdResultResponse404) & {
250
226
  headers: Headers;
251
227
  };
252
- export type getWorkflowIdTraceLogResponse = (getWorkflowIdTraceLogResponseSuccess | getWorkflowIdTraceLogResponseError);
253
- export declare const getGetWorkflowIdTraceLogUrl: (id: string) => string;
254
- export declare const getWorkflowIdTraceLog: (id: string, options?: ApiRequestOptions) => Promise<getWorkflowIdTraceLogResponse>;
228
+ export type getWorkflowIdResultResponse = (getWorkflowIdResultResponseSuccess | getWorkflowIdResultResponseError);
229
+ export declare const getGetWorkflowIdResultUrl: (id: string) => string;
230
+ export declare const getWorkflowIdResult: (id: string, options?: ApiRequestOptions) => Promise<getWorkflowIdResultResponse>;
255
231
  /**
256
232
  * @summary Get a specific workflow catalog by ID
257
233
  */
@@ -69,20 +69,11 @@ export const patchWorkflowIdStop = async (id, options) => {
69
69
  method: 'PATCH'
70
70
  });
71
71
  };
72
- export const getGetWorkflowIdOutputUrl = (id) => {
73
- return `/workflow/${id}/output`;
72
+ export const getGetWorkflowIdResultUrl = (id) => {
73
+ return `/workflow/${id}/result`;
74
74
  };
75
- export const getWorkflowIdOutput = async (id, options) => {
76
- return customFetchInstance(getGetWorkflowIdOutputUrl(id), {
77
- ...options,
78
- method: 'GET'
79
- });
80
- };
81
- export const getGetWorkflowIdTraceLogUrl = (id) => {
82
- return `/workflow/${id}/trace_log`;
83
- };
84
- export const getWorkflowIdTraceLog = async (id, options) => {
85
- return customFetchInstance(getGetWorkflowIdTraceLogUrl(id), {
75
+ export const getWorkflowIdResult = async (id, options) => {
76
+ return customFetchInstance(getGetWorkflowIdResultUrl(id), {
86
77
  ...options,
87
78
  method: 'GET'
88
79
  });
@@ -80,6 +80,7 @@ services:
80
80
  temporal:
81
81
  condition: service_healthy
82
82
  image: growthxteam/output-api:latest
83
+ pull_policy: always
83
84
  networks:
84
85
  - main
85
86
  environment:
@@ -87,8 +88,6 @@ services:
87
88
  - CATALOG_ID=main
88
89
  - TEMPORAL_ADDRESS=temporal:7233
89
90
  - NODE_ENV=development
90
- volumes:
91
- - ./logs:/app/logs:ro
92
91
  ports:
93
92
  - '3001:3001'
94
93
 
@@ -106,6 +105,7 @@ services:
106
105
  - REDIS_URL=redis://redis:6379
107
106
  - TEMPORAL_ADDRESS=temporal:7233
108
107
  - TRACE_LOCAL_ON=true
108
+ - HOST_TRACE_PATH=${PWD}/logs
109
109
  command: npm run start-worker
110
110
  working_dir: /app
111
111
  volumes:
@@ -7,15 +7,9 @@ export default class WorkflowDebug extends Command {
7
7
  };
8
8
  static flags: {
9
9
  format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
- remote: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
- 'download-dir': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
- open: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
- 'force-download': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
10
  };
15
11
  run(): Promise<void>;
16
- private getLocalTrace;
17
- private getRemoteTrace;
18
- private openInViewer;
19
- private formatDuration;
12
+ private outputJson;
13
+ private displayTextTrace;
20
14
  catch(error: Error): Promise<void>;
21
15
  }
@@ -1,21 +1,14 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
- import * as fs from 'node:fs/promises';
3
- import * as path from 'node:path';
4
- import { existsSync } from 'node:fs';
5
- import { getWorkflowIdOutput } from '#api/generated/api.js';
6
2
  import { OUTPUT_FORMAT } from '#utils/constants.js';
3
+ import { displayDebugTree } from '#utils/trace_formatter.js';
4
+ import { getTrace } from '#services/trace_reader.js';
7
5
  import { handleApiError } from '#utils/error_handler.js';
8
- import { s3Downloader } from '#utils/s3_downloader.js';
9
- import { traceFormatter } from '#utils/trace_formatter.js';
10
- // Note: 'open' dependency is optional for --open flag functionality
11
6
  export default class WorkflowDebug extends Command {
12
7
  static description = 'Get and display workflow execution trace for debugging';
13
8
  static examples = [
14
9
  '<%= config.bin %> <%= command.id %> wf-12345',
15
10
  '<%= config.bin %> <%= command.id %> wf-12345 --format json',
16
- '<%= config.bin %> <%= command.id %> wf-12345 --remote',
17
- '<%= config.bin %> <%= command.id %> wf-12345 --open',
18
- '<%= config.bin %> <%= command.id %> wf-12345 --download-dir ./my-traces'
11
+ '<%= config.bin %> <%= command.id %> wf-12345 --format text'
19
12
  ];
20
13
  static args = {
21
14
  workflowId: Args.string({
@@ -29,169 +22,36 @@ export default class WorkflowDebug extends Command {
29
22
  description: 'Output format',
30
23
  options: [OUTPUT_FORMAT.JSON, OUTPUT_FORMAT.TEXT],
31
24
  default: OUTPUT_FORMAT.TEXT
32
- }),
33
- remote: Flags.boolean({
34
- char: 'r',
35
- description: 'Prefer remote (S3) trace over local',
36
- default: false
37
- }),
38
- 'download-dir': Flags.string({
39
- char: 'd',
40
- description: 'Directory to save downloaded remote traces',
41
- default: path.join(process.cwd(), '.output', 'traces')
42
- }),
43
- open: Flags.boolean({
44
- char: 'o',
45
- description: 'Open trace file in default viewer/browser',
46
- default: false
47
- }),
48
- 'force-download': Flags.boolean({
49
- description: 'Force re-download of remote traces (bypass cache)',
50
- default: false
51
25
  })
52
26
  };
53
27
  async run() {
54
28
  const { args, flags } = await this.parse(WorkflowDebug);
55
- this.log(`Fetching debug information for workflow: ${args.workflowId}...`);
56
- // Get workflow output which includes trace destinations
57
- const response = await getWorkflowIdOutput(args.workflowId);
58
- if (!response || !response.data) {
59
- this.error('API returned invalid response', { exit: 1 });
60
- }
61
- const { trace } = response.data;
62
- const typedTrace = trace;
63
- if (!typedTrace || !typedTrace.destinations) {
64
- this.error('No trace information available for this workflow', { exit: 1 });
65
- }
66
- const { local: localPath, remote: remotePath } = typedTrace.destinations;
67
- // Determine which trace to use based on flags and availability
68
- // eslint-disable-next-line no-restricted-syntax
69
- let traceContent = null;
70
- // eslint-disable-next-line no-restricted-syntax
71
- let traceSource = '';
72
- if (flags.remote && remotePath) {
73
- // User prefers remote trace
74
- traceContent = await this.getRemoteTrace(remotePath, flags);
75
- traceSource = 'remote';
76
- }
77
- else if (localPath) {
78
- // Try local first
79
- traceContent = await this.getLocalTrace(localPath);
80
- traceSource = 'local';
81
- // If local not found but remote available, try remote
82
- if (!traceContent && remotePath && !flags.remote) {
83
- this.log('Local trace not found, trying remote...');
84
- traceContent = await this.getRemoteTrace(remotePath, flags);
85
- traceSource = 'remote';
86
- }
87
- }
88
- else if (remotePath) {
89
- // Only remote available
90
- traceContent = await this.getRemoteTrace(remotePath, flags);
91
- traceSource = 'remote';
92
- }
93
- if (!traceContent) {
94
- this.error('No trace file could be retrieved. The workflow may still be running or trace files may have been deleted.', { exit: 1 });
95
- }
96
- // Parse and validate trace JSON
97
- // eslint-disable-next-line init-declarations, no-restricted-syntax, @typescript-eslint/no-explicit-any
98
- let traceData;
99
- try {
100
- traceData = JSON.parse(traceContent);
101
- }
102
- catch {
103
- this.error('Invalid trace file format: could not parse JSON', { exit: 1 });
104
- }
105
- // Get summary statistics
106
- const summary = traceFormatter.getSummary(traceData);
107
- // Display source information
108
- this.log(`\nTrace source: ${traceSource}`);
109
- this.log(`Total events: ${summary.totalEvents}`);
110
- this.log(`Total steps: ${summary.totalSteps}`);
111
- this.log(`Total activities: ${summary.totalActivities}`);
112
- if (summary.totalDuration > 0) {
113
- this.log(`Total duration: ${this.formatDuration(summary.totalDuration)}`);
114
- }
115
- if (summary.hasErrors) {
116
- this.log('⚠️ Workflow contains errors');
117
- }
118
- this.log('');
119
- // Format and display trace
120
- const formattedOutput = traceFormatter.format(traceData, flags.format);
121
- this.log(formattedOutput);
122
- // Open in viewer if requested
123
- if (flags.open) {
124
- await this.openInViewer(traceContent, args.workflowId, flags['download-dir']);
125
- }
29
+ const isJsonFormat = flags.format === OUTPUT_FORMAT.JSON;
30
+ if (!isJsonFormat) {
31
+ this.log(`Fetching debug information for workflow: ${args.workflowId}...`);
32
+ }
33
+ const traceData = await getTrace(args.workflowId);
34
+ // Output based on format
35
+ if (isJsonFormat) {
36
+ this.outputJson(traceData);
37
+ return;
38
+ }
39
+ // Display text format
40
+ this.displayTextTrace(traceData);
126
41
  }
127
- async getLocalTrace(localPath) {
128
- try {
129
- // Check if file exists
130
- if (!existsSync(localPath)) {
131
- return null;
132
- }
133
- // Read file content
134
- const content = await fs.readFile(localPath, 'utf-8');
135
- return content;
136
- }
137
- catch (error) {
138
- this.warn(`Failed to read local trace file: ${error instanceof Error ? error.message : 'Unknown error'}`);
139
- return null;
140
- }
141
- }
142
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
143
- async getRemoteTrace(remotePath, flags) {
144
- try {
145
- // Check if S3 downloader is available
146
- if (!s3Downloader.isAvailable()) {
147
- this.error('AWS credentials not configured. Please set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables to access remote traces.', { exit: 1 });
148
- }
149
- this.log('Downloading trace from S3...');
150
- // Download with cache support
151
- const content = await s3Downloader.download(remotePath, {
152
- forceDownload: flags['force-download']
153
- });
154
- if (!flags['force-download']) {
155
- this.log('(Using cached version if available)');
156
- }
157
- return content;
158
- }
159
- catch (error) {
160
- this.warn(`Failed to download remote trace: ${error instanceof Error ? error.message : 'Unknown error'}`);
161
- return null;
162
- }
42
+ outputJson(data) {
43
+ this.log(JSON.stringify(data, null, 2));
163
44
  }
164
- async openInViewer(content, workflowId, downloadDir) {
165
- try {
166
- // Save to temporary file
167
- const tempDir = downloadDir;
168
- await fs.mkdir(tempDir, { recursive: true });
169
- const tempFile = path.join(tempDir, `${workflowId}_debug.json`);
170
- await fs.writeFile(tempFile, content, 'utf-8');
171
- this.log(`\nTrace file saved to: ${tempFile}`);
172
- this.log('You can open this file in your preferred JSON viewer or text editor.');
173
- // Note: To automatically open files, install the 'open' package and uncomment below:
174
- // await open(tempFile);
175
- }
176
- catch (error) {
177
- this.warn(`Failed to save file: ${error instanceof Error ? error.message : 'Unknown error'}`);
178
- }
179
- }
180
- formatDuration(ms) {
181
- if (ms < 1000) {
182
- return `${ms}ms`;
183
- }
184
- if (ms < 60000) {
185
- return `${(ms / 1000).toFixed(2)}s`;
186
- }
187
- const minutes = Math.floor(ms / 60000);
188
- const seconds = ((ms % 60000) / 1000).toFixed(0);
189
- return `${minutes}m ${seconds}s`;
45
+ displayTextTrace(traceData) {
46
+ this.log('\nTrace Log:');
47
+ this.log('─'.repeat(80));
48
+ this.log(displayDebugTree(traceData));
49
+ this.log('\n' + '─'.repeat(80));
50
+ this.log('Tip: Use --format json for the full untruncated trace');
190
51
  }
191
52
  async catch(error) {
192
53
  return handleApiError(error, (...args) => this.error(...args), {
193
- 404: 'Workflow not found. Check the workflow ID.',
194
- 500: 'Server error. The workflow may still be running or the trace may not be available yet.'
54
+ 404: 'Workflow not found or trace not available. Check the workflow ID.'
195
55
  });
196
56
  }
197
57
  }