@peernova/cuneiform-sf 1.0.2 → 1.0.4-beta.10

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 (488) hide show
  1. package/LICENSE +81 -30
  2. package/README.md +168 -134
  3. package/lib/adapters/connection-facade.d.ts +458 -0
  4. package/lib/adapters/connection-facade.js +379 -0
  5. package/lib/adapters/connection-facade.js.map +1 -0
  6. package/lib/adapters/errors.d.ts +547 -0
  7. package/lib/adapters/errors.js +937 -0
  8. package/lib/adapters/errors.js.map +1 -0
  9. package/lib/adapters/lifecycle.d.ts +112 -0
  10. package/lib/adapters/lifecycle.js +94 -0
  11. package/lib/adapters/lifecycle.js.map +1 -0
  12. package/lib/adapters/rest/cache.d.ts +69 -0
  13. package/lib/adapters/rest/cache.js +133 -0
  14. package/lib/adapters/rest/cache.js.map +1 -0
  15. package/lib/adapters/rest/index.d.ts +11 -0
  16. package/lib/adapters/rest/index.js +18 -0
  17. package/lib/adapters/rest/index.js.map +1 -0
  18. package/lib/adapters/rest/profiling-rest-client.d.ts +137 -0
  19. package/lib/adapters/rest/profiling-rest-client.js +115 -0
  20. package/lib/adapters/rest/profiling-rest-client.js.map +1 -0
  21. package/lib/adapters/rest/rest-api-adapter.d.ts +393 -0
  22. package/lib/adapters/rest/rest-api-adapter.js +764 -0
  23. package/lib/adapters/rest/rest-api-adapter.js.map +1 -0
  24. package/lib/adapters/rest/types.d.ts +34 -0
  25. package/lib/adapters/rest/types.js +9 -0
  26. package/lib/adapters/rest/types.js.map +1 -0
  27. package/lib/adapters/retry.d.ts +91 -0
  28. package/lib/adapters/retry.js +215 -0
  29. package/lib/adapters/retry.js.map +1 -0
  30. package/lib/adapters/soql/cuneiform-query-builder.d.ts +418 -0
  31. package/lib/adapters/soql/cuneiform-query-builder.js +606 -0
  32. package/lib/adapters/soql/cuneiform-query-builder.js.map +1 -0
  33. package/lib/adapters/soql/soql-query-adapter.d.ts +141 -0
  34. package/lib/adapters/soql/soql-query-adapter.js +259 -0
  35. package/lib/adapters/soql/soql-query-adapter.js.map +1 -0
  36. package/lib/adapters/soql/types.d.ts +37 -0
  37. package/lib/adapters/soql/types.js +19 -0
  38. package/lib/adapters/soql/types.js.map +1 -0
  39. package/lib/adapters/testing/index.d.ts +37 -0
  40. package/lib/adapters/testing/index.js +20 -0
  41. package/lib/adapters/testing/index.js.map +1 -0
  42. package/lib/adapters/testing/mock-connection.d.ts +77 -0
  43. package/lib/adapters/testing/mock-connection.js +207 -0
  44. package/lib/adapters/testing/mock-connection.js.map +1 -0
  45. package/lib/adapters/testing/mock-logger.d.ts +29 -0
  46. package/lib/adapters/testing/mock-logger.js +57 -0
  47. package/lib/adapters/testing/mock-logger.js.map +1 -0
  48. package/lib/adapters/testing/mock-mcp-adapters.d.ts +32 -0
  49. package/lib/adapters/testing/mock-mcp-adapters.js +52 -0
  50. package/lib/adapters/testing/mock-mcp-adapters.js.map +1 -0
  51. package/lib/adapters/testing/mock-oclif-config.d.ts +22 -0
  52. package/lib/adapters/testing/mock-oclif-config.js +90 -0
  53. package/lib/adapters/testing/mock-oclif-config.js.map +1 -0
  54. package/lib/adapters/testing/mock-rest-adapter.d.ts +26 -0
  55. package/lib/adapters/testing/mock-rest-adapter.js +243 -0
  56. package/lib/adapters/testing/mock-rest-adapter.js.map +1 -0
  57. package/lib/adapters/testing/mock-salesforce-connection.d.ts +40 -0
  58. package/lib/adapters/testing/mock-salesforce-connection.js +61 -0
  59. package/lib/adapters/testing/mock-salesforce-connection.js.map +1 -0
  60. package/lib/adapters/testing/mock-soql-adapter.d.ts +30 -0
  61. package/lib/adapters/testing/mock-soql-adapter.js +120 -0
  62. package/lib/adapters/testing/mock-soql-adapter.js.map +1 -0
  63. package/lib/adapters/testing/mock-tooling-adapter.d.ts +24 -0
  64. package/lib/adapters/testing/mock-tooling-adapter.js +163 -0
  65. package/lib/adapters/testing/mock-tooling-adapter.js.map +1 -0
  66. package/lib/adapters/testing/stub-connection.d.ts +93 -0
  67. package/lib/adapters/testing/stub-connection.js +97 -0
  68. package/lib/adapters/testing/stub-connection.js.map +1 -0
  69. package/lib/adapters/testing/stub-rest-adapter.d.ts +52 -0
  70. package/lib/adapters/testing/stub-rest-adapter.js +58 -0
  71. package/lib/adapters/testing/stub-rest-adapter.js.map +1 -0
  72. package/lib/adapters/testing/stub-soql-adapter.d.ts +56 -0
  73. package/lib/adapters/testing/stub-soql-adapter.js +50 -0
  74. package/lib/adapters/testing/stub-soql-adapter.js.map +1 -0
  75. package/lib/adapters/testing/types.d.ts +71 -0
  76. package/lib/adapters/testing/types.js +9 -0
  77. package/lib/adapters/testing/types.js.map +1 -0
  78. package/lib/adapters/tooling/index.d.ts +10 -0
  79. package/lib/adapters/tooling/index.js +17 -0
  80. package/lib/adapters/tooling/index.js.map +1 -0
  81. package/lib/adapters/tooling/tooling-api-adapter.d.ts +157 -0
  82. package/lib/adapters/tooling/tooling-api-adapter.js +339 -0
  83. package/lib/adapters/tooling/tooling-api-adapter.js.map +1 -0
  84. package/lib/adapters/tooling/types.d.ts +81 -0
  85. package/lib/adapters/tooling/types.js +9 -0
  86. package/lib/adapters/tooling/types.js.map +1 -0
  87. package/lib/adapters/types.d.ts +112 -0
  88. package/lib/adapters/types.js +169 -0
  89. package/lib/adapters/types.js.map +1 -0
  90. package/lib/base/cuneiform-command.d.ts +175 -0
  91. package/lib/base/cuneiform-command.js +326 -0
  92. package/lib/base/cuneiform-command.js.map +1 -0
  93. package/lib/commands/cuneiform/compatibility/check.d.ts +43 -0
  94. package/lib/commands/cuneiform/compatibility/check.js +114 -0
  95. package/lib/commands/cuneiform/compatibility/check.js.map +1 -0
  96. package/lib/commands/cuneiform/definition/create.d.ts +120 -0
  97. package/lib/commands/cuneiform/definition/create.js +737 -0
  98. package/lib/commands/cuneiform/definition/create.js.map +1 -0
  99. package/lib/commands/cuneiform/definition/export.d.ts +57 -0
  100. package/lib/commands/cuneiform/definition/export.js +133 -0
  101. package/lib/commands/cuneiform/definition/export.js.map +1 -0
  102. package/lib/commands/cuneiform/definition/get.d.ts +86 -0
  103. package/lib/commands/cuneiform/definition/get.js +277 -0
  104. package/lib/commands/cuneiform/definition/get.js.map +1 -0
  105. package/lib/commands/cuneiform/definition/import.d.ts +54 -0
  106. package/lib/commands/cuneiform/definition/import.js +118 -0
  107. package/lib/commands/cuneiform/definition/import.js.map +1 -0
  108. package/lib/commands/cuneiform/definition/list.d.ts +110 -0
  109. package/lib/commands/cuneiform/definition/list.js +351 -0
  110. package/lib/commands/cuneiform/definition/list.js.map +1 -0
  111. package/lib/commands/cuneiform/definition/purge.d.ts +109 -0
  112. package/lib/commands/cuneiform/definition/purge.js +578 -0
  113. package/lib/commands/cuneiform/definition/purge.js.map +1 -0
  114. package/lib/commands/cuneiform/definition/update.d.ts +58 -0
  115. package/lib/commands/cuneiform/definition/update.js +209 -0
  116. package/lib/commands/cuneiform/definition/update.js.map +1 -0
  117. package/lib/commands/cuneiform/mcp/serve.d.ts +56 -0
  118. package/lib/commands/cuneiform/mcp/serve.js +109 -0
  119. package/lib/commands/cuneiform/mcp/serve.js.map +1 -0
  120. package/lib/commands/cuneiform/object/describe.d.ts +61 -0
  121. package/lib/commands/cuneiform/object/describe.js +461 -0
  122. package/lib/commands/cuneiform/object/describe.js.map +1 -0
  123. package/lib/commands/cuneiform/object/list.d.ts +123 -0
  124. package/lib/commands/cuneiform/object/list.js +264 -0
  125. package/lib/commands/cuneiform/object/list.js.map +1 -0
  126. package/lib/commands/cuneiform/org/details.d.ts +99 -0
  127. package/lib/commands/cuneiform/org/details.js +521 -0
  128. package/lib/commands/cuneiform/org/details.js.map +1 -0
  129. package/lib/commands/cuneiform/org/reset.d.ts +46 -0
  130. package/lib/commands/cuneiform/org/reset.js +135 -0
  131. package/lib/commands/cuneiform/org/reset.js.map +1 -0
  132. package/lib/commands/cuneiform/profile/request/cancel.d.ts +59 -0
  133. package/lib/commands/cuneiform/profile/request/cancel.js +202 -0
  134. package/lib/commands/cuneiform/profile/request/cancel.js.map +1 -0
  135. package/lib/commands/cuneiform/profile/request/delete.d.ts +59 -0
  136. package/lib/commands/cuneiform/profile/request/delete.js +223 -0
  137. package/lib/commands/cuneiform/profile/request/delete.js.map +1 -0
  138. package/lib/commands/cuneiform/profile/request/list.d.ts +35 -0
  139. package/lib/commands/cuneiform/profile/request/list.js +102 -0
  140. package/lib/commands/cuneiform/profile/request/list.js.map +1 -0
  141. package/lib/commands/cuneiform/profile.d.ts +93 -0
  142. package/lib/commands/cuneiform/profile.js +353 -0
  143. package/lib/commands/cuneiform/profile.js.map +1 -0
  144. package/lib/commands/cuneiform/summary/purge.d.ts +80 -0
  145. package/lib/commands/cuneiform/summary/purge.js +467 -0
  146. package/lib/commands/cuneiform/summary/purge.js.map +1 -0
  147. package/lib/commands/cuneiform/summary/reprofile.d.ts +60 -0
  148. package/lib/commands/cuneiform/summary/reprofile.js +236 -0
  149. package/lib/commands/cuneiform/summary/reprofile.js.map +1 -0
  150. package/lib/commands/cuneiform/summary/stop.d.ts +59 -0
  151. package/lib/commands/cuneiform/summary/stop.js +234 -0
  152. package/lib/commands/cuneiform/summary/stop.js.map +1 -0
  153. package/lib/commands/cuneiform/user/details.d.ts +77 -0
  154. package/lib/commands/cuneiform/user/details.js +414 -0
  155. package/lib/commands/cuneiform/user/details.js.map +1 -0
  156. package/lib/constants/namespace-constants.d.ts +102 -0
  157. package/lib/constants/namespace-constants.js +225 -0
  158. package/lib/constants/namespace-constants.js.map +1 -0
  159. package/lib/debug/command-debug-proxy.d.ts +101 -0
  160. package/lib/debug/command-debug-proxy.js +171 -0
  161. package/lib/debug/command-debug-proxy.js.map +1 -0
  162. package/lib/debug/debug-logger.d.ts +85 -0
  163. package/lib/debug/debug-logger.js +133 -0
  164. package/lib/debug/debug-logger.js.map +1 -0
  165. package/lib/debug/service-debug-proxy.d.ts +30 -0
  166. package/lib/debug/service-debug-proxy.js +102 -0
  167. package/lib/debug/service-debug-proxy.js.map +1 -0
  168. package/lib/hooks/prerun.d.ts +25 -0
  169. package/lib/hooks/prerun.js +47 -0
  170. package/lib/hooks/prerun.js.map +1 -0
  171. package/lib/mcp/config/mcp-config.d.ts +55 -0
  172. package/lib/mcp/config/mcp-config.js +51 -0
  173. package/lib/mcp/config/mcp-config.js.map +1 -0
  174. package/lib/mcp/config/pagination.d.ts +96 -0
  175. package/lib/mcp/config/pagination.js +108 -0
  176. package/lib/mcp/config/pagination.js.map +1 -0
  177. package/lib/mcp/config/system-prompts.d.ts +18 -0
  178. package/lib/mcp/config/system-prompts.js +92 -0
  179. package/lib/mcp/config/system-prompts.js.map +1 -0
  180. package/lib/mcp/errors.d.ts +23 -0
  181. package/lib/mcp/errors.js +27 -0
  182. package/lib/mcp/errors.js.map +1 -0
  183. package/lib/mcp/schemas/input-schemas.d.ts +327 -0
  184. package/lib/mcp/schemas/input-schemas.js +310 -0
  185. package/lib/mcp/schemas/input-schemas.js.map +1 -0
  186. package/lib/mcp/server.d.ts +40 -0
  187. package/lib/mcp/server.js +316 -0
  188. package/lib/mcp/server.js.map +1 -0
  189. package/lib/mcp/tools/contactpoint-tools.d.ts +14 -0
  190. package/lib/mcp/tools/contactpoint-tools.js +34 -0
  191. package/lib/mcp/tools/contactpoint-tools.js.map +1 -0
  192. package/lib/mcp/tools/definition-io-tools.d.ts +19 -0
  193. package/lib/mcp/tools/definition-io-tools.js +152 -0
  194. package/lib/mcp/tools/definition-io-tools.js.map +1 -0
  195. package/lib/mcp/tools/definition-tools.d.ts +51 -0
  196. package/lib/mcp/tools/definition-tools.js +220 -0
  197. package/lib/mcp/tools/definition-tools.js.map +1 -0
  198. package/lib/mcp/tools/index.d.ts +37 -0
  199. package/lib/mcp/tools/index.js +88 -0
  200. package/lib/mcp/tools/index.js.map +1 -0
  201. package/lib/mcp/tools/object-tools.d.ts +22 -0
  202. package/lib/mcp/tools/object-tools.js +327 -0
  203. package/lib/mcp/tools/object-tools.js.map +1 -0
  204. package/lib/mcp/tools/org-tools.d.ts +14 -0
  205. package/lib/mcp/tools/org-tools.js +177 -0
  206. package/lib/mcp/tools/org-tools.js.map +1 -0
  207. package/lib/mcp/tools/profile-tools.d.ts +59 -0
  208. package/lib/mcp/tools/profile-tools.js +213 -0
  209. package/lib/mcp/tools/profile-tools.js.map +1 -0
  210. package/lib/mcp/tools/summary-tools.d.ts +14 -0
  211. package/lib/mcp/tools/summary-tools.js +38 -0
  212. package/lib/mcp/tools/summary-tools.js.map +1 -0
  213. package/lib/mcp/tools/tool-factory.d.ts +63 -0
  214. package/lib/mcp/tools/tool-factory.js +146 -0
  215. package/lib/mcp/tools/tool-factory.js.map +1 -0
  216. package/lib/mcp/tools/user-tools.d.ts +25 -0
  217. package/lib/mcp/tools/user-tools.js +167 -0
  218. package/lib/mcp/tools/user-tools.js.map +1 -0
  219. package/lib/models/cascade-skip-accumulator.d.ts +25 -0
  220. package/lib/models/cascade-skip-accumulator.js +9 -0
  221. package/lib/models/cascade-skip-accumulator.js.map +1 -0
  222. package/lib/models/date-literal.d.ts +280 -0
  223. package/lib/models/date-literal.js +1164 -0
  224. package/lib/models/date-literal.js.map +1 -0
  225. package/lib/models/object-describe-types.d.ts +173 -0
  226. package/lib/models/object-describe-types.js +9 -0
  227. package/lib/models/object-describe-types.js.map +1 -0
  228. package/lib/models/portability-recipe.d.ts +35 -0
  229. package/lib/models/portability-recipe.js +113 -0
  230. package/lib/models/portability-recipe.js.map +1 -0
  231. package/lib/models/profile-request-types.d.ts +118 -0
  232. package/lib/models/profile-request-types.js +23 -0
  233. package/lib/models/profile-request-types.js.map +1 -0
  234. package/lib/models/profiling-execution-types.d.ts +154 -0
  235. package/lib/models/profiling-execution-types.js +14 -0
  236. package/lib/models/profiling-execution-types.js.map +1 -0
  237. package/lib/models/service-result.d.ts +114 -0
  238. package/lib/models/service-result.js +81 -0
  239. package/lib/models/service-result.js.map +1 -0
  240. package/lib/models/sfdmu-types.d.ts +49 -0
  241. package/lib/models/sfdmu-types.js +23 -0
  242. package/lib/models/sfdmu-types.js.map +1 -0
  243. package/lib/models/status-types.d.ts +38 -0
  244. package/lib/models/status-types.js +12 -0
  245. package/lib/models/status-types.js.map +1 -0
  246. package/lib/models/summary-bulk-types.d.ts +61 -0
  247. package/lib/models/summary-bulk-types.js +23 -0
  248. package/lib/models/summary-bulk-types.js.map +1 -0
  249. package/lib/models/user-details-types.d.ts +188 -0
  250. package/lib/models/user-details-types.js +9 -0
  251. package/lib/models/user-details-types.js.map +1 -0
  252. package/lib/models/year-range.d.ts +78 -0
  253. package/lib/models/year-range.js +153 -0
  254. package/lib/models/year-range.js.map +1 -0
  255. package/lib/operations/CompatibilityCheckOperation.d.ts +62 -0
  256. package/lib/operations/CompatibilityCheckOperation.js +102 -0
  257. package/lib/operations/CompatibilityCheckOperation.js.map +1 -0
  258. package/lib/operations/DefinitionCreateOperation.d.ts +427 -0
  259. package/lib/operations/DefinitionCreateOperation.js +1270 -0
  260. package/lib/operations/DefinitionCreateOperation.js.map +1 -0
  261. package/lib/operations/DefinitionExportOperation.d.ts +155 -0
  262. package/lib/operations/DefinitionExportOperation.js +281 -0
  263. package/lib/operations/DefinitionExportOperation.js.map +1 -0
  264. package/lib/operations/DefinitionImportOperation.d.ts +144 -0
  265. package/lib/operations/DefinitionImportOperation.js +357 -0
  266. package/lib/operations/DefinitionImportOperation.js.map +1 -0
  267. package/lib/operations/DefinitionListOperation.d.ts +66 -0
  268. package/lib/operations/DefinitionListOperation.js +108 -0
  269. package/lib/operations/DefinitionListOperation.js.map +1 -0
  270. package/lib/operations/DefinitionPurgeOperation.d.ts +203 -0
  271. package/lib/operations/DefinitionPurgeOperation.js +465 -0
  272. package/lib/operations/DefinitionPurgeOperation.js.map +1 -0
  273. package/lib/operations/DefinitionUpdateOperation.d.ts +78 -0
  274. package/lib/operations/DefinitionUpdateOperation.js +142 -0
  275. package/lib/operations/DefinitionUpdateOperation.js.map +1 -0
  276. package/lib/operations/OrgDetailsOperation.d.ts +253 -0
  277. package/lib/operations/OrgDetailsOperation.js +456 -0
  278. package/lib/operations/OrgDetailsOperation.js.map +1 -0
  279. package/lib/operations/OrgResetOperation.d.ts +114 -0
  280. package/lib/operations/OrgResetOperation.js +209 -0
  281. package/lib/operations/OrgResetOperation.js.map +1 -0
  282. package/lib/operations/ProfileOperation.d.ts +192 -0
  283. package/lib/operations/ProfileOperation.js +371 -0
  284. package/lib/operations/ProfileOperation.js.map +1 -0
  285. package/lib/operations/ProfileRequestCancelOperation.d.ts +59 -0
  286. package/lib/operations/ProfileRequestCancelOperation.js +137 -0
  287. package/lib/operations/ProfileRequestCancelOperation.js.map +1 -0
  288. package/lib/operations/ProfileRequestDeleteOperation.d.ts +64 -0
  289. package/lib/operations/ProfileRequestDeleteOperation.js +134 -0
  290. package/lib/operations/ProfileRequestDeleteOperation.js.map +1 -0
  291. package/lib/operations/ProfileRequestListOperation.d.ts +39 -0
  292. package/lib/operations/ProfileRequestListOperation.js +61 -0
  293. package/lib/operations/ProfileRequestListOperation.js.map +1 -0
  294. package/lib/operations/SummaryPurgeOperation.d.ts +134 -0
  295. package/lib/operations/SummaryPurgeOperation.js +257 -0
  296. package/lib/operations/SummaryPurgeOperation.js.map +1 -0
  297. package/lib/operations/SummaryReprofileOperation.d.ts +88 -0
  298. package/lib/operations/SummaryReprofileOperation.js +174 -0
  299. package/lib/operations/SummaryReprofileOperation.js.map +1 -0
  300. package/lib/operations/SummaryStopOperation.d.ts +87 -0
  301. package/lib/operations/SummaryStopOperation.js +175 -0
  302. package/lib/operations/SummaryStopOperation.js.map +1 -0
  303. package/lib/services/BulkExecutionService.d.ts +120 -0
  304. package/lib/services/BulkExecutionService.js +535 -0
  305. package/lib/services/BulkExecutionService.js.map +1 -0
  306. package/lib/services/CompatibilityService.d.ts +81 -0
  307. package/lib/services/CompatibilityService.js +118 -0
  308. package/lib/services/CompatibilityService.js.map +1 -0
  309. package/lib/services/ConfigureMode.d.ts +98 -0
  310. package/lib/services/ConfigureMode.js +413 -0
  311. package/lib/services/ConfigureMode.js.map +1 -0
  312. package/lib/services/ContactPointService.d.ts +111 -0
  313. package/lib/services/ContactPointService.js +286 -0
  314. package/lib/services/ContactPointService.js.map +1 -0
  315. package/lib/services/DataAvailabilityService.d.ts +81 -0
  316. package/lib/services/DataAvailabilityService.js +128 -0
  317. package/lib/services/DataAvailabilityService.js.map +1 -0
  318. package/lib/services/DefinitionFieldGenerationService.d.ts +357 -0
  319. package/lib/services/DefinitionFieldGenerationService.js +899 -0
  320. package/lib/services/DefinitionFieldGenerationService.js.map +1 -0
  321. package/lib/services/DefinitionQueryBuilder.d.ts +92 -0
  322. package/lib/services/DefinitionQueryBuilder.js +328 -0
  323. package/lib/services/DefinitionQueryBuilder.js.map +1 -0
  324. package/lib/services/ObjectDescribeService.d.ts +436 -0
  325. package/lib/services/ObjectDescribeService.js +881 -0
  326. package/lib/services/ObjectDescribeService.js.map +1 -0
  327. package/lib/services/ObjectFilteringService.d.ts +484 -0
  328. package/lib/services/ObjectFilteringService.js +1080 -0
  329. package/lib/services/ObjectFilteringService.js.map +1 -0
  330. package/lib/services/ObjectListCommandService.d.ts +467 -0
  331. package/lib/services/ObjectListCommandService.js +904 -0
  332. package/lib/services/ObjectListCommandService.js.map +1 -0
  333. package/lib/services/ObjectListService.d.ts +201 -0
  334. package/lib/services/ObjectListService.js +350 -0
  335. package/lib/services/ObjectListService.js.map +1 -0
  336. package/lib/services/OrgInfoService.d.ts +493 -0
  337. package/lib/services/OrgInfoService.js +1142 -0
  338. package/lib/services/OrgInfoService.js.map +1 -0
  339. package/lib/services/PollingService.d.ts +105 -0
  340. package/lib/services/PollingService.js +117 -0
  341. package/lib/services/PollingService.js.map +1 -0
  342. package/lib/services/ProfileRequestService.d.ts +186 -0
  343. package/lib/services/ProfileRequestService.js +555 -0
  344. package/lib/services/ProfileRequestService.js.map +1 -0
  345. package/lib/services/ProfilingDefinitionService.d.ts +575 -0
  346. package/lib/services/ProfilingDefinitionService.js +1029 -0
  347. package/lib/services/ProfilingDefinitionService.js.map +1 -0
  348. package/lib/services/ProfilingExecutionService.d.ts +122 -0
  349. package/lib/services/ProfilingExecutionService.js +320 -0
  350. package/lib/services/ProfilingExecutionService.js.map +1 -0
  351. package/lib/services/ProfilingSummaryService.d.ts +292 -0
  352. package/lib/services/ProfilingSummaryService.js +688 -0
  353. package/lib/services/ProfilingSummaryService.js.map +1 -0
  354. package/lib/services/RecordTypeService.d.ts +129 -0
  355. package/lib/services/RecordTypeService.js +284 -0
  356. package/lib/services/RecordTypeService.js.map +1 -0
  357. package/lib/services/SFDMUService.d.ts +146 -0
  358. package/lib/services/SFDMUService.js +323 -0
  359. package/lib/services/SFDMUService.js.map +1 -0
  360. package/lib/services/TabDetectionService.d.ts +105 -0
  361. package/lib/services/TabDetectionService.js +206 -0
  362. package/lib/services/TabDetectionService.js.map +1 -0
  363. package/lib/services/UnconfigureMode.d.ts +74 -0
  364. package/lib/services/UnconfigureMode.js +378 -0
  365. package/lib/services/UnconfigureMode.js.map +1 -0
  366. package/lib/services/UserConfigurationService.d.ts +158 -0
  367. package/lib/services/UserConfigurationService.js +574 -0
  368. package/lib/services/UserConfigurationService.js.map +1 -0
  369. package/lib/services/UserConfigurationTypes.d.ts +181 -0
  370. package/lib/services/UserConfigurationTypes.js +14 -0
  371. package/lib/services/UserConfigurationTypes.js.map +1 -0
  372. package/lib/services/UserReadinessService.d.ts +347 -0
  373. package/lib/services/UserReadinessService.js +891 -0
  374. package/lib/services/UserReadinessService.js.map +1 -0
  375. package/lib/services/constants.d.ts +54 -0
  376. package/lib/services/constants.js +71 -0
  377. package/lib/services/constants.js.map +1 -0
  378. package/lib/services/namespace-constants.d.ts +1 -0
  379. package/lib/services/namespace-constants.js +11 -0
  380. package/lib/services/namespace-constants.js.map +1 -0
  381. package/lib/services/namespace-filter.d.ts +36 -0
  382. package/lib/services/namespace-filter.js +109 -0
  383. package/lib/services/namespace-filter.js.map +1 -0
  384. package/lib/services/validation.d.ts +47 -0
  385. package/lib/services/validation.js +119 -0
  386. package/lib/services/validation.js.map +1 -0
  387. package/lib/utils/batch-processor.d.ts +13 -0
  388. package/lib/utils/batch-processor.js +39 -0
  389. package/lib/utils/batch-processor.js.map +1 -0
  390. package/lib/utils/formatting/availability-grid.d.ts +81 -0
  391. package/lib/utils/formatting/availability-grid.js +94 -0
  392. package/lib/utils/formatting/availability-grid.js.map +1 -0
  393. package/lib/utils/formatting/business-process-grid.d.ts +51 -0
  394. package/lib/utils/formatting/business-process-grid.js +58 -0
  395. package/lib/utils/formatting/business-process-grid.js.map +1 -0
  396. package/lib/utils/formatting/command-display.d.ts +154 -0
  397. package/lib/utils/formatting/command-display.js +154 -0
  398. package/lib/utils/formatting/command-display.js.map +1 -0
  399. package/lib/utils/formatting/definition-create-display.d.ts +118 -0
  400. package/lib/utils/formatting/definition-create-display.js +230 -0
  401. package/lib/utils/formatting/definition-create-display.js.map +1 -0
  402. package/lib/utils/formatting/empty-states.d.ts +35 -0
  403. package/lib/utils/formatting/empty-states.js +70 -0
  404. package/lib/utils/formatting/empty-states.js.map +1 -0
  405. package/lib/utils/formatting/errors.d.ts +33 -0
  406. package/lib/utils/formatting/errors.js +72 -0
  407. package/lib/utils/formatting/errors.js.map +1 -0
  408. package/lib/utils/formatting/field-types.d.ts +32 -0
  409. package/lib/utils/formatting/field-types.js +88 -0
  410. package/lib/utils/formatting/field-types.js.map +1 -0
  411. package/lib/utils/formatting/index.d.ts +29 -0
  412. package/lib/utils/formatting/index.js +28 -0
  413. package/lib/utils/formatting/index.js.map +1 -0
  414. package/lib/utils/formatting/indicators.d.ts +113 -0
  415. package/lib/utils/formatting/indicators.js +161 -0
  416. package/lib/utils/formatting/indicators.js.map +1 -0
  417. package/lib/utils/formatting/loading-messages.d.ts +37 -0
  418. package/lib/utils/formatting/loading-messages.js +50 -0
  419. package/lib/utils/formatting/loading-messages.js.map +1 -0
  420. package/lib/utils/formatting/namespace-display.d.ts +31 -0
  421. package/lib/utils/formatting/namespace-display.js +64 -0
  422. package/lib/utils/formatting/namespace-display.js.map +1 -0
  423. package/lib/utils/formatting/numbers.d.ts +73 -0
  424. package/lib/utils/formatting/numbers.js +187 -0
  425. package/lib/utils/formatting/numbers.js.map +1 -0
  426. package/lib/utils/formatting/object-describe-display.d.ts +117 -0
  427. package/lib/utils/formatting/object-describe-display.js +447 -0
  428. package/lib/utils/formatting/object-describe-display.js.map +1 -0
  429. package/lib/utils/formatting/object-list-display.d.ts +225 -0
  430. package/lib/utils/formatting/object-list-display.js +718 -0
  431. package/lib/utils/formatting/object-list-display.js.map +1 -0
  432. package/lib/utils/formatting/org-identity.d.ts +15 -0
  433. package/lib/utils/formatting/org-identity.js +28 -0
  434. package/lib/utils/formatting/org-identity.js.map +1 -0
  435. package/lib/utils/formatting/record-age-grid.d.ts +41 -0
  436. package/lib/utils/formatting/record-age-grid.js +56 -0
  437. package/lib/utils/formatting/record-age-grid.js.map +1 -0
  438. package/lib/utils/formatting/sections.d.ts +108 -0
  439. package/lib/utils/formatting/sections.js +150 -0
  440. package/lib/utils/formatting/sections.js.map +1 -0
  441. package/lib/utils/formatting/tables.d.ts +90 -0
  442. package/lib/utils/formatting/tables.js +113 -0
  443. package/lib/utils/formatting/tables.js.map +1 -0
  444. package/lib/utils/formatting/user-details-display.d.ts +101 -0
  445. package/lib/utils/formatting/user-details-display.js +425 -0
  446. package/lib/utils/formatting/user-details-display.js.map +1 -0
  447. package/lib/utils/pagination/keypress-reader.d.ts +20 -0
  448. package/lib/utils/pagination/keypress-reader.js +63 -0
  449. package/lib/utils/pagination/keypress-reader.js.map +1 -0
  450. package/lib/utils/pagination/paginate-output.d.ts +48 -0
  451. package/lib/utils/pagination/paginate-output.js +136 -0
  452. package/lib/utils/pagination/paginate-output.js.map +1 -0
  453. package/messages/compatibility.check.md +71 -0
  454. package/messages/cuneiform.access.md +138 -0
  455. package/messages/definition.create.md +525 -0
  456. package/messages/definition.export.md +84 -0
  457. package/messages/definition.get.md +147 -0
  458. package/messages/definition.import.md +65 -0
  459. package/messages/definition.list.md +264 -0
  460. package/messages/definition.purge.md +330 -0
  461. package/messages/definition.update.md +118 -0
  462. package/messages/mcp.serve.md +66 -0
  463. package/messages/object.describe.md +205 -0
  464. package/messages/object.list.md +463 -0
  465. package/messages/org.details.md +386 -0
  466. package/messages/org.reset.md +71 -0
  467. package/messages/profile.md +243 -0
  468. package/messages/profile.request.cancel.md +143 -0
  469. package/messages/profile.request.delete.md +139 -0
  470. package/messages/profile.request.list.md +89 -0
  471. package/messages/summary.purge.md +218 -0
  472. package/messages/summary.reprofile.md +150 -0
  473. package/messages/summary.stop.md +157 -0
  474. package/messages/user.details.md +501 -0
  475. package/oclif.lock +3267 -2148
  476. package/oclif.manifest.json +2829 -31
  477. package/package.json +104 -18
  478. package/lib/commands/cuneiform/about.d.ts +0 -13
  479. package/lib/commands/cuneiform/about.js +0 -26
  480. package/lib/commands/cuneiform/about.js.map +0 -1
  481. package/lib/commands/hello/world.d.ts +0 -14
  482. package/lib/commands/hello/world.js +0 -27
  483. package/lib/commands/hello/world.js.map +0 -1
  484. package/lib/index.d.ts +0 -2
  485. package/lib/index.js +0 -2
  486. package/lib/index.js.map +0 -1
  487. package/messages/cuneiform.about.md +0 -19
  488. package/messages/hello.world.md +0 -29
@@ -0,0 +1,1270 @@
1
+ /*
2
+ * Copyright (c) 2026, PeerNova, Inc. All Rights Reserved.
3
+ * PROPRIETARY AND CONFIDENTIAL. Unauthorized copying, modification,
4
+ * or distribution is strictly prohibited. Use is governed by the
5
+ * Master Subscription Agreement (MSA) between PeerNova, Inc. and the
6
+ * licensee. See LICENSE file in the repo root.
7
+ */
8
+ import { createSuccessResult, createFailureResult } from '../models/service-result.js';
9
+ import { MAX_PAGINATION_LIMIT } from '../services/constants.js';
10
+ import { DefinitionFieldGenerationService } from '../services/DefinitionFieldGenerationService.js';
11
+ /**
12
+ * Error codes specific to create operations.
13
+ */
14
+ export const CreateErrorCodes = {
15
+ /** Object filtering failed */
16
+ FILTER_FAILED: 'CREATE_FILTER_FAILED',
17
+ /** No objects found matching filters */
18
+ NO_OBJECTS_FOUND: 'CREATE_NO_OBJECTS_FOUND',
19
+ /** None of the specified --objects exist in the org */
20
+ OBJECTS_NOT_FOUND: 'CREATE_OBJECTS_NOT_FOUND',
21
+ /** Operation failed unexpectedly */
22
+ OPERATION_FAILED: 'CREATE_OPERATION_FAILED',
23
+ /** No objects have been profiled yet */
24
+ NO_PROFILED_OBJECTS: 'CREATE_NO_PROFILED_OBJECTS',
25
+ /** REQ-002 portability run is missing the required category (CLI-4215) */
26
+ PORTABILITY_CATEGORY_REQUIRED: 'CREATE_PORTABILITY_CATEGORY_REQUIRED',
27
+ };
28
+ /**
29
+ * Orchestrates bulk creation of profiling definitions for filtered objects.
30
+ *
31
+ * Follows the 4-layer architecture: Command -> Operation -> Service -> API
32
+ * This operation layer handles business logic orchestration:
33
+ * 1. Filters objects using ObjectFilteringService
34
+ * 2. Checks for existing definitions using ProfilingDefinitionService
35
+ * 3. Creates definitions for new objects only (deduplication)
36
+ * 4. Reports created/failed/skipped statistics
37
+ *
38
+ * Pure field generation logic (naming, categorisation, description, candidate inputs)
39
+ * is delegated to DefinitionFieldGenerationService.
40
+ */
41
+ /**
42
+ * Format a name list for inline display in a cascade-summary warning: first 5 names
43
+ * joined by ', ', with a `, +K more` suffix when the total exceeds 5. The asymmetric
44
+ * "5 concrete + 1 magnitude number" balances category recognition against terminal width.
45
+ *
46
+ * Module-scope (not a class method) — pure transformation, no instance or static class
47
+ * dependencies. See `emitCascadeSummaries` for the consumer (CLI-3341).
48
+ */
49
+ const CASCADE_SUMMARY_TRUNCATE_AT = 5;
50
+ function formatTruncatedNames(names) {
51
+ if (names.length <= CASCADE_SUMMARY_TRUNCATE_AT)
52
+ return names.join(', ');
53
+ const visible = names.slice(0, CASCADE_SUMMARY_TRUNCATE_AT).join(', ');
54
+ const overflow = names.length - CASCADE_SUMMARY_TRUNCATE_AT;
55
+ return `${visible}, +${overflow} more`;
56
+ }
57
+ /**
58
+ * Emit at most one aggregated summary line for the `--method full` cascade —
59
+ * one for the non-empty RT skip bucket. Mirrors the single-summary pattern at
60
+ * `buildFullCandidateInputs` for RecordTypeService absence + RT inputs failure.
61
+ *
62
+ * No prefix is used (matches the existing single-summary warning convention in this file);
63
+ * the `X of N objects` phrasing differentiates aggregate from per-object warnings.
64
+ *
65
+ * Truncation: first 5 names listed inline, with `, +K more` suffix when total > 5.
66
+ * When the bucket is empty, no line is emitted (suppression rule).
67
+ *
68
+ * `rtStatus` parity: when `rtStatus === 'all'`, the qualifier is dropped to match the
69
+ * standalone warning shape ('has no record types' vs 'has no active record types').
70
+ *
71
+ * CLI-3611: outcome skip bucket removed — silently skipping objects without outcome
72
+ * fields is expected platform behavior in --method full, not an error condition.
73
+ */
74
+ function emitCascadeSummaries(cascade, totalObjects, rtStatus, warnings) {
75
+ if (cascade.noRecordTypes.length > 0) {
76
+ const qualifier = rtStatus === 'all' ? '' : `${rtStatus} `;
77
+ warnings.push(`${cascade.noRecordTypes.length} of ${totalObjects} objects have no ${qualifier}record types — record type variant omitted (${formatTruncatedNames(cascade.noRecordTypes)}).`);
78
+ }
79
+ }
80
+ export class DefinitionCreateOperation {
81
+ definitionService;
82
+ filteringService;
83
+ logger;
84
+ profilingSummaryService;
85
+ recordTypeService;
86
+ dataAvailabilityService;
87
+ restClient;
88
+ /** Exposes the date literal constant map for external consumers and tests. */
89
+ static DATE_LITERAL_MAP = DefinitionFieldGenerationService.DATE_LITERAL_MAP;
90
+ /** The bullet separator used in definition names. */
91
+ static NAME_SEPARATOR = DefinitionFieldGenerationService.NAME_SEPARATOR;
92
+ /**
93
+ * Creates a new DefinitionCreateOperation instance.
94
+ *
95
+ * @param definitionService - Service for creating and querying profiling definitions
96
+ * @param filteringService - Service for filtering Salesforce objects
97
+ * @param logger - Optional logger for debug output
98
+ * @param profilingSummaryService - Optional service for querying profiled objects (required when profiled=true)
99
+ * @param recordTypeService - Optional service for querying record types (required when method=recordtype)
100
+ */
101
+ constructor(definitionService, filteringService, logger, profilingSummaryService, recordTypeService, dataAvailabilityService, restClient) {
102
+ this.definitionService = definitionService;
103
+ this.filteringService = filteringService;
104
+ this.logger = logger;
105
+ this.profilingSummaryService = profilingSummaryService;
106
+ this.recordTypeService = recordTypeService;
107
+ this.dataAvailabilityService = dataAvailabilityService;
108
+ this.restClient = restClient;
109
+ }
110
+ // ── Public Static Methods ────────────────────────────────────────────
111
+ /**
112
+ * Resolves the definition name from the method and context.
113
+ * Single source of truth for definition naming across all definition types.
114
+ *
115
+ * @param label - Object label (e.g., 'Account', 'Lead')
116
+ * @param method - ISV method (metadata, historical, comparative)
117
+ * @param context - Optional context: timeLabel, year, recordTypeName, outcomeLabels, unbounded
118
+ * @returns The formatted definition name
119
+ */
120
+ static resolveDefinitionName(...args) {
121
+ return DefinitionFieldGenerationService.resolveDefinitionName(...args);
122
+ }
123
+ /**
124
+ * Resolves all definition metadata (category, timeCategory, segmentCategory, description)
125
+ * from the method and context. Single source of truth for definition classification.
126
+ */
127
+ static resolveDefinitionMetadata(...args) {
128
+ return DefinitionFieldGenerationService.resolveDefinitionMetadata(...args);
129
+ }
130
+ /**
131
+ * Formats a human-readable message for a per-object result.
132
+ */
133
+ static formatObjectMessage(result) {
134
+ switch (result.status) {
135
+ case 'success':
136
+ return `created "${result.definitionName}"`;
137
+ case 'skip':
138
+ return 'definition already exists';
139
+ case 'fail':
140
+ return result.error ?? 'unknown error';
141
+ case 'preview':
142
+ return `would create "${result.definitionName}"`;
143
+ }
144
+ }
145
+ /**
146
+ * Derives the time category display value from an input's method and year.
147
+ */
148
+ static resolveTimeCategory(input) {
149
+ if (!input)
150
+ return undefined;
151
+ if (input.timeCategory)
152
+ return input.timeCategory;
153
+ if (input.method === 'metadata')
154
+ return 'N/A';
155
+ if (input.comparativeYear !== undefined) {
156
+ return input.usePrior
157
+ ? `${input.comparativeYear} vs Prior`
158
+ : `${input.comparativeYear} vs ${input.comparativeYear - 1}`;
159
+ }
160
+ if (input.historicalYear !== undefined) {
161
+ return String(input.historicalYear);
162
+ }
163
+ return 'Lifetime';
164
+ }
165
+ /**
166
+ * Derives the segment category display value from an input. Prefers the
167
+ * pre-resolved `input.segmentCategory` (populated by the field generation
168
+ * service, which honors the --segment-category override and falls back to
169
+ * method-derived defaults like 'N/A', 'Historical', or record type name).
170
+ * Falls back to `input.recordTypeName` for back-compat with consumers that
171
+ * build inputs without going through `resolveDefinitionMetadata`.
172
+ */
173
+ static resolveSegmentCategory(input) {
174
+ if (!input)
175
+ return undefined;
176
+ return input.segmentCategory ?? input.recordTypeName;
177
+ }
178
+ /**
179
+ * Maps Salesforce objects to their outcome boolean fields.
180
+ *
181
+ * @param objectName - Salesforce object API name (e.g., 'Opportunity', 'Case', 'Lead')
182
+ * @returns Outcome field mapping, or undefined if the object has no outcome field
183
+ */
184
+ static getOutcomeField(objectName) {
185
+ return DefinitionFieldGenerationService.getOutcomeField(objectName);
186
+ }
187
+ /**
188
+ * Builds a single outcome definition input for a given object, outcome mapping, and optional time/RT context.
189
+ * Consolidates the repeated context + input construction pattern used across buildOutcomeCandidateInputs
190
+ * and buildInputsForRecordType.
191
+ */
192
+ static buildOutcomeInput(...args) {
193
+ return DefinitionFieldGenerationService.buildOutcomeInput(...args);
194
+ }
195
+ /**
196
+ * Builds an ISV-compatible filterJson string for business process outcome comparisons.
197
+ * SetA filters for the true outcome, SetB filters for the false outcome.
198
+ * Produces the expression builder JSON schema that `fsc_expressionBuilder3` expects.
199
+ *
200
+ * @param fieldName - Boolean field API name (e.g., 'IsWon', 'IsClosed', 'IsConverted')
201
+ * @param objectName - Salesforce object API name (e.g., 'Opportunity', 'Case', 'Lead')
202
+ * @returns JSON string compatible with GlobalProfilingService.createProfilingDefinition()
203
+ */
204
+ static buildOutcomeFilterJson(...args) {
205
+ return DefinitionFieldGenerationService.buildOutcomeFilterJson(...args);
206
+ }
207
+ // ── Private Static Helpers (execution) ────────────────────────────
208
+ /**
209
+ * Applies outcome pre-filtering for the REST path. For outcome method, only objects
210
+ * with outcome fields (Opportunity, Case, Lead) are eligible. Returns a failure result
211
+ * when no eligible objects remain; otherwise returns the filtered array.
212
+ */
213
+ /**
214
+ * Composes the `nameSuffix` value sent to the ISV `create-smart` REST endpoint, layering the
215
+ * `No Value Frequency` disambiguator ahead of any user-supplied `--name-suffix`. The bullet
216
+ * separator prefix (`• `) is required because the server joins suffix segments with a
217
+ * plain space — this CLI carries the bullet so the final rendered name reads consistently
218
+ * with locally-built names from `DefinitionFieldGenerationService.buildName`.
219
+ *
220
+ * CLI-3064: Without the disambiguator, value-frequency and no-value-frequency variants of
221
+ * the same (object, method, time-segment) resolve to identical names on both client and
222
+ * server; the second invocation is silently dropped by the name-keyed dedup gate. Layering
223
+ * the disambiguator ahead of the user suffix preserves the user's `--name-suffix` semantics
224
+ * while disambiguating the variant.
225
+ *
226
+ * @param userSuffix - User-supplied `--name-suffix` value (optional)
227
+ * @param noValueFrequency - True when the request originates from `--no-value-frequency`
228
+ * @returns Composed suffix to send as `SmartCreateRequest.options.nameSuffix`, or undefined when neither applies
229
+ */
230
+ static composeRestNameSuffix(userSuffix, noValueFrequency) {
231
+ const SEP = '• ';
232
+ const variant = noValueFrequency ? 'No Value Frequency' : undefined;
233
+ if (variant && userSuffix)
234
+ return `${SEP}${variant} ${SEP}${userSuffix}`;
235
+ if (variant)
236
+ return `${SEP}${variant}`;
237
+ if (userSuffix)
238
+ return `${SEP}${userSuffix}`;
239
+ return undefined;
240
+ }
241
+ /**
242
+ * Applies a NamespaceFilter to a list of objects (CLI-3801).
243
+ *
244
+ * Mirrors the semantics of ObjectFilteringService.applyNamespaceFilter so the
245
+ * profiled-objects path produces the same set as the filtered-objects path
246
+ * when given the same filter.
247
+ */
248
+ static mergeUnresolvedFailures(result, unresolvedNames) {
249
+ if (unresolvedNames.length === 0 || !result.success)
250
+ return result;
251
+ const data = result.data;
252
+ data.failed += unresolvedNames.length;
253
+ data.total += unresolvedNames.length;
254
+ for (const name of unresolvedNames) {
255
+ data.failures.push({ objectName: name, error: 'Object not found in org', errorCode: 'E4101' });
256
+ }
257
+ return result;
258
+ }
259
+ static applyNamespaceFilter(objects, filter) {
260
+ if (filter === undefined || filter.kind === 'all')
261
+ return objects;
262
+ if (filter.kind === 'unmanaged') {
263
+ return objects.filter((obj) => obj.namespace === undefined);
264
+ }
265
+ const lowerSet = new Set(filter.namespaces.map((n) => n.toLowerCase()));
266
+ return objects.filter((obj) => obj.namespace !== undefined && lowerSet.has(obj.namespace.toLowerCase()));
267
+ }
268
+ static applyOutcomeFilter(objects, method, emptyResult, startTime) {
269
+ if (method !== 'outcome')
270
+ return objects;
271
+ const eligible = objects.filter((o) => DefinitionCreateOperation.getOutcomeField(o.name) !== undefined);
272
+ if (eligible.length === 0) {
273
+ return createFailureResult(emptyResult, CreateErrorCodes.NO_OBJECTS_FOUND, 'No objects with outcome fields found. Outcome definitions support Opportunity (Won vs Lost), Case (Closed vs Open), and Lead (Converted vs Unconverted) only.', { metadata: { duration: Date.now() - startTime } });
274
+ }
275
+ return eligible;
276
+ }
277
+ /**
278
+ * Invokes the onPreviewReady callback if provided and not in dry-run mode.
279
+ * Returns a cancellation result if the user declines, or undefined to proceed.
280
+ */
281
+ static async invokePreviewCallback(options, createInputs, skippedInputs, totalCount, skippedCount, recordCounts, emptyResult, startTime) {
282
+ if (!options.onPreviewReady || options.dryRun)
283
+ return undefined;
284
+ try {
285
+ const proceed = await options.onPreviewReady({
286
+ toCreate: createInputs,
287
+ toSkip: skippedInputs,
288
+ total: totalCount,
289
+ recordCounts,
290
+ });
291
+ if (!proceed) {
292
+ return createSuccessResult({ ...emptyResult, cancelled: true, skipped: skippedCount, total: totalCount }, { message: 'Creation cancelled by user.', metadata: { duration: Date.now() - startTime } });
293
+ }
294
+ return undefined;
295
+ }
296
+ catch (err) {
297
+ return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, `Confirmation prompt failed: ${err instanceof Error ? err.message : String(err)}`);
298
+ }
299
+ }
300
+ /**
301
+ * Maps a server-side SmartCreateDefinitionResult to an ObjectResult.
302
+ */
303
+ static mapServerResult(sr) {
304
+ return {
305
+ objectName: sr.objectName,
306
+ objectLabel: sr.objectName,
307
+ status: sr.status === 'created'
308
+ ? 'success'
309
+ : sr.status === 'skipped'
310
+ ? 'skip'
311
+ : sr.status === 'preview'
312
+ ? 'preview'
313
+ : 'fail',
314
+ definitionName: sr.definitionName,
315
+ definitionId: sr.definitionId,
316
+ definitionKey: sr.definitionKey,
317
+ fieldCount: sr.fieldCount,
318
+ type: sr.type,
319
+ category: sr.category,
320
+ timeCategory: sr.timeCategory,
321
+ segmentCategory: sr.segmentCategory,
322
+ };
323
+ }
324
+ /** Derives the definition type for a dry-run preview result from the requested method. */
325
+ static derivePreviewType(method) {
326
+ if (method === 'metadata')
327
+ return 'metadata';
328
+ if (method === 'historical')
329
+ return 'historical';
330
+ return 'comparative';
331
+ }
332
+ /** Derives the definition category for a dry-run preview result from the requested method. */
333
+ static derivePreviewCategory(method) {
334
+ if (method === 'metadata')
335
+ return 'Metadata';
336
+ if (method === 'recordtype')
337
+ return 'Record Types';
338
+ if (method === 'outcome')
339
+ return 'Comparative';
340
+ return 'Baseline';
341
+ }
342
+ /**
343
+ * Normalizes a REST-path result for dry-run uniformity (CLI-1832).
344
+ *
345
+ * When options.dryRun is true and the server returned status='skipped' (because the
346
+ * definition already exists), the JSON result's per-item status is remapped to 'preview'
347
+ * so callers see uniform dry-run output across create and skip paths. This mirrors the
348
+ * local-path buildDryRunResult behavior (see :936-937). Progress callbacks still fire
349
+ * with status='skip' so human UX differentiates "already exists" from "would create".
350
+ *
351
+ * After normalization, type/category are back-filled from the method when undefined
352
+ * (ISV create-smart omits classification fields per CLI-1756). 'full' is excluded
353
+ * because it produces multiple definition types per object.
354
+ */
355
+ static normalizeDryRunResult(r, sr, isDryRun, method) {
356
+ if (isDryRun && sr.status === 'skipped') {
357
+ // eslint-disable-next-line no-param-reassign -- normalizing result status in-place for uniform dry-run output (CLI-1832)
358
+ r.status = 'preview';
359
+ }
360
+ if (r.status === 'preview' && r.type === undefined && method !== 'full') {
361
+ // eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-1756: ISV omits these)
362
+ r.type = DefinitionCreateOperation.derivePreviewType(method);
363
+ // eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-1756)
364
+ r.category = DefinitionCreateOperation.derivePreviewCategory(method);
365
+ }
366
+ // CLI-3392: ISV create-smart omits classification for skipped definitions outside dry-run too.
367
+ if (!isDryRun && sr.status === 'skipped' && r.type === undefined && method !== 'full') {
368
+ // eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-3392: ISV omits type/category for skipped)
369
+ r.type = DefinitionCreateOperation.derivePreviewType(method);
370
+ // eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-3392)
371
+ r.category = r.category ?? DefinitionCreateOperation.derivePreviewCategory(method);
372
+ }
373
+ }
374
+ /** Fires the onObjectComplete progress callback for a single processed result. */
375
+ static notifyObjectComplete(r, sr, current, total, options) {
376
+ // CLI-1832: dry-run normalizes server 'skipped' → r.status='preview' for uniform JSON
377
+ // output. The progress callback still surfaces 'skip' from the original server status
378
+ // so human UX differentiates "already exists" from "would create". This mirrors
379
+ // buildDryRunResult's local-path behavior (see :936-937 and :945).
380
+ const callbackStatus = sr.status === 'skipped' ? 'skip' : r.status === 'preview' ? 'preview' : r.status;
381
+ const callbackMessage = sr.status === 'skipped'
382
+ ? 'definition already exists'
383
+ : r.status === 'success'
384
+ ? `created "${r.definitionName}"`
385
+ : r.status === 'skip'
386
+ ? 'definition already exists'
387
+ : r.error ?? sr.errorMessage ?? 'unknown';
388
+ options.onObjectComplete?.({
389
+ objectName: r.objectName,
390
+ status: callbackStatus,
391
+ message: callbackMessage,
392
+ current,
393
+ total,
394
+ type: r.type,
395
+ definitionName: r.definitionName,
396
+ definitionKey: r.definitionKey,
397
+ recordTypeName: r.segmentCategory,
398
+ category: r.category,
399
+ timeCategory: r.timeCategory,
400
+ segmentCategory: r.segmentCategory,
401
+ fieldCount: r.fieldCount,
402
+ });
403
+ }
404
+ // ── Public Instance Methods ──────────────────────────────────────────
405
+ /**
406
+ * Executes the definition create operation.
407
+ *
408
+ * @param options - Create operation options
409
+ * @returns ServiceResult containing creation statistics
410
+ */
411
+ // eslint-disable-next-line complexity -- 7-step orchestration pipeline with error handling at each step
412
+ async execute(options) {
413
+ const startTime = Date.now();
414
+ const emptyResult = {
415
+ created: 0,
416
+ failed: 0,
417
+ skipped: 0,
418
+ total: 0,
419
+ failures: [],
420
+ results: [],
421
+ };
422
+ try {
423
+ this.logger?.log('Starting definition create operation');
424
+ const operationWarnings = [];
425
+ // CLI-4215 (REQ-002): the bulk-recipe portability path requires a category applied
426
+ // identically to every definition in the run. Fail closed before any object
427
+ // resolution or writes when it is missing or blank.
428
+ if (options.portabilityNaming === true && (options.category === undefined || options.category.trim() === '')) {
429
+ return createFailureResult(emptyResult, CreateErrorCodes.PORTABILITY_CATEGORY_REQUIRED, 'A category is required for REQ-002 bulk runs. Supply a non-empty category so every definition in the run is grouped consistently.', { metadata: { duration: Date.now() - startTime } });
430
+ }
431
+ // Step 1: Resolve objects
432
+ const resolveResult = await this.resolveObjects(options, operationWarnings);
433
+ if (!resolveResult.success) {
434
+ return createFailureResult(emptyResult, resolveResult.errorCode, resolveResult.message, {
435
+ metadata: { duration: Date.now() - startTime },
436
+ });
437
+ }
438
+ // CLI-4214: thread the record-count reconciliation truncation disclosure (surfaced by the
439
+ // filtered-objects path) into the operation warnings so callers never lose it.
440
+ if (resolveResult.warnings && resolveResult.warnings.length > 0) {
441
+ operationWarnings.push(...resolveResult.warnings);
442
+ }
443
+ // CLI-4090: Track explicitly-requested objects that were not found in the org.
444
+ // These are surfaced as failures in the final result so the exit code reflects
445
+ // the partial failure.
446
+ const unresolvedNames = options.objects && options.objects.length > 0
447
+ ? options.objects.filter((name) => !resolveResult.data.some((obj) => obj.name.toLowerCase() === name.toLowerCase()))
448
+ : [];
449
+ const objectsBeforeLimit = this.applyMinRecordsThreshold(resolveResult.data, options, emptyResult, startTime);
450
+ if (!Array.isArray(objectsBeforeLimit))
451
+ return objectsBeforeLimit;
452
+ // Step 1b: Apply --limit to cap the number of objects processed
453
+ const { limited: objects, warning: objectLimitWarning } = this.applyObjectLimit(objectsBeforeLimit, options.limit);
454
+ if (objectLimitWarning) {
455
+ operationWarnings.push(objectLimitWarning);
456
+ }
457
+ // Step 2: Fetch record counts for resolved objects
458
+ const uniqueObjectNames = [...new Set(objects.map((o) => o.name))];
459
+ const countsResult = await this.filteringService.getRecordCounts(uniqueObjectNames);
460
+ const recordCounts = countsResult.success ? countsResult.data : new Map();
461
+ const method = options.method ?? 'metadata';
462
+ const year = options.year ?? new Date().getFullYear();
463
+ // Resolve year range: prefer explicit yearRange, fall back to year + usePrior
464
+ const yearRange = options.yearRange ?? {
465
+ entries: method === 'metadata' ? [] : [{ year, unbounded: options.usePrior ?? false }],
466
+ };
467
+ options.onProgress?.(`Checking existing definitions for ${objects.length} objects...`);
468
+ // Step 2.5: Build data availability grid (concurrent with Step 3)
469
+ let availabilityGrid;
470
+ if (this.dataAvailabilityService && yearRange.entries.length > 0) {
471
+ const gridResult = await this.dataAvailabilityService.buildGrid(uniqueObjectNames, yearRange);
472
+ if (gridResult.success) {
473
+ availabilityGrid = gridResult.data;
474
+ }
475
+ else {
476
+ this.logger?.log(`Data availability grid failed: ${gridResult.message ?? 'unknown'}`);
477
+ }
478
+ }
479
+ // REST API path: delegate to server when restClient is available.
480
+ // Fall back to the local path when:
481
+ // method='full' — server creates only 1 definition; local path composes all sub-methods
482
+ // lifetimePrimary=true — ISV Apex DefinitionFieldGenerationService has no lifetime-primary
483
+ // support (CLI-2944); local path pre-computes the lifetime filter
484
+ // JSON, name, timeCategory, and segmentCategory and persists them
485
+ // verbatim via create-definition. Remove this branch once the ISV
486
+ // Apex side mirrors the TS lifetime logic.
487
+ // timeCategory or segmentCategory override set — local path applies overrides verbatim through ctx builders (CLI-2957).
488
+ // CLI-3099 (ISV-7889 + ISV-7888 deployed): the previous "force local path for comparative
489
+ // + dateLiteralRange" clause was removed once ISV smart-create began emitting SetA+SetB
490
+ // filterJson for the comparative + dateLiteralEntries path. Comparative date-literal
491
+ // cascades now flow through the server smart-create endpoint like every other method.
492
+ // CLI-3425 + CLI-3834: force local path for ALL method=recordtype invocations — the ISV
493
+ // create-smart endpoint (a) ignores options.category for method=recordtype standalone,
494
+ // silently storing the hard-coded default "Record Types" instead, and (b) does NOT populate
495
+ // the server-side RT-scope filter fields (Prop_IsFiltered_SetA__c, Prop_Filter_JSON_SetA__c,
496
+ // Prop_Filter_SetA__c), so post-CLI-3834 defs would profile object-wide rather than restricted
497
+ // to the chosen RT. The local path (a) sends primaryCategory verbatim and (b) composes the
498
+ // RecordTypeId equality into filterJson via composeRecordTypeFilter (CLI-3843 + 770268a2 Id
499
+ // quoting). Both --category and --recordtype filters are honoured in the local fan-out.
500
+ // CLI-3446: force local path for historical + dateLiteralRange — the ISV create-smart
501
+ // endpoint fails to translate `:N`-suffix literals (N_YEARS_AGO:N, LAST_N_YEARS:N) into
502
+ // filterJson, producing defs with IsFiltered_SetA=false and Filter_JSON_SetA=null. The
503
+ // local path constructs filterJson correctly via buildDateLiteralFilterJson. Remove the
504
+ // historical dateLiteralRange disjunct once the ISV create-smart endpoint mirrors the TS
505
+ // date-literal logic for historical methods.
506
+ // CLI-4215 (REQ-002 portability naming): force the local path so definition names are
507
+ // built deterministically by DefinitionFieldGenerationService as `${label} • ${suffix}`.
508
+ // The ISV create-smart endpoint joins suffix segments server-side, which cannot guarantee
509
+ // the exact form REQ-002 requires; the local path applies the simplified naming verbatim.
510
+ const useLocalPath = options.method === 'full' ||
511
+ options.lifetimePrimary === true ||
512
+ options.timeCategory !== undefined ||
513
+ options.segmentCategory !== undefined ||
514
+ (options.dateLiteralRange !== undefined && options.method === 'historical') ||
515
+ options.method === 'recordtype' ||
516
+ options.portabilityNaming === true;
517
+ if (this.restClient && !useLocalPath) {
518
+ return DefinitionCreateOperation.mergeUnresolvedFailures(await this.executeCreationViaRest(objects, options, operationWarnings, startTime, availabilityGrid, recordCounts), unresolvedNames);
519
+ }
520
+ // Step 3: Check for existing definitions (local path — fallback when no REST client)
521
+ const existingDefsResult = await this.fetchAllExistingDefinitions();
522
+ if (!existingDefsResult.success) {
523
+ this.logger?.log('Failed to query existing definitions');
524
+ }
525
+ const existingDefinitions = existingDefsResult.success ? existingDefsResult.data : [];
526
+ const existingNames = new Set(existingDefinitions.map((def) => def.name));
527
+ // Step 4: Build candidate inputs
528
+ const candidateResult = await this.buildCandidateInputsForMethod(objects, method, year, yearRange, options, operationWarnings);
529
+ if (!candidateResult.success) {
530
+ return createFailureResult(emptyResult, candidateResult.errorCode, candidateResult.message, {
531
+ metadata: { duration: Date.now() - startTime },
532
+ });
533
+ }
534
+ const candidateInputs = candidateResult.data;
535
+ // Step 5: Deduplicate (partition into create vs skip)
536
+ const createInputsBeforeLimit = [];
537
+ const skippedInputs = [];
538
+ for (const input of candidateInputs) {
539
+ if (existingNames.has(input.name)) {
540
+ skippedInputs.push(input);
541
+ }
542
+ else {
543
+ createInputsBeforeLimit.push(input);
544
+ }
545
+ }
546
+ const skippedCount = skippedInputs.length;
547
+ if (createInputsBeforeLimit.length === 0) {
548
+ const totalDefs = candidateInputs.length;
549
+ if (totalDefs === 0) {
550
+ // No candidates generated (e.g., no record types found for --method recordtype)
551
+ return createFailureResult({ ...emptyResult, total: 0 }, CreateErrorCodes.NO_OBJECTS_FOUND, operationWarnings.length > 0
552
+ ? `No candidate definitions were generated: ${operationWarnings.join('; ')}`
553
+ : 'No candidate definitions were generated. Check object filters, record types, or method selection.', { metadata: { duration: Date.now() - startTime } });
554
+ }
555
+ // CLI-3419 AC14: all N candidates already exist — idempotent skip-only success.
556
+ // Bypass the preview callback (nothing to create, nothing to confirm) and delegate
557
+ // to the dry-run / create path with empty createInputs so the skip callbacks fire
558
+ // and the result carries `created=0, skipped=N, success=true`.
559
+ this.logger?.log(`All ${totalDefs} definitions already exist`);
560
+ if (options.dryRun) {
561
+ return DefinitionCreateOperation.mergeUnresolvedFailures(this.buildDryRunResult([], skippedInputs, totalDefs, operationWarnings, options, startTime, availabilityGrid, recordCounts), unresolvedNames);
562
+ }
563
+ return DefinitionCreateOperation.mergeUnresolvedFailures(await this.executeCreation([], skippedInputs, totalDefs, operationWarnings, options, startTime, availabilityGrid, recordCounts), unresolvedNames);
564
+ }
565
+ this.logger?.log(`${createInputsBeforeLimit.length} definitions to create, ${skippedCount} already exist`);
566
+ // Apply --limit safety cap
567
+ const { limited: createInputs, warning: limitWarning } = this.applyInputLimit(createInputsBeforeLimit, options.limit);
568
+ if (limitWarning) {
569
+ operationWarnings.push(limitWarning);
570
+ }
571
+ const totalForPreview = createInputs.length + skippedCount;
572
+ options.onProgress?.(`${totalForPreview} ${totalForPreview === 1 ? 'definition' : 'definitions'} to create`);
573
+ // Step 6: Preview callback (unless dry-run)
574
+ const cancelResult = await DefinitionCreateOperation.invokePreviewCallback(options, createInputs, skippedInputs, candidateInputs.length, skippedCount, recordCounts, emptyResult, startTime);
575
+ if (cancelResult)
576
+ return cancelResult;
577
+ // Step 7: Dry run or create
578
+ if (options.dryRun) {
579
+ return DefinitionCreateOperation.mergeUnresolvedFailures(this.buildDryRunResult(createInputs, skippedInputs, candidateInputs.length, operationWarnings, options, startTime, availabilityGrid, recordCounts), unresolvedNames);
580
+ }
581
+ return DefinitionCreateOperation.mergeUnresolvedFailures(await this.executeCreation(createInputs, skippedInputs, candidateInputs.length, operationWarnings, options, startTime, availabilityGrid, recordCounts), unresolvedNames);
582
+ }
583
+ catch (error) {
584
+ const errorMessage = error instanceof Error ? error.message : String(error);
585
+ this.logger?.log(`Definition create operation failed: ${errorMessage}`);
586
+ return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, errorMessage, {
587
+ metadata: { duration: Date.now() - startTime },
588
+ });
589
+ }
590
+ }
591
+ // ── Private Instance Methods ─────────────────────────────────────────
592
+ /**
593
+ * Applies the --min-records threshold, returning the filtered list or an early failure result.
594
+ */
595
+ applyMinRecordsThreshold(objects, options, emptyResult, startTime) {
596
+ if (!options.minRecords || options.minRecords <= 0)
597
+ return objects;
598
+ const filtered = this.applyMinRecordsFilter(objects, options.minRecords);
599
+ if (filtered.length === 0) {
600
+ return createFailureResult(emptyResult, CreateErrorCodes.NO_OBJECTS_FOUND, `No objects found with at least ${options.minRecords} records`, { metadata: { duration: Date.now() - startTime } });
601
+ }
602
+ return filtered;
603
+ }
604
+ /**
605
+ * Builds record-type candidate inputs by querying the RecordTypeService for each object.
606
+ *
607
+ * @param cascade - Optional accumulator. Presence signals cascade-mode (`buildFullCandidateInputs`):
608
+ * objects with no record types are pushed to `cascade.noRecordTypes` instead of warning per-object.
609
+ * Absence is the standalone caller \u2014 per-object warnings fire as before.
610
+ * Only the empty-result branch is routed; failed-query and `--recordtype X` no-match branches
611
+ * remain per-object (a query failure is genuinely per-object actionable, and a user-specified
612
+ * record-type narrowing justifies per-object diagnostics).
613
+ */
614
+ async buildRecordTypeCandidateInputs(objects, yearRange, options, warnings, cascade) {
615
+ if (!this.recordTypeService) {
616
+ return createFailureResult([], CreateErrorCodes.OPERATION_FAILED, 'RecordTypeService is required when method=recordtype');
617
+ }
618
+ const inputs = [];
619
+ const isSingleObject = objects.length === 1;
620
+ const rtStatus = options.recordTypeStatus ?? 'active';
621
+ for (const obj of objects) {
622
+ // eslint-disable-next-line no-await-in-loop -- Sequential per-object queries with per-object error handling
623
+ const rtResult = await this.recordTypeService.getRecordTypesByStatus(obj.name, rtStatus);
624
+ if (!rtResult.success) {
625
+ warnings.push(`Failed to query record types for ${obj.name}: ${rtResult.message}`);
626
+ continue;
627
+ }
628
+ let recordTypes = rtResult.data;
629
+ if (recordTypes.length === 0) {
630
+ if (cascade) {
631
+ cascade.noRecordTypes.push(obj.name);
632
+ }
633
+ else {
634
+ const statusLabel = rtStatus === 'all' ? '' : ` ${rtStatus}`;
635
+ warnings.push(`Object '${obj.name}' has no${statusLabel} record types \u2014 skipping.`);
636
+ }
637
+ continue;
638
+ }
639
+ // Apply --recordtype filter (case-insensitive on Name OR DeveloperName).
640
+ // DeveloperName matching supports cross-org scripting where Names may be
641
+ // translated/customized but DeveloperNames are stable API identifiers.
642
+ if (options.recordType) {
643
+ const targetLower = options.recordType.toLowerCase();
644
+ recordTypes = recordTypes.filter((rt) => rt.name.toLowerCase() === targetLower || rt.developerName.toLowerCase() === targetLower);
645
+ if (recordTypes.length === 0) {
646
+ if (isSingleObject) {
647
+ const available = rtResult.data
648
+ .map((rt) => (rt.name === rt.developerName ? rt.name : `${rt.name} (${rt.developerName})`))
649
+ .join(', ');
650
+ return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, `Record type '${options.recordType}' not found on ${obj.name}. Active record types: ${available}`);
651
+ }
652
+ warnings.push(`Object '${obj.name}' does not have record type '${options.recordType}' \u2014 skipping.`);
653
+ continue;
654
+ }
655
+ }
656
+ for (const rt of recordTypes) {
657
+ // CLI-3834: pass the full record-type ref (id + name) so buildInputsForRecordType
658
+ // can populate the server-side filter fields with the RT scope. Passing rt.name
659
+ // alone caused profiling to run object-wide.
660
+ inputs.push(...DefinitionFieldGenerationService.buildInputsForRecordType(obj, rt, yearRange, options));
661
+ }
662
+ }
663
+ return createSuccessResult(inputs);
664
+ }
665
+ /**
666
+ * Builds full candidate inputs by composing metadata + historical + comparative + recordtype methods.
667
+ * Degrades gracefully to metadata + historical + comparative when RecordTypeService is absent.
668
+ */
669
+ async buildFullCandidateInputs(objects, year, yearRange, options, warnings) {
670
+ // Cascade-mode accumulator: per-builder empty-result skips push here instead of
671
+ // emitting per-object warnings. After both builders run, we emit at most one
672
+ // aggregated summary line (RT bucket only). Mirrors the single-summary pattern
673
+ // already established below for RecordTypeService absence (CLI-3341).
674
+ //
675
+ // CLI-3611: outcome bucket removed — silently skipping objects without outcome
676
+ // fields is expected behavior in --method full (platform limits to Opportunity/Case/Lead).
677
+ const cascade = { noRecordTypes: [] };
678
+ // Phase 1: Build metadata + historical + comparative inputs
679
+ const allInputs = [
680
+ ...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'metadata', year, yearRange, options),
681
+ ...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'historical', year, yearRange, options),
682
+ ...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'comparative', year, yearRange, options),
683
+ ];
684
+ // Phase 1b: Build business process outcome inputs (always available — no service dependency)
685
+ // yearRange applies when user explicitly provided --year/--from/--to (options.year is set).
686
+ // Without explicit year flags, outcome defaults to lifetime (no year scoping).
687
+ const outcomeYearRange = options.year !== undefined ? yearRange : undefined;
688
+ allInputs.push(...DefinitionFieldGenerationService.buildOutcomeCandidateInputs(objects, options, warnings, outcomeYearRange, cascade));
689
+ // Phase 2: Build recordtype inputs (soft degradation if service absent)
690
+ if (!this.recordTypeService) {
691
+ warnings.push('RecordTypeService not available — full method degrading to metadata + historical + comparative + outcome only.');
692
+ emitCascadeSummaries(cascade, objects.length, options.recordTypeStatus ?? 'active', warnings);
693
+ return createSuccessResult(allInputs);
694
+ }
695
+ const rtResult = await this.buildRecordTypeCandidateInputs(objects, yearRange, options, warnings, cascade);
696
+ const rtInputs = rtResult.success ? rtResult.data : [];
697
+ if (!rtResult.success) {
698
+ warnings.push(`Record type inputs failed: ${rtResult.message ?? 'unknown error'} — using metadata + historical + comparative only.`);
699
+ }
700
+ // Emit aggregated skip summaries for both buckets (suppressed when bucket is empty).
701
+ emitCascadeSummaries(cascade, objects.length, options.recordTypeStatus ?? 'active', warnings);
702
+ // Phase 3: Merge and deduplicate by name (defensive — names are structurally distinct)
703
+ const seen = new Set();
704
+ const merged = [];
705
+ for (const input of [...allInputs, ...rtInputs]) {
706
+ if (!seen.has(input.name)) {
707
+ seen.add(input.name);
708
+ merged.push(input);
709
+ }
710
+ }
711
+ return createSuccessResult(merged);
712
+ }
713
+ /**
714
+ * Builds candidate inputs for any method, delegating to the appropriate builder.
715
+ */
716
+ async buildCandidateInputsForMethod(objects, method, year, yearRange, options, warnings) {
717
+ if (method === 'recordtype') {
718
+ return this.buildRecordTypeCandidateInputs(objects, yearRange, options, warnings);
719
+ }
720
+ if (method === 'outcome') {
721
+ // Only apply yearRange when user explicitly provided --year/--from/--to
722
+ const outcomeYR = options.year !== undefined ? yearRange : undefined;
723
+ return createSuccessResult(DefinitionFieldGenerationService.buildOutcomeCandidateInputs(objects, options, warnings, outcomeYR));
724
+ }
725
+ if (method === 'full') {
726
+ return this.buildFullCandidateInputs(objects, year, yearRange, options, warnings);
727
+ }
728
+ return createSuccessResult(DefinitionFieldGenerationService.buildCandidateInputs(objects, method, year, yearRange, options));
729
+ }
730
+ /**
731
+ * Builds a dry run result without creating any definitions.
732
+ */
733
+ buildDryRunResult(createInputs, skippedInputs, totalCount, warnings, options, startTime, availabilityGrid, recordCounts) {
734
+ // Build preview results from the inputs (fieldCount unavailable in dry runs)
735
+ const results = [];
736
+ for (const input of createInputs) {
737
+ results.push({
738
+ objectName: input.objectName,
739
+ objectLabel: input.objectLabel,
740
+ status: 'preview',
741
+ definitionName: input.name,
742
+ type: input.method,
743
+ category: input.category,
744
+ timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
745
+ segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
746
+ });
747
+ }
748
+ for (const input of skippedInputs) {
749
+ results.push({
750
+ objectName: input.objectName,
751
+ objectLabel: input.objectLabel,
752
+ status: 'preview',
753
+ definitionName: input.name,
754
+ type: DefinitionCreateOperation.derivePreviewType(options.method ?? 'metadata'),
755
+ category: input.category ?? DefinitionCreateOperation.derivePreviewCategory(options.method ?? 'metadata'),
756
+ timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
757
+ segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
758
+ });
759
+ }
760
+ // Fire callbacks — createInputs get 'preview', skippedInputs get 'skip' (progress display only;
761
+ // JSON result uses 'preview' for both so callers see a uniform dry-run output).
762
+ if (options.onObjectComplete) {
763
+ const createCount = createInputs.length;
764
+ for (let i = 0; i < results.length; i++) {
765
+ const r = results[i];
766
+ const isSkipped = i >= createCount;
767
+ options.onObjectComplete({
768
+ objectName: r.objectName,
769
+ status: isSkipped ? 'skip' : 'preview',
770
+ message: isSkipped ? 'definition already exists' : `would create "${r.definitionName}"`,
771
+ current: i + 1,
772
+ total: results.length,
773
+ type: r.type,
774
+ definitionName: r.definitionName,
775
+ definitionKey: r.definitionKey,
776
+ recordTypeName: r.segmentCategory,
777
+ category: r.category,
778
+ timeCategory: r.timeCategory,
779
+ segmentCategory: r.segmentCategory,
780
+ });
781
+ }
782
+ }
783
+ const dryRunResult = {
784
+ created: createInputs.length,
785
+ failed: 0,
786
+ skipped: skippedInputs.length,
787
+ total: totalCount,
788
+ dryRun: true,
789
+ failures: [],
790
+ results,
791
+ availabilityGrid,
792
+ recordCounts,
793
+ };
794
+ this.logger?.log(`Dry run: would create ${createInputs.length} definitions`);
795
+ return createSuccessResult(dryRunResult, {
796
+ message: `Dry run: would create ${createInputs.length} profiling definitions`,
797
+ warnings: warnings.length > 0 ? warnings : undefined,
798
+ metadata: { duration: Date.now() - startTime },
799
+ });
800
+ }
801
+ /**
802
+ * Executes sequential creation of definitions with per-item progress callbacks.
803
+ */
804
+ async executeCreation(createInputs, skippedInputs, totalCount, operationWarnings, options, startTime, availabilityGrid, recordCounts) {
805
+ const results = [];
806
+ const failures = [];
807
+ const totalItems = createInputs.length + skippedInputs.length;
808
+ let itemIndex = 0;
809
+ let createdCount = 0;
810
+ let failedCount = 0;
811
+ // Fire skipped items first
812
+ for (const input of skippedInputs) {
813
+ itemIndex++;
814
+ const r = {
815
+ objectName: input.objectName,
816
+ objectLabel: input.objectLabel,
817
+ status: 'skip',
818
+ definitionName: input.name,
819
+ type: input.method,
820
+ category: input.category,
821
+ timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
822
+ segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
823
+ };
824
+ results.push(r);
825
+ options.onObjectComplete?.({
826
+ objectName: r.objectName,
827
+ status: 'skip',
828
+ message: 'definition already exists',
829
+ current: itemIndex,
830
+ total: totalItems,
831
+ type: r.type,
832
+ definitionName: r.definitionName,
833
+ recordTypeName: r.segmentCategory,
834
+ category: r.category,
835
+ timeCategory: r.timeCategory,
836
+ segmentCategory: r.segmentCategory,
837
+ });
838
+ }
839
+ // Create definitions one at a time for real-time progress
840
+ for (const input of createInputs) {
841
+ itemIndex++;
842
+ // eslint-disable-next-line no-await-in-loop -- Sequential for real-time progress feedback
843
+ const createResult = await this.definitionService.createDefinition(input);
844
+ if (createResult.success && createResult.data) {
845
+ const def = createResult.data;
846
+ const fieldCount = createResult.metadata?.fieldCount ?? undefined;
847
+ createdCount++;
848
+ const r = {
849
+ objectName: input.objectName,
850
+ objectLabel: def.objectLabel ?? input.objectLabel,
851
+ status: 'success',
852
+ definitionName: def.name,
853
+ definitionId: def.id,
854
+ definitionKey: def.key,
855
+ type: input.method,
856
+ fieldCount,
857
+ category: def.category ?? input.category,
858
+ timeCategory: def.timeCategory ?? DefinitionCreateOperation.resolveTimeCategory(input),
859
+ segmentCategory: def.segmentCategory ?? DefinitionCreateOperation.resolveSegmentCategory(input),
860
+ };
861
+ results.push(r);
862
+ options.onObjectComplete?.({
863
+ objectName: r.objectName,
864
+ status: 'success',
865
+ message: DefinitionCreateOperation.formatObjectMessage(r),
866
+ current: itemIndex,
867
+ total: totalItems,
868
+ type: r.type,
869
+ definitionName: r.definitionName,
870
+ definitionKey: r.definitionKey,
871
+ recordTypeName: r.segmentCategory,
872
+ category: r.category,
873
+ timeCategory: r.timeCategory,
874
+ segmentCategory: r.segmentCategory,
875
+ fieldCount: r.fieldCount,
876
+ });
877
+ }
878
+ else {
879
+ failedCount++;
880
+ const errorMsg = createResult.message ?? 'Unknown error';
881
+ failures.push({
882
+ objectName: input.objectName,
883
+ error: errorMsg,
884
+ errorCode: createResult.errorCode ?? CreateErrorCodes.OPERATION_FAILED,
885
+ });
886
+ const r = {
887
+ objectName: input.objectName,
888
+ objectLabel: input.objectLabel,
889
+ status: 'fail',
890
+ definitionName: input.name,
891
+ type: input.method,
892
+ error: errorMsg,
893
+ category: input.category,
894
+ timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
895
+ segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
896
+ };
897
+ results.push(r);
898
+ options.onObjectComplete?.({
899
+ objectName: r.objectName,
900
+ status: 'fail',
901
+ message: errorMsg,
902
+ current: itemIndex,
903
+ total: totalItems,
904
+ type: r.type,
905
+ definitionName: r.definitionName,
906
+ recordTypeName: r.segmentCategory,
907
+ category: r.category,
908
+ timeCategory: r.timeCategory,
909
+ segmentCategory: r.segmentCategory,
910
+ });
911
+ }
912
+ }
913
+ const result = {
914
+ created: createdCount,
915
+ failed: failedCount,
916
+ skipped: skippedInputs.length,
917
+ total: totalCount,
918
+ failures,
919
+ results,
920
+ availabilityGrid,
921
+ recordCounts,
922
+ };
923
+ const duration = Date.now() - startTime;
924
+ this.logger?.log(`Created ${createdCount} definitions, ${failedCount} failed, ${skippedInputs.length} skipped`);
925
+ options.onProgress?.(`Complete: ${createdCount} created, ${failedCount} failed, ${skippedInputs.length} skipped`);
926
+ return createSuccessResult(result, {
927
+ message: `Created ${createdCount} profiling definitions`,
928
+ warnings: operationWarnings.length > 0 ? operationWarnings : undefined,
929
+ metadata: { duration },
930
+ });
931
+ }
932
+ /**
933
+ * Executes definition creation via the ISV REST API (create-smart endpoint).
934
+ * Server handles naming, categorization, deduplication, and creation.
935
+ * The CLI only provides objects, method, and options — no local business logic.
936
+ */
937
+ async executeCreationViaRest(objects, options, operationWarnings, startTime, availabilityGrid, recordCounts) {
938
+ const emptyResult = { created: 0, failed: 0, skipped: 0, total: 0, failures: [], results: [] };
939
+ this.logger?.log('Delegating definition creation to ISV REST API (create-smart)');
940
+ options.onProgress?.('Creating definitions via server-side pipeline...');
941
+ const method = options.method ?? 'metadata';
942
+ // Apply --limit safety cap before sending to ISV (ISV sees only the capped list).
943
+ const { limited: limitedObjects, warning: limitWarning } = this.applyObjectLimit(objects, options.limit);
944
+ if (limitWarning)
945
+ operationWarnings.push(limitWarning);
946
+ // Outcome pre-filter: only Opportunity, Case, Lead have outcome fields (CLI-1792).
947
+ const objectsToCreate = DefinitionCreateOperation.applyOutcomeFilter(limitedObjects, method, emptyResult, startTime);
948
+ if (!Array.isArray(objectsToCreate))
949
+ return objectsToCreate;
950
+ const restResult = await this.restClient.createSmart({
951
+ objects: objectsToCreate.map((o) => ({ name: o.name, label: o.label })),
952
+ method,
953
+ options: {
954
+ category: options.category,
955
+ timeCategory: options.timeCategory,
956
+ segmentCategory: options.segmentCategory,
957
+ year: options.year,
958
+ usePrior: options.usePrior,
959
+ noValueFrequency: options.noValueFrequency,
960
+ namePrefix: options.namePrefix,
961
+ // Prepend bullet separator — ISV joins suffix with a plain space, so we carry the bullet.
962
+ // CLI-3064: When --no-value-frequency is set, the resolved name on both client and server
963
+ // must include a "No Value Frequency" disambiguator \u2014 otherwise the value-frequency and
964
+ // no-value-frequency variants of the same (object, method, time-segment) collide on the
965
+ // name-keyed dedup gate and the second is silently skipped. The disambiguator is layered
966
+ // ahead of any user-supplied --name-suffix so user suffixes compose cleanly on top.
967
+ nameSuffix: DefinitionCreateOperation.composeRestNameSuffix(options.nameSuffix, options.noValueFrequency),
968
+ origin: options.origin,
969
+ recordType: options.recordType,
970
+ description: options.description,
971
+ dryRun: options.dryRun,
972
+ dateLiteralRange: options.dateLiteralRange,
973
+ yearEntries: options.yearRange?.entries.length
974
+ ? options.yearRange.entries.map(({ year, unbounded }) => ({ year, unbounded }))
975
+ : undefined,
976
+ },
977
+ });
978
+ if (!restResult.success) {
979
+ return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, restResult.message ?? 'REST API call failed', {
980
+ metadata: { duration: Date.now() - startTime },
981
+ });
982
+ }
983
+ const serverResponse = restResult.data;
984
+ const failures = [];
985
+ let createdCount = 0;
986
+ let failedCount = 0;
987
+ let skippedCount = 0;
988
+ // Map all server results synchronously, then enrich classification in parallel (CLI-1756).
989
+ const serverResults = serverResponse.results ?? [];
990
+ const resultPairs = serverResults.map((sr) => ({ sr, r: DefinitionCreateOperation.mapServerResult(sr) }));
991
+ // CLI-1756: ISV create-smart no longer returns classification fields (type, category,
992
+ // timeCategory, segmentCategory). Enrich all created definitions in parallel via GET
993
+ // so downstream consumers (JSON output, NUT assertions) see full classification metadata.
994
+ await this.enrichClassificationFields(resultPairs);
995
+ const results = [];
996
+ for (const { sr, r } of resultPairs) {
997
+ DefinitionCreateOperation.normalizeDryRunResult(r, sr, options.dryRun === true, method);
998
+ results.push(r);
999
+ if (sr.status === 'created' || sr.status === 'preview') {
1000
+ createdCount++;
1001
+ }
1002
+ else if (sr.status === 'skipped') {
1003
+ skippedCount++;
1004
+ }
1005
+ else if (sr.status === 'failed') {
1006
+ failedCount++;
1007
+ failures.push({
1008
+ objectName: sr.objectName,
1009
+ error: sr.errorMessage ?? 'Unknown error',
1010
+ errorCode: CreateErrorCodes.OPERATION_FAILED,
1011
+ });
1012
+ }
1013
+ DefinitionCreateOperation.notifyObjectComplete(r, sr, results.length, serverResults.length, options);
1014
+ }
1015
+ const createResult = {
1016
+ created: createdCount,
1017
+ failed: failedCount,
1018
+ skipped: skippedCount,
1019
+ total: serverResults.length,
1020
+ dryRun: options.dryRun,
1021
+ failures,
1022
+ results,
1023
+ availabilityGrid,
1024
+ recordCounts,
1025
+ };
1026
+ return createSuccessResult(createResult, {
1027
+ message: options.dryRun
1028
+ ? `Preview: ${results.length} definitions`
1029
+ : `Created ${createdCount} profiling definitions`,
1030
+ warnings: operationWarnings.length > 0 ? operationWarnings : undefined,
1031
+ metadata: { duration: Date.now() - startTime },
1032
+ });
1033
+ }
1034
+ /**
1035
+ * Enriches classification fields (type, category, timeCategory, segmentCategory) on created
1036
+ * results in parallel. CLI-1756: ISV create-smart no longer returns these fields in its response.
1037
+ */
1038
+ async enrichClassificationFields(pairs) {
1039
+ await Promise.all(pairs
1040
+ .filter(({ sr, r }) => (sr.status === 'created' || sr.status === 'skipped') && sr.definitionId && r.type === undefined)
1041
+ .map(async ({ sr, r }) => {
1042
+ const enrichResult = await this.definitionService.getDefinitionById(sr.definitionId);
1043
+ if (enrichResult.success && enrichResult.data) {
1044
+ const def = enrichResult.data;
1045
+ // eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756: ISV omits classification in create response)
1046
+ r.type = def.type;
1047
+ // eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
1048
+ r.category = def.category;
1049
+ // eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
1050
+ r.timeCategory = def.timeCategory;
1051
+ // eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
1052
+ r.segmentCategory = def.segmentCategory;
1053
+ }
1054
+ else {
1055
+ this.logger?.log(`CLI-1756: Failed to enrich classification for ${sr.objectName}: ${enrichResult.message ?? 'unknown'}`);
1056
+ }
1057
+ }));
1058
+ }
1059
+ /**
1060
+ * Resolves objects by explicit names, profiled set, or filtering criteria.
1061
+ */
1062
+ async resolveObjects(options, warnings) {
1063
+ if (options.profiled) {
1064
+ return this.resolveProfiledObjects(options, warnings);
1065
+ }
1066
+ if (options.objects && options.objects.length > 0) {
1067
+ return this.resolveExplicitObjects(options.objects, warnings, options.onProgress);
1068
+ }
1069
+ return this.resolveFilteredObjects(options);
1070
+ }
1071
+ /**
1072
+ * Resolves objects that have successful metadata profiling results.
1073
+ */
1074
+ async resolveProfiledObjects(options, warnings) {
1075
+ options.onProgress?.('Querying profiled objects...');
1076
+ this.logger?.log('Querying profiled objects from ProfilingSummaryService');
1077
+ if (!this.profilingSummaryService) {
1078
+ return createFailureResult([], CreateErrorCodes.OPERATION_FAILED, 'ProfilingSummaryService is required when profiled=true');
1079
+ }
1080
+ const profiledResult = await this.profilingSummaryService.queryProfiledObjects();
1081
+ if (!profiledResult.success) {
1082
+ return createFailureResult([], CreateErrorCodes.FILTER_FAILED, profiledResult.message);
1083
+ }
1084
+ let profiledNames = profiledResult.data;
1085
+ if (profiledNames.length === 0) {
1086
+ return createFailureResult([], CreateErrorCodes.NO_PROFILED_OBJECTS, 'No objects have been profiled yet. Run profiling with --method metadata first.');
1087
+ }
1088
+ this.logger?.log(`Found ${profiledNames.length} profiled objects`);
1089
+ if (options.objects && options.objects.length > 0) {
1090
+ const profiledSet = new Set(profiledNames.map((n) => n.toLowerCase()));
1091
+ const intersected = [];
1092
+ for (const obj of options.objects) {
1093
+ if (profiledSet.has(obj.toLowerCase())) {
1094
+ intersected.push(obj);
1095
+ }
1096
+ else {
1097
+ warnings.push(`Object '${obj}' is not in the profiled set and will be skipped.`);
1098
+ }
1099
+ }
1100
+ if (intersected.length === 0) {
1101
+ return createFailureResult([], CreateErrorCodes.NO_PROFILED_OBJECTS, 'None of the specified objects have been profiled. Run profiling with --method metadata first.');
1102
+ }
1103
+ profiledNames = intersected;
1104
+ }
1105
+ options.onProgress?.(`Resolving ${profiledNames.length} profiled objects...`);
1106
+ const resolveResult = await this.filteringService.getObjectsByName(profiledNames);
1107
+ if (!resolveResult.success) {
1108
+ return createFailureResult([], CreateErrorCodes.FILTER_FAILED, resolveResult.message);
1109
+ }
1110
+ if (resolveResult.warnings && resolveResult.warnings.length > 0) {
1111
+ warnings.push(...resolveResult.warnings);
1112
+ }
1113
+ if (resolveResult.data.length === 0) {
1114
+ return createFailureResult([], CreateErrorCodes.OBJECTS_NOT_FOUND, 'None of the profiled objects exist in the org');
1115
+ }
1116
+ let filtered = resolveResult.data;
1117
+ if (options.filter && options.filter !== 'all') {
1118
+ filtered = filtered.filter((obj) => (options.filter === 'custom' ? obj.isCustom : !obj.isCustom));
1119
+ }
1120
+ filtered = DefinitionCreateOperation.applyNamespaceFilter(filtered, options.namespace);
1121
+ if (options.pattern) {
1122
+ const pattern = options.pattern;
1123
+ if (pattern.includes('*')) {
1124
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
1125
+ filtered = filtered.filter((obj) => regex.test(obj.name));
1126
+ }
1127
+ else {
1128
+ const lower = pattern.toLowerCase();
1129
+ filtered = filtered.filter((obj) => obj.name.toLowerCase().includes(lower));
1130
+ }
1131
+ }
1132
+ if (filtered.length === 0) {
1133
+ return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, 'No profiled objects match the specified filters');
1134
+ }
1135
+ this.logger?.log(`Resolved ${filtered.length} profiled objects after filtering`);
1136
+ return createSuccessResult(filtered);
1137
+ }
1138
+ /**
1139
+ * Resolves objects by explicit API names.
1140
+ */
1141
+ async resolveExplicitObjects(objectNames, warnings, onProgress) {
1142
+ onProgress?.('Resolving specified objects...');
1143
+ this.logger?.log(`Resolving ${objectNames.length} explicitly specified objects`);
1144
+ const resolveResult = await this.filteringService.getObjectsByName(objectNames);
1145
+ if (!resolveResult.success) {
1146
+ this.logger?.log(`Object resolution failed: ${resolveResult.message}`);
1147
+ return createFailureResult([], CreateErrorCodes.FILTER_FAILED, resolveResult.message);
1148
+ }
1149
+ if (resolveResult.warnings && resolveResult.warnings.length > 0) {
1150
+ // Surface "not found" warnings immediately via progress callback
1151
+ for (const w of resolveResult.warnings) {
1152
+ onProgress?.(w);
1153
+ }
1154
+ warnings.push(...resolveResult.warnings);
1155
+ }
1156
+ if (resolveResult.data.length === 0) {
1157
+ const notFoundNames = objectNames.join(', ');
1158
+ this.logger?.log(`None of the specified objects exist in the org: ${notFoundNames}`);
1159
+ return createFailureResult([], CreateErrorCodes.OBJECTS_NOT_FOUND, `None of the specified objects exist in the org: ${notFoundNames}`);
1160
+ }
1161
+ this.logger?.log(`Resolved ${resolveResult.data.length} of ${objectNames.length} specified objects`);
1162
+ return createSuccessResult(resolveResult.data);
1163
+ }
1164
+ /**
1165
+ * Resolves objects by filtering criteria.
1166
+ */
1167
+ async resolveFilteredObjects(options) {
1168
+ options.onProgress?.('Filtering objects...');
1169
+ const filterOptions = {
1170
+ type: options.filter,
1171
+ namespace: options.namespace,
1172
+ classification: options.classification,
1173
+ withRecords: options.minRecords && options.minRecords > 0 ? true : options.withRecords,
1174
+ withoutRecords: options.withoutRecords,
1175
+ hasRecordTypes: options.withRecordTypes,
1176
+ // CLI-3085: __mdt and other non-layoutable system objects (history/share/feed/big/platform-event)
1177
+ // are never valid profiling targets — opt in to the in-memory layoutable + keyPrefix predicate
1178
+ // unconditionally so the create flow stays tight regardless of classification path behavior.
1179
+ excludeSystemObjects: true,
1180
+ };
1181
+ if (options.pattern) {
1182
+ filterOptions.nameFilter = {
1183
+ value: options.pattern,
1184
+ operator: options.pattern.includes('*') ? 'wildcard' : 'contains',
1185
+ };
1186
+ }
1187
+ const filterResult = await this.filteringService.filter(filterOptions);
1188
+ if (!filterResult.success) {
1189
+ this.logger?.log(`Object filtering failed: ${filterResult.message}`);
1190
+ return createFailureResult([], CreateErrorCodes.FILTER_FAILED, filterResult.message);
1191
+ }
1192
+ if (filterResult.data.length === 0) {
1193
+ this.logger?.log('No objects found matching the specified filters');
1194
+ return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, 'No objects found matching the specified filters');
1195
+ }
1196
+ this.logger?.log(`Found ${filterResult.data.length} objects matching filters`);
1197
+ // CLI-4214: carry forward the filtering chain's reconciliation truncation disclosure so the
1198
+ // operation can surface it in its result warnings instead of silently dropping it.
1199
+ return createSuccessResult(filterResult.data, {
1200
+ warnings: filterResult.warnings && filterResult.warnings.length > 0 ? filterResult.warnings : undefined,
1201
+ });
1202
+ }
1203
+ /**
1204
+ * Filters objects by minimum record count threshold.
1205
+ */
1206
+ applyMinRecordsFilter(objects, minRecords) {
1207
+ const filtered = objects.filter((obj) => (obj.recordCount ?? 0) >= minRecords);
1208
+ this.logger?.log(`After min-records filter (>=${minRecords}): ${filtered.length} of ${objects.length} objects remain`);
1209
+ return filtered;
1210
+ }
1211
+ /**
1212
+ * Applies a safety cap to the number of definition inputs to process.
1213
+ */
1214
+ applyInputLimit(inputs, limit) {
1215
+ if (!limit || limit <= 0 || inputs.length <= limit) {
1216
+ return { limited: inputs };
1217
+ }
1218
+ this.logger?.log(`Applied limit: ${limit} of ${inputs.length} definitions`);
1219
+ return {
1220
+ limited: inputs.slice(0, limit),
1221
+ warning: `Results limited to ${limit} definitions (${inputs.length} matched). Use --limit to increase.`,
1222
+ };
1223
+ }
1224
+ /**
1225
+ * Applies a safety cap to the number of SObjects sent to the ISV REST API.
1226
+ * Mirrors applyInputLimit for the REST path where objects are capped before the ISV call.
1227
+ */
1228
+ applyObjectLimit(objects, limit) {
1229
+ if (!limit || limit <= 0 || objects.length <= limit) {
1230
+ return { limited: objects };
1231
+ }
1232
+ this.logger?.log(`Applied object limit: ${limit} of ${objects.length} objects`);
1233
+ return {
1234
+ limited: objects.slice(0, limit),
1235
+ warning: `Results limited to ${limit} definitions (${objects.length} matched). Use --limit to increase.`,
1236
+ };
1237
+ }
1238
+ /**
1239
+ * Fetches all existing profiling definitions using pagination.
1240
+ */
1241
+ async fetchAllExistingDefinitions() {
1242
+ const allDefinitions = [];
1243
+ let offset = 0;
1244
+ const pageSize = MAX_PAGINATION_LIMIT;
1245
+ // eslint-disable-next-line no-constant-condition -- Pagination loop exits on short page or failure
1246
+ while (true) {
1247
+ // eslint-disable-next-line no-await-in-loop -- Sequential pagination: each page depends on knowing if more exist
1248
+ const pageResult = await this.definitionService.getDefinitions({ limit: pageSize, offset });
1249
+ if (!pageResult.success) {
1250
+ if (allDefinitions.length > 0) {
1251
+ this.logger?.log(`Pagination failed at offset ${offset}, using ${allDefinitions.length} definitions fetched so far`);
1252
+ return createSuccessResult(allDefinitions, {
1253
+ warnings: [`Pagination incomplete: failed at offset ${offset}. Deduplication may be partial.`],
1254
+ });
1255
+ }
1256
+ return pageResult;
1257
+ }
1258
+ allDefinitions.push(...pageResult.data);
1259
+ if (pageResult.data.length < pageSize) {
1260
+ break;
1261
+ }
1262
+ offset += pageSize;
1263
+ }
1264
+ this.logger?.log(`Fetched ${allDefinitions.length} total existing definitions across pagination`);
1265
+ return createSuccessResult(allDefinitions, {
1266
+ message: `Found ${allDefinitions.length} existing definitions`,
1267
+ });
1268
+ }
1269
+ }
1270
+ //# sourceMappingURL=DefinitionCreateOperation.js.map