@hubspot/cli 7.7.21-experimental.0 → 7.7.22-experimental.0

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 (75) hide show
  1. package/bin/cli.js +6 -2
  2. package/commands/__tests__/getStarted.test.js +0 -10
  3. package/commands/create/api-sample.d.ts +1 -1
  4. package/commands/create/app.d.ts +1 -1
  5. package/commands/create/function.d.ts +1 -1
  6. package/commands/create/index.d.ts +1 -1
  7. package/commands/create/module.d.ts +1 -1
  8. package/commands/create/react-app.d.ts +1 -1
  9. package/commands/create/template.d.ts +1 -1
  10. package/commands/create/vue-app.d.ts +1 -1
  11. package/commands/create/webpack-serverless.d.ts +1 -1
  12. package/commands/create/website-theme.d.ts +1 -1
  13. package/commands/create.d.ts +1 -1
  14. package/commands/getStarted.js +12 -27
  15. package/commands/mcp/setup.js +1 -0
  16. package/commands/mcp/start.d.ts +4 -1
  17. package/commands/mcp/start.js +8 -3
  18. package/commands/project/__tests__/deploy.test.js +28 -26
  19. package/commands/project/__tests__/devUnifiedFlow.test.js +19 -16
  20. package/commands/project/create.js +2 -2
  21. package/commands/project/deploy.d.ts +3 -2
  22. package/commands/project/deploy.js +63 -54
  23. package/commands/project/dev/unifiedFlow.js +7 -6
  24. package/commands/testAccount/__tests__/createConfig.test.js +0 -3
  25. package/commands/testAccount/create.js +12 -25
  26. package/commands/testAccount/createConfig.d.ts +0 -2
  27. package/commands/testAccount/createConfig.js +8 -9
  28. package/lang/en.d.ts +40 -23
  29. package/lang/en.js +41 -24
  30. package/lang/en.lyaml +0 -26
  31. package/lib/__tests__/buildAccount.test.js +31 -3
  32. package/lib/__tests__/usageTracking.test.js +8 -14
  33. package/lib/buildAccount.d.ts +8 -2
  34. package/lib/buildAccount.js +54 -5
  35. package/lib/mcp/setup.js +26 -5
  36. package/lib/projects/add/legacyAddComponent.js +2 -2
  37. package/lib/projects/add/v3AddComponent.js +2 -2
  38. package/lib/projects/localDev/DevServerManager.js +0 -2
  39. package/lib/projects/localDev/DevServerManagerV2.js +0 -2
  40. package/lib/projects/localDev/helpers.d.ts +1 -1
  41. package/lib/projects/localDev/helpers.js +2 -2
  42. package/lib/projects/upload.js +1 -1
  43. package/lib/prompts/createApiSamplePrompt.d.ts +1 -1
  44. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +11 -10
  45. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +73 -31
  46. package/lib/prompts/promptUtils.js +66 -56
  47. package/lib/prompts/sandboxesPrompt.d.ts +1 -1
  48. package/lib/sandboxSync.d.ts +1 -1
  49. package/lib/sandboxes.d.ts +1 -1
  50. package/lib/schema.js +5 -1
  51. package/lib/ui/index.js +1 -1
  52. package/lib/usageTracking.d.ts +11 -0
  53. package/lib/usageTracking.js +66 -75
  54. package/mcp-server/tools/project/AddFeatureToProject.js +4 -1
  55. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  56. package/mcp-server/tools/project/CreateProjectTool.js +4 -1
  57. package/mcp-server/tools/project/DeployProject.js +4 -1
  58. package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -1
  59. package/mcp-server/tools/project/UploadProjectTools.js +4 -1
  60. package/mcp-server/tools/project/ValidateProjectTool.js +4 -1
  61. package/mcp-server/tools/project/__tests__/AddFeatureToProject.test.js +1 -0
  62. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -0
  63. package/mcp-server/tools/project/__tests__/DeployProject.test.js +1 -0
  64. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -0
  65. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -0
  66. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -0
  67. package/mcp-server/utils/__tests__/project.test.js +9 -6
  68. package/mcp-server/utils/project.js +3 -0
  69. package/mcp-server/utils/toolUsageTracking.d.ts +1 -0
  70. package/mcp-server/utils/toolUsageTracking.js +22 -0
  71. package/package.json +4 -4
  72. /package/types/{cms.d.ts → Cms.d.ts} +0 -0
  73. /package/types/{cms.js → Cms.js} +0 -0
  74. /package/types/{sandboxes.d.ts → Sandboxes.d.ts} +0 -0
  75. /package/types/{sandboxes.js → Sandboxes.js} +0 -0
@@ -1,60 +1,48 @@
1
- import chalk from 'chalk';
2
1
  import { deployProject, fetchProject, } from '@hubspot/local-dev-lib/api/projects';
3
2
  import { getAccountConfig } from '@hubspot/local-dev-lib/config';
4
- import { logger } from '@hubspot/local-dev-lib/logger';
5
3
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
4
  import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
7
5
  import { trackCommandUsage } from '../../lib/usageTracking.js';
8
6
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
9
7
  import { getProjectConfig } from '../../lib/projects/config.js';
10
8
  import { pollDeployStatus } from '../../lib/projects/buildAndDeploy.js';
11
- import { getProjectDetailUrl } from '../../lib/projects/urls.js';
12
9
  import { projectNamePrompt } from '../../lib/prompts/projectNamePrompt.js';
13
10
  import { promptUser } from '../../lib/prompts/promptUtils.js';
14
- import { i18n } from '../../lib/lang.js';
15
- import { uiBetaTag, uiLine, uiLink } from '../../lib/ui/index.js';
11
+ import { uiBetaTag, uiLine } from '../../lib/ui/index.js';
16
12
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
17
- import { uiCommandReference, uiAccountDescription, } from '../../lib/ui/index.js';
13
+ import { uiLogger } from '../../lib/ui/logger.js';
18
14
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
19
15
  import { loadProfile, logProfileFooter, logProfileHeader, exitIfUsingProfiles, } from '../../lib/projectProfiles.js';
20
- import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
16
+ import { PROJECT_ERROR_TYPES, PROJECT_DEPLOY_TEXT, } from '../../lib/constants.js';
17
+ import { commands } from '../../lang/en.js';
21
18
  const command = 'deploy';
22
- const describe = uiBetaTag(i18n(`commands.project.subcommands.deploy.describe`), false);
19
+ const describe = uiBetaTag(commands.project.deploy.describe, false);
23
20
  function validateBuildId(buildId, deployedBuildId, latestBuildId, projectName, accountId) {
24
21
  if (Number(buildId) > latestBuildId) {
25
- return i18n(`commands.project.subcommands.deploy.errors.buildIdDoesNotExist`, {
26
- buildId: buildId,
27
- projectName: projectName,
28
- linkToProject: uiLink(i18n(`commands.project.subcommands.deploy.errors.viewProjectsBuilds`), getProjectDetailUrl(projectName, accountId)),
29
- });
22
+ return commands.project.deploy.errors.buildIdDoesNotExist(accountId, buildId, projectName);
30
23
  }
31
24
  if (Number(buildId) === deployedBuildId) {
32
- return i18n(`commands.project.subcommands.deploy.errors.buildAlreadyDeployed`, {
33
- buildId: buildId,
34
- linkToProject: uiLink(i18n(`commands.project.subcommands.deploy.errors.viewProjectsBuilds`), getProjectDetailUrl(projectName, accountId)),
35
- });
25
+ return commands.project.deploy.errors.buildAlreadyDeployed(accountId, buildId, projectName);
36
26
  }
37
27
  return true;
38
28
  }
39
29
  function logDeployErrors(errorData) {
40
- logger.error(errorData.message);
30
+ uiLogger.error(errorData.message);
41
31
  errorData.errors.forEach(err => {
42
32
  if (err.subCategory === PROJECT_ERROR_TYPES.DEPLOY_CONTAINS_REMOVALS) {
43
- logger.log(i18n(`commands.project.subcommands.deploy.errors.deployContainsRemovals`, {
44
- componentName: err.context.COMPONENT_NAME,
45
- forceFlag: uiCommandReference('--force'),
46
- }));
33
+ uiLogger.log(commands.project.deploy.errors.deployContainsRemovals(err.context.COMPONENT_NAME));
47
34
  }
48
35
  else {
49
- logger.log(err.message);
36
+ uiLogger.log(err.message);
50
37
  }
51
38
  });
52
39
  }
53
40
  async function handler(args) {
54
- const { derivedAccountId, project: projectOption, buildId: buildIdOption, force: forceOption, } = args;
41
+ const { derivedAccountId, project: projectOption, buildId: buildIdOption, force: forceOption, deployLatestBuild: deployLatestBuildOption, json: formatOutputAsJson, } = args;
55
42
  const accountConfig = getAccountConfig(derivedAccountId);
56
43
  const accountType = accountConfig && accountConfig.accountType;
57
44
  let targetAccountId;
45
+ const jsonOutput = {};
58
46
  const { projectConfig, projectDir } = await getProjectConfig();
59
47
  if (useV3Api(projectConfig?.platformVersion)) {
60
48
  if (args.profile) {
@@ -85,55 +73,63 @@ async function handler(args) {
85
73
  });
86
74
  projectName = namePromptResponse.projectName;
87
75
  let buildIdToDeploy = buildIdOption;
76
+ let deploySuccess = false;
88
77
  try {
89
78
  const { data: { latestBuild, deployedBuildId }, } = await fetchProject(targetAccountId, projectName);
90
79
  if (!latestBuild || !latestBuild.buildId) {
91
- logger.error(i18n(`commands.project.subcommands.deploy.errors.noBuilds`));
80
+ uiLogger.error(commands.project.deploy.errors.noBuilds);
92
81
  return process.exit(EXIT_CODES.ERROR);
93
82
  }
94
83
  if (buildIdToDeploy) {
95
84
  const validationResult = validateBuildId(buildIdToDeploy, deployedBuildId, latestBuild.buildId, projectName, targetAccountId);
96
85
  if (validationResult !== true) {
97
- logger.error(validationResult);
86
+ uiLogger.error(validationResult.toString());
98
87
  return process.exit(EXIT_CODES.ERROR);
99
88
  }
100
89
  }
101
90
  else {
102
- const deployBuildIdPromptResponse = await promptUser({
103
- name: 'buildId',
104
- message: i18n(`commands.project.subcommands.deploy.deployBuildIdPrompt`),
105
- default: latestBuild.buildId === deployedBuildId
106
- ? undefined
107
- : latestBuild.buildId,
108
- validate: (buildId) => validateBuildId(buildId, deployedBuildId, latestBuild.buildId, projectName, targetAccountId),
109
- });
110
- buildIdToDeploy = deployBuildIdPromptResponse.buildId;
91
+ if (deployLatestBuildOption) {
92
+ buildIdToDeploy = latestBuild.buildId;
93
+ }
94
+ else {
95
+ const deployBuildIdPromptResponse = await promptUser({
96
+ name: 'buildId',
97
+ message: commands.project.deploy.deployBuildIdPrompt,
98
+ default: latestBuild.buildId === deployedBuildId
99
+ ? undefined
100
+ : latestBuild.buildId,
101
+ validate: buildId => validateBuildId(buildId, deployedBuildId, latestBuild.buildId, projectName, targetAccountId),
102
+ });
103
+ buildIdToDeploy = deployBuildIdPromptResponse.buildId;
104
+ }
111
105
  }
112
106
  if (!buildIdToDeploy) {
113
- logger.error(i18n(`commands.project.subcommands.deploy.errors.noBuildId`));
107
+ uiLogger.error(commands.project.deploy.errors.noBuildId);
114
108
  return process.exit(EXIT_CODES.ERROR);
115
109
  }
116
110
  const { data: deployResp } = await deployProject(targetAccountId, projectName, buildIdToDeploy, useV3Api(projectConfig?.platformVersion), forceOption);
117
- if (!deployResp) {
118
- logger.error(i18n(`commands.project.subcommands.deploy.errors.deploy`));
111
+ if (!deployResp || deployResp.buildResultType !== 'DEPLOY_QUEUED') {
112
+ uiLogger.error(commands.project.deploy.errors.deploy);
119
113
  return process.exit(EXIT_CODES.ERROR);
120
114
  }
121
- await pollDeployStatus(targetAccountId, projectName, Number(deployResp.id), buildIdToDeploy);
115
+ else if (formatOutputAsJson) {
116
+ jsonOutput.deployId = Number(deployResp.id);
117
+ }
118
+ const deployResult = await pollDeployStatus(targetAccountId, projectName, Number(deployResp.id), buildIdToDeploy);
119
+ if (deployResult.status === PROJECT_DEPLOY_TEXT.STATES.SUCCESS) {
120
+ deploySuccess = true;
121
+ }
122
122
  }
123
123
  catch (e) {
124
124
  if (isHubSpotHttpError(e) && e.status === 404) {
125
- logger.error(i18n(`commands.project.subcommands.deploy.errors.projectNotFound`, {
126
- projectName: chalk.bold(projectName),
127
- accountIdentifier: uiAccountDescription(targetAccountId),
128
- command: uiCommandReference('hs project upload'),
129
- }));
125
+ uiLogger.error(commands.project.deploy.errors.projectNotFound(targetAccountId, projectName));
130
126
  }
131
127
  else if (isHubSpotHttpError(e) && e.status === 400) {
132
128
  if (e.data?.message && e.data?.errors) {
133
129
  logDeployErrors(e.data);
134
130
  }
135
131
  else {
136
- logger.error(e.message);
132
+ uiLogger.error(e.message);
137
133
  }
138
134
  }
139
135
  else {
@@ -144,27 +140,42 @@ async function handler(args) {
144
140
  }
145
141
  return process.exit(EXIT_CODES.ERROR);
146
142
  }
143
+ if (formatOutputAsJson) {
144
+ uiLogger.json(jsonOutput);
145
+ }
146
+ if (deploySuccess) {
147
+ process.exit(EXIT_CODES.SUCCESS);
148
+ }
149
+ else {
150
+ process.exit(EXIT_CODES.ERROR);
151
+ }
147
152
  }
148
153
  function projectDeployBuilder(yargs) {
149
154
  yargs.options({
150
155
  project: {
151
- describe: i18n(`commands.project.subcommands.deploy.options.project.describe`),
156
+ describe: commands.project.deploy.options.project,
152
157
  type: 'string',
153
158
  },
154
159
  build: {
155
160
  alias: ['build-id'],
156
- describe: i18n(`commands.project.subcommands.deploy.options.build.describe`),
161
+ describe: commands.project.deploy.options.build,
157
162
  type: 'number',
158
163
  },
164
+ deployLatestBuild: {
165
+ alias: ['deploy-latest-build'],
166
+ describe: commands.project.deploy.options.deployLatestBuild,
167
+ default: false,
168
+ type: 'boolean',
169
+ },
159
170
  profile: {
160
171
  alias: ['p'],
161
- describe: i18n(`commands.project.subcommands.deploy.options.profile.describe`),
172
+ describe: commands.project.deploy.options.profile,
162
173
  type: 'string',
163
174
  hidden: true,
164
175
  },
165
176
  force: {
166
177
  alias: ['f'],
167
- describe: i18n(`commands.project.subcommands.deploy.options.force.describe`),
178
+ describe: commands.project.deploy.options.force,
168
179
  default: false,
169
180
  type: 'boolean',
170
181
  },
@@ -172,13 +183,10 @@ function projectDeployBuilder(yargs) {
172
183
  yargs.conflicts('profile', 'project');
173
184
  yargs.conflicts('profile', 'account');
174
185
  yargs.example([
175
- [
176
- '$0 project deploy',
177
- i18n(`commands.project.subcommands.deploy.examples.default`),
178
- ],
186
+ ['$0 project deploy', commands.project.deploy.examples.default],
179
187
  [
180
188
  '$0 project deploy --project="my-project" --build=5',
181
- i18n(`commands.project.subcommands.deploy.examples.withOptions`),
189
+ commands.project.deploy.examples.withOptions,
182
190
  ],
183
191
  ]);
184
192
  return yargs;
@@ -188,6 +196,7 @@ const builder = makeYargsBuilder(projectDeployBuilder, command, describe, {
188
196
  useConfigOptions: true,
189
197
  useAccountOptions: true,
190
198
  useEnvironmentOptions: true,
199
+ useJSONOutputOptions: true,
191
200
  });
192
201
  const projectDeployCommand = {
193
202
  command,
@@ -58,11 +58,12 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
58
58
  process.exit(EXIT_CODES.ERROR);
59
59
  }
60
60
  let targetTestingAccountId = providedTargetTestingAccountId;
61
- if (profileConfig) {
62
- // Bypass the prompt for the testing account if the user has a profile configured
63
- targetTestingAccountId = profileConfig.accountId;
64
- }
65
- else if (
61
+ // Temporarily removing logic to use profile account as testing account
62
+ // if (profileConfig) {
63
+ // // Bypass the prompt for the testing account if the user has a profile configured
64
+ // targetTestingAccountId = profileConfig.accountId;
65
+ // } else
66
+ if (
66
67
  // Bypass the prompt for the testing account if default account is already a test account
67
68
  !targetTestingAccountId &&
68
69
  targetProjectAccountIsTestAccountOrSandbox) {
@@ -87,7 +88,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
87
88
  }
88
89
  else if (devAccountPromptResponse.createNestedAccount) {
89
90
  // Create a new developer test account and automatically add it to the CLI config
90
- targetTestingAccountId = await createDeveloperTestAccountForLocalDev(targetProjectAccountId, targetProjectAccountConfig, env);
91
+ targetTestingAccountId = await createDeveloperTestAccountForLocalDev(targetProjectAccountId, targetProjectAccountConfig, env, true);
91
92
  }
92
93
  }
93
94
  else if (accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX) {
@@ -24,9 +24,6 @@ describe('commands/testAccount/createConfig', () => {
24
24
  expect(optionSpy).toHaveBeenCalledWith('description', expect.objectContaining({
25
25
  type: 'string',
26
26
  }));
27
- expect(optionSpy).toHaveBeenCalledWith('tiers', expect.objectContaining({
28
- type: 'array',
29
- }));
30
27
  expect(optionSpy).toHaveBeenCalledWith('path', expect.objectContaining({
31
28
  type: 'string',
32
29
  }));
@@ -1,6 +1,5 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
- import { createDeveloperTestAccount, fetchDeveloperTestAccountGateSyncStatus, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
4
3
  import { getCwd } from '@hubspot/local-dev-lib/path';
5
4
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
6
5
  import { promptUser, listPrompt } from '../../lib/prompts/promptUtils.js';
@@ -10,9 +9,9 @@ import { trackCommandUsage } from '../../lib/usageTracking.js';
10
9
  import { fileExists } from '../../lib/validation.js';
11
10
  import { commands } from '../../lang/en.js';
12
11
  import { createDeveloperTestAccountConfigPrompt } from '../../lib/prompts/createDeveloperTestAccountConfigPrompt.js';
13
- import { debugError, logError } from '../../lib/errorHandlers/index.js';
14
- import { poll } from '../../lib/polling.js';
12
+ import { logError } from '../../lib/errorHandlers/index.js';
15
13
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
14
+ import { createDeveloperTestAccountV3 } from '../../lib/buildAccount.js';
16
15
  const command = 'create';
17
16
  const describe = commands.testAccount.create.describe;
18
17
  async function handler(args) {
@@ -68,36 +67,24 @@ async function handler(args) {
68
67
  text: commands.testAccount.create.polling.start(testAccountConfig.accountName),
69
68
  });
70
69
  try {
71
- const { data } = await createDeveloperTestAccount(derivedAccountId, testAccountConfig);
70
+ const result = await createDeveloperTestAccountV3(derivedAccountId, testAccountConfig);
72
71
  if (formatOutputAsJson) {
73
- jsonOutput.accountName = data.accountName;
74
- jsonOutput.accountId = data.id;
75
- jsonOutput.personalAccessKey = data.personalAccessKey;
72
+ jsonOutput.accountName = result.accountName;
73
+ jsonOutput.accountId = result.accountId;
74
+ jsonOutput.personalAccessKey = result.personalAccessKey;
76
75
  }
77
- testAccountId = data.id;
76
+ testAccountId = result.accountId;
78
77
  }
79
78
  catch (err) {
80
79
  logError(err);
81
- process.exit(EXIT_CODES.ERROR);
82
- }
83
- SpinniesManager.update('createTestAccount', {
84
- text: commands.testAccount.create.polling.syncing,
85
- });
86
- try {
87
- await poll(() => fetchDeveloperTestAccountGateSyncStatus(derivedAccountId, testAccountId), {
88
- successStates: ['SUCCESS'],
89
- errorStates: [],
90
- });
91
- SpinniesManager.succeed('createTestAccount', {
92
- text: commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
93
- });
94
- }
95
- catch (err) {
96
- debugError(err);
97
80
  SpinniesManager.fail('createTestAccount', {
98
- text: commands.testAccount.create.polling.failure,
81
+ text: commands.testAccount.create.polling.createFailure,
99
82
  });
83
+ process.exit(EXIT_CODES.ERROR);
100
84
  }
85
+ SpinniesManager.succeed('createTestAccount', {
86
+ text: commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
87
+ });
101
88
  if (formatOutputAsJson) {
102
89
  uiLogger.json(jsonOutput);
103
90
  }
@@ -1,9 +1,7 @@
1
1
  import { CommonArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- import { HubConfig } from '../../lib/prompts/createDeveloperTestAccountConfigPrompt.js';
3
2
  type CreateTestAccountConfigArgs = CommonArgs & {
4
3
  name?: string;
5
4
  description?: string;
6
- tiers?: HubConfig[];
7
5
  path?: string;
8
6
  };
9
7
  declare const createTestAccountConfigCommand: YargsCommandModule<unknown, CreateTestAccountConfigArgs>;
@@ -12,27 +12,30 @@ import { fileExists } from '../../lib/validation.js';
12
12
  const command = 'create-config';
13
13
  const describe = commands.testAccount.createConfig.describe;
14
14
  async function handler(args) {
15
- const { derivedAccountId, name, tiers, description, path: configPath } = args;
15
+ const { derivedAccountId, name, description, path: configPath } = args;
16
16
  trackCommandUsage('test-account-create-config', {}, derivedAccountId);
17
17
  let accountConfigPath = configPath;
18
18
  const testAccountConfig = await createDeveloperTestAccountConfigPrompt({
19
19
  name,
20
20
  description,
21
- tiers,
22
21
  });
23
22
  if (!accountConfigPath) {
24
23
  const pathPromptResult = await promptUser({
25
24
  name: 'path',
26
25
  message: commands.testAccount.createConfig.pathPrompt,
27
26
  type: 'input',
28
- default: 'test-account-config.json',
29
- validate: (path) => {
27
+ default: testAccountConfig.accountName.toLowerCase().replace(/\s+/g, '-') +
28
+ '.json',
29
+ validate: path => {
30
30
  if (!path) {
31
31
  return commands.testAccount.createConfig.errors.pathError;
32
32
  }
33
33
  else if (!path.endsWith('.json')) {
34
34
  return commands.testAccount.createConfig.errors.pathFormatError;
35
35
  }
36
+ else if (fileExists(path)) {
37
+ return commands.testAccount.createConfig.errors.pathExistsError;
38
+ }
36
39
  return true;
37
40
  },
38
41
  });
@@ -65,17 +68,13 @@ function createTestAccountConfigBuilder(yargs) {
65
68
  type: 'string',
66
69
  description: commands.testAccount.createConfig.options.description,
67
70
  });
68
- yargs.option('tiers', {
69
- type: 'array',
70
- description: commands.testAccount.createConfig.options.tiers,
71
- });
72
71
  yargs.option('path', {
73
72
  type: 'string',
74
73
  description: commands.testAccount.createConfig.options.path,
75
74
  });
76
75
  yargs.example([
77
76
  [
78
- '$0 create-config --name my-account',
77
+ '$0 test-account create-config --name my-account',
79
78
  commands.testAccount.createConfig.example('my-account'),
80
79
  ],
81
80
  ]);
package/lang/en.d.ts CHANGED
@@ -36,7 +36,6 @@ export declare const commands: {
36
36
  readonly app: "App";
37
37
  readonly cms: "CMS";
38
38
  };
39
- readonly installDependencies: "Would you like to install dependencies now?";
40
39
  readonly uploadProject: "Would you like to upload your project to HubSpot now?";
41
40
  readonly projectCreated: {
42
41
  readonly title: string;
@@ -49,7 +48,6 @@ You can use ${string} to ${string} and ${string} to ${string} your project.`;
49
48
  Projects are what you can use to create apps, themes, and more at HubSpot.
50
49
  Usually you'll use the ${string} command, but we'll go ahead and make one now.`;
51
50
  readonly dependenciesInstalled: "Dependencies installed successfully.";
52
- readonly dependenciesNotInstalled: `Dependencies not installed. Remember to do this later with the command ${string} from the project directory.`;
53
51
  readonly uploadingProject: "Uploading your project to HubSpot...";
54
52
  readonly uploadSuccess: "Project uploaded successfully!";
55
53
  readonly developerOverviewLink: "Open this link to navigate to your HubSpot developer portal";
@@ -837,6 +835,7 @@ Global configuration replaces hubspot.config.yml, and you will be prompted to mi
837
835
  readonly success: (derivedTargets: string[]) => string;
838
836
  readonly errors: {
839
837
  readonly needsNode20: "This feature requires node >=20";
838
+ readonly errorParsingJsonFIle: (filename: string, errorMessage: string) => string;
840
839
  };
841
840
  readonly spinners: {
842
841
  readonly failedToConfigure: "Failed to configure the HubSpot mcp server.";
@@ -1143,16 +1142,16 @@ ${string}`;
1143
1142
  readonly creatingComponent: (projectName: string) => string;
1144
1143
  readonly success: (componentName: string, multiple?: boolean) => string;
1145
1144
  readonly error: {
1146
- readonly failedToDownloadComponent: "Failed to download project component. Please try again later.";
1145
+ readonly failedToDownloadComponent: "Failed to download project. Please try again later.";
1147
1146
  readonly maxExceeded: (maxCount: number) => string;
1148
1147
  readonly authTypeNotAllowed: (authType: string) => string;
1149
1148
  readonly distributionNotAllowed: (dist: string) => string;
1150
1149
  readonly locationInProject: "This command must be run from within a project directory.";
1151
- readonly failedToFetchComponentList: "Failed to fetch the list of available components. Please try again later.";
1150
+ readonly failedToFetchComponentList: "Failed to fetch the list of available features. Please try again later.";
1152
1151
  readonly projectContainsPublicApp: "This project contains a public app. This command is currently only compatible with projects that contain private apps.";
1153
1152
  };
1154
1153
  readonly examples: {
1155
- readonly default: "Create a component within your project";
1154
+ readonly default: "Create an app feature within your project";
1156
1155
  readonly withFlags: "Use --name and --type flags to bypass the prompt.";
1157
1156
  };
1158
1157
  };
@@ -1163,25 +1162,24 @@ ${string}`;
1163
1162
  readonly deploying: (path: string) => string;
1164
1163
  };
1165
1164
  readonly errors: {
1166
- readonly deploy: (details: string) => string;
1165
+ readonly deploy: "Deploy error: an unknown error occurred.";
1167
1166
  readonly noBuilds: "Deploy error: no builds for this project were found.";
1168
1167
  readonly noBuildId: "You must specify a build to deploy";
1169
- readonly projectNotFound: (projectName: string, accountIdentifier: string, command: string) => string;
1170
- readonly buildIdDoesNotExist: (buildId: string, projectName: string, linkToProject: string) => string;
1171
- readonly buildAlreadyDeployed: (buildId: string, linkToProject: string) => string;
1172
- readonly viewProjectsBuilds: "View project builds in HubSpot";
1168
+ readonly projectNotFound: (accountId: number, projectName: string) => string;
1169
+ readonly buildIdDoesNotExist: (accountId: number, buildId: number, projectName: string) => string;
1170
+ readonly buildAlreadyDeployed: (accountId: number, buildId: number, projectName: string) => string;
1171
+ readonly deployContainsRemovals: (componentName: string) => string;
1173
1172
  };
1174
1173
  readonly examples: {
1175
1174
  readonly default: "Deploy the latest build of the current project";
1176
1175
  readonly withOptions: "Deploy build 5 of the project my-project";
1177
1176
  };
1178
1177
  readonly options: {
1179
- readonly build: {
1180
- readonly describe: "Project build ID to be deployed";
1181
- };
1182
- readonly project: {
1183
- readonly describe: "Project name";
1184
- };
1178
+ readonly build: "Project build ID to be deployed";
1179
+ readonly project: "Project name";
1180
+ readonly profile: "The profile to target with this deploy";
1181
+ readonly force: "Skip warnings and force deploy. Use this carefully as it will bypass warnings for destructive actions.";
1182
+ readonly deployLatestBuild: "Deploy the latest build of the current project";
1185
1183
  };
1186
1184
  };
1187
1185
  readonly listBuilds: {
@@ -1811,7 +1809,7 @@ ${string}`;
1811
1809
  readonly start: (testAccountName: string) => string;
1812
1810
  readonly syncing: "Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)";
1813
1811
  readonly success: (testAccountName: string, testAccountId: number) => string;
1814
- readonly failure: "Failed to sync data into test account. The account may not be ready to use.";
1812
+ readonly createFailure: "Failed to create test account.";
1815
1813
  };
1816
1814
  readonly options: {
1817
1815
  readonly configPath: "The path to the test account config";
@@ -1820,7 +1818,7 @@ ${string}`;
1820
1818
  };
1821
1819
  readonly createConfig: {
1822
1820
  readonly describe: "Create a test account config file.";
1823
- readonly pathPrompt: "[--path] What is the path to the test account config?";
1821
+ readonly pathPrompt: "[--path] Enter the name of the Test Account config file: ";
1824
1822
  readonly errors: {
1825
1823
  readonly pathError: "Path is required";
1826
1824
  readonly pathFormatError: "Path must end with .json";
@@ -1833,7 +1831,6 @@ ${string}`;
1833
1831
  readonly options: {
1834
1832
  readonly name: "The name of the test account";
1835
1833
  readonly description: "The description of the test account";
1836
- readonly tiers: "The tiers of the test account";
1837
1834
  readonly path: "The path to the test account config";
1838
1835
  };
1839
1836
  readonly example: (name: string) => string;
@@ -2763,6 +2760,12 @@ Run ${string} to upgrade to version ${string}`;
2763
2760
  readonly noLogsFound: "No logs found.";
2764
2761
  };
2765
2762
  };
2763
+ readonly buildAccount: {
2764
+ readonly createDeveloperTestAccountV3: {
2765
+ readonly syncFailure: "Failed to sync developer test account";
2766
+ readonly pakFailure: "Failed to generate personal access key for developer test account";
2767
+ };
2768
+ };
2766
2769
  readonly configOptions: {
2767
2770
  readonly enableOrDisableBooleanFieldPrompt: {
2768
2771
  readonly message: (fieldName: string) => string;
@@ -2845,11 +2848,25 @@ Run ${string} to upgrade to version ${string}`;
2845
2848
  readonly keepingCurrentDefault: (accountName: string) => string;
2846
2849
  };
2847
2850
  readonly createDeveloperTestAccountConfigPrompt: {
2848
- readonly namePrompt: "[--name] What is the name of the test account?";
2849
- readonly descriptionPrompt: "[--description] What is the description of the test account?";
2850
- readonly tiersPrompt: "[--tiers] Which product tiers should the test account have?";
2851
+ readonly namePrompt: (withFlag?: boolean) => string;
2852
+ readonly descriptionPrompt: (withFlag?: boolean) => string;
2853
+ readonly useDefaultAccountLevelsPrompt: {
2854
+ readonly message: "Would you like to create a default Test Account, or customize your own?";
2855
+ readonly default: "Default (All Hubs, ENTERPRISE)";
2856
+ readonly manual: "Customize my own";
2857
+ };
2858
+ readonly tiersPrompt: "Select an option per hub to customize tiers. If left blank, default is ENTERPRISE";
2859
+ readonly hubTypes: {
2860
+ readonly marketing: "Marketing";
2861
+ readonly ops: "Ops";
2862
+ readonly service: "Service";
2863
+ readonly sales: "Sales";
2864
+ readonly content: "Content";
2865
+ };
2851
2866
  readonly errors: {
2867
+ readonly allHubsRequired: "Select a tier for each hub";
2852
2868
  readonly tiersError: "Cannot have more than one tier per hub";
2869
+ readonly nameRequired: "The name may not be blank. Please add a name for the Test Account.";
2853
2870
  };
2854
2871
  };
2855
2872
  readonly accountNamePrompt: {
@@ -2972,7 +2989,7 @@ Run ${string} to upgrade to version ${string}`;
2972
2989
  };
2973
2990
  };
2974
2991
  readonly projectAddPrompt: {
2975
- readonly selectType: "[--type] Select a component to add: ";
2992
+ readonly selectType: "[--type] Select an app feature to add: ";
2976
2993
  readonly enterName: "[--name] Give your component a name: ";
2977
2994
  readonly errors: {
2978
2995
  readonly nameRequired: "A component name is required";