@uipath/uipath-python-bridge 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +565 -0
  2. package/package.json +42 -0
package/dist/index.js ADDED
@@ -0,0 +1,565 @@
1
+ // src/cache.ts
2
+ import { catchError, logger } from "@uipath/common";
3
+ import { getFileSystem } from "@uipath/filesystem";
4
+ async function readCache(cacheFile) {
5
+ const fs = getFileSystem();
6
+ const [existsError, exists] = await catchError(fs.exists(cacheFile));
7
+ if (existsError || !exists)
8
+ return null;
9
+ const [readError, content] = await catchError(fs.readFile(cacheFile, "utf-8"));
10
+ if (readError) {
11
+ logger.warn(`Failed to load cache: ${readError}`);
12
+ return null;
13
+ }
14
+ const [parseError, cache] = catchError(() => JSON.parse(content));
15
+ if (parseError) {
16
+ logger.warn(`Failed to parse cache: ${parseError}`);
17
+ return null;
18
+ }
19
+ return cache;
20
+ }
21
+ // src/config.ts
22
+ var DEFAULT_CONFIG = {
23
+ allowedPythonVersions: ["3.13", "3.12", "3.11"],
24
+ packageName: "uipath",
25
+ cacheFileName: ".uipath-python-cache.json"
26
+ };
27
+ function getAllowedPythonVersions() {
28
+ const envVersions = process.env.PYTHON_TOOL_PYTHON_VERSIONS;
29
+ if (envVersions) {
30
+ return envVersions.split(",").map((v) => v.trim()).filter(Boolean);
31
+ }
32
+ return DEFAULT_CONFIG.allowedPythonVersions;
33
+ }
34
+ function getPackageName() {
35
+ return DEFAULT_CONFIG.packageName;
36
+ }
37
+ function getCacheFileName() {
38
+ return DEFAULT_CONFIG.cacheFileName;
39
+ }
40
+ function matchesPattern(args, pattern) {
41
+ if (typeof pattern === "string") {
42
+ return args.includes(pattern);
43
+ }
44
+ if (Array.isArray(pattern)) {
45
+ for (let i = 0;i <= args.length - pattern.length; i++) {
46
+ let match = true;
47
+ for (let j = 0;j < pattern.length; j++) {
48
+ if (args[i + j] !== pattern[j]) {
49
+ match = false;
50
+ break;
51
+ }
52
+ }
53
+ if (match) {
54
+ return true;
55
+ }
56
+ }
57
+ }
58
+ return false;
59
+ }
60
+ function processCommandArgs(args, rules) {
61
+ const hasForceFlag = args.includes("--force");
62
+ const argsWithoutForce = args.filter((arg) => arg !== "--force");
63
+ for (const rule of rules) {
64
+ if (matchesPattern(argsWithoutForce, rule.pattern)) {
65
+ switch (rule.action) {
66
+ case "filter":
67
+ if (hasForceFlag) {
68
+ return {
69
+ allowed: true,
70
+ args: [...argsWithoutForce]
71
+ };
72
+ }
73
+ return {
74
+ allowed: false,
75
+ args: [],
76
+ errorMessage: rule.filterMessage || "This command is not allowed"
77
+ };
78
+ case "append":
79
+ if (rule.appendArgs && rule.appendArgs.length > 0) {
80
+ return {
81
+ allowed: true,
82
+ args: [...argsWithoutForce, ...rule.appendArgs]
83
+ };
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ return {
90
+ allowed: true,
91
+ args: [...args]
92
+ };
93
+ }
94
+ // src/execute.ts
95
+ import { spawn } from "node:child_process";
96
+ import { getLoginStatusAsync } from "@uipath/auth";
97
+ import {
98
+ catchError as catchError2,
99
+ logger as logger2,
100
+ OutputFormatter,
101
+ processContext,
102
+ RESULTS,
103
+ UIPATH_HOME_DIR
104
+ } from "@uipath/common";
105
+ import { getFileSystem as getFileSystem2 } from "@uipath/filesystem";
106
+ async function buildAuthEnv() {
107
+ const authEnv = {};
108
+ const [authError, status] = await catchError2(getLoginStatusAsync());
109
+ if (authError) {
110
+ logger2.debug(`Auth unavailable — continuing without credentials: ${authError.message}`);
111
+ return authEnv;
112
+ }
113
+ if (status.loginStatus === "Logged in" && status.accessToken) {
114
+ authEnv.UIPATH_ACCESS_TOKEN = status.accessToken;
115
+ if (status.baseUrl) {
116
+ const org = status.organizationName || status.organizationId;
117
+ const tenant = status.tenantName || status.tenantId;
118
+ if (org && tenant) {
119
+ authEnv.UIPATH_URL = `${status.baseUrl.replace(/\/+$/, "")}/${org}/${tenant}`;
120
+ }
121
+ }
122
+ if (status.organizationId)
123
+ authEnv.UIPATH_ORGANIZATION_ID = status.organizationId;
124
+ if (status.organizationName)
125
+ authEnv.UIPATH_ORGANIZATION_NAME = status.organizationName;
126
+ if (status.tenantId)
127
+ authEnv.UIPATH_TENANT_ID = status.tenantId;
128
+ if (status.tenantName)
129
+ authEnv.UIPATH_TENANT_NAME = status.tenantName;
130
+ }
131
+ return authEnv;
132
+ }
133
+ function createExecuteCommand(config) {
134
+ const { commandPrefix, telemetryEvent, commandRules } = config;
135
+ const executeCommand = async (rawArgs, _options) => {
136
+ const runIndex = rawArgs.indexOf("exec");
137
+ const actualArgs = runIndex >= 0 ? rawArgs.slice(runIndex + 1) : [];
138
+ const fs = getFileSystem2();
139
+ const cacheFile = fs.path.join(fs.env.homedir(), UIPATH_HOME_DIR, getCacheFileName());
140
+ const setupHint = commandPrefix ? `Run 'uip ${commandPrefix} setup' first to configure environment.` : "Run setup first to configure environment.";
141
+ const cache = await readCache(cacheFile);
142
+ if (!cache || !cache.uipathExePath) {
143
+ OutputFormatter.error({
144
+ Result: RESULTS.Failure,
145
+ Message: "Python not configured.",
146
+ Instructions: setupHint
147
+ });
148
+ processContext.exit(1);
149
+ return;
150
+ }
151
+ if (!await fs.exists(cache.uipathExePath)) {
152
+ OutputFormatter.error({
153
+ Result: RESULTS.Failure,
154
+ Message: "uipath executable not found.",
155
+ Instructions: setupHint
156
+ });
157
+ processContext.exit(1);
158
+ return;
159
+ }
160
+ const processed = processCommandArgs(actualArgs, commandRules);
161
+ if (!processed.allowed) {
162
+ OutputFormatter.error({
163
+ Result: RESULTS.Failure,
164
+ Message: processed.errorMessage || "Command disabled.",
165
+ Instructions: "Use of --force flag is not recommended. Favor alternate command."
166
+ });
167
+ processContext.exit(1);
168
+ return;
169
+ }
170
+ const commandArgs = commandPrefix ? [commandPrefix, ...processed.args] : [...processed.args];
171
+ const authEnv = await buildAuthEnv();
172
+ const proc = spawn(cache.uipathExePath, commandArgs, {
173
+ cwd: fs.env.cwd(),
174
+ env: {
175
+ ...process.env,
176
+ ...authEnv
177
+ },
178
+ stdio: "inherit"
179
+ });
180
+ const [spawnError] = await catchError2(new Promise((resolve, reject) => {
181
+ proc.on("exit", (code) => {
182
+ processContext.exit(code ?? 1);
183
+ resolve();
184
+ });
185
+ proc.on("error", reject);
186
+ }));
187
+ if (spawnError) {
188
+ OutputFormatter.error({
189
+ Result: RESULTS.Failure,
190
+ Message: spawnError.message,
191
+ Instructions: setupHint
192
+ });
193
+ processContext.exit(1);
194
+ }
195
+ };
196
+ const registerExecCommand = (program) => {
197
+ program.command("exec", { hidden: true }).description("Execute the uipath package with provided arguments").allowUnknownOption(true).allowExcessArguments(true).trackedAction(processContext, telemetryEvent, async (_options, cmd) => {
198
+ await executeCommand(["_", "_", "exec", ...cmd.args], {});
199
+ });
200
+ };
201
+ return { executeCommand, registerExecCommand };
202
+ }
203
+ // src/python-service.ts
204
+ import { spawn as spawn2 } from "node:child_process";
205
+ import { platform } from "node:os";
206
+ import { catchError as catchError3, logger as logger3, UIPATH_HOME_DIR as UIPATH_HOME_DIR2 } from "@uipath/common";
207
+ import { getFileSystem as getFileSystem3 } from "@uipath/filesystem";
208
+ class PythonService {
209
+ cacheFile;
210
+ config;
211
+ uipathExePath;
212
+ constructor(config) {
213
+ const fs = getFileSystem3();
214
+ this.config = config;
215
+ this.cacheFile = config.cacheFile || fs.path.join(fs.env.homedir(), UIPATH_HOME_DIR2, getCacheFileName());
216
+ }
217
+ async setup(packageName, force = false) {
218
+ const [error, result] = await catchError3(this._setupInternal(packageName, force));
219
+ if (error) {
220
+ return { success: false, error: error.message };
221
+ }
222
+ return result;
223
+ }
224
+ async _setupInternal(packageName, force) {
225
+ const fs = getFileSystem3();
226
+ let pythonPath;
227
+ let version;
228
+ if (!force) {
229
+ logger3.debug("Checking cache...");
230
+ const cached = await this.loadCache();
231
+ if (cached && cached.uipathExePath && await fs.exists(cached.uipathExePath)) {
232
+ pythonPath = cached.pythonPath;
233
+ version = cached.version;
234
+ this.uipathExePath = cached.uipathExePath;
235
+ logger3.info(`Using cached uipath executable: ${this.uipathExePath}`);
236
+ await this.saveCache({
237
+ pythonPath,
238
+ version,
239
+ lastValidated: new Date().toISOString(),
240
+ packageName,
241
+ uipathExePath: this.uipathExePath
242
+ });
243
+ return {
244
+ success: true,
245
+ pythonPath,
246
+ pythonVersion: version,
247
+ packageInstalled: true
248
+ };
249
+ } else if (cached) {
250
+ logger3.warn("Cached Python path no longer exists, re-detecting...");
251
+ }
252
+ }
253
+ logger3.info("Checking Python...");
254
+ const detection = await this.detectPython();
255
+ if (!detection.success || !detection.pythonPath || !detection.version) {
256
+ return {
257
+ success: false,
258
+ error: detection.error || "Failed to detect Python"
259
+ };
260
+ }
261
+ pythonPath = detection.pythonPath;
262
+ version = detection.version;
263
+ this.uipathExePath = detection.uipathExePath;
264
+ if (!this.uipathExePath) {
265
+ return {
266
+ success: false,
267
+ pythonPath,
268
+ pythonVersion: version,
269
+ packageInstalled: false,
270
+ error: `Package '${packageName}' is not installed.
271
+
272
+ To install the package, run:
273
+ ${pythonPath} -m pip install ${packageName}`
274
+ };
275
+ }
276
+ await this.saveCache({
277
+ pythonPath,
278
+ version,
279
+ lastValidated: new Date().toISOString(),
280
+ packageName,
281
+ uipathExePath: this.uipathExePath
282
+ });
283
+ return {
284
+ success: true,
285
+ pythonPath,
286
+ pythonVersion: version,
287
+ packageInstalled: true
288
+ };
289
+ }
290
+ async detectPython() {
291
+ const pythonCommands = this.getDefaultPythonPaths();
292
+ const checkedVersions = [];
293
+ const searchedCommands = [];
294
+ for (const { command, args } of pythonCommands) {
295
+ const result = await this.checkPythonCommand(command, args, checkedVersions, searchedCommands);
296
+ if (result)
297
+ return result;
298
+ }
299
+ return {
300
+ success: false,
301
+ error: this.buildNotFoundError(checkedVersions, searchedCommands)
302
+ };
303
+ }
304
+ async checkPythonCommand(command, args, checkedVersions, searchedCommands) {
305
+ const fs = getFileSystem3();
306
+ const commandStr = args.length > 0 ? `${command} ${args.join(" ")}` : command;
307
+ searchedCommands.push(commandStr);
308
+ logger3.debug(`Checking Python command: ${commandStr}`);
309
+ const versionArgs = [...args, "--version"];
310
+ const versionProc = spawn2(command, versionArgs, {
311
+ stdio: ["ignore", "pipe", "pipe"]
312
+ });
313
+ const stdoutChunks = [];
314
+ const stderrChunks = [];
315
+ versionProc.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
316
+ versionProc.stderr.on("data", (chunk) => stderrChunks.push(chunk));
317
+ const [versionError, exitCode] = await catchError3(new Promise((resolve, reject) => {
318
+ versionProc.on("exit", (code) => resolve(code ?? 1));
319
+ versionProc.on("error", (error) => reject(error));
320
+ }));
321
+ if (versionError) {
322
+ logger3.debug(`Failed to check ${commandStr}: ${versionError}`);
323
+ return null;
324
+ }
325
+ const output = Buffer.concat(stdoutChunks).toString("utf-8");
326
+ const stderr = Buffer.concat(stderrChunks).toString("utf-8");
327
+ logger3.debug(`${output.trim()}`);
328
+ if (stderr.trim()) {
329
+ logger3.debug(`stderr: ${stderr.trim()}`);
330
+ }
331
+ if (exitCode !== 0)
332
+ return null;
333
+ const version = output.trim().replace("Python ", "");
334
+ const majorMinor = version.match(/^(\d+\.\d+)/)?.[1];
335
+ if (majorMinor) {
336
+ checkedVersions.push(`${version} at ${commandStr}`);
337
+ }
338
+ if (!majorMinor || !this.config.allowedVersions.includes(majorMinor)) {
339
+ logger3.info(`Python ${version} at ${commandStr} is not in allowed versions`);
340
+ return null;
341
+ }
342
+ logger3.info(`Found valid Python: ${commandStr} - ${version}`);
343
+ const uipathExePath = await this.findUipathExe(fs, command, args);
344
+ return {
345
+ success: true,
346
+ pythonPath: commandStr,
347
+ version,
348
+ uipathExePath
349
+ };
350
+ }
351
+ async findUipathExe(fs, command, args) {
352
+ const isWindows = platform() === "win32";
353
+ const candidatePaths = [];
354
+ const virtualEnv = process.env.VIRTUAL_ENV;
355
+ if (virtualEnv) {
356
+ candidatePaths.push(isWindows ? fs.path.join(virtualEnv, "Scripts", "uipath.exe") : fs.path.join(virtualEnv, "bin", "uipath"));
357
+ }
358
+ const prefixArgs = [...args, "-c", "import sys; print(sys.prefix)"];
359
+ const prefixProc = spawn2(command, prefixArgs, {
360
+ stdio: ["ignore", "pipe", "pipe"]
361
+ });
362
+ const prefixChunks = [];
363
+ prefixProc.stdout.on("data", (chunk) => prefixChunks.push(chunk));
364
+ const [prefixError, prefixExitCode] = await catchError3(new Promise((resolve, reject) => {
365
+ prefixProc.on("exit", (code) => resolve(code ?? 1));
366
+ prefixProc.on("error", (error) => reject(error));
367
+ }));
368
+ if (prefixError) {
369
+ logger3.debug(`Failed to locate uipath executable: ${prefixError}`);
370
+ } else if (prefixExitCode === 0) {
371
+ const prefix = Buffer.concat(prefixChunks).toString("utf-8").trim();
372
+ candidatePaths.push(isWindows ? fs.path.join(prefix, "Scripts", "uipath.exe") : fs.path.join(prefix, "bin", "uipath"));
373
+ }
374
+ for (const candidate of candidatePaths) {
375
+ logger3.debug(`Checking for uipath executable at: ${candidate}`);
376
+ if (await fs.exists(candidate)) {
377
+ logger3.info(`Found uipath executable at: ${candidate}`);
378
+ return candidate;
379
+ }
380
+ }
381
+ logger3.error(`uipath executable not found. Checked: ${candidatePaths.join(", ")}`);
382
+ return;
383
+ }
384
+ buildNotFoundError(checkedVersions, searchedCommands) {
385
+ let msg = `No compatible Python installation found.
386
+
387
+ `;
388
+ msg += `Required versions: ${this.config.allowedVersions.join(", ")}
389
+ `;
390
+ if (checkedVersions.length > 0) {
391
+ msg += `
392
+ Found Python installations (incompatible versions):
393
+ `;
394
+ for (const ver of checkedVersions) {
395
+ msg += ` - ${ver}
396
+ `;
397
+ }
398
+ } else {
399
+ msg += `
400
+ No Python installations found in PATH or default locations.
401
+ `;
402
+ }
403
+ msg += `
404
+ Searched commands (${searchedCommands.length} commands):
405
+ `;
406
+ const uniqueCommands = [...new Set(searchedCommands)].slice(0, 10);
407
+ for (const cmd of uniqueCommands) {
408
+ msg += ` - ${cmd}
409
+ `;
410
+ }
411
+ if (searchedCommands.length > 10) {
412
+ msg += ` ... and ${searchedCommands.length - 10} more
413
+ `;
414
+ }
415
+ msg += `
416
+ Please install one of the required Python versions:
417
+ `;
418
+ msg += ` - Download from: https://www.python.org/downloads/
419
+ `;
420
+ msg += ` - Or use environment variable: PYTHON_TOOL_PYTHON_VERSIONS=<versions>
421
+ `;
422
+ return msg;
423
+ }
424
+ getDefaultPythonPaths() {
425
+ const paths = [];
426
+ const isWindows = platform() === "win32";
427
+ if (isWindows) {
428
+ paths.push({ command: "python", args: [] });
429
+ paths.push({ command: "python3", args: [] });
430
+ for (const version of this.config.allowedVersions) {
431
+ paths.push({ command: `python${version}`, args: [] });
432
+ }
433
+ for (const version of this.config.allowedVersions) {
434
+ paths.push({ command: "py", args: [`-${version}`] });
435
+ }
436
+ paths.push({ command: "py", args: [] });
437
+ } else {
438
+ for (const version of this.config.allowedVersions) {
439
+ paths.push({ command: `python${version}`, args: [] });
440
+ }
441
+ paths.push({ command: "python3", args: [] });
442
+ paths.push({ command: "python", args: [] });
443
+ }
444
+ return paths;
445
+ }
446
+ async loadCache() {
447
+ return readCache(this.cacheFile);
448
+ }
449
+ async saveCache(cache) {
450
+ const fs = getFileSystem3();
451
+ const dir = fs.path.dirname(this.cacheFile);
452
+ const [mkdirError] = await catchError3(fs.mkdir(dir, { recursive: true }));
453
+ if (mkdirError) {
454
+ logger3.warn(`Failed to create cache directory: ${mkdirError}`);
455
+ return;
456
+ }
457
+ const [writeError] = await catchError3(fs.writeFile(this.cacheFile, JSON.stringify(cache, null, 2)));
458
+ if (writeError) {
459
+ logger3.warn(`Failed to save cache: ${writeError}`);
460
+ return;
461
+ }
462
+ logger3.info(`Cache saved to ${this.cacheFile}`);
463
+ }
464
+ }
465
+ // src/register.ts
466
+ import {
467
+ logger as logger4,
468
+ OutputFormatter as OutputFormatter2,
469
+ processContext as processContext2,
470
+ RESULTS as RESULTS2
471
+ } from "@uipath/common";
472
+ import { getFileSystem as getFileSystem4 } from "@uipath/filesystem";
473
+ function createSetupCommand(config) {
474
+ return (program) => {
475
+ program.command("setup").description("Detect Python installation and verify package is installed").option("--force", "Force re-detection of Python even if cached", false).trackedAction(processContext2, config.telemetryEvent, async (options) => {
476
+ const packageName = config.packageName || getPackageName();
477
+ const allowedVersions = getAllowedPythonVersions();
478
+ if (allowedVersions.length === 0) {
479
+ OutputFormatter2.error({
480
+ Result: RESULTS2.Failure,
481
+ Message: "Invalid configuration. Allowed Python list misconfigured.",
482
+ Instructions: "Check env variable PYTHON_TOOL_PYTHON_VERSIONS"
483
+ });
484
+ processContext2.exit(1);
485
+ return;
486
+ }
487
+ const fs = getFileSystem4();
488
+ const venvPath = fs.path.join(fs.env.cwd(), ".venv");
489
+ if (await fs.exists(venvPath) && !process.env.VIRTUAL_ENV) {
490
+ OutputFormatter2.error({
491
+ Result: RESULTS2.Failure,
492
+ Message: "Found .venv in current directory but no virtual environment is activated.",
493
+ Instructions: process.platform === "win32" ? "Run '.venv\\Scripts\\activate' first, then re-run setup." : "Run 'source .venv/bin/activate' first, then re-run setup."
494
+ });
495
+ processContext2.exit(1);
496
+ return;
497
+ }
498
+ logger4.info(`
499
+ Searching for Python installations: ${allowedVersions}`);
500
+ const service = new PythonService({
501
+ allowedVersions,
502
+ packageName
503
+ });
504
+ const result = await service.setup(packageName, options.force);
505
+ if (!result.success) {
506
+ OutputFormatter2.error({
507
+ Result: RESULTS2.Failure,
508
+ Message: result.error || "Setup failed with no error.",
509
+ Instructions: result.instructions || ""
510
+ });
511
+ processContext2.exit(1);
512
+ return;
513
+ }
514
+ OutputFormatter2.success({
515
+ Result: RESULTS2.Success,
516
+ Code: config.successCode,
517
+ Data: {
518
+ PythonPath: result.pythonPath,
519
+ Package: packageName,
520
+ PackageInstalled: result.packageInstalled ? "Yes" : "No",
521
+ PackageVersion: result.packageVersion ?? "N/A"
522
+ }
523
+ });
524
+ });
525
+ };
526
+ }
527
+ function createDefaultAction(config, executeCommand) {
528
+ return (program) => {
529
+ program.trackedAction(processContext2, config.defaultTelemetryEvent, async () => {
530
+ const userArgs = program.args.length > 0 ? program.args : [];
531
+ const extra = userArgs.length > 0 ? userArgs : ["--help"];
532
+ await executeCommand(["_", "_", "exec", ...extra], {});
533
+ });
534
+ };
535
+ }
536
+ function createHelpCommand(config, executeCommand) {
537
+ return (program) => {
538
+ program.command("help").description("Display help for the python tool").trackedAction(processContext2, config.helpTelemetryEvent, async () => {
539
+ await executeCommand(["_", "_", "exec", "--help"], {});
540
+ });
541
+ };
542
+ }
543
+ function createCommandForwarder(executeCommand) {
544
+ return (program) => {
545
+ program.on("command:*", async (operands) => {
546
+ const unknownCommand = operands[0];
547
+ if (!program.commands.some((c) => c.name() === unknownCommand)) {
548
+ await executeCommand(["_", "_", "exec", ...operands], {});
549
+ }
550
+ });
551
+ };
552
+ }
553
+ export {
554
+ readCache,
555
+ processCommandArgs,
556
+ getPackageName,
557
+ getCacheFileName,
558
+ getAllowedPythonVersions,
559
+ createSetupCommand,
560
+ createHelpCommand,
561
+ createExecuteCommand,
562
+ createDefaultAction,
563
+ createCommandForwarder,
564
+ PythonService
565
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@uipath/uipath-python-bridge",
3
+ "version": "0.9.0",
4
+ "description": "Shared Python detection, caching, and CLI bridge for UiPath Python SDK tools.",
5
+ "keywords": [
6
+ "uip",
7
+ "python",
8
+ "bridge"
9
+ ],
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "exports": {
13
+ ".": "./dist/index.js"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/UiPath/cli.git",
21
+ "directory": "packages/uipath-python-bridge"
22
+ },
23
+ "publishConfig": {
24
+ "registry": "https://registry.npmjs.org/"
25
+ },
26
+ "scripts": {
27
+ "build": "bun build ./src/index.ts --outdir dist --format esm --target node --external commander --external @uipath/common --external @uipath/auth --external @uipath/filesystem",
28
+ "test": "vitest run",
29
+ "test:coverage": "vitest run --coverage",
30
+ "lint": "biome check .",
31
+ "lint:fix": "biome check --write ."
32
+ },
33
+ "devDependencies": {
34
+ "@uipath/auth": "0.9.0",
35
+ "@uipath/common": "0.9.0",
36
+ "@uipath/filesystem": "0.9.0",
37
+ "@types/bun": "^1.3.9",
38
+ "commander": "^14.0.3",
39
+ "typescript": "^5"
40
+ },
41
+ "gitHead": "3f1b4d8e9f910be81e4cab956537f21dbd5d63ac"
42
+ }