@uipath/packager-tool-workflowcompiler 1.199.0-preview.99 → 1.199.1-preview.119

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
@@ -656,6 +656,30 @@ import {
656
656
  translate as translate6
657
657
  } from "@uipath/solutionpackager-tool-core";
658
658
 
659
+ // src/workflow-compiler-config.ts
660
+ var DEFAULT_WORKFLOW_COMPILER_VERSION = "26.0.198-alpha.24031";
661
+ var DEFAULT_DOTNET_PATH = "dotnet";
662
+ var workflowCompilerConfig = {
663
+ workflowCompilerPath: undefined,
664
+ workflowCompilerVersion: DEFAULT_WORKFLOW_COMPILER_VERSION,
665
+ dotnetPath: DEFAULT_DOTNET_PATH,
666
+ dotnetEnv: undefined
667
+ };
668
+ function setupWorkflowCompiler(options) {
669
+ if (options.compilerPath !== undefined) {
670
+ workflowCompilerConfig.workflowCompilerPath = options.compilerPath;
671
+ }
672
+ if (options.version !== undefined) {
673
+ workflowCompilerConfig.workflowCompilerVersion = options.version;
674
+ }
675
+ if (options.dotnetPath !== undefined) {
676
+ workflowCompilerConfig.dotnetPath = options.dotnetPath;
677
+ }
678
+ if (options.dotnetEnv !== undefined) {
679
+ workflowCompilerConfig.dotnetEnv = options.dotnetEnv;
680
+ }
681
+ }
682
+
659
683
  // ../packager-orchestrator-client/dist/index.js
660
684
  import { I18nManager as I18nManager2 } from "@uipath/solutionpackager-tool-core";
661
685
  import {
@@ -960,29 +984,6 @@ import {
960
984
  translate as translate5
961
985
  } from "@uipath/solutionpackager-tool-core";
962
986
 
963
- // src/workflow-compiler-config.ts
964
- var DEFAULT_WORKFLOW_COMPILER_VERSION = "26.0.198-alpha.24031";
965
- var workflowCompilerConfig = {
966
- workflowCompilerPath: undefined,
967
- workflowCompilerVersion: DEFAULT_WORKFLOW_COMPILER_VERSION,
968
- dotnetPath: "dotnet",
969
- dotnetEnv: undefined
970
- };
971
- function setupWorkflowCompiler(options) {
972
- if (options.compilerPath !== undefined) {
973
- workflowCompilerConfig.workflowCompilerPath = options.compilerPath;
974
- }
975
- if (options.version !== undefined) {
976
- workflowCompilerConfig.workflowCompilerVersion = options.version;
977
- }
978
- if (options.dotnetPath !== undefined) {
979
- workflowCompilerConfig.dotnetPath = options.dotnetPath;
980
- }
981
- if (options.dotnetEnv !== undefined) {
982
- workflowCompilerConfig.dotnetEnv = options.dotnetEnv;
983
- }
984
- }
985
-
986
987
  // src/workflow-compiler-path-resolver.ts
987
988
  import { execFileSync } from "node:child_process";
988
989
  import { homedir, platform } from "node:os";
@@ -1156,6 +1157,7 @@ class WorkflowCompilerExecutor {
1156
1157
  return new Promise((resolve) => {
1157
1158
  let result = null;
1158
1159
  const fallbackErrors = [];
1160
+ const analyzerFindings = [];
1159
1161
  const childProcess = this.spawnProcess(executable, commandArgs, workflowCompilerConfig.dotnetEnv);
1160
1162
  let stdoutEnded = false;
1161
1163
  let stderrEnded = false;
@@ -1171,7 +1173,7 @@ class WorkflowCompilerExecutor {
1171
1173
  errorCode: result.errorCode
1172
1174
  }));
1173
1175
  const toolResult = new ToolResult(result.errorCode, result.message, result.outputPackages);
1174
- toolResult.details = getAdditionalResultDetails(result);
1176
+ toolResult.details = withAnalyzerFindings(getAdditionalResultDetails(result), analyzerFindings);
1175
1177
  resolve(toolResult);
1176
1178
  } else {
1177
1179
  const exitCode = childProcess.exitCode ?? -1;
@@ -1201,8 +1203,8 @@ class WorkflowCompilerExecutor {
1201
1203
  checkComplete();
1202
1204
  }
1203
1205
  };
1204
- this.setupStdoutHandling(childProcess, streamCompletion, (r) => result = r);
1205
- this.setupStderrHandling(childProcess, streamCompletion, fallbackErrors);
1206
+ this.setupStdoutHandling(childProcess, streamCompletion, (r) => result = r, analyzerFindings);
1207
+ this.setupStderrHandling(childProcess, streamCompletion, fallbackErrors, analyzerFindings);
1206
1208
  this.setupProcessEventHandlers(childProcess, streamCompletion, resolve);
1207
1209
  this.setupCancellationHandler(childProcess, cancellationToken, resolve);
1208
1210
  });
@@ -1224,7 +1226,7 @@ class WorkflowCompilerExecutor {
1224
1226
  command: fullCommand.join(" ")
1225
1227
  }));
1226
1228
  }
1227
- setupStdoutHandling(childProcess, streamCompletion, onResult) {
1229
+ setupStdoutHandling(childProcess, streamCompletion, onResult, analyzerFindings) {
1228
1230
  if (!childProcess.stdout) {
1229
1231
  streamCompletion.markStdoutEnded();
1230
1232
  return;
@@ -1238,24 +1240,29 @@ class WorkflowCompilerExecutor {
1238
1240
  for (const line of lines) {
1239
1241
  if (!line.trim())
1240
1242
  continue;
1241
- this.processOutputLine(line, onResult);
1243
+ this.processOutputLine(line, onResult, analyzerFindings);
1242
1244
  }
1243
1245
  });
1244
1246
  childProcess.stdout.on("end", () => {
1245
1247
  if (buffer.trim()) {
1246
- this.processOutputLine(buffer, onResult);
1248
+ this.processOutputLine(buffer, onResult, analyzerFindings);
1247
1249
  }
1248
1250
  streamCompletion.markStdoutEnded();
1249
1251
  });
1250
1252
  }
1251
- processOutputLine(line, onResult) {
1253
+ processOutputLine(line, onResult, analyzerFindings) {
1252
1254
  const entry = this.parseOutputEntry(line);
1253
1255
  if (!entry)
1254
1256
  return;
1255
1257
  if (entry.type === "Result") {
1256
1258
  onResult(entry);
1257
1259
  } else if (entry.type === "Log") {
1258
- this.logMessage(entry);
1260
+ const log = entry;
1261
+ const finding = toAnalyzerFinding(log);
1262
+ if (finding) {
1263
+ analyzerFindings.push(finding);
1264
+ }
1265
+ this.logMessage(log);
1259
1266
  } else if (entry.type === "Progress") {
1260
1267
  this.logProgress(entry);
1261
1268
  }
@@ -1278,7 +1285,7 @@ class WorkflowCompilerExecutor {
1278
1285
  const separator = percent && progress.message ? " - " : "";
1279
1286
  this.logger.progress(`${percent}${separator}${progress.message ?? ""}`);
1280
1287
  }
1281
- setupStderrHandling(childProcess, streamCompletion, fallbackErrors) {
1288
+ setupStderrHandling(childProcess, streamCompletion, fallbackErrors, analyzerFindings) {
1282
1289
  if (!childProcess.stderr) {
1283
1290
  streamCompletion.markStderrEnded();
1284
1291
  return;
@@ -1292,20 +1299,25 @@ class WorkflowCompilerExecutor {
1292
1299
  for (const line of lines) {
1293
1300
  if (!line.trim())
1294
1301
  continue;
1295
- this.processErrorLine(line, fallbackErrors);
1302
+ this.processErrorLine(line, fallbackErrors, analyzerFindings);
1296
1303
  }
1297
1304
  });
1298
1305
  childProcess.stderr.on("end", () => {
1299
1306
  if (buffer.trim()) {
1300
- this.processErrorLine(buffer, fallbackErrors);
1307
+ this.processErrorLine(buffer, fallbackErrors, analyzerFindings);
1301
1308
  }
1302
1309
  streamCompletion.markStderrEnded();
1303
1310
  });
1304
1311
  }
1305
- processErrorLine(line, fallbackErrors) {
1312
+ processErrorLine(line, fallbackErrors, analyzerFindings) {
1306
1313
  const entry = this.parseOutputEntry(line);
1307
1314
  if (entry && entry.type === "Log") {
1308
- this.logger.error(entry.message);
1315
+ const log = entry;
1316
+ const finding = toAnalyzerFinding(log);
1317
+ if (finding) {
1318
+ analyzerFindings.push(finding);
1319
+ }
1320
+ this.logger.error(log.message);
1309
1321
  } else {
1310
1322
  fallbackErrors.push(line);
1311
1323
  this.logger.error(line);
@@ -1369,6 +1381,54 @@ function getAdditionalResultDetails(result) {
1369
1381
  }
1370
1382
  return Object.keys(details).length > 0 ? details : undefined;
1371
1383
  }
1384
+ var ANALYZER_LOG_SOURCE = "Analyzer";
1385
+ function withAnalyzerFindings(details, findings) {
1386
+ const fromEnvelope = details?.findings;
1387
+ if (findings.length === 0 || Array.isArray(fromEnvelope) && fromEnvelope.length > 0) {
1388
+ return details;
1389
+ }
1390
+ return { ...details, findings };
1391
+ }
1392
+ function toAnalyzerFinding(log) {
1393
+ if (log.source !== ANALYZER_LOG_SOURCE) {
1394
+ return;
1395
+ }
1396
+ const message = parseAnalyzerMessage(log.data) ?? {};
1397
+ const activityId = message.ActivityId;
1398
+ const item = message.Item;
1399
+ return {
1400
+ ...message,
1401
+ ErrorCode: message.ErrorCode ?? log.code,
1402
+ Description: message.Description ?? log.message,
1403
+ FilePath: message.FilePath ?? log.filePath,
1404
+ ErrorSeverity: message.ErrorSeverity ?? toErrorSeverity(log.logLevel),
1405
+ ActivityIdRef: activityId?.IdRef ?? log.id,
1406
+ AnalyzerItemName: item?.Name,
1407
+ AnalyzerItemType: item?.Type
1408
+ };
1409
+ }
1410
+ function toErrorSeverity(logLevel) {
1411
+ switch (logLevel) {
1412
+ case "Debug":
1413
+ case "Trace":
1414
+ return "Verbose";
1415
+ case "Information":
1416
+ return "Info";
1417
+ default:
1418
+ return logLevel;
1419
+ }
1420
+ }
1421
+ function parseAnalyzerMessage(data) {
1422
+ if (!data) {
1423
+ return;
1424
+ }
1425
+ try {
1426
+ const parsed = JSON.parse(data);
1427
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : undefined;
1428
+ } catch {
1429
+ return;
1430
+ }
1431
+ }
1372
1432
 
1373
1433
  // src/workflow-compiler-tool.ts
1374
1434
  class WorkflowCompilerTool extends ProjectTool {
@@ -1637,11 +1697,14 @@ class WorkflowCompilerToolFactory {
1637
1697
  ProjectTypes.WebApp
1638
1698
  ];
1639
1699
  async createAsync(logger, fileSystem, context) {
1640
- if (!this.isDotnetAvailable()) {
1700
+ if (!this.isPinnedByCaller() && !this.isDotnetAvailable()) {
1641
1701
  throw new Error(translate6.t("toolWorkflowcompiler.errors.dotnetNotAvailable"));
1642
1702
  }
1643
1703
  return new WorkflowCompilerTool(fileSystem, logger, context);
1644
1704
  }
1705
+ isPinnedByCaller() {
1706
+ return workflowCompilerConfig.workflowCompilerPath !== undefined && workflowCompilerConfig.dotnetPath !== DEFAULT_DOTNET_PATH;
1707
+ }
1645
1708
  isDotnetAvailable() {
1646
1709
  if (WorkflowCompilerToolFactory.cachedDotnetAvailable !== undefined) {
1647
1710
  return WorkflowCompilerToolFactory.cachedDotnetAvailable;
@@ -1662,4 +1725,4 @@ export {
1662
1725
  WorkflowCompilerToolFactory
1663
1726
  };
1664
1727
 
1665
- //# debugId=DF8E70BC8F5CC6D964756E2164756E21
1728
+ //# debugId=9E5F0B597C7A3E6E64756E2164756E21
@@ -15,12 +15,18 @@ export interface IOutputMessage {
15
15
  inputId?: string;
16
16
  }
17
17
  /**
18
- * Log message from workflow compiler output
18
+ * Log message from workflow compiler output. Analyzer findings are reported only here.
19
19
  */
20
20
  export interface IOutputLog extends IOutputMessage {
21
21
  type: OutputMessageType.Log;
22
22
  message: string;
23
- logLevel: "Information" | "Warning" | "Error";
23
+ logLevel: "Trace" | "Debug" | "Information" | "Warning" | "Error" | "None";
24
+ source?: string;
25
+ code?: string;
26
+ filePath?: string;
27
+ id?: string;
28
+ /** Serialized `AnalyzerMessage`. */
29
+ data?: string;
24
30
  }
25
31
  /**
26
32
  * Progress update from workflow compiler output
@@ -1,4 +1,6 @@
1
1
  export declare const DEFAULT_WORKFLOW_COMPILER_VERSION = "26.0.198-alpha.24031";
2
+ /** The dotnet host used when no consumer pins one: whatever `dotnet` PATH resolves to. */
3
+ export declare const DEFAULT_DOTNET_PATH = "dotnet";
2
4
  export declare const workflowCompilerConfig: {
3
5
  workflowCompilerPath: string | undefined;
4
6
  workflowCompilerVersion: string;
@@ -12,5 +12,17 @@ export declare class WorkflowCompilerToolFactory implements IProjectToolFactory
12
12
  private static cachedDotnetAvailable;
13
13
  readonly supportedTypes: readonly ProjectType[];
14
14
  createAsync(logger: IToolLogger, fileSystem: IFileSystem, context?: ProjectOperationContext): Promise<ProjectTool>;
15
+ /**
16
+ * True when the caller has supplied both the compiler and the dotnet host to
17
+ * run it with — i.e. it resolved its own .NET and neither the NuGet-restore
18
+ * fallback nor a machine-wide install is involved.
19
+ *
20
+ * The preflight below asks PATH for an SDK. A pinned host is typically a
21
+ * runtime-only bundle (Studio/Robot ship the runtime, never the SDK), which
22
+ * cannot answer `dotnet --version` at all — that is an SDK verb. Probing it
23
+ * can therefore only reject a configuration that works, so a caller that has
24
+ * pinned both is trusted and the tool is created unconditionally.
25
+ */
26
+ private isPinnedByCaller;
15
27
  private isDotnetAvailable;
16
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/packager-tool-workflowcompiler",
3
- "version": "1.199.0-preview.99",
3
+ "version": "1.199.1-preview.119",
4
4
  "description": "UiPath Workflow Compiler tool implementation",
5
5
  "type": "module",
6
6
  "exports": {
@@ -28,5 +28,5 @@
28
28
  "@uipath/solutionpackager-tool-core": "1.199.0"
29
29
  },
30
30
  "dependencies": {},
31
- "gitHead": "6ba217cddceb86e3fa39ed82e49c5062878a85c6"
31
+ "gitHead": "9237653cf731fb275714c8ee5aab5dc057424b42"
32
32
  }
@@ -17,12 +17,18 @@ export interface IOutputMessage {
17
17
  }
18
18
 
19
19
  /**
20
- * Log message from workflow compiler output
20
+ * Log message from workflow compiler output. Analyzer findings are reported only here.
21
21
  */
22
22
  export interface IOutputLog extends IOutputMessage {
23
23
  type: OutputMessageType.Log;
24
24
  message: string;
25
- logLevel: "Information" | "Warning" | "Error";
25
+ logLevel: "Trace" | "Debug" | "Information" | "Warning" | "Error" | "None";
26
+ source?: string;
27
+ code?: string;
28
+ filePath?: string;
29
+ id?: string;
30
+ /** Serialized `AnalyzerMessage`. */
31
+ data?: string;
26
32
  }
27
33
 
28
34
  /**
@@ -1,12 +1,15 @@
1
1
  export const DEFAULT_WORKFLOW_COMPILER_VERSION = "26.0.198-alpha.24031";
2
2
 
3
+ /** The dotnet host used when no consumer pins one: whatever `dotnet` PATH resolves to. */
4
+ export const DEFAULT_DOTNET_PATH = "dotnet";
5
+
3
6
  export const workflowCompilerConfig = {
4
7
  workflowCompilerPath: undefined as string | undefined,
5
8
  workflowCompilerVersion: DEFAULT_WORKFLOW_COMPILER_VERSION as string,
6
9
  // The dotnet host used to launch `UiPath.WorkflowCompiler.dll`. Defaults to `dotnet` on PATH.
7
10
  // Consumers that ship a bundled runtime (e.g. rpa-tool resolving Robot/Studio's .NET) point this
8
11
  // at the bundled muxer so the compiler runs under that runtime instead of a machine-wide install.
9
- dotnetPath: "dotnet" as string,
12
+ dotnetPath: DEFAULT_DOTNET_PATH as string,
10
13
  // Extra environment variables for the compiler process (e.g. DOTNET_ROOT / DOTNET_MULTILEVEL_LOOKUP).
11
14
  // Merged over the inherited process env. Undefined means inherit the parent env unchanged.
12
15
  dotnetEnv: undefined as Record<string, string> | undefined,
@@ -82,6 +82,7 @@ export class WorkflowCompilerExecutor {
82
82
  return new Promise((resolve) => {
83
83
  let result: IOutputResult | null = null;
84
84
  const fallbackErrors: string[] = [];
85
+ const analyzerFindings: Record<string, unknown>[] = [];
85
86
 
86
87
  const childProcess = this.spawnProcess(
87
88
  executable,
@@ -115,7 +116,10 @@ export class WorkflowCompilerExecutor {
115
116
  result.message,
116
117
  result.outputPackages,
117
118
  );
118
- toolResult.details = getAdditionalResultDetails(result);
119
+ toolResult.details = withAnalyzerFindings(
120
+ getAdditionalResultDetails(result),
121
+ analyzerFindings,
122
+ );
119
123
  resolve(toolResult);
120
124
  } else {
121
125
  const exitCode = childProcess.exitCode ?? -1;
@@ -163,11 +167,13 @@ export class WorkflowCompilerExecutor {
163
167
  childProcess,
164
168
  streamCompletion,
165
169
  (r) => (result = r),
170
+ analyzerFindings,
166
171
  );
167
172
  this.setupStderrHandling(
168
173
  childProcess,
169
174
  streamCompletion,
170
175
  fallbackErrors,
176
+ analyzerFindings,
171
177
  );
172
178
  this.setupProcessEventHandlers(
173
179
  childProcess,
@@ -219,6 +225,7 @@ export class WorkflowCompilerExecutor {
219
225
  childProcess: ChildProcess,
220
226
  streamCompletion: StreamCompletion,
221
227
  onResult: (result: IOutputResult) => void,
228
+ analyzerFindings: Record<string, unknown>[],
222
229
  ): void {
223
230
  if (!childProcess.stdout) {
224
231
  streamCompletion.markStdoutEnded();
@@ -233,13 +240,13 @@ export class WorkflowCompilerExecutor {
233
240
  buffer = lines.pop()!;
234
241
  for (const line of lines) {
235
242
  if (!line.trim()) continue;
236
- this.processOutputLine(line, onResult);
243
+ this.processOutputLine(line, onResult, analyzerFindings);
237
244
  }
238
245
  });
239
246
 
240
247
  childProcess.stdout.on("end", () => {
241
248
  if (buffer.trim()) {
242
- this.processOutputLine(buffer, onResult);
249
+ this.processOutputLine(buffer, onResult, analyzerFindings);
243
250
  }
244
251
  streamCompletion.markStdoutEnded();
245
252
  });
@@ -248,6 +255,7 @@ export class WorkflowCompilerExecutor {
248
255
  private processOutputLine(
249
256
  line: string,
250
257
  onResult: (result: IOutputResult) => void,
258
+ analyzerFindings: Record<string, unknown>[],
251
259
  ): void {
252
260
  const entry = this.parseOutputEntry(line);
253
261
  if (!entry) return;
@@ -255,7 +263,12 @@ export class WorkflowCompilerExecutor {
255
263
  if (entry.type === "Result") {
256
264
  onResult(entry as IOutputResult);
257
265
  } else if (entry.type === "Log") {
258
- this.logMessage(entry as IOutputLog);
266
+ const log = entry as IOutputLog;
267
+ const finding = toAnalyzerFinding(log);
268
+ if (finding) {
269
+ analyzerFindings.push(finding);
270
+ }
271
+ this.logMessage(log);
259
272
  } else if (entry.type === "Progress") {
260
273
  this.logProgress(entry as IOutputProgress);
261
274
  }
@@ -285,6 +298,7 @@ export class WorkflowCompilerExecutor {
285
298
  childProcess: ChildProcess,
286
299
  streamCompletion: StreamCompletion,
287
300
  fallbackErrors: string[],
301
+ analyzerFindings: Record<string, unknown>[],
288
302
  ): void {
289
303
  if (!childProcess.stderr) {
290
304
  streamCompletion.markStderrEnded();
@@ -298,23 +312,32 @@ export class WorkflowCompilerExecutor {
298
312
  buffer = lines.pop()!;
299
313
  for (const line of lines) {
300
314
  if (!line.trim()) continue;
301
- this.processErrorLine(line, fallbackErrors);
315
+ this.processErrorLine(line, fallbackErrors, analyzerFindings);
302
316
  }
303
317
  });
304
318
 
305
319
  childProcess.stderr.on("end", () => {
306
320
  if (buffer.trim()) {
307
- this.processErrorLine(buffer, fallbackErrors);
321
+ this.processErrorLine(buffer, fallbackErrors, analyzerFindings);
308
322
  }
309
323
  streamCompletion.markStderrEnded();
310
324
  });
311
325
  }
312
326
 
313
- private processErrorLine(line: string, fallbackErrors: string[]): void {
327
+ private processErrorLine(
328
+ line: string,
329
+ fallbackErrors: string[],
330
+ analyzerFindings: Record<string, unknown>[],
331
+ ): void {
314
332
  const entry = this.parseOutputEntry(line);
315
333
 
316
334
  if (entry && entry.type === "Log") {
317
- this.logger.error((entry as IOutputLog).message);
335
+ const log = entry as IOutputLog;
336
+ const finding = toAnalyzerFinding(log);
337
+ if (finding) {
338
+ analyzerFindings.push(finding);
339
+ }
340
+ this.logger.error(log.message);
318
341
  } else {
319
342
  fallbackErrors.push(line);
320
343
  this.logger.error(line);
@@ -434,3 +457,74 @@ function getAdditionalResultDetails(
434
457
 
435
458
  return Object.keys(details).length > 0 ? details : undefined;
436
459
  }
460
+
461
+ const ANALYZER_LOG_SOURCE = "Analyzer";
462
+
463
+ /** Only a *populated* envelope array wins — `CommandResult` defaults its lists to `[]`. */
464
+ function withAnalyzerFindings(
465
+ details: Record<string, unknown> | undefined,
466
+ findings: Record<string, unknown>[],
467
+ ): Record<string, unknown> | undefined {
468
+ const fromEnvelope = details?.findings;
469
+ if (
470
+ findings.length === 0 ||
471
+ (Array.isArray(fromEnvelope) && fromEnvelope.length > 0)
472
+ ) {
473
+ return details;
474
+ }
475
+ return { ...details, findings };
476
+ }
477
+
478
+ /** Flattened because consumers match flat keys only; the payload omits null members. */
479
+ function toAnalyzerFinding(
480
+ log: IOutputLog,
481
+ ): Record<string, unknown> | undefined {
482
+ if (log.source !== ANALYZER_LOG_SOURCE) {
483
+ return undefined;
484
+ }
485
+
486
+ const message = parseAnalyzerMessage(log.data) ?? {};
487
+ const activityId = message.ActivityId as { IdRef?: string } | undefined;
488
+ const item = message.Item as { Name?: string; Type?: string } | undefined;
489
+ return {
490
+ ...message,
491
+ ErrorCode: message.ErrorCode ?? log.code,
492
+ Description: message.Description ?? log.message,
493
+ FilePath: message.FilePath ?? log.filePath,
494
+ ErrorSeverity: message.ErrorSeverity ?? toErrorSeverity(log.logLevel),
495
+ ActivityIdRef: activityId?.IdRef ?? log.id,
496
+ AnalyzerItemName: item?.Name,
497
+ AnalyzerItemType: item?.Type,
498
+ };
499
+ }
500
+
501
+ /** Undo the compiler's `TraceLevel` → `LogLevel` mapping, so a consumer's lookup still matches. */
502
+ function toErrorSeverity(logLevel: IOutputLog["logLevel"]): string {
503
+ switch (logLevel) {
504
+ case "Debug":
505
+ case "Trace":
506
+ return "Verbose";
507
+ case "Information":
508
+ return "Info";
509
+ default:
510
+ return logLevel;
511
+ }
512
+ }
513
+
514
+ function parseAnalyzerMessage(
515
+ data: string | undefined,
516
+ ): Record<string, unknown> | undefined {
517
+ if (!data) {
518
+ return undefined;
519
+ }
520
+ try {
521
+ const parsed: unknown = JSON.parse(data);
522
+ return typeof parsed === "object" &&
523
+ parsed !== null &&
524
+ !Array.isArray(parsed)
525
+ ? (parsed as Record<string, unknown>)
526
+ : undefined;
527
+ } catch {
528
+ return undefined;
529
+ }
530
+ }
@@ -9,6 +9,10 @@ import {
9
9
  ProjectTypes,
10
10
  translate,
11
11
  } from "@uipath/solutionpackager-tool-core";
12
+ import {
13
+ DEFAULT_DOTNET_PATH,
14
+ workflowCompilerConfig,
15
+ } from "./workflow-compiler-config.js";
12
16
  import { WorkflowCompilerTool } from "./workflow-compiler-tool.js";
13
17
 
14
18
  /**
@@ -35,7 +39,7 @@ export class WorkflowCompilerToolFactory implements IProjectToolFactory {
35
39
  fileSystem: IFileSystem,
36
40
  context?: ProjectOperationContext,
37
41
  ): Promise<ProjectTool> {
38
- if (!this.isDotnetAvailable()) {
42
+ if (!this.isPinnedByCaller() && !this.isDotnetAvailable()) {
39
43
  throw new Error(
40
44
  translate.t("toolWorkflowcompiler.errors.dotnetNotAvailable"),
41
45
  );
@@ -43,6 +47,24 @@ export class WorkflowCompilerToolFactory implements IProjectToolFactory {
43
47
  return new WorkflowCompilerTool(fileSystem, logger, context);
44
48
  }
45
49
 
50
+ /**
51
+ * True when the caller has supplied both the compiler and the dotnet host to
52
+ * run it with — i.e. it resolved its own .NET and neither the NuGet-restore
53
+ * fallback nor a machine-wide install is involved.
54
+ *
55
+ * The preflight below asks PATH for an SDK. A pinned host is typically a
56
+ * runtime-only bundle (Studio/Robot ship the runtime, never the SDK), which
57
+ * cannot answer `dotnet --version` at all — that is an SDK verb. Probing it
58
+ * can therefore only reject a configuration that works, so a caller that has
59
+ * pinned both is trusted and the tool is created unconditionally.
60
+ */
61
+ private isPinnedByCaller(): boolean {
62
+ return (
63
+ workflowCompilerConfig.workflowCompilerPath !== undefined &&
64
+ workflowCompilerConfig.dotnetPath !== DEFAULT_DOTNET_PATH
65
+ );
66
+ }
67
+
46
68
  private isDotnetAvailable(): boolean {
47
69
  if (WorkflowCompilerToolFactory.cachedDotnetAvailable !== undefined) {
48
70
  return WorkflowCompilerToolFactory.cachedDotnetAvailable;