@hubspot/cli 7.7.16-experimental.0 → 7.7.16-experimental.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 (106) hide show
  1. package/bin/cli.js +4 -0
  2. package/bin/hs +1 -1
  3. package/commands/account/auth.js +3 -3
  4. package/commands/app/install.d.ts +8 -0
  5. package/commands/app/install.js +127 -0
  6. package/commands/app.js +6 -1
  7. package/commands/auth.js +23 -25
  8. package/commands/getStarted.d.ts +9 -0
  9. package/commands/getStarted.js +274 -0
  10. package/commands/init.js +35 -32
  11. package/commands/mcp/setup.d.ts +2 -2
  12. package/commands/mcp/setup.js +2 -0
  13. package/commands/mcp/start.d.ts +2 -2
  14. package/commands/mcp/start.js +3 -1
  15. package/commands/project/cloneApp.js +4 -4
  16. package/commands/project/create.js +9 -9
  17. package/commands/project/deploy.d.ts +1 -0
  18. package/commands/project/deploy.js +29 -3
  19. package/commands/project/dev/deprecatedFlow.js +4 -4
  20. package/commands/project/dev/index.js +5 -5
  21. package/commands/project/dev/unifiedFlow.js +8 -0
  22. package/commands/project/upload.d.ts +2 -2
  23. package/commands/project/upload.js +18 -23
  24. package/commands/project/validate.d.ts +6 -0
  25. package/commands/project/validate.js +82 -0
  26. package/commands/project.js +2 -0
  27. package/commands/sandbox/delete.js +5 -5
  28. package/commands/testAccount/create.d.ts +6 -0
  29. package/commands/testAccount/create.js +160 -0
  30. package/commands/testAccount/createConfig.d.ts +10 -0
  31. package/commands/testAccount/createConfig.js +98 -0
  32. package/commands/testAccount/delete.d.ts +6 -0
  33. package/commands/testAccount/delete.js +48 -0
  34. package/commands/testAccount.d.ts +3 -0
  35. package/commands/testAccount.js +28 -0
  36. package/lang/en.d.ts +201 -35
  37. package/lang/en.js +201 -38
  38. package/lang/en.lyaml +9 -14
  39. package/lib/accountTypes.d.ts +1 -0
  40. package/lib/accountTypes.js +20 -9
  41. package/lib/app/migrate.js +15 -3
  42. package/lib/app/migrate_legacy.js +2 -3
  43. package/lib/app/urls.d.ts +1 -1
  44. package/lib/commonOpts.d.ts +2 -0
  45. package/lib/commonOpts.js +21 -9
  46. package/lib/constants.d.ts +5 -0
  47. package/lib/constants.js +6 -1
  48. package/lib/doctor/Doctor.js +1 -1
  49. package/lib/errorHandlers/index.js +7 -0
  50. package/lib/mcp/setup.d.ts +9 -0
  51. package/lib/mcp/setup.js +23 -21
  52. package/lib/middleware/__test__/configMiddleware.test.js +2 -2
  53. package/lib/middleware/configMiddleware.js +10 -2
  54. package/lib/parsing.d.ts +1 -0
  55. package/lib/parsing.js +11 -0
  56. package/lib/polling.d.ts +1 -1
  57. package/lib/polling.js +11 -1
  58. package/lib/projectProfiles.d.ts +1 -0
  59. package/lib/projectProfiles.js +18 -0
  60. package/lib/projects/add/v3AddComponent.js +4 -0
  61. package/lib/projects/buildAndDeploy.js +1 -1
  62. package/lib/projects/create/index.d.ts +3 -2
  63. package/lib/projects/create/index.js +11 -5
  64. package/lib/projects/create/v3.d.ts +3 -3
  65. package/lib/projects/create/v3.js +2 -2
  66. package/lib/projects/localDev/AppDevModeInterface.d.ts +3 -0
  67. package/lib/projects/localDev/AppDevModeInterface.js +46 -17
  68. package/lib/projects/localDev/LocalDevManager.js +1 -1
  69. package/lib/projects/localDev/LocalDevProcess.d.ts +3 -2
  70. package/lib/projects/localDev/LocalDevProcess.js +16 -12
  71. package/lib/projects/localDev/LocalDevState.d.ts +10 -5
  72. package/lib/projects/localDev/LocalDevState.js +18 -20
  73. package/lib/projects/localDev/LocalDevWatcher.js +1 -1
  74. package/lib/projects/structure.d.ts +2 -2
  75. package/lib/projects/upload.d.ts +4 -0
  76. package/lib/projects/upload.js +57 -22
  77. package/lib/projects/urls.d.ts +2 -0
  78. package/lib/projects/urls.js +10 -0
  79. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +17 -0
  80. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +96 -0
  81. package/lib/prompts/installAppPrompt.d.ts +2 -1
  82. package/lib/prompts/installAppPrompt.js +12 -2
  83. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  84. package/lib/prompts/projectNameAndDestPrompt.d.ts +3 -0
  85. package/lib/prompts/projectNameAndDestPrompt.js +60 -0
  86. package/lib/prompts/promptUtils.d.ts +1 -0
  87. package/lib/prompts/promptUtils.js +2 -0
  88. package/lib/prompts/selectProjectTemplatePrompt.d.ts +26 -0
  89. package/lib/prompts/{createProjectPrompt.js → selectProjectTemplatePrompt.js} +6 -55
  90. package/lib/ui/logger.d.ts +1 -0
  91. package/lib/ui/logger.js +1 -0
  92. package/lib/validation.d.ts +1 -1
  93. package/lib/validation.js +4 -4
  94. package/lib/yargsUtils.d.ts +1 -0
  95. package/lib/yargsUtils.js +3 -0
  96. package/mcp-server/tools/index.js +2 -0
  97. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
  98. package/mcp-server/tools/project/CreateProjectTool.js +5 -1
  99. package/mcp-server/tools/project/DeployProject.js +1 -1
  100. package/mcp-server/tools/project/UploadProjectTools.js +1 -1
  101. package/mcp-server/tools/project/ValidateProjectTool.d.ts +17 -0
  102. package/mcp-server/tools/project/ValidateProjectTool.js +35 -0
  103. package/package.json +10 -9
  104. package/types/LocalDev.d.ts +2 -0
  105. package/types/Yargs.d.ts +5 -1
  106. package/lib/prompts/createProjectPrompt.d.ts +0 -28
package/lang/en.js CHANGED
@@ -22,6 +22,55 @@ exports.commands = {
22
22
  configFileExists: (configPath) => `A configuration file already exists at ${configPath}. To specify a new configuration file, delete the existing one and try again.`,
23
23
  },
24
24
  },
25
+ getStarted: {
26
+ options: {
27
+ dest: {
28
+ describe: 'Directory where the project should be created',
29
+ },
30
+ name: {
31
+ describe: 'Project name (cannot be changed)',
32
+ },
33
+ templateSource: {
34
+ describe: 'Path to custom GitHub repository from which to create project template',
35
+ },
36
+ },
37
+ startTitle: 'Welcome to HubSpot Development!',
38
+ verboseDescribe: 'A step-by-step command to get you started with a HubSpot project.',
39
+ startDescription: 'You can use the HubSpot CLI to build apps, CMS themes, and more.',
40
+ designManager: 'To onboard with CMS, please visit the HubSpot Design Manager in your account and follow the checklist items.',
41
+ openDesignManager: 'Click here to go to the HubSpot Design Manager',
42
+ openDesignManagerPrompt: 'Open Design Manager in your browser?',
43
+ openedDesignManager: 'Redirected to Design Manager!',
44
+ developerOverviewBrowserOpenPrep: "We'll take you to your HubSpot account and walk you through installing and previewing your new app.",
45
+ openInstallUrl: 'Open HubSpot to install your app in your account?',
46
+ openedDeveloperOverview: 'HubSpot opened!',
47
+ prompts: {
48
+ selectOption: 'Are you looking to build apps or CMS?',
49
+ options: {
50
+ app: 'App',
51
+ cms: 'CMS',
52
+ },
53
+ installDependencies: 'Would you like to install dependencies now?',
54
+ uploadProject: 'Would you like to upload your project to HubSpot now?',
55
+ projectCreated: {
56
+ title: chalk_1.default.bold('Next steps:'),
57
+ description: `Let's prepare and upload your project to HubSpot.\nYou can use ${(0, ui_1.uiCommandReference)('hs project install-deps')} to ${chalk_1.default.bold('install dependencies')} and ${(0, ui_1.uiCommandReference)('hs project upload')} to ${chalk_1.default.bold('upload')} your project.`,
58
+ },
59
+ },
60
+ logs: {
61
+ appSelected: `We'll create a new project with a sample app for you.\nProjects are what you can use to create apps, themes, and more at HubSpot.\nUsually you'll use the ${(0, ui_1.uiCommandReference)('hs project create')} command, but we'll go ahead and make one now.`,
62
+ dependenciesInstalled: 'Dependencies installed successfully.',
63
+ dependenciesNotInstalled: `Dependencies not installed. Remember to do this later with the command ${(0, ui_1.uiCommandReference)('hs project install-deps')} from the project directory.`,
64
+ uploadingProject: 'Uploading your project to HubSpot...',
65
+ uploadSuccess: 'Project uploaded successfully!',
66
+ developerOverviewLink: 'Open this link to navigate to your HubSpot developer portal',
67
+ },
68
+ errors: {
69
+ uploadFailed: 'Failed to upload project to HubSpot.',
70
+ configFileNotFound: 'Could not find project configuration for upload.',
71
+ installDepsFailed: 'Failed to install dependencies.',
72
+ },
73
+ },
25
74
  completion: {
26
75
  describe: 'Enable bash completion shortcuts for commands. Concat the generated script to your .bashrc, .bash_profile, or .zshrc file.',
27
76
  examples: {
@@ -151,8 +200,11 @@ exports.commands = {
151
200
  },
152
201
  },
153
202
  auth: {
154
- describe: (configName) => `Configure authentication for your HubSpot account. This will update the ${configName} file that stores your account information.`,
203
+ describe: 'Configure authentication for your HubSpot account.',
204
+ verboseDescribe: (configName, authMethod) => `Configure authentication for a HubSpot account. This will update the ${configName} file that stores your account information.\n\nThe recommended authentication method is ${chalk_1.default.bold(authMethod)}, which uses an access token tied to a specific user account.`,
155
205
  errors: {
206
+ invalidAccountIdProvided: `--account must be a number.`,
207
+ globalConfigFileExists: (accountAuthCommand) => `You are using our new global configuration for account management, which is not compatible with this command. Please use ${(0, ui_1.uiCommandReference)(accountAuthCommand)} instead.`,
156
208
  noConfigFileFound: 'No config file was found. To create a new config file, use the "hs init" command.',
157
209
  unsupportedAuthType: (type, supportedProtocols) => `Unsupported auth type: ${type}. The only supported authentication protocols are ${supportedProtocols}.`,
158
210
  },
@@ -699,7 +751,8 @@ exports.commands = {
699
751
  },
700
752
  },
701
753
  init: {
702
- describe: (configName) => `Configure authentication for your HubSpot account. This will create a ${configName} file to store your account information.`,
754
+ describe: 'Create a CLI config file and configure authentication for your HubSpot account.',
755
+ verboseDescribe: (configName, command, authMethod) => `Configure authentication for a HubSpot account. This will create a ${configName} file to store your account information. To configure authentication for additional accounts, run ${command}.\n\nThe recommended authentication method is ${chalk_1.default.bold(authMethod)}, which uses an access token tied to a specific user account.`,
703
756
  options: {
704
757
  authType: {
705
758
  describe: 'Authentication mechanism',
@@ -714,14 +767,16 @@ exports.commands = {
714
767
  },
715
768
  success: {
716
769
  configFileCreated: (configPath) => `Created config file "${configPath}"`,
717
- configFileUpdated: (account, authType) => `Connected account "${account}" using "${authType}" and set it as the default account`,
770
+ configFileUpdated: (authType, account) => `Connected account "${account}" using "${authType}" and set it as the default account`,
718
771
  },
719
772
  logs: {
720
773
  updateConfig: 'To update an existing config file, use the "hs auth" command.',
721
774
  },
722
775
  errors: {
776
+ invalidAccountIdProvided: `--account must be a number.`,
723
777
  configFileExists: (configPath) => `The config file ${configPath} already exists.`,
724
778
  bothConfigFilesNotAllowed: (path) => `Unable to create config file, because there is an existing one at "${path}". To create a new config file, delete the existing one and try again.`,
779
+ globalConfigFileExists: `You are using our new global configuration for account management, which is not compatible with this command. Please use ${(0, ui_1.uiCommandReference)('hs account auth')} instead.`,
725
780
  },
726
781
  },
727
782
  lint: {
@@ -788,7 +843,7 @@ exports.commands = {
788
843
  client: 'Target applications to configure',
789
844
  docsSearch: 'Should the docs search mcp server be installed',
790
845
  },
791
- success: (derivedTargets) => `You can now use the HubSpot CLI tools in ${derivedTargets.join(', ')}. ${chalk_1.default.bold('You may need to restart these tools to apply the changes')}.`,
846
+ success: (derivedTargets) => `You can now use the HubSpot CLI MCP Server in ${derivedTargets.join(', ')}. ${chalk_1.default.bold('You may need to restart these tools to apply the changes')}.`,
792
847
  errors: {
793
848
  needsNode20: `This feature requires node >=20`,
794
849
  },
@@ -802,13 +857,11 @@ exports.commands = {
802
857
  claudeCodeInstallFailed: 'Claude Code CLI not working - skipping configuration',
803
858
  failedToConfigureClaudeDesktop: 'Failed to configure Claude Desktop',
804
859
  configuringCursor: 'Configuring Cursor...',
805
- noCursorMcpFile: (configFile) => `No ${configFile} file found - skipping Cursor configuration`,
806
860
  failedToConfigureCursor: 'Failed to configure Cursor',
807
861
  configuredCursor: 'Configured Cursor',
808
862
  alreadyInstalled: 'HubSpot CLI mcp server already installed, reinstalling',
809
- configuringWindsurf: 'Configuring Cursor...',
810
- noWindsurfFile: (configFile) => `No ${configFile} file found - skipping Windsurf configuration`,
811
- failedToConfigureWindsurf: 'Failed to configure Cursor',
863
+ configuringWindsurf: 'Configuring Windsurf...',
864
+ failedToConfigureWindsurf: 'Failed to configure Windsurf',
812
865
  configuredWindsurf: 'Configured Windsurf',
813
866
  },
814
867
  prompts: {
@@ -1322,6 +1375,20 @@ exports.commands = {
1322
1375
  noPackageJsonInProject: (projectName, link) => `No dependencies to install. The project ${projectName} folder might be missing component or subcomponent files. ${link}`,
1323
1376
  packageManagerNotInstalled: (packageManager, link) => `This command depends on ${packageManager}, install ${chalk_1.default.bold(link)}`,
1324
1377
  },
1378
+ validate: {
1379
+ describe: 'Validate the project before uploading',
1380
+ mustBeRanWithinAProject: 'This command must be run from within a project directory.',
1381
+ badVersion: 'This command is only available for projects 2025.2 and later.',
1382
+ examples: {
1383
+ default: 'Validate the project before uploading',
1384
+ },
1385
+ success: (projectName) => `Project ${projectName} is valid and ready to upload`,
1386
+ options: {
1387
+ profile: {
1388
+ describe: 'The profile to target for this validation',
1389
+ },
1390
+ },
1391
+ },
1325
1392
  },
1326
1393
  remove: {
1327
1394
  describe: 'Delete a file or folder from the HubSpot CMS.',
@@ -1433,6 +1500,28 @@ exports.commands = {
1433
1500
  app: {
1434
1501
  describe: 'Commands for managing apps.',
1435
1502
  subcommands: {
1503
+ install: {
1504
+ describe: 'Install an OAuth app into a test account.',
1505
+ options: {
1506
+ appUid: 'The uid of the app to install',
1507
+ projectName: 'The name of the project that contains the app',
1508
+ },
1509
+ positionals: {
1510
+ testAccountId: 'The id of the test account to install the app into',
1511
+ },
1512
+ errors: {
1513
+ mustSpecifyProjectName: `You must specify a project name. Use the ${(0, ui_1.uiCommandReference)('--project-name')} flag to specify the project name or run this command from within a project directory.`,
1514
+ noAppUidFound: `No app uid found. Please specify the app uid with the ${(0, ui_1.uiCommandReference)('--app-uid')} flag or run this command from within a project that contains an app.`,
1515
+ appMustBeOauth: 'This command only supports installing oauth apps. Please specify an app with oauth auth type.',
1516
+ },
1517
+ polling: {
1518
+ start: 'Installing app...',
1519
+ success: 'App installed successfully',
1520
+ failure: 'App installation failed',
1521
+ error: 'Error installing app',
1522
+ },
1523
+ example: 'Install the app with uid my-app-uid from the project named "my-project" into the target account with id 1234567890',
1524
+ },
1436
1525
  secret: {
1437
1526
  describe: 'Commands for managing secrets.',
1438
1527
  subcommands: {
@@ -1726,6 +1815,66 @@ exports.commands = {
1726
1815
  missingSrc: 'Please specify the path to your javascript fields file or directory with the --src flag.',
1727
1816
  },
1728
1817
  },
1818
+ testAccount: {
1819
+ describe: 'Commands for working with test accounts.',
1820
+ create: {
1821
+ describe: 'Create a test account from a config file',
1822
+ configPathPrompt: '[--config-path] Enter the path to the test account config: ',
1823
+ createTestAccountFromConfigPrompt: 'How would you like to create your test account?',
1824
+ createFromConfigOption: 'Create test account from config file',
1825
+ createFromScratchOption: 'Create test account from scratch',
1826
+ errors: {
1827
+ configFileNotFound: (configPath) => `No test account config file exists at ${configPath}. Create a test account config file with the ${(0, ui_1.uiCommandReference)('hs test-account create-config')} command.`,
1828
+ configFileParseFailed: (configPath) => `Failed to parse test account config file at ${configPath}`,
1829
+ },
1830
+ polling: {
1831
+ start: (testAccountName) => `Creating test account "${chalk_1.default.bold(testAccountName)}"...`,
1832
+ syncing: 'Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)',
1833
+ success: (testAccountName, testAccountId) => `Test account "${chalk_1.default.bold(testAccountName)}" successfully created with id: ${chalk_1.default.bold(testAccountId)}`,
1834
+ createFailure: 'Failed to create test account.',
1835
+ syncFailure: 'Failed to sync data into test account. The account may not be ready to use.',
1836
+ pakFailure: 'Failed to generate a personal access key for the test account.',
1837
+ },
1838
+ options: {
1839
+ configPath: 'The path to the test account config',
1840
+ },
1841
+ example: (configPath) => `Create a test account from the config file at ${configPath}`,
1842
+ },
1843
+ createConfig: {
1844
+ describe: 'Create a test account config file.',
1845
+ pathPrompt: '[--path] What is the path to the test account config?',
1846
+ errors: {
1847
+ pathError: 'Path is required',
1848
+ pathFormatError: 'Path must end with .json',
1849
+ failedToCreate: 'Failed to create test account config',
1850
+ pathExistsError: 'A file already exists at this path. Please try again with a different path.',
1851
+ },
1852
+ success: {
1853
+ configFileCreated: (path) => `Test account config successfully created at ${path}`,
1854
+ },
1855
+ options: {
1856
+ name: 'The name of the test account',
1857
+ description: 'The description of the test account',
1858
+ tiers: 'The tiers of the test account',
1859
+ path: 'The path to the test account config',
1860
+ },
1861
+ example: (name) => `Create a test account config file with the name "${name}"`,
1862
+ },
1863
+ delete: {
1864
+ describe: 'Delete a test account config file.',
1865
+ pathPrompt: '[--path] What is the path to the test account config?',
1866
+ errors: {
1867
+ failedToDelete: 'Failed to delete test account',
1868
+ },
1869
+ success: {
1870
+ testAccountDeleted: (testAccountId) => `Test account with id ${testAccountId} successfully deleted`,
1871
+ },
1872
+ positionals: {
1873
+ testAccountId: 'The id of the test account',
1874
+ },
1875
+ example: (testAccountId) => `Delete a test account with the id "${testAccountId}"`,
1876
+ },
1877
+ },
1729
1878
  secrets: {
1730
1879
  add: {
1731
1880
  loading: {
@@ -2311,6 +2460,12 @@ exports.commands = {
2311
2460
  },
2312
2461
  };
2313
2462
  exports.lib = {
2463
+ parsing: {
2464
+ unableToParseStringToNumber: 'Unable to parse string to number',
2465
+ },
2466
+ configMiddleWare: {
2467
+ invalidAccountIdEnvironmentVariable: 'Unable to parse `HUBSPOT_ACCOUNT_ID` environment variable into a number',
2468
+ },
2314
2469
  process: {
2315
2470
  exitDebug: (signal) => `Attempting to gracefully exit. Triggered by ${signal}`,
2316
2471
  },
@@ -2320,7 +2475,6 @@ exports.lib = {
2320
2475
  noCompatibleComponents: (serverKey) => `Skipping call to ${serverKey} because there are no compatible components in the project.`,
2321
2476
  },
2322
2477
  LocalDevManager: {
2323
- staticAuthAccountsMustMatch: 'You must test static auth apps in the account the project exists in',
2324
2478
  appNotFound: (accountId, appUid) => `Unable to find app with uid ${appUid} in account ${(0, ui_1.uiAccountDescription)(accountId)}`,
2325
2479
  failedToInitialize: 'Missing required arguments to initialize Local Dev',
2326
2480
  noDeployedBuild: (projectName, accountIdentifier, uploadCommand) => `Your project ${chalk_1.default.bold(projectName)} exists in ${accountIdentifier}, but has no deployed build. Projects must be successfully deployed to be developed locally. Address any build and deploy errors your project may have, then run ${uploadCommand} to upload and deploy your project.`,
@@ -2365,6 +2519,9 @@ exports.lib = {
2365
2519
  },
2366
2520
  AppDevModeInterface: {
2367
2521
  defaultMarketplaceAppWarning: (installCount) => `\n\nYour marketplace app is currently installed in ${chalk_1.default.bold(`${installCount} ${installCount === 1 ? 'account' : 'accounts'}`)}. Any uploaded changes will impact your app's users. We strongly recommend creating a copy of this app to test your changes before proceding.`,
2522
+ autoInstallDeclined: 'You must install your app on your target test account to proceed with local development.',
2523
+ autoInstallSuccess: (appName, targetTestAccountId) => `Successfully installed app ${appName} on account ${(0, ui_1.uiAccountDescription)(targetTestAccountId)}\n`,
2524
+ autoInstallError: (appName, targetTestAccountId) => `Error installing app ${appName} on account ${(0, ui_1.uiAccountDescription)(targetTestAccountId)}. You may still be able to install your app in your browser.`,
2368
2525
  },
2369
2526
  LocalDevWebsocketServer: {
2370
2527
  errors: {
@@ -2477,6 +2634,9 @@ exports.lib = {
2477
2634
  invalidAuthDistCombo: (authType, distribution) => `Invalid distribution and auth combination. Apps with distribution '${distribution}' must have auth '${authType}'`,
2478
2635
  },
2479
2636
  },
2637
+ add: {
2638
+ nothingAdded: 'No features added.',
2639
+ },
2480
2640
  validateProjectConfig: {
2481
2641
  configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${(0, ui_1.uiCommandReference)('hs project create')} to create a new project.`,
2482
2642
  configMissingFields: 'The project configuration file is missing required fields.',
@@ -2513,8 +2673,8 @@ exports.lib = {
2513
2673
  pollProjectBuildAndDeploy: {
2514
2674
  buildSucceededAutomaticallyDeploying: (buildId, accountIdentifier) => `Build #${buildId} succeeded. ${chalk_1.default.bold('Automatically deploying')} to ${accountIdentifier}\n`,
2515
2675
  cleanedUpTempFile: (path) => `Cleaned up temporary file ${path}`,
2516
- viewDeploys: 'View all deploys for this project in HubSpot',
2517
- unableToFindAutodeployStatus: (buildId, viewDeploysLink) => `Unable to find the auto deploy for build #${buildId}. This deploy may have been skipped. ${viewDeploysLink}.`,
2676
+ viewDeploys: 'view all deploys for this project in HubSpot',
2677
+ unableToFindAutodeployStatus: (buildId, viewDeploysLink) => `Unable to find the auto deploy for build #${buildId}. This deploy may have been skipped or blocked due to components being removed. Manually deploy with ${(0, ui_1.uiCommandReference)('hs project deploy')} or ${viewDeploysLink}.`,
2518
2678
  },
2519
2679
  },
2520
2680
  projectUpload: {
@@ -2594,7 +2754,7 @@ exports.lib = {
2594
2754
  },
2595
2755
  projectDevCommand: {
2596
2756
  command: 'hs project dev',
2597
- message: (command) => `Run ${command} to set up your test environment and start local development`,
2757
+ message: (command) => `Run ${command} from within your project directory to set up your test environment and start local development`,
2598
2758
  },
2599
2759
  projectInstallDepsCommand: {
2600
2760
  command: 'hs project install-deps',
@@ -2650,31 +2810,18 @@ exports.lib = {
2650
2810
  },
2651
2811
  commonOpts: {
2652
2812
  options: {
2653
- account: {
2654
- describe: 'HubSpot account id or name from config',
2655
- },
2656
- config: {
2657
- describe: 'Path to a config file',
2658
- },
2659
- overwrite: {
2660
- describe: 'Overwrite existing files',
2661
- },
2813
+ account: 'HubSpot account id or name from config',
2814
+ config: 'Path to a config file',
2815
+ overwrite: 'Overwrite existing files',
2662
2816
  modes: {
2663
- describe: {
2664
- default: (modes) => `${modes}`,
2665
- read: (modes) => `Read from ${modes}`,
2666
- write: (modes) => `Write to ${modes}`,
2667
- },
2668
- },
2669
- qa: {
2670
- describe: 'Run command in QA mode',
2671
- },
2672
- useEnv: {
2673
- describe: 'Use environment variable config',
2674
- },
2675
- debug: {
2676
- describe: 'Set log level to debug',
2817
+ default: (modes) => `${modes}`,
2818
+ read: (modes) => `Read from ${modes}`,
2819
+ write: (modes) => `Write to ${modes}`,
2677
2820
  },
2821
+ qa: 'Run command in QA mode',
2822
+ useEnv: 'Use environment variable config',
2823
+ jsonOutput: 'Format output as JSON',
2824
+ debug: 'Set log level to debug',
2678
2825
  },
2679
2826
  },
2680
2827
  configMigrate: {
@@ -2716,6 +2863,14 @@ exports.lib = {
2716
2863
  setAsDefaultAccount: (accountName) => `Account "${accountName}" set as the default account`,
2717
2864
  keepingCurrentDefault: (accountName) => `Account "${accountName}" will continue to be the default account`,
2718
2865
  },
2866
+ createDeveloperTestAccountConfigPrompt: {
2867
+ namePrompt: '[--name] What is the name of the test account?',
2868
+ descriptionPrompt: '[--description] What is the description of the test account?',
2869
+ tiersPrompt: '[--tiers] Which product tiers should the test account have?',
2870
+ errors: {
2871
+ tiersError: 'Cannot have more than one tier per hub',
2872
+ },
2873
+ },
2719
2874
  accountNamePrompt: {
2720
2875
  enterAccountName: 'Enter a unique name to reference this account in the CLI:',
2721
2876
  enterDeveloperTestAccountName: 'Name your developer test account:',
@@ -2790,16 +2945,20 @@ exports.lib = {
2790
2945
  languageRequired: "Please select API sample app's language",
2791
2946
  },
2792
2947
  },
2793
- createProjectPrompt: {
2948
+ projectNameAndDestPrompt: {
2794
2949
  enterName: '[--name] Give your project a name: ',
2795
2950
  enterDest: '[--dest] Enter the folder to create the project in:',
2796
- selectTemplate: '[--template] Choose a project template: ',
2797
- features: '[--features] Which features would you like your app to include?',
2798
2951
  errors: {
2799
2952
  nameRequired: 'A project name is required',
2800
2953
  destRequired: 'A project dest is required',
2801
2954
  invalidDest: 'There is an existing project at this destination. Please provide a new path for this project.',
2802
2955
  invalidCharacters: 'The selected destination contains invalid characters. Please provide a new path and try again.',
2956
+ },
2957
+ },
2958
+ selectProjectTemplatePrompt: {
2959
+ selectTemplate: '[--template] Choose a project template: ',
2960
+ features: '[--features] Which features would you like your app to include?',
2961
+ errors: {
2803
2962
  invalidTemplate: (template) => `[--template] Could not find template "${template}". Please choose an available template:`,
2804
2963
  projectTemplateRequired: 'Project template is required when projectTemplates is provided',
2805
2964
  },
@@ -2888,6 +3047,7 @@ exports.lib = {
2888
3047
  explanation: 'Local development requires this app to be installed in the target test account',
2889
3048
  reinstallExplanation: "This app's required scopes have been updated since it was last installed on the target test account. To avoid issues with local development, we recommend reinstalling the app with the updated scopes.",
2890
3049
  prompt: 'Open HubSpot to install this app?',
3050
+ autoPrompt: 'Install this app in your target test account?',
2891
3051
  reinstallPrompt: 'Open HubSpot to reinstall this app?',
2892
3052
  decline: `To continue local development of this app, install it in your target test account and re-run ${chalk_1.default.bold('`hs project dev`')}`,
2893
3053
  },
@@ -2903,6 +3063,9 @@ exports.lib = {
2903
3063
  },
2904
3064
  },
2905
3065
  },
3066
+ polling: {
3067
+ timeoutError: (timeoutMs) => `Polling timed out after ${timeoutMs}ms.`,
3068
+ },
2906
3069
  convertFields: {
2907
3070
  positionals: {
2908
3071
  src: {
package/lang/en.lyaml CHANGED
@@ -694,6 +694,7 @@ en:
694
694
  buildIdDoesNotExist: "Build {{ buildId }} does not exist for project {{ projectName }}. {{ linkToProject }}"
695
695
  buildAlreadyDeployed: "Build {{ buildId }} is already deployed. {{ linkToProject}}"
696
696
  viewProjectsBuilds: 'View project builds in HubSpot'
697
+ deployContainsRemovals: "- This deploy would remove the {{#bold}}{{ componentName }}{{/bold}} component. To proceed, run the deploy command with the {{ forceFlag }} flag"
697
698
  examples:
698
699
  default: "Deploy the latest build of the current project"
699
700
  withOptions: "Deploy build 5 of the project my-project"
@@ -704,6 +705,8 @@ en:
704
705
  describe: "Project name"
705
706
  profile:
706
707
  describe: "The profile to target with this deploy"
708
+ force:
709
+ describe: "Skip warnings and force deploy. Use this carefully as it will bypass warnings for destructive actions."
707
710
  listBuilds:
708
711
  describe: "List the project's builds."
709
712
  continueOrExitPrompt: "Press <enter> to load more, or ctrl+c to exit"
@@ -1049,19 +1052,6 @@ en:
1049
1052
  logFeedbackMessage:
1050
1053
  feedbackHeader: "We'd love to hear your feedback!"
1051
1054
  feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n"
1052
- projectBuildAndDeploy:
1053
- makePollTaskStatusFunc:
1054
- componentCountSingular: "Found 1 component in this project"
1055
- componentCount: "Found {{ numComponents }} components in this project"
1056
- successStatusText: "DONE"
1057
- failedStatusText: "FAILED"
1058
- errorFetchingTaskStatus: "An error occurred while fetching the status of the current {{ taskType }}. For more information, view this project in HubSpot by running {{ openCommand }}."
1059
- pollBuildAutodeployStatusError: "Error fetching autodeploy status for build #{{ buildId }}"
1060
- pollProjectBuildAndDeploy:
1061
- buildSucceededAutomaticallyDeploying: "Build #{{ buildId }} succeeded. {{#bold}}Automatically deploying{{/bold}} to {{ accountIdentifier }}\n"
1062
- cleanedUpTempFile: "Cleaned up temporary file {{ path }}"
1063
- viewDeploys: "View all deploys for this project in HubSpot"
1064
- unableToFindAutodeployStatus: "Unable to find the auto deploy for build #{{ buildId }}. This deploy may have been skipped. {{ viewDeploysLink }}."
1065
1055
  projectUpload:
1066
1056
  uploadProjectFiles:
1067
1057
  add: "Uploading {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}"
@@ -1107,6 +1097,9 @@ en:
1107
1097
  feedbackCommand:
1108
1098
  command: "hs feedback"
1109
1099
  message: "Run {{ command }} to report a bug or leave feedback"
1100
+ getStartedCommand:
1101
+ command: "hs get-started"
1102
+ message: "Run {{ command }} to get started with HubSpot development"
1110
1103
  helpCommand:
1111
1104
  command: "hs help"
1112
1105
  message: "Run {{ command }} to see a list of available commands"
@@ -1124,7 +1117,7 @@ en:
1124
1117
  message: "Run {{ command }} to upload your project to your HubSpot account"
1125
1118
  projectDevCommand:
1126
1119
  command: "hs project dev"
1127
- message: "Run {{ command }} to set up your test environment and start local development"
1120
+ message: "Run {{ command }} from within your project directory to set up your test environment and start local development"
1128
1121
  projectInstallDepsCommand:
1129
1122
  command: "hs project install-deps"
1130
1123
  message: "Run {{ command }} to install dependencies for your project components"
@@ -1165,6 +1158,8 @@ en:
1165
1158
  describe: "Use environment variable config"
1166
1159
  debug:
1167
1160
  describe: "Set log level to debug"
1161
+ jsonOutput:
1162
+ describe: "Format output as JSON"
1168
1163
  prompts:
1169
1164
  projectDevTargetAccountPrompt:
1170
1165
  createNewSandboxOption: "<Test on a new development sandbox>"
@@ -5,4 +5,5 @@ export declare function isStandardSandbox(accountConfig: CLIAccount): boolean;
5
5
  export declare function isDevelopmentSandbox(accountConfig: CLIAccount): boolean;
6
6
  export declare function isDeveloperTestAccount(accountConfig: CLIAccount): boolean;
7
7
  export declare function isAppDeveloperAccount(accountConfig: CLIAccount): boolean;
8
+ export declare function isTestAccountOrSandbox(accountConfig: CLIAccount): boolean;
8
9
  export declare function isUnifiedAccount(account: CLIAccount): Promise<boolean>;
@@ -6,33 +6,44 @@ exports.isStandardSandbox = isStandardSandbox;
6
6
  exports.isDevelopmentSandbox = isDevelopmentSandbox;
7
7
  exports.isDeveloperTestAccount = isDeveloperTestAccount;
8
8
  exports.isAppDeveloperAccount = isAppDeveloperAccount;
9
+ exports.isTestAccountOrSandbox = isTestAccountOrSandbox;
9
10
  exports.isUnifiedAccount = isUnifiedAccount;
10
11
  const config_1 = require("@hubspot/local-dev-lib/constants/config");
11
12
  const hasFeature_1 = require("./hasFeature");
12
13
  const constants_1 = require("./constants");
13
14
  const getAccountIdentifier_1 = require("@hubspot/local-dev-lib/config/getAccountIdentifier");
14
15
  function isAccountType(accountConfig, accountType) {
15
- return (Boolean(accountConfig.accountType) &&
16
- accountConfig.accountType === accountType);
16
+ return Boolean(accountConfig.accountType && accountType.includes(accountConfig.accountType));
17
17
  }
18
18
  function isStandardAccount(accountConfig) {
19
- return isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD);
19
+ return isAccountType(accountConfig, [config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD]);
20
20
  }
21
21
  function isSandbox(accountConfig) {
22
- return (isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX) ||
23
- isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX));
22
+ return isAccountType(accountConfig, [
23
+ config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
24
+ config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
25
+ ]);
24
26
  }
25
27
  function isStandardSandbox(accountConfig) {
26
- return isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX);
28
+ return isAccountType(accountConfig, [config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX]);
27
29
  }
28
30
  function isDevelopmentSandbox(accountConfig) {
29
- return isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX);
31
+ return isAccountType(accountConfig, [
32
+ config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
33
+ ]);
30
34
  }
31
35
  function isDeveloperTestAccount(accountConfig) {
32
- return isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST);
36
+ return isAccountType(accountConfig, [config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST]);
33
37
  }
34
38
  function isAppDeveloperAccount(accountConfig) {
35
- return isAccountType(accountConfig, config_1.HUBSPOT_ACCOUNT_TYPES.APP_DEVELOPER);
39
+ return isAccountType(accountConfig, [config_1.HUBSPOT_ACCOUNT_TYPES.APP_DEVELOPER]);
40
+ }
41
+ function isTestAccountOrSandbox(accountConfig) {
42
+ return isAccountType(accountConfig, [
43
+ config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
44
+ config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
45
+ config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
46
+ ]);
36
47
  }
37
48
  async function isUnifiedAccount(account) {
38
49
  const accountId = (0, getAccountIdentifier_1.getAccountIdentifier)(account);
@@ -236,9 +236,21 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
236
236
  if (Object.values(componentsRequiringUids).length !== 0) {
237
237
  for (const [componentId, component] of Object.entries(componentsRequiringUids)) {
238
238
  const { componentHint, componentType } = component;
239
- uidMap[componentId] = await (0, promptUtils_1.inputPrompt)(en_1.lib.migrate.prompt.uidForComponent(componentHint
240
- ? `${(0, transform_1.mapToUserFacingType)(componentType)} '${componentHint}'`
241
- : (0, transform_1.mapToUserFacingType)(componentType)), {
239
+ // Extract the internal ID from the base64-encoded ComponentExternalId
240
+ let internalId;
241
+ try {
242
+ const decoded = Buffer.from(componentId, 'base64').toString('utf8');
243
+ const parts = decoded.split('$$');
244
+ internalId = parts[1] || componentId;
245
+ }
246
+ catch {
247
+ // If decoding fails, use the componentId as the internalId
248
+ internalId = componentId;
249
+ }
250
+ const promptText = componentHint
251
+ ? `${(0, transform_1.mapToUserFacingType)(componentType)} '${componentHint}' (ID: ${internalId})`
252
+ : `${(0, transform_1.mapToUserFacingType)(componentType)} (ID: ${internalId})`;
253
+ uidMap[componentId] = await (0, promptUtils_1.inputPrompt)(en_1.lib.migrate.prompt.uidForComponent(promptText), {
242
254
  validate: (uid) => {
243
255
  const result = (0, project_parsing_lib_1.validateUid)(uid);
244
256
  return result === undefined ? true : result;
@@ -18,7 +18,7 @@ const ui_1 = require("../ui");
18
18
  const lang_1 = require("../lang");
19
19
  const accountTypes_1 = require("../accountTypes");
20
20
  const selectPublicAppForMigrationPrompt_1 = require("../prompts/selectPublicAppForMigrationPrompt");
21
- const createProjectPrompt_1 = require("../prompts/createProjectPrompt");
21
+ const projectNameAndDestPrompt_1 = require("../prompts/projectNameAndDestPrompt");
22
22
  const ensureProjectExists_1 = require("../projects/ensureProjectExists");
23
23
  const usageTracking_1 = require("../usageTracking");
24
24
  const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
@@ -58,8 +58,7 @@ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
58
58
  (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
59
59
  return process.exit(exitCodes_1.EXIT_CODES.ERROR);
60
60
  }
61
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
62
- const { name: projectName, dest: projectDest } = createProjectPromptResponse;
61
+ const { name: projectName, dest: projectDest } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(options);
63
62
  const { projectExists } = await (0, ensureProjectExists_1.ensureProjectExists)(derivedAccountId, projectName, {
64
63
  allowCreate: false,
65
64
  noLogs: true,
package/lib/app/urls.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Environment } from '@hubspot/local-dev-lib/types/Config';
2
2
  type PrivateAppInstallUrlArgs = {
3
3
  targetAccountId: number;
4
4
  env: Environment;
5
- appId: string;
5
+ appId: number;
6
6
  };
7
7
  type PublicAppInstallUrlArgs = {
8
8
  targetAccountId: number;
@@ -11,10 +11,12 @@ export declare function addCmsPublishModeOptions(yargs: Argv, { read, write }: {
11
11
  }): Argv;
12
12
  export declare function addTestingOptions(yargs: Argv): Argv;
13
13
  export declare function addUseEnvironmentOptions(yargs: Argv): Argv;
14
+ export declare function addJSONOutputOptions(yargs: Argv): Argv;
14
15
  export declare function addCustomHelpOutput(yargs: Argv, command: string | string[], describe?: string): Promise<void>;
15
16
  export declare function setLogLevel(options: Arguments<{
16
17
  debug?: boolean;
17
18
  networkDebug?: boolean;
19
+ json?: boolean;
18
20
  }>): void;
19
21
  export declare function getCommandName(argv: Arguments): string;
20
22
  export declare function getCmsPublishMode(options: Arguments<{