@uipath/solution-tool 1.203.0-preview.203 → 1.204.0-preview.206

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 (76) hide show
  1. package/README.md +2 -2
  2. package/dist/THIRD-PARTY-NOTICES.md +42 -4
  3. package/dist/deploy-delete-service-y9dwehmn.js +22 -0
  4. package/dist/deploy-status-service-nmhnnjmy.js +256 -0
  5. package/dist/deploy.d.ts +11 -4
  6. package/dist/deploy.js +19 -7
  7. package/dist/deployment-search-eb337bjh.js +49 -0
  8. package/dist/{embedded-file-reader-xxqe8vs8.js → embedded-file-reader-rf2g1kfj.js} +2 -2
  9. package/dist/feed-resolver-dmtnswcc.js +27 -0
  10. package/dist/feed-scope-failure-e2yaqfg2.js +18 -0
  11. package/dist/feed-session-sxga31vn.js +17 -0
  12. package/dist/index.js +27 -18
  13. package/dist/init.js +10 -7
  14. package/dist/{list-n0xd5rgn.js → list-rbjqgz6s.js} +9 -6
  15. package/dist/pack.js +14 -11
  16. package/dist/{packager-tool-vas0xg5h.js → packager-tool-2cntqvdv.js} +5 -3
  17. package/dist/{packager-tool-1haahq17.js → packager-tool-3enm2h28.js} +5 -5
  18. package/dist/{packager-tool-2syrt51a.js → packager-tool-3fv6zc86.js} +1062 -825
  19. package/dist/packager-tool-3fyq6wjs.js +5889 -0
  20. package/dist/{packager-tool-k4mskzww.js → packager-tool-5dzjsw5q.js} +3 -3
  21. package/dist/{packager-tool-0f0wt9vh.js → packager-tool-5fjp60dk.js} +3071 -2794
  22. package/dist/{packager-tool-x6gzyxnn.js → packager-tool-752zvh64.js} +756 -359
  23. package/dist/{packager-tool-bkwnetqn.js → packager-tool-83rzavkx.js} +383 -88
  24. package/dist/{packager-tool-7znqtw3f.js → packager-tool-9vvdgbay.js} +8 -6
  25. package/dist/packager-tool-b8pppqbb.js +172 -0
  26. package/dist/packager-tool-bqre28m1.js +43 -0
  27. package/dist/packager-tool-dh0m3ebf.js +173 -0
  28. package/dist/packager-tool-f5gq77m5.js +28 -0
  29. package/dist/{packager-tool-nzghfa48.js → packager-tool-fv7xyzg2.js} +550 -2
  30. package/dist/{packager-tool-3jrq7smt.js → packager-tool-gb35b4qs.js} +206 -289
  31. package/dist/{packager-tool-j2cqgegq.js → packager-tool-he7ak44z.js} +16 -74
  32. package/dist/packager-tool-myn57mc3.js +322 -0
  33. package/dist/{packager-tool-4rzjjv2p.js → packager-tool-n1nzj2b9.js} +1008 -647
  34. package/dist/packager-tool-n6yb6zp9.js +113 -0
  35. package/dist/{packager-tool-h4wn0y42.js → packager-tool-qgaqqq41.js} +320 -151
  36. package/dist/{packager-tool-resolver-fmjr60x8.js → packager-tool-resolver-2cbxyq6k.js} +6 -5
  37. package/dist/{packager-tool-ge4rvy7p.js → packager-tool-t12hj6pd.js} +1022 -1342
  38. package/dist/{packager-tool-znakt6yw.js → packager-tool-vh4ng74p.js} +8 -6
  39. package/dist/packager-tool-vmsxq1pc.js +104 -0
  40. package/dist/packager-tool-w6jr4638.js +166 -0
  41. package/dist/packager-tool-zf3929se.js +237 -0
  42. package/dist/packager-tool-zns6n8zp.js +837 -0
  43. package/dist/packager-tool-zw3036b8.js +37 -0
  44. package/dist/packager-tool.js +2 -2
  45. package/dist/prepare-solution-resources-p3gzdecy.js +25 -0
  46. package/dist/{project-contributions-cvttys34.js → project-contributions-txe8v6sm.js} +12 -9
  47. package/dist/publish.js +12 -7
  48. package/dist/resource.js +9 -6
  49. package/dist/services/activation.d.ts +17 -2
  50. package/dist/services/deploy-activate-service.d.ts +10 -0
  51. package/dist/services/deploy-delete-service.d.ts +82 -0
  52. package/dist/services/deploy-list-service.d.ts +15 -45
  53. package/dist/services/deploy-run-service.d.ts +36 -23
  54. package/dist/services/deploy-upgrade-service.d.ts +198 -39
  55. package/dist/services/deployment-feed-locator.d.ts +50 -12
  56. package/dist/services/deployment-search-client.d.ts +55 -0
  57. package/dist/services/deployment-search.d.ts +87 -34
  58. package/dist/services/deployment-state.d.ts +119 -0
  59. package/dist/services/feed-resolver.d.ts +31 -0
  60. package/dist/services/feed-session.d.ts +70 -0
  61. package/dist/services/folder-helper.d.ts +4 -27
  62. package/dist/services/http-status.d.ts +9 -0
  63. package/dist/services/incomplete-feed-sweep.d.ts +77 -0
  64. package/dist/services/legacy-deployment-search-v3.d.ts +23 -0
  65. package/dist/services/packages-list-service.d.ts +5 -0
  66. package/dist/services/pipeline-deploy-poll.d.ts +69 -0
  67. package/dist/services/publish-service.d.ts +14 -16
  68. package/dist/services/search-failure.d.ts +27 -0
  69. package/dist/templates/AGENTS.md +60 -20
  70. package/dist/tool.js +27 -18
  71. package/dist/utils/deployment-errors.d.ts +57 -0
  72. package/package.json +2 -2
  73. package/dist/packager-tool-07bqr90h.js +0 -51960
  74. package/dist/packager-tool-jz2wbfjz.js +0 -2275
  75. package/dist/prepare-solution-resources-wds3r8bq.js +0 -22
  76. package/dist/services/personal-workspace-deploy.d.ts +0 -49
@@ -1,7 +1,10 @@
1
1
  import {
2
2
  getStudioWebAuthWithOrganizationId,
3
3
  useStudioWebAuth
4
- } from "./packager-tool-1haahq17.js";
4
+ } from "./packager-tool-3enm2h28.js";
5
+ import {
6
+ resolveFeedScopeOrFailureAsync
7
+ } from "./packager-tool-zw3036b8.js";
5
8
  import {
6
9
  activateDeploymentAsync,
7
10
  deployRunAsync,
@@ -11,11 +14,11 @@ import {
11
14
  listPackagesAsync,
12
15
  uninstallDeploymentAsync,
13
16
  upgradeDeploymentAsync
14
- } from "./packager-tool-4rzjjv2p.js";
17
+ } from "./packager-tool-n1nzj2b9.js";
15
18
  import {
16
19
  SolutionInitError,
17
20
  solutionInitAsync
18
- } from "./packager-tool-vas0xg5h.js";
21
+ } from "./packager-tool-2cntqvdv.js";
19
22
  import {
20
23
  GOVERNANCE_OPTION_INSTRUCTIONS,
21
24
  PackCommandService,
@@ -28,32 +31,29 @@ import {
28
31
  readSolutionFileAsUint8Array,
29
32
  resolveSdkLogLevel,
30
33
  validateGovernanceOptions
31
- } from "./packager-tool-07bqr90h.js";
34
+ } from "./packager-tool-3fyq6wjs.js";
32
35
  import {
33
36
  prepareSolutionResources
34
- } from "./packager-tool-7znqtw3f.js";
37
+ } from "./packager-tool-9vvdgbay.js";
35
38
  import {
36
39
  ensurePackagerTools,
37
40
  isUnpackableProjectTypeError,
38
41
  toolVerbForProjectType
39
- } from "./packager-tool-k4mskzww.js";
42
+ } from "./packager-tool-5dzjsw5q.js";
40
43
  import {
41
44
  publishSolutionAsync
42
- } from "./packager-tool-j2cqgegq.js";
45
+ } from "./packager-tool-he7ak44z.js";
43
46
  import {
44
47
  Configuration,
45
- PipelinesApi,
46
- feedResolutionFailureInstructions,
48
+ PipelinesApi
49
+ } from "./packager-tool-qgaqqq41.js";
50
+ import {
47
51
  feedScopeInitOverride,
48
- listSelectablePublishLocations,
49
- resolveFeedScope
50
- } from "./packager-tool-h4wn0y42.js";
52
+ listSelectablePublishLocations
53
+ } from "./packager-tool-dh0m3ebf.js";
51
54
  import {
52
- Configuration as Configuration2,
53
55
  DeploymentActivationStatus,
54
56
  DeploymentOperationStatus,
55
- PackagesApi,
56
- SearchApi,
57
57
  StudioWebIncompatibleProjectError,
58
58
  buildSolutionUploadFailureOutput,
59
59
  bundleSolution,
@@ -63,20 +63,22 @@ import {
63
63
  isDebugProvisioningTerminal,
64
64
  isSolutionUploadHttpError,
65
65
  overwriteSolution,
66
- searchPackageVersions,
67
66
  solutionExistsOnStudioWeb
68
- } from "./packager-tool-ge4rvy7p.js";
67
+ } from "./packager-tool-t12hj6pd.js";
69
68
  import {
70
- Tokens,
71
69
  applyEntryPointEnhancementAsync,
72
70
  assertSolutionManifest,
73
71
  createLocalResource,
74
72
  createProjectInSolutionBuilder,
75
73
  createResourceBuilderServices,
76
74
  createResourceKindMetadataResolver,
75
+ exportResourceDefinitionAsync,
76
+ findCatalogEntityAsync,
77
77
  findMatchingLocalResource,
78
78
  findProjectFile,
79
79
  findResourceByKeyInRcs,
80
+ formatResourceSubtypes,
81
+ getRemoteResourceClients,
80
82
  hasAnyTemplateRow,
81
83
  hasBareTemplateRow,
82
84
  isMissingProjectTypeError,
@@ -85,41 +87,47 @@ import {
85
87
  normalizeResourceFileCasing,
86
88
  readProjectFile,
87
89
  readSolutionFile,
90
+ readSpecProperty,
91
+ resolveResourceKindMetadata,
88
92
  resolveSolutionFilePath,
89
93
  resourceRefreshAsync,
90
94
  resourceRemoteSyncAsync,
91
95
  restoreSolutionFile,
96
+ sameResourceSubtype,
92
97
  saveCasingNormalized,
93
98
  searchRcsResources,
94
99
  syncResourcesFromBindings,
100
+ toResourceReference,
101
+ validateResourceName,
95
102
  writeSolutionFile
96
- } from "./packager-tool-bkwnetqn.js";
103
+ } from "./packager-tool-83rzavkx.js";
97
104
  import {
98
105
  ToolResult
99
- } from "./packager-tool-nzghfa48.js";
106
+ } from "./packager-tool-fv7xyzg2.js";
100
107
  import {
101
108
  getSolutionAuthContext
102
- } from "./packager-tool-2syrt51a.js";
109
+ } from "./packager-tool-f5gq77m5.js";
103
110
  import {
104
- getLoginStatusAsync,
105
111
  resolveSolutionDir,
106
112
  toPortableRelativePath,
107
113
  updateUipxSolutionId
108
- } from "./packager-tool-3jrq7smt.js";
114
+ } from "./packager-tool-vmsxq1pc.js";
109
115
  import {
116
+ CommandDimensions,
110
117
  DEFAULT_PAGE_SIZE,
111
118
  Option,
112
119
  OutputFormatter,
113
120
  Pagination,
114
121
  PollOutcome,
115
122
  RESULTS,
123
+ ShipDimensions,
116
124
  carriedErrorCode,
117
125
  carriedInstructions,
126
+ carriedRetry,
118
127
  catchError,
119
128
  createHiddenDeprecatedTenantOption,
120
129
  extractErrorDetails,
121
130
  extractErrorMessage,
122
- getFileSystem,
123
131
  isGuid,
124
132
  isPreviewBuild,
125
133
  logger,
@@ -137,7 +145,13 @@ import {
137
145
  unsupportedSolutionProjectType,
138
146
  warnDeprecatedOptionAlias,
139
147
  withCompleter
140
- } from "./packager-tool-0f0wt9vh.js";
148
+ } from "./packager-tool-5fjp60dk.js";
149
+ import {
150
+ getLoginStatusAsync
151
+ } from "./packager-tool-gb35b4qs.js";
152
+ import {
153
+ getFileSystem
154
+ } from "./packager-tool-zf3929se.js";
141
155
  import {
142
156
  strFromU8,
143
157
  unzip,
@@ -151,7 +165,7 @@ var package_default = {
151
165
  name: "@uipath/solution-tool",
152
166
  author: "UiPath",
153
167
  license: "SEE LICENSE IN LICENSE.txt",
154
- version: "1.203.0-preview.203",
168
+ version: "1.204.0-preview.206",
155
169
  description: "Create, pack, publish, and deploy UiPath Automation Solutions.",
156
170
  repository: {
157
171
  type: "git",
@@ -214,8 +228,8 @@ var package_default = {
214
228
  "@uipath/packager-tool-connector": "workspace:*",
215
229
  "@uipath/pipelines-sdk": "workspace:*",
216
230
  "@uipath/project-executor": "workspace:*",
217
- "@uipath/resource-builder-sdk": "2025.11.0-alpha5891-4020",
218
- "@uipath/resource-builder-tool": "2025.11.0-alpha4535-3530",
231
+ "@uipath/resource-builder-sdk": "2025.11.0-alpha6004-4107",
232
+ "@uipath/resource-builder-tool": "2025.11.0-alpha6004-4107",
219
233
  "@uipath/solution-packager": "workspace:*",
220
234
  "@uipath/solution-sdk": "workspace:*",
221
235
  "@uipath/solutionpackager-tool-core": "workspace:*",
@@ -489,7 +503,9 @@ var registerDeployActivateCommand = (program) => {
489
503
  OutputFormatter.error({
490
504
  Result: RESULTS.Failure,
491
505
  Message: result.message,
492
- Instructions: result.instructions
506
+ Instructions: result.instructions,
507
+ ErrorCode: result.errorCode,
508
+ Retry: result.retry
493
509
  });
494
510
  processContext.exit(result.exitCode);
495
511
  return;
@@ -1016,6 +1032,54 @@ var registerDeployConfigCommand = (program) => {
1016
1032
  registerDeployConfigUnlinkCommand(config);
1017
1033
  };
1018
1034
 
1035
+ // src/commands/deploy-delete.ts
1036
+ var SOLUTION_DEPLOY_DELETE_EXAMPLES = [
1037
+ {
1038
+ Description: "Delete an inactive deployment record left behind by 'deploy uninstall'",
1039
+ Command: "uip solution deploy delete my-deployment --yes",
1040
+ Output: {
1041
+ Code: "SolutionDeployDelete",
1042
+ Data: {
1043
+ Status: "Deleted",
1044
+ DeploymentName: "my-deployment",
1045
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001"
1046
+ }
1047
+ }
1048
+ }
1049
+ ];
1050
+ var registerDeployDeleteCommand = (program) => {
1051
+ program.command("delete").description("Delete a deployment from the tenant. Use this for a deployment that 'deploy uninstall' cannot remove: one left inactive after an uninstall, one superseded by a newer version, or one left behind by a failed install — Orchestrator refuses to uninstall those with error 4007. The command reads the deployment first, and refuses when its own action list offers actions but not Delete, naming the state and the actions that are available. A record that lists no actions at all says nothing, so there the request goes to the server and the server decides.").argument("<deployment-name>", "Name of the deployment to delete. Use 'solution deploy list' to find deployment names.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("-y, --yes", "Confirm this irreversible operation (required; the CLI never prompts)").examples(SOLUTION_DEPLOY_DELETE_EXAMPLES).trackedAction(processContext, async (deploymentName, options) => {
1052
+ if (!requireConfirmation(options, `delete deployment '${deploymentName}'`)) {
1053
+ return;
1054
+ }
1055
+ const { deleteDeploymentAsync } = await import("./deploy-delete-service-y9dwehmn.js");
1056
+ const result = await deleteDeploymentAsync(deploymentName, {
1057
+ tenant: options.tenant,
1058
+ loginValidity: options.loginValidity
1059
+ });
1060
+ if (!result.ok) {
1061
+ OutputFormatter.error({
1062
+ Result: RESULTS.Failure,
1063
+ Message: result.message,
1064
+ Instructions: result.instructions,
1065
+ ErrorCode: result.errorCode,
1066
+ Retry: result.retry
1067
+ });
1068
+ processContext.exit(result.exitCode);
1069
+ return;
1070
+ }
1071
+ OutputFormatter.success({
1072
+ Result: RESULTS.Success,
1073
+ Code: "SolutionDeployDelete",
1074
+ Data: {
1075
+ Status: "Deleted",
1076
+ DeploymentName: result.deploymentName,
1077
+ DeploymentKey: result.deploymentKey
1078
+ }
1079
+ });
1080
+ });
1081
+ };
1082
+
1019
1083
  // src/commands/deploy-list.ts
1020
1084
  var OPERATION_STATUS_VALUES = Object.values(DeploymentOperationStatus);
1021
1085
  var ACTIVATION_STATUS_VALUES = Object.values(DeploymentActivationStatus);
@@ -1096,7 +1160,7 @@ var SOLUTION_DEPLOY_LIST_EXAMPLES = [
1096
1160
  }
1097
1161
  ];
1098
1162
  var registerDeployListCommand = (program) => {
1099
- const command = program.command("list").description("List solution deployments. Shows deployment name, status, package version (current/target), pending operation, and folder path. --operation-status/--activation-status filter server-side; --folder-path filters after fetching.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Filter by parent folder path (e.g., 'Shared')").option("--folder-key <key>", "Filter by parent folder key (GUID). Alternative to --folder-path.").option("-l, --limit <number>", "Max deployments to fetch. Note: --folder-path filtering happens after fetching, so increase this value if results seem incomplete.", parseLimit, DEFAULT_PAGE_SIZE).option("--offset <number>", "Number of deployments to skip (applied before --folder-path/--folder-key filtering)", parseOffset, 0).option("--sort-by <column>", "Column to sort by (default: startTime)", "startTime").option("--sort-order <direction>", "Sort direction: Ascending or Descending (default: Descending)", "Descending").option("--operation-status <statuses>", `Filter by deployment operation status, server-side (comma-separated). One or more of: ${OPERATION_STATUS_VALUES.join(", ")}.`).option("--activation-status <statuses>", `Filter by deployment activation status, server-side (comma-separated). One or more of: ${ACTIVATION_STATUS_VALUES.join(", ")}.`).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10);
1163
+ const command = program.command("list").description("List solution deployments. Shows deployment name, status, package version (current/target), pending operation, and folder path. --operation-status, --activation-status and --folder-path/--folder-key all filter server-side.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--folder-path <path>", "Filter by the full path of the folder the deployment was installed into (e.g., 'Shared' or 'Shared/Finance'). Exact match, not case-sensitive; subfolders are not included.").option("--folder-key <key>", "Filter by the key (GUID) of the folder the deployment was installed into. Alternative to --folder-path.").option("-l, --limit <number>", "Max deployments to return", parseLimit, DEFAULT_PAGE_SIZE).option("--offset <number>", "Number of deployments to skip", parseOffset, 0).option("--sort-by <column>", "Column to sort by (default: startTime)", "startTime").option("--sort-order <direction>", "Sort direction: Ascending or Descending (default: Descending)", "Descending").option("--operation-status <statuses>", `Filter by deployment operation status, server-side (comma-separated). One or more of: ${OPERATION_STATUS_VALUES.join(", ")}.`).option("--activation-status <statuses>", `Filter by deployment activation status, server-side (comma-separated). One or more of: ${ACTIVATION_STATUS_VALUES.join(", ")}.`).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10);
1100
1164
  command.addOption(new Option("--feed <name-or-key>", "Only list deployments from this feed (name or folder key, from 'solution feeds list'). Mutually exclusive with --personal-workspace.").conflicts("personalWorkspace")).option("--personal-workspace", "Only list deployments from the current user's Personal Workspace feed.");
1101
1165
  command.examples(SOLUTION_DEPLOY_LIST_EXAMPLES).trackedAction(processContext, async (options) => {
1102
1166
  const operationStatus = parseStatusFilter(options.operationStatus, OPERATION_STATUS_VALUES, "--operation-status");
@@ -1137,7 +1201,10 @@ var registerDeployListCommand = (program) => {
1137
1201
  OutputFormatter.error({
1138
1202
  Result: RESULTS.Failure,
1139
1203
  Message: result.message,
1140
- Instructions: result.instructions
1204
+ Instructions: result.instructions,
1205
+ ErrorCode: result.errorCode,
1206
+ Retry: result.retry,
1207
+ ...result.context ? { Context: result.context } : {}
1141
1208
  });
1142
1209
  processContext.exit(result.exitCode);
1143
1210
  return;
@@ -1237,35 +1304,49 @@ var SOLUTION_DEPLOY_RUN_EXAMPLES = [
1237
1304
  }
1238
1305
  },
1239
1306
  {
1240
- Description: "Deploy a solution package into the current user's Personal Workspace",
1241
- Command: "uip solution deploy run --name my-deployment --package-name my-package --package-version 1.0.0 --folder-name MySolution --personal-workspace",
1307
+ Description: "A deploy that succeeded but is not live: a resource needs 'Setup activation' in Orchestrator before the deployment can be activated (Result: Success; do not deploy again)",
1308
+ Command: 'uip solution deploy run --name my-deployment --package-name my-package --package-version 1.0.0 --folder-name MySolution --parent-folder-path "Shared"',
1242
1309
  Output: {
1243
1310
  Code: "SolutionDeployRun",
1244
1311
  Data: {
1245
- Status: "DeploymentStarted",
1246
- DeploymentName: "my-deployment",
1247
- PackageName: "my-package",
1248
- PackageVersion: "1.0.0",
1312
+ Status: "DeploymentSucceeded",
1313
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000003",
1314
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000003",
1315
+ InstanceId: null,
1249
1316
  FolderName: "MySolution",
1250
- FolderPath: "alice@uipath.com/MySolution",
1251
- ActivationStatus: "Auto",
1252
- NextSteps: "Deployment created in your Personal Workspace and will auto-activate. Check status with: uip solution deploy list."
1317
+ FolderPath: "Shared/MySolution",
1318
+ ActivationStatus: "NeedsSetupToActivate",
1319
+ PendingResources: [
1320
+ {
1321
+ Kind: "connection",
1322
+ Name: "Outlook",
1323
+ Type: "uipath-microsoft-outlook365",
1324
+ Reason: "[CNS1072] You will need to authenticate this connection before proceeding further"
1325
+ }
1326
+ ],
1327
+ NextSteps: [
1328
+ "Deployment 'my-deployment' is installed at version 1.0.0 but not live: it needs 'Setup activation' before it can be activated.",
1329
+ "Resources that need configuration: connection 'Outlook' (uipath-microsoft-outlook365): [CNS1072] You will need to authenticate this connection before proceeding further."
1330
+ ]
1253
1331
  }
1254
1332
  }
1255
1333
  },
1256
1334
  {
1257
- Description: "Deploy into the Personal Workspace and wait for the install to finish before returning",
1258
- Command: "uip solution deploy run --name my-deployment --package-name my-package --package-version 1.0.0 --folder-name MySolution --personal-workspace --wait",
1335
+ Description: "Deploy a solution package into the current user's Personal Workspace",
1336
+ Command: "uip solution deploy run --name my-deployment --package-name my-package --package-version 1.0.0 --folder-name MySolution --personal-workspace",
1259
1337
  Output: {
1260
1338
  Code: "SolutionDeployRun",
1261
1339
  Data: {
1262
1340
  Status: "DeploymentSucceeded",
1263
- DeploymentName: "my-deployment",
1264
- PackageName: "my-package",
1265
- PackageVersion: "1.0.0",
1341
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001",
1342
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000001",
1343
+ InstanceId: "c3d4e5f6-0000-0000-0000-000000000001",
1266
1344
  FolderName: "MySolution",
1267
1345
  FolderPath: "alice@uipath.com/MySolution",
1268
- ActivationStatus: "Auto"
1346
+ ActivationStatus: "SuccessfulActivate",
1347
+ DeploymentName: "my-deployment",
1348
+ PackageName: "my-package",
1349
+ PackageVersion: "1.0.0"
1269
1350
  }
1270
1351
  }
1271
1352
  },
@@ -1292,20 +1373,22 @@ var SOLUTION_DEPLOY_RUN_FEED_EXAMPLE = {
1292
1373
  Output: {
1293
1374
  Code: "SolutionDeployRun",
1294
1375
  Data: {
1295
- Status: "DeploymentStarted",
1296
- DeploymentName: "my-deployment",
1297
- PackageName: "my-package",
1298
- PackageVersion: "1.0.0",
1376
+ Status: "DeploymentSucceeded",
1377
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001",
1378
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000001",
1379
+ InstanceId: "c3d4e5f6-0000-0000-0000-000000000001",
1299
1380
  FolderName: "MySolution",
1300
1381
  FolderPath: "Finance/MySolution",
1301
- ActivationStatus: "Auto",
1302
- NextSteps: "Deployment created in feed 'Finance' and will auto-activate. Check status with: uip solution deploy list."
1382
+ ActivationStatus: "SuccessfulActivate",
1383
+ DeploymentName: "my-deployment",
1384
+ PackageName: "my-package",
1385
+ PackageVersion: "1.0.0"
1303
1386
  }
1304
1387
  }
1305
1388
  };
1306
1389
  var registerDeployRunCommand = (program) => {
1307
- const command = program.command("run").description("Deploy a solution package to Orchestrator. Creates a folder, provisions resources, and (by default) activates the solution. This always creates a NEW deployment in a NEW folder — it never updates an existing one — so if the package is already deployed the command stops and points you at the upgrade path; pass --yes to deploy a second, separate copy anyway. Pass --skip-activate to leave the deployment in 'Inactive (Ready to activate)' state and activate later with 'deploy activate'. To customize resource settings before deploying, use 'config get' to fetch the default config, 'config set' / 'config link' to edit it, then pass it here with --config-file.").requiredOption("-n, --name <deployment-name>", "Name for the deployment").addOption(withCompleter(new Option("--package-name <name>", "Solution package name to deploy. Use 'solution packages list' to find available names.").makeOptionMandatory(), packageNameCompleter)).addOption(withCompleter(new Option("--package-version <version>", "Solution package version to deploy. Use 'solution packages list' to find available versions.").makeOptionMandatory(), packageVersionCompleter)).requiredOption("--folder-name <name>", "Name for the new Orchestrator folder created for this deployment (created under --parent-folder-path if specified)").addOption(new Option("--parent-folder-path <path>", "Parent folder path (e.g., 'Shared'). Solution folder is created under this.").conflicts("parentFolderKey")).option("--parent-folder-key <key>", "Parent folder key (GUID). Alternative to --parent-folder-path.").addOption(new Option("--personal-workspace", "Deploy into the current user's Personal Workspace. Resolves the workspace name from Orchestrator automatically. Mutually exclusive with --parent-folder-path and --parent-folder-key.").conflicts(["parentFolderPath", "parentFolderKey"])).option("--config-file <path>", "JSON or YAML configuration file. Generate with: uip solution deploy config get <name> -d config.json, then customize with 'config set' or 'config link'.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--timeout <seconds>", "Timeout in seconds applied per polling phase — deploy and (when not skipped) activate (default: 360 each)", (v) => parseInt(v, 10), 360).option("--poll-interval <ms>", "Milliseconds between status polls during the deploy and activate phases (default: 5000)", (v) => parseInt(v, 10), 5000).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("--wait", "Wait for a --personal-workspace / --feed deploy to finish instead of returning as soon as it starts. Bounded by --timeout. The tenant path always waits, so this changes nothing there.").option("--skip-activate", "Skip auto-activation; leave the deployment in 'Inactive (Ready to activate)' state. Activate later with 'uip solution deploy activate <name>'.").option("-y, --yes", "Deploy even when this package already has a deployment. Without it, deploy run looks the package up and stops if it is already deployed. That check is best-effort, not a guarantee: it reads the Solutions search, which needs a user session, so an application (client-credentials) login deploys without it, and a lookup failure only warns.");
1308
- command.addOption(new Option("--feed <name-or-key>", "Deploy a package from a specific feed (name or folder key, from 'solution feeds list') instead of the tenant feed. Mutually exclusive with --personal-workspace.").conflicts("personalWorkspace"));
1390
+ const command = program.command("run").description("Deploy a solution package to Orchestrator. Creates a folder, provisions resources, and (by default) activates the solution. The deployment is keyed on --name: a name that does not exist yet gets a NEW deployment in a NEW folder (the normal case), while re-using an existing deployment's name updates that deployment in place — use 'deploy upgrade' when that is what you want. If the package is already deployed the command stops and points you at the upgrade path; pass --yes with a different --name to deploy a second, separate copy anyway. Pass --skip-activate to leave the deployment in 'Inactive (Ready to activate)' state and activate later with 'deploy activate'. A deployment whose resources need 'Setup activation' in Orchestrator is installed but not activated: the command reports Result: Success with ActivationStatus: NeedsSetupToActivate, the resources and the steps left — do not deploy it again. To customize resource settings before deploying, use 'config get' to fetch the default config, 'config set' / 'config link' to edit it, then pass it here with --config-file.").requiredOption("-n, --name <deployment-name>", "Name for the deployment").addOption(withCompleter(new Option("--package-name <name>", "Solution package name to deploy. Use 'solution packages list' to find available names.").makeOptionMandatory(), packageNameCompleter)).addOption(withCompleter(new Option("--package-version <version>", "Solution package version to deploy. Use 'solution packages list' to find available versions.").makeOptionMandatory(), packageVersionCompleter)).requiredOption("--folder-name <name>", "Name for the new Orchestrator folder created for this deployment (created under --parent-folder-path if specified)").addOption(new Option("--parent-folder-path <path>", "Parent folder path (e.g., 'Shared'). Solution folder is created under this.").conflicts("parentFolderKey")).option("--parent-folder-key <key>", "Parent folder key (GUID). Alternative to --parent-folder-path.").addOption(new Option("--personal-workspace", "Deploy into the current user's Personal Workspace. Resolves the workspace name from Orchestrator automatically; needs a user session (an external app has no workspace, and the server ignores the feed header on client-credentials requests). Mutually exclusive with --parent-folder-path and --parent-folder-key.").conflicts(["parentFolderPath", "parentFolderKey"])).option("--config-file <path>", "JSON or YAML configuration file. Generate with: uip solution deploy config get <name> -d config.json, then customize with 'config set' or 'config link'.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--timeout <seconds>", "Timeout in seconds applied per polling phase — deploy and (when not skipped) activate (default: 360 each)", (v) => parseInt(v, 10), 360).option("--poll-interval <ms>", "Milliseconds between status polls during the deploy and activate phases (default: 5000)", (v) => parseInt(v, 10), 5000).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).addOption(new Option("--wait", "Deprecated and ignored: every deploy now waits for the install to finish (bounded by --timeout).").hideHelp()).option("--skip-activate", "Skip auto-activation; leave the deployment in 'Inactive (Ready to activate)' state. Activate later with 'uip solution deploy activate <name>'.").option("-y, --yes", "Deploy even when this package already has a deployment. Without it, deploy run looks the package up and stops if it is already deployed. That check is best-effort, not a guarantee: a lookup failure only warns, and under an application (client-credentials) login it never stops the deploy — an existing deployment is reported as a warning, or the check is skipped on servers without the Pipelines deployment search. --yes only skips that check: the install is keyed on --name, so re-using an existing deployment's name updates that deployment in place rather than creating a second copy — pass a different --name for a separate deployment.");
1391
+ command.addOption(new Option("--feed <name-or-key>", "Deploy a package from a specific feed (name or folder key, from 'solution feeds list') instead of the tenant feed. Needs a user session: the server ignores the feed header on client-credentials requests, so an external app is refused rather than deploying to the tenant feed by accident. Mutually exclusive with --personal-workspace.").conflicts("personalWorkspace"));
1309
1392
  command.examples([
1310
1393
  ...SOLUTION_DEPLOY_RUN_EXAMPLES,
1311
1394
  SOLUTION_DEPLOY_RUN_FEED_EXAMPLE
@@ -1321,7 +1404,6 @@ var registerDeployRunCommand = (program) => {
1321
1404
  personalWorkspace: options.personalWorkspace,
1322
1405
  feed: options.feed,
1323
1406
  configFile: options.configFile,
1324
- wait: options.wait,
1325
1407
  timeout: options.timeout,
1326
1408
  pollInterval: options.pollInterval,
1327
1409
  loginValidity: options.loginValidity,
@@ -1353,21 +1435,29 @@ var registerDeployRunCommand = (program) => {
1353
1435
  RequestedFolderName: result.requestedFolderName,
1354
1436
  FolderNote: result.requestedFolderName === undefined ? undefined : `Requested folder '${result.requestedFolderName}' already existed, so Orchestrator created '${result.folderName}' instead. Deploying cannot target a pre-existing folder; provision resources into '${result.folderPath}', or re-run with a free --folder-name.`,
1355
1437
  ActivationStatus: result.activationStatus,
1438
+ ...result.pendingResources ? {
1439
+ PendingResources: result.pendingResources.map((resource) => ({
1440
+ Kind: resource.kind,
1441
+ Name: resource.name,
1442
+ Type: resource.type ?? null,
1443
+ Reason: resource.reason ?? null
1444
+ }))
1445
+ } : {},
1446
+ ...result.nextSteps ? { NextSteps: result.nextSteps } : {},
1356
1447
  DeploymentName: result.deploymentName,
1357
1448
  PackageName: result.packageName,
1358
- PackageVersion: result.packageVersion,
1359
- NextSteps: result.nextSteps
1449
+ PackageVersion: result.packageVersion
1360
1450
  }
1361
1451
  });
1362
1452
  trackShipSucceeded({
1363
- ship_kind: "deploy",
1364
- target: result.feedKind === "personal" ? "personal_workspace_orchestrator" : result.feedKind === "folder" ? "folder_orchestrator" : "orchestrator",
1365
- project_type: "solution",
1366
- command_name: "uip.solution.deploy.run",
1367
- artifact_correlation_key: result.deploymentKey ?? result.pipelineDeploymentId ?? result.deploymentName,
1368
- deployment_key: result.deploymentKey,
1369
- package_name: options.packageName,
1370
- package_version: options.packageVersion
1453
+ [ShipDimensions.ShipKind]: "deploy",
1454
+ [ShipDimensions.Target]: result.feedKind === "personal" ? "personal_workspace_orchestrator" : result.feedKind === "folder" ? "folder_orchestrator" : "orchestrator",
1455
+ [ShipDimensions.ProjectType]: "solution",
1456
+ [CommandDimensions.CommandName]: "uip solution deploy run",
1457
+ [ShipDimensions.ArtifactCorrelationKey]: result.deploymentKey ?? result.pipelineDeploymentId ?? result.deploymentName,
1458
+ [ShipDimensions.DeploymentKey]: result.deploymentKey,
1459
+ [ShipDimensions.PackageName]: options.packageName,
1460
+ [ShipDimensions.PackageVersion]: options.packageVersion
1371
1461
  });
1372
1462
  });
1373
1463
  };
@@ -1375,7 +1465,66 @@ var registerDeployRunCommand = (program) => {
1375
1465
  // src/commands/deploy-status.ts
1376
1466
  var SOLUTION_DEPLOY_STATUS_EXAMPLES = [
1377
1467
  {
1378
- Description: "Check the status of a pipeline deployment",
1468
+ Description: "Check a deployment by name: here one that is upgraded but not live",
1469
+ Command: 'uip solution deploy status "my-deployment"',
1470
+ Output: {
1471
+ Code: "SolutionDeployment",
1472
+ Data: {
1473
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000002",
1474
+ Superseded: false,
1475
+ CurrentDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000002",
1476
+ InstallDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001",
1477
+ Name: "my-deployment",
1478
+ PackageName: "my-package",
1479
+ PackageVersion: "2.0.0",
1480
+ NewPackageVersionAvailable: null,
1481
+ Operation: "VersionChange",
1482
+ OperationStatus: "Successful",
1483
+ DeploymentStatus: "SuccessfulInstall",
1484
+ ActivationStatus: "NeedsSetupToActivate",
1485
+ Actions: ["SetupActivation", "Uninstall", "Upgrade"],
1486
+ PendingResources: [
1487
+ {
1488
+ Kind: "connection",
1489
+ Name: "Outlook",
1490
+ Type: "uipath-microsoft-outlook365",
1491
+ Reason: "[CNS1072] You will need to authenticate this connection before proceeding further"
1492
+ }
1493
+ ],
1494
+ NextSteps: [
1495
+ "Deployment 'my-deployment' is installed at version 2.0.0 but not live: it needs 'Setup activation' before it can be activated.",
1496
+ "Resources that need configuration: connection 'Outlook' (uipath-microsoft-outlook365): [CNS1072] You will need to authenticate this connection before proceeding further."
1497
+ ]
1498
+ }
1499
+ }
1500
+ },
1501
+ {
1502
+ Description: "Check a deployment key from deploy run or deploy list: here one an upgrade has superseded",
1503
+ Command: "uip solution deploy status a1b2c3d4-0000-0000-0000-000000000001",
1504
+ Output: {
1505
+ Code: "SolutionDeployment",
1506
+ Data: {
1507
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001",
1508
+ Superseded: true,
1509
+ CurrentDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000002",
1510
+ InstallDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000001",
1511
+ Name: "my-deployment",
1512
+ PackageName: "my-package",
1513
+ PackageVersion: "2.0.0",
1514
+ NewPackageVersionAvailable: null,
1515
+ Operation: "ActivationSetup",
1516
+ OperationStatus: "Successful",
1517
+ DeploymentStatus: "SuccessfulActivate",
1518
+ ActivationStatus: "Active",
1519
+ Actions: ["Uninstall", "Upgrade"],
1520
+ NextSteps: [
1521
+ "Key 'a1b2c3d4-0000-0000-0000-000000000001' is superseded: 'my-deployment' is now record 'a1b2c3d4-0000-0000-0000-000000000002' (ActivationSetup/Successful, version 2.0.0). Every operation creates a new record; use the current key from now on."
1522
+ ]
1523
+ }
1524
+ }
1525
+ },
1526
+ {
1527
+ Description: "Check the pipeline deployment run that deploy run started",
1379
1528
  Command: "uip solution deploy status b2c3d4e5-0000-0000-0000-000000000001",
1380
1529
  Output: {
1381
1530
  Code: "SolutionDeployStatus",
@@ -1392,10 +1541,32 @@ var SOLUTION_DEPLOY_STATUS_EXAMPLES = [
1392
1541
  }
1393
1542
  }
1394
1543
  }
1544
+ },
1545
+ {
1546
+ Description: "Check a deployment key that lives in your Personal Workspace feed",
1547
+ Command: "uip solution deploy status a1b2c3d4-0000-0000-0000-000000000003 --personal-workspace",
1548
+ Output: {
1549
+ Code: "SolutionDeployment",
1550
+ Data: {
1551
+ DeploymentKey: "a1b2c3d4-0000-0000-0000-000000000003",
1552
+ Superseded: false,
1553
+ CurrentDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000003",
1554
+ InstallDeploymentKey: "a1b2c3d4-0000-0000-0000-000000000003",
1555
+ Name: "my-deployment",
1556
+ PackageName: "my-package",
1557
+ PackageVersion: "1.0.0",
1558
+ NewPackageVersionAvailable: null,
1559
+ Operation: "Install",
1560
+ OperationStatus: "Successful",
1561
+ DeploymentStatus: "SuccessfulActivate",
1562
+ ActivationStatus: "Active",
1563
+ Actions: ["Uninstall", "Upgrade"]
1564
+ }
1565
+ }
1395
1566
  }
1396
1567
  ];
1397
1568
  var registerDeployStatusCommand = (program) => {
1398
- program.command("status").description("Check the current status of a pipeline deployment. Returns deployment state, progress, and any errors.").argument("<pipeline-deployment-id>", "Pipeline deployment ID (GUID) returned by 'solution deploy run'.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).examples(SOLUTION_DEPLOY_STATUS_EXAMPLES).trackedAction(processContext, async (pipelineDeploymentId, options) => {
1569
+ program.command("status").description("Check the state of a deployment by name, or by a deployment key from 'solution deploy list' / 'solution deploy upgrade': operation, activation status, and what is left to do before it runs. Also takes the pipeline deployment ID from 'solution deploy run' for that run's progress and errors.").argument("<deployment>", "Deployment name (preferred). A deployment key from 'solution deploy list' / 'solution deploy upgrade', or the pipeline deployment ID from 'solution deploy run', works as well. A key is resolved through the Pipelines deployment lookup, which spans every feed and answers a superseded key with the deployment's current record.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).addOption(new Option("--feed <name-or-key>", "For a deployment name: the feed to look it up in (name or folder key, from 'solution feeds list'). For a key: read only on a server without the Pipelines by-key lookup, whose read is feed-scoped; the lookup itself spans every feed and answers the key wherever it lives. Mutually exclusive with --personal-workspace.").conflicts("personalWorkspace")).option("--personal-workspace", "For a deployment name: look it up in your Personal Workspace feed instead of the tenant. For a key: read only on a server without the Pipelines by-key lookup; the lookup itself spans every feed.").examples(SOLUTION_DEPLOY_STATUS_EXAMPLES).trackedAction(processContext, async (deployment, options) => {
1399
1570
  const [authError, auth] = await catchError(getSolutionAuthContext({
1400
1571
  tenant: options.tenant,
1401
1572
  loginValidity: options.loginValidity
@@ -1409,20 +1580,106 @@ var registerDeployStatusCommand = (program) => {
1409
1580
  processContext.exit(1);
1410
1581
  return;
1411
1582
  }
1583
+ const { feedScopeInitOverride: feedScopeInitOverride2 } = await import("./feed-resolver-dmtnswcc.js");
1584
+ const { FeedReadRefusedError, feedReadRefusalForApplication } = await import("./feed-session-sxga31vn.js");
1585
+ const refuseFeed = (action) => {
1586
+ const refusal = feedReadRefusalForApplication(auth, action);
1587
+ if (!refusal) {
1588
+ return false;
1589
+ }
1590
+ OutputFormatter.error({
1591
+ Result: RESULTS.Failure,
1592
+ Message: refusal.message,
1593
+ Instructions: refusal.instructions,
1594
+ ErrorCode: "permission_denied",
1595
+ Retry: "RetryWillNotFix"
1596
+ });
1597
+ processContext.exit(1);
1598
+ return true;
1599
+ };
1600
+ if (options.personalWorkspace === true && refuseFeed("Reading a Personal Workspace deployment")) {
1601
+ return;
1602
+ }
1603
+ const { resolveFeedScopeOrFailureAsync: resolveFeedScopeOrFailureAsync2 } = await import("./feed-scope-failure-e2yaqfg2.js");
1604
+ const [scopeFailure, feedScope] = await resolveFeedScopeOrFailureAsync2(options, auth);
1605
+ if (scopeFailure) {
1606
+ OutputFormatter.error(scopeFailure);
1607
+ processContext.exit(1);
1608
+ return;
1609
+ }
1610
+ const { describeDeploymentAsync, looksLikeDeploymentKey } = await import("./deploy-status-service-nmhnnjmy.js");
1611
+ if (feedScope.kind !== "tenant" && !looksLikeDeploymentKey(deployment) && refuseFeed(`Reading a deployment in the feed '${feedScope.name ?? feedScope.folderKey}'`)) {
1612
+ return;
1613
+ }
1614
+ const feedSelected = options.personalWorkspace === true || options.feed !== undefined;
1615
+ const describe = () => describeDeploymentAsync(auth, deployment, {
1616
+ selectedFeed: feedSelected ? feedScope : undefined,
1617
+ locate: {
1618
+ tenant: options.tenant,
1619
+ loginValidity: options.loginValidity
1620
+ }
1621
+ });
1622
+ if (!looksLikeDeploymentKey(deployment)) {
1623
+ const [stateError, state] = await catchError(describe());
1624
+ if (stateError) {
1625
+ await reportStateError(deployment, stateError);
1626
+ return;
1627
+ }
1628
+ if (!state) {
1629
+ OutputFormatter.error({
1630
+ Result: RESULTS.Failure,
1631
+ Message: `Deployment '${deployment}' was not found.`,
1632
+ Instructions: "No deployment of that name is visible in the feeds this session can reach. Run 'uip solution deploy list' to see the names; add --personal-workspace or --feed <name-or-key> for a feed outside the tenant."
1633
+ });
1634
+ processContext.exit(1);
1635
+ return;
1636
+ }
1637
+ OutputFormatter.success({
1638
+ Result: RESULTS.Success,
1639
+ Code: "SolutionDeployment",
1640
+ Data: deploymentStateData(state)
1641
+ });
1642
+ return;
1643
+ }
1412
1644
  const configuration = new Configuration({
1413
1645
  basePath: auth.basePath,
1414
1646
  accessToken: auth.accessToken
1415
1647
  });
1416
1648
  const api = new PipelinesApi(configuration);
1417
- const [statusError, result] = await catchError(api.pipelinesGetPipelineDeploymentStatus({
1418
- pipelineDeploymentId
1419
- }));
1649
+ const [statusError, result] = await catchError(api.pipelinesGetPipelineDeploymentStatus({ pipelineDeploymentId: deployment }, feedSelected ? feedScopeInitOverride2(feedScope) : undefined));
1420
1650
  if (statusError) {
1651
+ const { isPipelineDeploymentNotFoundError } = await import("./deployment-search-eb337bjh.js");
1652
+ if (await isPipelineDeploymentNotFoundError(statusError)) {
1653
+ const [stateError, state] = await catchError(describe());
1654
+ if (stateError instanceof FeedReadRefusedError) {
1655
+ OutputFormatter.error({
1656
+ Result: RESULTS.Failure,
1657
+ Message: stateError.refusal.message,
1658
+ Instructions: stateError.refusal.instructions,
1659
+ ErrorCode: "permission_denied",
1660
+ Retry: "RetryWillNotFix"
1661
+ });
1662
+ processContext.exit(1);
1663
+ return;
1664
+ }
1665
+ if (stateError) {
1666
+ await reportStateError(deployment, stateError);
1667
+ return;
1668
+ }
1669
+ if (state) {
1670
+ OutputFormatter.success({
1671
+ Result: RESULTS.Success,
1672
+ Code: "SolutionDeployment",
1673
+ Data: deploymentStateData(state)
1674
+ });
1675
+ return;
1676
+ }
1677
+ }
1421
1678
  const { message, details } = await extractErrorDetails(statusError);
1422
1679
  OutputFormatter.error({
1423
1680
  Result: RESULTS.Failure,
1424
1681
  Message: message,
1425
- Instructions: `Check the pipeline deployment ID. Get it from deploy run output. Details: ${details}`
1682
+ Instructions: `Check the pipeline deployment ID (from 'deploy run' output) or the deployment key (from 'deploy list' / 'deploy upgrade'); a deployment name works too. A deployment outside the tenant feed needs --personal-workspace or --feed. Details: ${details}`
1426
1683
  });
1427
1684
  processContext.exit(1);
1428
1685
  return;
@@ -1433,7 +1690,7 @@ var registerDeployStatusCommand = (program) => {
1433
1690
  Result: RESULTS.Success,
1434
1691
  Code: "SolutionDeployStatus",
1435
1692
  Data: {
1436
- PipelineDeploymentId: pipelineDeploymentId,
1693
+ PipelineDeploymentId: deployment,
1437
1694
  Status: result.status,
1438
1695
  DeploymentKey: result.deploymentKey,
1439
1696
  ConfigurationKey: result.configurationKey,
@@ -1451,6 +1708,44 @@ var registerDeployStatusCommand = (program) => {
1451
1708
  });
1452
1709
  });
1453
1710
  };
1711
+ async function reportStateError(deployment, stateError) {
1712
+ const { message, details } = await extractErrorDetails(stateError);
1713
+ OutputFormatter.error({
1714
+ Result: RESULTS.Failure,
1715
+ Message: message,
1716
+ Instructions: carriedInstructions(stateError) ?? `The deployments service could not read deployment '${deployment}'. Details: ${details}`,
1717
+ ErrorCode: carriedErrorCode(stateError),
1718
+ Retry: carriedRetry(stateError)
1719
+ });
1720
+ processContext.exit(1);
1721
+ }
1722
+ function deploymentStateData(state) {
1723
+ const { current } = state;
1724
+ return {
1725
+ DeploymentKey: state.requestedKey,
1726
+ Superseded: state.superseded,
1727
+ CurrentDeploymentKey: current.key,
1728
+ InstallDeploymentKey: current.installDeploymentKey,
1729
+ Name: current.name,
1730
+ PackageName: current.packageName,
1731
+ PackageVersion: current.currentPackageVersion ?? current.packageVersion,
1732
+ NewPackageVersionAvailable: current.newPackageVersionAvailable ?? null,
1733
+ Operation: current.operation,
1734
+ OperationStatus: current.operationStatus,
1735
+ DeploymentStatus: current.deploymentStatus ?? null,
1736
+ ActivationStatus: current.activationStatus ?? null,
1737
+ Actions: current.actions ?? null,
1738
+ ...state.pendingResources ? {
1739
+ PendingResources: state.pendingResources.map((resource) => ({
1740
+ Kind: resource.kind,
1741
+ Name: resource.name,
1742
+ Type: resource.type ?? null,
1743
+ Reason: resource.reason ?? null
1744
+ }))
1745
+ } : {},
1746
+ ...state.nextSteps ? { NextSteps: state.nextSteps } : {}
1747
+ };
1748
+ }
1454
1749
 
1455
1750
  // src/commands/deploy-uninstall.ts
1456
1751
  var SOLUTION_DEPLOY_UNINSTALL_EXAMPLES = [
@@ -1528,50 +1823,147 @@ var registerDeployUninstallCommand = (program) => {
1528
1823
  // src/commands/deploy-upgrade.ts
1529
1824
  var SOLUTION_DEPLOY_UPGRADE_EXAMPLES = [
1530
1825
  {
1531
- Description: "Upgrade a deployment to the newest published version",
1532
- Command: "uip solution deploy upgrade a1b2c3d4-0000-0000-0000-000000000001",
1826
+ Description: "Upgrade a deployment by its key to the newest published version (name, package and feed are read from the deployment)",
1827
+ Command: "uip solution deploy upgrade c3d4e5f6-0000-0000-0000-000000000003",
1533
1828
  Output: {
1534
1829
  Code: "SolutionDeployUpgrade",
1535
1830
  Data: {
1536
- Status: "Successful",
1537
- DeploymentName: "billing-solution",
1538
- FromVersion: "1.0.0",
1831
+ Status: "DeploymentSucceeded",
1832
+ Operation: "VersionChange",
1833
+ DeploymentStatus: "SuccessfulActivate",
1834
+ Actions: ["Uninstall", "Upgrade"],
1835
+ DeploymentName: "my-deployment",
1836
+ FromVersion: "1.5.0",
1837
+ ToVersion: "2.0.0",
1838
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000002",
1839
+ DeploymentKey: "d4e5f6a7-0000-0000-0000-000000000004",
1840
+ InstallDeploymentKey: "c3d4e5f6-0000-0000-0000-000000000003"
1841
+ }
1842
+ }
1843
+ },
1844
+ {
1845
+ Description: "An upgrade that succeeded but is not live: a resource needs setup before activation",
1846
+ Command: "uip solution deploy upgrade c3d4e5f6-0000-0000-0000-000000000003",
1847
+ Output: {
1848
+ Code: "SolutionDeployUpgrade",
1849
+ Data: {
1850
+ Status: "DeploymentSucceeded",
1851
+ Operation: "VersionChange",
1852
+ DeploymentStatus: "SuccessfulInstall",
1853
+ Actions: ["SetupActivation", "Uninstall", "Upgrade"],
1854
+ ActivationStatus: "NeedsSetupToActivate",
1855
+ PendingResources: [
1856
+ {
1857
+ Kind: "connection",
1858
+ Name: "Outlook",
1859
+ Type: "uipath-microsoft-outlook365",
1860
+ Reason: "[CNS1072] You will need to authenticate this connection before proceeding further"
1861
+ }
1862
+ ],
1863
+ NextSteps: [
1864
+ "Deployment 'my-deployment' is installed at version 2.0.0 but not live: it needs 'Setup activation' before it can be activated.",
1865
+ "Resources that need configuration: connection 'Outlook' (uipath-microsoft-outlook365): [CNS1072] You will need to authenticate this connection before proceeding further."
1866
+ ],
1867
+ DeploymentName: "my-deployment",
1868
+ FromVersion: "1.5.0",
1869
+ ToVersion: "2.0.0",
1870
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000002",
1871
+ DeploymentKey: "d4e5f6a7-0000-0000-0000-000000000004",
1872
+ InstallDeploymentKey: "c3d4e5f6-0000-0000-0000-000000000003"
1873
+ }
1874
+ }
1875
+ },
1876
+ {
1877
+ Description: "Upgrade a deployment by name to the newest published version",
1878
+ Command: "uip solution deploy upgrade --name my-deployment --package-name my-package",
1879
+ Output: {
1880
+ Code: "SolutionDeployUpgrade",
1881
+ Data: {
1882
+ Status: "DeploymentSucceeded",
1883
+ Operation: "VersionChange",
1884
+ DeploymentStatus: "SuccessfulActivate",
1885
+ Actions: ["Uninstall", "Upgrade"],
1886
+ DeploymentName: "my-deployment",
1539
1887
  ToVersion: "2.0.0",
1540
- VersionChangeKey: "b2c3d4e5-0000-0000-0000-000000000002"
1888
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000002",
1889
+ DeploymentKey: "c3d4e5f6-0000-0000-0000-000000000003"
1890
+ }
1891
+ }
1892
+ },
1893
+ {
1894
+ Description: "Upgrade to a specific published version (the CI/CD form: no version lookup, one existence check and the install)",
1895
+ Command: "uip solution deploy upgrade --name my-deployment --package-name my-package --version 1.5.0",
1896
+ Output: {
1897
+ Code: "SolutionDeployUpgrade",
1898
+ Data: {
1899
+ Status: "DeploymentSucceeded",
1900
+ Operation: "VersionChange",
1901
+ DeploymentStatus: "SuccessfulActivate",
1902
+ Actions: ["Uninstall", "Upgrade"],
1903
+ DeploymentName: "my-deployment",
1904
+ ToVersion: "1.5.0",
1905
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000002",
1906
+ DeploymentKey: "c3d4e5f6-0000-0000-0000-000000000003"
1541
1907
  }
1542
1908
  }
1543
1909
  },
1544
1910
  {
1545
1911
  Description: "Start the upgrade without waiting for it to finish",
1546
- Command: "uip solution deploy upgrade a1b2c3d4-0000-0000-0000-000000000001 --no-wait",
1912
+ Command: "uip solution deploy upgrade --name my-deployment --package-name my-package --no-wait",
1547
1913
  Output: {
1548
1914
  Code: "SolutionDeployUpgrade",
1549
1915
  Data: {
1550
- Status: "Draft",
1551
- DeploymentName: "billing-solution",
1552
- FromVersion: "1.0.0",
1916
+ Status: "Accepted",
1917
+ DeploymentName: "my-deployment",
1553
1918
  ToVersion: "2.0.0",
1554
- VersionChangeKey: "b2c3d4e5-0000-0000-0000-000000000002"
1919
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000002"
1920
+ }
1921
+ }
1922
+ },
1923
+ {
1924
+ Description: "Discard the pending draft an earlier, rejected attempt left behind, then upgrade the live version",
1925
+ Command: "uip solution deploy upgrade c3d4e5f6-0000-0000-0000-000000000003 --version 2.0.0 --discard-draft",
1926
+ Output: {
1927
+ Code: "SolutionDeployUpgrade",
1928
+ Data: {
1929
+ Status: "DeploymentSucceeded",
1930
+ Operation: "VersionChange",
1931
+ DeploymentStatus: "SuccessfulActivate",
1932
+ Actions: ["Uninstall", "Upgrade"],
1933
+ DeploymentName: "my-deployment",
1934
+ FromVersion: "1.5.0",
1935
+ ToVersion: "2.0.0",
1936
+ PipelineDeploymentId: "b2c3d4e5-0000-0000-0000-000000000005",
1937
+ DeploymentKey: "d4e5f6a7-0000-0000-0000-000000000006",
1938
+ InstallDeploymentKey: "c3d4e5f6-0000-0000-0000-000000000003",
1939
+ DiscardedDraftKey: "e5f6a7b8-0000-0000-0000-000000000007"
1555
1940
  }
1556
1941
  }
1557
1942
  }
1558
1943
  ];
1559
1944
  var registerDeployUpgradeCommand = (program) => {
1560
- program.command("upgrade").description("Upgrade an existing deployment to a newer package version in place — the CLI equivalent of the Orchestrator UI 'Upgrade' button. Use this when 'deploy run' is blocked because a deployment already exists. The deployment's existing configuration is preserved, so values already set on it (for example a credential asset's secret) are not reset to the package defaults. Waits for the upgrade to finish unless --no-wait is passed.").argument("<deployment-key>", "Key of the deployment to upgrade. Use 'solution deploy list' to find it.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--version <version>", "Target package version (default: the newest available). Only the latest published version is supported today.").option("--personal-workspace", "Upgrade a deployment in your Personal Workspace feed instead of the tenant.").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("--no-wait", "Return as soon as the upgrade is accepted instead of waiting for it to finish.").option("--timeout <seconds>", "Seconds to wait for the upgrade to finish (default: 300)", (v) => parseInt(v, 10), 300).option("--poll-interval <ms>", "Milliseconds between status polls (default: 5000)", (v) => parseInt(v, 10), 5000).examples(SOLUTION_DEPLOY_UPGRADE_EXAMPLES).trackedAction(processContext, async (deploymentKey, options) => {
1561
- const result = await upgradeDeploymentAsync(deploymentKey, {
1945
+ program.command("upgrade").description("Upgrade an existing deployment to another published version of its package in place — the CLI equivalent of the Orchestrator UI 'Upgrade' button. Use this when 'deploy run' is blocked because a deployment already exists. The deployment's existing configuration is preserved, so values already set on it (for example a credential asset's secret) are not reset to the package defaults. The package is validated against the target before anything is installed; a validation failure reports the errors and leaves the deployment on its current version. Address the deployment either by key (positional) or by --name with --package-name. Every call this command makes is an external-app (client-credentials) capable Pipelines endpoint, so both forms work from a CI/CD pipeline (on a server that predates the Pipelines deployment lookup, the key form falls back to the Solutions API for a user session); a deployment in a Personal Workspace or folder feed needs a user session, because the server ignores the feed header on client-credentials requests. Waits for the upgrade to finish unless --no-wait is passed; track a running upgrade with 'deploy status <pipeline-deployment-id>'.").argument("[deployment-key]", "Key of the deployment to upgrade, as 'solution deploy list' reports it (Key), or a stored InstallDeploymentKey. Resolved through the Pipelines deployment lookup: the deployment's name, package, current version and feed come from the server, so --package-name and --personal-workspace are not needed. On a server without that lookup, a user session reads the key through the Solutions API instead, where a Personal Workspace deployment needs --personal-workspace. Use either this or --name with --package-name.").option("-n, --name <deployment-name>", "Name of the deployment to upgrade, as reported by 'solution deploy list'. Goes with --package-name. The name is checked to exist first, because the install route would create a new deployment for a name it cannot find; this form never does.").option("--package-name <name>", "The deployment's package, for the --name form. Required there: it identifies the package version to install, and nothing name-keyed in Pipelines reports it.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--version <version>", "Target package version (default: the newest published). Any published version of the same package is accepted, including an older one.").option("--personal-workspace", "With --name: upgrade a deployment in your Personal Workspace feed instead of the tenant. With a key the feed is read from the deployment itself and this flag is not needed, except on a server without the Pipelines deployment lookup, where a key is read on the tenant feed unless you pass it.").option("--discard-draft", "When the deployment has a pending draft (an earlier attempt that never completed, usually one rejected by validation), discard it first and upgrade the live version. Without it such a deployment is refused, because the server would re-run the draft, with the configuration it was rejected for, in place of this upgrade. With --name the draft is found through a user session only; under an external app, pass the deployment key.").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("--no-wait", "Return as soon as the upgrade is accepted instead of waiting for it to finish.").option("--timeout <seconds>", "Seconds to wait for the upgrade to finish (default: 300)", (v) => parseInt(v, 10), 300).option("--poll-interval <ms>", "Milliseconds between status polls (default: 5000)", (v) => parseInt(v, 10), 5000).examples(SOLUTION_DEPLOY_UPGRADE_EXAMPLES).trackedAction(processContext, async (deploymentKey, options) => {
1946
+ const result = await upgradeDeploymentAsync({
1947
+ deploymentKey,
1948
+ deploymentName: options.name,
1949
+ packageName: options.packageName,
1562
1950
  tenant: options.tenant,
1563
1951
  version: options.version,
1564
1952
  personalWorkspace: options.personalWorkspace,
1953
+ discardDraft: options.discardDraft,
1565
1954
  loginValidity: options.loginValidity,
1566
1955
  noWait: options.wait === false,
1567
1956
  timeout: options.timeout,
1568
- pollInterval: options.pollInterval
1957
+ pollInterval: options.pollInterval,
1958
+ signal: processContext.pollSignal
1569
1959
  });
1570
1960
  if (!result.ok) {
1571
1961
  OutputFormatter.error({
1572
1962
  Result: RESULTS.Failure,
1573
1963
  Message: result.message,
1574
- Instructions: result.instructions
1964
+ Instructions: result.instructions,
1965
+ ErrorCode: result.errorCode,
1966
+ Retry: result.retry
1575
1967
  });
1576
1968
  processContext.exit(result.exitCode);
1577
1969
  return;
@@ -1581,10 +1973,26 @@ var registerDeployUpgradeCommand = (program) => {
1581
1973
  Code: "SolutionDeployUpgrade",
1582
1974
  Data: {
1583
1975
  Status: result.status,
1976
+ Operation: result.operation,
1977
+ DeploymentStatus: result.deploymentStatus,
1978
+ Actions: result.actions,
1979
+ ActivationStatus: result.activationStatus,
1980
+ ...result.pendingResources ? {
1981
+ PendingResources: result.pendingResources.map((resource) => ({
1982
+ Kind: resource.kind,
1983
+ Name: resource.name,
1984
+ Type: resource.type ?? null,
1985
+ Reason: resource.reason ?? null
1986
+ }))
1987
+ } : {},
1988
+ ...result.nextSteps ? { NextSteps: result.nextSteps } : {},
1584
1989
  DeploymentName: result.deploymentName,
1585
1990
  FromVersion: result.fromVersion,
1586
1991
  ToVersion: result.toVersion,
1587
- VersionChangeKey: result.versionChangeKey
1992
+ PipelineDeploymentId: result.pipelineDeploymentId,
1993
+ DeploymentKey: result.deploymentKey,
1994
+ InstallDeploymentKey: result.installDeploymentKey,
1995
+ DiscardedDraftKey: result.discardedDraftKey
1588
1996
  }
1589
1997
  });
1590
1998
  });
@@ -1592,12 +2000,13 @@ var registerDeployUpgradeCommand = (program) => {
1592
2000
 
1593
2001
  // src/commands/deploy.ts
1594
2002
  var registerDeployCommand = (program) => {
1595
- const deploy = program.command("deploy").description("Deploy, activate, uninstall, and monitor solution deployments. Typical workflow: run -> check status -> (optionally) activate -> uninstall.");
2003
+ const deploy = program.command("deploy").description("Deploy, activate, uninstall, and monitor solution deployments. Typical workflow: run -> check status -> (optionally) activate -> uninstall -> delete.");
1596
2004
  registerDeployRunCommand(deploy);
1597
2005
  registerDeployStatusCommand(deploy);
1598
2006
  registerDeployConfigCommand(deploy);
1599
2007
  registerDeployActivateCommand(deploy);
1600
2008
  registerDeployUninstallCommand(deploy);
2009
+ registerDeployDeleteCommand(deploy);
1601
2010
  registerDeployListCommand(deploy);
1602
2011
  registerDeployUpgradeCommand(deploy);
1603
2012
  };
@@ -2043,7 +2452,7 @@ var SOLUTION_PACK_EXAMPLES = [
2043
2452
  }
2044
2453
  ];
2045
2454
  var registerPackCommand = (program) => {
2046
- const command = program.command("pack").description("Pack a UiPath solution into a deployable .zip package. Accepts a solution directory (containing .uipx) or a .uis file. Output is used with 'solution publish' to upload to UiPath. Pass --dry-run to check that the solution packs without producing a package.").argument("<solutionPath>", "Path to a solution directory (containing .uipx) or a .uis file").argument("[output-path]", "Output directory where the packed solution will be saved. Required unless --dry-run is set.").option("-n, --name <name>", "Package name (default: solution folder name or .uis file name)").option("-v, --version <version>", "Package version (default: 1.0.0)", "1.0.0").addOption(new Option("--solution-type <type>", "What kind of solution this is. Omitted by default, which means a standard solution.").choices(["standard", "vertical"]).hideHelp()).option("--nuget-sources-config-path <path>", "Path to NuGet sources configuration file").option("--exclude-configured-sources", "Resolve project dependencies only from the tenant feeds and any --nuget-sources-config-path. Drops the built-in UiPath and nuget.org feeds, so a dependency that is not on those feeds fails to restore.").option("--feed-folder <name>", "Resolve project dependencies from this Orchestrator folder's library feed instead of every tenant feed. Accepts a folder name or fully qualified path.").option("--signing-certificate-path <path>", "Path to .pfx certificate file used to sign each packed project .nupkg").option("--signing-certificate-password <password>", "Certificate password. Use env.ENV_NAME to read from an environment variable.").option("--signing-timestamp-server <url>", "Timestamp server URL").option("--skip-analyze", "Skip the workflow analyzer for every RPA project in the solution. Compilation and validation still run.").option("--governance-file-path <path>", "Analyze every RPA project against this local governance policy file, instead of the analyzer rules shipped with the WorkflowCompiler. When you are signed in the tenant is asked first — about StudioWeb unless --governance-product names another product — and this file is refused if the tenant publishes a policy of its own.").option("--governance-product <product>", "Analyze every RPA project against the governance policy published in AutomationOps for the signed-in tenant. The value is the product whose policy is downloaded, e.g. StudioWeb, Development, Business.").addOption(new Option("--automation-ops-profile <profile>").hideHelp());
2455
+ const command = program.command("pack").description("Pack a UiPath solution into a deployable .zip package. Accepts a solution directory (containing .uipx) or a .uis file. Output is used with 'solution publish' to upload to UiPath. Pass --dry-run to check that the solution packs without producing a package.").argument("<solutionPath>", "Path to a solution directory (containing .uipx) or a .uis file").argument("[output-path]", "Output directory where the packed solution will be saved. Required unless --dry-run is set.").option("-n, --name <name>", "Package name (default: solution folder name or .uis file name)").option("-v, --version <version>", "Package version (default: 1.0.0)", "1.0.0").addOption(new Option("--solution-type <type>", "What kind of solution this is. Omitted by default, which means a standard solution.").choices(["standard", "vertical"]).hideHelp()).option("--nuget-sources-config-path <path>", "Path to NuGet sources configuration file").option("--exclude-configured-sources", "Resolve project dependencies only from the tenant feeds and any --nuget-sources-config-path. Drops the built-in UiPath and nuget.org feeds, so a dependency that is not on those feeds fails to restore.").option("--feed-folder <name>", "Resolve project dependencies from this Orchestrator folder's library feed instead of every tenant feed. Accepts a folder name or fully qualified path.").option("--signing-certificate-path <path>", "Path to .pfx certificate file used to sign each packed project .nupkg").option("--signing-certificate-password <password>", "Certificate password. Use env.ENV_NAME to read from an environment variable.").option("--signing-timestamp-server <url>", "Timestamp server URL").option("--skip-analyze", "Skip the workflow analyzer for every RPA project in the solution. Compilation and validation still run.").option("--governance-file-path <path>", "Analyze every RPA project against this local governance policy file, instead of the analyzer rules shipped with the WorkflowCompiler. When you are signed in the tenant is asked first — about StudioWeb unless --governance-product names another product — and when the tenant publishes a policy of its own, that policy is used instead and this file is ignored with a warning.").option("--governance-product <product>", "Analyze every RPA project against the governance policy published in AutomationOps for the signed-in tenant. The value is the product whose policy is downloaded, e.g. StudioWeb, Development, Business.").addOption(new Option("--automation-ops-profile <profile>").hideHelp());
2047
2456
  registerPackageMetadataOptions(command).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("--dry-run", "Run the full pack pipeline against a temporary directory and discard the output. Catches pack-time failures; does not inspect the produced package contents.").examples(SOLUTION_PACK_EXAMPLES).trackedAction(processContext, async (solutionPath, outputPath, options) => {
2048
2457
  if (!options.dryRun && outputPath === undefined) {
2049
2458
  OutputFormatter.error({
@@ -2122,16 +2531,6 @@ var SOLUTION_PACKAGES_DELETE_EXAMPLES = [
2122
2531
  }
2123
2532
  }
2124
2533
  ];
2125
- var SEARCH_PAGE_SIZE = 50;
2126
- function scopeName(scope) {
2127
- if (scope.kind === "tenant") {
2128
- return "the tenant feed";
2129
- }
2130
- if (scope.name) {
2131
- return `'${scope.name}'`;
2132
- }
2133
- return scope.kind === "personal" ? "the Personal Workspace feed" : "the selected feed";
2134
- }
2135
2534
  function packageDeleteFailureInstructions(scope, packageName) {
2136
2535
  const base = "Check that the package name and version are correct and that you have permission to delete it.";
2137
2536
  if (scope.kind === "personal") {
@@ -2142,70 +2541,12 @@ function packageDeleteFailureInstructions(scope, packageName) {
2142
2541
  }
2143
2542
  return `${base} If the package was published to a Personal Workspace or folder feed, add --personal-workspace or --feed.`;
2144
2543
  }
2145
- async function resolvePackageVersionKey(auth, scope, packageName, packageVersion) {
2146
- const config = new Configuration2({
2147
- basePath: auth.basePath,
2148
- accessToken: auth.accessToken
2149
- });
2150
- const searchApi = new SearchApi(config);
2151
- const pkg = await findPackage(searchApi, scope, packageName);
2152
- if (pkg.latestVersion === packageVersion) {
2153
- return pkg.packageVersionKey;
2154
- }
2155
- for (let skip = 0;; ) {
2156
- const page = await searchPackageVersions({ basePath: auth.basePath, accessToken: auth.accessToken }, pkg.key, {
2157
- searchTerm: packageVersion,
2158
- take: SEARCH_PAGE_SIZE,
2159
- skip,
2160
- excludeInvalidPackages: true
2161
- }, scope.folderKey);
2162
- const match = page.values.find((version) => version.version === packageVersion);
2163
- if (match) {
2164
- return match.key;
2165
- }
2166
- if (page.values.length < SEARCH_PAGE_SIZE) {
2167
- throw new Error(`Package version '${packageName}@${packageVersion}' was not found in ${scopeName(scope)}.`);
2168
- }
2169
- skip += page.values.length;
2170
- }
2171
- }
2172
- async function findPackage(searchApi, scope, packageName) {
2173
- for (let skip = 0;; ) {
2174
- const packages = await searchApi.searchSearchPackages({
2175
- searchFilter: {
2176
- searchTerm: packageName,
2177
- take: SEARCH_PAGE_SIZE,
2178
- skip
2179
- }
2180
- }, feedScopeInitOverride(scope));
2181
- const values = packages.values ?? [];
2182
- const match = values.find((pkg) => pkg.name === packageName);
2183
- if (match) {
2184
- return match;
2185
- }
2186
- if (values.length < SEARCH_PAGE_SIZE) {
2187
- throw new Error(`Package '${packageName}' was not found in ${scopeName(scope)}.`);
2188
- }
2189
- skip += values.length;
2190
- }
2191
- }
2192
- async function deleteTenantPackageVersion(auth, packageName, packageVersion) {
2544
+ async function deletePackageVersion(auth, scope, packageName, packageVersion) {
2193
2545
  const api = new PipelinesApi(new Configuration({
2194
2546
  basePath: auth.basePath,
2195
2547
  accessToken: auth.accessToken
2196
2548
  }));
2197
- await api.pipelinesPackageDelete({
2198
- packageName,
2199
- packageVersion
2200
- });
2201
- }
2202
- async function deleteScopedPackageVersion(auth, scope, packageName, packageVersion) {
2203
- const packageVersionKey = await resolvePackageVersionKey(auth, scope, packageName, packageVersion);
2204
- const packagesApi = new PackagesApi(new Configuration2({
2205
- basePath: auth.basePath,
2206
- accessToken: auth.accessToken
2207
- }));
2208
- await packagesApi.packagesDeleteVersion({ packageVersionKey }, feedScopeInitOverride(scope));
2549
+ await api.pipelinesPackageDelete({ packageName, packageVersion }, feedScopeInitOverride(scope));
2209
2550
  }
2210
2551
  var registerPackagesDeleteCommand = (program) => {
2211
2552
  const command = program.command("delete").description("Delete a specific version of a solution package. " + "Use 'solution packages list' to find available package names and versions.").argument("<package-name>", "The name of the package").argument("<package-version>", "The version to delete (e.g. 1.0.0)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("-y, --yes", "Confirm this irreversible operation (required; the CLI never prompts)").option("--personal-workspace", "Delete the package version from the current user's Personal Workspace feed.");
@@ -2227,22 +2568,13 @@ var registerPackagesDeleteCommand = (program) => {
2227
2568
  processContext.exit(1);
2228
2569
  return;
2229
2570
  }
2230
- const [scopeError, scope] = await catchError(resolveFeedScope({
2231
- personalWorkspace: options.personalWorkspace,
2232
- feed: options.feed,
2233
- tenant: options.tenant,
2234
- loginValidity: options.loginValidity
2235
- }));
2236
- if (scopeError) {
2237
- OutputFormatter.error({
2238
- Result: RESULTS.Failure,
2239
- Message: scopeError.message,
2240
- Instructions: feedResolutionFailureInstructions(options)
2241
- });
2571
+ const [scopeFailure, scope] = await resolveFeedScopeOrFailureAsync(options, auth);
2572
+ if (scopeFailure) {
2573
+ OutputFormatter.error(scopeFailure);
2242
2574
  processContext.exit(1);
2243
2575
  return;
2244
2576
  }
2245
- const [deleteError] = await catchError(scope.kind === "tenant" ? deleteTenantPackageVersion(auth, packageName, packageVersion) : deleteScopedPackageVersion(auth, scope, packageName, packageVersion));
2577
+ const [deleteError] = await catchError(deletePackageVersion(auth, scope, packageName, packageVersion));
2246
2578
  if (deleteError) {
2247
2579
  const { message } = await extractErrorDetails(deleteError);
2248
2580
  OutputFormatter.error({
@@ -2461,9 +2793,9 @@ var SOLUTION_PACKAGES_LIST_EXAMPLES = [
2461
2793
  Code: "SolutionPackagesList",
2462
2794
  Data: [
2463
2795
  {
2464
- packageName: "MyPackage",
2465
- packageVersion: "1.0.0",
2466
- publishDate: "2025-04-15T10:30:00Z"
2796
+ Name: "MyPackage",
2797
+ LatestVersion: "1.0.0",
2798
+ PublishDate: "2025-04-15T10:30:00Z"
2467
2799
  }
2468
2800
  ]
2469
2801
  }
@@ -2488,7 +2820,10 @@ var registerPackagesListCommand = (program) => {
2488
2820
  OutputFormatter.error({
2489
2821
  Result: RESULTS.Failure,
2490
2822
  Message: result.message,
2491
- Instructions: result.instructions
2823
+ Instructions: result.instructions,
2824
+ ErrorCode: result.errorCode,
2825
+ Retry: result.retry,
2826
+ ...result.context ? { Context: result.context } : {}
2492
2827
  });
2493
2828
  processContext.exit(result.exitCode);
2494
2829
  return;
@@ -3129,12 +3464,12 @@ var registerProjectPublishCommand = (project) => {
3129
3464
  return;
3130
3465
  }
3131
3466
  trackShipSucceeded({
3132
- ship_kind: "publish",
3133
- target: "solution_package_feed",
3134
- project_type: "solution_project",
3135
- command_name: "uip.solution.projects.publish",
3136
- package_name: options.packageName,
3137
- package_version: options.packageVersion
3467
+ [ShipDimensions.ShipKind]: "publish",
3468
+ [ShipDimensions.Target]: "solution_package_feed",
3469
+ [ShipDimensions.ProjectType]: "solution_project",
3470
+ [CommandDimensions.CommandName]: "uip solution projects publish",
3471
+ [ShipDimensions.PackageName]: options.packageName,
3472
+ [ShipDimensions.PackageVersion]: options.packageVersion
3138
3473
  });
3139
3474
  OutputFormatter.success({
3140
3475
  Result: RESULTS.Success,
@@ -3529,21 +3864,21 @@ async function inspectSolutionPackageProjectTypes(packagePath) {
3529
3864
  const fs = getFileSystem();
3530
3865
  const [statError, stats] = await catchError(fs.stat(packagePath));
3531
3866
  if (statError || !stats) {
3532
- logger.debug(`[uip.ship.succeeded] Could not stat solution package for project type telemetry: ${statError?.message ?? "no stats"}`);
3867
+ logger.debug(`[Cli.ShipSucceeded] Could not stat solution package for project type telemetry: ${statError?.message ?? "no stats"}`);
3533
3868
  return { projectType: "unknown" };
3534
3869
  }
3535
3870
  if (stats.size > MAX_INSPECTABLE_PACKAGE_BYTES) {
3536
- logger.debug(`[uip.ship.succeeded] Solution package is ${stats.size} bytes, over the ${MAX_INSPECTABLE_PACKAGE_BYTES}-byte inspection cap; skipping project type telemetry.`);
3871
+ logger.debug(`[Cli.ShipSucceeded] Solution package is ${stats.size} bytes, over the ${MAX_INSPECTABLE_PACKAGE_BYTES}-byte inspection cap; skipping project type telemetry.`);
3537
3872
  return { projectType: "unknown" };
3538
3873
  }
3539
3874
  const [readError, archive] = await catchError(fs.readFile(packagePath));
3540
3875
  if (readError || !archive) {
3541
- logger.debug(`[uip.ship.succeeded] Could not read solution package for project type telemetry: ${readError?.message ?? "empty archive"}`);
3876
+ logger.debug(`[Cli.ShipSucceeded] Could not read solution package for project type telemetry: ${readError?.message ?? "empty archive"}`);
3542
3877
  return { projectType: "unknown" };
3543
3878
  }
3544
3879
  const [unzipError, entries] = await catchError(unzipProjectManifests(new Uint8Array(archive)));
3545
3880
  if (unzipError || !entries) {
3546
- logger.debug(`[uip.ship.succeeded] Could not inspect solution package zip: ${unzipError?.message ?? "no entries"}`);
3881
+ logger.debug(`[Cli.ShipSucceeded] Could not inspect solution package zip: ${unzipError?.message ?? "no entries"}`);
3547
3882
  return { projectType: "unknown" };
3548
3883
  }
3549
3884
  const decoder = new TextDecoder;
@@ -3554,7 +3889,7 @@ async function inspectSolutionPackageProjectTypes(packagePath) {
3554
3889
  }
3555
3890
  const [parseError, parsedTypes] = await catchError(Promise.resolve().then(() => readProjectTypesFromUipx(decoder.decode(entryBytes))));
3556
3891
  if (parseError) {
3557
- logger.debug(`[uip.ship.succeeded] Could not parse ${entryName} for project type telemetry: ${parseError.message}`);
3892
+ logger.debug(`[Cli.ShipSucceeded] Could not parse ${entryName} for project type telemetry: ${parseError.message}`);
3558
3893
  continue;
3559
3894
  }
3560
3895
  projectTypes.push(...parsedTypes);
@@ -3565,8 +3900,8 @@ function trackSolutionShipSucceeded(payload) {
3565
3900
  const { projectTypeSummary, ...rest } = payload;
3566
3901
  return trackShipSucceeded({
3567
3902
  ...rest,
3568
- project_type: projectTypeSummary.projectType,
3569
- project_types: projectTypeSummary.projectTypes
3903
+ [ShipDimensions.ProjectType]: projectTypeSummary.projectType,
3904
+ [ShipDimensions.ProjectTypes]: projectTypeSummary.projectTypes
3570
3905
  });
3571
3906
  }
3572
3907
 
@@ -3716,13 +4051,13 @@ var registerPublishCommand = (program) => {
3716
4051
  });
3717
4052
  const projectTypeSummary = await inspectSolutionPackageProjectTypes(packagePath);
3718
4053
  trackSolutionShipSucceeded({
3719
- ship_kind: "publish",
3720
- target: result.feedKind === "personal" ? "personal_workspace_solution_feed" : result.feedKind === "folder" ? "folder_solution_feed" : "tenant_solution_feed",
3721
- command_name: "uip.solution.publish",
3722
- artifact_correlation_key: result.packageVersionKey,
3723
- package_version_key: result.packageVersionKey,
3724
- package_name: result.packageName,
3725
- package_version: result.packageVersion,
4054
+ [ShipDimensions.ShipKind]: "publish",
4055
+ [ShipDimensions.Target]: result.feedKind === "personal" ? "personal_workspace_solution_feed" : result.feedKind === "folder" ? "folder_solution_feed" : "tenant_solution_feed",
4056
+ [CommandDimensions.CommandName]: "uip solution publish",
4057
+ [ShipDimensions.ArtifactCorrelationKey]: result.packageVersionKey,
4058
+ [ShipDimensions.PackageVersionKey]: result.packageVersionKey,
4059
+ [ShipDimensions.PackageName]: result.packageName,
4060
+ [ShipDimensions.PackageVersion]: result.packageVersion,
3726
4061
  projectTypeSummary
3727
4062
  });
3728
4063
  });
@@ -3765,7 +4100,7 @@ var RESOURCE_ADD_EXAMPLES = [
3765
4100
  }
3766
4101
  ];
3767
4102
  var registerResourceAddCommand = (resource) => {
3768
- resource.command("add").description("Add a resource to the solution. Use --source local to create a virtual stub, " + "or --source remote to import an existing Orchestrator resource. Idempotent: " + "if a resource with the same (kind, name, folder) already exists, it is returned unchanged.").option("--source <source>", "Resource source: local (virtual stub) or remote (import from Orchestrator)").option("--kind <kind>", "Resource kind (e.g. Queue, Asset, Bucket, Process, Connection, App, Index, Trigger, Entity, ChoiceSet). Case-insensitive, matched against SDK metadata.").option("--name <name>", "Resource name").option("--type <type>", "Resource subtype (e.g. Text/Bool/Integer for Asset, connector type for Connection)").option("--folder-path <path>", "Orchestrator folder path for remote lookup. Required to disambiguate when more than one remote match exists. Not valid with --source local.").option("--cloud-key <guid>", "Skip remote search and import this exact resource key. Only valid with --source remote.").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).examples(RESOURCE_ADD_EXAMPLES).trackedAction(processContext, async (options) => {
4103
+ resource.command("add").description("Add a resource to the solution. Use --source local to create a virtual stub, " + "or --source remote to import an existing Orchestrator resource. Idempotent: " + "if a resource with the same (kind, name, folder) already exists, it is returned unchanged.").option("--source <source>", "Resource source: local (virtual stub) or remote (import from Orchestrator)").option("--kind <kind>", "Resource kind (e.g. Queue, Asset, Bucket, Process, Connection, App, Index, Trigger, Entity, ChoiceSet). Case-insensitive, matched against SDK metadata.").option("--name <name>", "Resource name").option("--type <type>", "Resource subtype, case-insensitive (e.g. Text/Integer/Bool/Credential/Secret or stringAsset/credentialAsset for Asset, connector type for Connection). Rejected when the kind does not declare it or has no subtypes (Queue); with --source remote it must match the resource's type and narrows same-name matches.").option("--folder-path <path>", "Orchestrator folder path for remote lookup. Required to disambiguate when more than one remote match exists. Not valid with --source local.").option("--cloud-key <guid>", "Skip remote search and import this exact resource key. Only valid with --source remote.").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).examples(RESOURCE_ADD_EXAMPLES).trackedAction(processContext, async (options) => {
3769
4104
  const validation = validateOptions(options);
3770
4105
  if (!validation.ok) {
3771
4106
  OutputFormatter.error({
@@ -3856,6 +4191,10 @@ var registerResourceAddCommand = (resource) => {
3856
4191
  OutputFormatter.error({
3857
4192
  Result: RESULTS.Failure,
3858
4193
  Message: outcome.message,
4194
+ ...outcome.invalidArgument ? {
4195
+ ErrorCode: "invalid_argument",
4196
+ Retry: "RetryWillNotFix"
4197
+ } : {},
3859
4198
  Instructions: outcome.instructions
3860
4199
  });
3861
4200
  processContext.exit(1);
@@ -3889,15 +4228,6 @@ function canonicalizeKind(kind) {
3889
4228
  return trimmed;
3890
4229
  return trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
3891
4230
  }
3892
- var MAX_NAME_LENGTH = 256;
3893
- var UNSAFE_NAME_CHARS = /[\\/:*?"<>|]/;
3894
- function hasControlChar(s) {
3895
- for (let i = 0;i < s.length; i++) {
3896
- if (s.charCodeAt(i) < 32)
3897
- return true;
3898
- }
3899
- return false;
3900
- }
3901
4231
  var GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3902
4232
  function validateOptions(options) {
3903
4233
  if (!options.source) {
@@ -3929,18 +4259,12 @@ function validateOptions(options) {
3929
4259
  instructions: "Pass --name <resource-name>"
3930
4260
  };
3931
4261
  }
3932
- if (options.name.length > MAX_NAME_LENGTH) {
3933
- return {
3934
- ok: false,
3935
- message: `--name exceeds the ${MAX_NAME_LENGTH}-character limit (got ${options.name.length})`,
3936
- instructions: "Shorten the resource name. Orchestrator name limits are kind-specific (queues cap at 50, assets at 256)."
3937
- };
3938
- }
3939
- if (UNSAFE_NAME_CHARS.test(options.name) || hasControlChar(options.name)) {
4262
+ const nameCheck = validateResourceName(options.name);
4263
+ if (!nameCheck.ok) {
3940
4264
  return {
3941
4265
  ok: false,
3942
- message: "--name contains unsafe characters",
3943
- instructions: 'Resource names cannot contain path separators (/, \\), control characters, or any of: : * ? " < > |'
4266
+ message: nameCheck.message,
4267
+ instructions: nameCheck.instructions
3944
4268
  };
3945
4269
  }
3946
4270
  if (options.cloudKey && source !== "remote") {
@@ -3976,10 +4300,53 @@ function validateOptions(options) {
3976
4300
  }
3977
4301
  };
3978
4302
  }
3979
- async function runAdd(builder, services, input) {
4303
+ async function resolveTypeInput(services, kind, type) {
4304
+ if (type === undefined)
4305
+ return { ok: true, type };
4306
+ const metadata = await resolveResourceKindMetadata(services, kind, type);
4307
+ if (metadata?.typeMatched) {
4308
+ return { ok: true, type: metadata.type ?? type };
4309
+ }
4310
+ const subtypes = metadata?.subtypes ?? [];
4311
+ const useOneOf = `Use one of: ${formatResourceSubtypes(subtypes)}. Either name works, case-insensitive.`;
4312
+ if (type.trim() === "") {
4313
+ return refuseType("--type is empty", subtypes.length > 0 ? `${useOneOf} Or drop --type.` : "Drop --type.");
4314
+ }
4315
+ if (!metadata)
4316
+ return { ok: true, type };
4317
+ return subtypes.length > 0 ? refuseType(`Unknown --type "${type}" for kind ${kind}`, useOneOf) : refuseType(`--type does not apply to kind ${kind}`, `A ${kind} has no subtypes. Drop --type.`);
4318
+ }
4319
+ function refuseType(message, instructions) {
4320
+ return {
4321
+ ok: false,
4322
+ outcome: {
4323
+ kind: "error",
4324
+ message,
4325
+ instructions,
4326
+ invalidArgument: true
4327
+ }
4328
+ };
4329
+ }
4330
+ function formatCandidates(matches) {
4331
+ return matches.map((m) => ` - Folder=${m.folder?.fullyQualifiedName ?? "<none>"} Type=${m.type ?? "<none>"} Key=${m.key}`).join(`
4332
+ `);
4333
+ }
4334
+ async function runAdd(builder, services, rawInput) {
4335
+ const typeResolution = await resolveTypeInput(services, rawInput.kind, rawInput.type);
4336
+ if (!typeResolution.ok)
4337
+ return typeResolution.outcome;
4338
+ const input = { ...rawInput, type: typeResolution.type };
3980
4339
  const solution = await builder.context.loadAsync();
3981
4340
  if (input.source === "local") {
3982
4341
  const existing = findMatchingLocalResource(solution.resources, input.kind, input.name, input.folderPath);
4342
+ if (existing && input.type !== undefined && !sameResourceSubtype(existing.type, input.type)) {
4343
+ return {
4344
+ kind: "error",
4345
+ message: `A local ${input.kind} named ${existing.name} already exists with type ${existing.type ?? "<none>"}, not ${input.type}`,
4346
+ instructions: existing.type ? `Drop --type to reuse it, pass --type ${existing.type}, or pick another --name.` : "Drop --type to reuse it, or pick another --name.",
4347
+ invalidArgument: true
4348
+ };
4349
+ }
3983
4350
  if (existing) {
3984
4351
  return {
3985
4352
  kind: "success",
@@ -4026,27 +4393,36 @@ async function runAdd(builder, services, input) {
4026
4393
  instructions: searchError.message
4027
4394
  };
4028
4395
  }
4029
- const filtered = filterMatchesByFolder(matches, input.folderPath);
4030
- if (filtered.length === 0) {
4396
+ const inFolder = filterMatchesByFolder(matches, input.folderPath);
4397
+ if (inFolder.length === 0) {
4031
4398
  return {
4032
4399
  kind: "error",
4033
4400
  message: `No remote resource found matching kind=${input.kind} name=${input.name}`,
4034
4401
  instructions: `Use 'uip solution resources list --source remote --kind ${input.kind} --search ${input.name}' to discover candidates, or pass --source local to create a local stub.`
4035
4402
  };
4036
4403
  }
4404
+ const wantedType = input.type;
4405
+ const filtered = wantedType === undefined ? inFolder : inFolder.filter((m) => sameResourceSubtype(m.type, wantedType));
4406
+ if (filtered.length === 0) {
4407
+ return {
4408
+ kind: "error",
4409
+ message: `No remote ${input.kind} named ${input.name} has type ${wantedType}`,
4410
+ instructions: `Drop --type, or pass the type of the one you want:
4411
+ ${formatCandidates(inFolder)}`,
4412
+ invalidArgument: true
4413
+ };
4414
+ }
4037
4415
  if (filtered.length > 1) {
4038
- const candidates = filtered.map((m) => ` - Folder=${m.folder?.fullyQualifiedName ?? "<none>"} Type=${m.type ?? "<none>"} Key=${m.key}`).join(`
4039
- `);
4040
4416
  return {
4041
4417
  kind: "error",
4042
4418
  message: `Ambiguous match: ${filtered.length} remote resources matching kind=${input.kind} name=${input.name}`,
4043
- instructions: `Candidates (disambiguate with --cloud-key <key>; --folder-path only helps when they are in different folders):
4044
- ${candidates}`
4419
+ instructions: `Candidates (disambiguate with --cloud-key <key>; --folder-path and --type only help when they differ in folder or type):
4420
+ ${formatCandidates(filtered)}`
4045
4421
  };
4046
4422
  }
4047
4423
  cloudKey = filtered[0].key;
4048
4424
  matchFolder = filtered[0].folder;
4049
- resolvedType = resolvedType ?? filtered[0].type;
4425
+ resolvedType = filtered[0].type ?? resolvedType;
4050
4426
  } else {
4051
4427
  const [lookupError, match] = await catchError(findResourceByKeyInRcs(builder, input.kind, cloudKey, input.folderPath, true));
4052
4428
  if (lookupError) {
@@ -4057,8 +4433,16 @@ ${candidates}`
4057
4433
  };
4058
4434
  }
4059
4435
  if (match) {
4436
+ if (input.type !== undefined && !sameResourceSubtype(match.type, input.type)) {
4437
+ return {
4438
+ kind: "error",
4439
+ message: `Remote ${input.kind} ${cloudKey} has type ${match.type ?? "<none>"}, not ${input.type}`,
4440
+ instructions: match.type ? `Drop --type, or pass --type ${match.type}.` : "Drop --type.",
4441
+ invalidArgument: true
4442
+ };
4443
+ }
4060
4444
  matchFolder = match.folder;
4061
- resolvedType = resolvedType ?? match.type;
4445
+ resolvedType = match.type ?? resolvedType;
4062
4446
  }
4063
4447
  }
4064
4448
  const existingByKey = solution.resources.find((r) => r.key.toLowerCase() === cloudKey);
@@ -4622,7 +5006,7 @@ async function getRemoteConfiguration(services, resourceKey, includeDependencies
4622
5006
  if (!reference) {
4623
5007
  throw new Error(`Resource '${resourceKey}' was not found in the solution or in the resource catalog`);
4624
5008
  }
4625
- const importer = services.container.resolve(Tokens.IImportResourceHelper);
5009
+ const { importer } = getRemoteResourceClients(services);
4626
5010
  const payload = await importer.exportResourceAsync(reference);
4627
5011
  const definitions = payload.resourceDefinitions ?? [];
4628
5012
  const primary = definitions.find((d) => d.key === resourceKey) ?? definitions[0];
@@ -4660,7 +5044,7 @@ async function attachLiveSpecOnMismatchAsync(services, resource, config) {
4660
5044
  if (overwriteData?.matchingOverwriteConfiguration !== false || !overwrite || !resource) {
4661
5045
  return;
4662
5046
  }
4663
- const importer = services.container.resolve(Tokens.IImportResourceHelper);
5047
+ const { importer } = getRemoteResourceClients(services);
4664
5048
  const [exportError, exported] = await catchError(importer.exportResourceOverwriteAsync(resource, overwrite));
4665
5049
  if (exportError || !exported?.spec) {
4666
5050
  return;
@@ -4690,30 +5074,8 @@ async function refreshArtefactSpecAsync(builder, data, includeDeps) {
4690
5074
  return requestedResource;
4691
5075
  }
4692
5076
  async function findRemoteReferenceByKey(services, resourceKey) {
4693
- const rcs = services.container.resolve(Tokens.IResourceCatalogClientProxy);
4694
- let pageCursor;
4695
- do {
4696
- const result = await rcs.searchFolderEntities({
4697
- pageSize: 100,
4698
- pageCursor
4699
- });
4700
- for (const item of result.items ?? []) {
4701
- if (item.entityKey === resourceKey) {
4702
- return {
4703
- kind: item.entityType ?? "",
4704
- type: item.entitySubType ?? undefined,
4705
- key: item.entityKey ?? resourceKey,
4706
- name: item.entityName ?? undefined,
4707
- folder: item.fullyQualifiedName ? {
4708
- fullyQualifiedName: item.fullyQualifiedName,
4709
- folderKey: item.folderKey ?? undefined
4710
- } : undefined
4711
- };
4712
- }
4713
- }
4714
- pageCursor = result.nextPage ?? undefined;
4715
- } while (pageCursor);
4716
- return null;
5077
+ const entity = await findCatalogEntityAsync(getRemoteResourceClients(services).catalog, {}, (item) => item.entityKey === resourceKey);
5078
+ return entity ? toResourceReference(entity) : null;
4717
5079
  }
4718
5080
 
4719
5081
  // src/services/resource-version-lookup.ts
@@ -4735,7 +5097,7 @@ async function resolveResourceVersionsAsync(services, builder, targets) {
4735
5097
  if (versioned.length === 0) {
4736
5098
  return versions;
4737
5099
  }
4738
- const importer = services.container.resolve(Tokens.IImportResourceHelper);
5100
+ const { importer } = getRemoteResourceClients(services);
4739
5101
  for (let i = 0;i < versioned.length; i += LOOKUP_CONCURRENCY) {
4740
5102
  const batch = versioned.slice(i, i + LOOKUP_CONCURRENCY);
4741
5103
  const resolved = await Promise.all(batch.map((target) => target.source === "Local" ? readLocalVersionAsync(builder, target) : readRemoteVersionAsync(importer, target)));
@@ -4766,13 +5128,11 @@ async function readRemoteVersionAsync(importer, target) {
4766
5128
  folderKey: target.folderKey
4767
5129
  } : undefined
4768
5130
  };
4769
- const [error, payload] = await catchError(importer.exportResourceAsync(reference));
4770
- if (error || !payload) {
5131
+ const [error, primary] = await catchError(exportResourceDefinitionAsync(importer, reference));
5132
+ if (error) {
4771
5133
  warnLookupFailed(target, error);
4772
5134
  return [target.id, undefined];
4773
5135
  }
4774
- const definitions = payload.resourceDefinitions ?? [];
4775
- const primary = definitions.find((d) => d.key === target.key);
4776
5136
  if (!primary) {
4777
5137
  logger.warn(`Export for ${target.kind} '${target.name ?? target.key}' returned no definition for that key; version omitted.`);
4778
5138
  return [target.id, undefined];
@@ -4780,18 +5140,7 @@ async function readRemoteVersionAsync(importer, target) {
4780
5140
  return [target.id, readVersion(primary.spec)];
4781
5141
  }
4782
5142
  function readVersion(spec) {
4783
- if (!spec) {
4784
- return;
4785
- }
4786
- let value = spec[VERSION_PROPERTY];
4787
- if (value === undefined) {
4788
- for (const [key, candidate] of Object.entries(spec)) {
4789
- if (key.toLowerCase() === VERSION_PROPERTY) {
4790
- value = candidate;
4791
- break;
4792
- }
4793
- }
4794
- }
5143
+ const value = readSpecProperty(spec, VERSION_PROPERTY);
4795
5144
  if (value === undefined || value === null || value === "") {
4796
5145
  return;
4797
5146
  }
@@ -4839,7 +5188,7 @@ var RESOURCE_LIST_EXAMPLES = [
4839
5188
  }
4840
5189
  ];
4841
5190
  var registerResourceListCommand = (resource) => {
4842
- resource.command("list").description("List resources in the solution and/or available in Orchestrator. " + "Shows local solution resources, remote Orchestrator resources, or both.").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").option("--kind <kind>", "Filter by resource kind (e.g. Queue, Asset, Bucket, Process, Connection, App, Index, Trigger, Entity, ChoiceSet). Any kind RCS indexes is accepted.").option("--search <term>", "Filter resources by name").option("--source <source>", "Resource source: all, local, or remote (default: all)", "all").option("--include-version", "Also report each resource's version, for the kinds that carry one (app, appVersion, package, process). " + "Remote rows report the version live in the folder, local rows the version the solution pins. " + "Costs one extra call per resource, so it is off by default.").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).examples(RESOURCE_LIST_EXAMPLES).trackedAction(processContext, async (options) => {
5191
+ resource.command("list").description("List resources in the solution and/or available in Orchestrator. " + "Shows local solution resources, remote Orchestrator resources, or both.").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").option("--kind <kind>", "Filter by resource kind (e.g. Queue, Asset, Bucket, Process, Connection, App, Index, Trigger, Entity, ChoiceSet). Any kind RCS indexes is accepted.").option("--search <term>", "Filter resources by name").option("--source <source>", "Resource source: all, local, or remote (default: all)", "all").option("--include-version", "Also report each resource's version, for the kinds that carry one (app, appVersion, package, process). " + "Remote rows report the version live in the folder, local rows the version the solution pins. " + "Costs one extra call per resource, so it is off by default.").option("-l, --limit <number>", "Number of resources to return", parseLimit, DEFAULT_PAGE_SIZE).option("--offset <number>", "Only 0 is accepted: the resource catalog pages by cursor. Use --next-page instead", parseOffset).option("--next-page <cursor>", "Cursor from a previous response's Pagination.NextPage").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).examples(RESOURCE_LIST_EXAMPLES).trackedAction(processContext, async (options) => {
4843
5192
  const solutionPath = options.solutionFolder ?? ".";
4844
5193
  const fs = getFileSystem();
4845
5194
  const resolvedPath = fs.path.resolve(fs.env.cwd(), solutionPath);
@@ -4863,6 +5212,10 @@ var registerResourceListCommand = (resource) => {
4863
5212
  processContext.exit(1);
4864
5213
  return;
4865
5214
  }
5215
+ const start = resolveListStart(options);
5216
+ if (start === undefined) {
5217
+ return;
5218
+ }
4866
5219
  const normalizedKind = options.kind;
4867
5220
  const [authError] = await catchError(getSolutionAuthContext({
4868
5221
  loginValidity: options.loginValidity
@@ -4896,7 +5249,7 @@ var registerResourceListCommand = (resource) => {
4896
5249
  processContext.exit(1);
4897
5250
  return;
4898
5251
  }
4899
- const [listError, data] = await catchError(listResources(builder, services, source, normalizedKind, options.search, options.includeVersion === true));
5252
+ const [listError, data] = await catchError(listResources(builder, services, source, options.limit, start, normalizedKind, options.search, options.includeVersion === true));
4900
5253
  await builder.disposeAsync();
4901
5254
  if (listError) {
4902
5255
  OutputFormatter.error({
@@ -4907,37 +5260,106 @@ var registerResourceListCommand = (resource) => {
4907
5260
  processContext.exit(1);
4908
5261
  return;
4909
5262
  }
5263
+ const { rows, next } = data;
4910
5264
  OutputFormatter.success({
4911
5265
  Result: RESULTS.Success,
4912
5266
  Code: "ResourceList",
4913
- Data: data
5267
+ Data: rows,
5268
+ Pagination: new Pagination({
5269
+ returned: rows.length,
5270
+ limit: options.limit,
5271
+ hasMore: next !== undefined,
5272
+ nextPage: next && encodeListPosition(next)
5273
+ })
4914
5274
  });
4915
5275
  });
4916
5276
  };
4917
- async function listResources(builder, services, source, kind, search, includeVersion = false) {
4918
- const entries = await collectResources(builder, services, source, kind, search);
4919
- if (includeVersion) {
4920
- await annotateVersions(services, builder, entries);
5277
+ function resolveListStart(options) {
5278
+ if (options.offset !== undefined && options.offset !== 0) {
5279
+ failListArgument("--offset is not supported when listing resources", "The resource catalog pages by cursor, not by offset. Drop --offset, " + "then pass the Pagination.NextPage value from the previous " + "response to --next-page.");
5280
+ return;
5281
+ }
5282
+ if (options.nextPage === undefined) {
5283
+ return { at: "local", index: 0 };
4921
5284
  }
4922
- return entries;
5285
+ const position = decodeListPosition(options.nextPage);
5286
+ if (position === undefined) {
5287
+ failListArgument("Invalid --next-page value", "Pass the Pagination.NextPage value from the previous " + "`resources list` response unchanged, or drop --next-page to " + "start from the first page.");
5288
+ }
5289
+ return position;
4923
5290
  }
4924
- async function collectResources(builder, services, source, kind, search) {
4925
- const includeLocal = source === "local" || source === "all";
4926
- const includeRemote = source === "remote" || source === "all";
4927
- if (kind) {
4928
- return querySingleKind(builder, kind, search, includeLocal, includeRemote);
5291
+ function failListArgument(message, instructions) {
5292
+ OutputFormatter.error({
5293
+ Result: RESULTS.Failure,
5294
+ ErrorCode: "invalid_argument",
5295
+ Retry: "RetryWillNotFix",
5296
+ Message: message,
5297
+ Instructions: instructions
5298
+ });
5299
+ processContext.exit(1);
5300
+ }
5301
+ function encodeListPosition(position) {
5302
+ return Buffer.from(JSON.stringify(position), "utf8").toString("base64url");
5303
+ }
5304
+ function decodeListPosition(cursor) {
5305
+ const [parseError, value] = catchError(() => JSON.parse(Buffer.from(cursor, "base64url").toString("utf8")));
5306
+ if (parseError || typeof value !== "object" || value === null) {
5307
+ return;
4929
5308
  }
4930
- const all = [];
4931
- if (includeLocal) {
4932
- all.push(...await listLocalResources(builder, undefined, search));
5309
+ const { at, index, page, skip } = value;
5310
+ if (at === "local" && isRowCount(index)) {
5311
+ return { at, index };
4933
5312
  }
4934
- if (includeRemote) {
4935
- const remote = await listAllRemoteResources(services, search);
4936
- const localKeys = new Set(all.map((e) => `${e.Kind}:${e.Name}`.toLowerCase()));
4937
- const uniqueRemote = remote.filter((r) => !localKeys.has(`${r.Kind}:${r.Name}`.toLowerCase()));
4938
- all.push(...uniqueRemote);
5313
+ if (at === "remote" && isRowCount(skip) && (page === undefined || typeof page === "string")) {
5314
+ return { at, page, skip };
4939
5315
  }
4940
- return all;
5316
+ return;
5317
+ }
5318
+ function isRowCount(value) {
5319
+ return Number.isInteger(value) && value >= 0;
5320
+ }
5321
+ async function listResources(builder, services, source, limit, start, kind, search, includeVersion = false) {
5322
+ const listed = await collectWindow(builder, services, source, limit, start, kind, search);
5323
+ if (includeVersion) {
5324
+ await annotateVersions(services, builder, listed.rows);
5325
+ }
5326
+ return listed;
5327
+ }
5328
+ function resourceIdentity(entry) {
5329
+ return `${entry.Kind}:${entry.Name}`.toLowerCase();
5330
+ }
5331
+ async function collectWindow(builder, services, source, limit, start, kind, search) {
5332
+ const local = source === "remote" ? [] : await listLocalResources(builder, kind, search);
5333
+ const want = limit + 1;
5334
+ const found = [];
5335
+ if (start.at === "local") {
5336
+ for (let i = start.index;i < local.length && found.length < want; i++) {
5337
+ found.push({ entry: local[i], at: { at: "local", index: i } });
5338
+ }
5339
+ }
5340
+ if (source !== "local" && found.length < want) {
5341
+ const localKeys = new Set(local.map(resourceIdentity));
5342
+ let page = start.at === "remote" ? start.page : undefined;
5343
+ let skip = start.at === "remote" ? start.skip : 0;
5344
+ for (;; ) {
5345
+ const result = kind ? await remoteKindPage(builder, kind, search, page) : await allRemotePage(services, search, page);
5346
+ for (let i = skip;i < result.entries.length && found.length < want; i++) {
5347
+ const entry = result.entries[i];
5348
+ if (!localKeys.has(resourceIdentity(entry))) {
5349
+ found.push({ entry, at: { at: "remote", page, skip: i } });
5350
+ }
5351
+ }
5352
+ if (found.length >= want || result.nextPage === undefined) {
5353
+ break;
5354
+ }
5355
+ page = result.nextPage;
5356
+ skip = 0;
5357
+ }
5358
+ }
5359
+ return {
5360
+ rows: found.slice(0, limit).map((row) => row.entry),
5361
+ next: found[limit]?.at
5362
+ };
4941
5363
  }
4942
5364
  function versionLookupId(entry) {
4943
5365
  return `${entry.Source}|${entry.Key}|${entry.Folder ?? ""}`;
@@ -4973,34 +5395,25 @@ async function annotateVersions(services, builder, entries) {
4973
5395
  }
4974
5396
  }
4975
5397
  }
4976
- async function listAllRemoteResources(services, search) {
4977
- const rcs = services.container.resolve(Tokens.IResourceCatalogClientProxy);
4978
- const entries = [];
4979
- let pageCursor;
4980
- do {
4981
- const [err, result] = await catchError(rcs.searchFolderEntities({
4982
- name: search,
4983
- pageSize: 100,
4984
- pageCursor
4985
- }));
4986
- if (err) {
4987
- logger.warn(`Failed to search remote resources: ${err.message}`);
4988
- return entries;
4989
- }
4990
- for (const item of result.items ?? []) {
4991
- entries.push({
4992
- Source: "Remote",
4993
- Key: item.entityKey ?? "",
4994
- Name: item.entityName ?? "",
4995
- Kind: item.entityType ?? "",
4996
- Type: item.entitySubType ?? undefined,
4997
- Folder: item.fullyQualifiedName,
4998
- FolderKey: item.folderKey
4999
- });
5000
- }
5001
- pageCursor = result.nextPage ?? undefined;
5002
- } while (pageCursor);
5003
- return entries;
5398
+ async function allRemotePage(services, search, pageCursor) {
5399
+ const rcs = getRemoteResourceClients(services).catalog;
5400
+ const result = await rcs.searchFolderEntities({
5401
+ name: search,
5402
+ pageSize: 100,
5403
+ pageCursor
5404
+ });
5405
+ return {
5406
+ entries: (result.items ?? []).map((item) => ({
5407
+ Source: "Remote",
5408
+ Key: item.entityKey ?? "",
5409
+ Name: item.entityName ?? "",
5410
+ Kind: item.entityType ?? "",
5411
+ Type: item.entitySubType ?? undefined,
5412
+ Folder: item.fullyQualifiedName,
5413
+ FolderKey: item.folderKey
5414
+ })),
5415
+ nextPage: result.nextPage || undefined
5416
+ };
5004
5417
  }
5005
5418
  async function listLocalResources(builder, kind, search) {
5006
5419
  const solution = await builder.context.loadAsync();
@@ -5021,36 +5434,20 @@ async function listLocalResources(builder, kind, search) {
5021
5434
  Folder: r.folders?.[0]?.fullyQualifiedName
5022
5435
  }));
5023
5436
  }
5024
- async function querySingleKind(builder, kind, search, includeLocal, includeRemote) {
5025
- const entries = [];
5026
- if (includeLocal) {
5027
- entries.push(...await listLocalResources(builder, kind, search));
5028
- }
5029
- if (includeRemote) {
5030
- let pageCursor;
5031
- do {
5032
- const result = await builder.searchResourcesAsync(kind, undefined, search, pageCursor, 100, undefined, false);
5033
- for (const folder of result.availableResources ?? []) {
5034
- for (const r of folder.resources ?? []) {
5035
- entries.push({
5036
- Source: "Remote",
5037
- Key: r.key,
5038
- Name: r.name,
5039
- Kind: r.kind,
5040
- Type: r.type,
5041
- Folder: folder.fullyQualifiedName,
5042
- FolderKey: folder.key
5043
- });
5044
- }
5045
- }
5046
- pageCursor = result.nextPage;
5047
- } while (pageCursor);
5048
- }
5049
- if (includeLocal && includeRemote) {
5050
- const localKeys = new Set(entries.filter((e) => e.Source === "Local").map((e) => `${e.Kind}:${e.Name}`.toLowerCase()));
5051
- return entries.filter((e) => e.Source === "Local" || !localKeys.has(`${e.Kind}:${e.Name}`.toLowerCase()));
5052
- }
5053
- return entries;
5437
+ async function remoteKindPage(builder, kind, search, pageCursor) {
5438
+ const result = await builder.searchResourcesAsync(kind, undefined, search, pageCursor, 100, undefined, false);
5439
+ return {
5440
+ entries: (result.availableResources ?? []).flatMap((folder) => (folder.resources ?? []).map((r) => ({
5441
+ Source: "Remote",
5442
+ Key: r.key,
5443
+ Name: r.name,
5444
+ Kind: r.kind,
5445
+ Type: r.type,
5446
+ Folder: folder.fullyQualifiedName,
5447
+ FolderKey: folder.key
5448
+ }))),
5449
+ nextPage: result.nextPage || undefined
5450
+ };
5054
5451
  }
5055
5452
 
5056
5453
  // src/commands/resource-refresh.ts
@@ -5093,9 +5490,9 @@ var registerResourceRefreshSubcommand = (resource) => {
5093
5490
  contributionErrorMessages
5094
5491
  }
5095
5492
  ] = await Promise.all([
5096
- import("./packager-tool-resolver-fmjr60x8.js"),
5097
- import("./prepare-solution-resources-wds3r8bq.js"),
5098
- import("./project-contributions-cvttys34.js")
5493
+ import("./packager-tool-resolver-2cbxyq6k.js"),
5494
+ import("./prepare-solution-resources-p3gzdecy.js"),
5495
+ import("./project-contributions-txe8v6sm.js")
5099
5496
  ]);
5100
5497
  const resolveProjectSubTypesAsync = async () => {
5101
5498
  await ensurePackagerTools2(solutionFolder, fs);
@@ -6293,11 +6690,11 @@ var registerUploadCommand = (program) => {
6293
6690
  });
6294
6691
  const projectTypeSummary = bundledProjectTypes.length > 0 ? summarizeShipProjectTypes(bundledProjectTypes) : await inspectSolutionPackageProjectTypes(uisPath);
6295
6692
  trackSolutionShipSucceeded({
6296
- ship_kind: "upload",
6297
- target: "studio_web",
6298
- command_name: "uip.solution.upload",
6299
- artifact_correlation_key: returnedSolutionId,
6300
- solution_id: returnedSolutionId,
6693
+ [ShipDimensions.ShipKind]: "upload",
6694
+ [ShipDimensions.Target]: "studio_web",
6695
+ [CommandDimensions.CommandName]: "uip solution upload",
6696
+ [ShipDimensions.ArtifactCorrelationKey]: returnedSolutionId,
6697
+ [ShipDimensions.SolutionId]: returnedSolutionId,
6301
6698
  projectTypeSummary
6302
6699
  });
6303
6700
  } finally {
@@ -6387,7 +6784,7 @@ var registerCommands = async (program) => {
6387
6784
  registerResourceCommand(program);
6388
6785
  registerDeleteCommand(program);
6389
6786
  if (isPreviewBuild()) {
6390
- const { registerListCommand } = await import("./list-n0xd5rgn.js");
6787
+ const { registerListCommand } = await import("./list-rbjqgz6s.js");
6391
6788
  registerListCommand(program);
6392
6789
  }
6393
6790
  registerFeedsCommand(program);
@@ -6395,4 +6792,4 @@ var registerCommands = async (program) => {
6395
6792
 
6396
6793
  export { metadata, registerCommands };
6397
6794
 
6398
- //# debugId=46D58B6BDE35333364756E2164756E21
6795
+ //# debugId=D929C7F75D94828664756E2164756E21