@uipath/ixp-tool 1.204.0-preview.254 → 1.205.0-preview.256

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 CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  Command,
4
4
  package_default,
5
5
  registerCommands
6
- } from "./tool-vsg7smdq.js";
6
+ } from "./tool-6j0f3qjh.js";
7
7
  import"./tool-1de529jm.js";
8
8
 
9
9
  // src/index.ts
@@ -2101,7 +2101,7 @@ var package_default = {
2101
2101
  name: "@uipath/ixp-tool",
2102
2102
  author: "UiPath",
2103
2103
  license: "SEE LICENSE IN LICENSE.txt",
2104
- version: "1.204.0-preview.254",
2104
+ version: "1.205.0-preview.256",
2105
2105
  description: "Manage UiPath IXP projects, prompts, predictions, and model publishing.",
2106
2106
  private: false,
2107
2107
  repository: {
@@ -2324,6 +2324,16 @@ class NodeFileSystem {
2324
2324
  async rename(oldPath, newPath) {
2325
2325
  await fs.rename(oldPath, newPath);
2326
2326
  }
2327
+ async isSymbolicLink(filePath) {
2328
+ try {
2329
+ return (await fs.lstat(filePath)).isSymbolicLink();
2330
+ } catch (error) {
2331
+ if (this.isEnoent(error) || this.hasErrnoCode(error, "ENOTDIR")) {
2332
+ return false;
2333
+ }
2334
+ throw error;
2335
+ }
2336
+ }
2327
2337
  async realpath(filePath) {
2328
2338
  try {
2329
2339
  return await fs.realpath(filePath);
@@ -3355,7 +3365,7 @@ function setGlobalLogFilePath(path2) {
3355
3365
  function getGlobalLogFilePath() {
3356
3366
  return logFilePathSlot.get("");
3357
3367
  }
3358
- var DEFAULT_LOG_LEVEL = 3 /* ERROR */;
3368
+ var DEFAULT_LOG_LEVEL = 2 /* WARN */;
3359
3369
 
3360
3370
  class SimpleLogger {
3361
3371
  __brand = "SimpleLogger";
@@ -3622,7 +3632,9 @@ var ErrorDimensions = {
3622
3632
  Result: "Result",
3623
3633
  ErrorCode: "ErrorCode",
3624
3634
  Retry: "Retry",
3625
- ErrorMessage: "ErrorMessage"
3635
+ ErrorMessage: "ErrorMessage",
3636
+ HttpStatus: "HttpStatus",
3637
+ UpstreamErrorCode: "UpstreamErrorCode"
3626
3638
  };
3627
3639
  var AuthDimensions = {
3628
3640
  AuthenticationMethod: "AuthenticationMethod",
@@ -4616,7 +4628,9 @@ var CLI_ERROR_CODES = [
4616
4628
  "timeout",
4617
4629
  "server_error",
4618
4630
  "method_not_allowed",
4631
+ "not_supported",
4619
4632
  "configuration_error",
4633
+ "execution_failed",
4620
4634
  "unknown_error"
4621
4635
  ];
4622
4636
  var RETRY_HINTS = [
@@ -5573,7 +5587,9 @@ var OutputFormatter;
5573
5587
  [ErrorDimensions.Result]: data.Result,
5574
5588
  [ErrorDimensions.ErrorCode]: data.ErrorCode,
5575
5589
  [ErrorDimensions.Retry]: data.Retry,
5576
- [ErrorDimensions.ErrorMessage]: data.Message
5590
+ [ErrorDimensions.ErrorMessage]: data.Message,
5591
+ [ErrorDimensions.HttpStatus]: data.Context?.httpStatus?.toString(),
5592
+ [ErrorDimensions.UpstreamErrorCode]: data.Context?.errorCode
5577
5593
  });
5578
5594
  }
5579
5595
  logOutput(normalizeOutputKeys(envelope), getOutputFormat());
@@ -6347,6 +6363,52 @@ var BOOLEAN_FLAGS = new Set(HOST_GLOBAL_FLAGS);
6347
6363
  // ../common/src/interactivity-context.ts
6348
6364
  var modeSlot = singleton("InteractivityMode");
6349
6365
  var interactiveFlagSlot = singleton("InteractiveFlag");
6366
+ // ../common/src/json-option.ts
6367
+ function jsonFileOptionHelp(inlineFlag) {
6368
+ return `Path to a file holding the ${inlineFlag} JSON. Use it on Windows cmd/PowerShell, where quotes inside an inline JSON argument are stripped before the CLI sees them.`;
6369
+ }
6370
+ async function readJsonOption(source) {
6371
+ const read = await readJsonOptionText(source);
6372
+ return read === undefined ? undefined : parseJsonOptionText(read, source);
6373
+ }
6374
+ async function readJsonOptionText(source) {
6375
+ const { inline, file, inlineFlag, fileFlag } = source;
6376
+ if (file !== undefined) {
6377
+ const fs2 = getFileSystem();
6378
+ const bytes = await fs2.readFile(file);
6379
+ if (bytes === null) {
6380
+ throw new Error(`File not found: ${fs2.path.resolve(file)}`);
6381
+ }
6382
+ const text = decodeJsonFile(bytes).trim();
6383
+ if (text === "") {
6384
+ throw new Error(`Expected JSON in ${file} but the file is empty.`);
6385
+ }
6386
+ return { text, origin: "file", label: `${fileFlag} ${file}` };
6387
+ }
6388
+ if (inline === undefined) {
6389
+ return;
6390
+ }
6391
+ return { text: inline, origin: "inline", label: inlineFlag };
6392
+ }
6393
+ function decodeJsonFile(bytes) {
6394
+ const utf16le = bytes[0] === 255 && bytes[1] === 254;
6395
+ return new TextDecoder(utf16le ? "utf-16le" : "utf-8").decode(bytes);
6396
+ }
6397
+ function parseJsonOptionText(read, flags) {
6398
+ try {
6399
+ return JSON.parse(read.text);
6400
+ } catch (err) {
6401
+ const detail = err instanceof Error ? err.message : String(err);
6402
+ const hint = read.origin === "inline" ? windowsJsonHint(flags) : "";
6403
+ throw new Error(`${read.label} is not valid JSON: ${detail}.${hint}`);
6404
+ }
6405
+ }
6406
+ function windowsJsonHint(flags) {
6407
+ if (process.platform !== "win32") {
6408
+ return "";
6409
+ }
6410
+ return ` On Windows cmd/PowerShell, quotes inside an inline JSON argument are stripped and \`& | < > ^\` split the command — pass the file with \`${flags.fileFlag} <path>\` instead.`;
6411
+ }
6350
6412
  // ../common/src/mime-types.ts
6351
6413
  var MIME_TYPES_BY_EXTENSION = Object.freeze({
6352
6414
  pdf: "application/pdf",
@@ -6386,6 +6448,35 @@ function warnDeprecatedOptionAlias(deprecatedFlag, preferredFlag) {
6386
6448
  getOutputSink().writeErr(`[WARN] ${deprecatedFlag} is deprecated. Use ${preferredFlag} instead.
6387
6449
  `);
6388
6450
  }
6451
+ function addDeprecatedOptionAlias(command, deprecatedFlags, preferredLong) {
6452
+ const preferred = command.options.find((option) => option.long === preferredLong);
6453
+ if (preferred === undefined) {
6454
+ throw new Error(`${preferredLong} must be registered before its deprecated alias`);
6455
+ }
6456
+ const deprecated = new Option(deprecatedFlags, `Deprecated alias for ${preferredLong}`).hideHelp();
6457
+ const preferredKey = preferred.attributeName();
6458
+ const deprecatedLabel = [deprecated.short, deprecated.long].filter((flag) => flag !== undefined).join("/");
6459
+ let aliasUsed = false;
6460
+ const conflict = () => command.error(`error: option '${deprecated.flags}' cannot be used with option '${preferred.flags}'`, {
6461
+ code: "commander.conflictingOption",
6462
+ exitCode: EXIT_CODES.ValidationError
6463
+ });
6464
+ command.on(`option:${preferred.name()}`, () => {
6465
+ if (aliasUsed)
6466
+ conflict();
6467
+ });
6468
+ command.on(`option:${deprecated.name()}`, (value) => {
6469
+ if (!aliasUsed) {
6470
+ if (command.getOptionValueSource(preferredKey) === "cli") {
6471
+ conflict();
6472
+ }
6473
+ warnDeprecatedOptionAlias(deprecatedLabel, preferredLong);
6474
+ aliasUsed = true;
6475
+ }
6476
+ command.setOptionValueWithSource(preferredKey, value, "cli");
6477
+ });
6478
+ return command.addOption(deprecated);
6479
+ }
6389
6480
  var TENANT_SWITCH_COMMAND = "uip login tenant set <tenant>";
6390
6481
  function createHiddenDeprecatedTenantOption(flags = "-t, --tenant <tenant-name>") {
6391
6482
  return new Option(flags, `Tenant name. Deprecated; use ${TENANT_SWITCH_COMMAND} to switch active tenants.`).hideHelp().argParser((tenant) => {
@@ -6398,6 +6489,30 @@ function warnDeprecatedTenantOption(tenant) {
6398
6489
  return;
6399
6490
  warnDeprecatedOptionAlias("--tenant", TENANT_SWITCH_COMMAND);
6400
6491
  }
6492
+ // ../common/src/option-groups.ts
6493
+ function requireOneOfOptions(command, longFlags) {
6494
+ const options = longFlags.map((long) => {
6495
+ const option = command.options.find((o) => o.long === long);
6496
+ if (option === undefined) {
6497
+ throw new Error(`${long} must be registered on '${command.name()}' before requireOneOfOptions`);
6498
+ }
6499
+ return option;
6500
+ });
6501
+ const flags = options.map((option) => `'${option.flags}'`).join(" or ");
6502
+ command.hook("preAction", (thisCommand) => {
6503
+ const given = options.some((option) => {
6504
+ const source = thisCommand.getOptionValueSource(option.attributeName());
6505
+ return source !== undefined && source !== "default";
6506
+ });
6507
+ if (given) {
6508
+ return;
6509
+ }
6510
+ thisCommand.error(`error: required option ${flags} not specified`, {
6511
+ code: "commander.missingMandatoryOptionValue",
6512
+ exitCode: EXIT_CODES.ValidationError
6513
+ });
6514
+ });
6515
+ }
6401
6516
  // ../common/src/option-validators.ts
6402
6517
  function parseLimit(raw, _previous) {
6403
6518
  return parseBoundedInt(raw, "--limit", { min: 1, max: 1e4 });
@@ -6661,22 +6776,12 @@ var resolveConfigAsync = async ({
6661
6776
  baseUrl = DEFAULT_BASE_URL;
6662
6777
  }
6663
6778
  baseUrl = normalizeAndValidateBaseUrl(baseUrl);
6664
- let clientId = customClientId;
6665
- if (!clientId && fileAuth.clientId) {
6666
- clientId = fileAuth.clientId;
6667
- }
6668
- if (!clientId) {
6669
- clientId = DEFAULT_CLIENT_ID;
6670
- }
6671
- let clientSecret = customClientSecret;
6672
- if (!clientSecret && fileAuth.clientSecret) {
6673
- clientSecret = fileAuth.clientSecret;
6674
- }
6675
- const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
6779
+ const clientId = customClientId || DEFAULT_CLIENT_ID;
6780
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
6676
6781
  const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
6677
6782
  return {
6678
6783
  clientId,
6679
- clientSecret,
6784
+ clientSecret: customClientSecret,
6680
6785
  scopes,
6681
6786
  baseUrl,
6682
6787
  authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
@@ -6850,6 +6955,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
6850
6955
  }
6851
6956
  return;
6852
6957
  };
6958
+ var resolveApplicationSubtype = (claims, authFlow) => {
6959
+ switch (asString(claims?.sub_type)) {
6960
+ case "service.external":
6961
+ return "External";
6962
+ case "service.internal":
6963
+ return "Internal";
6964
+ default:
6965
+ return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
6966
+ }
6967
+ };
6853
6968
  var looksLikeEmail = (value) => value?.includes("@") ?? false;
6854
6969
  var pickEmail = (claims) => {
6855
6970
  for (const candidate of [claims?.email, claims?.preferred_username]) {
@@ -6891,6 +7006,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
6891
7006
  const clientId = asString(claims?.client_id);
6892
7007
  if (clientId)
6893
7008
  identity.clientId = clientId;
7009
+ const subType = asString(claims?.sub_type);
7010
+ if (subType)
7011
+ identity.subType = subType;
7012
+ const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
7013
+ if (applicationSubtype)
7014
+ identity.applicationSubtype = applicationSubtype;
6894
7015
  return identity;
6895
7016
  };
6896
7017
  var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
@@ -7183,6 +7304,40 @@ var tryRobotClientFallback = async (options = {}) => {
7183
7304
  }
7184
7305
  };
7185
7306
 
7307
+ // ../auth/src/tenantSelection.ts
7308
+ var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
7309
+ var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
7310
+ var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
7311
+ var describeNonJsonResponse = (organizationId, response, parseError) => {
7312
+ if (response.redirected) {
7313
+ return `Could not find organization '${organizationId}': the request was ` + `redirected to a sign-in page instead of the organization's tenant ` + `list. ${LOGIN_STATUS_HINT}`;
7314
+ }
7315
+ const contentType = response.headers.get("content-type") ?? "unknown";
7316
+ return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
7317
+ };
7318
+ var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
7319
+ const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
7320
+ const response = await fetch(url, {
7321
+ headers: {
7322
+ Authorization: `Bearer ${accessToken}`
7323
+ },
7324
+ ...signal ? { signal } : {}
7325
+ });
7326
+ if (!response.ok) {
7327
+ if (response.status === 401) {
7328
+ throw new Error(`Unauthorized: the access token was rejected, it was not ` + `issued for organization '${organizationId}', or ` + `'${organizationId}' was not accepted as an organization ` + `URL segment in this environment. ` + LOGIN_STATUS_HINT);
7329
+ }
7330
+ const errorText = await response.text();
7331
+ const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
7332
+ throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
7333
+ }
7334
+ const [parseError, data] = await catchError2(response.json());
7335
+ if (parseError) {
7336
+ throw new Error(describeNonJsonResponse(organizationId, response, parseError));
7337
+ }
7338
+ return data;
7339
+ };
7340
+
7186
7341
  // ../auth/src/tokenRefresh.ts
7187
7342
  var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
7188
7343
 
@@ -7395,6 +7550,8 @@ var saveEnvFileAsync = async ({
7395
7550
  };
7396
7551
 
7397
7552
  // ../auth/src/loginStatus.ts
7553
+ var defaultRobotTenantIdCache = new Map;
7554
+ var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
7398
7555
  var getLoginStatusAsync = async (options = {}) => {
7399
7556
  return getLoginStatusWithDeps(options);
7400
7557
  };
@@ -7407,12 +7564,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
7407
7564
  refreshToken: refreshTokenFn = refreshAccessToken,
7408
7565
  resolveConfig = resolveConfigAsync,
7409
7566
  robotFallback = tryRobotClientFallback,
7567
+ fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
7568
+ robotTenantIdCache = defaultRobotTenantIdCache,
7569
+ robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
7410
7570
  loadBreaker = loadRefreshBreaker,
7411
7571
  saveBreaker = saveRefreshBreaker,
7412
7572
  clearBreaker = clearRefreshBreaker
7413
7573
  } = deps;
7574
+ const robotDeps = {
7575
+ fetchTenantsAndOrgs,
7576
+ cache: robotTenantIdCache,
7577
+ lookupTimeoutMs: robotTenantLookupTimeoutMs
7578
+ };
7414
7579
  if (isRobotAuthEnforced()) {
7415
- return resolveRobotEnforcedStatus(robotFallback);
7580
+ return resolveRobotEnforcedStatus(robotFallback, robotDeps);
7416
7581
  }
7417
7582
  if (isEnvAuthEnabled()) {
7418
7583
  return readAuthFromEnv();
@@ -7430,7 +7595,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
7430
7595
  hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
7431
7596
  };
7432
7597
  }
7433
- return resolveBorrowedRobotStatus(robotFallback);
7598
+ return resolveBorrowedRobotStatus(robotFallback, robotDeps);
7434
7599
  }
7435
7600
  const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
7436
7601
  if ("status" in loaded) {
@@ -7472,7 +7637,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
7472
7637
  }
7473
7638
  return buildFileStatus(tokens, credentials, globalHint);
7474
7639
  };
7475
- async function resolveRobotEnforcedStatus(robotFallback) {
7640
+ async function resolveRobotEnforcedStatus(robotFallback, deps) {
7476
7641
  if (isEnvAuthEnabled()) {
7477
7642
  throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
7478
7643
  }
@@ -7483,11 +7648,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
7483
7648
  hint: `${ENFORCE_ROBOT_AUTH_VAR}=true but the UiPath Robot ` + `session is unavailable. Start and sign in to the Assistant, ` + `or unset ${ENFORCE_ROBOT_AUTH_VAR} to fall back to file or ` + `env-var authentication.`
7484
7649
  };
7485
7650
  }
7486
- return buildRobotStatus(robotCreds);
7651
+ return buildRobotStatus(robotCreds, deps);
7487
7652
  }
7488
- async function resolveBorrowedRobotStatus(robotFallback) {
7653
+ async function resolveBorrowedRobotStatus(robotFallback, deps) {
7489
7654
  const robotCreds = await robotFallback();
7490
- return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
7655
+ return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
7491
7656
  }
7492
7657
  async function loadFileCredentials(loadEnvFile, absolutePath) {
7493
7658
  let credentials;
@@ -7622,9 +7787,10 @@ function identityFields(accessToken, credentials) {
7622
7787
  ...scopes ? { scopes } : {}
7623
7788
  };
7624
7789
  }
7625
- function buildRobotStatus(robotCreds) {
7790
+ async function buildRobotStatus(robotCreds, deps) {
7626
7791
  const identity = resolveSessionIdentity(robotCreds.accessToken);
7627
7792
  const scopes = readTokenScopes(robotCreds.accessToken);
7793
+ const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
7628
7794
  return {
7629
7795
  loginStatus: "Logged in",
7630
7796
  accessToken: robotCreds.accessToken,
@@ -7632,14 +7798,62 @@ function buildRobotStatus(robotCreds) {
7632
7798
  organizationName: robotCreds.organizationName,
7633
7799
  organizationId: robotCreds.organizationId,
7634
7800
  tenantName: robotCreds.tenantName,
7635
- tenantId: robotCreds.tenantId,
7801
+ tenantId: tenant.tenantId,
7636
7802
  issuer: robotCreds.issuer,
7637
7803
  expiration: getTokenExpiration(robotCreds.accessToken),
7638
7804
  source: "robot" /* Robot */,
7805
+ ...tenant.hint ? { hint: tenant.hint } : {},
7639
7806
  ...identity ? { identity } : {},
7640
7807
  ...scopes ? { scopes } : {}
7641
7808
  };
7642
7809
  }
7810
+ async function resolveRobotTenantId(robotCreds, deps) {
7811
+ const { baseUrl, accessToken, tenantName } = robotCreds;
7812
+ const organization = robotCreds.organizationName ?? robotCreds.organizationId;
7813
+ if (!tenantName || !organization) {
7814
+ return {};
7815
+ }
7816
+ const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
7817
+ let pending = deps.cache.get(key);
7818
+ if (!pending) {
7819
+ pending = catchError2(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
7820
+ const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
7821
+ if (!settled.tenantId) {
7822
+ deps.cache.delete(key);
7823
+ }
7824
+ return settled;
7825
+ });
7826
+ deps.cache.set(key, pending);
7827
+ }
7828
+ return pending;
7829
+ }
7830
+ async function lookupRobotTenantId(target, deps) {
7831
+ const { baseUrl, accessToken, organization, tenantName } = target;
7832
+ const [error, data] = await catchError2(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
7833
+ if (error) {
7834
+ const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
7835
+ return { hint: tenantLookupFailureHint(tenantName, reason) };
7836
+ }
7837
+ const rows = data?.tenants;
7838
+ const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
7839
+ const wantedName = decodePathSegment(tenantName);
7840
+ const wanted = wantedName.toLowerCase();
7841
+ const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
7842
+ if (!match) {
7843
+ const names = tenants.map((tenant) => tenant.name).join(", ");
7844
+ return {
7845
+ hint: `The Robot session targets tenant '${tenantName}', but ` + `organization '${organization}' lists no tenant of that name` + `${names ? ` (available: ${names})` : ""}. Commands that need ` + `the tenant id will fail until it can be resolved.`
7846
+ };
7847
+ }
7848
+ return { tenantId: match.id };
7849
+ }
7850
+ function tenantLookupFailureHint(tenantName, reason) {
7851
+ return `Could not resolve the id of tenant '${tenantName}' from the ` + `Robot session: ${reason} Commands that need the tenant id will ` + `fail until it can be resolved.`;
7852
+ }
7853
+ function decodePathSegment(segment) {
7854
+ const [error, decoded] = catchError2(() => decodeURIComponent(segment));
7855
+ return error ? segment : decoded;
7856
+ }
7643
7857
  var isFileNotFoundError = (error) => {
7644
7858
  if (!(error instanceof Object))
7645
7859
  return false;
@@ -7875,9 +8089,6 @@ function normalizeTokenRefreshUnavailableFailure() {
7875
8089
  function errorMessage(error) {
7876
8090
  return error instanceof Error ? error.message : String(error);
7877
8091
  }
7878
- // ../auth/src/tenantSelection.ts
7879
- var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
7880
-
7881
8092
  // ../auth/src/selectTenant.ts
7882
8093
  var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
7883
8094
  var INVALID_TENANT_CODE = "INVALID_TENANT";
@@ -7890,7 +8101,7 @@ var package_default2 = {
7890
8101
  name: "@uipath/ixp-sdk",
7891
8102
  author: "UiPath",
7892
8103
  license: "SEE LICENSE IN LICENSE.txt",
7893
- version: "1.204.0-preview.254",
8104
+ version: "1.205.0-preview.256",
7894
8105
  description: "SDK for the UiPath IXP (Intelligent eXtraction Platform) API — projects, taxonomies, prompts, predictions, and model publishing.",
7895
8106
  repository: {
7896
8107
  type: "git",
@@ -8329,13 +8540,8 @@ var MAX_TITLE_LENGTH = 1024;
8329
8540
  var MAX_FOLDER_KEY_LENGTH = 256;
8330
8541
 
8331
8542
  // src/commands/data-types.ts
8332
- function parseChoicesJson(raw) {
8333
- let parsed;
8334
- try {
8335
- parsed = JSON.parse(raw);
8336
- } catch (e) {
8337
- throw new Error(`--choices is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
8338
- }
8543
+ var CHOICES_FLAGS = { inlineFlag: "--choices", fileFlag: "--choices-file" };
8544
+ function parseChoicesJson(parsed) {
8339
8545
  if (!Array.isArray(parsed)) {
8340
8546
  throw new Error("--choices must be a JSON array");
8341
8547
  }
@@ -8398,6 +8604,19 @@ var DATA_TYPES_ADD_EXAMPLES = [
8398
8604
  InputValue: "exact-match"
8399
8605
  }
8400
8606
  }
8607
+ },
8608
+ {
8609
+ Description: "Create a Choice data type with the choices read from a file (use this on Windows PowerShell, which strips quotes from inline JSON)",
8610
+ Command: 'uip ixp data-types add my-invoices --name "Citizenship" --kind choice --instructions "Borrower citizenship status." --input-value exact-match --choices-file choices.json',
8611
+ Output: {
8612
+ Code: "IxpDataTypesAdd",
8613
+ Data: {
8614
+ ProjectName: "my-invoices",
8615
+ Name: "Citizenship",
8616
+ Kind: "choice",
8617
+ InputValue: "exact-match"
8618
+ }
8619
+ }
8401
8620
  }
8402
8621
  ];
8403
8622
  var DATA_TYPES_UPDATE_INSTRUCTIONS_EXAMPLES = [
@@ -8442,9 +8661,14 @@ var DATA_TYPES_DELETE_EXAMPLES = [
8442
8661
  ];
8443
8662
  var registerDataTypesCommand = (program2) => {
8444
8663
  const dataTypes = program2.command("data-types").description("Manage data types (entity_defs) — the reusable type definitions fields reference via field_type_id");
8445
- dataTypes.command("add").description("Create a new data type in the project").argument("<project-name>", "Project name").requiredOption("--name <name>", `Data type name (at most ${MAX_NAME_LENGTH} characters)`).requiredOption("--kind <kind>", "Underlying data type kind: text, date, money, number, boolean, choice").requiredOption("--instructions <text>", `Instructions describing what this type represents and where its values appear (at most ${MAX_INSTRUCTIONS_LENGTH} characters)`).option("--input-value <mode>", "Whether the value appears verbatim in the document (exact-match) or is inferred/computed (inferred). Required when --kind is text or choice; forbidden for date, money, number, and boolean (those kinds don't have this property — matches the IXP UI's radio visibility).").option("--choices <json>", 'Required when --kind choice. JSON array of choices: [{"value":"<canonical>","alternates":["<alt1>","<alt2>",...]}]. `value` (required) is the canonical display name (model output). `alternates` (optional, defaults to []) are alternate spellings the model maps to `value` — omit or set to [] when the canonical value is the only matched form.').addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(DATA_TYPES_ADD_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
8664
+ dataTypes.command("add").description("Create a new data type in the project").argument("<project-name>", "Project name").requiredOption("--name <name>", `Data type name (at most ${MAX_NAME_LENGTH} characters)`).requiredOption("--kind <kind>", "Underlying data type kind: text, date, money, number, boolean, choice").requiredOption("--instructions <text>", `Instructions describing what this type represents and where its values appear (at most ${MAX_INSTRUCTIONS_LENGTH} characters)`).option("--input-value <mode>", "Whether the value appears verbatim in the document (exact-match) or is inferred/computed (inferred). Required when --kind is text or choice; forbidden for date, money, number, and boolean (those kinds don't have this property — matches the IXP UI's radio visibility).").option("--choices <json>", 'Required when --kind choice. JSON array of choices: [{"value":"<canonical>","alternates":["<alt1>","<alt2>",...]}]. `value` (required) is the canonical display name (model output). `alternates` (optional, defaults to []) are alternate spellings the model maps to `value` — omit or set to [] when the canonical value is the only matched form.').addOption(new Option("--choices-file <path>", jsonFileOptionHelp("--choices")).conflicts("choices")).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(DATA_TYPES_ADD_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
8446
8665
  const [err, response] = await catchError((async () => {
8447
- const choices = options.choices ? parseChoicesJson(options.choices) : undefined;
8666
+ const rawChoices = await readJsonOption({
8667
+ inline: options.choices,
8668
+ file: options.choicesFile,
8669
+ ...CHOICES_FLAGS
8670
+ });
8671
+ const choices = rawChoices === undefined ? undefined : parseChoicesJson(rawChoices);
8448
8672
  const config = await createIxpConfig({
8449
8673
  tenant: options.tenant
8450
8674
  });
@@ -8852,7 +9076,7 @@ var registerDocumentsCommand = (program2) => {
8852
9076
  Data: page
8853
9077
  }, { preserveDataKeys: true });
8854
9078
  });
8855
- document.command("download").description("Download the original document file (PDF/PNG/JPG/etc.) for viewing").argument("<project-name>", "Project name").argument("<document-id>", "Document ID").option("-o, --output <path>", "Output file path (extension auto-corrected to match content type)", defaultDownloadPath()).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(DOCUMENTS_DOWNLOAD_EXAMPLES).trackedAction(processContext, async (projectName, documentUid, options) => {
9079
+ const download = document.command("download").description("Download the original document file (PDF/PNG/JPG/etc.) for viewing").argument("<project-name>", "Project name").argument("<document-id>", "Document ID").option("-o, --output-file <path>", "Output file path (extension auto-corrected to match content type)", defaultDownloadPath()).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(DOCUMENTS_DOWNLOAD_EXAMPLES).trackedAction(processContext, async (projectName, documentUid, options) => {
8856
9080
  const [err, result] = await catchError((async () => {
8857
9081
  const config = await createIxpConfig({
8858
9082
  tenant: options.tenant
@@ -8861,7 +9085,7 @@ var registerDocumentsCommand = (program2) => {
8861
9085
  const bytes = new Uint8Array(buffer);
8862
9086
  const detectedExt = extensionForContentType(contentType);
8863
9087
  const fs2 = getFileSystem();
8864
- const finalPath = applyDetectedExtension(options.output, detectedExt);
9088
+ const finalPath = applyDetectedExtension(options.outputFile, detectedExt);
8865
9089
  await fs2.writeFile(finalPath, bytes);
8866
9090
  return {
8867
9091
  path: finalPath,
@@ -8884,6 +9108,7 @@ var registerDocumentsCommand = (program2) => {
8884
9108
  }
8885
9109
  });
8886
9110
  });
9111
+ addDeprecatedOptionAlias(download, "--output <path>", "--output-file");
8887
9112
  document.command("upload").description("Upload a document file to an existing project").argument("<project-name>", "Project name").argument("<file>", "Path to the document file to upload").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(DOCUMENTS_UPLOAD_EXAMPLES).trackedAction(processContext, async (projectName, file, options) => {
8888
9113
  const [err, response] = await catchError((async () => {
8889
9114
  const fs2 = getFileSystem();
@@ -8940,6 +9165,7 @@ var registerDocumentsCommand = (program2) => {
8940
9165
  };
8941
9166
 
8942
9167
  // src/commands/fields.ts
9168
+ var UPDATES_FLAGS = { inlineFlag: "--updates", fileFlag: "--updates-file" };
8943
9169
  var FIELDS_ADD_EXAMPLES = [
8944
9170
  {
8945
9171
  Description: "Add a new field to a field group",
@@ -9011,6 +9237,18 @@ var FIELDS_UPDATE_PROMPTS_EXAMPLES = [
9011
9237
  Unmatched: []
9012
9238
  }
9013
9239
  }
9240
+ },
9241
+ {
9242
+ Description: "Read the updates from a file (use this on Windows PowerShell, which strips quotes from inline JSON)",
9243
+ Command: "uip ixp fields update-prompts my-invoices --updates-file updates.json",
9244
+ Output: {
9245
+ Code: "IxpFieldsUpdatePrompts",
9246
+ Data: {
9247
+ ProjectName: "my-invoices",
9248
+ FieldsUpdated: 2,
9249
+ Unmatched: []
9250
+ }
9251
+ }
9014
9252
  }
9015
9253
  ];
9016
9254
  var registerFieldsCommand = (program2) => {
@@ -9095,9 +9333,13 @@ var registerFieldsCommand = (program2) => {
9095
9333
  Data: response
9096
9334
  }, { preserveDataKeys: true });
9097
9335
  });
9098
- fields.command("update-prompts").description("Bulk-update per-field extraction instructions. Match by field name within each update's field group; existing definitions preserved.").argument("<project-name>", "Project name").requiredOption("--updates <json>", `JSON array of per-field instruction updates: [{"group":"Invoice","name":"Invoice Number","instructions":"..."}]. "group" is the field group (label_def) name, "name" is the field (moon_form) name within that group. Each \`instructions\` is at most ${MAX_INSTRUCTIONS_LENGTH} characters, each \`name\` at most ${MAX_NAME_LENGTH}.`).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(FIELDS_UPDATE_PROMPTS_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9336
+ const updatePrompts = fields.command("update-prompts").description("Bulk-update per-field extraction instructions. Match by field name within each update's field group; existing definitions preserved.").argument("<project-name>", "Project name").option("--updates <json>", `JSON array of per-field instruction updates: [{"group":"Invoice","name":"Invoice Number","instructions":"..."}]. "group" is the field group (label_def) name, "name" is the field (moon_form) name within that group. Each \`instructions\` is at most ${MAX_INSTRUCTIONS_LENGTH} characters, each \`name\` at most ${MAX_NAME_LENGTH}. Required unless --updates-file is given.`).addOption(new Option("--updates-file <path>", jsonFileOptionHelp("--updates")).conflicts("updates")).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(FIELDS_UPDATE_PROMPTS_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9099
9337
  const [err, response] = await catchError((async () => {
9100
- const rawUpdates = JSON.parse(options.updates);
9338
+ const rawUpdates = await readJsonOption({
9339
+ inline: options.updates,
9340
+ file: options.updatesFile,
9341
+ ...UPDATES_FLAGS
9342
+ });
9101
9343
  if (!Array.isArray(rawUpdates)) {
9102
9344
  throw new Error('--updates must be a JSON array, e.g. [{"group":"Invoice","name":"Invoice Number","instructions":"..."}]');
9103
9345
  }
@@ -9117,16 +9359,13 @@ var registerFieldsCommand = (program2) => {
9117
9359
  Data: response
9118
9360
  }, { preserveDataKeys: true });
9119
9361
  });
9362
+ requireOneOfOptions(updatePrompts, ["--updates", "--updates-file"]);
9120
9363
  };
9121
9364
 
9122
9365
  // src/commands/groups.ts
9123
- function parseFieldsJson(raw) {
9124
- let parsed;
9125
- try {
9126
- parsed = JSON.parse(raw);
9127
- } catch (e) {
9128
- throw new Error(`--fields is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
9129
- }
9366
+ var FIELDS_FLAGS = { inlineFlag: "--fields", fileFlag: "--fields-file" };
9367
+ var UPDATES_FLAGS2 = { inlineFlag: "--updates", fileFlag: "--updates-file" };
9368
+ function parseFieldsJson(parsed) {
9130
9369
  if (!Array.isArray(parsed)) {
9131
9370
  throw new Error("--fields must be a JSON array");
9132
9371
  }
@@ -9156,13 +9395,7 @@ function parseFieldsJson(raw) {
9156
9395
  }
9157
9396
  return result;
9158
9397
  }
9159
- function parseUpdatesJson(raw) {
9160
- let parsed;
9161
- try {
9162
- parsed = JSON.parse(raw);
9163
- } catch (e) {
9164
- throw new Error(`--updates is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
9165
- }
9398
+ function parseUpdatesJson(parsed) {
9166
9399
  if (!Array.isArray(parsed)) {
9167
9400
  throw new Error('--updates must be a JSON array, e.g. [{"name":"Invoice","instructions":"..."}]');
9168
9401
  }
@@ -9194,6 +9427,18 @@ var GROUPS_ADD_EXAMPLES = [
9194
9427
  FieldsCreated: 3
9195
9428
  }
9196
9429
  }
9430
+ },
9431
+ {
9432
+ Description: "Create a field group with the fields read from a file (use this on Windows PowerShell, which strips quotes from inline JSON)",
9433
+ Command: 'uip ixp groups add my-invoices --name Invoice --instructions "Header fields" --fields-file fields.json',
9434
+ Output: {
9435
+ Code: "IxpGroupsAdd",
9436
+ Data: {
9437
+ ProjectName: "my-invoices",
9438
+ Group: "Invoice",
9439
+ FieldsCreated: 3
9440
+ }
9441
+ }
9197
9442
  }
9198
9443
  ];
9199
9444
  var GROUPS_DELETE_EXAMPLES = [
@@ -9235,13 +9480,29 @@ var GROUPS_UPDATE_PROMPTS_EXAMPLES = [
9235
9480
  Unmatched: []
9236
9481
  }
9237
9482
  }
9483
+ },
9484
+ {
9485
+ Description: "Read the updates from a file (use this on Windows PowerShell, which strips quotes from inline JSON)",
9486
+ Command: "uip ixp groups update-prompts my-invoices --updates-file updates.json",
9487
+ Output: {
9488
+ Code: "IxpGroupsUpdatePrompts",
9489
+ Data: {
9490
+ ProjectName: "my-invoices",
9491
+ GroupsUpdated: 1,
9492
+ Unmatched: []
9493
+ }
9494
+ }
9238
9495
  }
9239
9496
  ];
9240
9497
  var registerGroupsCommand = (program2) => {
9241
9498
  const groups = program2.command("groups").description("Manage field groups (label_defs) — the document type containers for fields");
9242
- groups.command("add").description("Create a new field group with instructions and at least one field").argument("<project-name>", "Project name").requiredOption("--name <name>", `New field group name (at most ${MAX_NAME_LENGTH} characters)`).requiredOption("--instructions <text>", `Instructions for the group — describes what kind of document/section it covers (at most ${MAX_INSTRUCTIONS_LENGTH} characters)`).requiredOption("--fields <json>", `JSON array of fields to create in the group (at least one): [{"name":"...","type":"<type-name>","instructions":"..."}]. \`type\` is the name of an entity_def in the project taxonomy. \`name\` and \`type\` are at most ${MAX_NAME_LENGTH} characters, \`instructions\` at most ${MAX_INSTRUCTIONS_LENGTH}.`).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(GROUPS_ADD_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9499
+ const add = groups.command("add").description("Create a new field group with instructions and at least one field").argument("<project-name>", "Project name").requiredOption("--name <name>", `New field group name (at most ${MAX_NAME_LENGTH} characters)`).requiredOption("--instructions <text>", `Instructions for the group — describes what kind of document/section it covers (at most ${MAX_INSTRUCTIONS_LENGTH} characters)`).option("--fields <json>", `JSON array of fields to create in the group (at least one): [{"name":"...","type":"<type-name>","instructions":"..."}]. \`type\` is the name of an entity_def in the project taxonomy. \`name\` and \`type\` are at most ${MAX_NAME_LENGTH} characters, \`instructions\` at most ${MAX_INSTRUCTIONS_LENGTH}. Required unless --fields-file is given.`).addOption(new Option("--fields-file <path>", jsonFileOptionHelp("--fields")).conflicts("fields")).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(GROUPS_ADD_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9243
9500
  const [err, response] = await catchError((async () => {
9244
- const fields = parseFieldsJson(options.fields);
9501
+ const fields = parseFieldsJson(await readJsonOption({
9502
+ inline: options.fields,
9503
+ file: options.fieldsFile,
9504
+ ...FIELDS_FLAGS
9505
+ }));
9245
9506
  const config = await createIxpConfig({
9246
9507
  tenant: options.tenant
9247
9508
  });
@@ -9263,6 +9524,7 @@ var registerGroupsCommand = (program2) => {
9263
9524
  Data: response
9264
9525
  }, { preserveDataKeys: true });
9265
9526
  });
9527
+ requireOneOfOptions(add, ["--fields", "--fields-file"]);
9266
9528
  groups.command("delete").description("Delete a field group. IRREVERSIBLE: all annotations on all fields in the group are deleted.").argument("<project-name>", "Project name").requiredOption("--name <name>", "Field group name to delete").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-y, --yes", "Confirm this irreversible operation (required; the CLI never prompts)").examples(GROUPS_DELETE_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9267
9529
  if (!requireConfirmation(options, `delete group '${options.name}'`))
9268
9530
  return;
@@ -9303,9 +9565,13 @@ var registerGroupsCommand = (program2) => {
9303
9565
  Data: response
9304
9566
  }, { preserveDataKeys: true });
9305
9567
  });
9306
- groups.command("update-prompts").description("Bulk-update field group (label_def) extraction instructions. Match by group name; existing fields preserved.").argument("<project-name>", "Project name").requiredOption("--updates <json>", `JSON array of field group instruction updates: [{"name":"Invoice","instructions":"..."}]. Match by label_def name. Each \`instructions\` is at most ${MAX_INSTRUCTIONS_LENGTH} characters, each \`name\` at most ${MAX_NAME_LENGTH}.`).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(GROUPS_UPDATE_PROMPTS_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9568
+ const updatePrompts = groups.command("update-prompts").description("Bulk-update field group (label_def) extraction instructions. Match by group name; existing fields preserved.").argument("<project-name>", "Project name").option("--updates <json>", `JSON array of field group instruction updates: [{"name":"Invoice","instructions":"..."}]. Match by label_def name. Each \`instructions\` is at most ${MAX_INSTRUCTIONS_LENGTH} characters, each \`name\` at most ${MAX_NAME_LENGTH}. Required unless --updates-file is given.`).addOption(new Option("--updates-file <path>", jsonFileOptionHelp("--updates")).conflicts("updates")).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(GROUPS_UPDATE_PROMPTS_EXAMPLES).trackedAction(processContext, async (projectName, options) => {
9307
9569
  const [err, response] = await catchError((async () => {
9308
- const updates = parseUpdatesJson(options.updates);
9570
+ const updates = parseUpdatesJson(await readJsonOption({
9571
+ inline: options.updates,
9572
+ file: options.updatesFile,
9573
+ ...UPDATES_FLAGS2
9574
+ }));
9309
9575
  const config = await createIxpConfig({
9310
9576
  tenant: options.tenant
9311
9577
  });
@@ -9325,14 +9591,16 @@ var registerGroupsCommand = (program2) => {
9325
9591
  Data: response
9326
9592
  }, { preserveDataKeys: true });
9327
9593
  });
9594
+ requireOneOfOptions(updatePrompts, ["--updates", "--updates-file"]);
9328
9595
  };
9329
9596
 
9330
9597
  // src/commands/labellings.ts
9598
+ var UPDATES_FLAGS3 = { inlineFlag: "--updates", fileFlag: "--updates-file" };
9331
9599
  function validateConfirmMode(documentUid, options) {
9332
- if (options.updates && options.occurrence !== undefined) {
9600
+ if (options.updates !== undefined && options.occurrence !== undefined) {
9333
9601
  throw new Error("--occurrence and --updates are mutually exclusive. Use --occurrence for a single occurrence; use --updates to batch multiple occurrences in one call.");
9334
9602
  }
9335
- if (options.updates) {
9603
+ if (options.updates !== undefined) {
9336
9604
  if (options.fields || options.corrections) {
9337
9605
  throw new Error("--updates cannot be combined with --fields or --corrections. Move per-field corrections into the corrections map inside --updates.");
9338
9606
  }
@@ -9354,8 +9622,8 @@ function validateConfirmMode(documentUid, options) {
9354
9622
  return;
9355
9623
  }
9356
9624
  }
9357
- function parseConfirmUpdates(updatesJson) {
9358
- const parsed = JSON.parse(updatesJson);
9625
+ function parseConfirmUpdates(updates) {
9626
+ const parsed = updates;
9359
9627
  if (!Array.isArray(parsed) || parsed.length === 0) {
9360
9628
  throw new Error("--updates must be a non-empty JSON array of {occurrence, fields?, corrections?} entries.");
9361
9629
  }
@@ -9416,7 +9684,7 @@ function buildConfirmBody(options) {
9416
9684
  return options.modelVersion === undefined ? body : { ...body, ModelVersion: options.modelVersion };
9417
9685
  }
9418
9686
  function buildConfirmTargeting(options) {
9419
- if (options.updates && options.group) {
9687
+ if (options.updates !== undefined && options.group) {
9420
9688
  return {
9421
9689
  Group: options.group,
9422
9690
  Updates: parseConfirmUpdates(options.updates)
@@ -9438,10 +9706,10 @@ function buildConfirmTargeting(options) {
9438
9706
  };
9439
9707
  }
9440
9708
  function validateUnconfirmMode(options) {
9441
- if (options.updates && options.occurrence !== undefined) {
9709
+ if (options.updates !== undefined && options.occurrence !== undefined) {
9442
9710
  throw new Error("--occurrence and --updates are mutually exclusive. Use --occurrence for a single occurrence; use --updates to unconfirm several occurrences in one call.");
9443
9711
  }
9444
- if (options.updates) {
9712
+ if (options.updates !== undefined) {
9445
9713
  if (options.fields) {
9446
9714
  throw new Error("--updates cannot be combined with --fields. List the field IDs inside each --updates entry instead.");
9447
9715
  }
@@ -9457,8 +9725,8 @@ function validateUnconfirmMode(options) {
9457
9725
  throw new Error("Provide --fields <ids> to unconfirm specific fields, or --group <name> to unconfirm a repeatable field group (optionally narrowed with --occurrence/--updates/--fields).");
9458
9726
  }
9459
9727
  }
9460
- function parseUnconfirmUpdates(updatesJson) {
9461
- const parsed = JSON.parse(updatesJson);
9728
+ function parseUnconfirmUpdates(updates) {
9729
+ const parsed = updates;
9462
9730
  if (!Array.isArray(parsed) || parsed.length === 0) {
9463
9731
  throw new Error("--updates must be a non-empty JSON array of {occurrence, fields?} entries.");
9464
9732
  }
@@ -9483,7 +9751,7 @@ function parseUnconfirmUpdates(updatesJson) {
9483
9751
  });
9484
9752
  }
9485
9753
  function buildUnconfirmBody(options) {
9486
- if (options.updates && options.group) {
9754
+ if (options.updates !== undefined && options.group) {
9487
9755
  return {
9488
9756
  Group: options.group,
9489
9757
  Updates: parseUnconfirmUpdates(options.updates)
@@ -9677,6 +9945,19 @@ var LABELLINGS_UNCONFIRM_EXAMPLES = [
9677
9945
  Unmatched: []
9678
9946
  }
9679
9947
  }
9948
+ },
9949
+ {
9950
+ Description: "Batched per-occurrence unconfirm with the entries read from a file (use this on Windows PowerShell, which strips quotes from inline JSON)",
9951
+ Command: 'uip ixp labellings unconfirm my-invoices 5f3a9c21-7e4b-4d8a-9f12-6c0b8e3d2a14.7f3c8a21 --group "Line Items" --updates-file updates.json',
9952
+ Output: {
9953
+ Code: "IxpLabellingsUnconfirm",
9954
+ Data: {
9955
+ ProjectName: "my-invoices",
9956
+ DocumentId: "5f3a9c21-7e4b-4d8a-9f12-6c0b8e3d2a14.7f3c8a21",
9957
+ FieldsUnconfirmed: 4,
9958
+ Unmatched: []
9959
+ }
9960
+ }
9680
9961
  }
9681
9962
  ];
9682
9963
  var LABELLINGS_MARK_MISSING_EXAMPLES = [
@@ -9743,7 +10024,7 @@ async function listAllDocumentIds(config, projectName) {
9743
10024
  }
9744
10025
  var registerLabellingsCommand = (program2) => {
9745
10026
  const labelling = program2.command("labellings").description("Manage IXP labellings and predictions");
9746
- labelling.command("confirm").description("Confirm IXP-generated predictions as ground truth for one document. Omitting <document-id> confirms every document in the project — deprecated, and removed in the next release. For a repeatable field group, narrow with --group: alone it confirms every occurrence; add --occurrence to confirm ONE occurrence (the ergonomic single-line form); or use --updates to confirm SEVERAL occurrences in one atomic call (one request). --updates is the superset — --occurrence <N> equals --updates with a single entry — so reach for --occurrence for one line and --updates when several lines need confirming together (or with different per-line fields/corrections).").argument("<project-name>", "Project name").argument("[document-id]", "Document ID. Omitting it confirms every document in the project — deprecated, and removed in the next release.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-f, --fields <field-ids>", "Comma-separated field IDs to confirm (omit to confirm all predicted fields). Without --group, confirms each field_id across every occurrence it appears in. With --group + --occurrence, confirms only within that specific occurrence.").option("-c, --corrections <json>", 'Override predicted values while keeping references: [{"field_id":"...","value":"corrected"}]. Applies across every occurrence the field appears in (or just the targeted occurrence when --group + --occurrence are given).').option("--group <name>", 'Target field group (label_def). Must be the FULL label path exactly as shown in the "Name" field of `get-predictions` (e.g. "Invoice > Line Items"), not just the leaf name. On its own, confirms every occurrence of the group as-is. Add --occurrence to target a single occurrence, or --updates to batch specific occurrences in one call. Combine with --fields to limit to specific fields within the group.').option("--occurrence <index>", "Single-occurrence form: 0-based index of ONE occurrence within --group to confirm. Use --fields to limit to specific fields in that occurrence; omit --fields to confirm every predicted field there. Requires --group. Mutually exclusive with --updates — for several occurrences in one call, use --updates instead.").option("--updates <json>", 'Batched form: confirm SEVERAL occurrences of --group in one atomic call. JSON array of {"occurrence":<0-based-index>,"fields"?:["<field_id>",...],"corrections"?:{"<field_id>":"<value>"}}. Per entry: omit "fields" to confirm every predicted field in that occurrence (same default as --occurrence without --fields), or list specific ones. Un-selected fields in a selected occurrence carry forward their existing annotation; occurrences not listed are left as-is. Equivalent to running --occurrence once per entry, but in a single request. Mutually exclusive with --fields, --corrections, and --occurrence.').option("-m, --model-version <version>", "Optimistic-concurrency guard: the model version (from `get-predictions`' ModelVersion) the predictions being confirmed were reviewed against. If a retrain has produced a newer version since, the confirm is rejected instead of stamping drifted values as ground truth — re-read predictions and review again. Omit to skip the check.", (raw) => parseBoundedInt(raw, "--model-version", {
10027
+ labelling.command("confirm").description("Confirm IXP-generated predictions as ground truth for one document. Omitting <document-id> confirms every document in the project — deprecated, and removed in the next release. For a repeatable field group, narrow with --group: alone it confirms every occurrence; add --occurrence to confirm ONE occurrence (the ergonomic single-line form); or use --updates to confirm SEVERAL occurrences in one atomic call (one request). --updates is the superset — --occurrence <N> equals --updates with a single entry — so reach for --occurrence for one line and --updates when several lines need confirming together (or with different per-line fields/corrections).").argument("<project-name>", "Project name").argument("[document-id]", "Document ID. Omitting it confirms every document in the project — deprecated, and removed in the next release.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("-f, --fields <field-ids>", "Comma-separated field IDs to confirm (omit to confirm all predicted fields). Without --group, confirms each field_id across every occurrence it appears in. With --group + --occurrence, confirms only within that specific occurrence.").option("-c, --corrections <json>", 'Override predicted values while keeping references: [{"field_id":"...","value":"corrected"}]. Applies across every occurrence the field appears in (or just the targeted occurrence when --group + --occurrence are given).').option("--group <name>", 'Target field group (label_def). Must be the FULL label path exactly as shown in the "Name" field of `get-predictions` (e.g. "Invoice > Line Items"), not just the leaf name. On its own, confirms every occurrence of the group as-is. Add --occurrence to target a single occurrence, or --updates to batch specific occurrences in one call. Combine with --fields to limit to specific fields within the group.').option("--occurrence <index>", "Single-occurrence form: 0-based index of ONE occurrence within --group to confirm. Use --fields to limit to specific fields in that occurrence; omit --fields to confirm every predicted field there. Requires --group. Mutually exclusive with --updates — for several occurrences in one call, use --updates instead.").option("--updates <json>", 'Batched form: confirm SEVERAL occurrences of --group in one atomic call. JSON array of {"occurrence":<0-based-index>,"fields"?:["<field_id>",...],"corrections"?:{"<field_id>":"<value>"}}. Per entry: omit "fields" to confirm every predicted field in that occurrence (same default as --occurrence without --fields), or list specific ones. Un-selected fields in a selected occurrence carry forward their existing annotation; occurrences not listed are left as-is. Equivalent to running --occurrence once per entry, but in a single request. Mutually exclusive with --fields, --corrections, and --occurrence.').addOption(new Option("--updates-file <path>", jsonFileOptionHelp("--updates")).conflicts("updates")).option("-m, --model-version <version>", "Optimistic-concurrency guard: the model version (from `get-predictions`' ModelVersion) the predictions being confirmed were reviewed against. If a retrain has produced a newer version since, the confirm is rejected instead of stamping drifted values as ground truth — re-read predictions and review again. Omit to skip the check.", (raw) => parseBoundedInt(raw, "--model-version", {
9747
10028
  min: 0,
9748
10029
  max: Number.MAX_SAFE_INTEGER
9749
10030
  })).examples(LABELLINGS_CONFIRM_EXAMPLES).trackedAction(processContext, async (projectName, documentUid, options) => {
@@ -9751,11 +10032,19 @@ var registerLabellingsCommand = (program2) => {
9751
10032
  getOutputSink().writeErr(PROJECT_WIDE_DEPRECATION_WARNING);
9752
10033
  }
9753
10034
  const [err, result] = await catchError((async () => {
9754
- validateConfirmMode(documentUid, options);
10035
+ validateConfirmMode(documentUid, {
10036
+ ...options,
10037
+ updates: options.updates ?? options.updatesFile
10038
+ });
10039
+ const updates = await readJsonOption({
10040
+ inline: options.updates,
10041
+ file: options.updatesFile,
10042
+ ...UPDATES_FLAGS3
10043
+ });
9755
10044
  const config = await createIxpConfig({
9756
10045
  tenant: options.tenant
9757
10046
  });
9758
- const body = buildConfirmBody(options);
10047
+ const body = buildConfirmBody({ ...options, updates });
9759
10048
  if (documentUid) {
9760
10049
  const res = await confirmLabelling(config, projectName, documentUid, body);
9761
10050
  return {
@@ -9790,13 +10079,21 @@ var registerLabellingsCommand = (program2) => {
9790
10079
  }
9791
10080
  });
9792
10081
  });
9793
- labelling.command("unconfirm").description("Remove confirmations from a document — the targeted fields go back to un-annotated state. Use to roll back an earlier confirm or mark-missing when you realize it was a mistake. Every other annotation on the document is carried forward. With --fields alone, each field_id is unconfirmed across every occurrence it appears in. For a repeatable field group, narrow with --group: alone it unconfirms every occurrence; add --occurrence to roll back ONE occurrence (the ergonomic single-line form); or use --updates to roll back SEVERAL occurrences in one atomic call. Mirrors `confirm`'s targeting flags.").argument("<project-name>", "Project name").argument("<document-id>", "Document ID").option("-f, --fields <field-ids>", "Comma-separated field IDs to unconfirm. Without --group, unconfirms each field_id across every occurrence it appears in. With --group + --occurrence, limits to that specific occurrence; omit it to unconfirm every annotated field in the targeted occurrence(s).").option("--group <name>", 'Target field group (label_def). Must be the FULL label path exactly as shown in the "Name" field of `get-predictions` (e.g. "Invoice > Line Items"), not just the leaf name. On its own, unconfirms every occurrence of the group. Add --occurrence to target a single occurrence, or --updates to batch specific occurrences in one call. Combine with --fields to limit to specific fields within the group.').option("--occurrence <index>", "Single-occurrence form: 0-based index of ONE occurrence within --group to unconfirm. Use --fields to limit to specific fields in that occurrence; omit --fields to unconfirm every annotated field there. Requires --group. Mutually exclusive with --updates.").option("--updates <json>", 'Batched form: unconfirm SEVERAL occurrences of --group in one atomic call. JSON array of {"occurrence":<0-based-index>,"fields"?:["<field_id>",...]}. Per entry: omit "fields" to unconfirm every annotated field in that occurrence, or list specific ones. Occurrences not listed are left as-is. Mutually exclusive with --fields and --occurrence.').addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(LABELLINGS_UNCONFIRM_EXAMPLES).trackedAction(processContext, async (projectName, documentUid, options) => {
10082
+ labelling.command("unconfirm").description("Remove confirmations from a document — the targeted fields go back to un-annotated state. Use to roll back an earlier confirm or mark-missing when you realize it was a mistake. Every other annotation on the document is carried forward. With --fields alone, each field_id is unconfirmed across every occurrence it appears in. For a repeatable field group, narrow with --group: alone it unconfirms every occurrence; add --occurrence to roll back ONE occurrence (the ergonomic single-line form); or use --updates to roll back SEVERAL occurrences in one atomic call. Mirrors `confirm`'s targeting flags.").argument("<project-name>", "Project name").argument("<document-id>", "Document ID").option("-f, --fields <field-ids>", "Comma-separated field IDs to unconfirm. Without --group, unconfirms each field_id across every occurrence it appears in. With --group + --occurrence, limits to that specific occurrence; omit it to unconfirm every annotated field in the targeted occurrence(s).").option("--group <name>", 'Target field group (label_def). Must be the FULL label path exactly as shown in the "Name" field of `get-predictions` (e.g. "Invoice > Line Items"), not just the leaf name. On its own, unconfirms every occurrence of the group. Add --occurrence to target a single occurrence, or --updates to batch specific occurrences in one call. Combine with --fields to limit to specific fields within the group.').option("--occurrence <index>", "Single-occurrence form: 0-based index of ONE occurrence within --group to unconfirm. Use --fields to limit to specific fields in that occurrence; omit --fields to unconfirm every annotated field there. Requires --group. Mutually exclusive with --updates.").option("--updates <json>", 'Batched form: unconfirm SEVERAL occurrences of --group in one atomic call. JSON array of {"occurrence":<0-based-index>,"fields"?:["<field_id>",...]}. Per entry: omit "fields" to unconfirm every annotated field in that occurrence, or list specific ones. Occurrences not listed are left as-is. Mutually exclusive with --fields and --occurrence.').addOption(new Option("--updates-file <path>", jsonFileOptionHelp("--updates")).conflicts("updates")).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).examples(LABELLINGS_UNCONFIRM_EXAMPLES).trackedAction(processContext, async (projectName, documentUid, options) => {
9794
10083
  const [err, result] = await catchError((async () => {
9795
- validateUnconfirmMode(options);
10084
+ validateUnconfirmMode({
10085
+ ...options,
10086
+ updates: options.updates ?? options.updatesFile
10087
+ });
10088
+ const updates = await readJsonOption({
10089
+ inline: options.updates,
10090
+ file: options.updatesFile,
10091
+ ...UPDATES_FLAGS3
10092
+ });
9796
10093
  const config = await createIxpConfig({
9797
10094
  tenant: options.tenant
9798
10095
  });
9799
- return await unconfirmLabelling(config, projectName, documentUid, buildUnconfirmBody(options));
10096
+ return await unconfirmLabelling(config, projectName, documentUid, buildUnconfirmBody({ ...options, updates }));
9800
10097
  })());
9801
10098
  if (err) {
9802
10099
  await emitError(err, "Failed to unconfirm fields");
@@ -10750,4 +11047,4 @@ var registerCommands = async (program2) => {
10750
11047
 
10751
11048
  export { package_default, Command, metadata, registerCommands };
10752
11049
 
10753
- //# debugId=95A3C2252B9957AE64756E2164756E21
11050
+ //# debugId=2CB8F8700FFEB6D264756E2164756E21
package/dist/tool.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  metadata,
3
3
  registerCommands
4
- } from "./tool-vsg7smdq.js";
4
+ } from "./tool-6j0f3qjh.js";
5
5
  import"./tool-1de529jm.js";
6
6
  export {
7
7
  metadata,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/ixp-tool",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.204.0-preview.254",
5
+ "version": "1.205.0-preview.256",
6
6
  "description": "Manage UiPath IXP projects, prompts, predictions, and model publishing.",
7
7
  "private": false,
8
8
  "repository": {
@@ -27,5 +27,5 @@
27
27
  "files": [
28
28
  "dist"
29
29
  ],
30
- "gitHead": "3ee79cdec05b36231a8da9e8de6bf0043585526a"
30
+ "gitHead": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
31
31
  }