@output.ai/cli 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -171
- package/dist/api/generated/api.d.ts +66 -0
- package/dist/api/generated/api.js +26 -0
- package/dist/assets/docker/docker-compose-dev.yml +0 -1
- package/dist/commands/workflow/runs/list.d.ts +14 -0
- package/dist/commands/workflow/runs/list.js +104 -0
- package/dist/services/workflow_runs.d.ts +14 -0
- package/dist/services/workflow_runs.js +24 -0
- package/dist/templates/project/.gitignore.template +0 -3
- package/dist/templates/project/README.md.template +2 -2
- package/dist/utils/date_formatter.d.ts +15 -0
- package/dist/utils/date_formatter.js +31 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,194 +1,59 @@
|
|
|
1
1
|
# @output.ai/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Command-line interface for creating and running Output Framework workflows.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@output.ai/cli)
|
|
6
|
+
[](https://docs.output.ai/packages/cli)
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
6
9
|
|
|
7
10
|
```bash
|
|
8
|
-
|
|
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
|
-
##
|
|
16
|
-
|
|
17
|
-
### Initialize a New Project
|
|
14
|
+
## Quick Start
|
|
18
15
|
|
|
19
16
|
```bash
|
|
20
|
-
# Create a new
|
|
17
|
+
# Create a new project
|
|
21
18
|
output init my-project
|
|
22
|
-
|
|
19
|
+
cd my-project
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
#
|
|
38
|
-
output
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
#### What It Does
|
|
109
|
-
|
|
110
|
-
The `debug` command retrieves and displays detailed execution traces for debugging workflow runs. It shows:
|
|
111
|
-
- Complete execution timeline with all events
|
|
112
|
-
- Hierarchical execution tree showing workflow structure
|
|
113
|
-
- Step and activity inputs/outputs
|
|
114
|
-
- Error details and stack traces
|
|
115
|
-
- Performance metrics and durations
|
|
116
|
-
|
|
117
|
-
#### Command Options
|
|
118
|
-
|
|
119
|
-
- `--format, -f` - Output format: `text` (default, human-readable) or `json` (raw trace data)
|
|
120
|
-
|
|
121
|
-
#### Environment Variables
|
|
122
|
-
|
|
123
|
-
- `HOST_TRACE_PATH` - When running in Docker, this maps the container's trace log path to the host filesystem path. Set this to your project's `logs` directory (e.g., `${PWD}/logs`). Required for trace files to be accessible from the CLI when workflows run in containers.
|
|
124
|
-
|
|
125
|
-
### Generate a Workflow
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
# Generate a complete workflow with example steps
|
|
129
|
-
output workflow generate my-workflow --description "My awesome workflow"
|
|
130
|
-
|
|
131
|
-
# Generate a minimal skeleton workflow
|
|
132
|
-
output workflow generate my-workflow --skeleton
|
|
133
|
-
|
|
134
|
-
# Generate in a specific directory
|
|
135
|
-
output workflow generate my-workflow --output-dir ./src/workflows
|
|
136
|
-
|
|
137
|
-
# Force overwrite existing workflow
|
|
138
|
-
output workflow generate my-workflow --force
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
#### Command Options
|
|
142
|
-
|
|
143
|
-
- `--description, -d` - Description of the workflow
|
|
144
|
-
- `--skeleton, -s` - Generate minimal skeleton without example steps
|
|
145
|
-
- `--output-dir, -o` - Output directory (default: `src/`)
|
|
146
|
-
- `--force, -f` - Overwrite existing directory
|
|
147
|
-
|
|
148
|
-
#### Generated Structure
|
|
149
|
-
|
|
150
|
-
The CLI creates a complete workflow structure:
|
|
151
|
-
|
|
152
|
-
```
|
|
153
|
-
my-workflow/
|
|
154
|
-
├── workflow.ts # Main workflow definition
|
|
155
|
-
├── steps.ts # Activity/step implementations
|
|
156
|
-
├── prompt@v1.prompt # LLM prompt template (if not skeleton)
|
|
157
|
-
└── README.md # Workflow documentation
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Initialize Agent Configuration
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
# Initialize agent configuration for your coding agent
|
|
164
|
-
output-cli agents init
|
|
165
|
-
|
|
166
|
-
# Specify your agent provider (default: claude-code)
|
|
167
|
-
output-cli agents init --agent-provider claude-code
|
|
168
|
-
|
|
169
|
-
# Force overwrite existing configuration
|
|
170
|
-
output-cli agents init --force
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
#### What It Does
|
|
174
|
-
|
|
175
|
-
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.
|
|
176
|
-
|
|
177
|
-
**Note:** Currently this only works for [Claude Code](https://claude.ai/code), but we plan to add support for other coding agents over time.
|
|
178
|
-
|
|
179
|
-
#### Command Options
|
|
28
|
+
## Command Reference
|
|
180
29
|
|
|
181
|
-
|
|
182
|
-
|
|
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 |
|
|
183
43
|
|
|
184
|
-
|
|
44
|
+
## Development Services
|
|
185
45
|
|
|
186
|
-
|
|
46
|
+
Running `output dev` starts:
|
|
187
47
|
|
|
188
|
-
|
|
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 |
|
|
189
53
|
|
|
190
|
-
|
|
54
|
+
## Documentation
|
|
191
55
|
|
|
192
|
-
|
|
56
|
+
For comprehensive documentation, visit:
|
|
193
57
|
|
|
194
|
-
|
|
58
|
+
- [CLI Reference](https://docs.output.ai/packages/cli)
|
|
59
|
+
- [Getting Started](https://docs.output.ai/quickstart)
|
|
@@ -54,6 +54,39 @@ export interface TraceInfo {
|
|
|
54
54
|
/** File destinations for trace data */
|
|
55
55
|
destinations?: TraceInfoDestinations;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Current run status
|
|
59
|
+
*/
|
|
60
|
+
export type WorkflowRunInfoStatus = typeof WorkflowRunInfoStatus[keyof typeof WorkflowRunInfoStatus];
|
|
61
|
+
export declare const WorkflowRunInfoStatus: {
|
|
62
|
+
readonly running: "running";
|
|
63
|
+
readonly completed: "completed";
|
|
64
|
+
readonly failed: "failed";
|
|
65
|
+
readonly canceled: "canceled";
|
|
66
|
+
readonly terminated: "terminated";
|
|
67
|
+
readonly timed_out: "timed_out";
|
|
68
|
+
readonly continued: "continued";
|
|
69
|
+
};
|
|
70
|
+
export interface WorkflowRunInfo {
|
|
71
|
+
/** Unique identifier for this run */
|
|
72
|
+
workflowId?: string;
|
|
73
|
+
/** Name of the workflow definition */
|
|
74
|
+
workflowType?: string;
|
|
75
|
+
/** Current run status */
|
|
76
|
+
status?: WorkflowRunInfoStatus;
|
|
77
|
+
/** ISO 8601 timestamp of run start */
|
|
78
|
+
startedAt?: string;
|
|
79
|
+
/**
|
|
80
|
+
* ISO 8601 timestamp of completion, or null if still running
|
|
81
|
+
* @nullable
|
|
82
|
+
*/
|
|
83
|
+
completedAt?: string | null;
|
|
84
|
+
}
|
|
85
|
+
export interface WorkflowRunsResponse {
|
|
86
|
+
runs?: WorkflowRunInfo[];
|
|
87
|
+
/** Total number of runs returned */
|
|
88
|
+
count?: number;
|
|
89
|
+
}
|
|
57
90
|
export type PostWorkflowRunBody = {
|
|
58
91
|
/** The name of the workflow to execute */
|
|
59
92
|
workflowName: string;
|
|
@@ -124,6 +157,18 @@ export type GetWorkflowCatalog200 = {
|
|
|
124
157
|
/** Each workflow available in this catalog */
|
|
125
158
|
workflows?: Workflow[];
|
|
126
159
|
};
|
|
160
|
+
export type GetWorkflowRunsParams = {
|
|
161
|
+
/**
|
|
162
|
+
* Filter by workflow type/name
|
|
163
|
+
*/
|
|
164
|
+
workflowType?: string;
|
|
165
|
+
/**
|
|
166
|
+
* Maximum number of runs to return
|
|
167
|
+
* @minimum 1
|
|
168
|
+
* @maximum 1000
|
|
169
|
+
*/
|
|
170
|
+
limit?: number;
|
|
171
|
+
};
|
|
127
172
|
export type PostWorkflowIdFeedbackBody = {
|
|
128
173
|
/** The payload to send to the workflow */
|
|
129
174
|
payload?: unknown;
|
|
@@ -254,6 +299,27 @@ export type getWorkflowCatalogResponseSuccess = (getWorkflowCatalogResponse200)
|
|
|
254
299
|
export type getWorkflowCatalogResponse = (getWorkflowCatalogResponseSuccess);
|
|
255
300
|
export declare const getGetWorkflowCatalogUrl: () => string;
|
|
256
301
|
export declare const getWorkflowCatalog: (options?: ApiRequestOptions) => Promise<getWorkflowCatalogResponse>;
|
|
302
|
+
/**
|
|
303
|
+
* Returns a list of workflow runs with optional filtering by workflow type
|
|
304
|
+
* @summary List workflow runs
|
|
305
|
+
*/
|
|
306
|
+
export type getWorkflowRunsResponse200 = {
|
|
307
|
+
data: WorkflowRunsResponse;
|
|
308
|
+
status: 200;
|
|
309
|
+
};
|
|
310
|
+
export type getWorkflowRunsResponse400 = {
|
|
311
|
+
data: void;
|
|
312
|
+
status: 400;
|
|
313
|
+
};
|
|
314
|
+
export type getWorkflowRunsResponseSuccess = (getWorkflowRunsResponse200) & {
|
|
315
|
+
headers: Headers;
|
|
316
|
+
};
|
|
317
|
+
export type getWorkflowRunsResponseError = (getWorkflowRunsResponse400) & {
|
|
318
|
+
headers: Headers;
|
|
319
|
+
};
|
|
320
|
+
export type getWorkflowRunsResponse = (getWorkflowRunsResponseSuccess | getWorkflowRunsResponseError);
|
|
321
|
+
export declare const getGetWorkflowRunsUrl: (params?: GetWorkflowRunsParams) => string;
|
|
322
|
+
export declare const getWorkflowRuns: (params?: GetWorkflowRunsParams, options?: ApiRequestOptions) => Promise<getWorkflowRunsResponse>;
|
|
257
323
|
/**
|
|
258
324
|
* @summary Send feedback to a payload
|
|
259
325
|
*/
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { customFetchInstance } from '../http_client.js';
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
10
|
+
export const WorkflowRunInfoStatus = {
|
|
11
|
+
running: 'running',
|
|
12
|
+
completed: 'completed',
|
|
13
|
+
failed: 'failed',
|
|
14
|
+
canceled: 'canceled',
|
|
15
|
+
terminated: 'terminated',
|
|
16
|
+
timed_out: 'timed_out',
|
|
17
|
+
continued: 'continued',
|
|
18
|
+
};
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
10
20
|
export const GetWorkflowIdStatus200Status = {
|
|
11
21
|
canceled: 'canceled',
|
|
12
22
|
completed: 'completed',
|
|
@@ -98,6 +108,22 @@ export const getWorkflowCatalog = async (options) => {
|
|
|
98
108
|
method: 'GET'
|
|
99
109
|
});
|
|
100
110
|
};
|
|
111
|
+
export const getGetWorkflowRunsUrl = (params) => {
|
|
112
|
+
const normalizedParams = new URLSearchParams();
|
|
113
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
114
|
+
if (value !== undefined) {
|
|
115
|
+
normalizedParams.append(key, value === null ? 'null' : value.toString());
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const stringifiedParams = normalizedParams.toString();
|
|
119
|
+
return stringifiedParams.length > 0 ? `/workflow/runs?${stringifiedParams}` : `/workflow/runs`;
|
|
120
|
+
};
|
|
121
|
+
export const getWorkflowRuns = async (params, options) => {
|
|
122
|
+
return customFetchInstance(getGetWorkflowRunsUrl(params), {
|
|
123
|
+
...options,
|
|
124
|
+
method: 'GET'
|
|
125
|
+
});
|
|
126
|
+
};
|
|
101
127
|
;
|
|
102
128
|
export const getPostWorkflowIdFeedbackUrl = (id) => {
|
|
103
129
|
return `/workflow/${id}/feedback`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class WorkflowRunsList extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
workflowName: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
catch(error: Error): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
import { fetchWorkflowRuns } from '#services/workflow_runs.js';
|
|
4
|
+
import { formatDate, formatDurationFromTimestamps } from '#utils/date_formatter.js';
|
|
5
|
+
import { handleApiError } from '#utils/error_handler.js';
|
|
6
|
+
const OUTPUT_FORMAT = {
|
|
7
|
+
TABLE: 'table',
|
|
8
|
+
JSON: 'json',
|
|
9
|
+
TEXT: 'text'
|
|
10
|
+
};
|
|
11
|
+
function createRunsTable(runs) {
|
|
12
|
+
const table = new Table({
|
|
13
|
+
head: ['Workflow ID', 'Type', 'Status', 'Started', 'Duration'],
|
|
14
|
+
colWidths: [40, 20, 12, 22, 10],
|
|
15
|
+
wordWrap: true,
|
|
16
|
+
style: {
|
|
17
|
+
head: ['cyan']
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
runs.forEach(run => {
|
|
21
|
+
table.push([
|
|
22
|
+
run.workflowId || '-',
|
|
23
|
+
run.workflowType || '-',
|
|
24
|
+
run.status || '-',
|
|
25
|
+
formatDate(run.startedAt),
|
|
26
|
+
formatDurationFromTimestamps(run.startedAt || '', run.completedAt)
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
return table.toString();
|
|
30
|
+
}
|
|
31
|
+
function formatRunsAsText(runs) {
|
|
32
|
+
if (runs.length === 0) {
|
|
33
|
+
return 'No workflow runs found.';
|
|
34
|
+
}
|
|
35
|
+
return runs.map(run => {
|
|
36
|
+
const duration = formatDurationFromTimestamps(run.startedAt || '', run.completedAt);
|
|
37
|
+
return `${run.workflowId} (${run.workflowType}) - ${run.status} [${duration}]`;
|
|
38
|
+
}).join('\n');
|
|
39
|
+
}
|
|
40
|
+
function formatRunsAsJson(runs) {
|
|
41
|
+
return JSON.stringify(runs, null, 2);
|
|
42
|
+
}
|
|
43
|
+
function formatRuns(runs, format) {
|
|
44
|
+
if (format === OUTPUT_FORMAT.JSON) {
|
|
45
|
+
return formatRunsAsJson(runs);
|
|
46
|
+
}
|
|
47
|
+
if (format === OUTPUT_FORMAT.TABLE) {
|
|
48
|
+
return createRunsTable(runs);
|
|
49
|
+
}
|
|
50
|
+
return formatRunsAsText(runs);
|
|
51
|
+
}
|
|
52
|
+
export default class WorkflowRunsList extends Command {
|
|
53
|
+
static description = 'List workflow runs with optional filtering by workflow type';
|
|
54
|
+
static examples = [
|
|
55
|
+
'<%= config.bin %> <%= command.id %>',
|
|
56
|
+
'<%= config.bin %> <%= command.id %> simple',
|
|
57
|
+
'<%= config.bin %> <%= command.id %> simple --limit 10',
|
|
58
|
+
'<%= config.bin %> <%= command.id %> --format json',
|
|
59
|
+
'<%= config.bin %> <%= command.id %> --format table'
|
|
60
|
+
];
|
|
61
|
+
static args = {
|
|
62
|
+
workflowName: Args.string({
|
|
63
|
+
description: 'Filter by workflow type/name',
|
|
64
|
+
required: false
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
static flags = {
|
|
68
|
+
limit: Flags.integer({
|
|
69
|
+
char: 'l',
|
|
70
|
+
description: 'Maximum number of runs to return',
|
|
71
|
+
default: 100
|
|
72
|
+
}),
|
|
73
|
+
format: Flags.string({
|
|
74
|
+
char: 'f',
|
|
75
|
+
description: 'Output format',
|
|
76
|
+
options: [OUTPUT_FORMAT.TABLE, OUTPUT_FORMAT.JSON, OUTPUT_FORMAT.TEXT],
|
|
77
|
+
default: OUTPUT_FORMAT.TABLE
|
|
78
|
+
})
|
|
79
|
+
};
|
|
80
|
+
async run() {
|
|
81
|
+
const { args, flags } = await this.parse(WorkflowRunsList);
|
|
82
|
+
const { runs, count } = await fetchWorkflowRuns({
|
|
83
|
+
workflowType: args.workflowName,
|
|
84
|
+
limit: flags.limit
|
|
85
|
+
});
|
|
86
|
+
if (runs.length === 0) {
|
|
87
|
+
const filterMsg = args.workflowName ? ` for workflow type "${args.workflowName}"` : '';
|
|
88
|
+
this.log(`No workflow runs found${filterMsg}.`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const output = formatRuns(runs, flags.format);
|
|
92
|
+
this.log(output);
|
|
93
|
+
if (flags.format !== OUTPUT_FORMAT.JSON) {
|
|
94
|
+
const filterMsg = args.workflowName ? ` of type "${args.workflowName}"` : '';
|
|
95
|
+
this.log(`\nFound ${count} run(s)${filterMsg}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async catch(error) {
|
|
99
|
+
return handleApiError(error, (...args) => this.error(...args), {
|
|
100
|
+
400: 'Invalid parameters provided.',
|
|
101
|
+
503: 'Workflow service temporarily unavailable.'
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow runs service for fetching workflow run data from the API
|
|
3
|
+
*/
|
|
4
|
+
import { type WorkflowRunInfo } from '#api/generated/api.js';
|
|
5
|
+
export type WorkflowRun = WorkflowRunInfo;
|
|
6
|
+
export interface WorkflowRunsResult {
|
|
7
|
+
runs: WorkflowRun[];
|
|
8
|
+
count: number;
|
|
9
|
+
}
|
|
10
|
+
export interface FetchWorkflowRunsOptions {
|
|
11
|
+
workflowType?: string;
|
|
12
|
+
limit?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function fetchWorkflowRuns(options?: FetchWorkflowRunsOptions): Promise<WorkflowRunsResult>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow runs service for fetching workflow run data from the API
|
|
3
|
+
*/
|
|
4
|
+
import { getWorkflowRuns } from '#api/generated/api.js';
|
|
5
|
+
export async function fetchWorkflowRuns(options = {}) {
|
|
6
|
+
const params = {};
|
|
7
|
+
if (options.limit) {
|
|
8
|
+
params.limit = options.limit;
|
|
9
|
+
}
|
|
10
|
+
if (options.workflowType) {
|
|
11
|
+
params.workflowType = options.workflowType;
|
|
12
|
+
}
|
|
13
|
+
const response = await getWorkflowRuns(params);
|
|
14
|
+
if (!response) {
|
|
15
|
+
throw new Error('Failed to connect to API server. Is it running?');
|
|
16
|
+
}
|
|
17
|
+
if (!response.data) {
|
|
18
|
+
throw new Error('API returned invalid response (missing data)');
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
runs: response.data.runs || [],
|
|
22
|
+
count: response.data.count || 0
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -30,7 +30,7 @@ Edit `.env` to add:
|
|
|
30
30
|
### 3. Start Output Services
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
output dev
|
|
33
|
+
npx output dev
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
This starts:
|
|
@@ -44,7 +44,7 @@ This starts:
|
|
|
44
44
|
In a new terminal:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
output workflow run simple --input '{"question": "who really is ada lovelace?"}'
|
|
47
|
+
npx output workflow run simple --input '{"question": "who really is ada lovelace?"}'
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
### 5. Stop Services
|
|
@@ -6,3 +6,18 @@
|
|
|
6
6
|
* @returns Formatted duration string (e.g., "150ms", "2.50s", "3 minutes 45 seconds")
|
|
7
7
|
*/
|
|
8
8
|
export declare function formatDuration(ms: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* Format an ISO date string to a human-readable format
|
|
11
|
+
*
|
|
12
|
+
* @param isoString - ISO 8601 date string
|
|
13
|
+
* @returns Formatted date string (e.g., "Dec 3, 2025 10:30 AM")
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatDate(isoString: string | null | undefined): string;
|
|
16
|
+
/**
|
|
17
|
+
* Format a duration between two ISO timestamps
|
|
18
|
+
*
|
|
19
|
+
* @param startedAt - ISO 8601 start timestamp
|
|
20
|
+
* @param completedAt - ISO 8601 end timestamp (or null if still running)
|
|
21
|
+
* @returns Human-readable duration string (e.g., "5 seconds", "running")
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatDurationFromTimestamps(startedAt: string, completedAt: string | null | undefined): string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Date and duration formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import { format, formatDistanceStrict, formatDuration as formatDurationFns, intervalToDuration, parseISO } from 'date-fns';
|
|
2
5
|
/**
|
|
3
6
|
* Format a duration in milliseconds to a human-readable string.
|
|
4
7
|
* Uses date-fns for durations >= 1 minute, custom formatting for shorter durations.
|
|
@@ -17,3 +20,30 @@ export function formatDuration(ms) {
|
|
|
17
20
|
}
|
|
18
21
|
return formatDurationFns(duration, { format: ['minutes', 'seconds'] });
|
|
19
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Format an ISO date string to a human-readable format
|
|
25
|
+
*
|
|
26
|
+
* @param isoString - ISO 8601 date string
|
|
27
|
+
* @returns Formatted date string (e.g., "Dec 3, 2025 10:30 AM")
|
|
28
|
+
*/
|
|
29
|
+
export function formatDate(isoString) {
|
|
30
|
+
if (!isoString) {
|
|
31
|
+
return '-';
|
|
32
|
+
}
|
|
33
|
+
return format(parseISO(isoString), 'MMM d, yyyy h:mm a');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Format a duration between two ISO timestamps
|
|
37
|
+
*
|
|
38
|
+
* @param startedAt - ISO 8601 start timestamp
|
|
39
|
+
* @param completedAt - ISO 8601 end timestamp (or null if still running)
|
|
40
|
+
* @returns Human-readable duration string (e.g., "5 seconds", "running")
|
|
41
|
+
*/
|
|
42
|
+
export function formatDurationFromTimestamps(startedAt, completedAt) {
|
|
43
|
+
if (!completedAt) {
|
|
44
|
+
return 'running';
|
|
45
|
+
}
|
|
46
|
+
const start = parseISO(startedAt);
|
|
47
|
+
const end = parseISO(completedAt);
|
|
48
|
+
return formatDistanceStrict(start, end, { addSuffix: false });
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@output.ai/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "CLI for Output.ai workflow generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -43,7 +43,10 @@
|
|
|
43
43
|
"copyfiles": "2.4.1",
|
|
44
44
|
"orval": "7.13.2"
|
|
45
45
|
},
|
|
46
|
-
"license": "
|
|
46
|
+
"license": "Apache-2.0",
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
47
50
|
"imports": {
|
|
48
51
|
"#*": "./dist/*"
|
|
49
52
|
},
|