@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/lib/commonOpts.js CHANGED
@@ -10,6 +10,7 @@ exports.addOverwriteOptions = addOverwriteOptions;
10
10
  exports.addCmsPublishModeOptions = addCmsPublishModeOptions;
11
11
  exports.addTestingOptions = addTestingOptions;
12
12
  exports.addUseEnvironmentOptions = addUseEnvironmentOptions;
13
+ exports.addJSONOutputOptions = addJSONOutputOptions;
13
14
  exports.addCustomHelpOutput = addCustomHelpOutput;
14
15
  exports.setLogLevel = setLogLevel;
15
16
  exports.getCommandName = getCommandName;
@@ -19,16 +20,16 @@ const yargs_parser_1 = __importDefault(require("yargs-parser"));
19
20
  const logger_1 = require("@hubspot/local-dev-lib/logger");
20
21
  const files_1 = require("@hubspot/local-dev-lib/constants/files");
21
22
  const config_1 = require("@hubspot/local-dev-lib/config");
22
- const lang_1 = require("./lang");
23
23
  const errorHandlers_1 = require("./errorHandlers");
24
24
  const exitCodes_1 = require("./enums/exitCodes");
25
25
  const ui_1 = require("./ui");
26
+ const lang_1 = require("./lang");
26
27
  function addGlobalOptions(yargs) {
27
28
  yargs.version(false);
28
29
  yargs.option('debug', {
29
30
  alias: 'd',
30
31
  default: false,
31
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.debug.describe`),
32
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.debug.describe'),
32
33
  type: 'boolean',
33
34
  });
34
35
  yargs.option('network-debug', {
@@ -41,21 +42,21 @@ function addGlobalOptions(yargs) {
41
42
  function addAccountOptions(yargs) {
42
43
  return yargs.option('account', {
43
44
  alias: 'a',
44
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.account.describe`),
45
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.account.describe'),
45
46
  type: 'string',
46
47
  });
47
48
  }
48
49
  function addConfigOptions(yargs) {
49
50
  return yargs.option('config', {
50
51
  alias: 'c',
51
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.config.describe`),
52
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.config.describe'),
52
53
  type: 'string',
53
54
  });
54
55
  }
55
56
  function addOverwriteOptions(yargs) {
56
57
  return yargs.option('overwrite', {
57
58
  alias: 'o',
58
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.overwrite.describe`),
59
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.overwrite.describe'),
59
60
  type: 'boolean',
60
61
  default: false,
61
62
  });
@@ -70,7 +71,7 @@ function addCmsPublishModeOptions(yargs, { read, write }) {
70
71
  }
71
72
  function addTestingOptions(yargs) {
72
73
  return yargs.option('qa', {
73
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.qa.describe`),
74
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.qa.describe'),
74
75
  type: 'boolean',
75
76
  default: false,
76
77
  hidden: true,
@@ -78,12 +79,20 @@ function addTestingOptions(yargs) {
78
79
  }
79
80
  function addUseEnvironmentOptions(yargs) {
80
81
  yargs.option('use-env', {
81
- describe: (0, lang_1.i18n)(`lib.commonOpts.options.useEnv.describe`),
82
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.useEnv.describe'),
82
83
  type: 'boolean',
83
84
  });
84
85
  yargs.conflicts('use-env', 'account');
85
86
  return yargs;
86
87
  }
88
+ function addJSONOutputOptions(yargs) {
89
+ return yargs.option('json', {
90
+ alias: 'format-output-as-json',
91
+ describe: (0, lang_1.i18n)('lib.commonOpts.options.jsonOutput.describe'),
92
+ type: 'boolean',
93
+ hidden: true,
94
+ });
95
+ }
87
96
  async function addCustomHelpOutput(yargs, command, describe) {
88
97
  try {
89
98
  const parsedArgv = (0, yargs_parser_1.default)(process.argv.slice(2));
@@ -125,8 +134,11 @@ async function addCustomHelpOutput(yargs, command, describe) {
125
134
  }
126
135
  }
127
136
  function setLogLevel(options) {
128
- const { debug, networkDebug } = options;
129
- if (debug) {
137
+ const { debug, networkDebug, json } = options;
138
+ if (json) {
139
+ (0, logger_1.setLogLevel)(logger_1.LOG_LEVEL.ERROR);
140
+ }
141
+ else if (debug) {
130
142
  (0, logger_1.setLogLevel)(logger_1.LOG_LEVEL.DEBUG);
131
143
  }
132
144
  else {
@@ -49,6 +49,7 @@ export declare const PROJECT_ERROR_TYPES: {
49
49
  readonly BUILD_NOT_IN_PROGRESS: "BuildPipelineErrorType.BUILD_NOT_IN_PROGRESS";
50
50
  readonly SUBBUILD_FAILED: "BuildPipelineErrorType.DEPENDENT_SUBBUILD_FAILED";
51
51
  readonly SUBDEPLOY_FAILED: "DeployPipelineErrorType.DEPENDENT_SUBDEPLOY_FAILED";
52
+ readonly DEPLOY_CONTAINS_REMOVALS: "DeployPipelineErrorType.WARNING_DEPLOY_CONTAINS_REMOVALS";
52
53
  };
53
54
  export declare const PROJECT_TASK_TYPES: {
54
55
  [key: string]: string;
@@ -98,6 +99,10 @@ export declare const oAuth = "oauth";
98
99
  export declare const privateDistribution = "private";
99
100
  export declare const marketplaceDistribution = "marketplace";
100
101
  export declare const appComponent = "app";
102
+ export declare const GET_STARTED_OPTIONS: {
103
+ readonly APP: "APP";
104
+ readonly CMS: "CMS";
105
+ };
101
106
  export declare const LOCAL_DEV_SERVER_MESSAGE_TYPES: {
102
107
  readonly INITIAL: "INITIAL";
103
108
  readonly WEBSOCKET_SERVER_CONNECTED: "WEBSOCKET_SERVER_CONNECTED";
package/lib/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LOCAL_DEV_SERVER_MESSAGE_TYPES = exports.appComponent = exports.marketplaceDistribution = exports.privateDistribution = exports.oAuth = exports.staticAuth = exports.APP_INSTALLATION_STATES = exports.LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES = exports.LOCAL_DEV_UI_MESSAGE_SEND_TYPES = exports.FEATURES = exports.APP_AUTH_TYPES = exports.APP_DISTRIBUTION_TYPES = exports.IR_COMPONENT_TYPES = exports.PLATFORM_VERSION_ERROR_TYPES = exports.PROJECT_COMPONENT_TYPES = exports.PROJECT_TASK_TYPES = exports.PROJECT_ERROR_TYPES = exports.PROJECT_DEPLOY_TEXT = exports.PROJECT_BUILD_TEXT = exports.PROJECT_DEPLOY_STATES = exports.PROJECT_BUILD_STATES = exports.PROJECT_CONFIG_FILE = exports.DEFAULT_POLLING_DELAY = exports.MARKETPLACE_FOLDER = exports.HUBSPOT_FOLDER = exports.FEEDBACK_INTERVAL = exports.DEFAULT_PROJECT_TEMPLATE_BRANCH = exports.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH = void 0;
3
+ exports.LOCAL_DEV_SERVER_MESSAGE_TYPES = exports.GET_STARTED_OPTIONS = exports.appComponent = exports.marketplaceDistribution = exports.privateDistribution = exports.oAuth = exports.staticAuth = exports.APP_INSTALLATION_STATES = exports.LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES = exports.LOCAL_DEV_UI_MESSAGE_SEND_TYPES = exports.FEATURES = exports.APP_AUTH_TYPES = exports.APP_DISTRIBUTION_TYPES = exports.IR_COMPONENT_TYPES = exports.PLATFORM_VERSION_ERROR_TYPES = exports.PROJECT_COMPONENT_TYPES = exports.PROJECT_TASK_TYPES = exports.PROJECT_ERROR_TYPES = exports.PROJECT_DEPLOY_TEXT = exports.PROJECT_BUILD_TEXT = exports.PROJECT_DEPLOY_STATES = exports.PROJECT_BUILD_STATES = exports.PROJECT_CONFIG_FILE = exports.DEFAULT_POLLING_DELAY = exports.MARKETPLACE_FOLDER = exports.HUBSPOT_FOLDER = exports.FEEDBACK_INTERVAL = exports.DEFAULT_PROJECT_TEMPLATE_BRANCH = exports.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH = void 0;
4
4
  exports.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH = 'HubSpot/hubspot-project-components';
5
5
  exports.DEFAULT_PROJECT_TEMPLATE_BRANCH = 'main';
6
6
  exports.FEEDBACK_INTERVAL = 10;
@@ -41,6 +41,7 @@ exports.PROJECT_ERROR_TYPES = {
41
41
  BUILD_NOT_IN_PROGRESS: 'BuildPipelineErrorType.BUILD_NOT_IN_PROGRESS',
42
42
  SUBBUILD_FAILED: 'BuildPipelineErrorType.DEPENDENT_SUBBUILD_FAILED',
43
43
  SUBDEPLOY_FAILED: 'DeployPipelineErrorType.DEPENDENT_SUBDEPLOY_FAILED',
44
+ DEPLOY_CONTAINS_REMOVALS: 'DeployPipelineErrorType.WARNING_DEPLOY_CONTAINS_REMOVALS',
44
45
  };
45
46
  exports.PROJECT_TASK_TYPES = {
46
47
  PRIVATE_APP: 'private app',
@@ -93,6 +94,10 @@ exports.oAuth = 'oauth';
93
94
  exports.privateDistribution = 'private';
94
95
  exports.marketplaceDistribution = 'marketplace';
95
96
  exports.appComponent = 'app';
97
+ exports.GET_STARTED_OPTIONS = {
98
+ APP: 'APP',
99
+ CMS: 'CMS',
100
+ };
96
101
  exports.LOCAL_DEV_SERVER_MESSAGE_TYPES = {
97
102
  INITIAL: 'INITIAL',
98
103
  WEBSOCKET_SERVER_CONNECTED: 'WEBSOCKET_SERVER_CONNECTED',
@@ -262,7 +262,7 @@ class Doctor {
262
262
  this.diagnosis?.addCliSection({
263
263
  type: 'success',
264
264
  message: i18n(`lib.doctor.hsChecks.latest`, {
265
- hsVersion: latestCLIVersion,
265
+ hsVersion: package_json_1.default.version,
266
266
  }),
267
267
  });
268
268
  }
@@ -15,6 +15,10 @@ const util_1 = __importDefault(require("util"));
15
15
  const ui_1 = require("../ui");
16
16
  function logError(error, context) {
17
17
  debugError(error, context);
18
+ if (isProjectValidationError(error)) {
19
+ logger_1.logger.error(error.message);
20
+ return;
21
+ }
18
22
  if ((0, suppressError_1.shouldSuppressError)(error, context)) {
19
23
  return;
20
24
  }
@@ -89,6 +93,9 @@ class ApiErrorContext {
89
93
  }
90
94
  }
91
95
  exports.ApiErrorContext = ApiErrorContext;
96
+ function isProjectValidationError(error) {
97
+ return error instanceof Error && error.name === 'ProjectValidationError';
98
+ }
92
99
  function isErrorWithMessageOrReason(error) {
93
100
  return (typeof error === 'object' &&
94
101
  error !== null &&
@@ -8,5 +8,14 @@ export declare const supportedTools: ({
8
8
  name: "Windsurf";
9
9
  value: string;
10
10
  })[];
11
+ interface McpCommand {
12
+ command: string;
13
+ args: string[];
14
+ }
11
15
  export declare function addMintlifyMcpServer(installTargets: string[]): Promise<void>;
16
+ export declare function setupMintlify(derivedTargets?: string[]): Promise<boolean>;
12
17
  export declare function addMcpServerToConfig(targets: string[] | undefined): Promise<string[]>;
18
+ export declare function setupClaudeCode(mcpCommand?: McpCommand): Promise<boolean>;
19
+ export declare function setupCursor(mcpCommand?: McpCommand): boolean;
20
+ export declare function setupWindsurf(mcpCommand?: McpCommand): boolean;
21
+ export {};
package/lib/mcp/setup.js CHANGED
@@ -5,17 +5,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.supportedTools = void 0;
7
7
  exports.addMintlifyMcpServer = addMintlifyMcpServer;
8
+ exports.setupMintlify = setupMintlify;
8
9
  exports.addMcpServerToConfig = addMcpServerToConfig;
10
+ exports.setupClaudeCode = setupClaudeCode;
11
+ exports.setupCursor = setupCursor;
12
+ exports.setupWindsurf = setupWindsurf;
9
13
  const logger_1 = require("../ui/logger");
10
14
  const en_1 = require("../../lang/en");
11
- const child_process_1 = require("child_process");
12
15
  const promptUtils_1 = require("../prompts/promptUtils");
13
16
  const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
14
17
  const errorHandlers_1 = require("../errorHandlers");
15
- const fs_1 = __importDefault(require("fs"));
16
18
  const command_1 = require("../../mcp-server/utils/command");
19
+ const child_process_1 = require("child_process");
17
20
  const path_1 = __importDefault(require("path"));
18
21
  const os_1 = __importDefault(require("os"));
22
+ const fs_extra_1 = __importDefault(require("fs-extra"));
23
+ const fs_1 = require("fs");
19
24
  const mcpServerName = 'hubspot-cli-mcp';
20
25
  const claudeCode = 'claude';
21
26
  const windsurf = 'windsurf';
@@ -26,12 +31,14 @@ exports.supportedTools = [
26
31
  { name: en_1.commands.mcp.setup.cursor, value: cursor },
27
32
  { name: en_1.commands.mcp.setup.windsurf, value: windsurf },
28
33
  ];
29
- const hsCommand = 'hs';
30
- const mcpCommandArgs = ['mcp', 'start'];
34
+ const defaultMcpCommand = {
35
+ command: 'hs',
36
+ args: ['mcp', 'start'],
37
+ };
31
38
  async function addMintlifyMcpServer(installTargets) {
32
39
  await runSetupFunction(() => setupMintlify(installTargets));
33
40
  }
34
- async function setupMintlify(derivedTargets) {
41
+ async function setupMintlify(derivedTargets = supportedMintlifyClients) {
35
42
  logger_1.uiLogger.info(en_1.commands.mcp.setup.installingDocSearch);
36
43
  logger_1.uiLogger.log('');
37
44
  return new Promise(resolve => {
@@ -101,15 +108,12 @@ function setupMcpConfigFile(config) {
101
108
  SpinniesManager_1.default.add('spinner', {
102
109
  text: config.configuringMessage,
103
110
  });
104
- if (!fs_1.default.existsSync(config.configPath)) {
105
- SpinniesManager_1.default.fail('spinner', {
106
- text: config.configMissingMessage,
107
- });
108
- return false;
111
+ if (!(0, fs_1.existsSync)(config.configPath)) {
112
+ fs_extra_1.default.writeFileSync(config.configPath, JSON.stringify({}, null, 2));
109
113
  }
110
114
  let mcpConfig = {};
111
115
  try {
112
- const configContent = fs_1.default.readFileSync(config.configPath, 'utf8');
116
+ const configContent = fs_extra_1.default.readFileSync(config.configPath, 'utf8');
113
117
  mcpConfig = JSON.parse(configContent);
114
118
  }
115
119
  catch (error) {
@@ -125,11 +129,10 @@ function setupMcpConfigFile(config) {
125
129
  }
126
130
  // Add or update HubSpot CLI MCP server
127
131
  mcpConfig.mcpServers[mcpServerName] = {
128
- command: hsCommand,
129
- args: mcpCommandArgs,
132
+ ...config.mcpCommand,
130
133
  };
131
134
  // Write the updated config
132
- fs_1.default.writeFileSync(config.configPath, JSON.stringify(mcpConfig, null, 2));
135
+ fs_extra_1.default.writeFileSync(config.configPath, JSON.stringify(mcpConfig, null, 2));
133
136
  SpinniesManager_1.default.succeed('spinner', {
134
137
  text: config.configuredMessage,
135
138
  });
@@ -143,7 +146,7 @@ function setupMcpConfigFile(config) {
143
146
  return false;
144
147
  }
145
148
  }
146
- async function setupClaudeCode() {
149
+ async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
147
150
  try {
148
151
  SpinniesManager_1.default.add('claudeCode', {
149
152
  text: en_1.commands.mcp.setup.spinners.configuringClaudeCode,
@@ -154,8 +157,7 @@ async function setupClaudeCode() {
154
157
  // Run claude mcp add command
155
158
  const mcpConfig = JSON.stringify({
156
159
  type: 'stdio',
157
- command: hsCommand,
158
- args: mcpCommandArgs,
160
+ ...mcpCommand,
159
161
  });
160
162
  const { stdout } = await (0, command_1.execAsync)('claude mcp list');
161
163
  if (stdout.includes(mcpServerName)) {
@@ -194,23 +196,23 @@ async function setupClaudeCode() {
194
196
  return false;
195
197
  }
196
198
  }
197
- function setupCursor() {
199
+ function setupCursor(mcpCommand = defaultMcpCommand) {
198
200
  const cursorConfigPath = path_1.default.join(os_1.default.homedir(), '.cursor', 'mcp.json');
199
201
  return setupMcpConfigFile({
200
202
  configPath: cursorConfigPath,
201
203
  configuringMessage: en_1.commands.mcp.setup.spinners.configuringCursor,
202
204
  configuredMessage: en_1.commands.mcp.setup.spinners.configuredCursor,
203
205
  failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureCursor,
204
- configMissingMessage: en_1.commands.mcp.setup.spinners.noCursorMcpFile(cursorConfigPath),
206
+ mcpCommand,
205
207
  });
206
208
  }
207
- function setupWindsurf() {
209
+ function setupWindsurf(mcpCommand = defaultMcpCommand) {
208
210
  const windsurfConfigPath = path_1.default.join(os_1.default.homedir(), '.codeium', 'windsurf', 'mcp_config.json');
209
211
  return setupMcpConfigFile({
210
212
  configPath: windsurfConfigPath,
211
213
  configuringMessage: en_1.commands.mcp.setup.spinners.configuringWindsurf,
212
214
  configuredMessage: en_1.commands.mcp.setup.spinners.configuredWindsurf,
213
215
  failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureWindsurf,
214
- configMissingMessage: en_1.commands.mcp.setup.spinners.noWindsurfFile(windsurfConfigPath),
216
+ mcpCommand,
215
217
  });
216
218
  }
@@ -109,7 +109,7 @@ describe('lib/middleware/configMiddleware', () => {
109
109
  $0: 'hs',
110
110
  };
111
111
  await (0, configMiddleware_1.injectAccountIdMiddleware)(argv);
112
- expect(argv.providedAccountId).toBeUndefined();
112
+ expect(argv.userProvidedAccount).toBeUndefined();
113
113
  expect(argv.derivedAccountId).toBe(123);
114
114
  expect(getAccountIdSpy).not.toHaveBeenCalled();
115
115
  process.env = originalEnv;
@@ -123,7 +123,7 @@ describe('lib/middleware/configMiddleware', () => {
123
123
  $0: 'hs',
124
124
  };
125
125
  await (0, configMiddleware_1.injectAccountIdMiddleware)(argv);
126
- expect(argv.providedAccountId).toBe('test-account');
126
+ expect(argv.userProvidedAccount).toBe('test-account');
127
127
  expect(argv.derivedAccountId).toBe(456);
128
128
  expect(getAccountIdSpy).toHaveBeenCalledWith('test-account');
129
129
  });
@@ -11,6 +11,9 @@ const exitCodes_1 = require("../enums/exitCodes");
11
11
  const lang_1 = require("../lang");
12
12
  const ui_1 = require("../ui");
13
13
  const utils_1 = require("./utils");
14
+ const parsing_1 = require("../parsing");
15
+ const logger_2 = require("../ui/logger");
16
+ const en_1 = require("../../lang/en");
14
17
  function handleDeprecatedEnvVariables(argv) {
15
18
  // HUBSPOT_PORTAL_ID is deprecated, but we'll still support it for now
16
19
  // The HubSpot GH Deploy Action still uses HUBSPOT_PORTAL_ID
@@ -29,9 +32,14 @@ function handleDeprecatedEnvVariables(argv) {
29
32
  async function injectAccountIdMiddleware(argv) {
30
33
  const { account } = argv;
31
34
  // Preserves the original --account flag for certain commands.
32
- argv.providedAccountId = account;
35
+ argv.userProvidedAccount = account;
33
36
  if (argv.useEnv && process.env.HUBSPOT_ACCOUNT_ID) {
34
- argv.derivedAccountId = parseInt(process.env.HUBSPOT_ACCOUNT_ID, 10);
37
+ try {
38
+ argv.derivedAccountId = (0, parsing_1.parseStringToNumber)(process.env.HUBSPOT_ACCOUNT_ID);
39
+ }
40
+ catch (err) {
41
+ logger_2.uiLogger.error(en_1.lib.configMiddleWare.invalidAccountIdEnvironmentVariable);
42
+ }
35
43
  }
36
44
  else {
37
45
  argv.derivedAccountId = (0, config_1.getAccountId)(account);
@@ -0,0 +1 @@
1
+ export declare function parseStringToNumber(maybeNumber: string): number;
package/lib/parsing.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseStringToNumber = parseStringToNumber;
4
+ const en_1 = require("../lang/en");
5
+ function parseStringToNumber(maybeNumber) {
6
+ const result = parseInt(maybeNumber, 10);
7
+ if (Number.isNaN(result) || !/^-?\d+$/.test(maybeNumber)) {
8
+ throw new Error(en_1.lib.parsing.unableToParseStringToNumber);
9
+ }
10
+ return result;
11
+ }
package/lib/polling.d.ts CHANGED
@@ -17,5 +17,5 @@ type PollingCallback<T extends GenericPollingResponse> = () => HubSpotPromise<T>
17
17
  export declare function poll<T extends GenericPollingResponse>(callback: PollingCallback<T>, statusLookup?: {
18
18
  successStates: string[];
19
19
  errorStates: string[];
20
- }): Promise<T>;
20
+ }, timeoutMs?: number): Promise<T>;
21
21
  export {};
package/lib/polling.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_POLLING_STATUS_LOOKUP = exports.DEFAULT_POLLING_STATES = void 0;
4
4
  exports.poll = poll;
5
5
  const constants_1 = require("./constants");
6
+ const en_1 = require("../lang/en");
6
7
  exports.DEFAULT_POLLING_STATES = {
7
8
  STARTED: 'STARTED',
8
9
  SUCCESS: 'SUCCESS',
@@ -18,7 +19,8 @@ exports.DEFAULT_POLLING_STATUS_LOOKUP = {
18
19
  exports.DEFAULT_POLLING_STATES.FAILURE,
19
20
  ],
20
21
  };
21
- function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
22
+ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP, timeoutMs = 60000 // Default 60 second timeout
23
+ ) {
22
24
  return new Promise((resolve, reject) => {
23
25
  const pollInterval = setInterval(async () => {
24
26
  try {
@@ -26,17 +28,25 @@ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
26
28
  const { status } = pollResp;
27
29
  if (statusLookup.successStates.includes(status)) {
28
30
  clearInterval(pollInterval);
31
+ clearTimeout(timeoutId);
29
32
  resolve(pollResp);
30
33
  }
31
34
  else if (statusLookup.errorStates.includes(status)) {
32
35
  clearInterval(pollInterval);
36
+ clearTimeout(timeoutId);
33
37
  reject(pollResp);
34
38
  }
35
39
  }
36
40
  catch (error) {
37
41
  clearInterval(pollInterval);
42
+ clearTimeout(timeoutId);
38
43
  reject(error);
39
44
  }
40
45
  }, constants_1.DEFAULT_POLLING_DELAY);
46
+ // Set a timeout to stop polling after specified duration
47
+ const timeoutId = setTimeout(() => {
48
+ clearInterval(pollInterval);
49
+ reject(new Error(en_1.lib.polling.timeoutError(timeoutMs)));
50
+ }, timeoutMs);
41
51
  });
42
52
  }
@@ -4,3 +4,4 @@ export declare function logProfileHeader(profileName: string): void;
4
4
  export declare function logProfileFooter(profile: HsProfileFile, includeVariables?: boolean): void;
5
5
  export declare function loadProfile(projectConfig: ProjectConfig | null, projectDir: string | null, profileName: string): HsProfileFile | undefined;
6
6
  export declare function exitIfUsingProfiles(projectConfig: ProjectConfig | null, projectDir: string | null): Promise<void>;
7
+ export declare function loadAndValidateProfile(projectConfig: ProjectConfig | null, projectDir: string | null, argsProfile: string | undefined): Promise<number | undefined>;
@@ -7,6 +7,7 @@ exports.logProfileHeader = logProfileHeader;
7
7
  exports.logProfileFooter = logProfileFooter;
8
8
  exports.loadProfile = loadProfile;
9
9
  exports.exitIfUsingProfiles = exitIfUsingProfiles;
10
+ exports.loadAndValidateProfile = loadAndValidateProfile;
10
11
  const path_1 = __importDefault(require("path"));
11
12
  const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
12
13
  const en_1 = require("../lang/en");
@@ -63,3 +64,20 @@ async function exitIfUsingProfiles(projectConfig, projectDir) {
63
64
  }
64
65
  }
65
66
  }
67
+ async function loadAndValidateProfile(projectConfig, projectDir, argsProfile) {
68
+ if (argsProfile) {
69
+ logProfileHeader(argsProfile);
70
+ const profile = loadProfile(projectConfig, projectDir, argsProfile);
71
+ if (!profile) {
72
+ (0, ui_1.uiLine)();
73
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
74
+ }
75
+ logProfileFooter(profile, true);
76
+ return profile.accountId;
77
+ }
78
+ else {
79
+ // A profile must be specified if this project has profiles configured
80
+ await exitIfUsingProfiles(projectConfig, projectDir);
81
+ }
82
+ return undefined;
83
+ }
@@ -66,6 +66,10 @@ async function v3AddComponent(args, projectDir, projectConfig) {
66
66
  components.push(path_1.default.join(projectConfig.platformVersion, parentComponent.path));
67
67
  }
68
68
  }
69
+ if (components.length === 0) {
70
+ logger_1.uiLogger.log(en_1.lib.projects.add.nothingAdded);
71
+ return;
72
+ }
69
73
  await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDir, {
70
74
  sourceDir: components,
71
75
  hideLogs: true,
@@ -228,7 +228,7 @@ function makePollTaskStatusFunc({ statusFn, structureFn, statusText, statusStrin
228
228
  }
229
229
  function pollBuildAutodeployStatus(accountId, taskName, buildId) {
230
230
  return new Promise((resolve, reject) => {
231
- let maxIntervals = (30 * 1000) / constants_1.DEFAULT_POLLING_DELAY; // Num of intervals in ~30s
231
+ let maxIntervals = (15 * 1000) / constants_1.DEFAULT_POLLING_DELAY; // Num of intervals in ~15s
232
232
  const pollInterval = setInterval(async () => {
233
233
  let build;
234
234
  try {
@@ -1,6 +1,6 @@
1
1
  import { ArgumentsCamelCase } from 'yargs';
2
2
  import { ProjectTemplateRepoConfig } from '../../../types/Projects';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse, ProjectNameAndDestPromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../../types/Yargs';
5
5
  import { RepoPath } from '@hubspot/local-dev-lib/types/Github';
6
6
  export type ProjectCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
@@ -19,5 +19,6 @@ export declare function handleProjectCreationFlow(args: ArgumentsCamelCase<Proje
19
19
  distribution?: string;
20
20
  repoConfig?: ProjectTemplateRepoConfig;
21
21
  projectContents?: string;
22
- createProjectPromptResponse: CreateProjectPromptResponse;
22
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
23
+ projectNameAndDestPromptResponse: ProjectNameAndDestPromptResponse;
23
24
  }>;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleProjectCreationFlow = handleProjectCreationFlow;
4
- const createProjectPrompt_1 = require("../../prompts/createProjectPrompt");
4
+ const selectProjectTemplatePrompt_1 = require("../../prompts/selectProjectTemplatePrompt");
5
+ const projectNameAndDestPrompt_1 = require("../../prompts/projectNameAndDestPrompt");
5
6
  const constants_1 = require("../../constants");
6
7
  const buildAndDeploy_1 = require("../buildAndDeploy");
7
8
  const v3_1 = require("./v3");
@@ -12,15 +13,17 @@ const exitCodes_1 = require("../../enums/exitCodes");
12
13
  async function handleProjectCreationFlow(args) {
13
14
  const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
14
15
  const repo = templateSource || constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
16
+ const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
15
17
  if ((0, buildAndDeploy_1.useV3Api)(platformVersion)) {
16
18
  const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await (0, v3_1.v3ComponentFlow)(platformVersion, projectBase, providedAuth, providedDistribution);
17
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
19
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
18
20
  return {
19
21
  authType,
20
22
  distribution,
21
23
  repoConfig,
22
24
  projectContents,
23
- createProjectPromptResponse,
25
+ selectProjectTemplatePromptResponse,
26
+ projectNameAndDestPromptResponse,
24
27
  };
25
28
  }
26
29
  const projectTemplates = await (0, legacy_1.getProjectTemplateListFromRepo)(repo, 'main');
@@ -28,6 +31,9 @@ async function handleProjectCreationFlow(args) {
28
31
  logger_1.uiLogger.error(en_1.commands.project.create.errors.failedToFetchProjectList);
29
32
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
30
33
  }
31
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, projectTemplates);
32
- return { createProjectPromptResponse };
34
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, projectTemplates);
35
+ return {
36
+ selectProjectTemplatePromptResponse,
37
+ projectNameAndDestPromptResponse,
38
+ };
33
39
  }
@@ -1,6 +1,6 @@
1
1
  import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects';
2
2
  import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  export declare const EMPTY_PROJECT = "empty";
5
5
  export declare const PROJECT_WITH_APP = "app";
6
6
  export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
@@ -16,8 +16,8 @@ type V3ComponentInfo = {
16
16
  componentTemplateChoices?: ComponentTemplateChoice[];
17
17
  };
18
18
  export declare function v3ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined): Promise<V3ComponentInfo>;
19
- export declare function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
- createProjectPromptResponse: CreateProjectPromptResponse;
19
+ export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
21
21
  platformVersion: string;
22
22
  repoConfig?: ProjectTemplateRepoConfig;
23
23
  projectContents?: string;
@@ -134,11 +134,11 @@ async function v3ComponentFlow(platformVersion, projectBase, providedAuth, provi
134
134
  repoConfig,
135
135
  };
136
136
  }
137
- function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
137
+ function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
138
138
  if (!(0, buildAndDeploy_1.useV3Api)(platformVersion)) {
139
139
  return [];
140
140
  }
141
- const components = createProjectPromptResponse.componentTemplates?.map((componentTemplate) => {
141
+ const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
142
142
  return path_1.default.join(platformVersion, componentTemplate.path);
143
143
  }) || [];
144
144
  if (projectContents && projectContents !== exports.EMPTY_PROJECT) {
@@ -14,9 +14,12 @@ declare class AppDevModeInterface {
14
14
  private get appNode();
15
15
  private get appData();
16
16
  private set appData(value);
17
+ private isAutomaticallyInstallable;
17
18
  private getAppInstallUrl;
18
19
  private fetchAppData;
19
20
  private checkMarketplaceAppInstalls;
21
+ private autoInstallStaticAuthApp;
22
+ private installAppOrOpenInstallUrl;
20
23
  private checkTestAccountAppInstallation;
21
24
  private setUpLocalDevServerMessageListeners;
22
25
  setup(args: any): Promise<void>;