@hubspot/cli 8.2.0-experimental.2 → 8.2.1-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 (147) hide show
  1. package/commands/account/clean.js +1 -1
  2. package/commands/account/list.js +1 -1
  3. package/commands/account/remove.js +1 -1
  4. package/commands/account/rename.js +1 -1
  5. package/commands/account/use.js +1 -1
  6. package/commands/api.d.ts +4 -1
  7. package/commands/api.js +11 -14
  8. package/commands/config/set.js +24 -5
  9. package/commands/customObject/createSchema.js +2 -3
  10. package/commands/customObject/updateSchema.js +2 -3
  11. package/commands/getStarted.js +1 -0
  12. package/commands/hubdb/list.d.ts +1 -1
  13. package/commands/hubdb/list.js +7 -8
  14. package/commands/mcp/setup.d.ts +2 -0
  15. package/commands/mcp/setup.js +29 -1
  16. package/commands/project/appInstallStatus.d.ts +2 -1
  17. package/commands/project/appInstallStatus.js +21 -19
  18. package/commands/project/create.js +0 -1
  19. package/commands/project/deploy.d.ts +2 -1
  20. package/commands/project/deploy.js +31 -14
  21. package/commands/project/dev/index.js +18 -64
  22. package/commands/project/dev/unifiedFlow.js +3 -1
  23. package/commands/project/info.d.ts +2 -1
  24. package/commands/project/info.js +8 -6
  25. package/commands/project/installApp.d.ts +2 -1
  26. package/commands/project/installApp.js +26 -27
  27. package/commands/project/list.js +1 -1
  28. package/commands/project/listBuilds.d.ts +1 -1
  29. package/commands/project/listBuilds.js +8 -6
  30. package/commands/project/logs.js +2 -4
  31. package/commands/project/profile/add.d.ts +2 -1
  32. package/commands/project/profile/add.js +22 -1
  33. package/commands/project/profile/delete.d.ts +1 -1
  34. package/commands/project/release/create.d.ts +2 -1
  35. package/commands/project/release/create.js +68 -69
  36. package/commands/project/release/info.d.ts +2 -1
  37. package/commands/project/release/info.js +7 -6
  38. package/commands/project/release/list.d.ts +2 -1
  39. package/commands/project/release/list.js +15 -7
  40. package/commands/project/upload.d.ts +4 -1
  41. package/commands/project/upload.js +48 -21
  42. package/commands/project/validate.d.ts +1 -1
  43. package/commands/project/watch.js +3 -2
  44. package/commands/project.js +2 -2
  45. package/commands/sandbox/delete.js +2 -3
  46. package/commands/testAccount/create.d.ts +2 -1
  47. package/commands/testAccount/create.js +7 -7
  48. package/commands/testAccount/importData.d.ts +1 -1
  49. package/lang/en.d.ts +61 -33
  50. package/lang/en.js +77 -48
  51. package/lib/app/urls.js +2 -3
  52. package/lib/commonOpts.js +6 -1
  53. package/lib/configOptions.d.ts +10 -10
  54. package/lib/configOptions.js +10 -11
  55. package/lib/constants.d.ts +2 -0
  56. package/lib/constants.js +2 -0
  57. package/lib/dependencyManagement.js +7 -7
  58. package/lib/getStartedV2Actions.js +2 -1
  59. package/lib/importData.js +3 -4
  60. package/lib/jsonOutput.d.ts +109 -0
  61. package/lib/jsonOutput.js +94 -0
  62. package/lib/links.js +6 -5
  63. package/lib/mcp/clients.d.ts +1 -1
  64. package/lib/mcp/clients.js +8 -1
  65. package/lib/mcp/setup.d.ts +9 -4
  66. package/lib/mcp/setup.js +115 -35
  67. package/lib/npm/npmCli.d.ts +1 -0
  68. package/lib/npm/npmCli.js +13 -0
  69. package/lib/projects/builds.d.ts +2 -0
  70. package/lib/projects/builds.js +22 -0
  71. package/lib/projects/create/v2.js +1 -0
  72. package/lib/projects/installApp.d.ts +1 -1
  73. package/lib/projects/installApp.js +8 -3
  74. package/lib/projects/localDev/DevSessionManager.d.ts +2 -2
  75. package/lib/projects/localDev/DevSessionManager.js +4 -30
  76. package/lib/projects/localDev/LocalDevProcess.js +7 -5
  77. package/lib/projects/localDev/helpers/account.d.ts +0 -7
  78. package/lib/projects/localDev/helpers/account.js +1 -80
  79. package/lib/projects/localDev/helpers/project.js +3 -2
  80. package/lib/projects/release.d.ts +4 -0
  81. package/lib/projects/release.js +90 -0
  82. package/lib/projects/ui.d.ts +1 -0
  83. package/lib/projects/ui.js +14 -0
  84. package/lib/projects/upload.d.ts +10 -2
  85. package/lib/projects/upload.js +14 -7
  86. package/lib/projects/urls.d.ts +0 -1
  87. package/lib/projects/urls.js +6 -13
  88. package/lib/yargs/makeWrappedYargsHandler.d.ts +5 -1
  89. package/lib/yargs/makeWrappedYargsHandler.js +123 -65
  90. package/mcp-server/Tool.d.ts +8 -3
  91. package/mcp-server/Tool.js +58 -32
  92. package/mcp-server/server.js +10 -6
  93. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
  94. package/mcp-server/tools/cms/HsCreateFunctionTool.js +10 -17
  95. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
  96. package/mcp-server/tools/cms/HsCreateModuleTool.js +12 -18
  97. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +2 -2
  98. package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -10
  99. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +2 -2
  100. package/mcp-server/tools/cms/HsFunctionLogsTool.js +9 -9
  101. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +2 -2
  102. package/mcp-server/tools/cms/HsListFunctionsTool.js +7 -7
  103. package/mcp-server/tools/cms/HsListTool.d.ts +2 -2
  104. package/mcp-server/tools/cms/HsListTool.js +6 -10
  105. package/mcp-server/tools/index.js +2 -0
  106. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -2
  107. package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -9
  108. package/mcp-server/tools/project/AuthAccountTool.d.ts +18 -0
  109. package/mcp-server/tools/project/AuthAccountTool.js +78 -0
  110. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -2
  111. package/mcp-server/tools/project/CreateProjectTool.js +13 -12
  112. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +2 -2
  113. package/mcp-server/tools/project/CreateTestAccountTool.js +14 -15
  114. package/mcp-server/tools/project/DeployProjectTool.d.ts +2 -2
  115. package/mcp-server/tools/project/DeployProjectTool.js +10 -10
  116. package/mcp-server/tools/project/DocFetchTool.js +1 -1
  117. package/mcp-server/tools/project/DocsSearchTool.js +8 -7
  118. package/mcp-server/tools/project/FindProjectsTool.js +1 -1
  119. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +2 -1
  120. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -8
  121. package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +2 -1
  122. package/mcp-server/tools/project/GetApplicationInfoTool.js +12 -9
  123. package/mcp-server/tools/project/GetBuildLogsTool.js +11 -7
  124. package/mcp-server/tools/project/GetBuildStatusTool.js +11 -7
  125. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +2 -1
  126. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
  127. package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
  128. package/mcp-server/tools/project/UploadProjectTools.d.ts +2 -2
  129. package/mcp-server/tools/project/UploadProjectTools.js +9 -8
  130. package/mcp-server/tools/project/ValidateProjectTool.d.ts +2 -2
  131. package/mcp-server/tools/project/ValidateProjectTool.js +5 -4
  132. package/mcp-server/tools/project/constants.d.ts +1 -0
  133. package/mcp-server/tools/project/constants.js +2 -1
  134. package/mcp-server/utils/command.d.ts +25 -2
  135. package/mcp-server/utils/command.js +67 -17
  136. package/mcp-server/utils/config.js +5 -0
  137. package/mcp-server/utils/logger.d.ts +3 -0
  138. package/mcp-server/utils/logger.js +30 -0
  139. package/mcp-server/utils/toolUsageTracking.js +18 -3
  140. package/package.json +11 -9
  141. package/types/Yargs.d.ts +3 -1
  142. package/commands/project/dev/deprecatedFlow.d.ts +0 -11
  143. package/commands/project/dev/deprecatedFlow.js +0 -180
  144. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +0 -43
  145. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +0 -128
  146. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +0 -64
  147. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +0 -394
package/lib/mcp/setup.js CHANGED
@@ -11,29 +11,36 @@ import fs from 'fs-extra';
11
11
  import { existsSync } from 'fs';
12
12
  const mcpServerName = MCP_SERVER_NAME;
13
13
  const claudeCode = 'claude';
14
- const windsurf = 'windsurf';
15
14
  const cursor = 'cursor';
15
+ const devin = 'devin';
16
16
  const vscode = 'vscode';
17
17
  const codex = 'codex';
18
18
  const gemini = 'gemini';
19
+ const opencode = 'opencode';
20
+ const OTHER_TOOL = 'other';
19
21
  const clientLabels = {
20
22
  codex: commands.mcp.setup.codex,
21
23
  claude: commands.mcp.setup.claudeCode,
22
24
  cursor: commands.mcp.setup.cursor,
25
+ devin: commands.mcp.setup.devin,
23
26
  gemini: commands.mcp.setup.gemini,
27
+ opencode: commands.mcp.setup.opencode,
24
28
  vscode: commands.mcp.setup.vsCode,
25
- windsurf: commands.mcp.setup.windsurf,
26
29
  };
27
- export const supportedTools = MCP_CLIENTS.map(client => ({
28
- name: clientLabels[client.id],
29
- value: client.id,
30
- }));
30
+ export const supportedTools = [
31
+ ...MCP_CLIENTS.map(client => ({
32
+ name: clientLabels[client.id],
33
+ value: client.id,
34
+ })),
35
+ { name: commands.mcp.setup.other, value: OTHER_TOOL },
36
+ ];
31
37
  const defaultMcpCommand = {
32
38
  command: 'hs',
33
39
  args: ['mcp', 'start'],
34
40
  };
35
- export async function configureMcpServer(targets) {
41
+ export async function configureMcpServer(options) {
36
42
  try {
43
+ const { targets, standalone, cliVersion: cliVersionFlag } = options;
37
44
  let derivedTargets = [];
38
45
  if (!targets || targets.length === 0) {
39
46
  const { selectedTargets } = await promptUser({
@@ -41,6 +48,7 @@ export async function configureMcpServer(targets) {
41
48
  type: 'checkbox',
42
49
  message: commands.mcp.setup.prompts.targets,
43
50
  choices: supportedTools,
51
+ pageSize: supportedTools.length,
44
52
  validate: (choices) => {
45
53
  return choices.length === 0
46
54
  ? commands.mcp.setup.prompts.targetsRequired
@@ -52,23 +60,34 @@ export async function configureMcpServer(targets) {
52
60
  else {
53
61
  derivedTargets = targets;
54
62
  }
55
- // Prompt for standalone mode
56
- const { useStandaloneMode } = await promptUser({
57
- name: 'useStandaloneMode',
58
- type: 'confirm',
59
- message: commands.mcp.setup.prompts.standaloneMode,
60
- default: false,
61
- });
62
- const { cliVersion } = useStandaloneMode
63
- ? await promptUser({
64
- name: 'cliVersion',
65
- type: 'input',
66
- message: commands.mcp.setup.prompts.cliVersion,
67
- validate: (v) => !v || /^[\d]+\.[\d]+\.[\d]+([-+][\w.]+)?$/.test(v.trim())
68
- ? true
69
- : 'Please enter a valid semver version (e.g. 8.0.1) or leave blank for latest.',
70
- })
71
- : { cliVersion: '' };
63
+ const onlyOther = derivedTargets.length === 1 && derivedTargets[0] === OTHER_TOOL;
64
+ let useStandaloneMode = onlyOther ? false : standalone;
65
+ if (useStandaloneMode === undefined) {
66
+ const response = await promptUser({
67
+ name: 'useStandaloneMode',
68
+ type: 'confirm',
69
+ message: commands.mcp.setup.prompts.standaloneMode,
70
+ default: false,
71
+ });
72
+ useStandaloneMode = response.useStandaloneMode;
73
+ }
74
+ let cliVersion = '';
75
+ if (useStandaloneMode) {
76
+ if (cliVersionFlag !== undefined) {
77
+ cliVersion = cliVersionFlag;
78
+ }
79
+ else {
80
+ const response = await promptUser({
81
+ name: 'cliVersion',
82
+ type: 'input',
83
+ message: commands.mcp.setup.prompts.cliVersion,
84
+ validate: (v) => !v || /^[\d]+\.[\d]+\.[\d]+([-+][\w.]+)?$/.test(v.trim())
85
+ ? true
86
+ : 'Please enter a valid semver version (e.g. 8.0.1) or leave blank for latest.',
87
+ });
88
+ cliVersion = response.cliVersion;
89
+ }
90
+ }
72
91
  const cliPackage = cliVersion
73
92
  ? `@hubspot/cli@${cliVersion}`
74
93
  : '@hubspot/cli';
@@ -91,8 +110,8 @@ export async function configureMcpServer(targets) {
91
110
  if (derivedTargets.includes(cursor)) {
92
111
  await runSetupFunction(() => setupCursor(mcpCommand));
93
112
  }
94
- if (derivedTargets.includes(windsurf)) {
95
- await runSetupFunction(() => setupWindsurf(mcpCommand));
113
+ if (derivedTargets.includes(devin)) {
114
+ await runSetupFunction(() => setupDevin(mcpCommand));
96
115
  }
97
116
  if (derivedTargets.includes(vscode)) {
98
117
  await runSetupFunction(() => setupVsCode(mcpCommand));
@@ -103,8 +122,17 @@ export async function configureMcpServer(targets) {
103
122
  if (derivedTargets.includes(gemini)) {
104
123
  await runSetupFunction(() => setupGemini(mcpCommand));
105
124
  }
106
- uiLogger.info(commands.mcp.setup.success(derivedTargets));
107
- return derivedTargets;
125
+ if (derivedTargets.includes(opencode)) {
126
+ await runSetupFunction(() => setupOpenCode(mcpCommand));
127
+ }
128
+ if (derivedTargets.includes(OTHER_TOOL)) {
129
+ logOtherToolInstructions(mcpCommand);
130
+ }
131
+ const configuredTargets = derivedTargets.filter(t => t !== OTHER_TOOL);
132
+ if (configuredTargets.length > 0) {
133
+ uiLogger.info(commands.mcp.setup.success(configuredTargets));
134
+ }
135
+ return configuredTargets;
108
136
  }
109
137
  catch (error) {
110
138
  SpinniesManager.fail('mcpSetup', {
@@ -261,14 +289,14 @@ export function setupCursor(mcpCommand = defaultMcpCommand) {
261
289
  mcpCommand: buildCommandWithAgentString(mcpCommand, cursor),
262
290
  });
263
291
  }
264
- export function setupWindsurf(mcpCommand = defaultMcpCommand) {
265
- const windsurfConfigPath = path.join(os.homedir(), ...getMcpClientPathSegments(windsurf));
292
+ export function setupDevin(mcpCommand = defaultMcpCommand) {
293
+ const devinConfigPath = path.join(os.homedir(), ...getMcpClientPathSegments(devin));
266
294
  return setupMcpConfigFile({
267
- configPath: windsurfConfigPath,
268
- configuringMessage: commands.mcp.setup.spinners.configuringWindsurf,
269
- configuredMessage: commands.mcp.setup.spinners.configuredWindsurf,
270
- failedMessage: commands.mcp.setup.spinners.failedToConfigureWindsurf,
271
- mcpCommand: buildCommandWithAgentString(mcpCommand, windsurf),
295
+ configPath: devinConfigPath,
296
+ configuringMessage: commands.mcp.setup.spinners.configuringDevin,
297
+ configuredMessage: commands.mcp.setup.spinners.configuredDevin,
298
+ failedMessage: commands.mcp.setup.spinners.failedToConfigureDevin,
299
+ mcpCommand: buildCommandWithAgentString(mcpCommand, devin),
272
300
  });
273
301
  }
274
302
  export async function setupCodex(mcpCommand = defaultMcpCommand) {
@@ -330,6 +358,58 @@ export async function setupGemini(mcpCommand = defaultMcpCommand) {
330
358
  return false;
331
359
  }
332
360
  }
361
+ export async function setupOpenCode(mcpCommand = defaultMcpCommand) {
362
+ try {
363
+ SpinniesManager.add('openCodeSpinner', {
364
+ text: commands.mcp.setup.spinners.configuringOpenCode,
365
+ });
366
+ try {
367
+ await execAsync('opencode --version');
368
+ }
369
+ catch (error) {
370
+ SpinniesManager.fail('openCodeSpinner', {
371
+ text: commands.mcp.setup.spinners.openCodeNotFound,
372
+ });
373
+ return false;
374
+ }
375
+ const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, opencode);
376
+ await execAsync(`opencode mcp add "${mcpServerName}"${buildEnvFlagString(mcpCommand)} -- ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
377
+ SpinniesManager.succeed('openCodeSpinner', {
378
+ text: commands.mcp.setup.spinners.configuredOpenCode,
379
+ });
380
+ return true;
381
+ }
382
+ catch (error) {
383
+ SpinniesManager.fail('openCodeSpinner', {
384
+ text: commands.mcp.setup.spinners.openCodeInstallFailed,
385
+ });
386
+ logError(error);
387
+ return false;
388
+ }
389
+ }
390
+ function logOtherToolInstructions(mcpCommand) {
391
+ const { otherInstructions } = commands.mcp.setup;
392
+ uiLogger.log('');
393
+ uiLogger.log(otherInstructions.header);
394
+ uiLogger.log(otherInstructions.docsNote);
395
+ uiLogger.log('');
396
+ uiLogger.log(` ${otherInstructions.commandLabel}`);
397
+ uiLogger.log(` ${mcpCommand.command} ${mcpCommand.args.join(' ')}`);
398
+ uiLogger.log('');
399
+ uiLogger.log(` ${otherInstructions.jsonLabel}`);
400
+ uiLogger.log('');
401
+ const jsonConfig = {
402
+ mcpServers: {
403
+ [mcpServerName]: mcpCommand,
404
+ },
405
+ };
406
+ const indented = JSON.stringify(jsonConfig, null, 2)
407
+ .split('\n')
408
+ .map(line => ` ${line}`)
409
+ .join('\n');
410
+ uiLogger.log(indented);
411
+ uiLogger.log('');
412
+ }
333
413
  function buildCommandWithAgentString(mcpCommand, agent) {
334
414
  const mcpCommandCopy = structuredClone(mcpCommand);
335
415
  mcpCommandCopy.args.push('--ai-agent', agent);
@@ -4,6 +4,7 @@ export declare function getLatestPackageVersion(packageName: string): Promise<{
4
4
  latest: string | null;
5
5
  next: string | null;
6
6
  }>;
7
+ export declare function getNpmExecErrorOutput(error: unknown): string | null;
7
8
  export declare function executeInstall(packages?: string[], flags?: string | null, options?: {
8
9
  cwd?: string;
9
10
  }): Promise<void>;
package/lib/npm/npmCli.js CHANGED
@@ -23,6 +23,19 @@ export async function getLatestPackageVersion(packageName) {
23
23
  return { latest: null, next: null };
24
24
  }
25
25
  }
26
+ function isNpmExecError(error) {
27
+ return (typeof error === 'object' &&
28
+ error !== null &&
29
+ ('stderr' in error || 'stdout' in error));
30
+ }
31
+ export function getNpmExecErrorOutput(error) {
32
+ if (!isNpmExecError(error)) {
33
+ return null;
34
+ }
35
+ const stderr = error.stderr?.trim();
36
+ const stdout = error.stdout?.trim();
37
+ return stderr || stdout || null;
38
+ }
26
39
  export async function executeInstall(packages = [], flags, options) {
27
40
  const installCommand = `${DEFAULT_PACKAGE_MANAGER} install${flags ? ` ${flags}` : ''} ${packages.join(' ')}`;
28
41
  uiLogger.debug('Running', installCommand);
@@ -0,0 +1,2 @@
1
+ import { type Build } from '@hubspot/local-dev-lib/types/Build';
2
+ export declare function getLastSuccessfulBuild(accountId: number, projectName: string, latestBuild?: Build): Promise<Build | undefined>;
@@ -0,0 +1,22 @@
1
+ import { fetchProjectBuilds } from '@hubspot/local-dev-lib/api/projects';
2
+ import { BUILD_STATUS } from '@hubspot/local-dev-lib/enums/build';
3
+ export async function getLastSuccessfulBuild(accountId, projectName, latestBuild) {
4
+ if (latestBuild?.status === BUILD_STATUS.SUCCESS) {
5
+ return latestBuild;
6
+ }
7
+ let after;
8
+ let hasMore = true;
9
+ while (hasMore) {
10
+ const { data: { results, paging }, } = await fetchProjectBuilds(accountId, projectName, {
11
+ limit: 100,
12
+ ...(after ? { after } : {}),
13
+ });
14
+ const successfulBuild = results.find(build => build.status === BUILD_STATUS.SUCCESS);
15
+ if (successfulBuild) {
16
+ return successfulBuild;
17
+ }
18
+ after = paging?.next?.after;
19
+ hasMore = !!after;
20
+ }
21
+ return undefined;
22
+ }
@@ -48,6 +48,7 @@ export async function createV2App(providedAuth, providedDistribution) {
48
48
  const componentTypeToGateMap = {
49
49
  [AppEventsKey]: FEATURES.APP_EVENTS,
50
50
  'workflow-action-tool': FEATURES.AGENT_TOOLS,
51
+ 'crm-bulk-action': FEATURES.APP_ACTIONS,
51
52
  };
52
53
  export async function calculateComponentTemplateChoices(components, authType, distribution, accountId, projectMetadata) {
53
54
  const enabledComponents = [];
@@ -43,7 +43,7 @@ export declare function resolveProjectAccountId(derivedAccountId: number, projec
43
43
  accountId: number;
44
44
  profileName?: string;
45
45
  } | null>;
46
- export declare function loadInstallableAppNode(projectConfig: ProjectConfig, projectDir: string, accountId: number): Promise<AppIRNode | null>;
46
+ export declare function loadInstallableAppNode(projectConfig: ProjectConfig, projectDir: string, accountId: number, force?: boolean): Promise<AppIRNode | null>;
47
47
  export declare function resolveValidInstallAccount(targetAccountId: number, force: boolean, formatOutputAsJson: boolean): Promise<number | null>;
48
48
  export declare function resolveProjectId(options: UploadAndDeployOptions): Promise<number | null>;
49
49
  export declare function resolveAppMetadata(options: UploadAndDeployOptions & {
@@ -6,6 +6,7 @@ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
6
  import { getAllConfigAccounts, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
7
7
  import { translateForLocalDev } from '@hubspot/project-parsing-lib/translate';
8
8
  import { commands } from '../../lang/en.js';
9
+ import { warnAboutSkippedHsMetaFiles } from './ui.js';
9
10
  import { isAppDeveloperAccount } from '../accountTypes.js';
10
11
  import { ApiErrorContext, debugError, logError, } from '../errorHandlers/index.js';
11
12
  import { confirmPrompt, listPrompt } from '../prompts/promptUtils.js';
@@ -33,15 +34,19 @@ export async function resolveProjectAccountId(derivedAccountId, projectConfig, p
33
34
  return null;
34
35
  }
35
36
  }
36
- export async function loadInstallableAppNode(projectConfig, projectDir, accountId) {
37
+ export async function loadInstallableAppNode(projectConfig, projectDir, accountId, force = false) {
37
38
  let appNode;
38
39
  try {
39
- const { intermediateNodesIndexedByUid } = await translateForLocalDev({
40
+ const { intermediateRepresentation, skippedHsMetaFiles } = await translateForLocalDev({
40
41
  projectSourceDir: path.join(projectDir, projectConfig.srcDir),
41
42
  platformVersion: projectConfig.platformVersion,
42
43
  accountId,
43
44
  }, { skipValidation: true });
44
- appNode = getAppNodeFromProjectNodes(intermediateNodesIndexedByUid);
45
+ const shouldContinue = await warnAboutSkippedHsMetaFiles(skippedHsMetaFiles, force, false);
46
+ if (!shouldContinue) {
47
+ return null;
48
+ }
49
+ appNode = getAppNodeFromProjectNodes(intermediateRepresentation.intermediateNodesIndexedByUid);
45
50
  }
46
51
  catch (error) {
47
52
  debugError(error);
@@ -2,11 +2,11 @@ import LocalDevLogger from './LocalDevLogger.js';
2
2
  import { ExitFunction } from '../../../types/Yargs.js';
3
3
  type DevSessionManagerConstructorOptions = {
4
4
  targetTestingAccountId: number;
5
- localDevLogger?: LocalDevLogger;
5
+ localDevLogger: LocalDevLogger;
6
6
  exit: ExitFunction;
7
7
  };
8
8
  declare class DevSessionManager {
9
- localDevLogger?: LocalDevLogger;
9
+ localDevLogger: LocalDevLogger;
10
10
  targetTestingAccountId: number;
11
11
  protected devSessionId: number | undefined;
12
12
  private heartbeatInterval;
@@ -1,9 +1,7 @@
1
1
  import { getActiveServers } from '@hubspot/local-dev-lib/portManager';
2
2
  import { devSessionHeartbeat, registerDevSession, deleteDevSession, } from './helpers/devSessionsApi.js';
3
3
  import { EXIT_CODES } from '../../enums/exitCodes.js';
4
- import { uiLogger } from '../../ui/logger.js';
5
4
  import { lib } from '../../../lang/en.js';
6
- import { getErrorMessage } from '../../errorHandlers/index.js';
7
5
  class DevSessionManager {
8
6
  localDevLogger;
9
7
  targetTestingAccountId;
@@ -21,13 +19,7 @@ class DevSessionManager {
21
19
  }
22
20
  validateSessionIdExists() {
23
21
  if (!this.devSessionId) {
24
- if (this.localDevLogger) {
25
- this.localDevLogger.devSessionMissingSessionIdError();
26
- }
27
- else {
28
- // Fallback for deprecated local dev manager
29
- uiLogger.error(lib.LocalDevManager.devSession.missingSessionIdError);
30
- }
22
+ this.localDevLogger.devSessionMissingSessionIdError();
31
23
  throw new Error(lib.LocalDevManager.devSession.missingSessionIdError);
32
24
  }
33
25
  }
@@ -39,13 +31,7 @@ class DevSessionManager {
39
31
  this.devSessionId = registerDevSessionResponse.data.sessionId;
40
32
  }
41
33
  catch (e) {
42
- if (this.localDevLogger) {
43
- this.localDevLogger.devSessionRegistrationError(e);
44
- }
45
- else {
46
- // Fallback for deprecated local dev manager
47
- uiLogger.error(lib.LocalDevManager.devSession.registrationError(getErrorMessage(e)));
48
- }
34
+ this.localDevLogger.devSessionRegistrationError(e);
49
35
  return false;
50
36
  }
51
37
  try {
@@ -73,13 +59,7 @@ class DevSessionManager {
73
59
  this.heartbeatRetries++;
74
60
  return;
75
61
  }
76
- if (this.localDevLogger) {
77
- this.localDevLogger.devSessionHeartbeatError(e);
78
- }
79
- else {
80
- // Fallback for deprecated local dev manager
81
- uiLogger.error(lib.LocalDevManager.devSession.heartbeatError(getErrorMessage(e)));
82
- }
62
+ this.localDevLogger.devSessionHeartbeatError(e);
83
63
  return this.exit(EXIT_CODES.ERROR);
84
64
  }
85
65
  }, 30000);
@@ -91,13 +71,7 @@ class DevSessionManager {
91
71
  await deleteDevSession(this.targetTestingAccountId, this.devSessionId);
92
72
  }
93
73
  catch (e) {
94
- if (this.localDevLogger) {
95
- this.localDevLogger.devSessionDeletionError(e);
96
- }
97
- else {
98
- // Fallback for deprecated local dev manager
99
- uiLogger.error(lib.LocalDevManager.devSession.deletionError(getErrorMessage(e)));
100
- }
74
+ this.localDevLogger.devSessionDeletionError(e);
101
75
  return false;
102
76
  }
103
77
  }
@@ -95,8 +95,8 @@ class LocalDevProcess {
95
95
  });
96
96
  return true;
97
97
  }
98
- getIntermediateRepresentation(projectNodesAtLastDeploy) {
99
- return translateForLocalDev({
98
+ async getIntermediateRepresentation(projectNodesAtLastDeploy) {
99
+ const { intermediateRepresentation } = await translateForLocalDev({
100
100
  projectSourceDir: path.join(this.state.projectDir, this.state.projectConfig.srcDir),
101
101
  platformVersion: this.state.projectConfig.platformVersion,
102
102
  accountId: this.state.targetProjectAccountId,
@@ -104,6 +104,7 @@ class LocalDevProcess {
104
104
  projectNodesAtLastUpload: projectNodesAtLastDeploy,
105
105
  profile: this.state.profile,
106
106
  });
107
+ return intermediateRepresentation;
107
108
  }
108
109
  async updateProjectNodes() {
109
110
  const intermediateRepresentation = await this.getIntermediateRepresentation(this.state.projectNodesAtLastDeploy);
@@ -152,14 +153,14 @@ class LocalDevProcess {
152
153
  return this.state.actions.exit(EXIT_CODES.ERROR);
153
154
  }
154
155
  this.logger.startupMessage();
155
- if (isConfigFlagEnabled(CONFIG_FLAGS.AUTO_OPEN_BROWSER, true)) {
156
- this.openLocalDevUi();
157
- }
158
156
  await this.startDevServers();
159
157
  const devSessionRegistered = await this.devSessionManager.registerSession();
160
158
  if (!devSessionRegistered) {
161
159
  return this.state.actions.exit(EXIT_CODES.ERROR);
162
160
  }
161
+ if (isConfigFlagEnabled(CONFIG_FLAGS.AUTO_OPEN_BROWSER, true)) {
162
+ this.openLocalDevUi();
163
+ }
163
164
  this.state.devServersStarted = true;
164
165
  this.logger.monitorConsoleOutput();
165
166
  }
@@ -197,6 +198,7 @@ class LocalDevProcess {
197
198
  projectDir: this.state.projectDir,
198
199
  callbackFunc: pollProjectBuildAndDeploy,
199
200
  sendIR: true,
201
+ force: true,
200
202
  });
201
203
  const deploy = result?.deployResult;
202
204
  if (uploadError) {
@@ -1,13 +1,6 @@
1
1
  import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
2
  import { Environment } from '@hubspot/local-dev-lib/types/Accounts';
3
3
  import { DeveloperTestAccount } from '@hubspot/local-dev-lib/types/developerTestAccounts.js';
4
- import { ProjectDevTargetAccountPromptResponse } from '../../../prompts/projectDevTargetAccountPrompt.js';
5
- import { ExitFunction } from '../../../../types/Yargs.js';
6
- export declare function confirmDefaultAccountIsTarget(accountConfig: HubSpotConfigAccount, exit: ExitFunction): Promise<void>;
7
- export declare function checkIfDefaultAccountIsSupported(accountConfig: HubSpotConfigAccount, hasPublicApps: boolean, exit: ExitFunction): Promise<void>;
8
- export declare function checkIfParentAccountIsAuthed(accountConfig: HubSpotConfigAccount): void;
9
- export declare function checkIfAccountFlagIsSupported(accountConfig: HubSpotConfigAccount, hasPublicApps: boolean): void;
10
- export declare function suggestRecommendedNestedAccount(accounts: HubSpotConfigAccount[], accountConfig: HubSpotConfigAccount, hasPublicApps: boolean): Promise<ProjectDevTargetAccountPromptResponse>;
11
4
  export declare function createSandboxForLocalDev(accountId: number, accountConfig: HubSpotConfigAccount, env: Environment): Promise<number>;
12
5
  export declare function createDeveloperTestAccountForLocalDev(accountId: number, accountConfig: HubSpotConfigAccount, env: Environment, useV2?: boolean): Promise<number>;
13
6
  export declare function useExistingDevTestAccount(env: Environment, account: DeveloperTestAccount): Promise<boolean>;
@@ -1,5 +1,3 @@
1
- import { HUBSPOT_ACCOUNT_TYPE_STRINGS } from '@hubspot/local-dev-lib/constants/config';
2
- import { getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
3
1
  import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
4
2
  import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
5
3
  import { isMissingScopeError } from '@hubspot/local-dev-lib/errors/index';
@@ -7,15 +5,6 @@ import { PERSONAL_ACCESS_KEY_AUTH_METHOD } from '@hubspot/local-dev-lib/constant
7
5
  import { getSandboxUsageLimits } from '@hubspot/local-dev-lib/api/sandboxHubs';
8
6
  import { uiLogger } from '../../../ui/logger.js';
9
7
  import { lib } from '../../../../lang/en.js';
10
- import { EXIT_CODES } from '../../../enums/exitCodes.js';
11
- import { confirmDefaultAccountPrompt } from '../../../prompts/projectDevTargetAccountPrompt.js';
12
- import { isUnifiedAccount } from '../../../accountTypes.js';
13
- import { isAppDeveloperAccount } from '../../../accountTypes.js';
14
- import { isDeveloperTestAccount } from '../../../accountTypes.js';
15
- import { uiAccountDescription } from '../../../ui/index.js';
16
- import { uiLine } from '../../../ui/index.js';
17
- import { selectDeveloperTestTargetAccountPrompt } from '../../../prompts/projectDevTargetAccountPrompt.js';
18
- import { selectSandboxTargetAccountPrompt } from '../../../prompts/projectDevTargetAccountPrompt.js';
19
8
  import { validateSandboxUsageLimits } from '../../../sandboxes.js';
20
9
  import { logError } from '../../../errorHandlers/index.js';
21
10
  import { hubspotAccountNamePrompt } from '../../../prompts/accountNamePrompt.js';
@@ -25,73 +14,6 @@ import { buildDeveloperTestAccount, saveAccountToConfig, buildV2Sandbox, } from
25
14
  import { debugError } from '../../../errorHandlers/index.js';
26
15
  import { listPrompt } from '../../../prompts/promptUtils.js';
27
16
  import { confirmUseExistingDeveloperTestAccountPrompt } from '../../../prompts/projectDevTargetAccountPrompt.js';
28
- // If the user passed in the --account flag, confirm they want to use that account as
29
- // their target account, otherwise exit
30
- export async function confirmDefaultAccountIsTarget(accountConfig, exit) {
31
- if (!accountConfig.name || !accountConfig.accountType) {
32
- uiLogger.error(lib.localDevHelpers.account.confirmDefaultAccountIsTarget.configError);
33
- return exit(EXIT_CODES.ERROR);
34
- }
35
- uiLogger.log('');
36
- const useDefaultAccount = await confirmDefaultAccountPrompt(accountConfig.name, HUBSPOT_ACCOUNT_TYPE_STRINGS[accountConfig.accountType]);
37
- if (!useDefaultAccount) {
38
- uiLogger.log(lib.localDevHelpers.account.confirmDefaultAccountIsTarget
39
- .declineDefaultAccountExplanation);
40
- return exit(EXIT_CODES.SUCCESS);
41
- }
42
- }
43
- // Confirm the default account is supported for the type of apps being developed
44
- export async function checkIfDefaultAccountIsSupported(accountConfig, hasPublicApps, exit) {
45
- const defaultAccountIsUnified = await isUnifiedAccount(accountConfig);
46
- if (hasPublicApps &&
47
- !(isAppDeveloperAccount(accountConfig) ||
48
- isDeveloperTestAccount(accountConfig) ||
49
- defaultAccountIsUnified)) {
50
- uiLogger.error(lib.localDevHelpers.account.checkIfDefaultAccountIsSupported.publicApp);
51
- return exit(EXIT_CODES.SUCCESS);
52
- }
53
- else if (!hasPublicApps && isAppDeveloperAccount(accountConfig)) {
54
- uiLogger.error(lib.localDevHelpers.account.checkIfDefaultAccountIsSupported.privateApp);
55
- return exit(EXIT_CODES.SUCCESS);
56
- }
57
- }
58
- export function checkIfParentAccountIsAuthed(accountConfig) {
59
- if (!accountConfig.parentAccountId ||
60
- !getConfigAccountIfExists(accountConfig.parentAccountId)?.accountId) {
61
- throw new Error(lib.localDevHelpers.account.checkIfParentAccountIsAuthed.notAuthedError(accountConfig.parentAccountId || '', uiAccountDescription(accountConfig.accountId)));
62
- }
63
- }
64
- // Confirm the default account is a developer account if developing public apps
65
- export function checkIfAccountFlagIsSupported(accountConfig, hasPublicApps) {
66
- if (hasPublicApps) {
67
- if (!isDeveloperTestAccount(accountConfig)) {
68
- throw new Error(lib.localDevHelpers.account.validateAccountOption
69
- .invalidPublicAppAccount);
70
- }
71
- checkIfParentAccountIsAuthed(accountConfig);
72
- }
73
- else if (isAppDeveloperAccount(accountConfig)) {
74
- throw new Error(lib.localDevHelpers.account.validateAccountOption.invalidPrivateAppAccount);
75
- }
76
- }
77
- // If the user isn't using the recommended account type, prompt them to use or create one
78
- export async function suggestRecommendedNestedAccount(accounts, accountConfig, hasPublicApps) {
79
- uiLogger.log('');
80
- uiLine();
81
- if (hasPublicApps) {
82
- uiLogger.log(lib.localDevHelpers.account.validateAccountOption
83
- .publicAppNonDeveloperTestAccountWarning);
84
- }
85
- else {
86
- uiLogger.log(lib.localDevHelpers.account.validateAccountOption.nonSandboxWarning);
87
- }
88
- uiLine();
89
- uiLogger.log('');
90
- const targetAccountPrompt = hasPublicApps
91
- ? selectDeveloperTestTargetAccountPrompt
92
- : selectSandboxTargetAccountPrompt;
93
- return targetAccountPrompt(accounts, accountConfig);
94
- }
95
17
  // Create a new sandbox and return its accountId
96
18
  export async function createSandboxForLocalDev(accountId, accountConfig, env) {
97
19
  try {
@@ -166,8 +88,7 @@ export async function useExistingDevTestAccount(env, account) {
166
88
  const useExistingDevTestAcct = await confirmUseExistingDeveloperTestAccountPrompt(account);
167
89
  if (!useExistingDevTestAcct) {
168
90
  uiLogger.log('');
169
- uiLogger.log(lib.localDevHelpers.account.confirmDefaultAccountIsTarget
170
- .declineDefaultAccountExplanation);
91
+ uiLogger.log(lib.localDevHelpers.account.declineDefaultAccountExplanation);
171
92
  uiLogger.log('');
172
93
  return false;
173
94
  }
@@ -85,6 +85,7 @@ export async function createInitialBuildForNewProject(projectConfig, projectDir,
85
85
  skipValidation: true,
86
86
  sendIR,
87
87
  profile,
88
+ force: true,
88
89
  });
89
90
  if (uploadError) {
90
91
  if (isSpecifiedError(uploadError, {
@@ -173,12 +174,12 @@ export async function getDeployedProjectNodes(projectConfig, accountId, deployed
173
174
  }
174
175
  }
175
176
  const deployedProjectSourceDir = path.join(tempDir, deployedSrcDir);
176
- const { intermediateNodesIndexedByUid } = await translate({
177
+ const { intermediateRepresentation } = await translate({
177
178
  projectSourceDir: deployedProjectSourceDir,
178
179
  platformVersion: projectConfig.platformVersion,
179
180
  accountId: accountId,
180
181
  }, { profile });
181
- return intermediateNodesIndexedByUid;
182
+ return intermediateRepresentation.intermediateNodesIndexedByUid;
182
183
  }
183
184
  finally {
184
185
  if (tempDir && (await fs.pathExists(tempDir))) {
@@ -0,0 +1,4 @@
1
+ import { type Release } from '../../api/releases.js';
2
+ export declare function resolveBuildId(accountId: number, projectName: string, buildOption?: number, force?: boolean): Promise<number | null | undefined>;
3
+ export declare function validateBuildForRelease(accountId: number, projectName: string, buildId: number): Promise<boolean>;
4
+ export declare function executeRelease(accountId: number, projectName: string, buildId: number): Promise<Release>;