@hubspot/cli 7.7.35-experimental.0 → 7.8.0-beta.1

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 (320) hide show
  1. package/bin/cli.js +31 -25
  2. package/commands/__tests__/auth.test.js +5 -0
  3. package/commands/__tests__/doctor.test.js +16 -16
  4. package/commands/__tests__/getStarted.test.js +2 -2
  5. package/commands/__tests__/mcp.test.js +1 -1
  6. package/commands/__tests__/project.test.js +2 -3
  7. package/commands/account/auth.js +1 -0
  8. package/commands/account/clean.js +18 -27
  9. package/commands/account/createOverride.js +13 -31
  10. package/commands/account/info.js +20 -31
  11. package/commands/account/list.js +16 -22
  12. package/commands/account/remove.js +12 -20
  13. package/commands/account/removeOverride.js +11 -21
  14. package/commands/account/rename.js +6 -9
  15. package/commands/account/use.js +12 -26
  16. package/commands/account.js +2 -2
  17. package/commands/app/__tests__/migrate.test.js +5 -6
  18. package/commands/app/migrate.js +13 -19
  19. package/commands/app/secret/add.js +2 -1
  20. package/commands/app/secret/delete.js +2 -1
  21. package/commands/app/secret/list.js +2 -1
  22. package/commands/app/secret/update.js +2 -1
  23. package/commands/app/secret.js +2 -1
  24. package/commands/app.js +2 -2
  25. package/commands/auth.d.ts +1 -0
  26. package/commands/auth.js +17 -7
  27. package/commands/cms/convertFields.js +7 -9
  28. package/commands/cms/getReactModule.js +9 -14
  29. package/commands/cms/lighthouseScore.js +33 -36
  30. package/commands/cms.js +2 -2
  31. package/commands/completion.js +3 -3
  32. package/commands/config/set.d.ts +1 -1
  33. package/commands/config/set.js +64 -37
  34. package/commands/config.js +2 -2
  35. package/commands/create.js +2 -2
  36. package/commands/customObject/create.js +10 -12
  37. package/commands/customObject/schema/create.js +9 -11
  38. package/commands/customObject/schema/delete.js +16 -16
  39. package/commands/customObject/schema/fetch-all.js +12 -11
  40. package/commands/customObject/schema/fetch.js +15 -15
  41. package/commands/customObject/schema/list.js +4 -4
  42. package/commands/customObject/schema/update.js +13 -13
  43. package/commands/customObject/schema.js +2 -2
  44. package/commands/customObject.js +6 -7
  45. package/commands/doctor.js +8 -11
  46. package/commands/feedback.js +8 -13
  47. package/commands/fetch.js +8 -8
  48. package/commands/filemanager/fetch.js +7 -7
  49. package/commands/filemanager/upload.js +15 -34
  50. package/commands/filemanager.js +2 -2
  51. package/commands/function/deploy.js +11 -29
  52. package/commands/function/list.js +8 -8
  53. package/commands/function/server.js +9 -11
  54. package/commands/function.d.ts +1 -1
  55. package/commands/function.js +2 -2
  56. package/commands/getStarted.d.ts +0 -2
  57. package/commands/getStarted.js +4 -4
  58. package/commands/hubdb/clear.js +7 -15
  59. package/commands/hubdb/create.js +9 -15
  60. package/commands/hubdb/delete.js +8 -15
  61. package/commands/hubdb/fetch.js +6 -9
  62. package/commands/hubdb.d.ts +1 -1
  63. package/commands/hubdb.js +2 -2
  64. package/commands/init.js +2 -3
  65. package/commands/lint.js +16 -16
  66. package/commands/list.js +8 -14
  67. package/commands/logs.js +14 -20
  68. package/commands/mcp/__tests__/setup.test.js +2 -2
  69. package/commands/mcp/setup.js +11 -2
  70. package/commands/mcp.js +3 -3
  71. package/commands/mv.js +6 -17
  72. package/commands/open.js +5 -5
  73. package/commands/project/__tests__/add.test.js +15 -13
  74. package/commands/project/__tests__/create.test.js +6 -6
  75. package/commands/project/__tests__/deploy.test.js +3 -7
  76. package/commands/project/__tests__/devUnifiedFlow.test.js +2 -4
  77. package/commands/project/__tests__/installDeps.test.js +8 -8
  78. package/commands/project/__tests__/list.test.js +31 -0
  79. package/commands/project/__tests__/logs.test.js +1 -4
  80. package/commands/project/__tests__/migrate.test.js +7 -7
  81. package/commands/project/__tests__/migrateApp.test.js +3 -7
  82. package/commands/project/__tests__/profile.test.js +1 -1
  83. package/commands/project/__tests__/validate.test.js +98 -0
  84. package/commands/project/add.d.ts +2 -2
  85. package/commands/project/add.js +7 -10
  86. package/commands/project/cloneApp.js +14 -19
  87. package/commands/project/create.js +3 -10
  88. package/commands/project/deploy.js +5 -5
  89. package/commands/project/dev/deprecatedFlow.js +9 -18
  90. package/commands/project/dev/index.js +21 -18
  91. package/commands/project/dev/unifiedFlow.js +14 -7
  92. package/commands/project/download.js +15 -16
  93. package/commands/project/installDeps.d.ts +2 -2
  94. package/commands/project/installDeps.js +9 -9
  95. package/commands/project/list.d.ts +4 -0
  96. package/commands/project/list.js +62 -0
  97. package/commands/project/listBuilds.js +12 -21
  98. package/commands/project/logs.js +21 -24
  99. package/commands/project/migrate.js +46 -15
  100. package/commands/project/migrateApp.js +10 -17
  101. package/commands/project/open.js +6 -14
  102. package/commands/project/profile/add.js +3 -3
  103. package/commands/project/profile/delete.js +1 -2
  104. package/commands/project/profile.js +2 -3
  105. package/commands/project/upload.js +16 -25
  106. package/commands/project/validate.js +7 -7
  107. package/commands/project/watch.js +13 -22
  108. package/commands/project.js +4 -3
  109. package/commands/sandbox/__tests__/create.test.js +5 -5
  110. package/commands/sandbox/create.js +22 -32
  111. package/commands/sandbox/delete.js +39 -64
  112. package/commands/sandbox.js +2 -2
  113. package/commands/secret/addSecret.js +7 -17
  114. package/commands/secret/deleteSecret.js +10 -20
  115. package/commands/secret/listSecret.js +8 -10
  116. package/commands/secret/updateSecret.js +9 -17
  117. package/commands/secret.js +2 -2
  118. package/commands/testAccount/__tests__/delete.test.js +2 -4
  119. package/commands/testAccount/create.js +2 -2
  120. package/commands/testAccount/delete.d.ts +4 -3
  121. package/commands/testAccount/delete.js +155 -14
  122. package/commands/testAccount/importData.d.ts +1 -1
  123. package/commands/testAccount/importData.js +1 -1
  124. package/commands/testAccount.js +1 -1
  125. package/commands/theme/preview.js +1 -4
  126. package/lang/en.d.ts +364 -110
  127. package/lang/en.js +409 -158
  128. package/lang/en.lyaml +4 -4
  129. package/lib/__tests__/buildAccount.test.js +4 -3
  130. package/lib/__tests__/commonOpts.test.js +1 -1
  131. package/lib/__tests__/dependencyManagement.test.js +1 -1
  132. package/lib/__tests__/developerTestAccounts.test.js +3 -3
  133. package/lib/__tests__/npm.test.js +1 -1
  134. package/lib/__tests__/oauth.test.js +4 -4
  135. package/lib/__tests__/process.test.js +10 -5
  136. package/lib/__tests__/sandboxSync.test.js +8 -8
  137. package/lib/__tests__/sandboxes.test.js +8 -8
  138. package/lib/__tests__/serverlessLogs.test.js +1 -1
  139. package/lib/__tests__/usageTracking.test.js +5 -5
  140. package/lib/__tests__/validation.test.js +2 -1
  141. package/lib/__tests__/yargsUtils.test.js +83 -9
  142. package/lib/app/__tests__/migrate.test.js +19 -56
  143. package/lib/app/__tests__/migrate_legacy.test.js +1 -1
  144. package/lib/app/migrate.d.ts +2 -8
  145. package/lib/app/migrate.js +6 -81
  146. package/lib/app/migrate_legacy.js +20 -24
  147. package/lib/buildAccount.d.ts +2 -2
  148. package/lib/buildAccount.js +32 -64
  149. package/lib/commonOpts.d.ts +1 -1
  150. package/lib/commonOpts.js +25 -22
  151. package/lib/configMigrate.js +88 -9
  152. package/lib/configOptions.js +7 -0
  153. package/lib/constants.d.ts +21 -1
  154. package/lib/constants.js +25 -1
  155. package/lib/dependencyManagement.js +9 -27
  156. package/lib/developerTestAccounts.js +9 -23
  157. package/lib/doctor/Diagnosis.js +11 -23
  158. package/lib/doctor/DiagnosticInfoBuilder.js +12 -11
  159. package/lib/doctor/Doctor.js +42 -90
  160. package/lib/doctor/__tests__/Doctor.test.js +4 -4
  161. package/lib/errorHandlers/index.js +12 -20
  162. package/lib/errorHandlers/suppressError.js +11 -18
  163. package/lib/lang.js +6 -5
  164. package/lib/links.d.ts +1 -0
  165. package/lib/links.js +14 -7
  166. package/lib/mcp/setup.js +1 -1
  167. package/lib/middleware/__test__/commandTargetingUtils.test.js +99 -0
  168. package/lib/middleware/__test__/configMiddleware.test.js +11 -11
  169. package/lib/middleware/__test__/yargsChecksMiddleware.test.js +6 -8
  170. package/lib/middleware/commandTargetingUtils.d.ts +8 -0
  171. package/lib/middleware/commandTargetingUtils.js +74 -0
  172. package/lib/middleware/configMiddleware.d.ts +1 -1
  173. package/lib/middleware/configMiddleware.js +21 -81
  174. package/lib/middleware/fireAlarmMiddleware.js +15 -5
  175. package/lib/middleware/gitMiddleware.js +5 -1
  176. package/lib/middleware/notificationsMiddleware.js +5 -11
  177. package/lib/middleware/yargsChecksMiddleware.js +6 -9
  178. package/lib/npm.js +2 -2
  179. package/lib/oauth.js +5 -5
  180. package/lib/process.js +5 -4
  181. package/lib/projects/__tests__/AppDevModeInterface.test.js +87 -90
  182. package/lib/projects/__tests__/LocalDevProcess.test.js +231 -19
  183. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +89 -63
  184. package/lib/projects/__tests__/deploy.test.js +73 -8
  185. package/lib/projects/__tests__/localDevProjectHelpers.test.js +6 -2
  186. package/lib/projects/__tests__/platformVersion.test.js +8 -8
  187. package/lib/projects/__tests__/projects.test.js +12 -12
  188. package/lib/projects/__tests__/structure.test.js +3 -3
  189. package/lib/projects/__tests__/upload.test.d.ts +1 -0
  190. package/lib/projects/__tests__/upload.test.js +82 -0
  191. package/lib/projects/add/__tests__/legacyAddComponent.test.js +6 -6
  192. package/lib/projects/add/__tests__/v2AddComponent.test.d.ts +1 -0
  193. package/lib/projects/add/__tests__/{v3AddComponent.test.js → v2AddComponent.test.js} +39 -39
  194. package/lib/projects/add/{v3AddComponent.d.ts → v2AddComponent.d.ts} +1 -1
  195. package/lib/projects/add/{v3AddComponent.js → v2AddComponent.js} +5 -5
  196. package/lib/projects/create/__tests__/legacy.test.js +5 -5
  197. package/lib/projects/create/__tests__/v2.test.d.ts +1 -0
  198. package/lib/projects/create/__tests__/{v3.test.js → v2.test.js} +82 -7
  199. package/lib/projects/create/index.js +4 -4
  200. package/lib/projects/create/legacy.js +2 -2
  201. package/lib/projects/create/{v3.d.ts → v2.d.ts} +3 -3
  202. package/lib/projects/create/{v3.js → v2.js} +13 -11
  203. package/lib/projects/deploy.d.ts +1 -1
  204. package/lib/projects/deploy.js +2 -2
  205. package/lib/projects/localDev/AppDevModeInterface.d.ts +10 -1
  206. package/lib/projects/localDev/AppDevModeInterface.js +118 -89
  207. package/lib/projects/localDev/DevServerManager.d.ts +11 -29
  208. package/lib/projects/localDev/DevServerManager.js +19 -61
  209. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +40 -0
  210. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +120 -0
  211. package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
  212. package/lib/projects/localDev/LocalDevLogger.js +27 -6
  213. package/lib/projects/localDev/{LocalDevManager.js → LocalDevManager_DEPRECATED.js} +10 -11
  214. package/lib/projects/localDev/LocalDevProcess.d.ts +7 -5
  215. package/lib/projects/localDev/LocalDevProcess.js +93 -21
  216. package/lib/projects/localDev/LocalDevState.d.ts +12 -8
  217. package/lib/projects/localDev/LocalDevState.js +27 -17
  218. package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +6 -1
  219. package/lib/projects/localDev/LocalDevWebsocketServer.js +94 -33
  220. package/lib/projects/localDev/helpers/account.d.ts +1 -1
  221. package/lib/projects/localDev/helpers/account.js +2 -2
  222. package/lib/projects/localDev/helpers/project.d.ts +1 -0
  223. package/lib/projects/localDev/helpers/project.js +44 -4
  224. package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +7 -0
  225. package/lib/projects/localDev/localDevWebsocketServerUtils.js +19 -0
  226. package/lib/projects/platformVersion.d.ts +1 -1
  227. package/lib/projects/platformVersion.js +1 -1
  228. package/lib/projects/pollProjectBuildAndDeploy.js +4 -4
  229. package/lib/projects/structure.js +6 -6
  230. package/lib/projects/upload.d.ts +1 -1
  231. package/lib/projects/upload.js +17 -8
  232. package/lib/projects/urls.d.ts +0 -1
  233. package/lib/projects/urls.js +0 -3
  234. package/lib/prompts/__tests__/downloadProjectPrompt.test.js +1 -0
  235. package/lib/prompts/__tests__/projectAddPrompt.test.js +10 -10
  236. package/lib/prompts/accountNamePrompt.js +14 -19
  237. package/lib/prompts/accountsPrompt.js +2 -2
  238. package/lib/prompts/cmsFieldPrompt.js +2 -2
  239. package/lib/prompts/createApiSamplePrompt.js +5 -5
  240. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +10 -1
  241. package/lib/prompts/createFunctionPrompt.js +14 -14
  242. package/lib/prompts/createModulePrompt.js +9 -9
  243. package/lib/prompts/createTemplatePrompt.js +2 -2
  244. package/lib/prompts/downloadProjectPrompt.js +5 -8
  245. package/lib/prompts/installAppPrompt.d.ts +1 -6
  246. package/lib/prompts/installAppPrompt.js +1 -6
  247. package/lib/prompts/personalAccessKeyPrompt.js +3 -3
  248. package/lib/prompts/previewPrompt.js +6 -6
  249. package/lib/prompts/projectAddPrompt.d.ts +2 -2
  250. package/lib/prompts/projectAddPrompt.js +9 -2
  251. package/lib/prompts/projectDevTargetAccountPrompt.js +20 -32
  252. package/lib/prompts/projectNamePrompt.js +4 -8
  253. package/lib/prompts/projectsLogsPrompt.js +2 -4
  254. package/lib/prompts/promptUtils.js +30 -9
  255. package/lib/prompts/sandboxesPrompt.js +7 -7
  256. package/lib/prompts/secretPrompt.js +3 -3
  257. package/lib/prompts/selectAppPrompt.js +3 -3
  258. package/lib/prompts/selectHubDBTablePrompt.js +9 -13
  259. package/lib/prompts/selectProjectTemplatePrompt.js +2 -0
  260. package/lib/prompts/selectPublicAppForMigrationPrompt.js +15 -19
  261. package/lib/prompts/setAsDefaultAccountPrompt.js +4 -8
  262. package/lib/prompts/uploadPrompt.js +5 -5
  263. package/lib/sandboxSync.js +24 -41
  264. package/lib/sandboxes.js +19 -47
  265. package/lib/schema.js +3 -3
  266. package/lib/serverlessLogs.js +11 -13
  267. package/lib/theme/__tests__/migrate.test.d.ts +1 -0
  268. package/lib/theme/__tests__/migrate.test.js +233 -0
  269. package/lib/theme/migrate.d.ts +13 -0
  270. package/lib/theme/migrate.js +90 -0
  271. package/lib/ui/SpinniesManager.d.ts +2 -0
  272. package/lib/ui/SpinniesManager.js +7 -0
  273. package/lib/ui/boxen.js +1 -2
  274. package/lib/ui/git.js +13 -10
  275. package/lib/ui/index.d.ts +4 -0
  276. package/lib/ui/index.js +47 -38
  277. package/lib/ui/serverlessFunctionLogs.js +9 -7
  278. package/lib/ui/uiMessages.d.ts +72 -0
  279. package/lib/ui/uiMessages.js +75 -0
  280. package/lib/usageTracking.js +8 -8
  281. package/lib/validation.js +20 -23
  282. package/lib/yargsUtils.d.ts +1 -1
  283. package/lib/yargsUtils.js +12 -5
  284. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
  285. package/mcp-server/tools/index.js +4 -0
  286. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +2 -2
  287. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  288. package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
  289. package/mcp-server/tools/project/DocsSearchTool.js +5 -5
  290. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +23 -0
  291. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +68 -0
  292. package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +11 -0
  293. package/mcp-server/tools/project/GetApplicationInfoTool.js +49 -0
  294. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
  295. package/mcp-server/tools/project/GetConfigValuesTool.js +12 -6
  296. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +2 -2
  297. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
  298. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +12 -10
  299. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.d.ts +1 -0
  300. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +169 -0
  301. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.d.ts +1 -0
  302. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +115 -0
  303. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -7
  304. package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
  305. package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
  306. package/mcp-server/utils/cliConfig.d.ts +1 -0
  307. package/mcp-server/utils/cliConfig.js +12 -0
  308. package/mcp-server/utils/toolUsageTracking.js +2 -2
  309. package/package.json +8 -7
  310. package/types/LocalDev.d.ts +19 -3
  311. package/ui/index.js +1 -1
  312. package/lib/middleware/__test__/utils.test.js +0 -51
  313. package/lib/middleware/utils.d.ts +0 -8
  314. package/lib/middleware/utils.js +0 -14
  315. package/lib/projects/localDev/DevServerManagerV2.d.ts +0 -22
  316. package/lib/projects/localDev/DevServerManagerV2.js +0 -81
  317. /package/{lib/middleware/__test__/utils.test.d.ts → commands/project/__tests__/list.test.d.ts} +0 -0
  318. /package/{lib/projects/add/__tests__/v3AddComponent.test.d.ts → commands/project/__tests__/validate.test.d.ts} +0 -0
  319. /package/lib/{projects/create/__tests__/v3.test.d.ts → middleware/__test__/commandTargetingUtils.test.d.ts} +0 -0
  320. /package/lib/projects/localDev/{LocalDevManager.d.ts → LocalDevManager_DEPRECATED.d.ts} +0 -0
@@ -2,7 +2,7 @@ import { legacyAddComponent } from '../legacyAddComponent.js';
2
2
  import { findProjectComponents } from '../../structure.js';
3
3
  import { getProjectComponentListFromRepo } from '../../create/legacy.js';
4
4
  import { projectAddPrompt } from '../../../prompts/projectAddPrompt.js';
5
- import { logger } from '@hubspot/local-dev-lib/logger';
5
+ import { uiLogger } from '../../../ui/logger.js';
6
6
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
7
7
  import { trackCommandUsage } from '../../../usageTracking.js';
8
8
  import { ComponentTypes, } from '../../../../types/Projects.js';
@@ -10,13 +10,13 @@ import { commands } from '../../../../lang/en.js';
10
10
  vi.mock('../../structure');
11
11
  vi.mock('../../create/legacy');
12
12
  vi.mock('../../../prompts/projectAddPrompt');
13
- vi.mock('@hubspot/local-dev-lib/logger');
13
+ vi.mock('../../../ui/logger.js');
14
14
  vi.mock('@hubspot/local-dev-lib/github');
15
15
  vi.mock('../../../usageTracking.js');
16
16
  const mockedFindProjectComponents = vi.mocked(findProjectComponents);
17
17
  const mockedGetProjectComponentListFromRepo = vi.mocked(getProjectComponentListFromRepo);
18
18
  const mockedProjectAddPrompt = vi.mocked(projectAddPrompt);
19
- const mockedLogger = vi.mocked(logger);
19
+ const mockedUiLogger = vi.mocked(uiLogger);
20
20
  const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
21
21
  const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
22
22
  describe('lib/projects/add/legacyAddComponent', () => {
@@ -75,8 +75,8 @@ describe('lib/projects/add/legacyAddComponent', () => {
75
75
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
76
76
  type: 'module',
77
77
  }, accountId);
78
- expect(mockedLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
79
- expect(mockedLogger.success).toHaveBeenCalledWith(commands.project.add.success('new-component'));
78
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
79
+ expect(mockedUiLogger.success).toHaveBeenCalledWith(commands.project.add.success('new-component'));
80
80
  });
81
81
  it('throws an error when project contains a public app', async () => {
82
82
  const mockComponents = [
@@ -206,7 +206,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
206
206
  mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
207
207
  await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
208
208
  expect(mockedCloneGithubRepo).toHaveBeenCalled();
209
- expect(mockedLogger.success).not.toHaveBeenCalled();
209
+ expect(mockedUiLogger.success).not.toHaveBeenCalled();
210
210
  });
211
211
  it('calls trackCommandUsage with correct component type', async () => {
212
212
  const mockComponents = [
@@ -1,37 +1,37 @@
1
1
  import fs from 'fs';
2
- import { v3AddComponent } from '../v3AddComponent.js';
2
+ import { v2AddComponent } from '../v2AddComponent.js';
3
3
  import { getConfigForPlatformVersion } from '../../create/legacy.js';
4
- import { createV3App } from '../../create/v3.js';
4
+ import { createV2App } from '../../create/v2.js';
5
5
  import { confirmPrompt } from '../../../prompts/promptUtils.js';
6
- import { projectAddPromptV3 } from '../../../prompts/projectAddPrompt.js';
6
+ import { projectAddPromptV2 } from '../../../prompts/projectAddPrompt.js';
7
7
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
8
- import { logger } from '@hubspot/local-dev-lib/logger';
8
+ import { uiLogger } from '../../../ui/logger.js';
9
9
  import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
10
10
  import { trackCommandUsage } from '../../../usageTracking.js';
11
11
  import { commands } from '../../../../lang/en.js';
12
12
  vi.mock('fs');
13
13
  vi.mock('../../../prompts/promptUtils');
14
14
  vi.mock('../../create/legacy');
15
- vi.mock('../../create/v3');
15
+ vi.mock('../../create/v2');
16
16
  vi.mock('../../../prompts/projectAddPrompt');
17
17
  vi.mock('@hubspot/local-dev-lib/github');
18
- vi.mock('@hubspot/local-dev-lib/logger');
18
+ vi.mock('../../../ui/logger.js');
19
19
  vi.mock('@hubspot/project-parsing-lib/src/lib/project');
20
20
  vi.mock('../../../usageTracking');
21
21
  const mockedFs = vi.mocked(fs);
22
22
  const mockedGetConfigForPlatformVersion = vi.mocked(getConfigForPlatformVersion);
23
23
  const mockedConfirmPrompt = vi.mocked(confirmPrompt);
24
- const mockedCreateV3App = vi.mocked(createV3App);
25
- const mockedProjectAddPromptV3 = vi.mocked(projectAddPromptV3);
24
+ const mockedCreateV2App = vi.mocked(createV2App);
25
+ const mockedProjectAddPromptV2 = vi.mocked(projectAddPromptV2);
26
26
  const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
27
- const mockedLogger = vi.mocked(logger);
27
+ const mockedUiLogger = vi.mocked(uiLogger);
28
28
  const mockedGetProjectMetadata = vi.mocked(getProjectMetadata);
29
29
  const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
30
- describe('lib/projects/add/v3AddComponent', () => {
30
+ describe('lib/projects/add/v2AddComponent', () => {
31
31
  const mockProjectConfig = {
32
32
  name: 'test-project',
33
33
  srcDir: 'src',
34
- platformVersion: 'v3',
34
+ platformVersion: '2025.2',
35
35
  };
36
36
  const mockArgs = {
37
37
  name: 'test-component',
@@ -66,13 +66,13 @@ describe('lib/projects/add/v3AddComponent', () => {
66
66
  },
67
67
  };
68
68
  beforeEach(() => {
69
- mockedCreateV3App.mockResolvedValue({
69
+ mockedCreateV2App.mockResolvedValue({
70
70
  authType: 'oauth',
71
71
  distribution: 'private',
72
72
  });
73
73
  mockedTrackCommandUsage.mockResolvedValue();
74
74
  });
75
- describe('v3AddComponent()', () => {
75
+ describe('v2AddComponent()', () => {
76
76
  it('successfully adds a component when app already exists', async () => {
77
77
  const mockAppMeta = {
78
78
  config: {
@@ -86,21 +86,21 @@ describe('lib/projects/add/v3AddComponent', () => {
86
86
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
87
87
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
88
88
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
89
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
89
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
90
90
  mockedCloneGithubRepo.mockResolvedValue(true);
91
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
92
- expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('v3');
91
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
92
+ expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('2025.2');
93
93
  expect(mockedGetProjectMetadata).toHaveBeenCalledWith('/path/to/project/src');
94
- expect(mockedProjectAddPromptV3).toHaveBeenCalled();
94
+ expect(mockedProjectAddPromptV2).toHaveBeenCalled();
95
95
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
96
96
  type: 'module',
97
97
  }, mockAccountId);
98
98
  expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
99
- sourceDir: ['v3/test-component'],
99
+ sourceDir: ['2025.2/test-component'],
100
100
  hideLogs: true,
101
101
  branch: 'main',
102
102
  }));
103
- expect(mockedLogger.success).toHaveBeenCalled();
103
+ expect(mockedUiLogger.success).toHaveBeenCalled();
104
104
  });
105
105
  it('creates an app when no app exists and user confirms', async () => {
106
106
  const mockProjectMetadataNoApps = {
@@ -116,15 +116,15 @@ describe('lib/projects/add/v3AddComponent', () => {
116
116
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
117
117
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
118
118
  mockedConfirmPrompt.mockResolvedValue(true);
119
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
119
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
120
120
  mockedCloneGithubRepo.mockResolvedValue(true);
121
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
122
- expect(mockedCreateV3App).toHaveBeenCalled();
121
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
122
+ expect(mockedCreateV2App).toHaveBeenCalled();
123
123
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
124
124
  type: 'module',
125
125
  }, mockAccountId);
126
126
  expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
127
- sourceDir: ['v3/test-component', 'v3/app-template'],
127
+ sourceDir: ['2025.2/test-component', '2025.2/app-template'],
128
128
  }));
129
129
  });
130
130
  it('should not call clone', async () => {
@@ -145,10 +145,10 @@ describe('lib/projects/add/v3AddComponent', () => {
145
145
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
146
146
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
147
147
  mockedConfirmPrompt.mockResolvedValue(true);
148
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
148
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
149
149
  mockedCloneGithubRepo.mockResolvedValue(true);
150
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
151
- expect(mockedCreateV3App).not.toHaveBeenCalled();
150
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
151
+ expect(mockedCreateV2App).not.toHaveBeenCalled();
152
152
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
153
153
  type: '',
154
154
  }, mockAccountId);
@@ -164,7 +164,7 @@ describe('lib/projects/add/v3AddComponent', () => {
164
164
  };
165
165
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
166
166
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataMaxApps);
167
- await expect(v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('This project currently has the maximum number of apps: 1');
167
+ await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('This project currently has the maximum number of apps: 1');
168
168
  });
169
169
  it('throws an error when components list is empty', async () => {
170
170
  const mockEmptyConfig = {
@@ -172,7 +172,7 @@ describe('lib/projects/add/v3AddComponent', () => {
172
172
  parentComponents: [],
173
173
  };
174
174
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockEmptyConfig);
175
- await expect(v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
175
+ await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
176
176
  });
177
177
  it('throws an error when app meta file cannot be parsed', async () => {
178
178
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
@@ -180,7 +180,7 @@ describe('lib/projects/add/v3AddComponent', () => {
180
180
  mockedFs.readFileSync.mockImplementation(() => {
181
181
  throw new Error('File read error');
182
182
  });
183
- await expect(v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('Unable to parse app file');
183
+ await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('Unable to parse app file');
184
184
  });
185
185
  it('throws an error when cloning fails', async () => {
186
186
  const mockAppMeta = {
@@ -195,9 +195,9 @@ describe('lib/projects/add/v3AddComponent', () => {
195
195
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
196
196
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
197
197
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
198
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
198
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
199
199
  mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
200
- await expect(v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
200
+ await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
201
201
  });
202
202
  it('should track usage with multiple component types', async () => {
203
203
  const mockAppMeta = {
@@ -219,9 +219,9 @@ describe('lib/projects/add/v3AddComponent', () => {
219
219
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
220
220
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
221
221
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
222
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
222
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
223
223
  mockedCloneGithubRepo.mockResolvedValue(true);
224
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
224
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
225
225
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
226
226
  type: 'module,card',
227
227
  }, mockAccountId);
@@ -243,8 +243,8 @@ describe('lib/projects/add/v3AddComponent', () => {
243
243
  };
244
244
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
245
245
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
246
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
247
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
246
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
247
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
248
248
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
249
249
  type: '',
250
250
  }, mockAccountId);
@@ -270,9 +270,9 @@ describe('lib/projects/add/v3AddComponent', () => {
270
270
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
271
271
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
272
272
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
273
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
273
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
274
274
  mockedCloneGithubRepo.mockResolvedValue(true);
275
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
275
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
276
276
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
277
277
  type: 'workflow-action-tool',
278
278
  }, mockAccountId);
@@ -308,9 +308,9 @@ describe('lib/projects/add/v3AddComponent', () => {
308
308
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
309
309
  mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
310
310
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
311
- mockedProjectAddPromptV3.mockResolvedValue(mockPromptResponse);
311
+ mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
312
312
  mockedCloneGithubRepo.mockResolvedValue(true);
313
- await v3AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
313
+ await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
314
314
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
315
315
  type: 'workflow-action-tool,module',
316
316
  }, mockAccountId);
@@ -1,5 +1,5 @@
1
1
  import { ProjectConfig } from '../../../types/Projects.js';
2
- export declare function v3AddComponent(args: {
2
+ export declare function v2AddComponent(args: {
3
3
  name?: string;
4
4
  type?: string;
5
5
  features?: string[];
@@ -1,10 +1,10 @@
1
1
  import { commands, lib } from '../../../lang/en.js';
2
2
  import { getConfigForPlatformVersion } from '../create/legacy.js';
3
- import { calculateComponentTemplateChoices, createV3App, } from '../create/v3.js';
3
+ import { calculateComponentTemplateChoices, createV2App, } from '../create/v2.js';
4
4
  import { PROJECT_WITH_APP } from '../../constants.js';
5
5
  import path from 'path';
6
6
  import fs from 'fs';
7
- import { projectAddPromptV3 } from '../../prompts/projectAddPrompt.js';
7
+ import { projectAddPromptV2 } from '../../prompts/projectAddPrompt.js';
8
8
  import { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, DEFAULT_PROJECT_TEMPLATE_BRANCH, } from '../../constants.js';
9
9
  import { updateHsMetaFilesWithAutoGeneratedFields, handleComponentCollision, } from '../components.js';
10
10
  import { getProjectMetadata, } from '@hubspot/project-parsing-lib/src/lib/project.js';
@@ -13,7 +13,7 @@ import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
13
13
  import { debugError } from '../../errorHandlers/index.js';
14
14
  import { uiLogger } from '../../ui/logger.js';
15
15
  import { trackCommandUsage } from '../../usageTracking.js';
16
- export async function v3AddComponent(args, projectDir, projectConfig, accountId) {
16
+ export async function v2AddComponent(args, projectDir, projectConfig, accountId) {
17
17
  uiLogger.log(commands.project.add.creatingComponent(projectConfig.name));
18
18
  const config = await getConfigForPlatformVersion(projectConfig.platformVersion);
19
19
  const { components, parentComponents } = config;
@@ -27,7 +27,7 @@ export async function v3AddComponent(args, projectDir, projectConfig, accountId)
27
27
  const appsMetadata = currentProjectMetadata.components[AppKey];
28
28
  const shouldCreateApp = appsMetadata.count === 0;
29
29
  if (shouldCreateApp) {
30
- const { authType, distribution } = await createV3App(args.auth, args.distribution);
30
+ const { authType, distribution } = await createV2App(args.auth, args.distribution);
31
31
  derivedDistribution = distribution;
32
32
  derivedAuthType = authType;
33
33
  }
@@ -47,7 +47,7 @@ export async function v3AddComponent(args, projectDir, projectConfig, accountId)
47
47
  derivedAuthType = apps[0].config?.auth?.type;
48
48
  }
49
49
  const componentTemplateChoices = await calculateComponentTemplateChoices(components, derivedAuthType, derivedDistribution, args.derivedAccountId, currentProjectMetadata);
50
- const projectAddPromptResponse = await projectAddPromptV3(componentTemplateChoices, args.features);
50
+ const projectAddPromptResponse = await projectAddPromptV2(componentTemplateChoices, args.features);
51
51
  const componentTypes = projectAddPromptResponse.componentTemplate?.map(componentTemplate => componentTemplate.cliSelector || componentTemplate.type);
52
52
  await trackCommandUsage('project-add', {
53
53
  type: componentTypes?.join(','),
@@ -1,9 +1,9 @@
1
- import { logger } from '@hubspot/local-dev-lib/logger';
1
+ import { uiLogger } from '../../../ui/logger.js';
2
2
  import * as github from '@hubspot/local-dev-lib/api/github';
3
3
  import { EXIT_CODES } from '../../../enums/exitCodes.js';
4
4
  import { getProjectComponentListFromRepo, getProjectTemplateListFromRepo, } from '../legacy.js';
5
5
  import { PROJECT_COMPONENT_TYPES, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../../../constants.js';
6
- vi.mock('@hubspot/local-dev-lib/logger');
6
+ vi.mock('../../../ui/logger.js');
7
7
  vi.mock('@hubspot/local-dev-lib/api/github');
8
8
  const mockedFetchRepoFile = vi.mocked(github.fetchRepoFile);
9
9
  const repoConfig = {
@@ -60,14 +60,14 @@ describe('lib/projects/create/legacy', () => {
60
60
  it('Logs an error and exits the process if the request for the template list fails', async () => {
61
61
  mockedFetchRepoFile.mockRejectedValue(new Error('Not found'));
62
62
  await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
63
- expect(logger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to fetch the config.json file from the target repository/));
63
+ expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to fetch the config.json file from the target repository/));
64
64
  expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
65
65
  });
66
66
  it('Logs an error and exits the process if there are no projects listed in the repo config', async () => {
67
67
  // @ts-expect-error - Mocking AxiosResponse
68
68
  mockedFetchRepoFile.mockResolvedValue({});
69
69
  await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
70
- expect(logger.error).toHaveBeenCalledWith(expect.stringMatching(/Unable to find any projects in the target repository's config.json file/));
70
+ expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Unable to find any projects in the target repository's config.json file/));
71
71
  expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
72
72
  });
73
73
  it('Logs an error and exits the process if any of the projects in the repo config are missing required properties', async () => {
@@ -84,7 +84,7 @@ describe('lib/projects/create/legacy', () => {
84
84
  },
85
85
  });
86
86
  await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
87
- expect(logger.error).toHaveBeenCalledWith(expect.stringMatching(/Found misconfigured projects in the target repository's config.json file/));
87
+ expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Found misconfigured projects in the target repository's config.json file/));
88
88
  expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
89
89
  });
90
90
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,17 @@
1
- import { calculateComponentTemplateChoices } from '../v3.js';
2
- vi.mock('@hubspot/local-dev-lib/logger');
1
+ import { calculateComponentTemplateChoices } from '../v2.js';
2
+ import { hasFeature } from '../../../hasFeature.js';
3
+ vi.mock('../../ui/logger.js');
3
4
  vi.mock('@hubspot/local-dev-lib/api/github');
4
- describe('lib/projects/create/v3', () => {
5
+ vi.mock('../../../hasFeature.js');
6
+ const mockHasFeature = vi.mocked(hasFeature);
7
+ describe('lib/projects/create/v2', () => {
8
+ beforeEach(() => {
9
+ mockHasFeature.mockResolvedValue(true);
10
+ });
5
11
  describe('calculateComponentTemplateChoices()', () => {
12
+ beforeEach(() => {
13
+ mockHasFeature.mockClear();
14
+ });
6
15
  const mockComponents = [
7
16
  {
8
17
  label: 'Module Component',
@@ -30,7 +39,7 @@ describe('lib/projects/create/v3', () => {
30
39
  const choices = await calculateComponentTemplateChoices(mockComponents, 'oauth', 'private', 123, mockProjectMetadataForChoices);
31
40
  expect(choices).toHaveLength(4); // includes separator
32
41
  expect(choices[0]).toEqual({
33
- name: 'Module Component',
42
+ name: 'Module Component [module]',
34
43
  value: mockComponents[0],
35
44
  });
36
45
  expect(choices[2]).toEqual({
@@ -70,7 +79,7 @@ describe('lib/projects/create/v3', () => {
70
79
  components: { module: { count: 0, maxCount: 5, hsMetaFiles: [] } },
71
80
  });
72
81
  expect(choices[0]).toEqual({
73
- name: 'Unrestricted Component',
82
+ name: 'Unrestricted Component [module]',
74
83
  value: componentsWithoutRestrictions[0],
75
84
  });
76
85
  });
@@ -94,7 +103,7 @@ describe('lib/projects/create/v3', () => {
94
103
  const choices = await calculateComponentTemplateChoices(componentWithCliSelector, 'oauth', 'private', 213, projectMetadataWithWorkflowAction);
95
104
  expect(choices).toHaveLength(1); // no disabled components
96
105
  expect(choices[0]).toEqual({
97
- name: 'Workflow Action Tool',
106
+ name: 'Workflow Action Tool [workflow-action-tool]',
98
107
  value: componentWithCliSelector[0],
99
108
  });
100
109
  });
@@ -137,7 +146,7 @@ describe('lib/projects/create/v3', () => {
137
146
  const choices = await calculateComponentTemplateChoices(componentWithCliSelector, 'oauth', 'private', 123, undefined);
138
147
  expect(choices).toHaveLength(1); // no disabled components
139
148
  expect(choices[0]).toEqual({
140
- name: 'Workflow Action Tool',
149
+ name: 'Workflow Action Tool [workflow-action-tool]',
141
150
  value: componentWithCliSelector[0],
142
151
  });
143
152
  });
@@ -162,5 +171,71 @@ describe('lib/projects/create/v3', () => {
162
171
  // @ts-expect-error breaking stuff on purpose
163
172
  projectMetadataWithoutComponents)).rejects.toThrow();
164
173
  });
174
+ it('disables gated components when hasFeature returns false', async () => {
175
+ mockHasFeature.mockResolvedValue(false);
176
+ const gatedComponent = [
177
+ {
178
+ label: 'Workflow Action Tool',
179
+ path: 'workflow-action-tool',
180
+ type: 'workflow-action',
181
+ cliSelector: 'workflow-action-tool',
182
+ supportedAuthTypes: ['oauth'],
183
+ supportedDistributions: ['private'],
184
+ },
185
+ ];
186
+ const choices = await calculateComponentTemplateChoices(gatedComponent, 'oauth', 'private', 123, mockProjectMetadataForChoices);
187
+ expect(choices).toHaveLength(3); // includes separators
188
+ expect(choices[1]).toEqual({
189
+ name: expect.stringContaining('Workflow Action Tool'),
190
+ value: gatedComponent[0],
191
+ disabled: expect.stringContaining('does not have access to this feature'),
192
+ });
193
+ expect(mockHasFeature).toHaveBeenCalledWith(123, expect.any(String));
194
+ });
195
+ it('enables gated components when hasFeature returns true', async () => {
196
+ mockHasFeature.mockResolvedValue(true);
197
+ const gatedComponent = [
198
+ {
199
+ label: 'Workflow Action Tool',
200
+ path: 'workflow-action-tool',
201
+ type: 'workflow-action',
202
+ cliSelector: 'workflow-action-tool',
203
+ supportedAuthTypes: ['oauth'],
204
+ supportedDistributions: ['private'],
205
+ },
206
+ ];
207
+ const projectMetadataWithWorkflowAction = {
208
+ hsMetaFiles: [],
209
+ components: {
210
+ 'workflow-action': { count: 0, maxCount: 3, hsMetaFiles: [] },
211
+ },
212
+ };
213
+ const choices = await calculateComponentTemplateChoices(gatedComponent, 'oauth', 'private', 123, projectMetadataWithWorkflowAction);
214
+ expect(choices).toHaveLength(1); // no disabled components
215
+ expect(choices[0]).toEqual({
216
+ name: 'Workflow Action Tool [workflow-action-tool]',
217
+ value: gatedComponent[0],
218
+ });
219
+ expect(mockHasFeature).toHaveBeenCalledWith(123, expect.any(String));
220
+ });
221
+ it('handles non-gated components without calling hasFeature', async () => {
222
+ const nonGatedComponent = [
223
+ {
224
+ label: 'Regular Component',
225
+ path: 'regular',
226
+ type: 'module',
227
+ supportedAuthTypes: ['oauth'],
228
+ supportedDistributions: ['private'],
229
+ },
230
+ ];
231
+ const choices = await calculateComponentTemplateChoices(nonGatedComponent, 'oauth', 'private', 123, mockProjectMetadataForChoices);
232
+ expect(choices).toHaveLength(1);
233
+ expect(choices[0]).toEqual({
234
+ name: 'Regular Component [module]',
235
+ value: nonGatedComponent[0],
236
+ });
237
+ // hasFeature should not be called for non-gated components
238
+ expect(mockHasFeature).not.toHaveBeenCalled();
239
+ });
165
240
  });
166
241
  });
@@ -1,8 +1,8 @@
1
1
  import { selectProjectTemplatePrompt, } from '../../prompts/selectProjectTemplatePrompt.js';
2
2
  import { projectNameAndDestPrompt } from '../../prompts/projectNameAndDestPrompt.js';
3
3
  import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, EMPTY_PROJECT, } from '../../constants.js';
4
- import { useV3Api } from '../platformVersion.js';
5
- import { v3ComponentFlow } from './v3.js';
4
+ import { isV2Project } from '../platformVersion.js';
5
+ import { v2ComponentFlow } from './v2.js';
6
6
  import { getProjectTemplateListFromRepo } from './legacy.js';
7
7
  import { uiLogger } from '../../ui/logger.js';
8
8
  import { commands } from '../../../lang/en.js';
@@ -11,8 +11,8 @@ export async function handleProjectCreationFlow(args) {
11
11
  const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
12
12
  const repo = templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
13
13
  const projectNameAndDestPromptResponse = await projectNameAndDestPrompt(args);
14
- if (useV3Api(platformVersion)) {
15
- const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await v3ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, args.derivedAccountId);
14
+ if (isV2Project(platformVersion)) {
15
+ const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await v2ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, args.derivedAccountId);
16
16
  const selectProjectTemplatePromptResponse = await selectProjectTemplatePrompt(args, undefined, projectContents !== EMPTY_PROJECT ? componentTemplateChoices : undefined);
17
17
  return {
18
18
  authType,
@@ -3,13 +3,13 @@ import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH
3
3
  import { EXIT_CODES } from '../../enums/exitCodes.js';
4
4
  import { debugError } from '../../errorHandlers/index.js';
5
5
  import { uiLogger } from '../../ui/logger.js';
6
- import { useV3Api } from '../platformVersion.js';
6
+ import { isV2Project } from '../platformVersion.js';
7
7
  import { lib } from '../../../lang/en.js';
8
8
  const PROJECT_TEMPLATE_PROPERTIES = ['name', 'label', 'path'];
9
9
  export const EMPTY_PROJECT_TEMPLATE_NAME = 'no-template';
10
10
  export async function getConfigForPlatformVersion(platformVersion) {
11
11
  let path = '';
12
- if (useV3Api(platformVersion)) {
12
+ if (isV2Project(platformVersion)) {
13
13
  path = `${platformVersion}/`;
14
14
  }
15
15
  const { data } = await fetchRepoFile(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, `${path}config.json`, DEFAULT_PROJECT_TEMPLATE_BRANCH);
@@ -2,19 +2,19 @@ import { Separator } from '@inquirer/prompts';
2
2
  import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects.js';
3
3
  import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
4
4
  import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt.js';
5
- export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
5
+ export declare function createV2App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
6
6
  authType: string;
7
7
  distribution: string;
8
8
  }>;
9
9
  export declare function calculateComponentTemplateChoices(components: ComponentTemplate[], authType: string | undefined, distribution: string | undefined, accountId: number, projectMetadata?: ProjectMetadata): Promise<(ComponentTemplateChoice | Separator)[]>;
10
- type V3ComponentInfo = {
10
+ type V2ComponentInfo = {
11
11
  authType?: string;
12
12
  distribution?: string;
13
13
  repoConfig?: ProjectTemplateRepoConfig;
14
14
  projectContents?: string;
15
15
  componentTemplateChoices?: (ComponentTemplateChoice | Separator)[];
16
16
  };
17
- export declare function v3ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined, accountId: number): Promise<V3ComponentInfo>;
17
+ export declare function v2ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined, accountId: number): Promise<V2ComponentInfo>;
18
18
  export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
19
19
  selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
20
20
  platformVersion: string;
@@ -3,14 +3,14 @@ import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, EMPTY_
3
3
  import { commands, lib } from '../../../lang/en.js';
4
4
  import { listPrompt } from '../../prompts/promptUtils.js';
5
5
  import chalk from 'chalk';
6
- import { useV3Api } from '../platformVersion.js';
6
+ import { isV2Project } from '../platformVersion.js';
7
7
  import path from 'path';
8
8
  import { getConfigForPlatformVersion } from './legacy.js';
9
9
  import { logError } from '../../errorHandlers/index.js';
10
10
  import { EXIT_CODES } from '../../enums/exitCodes.js';
11
11
  import { hasFeature } from '../../hasFeature.js';
12
12
  import { AppEventsKey, PagesKey, } from '@hubspot/project-parsing-lib/src/lib/constants.js';
13
- export async function createV3App(providedAuth, providedDistribution) {
13
+ export async function createV2App(providedAuth, providedDistribution) {
14
14
  let authType;
15
15
  if (providedAuth &&
16
16
  providedDistribution === marketplaceDistribution &&
@@ -52,6 +52,7 @@ export async function createV3App(providedAuth, providedDistribution) {
52
52
  const componentTypeToGateMap = {
53
53
  [AppEventsKey]: FEATURES.APP_EVENTS,
54
54
  [PagesKey]: FEATURES.APPS_HOME,
55
+ 'workflow-action-tool': FEATURES.AGENT_TOOLS,
55
56
  };
56
57
  export async function calculateComponentTemplateChoices(components, authType, distribution, accountId, projectMetadata) {
57
58
  const enabledComponents = [];
@@ -73,18 +74,19 @@ export async function calculateComponentTemplateChoices(components, authType, di
73
74
  }
74
75
  if (Array.isArray(supportedAuthTypes) &&
75
76
  authType &&
76
- !supportedAuthTypes.includes(authType)) {
77
+ !supportedAuthTypes.includes(authType.toLowerCase())) {
77
78
  disabledReasons.push(commands.project.add.error.authTypeNotAllowed(authType));
78
79
  }
79
80
  if (Array.isArray(supportedDistributions) &&
80
81
  distribution &&
81
- !supportedDistributions.includes(distribution)) {
82
+ !supportedDistributions.includes(distribution.toLowerCase())) {
82
83
  disabledReasons.push(commands.project.add.error.distributionNotAllowed(distribution));
83
84
  }
84
- if (componentTypeToGateMap[template.type]) {
85
- const isUngated = await hasFeature(accountId, componentTypeToGateMap[template.type]);
85
+ const templateGate = componentTypeToGateMap[template.cliSelector || template.type];
86
+ if (templateGate) {
87
+ const isUngated = await hasFeature(accountId, templateGate);
86
88
  if (!isUngated) {
87
- disabledReasons.push(commands.project.add.error.portalDoesNotHaveAccessToThisFeature(accountId));
89
+ disabledReasons.unshift(commands.project.add.error.portalDoesNotHaveAccessToThisFeature(accountId));
88
90
  }
89
91
  }
90
92
  if (disabledReasons.length > 0) {
@@ -96,7 +98,7 @@ export async function calculateComponentTemplateChoices(components, authType, di
96
98
  }
97
99
  else {
98
100
  enabledComponents.push({
99
- name: template.label,
101
+ name: `${template.label} [${template.cliSelector || template.type}]`,
100
102
  value: template,
101
103
  });
102
104
  }
@@ -110,7 +112,7 @@ export async function calculateComponentTemplateChoices(components, authType, di
110
112
  ]
111
113
  : [...enabledComponents];
112
114
  }
113
- export async function v3ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, accountId) {
115
+ export async function v2ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, accountId) {
114
116
  let repoConfig = undefined;
115
117
  let authType;
116
118
  let distribution;
@@ -132,7 +134,7 @@ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth
132
134
  ],
133
135
  }));
134
136
  if (projectContentsChoice === PROJECT_WITH_APP) {
135
- const { authType: selectedAuthType, distribution: selectedDistribution } = await createV3App(providedAuth, providedDistribution);
137
+ const { authType: selectedAuthType, distribution: selectedDistribution } = await createV2App(providedAuth, providedDistribution);
136
138
  authType = selectedAuthType;
137
139
  distribution = selectedDistribution;
138
140
  }
@@ -146,7 +148,7 @@ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth
146
148
  };
147
149
  }
148
150
  export function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
149
- if (!useV3Api(platformVersion)) {
151
+ if (!isV2Project(platformVersion)) {
150
152
  return [];
151
153
  }
152
154
  const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
@@ -10,4 +10,4 @@ export declare function logDeployErrors(errorData: {
10
10
  };
11
11
  }>;
12
12
  }): void;
13
- export declare function handleProjectDeploy(targetAccountId: number, projectName: string, buildId: number, useV3Api: boolean, force: boolean): Promise<Deploy | undefined>;
13
+ export declare function handleProjectDeploy(targetAccountId: number, projectName: string, buildId: number, isV2Project: boolean, force: boolean): Promise<Deploy | undefined>;