@output.ai/cli 0.0.0 → 0.0.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.
- package/README.md +34 -1
- package/dist/api/generated/api.d.ts +272 -0
- package/dist/api/generated/api.js +131 -0
- package/dist/api/http_client.d.ts +6 -0
- package/dist/api/http_client.js +41 -0
- package/dist/api/orval_post_process.d.ts +10 -0
- package/dist/api/orval_post_process.js +33 -0
- package/dist/api/parser.d.ts +17 -0
- package/dist/api/parser.js +71 -0
- package/dist/commands/workflow/list.d.ts +21 -0
- package/dist/commands/workflow/list.js +169 -0
- package/dist/commands/workflow/list.test.d.ts +1 -0
- package/dist/commands/workflow/list.test.js +83 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +19 -0
- package/dist/templates/workflow/README.md.template +2 -2
- package/dist/templates/workflow/workflow.ts.template +2 -2
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -14,6 +14,39 @@ npx @output.ai/cli
|
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
|
+
### List Workflows
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# List all available workflows (simple list, default)
|
|
21
|
+
output-cli workflow list
|
|
22
|
+
|
|
23
|
+
# List workflows with custom API URL
|
|
24
|
+
API_URL=http://localhost:3001 output-cli workflow list
|
|
25
|
+
|
|
26
|
+
# List workflows with authentication
|
|
27
|
+
API_AUTH_TOKEN=your-token output-cli workflow list
|
|
28
|
+
|
|
29
|
+
# Show detailed table view with all information
|
|
30
|
+
output-cli workflow list --format table
|
|
31
|
+
|
|
32
|
+
# Show detailed table with expanded parameter info
|
|
33
|
+
output-cli workflow list --format table --detailed
|
|
34
|
+
|
|
35
|
+
# List workflows in JSON format
|
|
36
|
+
output-cli workflow list --format json
|
|
37
|
+
|
|
38
|
+
# Filter workflows by name (partial match)
|
|
39
|
+
output-cli workflow list --filter simple
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Command Options
|
|
43
|
+
|
|
44
|
+
- `--format, -f` - Output format: `list` (default, simple column), `table`, or `json`
|
|
45
|
+
- `--detailed, -d` - Show detailed parameter information in table view
|
|
46
|
+
- `--filter` - Filter workflows by name (case-insensitive partial match)
|
|
47
|
+
|
|
48
|
+
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.
|
|
49
|
+
|
|
17
50
|
### Generate a Workflow
|
|
18
51
|
|
|
19
52
|
```bash
|
|
@@ -44,7 +77,7 @@ The CLI creates a complete workflow structure:
|
|
|
44
77
|
```
|
|
45
78
|
my-workflow/
|
|
46
79
|
├── index.ts # Main workflow definition
|
|
47
|
-
├── steps.ts # Activity/step implementations
|
|
80
|
+
├── steps.ts # Activity/step implementations
|
|
48
81
|
├── types.ts # TypeScript interfaces
|
|
49
82
|
├── prompt@v1.prompt # LLM prompt template (if not skeleton)
|
|
50
83
|
└── README.md # Workflow documentation
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
export type JSONSchemaProperties = {
|
|
2
|
+
[key: string]: JSONSchema;
|
|
3
|
+
};
|
|
4
|
+
export type JSONSchemaPropertyNames = {
|
|
5
|
+
type?: string;
|
|
6
|
+
};
|
|
7
|
+
export interface JSONSchema {
|
|
8
|
+
$schema?: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
properties?: JSONSchemaProperties;
|
|
11
|
+
items?: JSONSchema;
|
|
12
|
+
required?: string[];
|
|
13
|
+
description?: string;
|
|
14
|
+
additionalProperties?: boolean;
|
|
15
|
+
propertyNames?: JSONSchemaPropertyNames;
|
|
16
|
+
anyOf?: JSONSchema[];
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface Workflow {
|
|
20
|
+
/** The name of the workflow */
|
|
21
|
+
name: string;
|
|
22
|
+
/** The description of the workflow */
|
|
23
|
+
description?: string;
|
|
24
|
+
inputSchema?: JSONSchema;
|
|
25
|
+
outputSchema?: JSONSchema;
|
|
26
|
+
}
|
|
27
|
+
export type PostWorkflowRunBody = {
|
|
28
|
+
/** The name of the workflow to execute */
|
|
29
|
+
workflowName: string;
|
|
30
|
+
/** The payload to send to the workflow */
|
|
31
|
+
input: unknown;
|
|
32
|
+
/** The name of the task queue to send the workflow to */
|
|
33
|
+
taskQueue?: string;
|
|
34
|
+
};
|
|
35
|
+
export type PostWorkflowRun200 = {
|
|
36
|
+
/** The workflow execution id */
|
|
37
|
+
workflowId?: string;
|
|
38
|
+
/** The output of the the workflow */
|
|
39
|
+
output?: unknown;
|
|
40
|
+
};
|
|
41
|
+
export type PostWorkflowStartBody = {
|
|
42
|
+
/** The name of the workflow to execute */
|
|
43
|
+
workflowName: string;
|
|
44
|
+
/** The payload to send to the workflow */
|
|
45
|
+
input: unknown;
|
|
46
|
+
/** The name of the task queue to send the workflow to */
|
|
47
|
+
taskQueue?: string;
|
|
48
|
+
};
|
|
49
|
+
export type PostWorkflowStart200 = {
|
|
50
|
+
/** The id of the started workflow */
|
|
51
|
+
workflowId?: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* The workflow execution status
|
|
55
|
+
*/
|
|
56
|
+
export type GetWorkflowIdStatus200Status = typeof GetWorkflowIdStatus200Status[keyof typeof GetWorkflowIdStatus200Status];
|
|
57
|
+
export declare const GetWorkflowIdStatus200Status: {
|
|
58
|
+
readonly canceled: "canceled";
|
|
59
|
+
readonly completed: "completed";
|
|
60
|
+
readonly continued_as_new: "continued_as_new";
|
|
61
|
+
readonly failed: "failed";
|
|
62
|
+
readonly running: "running";
|
|
63
|
+
readonly terminated: "terminated";
|
|
64
|
+
readonly timed_out: "timed_out";
|
|
65
|
+
readonly unspecified: "unspecified";
|
|
66
|
+
};
|
|
67
|
+
export type GetWorkflowIdStatus200 = {
|
|
68
|
+
/** The id of workflow */
|
|
69
|
+
workflowId?: string;
|
|
70
|
+
/** The workflow execution status */
|
|
71
|
+
status?: GetWorkflowIdStatus200Status;
|
|
72
|
+
/** An epoch timestamp representing when the workflow started */
|
|
73
|
+
startedAt?: number;
|
|
74
|
+
/** An epoch timestamp representing when the workflow ended */
|
|
75
|
+
completedAt?: number;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* The output of workflow
|
|
79
|
+
*/
|
|
80
|
+
export type GetWorkflowIdOutput200Output = {
|
|
81
|
+
[key: string]: unknown;
|
|
82
|
+
};
|
|
83
|
+
export type GetWorkflowIdOutput200 = {
|
|
84
|
+
/** The workflow execution id */
|
|
85
|
+
workflowId?: string;
|
|
86
|
+
/** The output of workflow */
|
|
87
|
+
output?: GetWorkflowIdOutput200Output;
|
|
88
|
+
};
|
|
89
|
+
export type GetWorkflowCatalogId200 = {
|
|
90
|
+
/** Each workflow available in this catalog */
|
|
91
|
+
workflows?: Workflow[];
|
|
92
|
+
};
|
|
93
|
+
export type GetWorkflowCatalog200 = {
|
|
94
|
+
/** Each workflow available in this catalog */
|
|
95
|
+
workflows?: Workflow[];
|
|
96
|
+
};
|
|
97
|
+
export type PostWorkflowIdFeedbackBody = {
|
|
98
|
+
/** The payload to send to the workflow */
|
|
99
|
+
payload?: unknown;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* @summary Health check the API
|
|
103
|
+
*/
|
|
104
|
+
export type getHealthResponse200 = {
|
|
105
|
+
data: void;
|
|
106
|
+
status: 200;
|
|
107
|
+
};
|
|
108
|
+
export type getHealthResponseSuccess = (getHealthResponse200) & {
|
|
109
|
+
headers: Headers;
|
|
110
|
+
};
|
|
111
|
+
export type getHealthResponse = (getHealthResponseSuccess);
|
|
112
|
+
export declare const getGetHealthUrl: () => string;
|
|
113
|
+
export declare const getHealth: (options?: RequestInit) => Promise<getHealthResponse>;
|
|
114
|
+
/**
|
|
115
|
+
* Executes a workflow and waits for it to complete before returning the result
|
|
116
|
+
* @summary Execute a workflow synchronously
|
|
117
|
+
*/
|
|
118
|
+
export type postWorkflowRunResponse200 = {
|
|
119
|
+
data: PostWorkflowRun200;
|
|
120
|
+
status: 200;
|
|
121
|
+
};
|
|
122
|
+
export type postWorkflowRunResponseSuccess = (postWorkflowRunResponse200) & {
|
|
123
|
+
headers: Headers;
|
|
124
|
+
};
|
|
125
|
+
export type postWorkflowRunResponse = (postWorkflowRunResponseSuccess);
|
|
126
|
+
export declare const getPostWorkflowRunUrl: () => string;
|
|
127
|
+
export declare const postWorkflowRun: (postWorkflowRunBody: PostWorkflowRunBody, options?: RequestInit) => Promise<postWorkflowRunResponse>;
|
|
128
|
+
/**
|
|
129
|
+
* @summary Start a workflow asynchronously
|
|
130
|
+
*/
|
|
131
|
+
export type postWorkflowStartResponse200 = {
|
|
132
|
+
data: PostWorkflowStart200;
|
|
133
|
+
status: 200;
|
|
134
|
+
};
|
|
135
|
+
export type postWorkflowStartResponseSuccess = (postWorkflowStartResponse200) & {
|
|
136
|
+
headers: Headers;
|
|
137
|
+
};
|
|
138
|
+
export type postWorkflowStartResponse = (postWorkflowStartResponseSuccess);
|
|
139
|
+
export declare const getPostWorkflowStartUrl: () => string;
|
|
140
|
+
export declare const postWorkflowStart: (postWorkflowStartBody: PostWorkflowStartBody, options?: RequestInit) => Promise<postWorkflowStartResponse>;
|
|
141
|
+
/**
|
|
142
|
+
* @summary Get workflow execution status
|
|
143
|
+
*/
|
|
144
|
+
export type getWorkflowIdStatusResponse200 = {
|
|
145
|
+
data: GetWorkflowIdStatus200;
|
|
146
|
+
status: 200;
|
|
147
|
+
};
|
|
148
|
+
export type getWorkflowIdStatusResponse404 = {
|
|
149
|
+
data: void;
|
|
150
|
+
status: 404;
|
|
151
|
+
};
|
|
152
|
+
export type getWorkflowIdStatusResponseSuccess = (getWorkflowIdStatusResponse200) & {
|
|
153
|
+
headers: Headers;
|
|
154
|
+
};
|
|
155
|
+
export type getWorkflowIdStatusResponseError = (getWorkflowIdStatusResponse404) & {
|
|
156
|
+
headers: Headers;
|
|
157
|
+
};
|
|
158
|
+
export type getWorkflowIdStatusResponse = (getWorkflowIdStatusResponseSuccess | getWorkflowIdStatusResponseError);
|
|
159
|
+
export declare const getGetWorkflowIdStatusUrl: (id: unknown) => string;
|
|
160
|
+
export declare const getWorkflowIdStatus: (id: unknown, options?: RequestInit) => Promise<getWorkflowIdStatusResponse>;
|
|
161
|
+
/**
|
|
162
|
+
* @summary Stop a workflow execution
|
|
163
|
+
*/
|
|
164
|
+
export type patchWorkflowIdStopResponse200 = {
|
|
165
|
+
data: void;
|
|
166
|
+
status: 200;
|
|
167
|
+
};
|
|
168
|
+
export type patchWorkflowIdStopResponse404 = {
|
|
169
|
+
data: void;
|
|
170
|
+
status: 404;
|
|
171
|
+
};
|
|
172
|
+
export type patchWorkflowIdStopResponseSuccess = (patchWorkflowIdStopResponse200) & {
|
|
173
|
+
headers: Headers;
|
|
174
|
+
};
|
|
175
|
+
export type patchWorkflowIdStopResponseError = (patchWorkflowIdStopResponse404) & {
|
|
176
|
+
headers: Headers;
|
|
177
|
+
};
|
|
178
|
+
export type patchWorkflowIdStopResponse = (patchWorkflowIdStopResponseSuccess | patchWorkflowIdStopResponseError);
|
|
179
|
+
export declare const getPatchWorkflowIdStopUrl: (id: unknown) => string;
|
|
180
|
+
export declare const patchWorkflowIdStop: (id: unknown, options?: RequestInit) => Promise<patchWorkflowIdStopResponse>;
|
|
181
|
+
/**
|
|
182
|
+
* @summary Return the output of a workflow
|
|
183
|
+
*/
|
|
184
|
+
export type getWorkflowIdOutputResponse200 = {
|
|
185
|
+
data: GetWorkflowIdOutput200;
|
|
186
|
+
status: 200;
|
|
187
|
+
};
|
|
188
|
+
export type getWorkflowIdOutputResponse404 = {
|
|
189
|
+
data: void;
|
|
190
|
+
status: 404;
|
|
191
|
+
};
|
|
192
|
+
export type getWorkflowIdOutputResponseSuccess = (getWorkflowIdOutputResponse200) & {
|
|
193
|
+
headers: Headers;
|
|
194
|
+
};
|
|
195
|
+
export type getWorkflowIdOutputResponseError = (getWorkflowIdOutputResponse404) & {
|
|
196
|
+
headers: Headers;
|
|
197
|
+
};
|
|
198
|
+
export type getWorkflowIdOutputResponse = (getWorkflowIdOutputResponseSuccess | getWorkflowIdOutputResponseError);
|
|
199
|
+
export declare const getGetWorkflowIdOutputUrl: (id: unknown) => string;
|
|
200
|
+
export declare const getWorkflowIdOutput: (id: unknown, options?: RequestInit) => Promise<getWorkflowIdOutputResponse>;
|
|
201
|
+
/**
|
|
202
|
+
* @summary Return the trace of a workflow execution
|
|
203
|
+
*/
|
|
204
|
+
export type getWorkflowIdTraceResponse200 = {
|
|
205
|
+
data: string[];
|
|
206
|
+
status: 200;
|
|
207
|
+
};
|
|
208
|
+
export type getWorkflowIdTraceResponse404 = {
|
|
209
|
+
data: void;
|
|
210
|
+
status: 404;
|
|
211
|
+
};
|
|
212
|
+
export type getWorkflowIdTraceResponseSuccess = (getWorkflowIdTraceResponse200) & {
|
|
213
|
+
headers: Headers;
|
|
214
|
+
};
|
|
215
|
+
export type getWorkflowIdTraceResponseError = (getWorkflowIdTraceResponse404) & {
|
|
216
|
+
headers: Headers;
|
|
217
|
+
};
|
|
218
|
+
export type getWorkflowIdTraceResponse = (getWorkflowIdTraceResponseSuccess | getWorkflowIdTraceResponseError);
|
|
219
|
+
export declare const getGetWorkflowIdTraceUrl: (id: unknown) => string;
|
|
220
|
+
export declare const getWorkflowIdTrace: (id: unknown, options?: RequestInit) => Promise<getWorkflowIdTraceResponse>;
|
|
221
|
+
/**
|
|
222
|
+
* @summary Get a specific workflow catalog by ID
|
|
223
|
+
*/
|
|
224
|
+
export type getWorkflowCatalogIdResponse200 = {
|
|
225
|
+
data: GetWorkflowCatalogId200;
|
|
226
|
+
status: 200;
|
|
227
|
+
};
|
|
228
|
+
export type getWorkflowCatalogIdResponseSuccess = (getWorkflowCatalogIdResponse200) & {
|
|
229
|
+
headers: Headers;
|
|
230
|
+
};
|
|
231
|
+
export type getWorkflowCatalogIdResponse = (getWorkflowCatalogIdResponseSuccess);
|
|
232
|
+
export declare const getGetWorkflowCatalogIdUrl: (id: unknown) => string;
|
|
233
|
+
export declare const getWorkflowCatalogId: (id: unknown, options?: RequestInit) => Promise<getWorkflowCatalogIdResponse>;
|
|
234
|
+
/**
|
|
235
|
+
* @summary Get the default workflow catalog
|
|
236
|
+
*/
|
|
237
|
+
export type getWorkflowCatalogResponse200 = {
|
|
238
|
+
data: GetWorkflowCatalog200;
|
|
239
|
+
status: 200;
|
|
240
|
+
};
|
|
241
|
+
export type getWorkflowCatalogResponseSuccess = (getWorkflowCatalogResponse200) & {
|
|
242
|
+
headers: Headers;
|
|
243
|
+
};
|
|
244
|
+
export type getWorkflowCatalogResponse = (getWorkflowCatalogResponseSuccess);
|
|
245
|
+
export declare const getGetWorkflowCatalogUrl: () => string;
|
|
246
|
+
export declare const getWorkflowCatalog: (options?: RequestInit) => Promise<getWorkflowCatalogResponse>;
|
|
247
|
+
/**
|
|
248
|
+
* @summary Send feedback to a payload
|
|
249
|
+
*/
|
|
250
|
+
export type postWorkflowIdFeedbackResponse200 = {
|
|
251
|
+
data: void;
|
|
252
|
+
status: 200;
|
|
253
|
+
};
|
|
254
|
+
export type postWorkflowIdFeedbackResponseSuccess = (postWorkflowIdFeedbackResponse200) & {
|
|
255
|
+
headers: Headers;
|
|
256
|
+
};
|
|
257
|
+
export type postWorkflowIdFeedbackResponse = (postWorkflowIdFeedbackResponseSuccess);
|
|
258
|
+
export declare const getPostWorkflowIdFeedbackUrl: (id: unknown) => string;
|
|
259
|
+
export declare const postWorkflowIdFeedback: (id: unknown, postWorkflowIdFeedbackBody: PostWorkflowIdFeedbackBody, options?: RequestInit) => Promise<postWorkflowIdFeedbackResponse>;
|
|
260
|
+
/**
|
|
261
|
+
* @summary A dummy post endpoint for test only
|
|
262
|
+
*/
|
|
263
|
+
export type postHeartbeatResponse204 = {
|
|
264
|
+
data: void;
|
|
265
|
+
status: 204;
|
|
266
|
+
};
|
|
267
|
+
export type postHeartbeatResponseSuccess = (postHeartbeatResponse204) & {
|
|
268
|
+
headers: Headers;
|
|
269
|
+
};
|
|
270
|
+
export type postHeartbeatResponse = (postHeartbeatResponseSuccess);
|
|
271
|
+
export declare const getPostHeartbeatUrl: () => string;
|
|
272
|
+
export declare const postHeartbeat: (options?: RequestInit) => Promise<postHeartbeatResponse>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by orval v7.13.0 🍺
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
* Output.ai SDK API
|
|
5
|
+
* API for managing and executing Temporal workflows through Flow SDK
|
|
6
|
+
* OpenAPI spec version: 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
import { customFetchInstance } from '../http_client.js';
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
10
|
+
export const GetWorkflowIdStatus200Status = {
|
|
11
|
+
canceled: 'canceled',
|
|
12
|
+
completed: 'completed',
|
|
13
|
+
continued_as_new: 'continued_as_new',
|
|
14
|
+
failed: 'failed',
|
|
15
|
+
running: 'running',
|
|
16
|
+
terminated: 'terminated',
|
|
17
|
+
timed_out: 'timed_out',
|
|
18
|
+
unspecified: 'unspecified',
|
|
19
|
+
};
|
|
20
|
+
;
|
|
21
|
+
export const getGetHealthUrl = () => {
|
|
22
|
+
return `/health`;
|
|
23
|
+
};
|
|
24
|
+
export const getHealth = async (options) => {
|
|
25
|
+
return customFetchInstance(getGetHealthUrl(), {
|
|
26
|
+
...options,
|
|
27
|
+
method: 'GET'
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
;
|
|
31
|
+
export const getPostWorkflowRunUrl = () => {
|
|
32
|
+
return `/workflow/run`;
|
|
33
|
+
};
|
|
34
|
+
export const postWorkflowRun = async (postWorkflowRunBody, options) => {
|
|
35
|
+
return customFetchInstance(getPostWorkflowRunUrl(), {
|
|
36
|
+
...options,
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
39
|
+
body: JSON.stringify(postWorkflowRunBody)
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
;
|
|
43
|
+
export const getPostWorkflowStartUrl = () => {
|
|
44
|
+
return `/workflow/start`;
|
|
45
|
+
};
|
|
46
|
+
export const postWorkflowStart = async (postWorkflowStartBody, options) => {
|
|
47
|
+
return customFetchInstance(getPostWorkflowStartUrl(), {
|
|
48
|
+
...options,
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
51
|
+
body: JSON.stringify(postWorkflowStartBody)
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
export const getGetWorkflowIdStatusUrl = (id) => {
|
|
55
|
+
return `/workflow/${id}/status`;
|
|
56
|
+
};
|
|
57
|
+
export const getWorkflowIdStatus = async (id, options) => {
|
|
58
|
+
return customFetchInstance(getGetWorkflowIdStatusUrl(id), {
|
|
59
|
+
...options,
|
|
60
|
+
method: 'GET'
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
export const getPatchWorkflowIdStopUrl = (id) => {
|
|
64
|
+
return `/workflow/${id}/stop`;
|
|
65
|
+
};
|
|
66
|
+
export const patchWorkflowIdStop = async (id, options) => {
|
|
67
|
+
return customFetchInstance(getPatchWorkflowIdStopUrl(id), {
|
|
68
|
+
...options,
|
|
69
|
+
method: 'PATCH'
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
export const getGetWorkflowIdOutputUrl = (id) => {
|
|
73
|
+
return `/workflow/${id}/output`;
|
|
74
|
+
};
|
|
75
|
+
export const getWorkflowIdOutput = async (id, options) => {
|
|
76
|
+
return customFetchInstance(getGetWorkflowIdOutputUrl(id), {
|
|
77
|
+
...options,
|
|
78
|
+
method: 'GET'
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
export const getGetWorkflowIdTraceUrl = (id) => {
|
|
82
|
+
return `/workflow/${id}/trace`;
|
|
83
|
+
};
|
|
84
|
+
export const getWorkflowIdTrace = async (id, options) => {
|
|
85
|
+
return customFetchInstance(getGetWorkflowIdTraceUrl(id), {
|
|
86
|
+
...options,
|
|
87
|
+
method: 'GET'
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
;
|
|
91
|
+
export const getGetWorkflowCatalogIdUrl = (id) => {
|
|
92
|
+
return `/workflow/catalog/${id}`;
|
|
93
|
+
};
|
|
94
|
+
export const getWorkflowCatalogId = async (id, options) => {
|
|
95
|
+
return customFetchInstance(getGetWorkflowCatalogIdUrl(id), {
|
|
96
|
+
...options,
|
|
97
|
+
method: 'GET'
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
;
|
|
101
|
+
export const getGetWorkflowCatalogUrl = () => {
|
|
102
|
+
return `/workflow/catalog`;
|
|
103
|
+
};
|
|
104
|
+
export const getWorkflowCatalog = async (options) => {
|
|
105
|
+
return customFetchInstance(getGetWorkflowCatalogUrl(), {
|
|
106
|
+
...options,
|
|
107
|
+
method: 'GET'
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
;
|
|
111
|
+
export const getPostWorkflowIdFeedbackUrl = (id) => {
|
|
112
|
+
return `/workflow/${id}/feedback`;
|
|
113
|
+
};
|
|
114
|
+
export const postWorkflowIdFeedback = async (id, postWorkflowIdFeedbackBody, options) => {
|
|
115
|
+
return customFetchInstance(getPostWorkflowIdFeedbackUrl(id), {
|
|
116
|
+
...options,
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
119
|
+
body: JSON.stringify(postWorkflowIdFeedbackBody)
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
;
|
|
123
|
+
export const getPostHeartbeatUrl = () => {
|
|
124
|
+
return `/heartbeat`;
|
|
125
|
+
};
|
|
126
|
+
export const postHeartbeat = async (options) => {
|
|
127
|
+
return customFetchInstance(getPostHeartbeatUrl(), {
|
|
128
|
+
...options,
|
|
129
|
+
method: 'POST'
|
|
130
|
+
});
|
|
131
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom ky-based HTTP client for Orval-generated API
|
|
3
|
+
*/
|
|
4
|
+
import ky from 'ky';
|
|
5
|
+
import { config } from '../config.js';
|
|
6
|
+
const api = ky.create({
|
|
7
|
+
prefixUrl: config.apiUrl,
|
|
8
|
+
timeout: config.requestTimeout,
|
|
9
|
+
retry: {
|
|
10
|
+
limit: 2,
|
|
11
|
+
methods: ['get', 'put', 'head', 'delete', 'options', 'trace'],
|
|
12
|
+
statusCodes: [408, 413, 429, 500, 502, 503, 504]
|
|
13
|
+
},
|
|
14
|
+
hooks: {
|
|
15
|
+
beforeRequest: [
|
|
16
|
+
request => {
|
|
17
|
+
// Add auth token if available
|
|
18
|
+
if (config.apiToken) {
|
|
19
|
+
request.headers.set('Authorization', `Basic ${config.apiToken}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const stripLeadingSlash = (url) => url.startsWith('/') ? url.slice(1) : url;
|
|
26
|
+
const buildKyOptions = (options) => ({
|
|
27
|
+
method: options.method,
|
|
28
|
+
headers: options.headers,
|
|
29
|
+
searchParams: options.params,
|
|
30
|
+
body: options.body && options.method !== 'GET' ? options.body : undefined
|
|
31
|
+
});
|
|
32
|
+
const wrapResponse = (response, data) => ({
|
|
33
|
+
data,
|
|
34
|
+
status: response.status,
|
|
35
|
+
headers: response.headers
|
|
36
|
+
});
|
|
37
|
+
export const customFetchInstance = async (url, options) => {
|
|
38
|
+
const response = await api(stripLeadingSlash(url), buildKyOptions(options));
|
|
39
|
+
const data = await response.json().catch(() => undefined);
|
|
40
|
+
return wrapResponse(response, data);
|
|
41
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orval post-generation hook to fix ES module imports by adding .js extensions.
|
|
3
|
+
* This is necessary because the SDK uses "type": "module" in package.json,
|
|
4
|
+
* which requires all relative imports to have explicit .js extensions.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fixEsmImports(outputPath: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Run ESLint fix on generated files to ensure they follow project standards
|
|
9
|
+
*/
|
|
10
|
+
export declare function runEslintFix(): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
/**
|
|
4
|
+
* Orval post-generation hook to fix ES module imports by adding .js extensions.
|
|
5
|
+
* This is necessary because the SDK uses "type": "module" in package.json,
|
|
6
|
+
* which requires all relative imports to have explicit .js extensions.
|
|
7
|
+
*/
|
|
8
|
+
export async function fixEsmImports(outputPath) {
|
|
9
|
+
const content = readFileSync(outputPath, 'utf8');
|
|
10
|
+
const fixedContent = content.replace(/from '\.\.\/http_client'/g, 'from \'../http_client.js\'');
|
|
11
|
+
writeFileSync(outputPath, fixedContent, 'utf8');
|
|
12
|
+
console.log('✅ Fixed ESM imports in Orval generated file');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run ESLint fix on generated files to ensure they follow project standards
|
|
16
|
+
*/
|
|
17
|
+
export async function runEslintFix() {
|
|
18
|
+
try {
|
|
19
|
+
execSync('npx eslint --fix src/api/generated/api.ts', {
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
stdio: 'pipe' // Suppress output
|
|
22
|
+
});
|
|
23
|
+
console.log('✅ Applied ESLint fixes to generated file');
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof Error && 'status' in error && error.status === 1) {
|
|
27
|
+
console.log('✅ Applied ESLint fixes to generated file (with warnings)');
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.warn('⚠️ ESLint fix encountered an issue:', error instanceof Error ? error.message : error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Workflow } from './generated/api.js';
|
|
2
|
+
interface WorkflowParameter {
|
|
3
|
+
name: string;
|
|
4
|
+
type: string;
|
|
5
|
+
required: boolean;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
interface ParsedWorkflow {
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
inputs: WorkflowParameter[];
|
|
12
|
+
outputs: WorkflowParameter[];
|
|
13
|
+
}
|
|
14
|
+
export declare function parseWorkflowDefinition(workflow: Workflow): ParsedWorkflow;
|
|
15
|
+
export declare function formatParameterType(param: WorkflowParameter): string;
|
|
16
|
+
export declare function formatParameters(params: WorkflowParameter[]): string;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// json-schema-library is a CommonJS module that doesn't properly export named exports for ESM.
|
|
2
|
+
// We need to use the default import pattern and destructure from it.
|
|
3
|
+
import pkg from 'json-schema-library';
|
|
4
|
+
const { compileSchema, draft07 } = pkg;
|
|
5
|
+
function formatType(schema) {
|
|
6
|
+
if (!schema) {
|
|
7
|
+
return 'any';
|
|
8
|
+
}
|
|
9
|
+
if (schema.type === 'array') {
|
|
10
|
+
const itemsType = schema.items?.type || 'any';
|
|
11
|
+
return `array<${itemsType}>`;
|
|
12
|
+
}
|
|
13
|
+
return schema.type || 'any';
|
|
14
|
+
}
|
|
15
|
+
function processProperties(properties, prefix = '', requiredList = []) {
|
|
16
|
+
return Object.entries(properties).flatMap(([key, propSchema]) => {
|
|
17
|
+
const prop = propSchema;
|
|
18
|
+
const propName = prefix ? `${prefix}.${key}` : key;
|
|
19
|
+
if (prop.type === 'object' && prop.properties) {
|
|
20
|
+
const nestedRequired = prop.required || [];
|
|
21
|
+
return processProperties(prop.properties, propName, nestedRequired);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
name: propName,
|
|
25
|
+
type: formatType(prop),
|
|
26
|
+
required: requiredList.includes(key),
|
|
27
|
+
description: prop.description
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function extractParametersFromSchema(schema) {
|
|
32
|
+
if (!schema) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const schemaNode = compileSchema(schema, { drafts: [draft07] });
|
|
36
|
+
const compiledSchema = schemaNode.schema;
|
|
37
|
+
if (compiledSchema.type === 'object' && compiledSchema.properties) {
|
|
38
|
+
const required = compiledSchema.required || [];
|
|
39
|
+
return processProperties(compiledSchema.properties, '', required);
|
|
40
|
+
}
|
|
41
|
+
if (compiledSchema.type) {
|
|
42
|
+
return [{
|
|
43
|
+
name: 'value',
|
|
44
|
+
type: compiledSchema.type,
|
|
45
|
+
required: true,
|
|
46
|
+
description: compiledSchema.description
|
|
47
|
+
}];
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
export function parseWorkflowDefinition(workflow) {
|
|
52
|
+
return {
|
|
53
|
+
name: workflow.name,
|
|
54
|
+
description: workflow.description,
|
|
55
|
+
inputs: extractParametersFromSchema(workflow.inputSchema),
|
|
56
|
+
outputs: extractParametersFromSchema(workflow.outputSchema)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function formatParameterType(param) {
|
|
60
|
+
const typeStr = param.type;
|
|
61
|
+
const reqStr = param.required ? '' : '?';
|
|
62
|
+
return `${typeStr}${reqStr}`;
|
|
63
|
+
}
|
|
64
|
+
export function formatParameters(params) {
|
|
65
|
+
if (params.length === 0) {
|
|
66
|
+
return 'none';
|
|
67
|
+
}
|
|
68
|
+
return params
|
|
69
|
+
.map(p => `${p.name}: ${formatParameterType(p)}`)
|
|
70
|
+
.join(', ');
|
|
71
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { type Workflow } from '../../api/generated/api.js';
|
|
3
|
+
interface WorkflowDisplay {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputs: string;
|
|
7
|
+
outputs: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseWorkflowForDisplay(workflow: Workflow): WorkflowDisplay;
|
|
10
|
+
export default class WorkflowList extends Command {
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: string[];
|
|
13
|
+
static flags: {
|
|
14
|
+
format: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
15
|
+
detailed: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
16
|
+
filter: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
private handleError;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
import { getWorkflowCatalog } from '../../api/generated/api.js';
|
|
4
|
+
import { parseWorkflowDefinition, formatParameters } from '../../api/parser.js';
|
|
5
|
+
import { config } from '../../config.js';
|
|
6
|
+
const OUTPUT_FORMAT = {
|
|
7
|
+
LIST: 'list',
|
|
8
|
+
TABLE: 'table',
|
|
9
|
+
JSON: 'json'
|
|
10
|
+
};
|
|
11
|
+
export function parseWorkflowForDisplay(workflow) {
|
|
12
|
+
const parsed = parseWorkflowDefinition(workflow);
|
|
13
|
+
return {
|
|
14
|
+
name: parsed.name,
|
|
15
|
+
description: parsed.description || 'No description',
|
|
16
|
+
inputs: formatParameters(parsed.inputs),
|
|
17
|
+
outputs: formatParameters(parsed.outputs)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function caseInsensitiveIncludes(str, filter) {
|
|
21
|
+
return str.toLowerCase().includes(filter.toLowerCase());
|
|
22
|
+
}
|
|
23
|
+
function matchName(filterString) {
|
|
24
|
+
return workflow => {
|
|
25
|
+
const name = workflow.name || '';
|
|
26
|
+
return caseInsensitiveIncludes(name, filterString);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function sortWorkflowsByName(workflows) {
|
|
30
|
+
return [...workflows].sort((a, b) => {
|
|
31
|
+
const nameA = (a.name || '').toLowerCase();
|
|
32
|
+
const nameB = (b.name || '').toLowerCase();
|
|
33
|
+
return nameA.localeCompare(nameB);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function createWorkflowTable(workflows, detailed) {
|
|
37
|
+
const table = new Table({
|
|
38
|
+
head: ['Name', 'Description', 'Inputs', 'Outputs'],
|
|
39
|
+
colWidths: detailed ? [25, 40, 40, 40] : [20, 30, 25, 25],
|
|
40
|
+
wordWrap: true,
|
|
41
|
+
style: {
|
|
42
|
+
head: ['cyan']
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const sortedWorkflows = sortWorkflowsByName(workflows);
|
|
46
|
+
sortedWorkflows.forEach(workflow => {
|
|
47
|
+
const display = parseWorkflowForDisplay(workflow);
|
|
48
|
+
if (detailed) {
|
|
49
|
+
const inputs = display.inputs.split(', ').join('\n');
|
|
50
|
+
const outputs = display.outputs.split(', ').join('\n');
|
|
51
|
+
table.push([display.name, display.description, inputs, outputs]);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const maxLen = 22;
|
|
55
|
+
const inputs = display.inputs.length > maxLen ?
|
|
56
|
+
display.inputs.substring(0, maxLen) + '...' :
|
|
57
|
+
display.inputs;
|
|
58
|
+
const outputs = display.outputs.length > maxLen ?
|
|
59
|
+
display.outputs.substring(0, maxLen) + '...' :
|
|
60
|
+
display.outputs;
|
|
61
|
+
table.push([display.name, display.description, inputs, outputs]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return table.toString();
|
|
65
|
+
}
|
|
66
|
+
function formatWorkflowsAsList(workflows) {
|
|
67
|
+
const sortedWorkflows = sortWorkflowsByName(workflows);
|
|
68
|
+
const names = sortedWorkflows.map(w => parseWorkflowForDisplay(w).name);
|
|
69
|
+
return `\nWorkflows:\n\n${names.map(name => `- ${name}`).join('\n')}`;
|
|
70
|
+
}
|
|
71
|
+
function formatWorkflowsAsJson(workflows) {
|
|
72
|
+
const output = {
|
|
73
|
+
workflows: workflows.map(w => {
|
|
74
|
+
const display = parseWorkflowForDisplay(w);
|
|
75
|
+
return {
|
|
76
|
+
name: display.name,
|
|
77
|
+
description: display.description,
|
|
78
|
+
inputs: display.inputs.split(', '),
|
|
79
|
+
outputs: display.outputs.split(', '),
|
|
80
|
+
raw: w
|
|
81
|
+
};
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
return JSON.stringify(output, null, 2);
|
|
85
|
+
}
|
|
86
|
+
function formatWorkflows(workflows, format, detailed) {
|
|
87
|
+
if (format === OUTPUT_FORMAT.JSON) {
|
|
88
|
+
return formatWorkflowsAsJson(workflows);
|
|
89
|
+
}
|
|
90
|
+
if (format === OUTPUT_FORMAT.TABLE) {
|
|
91
|
+
return createWorkflowTable(workflows, detailed);
|
|
92
|
+
}
|
|
93
|
+
return formatWorkflowsAsList(workflows);
|
|
94
|
+
}
|
|
95
|
+
export default class WorkflowList extends Command {
|
|
96
|
+
static description = 'List available workflows from the catalog';
|
|
97
|
+
static examples = [
|
|
98
|
+
'<%= config.bin %> <%= command.id %>',
|
|
99
|
+
'<%= config.bin %> <%= command.id %> --format table',
|
|
100
|
+
'<%= config.bin %> <%= command.id %> --format json',
|
|
101
|
+
'<%= config.bin %> <%= command.id %> --detailed',
|
|
102
|
+
'<%= config.bin %> <%= command.id %> --filter simple'
|
|
103
|
+
];
|
|
104
|
+
static flags = {
|
|
105
|
+
format: Flags.string({
|
|
106
|
+
char: 'f',
|
|
107
|
+
description: 'Output format',
|
|
108
|
+
options: [OUTPUT_FORMAT.LIST, OUTPUT_FORMAT.TABLE, OUTPUT_FORMAT.JSON],
|
|
109
|
+
default: OUTPUT_FORMAT.LIST
|
|
110
|
+
}),
|
|
111
|
+
detailed: Flags.boolean({
|
|
112
|
+
char: 'd',
|
|
113
|
+
description: 'Show detailed parameter information',
|
|
114
|
+
default: false
|
|
115
|
+
}),
|
|
116
|
+
filter: Flags.string({
|
|
117
|
+
description: 'Filter workflows by name'
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
async run() {
|
|
121
|
+
const { flags } = await this.parse(WorkflowList);
|
|
122
|
+
try {
|
|
123
|
+
this.log('Fetching workflow catalog...');
|
|
124
|
+
const response = await getWorkflowCatalog();
|
|
125
|
+
if (!response) {
|
|
126
|
+
this.error('Failed to connect to API server. Is it running?', { exit: 1 });
|
|
127
|
+
}
|
|
128
|
+
if (!response.data) {
|
|
129
|
+
this.error('API returned invalid response (missing data)', { exit: 1 });
|
|
130
|
+
}
|
|
131
|
+
if (!response.data.workflows) {
|
|
132
|
+
this.error('API returned invalid response (missing workflows)', { exit: 1 });
|
|
133
|
+
}
|
|
134
|
+
if (response.data.workflows.length === 0) {
|
|
135
|
+
this.log('No workflows found in catalog.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const workflows = flags.filter ?
|
|
139
|
+
response.data.workflows.filter(matchName(flags.filter)) :
|
|
140
|
+
response.data.workflows;
|
|
141
|
+
if (workflows.length === 0 && flags.filter) {
|
|
142
|
+
this.log(`No workflows matching filter: ${flags.filter}`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const output = formatWorkflows(workflows, flags.format, flags.detailed);
|
|
146
|
+
this.log(output);
|
|
147
|
+
this.log(`\nFound ${workflows.length} workflow(s)`);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
this.handleError(error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
handleError(error) {
|
|
154
|
+
const apiError = error;
|
|
155
|
+
if (apiError.code === 'ECONNREFUSED') {
|
|
156
|
+
this.error(`Connection refused to ${config.apiUrl}`, { exit: 1 });
|
|
157
|
+
}
|
|
158
|
+
if (apiError.response?.status === 401) {
|
|
159
|
+
this.error('Authentication failed.', { exit: 1 });
|
|
160
|
+
}
|
|
161
|
+
if (apiError.response?.status === 404) {
|
|
162
|
+
this.error('Not found.', { exit: 1 });
|
|
163
|
+
}
|
|
164
|
+
if (apiError.message) {
|
|
165
|
+
this.error(`Failed to fetch workflow catalog: ${apiError.message}`, { exit: 1 });
|
|
166
|
+
}
|
|
167
|
+
this.error('Failed to fetch workflow catalog: Unknown error', { exit: 1 });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
describe('workflow list command', () => {
|
|
3
|
+
beforeEach(() => {
|
|
4
|
+
vi.clearAllMocks();
|
|
5
|
+
});
|
|
6
|
+
describe('command functionality', () => {
|
|
7
|
+
it('should export a valid OCLIF command', async () => {
|
|
8
|
+
const WorkflowList = (await import('./list.js')).default;
|
|
9
|
+
expect(WorkflowList).toBeDefined();
|
|
10
|
+
expect(WorkflowList.description).toContain('List available workflows');
|
|
11
|
+
expect(WorkflowList.flags).toHaveProperty('format');
|
|
12
|
+
expect(WorkflowList.flags).toHaveProperty('detailed');
|
|
13
|
+
expect(WorkflowList.flags).toHaveProperty('filter');
|
|
14
|
+
});
|
|
15
|
+
it('should have correct flag configuration', async () => {
|
|
16
|
+
const WorkflowList = (await import('./list.js')).default;
|
|
17
|
+
expect(WorkflowList.flags.format.options).toEqual(['list', 'table', 'json']);
|
|
18
|
+
expect(WorkflowList.flags.format.default).toBe('list');
|
|
19
|
+
expect(WorkflowList.flags.detailed.default).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('workflow list parsing', () => {
|
|
24
|
+
it('should parse workflow definitions correctly', async () => {
|
|
25
|
+
const { parseWorkflowForDisplay } = await import('./list.js');
|
|
26
|
+
const mockWorkflow = {
|
|
27
|
+
name: 'test-workflow',
|
|
28
|
+
description: 'A test workflow',
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
message: { type: 'string', description: 'The message' },
|
|
33
|
+
count: { type: 'number', description: 'The count' }
|
|
34
|
+
},
|
|
35
|
+
required: ['message']
|
|
36
|
+
},
|
|
37
|
+
outputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
result: { type: 'string' }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const parsed = parseWorkflowForDisplay(mockWorkflow);
|
|
45
|
+
expect(parsed.name).toBe('test-workflow');
|
|
46
|
+
expect(parsed.description).toBe('A test workflow');
|
|
47
|
+
expect(parsed.inputs).toContain('message: string');
|
|
48
|
+
expect(parsed.inputs).toContain('count: number?');
|
|
49
|
+
expect(parsed.outputs).toContain('result: string?');
|
|
50
|
+
});
|
|
51
|
+
it('should handle workflows without schemas', async () => {
|
|
52
|
+
const { parseWorkflowForDisplay } = await import('./list.js');
|
|
53
|
+
const mockWorkflow = {
|
|
54
|
+
name: 'simple-workflow',
|
|
55
|
+
description: 'No parameters'
|
|
56
|
+
};
|
|
57
|
+
const parsed = parseWorkflowForDisplay(mockWorkflow);
|
|
58
|
+
expect(parsed.name).toBe('simple-workflow');
|
|
59
|
+
expect(parsed.inputs).toBe('none');
|
|
60
|
+
expect(parsed.outputs).toBe('none');
|
|
61
|
+
});
|
|
62
|
+
it('should format nested parameters correctly', async () => {
|
|
63
|
+
const { parseWorkflowForDisplay } = await import('./list.js');
|
|
64
|
+
const mockWorkflow = {
|
|
65
|
+
name: 'nested-workflow',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {
|
|
69
|
+
user: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
name: { type: 'string' },
|
|
73
|
+
email: { type: 'string' }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const parsed = parseWorkflowForDisplay(mockWorkflow);
|
|
80
|
+
expect(parsed.inputs).toContain('user.name: string');
|
|
81
|
+
expect(parsed.inputs).toContain('user.email: string');
|
|
82
|
+
});
|
|
83
|
+
});
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI configuration
|
|
3
|
+
*/
|
|
4
|
+
export declare const config: {
|
|
5
|
+
/**
|
|
6
|
+
* Base URL for the Output.ai API server
|
|
7
|
+
* Can be overridden with API_URL environment variable
|
|
8
|
+
*/
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
/**
|
|
11
|
+
* API authentication token
|
|
12
|
+
* Set via API_AUTH_TOKEN environment variable
|
|
13
|
+
*/
|
|
14
|
+
apiToken: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Default timeout for API requests (in milliseconds)
|
|
17
|
+
*/
|
|
18
|
+
requestTimeout: number;
|
|
19
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI configuration
|
|
3
|
+
*/
|
|
4
|
+
export const config = {
|
|
5
|
+
/**
|
|
6
|
+
* Base URL for the Output.ai API server
|
|
7
|
+
* Can be overridden with API_URL environment variable
|
|
8
|
+
*/
|
|
9
|
+
apiUrl: process.env.API_URL || 'http://localhost:3001',
|
|
10
|
+
/**
|
|
11
|
+
* API authentication token
|
|
12
|
+
* Set via API_AUTH_TOKEN environment variable
|
|
13
|
+
*/
|
|
14
|
+
apiToken: process.env.API_AUTH_TOKEN,
|
|
15
|
+
/**
|
|
16
|
+
* Default timeout for API requests (in milliseconds)
|
|
17
|
+
*/
|
|
18
|
+
requestTimeout: 30000
|
|
19
|
+
};
|
|
@@ -159,8 +159,8 @@ export const llmStep = step( {
|
|
|
159
159
|
},
|
|
160
160
|
outputSchema: { type: 'string' },
|
|
161
161
|
fn: async ( input: { userInput: string } ) => {
|
|
162
|
-
const prompt = loadPrompt( 'prompt@v1', {
|
|
163
|
-
userInput: input.userInput
|
|
162
|
+
const prompt = loadPrompt( 'prompt@v1', {
|
|
163
|
+
userInput: input.userInput
|
|
164
164
|
} );
|
|
165
165
|
const response = await generateText( prompt as Prompt );
|
|
166
166
|
return response;
|
|
@@ -5,7 +5,7 @@ import { exampleLLMStep, processDataStep } from './steps.js';
|
|
|
5
5
|
const inputSchema = {
|
|
6
6
|
type: 'object',
|
|
7
7
|
properties: {
|
|
8
|
-
prompt: {
|
|
8
|
+
prompt: {
|
|
9
9
|
type: 'string',
|
|
10
10
|
description: 'The prompt to send to the LLM'
|
|
11
11
|
},
|
|
@@ -60,7 +60,7 @@ export default workflow( {
|
|
|
60
60
|
} );
|
|
61
61
|
|
|
62
62
|
// Process data if provided, otherwise use defaults
|
|
63
|
-
const processedData = await processDataStep(
|
|
63
|
+
const processedData = await processDataStep(
|
|
64
64
|
input.data || { value: 42, type: 'default' }
|
|
65
65
|
);
|
|
66
66
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@output.ai/cli",
|
|
3
3
|
"description": "CLI for Output.ai workflow generation",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.1",
|
|
5
5
|
"author": "Ben Church",
|
|
6
6
|
"bin": {
|
|
7
7
|
"output-cli": "./bin/run.js"
|
|
@@ -12,14 +12,19 @@
|
|
|
12
12
|
"@oclif/plugin-help": "^6",
|
|
13
13
|
"@oclif/plugin-plugins": "^5",
|
|
14
14
|
"change-case": "^5.4.4",
|
|
15
|
-
"
|
|
15
|
+
"cli-table3": "^0.6.5",
|
|
16
|
+
"handlebars": "^4.7.8",
|
|
17
|
+
"json-schema-library": "^10.2.1",
|
|
18
|
+
"ky": "^1.11.0"
|
|
16
19
|
},
|
|
17
20
|
"devDependencies": {
|
|
18
21
|
"@oclif/test": "^4",
|
|
19
22
|
"@types/handlebars": "^4.0.40",
|
|
20
23
|
"@types/node": "^18",
|
|
21
24
|
"copyfiles": "^2.4.1",
|
|
22
|
-
"oclif": "^4"
|
|
25
|
+
"oclif": "^4",
|
|
26
|
+
"orval": "^7.13.0",
|
|
27
|
+
"slash": "^5.1.0"
|
|
23
28
|
},
|
|
24
29
|
"engines": {
|
|
25
30
|
"node": ">=18.0.0"
|
|
@@ -54,7 +59,9 @@
|
|
|
54
59
|
"repository": "sdk/cli",
|
|
55
60
|
"scripts": {
|
|
56
61
|
"build": "rm -rf ./dist && tsc && copyfiles -u 1 './src/templates/**/*.template' './src/templates/**/.env.template' './src/templates/**/*.prompt.template' dist",
|
|
57
|
-
"test": "vitest run"
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"generate:api": "orval --config ./orval.config.ts",
|
|
64
|
+
"prebuild": "npm run generate:api"
|
|
58
65
|
},
|
|
59
66
|
"types": "dist/index.d.ts"
|
|
60
67
|
}
|