@uipath/tasks-tool 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +57154 -0
- package/dist/tool.js +57145 -0
- package/package.json +32 -0
- package/src/commands/tasks.spec.ts +692 -0
- package/src/commands/tasks.ts +552 -0
- package/src/index.ts +13 -0
- package/src/tool.ts +14 -0
- package/src/utils/sdk-client.ts +25 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +1 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import {
|
|
2
|
+
catchError,
|
|
3
|
+
extractErrorMessage,
|
|
4
|
+
extractErrorMessageSync,
|
|
5
|
+
OutputFormatter,
|
|
6
|
+
processContext,
|
|
7
|
+
RESULTS,
|
|
8
|
+
} from "@uipath/common";
|
|
9
|
+
import type { TaskCompletionOptions } from "@uipath/uipath-typescript";
|
|
10
|
+
import type { Command } from "commander";
|
|
11
|
+
|
|
12
|
+
import { createTasksClient } from "../utils/sdk-client";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_PAGE_SIZE = 100;
|
|
15
|
+
|
|
16
|
+
const VALID_TASK_TYPES = [
|
|
17
|
+
"FormTask",
|
|
18
|
+
"ExternalTask",
|
|
19
|
+
"AppTask",
|
|
20
|
+
"DocumentValidationTask",
|
|
21
|
+
"DocumentClassificationTask",
|
|
22
|
+
"DataLabelingTask",
|
|
23
|
+
] as const;
|
|
24
|
+
type ValidTaskType = (typeof VALID_TASK_TYPES)[number];
|
|
25
|
+
|
|
26
|
+
interface ListOptions {
|
|
27
|
+
tenant?: string;
|
|
28
|
+
folderId?: string;
|
|
29
|
+
asAdmin?: boolean;
|
|
30
|
+
limit?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface GetOptions {
|
|
34
|
+
tenant?: string;
|
|
35
|
+
taskType?: string;
|
|
36
|
+
folderId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface AssignOptions {
|
|
40
|
+
tenant?: string;
|
|
41
|
+
userId?: string;
|
|
42
|
+
user?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface CompleteOptions {
|
|
46
|
+
tenant?: string;
|
|
47
|
+
type: string;
|
|
48
|
+
data?: string;
|
|
49
|
+
action?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const registerTasksCommand = (program: Command) => {
|
|
53
|
+
program
|
|
54
|
+
.command("list")
|
|
55
|
+
.description("List tasks across folders")
|
|
56
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
57
|
+
.option("--folder-id <id>", "Filter by folder ID")
|
|
58
|
+
.option("--as-admin", "List tasks as admin")
|
|
59
|
+
.option(
|
|
60
|
+
"-l, --limit <number>",
|
|
61
|
+
"Maximum number of items to return (fetches all if omitted)",
|
|
62
|
+
)
|
|
63
|
+
.trackedAction(processContext, async (options: ListOptions) => {
|
|
64
|
+
const [clientError, sdk] = await catchError(
|
|
65
|
+
createTasksClient(options.tenant),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (clientError) {
|
|
69
|
+
OutputFormatter.error({
|
|
70
|
+
Result: RESULTS.Failure,
|
|
71
|
+
Message: "Error connecting to Action Center",
|
|
72
|
+
Instructions: await extractErrorMessage(clientError),
|
|
73
|
+
});
|
|
74
|
+
processContext.exit(1);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let limit: number | undefined;
|
|
79
|
+
if (options.limit) {
|
|
80
|
+
const parsed = parsePositiveInt(options.limit, "--limit");
|
|
81
|
+
if (!parsed.valid) {
|
|
82
|
+
reportInvalidInt(parsed);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
limit = parsed.value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let folderId: number | undefined;
|
|
89
|
+
if (options.folderId) {
|
|
90
|
+
const parsed = parsePositiveInt(
|
|
91
|
+
options.folderId,
|
|
92
|
+
"--folder-id",
|
|
93
|
+
);
|
|
94
|
+
if (!parsed.valid) {
|
|
95
|
+
reportInvalidInt(parsed);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
folderId = parsed.value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const allItems: unknown[] = [];
|
|
102
|
+
let cursor: { value: string } | undefined;
|
|
103
|
+
|
|
104
|
+
do {
|
|
105
|
+
const getOptions: Record<string, unknown> = {
|
|
106
|
+
pageSize: DEFAULT_PAGE_SIZE,
|
|
107
|
+
};
|
|
108
|
+
if (folderId !== undefined) {
|
|
109
|
+
getOptions.folderId = folderId;
|
|
110
|
+
}
|
|
111
|
+
if (options.asAdmin) {
|
|
112
|
+
getOptions.asTaskAdmin = true;
|
|
113
|
+
}
|
|
114
|
+
if (cursor) {
|
|
115
|
+
getOptions.cursor = cursor;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const [listError, result] = await catchError(
|
|
119
|
+
sdk.tasks.getAll(getOptions),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (listError) {
|
|
123
|
+
OutputFormatter.error({
|
|
124
|
+
Result: RESULTS.Failure,
|
|
125
|
+
Message: "Error listing tasks",
|
|
126
|
+
Instructions: await extractErrorMessage(listError),
|
|
127
|
+
});
|
|
128
|
+
processContext.exit(1);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (Array.isArray(result)) {
|
|
133
|
+
allItems.push(...result);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const page = result as unknown as Record<string, unknown>;
|
|
138
|
+
const items = (page.items ?? []) as unknown[];
|
|
139
|
+
allItems.push(...items);
|
|
140
|
+
|
|
141
|
+
cursor = page.hasNextPage
|
|
142
|
+
? (page.nextCursor as { value: string })
|
|
143
|
+
: undefined;
|
|
144
|
+
|
|
145
|
+
if (limit && allItems.length >= limit) {
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
} while (cursor);
|
|
149
|
+
|
|
150
|
+
const data = limit ? allItems.slice(0, limit) : allItems;
|
|
151
|
+
|
|
152
|
+
OutputFormatter.success({
|
|
153
|
+
Result: RESULTS.Success,
|
|
154
|
+
Code: "TaskList",
|
|
155
|
+
Data: data,
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
program
|
|
160
|
+
.command("get")
|
|
161
|
+
.description(
|
|
162
|
+
"Get details of a task by ID. Use 'tasks list' to find task IDs.",
|
|
163
|
+
)
|
|
164
|
+
.argument("<id>", "Task ID")
|
|
165
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
166
|
+
.option(
|
|
167
|
+
"--task-type <type>",
|
|
168
|
+
"Task type (FormTask, ExternalTask, AppTask, DocumentValidationTask, DocumentClassificationTask, DataLabelingTask)",
|
|
169
|
+
)
|
|
170
|
+
.option(
|
|
171
|
+
"--folder-id <id>",
|
|
172
|
+
"Folder ID (required when task-type is specified)",
|
|
173
|
+
)
|
|
174
|
+
.trackedAction(
|
|
175
|
+
processContext,
|
|
176
|
+
async (id: string, options: GetOptions) => {
|
|
177
|
+
const [clientError, sdk] = await catchError(
|
|
178
|
+
createTasksClient(options.tenant),
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
if (clientError) {
|
|
182
|
+
OutputFormatter.error({
|
|
183
|
+
Result: RESULTS.Failure,
|
|
184
|
+
Message: "Error connecting to Action Center",
|
|
185
|
+
Instructions: await extractErrorMessage(clientError),
|
|
186
|
+
});
|
|
187
|
+
processContext.exit(1);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const parsedId = parsePositiveInt(id, "<id>");
|
|
192
|
+
if (!parsedId.valid) {
|
|
193
|
+
reportInvalidInt(parsedId);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (options.taskType && !options.folderId) {
|
|
198
|
+
OutputFormatter.error({
|
|
199
|
+
Result: RESULTS.Failure,
|
|
200
|
+
Message:
|
|
201
|
+
"--folder-id is required when --task-type is specified",
|
|
202
|
+
Instructions:
|
|
203
|
+
"Provide a folder ID with --folder-id <id>.",
|
|
204
|
+
});
|
|
205
|
+
processContext.exit(1);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const getOptions: Record<string, unknown> = {};
|
|
210
|
+
if (options.taskType) {
|
|
211
|
+
getOptions.taskType = options.taskType;
|
|
212
|
+
}
|
|
213
|
+
let folderId: number | undefined;
|
|
214
|
+
if (options.folderId) {
|
|
215
|
+
const parsed = parsePositiveInt(
|
|
216
|
+
options.folderId,
|
|
217
|
+
"--folder-id",
|
|
218
|
+
);
|
|
219
|
+
if (!parsed.valid) {
|
|
220
|
+
reportInvalidInt(parsed);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
folderId = parsed.value;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const [getError, task] = await catchError(
|
|
227
|
+
sdk.tasks.getById(parsedId.value, getOptions, folderId),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (getError) {
|
|
231
|
+
OutputFormatter.error({
|
|
232
|
+
Result: RESULTS.Failure,
|
|
233
|
+
Message: `Error getting task '${id}'`,
|
|
234
|
+
Instructions: await extractErrorMessage(getError),
|
|
235
|
+
});
|
|
236
|
+
processContext.exit(1);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
OutputFormatter.success({
|
|
241
|
+
Result: RESULTS.Success,
|
|
242
|
+
Code: "TaskDetails",
|
|
243
|
+
Data: task,
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
program
|
|
249
|
+
.command("assign")
|
|
250
|
+
.description("Assign a task to a user")
|
|
251
|
+
.argument("<task-id>", "Task ID")
|
|
252
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
253
|
+
.option("--user-id <id>", "User ID")
|
|
254
|
+
.option(
|
|
255
|
+
"--user <email>",
|
|
256
|
+
"User name or email (alternative to --user-id)",
|
|
257
|
+
)
|
|
258
|
+
.trackedAction(
|
|
259
|
+
processContext,
|
|
260
|
+
async (taskId: string, options: AssignOptions) => {
|
|
261
|
+
await assignOrReassign(taskId, options, "assign");
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
program
|
|
266
|
+
.command("reassign")
|
|
267
|
+
.description("Reassign a task to a different user")
|
|
268
|
+
.argument("<task-id>", "Task ID")
|
|
269
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
270
|
+
.option("--user-id <id>", "User ID")
|
|
271
|
+
.option(
|
|
272
|
+
"--user <email>",
|
|
273
|
+
"User name or email (alternative to --user-id)",
|
|
274
|
+
)
|
|
275
|
+
.trackedAction(
|
|
276
|
+
processContext,
|
|
277
|
+
async (taskId: string, options: AssignOptions) => {
|
|
278
|
+
await assignOrReassign(taskId, options, "reassign");
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
program
|
|
283
|
+
.command("unassign")
|
|
284
|
+
.description("Remove the assignee from a task")
|
|
285
|
+
.argument("<task-id>", "Task ID")
|
|
286
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
287
|
+
.trackedAction(
|
|
288
|
+
processContext,
|
|
289
|
+
async (taskId: string, options: { tenant?: string }) => {
|
|
290
|
+
const [clientError, sdk] = await catchError(
|
|
291
|
+
createTasksClient(options.tenant),
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
if (clientError) {
|
|
295
|
+
OutputFormatter.error({
|
|
296
|
+
Result: RESULTS.Failure,
|
|
297
|
+
Message: "Error connecting to Action Center",
|
|
298
|
+
Instructions: await extractErrorMessage(clientError),
|
|
299
|
+
});
|
|
300
|
+
processContext.exit(1);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const parsedId = parsePositiveInt(taskId, "<task-id>");
|
|
305
|
+
if (!parsedId.valid) {
|
|
306
|
+
reportInvalidInt(parsedId);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const [unassignError, result] = await catchError(
|
|
311
|
+
sdk.tasks.unassign(parsedId.value),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
if (unassignError) {
|
|
315
|
+
OutputFormatter.error({
|
|
316
|
+
Result: RESULTS.Failure,
|
|
317
|
+
Message: `Error unassigning task '${taskId}'`,
|
|
318
|
+
Instructions: await extractErrorMessage(unassignError),
|
|
319
|
+
});
|
|
320
|
+
processContext.exit(1);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
OutputFormatter.success({
|
|
325
|
+
Result: RESULTS.Success,
|
|
326
|
+
Code: "TaskUnassigned",
|
|
327
|
+
Data: result,
|
|
328
|
+
});
|
|
329
|
+
},
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
program
|
|
333
|
+
.command("complete")
|
|
334
|
+
.description("Complete a task with an action and optional data")
|
|
335
|
+
.argument("<task-id>", "Task ID")
|
|
336
|
+
.requiredOption(
|
|
337
|
+
"--type <type>",
|
|
338
|
+
"Task type (FormTask, ExternalTask, AppTask, DocumentValidationTask, DocumentClassificationTask, DataLabelingTask)",
|
|
339
|
+
)
|
|
340
|
+
.requiredOption("--folder-id <id>", "Folder ID (required)")
|
|
341
|
+
.option("-t, --tenant <tenant-name>", "Tenant name")
|
|
342
|
+
.option("--data <json>", "Task data as JSON string")
|
|
343
|
+
.option(
|
|
344
|
+
"--action <action>",
|
|
345
|
+
"Action name (required for FormTask and AppTask)",
|
|
346
|
+
)
|
|
347
|
+
.trackedAction(
|
|
348
|
+
processContext,
|
|
349
|
+
async (
|
|
350
|
+
taskId: string,
|
|
351
|
+
options: CompleteOptions & { folderId: string },
|
|
352
|
+
) => {
|
|
353
|
+
const [clientError, sdk] = await catchError(
|
|
354
|
+
createTasksClient(options.tenant),
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
if (clientError) {
|
|
358
|
+
OutputFormatter.error({
|
|
359
|
+
Result: RESULTS.Failure,
|
|
360
|
+
Message: "Error connecting to Action Center",
|
|
361
|
+
Instructions: await extractErrorMessage(clientError),
|
|
362
|
+
});
|
|
363
|
+
processContext.exit(1);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const parsedTaskId = parsePositiveInt(taskId, "<task-id>");
|
|
368
|
+
if (!parsedTaskId.valid) {
|
|
369
|
+
reportInvalidInt(parsedTaskId);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const parsedFolderId = parsePositiveInt(
|
|
374
|
+
options.folderId,
|
|
375
|
+
"--folder-id",
|
|
376
|
+
);
|
|
377
|
+
if (!parsedFolderId.valid) {
|
|
378
|
+
reportInvalidInt(parsedFolderId);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!VALID_TASK_TYPES.includes(options.type as ValidTaskType)) {
|
|
383
|
+
OutputFormatter.error({
|
|
384
|
+
Result: RESULTS.Failure,
|
|
385
|
+
Message: `Invalid task type '${options.type}'`,
|
|
386
|
+
Instructions: `Valid types: ${VALID_TASK_TYPES.join(", ")}`,
|
|
387
|
+
});
|
|
388
|
+
processContext.exit(1);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const completionOptions: Record<string, unknown> = {
|
|
393
|
+
taskId: parsedTaskId.value,
|
|
394
|
+
type: options.type,
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
if (options.action) {
|
|
398
|
+
completionOptions.action = options.action;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (options.data) {
|
|
402
|
+
const [parseError, parsed] = await catchError(
|
|
403
|
+
Promise.resolve().then(
|
|
404
|
+
() => JSON.parse(options.data as string) as unknown,
|
|
405
|
+
),
|
|
406
|
+
);
|
|
407
|
+
if (parseError) {
|
|
408
|
+
OutputFormatter.error({
|
|
409
|
+
Result: RESULTS.Failure,
|
|
410
|
+
Message: "Invalid JSON in --data",
|
|
411
|
+
Instructions: extractErrorMessageSync(parseError),
|
|
412
|
+
});
|
|
413
|
+
processContext.exit(1);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
completionOptions.data = parsed;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// CLI receives type as a raw string; SDK expects a TaskType enum discriminated union.
|
|
420
|
+
const [completeError, result] = await catchError(
|
|
421
|
+
sdk.tasks.complete(
|
|
422
|
+
completionOptions as unknown as TaskCompletionOptions,
|
|
423
|
+
parsedFolderId.value,
|
|
424
|
+
),
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
if (completeError) {
|
|
428
|
+
OutputFormatter.error({
|
|
429
|
+
Result: RESULTS.Failure,
|
|
430
|
+
Message: `Error completing task '${taskId}'`,
|
|
431
|
+
Instructions: await extractErrorMessage(completeError),
|
|
432
|
+
});
|
|
433
|
+
processContext.exit(1);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
OutputFormatter.success({
|
|
438
|
+
Result: RESULTS.Success,
|
|
439
|
+
Code: "TaskCompleted",
|
|
440
|
+
Data: result,
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
);
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
async function assignOrReassign(
|
|
447
|
+
taskId: string,
|
|
448
|
+
options: AssignOptions,
|
|
449
|
+
action: "assign" | "reassign",
|
|
450
|
+
): Promise<void> {
|
|
451
|
+
if (!options.userId && !options.user) {
|
|
452
|
+
OutputFormatter.error({
|
|
453
|
+
Result: RESULTS.Failure,
|
|
454
|
+
Message: "Missing assignee",
|
|
455
|
+
Instructions:
|
|
456
|
+
action === "assign"
|
|
457
|
+
? "Provide either --user-id or --user to specify the assignee."
|
|
458
|
+
: "Provide either --user-id or --user to specify the new assignee.",
|
|
459
|
+
});
|
|
460
|
+
processContext.exit(1);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const [clientError, sdk] = await catchError(
|
|
465
|
+
createTasksClient(options.tenant),
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
if (clientError) {
|
|
469
|
+
OutputFormatter.error({
|
|
470
|
+
Result: RESULTS.Failure,
|
|
471
|
+
Message: "Error connecting to Action Center",
|
|
472
|
+
Instructions: await extractErrorMessage(clientError),
|
|
473
|
+
});
|
|
474
|
+
processContext.exit(1);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const parsedTaskId = parsePositiveInt(taskId, "<task-id>");
|
|
479
|
+
if (!parsedTaskId.valid) {
|
|
480
|
+
reportInvalidInt(parsedTaskId);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const assignment: Record<string, unknown> = {
|
|
485
|
+
taskId: parsedTaskId.value,
|
|
486
|
+
};
|
|
487
|
+
if (options.userId) {
|
|
488
|
+
const parsedUserId = parsePositiveInt(options.userId, "--user-id");
|
|
489
|
+
if (!parsedUserId.valid) {
|
|
490
|
+
reportInvalidInt(parsedUserId);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
assignment.userId = parsedUserId.value;
|
|
494
|
+
} else {
|
|
495
|
+
assignment.userNameOrEmail = options.user;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
type TaskAssignment =
|
|
499
|
+
| { taskId: number; userId: number }
|
|
500
|
+
| { taskId: number; userNameOrEmail: string };
|
|
501
|
+
|
|
502
|
+
const [error, result] = await catchError(
|
|
503
|
+
action === "assign"
|
|
504
|
+
? sdk.tasks.assign(assignment as TaskAssignment)
|
|
505
|
+
: sdk.tasks.reassign(assignment as TaskAssignment),
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
if (error) {
|
|
509
|
+
OutputFormatter.error({
|
|
510
|
+
Result: RESULTS.Failure,
|
|
511
|
+
Message: `Error ${action === "assign" ? "assigning" : "reassigning"} task '${taskId}'`,
|
|
512
|
+
Instructions: await extractErrorMessage(error),
|
|
513
|
+
});
|
|
514
|
+
processContext.exit(1);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
OutputFormatter.success({
|
|
519
|
+
Result: RESULTS.Success,
|
|
520
|
+
Code: action === "assign" ? "TaskAssigned" : "TaskReassigned",
|
|
521
|
+
Data: result,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function parsePositiveInt(
|
|
526
|
+
value: string,
|
|
527
|
+
label: string,
|
|
528
|
+
):
|
|
529
|
+
| { valid: true; value: number }
|
|
530
|
+
| { valid: false; message: string; instructions: string } {
|
|
531
|
+
const parsed = Number(value);
|
|
532
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
533
|
+
return {
|
|
534
|
+
valid: false,
|
|
535
|
+
message: `Invalid ${label}: ${value}`,
|
|
536
|
+
instructions: "Must be a positive integer.",
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return { valid: true, value: parsed };
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function reportInvalidInt(error: {
|
|
543
|
+
message: string;
|
|
544
|
+
instructions: string;
|
|
545
|
+
}): void {
|
|
546
|
+
OutputFormatter.error({
|
|
547
|
+
Result: RESULTS.Failure,
|
|
548
|
+
Message: error.message,
|
|
549
|
+
Instructions: error.instructions,
|
|
550
|
+
});
|
|
551
|
+
processContext.exit(1);
|
|
552
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import pkg from "../package.json" with { type: "json" };
|
|
4
|
+
import { registerTasksCommand } from "./commands/tasks";
|
|
5
|
+
|
|
6
|
+
const program = new Command();
|
|
7
|
+
program
|
|
8
|
+
.name("tasks-tool")
|
|
9
|
+
.description("UiPath Tasks Tool - Standalone CLI")
|
|
10
|
+
.version(pkg.version);
|
|
11
|
+
|
|
12
|
+
registerTasksCommand(program);
|
|
13
|
+
program.parse(process.argv);
|
package/src/tool.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import pkg from "../package.json" with { type: "json" };
|
|
3
|
+
import { registerTasksCommand } from "./commands/tasks";
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
name: "tasks-tool",
|
|
7
|
+
version: pkg.version,
|
|
8
|
+
description: "Manage Action Center tasks.",
|
|
9
|
+
commandPrefix: "tasks",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const registerCommands = async (program: Command): Promise<void> => {
|
|
13
|
+
registerTasksCommand(program);
|
|
14
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getLoginStatusAsync } from "@uipath/auth";
|
|
2
|
+
import { UiPath } from "@uipath/uipath-typescript";
|
|
3
|
+
|
|
4
|
+
export const createTasksClient = async (
|
|
5
|
+
tenantOverride?: string,
|
|
6
|
+
): Promise<UiPath> => {
|
|
7
|
+
const status = await getLoginStatusAsync({
|
|
8
|
+
ensureTokenValidityMinutes: 10,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
if (
|
|
12
|
+
status.loginStatus !== "Logged in" ||
|
|
13
|
+
!status.accessToken ||
|
|
14
|
+
!status.baseUrl
|
|
15
|
+
) {
|
|
16
|
+
throw new Error(status.hint ?? "Not logged in. Run 'uip login' first.");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return new UiPath({
|
|
20
|
+
secret: status.accessToken,
|
|
21
|
+
baseUrl: status.baseUrl,
|
|
22
|
+
orgName: status.organizationName,
|
|
23
|
+
tenantName: tenantOverride ?? status.tenantName,
|
|
24
|
+
});
|
|
25
|
+
};
|
package/tsconfig.json
ADDED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../vitest.base.config";
|