@hubspot/cli 7.7.20-experimental.0 → 7.7.21-experimental.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 (62) hide show
  1. package/bin/cli.js +6 -2
  2. package/commands/__tests__/getStarted.test.js +0 -10
  3. package/commands/app/__tests__/install.test.d.ts +1 -0
  4. package/commands/app/__tests__/install.test.js +52 -0
  5. package/commands/app/install.d.ts +8 -0
  6. package/commands/app/install.js +127 -0
  7. package/commands/app.js +6 -1
  8. package/commands/getStarted.js +12 -27
  9. package/commands/mcp/setup.js +1 -0
  10. package/commands/mcp/start.d.ts +4 -1
  11. package/commands/mcp/start.js +8 -3
  12. package/commands/project/__tests__/deploy.test.js +27 -25
  13. package/commands/project/__tests__/devUnifiedFlow.test.js +20 -16
  14. package/commands/project/create.js +1 -1
  15. package/commands/project/deploy.d.ts +3 -2
  16. package/commands/project/deploy.js +61 -55
  17. package/commands/project/dev/unifiedFlow.js +7 -6
  18. package/commands/testAccount/__tests__/createConfig.test.js +0 -3
  19. package/commands/testAccount/create.js +14 -24
  20. package/commands/testAccount/createConfig.d.ts +0 -2
  21. package/commands/testAccount/createConfig.js +7 -8
  22. package/lang/en.d.ts +61 -23
  23. package/lang/en.js +62 -24
  24. package/lang/en.lyaml +0 -26
  25. package/lib/__tests__/buildAccount.test.js +30 -2
  26. package/lib/__tests__/usageTracking.test.js +8 -14
  27. package/lib/buildAccount.d.ts +7 -1
  28. package/lib/buildAccount.js +54 -4
  29. package/lib/mcp/setup.js +8 -3
  30. package/lib/projects/add/legacyAddComponent.js +1 -1
  31. package/lib/projects/add/v3AddComponent.js +1 -1
  32. package/lib/projects/localDev/DevServerManager.js +0 -2
  33. package/lib/projects/localDev/DevServerManagerV2.js +0 -2
  34. package/lib/projects/localDev/helpers.d.ts +1 -1
  35. package/lib/projects/localDev/helpers.js +2 -2
  36. package/lib/projects/structure.d.ts +2 -2
  37. package/lib/projects/upload.d.ts +2 -1
  38. package/lib/projects/upload.js +2 -1
  39. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +11 -10
  40. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +73 -31
  41. package/lib/prompts/promptUtils.js +66 -56
  42. package/lib/ui/index.js +1 -1
  43. package/lib/usageTracking.d.ts +11 -0
  44. package/lib/usageTracking.js +67 -73
  45. package/mcp-server/tools/project/AddFeatureToProject.js +4 -1
  46. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  47. package/mcp-server/tools/project/CreateProjectTool.js +4 -1
  48. package/mcp-server/tools/project/DeployProject.js +4 -1
  49. package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -1
  50. package/mcp-server/tools/project/UploadProjectTools.js +4 -1
  51. package/mcp-server/tools/project/ValidateProjectTool.js +4 -1
  52. package/mcp-server/tools/project/__tests__/AddFeatureToProject.test.js +1 -0
  53. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -0
  54. package/mcp-server/tools/project/__tests__/DeployProject.test.js +1 -0
  55. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -0
  56. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -0
  57. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -0
  58. package/mcp-server/utils/__tests__/project.test.js +9 -6
  59. package/mcp-server/utils/project.js +3 -0
  60. package/mcp-server/utils/toolUsageTracking.d.ts +1 -0
  61. package/mcp-server/utils/toolUsageTracking.js +25 -0
  62. package/package.json +4 -4
package/lang/en.js CHANGED
@@ -50,7 +50,6 @@ exports.commands = {
50
50
  app: 'App',
51
51
  cms: 'CMS',
52
52
  },
53
- installDependencies: 'Would you like to install dependencies now?',
54
53
  uploadProject: 'Would you like to upload your project to HubSpot now?',
55
54
  projectCreated: {
56
55
  title: chalk_1.default.bold('Next steps:'),
@@ -60,7 +59,6 @@ exports.commands = {
60
59
  logs: {
61
60
  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
61
  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
62
  uploadingProject: 'Uploading your project to HubSpot...',
65
63
  uploadSuccess: 'Project uploaded successfully!',
66
64
  developerOverviewLink: 'Open this link to navigate to your HubSpot developer portal',
@@ -1141,19 +1139,19 @@ exports.commands = {
1141
1139
  describe: 'Which features to include with the application.',
1142
1140
  },
1143
1141
  },
1144
- creatingComponent: (projectName) => `\nAdding a new component to ${chalk_1.default.bold(projectName)}\n`,
1142
+ creatingComponent: (projectName) => `\nAdding a new app feature to ${chalk_1.default.bold(projectName)}\n`,
1145
1143
  success: (componentName, multiple = false) => `${componentName || 'An app'} ${multiple ? 'were' : 'was'} successfully added to your ${componentName ? 'app' : 'project'}.`,
1146
1144
  error: {
1147
- failedToDownloadComponent: 'Failed to download project component. Please try again later.',
1145
+ failedToDownloadComponent: 'Failed to download project. Please try again later.',
1148
1146
  maxExceeded: (maxCount) => `This project has the maximum allowed(${maxCount})`,
1149
1147
  authTypeNotAllowed: (authType) => `Auth type '${authType}' not allowed.`,
1150
1148
  distributionNotAllowed: (dist) => `Distribution '${dist}' not allowed.`,
1151
1149
  locationInProject: 'This command must be run from within a project directory.',
1152
- failedToFetchComponentList: 'Failed to fetch the list of available components. Please try again later.',
1150
+ failedToFetchComponentList: 'Failed to fetch the list of available features. Please try again later.',
1153
1151
  projectContainsPublicApp: 'This project contains a public app. This command is currently only compatible with projects that contain private apps.',
1154
1152
  },
1155
1153
  examples: {
1156
- default: 'Create a component within your project',
1154
+ default: 'Create an app feature within your project',
1157
1155
  withFlags: 'Use --name and --type flags to bypass the prompt.',
1158
1156
  },
1159
1157
  },
@@ -1164,25 +1162,24 @@ exports.commands = {
1164
1162
  deploying: (path) => `Deploying project at path: ${path}`,
1165
1163
  },
1166
1164
  errors: {
1167
- deploy: (details) => `Deploy error: ${details}`,
1165
+ deploy: 'Deploy error: an unknown error occurred.',
1168
1166
  noBuilds: 'Deploy error: no builds for this project were found.',
1169
1167
  noBuildId: 'You must specify a build to deploy',
1170
- projectNotFound: (projectName, accountIdentifier, command) => `The project ${chalk_1.default.bold(projectName)} does not exist in account ${accountIdentifier}. Run ${command} to upload your project files to HubSpot.`,
1171
- buildIdDoesNotExist: (buildId, projectName, linkToProject) => `Build ${buildId} does not exist for project ${chalk_1.default.bold(projectName)}. ${linkToProject}`,
1172
- buildAlreadyDeployed: (buildId, linkToProject) => `Build ${buildId} is already deployed. ${linkToProject}`,
1173
- viewProjectsBuilds: 'View project builds in HubSpot',
1168
+ projectNotFound: (accountId, projectName) => `The project ${chalk_1.default.bold(projectName)} does not exist in account ${(0, ui_1.uiAccountDescription)(accountId)}. Run ${(0, ui_1.uiCommandReference)('hs project upload')} to upload your project files to HubSpot.`,
1169
+ buildIdDoesNotExist: (accountId, buildId, projectName) => `Build ${buildId} does not exist for project ${chalk_1.default.bold(projectName)}. ${(0, ui_1.uiLink)('View project builds in HubSpot', (0, urls_1.getProjectDetailUrl)(projectName, accountId))}`,
1170
+ buildAlreadyDeployed: (accountId, buildId, projectName) => `Build ${buildId} is already deployed. ${(0, ui_1.uiLink)('View project builds in HubSpot', (0, urls_1.getProjectDetailUrl)(projectName, accountId))}`,
1171
+ deployContainsRemovals: (componentName) => `- This deploy would remove the ${chalk_1.default.bold(componentName)} component. To proceed, run the deploy command with the ${(0, ui_1.uiCommandReference)('--force')} flag`,
1174
1172
  },
1175
1173
  examples: {
1176
1174
  default: 'Deploy the latest build of the current project',
1177
1175
  withOptions: 'Deploy build 5 of the project my-project',
1178
1176
  },
1179
1177
  options: {
1180
- build: {
1181
- describe: 'Project build ID to be deployed',
1182
- },
1183
- project: {
1184
- describe: 'Project name',
1185
- },
1178
+ build: 'Project build ID to be deployed',
1179
+ project: 'Project name',
1180
+ profile: 'The profile to target with this deploy',
1181
+ force: 'Skip warnings and force deploy. Use this carefully as it will bypass warnings for destructive actions.',
1182
+ deployLatestBuild: 'Deploy the latest build of the current project',
1186
1183
  },
1187
1184
  },
1188
1185
  listBuilds: {
@@ -1501,6 +1498,28 @@ exports.commands = {
1501
1498
  app: {
1502
1499
  describe: 'Commands for managing apps.',
1503
1500
  subcommands: {
1501
+ install: {
1502
+ describe: 'Install an OAuth app into a test account.',
1503
+ options: {
1504
+ appUid: 'The uid of the app to install',
1505
+ projectName: 'The name of the project that contains the app',
1506
+ },
1507
+ positionals: {
1508
+ testAccountId: 'The id of the test account to install the app into',
1509
+ },
1510
+ errors: {
1511
+ 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.`,
1512
+ 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.`,
1513
+ appMustBeOauth: 'This command only supports installing oauth apps. Please specify an app with oauth auth type.',
1514
+ },
1515
+ polling: {
1516
+ start: 'Installing app...',
1517
+ success: 'App installed successfully',
1518
+ failure: 'App installation failed',
1519
+ error: 'Error installing app',
1520
+ },
1521
+ example: 'Install the app with uid my-app-uid from the project named "my-project" into the target account with id 1234567890',
1522
+ },
1504
1523
  secret: {
1505
1524
  describe: 'Commands for managing secrets.',
1506
1525
  subcommands: {
@@ -1810,7 +1829,7 @@ exports.commands = {
1810
1829
  start: (testAccountName) => `Creating test account "${chalk_1.default.bold(testAccountName)}"...`,
1811
1830
  syncing: 'Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)',
1812
1831
  success: (testAccountName, testAccountId) => `Test account "${chalk_1.default.bold(testAccountName)}" successfully created with id: ${chalk_1.default.bold(testAccountId)}`,
1813
- failure: 'Failed to sync data into test account. The account may not be ready to use.',
1832
+ createFailure: 'Failed to create test account.',
1814
1833
  },
1815
1834
  options: {
1816
1835
  configPath: 'The path to the test account config',
@@ -1819,7 +1838,7 @@ exports.commands = {
1819
1838
  },
1820
1839
  createConfig: {
1821
1840
  describe: 'Create a test account config file.',
1822
- pathPrompt: '[--path] What is the path to the test account config?',
1841
+ pathPrompt: '[--path] Enter the name of the Test Account config file: ',
1823
1842
  errors: {
1824
1843
  pathError: 'Path is required',
1825
1844
  pathFormatError: 'Path must end with .json',
@@ -1832,7 +1851,6 @@ exports.commands = {
1832
1851
  options: {
1833
1852
  name: 'The name of the test account',
1834
1853
  description: 'The description of the test account',
1835
- tiers: 'The tiers of the test account',
1836
1854
  path: 'The path to the test account config',
1837
1855
  },
1838
1856
  example: (name) => `Create a test account config file with the name "${name}"`,
@@ -2759,6 +2777,12 @@ exports.lib = {
2759
2777
  noLogsFound: 'No logs found.',
2760
2778
  },
2761
2779
  },
2780
+ buildAccount: {
2781
+ createDeveloperTestAccountV3: {
2782
+ syncFailure: 'Failed to sync developer test account',
2783
+ pakFailure: 'Failed to generate personal access key for developer test account',
2784
+ },
2785
+ },
2762
2786
  configOptions: {
2763
2787
  enableOrDisableBooleanFieldPrompt: {
2764
2788
  message: (fieldName) => `Choose to enable or disable ${fieldName}`,
@@ -2841,11 +2865,25 @@ exports.lib = {
2841
2865
  keepingCurrentDefault: (accountName) => `Account "${accountName}" will continue to be the default account`,
2842
2866
  },
2843
2867
  createDeveloperTestAccountConfigPrompt: {
2844
- namePrompt: '[--name] What is the name of the test account?',
2845
- descriptionPrompt: '[--description] What is the description of the test account?',
2846
- tiersPrompt: '[--tiers] Which product tiers should the test account have?',
2868
+ namePrompt: (withFlag = true) => `${withFlag ? '[--name] ' : ''}Enter the name of the Test Account:`,
2869
+ descriptionPrompt: (withFlag = true) => `${withFlag ? '[--description] ' : ''}Enter the description of the Test Account:`,
2870
+ useDefaultAccountLevelsPrompt: {
2871
+ message: 'Would you like to create a default Test Account, or customize your own?',
2872
+ default: 'Default (All Hubs, ENTERPRISE)',
2873
+ manual: 'Customize my own',
2874
+ },
2875
+ tiersPrompt: 'Select an option per hub to customize tiers. If left blank, default is ENTERPRISE',
2876
+ hubTypes: {
2877
+ marketing: 'Marketing',
2878
+ ops: 'Ops',
2879
+ service: 'Service',
2880
+ sales: 'Sales',
2881
+ content: 'Content',
2882
+ },
2847
2883
  errors: {
2884
+ allHubsRequired: 'Select a tier for each hub',
2848
2885
  tiersError: 'Cannot have more than one tier per hub',
2886
+ nameRequired: 'The name may not be blank. Please add a name for the Test Account.',
2849
2887
  },
2850
2888
  },
2851
2889
  accountNamePrompt: {
@@ -2968,7 +3006,7 @@ exports.lib = {
2968
3006
  },
2969
3007
  },
2970
3008
  projectAddPrompt: {
2971
- selectType: '[--type] Select a component to add: ',
3009
+ selectType: '[--type] Select an app feature to add: ',
2972
3010
  enterName: '[--name] Give your component a name: ',
2973
3011
  errors: {
2974
3012
  nameRequired: 'A component name is required',
package/lang/en.lyaml CHANGED
@@ -681,32 +681,6 @@ en:
681
681
  examples:
682
682
  default: "Create a component within your project"
683
683
  withFlags: "Use --name and --type flags to bypass the prompt."
684
- deploy:
685
- describe: "Deploy a project build."
686
- deployBuildIdPrompt: "[--build] Deploy which build?"
687
- debug:
688
- deploying: "Deploying project at path: {{ path }}"
689
- errors:
690
- deploy: "Deploy error: an unknown error occurred."
691
- noBuilds: "Deploy error: no builds for this project were found."
692
- noBuildId: "You must specify a build to deploy"
693
- projectNotFound: "The project {{ projectName }} does not exist in account {{ accountIdentifier }}. Run {{ command }} to upload your project files to HubSpot."
694
- buildIdDoesNotExist: "Build {{ buildId }} does not exist for project {{ projectName }}. {{ linkToProject }}"
695
- buildAlreadyDeployed: "Build {{ buildId }} is already deployed. {{ linkToProject}}"
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"
698
- examples:
699
- default: "Deploy the latest build of the current project"
700
- withOptions: "Deploy build 5 of the project my-project"
701
- options:
702
- build:
703
- describe: "Project build ID to be deployed"
704
- project:
705
- describe: "Project name"
706
- profile:
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."
710
684
  listBuilds:
711
685
  describe: "List the project's builds."
712
686
  continueOrExitPrompt: "Press <enter> to load more, or ctrl+c to exit"
@@ -65,6 +65,8 @@ const mockedWriteConfig = config_1.writeConfig;
65
65
  const mockedCliAccountNamePrompt = accountNamePrompt_1.cliAccountNamePrompt;
66
66
  const mockedGetAccountId = config_1.getAccountId;
67
67
  const mockedCreateDeveloperTestAccount = developerTestAccounts_1.createDeveloperTestAccount;
68
+ const mockedFetchDeveloperTestAccountGateSyncStatus = developerTestAccounts_1.fetchDeveloperTestAccountGateSyncStatus;
69
+ const mockedGenerateDeveloperTestAccountPersonalAccessKey = developerTestAccounts_1.generateDeveloperTestAccountPersonalAccessKey;
68
70
  const mockedCreateSandbox = sandboxHubs_1.createSandbox;
69
71
  describe('lib/buildAccount', () => {
70
72
  describe('saveAccountToConfig()', () => {
@@ -132,11 +134,37 @@ describe('lib/buildAccount', () => {
132
134
  expect(result).toBe('test-account-with-new-name');
133
135
  });
134
136
  });
137
+ describe('createDeveloperTestAccountV3()', () => {
138
+ const parentAccountId = 123456;
139
+ const mockDeveoperTestAccountConfig = {
140
+ accountName: 'Developer Test Account',
141
+ description: 'Test Account created by the HubSpot CLI',
142
+ };
143
+ beforeEach(() => {
144
+ mockedCreateDeveloperTestAccount.mockResolvedValue({
145
+ data: { id: 123456 },
146
+ });
147
+ mockedFetchDeveloperTestAccountGateSyncStatus.mockResolvedValue({
148
+ data: { status: 'SUCCESS' },
149
+ });
150
+ mockedGenerateDeveloperTestAccountPersonalAccessKey.mockResolvedValue({
151
+ data: { personalAccessKey: 'test-key' },
152
+ });
153
+ });
154
+ it('should create a developer test account successfully', async () => {
155
+ const result = await buildAccount.createDeveloperTestAccountV3(parentAccountId, mockDeveoperTestAccountConfig);
156
+ expect(result).toEqual({
157
+ accountName: mockDeveoperTestAccountConfig.accountName,
158
+ accountId: 123456,
159
+ personalAccessKey: 'test-key',
160
+ });
161
+ }, 10000);
162
+ });
135
163
  describe('buildDeveloperTestAccount()', () => {
136
164
  const mockParentAccountConfig = {
137
- name: 'Developer Test Account',
165
+ name: 'Developer Account',
138
166
  accountId: 123456,
139
- accountType: config_2.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
167
+ accountType: config_2.HUBSPOT_ACCOUNT_TYPES.APP_DEVELOPER,
140
168
  env: 'prod',
141
169
  };
142
170
  const mockDeveloperTestAccount = {
@@ -31,8 +31,6 @@ describe('lib/usageTracking', () => {
31
31
  });
32
32
  it('should track command usage with default auth type', async () => {
33
33
  await (0, usageTracking_1.trackCommandUsage)(mockCommand, {}, mockAccountId);
34
- // Allow setImmediate to execute
35
- await new Promise(resolve => setImmediate(resolve));
36
34
  expect(mockedTrackUsage).toHaveBeenCalledWith('cli-interaction', 'INTERACTION', expect.objectContaining({
37
35
  action: 'cli-command',
38
36
  command: mockCommand,
@@ -46,18 +44,16 @@ describe('lib/usageTracking', () => {
46
44
  it('should track command usage with custom auth type', async () => {
47
45
  mockedGetAccountConfig.mockReturnValue({ authType: 'oauth2' });
48
46
  await (0, usageTracking_1.trackCommandUsage)(mockCommand, {}, mockAccountId);
49
- // Allow setImmediate to execute
50
- await new Promise(resolve => setImmediate(resolve));
51
47
  expect(mockedTrackUsage).toHaveBeenCalledWith('cli-interaction', 'INTERACTION', expect.objectContaining({
52
48
  authType: 'oauth2',
53
49
  }), mockAccountId);
54
50
  });
55
51
  it('should handle tracking errors gracefully', async () => {
56
52
  const error = new Error('Tracking failed');
57
- mockedTrackUsage.mockRejectedValue(error);
53
+ mockedTrackUsage.mockImplementationOnce(() => {
54
+ throw error;
55
+ });
58
56
  await (0, usageTracking_1.trackCommandUsage)(mockCommand);
59
- // Allow setImmediate to execute
60
- await new Promise(resolve => setImmediate(resolve));
61
57
  expect(mockedLogger.debug).toHaveBeenCalledWith(expect.stringContaining(error.message));
62
58
  });
63
59
  });
@@ -77,7 +73,7 @@ describe('lib/usageTracking', () => {
77
73
  nodeVersion: mockNodeVersion,
78
74
  nodeMajorVersion: 'v16',
79
75
  version: package_json_1.version,
80
- }));
76
+ }), undefined);
81
77
  });
82
78
  it('should track main help usage without command', async () => {
83
79
  await (0, usageTracking_1.trackHelpUsage)('');
@@ -100,7 +96,7 @@ describe('lib/usageTracking', () => {
100
96
  nodeVersion: mockNodeVersion,
101
97
  nodeMajorVersion: 'v16',
102
98
  version: package_json_1.version,
103
- }));
99
+ }), undefined);
104
100
  });
105
101
  });
106
102
  describe('trackAuthAction()', () => {
@@ -138,8 +134,6 @@ describe('lib/usageTracking', () => {
138
134
  });
139
135
  it('should track command metadata usage', async () => {
140
136
  await (0, usageTracking_1.trackCommandMetadataUsage)(mockCommand, mockMeta, mockAccountId);
141
- // Allow setImmediate to execute
142
- await new Promise(resolve => setImmediate(resolve));
143
137
  expect(mockedTrackUsage).toHaveBeenCalledWith('cli-interaction', 'INTERACTION', expect.objectContaining({
144
138
  action: 'cli-command-metadata',
145
139
  command: mockCommand,
@@ -155,17 +149,17 @@ describe('lib/usageTracking', () => {
155
149
  it('should return "macos" for darwin platform', async () => {
156
150
  Object.defineProperty(process, 'platform', { value: 'darwin' });
157
151
  await (0, usageTracking_1.trackHelpUsage)('test');
158
- expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'macos' }));
152
+ expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'macos' }), undefined);
159
153
  });
160
154
  it('should return "windows" for win32 platform', async () => {
161
155
  Object.defineProperty(process, 'platform', { value: 'win32' });
162
156
  await (0, usageTracking_1.trackHelpUsage)('test');
163
- expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'windows' }));
157
+ expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'windows' }), undefined);
164
158
  });
165
159
  it('should return platform name for other platforms', async () => {
166
160
  Object.defineProperty(process, 'platform', { value: 'linux' });
167
161
  await (0, usageTracking_1.trackHelpUsage)('test');
168
- expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'linux' }));
162
+ expect(mockedTrackUsage).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({ os: 'linux' }), undefined);
169
163
  });
170
164
  });
171
165
  });
@@ -1,9 +1,15 @@
1
+ import { DeveloperTestAccountConfig } from '@hubspot/local-dev-lib/types/developerTestAccounts';
1
2
  import { Environment } from '@hubspot/local-dev-lib/types/Config';
2
3
  import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
3
4
  import { SandboxResponse } from '@hubspot/local-dev-lib/types/Sandbox';
4
5
  import { SandboxAccountType } from '../types/Sandboxes';
5
6
  export declare function saveAccountToConfig(accountId: number | undefined, accountName: string, env: Environment, personalAccessKey?: string, force?: boolean): Promise<string>;
6
- export declare function buildDeveloperTestAccount(testAccountName: string, parentAccountConfig: CLIAccount, env: Environment, portalLimit: number): Promise<number>;
7
+ export declare function createDeveloperTestAccountV3(parentAccountId: number, testAccountConfig: DeveloperTestAccountConfig): Promise<{
8
+ accountName: string;
9
+ accountId?: number;
10
+ personalAccessKey?: string;
11
+ }>;
12
+ export declare function buildDeveloperTestAccount(testAccountName: string, parentAccountConfig: CLIAccount, env: Environment, portalLimit: number, useV3?: boolean): Promise<number>;
7
13
  type SandboxAccount = SandboxResponse & {
8
14
  name: string;
9
15
  };
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.saveAccountToConfig = saveAccountToConfig;
7
+ exports.createDeveloperTestAccountV3 = createDeveloperTestAccountV3;
7
8
  exports.buildDeveloperTestAccount = buildDeveloperTestAccount;
8
9
  exports.buildSandbox = buildSandbox;
9
10
  const personalAccessKey_1 = require("@hubspot/local-dev-lib/personalAccessKey");
@@ -14,12 +15,15 @@ const developerTestAccounts_1 = require("@hubspot/local-dev-lib/api/developerTes
14
15
  const config_2 = require("@hubspot/local-dev-lib/constants/config");
15
16
  const sandboxHubs_1 = require("@hubspot/local-dev-lib/api/sandboxHubs");
16
17
  const personalAccessKeyPrompt_1 = require("./prompts/personalAccessKeyPrompt");
18
+ const createDeveloperTestAccountConfigPrompt_1 = require("./prompts/createDeveloperTestAccountConfigPrompt");
17
19
  const lang_1 = require("./lang");
18
20
  const accountNamePrompt_1 = require("./prompts/accountNamePrompt");
19
21
  const SpinniesManager_1 = __importDefault(require("./ui/SpinniesManager"));
20
22
  const index_1 = require("./errorHandlers/index");
21
23
  const sandboxes_1 = require("./sandboxes");
22
24
  const developerTestAccounts_2 = require("./developerTestAccounts");
25
+ const en_1 = require("../lang/en");
26
+ const polling_1 = require("./polling");
23
27
  async function saveAccountToConfig(accountId, accountName, env, personalAccessKey, force = false) {
24
28
  if (!personalAccessKey) {
25
29
  const configData = await (0, personalAccessKeyPrompt_1.personalAccessKeyPrompt)({
@@ -60,12 +64,51 @@ async function saveAccountToConfig(accountId, accountName, env, personalAccessKe
60
64
  logger_1.logger.log('');
61
65
  return validName;
62
66
  }
63
- async function buildDeveloperTestAccount(testAccountName, parentAccountConfig, env, portalLimit) {
67
+ async function createDeveloperTestAccountV3(parentAccountId, testAccountConfig) {
68
+ const result = {
69
+ accountName: testAccountConfig.accountName,
70
+ };
71
+ const { data } = await (0, developerTestAccounts_1.createDeveloperTestAccount)(parentAccountId, testAccountConfig);
72
+ result.accountId = data.id;
73
+ try {
74
+ await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountGateSyncStatus)(parentAccountId, result.accountId), {
75
+ successStates: ['SUCCESS'],
76
+ errorStates: [],
77
+ });
78
+ }
79
+ catch (err) {
80
+ (0, index_1.debugError)(err);
81
+ throw new Error(en_1.lib.buildAccount.createDeveloperTestAccountV3.syncFailure);
82
+ }
83
+ // HACK: The status endpoint sometimes returns an early success status.
84
+ // Sleep for an extra 5 seconds to make sure the sync is actually complete.
85
+ await new Promise(resolve => setTimeout(resolve, 5000));
86
+ try {
87
+ // Attempt to generate a new personal access key for the test account now that gate sync is complete.
88
+ const { data } = await (0, developerTestAccounts_1.generateDeveloperTestAccountPersonalAccessKey)(parentAccountId, result.accountId);
89
+ result.personalAccessKey = data.personalAccessKey;
90
+ }
91
+ catch (err) {
92
+ (0, index_1.debugError)(err);
93
+ throw new Error(en_1.lib.buildAccount.createDeveloperTestAccountV3.pakFailure);
94
+ }
95
+ return result;
96
+ }
97
+ async function buildDeveloperTestAccount(testAccountName, parentAccountConfig, env, portalLimit, useV3 = false) {
64
98
  const id = (0, getAccountIdentifier_1.getAccountIdentifier)(parentAccountConfig);
65
99
  const parentAccountId = (0, config_1.getAccountId)(id);
100
+ let testAccountConfig = {
101
+ accountName: testAccountName,
102
+ };
66
103
  if (!parentAccountId) {
67
104
  throw new Error((0, lang_1.i18n)(`lib.developerTestAccount.create.loading.fail`));
68
105
  }
106
+ if (useV3) {
107
+ testAccountConfig = await (0, createDeveloperTestAccountConfigPrompt_1.createDeveloperTestAccountConfigPrompt)({
108
+ name: testAccountConfig.accountName,
109
+ description: 'Test Account created by the HubSpot CLI',
110
+ }, false);
111
+ }
69
112
  SpinniesManager_1.default.init({
70
113
  succeedColor: 'white',
71
114
  });
@@ -78,9 +121,16 @@ async function buildDeveloperTestAccount(testAccountName, parentAccountConfig, e
78
121
  let developerTestAccountId;
79
122
  let developerTestAccountPersonalAccessKey;
80
123
  try {
81
- const { data } = await (0, developerTestAccounts_1.createDeveloperTestAccount)(parentAccountId, testAccountName);
82
- developerTestAccountId = data.id;
83
- developerTestAccountPersonalAccessKey = data.personalAccessKey;
124
+ if (useV3) {
125
+ const result = await createDeveloperTestAccountV3(parentAccountId, testAccountConfig);
126
+ developerTestAccountId = result.accountId;
127
+ developerTestAccountPersonalAccessKey = result.personalAccessKey;
128
+ }
129
+ else {
130
+ const { data } = await (0, developerTestAccounts_1.createDeveloperTestAccount)(parentAccountId, testAccountName);
131
+ developerTestAccountId = data.id;
132
+ developerTestAccountPersonalAccessKey = data.personalAccessKey;
133
+ }
84
134
  SpinniesManager_1.default.succeed('buildDeveloperTestAccount', {
85
135
  text: (0, lang_1.i18n)(`lib.developerTestAccount.create.loading.succeed`, {
86
136
  accountName: testAccountName,
package/lib/mcp/setup.js CHANGED
@@ -173,7 +173,7 @@ async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
173
173
  // Run claude mcp add command
174
174
  const mcpConfig = JSON.stringify({
175
175
  type: 'stdio',
176
- ...mcpCommand,
176
+ ...buildCommandWithAgentString(mcpCommand, claudeCode),
177
177
  });
178
178
  const { stdout } = await (0, command_1.execAsync)('claude mcp list');
179
179
  if (stdout.includes(mcpServerName)) {
@@ -219,7 +219,7 @@ function setupCursor(mcpCommand = defaultMcpCommand) {
219
219
  configuringMessage: en_1.commands.mcp.setup.spinners.configuringCursor,
220
220
  configuredMessage: en_1.commands.mcp.setup.spinners.configuredCursor,
221
221
  failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureCursor,
222
- mcpCommand,
222
+ mcpCommand: buildCommandWithAgentString(mcpCommand, cursor),
223
223
  });
224
224
  }
225
225
  function setupWindsurf(mcpCommand = defaultMcpCommand) {
@@ -229,6 +229,11 @@ function setupWindsurf(mcpCommand = defaultMcpCommand) {
229
229
  configuringMessage: en_1.commands.mcp.setup.spinners.configuringWindsurf,
230
230
  configuredMessage: en_1.commands.mcp.setup.spinners.configuredWindsurf,
231
231
  failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureWindsurf,
232
- mcpCommand,
232
+ mcpCommand: buildCommandWithAgentString(mcpCommand, windsurf),
233
233
  });
234
234
  }
235
+ function buildCommandWithAgentString(mcpCommand, agent) {
236
+ const mcpCommandCopy = structuredClone(mcpCommand);
237
+ mcpCommandCopy.args.push('--ai-agent', agent);
238
+ return mcpCommandCopy;
239
+ }
@@ -37,7 +37,7 @@ async function legacyAddComponent(args, projectDir, projectConfig) {
37
37
  const componentPath = path_1.default.join(projectDir, projectConfig.srcDir, projectAddPromptResponse.name);
38
38
  await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, componentPath, {
39
39
  sourceDir: projectAddPromptResponse.componentTemplate.path,
40
- branch: 'main',
40
+ branch: constants_1.DEFAULT_PROJECT_TEMPLATE_BRANCH,
41
41
  hideLogs: true,
42
42
  });
43
43
  logger_1.uiLogger.success(en_1.commands.project.add.success(projectAddPromptResponse.name));
@@ -73,7 +73,7 @@ async function v3AddComponent(args, projectDir, projectConfig) {
73
73
  await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDir, {
74
74
  sourceDir: components,
75
75
  hideLogs: true,
76
- branch: 'main',
76
+ branch: constants_1.DEFAULT_PROJECT_TEMPLATE_BRANCH,
77
77
  handleCollision: components_1.handleComponentCollision,
78
78
  });
79
79
  logger_1.uiLogger.success(en_1.commands.project.add.success(projectAddPromptResponse.componentTemplate
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const logger_1 = require("@hubspot/local-dev-lib/logger");
4
- const promptUtils_1 = require("../../prompts/promptUtils");
5
4
  const ui_extensions_dev_server_1 = require("@hubspot/ui-extensions-dev-server");
6
5
  const portManager_1 = require("@hubspot/local-dev-lib/portManager");
7
6
  const urls_1 = require("@hubspot/local-dev-lib/urls");
@@ -71,7 +70,6 @@ class DevServerManager {
71
70
  await serverInterface.setup({
72
71
  components: compatibleComponents,
73
72
  onUploadRequired,
74
- promptUser: promptUtils_1.promptUser,
75
73
  logger: logger_1.logger,
76
74
  urls: {
77
75
  api: (0, urls_1.getHubSpotApiOrigin)(env),
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const logger_1 = require("@hubspot/local-dev-lib/logger");
7
- const promptUtils_1 = require("../../prompts/promptUtils");
8
7
  const portManager_1 = require("@hubspot/local-dev-lib/portManager");
9
8
  const urls_1 = require("@hubspot/local-dev-lib/urls");
10
9
  const config_1 = require("@hubspot/local-dev-lib/config");
@@ -40,7 +39,6 @@ class DevServerManagerV2 {
40
39
  // @TODO: In the future, update UIE Dev Server to use LocalDevState
41
40
  await serverInterface.setup({
42
41
  components: this.localDevState.projectNodes,
43
- promptUser: promptUtils_1.promptUser,
44
42
  logger: logger_1.logger,
45
43
  urls: {
46
44
  api: (0, urls_1.getHubSpotApiOrigin)(env),
@@ -11,7 +11,7 @@ export declare function checkIfParentAccountIsAuthed(accountConfig: CLIAccount):
11
11
  export declare function checkIfAccountFlagIsSupported(accountConfig: CLIAccount, hasPublicApps: boolean): void;
12
12
  export declare function suggestRecommendedNestedAccount(accounts: CLIAccount[], accountConfig: CLIAccount, hasPublicApps: boolean): Promise<ProjectDevTargetAccountPromptResponse>;
13
13
  export declare function createSandboxForLocalDev(accountId: number, accountConfig: CLIAccount, env: Environment): Promise<number>;
14
- export declare function createDeveloperTestAccountForLocalDev(accountId: number, accountConfig: CLIAccount, env: Environment): Promise<number>;
14
+ export declare function createDeveloperTestAccountForLocalDev(accountId: number, accountConfig: CLIAccount, env: Environment, useV3?: boolean): Promise<number>;
15
15
  export declare function useExistingDevTestAccount(env: Environment, account: DeveloperTestAccount): Promise<void>;
16
16
  export declare function createNewProjectForLocalDev(projectConfig: ProjectConfig, targetAccountId: number, shouldCreateWithoutConfirmation: boolean, hasPublicApps: boolean): Promise<Project>;
17
17
  export declare function createInitialBuildForNewProject(projectConfig: ProjectConfig, projectDir: string, targetAccountId: number, sendIR?: boolean, profile?: string): Promise<Build>;
@@ -152,7 +152,7 @@ async function createSandboxForLocalDev(accountId, accountConfig, env) {
152
152
  }
153
153
  }
154
154
  // Create a developer test account and return its accountId
155
- async function createDeveloperTestAccountForLocalDev(accountId, accountConfig, env) {
155
+ async function createDeveloperTestAccountForLocalDev(accountId, accountConfig, env, useV3 = false) {
156
156
  let currentPortalCount = 0;
157
157
  let maxTestPortals = 10;
158
158
  try {
@@ -182,7 +182,7 @@ async function createDeveloperTestAccountForLocalDev(accountId, accountConfig, e
182
182
  accountType: config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
183
183
  });
184
184
  (0, usageTracking_1.trackCommandMetadataUsage)('developer-test-account-create', { step: 'project-dev' }, accountId);
185
- const result = await (0, buildAccount_1.buildDeveloperTestAccount)(name, accountConfig, env, maxTestPortals);
185
+ const result = await (0, buildAccount_1.buildDeveloperTestAccount)(name, accountConfig, env, maxTestPortals, useV3);
186
186
  return result;
187
187
  }
188
188
  catch (err) {
@@ -1,5 +1,5 @@
1
1
  import { ComponentTypes, Component, GenericComponentConfig, PublicAppComponentConfig, PrivateAppComponentConfig, AppCardComponentConfig } from '../../types/Projects';
2
- import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types';
2
+ import { IntermediateRepresentationNode, IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types';
3
3
  import { AppIRNode } from '../../types/ProjectComponents';
4
4
  export declare const CONFIG_FILES: {
5
5
  [k in ComponentTypes]: string;
@@ -15,4 +15,4 @@ export declare function getProjectComponentTypes(components: Array<Component>):
15
15
  export declare function getComponentUid(component?: Component | null): string | null;
16
16
  export declare function componentIsApp(component?: Component | null): component is Component<PublicAppComponentConfig | PrivateAppComponentConfig>;
17
17
  export declare function componentIsPublicApp(component?: Component | null): component is Component<PublicAppComponentConfig>;
18
- export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev): component is AppIRNode;
18
+ export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev | IntermediateRepresentationNode): component is AppIRNode;
@@ -1,4 +1,5 @@
1
1
  import { FileResult } from 'tmp';
2
+ import { IntermediateRepresentation } from '@hubspot/project-parsing-lib';
2
3
  import { ProjectConfig } from '../../types/Projects';
3
4
  type ProjectUploadCallbackFunction<T> = (accountId: number, projectConfig: ProjectConfig, tempFile: FileResult, buildId: number) => Promise<T>;
4
5
  type ProjectUploadResult<T> = {
@@ -20,5 +21,5 @@ type HandleProjectUploadArg<T> = {
20
21
  export declare function handleProjectUpload<T>({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage, forceCreate, isUploadCommand, sendIR, skipValidation, }: HandleProjectUploadArg<T>): Promise<ProjectUploadResult<T>>;
21
22
  export declare function validateSourceDirectory(srcDir: string, projectConfig: ProjectConfig): void;
22
23
  export declare function validateNoHSMetaMismatch(srcDir: string, projectConfig: ProjectConfig): Promise<void>;
23
- export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<unknown>;
24
+ export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<IntermediateRepresentation | undefined>;
24
25
  export {};
@@ -25,7 +25,7 @@ const buildAndDeploy_1 = require("./buildAndDeploy");
25
25
  const exitCodes_1 = require("../enums/exitCodes");
26
26
  async function uploadProjectFiles(accountId, projectName, filePath, uploadMessage, platformVersion, intermediateRepresentation) {
27
27
  SpinniesManager_1.default.init({});
28
- const accountIdentifier = (0, ui_1.uiAccountDescription)(accountId);
28
+ const accountIdentifier = (0, ui_1.uiAccountDescription)(accountId) || `${accountId}`;
29
29
  SpinniesManager_1.default.add('upload', {
30
30
  text: en_1.lib.projectUpload.uploadProjectFiles.add(projectName, accountIdentifier),
31
31
  succeedColor: 'white',
@@ -149,4 +149,5 @@ async function handleTranslate(projectDir, projectConfig, accountId, skipValidat
149
149
  (0, errorHandlers_1.logError)(e);
150
150
  }
151
151
  }
152
+ return undefined;
152
153
  }