@uipath/agent-sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -706,6 +706,7 @@ var init_open = __esm(() => {
706
706
  });
707
707
 
708
708
  // ../filesystem/src/node.ts
709
+ import { randomUUID } from "node:crypto";
709
710
  import { existsSync } from "node:fs";
710
711
  import * as fs6 from "node:fs/promises";
711
712
  import * as os2 from "node:os";
@@ -787,6 +788,90 @@ class NodeFileSystem {
787
788
  async mkdir(dirPath) {
788
789
  await fs6.mkdir(dirPath, { recursive: true });
789
790
  }
791
+ async acquireLock(lockPath) {
792
+ const canonicalPath = await this.canonicalizeLockTarget(lockPath);
793
+ const lockFile = `${canonicalPath}.lock`;
794
+ const ownerId = randomUUID();
795
+ const start = Date.now();
796
+ while (true) {
797
+ try {
798
+ await fs6.writeFile(lockFile, ownerId, { flag: "wx" });
799
+ return this.createLockRelease(lockFile, ownerId);
800
+ } catch (error) {
801
+ if (!this.hasErrnoCode(error, "EEXIST")) {
802
+ throw error;
803
+ }
804
+ const stats = await fs6.stat(lockFile).catch(() => null);
805
+ if (stats && Date.now() - stats.mtimeMs > LOCK_STALE_MS) {
806
+ const reclaimed = await fs6.rm(lockFile, { force: true }).then(() => true).catch(() => false);
807
+ if (reclaimed)
808
+ continue;
809
+ }
810
+ if (Date.now() - start > LOCK_MAX_WAIT_MS) {
811
+ throw new Error(`ELOCKED: timed out waiting for lock on ${canonicalPath}`);
812
+ }
813
+ await new Promise((resolve2) => setTimeout(resolve2, LOCK_RETRY_MIN_MS + Math.random() * LOCK_RETRY_JITTER_MS));
814
+ }
815
+ }
816
+ }
817
+ async canonicalizeLockTarget(lockPath) {
818
+ const absolute = path2.resolve(lockPath);
819
+ const fullReal = await fs6.realpath(absolute).catch(() => null);
820
+ if (fullReal)
821
+ return fullReal;
822
+ const parent = path2.dirname(absolute);
823
+ const base = path2.basename(absolute);
824
+ const canonicalParent = await fs6.realpath(parent).catch(() => parent);
825
+ return path2.join(canonicalParent, base);
826
+ }
827
+ createLockRelease(lockFile, ownerId) {
828
+ const heartbeatStart = Date.now();
829
+ let heartbeatTimer;
830
+ let stopped = false;
831
+ const stopHeartbeat = () => {
832
+ stopped = true;
833
+ if (heartbeatTimer)
834
+ clearTimeout(heartbeatTimer);
835
+ };
836
+ const scheduleNextHeartbeat = () => {
837
+ if (stopped)
838
+ return;
839
+ if (Date.now() - heartbeatStart >= LOCK_MAX_HOLD_MS) {
840
+ stopped = true;
841
+ return;
842
+ }
843
+ heartbeatTimer = setTimeout(() => {
844
+ runHeartbeat();
845
+ }, LOCK_HEARTBEAT_MS);
846
+ heartbeatTimer.unref?.();
847
+ };
848
+ const runHeartbeat = async () => {
849
+ if (stopped)
850
+ return;
851
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
852
+ if (stopped)
853
+ return;
854
+ if (current !== ownerId) {
855
+ stopped = true;
856
+ return;
857
+ }
858
+ const now = Date.now() / 1000;
859
+ await fs6.utimes(lockFile, now, now).catch(() => {});
860
+ scheduleNextHeartbeat();
861
+ };
862
+ scheduleNextHeartbeat();
863
+ let released = false;
864
+ return async () => {
865
+ if (released)
866
+ return;
867
+ released = true;
868
+ stopHeartbeat();
869
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
870
+ if (current === ownerId) {
871
+ await fs6.rm(lockFile, { force: true });
872
+ }
873
+ };
874
+ }
790
875
  async rm(filePath) {
791
876
  await fs6.rm(filePath, { recursive: true, force: true });
792
877
  }
@@ -832,9 +917,13 @@ class NodeFileSystem {
832
917
  }
833
918
  }
834
919
  isEnoent(error) {
835
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
920
+ return this.hasErrnoCode(error, "ENOENT");
921
+ }
922
+ hasErrnoCode(error, code) {
923
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
836
924
  }
837
925
  }
926
+ var LOCK_HEARTBEAT_MS = 5000, LOCK_STALE_MS = 15000, LOCK_MAX_WAIT_MS = 20000, LOCK_MAX_HOLD_MS = 60000, LOCK_RETRY_MIN_MS = 100, LOCK_RETRY_JITTER_MS = 200;
838
927
  var init_node = __esm(() => {
839
928
  init_open();
840
929
  });
@@ -848,7 +937,7 @@ var init_src = __esm(() => {
848
937
 
849
938
  // ../../node_modules/@uipath/coreipc/index.js
850
939
  var require_coreipc = __commonJS((exports, module) => {
851
- var __dirname = "/Users/alexandru.oltean/github/cli/node_modules/@uipath/coreipc";
940
+ var __dirname = "/home/runner/work/cli/cli/node_modules/@uipath/coreipc";
852
941
  /*! For license information please see index.js.LICENSE.txt */
853
942
  (function(e, t) {
854
943
  typeof exports == "object" && typeof module == "object" ? module.exports = t() : typeof define == "function" && define.amd ? define([], t) : typeof exports == "object" ? exports.ipc = t() : e.ipc = t();
@@ -19040,6 +19129,140 @@ var require_dist = __commonJS((exports) => {
19040
19129
  exports.RobotProxyConstructor = RobotProxyConstructor;
19041
19130
  __exportStar(require_agent(), exports);
19042
19131
  });
19132
+ // ../auth/src/server.ts
19133
+ var init_server = __esm(() => {
19134
+ init_constants();
19135
+ });
19136
+
19137
+ // ../common/src/singleton.ts
19138
+ var PREFIX = "@uipath/common/";
19139
+ var _g = globalThis;
19140
+ function singleton(ctorOrName) {
19141
+ const name = typeof ctorOrName === "string" ? ctorOrName : ctorOrName.name;
19142
+ const key = Symbol.for(PREFIX + name);
19143
+ return {
19144
+ get(fallback) {
19145
+ return _g[key] ?? fallback;
19146
+ },
19147
+ set(value) {
19148
+ _g[key] = value;
19149
+ },
19150
+ clear() {
19151
+ delete _g[key];
19152
+ },
19153
+ getOrInit(factory, guard) {
19154
+ const existing = _g[key];
19155
+ if (existing != null && typeof existing === "object") {
19156
+ if (!guard || guard(existing)) {
19157
+ return existing;
19158
+ }
19159
+ }
19160
+ const instance = factory();
19161
+ _g[key] = instance;
19162
+ return instance;
19163
+ }
19164
+ };
19165
+ }
19166
+
19167
+ // ../common/src/sdk-user-agent.ts
19168
+ var USER_AGENT_HEADER = "User-Agent";
19169
+ var sdkUserAgentHostToken = singleton("SdkUserAgentHostToken");
19170
+ function userAgentPatchKey(userAgent) {
19171
+ return Symbol.for(`@uipath/common/sdk-user-agent/${userAgent}`);
19172
+ }
19173
+ function splitUserAgentTokens(value) {
19174
+ return value?.trim().split(/\s+/).filter(Boolean) ?? [];
19175
+ }
19176
+ function appendUserAgentToken(value, userAgent) {
19177
+ const tokens = splitUserAgentTokens(value);
19178
+ const seen = new Set(tokens);
19179
+ for (const token of splitUserAgentTokens(userAgent)) {
19180
+ if (!seen.has(token)) {
19181
+ tokens.push(token);
19182
+ seen.add(token);
19183
+ }
19184
+ }
19185
+ return tokens.join(" ");
19186
+ }
19187
+ function getEffectiveUserAgent(userAgent) {
19188
+ return appendUserAgentToken(sdkUserAgentHostToken.get(), userAgent);
19189
+ }
19190
+ function isHeadersLike(headers) {
19191
+ return typeof headers === "object" && headers !== null && "get" in headers && typeof headers.get === "function" && "set" in headers && typeof headers.set === "function";
19192
+ }
19193
+ function getSdkUserAgentToken(pkg) {
19194
+ const packageName = pkg.name.replace(/^@uipath\//, "");
19195
+ return getEffectiveUserAgent(`${packageName}/${pkg.version}`);
19196
+ }
19197
+ function addSdkUserAgentHeader(headers, userAgent) {
19198
+ const result = { ...headers ?? {} };
19199
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
19200
+ const headerName = Object.keys(result).find((key) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
19201
+ if (headerName) {
19202
+ result[headerName] = appendUserAgentToken(result[headerName], effectiveUserAgent);
19203
+ } else {
19204
+ result[USER_AGENT_HEADER] = effectiveUserAgent;
19205
+ }
19206
+ return result;
19207
+ }
19208
+ function withSdkUserAgentHeader(headers, userAgent) {
19209
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
19210
+ if (isHeadersLike(headers)) {
19211
+ headers.set(USER_AGENT_HEADER, appendUserAgentToken(headers.get(USER_AGENT_HEADER), effectiveUserAgent));
19212
+ return headers;
19213
+ }
19214
+ if (Array.isArray(headers)) {
19215
+ const result = headers.map((entry) => {
19216
+ const [key, value] = entry;
19217
+ return [key, value];
19218
+ });
19219
+ const headerIndex = result.findIndex(([key]) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
19220
+ if (headerIndex >= 0) {
19221
+ const [key, value] = result[headerIndex];
19222
+ result[headerIndex] = [
19223
+ key,
19224
+ appendUserAgentToken(value, effectiveUserAgent)
19225
+ ];
19226
+ } else {
19227
+ result.push([USER_AGENT_HEADER, effectiveUserAgent]);
19228
+ }
19229
+ return result;
19230
+ }
19231
+ return addSdkUserAgentHeader(typeof headers === "object" && headers !== null ? { ...headers } : {}, effectiveUserAgent);
19232
+ }
19233
+ function withUserAgentInitOverride(initOverrides, userAgent) {
19234
+ return async (requestContext) => {
19235
+ const initWithUserAgent = {
19236
+ ...requestContext.init,
19237
+ headers: withSdkUserAgentHeader(requestContext.init.headers, userAgent)
19238
+ };
19239
+ const override = typeof initOverrides === "function" ? await initOverrides({
19240
+ ...requestContext,
19241
+ init: initWithUserAgent
19242
+ }) : initOverrides;
19243
+ return {
19244
+ ...override ?? {},
19245
+ headers: withSdkUserAgentHeader(override?.headers ?? initWithUserAgent.headers, userAgent)
19246
+ };
19247
+ };
19248
+ }
19249
+ function installSdkUserAgentHeader(BaseApiClass, userAgent) {
19250
+ const prototype = BaseApiClass.prototype;
19251
+ const patchKey = userAgentPatchKey(userAgent);
19252
+ if (prototype[patchKey]) {
19253
+ return;
19254
+ }
19255
+ if (typeof prototype.request !== "function") {
19256
+ throw new Error("Generated BaseAPI request function not found.");
19257
+ }
19258
+ const originalRequest = prototype.request;
19259
+ prototype.request = function requestWithUserAgent(context, initOverrides) {
19260
+ return originalRequest.call(this, context, withUserAgentInitOverride(initOverrides, userAgent));
19261
+ };
19262
+ Object.defineProperty(prototype, patchKey, {
19263
+ value: true
19264
+ });
19265
+ }
19043
19266
 
19044
19267
  // generated/src/runtime.ts
19045
19268
  var BASE_PATH = "http://localhost".replace(/\/+$/, "");
@@ -19348,6 +19571,57 @@ class TextApiResponse {
19348
19571
  return await this.raw.text();
19349
19572
  }
19350
19573
  }
19574
+ // package.json
19575
+ var package_default = {
19576
+ name: "@uipath/agent-sdk",
19577
+ license: "MIT",
19578
+ version: "1.2.0",
19579
+ description: "SDK for the UiPath Agent Runtime API — evaluation execution and debug sessions.",
19580
+ repository: {
19581
+ type: "git",
19582
+ url: "https://github.com/UiPath/cli.git",
19583
+ directory: "packages/agent-sdk"
19584
+ },
19585
+ publishConfig: {
19586
+ registry: "https://npm.pkg.github.com/@uipath"
19587
+ },
19588
+ keywords: [
19589
+ "uipath",
19590
+ "agent",
19591
+ "evaluation",
19592
+ "sdk"
19593
+ ],
19594
+ type: "module",
19595
+ main: "./dist/index.js",
19596
+ types: "./dist/src/index.d.ts",
19597
+ exports: {
19598
+ ".": {
19599
+ types: "./dist/src/index.d.ts",
19600
+ default: "./dist/index.js"
19601
+ }
19602
+ },
19603
+ files: [
19604
+ "dist"
19605
+ ],
19606
+ scripts: {
19607
+ build: "bun build ./src/index.ts --outdir dist --format esm --target node && tsc -p tsconfig.build.json --noCheck",
19608
+ generate: "bun run src/scripts/generate-sdk.ts",
19609
+ test: "vitest run",
19610
+ "test:coverage": "vitest run --coverage",
19611
+ lint: "biome check ."
19612
+ },
19613
+ devDependencies: {
19614
+ "@openapitools/openapi-generator-cli": "^2.31.1",
19615
+ "@types/node": "^25.5.2",
19616
+ "@uipath/auth": "workspace:*",
19617
+ "@uipath/common": "workspace:*",
19618
+ typescript: "^6.0.2"
19619
+ }
19620
+ };
19621
+
19622
+ // src/user-agent.ts
19623
+ var SDK_USER_AGENT = getSdkUserAgentToken(package_default);
19624
+ installSdkUserAgentHeader(BaseAPI, SDK_USER_AGENT);
19351
19625
  // generated/src/models/StartingPrompt.ts
19352
19626
  function instanceOfStartingPrompt(value) {
19353
19627
  return true;
@@ -22312,32 +22586,7 @@ class InvalidBaseUrlError extends Error {
22312
22586
  this.name = "InvalidBaseUrlError";
22313
22587
  }
22314
22588
  }
22315
- var DEFAULT_SCOPES = [
22316
- "offline_access",
22317
- "ProcessMining",
22318
- "OrchestratorApiUserAccess",
22319
- "StudioWebBackend",
22320
- "IdentityServerApi",
22321
- "ConnectionService",
22322
- "DataService",
22323
- "DataServiceApiUserAccess",
22324
- "DocumentUnderstanding",
22325
- "EnterpriseContextService",
22326
- "Directory",
22327
- "JamJamApi",
22328
- "LLMGateway",
22329
- "LLMOps",
22330
- "OMS",
22331
- "RCS.FolderAuthorization",
22332
- "RCS.TagsManagement",
22333
- "TestmanagerApiUserAccess",
22334
- "AutomationSolutions",
22335
- "StudioWebTypeCacheService",
22336
- "Docs.GPT.Search",
22337
- "Insights",
22338
- "ReferenceToken",
22339
- "Audit.Read"
22340
- ];
22589
+ var DEFAULT_SCOPES = ["openid", "profile", "offline_access"];
22341
22590
  var normalizeAndValidateBaseUrl = (rawUrl) => {
22342
22591
  let baseUrl = rawUrl;
22343
22592
  if (baseUrl.endsWith("/identity_/")) {
@@ -22387,7 +22636,8 @@ var resolveConfigAsync = async ({
22387
22636
  if (!clientSecret && fileAuth.clientSecret) {
22388
22637
  clientSecret = fileAuth.clientSecret;
22389
22638
  }
22390
- const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : DEFAULT_SCOPES;
22639
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && Boolean(clientSecret);
22640
+ const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : isExternalAppAuth ? [] : DEFAULT_SCOPES;
22391
22641
  return {
22392
22642
  clientId,
22393
22643
  clientSecret,
@@ -22887,6 +23137,129 @@ function normalizeTokenRefreshFailure() {
22887
23137
  function normalizeTokenRefreshUnavailableFailure() {
22888
23138
  return "token refresh failed before authentication completed";
22889
23139
  }
23140
+ function errorMessage(error) {
23141
+ return error instanceof Error ? error.message : String(error);
23142
+ }
23143
+ function computeExpirationThreshold(ensureTokenValidityMinutes) {
23144
+ return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
23145
+ }
23146
+ async function runRefreshLocked(inputs) {
23147
+ const {
23148
+ absolutePath,
23149
+ refreshToken: callerRefreshToken,
23150
+ customAuthority,
23151
+ ensureTokenValidityMinutes,
23152
+ loadEnvFile,
23153
+ saveEnvFile,
23154
+ refreshFn,
23155
+ resolveConfig
23156
+ } = inputs;
23157
+ const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
23158
+ let fresh;
23159
+ try {
23160
+ fresh = await loadEnvFile({ envPath: absolutePath });
23161
+ } catch (error) {
23162
+ return {
23163
+ kind: "fail",
23164
+ status: {
23165
+ loginStatus: "Refresh Failed",
23166
+ hint: "Could not read the auth file while refreshing. Retry, or run 'uip login' to re-authenticate.",
23167
+ tokenRefresh: {
23168
+ attempted: false,
23169
+ success: false,
23170
+ errorMessage: `auth file read failed: ${errorMessage(error)}`
23171
+ }
23172
+ }
23173
+ };
23174
+ }
23175
+ const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
23176
+ const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
23177
+ if (freshAccess && freshExp && freshExp > expirationThreshold) {
23178
+ return {
23179
+ kind: "ok",
23180
+ accessToken: freshAccess,
23181
+ refreshToken: fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken,
23182
+ expiration: freshExp,
23183
+ tokenRefresh: { attempted: false, success: true }
23184
+ };
23185
+ }
23186
+ const tokenForIdP = fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken;
23187
+ let refreshedAccess;
23188
+ let refreshedRefresh;
23189
+ try {
23190
+ const config = await resolveConfig({ customAuthority });
23191
+ const refreshed = await refreshFn({
23192
+ refreshToken: tokenForIdP,
23193
+ tokenEndpoint: config.tokenEndpoint,
23194
+ clientId: config.clientId,
23195
+ expectedAuthority: customAuthority
23196
+ });
23197
+ refreshedAccess = refreshed.accessToken;
23198
+ refreshedRefresh = refreshed.refreshToken;
23199
+ } catch (error) {
23200
+ const isOAuthFailure = isTokenRefreshOAuthFailure(error);
23201
+ const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
23202
+ const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
23203
+ return {
23204
+ kind: "fail",
23205
+ status: {
23206
+ loginStatus: "Refresh Failed",
23207
+ hint,
23208
+ tokenRefresh: {
23209
+ attempted: true,
23210
+ success: false,
23211
+ errorMessage: message
23212
+ }
23213
+ }
23214
+ };
23215
+ }
23216
+ const refreshedExp = getTokenExpiration(refreshedAccess);
23217
+ if (!refreshedExp || refreshedExp <= new Date) {
23218
+ return {
23219
+ kind: "fail",
23220
+ status: {
23221
+ loginStatus: "Refresh Failed",
23222
+ hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
23223
+ tokenRefresh: {
23224
+ attempted: true,
23225
+ success: false,
23226
+ errorMessage: "refreshed token has no valid expiration claim"
23227
+ }
23228
+ }
23229
+ };
23230
+ }
23231
+ try {
23232
+ await saveEnvFile({
23233
+ envPath: absolutePath,
23234
+ data: {
23235
+ UIPATH_ACCESS_TOKEN: refreshedAccess,
23236
+ UIPATH_REFRESH_TOKEN: refreshedRefresh
23237
+ },
23238
+ merge: true
23239
+ });
23240
+ return {
23241
+ kind: "ok",
23242
+ accessToken: refreshedAccess,
23243
+ refreshToken: refreshedRefresh,
23244
+ expiration: refreshedExp,
23245
+ tokenRefresh: { attempted: true, success: true }
23246
+ };
23247
+ } catch (error) {
23248
+ const msg = errorMessage(error);
23249
+ return {
23250
+ kind: "ok",
23251
+ accessToken: refreshedAccess,
23252
+ refreshToken: refreshedRefresh,
23253
+ expiration: refreshedExp,
23254
+ persistenceWarning: `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`,
23255
+ tokenRefresh: {
23256
+ attempted: true,
23257
+ success: true,
23258
+ errorMessage: `persistence failed: ${msg}`
23259
+ }
23260
+ };
23261
+ }
23262
+ }
22890
23263
  var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
22891
23264
  const {
22892
23265
  resolveEnvFilePath = resolveEnvFilePathAsync,
@@ -22961,73 +23334,103 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
22961
23334
  let refreshToken = credentials.UIPATH_REFRESH_TOKEN;
22962
23335
  let expiration = getTokenExpiration(accessToken);
22963
23336
  let persistenceWarning;
23337
+ let lockReleaseFailed = false;
22964
23338
  let tokenRefresh;
22965
- const expirationThreshold = new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
22966
- if (expiration && expiration <= expirationThreshold && refreshToken) {
22967
- let refreshedAccess;
22968
- let refreshedRefresh;
23339
+ const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
23340
+ const tryGlobalCredsHint = async () => {
23341
+ const fs7 = getFs();
23342
+ const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
23343
+ if (absolutePath === globalPath)
23344
+ return;
23345
+ if (!await fs7.exists(globalPath))
23346
+ return;
22969
23347
  try {
22970
- const config = await resolveConfig({
22971
- customAuthority: credentials.UIPATH_URL
22972
- });
22973
- const refreshed = await refreshTokenFn({
22974
- refreshToken,
22975
- tokenEndpoint: config.tokenEndpoint,
22976
- clientId: config.clientId,
22977
- expectedAuthority: credentials.UIPATH_URL
22978
- });
22979
- refreshedAccess = refreshed.accessToken;
22980
- refreshedRefresh = refreshed.refreshToken;
22981
- } catch (error) {
22982
- const isOAuthFailure = isTokenRefreshOAuthFailure(error);
22983
- const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
22984
- const errorMessage = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
22985
- return {
22986
- loginStatus: "Refresh Failed",
22987
- hint,
22988
- tokenRefresh: {
22989
- attempted: true,
22990
- success: false,
22991
- errorMessage
22992
- }
22993
- };
23348
+ const globalCreds = await loadEnvFile({ envPath: globalPath });
23349
+ if (!globalCreds.UIPATH_ACCESS_TOKEN)
23350
+ return;
23351
+ const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
23352
+ if (globalExp && globalExp <= new Date)
23353
+ return;
23354
+ return `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
23355
+ } catch {
23356
+ return;
22994
23357
  }
22995
- const refreshedExp = getTokenExpiration(refreshedAccess);
22996
- if (!refreshedExp || refreshedExp <= new Date) {
23358
+ };
23359
+ if (expiration && expiration <= outerThreshold && refreshToken) {
23360
+ let release;
23361
+ try {
23362
+ release = await getFs().acquireLock(absolutePath);
23363
+ } catch (error) {
23364
+ const msg = errorMessage(error);
23365
+ const globalHint = await tryGlobalCredsHint();
23366
+ if (globalHint) {
23367
+ return {
23368
+ loginStatus: "Expired",
23369
+ accessToken,
23370
+ refreshToken,
23371
+ baseUrl: credentials.UIPATH_URL,
23372
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
23373
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
23374
+ tenantName: credentials.UIPATH_TENANT_NAME,
23375
+ tenantId: credentials.UIPATH_TENANT_ID,
23376
+ expiration,
23377
+ source: "file" /* File */,
23378
+ hint: globalHint,
23379
+ tokenRefresh: {
23380
+ attempted: false,
23381
+ success: false,
23382
+ errorMessage: `lock acquisition failed: ${msg}`
23383
+ }
23384
+ };
23385
+ }
22997
23386
  return {
22998
23387
  loginStatus: "Refresh Failed",
22999
- hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
23388
+ hint: "Could not acquire the auth-file lock — too many concurrent `uip` processes, or a permission issue on the auth directory. Retry, or run 'uip login' to re-authenticate.",
23000
23389
  tokenRefresh: {
23001
- attempted: true,
23390
+ attempted: false,
23002
23391
  success: false,
23003
- errorMessage: "refreshed token has no valid expiration claim"
23392
+ errorMessage: `lock acquisition failed: ${msg}`
23004
23393
  }
23005
23394
  };
23006
23395
  }
23007
- accessToken = refreshedAccess;
23008
- refreshToken = refreshedRefresh;
23009
- expiration = refreshedExp;
23396
+ let lockedFailure;
23010
23397
  try {
23011
- await saveEnvFile({
23012
- envPath: absolutePath,
23013
- data: {
23014
- UIPATH_ACCESS_TOKEN: accessToken,
23015
- UIPATH_REFRESH_TOKEN: refreshToken
23016
- },
23017
- merge: true
23398
+ const outcome = await runRefreshLocked({
23399
+ absolutePath,
23400
+ refreshToken,
23401
+ customAuthority: credentials.UIPATH_URL,
23402
+ ensureTokenValidityMinutes,
23403
+ loadEnvFile,
23404
+ saveEnvFile,
23405
+ refreshFn: refreshTokenFn,
23406
+ resolveConfig
23018
23407
  });
23019
- tokenRefresh = {
23020
- attempted: true,
23021
- success: true
23022
- };
23023
- } catch (error) {
23024
- const msg = error instanceof Error ? error.message : String(error);
23025
- persistenceWarning = `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`;
23026
- tokenRefresh = {
23027
- attempted: true,
23028
- success: true,
23029
- errorMessage: `persistence failed: ${msg}`
23030
- };
23408
+ if (outcome.kind === "fail") {
23409
+ lockedFailure = outcome.status;
23410
+ } else {
23411
+ accessToken = outcome.accessToken;
23412
+ refreshToken = outcome.refreshToken;
23413
+ expiration = outcome.expiration;
23414
+ tokenRefresh = outcome.tokenRefresh;
23415
+ if (outcome.persistenceWarning) {
23416
+ persistenceWarning = outcome.persistenceWarning;
23417
+ }
23418
+ }
23419
+ } finally {
23420
+ try {
23421
+ await release();
23422
+ } catch {
23423
+ lockReleaseFailed = true;
23424
+ }
23425
+ }
23426
+ if (lockedFailure) {
23427
+ const globalHint = await tryGlobalCredsHint();
23428
+ const base = globalHint ? {
23429
+ ...lockedFailure,
23430
+ loginStatus: "Expired",
23431
+ hint: globalHint
23432
+ } : lockedFailure;
23433
+ return lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base;
23031
23434
  }
23032
23435
  }
23033
23436
  const result = {
@@ -23042,23 +23445,13 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
23042
23445
  expiration,
23043
23446
  source: "file" /* File */,
23044
23447
  ...persistenceWarning ? { hint: persistenceWarning, persistenceFailed: true } : {},
23448
+ ...lockReleaseFailed ? { lockReleaseFailed: true } : {},
23045
23449
  ...tokenRefresh ? { tokenRefresh } : {}
23046
23450
  };
23047
23451
  if (result.loginStatus === "Expired") {
23048
- const fs7 = getFs();
23049
- const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
23050
- if (absolutePath !== globalPath && await fs7.exists(globalPath)) {
23051
- try {
23052
- const globalCreds = await loadEnvFile({
23053
- envPath: globalPath
23054
- });
23055
- if (globalCreds.UIPATH_ACCESS_TOKEN) {
23056
- const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
23057
- if (!globalExp || globalExp > new Date) {
23058
- result.hint = `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
23059
- }
23060
- }
23061
- } catch {}
23452
+ const globalHint = await tryGlobalCredsHint();
23453
+ if (globalHint) {
23454
+ result.hint = globalHint;
23062
23455
  }
23063
23456
  }
23064
23457
  return result;
@@ -23106,6 +23499,10 @@ var getAuthContext = async (options = {}) => {
23106
23499
  init_src();
23107
23500
  // ../auth/src/logout.ts
23108
23501
  init_src();
23502
+
23503
+ // ../auth/src/index.ts
23504
+ init_server();
23505
+
23109
23506
  // src/client-factory.ts
23110
23507
  async function createAgentRuntimeConfig(options) {
23111
23508
  const ctx = await getAuthContext({
@@ -23116,10 +23513,10 @@ async function createAgentRuntimeConfig(options) {
23116
23513
  const organizationId = ctx.organizationId;
23117
23514
  const tenantId = ctx.tenantId;
23118
23515
  const basePath = `${ctx.baseUrl}/${organizationId}/${tenantId}/agentsruntime_`;
23119
- const headers = {
23516
+ const headers = addSdkUserAgentHeader({
23120
23517
  Authorization: `Bearer ${ctx.accessToken}`,
23121
23518
  "X-UiPath-Internal-TenantId": tenantId
23122
- };
23519
+ }, SDK_USER_AGENT);
23123
23520
  return new Configuration({
23124
23521
  basePath,
23125
23522
  headers
@@ -23338,6 +23735,7 @@ export {
23338
23735
  ScoreTypeFromJSONTyped,
23339
23736
  ScoreTypeFromJSON,
23340
23737
  ScoreType,
23738
+ SDK_USER_AGENT,
23341
23739
  RuntimeTypeToJSONTyped,
23342
23740
  RuntimeTypeToJSON,
23343
23741
  RuntimeTypeFromJSONTyped,
@@ -1,4 +1,6 @@
1
+ import "./user-agent.js";
1
2
  export * from "../generated/src/index.js";
2
3
  export { type CreateApiClientOptions, createAgentRuntimeConfig, createApiClient, } from "./client-factory.js";
3
4
  export { type AgentEnforcements, type GuardrailCatalogEntry, GuardrailCatalogUnavailableError, type GuardrailDefinition, type GuardrailParameterDefinition, type GuardrailsCatalogResponse, getAgentEnforcements, getAvailableModelNames, getGuardrailCatalog, getGuardrailDefinitions, } from "./governance.js";
4
5
  export { ProjectFilesSource } from "./types.js";
6
+ export { SDK_USER_AGENT } from "./user-agent.js";
package/package.json CHANGED
@@ -1,38 +1,47 @@
1
1
  {
2
- "name": "@uipath/agent-sdk",
3
- "version": "1.1.0",
4
- "description": "SDK for the UiPath Agent Runtime API — evaluation execution and debug sessions.",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/UiPath/cli.git",
8
- "directory": "packages/agent-sdk"
9
- },
10
- "publishConfig": {
11
- "registry": "https://registry.npmjs.org/"
12
- },
13
- "keywords": [
14
- "uipath",
15
- "agent",
16
- "evaluation",
17
- "sdk"
18
- ],
19
- "type": "module",
20
- "main": "./dist/index.js",
21
- "types": "./dist/src/index.d.ts",
22
- "exports": {
23
- ".": {
24
- "types": "./dist/src/index.d.ts",
25
- "default": "./dist/index.js"
26
- }
27
- },
28
- "files": [
29
- "dist"
30
- ],
31
- "devDependencies": {
32
- "@openapitools/openapi-generator-cli": "^2.31.1",
33
- "@types/node": "^25.5.2",
34
- "@uipath/auth": "1.1.0",
35
- "typescript": "^6.0.2"
36
- },
37
- "gitHead": "06e8c8f566df4b87da4a008635483c62f64f33f0"
2
+ "name": "@uipath/agent-sdk",
3
+ "license": "MIT",
4
+ "version": "1.2.0",
5
+ "description": "SDK for the UiPath Agent Runtime API — evaluation execution and debug sessions.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/UiPath/cli.git",
9
+ "directory": "packages/agent-sdk"
10
+ },
11
+ "publishConfig": {
12
+ "registry": "https://registry.npmjs.org/"
13
+ },
14
+ "keywords": [
15
+ "uipath",
16
+ "agent",
17
+ "evaluation",
18
+ "sdk"
19
+ ],
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/src/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/src/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "scripts": {
33
+ "build": "bun build ./src/index.ts --outdir dist --format esm --target node && tsc -p tsconfig.build.json --noCheck",
34
+ "generate": "bun run src/scripts/generate-sdk.ts",
35
+ "test": "vitest run",
36
+ "test:coverage": "vitest run --coverage",
37
+ "lint": "biome check ."
38
+ },
39
+ "devDependencies": {
40
+ "@openapitools/openapi-generator-cli": "^2.31.1",
41
+ "@types/node": "^25.5.2",
42
+ "@uipath/auth": "1.195.0",
43
+ "@uipath/common": "1.195.0",
44
+ "typescript": "^6.0.2"
45
+ },
46
+ "gitHead": "6c3cc1aecd77f184b0f55aaf89a7f563e2457320"
38
47
  }