@uipath/orchestrator-tool 1.204.0 → 1.205.0-preview.258
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-r2vc4whd.js → index-rkqk9b39.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/{kb-zgjw0vpk.js → kb-rqv35wke.js} +2 -2
- package/dist/{tool-s5ktt6fh.js → tool-16fzb4dj.js} +416 -124
- package/dist/{tool-ayyhwvs8.js → tool-6mw7b49q.js} +11 -1
- package/dist/{tool-ckjbpn0a.js → tool-qeyyg5yr.js} +7791 -17090
- package/dist/tool.js +3 -3
- package/package.json +2 -2
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
FoldersNavigationApi,
|
|
17
17
|
HttpTriggersApi,
|
|
18
18
|
InvalidArgumentError,
|
|
19
|
+
JobAttachmentsApi,
|
|
19
20
|
JobDtoToJSON,
|
|
20
21
|
JobsApi,
|
|
21
22
|
LibrariesApi,
|
|
@@ -51,12 +52,12 @@ import {
|
|
|
51
52
|
TriggerLogsApi,
|
|
52
53
|
UsersApi,
|
|
53
54
|
WebhooksApi,
|
|
55
|
+
addDeprecatedOptionAlias,
|
|
54
56
|
carriedErrorCode,
|
|
55
57
|
carriedRetry,
|
|
56
58
|
catchError,
|
|
57
59
|
createApiClient,
|
|
58
60
|
createHiddenDeprecatedTenantOption,
|
|
59
|
-
createOrchestratorConfig,
|
|
60
61
|
extractErrorDetails,
|
|
61
62
|
extractErrorMessage,
|
|
62
63
|
extractErrorMessageSync,
|
|
@@ -64,6 +65,7 @@ import {
|
|
|
64
65
|
isGuid,
|
|
65
66
|
isPreviewBuild,
|
|
66
67
|
logger,
|
|
68
|
+
nullArrayToEmptyMiddleware,
|
|
67
69
|
parseHttpStatusFromMessage,
|
|
68
70
|
pollUntil,
|
|
69
71
|
processContext,
|
|
@@ -78,10 +80,10 @@ import {
|
|
|
78
80
|
trackShipSucceeded,
|
|
79
81
|
unzipSync,
|
|
80
82
|
uploadJobAttachment
|
|
81
|
-
} from "./tool-
|
|
83
|
+
} from "./tool-qeyyg5yr.js";
|
|
82
84
|
import {
|
|
83
85
|
getFileSystem
|
|
84
|
-
} from "./tool-
|
|
86
|
+
} from "./tool-6mw7b49q.js";
|
|
85
87
|
import {
|
|
86
88
|
__require
|
|
87
89
|
} from "./tool-1de529jm.js";
|
|
@@ -90,7 +92,7 @@ var package_default = {
|
|
|
90
92
|
name: "@uipath/orchestrator-tool",
|
|
91
93
|
author: "UiPath",
|
|
92
94
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
93
|
-
version: "1.
|
|
95
|
+
version: "1.205.0-preview.258",
|
|
94
96
|
description: "Manage Orchestrator folders, jobs, processes, and releases.",
|
|
95
97
|
private: false,
|
|
96
98
|
repository: {
|
|
@@ -1299,7 +1301,7 @@ async function resolveJob(jobKey, options) {
|
|
|
1299
1301
|
var ATTACHMENTS_DOWNLOAD_EXAMPLES = [
|
|
1300
1302
|
{
|
|
1301
1303
|
Description: "Download an attachment to a specific output path",
|
|
1302
|
-
Command: "uip or attachments download a1b2c3d4-0000-0000-0000-000000000001 --
|
|
1304
|
+
Command: "uip or attachments download a1b2c3d4-0000-0000-0000-000000000001 --destination ./report.pdf",
|
|
1303
1305
|
Output: {
|
|
1304
1306
|
Code: "AttachmentDownloaded",
|
|
1305
1307
|
Data: {
|
|
@@ -1335,7 +1337,7 @@ var ATTACHMENTS_LIST_EXAMPLES = [
|
|
|
1335
1337
|
];
|
|
1336
1338
|
var registerAttachmentsCommand = (program) => {
|
|
1337
1339
|
const attachments = program.command("attachments").description("Manage job attachments. " + "Download files attached to jobs (screenshots, reports, data files). " + "Attachments are tenant-scoped — no folder context needed.");
|
|
1338
|
-
attachments.command("download").description("Download a job attachment to local disk. " + "Uses the DownloadAttachmentFile endpoint which returns a redirect to the blob storage URI. " + "Use job 'get' output to find attachment IDs.").argument("<attachment-id>", "Attachment ID (GUID)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-
|
|
1340
|
+
const download = attachments.command("download").description("Download a job attachment to local disk. " + "Uses the DownloadAttachmentFile endpoint which returns a redirect to the blob storage URI. " + "Use job 'get' output to find attachment IDs.").argument("<attachment-id>", "Attachment ID (GUID)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-d, --destination <path>", "Output file path (defaults to attachment-<id> in current directory)").examples(ATTACHMENTS_DOWNLOAD_EXAMPLES).trackedAction(processContext, async (attachmentId, options) => {
|
|
1339
1341
|
const [apiError, api] = await catchError(createApiClient(AttachmentsApi, {
|
|
1340
1342
|
tenant: options.tenant
|
|
1341
1343
|
}));
|
|
@@ -1394,8 +1396,8 @@ var registerAttachmentsCommand = (program) => {
|
|
|
1394
1396
|
processContext.exit(1);
|
|
1395
1397
|
return;
|
|
1396
1398
|
}
|
|
1397
|
-
const fileName = options.
|
|
1398
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
1399
|
+
const fileName = options.destination || `attachment-${attachmentId}`;
|
|
1400
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
1399
1401
|
const fs = getFileSystem2();
|
|
1400
1402
|
const [writeError] = await catchError(fs.writeFile(fileName, Buffer.from(buffer)));
|
|
1401
1403
|
if (writeError) {
|
|
@@ -1417,38 +1419,32 @@ var registerAttachmentsCommand = (program) => {
|
|
|
1417
1419
|
}
|
|
1418
1420
|
});
|
|
1419
1421
|
});
|
|
1422
|
+
addDeprecatedOptionAlias(download, "-o, --output <path>", "--destination");
|
|
1420
1423
|
attachments.command("list").description("List attachments for a job. " + "Shows attachment ID, name, and category. " + "Use the attachment ID with 'attachments download' or 'jobs start --attachment-id'.").requiredOption("--job-key <key>", "Job key (GUID) — list attachments for this job").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--all-fields", "Return all fields from the API response (default: curated subset)").examples(ATTACHMENTS_LIST_EXAMPLES).trackedAction(processContext, async (options) => {
|
|
1421
1424
|
const resolved = await resolveOrReportError(resolveJob(options.jobKey, { tenant: options.tenant }), "Error listing attachments");
|
|
1422
1425
|
if (resolved === null)
|
|
1423
1426
|
return;
|
|
1424
|
-
const [
|
|
1427
|
+
const [apiError, api] = await catchError(createApiClient(JobAttachmentsApi, {
|
|
1425
1428
|
tenant: options.tenant,
|
|
1426
1429
|
folderId: resolved.folderId.toString()
|
|
1427
1430
|
}));
|
|
1428
|
-
if (
|
|
1431
|
+
if (apiError) {
|
|
1429
1432
|
OutputFormatter.error({
|
|
1430
1433
|
Result: RESULTS.Failure,
|
|
1431
1434
|
Message: "Error listing attachments",
|
|
1432
|
-
Instructions:
|
|
1435
|
+
Instructions: apiError.message
|
|
1433
1436
|
});
|
|
1434
1437
|
processContext.exit(1);
|
|
1435
1438
|
return;
|
|
1436
1439
|
}
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
};
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
const msg = error ? error.message : `HTTP ${response.status}: ${response.statusText}`;
|
|
1443
|
-
OutputFormatter.error({
|
|
1444
|
-
Result: RESULTS.Failure,
|
|
1445
|
-
Message: "Error listing attachments",
|
|
1446
|
-
Instructions: msg
|
|
1447
|
-
});
|
|
1448
|
-
processContext.exit(1);
|
|
1440
|
+
const [error, response] = await catchError(api.withMiddleware(nullArrayToEmptyMiddleware).jobAttachmentsGetByJobKeyRaw({
|
|
1441
|
+
jobKey: options.jobKey
|
|
1442
|
+
}));
|
|
1443
|
+
if (error) {
|
|
1444
|
+
await reportFailure("Error listing attachments", error);
|
|
1449
1445
|
return;
|
|
1450
1446
|
}
|
|
1451
|
-
const [parseError, items] = await catchError(response.json());
|
|
1447
|
+
const [parseError, items] = await catchError(response.raw.json());
|
|
1452
1448
|
if (parseError) {
|
|
1453
1449
|
OutputFormatter.error({
|
|
1454
1450
|
Result: RESULTS.Failure,
|
|
@@ -3447,6 +3443,7 @@ var registerFeedsCommand = (program) => {
|
|
|
3447
3443
|
};
|
|
3448
3444
|
|
|
3449
3445
|
// src/commands/folders.ts
|
|
3446
|
+
var VALID_RUNTIMES_PROCESS_TYPES = ["Process", "Agent", "Function", "Api"];
|
|
3450
3447
|
var FOLDERS_LIST_EXAMPLES = [
|
|
3451
3448
|
{
|
|
3452
3449
|
Description: "List folders in the tenant",
|
|
@@ -3944,7 +3941,14 @@ var registerFoldersCommand = (program) => {
|
|
|
3944
3941
|
}
|
|
3945
3942
|
});
|
|
3946
3943
|
});
|
|
3947
|
-
folders.command("runtimes").description("List runtime allocations for a folder. " + "Shows how many runtime slots of each type (Unattended, Attended, NonProduction, etc.) " + "are total, connected, and available in the specified folder. " + "Useful for checking capacity before starting jobs.").argument("<folder-key-or-path>", "Folder key (GUID) or path — use 'folders list' to find").addOption(
|
|
3944
|
+
folders.command("runtimes").description("List runtime allocations for a folder. " + "Shows how many runtime slots of each type (Unattended, Attended, NonProduction, etc.) " + "are total, connected, and available in the specified folder. " + "Useful for checking capacity before starting jobs.").argument("<folder-key-or-path>", "Folder key (GUID) or path — use 'folders list' to find").addOption(new Option("--process-type <type>", "Report the runtimes a job of this process type can use. The Local row then counts only that job's slot pool, as the Start Job dialog does").choices(VALID_RUNTIMES_PROCESS_TYPES).argParser((value) => {
|
|
3945
|
+
const matched = VALID_RUNTIMES_PROCESS_TYPES.find((v) => v.toLowerCase() === value.toLowerCase());
|
|
3946
|
+
if (!matched) {
|
|
3947
|
+
throw new InvalidArgumentError(`Allowed choices are ${VALID_RUNTIMES_PROCESS_TYPES.join(", ")}.`);
|
|
3948
|
+
}
|
|
3949
|
+
return matched;
|
|
3950
|
+
})).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(FOLDERS_RUNTIMES_EXAMPLES).trackedAction(processContext, async (folderKeyArg, options) => {
|
|
3951
|
+
const processType = options.processType;
|
|
3948
3952
|
const folderInput = resolveFolderInput(folderKeyArg);
|
|
3949
3953
|
const [folderError, folder] = await catchError(resolveFolder(folderInput, { tenant: options.tenant }));
|
|
3950
3954
|
if (folderError) {
|
|
@@ -3964,7 +3968,8 @@ var registerFoldersCommand = (program) => {
|
|
|
3964
3968
|
return;
|
|
3965
3969
|
}
|
|
3966
3970
|
const [getError, result] = await catchError(api.machinesGetRuntimesForFolderByFolderid({
|
|
3967
|
-
folderId: folder.id
|
|
3971
|
+
folderId: folder.id,
|
|
3972
|
+
processType
|
|
3968
3973
|
}));
|
|
3969
3974
|
if (getError) {
|
|
3970
3975
|
await reportFailure("Error listing runtimes", getError);
|
|
@@ -4136,7 +4141,7 @@ async function downloadAttachment(attachmentId, outputPath, options) {
|
|
|
4136
4141
|
if (bufferError) {
|
|
4137
4142
|
throw new Error(`Failed to read attachment data: ${bufferError.message}`);
|
|
4138
4143
|
}
|
|
4139
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
4144
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
4140
4145
|
const fs = getFileSystem2();
|
|
4141
4146
|
const [writeError] = await catchError(fs.writeFile(outputPath, Buffer.from(buffer)));
|
|
4142
4147
|
if (writeError) {
|
|
@@ -4151,7 +4156,7 @@ async function downloadAttachment(attachmentId, outputPath, options) {
|
|
|
4151
4156
|
|
|
4152
4157
|
// src/utils/attachment-uploader.ts
|
|
4153
4158
|
async function uploadAttachment(filePath, name, options) {
|
|
4154
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
4159
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
4155
4160
|
const fs = getFileSystem2();
|
|
4156
4161
|
const [readError, fileBuffer] = await catchError(fs.readFile(filePath));
|
|
4157
4162
|
if (readError) {
|
|
@@ -4195,7 +4200,7 @@ async function parseAttachmentArg(arg) {
|
|
|
4195
4200
|
}
|
|
4196
4201
|
return { name, path };
|
|
4197
4202
|
}
|
|
4198
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
4203
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
4199
4204
|
const fs = getFileSystem2();
|
|
4200
4205
|
return { name: fs.path.basename(arg), path: arg };
|
|
4201
4206
|
}
|
|
@@ -4794,7 +4799,7 @@ var registerJobsCommand = (program) => {
|
|
|
4794
4799
|
Data: data
|
|
4795
4800
|
});
|
|
4796
4801
|
});
|
|
4797
|
-
jobs.command("start").description("Start a job for a process. Returns the created job(s) with keys. " + "The <process-key> is the GUID from 'processes list' (not 'packages list'). " + "Folder is optional — if not provided, it is inferred from the process. " + "Use 'packages entry-points' to see input/output argument schemas for the process.").argument("<process-key>", "Process key (GUID) from 'processes list'. Identifies which process to run.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Folder path (optional — inferred from process if not provided)").option("--folder-key <key>", "Folder key (optional — inferred from process if not provided)").option("--strategy <strategy>", "Execution strategy (ModernJobsCount, All, Specific, JobsCount)", "ModernJobsCount").option("--jobs-count <number>", "Number of jobs to create (for JobsCount/ModernJobsCount strategy)", "1").option("--input-arguments <json>", "Input arguments as JSON string (mutually exclusive with --input-file). " + "Auto-offloads to InputFile if >10K chars. " + "Use 'packages entry-points' to see the expected schema.").option("--input-file <path>", "Upload a file as the job's InputFile (mutually exclusive with --input-arguments). " + "The file is uploaded as an attachment and its ID is set on the InputFile field.").option("--attachment <[name=]path>", "Upload a file and attach it to the job (repeatable). " + "Format: path (auto-names from filename) or name=path (explicit name). " + "Example: --attachment ./doc.pdf --attachment invoice=./report.pdf", (val, prev) => prev ? [...prev, val] : [val]).option("--attachment-id <guid>", "Attach an existing attachment by ID (repeatable). " + "Use 'attachments list --job-key <key>' to find IDs from a previous job.", (val, prev) => prev ? [...prev, val] : [val]).option("--runtime-type <type>", "Execution runtime (Unattended, Headless, Serverless, NonProduction, Development, TestAutomation). Defaults to folder configuration.").option("--user-keys <keys>", "Comma-separated user keys (GUIDs) to run as. Use 'users list' to find keys.").option("--machine-keys <keys>", "Comma-separated machine keys (GUIDs) to target. Use 'machines list' to find keys.").option("--environment-variables <pairs>", "Environment variables as newline-separated KEY=VALUE pairs").option("--run-as-me", "Run job under the caller's identity").option("--healing-agent", "Enable Healing Agent (Autopilot for Robots) for this run. Use to recover from selector failures and similar runtime errors. Tenant-level Autopilot must already be enabled.").option("--job-priority <priority>", "Job priority (Low, Normal, High)").option("--reference <reference>", "User-specified reference for the job").option("--wait-for-completion", "Poll until the job reaches a terminal state (Successful, Faulted, Stopped) and return its output").option("--timeout <seconds>", "Maximum time to wait for completion in seconds (default: 300)", "300").option("--poll-interval <seconds>", "Seconds between status checks (default: 5)", "5").option("--output-dir <path>", "Directory for downloading OutputFile (default: current directory). Only with --wait-for-completion.").option("--no-download", "Skip automatic OutputFile download. Only with --wait-for-completion.").examples(JOBS_START_EXAMPLES).trackedAction(processContext, async (releaseKey, options) => {
|
|
4802
|
+
jobs.command("start").description("Start a job for a process. Returns the created job(s) with keys. " + "The <process-key> is the GUID from 'processes list' (not 'packages list'). " + "Folder is optional — if not provided, it is inferred from the process. " + "Use 'packages entry-points' to see input/output argument schemas for the process.").argument("<process-key>", "Process key (GUID) from 'processes list'. Identifies which process to run.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Folder path (optional — inferred from process if not provided)").option("--folder-key <key>", "Folder key (optional — inferred from process if not provided)").option("--strategy <strategy>", "Execution strategy (ModernJobsCount, All, Specific, JobsCount)", "ModernJobsCount").option("--jobs-count <number>", "Number of jobs to create (for JobsCount/ModernJobsCount strategy)", "1").option("--input-arguments <json>", "Input arguments as JSON string (mutually exclusive with --input-file). " + "Auto-offloads to InputFile if >10K chars. " + "Use 'packages entry-points' to see the expected schema.").option("--input-file <path>", "Upload a file as the job's InputFile (mutually exclusive with --input-arguments). " + "The file is uploaded as an attachment and its ID is set on the InputFile field.").option("--attachment <[name=]path>", "Upload a file and attach it to the job (repeatable). " + "Format: path (auto-names from filename) or name=path (explicit name). " + "Example: --attachment ./doc.pdf --attachment invoice=./report.pdf", (val, prev) => prev ? [...prev, val] : [val]).option("--attachment-id <guid>", "Attach an existing attachment by ID (repeatable). " + "Use 'attachments list --job-key <key>' to find IDs from a previous job.", (val, prev) => prev ? [...prev, val] : [val]).option("--runtime-type <type>", "Execution runtime (Unattended, Headless, Serverless, NonProduction, Development, TestAutomation, Local). Local runs Agent, Function and API workflow jobs on the folder machines' local slots. Defaults to folder configuration.").option("--user-keys <keys>", "Comma-separated user keys (GUIDs) to run as. Use 'users list' to find keys.").option("--machine-keys <keys>", "Comma-separated machine keys (GUIDs) to target. Use 'machines list' to find keys.").option("--environment-variables <pairs>", "Environment variables as newline-separated KEY=VALUE pairs").option("--run-as-me", "Run job under the caller's identity").option("--healing-agent", "Enable Healing Agent (Autopilot for Robots) for this run. Use to recover from selector failures and similar runtime errors. Tenant-level Autopilot must already be enabled.").option("--job-priority <priority>", "Job priority (Low, Normal, High)").option("--reference <reference>", "User-specified reference for the job").option("--wait-for-completion", "Poll until the job reaches a terminal state (Successful, Faulted, Stopped) and return its output").option("--timeout <seconds>", "Maximum time to wait for completion in seconds (default: 300)", "300").option("--poll-interval <seconds>", "Seconds between status checks (default: 5)", "5").option("--output-dir <path>", "Directory for downloading OutputFile (default: current directory). Only with --wait-for-completion.").option("--no-download", "Skip automatic OutputFile download. Only with --wait-for-completion.").examples(JOBS_START_EXAMPLES).trackedAction(processContext, async (releaseKey, options) => {
|
|
4798
4803
|
const validStrategies = [
|
|
4799
4804
|
"ModernJobsCount",
|
|
4800
4805
|
"All",
|
|
@@ -4975,7 +4980,8 @@ var registerJobsCommand = (program) => {
|
|
|
4975
4980
|
"Serverless",
|
|
4976
4981
|
"NonProduction",
|
|
4977
4982
|
"Development",
|
|
4978
|
-
"TestAutomation"
|
|
4983
|
+
"TestAutomation",
|
|
4984
|
+
"Local"
|
|
4979
4985
|
];
|
|
4980
4986
|
const matchedRuntimeType = validRuntimeTypes.find((v) => v.toLowerCase() === options.runtimeType?.toLowerCase());
|
|
4981
4987
|
if (!matchedRuntimeType) {
|
|
@@ -5360,7 +5366,7 @@ var registerJobsCommand = (program) => {
|
|
|
5360
5366
|
});
|
|
5361
5367
|
processContext.exit(1);
|
|
5362
5368
|
});
|
|
5363
|
-
jobs.command("healing-data").description("Download healing agent (Autopilot for Robots) recovery data as a ZIP file. " + "Contains screenshots, UI element data, and recovery logs. " + "Only available for jobs where the healing agent was active. " + "Triggers an async export, polls until complete, then downloads the ZIP.").argument("<job-key>", "Job key (GUID)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--directory-prefix <prefix>", "Path prefix to filter exported files").option("-
|
|
5369
|
+
const healingData = jobs.command("healing-data").description("Download healing agent (Autopilot for Robots) recovery data as a ZIP file. " + "Contains screenshots, UI element data, and recovery logs. " + "Only available for jobs where the healing agent was active. " + "Triggers an async export, polls until complete, then downloads the ZIP.").argument("<job-key>", "Job key (GUID)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--directory-prefix <prefix>", "Path prefix to filter exported files").option("-d, --destination <path>", "Output file path (defaults to healing-agent-data-<job-key>.zip)").examples(JOBS_HEALING_DATA_EXAMPLES).trackedAction(processContext, async (jobKey, options) => {
|
|
5364
5370
|
const resolved = await resolveJobForCommand(jobKey, options.tenant, "Error getting healing data");
|
|
5365
5371
|
if (resolved === null)
|
|
5366
5372
|
return;
|
|
@@ -5485,8 +5491,8 @@ var registerJobsCommand = (program) => {
|
|
|
5485
5491
|
processContext.exit(1);
|
|
5486
5492
|
return;
|
|
5487
5493
|
}
|
|
5488
|
-
const fileName = options.
|
|
5489
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
5494
|
+
const fileName = options.destination || `healing-agent-data-${jobKey}.zip`;
|
|
5495
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
5490
5496
|
const fs = getFileSystem2();
|
|
5491
5497
|
const [writeError] = await catchError(fs.writeFile(fileName, Buffer.from(buffer)));
|
|
5492
5498
|
if (writeError) {
|
|
@@ -5509,6 +5515,7 @@ var registerJobsCommand = (program) => {
|
|
|
5509
5515
|
}
|
|
5510
5516
|
});
|
|
5511
5517
|
});
|
|
5518
|
+
addDeprecatedOptionAlias(healingData, "-o, --output <path>", "--destination");
|
|
5512
5519
|
jobs.command("history").description("Get state transition history for a job. " + "Shows timestamps for each state change (Pending → Running → Successful/Faulted). " + "Useful for understanding job lifecycle and identifying delays. " + "Folder context is resolved automatically from the job key.").argument("<job-key>", "Job key (GUID)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(JOBS_HISTORY_EXAMPLES).trackedAction(processContext, async (jobKey, options) => {
|
|
5513
5520
|
const command = await resolveJobWithJobsApi(jobKey, options.tenant, "Error getting job history");
|
|
5514
5521
|
if (command === null)
|
|
@@ -5547,7 +5554,7 @@ async function buildJobCompletionOutput(job, elapsedMs, options) {
|
|
|
5547
5554
|
data.Duration = `${Math.round(elapsedMs / 1000)}s`;
|
|
5548
5555
|
}
|
|
5549
5556
|
if (job.outputFile && options.download !== false) {
|
|
5550
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
5557
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
5551
5558
|
const fsHelper = getFileSystem2();
|
|
5552
5559
|
const outputDir = options.outputDir || ".";
|
|
5553
5560
|
const fileName = fsHelper.path.join(outputDir, `output-${job.key || "job"}.dat`);
|
|
@@ -6388,6 +6395,12 @@ function formatMachineDetail(machine) {
|
|
|
6388
6395
|
HeadlessSlots: machine.headlessSlots ?? 0,
|
|
6389
6396
|
NonProductionSlots: machine.nonProductionSlots ?? 0,
|
|
6390
6397
|
TestAutomationSlots: machine.testAutomationSlots ?? 0,
|
|
6398
|
+
AgentSlots: machine.agentSlots ?? 0,
|
|
6399
|
+
FunctionSlots: machine.functionSlots ?? 0,
|
|
6400
|
+
VerticalsRpaSlots: machine.verticalsRpaSlots ?? 0,
|
|
6401
|
+
VerticalsAgentSlots: machine.verticalsAgentSlots ?? 0,
|
|
6402
|
+
VerticalsFunctionSlots: machine.verticalsFunctionSlots ?? 0,
|
|
6403
|
+
ExecutionOptions: machine.executionOptions || "None",
|
|
6391
6404
|
LicenseKey: machine.licenseKey || ""
|
|
6392
6405
|
};
|
|
6393
6406
|
}
|
|
@@ -6406,6 +6419,84 @@ function parseSlotOption(value, flag, errorContext) {
|
|
|
6406
6419
|
}
|
|
6407
6420
|
return n;
|
|
6408
6421
|
}
|
|
6422
|
+
var SLOT_OPTIONS = [
|
|
6423
|
+
{
|
|
6424
|
+
flag: "--unattended-slots",
|
|
6425
|
+
option: "unattendedSlots",
|
|
6426
|
+
field: "unattendedSlots"
|
|
6427
|
+
},
|
|
6428
|
+
{
|
|
6429
|
+
flag: "--headless-slots",
|
|
6430
|
+
option: "headlessSlots",
|
|
6431
|
+
field: "headlessSlots"
|
|
6432
|
+
},
|
|
6433
|
+
{
|
|
6434
|
+
flag: "--non-production-slots",
|
|
6435
|
+
option: "nonProductionSlots",
|
|
6436
|
+
field: "nonProductionSlots"
|
|
6437
|
+
},
|
|
6438
|
+
{
|
|
6439
|
+
flag: "--testing-slots",
|
|
6440
|
+
option: "testingSlots",
|
|
6441
|
+
field: "testAutomationSlots"
|
|
6442
|
+
},
|
|
6443
|
+
{
|
|
6444
|
+
flag: "--agent-slots",
|
|
6445
|
+
option: "agentSlots",
|
|
6446
|
+
field: "agentSlots"
|
|
6447
|
+
},
|
|
6448
|
+
{
|
|
6449
|
+
flag: "--function-slots",
|
|
6450
|
+
option: "functionSlots",
|
|
6451
|
+
field: "functionSlots"
|
|
6452
|
+
},
|
|
6453
|
+
{
|
|
6454
|
+
flag: "--verticals-rpa-slots",
|
|
6455
|
+
option: "verticalsRpaSlots",
|
|
6456
|
+
field: "verticalsRpaSlots"
|
|
6457
|
+
},
|
|
6458
|
+
{
|
|
6459
|
+
flag: "--verticals-agent-slots",
|
|
6460
|
+
option: "verticalsAgentSlots",
|
|
6461
|
+
field: "verticalsAgentSlots"
|
|
6462
|
+
},
|
|
6463
|
+
{
|
|
6464
|
+
flag: "--verticals-function-slots",
|
|
6465
|
+
option: "verticalsFunctionSlots",
|
|
6466
|
+
field: "verticalsFunctionSlots"
|
|
6467
|
+
}
|
|
6468
|
+
];
|
|
6469
|
+
var VALID_EXECUTION_OPTIONS = ["None", "AgentsOnUnattended", "RunVerticals"];
|
|
6470
|
+
function parseMachineSlotOptions(options, errorContext) {
|
|
6471
|
+
const body = {};
|
|
6472
|
+
for (const slot of SLOT_OPTIONS) {
|
|
6473
|
+
const value = parseSlotOption(options[slot.option], slot.flag, errorContext);
|
|
6474
|
+
if (value === null)
|
|
6475
|
+
return null;
|
|
6476
|
+
if (value !== undefined)
|
|
6477
|
+
body[slot.field] = value;
|
|
6478
|
+
}
|
|
6479
|
+
if (options.executionOptions !== undefined) {
|
|
6480
|
+
const values = options.executionOptions.flatMap((v) => v.split(",")).map((v) => v.trim()).filter((v) => v.length > 0);
|
|
6481
|
+
const matched = values.map((v) => VALID_EXECUTION_OPTIONS.find((valid) => valid.toLowerCase() === v.toLowerCase()));
|
|
6482
|
+
if (matched.length === 0 || matched.some((m) => m === undefined)) {
|
|
6483
|
+
OutputFormatter.error({
|
|
6484
|
+
Result: RESULTS.Failure,
|
|
6485
|
+
Message: errorContext,
|
|
6486
|
+
Instructions: `Invalid --execution-options '${options.executionOptions.join(" ")}'. Must be one or more of: ${VALID_EXECUTION_OPTIONS.join(", ")}`
|
|
6487
|
+
});
|
|
6488
|
+
processContext.exit(1);
|
|
6489
|
+
return null;
|
|
6490
|
+
}
|
|
6491
|
+
const unique = [...new Set(matched)];
|
|
6492
|
+
const flags = unique.filter((m) => m !== "None" || unique.length === 1);
|
|
6493
|
+
body.executionOptions = flags.join(", ");
|
|
6494
|
+
}
|
|
6495
|
+
return body;
|
|
6496
|
+
}
|
|
6497
|
+
function addSlotOptions(command) {
|
|
6498
|
+
return command.option("--unattended-slots <number>", "Number of unattended robot slots to allocate").option("--headless-slots <number>", "Number of headless robot slots to allocate").option("--non-production-slots <number>", "Number of non-production robot slots to allocate").option("--testing-slots <number>", "Number of test automation robot slots to allocate").option("--agent-slots <number>", "Number of Agent jobs that can run in parallel on the machine's Local runtime").option("--function-slots <number>", "Number of Function and API workflow jobs that can run in parallel on the machine's Local runtime").option("--verticals-rpa-slots <number>", "Number of Local RPA slots reserved for Vertical Solution legs. Used only with --execution-options RunVerticals").option("--verticals-agent-slots <number>", "Number of Local Agent slots reserved for Vertical Solution legs. Used only with --execution-options RunVerticals").option("--verticals-function-slots <number>", "Number of Local Function slots reserved for Vertical Solution legs. Used only with --execution-options RunVerticals").option("--execution-options <options...>", "Machine execution options, space-separated: None, AgentsOnUnattended (Function and API workflow jobs " + "use the Unattended slots), RunVerticals (the machine runs Vertical Solution legs on its vertical slots). " + "Replaces the current value");
|
|
6499
|
+
}
|
|
6409
6500
|
var MACHINES_LIST_EXAMPLES = [
|
|
6410
6501
|
{
|
|
6411
6502
|
Description: "List all machines in the tenant",
|
|
@@ -6424,6 +6515,12 @@ var MACHINES_LIST_EXAMPLES = [
|
|
|
6424
6515
|
HeadlessSlots: 0,
|
|
6425
6516
|
NonProductionSlots: 0,
|
|
6426
6517
|
TestAutomationSlots: 0,
|
|
6518
|
+
AgentSlots: 0,
|
|
6519
|
+
FunctionSlots: 0,
|
|
6520
|
+
VerticalsRpaSlots: 0,
|
|
6521
|
+
VerticalsAgentSlots: 0,
|
|
6522
|
+
VerticalsFunctionSlots: 0,
|
|
6523
|
+
ExecutionOptions: "None",
|
|
6427
6524
|
LicenseKey: "b1c2d3e4-0000-0000-0000-000000000100"
|
|
6428
6525
|
},
|
|
6429
6526
|
{
|
|
@@ -6437,6 +6534,12 @@ var MACHINES_LIST_EXAMPLES = [
|
|
|
6437
6534
|
HeadlessSlots: 0,
|
|
6438
6535
|
NonProductionSlots: 0,
|
|
6439
6536
|
TestAutomationSlots: 0,
|
|
6537
|
+
AgentSlots: 0,
|
|
6538
|
+
FunctionSlots: 0,
|
|
6539
|
+
VerticalsRpaSlots: 0,
|
|
6540
|
+
VerticalsAgentSlots: 0,
|
|
6541
|
+
VerticalsFunctionSlots: 0,
|
|
6542
|
+
ExecutionOptions: "None",
|
|
6440
6543
|
LicenseKey: "b1c2d3e4-0000-0000-0000-000000000200"
|
|
6441
6544
|
}
|
|
6442
6545
|
]
|
|
@@ -6460,6 +6563,12 @@ var MACHINES_GET_EXAMPLES = [
|
|
|
6460
6563
|
HeadlessSlots: 0,
|
|
6461
6564
|
NonProductionSlots: 0,
|
|
6462
6565
|
TestAutomationSlots: 0,
|
|
6566
|
+
AgentSlots: 0,
|
|
6567
|
+
FunctionSlots: 0,
|
|
6568
|
+
VerticalsRpaSlots: 0,
|
|
6569
|
+
VerticalsAgentSlots: 0,
|
|
6570
|
+
VerticalsFunctionSlots: 0,
|
|
6571
|
+
ExecutionOptions: "None",
|
|
6463
6572
|
LicenseKey: "b1c2d3e4-0000-0000-0000-000000000100"
|
|
6464
6573
|
}
|
|
6465
6574
|
}
|
|
@@ -6482,6 +6591,38 @@ var MACHINES_CREATE_EXAMPLES = [
|
|
|
6482
6591
|
HeadlessSlots: 0,
|
|
6483
6592
|
NonProductionSlots: 0,
|
|
6484
6593
|
TestAutomationSlots: 0,
|
|
6594
|
+
AgentSlots: 0,
|
|
6595
|
+
FunctionSlots: 0,
|
|
6596
|
+
VerticalsRpaSlots: 0,
|
|
6597
|
+
VerticalsAgentSlots: 0,
|
|
6598
|
+
VerticalsFunctionSlots: 0,
|
|
6599
|
+
ExecutionOptions: "None",
|
|
6600
|
+
LicenseKey: ""
|
|
6601
|
+
}
|
|
6602
|
+
}
|
|
6603
|
+
},
|
|
6604
|
+
{
|
|
6605
|
+
Description: "Create a template for local Agent and Function jobs, with slots reserved for Vertical Solution legs",
|
|
6606
|
+
Command: 'uip or machines create --name "local-worker" --agent-slots 2 --function-slots 2 --verticals-agent-slots 1 --execution-options RunVerticals',
|
|
6607
|
+
Output: {
|
|
6608
|
+
Code: "MachineCreated",
|
|
6609
|
+
Data: {
|
|
6610
|
+
Name: "local-worker",
|
|
6611
|
+
ID: 104,
|
|
6612
|
+
Key: "a1b2c3d4-0000-0000-0000-000000000011",
|
|
6613
|
+
Type: "Template",
|
|
6614
|
+
Scope: "Default",
|
|
6615
|
+
Description: "",
|
|
6616
|
+
UnattendedSlots: 0,
|
|
6617
|
+
HeadlessSlots: 0,
|
|
6618
|
+
NonProductionSlots: 0,
|
|
6619
|
+
TestAutomationSlots: 0,
|
|
6620
|
+
AgentSlots: 2,
|
|
6621
|
+
FunctionSlots: 2,
|
|
6622
|
+
VerticalsRpaSlots: 0,
|
|
6623
|
+
VerticalsAgentSlots: 1,
|
|
6624
|
+
VerticalsFunctionSlots: 0,
|
|
6625
|
+
ExecutionOptions: "RunVerticals",
|
|
6485
6626
|
LicenseKey: ""
|
|
6486
6627
|
}
|
|
6487
6628
|
}
|
|
@@ -6658,19 +6799,10 @@ var registerMachinesCommand = (program) => {
|
|
|
6658
6799
|
Data: options.allFields ? resolved.machine : formatMachineDetail(resolved.machine)
|
|
6659
6800
|
});
|
|
6660
6801
|
});
|
|
6661
|
-
machines.command("create").description("Create a new machine template (robot host definition). " + "Machines define where robots execute and how many license slots are allocated. " + "Use --serverless to create a serverless (cloud-hosted) machine. " + "Slot options control how many concurrent robot sessions of each type are allowed.").requiredOption("-n, --name <name>", "Machine name (must be unique within the tenant)").option("-d, --description <description>", "Machine description").option("--serverless", "Create a serverless (cloud-hosted) machine instead of a standard template")
|
|
6662
|
-
|
|
6663
|
-
const
|
|
6664
|
-
if (
|
|
6665
|
-
return;
|
|
6666
|
-
const headless = parseSlotOption(options.headlessSlots, "--headless-slots", ctx);
|
|
6667
|
-
if (headless === null)
|
|
6668
|
-
return;
|
|
6669
|
-
const nonProduction = parseSlotOption(options.nonProductionSlots, "--non-production-slots", ctx);
|
|
6670
|
-
if (nonProduction === null)
|
|
6671
|
-
return;
|
|
6672
|
-
const testing = parseSlotOption(options.testingSlots, "--testing-slots", ctx);
|
|
6673
|
-
if (testing === null)
|
|
6802
|
+
const createCommand = machines.command("create").description("Create a new machine template (robot host definition). " + "Machines define where robots execute and how many license slots are allocated. " + "Use --serverless to create a serverless (cloud-hosted) machine. " + "Slot options control how many concurrent robot sessions of each type are allowed.").requiredOption("-n, --name <name>", "Machine name (must be unique within the tenant)").option("-d, --description <description>", "Machine description").option("--serverless", "Create a serverless (cloud-hosted) machine instead of a standard template");
|
|
6803
|
+
addSlotOptions(createCommand).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(MACHINES_CREATE_EXAMPLES).trackedAction(processContext, async (options) => {
|
|
6804
|
+
const slots = parseMachineSlotOptions(options, "Error creating machine");
|
|
6805
|
+
if (slots === null)
|
|
6674
6806
|
return;
|
|
6675
6807
|
const [apiError, api] = await catchError(createApiClient(MachinesApi, { tenant: options.tenant }));
|
|
6676
6808
|
if (apiError) {
|
|
@@ -6678,6 +6810,7 @@ var registerMachinesCommand = (program) => {
|
|
|
6678
6810
|
return;
|
|
6679
6811
|
}
|
|
6680
6812
|
const machineData = {
|
|
6813
|
+
...slots,
|
|
6681
6814
|
name: options.name,
|
|
6682
6815
|
type: "Template"
|
|
6683
6816
|
};
|
|
@@ -6688,14 +6821,6 @@ var registerMachinesCommand = (program) => {
|
|
|
6688
6821
|
if (options.description) {
|
|
6689
6822
|
machineData.description = options.description;
|
|
6690
6823
|
}
|
|
6691
|
-
if (unattended !== undefined)
|
|
6692
|
-
machineData.unattendedSlots = unattended;
|
|
6693
|
-
if (headless !== undefined)
|
|
6694
|
-
machineData.headlessSlots = headless;
|
|
6695
|
-
if (nonProduction !== undefined)
|
|
6696
|
-
machineData.nonProductionSlots = nonProduction;
|
|
6697
|
-
if (testing !== undefined)
|
|
6698
|
-
machineData.testAutomationSlots = testing;
|
|
6699
6824
|
const [createError, result] = await catchError(api.machinesPost({
|
|
6700
6825
|
body: machineData
|
|
6701
6826
|
}));
|
|
@@ -6709,7 +6834,8 @@ var registerMachinesCommand = (program) => {
|
|
|
6709
6834
|
Data: formatMachineDetail(result)
|
|
6710
6835
|
});
|
|
6711
6836
|
});
|
|
6712
|
-
machines.command("update").alias("edit").description("Update machine properties (name, description, slot allocations). " + "Only the provided options are updated; omitted fields remain unchanged. " + "Use 'machines get' to see current values before updating.").argument("<machine-key>", "Machine key (GUID) — use 'machines list' to find").option("-n, --name <name>", "New machine name").option("-d, --description <description>", "New machine description")
|
|
6837
|
+
const updateCommand = machines.command("update").alias("edit").description("Update machine properties (name, description, slot allocations). " + "Only the provided options are updated; omitted fields remain unchanged. " + "Use 'machines get' to see current values before updating.").argument("<machine-key>", "Machine key (GUID) — use 'machines list' to find").option("-n, --name <name>", "New machine name").option("-d, --description <description>", "New machine description");
|
|
6838
|
+
addSlotOptions(updateCommand).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(MACHINES_EDIT_EXAMPLES).trackedAction(processContext, async (machineKey, options) => {
|
|
6713
6839
|
const resolved = await resolveMachineForCommand(machineKey, options.tenant, "Error updating machine");
|
|
6714
6840
|
if (resolved === null)
|
|
6715
6841
|
return;
|
|
@@ -6721,27 +6847,10 @@ var registerMachinesCommand = (program) => {
|
|
|
6721
6847
|
updateData.name = options.name;
|
|
6722
6848
|
if (options.description)
|
|
6723
6849
|
updateData.description = options.description;
|
|
6724
|
-
const
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
const headless = parseSlotOption(options.headlessSlots, "--headless-slots", ctx);
|
|
6729
|
-
if (headless === null)
|
|
6730
|
-
return;
|
|
6731
|
-
const nonProduction = parseSlotOption(options.nonProductionSlots, "--non-production-slots", ctx);
|
|
6732
|
-
if (nonProduction === null)
|
|
6733
|
-
return;
|
|
6734
|
-
const testing = parseSlotOption(options.testingSlots, "--testing-slots", ctx);
|
|
6735
|
-
if (testing === null)
|
|
6736
|
-
return;
|
|
6737
|
-
if (unattended !== undefined)
|
|
6738
|
-
updateData.unattendedSlots = unattended;
|
|
6739
|
-
if (headless !== undefined)
|
|
6740
|
-
updateData.headlessSlots = headless;
|
|
6741
|
-
if (nonProduction !== undefined)
|
|
6742
|
-
updateData.nonProductionSlots = nonProduction;
|
|
6743
|
-
if (testing !== undefined)
|
|
6744
|
-
updateData.testAutomationSlots = testing;
|
|
6850
|
+
const slots = parseMachineSlotOptions(options, "Error updating machine");
|
|
6851
|
+
if (slots === null)
|
|
6852
|
+
return;
|
|
6853
|
+
Object.assign(updateData, slots);
|
|
6745
6854
|
const [editError] = await catchError(api.machinesPatchById({
|
|
6746
6855
|
key: resolved.id,
|
|
6747
6856
|
body: updateData
|
|
@@ -7396,7 +7505,7 @@ var registerPackagesCommand = (program) => {
|
|
|
7396
7505
|
processContext.exit(1);
|
|
7397
7506
|
return;
|
|
7398
7507
|
}
|
|
7399
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
7508
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
7400
7509
|
const fs = getFileSystem2();
|
|
7401
7510
|
const [readError, fileBuffer] = await catchError(fs.readFile(filePath));
|
|
7402
7511
|
if (readError || fileBuffer === null) {
|
|
@@ -7566,7 +7675,7 @@ var registerPackagesCommand = (program) => {
|
|
|
7566
7675
|
await reportFailure("Error downloading package", bufferError);
|
|
7567
7676
|
return;
|
|
7568
7677
|
}
|
|
7569
|
-
const { getFileSystem: getFileSystem2 } = await import("./index-
|
|
7678
|
+
const { getFileSystem: getFileSystem2 } = await import("./index-rkqk9b39.js");
|
|
7570
7679
|
const fs = getFileSystem2();
|
|
7571
7680
|
const buffer = new Uint8Array(arrayBuffer);
|
|
7572
7681
|
const [writeError] = await catchError(fs.writeFile(options.destination, buffer));
|
|
@@ -11258,6 +11367,185 @@ var registerQueuesCommand = (program) => {
|
|
|
11258
11367
|
});
|
|
11259
11368
|
};
|
|
11260
11369
|
|
|
11370
|
+
// src/utils/role-permissions.ts
|
|
11371
|
+
var CATALOG_PAGE_SIZE = 1000;
|
|
11372
|
+
var MAX_SUGGESTIONS = 5;
|
|
11373
|
+
var ACTION_SUFFIX = /\.(View|Edit|Create|Delete)$/;
|
|
11374
|
+
var GROUP_HINTS = {
|
|
11375
|
+
triggers: "Schedules",
|
|
11376
|
+
folders: "Units",
|
|
11377
|
+
actioncatalogs: "TaskCatalogs"
|
|
11378
|
+
};
|
|
11379
|
+
async function fetchPermissionCatalog(api) {
|
|
11380
|
+
const catalog = [];
|
|
11381
|
+
for (let skip = 0;; skip += CATALOG_PAGE_SIZE) {
|
|
11382
|
+
const page = (await api.permissionsGet({
|
|
11383
|
+
$top: CATALOG_PAGE_SIZE,
|
|
11384
|
+
$skip: skip,
|
|
11385
|
+
$orderby: "Name asc"
|
|
11386
|
+
})).value ?? [];
|
|
11387
|
+
catalog.push(...page);
|
|
11388
|
+
if (page.length < CATALOG_PAGE_SIZE)
|
|
11389
|
+
return catalog;
|
|
11390
|
+
}
|
|
11391
|
+
}
|
|
11392
|
+
function planPermissionChanges(input) {
|
|
11393
|
+
const catalogByName = byName(input.catalog);
|
|
11394
|
+
const existingByName = byName(input.role.permissions ?? []);
|
|
11395
|
+
const resolveIn = (...sources) => {
|
|
11396
|
+
const canonical = new Map;
|
|
11397
|
+
for (const name of sources.flatMap((s) => [...s.keys()])) {
|
|
11398
|
+
canonical.set(name.toLowerCase(), name);
|
|
11399
|
+
}
|
|
11400
|
+
return (name) => sources.some((s) => s.has(name)) ? name : canonical.get(name.toLowerCase());
|
|
11401
|
+
};
|
|
11402
|
+
const resolveAdd = resolveIn(catalogByName);
|
|
11403
|
+
const resolveRemove = resolveIn(existingByName, catalogByName);
|
|
11404
|
+
const unknownNames = unique([
|
|
11405
|
+
...input.add.filter((n) => !resolveAdd(n)),
|
|
11406
|
+
...input.remove.filter((n) => !resolveRemove(n))
|
|
11407
|
+
]);
|
|
11408
|
+
if (unknownNames.length > 0) {
|
|
11409
|
+
const names = [
|
|
11410
|
+
...(catalogByName.size > 0 ? catalogByName : existingByName).keys()
|
|
11411
|
+
];
|
|
11412
|
+
return {
|
|
11413
|
+
kind: "unknown",
|
|
11414
|
+
unknown: unknownNames.map((name) => ({
|
|
11415
|
+
Name: name,
|
|
11416
|
+
Suggestions: suggestPermissionNames(name, names)
|
|
11417
|
+
})),
|
|
11418
|
+
catalogEmpty: catalogByName.size === 0
|
|
11419
|
+
};
|
|
11420
|
+
}
|
|
11421
|
+
const toAdd = new Set(input.add.map((n) => resolveAdd(n)));
|
|
11422
|
+
const toRemove = new Set(input.remove.map((n) => resolveRemove(n)));
|
|
11423
|
+
const conflicting = [...toAdd].filter((n) => toRemove.has(n));
|
|
11424
|
+
if (conflicting.length > 0) {
|
|
11425
|
+
return { kind: "conflicting", conflicting };
|
|
11426
|
+
}
|
|
11427
|
+
const rejected = rejectedForRoleType(input.role.type, toAdd, catalogByName);
|
|
11428
|
+
if (rejected.length > 0) {
|
|
11429
|
+
return {
|
|
11430
|
+
kind: "wrong-scope",
|
|
11431
|
+
roleType: input.role.type,
|
|
11432
|
+
rejected
|
|
11433
|
+
};
|
|
11434
|
+
}
|
|
11435
|
+
const permissions = [...existingByName.values()].map((p) => {
|
|
11436
|
+
if (toAdd.has(p.name))
|
|
11437
|
+
return { ...p, isGranted: true };
|
|
11438
|
+
if (toRemove.has(p.name))
|
|
11439
|
+
return { ...p, isGranted: false };
|
|
11440
|
+
return p;
|
|
11441
|
+
});
|
|
11442
|
+
for (const name of toAdd) {
|
|
11443
|
+
const template = catalogByName.get(name);
|
|
11444
|
+
if (!existingByName.has(name) && template) {
|
|
11445
|
+
permissions.push({ ...template, isGranted: true });
|
|
11446
|
+
}
|
|
11447
|
+
}
|
|
11448
|
+
const wasGranted = (name) => existingByName.get(name)?.isGranted === true;
|
|
11449
|
+
return {
|
|
11450
|
+
kind: "ok",
|
|
11451
|
+
permissions,
|
|
11452
|
+
added: [...toAdd].filter((n) => !wasGranted(n)),
|
|
11453
|
+
removed: [...toRemove].filter(wasGranted)
|
|
11454
|
+
};
|
|
11455
|
+
}
|
|
11456
|
+
function rejectedForRoleType(roleType, names, catalogByName) {
|
|
11457
|
+
if (roleType !== "Folder" && roleType !== "Tenant")
|
|
11458
|
+
return [];
|
|
11459
|
+
const rejected = [];
|
|
11460
|
+
for (const name of names) {
|
|
11461
|
+
const scope = catalogByName.get(name)?.scope;
|
|
11462
|
+
if (!scope || !ACTION_SUFFIX.test(name))
|
|
11463
|
+
continue;
|
|
11464
|
+
const isFolderScope = scope === "Folder";
|
|
11465
|
+
if (roleType === "Folder" !== isFolderScope) {
|
|
11466
|
+
rejected.push({ Name: name, Scope: scope });
|
|
11467
|
+
}
|
|
11468
|
+
}
|
|
11469
|
+
return rejected;
|
|
11470
|
+
}
|
|
11471
|
+
function suggestPermissionNames(input, names) {
|
|
11472
|
+
const candidates = names.filter((n) => n.includes("."));
|
|
11473
|
+
const lower = input.toLowerCase();
|
|
11474
|
+
const dot = lower.indexOf(".");
|
|
11475
|
+
const group = dot === -1 ? lower : lower.slice(0, dot);
|
|
11476
|
+
const action = dot === -1 ? "" : lower.slice(dot + 1);
|
|
11477
|
+
const suggestions = new Set;
|
|
11478
|
+
const inGroup = (g) => candidates.filter((n) => n.toLowerCase().startsWith(`${g}.`));
|
|
11479
|
+
const hinted = GROUP_HINTS[group]?.toLowerCase();
|
|
11480
|
+
if (hinted) {
|
|
11481
|
+
const exact = candidates.find((n) => n.toLowerCase() === `${hinted}.${action}`);
|
|
11482
|
+
for (const n of exact ? [exact] : inGroup(hinted))
|
|
11483
|
+
suggestions.add(n);
|
|
11484
|
+
}
|
|
11485
|
+
const maxEdits = Math.max(2, Math.floor(input.length / 4));
|
|
11486
|
+
const nearMisses = candidates.map((n) => ({ n, d: editDistance(lower, n.toLowerCase()) })).filter(({ d }) => d <= maxEdits).sort((a, b) => a.d - b.d || a.n.localeCompare(b.n));
|
|
11487
|
+
for (const { n } of nearMisses)
|
|
11488
|
+
suggestions.add(n);
|
|
11489
|
+
for (const n of inGroup(group))
|
|
11490
|
+
suggestions.add(n);
|
|
11491
|
+
return [...suggestions].slice(0, MAX_SUGGESTIONS);
|
|
11492
|
+
}
|
|
11493
|
+
function unknownPermissionsFailure(roleKey, unknown, catalogEmpty) {
|
|
11494
|
+
const hints = unknown.filter((u) => u.Suggestions.length > 0).map((u) => `${u.Suggestions.join(", ")} (for ${u.Name})`);
|
|
11495
|
+
const didYouMean = hints.length > 0 ? `Did you mean ${hints.join("; ")}? ` : "";
|
|
11496
|
+
const empty = catalogEmpty ? "The permission catalog came back empty for this login, so no name could be checked. " : "";
|
|
11497
|
+
return {
|
|
11498
|
+
Result: RESULTS.Failure,
|
|
11499
|
+
ErrorCode: "invalid_argument",
|
|
11500
|
+
Message: `Not in this tenant's permission catalog: ${unknown.map((u) => u.Name).join(", ")}. The role was not changed.`,
|
|
11501
|
+
Instructions: `${empty}${didYouMean}Run 'uip or roles permissions list --limit 1000' to see every permission name.`,
|
|
11502
|
+
Retry: "RetryWillNotFix",
|
|
11503
|
+
Data: { RoleKey: roleKey, UnknownPermissions: [...unknown] }
|
|
11504
|
+
};
|
|
11505
|
+
}
|
|
11506
|
+
function rejectedPermissionsFailure(roleKey, roleType, rejected) {
|
|
11507
|
+
const [held, other] = roleType === "Folder" ? ["tenant", "Tenant"] : ["folder", "Folder"];
|
|
11508
|
+
return {
|
|
11509
|
+
Result: RESULTS.Failure,
|
|
11510
|
+
ErrorCode: "invalid_argument",
|
|
11511
|
+
Message: `A ${roleType} role cannot hold ${held} permissions: ${rejected.map((r) => r.Name).join(", ")}. The role was not changed.`,
|
|
11512
|
+
Instructions: `Drop them from --add-permissions, or grant them through a ${other} role ('uip or roles list' shows each role's Type).`,
|
|
11513
|
+
Retry: "RetryWillNotFix",
|
|
11514
|
+
Data: {
|
|
11515
|
+
RoleKey: roleKey,
|
|
11516
|
+
RoleType: roleType,
|
|
11517
|
+
RejectedPermissions: [...rejected]
|
|
11518
|
+
}
|
|
11519
|
+
};
|
|
11520
|
+
}
|
|
11521
|
+
function conflictingPermissionsFailure(roleKey, conflicting) {
|
|
11522
|
+
return {
|
|
11523
|
+
Result: RESULTS.Failure,
|
|
11524
|
+
ErrorCode: "invalid_argument",
|
|
11525
|
+
Message: `Both added and removed: ${conflicting.join(", ")}. The role was not changed.`,
|
|
11526
|
+
Instructions: "Pass each permission to only one of --add-permissions and --remove-permissions.",
|
|
11527
|
+
Retry: "RetryWillNotFix",
|
|
11528
|
+
Data: { RoleKey: roleKey, ConflictingPermissions: [...conflicting] }
|
|
11529
|
+
};
|
|
11530
|
+
}
|
|
11531
|
+
function byName(permissions) {
|
|
11532
|
+
return new Map(permissions.filter((p) => p.name != null).map((p) => [p.name, p]));
|
|
11533
|
+
}
|
|
11534
|
+
function unique(names) {
|
|
11535
|
+
return [...new Set(names)];
|
|
11536
|
+
}
|
|
11537
|
+
function editDistance(a, b) {
|
|
11538
|
+
let previous = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
11539
|
+
for (let i = 1;i <= a.length; i++) {
|
|
11540
|
+
const current = [i];
|
|
11541
|
+
for (let j = 1;j <= b.length; j++) {
|
|
11542
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
11543
|
+
}
|
|
11544
|
+
previous = current;
|
|
11545
|
+
}
|
|
11546
|
+
return previous[b.length];
|
|
11547
|
+
}
|
|
11548
|
+
|
|
11261
11549
|
// src/utils/role-resolver.ts
|
|
11262
11550
|
async function resolveRoleGuid(roleKey) {
|
|
11263
11551
|
const [apiError, api] = await catchError(createApiClient(RolesApi));
|
|
@@ -11305,6 +11593,9 @@ async function resolveUserGuid(userInput) {
|
|
|
11305
11593
|
|
|
11306
11594
|
// src/commands/roles.ts
|
|
11307
11595
|
var ROLE_TYPE_ALLOWLIST = ["Tenant", "Folder"];
|
|
11596
|
+
function splitPermissionNames(value) {
|
|
11597
|
+
return value === undefined ? [] : value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
11598
|
+
}
|
|
11308
11599
|
function parseUserRolePrincipalType(value) {
|
|
11309
11600
|
switch (value.toLowerCase()) {
|
|
11310
11601
|
case "user":
|
|
@@ -11404,13 +11695,15 @@ var ROLES_CREATE_ROLE_EXAMPLES = [
|
|
|
11404
11695
|
];
|
|
11405
11696
|
var ROLES_EDIT_ROLE_EXAMPLES = [
|
|
11406
11697
|
{
|
|
11407
|
-
Description: "Add permissions to a role",
|
|
11408
|
-
Command: "uip or roles update a1b2c3d4-0000-0000-0000-000000000010 --add-permissions
|
|
11698
|
+
Description: "Add permissions to a tenant role",
|
|
11699
|
+
Command: "uip or roles update a1b2c3d4-0000-0000-0000-000000000010 --add-permissions Users.View,Robots.View",
|
|
11409
11700
|
Output: {
|
|
11410
11701
|
Code: "RoleUpdated",
|
|
11411
11702
|
Data: {
|
|
11412
11703
|
Key: "a1b2c3d4-0000-0000-0000-000000000010",
|
|
11413
|
-
Status: "Updated successfully"
|
|
11704
|
+
Status: "Updated successfully",
|
|
11705
|
+
AddedPermissions: ["Users.View", "Robots.View"],
|
|
11706
|
+
RemovedPermissions: []
|
|
11414
11707
|
}
|
|
11415
11708
|
}
|
|
11416
11709
|
}
|
|
@@ -11685,7 +11978,7 @@ var registerRolesCommand = (program) => {
|
|
|
11685
11978
|
}
|
|
11686
11979
|
});
|
|
11687
11980
|
});
|
|
11688
|
-
rolesCmd.command("update").alias("edit").description("Add or remove permissions on a role. " + "Reads current permissions, applies changes, and saves. " + "Use 'roles permissions list' to find valid permission names, 'roles get' to see current grants.").argument("<role-key>", "Role key (GUID) — use 'roles list' to find").option("--add-permissions <names>", "Comma-separated permission names to add to the role").option("--remove-permissions <names>", "Comma-separated permission names to remove from the role").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(ROLES_EDIT_ROLE_EXAMPLES).trackedAction(processContext, async (roleKey, options) => {
|
|
11981
|
+
rolesCmd.command("update").alias("edit").description("Add or remove permissions on a role. " + "Reads current permissions, applies changes, and saves. " + "Names are checked against the tenant's permission catalog before saving: an unknown name, " + "or a permission whose scope does not fit the role (a tenant permission on a Folder role, a folder permission on a Tenant role), " + "is refused and nothing is saved. Reports the permissions it actually added and removed. " + "Use 'roles permissions list' to find valid permission names, 'roles get' to see current grants.").argument("<role-key>", "Role key (GUID) — use 'roles list' to find").option("--add-permissions <names>", "Comma-separated permission names to add to the role").option("--remove-permissions <names>", "Comma-separated permission names to remove from the role").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(ROLES_EDIT_ROLE_EXAMPLES).trackedAction(processContext, async (roleKey, options) => {
|
|
11689
11982
|
if (!options.addPermissions && !options.removePermissions) {
|
|
11690
11983
|
OutputFormatter.error({
|
|
11691
11984
|
Result: RESULTS.Failure,
|
|
@@ -11715,38 +12008,32 @@ var registerRolesCommand = (program) => {
|
|
|
11715
12008
|
await reportFailure("Error fetching current role data", getError);
|
|
11716
12009
|
return;
|
|
11717
12010
|
}
|
|
11718
|
-
const toAdd = options.addPermissions ? new Set(options.addPermissions.split(",").map((p) => p.trim()).filter(Boolean)) : new Set;
|
|
11719
|
-
const toRemove = options.removePermissions ? new Set(options.removePermissions.split(",").map((p) => p.trim()).filter(Boolean)) : new Set;
|
|
11720
12011
|
const [permApiError, permApi] = await catchError(createApiClient(PermissionsApi, { tenant: options.tenant }));
|
|
11721
12012
|
if (permApiError) {
|
|
11722
12013
|
await reportFailure("Error fetching available permissions", permApiError);
|
|
11723
12014
|
return;
|
|
11724
12015
|
}
|
|
11725
|
-
const [
|
|
11726
|
-
if (
|
|
11727
|
-
await reportFailure("Error fetching available permissions",
|
|
12016
|
+
const [catalogError, catalog] = await catchError(fetchPermissionCatalog(permApi));
|
|
12017
|
+
if (catalogError) {
|
|
12018
|
+
await reportFailure("Error fetching available permissions", catalogError);
|
|
11728
12019
|
return;
|
|
11729
12020
|
}
|
|
11730
|
-
const
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
}
|
|
11736
|
-
if (p.name && toRemove.has(p.name)) {
|
|
11737
|
-
return { ...p, isGranted: false };
|
|
11738
|
-
}
|
|
11739
|
-
return p;
|
|
12021
|
+
const plan = planPermissionChanges({
|
|
12022
|
+
role: current,
|
|
12023
|
+
catalog,
|
|
12024
|
+
add: splitPermissionNames(options.addPermissions),
|
|
12025
|
+
remove: splitPermissionNames(options.removePermissions)
|
|
11740
12026
|
});
|
|
11741
|
-
|
|
11742
|
-
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
permissions.push({ ...template, isGranted: true });
|
|
11746
|
-
}
|
|
11747
|
-
}
|
|
12027
|
+
if (plan.kind !== "ok") {
|
|
12028
|
+
OutputFormatter.error(plan.kind === "unknown" ? unknownPermissionsFailure(roleKey, plan.unknown, plan.catalogEmpty) : plan.kind === "conflicting" ? conflictingPermissionsFailure(roleKey, plan.conflicting) : rejectedPermissionsFailure(roleKey, plan.roleType, plan.rejected));
|
|
12029
|
+
processContext.exit(1);
|
|
12030
|
+
return;
|
|
11748
12031
|
}
|
|
11749
|
-
const body = {
|
|
12032
|
+
const body = {
|
|
12033
|
+
...current,
|
|
12034
|
+
id: numericId,
|
|
12035
|
+
permissions: plan.permissions
|
|
12036
|
+
};
|
|
11750
12037
|
const [editError] = await catchError(api.rolesPutById({ key: numericId, body }));
|
|
11751
12038
|
if (editError) {
|
|
11752
12039
|
await reportFailure("Error updating role", editError);
|
|
@@ -11755,7 +12042,12 @@ var registerRolesCommand = (program) => {
|
|
|
11755
12042
|
OutputFormatter.success({
|
|
11756
12043
|
Result: RESULTS.Success,
|
|
11757
12044
|
Code: "RoleUpdated",
|
|
11758
|
-
Data: {
|
|
12045
|
+
Data: {
|
|
12046
|
+
Key: roleKey,
|
|
12047
|
+
Status: "Updated successfully",
|
|
12048
|
+
AddedPermissions: plan.added,
|
|
12049
|
+
RemovedPermissions: plan.removed
|
|
12050
|
+
}
|
|
11759
12051
|
});
|
|
11760
12052
|
});
|
|
11761
12053
|
rolesCmd.command("delete").description("Delete a role by key (GUID). " + "Only non-static (user-created) roles can be deleted. " + "Built-in roles (IsStatic=true) cannot be removed. " + "Use 'roles list' to find role keys.").argument("<role-key>", "Role key (GUID) — use 'roles list' to find").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-y, --yes", "Confirm this irreversible operation (required; the CLI never prompts)").examples(ROLES_DELETE_ROLE_EXAMPLES).trackedAction(processContext, async (roleKey, options) => {
|
|
@@ -12219,6 +12511,8 @@ function formatMachineSessionRuntime(runtime) {
|
|
|
12219
12511
|
MaintenanceMode: runtime.maintenanceMode || "",
|
|
12220
12512
|
HostMachineName: runtime.hostMachineName || "",
|
|
12221
12513
|
RuntimeType: runtime.runtimeType || "",
|
|
12514
|
+
ProcessType: runtime.processType || "",
|
|
12515
|
+
IsVertical: runtime.isVertical ?? false,
|
|
12222
12516
|
MachineType: runtime.machineType || "",
|
|
12223
12517
|
MachineScope: runtime.machineScope || "",
|
|
12224
12518
|
Status: runtime.status || "",
|
|
@@ -12354,6 +12648,8 @@ var SESSIONS_LIST_UNATTENDED_EXAMPLES = [
|
|
|
12354
12648
|
MaintenanceMode: "Default",
|
|
12355
12649
|
HostMachineName: "prod-worker-01",
|
|
12356
12650
|
RuntimeType: "Unattended",
|
|
12651
|
+
ProcessType: "",
|
|
12652
|
+
IsVertical: false,
|
|
12357
12653
|
MachineType: "Standard",
|
|
12358
12654
|
MachineScope: "Default",
|
|
12359
12655
|
Status: "Available",
|
|
@@ -13209,13 +13505,14 @@ function resolveBoolOption(value, fallback) {
|
|
|
13209
13505
|
return value !== undefined ? value : fallback;
|
|
13210
13506
|
}
|
|
13211
13507
|
var VALID_JOB_PRIORITIES = ["Low", "Normal", "High"];
|
|
13212
|
-
var
|
|
13508
|
+
var VALID_API_RUNTIME_TYPES = [
|
|
13213
13509
|
"Serverless",
|
|
13214
13510
|
"Unattended",
|
|
13215
13511
|
"Headless",
|
|
13216
13512
|
"NonProduction",
|
|
13217
13513
|
"AgentService"
|
|
13218
13514
|
];
|
|
13515
|
+
var VALID_RUNTIME_TYPES = [...VALID_API_RUNTIME_TYPES, "Local"];
|
|
13219
13516
|
var VALID_HTTP_METHODS = ["Get", "Post", "Put", "Delete"];
|
|
13220
13517
|
var VALID_CALLING_MODES = [
|
|
13221
13518
|
"AsyncRequestReply",
|
|
@@ -13245,8 +13542,8 @@ function validateJobPriority(options) {
|
|
|
13245
13542
|
options.jobPriority = result.value;
|
|
13246
13543
|
return true;
|
|
13247
13544
|
}
|
|
13248
|
-
function validateRuntimeType(options) {
|
|
13249
|
-
const result = normalizeEnumOption(options.runtimeType,
|
|
13545
|
+
function validateRuntimeType(options, validRuntimeTypes = VALID_RUNTIME_TYPES) {
|
|
13546
|
+
const result = normalizeEnumOption(options.runtimeType, validRuntimeTypes, "--runtime-type");
|
|
13250
13547
|
if (!result.ok)
|
|
13251
13548
|
return false;
|
|
13252
13549
|
options.runtimeType = result.value;
|
|
@@ -13724,7 +14021,7 @@ var registerTriggersCommand = (program) => {
|
|
|
13724
14021
|
});
|
|
13725
14022
|
}
|
|
13726
14023
|
});
|
|
13727
|
-
triggers.command("create").description("Create a new trigger. --type selects trigger type: time (default), queue, or api. Requires --name, --release-key, --runtime-type. " + "Time triggers need --cron; queue triggers need --queue-key. " + "API triggers need --slug and --method. " + "Folder is inferred from --release-key; pass --folder-path or --folder-key when your identity only has a folder-level role (such as an external app), since it cannot look processes up tenant-wide. " + "Use 'processes list' to find the release key.").option("--type <type>", "Trigger type (time, queue, api)", "time").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).requiredOption("--name <name>", "Trigger name").option("-d, --description <text>", "Trigger description").requiredOption("--release-key <key>", "Release key (GUID) of the process to trigger").option("--folder-path <path>", "Folder path of the process (e.g., 'Shared'). Optional — inferred from --release-key if not given").option("--folder-key <key>", "Folder key (GUID) of the process. Optional — inferred from --release-key if not given").option("--input-arguments <json>", `Input arguments as JSON string (e.g., '{"Arg1":"value"}')`).option("--calendar-key <key>", "Calendar key (GUID) for excluding non-working days. Use 'calendars list' to find keys.").option("--stop-strategy <strategy>", "How to stop running jobs: SoftStop or Kill").option("--kill-process-expression <expression>", "Cron expression for force-killing jobs (requires --stop-strategy Kill)").option("--cron <expression>", "Cron expression in Quartz 6-field format: 'sec min hour day month weekday' (e.g., '0 0 12 * * ?' for daily at noon). Note: standard Unix 5-field cron is not supported.").option("--time-zone <timezone>", "IANA time zone ID, e.g. 'UTC' or 'Europe/Bucharest' (applies to time-of-day fields)").option("--queue-key <key>", "Queue key (GUID) for queue trigger (queue only)").option("--items-threshold <number>", "Minimum queue items to trigger activation (queue only)", "1").option("--max-jobs <number>", "Maximum concurrent jobs for queue activation (queue only)", "1").option("--items-per-job <number>", "Target ratio of queue items per job (queue only)", "1").option("--activate-on-complete", "Re-trigger when a job completes (queue only)").option("--resume-on-same-context", "Resume suspended jobs on the same machine").option("--run-as-me", "Run job under the trigger creator's identity").option("--disabled", "Create the trigger in disabled state (default: enabled)").requiredOption("--runtime-type <type>", "Execution runtime (Serverless, Unattended, Headless, NonProduction, AgentService)").requiredOption("--job-priority <priority>", "Job execution priority (Low, Normal, High)", "Normal").option("--slug <slug>", "URL slug for API trigger (api only)").option("--method <method>", "HTTP method: Get, Post, Put, Delete (api only)").option("--calling-mode <mode>", "Calling mode: AsyncRequestReply, AsyncCallback, LongPolling, FireAndForget (api only)").option("--target <spec>", "Run target as 'machine=<guid>,user=<guid>,session=<int>' (any field optional). Repeat for multiple targets. Use 'machines list' and 'users list' to find keys.", (val, prev) => prev ? [...prev, val] : [val]).option("--mapping-mode <mode>", "Validation mode for --target: 'dynamic' (default) allows any combination of machine/user/session (session requires machine); 'strict' requires both machine and user on every target (use when the folder has 'Enable account-machine mappings' turned on).", "dynamic").examples(TRIGGERS_CREATE_EXAMPLES).trackedAction(processContext, async (options) => {
|
|
14024
|
+
triggers.command("create").description("Create a new trigger. --type selects trigger type: time (default), queue, or api. Requires --name, --release-key, --runtime-type. " + "Time triggers need --cron; queue triggers need --queue-key. " + "API triggers need --slug and --method. " + "Folder is inferred from --release-key; pass --folder-path or --folder-key when your identity only has a folder-level role (such as an external app), since it cannot look processes up tenant-wide. " + "Use 'processes list' to find the release key.").option("--type <type>", "Trigger type (time, queue, api)", "time").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).requiredOption("--name <name>", "Trigger name").option("-d, --description <text>", "Trigger description").requiredOption("--release-key <key>", "Release key (GUID) of the process to trigger").option("--folder-path <path>", "Folder path of the process (e.g., 'Shared'). Optional — inferred from --release-key if not given").option("--folder-key <key>", "Folder key (GUID) of the process. Optional — inferred from --release-key if not given").option("--input-arguments <json>", `Input arguments as JSON string (e.g., '{"Arg1":"value"}')`).option("--calendar-key <key>", "Calendar key (GUID) for excluding non-working days. Use 'calendars list' to find keys.").option("--stop-strategy <strategy>", "How to stop running jobs: SoftStop or Kill").option("--kill-process-expression <expression>", "Cron expression for force-killing jobs (requires --stop-strategy Kill)").option("--cron <expression>", "Cron expression in Quartz 6-field format: 'sec min hour day month weekday' (e.g., '0 0 12 * * ?' for daily at noon). Note: standard Unix 5-field cron is not supported.").option("--time-zone <timezone>", "IANA time zone ID, e.g. 'UTC' or 'Europe/Bucharest' (applies to time-of-day fields)").option("--queue-key <key>", "Queue key (GUID) for queue trigger (queue only)").option("--items-threshold <number>", "Minimum queue items to trigger activation (queue only)", "1").option("--max-jobs <number>", "Maximum concurrent jobs for queue activation (queue only)", "1").option("--items-per-job <number>", "Target ratio of queue items per job (queue only)", "1").option("--activate-on-complete", "Re-trigger when a job completes (queue only)").option("--resume-on-same-context", "Resume suspended jobs on the same machine").option("--run-as-me", "Run job under the trigger creator's identity").option("--disabled", "Create the trigger in disabled state (default: enabled)").requiredOption("--runtime-type <type>", "Execution runtime (Serverless, Unattended, Headless, NonProduction, AgentService, Local). Local runs Agent, Function and API workflow jobs on the folder machines' local slots; API triggers don't accept it").requiredOption("--job-priority <priority>", "Job execution priority (Low, Normal, High)", "Normal").option("--slug <slug>", "URL slug for API trigger (api only)").option("--method <method>", "HTTP method: Get, Post, Put, Delete (api only)").option("--calling-mode <mode>", "Calling mode: AsyncRequestReply, AsyncCallback, LongPolling, FireAndForget (api only)").option("--target <spec>", "Run target as 'machine=<guid>,user=<guid>,session=<int>' (any field optional). Repeat for multiple targets. Use 'machines list' and 'users list' to find keys.", (val, prev) => prev ? [...prev, val] : [val]).option("--mapping-mode <mode>", "Validation mode for --target: 'dynamic' (default) allows any combination of machine/user/session (session requires machine); 'strict' requires both machine and user on every target (use when the folder has 'Enable account-machine mappings' turned on).", "dynamic").examples(TRIGGERS_CREATE_EXAMPLES).trackedAction(processContext, async (options) => {
|
|
13728
14025
|
const triggerType = validateTriggerType(options.type);
|
|
13729
14026
|
if (!triggerType) {
|
|
13730
14027
|
emitInvalidTypeError(options.type);
|
|
@@ -13738,7 +14035,7 @@ var registerTriggersCommand = (program) => {
|
|
|
13738
14035
|
await createApiTrigger(options);
|
|
13739
14036
|
}
|
|
13740
14037
|
});
|
|
13741
|
-
triggers.command("update").description("Update an existing trigger by key (GUID). --type defaults to time. Only provided fields are changed. " + "All types require --folder-path or --folder-key. " + "Use 'triggers list' to retrieve the key.").argument("<trigger-key>", "Trigger key (GUID). Use 'triggers list' to retrieve the key.").option("--type <type>", "Trigger type (time, queue, api)", "time").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Folder path (e.g., 'Shared')").option("--folder-key <key>", "Folder key (GUID)").option("--name <name>", "New trigger name").option("--release-key <key>", "Release key (GUID) of the process to schedule").option("--cron <expression>", "Cron expression for scheduling (time only)").option("--time-zone <timezone>", "IANA time zone ID, e.g. 'UTC' or 'Europe/Bucharest' (applies to time-of-day fields)").option("--queue-key <key>", "Queue key (GUID) for queue-based trigger (queue only)").option("--runtime-type <type>", "Execution runtime (Serverless, Unattended, Headless, NonProduction, AgentService)").option("--job-priority <priority>", "Job execution priority (Low, Normal, High)").option("--items-threshold <number>", "Minimum queue items to trigger (queue only)").option("--max-jobs <number>", "Maximum concurrent jobs for queue activation (queue only)").option("--items-per-job <number>", "Target ratio of queue items per job (queue only)").option("--activate-on-complete", "Re-trigger when a job completes (queue only)").option("--no-activate-on-complete", "Disable re-trigger on job completion (queue only)").option("--resume-on-same-context", "Resume suspended jobs on same machine").option("--no-resume-on-same-context", "Disable resume on same context").option("--run-as-me", "Run under trigger creator's identity").option("--no-run-as-me", "Disable run-as-me").option("--slug <slug>", "URL slug (api only)").option("--method <method>", "HTTP method: Get, Post, Put, Delete (api only)").option("--calling-mode <mode>", "Calling mode (api only)").option("--target <spec>", "Run target as 'machine=<guid>,user=<guid>,session=<int>' (any field optional). Repeat for multiple targets. Use 'machines list' and 'users list' to find keys.", (val, prev) => prev ? [...prev, val] : [val]).option("--mapping-mode <mode>", "Validation mode for --target: 'dynamic' (default) allows any combination of machine/user/session (session requires machine); 'strict' requires both machine and user on every target (use when the folder has 'Enable account-machine mappings' turned on).", "dynamic").option("--enabled", "Enable the trigger").option("--disabled", "Disable the trigger").examples(TRIGGERS_UPDATE_EXAMPLES).trackedAction(processContext, async (triggerKey, options) => {
|
|
14038
|
+
triggers.command("update").description("Update an existing trigger by key (GUID). --type defaults to time. Only provided fields are changed. " + "All types require --folder-path or --folder-key. " + "Use 'triggers list' to retrieve the key.").argument("<trigger-key>", "Trigger key (GUID). Use 'triggers list' to retrieve the key.").option("--type <type>", "Trigger type (time, queue, api)", "time").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Folder path (e.g., 'Shared')").option("--folder-key <key>", "Folder key (GUID)").option("--name <name>", "New trigger name").option("--release-key <key>", "Release key (GUID) of the process to schedule").option("--cron <expression>", "Cron expression for scheduling (time only)").option("--time-zone <timezone>", "IANA time zone ID, e.g. 'UTC' or 'Europe/Bucharest' (applies to time-of-day fields)").option("--queue-key <key>", "Queue key (GUID) for queue-based trigger (queue only)").option("--runtime-type <type>", "Execution runtime (Serverless, Unattended, Headless, NonProduction, AgentService, Local). Local runs Agent, Function and API workflow jobs on the folder machines' local slots; API triggers don't accept it").option("--job-priority <priority>", "Job execution priority (Low, Normal, High)").option("--items-threshold <number>", "Minimum queue items to trigger (queue only)").option("--max-jobs <number>", "Maximum concurrent jobs for queue activation (queue only)").option("--items-per-job <number>", "Target ratio of queue items per job (queue only)").option("--activate-on-complete", "Re-trigger when a job completes (queue only)").option("--no-activate-on-complete", "Disable re-trigger on job completion (queue only)").option("--resume-on-same-context", "Resume suspended jobs on same machine").option("--no-resume-on-same-context", "Disable resume on same context").option("--run-as-me", "Run under trigger creator's identity").option("--no-run-as-me", "Disable run-as-me").option("--slug <slug>", "URL slug (api only)").option("--method <method>", "HTTP method: Get, Post, Put, Delete (api only)").option("--calling-mode <mode>", "Calling mode (api only)").option("--target <spec>", "Run target as 'machine=<guid>,user=<guid>,session=<int>' (any field optional). Repeat for multiple targets. Use 'machines list' and 'users list' to find keys.", (val, prev) => prev ? [...prev, val] : [val]).option("--mapping-mode <mode>", "Validation mode for --target: 'dynamic' (default) allows any combination of machine/user/session (session requires machine); 'strict' requires both machine and user on every target (use when the folder has 'Enable account-machine mappings' turned on).", "dynamic").option("--enabled", "Enable the trigger").option("--disabled", "Disable the trigger").examples(TRIGGERS_UPDATE_EXAMPLES).trackedAction(processContext, async (triggerKey, options) => {
|
|
13742
14039
|
const triggerType = validateTriggerType(options.type);
|
|
13743
14040
|
if (!triggerType) {
|
|
13744
14041
|
emitInvalidTypeError(options.type);
|
|
@@ -13919,7 +14216,8 @@ async function createScheduleTrigger(options, isCronType) {
|
|
|
13919
14216
|
"Unattended",
|
|
13920
14217
|
"Headless",
|
|
13921
14218
|
"NonProduction",
|
|
13922
|
-
"AgentService"
|
|
14219
|
+
"AgentService",
|
|
14220
|
+
"Local"
|
|
13923
14221
|
];
|
|
13924
14222
|
const matchedRuntimeType = validRuntimeTypes.find((v) => v.toLowerCase() === options.runtimeType?.toLowerCase());
|
|
13925
14223
|
if (!matchedRuntimeType) {
|
|
@@ -14073,13 +14371,7 @@ async function createApiTrigger(options) {
|
|
|
14073
14371
|
}
|
|
14074
14372
|
options.method = matchedMethod;
|
|
14075
14373
|
if (options.runtimeType) {
|
|
14076
|
-
const validRuntimeTypes =
|
|
14077
|
-
"Serverless",
|
|
14078
|
-
"Unattended",
|
|
14079
|
-
"Headless",
|
|
14080
|
-
"NonProduction",
|
|
14081
|
-
"AgentService"
|
|
14082
|
-
];
|
|
14374
|
+
const validRuntimeTypes = VALID_API_RUNTIME_TYPES;
|
|
14083
14375
|
const matchedRuntimeType = validRuntimeTypes.find((v) => v.toLowerCase() === options.runtimeType?.toLowerCase());
|
|
14084
14376
|
if (!matchedRuntimeType) {
|
|
14085
14377
|
OutputFormatter.error({
|
|
@@ -14224,7 +14516,7 @@ async function updateScheduleTrigger(triggerKey, options, triggerType) {
|
|
|
14224
14516
|
async function updateApiTrigger(triggerKey, options) {
|
|
14225
14517
|
if (!validateMethod(options))
|
|
14226
14518
|
return;
|
|
14227
|
-
if (!validateRuntimeType(options))
|
|
14519
|
+
if (!validateRuntimeType(options, VALID_API_RUNTIME_TYPES))
|
|
14228
14520
|
return;
|
|
14229
14521
|
if (!validateJobPriority(options))
|
|
14230
14522
|
return;
|
|
@@ -15832,7 +16124,7 @@ var registerCommands = async (program) => {
|
|
|
15832
16124
|
registerFoldersCommand(program);
|
|
15833
16125
|
registerJobsCommand(program);
|
|
15834
16126
|
if (isPreviewBuild()) {
|
|
15835
|
-
const { registerKbCommand } = await import("./kb-
|
|
16127
|
+
const { registerKbCommand } = await import("./kb-rqv35wke.js");
|
|
15836
16128
|
registerKbCommand(program);
|
|
15837
16129
|
}
|
|
15838
16130
|
registerLibrariesCommand(program);
|
|
@@ -15854,4 +16146,4 @@ var registerCommands = async (program) => {
|
|
|
15854
16146
|
|
|
15855
16147
|
export { metadata, registerCommands };
|
|
15856
16148
|
|
|
15857
|
-
//# debugId=
|
|
16149
|
+
//# debugId=1D581486482C102364756E2164756E21
|