@hubspot/cli 7.10.0 → 7.10.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 (199) hide show
  1. package/bin/cli.js +5 -4
  2. package/commands/__tests__/getStarted.test.js +10 -0
  3. package/commands/__tests__/project.test.js +3 -0
  4. package/commands/account/__tests__/rename.test.js +10 -3
  5. package/commands/account/auth.js +10 -14
  6. package/commands/account/clean.js +11 -19
  7. package/commands/account/createOverride.js +15 -11
  8. package/commands/account/info.js +8 -5
  9. package/commands/account/list.js +15 -19
  10. package/commands/account/remove.js +23 -22
  11. package/commands/account/removeOverride.js +6 -6
  12. package/commands/account/rename.js +2 -2
  13. package/commands/account/use.js +19 -8
  14. package/commands/app/__tests__/migrate.test.js +8 -4
  15. package/commands/app/migrate.js +2 -2
  16. package/commands/auth.js +18 -14
  17. package/commands/config/migrate.js +5 -5
  18. package/commands/customObject/createSchema.js +2 -3
  19. package/commands/customObject/updateSchema.js +2 -3
  20. package/commands/getStarted.js +2 -3
  21. package/commands/hubdb/__tests__/list.test.js +1 -0
  22. package/commands/hubdb/list.js +2 -2
  23. package/commands/init.js +36 -32
  24. package/commands/project/__tests__/deploy.test.js +10 -5
  25. package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
  26. package/commands/project/__tests__/lint.test.js +709 -0
  27. package/commands/project/__tests__/logs.test.js +4 -0
  28. package/commands/project/__tests__/validate.test.js +286 -28
  29. package/commands/project/cloneApp.js +2 -2
  30. package/commands/project/deploy.js +16 -8
  31. package/commands/project/dev/deprecatedFlow.js +4 -5
  32. package/commands/project/dev/index.js +19 -7
  33. package/commands/project/dev/unifiedFlow.js +4 -5
  34. package/commands/project/lint.d.ts +6 -0
  35. package/commands/project/lint.js +178 -0
  36. package/commands/project/logs.js +2 -3
  37. package/commands/project/migrate.js +4 -13
  38. package/commands/project/profile/add.js +6 -7
  39. package/commands/project/profile/delete.js +2 -2
  40. package/commands/project/upload.js +10 -4
  41. package/commands/project/validate.js +73 -13
  42. package/commands/project.js +2 -0
  43. package/commands/sandbox/__tests__/create.test.js +14 -5
  44. package/commands/sandbox/create.js +4 -5
  45. package/commands/sandbox/delete.js +23 -20
  46. package/commands/testAccount/create.js +2 -2
  47. package/commands/testAccount/delete.js +9 -8
  48. package/lang/en.d.ts +48 -11
  49. package/lang/en.js +58 -15
  50. package/lib/__tests__/buildAccount.test.js +22 -30
  51. package/lib/__tests__/commonOpts.test.js +9 -13
  52. package/lib/__tests__/developerTestAccounts.test.js +29 -17
  53. package/lib/__tests__/importData.test.js +20 -10
  54. package/lib/__tests__/oauth.test.js +19 -8
  55. package/lib/__tests__/projectProfiles.test.js +273 -32
  56. package/lib/__tests__/sandboxSync.test.js +33 -11
  57. package/lib/__tests__/sandboxes.test.js +30 -19
  58. package/lib/__tests__/usageTracking.test.js +10 -10
  59. package/lib/__tests__/validation.test.js +32 -32
  60. package/lib/accountTypes.d.ts +9 -9
  61. package/lib/accountTypes.js +2 -4
  62. package/lib/app/__tests__/migrate.test.js +15 -0
  63. package/lib/app/__tests__/migrate_legacy.test.js +9 -0
  64. package/lib/app/migrate_legacy.d.ts +2 -2
  65. package/lib/buildAccount.d.ts +4 -4
  66. package/lib/buildAccount.js +7 -14
  67. package/lib/commonOpts.js +3 -3
  68. package/lib/configMigrate.d.ts +2 -2
  69. package/lib/configMigrate.js +42 -18
  70. package/lib/configOptions.js +3 -2
  71. package/lib/developerTestAccounts.d.ts +3 -3
  72. package/lib/developerTestAccounts.js +4 -7
  73. package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
  74. package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
  75. package/lib/doctor/Doctor.js +4 -3
  76. package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
  77. package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
  78. package/lib/doctor/__tests__/Doctor.test.js +14 -0
  79. package/lib/importData.js +8 -7
  80. package/lib/links.js +5 -5
  81. package/lib/middleware/{__test__ → __tests__}/commandTargetingUtils.test.js +3 -3
  82. package/lib/middleware/{__test__ → __tests__}/configMiddleware.test.js +23 -22
  83. package/lib/middleware/{__test__ → __tests__}/gitMiddleware.test.js +9 -7
  84. package/lib/middleware/autoUpdateMiddleware.js +34 -23
  85. package/lib/middleware/commandTargetingUtils.js +3 -2
  86. package/lib/middleware/configMiddleware.d.ts +6 -1
  87. package/lib/middleware/configMiddleware.js +36 -15
  88. package/lib/middleware/fireAlarmMiddleware.js +4 -15
  89. package/lib/middleware/gitMiddleware.js +8 -4
  90. package/lib/oauth.d.ts +2 -2
  91. package/lib/oauth.js +8 -10
  92. package/lib/projectProfiles.d.ts +4 -3
  93. package/lib/projectProfiles.js +78 -32
  94. package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
  95. package/lib/projects/__tests__/DevServerManager.test.js +1 -0
  96. package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
  97. package/lib/projects/__tests__/deploy.test.js +1 -0
  98. package/lib/projects/__tests__/uieLinting.test.js +640 -0
  99. package/lib/projects/create/__tests__/v2.test.js +11 -0
  100. package/lib/projects/localDev/AppDevModeInterface.js +2 -2
  101. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
  102. package/lib/projects/localDev/LocalDevLogger.js +4 -4
  103. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
  104. package/lib/projects/localDev/helpers/account.d.ts +10 -10
  105. package/lib/projects/localDev/helpers/account.js +6 -11
  106. package/lib/projects/uieLinting.d.ts +33 -0
  107. package/lib/projects/uieLinting.js +222 -0
  108. package/lib/projects/urls.js +5 -6
  109. package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
  110. package/lib/prompts/accountNamePrompt.js +3 -3
  111. package/lib/prompts/accountsPrompt.d.ts +1 -1
  112. package/lib/prompts/accountsPrompt.js +6 -7
  113. package/lib/prompts/confirmImportDataPrompt.js +2 -2
  114. package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
  115. package/lib/prompts/downloadProjectPrompt.js +5 -2
  116. package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
  117. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  118. package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
  119. package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
  120. package/lib/prompts/sandboxesPrompt.js +7 -8
  121. package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
  122. package/lib/sandboxSync.d.ts +2 -2
  123. package/lib/sandboxSync.js +3 -9
  124. package/lib/sandboxes.d.ts +4 -4
  125. package/lib/sandboxes.js +6 -11
  126. package/lib/serverlessLogs.js +2 -2
  127. package/lib/theme/__tests__/migrate.test.js +15 -0
  128. package/lib/ui/index.js +6 -3
  129. package/lib/usageTracking.js +15 -8
  130. package/lib/validation.js +13 -11
  131. package/mcp-server/tools/cms/HsCreateFunctionTool.js +4 -2
  132. package/mcp-server/tools/cms/HsCreateModuleTool.js +4 -2
  133. package/mcp-server/tools/cms/HsCreateTemplateTool.js +4 -2
  134. package/mcp-server/tools/cms/HsFunctionLogsTool.js +4 -2
  135. package/mcp-server/tools/cms/HsListFunctionsTool.js +3 -1
  136. package/mcp-server/tools/cms/HsListTool.js +3 -1
  137. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
  138. package/mcp-server/tools/index.js +4 -0
  139. package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -2
  140. package/mcp-server/tools/project/CreateProjectTool.js +4 -2
  141. package/mcp-server/tools/project/CreateTestAccountTool.js +17 -7
  142. package/mcp-server/tools/project/DeployProjectTool.js +3 -1
  143. package/mcp-server/tools/project/DocFetchTool.js +6 -4
  144. package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
  145. package/mcp-server/tools/project/DocsSearchTool.js +10 -8
  146. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
  147. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -7
  148. package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
  149. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +26 -0
  150. package/mcp-server/tools/project/GetBuildLogsTool.js +125 -0
  151. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
  152. package/mcp-server/tools/project/GetBuildStatusTool.js +166 -0
  153. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
  154. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
  155. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
  156. package/mcp-server/tools/project/GuidedWalkthroughTool.js +5 -3
  157. package/mcp-server/tools/project/UploadProjectTools.js +3 -1
  158. package/mcp-server/tools/project/ValidateProjectTool.js +4 -2
  159. package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +12 -2
  160. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
  161. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +23 -11
  162. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
  163. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
  164. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.d.ts +1 -0
  165. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +305 -0
  166. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
  167. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
  168. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
  169. package/mcp-server/utils/__tests__/content.test.js +21 -20
  170. package/mcp-server/utils/__tests__/feedbackTracking.test.js +34 -28
  171. package/mcp-server/utils/config.d.ts +1 -0
  172. package/mcp-server/utils/config.js +10 -0
  173. package/mcp-server/utils/content.d.ts +1 -1
  174. package/mcp-server/utils/content.js +2 -2
  175. package/mcp-server/utils/feedbackTracking.d.ts +1 -1
  176. package/mcp-server/utils/feedbackTracking.js +3 -3
  177. package/mcp-server/utils/toolUsageTracking.js +4 -3
  178. package/package.json +9 -9
  179. package/ui/components/BoxWithTitle.d.ts +2 -1
  180. package/ui/components/BoxWithTitle.js +2 -2
  181. package/ui/components/StatusMessageBoxes.d.ts +5 -4
  182. package/ui/components/StatusMessageBoxes.js +8 -8
  183. package/lib/middleware/__test__/notificationsMiddleware.test.js +0 -8
  184. package/lib/middleware/notificationsMiddleware.d.ts +0 -1
  185. package/lib/middleware/notificationsMiddleware.js +0 -28
  186. package/lib/ui/boxen.d.ts +0 -5
  187. package/lib/ui/boxen.js +0 -26
  188. package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
  189. package/mcp-server/utils/cliConfig.d.ts +0 -1
  190. package/mcp-server/utils/cliConfig.js +0 -12
  191. /package/{lib/middleware/__test__/commandTargetingUtils.test.d.ts → commands/project/__tests__/lint.test.d.ts} +0 -0
  192. /package/lib/middleware/{__test__/configMiddleware.test.d.ts → __tests__/commandTargetingUtils.test.d.ts} +0 -0
  193. /package/lib/middleware/{__test__/gitMiddleware.test.d.ts → __tests__/configMiddleware.test.d.ts} +0 -0
  194. /package/lib/middleware/{__test__/notificationsMiddleware.test.d.ts → __tests__/gitMiddleware.test.d.ts} +0 -0
  195. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.d.ts +0 -0
  196. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.js +0 -0
  197. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.d.ts +0 -0
  198. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.js +0 -0
  199. /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → lib/projects/__tests__/uieLinting.test.d.ts} +0 -0
@@ -9,6 +9,8 @@ import { DocsSearchTool } from './project/DocsSearchTool.js';
9
9
  import { DocFetchTool } from './project/DocFetchTool.js';
10
10
  import { GetApiUsagePatternsByAppIdTool } from './project/GetApiUsagePatternsByAppIdTool.js';
11
11
  import { GetApplicationInfoTool } from './project/GetApplicationInfoTool.js';
12
+ import { GetBuildLogsTool } from './project/GetBuildLogsTool.js';
13
+ import { GetBuildStatusTool } from './project/GetBuildStatusTool.js';
12
14
  import { HsListTool } from './cms/HsListTool.js';
13
15
  import { HsCreateModuleTool } from './cms/HsCreateModuleTool.js';
14
16
  import { HsCreateTemplateTool } from './cms/HsCreateTemplateTool.js';
@@ -30,6 +32,8 @@ export function registerProjectTools(mcpServer) {
30
32
  new DocFetchTool(mcpServer).register(),
31
33
  new GetApiUsagePatternsByAppIdTool(mcpServer).register(),
32
34
  new GetApplicationInfoTool(mcpServer).register(),
35
+ new GetBuildLogsTool(mcpServer).register(),
36
+ new GetBuildStatusTool(mcpServer).register(),
33
37
  ];
34
38
  }
35
39
  export function registerCmsTools(mcpServer) {
@@ -6,6 +6,7 @@ import { absoluteCurrentWorkingDirectory, absoluteProjectPath, features, } from
6
6
  import { runCommandInDir } from '../../utils/project.js';
7
7
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
8
8
  import { trackToolUsage } from '../../utils/toolUsageTracking.js';
9
+ import { setupHubSpotConfig } from '../../utils/config.js';
9
10
  const inputSchema = {
10
11
  absoluteProjectPath,
11
12
  absoluteCurrentWorkingDirectory,
@@ -36,6 +37,7 @@ export class AddFeatureToProjectTool extends Tool {
36
37
  super(mcpServer);
37
38
  }
38
39
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, distribution, auth, features, addApp, }) {
40
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
39
41
  try {
40
42
  await trackToolUsage(toolName);
41
43
  let command = `hs project add`;
@@ -60,10 +62,10 @@ export class AddFeatureToProjectTool extends Tool {
60
62
  // If features isn't provided, pass an empty array to bypass the prompt
61
63
  command = addFlag(command, 'features', features || []);
62
64
  const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, command);
63
- return formatTextContents(absoluteCurrentWorkingDirectory, stdout, stderr);
65
+ return formatTextContents(stdout, stderr);
64
66
  }
65
67
  catch (error) {
66
- return formatTextContents(absoluteCurrentWorkingDirectory, error instanceof Error ? error.message : `${error}`);
68
+ return formatTextContents(error instanceof Error ? error.message : `${error}`);
67
69
  }
68
70
  }
69
71
  register() {
@@ -6,6 +6,7 @@ import { absoluteCurrentWorkingDirectory, features } from './constants.js';
6
6
  import { runCommandInDir } from '../../utils/project.js';
7
7
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
8
8
  import { trackToolUsage } from '../../utils/toolUsageTracking.js';
9
+ import { setupHubSpotConfig } from '../../utils/config.js';
9
10
  const inputSchema = {
10
11
  absoluteCurrentWorkingDirectory,
11
12
  name: z
@@ -41,6 +42,7 @@ export class CreateProjectTool extends Tool {
41
42
  super(mcpServer);
42
43
  }
43
44
  async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
45
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
44
46
  await trackToolUsage(toolName);
45
47
  let command = addFlag('hs project create', 'platform-version', '2025.2');
46
48
  const content = [];
@@ -77,10 +79,10 @@ export class CreateProjectTool extends Tool {
77
79
  command = addFlag(command, 'features', features || []);
78
80
  try {
79
81
  const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
80
- return formatTextContents(absoluteCurrentWorkingDirectory, stdout, stderr);
82
+ return formatTextContents(stdout, stderr);
81
83
  }
82
84
  catch (error) {
83
- return formatTextContents(absoluteCurrentWorkingDirectory, error instanceof Error ? error.message : `${error}`);
85
+ return formatTextContents(error instanceof Error ? error.message : `${error}`);
84
86
  }
85
87
  }
86
88
  register() {
@@ -6,8 +6,9 @@ import { formatTextContents, formatTextContent } from '../../utils/content.js';
6
6
  import { addFlag } from '../../utils/command.js';
7
7
  import { runCommandInDir } from '../../utils/project.js';
8
8
  import { ACCOUNT_LEVEL_CHOICES } from '../../../lib/constants.js';
9
- import { getAccountIdFromCliConfig } from '../../utils/cliConfig.js';
10
9
  import fs from 'fs';
10
+ import { getConfigAccountByName } from '@hubspot/local-dev-lib/config';
11
+ import { setupHubSpotConfig } from '../../utils/config.js';
11
12
  const inputSchema = {
12
13
  absoluteCurrentWorkingDirectory,
13
14
  configPath: z
@@ -61,6 +62,7 @@ export class CreateTestAccountTool extends Tool {
61
62
  super(mcpServer);
62
63
  }
63
64
  async handler({ absoluteCurrentWorkingDirectory, name, description, marketingLevel, opsLevel, serviceLevel, salesLevel, contentLevel, configPath, }) {
65
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
64
66
  await trackToolUsage(toolName);
65
67
  let command = 'hs test-account create';
66
68
  const content = [];
@@ -80,18 +82,26 @@ export class CreateTestAccountTool extends Tool {
80
82
  };
81
83
  }
82
84
  if (configJson.accountName) {
83
- const nameInConfig = getAccountIdFromCliConfig(absoluteCurrentWorkingDirectory, configJson.accountName);
84
- if (nameInConfig) {
85
- content.push(formatTextContent(`The account name "${configJson.accountName}" already exists in the CLI config. Please use a different name.`));
85
+ try {
86
+ if (getConfigAccountByName(configJson.accountName)) {
87
+ content.push(formatTextContent(`The account name "${configJson.accountName}" already exists in the CLI config. Please use a different name.`));
88
+ }
89
+ }
90
+ catch (error) {
91
+ // nothing to do here
86
92
  }
87
93
  }
88
94
  command = addFlag(command, 'config-path', configPath);
89
95
  }
90
96
  // Use flags if name is provided (when no config used)
91
97
  else if (name) {
92
- const nameInConfig = getAccountIdFromCliConfig(absoluteCurrentWorkingDirectory, name);
93
- if (nameInConfig) {
94
- content.push(formatTextContent(`The account name "${name}" already exists in the CLI config. Please use a different name.`));
98
+ try {
99
+ if (getConfigAccountByName(name)) {
100
+ content.push(formatTextContent(`The account name "${name}" already exists in the CLI config. Please use a different name.`));
101
+ }
102
+ }
103
+ catch (e) {
104
+ // nothing to do here
95
105
  }
96
106
  command = addFlag(command, 'name', name);
97
107
  command = addFlag(command, 'description', description || name);
@@ -5,6 +5,7 @@ import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constan
5
5
  import { runCommandInDir } from '../../utils/project.js';
6
6
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
7
7
  import { trackToolUsage } from '../../utils/toolUsageTracking.js';
8
+ import { setupHubSpotConfig } from '../../utils/config.js';
8
9
  const inputSchema = {
9
10
  absoluteProjectPath,
10
11
  absoluteCurrentWorkingDirectory,
@@ -22,6 +23,7 @@ export class DeployProjectTool extends Tool {
22
23
  super(mcpServer);
23
24
  }
24
25
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildNumber, }) {
26
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
25
27
  await trackToolUsage(toolName);
26
28
  let command = `hs project deploy`;
27
29
  const content = [];
@@ -38,7 +40,7 @@ export class DeployProjectTool extends Tool {
38
40
  };
39
41
  }
40
42
  const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, command);
41
- return formatTextContents(absoluteCurrentWorkingDirectory, stdout, stderr);
43
+ return formatTextContents(stdout, stderr);
42
44
  }
43
45
  register() {
44
46
  return this.mcpServer.registerTool(toolName, {
@@ -5,6 +5,7 @@ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
5
5
  import { absoluteCurrentWorkingDirectory, docUrl } from './constants.js';
6
6
  import { http } from '@hubspot/local-dev-lib/http/unauthed';
7
7
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
8
+ import { setupHubSpotConfig } from '../../utils/config.js';
8
9
  const inputSchema = {
9
10
  docUrl,
10
11
  absoluteCurrentWorkingDirectory,
@@ -19,6 +20,7 @@ export class DocFetchTool extends Tool {
19
20
  super(mcpServer);
20
21
  }
21
22
  async handler({ docUrl, absoluteCurrentWorkingDirectory, }) {
23
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
22
24
  await trackToolUsage(toolName);
23
25
  try {
24
26
  // Append .md extension to the URL
@@ -28,16 +30,16 @@ export class DocFetchTool extends Tool {
28
30
  });
29
31
  const content = response.data;
30
32
  if (!content || content.trim().length === 0) {
31
- return formatTextContents(absoluteCurrentWorkingDirectory, 'Document is empty or contains no content.');
33
+ return formatTextContents('Document is empty or contains no content.');
32
34
  }
33
- return formatTextContents(absoluteCurrentWorkingDirectory, content);
35
+ return formatTextContents(content);
34
36
  }
35
37
  catch (error) {
36
38
  if (isHubSpotHttpError(error)) {
37
- return formatTextContents(absoluteCurrentWorkingDirectory, error.toString());
39
+ return formatTextContents(error.toString());
38
40
  }
39
41
  const errorMessage = `Error fetching documentation: ${error instanceof Error ? error.message : String(error)}`;
40
- return formatTextContents(absoluteCurrentWorkingDirectory, errorMessage);
42
+ return formatTextContents(errorMessage);
41
43
  }
42
44
  }
43
45
  register() {
@@ -23,7 +23,7 @@ export interface DocsSearchResponse {
23
23
  type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
24
24
  export declare class DocsSearchTool extends Tool<InputSchemaType> {
25
25
  constructor(mcpServer: McpServer);
26
- handler({ absoluteCurrentWorkingDirectory, docsSearchQuery, }: InputSchemaType): Promise<TextContentResponse>;
26
+ handler({ docsSearchQuery, absoluteCurrentWorkingDirectory, }: InputSchemaType): Promise<TextContentResponse>;
27
27
  register(): RegisteredTool;
28
28
  }
29
29
  export {};
@@ -5,7 +5,8 @@ import { formatTextContents } from '../../utils/content.js';
5
5
  import { trackToolUsage } from '../../utils/toolUsageTracking.js';
6
6
  import { absoluteCurrentWorkingDirectory, docsSearchQuery, } from './constants.js';
7
7
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
8
- import { getAccountIdFromCliConfig } from '../../utils/cliConfig.js';
8
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
9
+ import { setupHubSpotConfig } from '../../utils/config.js';
9
10
  const inputSchema = {
10
11
  absoluteCurrentWorkingDirectory,
11
12
  docsSearchQuery,
@@ -19,12 +20,13 @@ export class DocsSearchTool extends Tool {
19
20
  constructor(mcpServer) {
20
21
  super(mcpServer);
21
22
  }
22
- async handler({ absoluteCurrentWorkingDirectory, docsSearchQuery, }) {
23
+ async handler({ docsSearchQuery, absoluteCurrentWorkingDirectory, }) {
24
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
23
25
  await trackToolUsage(toolName, { mode: docsSearchQuery });
24
- const accountId = getAccountIdFromCliConfig(absoluteCurrentWorkingDirectory);
26
+ const accountId = getConfigDefaultAccountIfExists()?.accountId;
25
27
  if (!accountId) {
26
28
  const authErrorMessage = `No account ID found. Please run \`hs account auth\` to configure an account, or set a default account with \`hs account use <account>\``;
27
- return formatTextContents(absoluteCurrentWorkingDirectory, authErrorMessage);
29
+ return formatTextContents(authErrorMessage);
28
30
  }
29
31
  try {
30
32
  const response = await http.post(accountId, {
@@ -35,21 +37,21 @@ export class DocsSearchTool extends Tool {
35
37
  });
36
38
  const results = response.data.results;
37
39
  if (!results || results.length === 0) {
38
- return formatTextContents(absoluteCurrentWorkingDirectory, 'No documentation found for your query.');
40
+ return formatTextContents('No documentation found for your query.');
39
41
  }
40
42
  const formattedResults = results
41
43
  .map(result => `**${result.title}**\n${result.description}\nURL: ${result.url}\nScore: ${result.score}\n\n${result.content}\n---\n`)
42
44
  .join('\n');
43
45
  const successMessage = `Found ${results.length} documentation results:\n\n${formattedResults}`;
44
- return formatTextContents(absoluteCurrentWorkingDirectory, successMessage);
46
+ return formatTextContents(successMessage);
45
47
  }
46
48
  catch (error) {
47
49
  if (isHubSpotHttpError(error)) {
48
50
  // Handle different status codes
49
- return formatTextContents(absoluteCurrentWorkingDirectory, error.toString());
51
+ return formatTextContents(error.toString());
50
52
  }
51
53
  const errorMessage = `Error searching documentation: ${error instanceof Error ? error.message : String(error)}`;
52
- return formatTextContents(absoluteCurrentWorkingDirectory, errorMessage);
54
+ return formatTextContents(errorMessage);
53
55
  }
54
56
  }
55
57
  register() {
@@ -20,7 +20,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
20
20
  export type GetApiUsagePatternsByAppIdInputSchema = z.infer<typeof inputSchemaZodObject>;
21
21
  export declare class GetApiUsagePatternsByAppIdTool extends Tool<GetApiUsagePatternsByAppIdInputSchema> {
22
22
  constructor(mcpServer: McpServer);
23
- handler({ absoluteCurrentWorkingDirectory, appId, startDate, endDate, }: GetApiUsagePatternsByAppIdInputSchema): Promise<TextContentResponse>;
23
+ handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }: GetApiUsagePatternsByAppIdInputSchema): Promise<TextContentResponse>;
24
24
  register(): RegisteredTool;
25
25
  }
26
26
  export {};
@@ -4,8 +4,9 @@ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
4
  import { http } from '@hubspot/local-dev-lib/http';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
6
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
7
- import { getAccountId } from '@hubspot/local-dev-lib/config';
7
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
8
8
  import { absoluteCurrentWorkingDirectory } from './constants.js';
9
+ import { setupHubSpotConfig } from '../../utils/config.js';
9
10
  const inputSchema = {
10
11
  absoluteCurrentWorkingDirectory,
11
12
  appId: z
@@ -30,14 +31,15 @@ export class GetApiUsagePatternsByAppIdTool extends Tool {
30
31
  constructor(mcpServer) {
31
32
  super(mcpServer);
32
33
  }
33
- async handler({ absoluteCurrentWorkingDirectory, appId, startDate, endDate, }) {
34
+ async handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }) {
35
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
34
36
  await trackToolUsage(toolName);
35
37
  try {
36
38
  // Get account ID from CLI config
37
- const accountId = getAccountId();
39
+ const accountId = getConfigDefaultAccountIfExists()?.accountId;
38
40
  if (!accountId) {
39
41
  const authErrorMessage = `No account ID found. Please run \`hs account auth\` to configure an account, or set a default account with \`hs account use <account>\``;
40
- return formatTextContents(absoluteCurrentWorkingDirectory, authErrorMessage);
42
+ return formatTextContents(authErrorMessage);
41
43
  }
42
44
  const response = await http.get(accountId, {
43
45
  url: `app/feature/utilization/public/v3/insights/app/${appId}/usage-patterns`,
@@ -49,15 +51,15 @@ export class GetApiUsagePatternsByAppIdTool extends Tool {
49
51
  // Format the response for display
50
52
  const { data } = response;
51
53
  const formattedResult = JSON.stringify(data, null, 2);
52
- return formatTextContents(absoluteCurrentWorkingDirectory, formattedResult);
54
+ return formatTextContents(formattedResult);
53
55
  }
54
56
  catch (error) {
55
57
  if (isHubSpotHttpError(error)) {
56
58
  // Handle HubSpot-specific HTTP errors
57
- return formatTextContents(absoluteCurrentWorkingDirectory, error.toString());
59
+ return formatTextContents(error.toString());
58
60
  }
59
61
  const errorMessage = `${error instanceof Error ? error.message : String(error)}`;
60
- return formatTextContents(absoluteCurrentWorkingDirectory, errorMessage);
62
+ return formatTextContents(errorMessage);
61
63
  }
62
64
  }
63
65
  register() {
@@ -4,8 +4,9 @@ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
4
  import { http } from '@hubspot/local-dev-lib/http';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
6
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
7
- import { getAccountId } from '@hubspot/local-dev-lib/config';
7
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
8
8
  import { absoluteCurrentWorkingDirectory } from './constants.js';
9
+ import { setupHubSpotConfig } from '../../utils/config.js';
9
10
  const inputSchema = { absoluteCurrentWorkingDirectory };
10
11
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
12
  const inputSchemaZodObject = z.object({ ...inputSchema });
@@ -15,13 +16,14 @@ export class GetApplicationInfoTool extends Tool {
15
16
  super(mcpServer);
16
17
  }
17
18
  async handler({ absoluteCurrentWorkingDirectory, }) {
19
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
18
20
  await trackToolUsage(toolName);
19
21
  try {
20
22
  // Get account ID from CLI config
21
- const accountId = getAccountId();
23
+ const accountId = getConfigDefaultAccountIfExists()?.accountId;
22
24
  if (!accountId) {
23
25
  const authErrorMessage = `No account ID found. Please run \`hs account auth\` to configure an account, or set a default account with \`hs account use <account>\``;
24
- return formatTextContents(absoluteCurrentWorkingDirectory, authErrorMessage);
26
+ return formatTextContents(authErrorMessage);
25
27
  }
26
28
  const response = await http.get(accountId, {
27
29
  url: `app/feature/utilization/public/v3/insights/apps`,
@@ -29,15 +31,15 @@ export class GetApplicationInfoTool extends Tool {
29
31
  // Format the response for display
30
32
  const { data } = response;
31
33
  const formattedResult = JSON.stringify(data, null, 2);
32
- return formatTextContents(absoluteCurrentWorkingDirectory, formattedResult);
34
+ return formatTextContents(formattedResult);
33
35
  }
34
36
  catch (error) {
35
37
  if (isHubSpotHttpError(error)) {
36
38
  // Handle HubSpot-specific HTTP errors
37
- return formatTextContents(absoluteCurrentWorkingDirectory, error.toString());
39
+ return formatTextContents(error.toString());
38
40
  }
39
41
  const errorMessage = `${error instanceof Error ? error.message : String(error)}`;
40
- return formatTextContents(absoluteCurrentWorkingDirectory, errorMessage);
42
+ return formatTextContents(errorMessage);
41
43
  }
42
44
  }
43
45
  register() {
@@ -0,0 +1,26 @@
1
+ import { TextContentResponse, Tool } from '../../types.js';
2
+ import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod';
4
+ declare const inputSchemaZodObject: z.ZodObject<{
5
+ absoluteProjectPath: z.ZodString;
6
+ absoluteCurrentWorkingDirectory: z.ZodString;
7
+ buildId: z.ZodNumber;
8
+ logLevel: z.ZodDefault<z.ZodOptional<z.ZodEnum<["ERROR", "WARN", "INFO", "ALL"]>>>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ buildId: number;
11
+ absoluteProjectPath: string;
12
+ absoluteCurrentWorkingDirectory: string;
13
+ logLevel: "ERROR" | "WARN" | "INFO" | "ALL";
14
+ }, {
15
+ buildId: number;
16
+ absoluteProjectPath: string;
17
+ absoluteCurrentWorkingDirectory: string;
18
+ logLevel?: "ERROR" | "WARN" | "INFO" | "ALL" | undefined;
19
+ }>;
20
+ export type GetBuildLogsInputSchema = z.infer<typeof inputSchemaZodObject>;
21
+ export declare class GetBuildLogsTool extends Tool<GetBuildLogsInputSchema> {
22
+ constructor(mcpServer: McpServer);
23
+ handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, logLevel, }: GetBuildLogsInputSchema): Promise<TextContentResponse>;
24
+ register(): RegisteredTool;
25
+ }
26
+ export {};
@@ -0,0 +1,125 @@
1
+ import { Tool } from '../../types.js';
2
+ import { z } from 'zod';
3
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
+ import { formatTextContents } from '../../utils/content.js';
5
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
+ import { http } from '@hubspot/local-dev-lib/http';
7
+ import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
8
+ import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
9
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
10
+ import { setupHubSpotConfig } from '../../utils/config.js';
11
+ const TOOL_NAME = 'get-build-logs';
12
+ const PROJECTS_LOGS_API_PATH = 'dfs/logging/v1';
13
+ const inputSchema = {
14
+ absoluteProjectPath,
15
+ absoluteCurrentWorkingDirectory,
16
+ buildId: z
17
+ .number()
18
+ .describe('Build ID to fetch logs for. Use get-build-status to find recent build IDs.'),
19
+ logLevel: z
20
+ .enum(['ERROR', 'WARN', 'INFO', 'ALL'])
21
+ .optional()
22
+ .default('ALL')
23
+ .describe('Filter logs by level. ERROR: Show only errors, WARN: Show only warnings, INFO: Show only info, ALL: Show all logs.'),
24
+ };
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
+ const inputSchemaZodObject = z.object({ ...inputSchema });
27
+ function flattenLogs(response) {
28
+ const allLogs = [];
29
+ response.logs.forEach(substep => {
30
+ substep.logs.forEach(log => {
31
+ allLogs.push(log);
32
+ });
33
+ });
34
+ return allLogs.sort((a, b) => a.timestamp - b.timestamp);
35
+ }
36
+ function filterLogsByLevel(logs, logLevel) {
37
+ if (logLevel === 'ALL') {
38
+ return logs;
39
+ }
40
+ return logs.filter(log => log.logLevel === logLevel);
41
+ }
42
+ function formatLogs(logs) {
43
+ if (logs.length === 0) {
44
+ return 'No logs found.';
45
+ }
46
+ return logs
47
+ .map(log => {
48
+ const timestamp = new Date(log.timestamp).toLocaleString('en-US', {
49
+ month: 'short',
50
+ day: 'numeric',
51
+ year: 'numeric',
52
+ hour: 'numeric',
53
+ minute: 'numeric',
54
+ second: 'numeric',
55
+ timeZoneName: 'short',
56
+ });
57
+ const component = log.pipelineSubstepName || `Step ${log.pipelineStepId}`;
58
+ return `[${log.logLevel}][${component}] ${timestamp} ${log.message}`;
59
+ })
60
+ .join('\n');
61
+ }
62
+ export class GetBuildLogsTool extends Tool {
63
+ constructor(mcpServer) {
64
+ super(mcpServer);
65
+ }
66
+ async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, logLevel, }) {
67
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
68
+ await trackToolUsage(TOOL_NAME);
69
+ try {
70
+ const accountId = getConfigDefaultAccountIfExists()?.accountId;
71
+ if (!accountId) {
72
+ return formatTextContents(absoluteCurrentWorkingDirectory, 'No account ID found. Please run `hs account auth` to configure an account, or set a default account with `hs account use <account>`');
73
+ }
74
+ const { projectConfig, projectDir } = await getProjectConfig(absoluteProjectPath);
75
+ validateProjectConfig(projectConfig, projectDir);
76
+ const projectName = projectConfig.name;
77
+ const response = await http.get(accountId, {
78
+ url: `${PROJECTS_LOGS_API_PATH}/logs/projects/${encodeURIComponent(projectName)}/builds/${buildId}`,
79
+ });
80
+ const buildLogsResponse = response.data;
81
+ if (!buildLogsResponse.logs || buildLogsResponse.logs.length === 0) {
82
+ return formatTextContents(absoluteCurrentWorkingDirectory, `No logs found for build #${buildId} in project '${projectName}'.`);
83
+ }
84
+ const allLogs = flattenLogs(buildLogsResponse);
85
+ if (allLogs.length === 0) {
86
+ return formatTextContents(absoluteCurrentWorkingDirectory, `No logs found for build #${buildId} in project '${projectName}'.`);
87
+ }
88
+ const filteredLogs = filterLogsByLevel(allLogs, logLevel);
89
+ let output;
90
+ if (filteredLogs.length === 0) {
91
+ // No logs match filter, show all logs instead
92
+ output = `No ${logLevel} level logs found for build #${buildId} in '${projectName}'.\nShowing all logs instead:\n\n${formatLogs(allLogs)}`;
93
+ }
94
+ else {
95
+ output = `Logs for build #${buildId} in '${projectName}' (${logLevel} level):\n\n${formatLogs(filteredLogs)}`;
96
+ }
97
+ return formatTextContents(absoluteCurrentWorkingDirectory, output);
98
+ }
99
+ catch (error) {
100
+ let errorMessage;
101
+ if (isHubSpotHttpError(error)) {
102
+ errorMessage = error.toString();
103
+ }
104
+ else if (error instanceof Error) {
105
+ errorMessage = error.message;
106
+ }
107
+ else {
108
+ errorMessage = String(error);
109
+ }
110
+ return formatTextContents(absoluteCurrentWorkingDirectory, errorMessage);
111
+ }
112
+ }
113
+ register() {
114
+ return this.mcpServer.registerTool(TOOL_NAME, {
115
+ title: 'Get HubSpot Project Build Logs',
116
+ description: 'Retrieves build logs for a specific HubSpot project build. Use this to debug build failures by viewing the full build pipeline output. This tool is for more comprehensive troubleshootings or addressing build WARNINGs, build errors should be troubleshooted with get-build-status tool first. Logs can be filtered by level (ERROR, WARN, INFO, or ALL). Use `hs project list-builds` first to identify the build ID and error messages.',
117
+ inputSchema,
118
+ annotations: {
119
+ readOnlyHint: true,
120
+ openWorldHint: true,
121
+ idempotentHint: true,
122
+ },
123
+ }, this.handler);
124
+ }
125
+ }
@@ -0,0 +1,26 @@
1
+ import { TextContentResponse, Tool } from '../../types.js';
2
+ import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod';
4
+ declare const inputSchemaZodObject: z.ZodObject<{
5
+ absoluteProjectPath: z.ZodString;
6
+ absoluteCurrentWorkingDirectory: z.ZodString;
7
+ buildId: z.ZodOptional<z.ZodNumber>;
8
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ limit: number;
11
+ absoluteProjectPath: string;
12
+ absoluteCurrentWorkingDirectory: string;
13
+ buildId?: number | undefined;
14
+ }, {
15
+ absoluteProjectPath: string;
16
+ absoluteCurrentWorkingDirectory: string;
17
+ limit?: number | undefined;
18
+ buildId?: number | undefined;
19
+ }>;
20
+ export type GetBuildStatusInputSchema = z.infer<typeof inputSchemaZodObject>;
21
+ export declare class GetBuildStatusTool extends Tool<GetBuildStatusInputSchema> {
22
+ constructor(mcpServer: McpServer);
23
+ handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, limit, }: GetBuildStatusInputSchema): Promise<TextContentResponse>;
24
+ register(): RegisteredTool;
25
+ }
26
+ export {};