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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/bin/cli.js +6 -2
  2. package/commands/__tests__/getStarted.test.js +0 -10
  3. package/commands/create/api-sample.d.ts +1 -1
  4. package/commands/create/app.d.ts +1 -1
  5. package/commands/create/function.d.ts +1 -1
  6. package/commands/create/index.d.ts +1 -1
  7. package/commands/create/module.d.ts +1 -1
  8. package/commands/create/react-app.d.ts +1 -1
  9. package/commands/create/template.d.ts +1 -1
  10. package/commands/create/vue-app.d.ts +1 -1
  11. package/commands/create/webpack-serverless.d.ts +1 -1
  12. package/commands/create/website-theme.d.ts +1 -1
  13. package/commands/create.d.ts +1 -1
  14. package/commands/getStarted.js +12 -27
  15. package/commands/mcp/setup.js +1 -0
  16. package/commands/mcp/start.d.ts +4 -1
  17. package/commands/mcp/start.js +8 -3
  18. package/commands/project/__tests__/deploy.test.js +28 -26
  19. package/commands/project/__tests__/devUnifiedFlow.test.js +19 -16
  20. package/commands/project/create.js +2 -2
  21. package/commands/project/deploy.d.ts +3 -2
  22. package/commands/project/deploy.js +63 -54
  23. package/commands/project/dev/unifiedFlow.js +7 -6
  24. package/commands/testAccount/__tests__/createConfig.test.js +0 -3
  25. package/commands/testAccount/create.js +12 -25
  26. package/commands/testAccount/createConfig.d.ts +0 -2
  27. package/commands/testAccount/createConfig.js +8 -9
  28. package/lang/en.d.ts +40 -23
  29. package/lang/en.js +41 -24
  30. package/lang/en.lyaml +0 -26
  31. package/lib/__tests__/buildAccount.test.js +31 -3
  32. package/lib/__tests__/usageTracking.test.js +8 -14
  33. package/lib/buildAccount.d.ts +8 -2
  34. package/lib/buildAccount.js +54 -5
  35. package/lib/mcp/setup.js +26 -5
  36. package/lib/projects/add/legacyAddComponent.js +2 -2
  37. package/lib/projects/add/v3AddComponent.js +2 -2
  38. package/lib/projects/localDev/DevServerManager.js +0 -2
  39. package/lib/projects/localDev/DevServerManagerV2.js +0 -2
  40. package/lib/projects/localDev/helpers.d.ts +1 -1
  41. package/lib/projects/localDev/helpers.js +2 -2
  42. package/lib/projects/upload.js +1 -1
  43. package/lib/prompts/createApiSamplePrompt.d.ts +1 -1
  44. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +11 -10
  45. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +73 -31
  46. package/lib/prompts/promptUtils.js +66 -56
  47. package/lib/prompts/sandboxesPrompt.d.ts +1 -1
  48. package/lib/sandboxSync.d.ts +1 -1
  49. package/lib/sandboxes.d.ts +1 -1
  50. package/lib/schema.js +5 -1
  51. package/lib/ui/index.js +1 -1
  52. package/lib/usageTracking.d.ts +11 -0
  53. package/lib/usageTracking.js +66 -75
  54. package/mcp-server/tools/project/AddFeatureToProject.js +4 -1
  55. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  56. package/mcp-server/tools/project/CreateProjectTool.js +4 -1
  57. package/mcp-server/tools/project/DeployProject.js +4 -1
  58. package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -1
  59. package/mcp-server/tools/project/UploadProjectTools.js +4 -1
  60. package/mcp-server/tools/project/ValidateProjectTool.js +4 -1
  61. package/mcp-server/tools/project/__tests__/AddFeatureToProject.test.js +1 -0
  62. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -0
  63. package/mcp-server/tools/project/__tests__/DeployProject.test.js +1 -0
  64. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -0
  65. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -0
  66. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -0
  67. package/mcp-server/utils/__tests__/project.test.js +9 -6
  68. package/mcp-server/utils/project.js +3 -0
  69. package/mcp-server/utils/toolUsageTracking.d.ts +1 -0
  70. package/mcp-server/utils/toolUsageTracking.js +22 -0
  71. package/package.json +4 -4
  72. /package/types/{cms.d.ts → Cms.d.ts} +0 -0
  73. /package/types/{cms.js → Cms.js} +0 -0
  74. /package/types/{sandboxes.d.ts → Sandboxes.d.ts} +0 -0
  75. /package/types/{sandboxes.js → Sandboxes.js} +0 -0
@@ -6,6 +6,7 @@ import { EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../lib/projects/create/v
6
6
  import { absoluteCurrentWorkingDirectory } from './constants.js';
7
7
  import { runCommandInDir } from '../../utils/project.js';
8
8
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
9
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
9
10
  const inputSchema = {
10
11
  absoluteCurrentWorkingDirectory,
11
12
  name: z
@@ -44,11 +45,13 @@ const inputSchema = {
44
45
  };
45
46
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
46
47
  const inputSchemaZodObject = z.object({ ...inputSchema });
48
+ const toolName = 'create-hubspot-project';
47
49
  export class CreateProjectTool extends Tool {
48
50
  constructor(mcpServer) {
49
51
  super(mcpServer);
50
52
  }
51
53
  async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
54
+ await trackToolUsage(toolName);
52
55
  let command = addFlag('hs project create', 'platform-version', '2025.2');
53
56
  const content = [];
54
57
  if (name) {
@@ -91,7 +94,7 @@ export class CreateProjectTool extends Tool {
91
94
  }
92
95
  }
93
96
  register() {
94
- return this.mcpServer.registerTool('create-hubspot-project', {
97
+ return this.mcpServer.registerTool(toolName, {
95
98
  title: 'Create HubSpot Project',
96
99
  description: 'Creates a HubSpot project with the provided name and outputs it in the provided destination',
97
100
  inputSchema,
@@ -4,6 +4,7 @@ import { addFlag } from '../../utils/command.js';
4
4
  import { absoluteProjectPath } from './constants.js';
5
5
  import { runCommandInDir } from '../../utils/project.js';
6
6
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
7
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
7
8
  const inputSchema = {
8
9
  absoluteProjectPath,
9
10
  buildNumber: z
@@ -14,11 +15,13 @@ const inputSchema = {
14
15
  const inputSchemaZodObject = z.object({
15
16
  ...inputSchema,
16
17
  });
18
+ const toolName = 'deploy-hubspot-project';
17
19
  export class DeployProject extends Tool {
18
20
  constructor(mcpServer) {
19
21
  super(mcpServer);
20
22
  }
21
23
  async handler({ absoluteProjectPath, buildNumber, }) {
24
+ await trackToolUsage(toolName);
22
25
  let command = `hs project deploy`;
23
26
  const content = [];
24
27
  if (!buildNumber) {
@@ -37,7 +40,7 @@ export class DeployProject extends Tool {
37
40
  return formatTextContents(stdout, stderr);
38
41
  }
39
42
  register() {
40
- return this.mcpServer.registerTool('deploy-hubspot-project', {
43
+ return this.mcpServer.registerTool(toolName, {
41
44
  title: 'Deploy a build of HubSpot Project',
42
45
  description: 'Takes a build number and a project name and deploys that build of the project. DO NOT run this tool unless the user specifies they would like to deploy the project.',
43
46
  inputSchema,
@@ -2,6 +2,7 @@ import { Tool } from '../../types.js';
2
2
  import { z } from 'zod';
3
3
  import { execAsync } from '../../utils/command.js';
4
4
  import { formatTextContents } from '../../utils/content.js';
5
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
5
6
  const nextCommands = {
6
7
  'hs init': 'hs auth',
7
8
  'hs auth': 'hs project create',
@@ -23,11 +24,13 @@ const inputSchema = {
23
24
  const inputSchemaZodObject = z.object({
24
25
  ...inputSchema,
25
26
  });
27
+ const toolName = 'guided-walkthrough-hubspot-cli';
26
28
  export class GuidedWalkthroughTool extends Tool {
27
29
  constructor(mcpServer) {
28
30
  super(mcpServer);
29
31
  }
30
32
  async handler({ command }) {
33
+ await trackToolUsage(toolName);
31
34
  if (command) {
32
35
  const { stdout } = await execAsync(`${command} --help`);
33
36
  return formatTextContents(`Display this help output for the user amd wait for them to acknowledge: ${stdout}. ${nextCommands[command] ? `Once they are ready, A good command to look at next is ${nextCommands[command]}` : ''}`);
@@ -35,7 +38,7 @@ export class GuidedWalkthroughTool extends Tool {
35
38
  return formatTextContents('Is there another command you would like to learn more about?');
36
39
  }
37
40
  register() {
38
- return this.mcpServer.registerTool('guided-walkthrough-hubspot-cli', {
41
+ return this.mcpServer.registerTool(toolName, {
39
42
  title: 'Guided walkthrough of the CLI',
40
43
  description: 'Give the user a guided walkthrough of the HubSpot CLI.',
41
44
  inputSchema: {
@@ -3,6 +3,7 @@ import { runCommandInDir } from '../../utils/project.js';
3
3
  import { absoluteProjectPath } from './constants.js';
4
4
  import z from 'zod';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
6
7
  const inputSchema = {
7
8
  absoluteProjectPath,
8
9
  };
@@ -10,16 +11,18 @@ const inputSchema = {
10
11
  const inputSchemaZodObject = z.object({
11
12
  ...inputSchema,
12
13
  });
14
+ const toolName = 'upload-hubspot-project';
13
15
  export class UploadProjectTools extends Tool {
14
16
  constructor(mcpServer) {
15
17
  super(mcpServer);
16
18
  }
17
19
  async handler({ absoluteProjectPath, }) {
20
+ await trackToolUsage(toolName);
18
21
  const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, `hs project upload --force-create`);
19
22
  return formatTextContents(stdout, stderr);
20
23
  }
21
24
  register() {
22
- return this.mcpServer.registerTool('upload-hubspot-project', {
25
+ return this.mcpServer.registerTool(toolName, {
23
26
  title: 'Upload HubSpot Project',
24
27
  description: 'Uploads the HubSpot project in current working directory. If the project does not exist, it will be created. MUST be ran from within the project directory. DO NOT run this tool unless the user specifies they would like to upload the project, it is potentially destructive',
25
28
  inputSchema,
@@ -3,16 +3,19 @@ import { z } from 'zod';
3
3
  import { absoluteProjectPath } from './constants.js';
4
4
  import { runCommandInDir } from '../../utils/project.js';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
+ import { trackToolUsage } from '../../utils/toolUsageTracking.js';
6
7
  const inputSchema = {
7
8
  absoluteProjectPath,
8
9
  };
9
10
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
11
  const inputSchemaZodObject = z.object({ ...inputSchema });
12
+ const toolName = 'validate-hubspot-project';
11
13
  export class ValidateProjectTool extends Tool {
12
14
  constructor(mcpServer) {
13
15
  super(mcpServer);
14
16
  }
15
17
  async handler({ absoluteProjectPath, }) {
18
+ await trackToolUsage(toolName);
16
19
  try {
17
20
  const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, 'hs project validate');
18
21
  return formatTextContents(stdout, stderr);
@@ -22,7 +25,7 @@ export class ValidateProjectTool extends Tool {
22
25
  }
23
26
  }
24
27
  register() {
25
- return this.mcpServer.registerTool('validate-hubspot-project', {
28
+ return this.mcpServer.registerTool(toolName, {
26
29
  title: 'Validate HubSpot Project',
27
30
  description: 'Validates the HubSpot project and its configuration files. This tool does not need to be ran before uploading the project',
28
31
  inputSchema,
@@ -6,6 +6,7 @@ vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
6
6
  vi.mock('../../../utils/project');
7
7
  vi.mock('../../../utils/command');
8
8
  vi.mock('../../../../lib/constants');
9
+ vi.mock('../../../utils/toolUsageTracking');
9
10
  const mockRunCommandInDir = runCommandInDir;
10
11
  const mockAddFlag = addFlag;
11
12
  describe('mcp-server/tools/project/AddFeatureToProject', () => {
@@ -8,6 +8,7 @@ vi.mock('../../../utils/project');
8
8
  vi.mock('../../../utils/command');
9
9
  vi.mock('../../../../lib/constants');
10
10
  vi.mock('../../../../lib/projects/create/v3');
11
+ vi.mock('../../../utils/toolUsageTracking');
11
12
  const mockRunCommandInDir = runCommandInDir;
12
13
  const mockAddFlag = addFlag;
13
14
  describe('mcp-server/tools/project/CreateProjectTool', () => {
@@ -4,6 +4,7 @@ import { addFlag } from '../../../utils/command.js';
4
4
  vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
5
5
  vi.mock('../../../utils/project');
6
6
  vi.mock('../../../utils/command');
7
+ vi.mock('../../../utils/toolUsageTracking');
7
8
  const mockRunCommandInDir = runCommandInDir;
8
9
  const mockAddFlag = addFlag;
9
10
  describe('mcp-server/tools/project/DeployProject', () => {
@@ -2,6 +2,7 @@ import { GuidedWalkthroughTool } from '../GuidedWalkthroughTool.js';
2
2
  import { execAsync } from '../../../utils/command.js';
3
3
  vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  vi.mock('../../../utils/command');
5
+ vi.mock('../../../utils/toolUsageTracking');
5
6
  const mockExecAsync = execAsync;
6
7
  describe('mcp-server/tools/project/GuidedWalkthroughTool', () => {
7
8
  let mockMcpServer;
@@ -2,6 +2,7 @@ import { UploadProjectTools } from '../UploadProjectTools.js';
2
2
  import { runCommandInDir } from '../../../utils/project.js';
3
3
  vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  vi.mock('../../../utils/project');
5
+ vi.mock('../../../utils/toolUsageTracking');
5
6
  const mockRunCommandInDir = runCommandInDir;
6
7
  describe('mcp-server/tools/project/UploadProjectTools', () => {
7
8
  let mockMcpServer;
@@ -2,6 +2,7 @@ import { ValidateProjectTool, } from '../ValidateProjectTool.js';
2
2
  import { runCommandInDir } from '../../../utils/project.js';
3
3
  vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
4
4
  vi.mock('../../../utils/project');
5
+ vi.mock('../../../utils/toolUsageTracking');
5
6
  const mockRunCommandInDir = runCommandInDir;
6
7
  describe('mcp-server/tools/project/ValidateProjectTool', () => {
7
8
  let mockMcpServer;
@@ -31,9 +31,10 @@ describe('mcp-server/utils/project', () => {
31
31
  expect(mockExistsSync).toHaveBeenCalledWith(mockDirectory);
32
32
  expect(mockMkdirSync).not.toHaveBeenCalled();
33
33
  expect(mockResolve).toHaveBeenCalledWith(mockDirectory);
34
- expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, {
34
+ expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, expect.objectContaining({
35
35
  cwd: mockResolvedPath,
36
- });
36
+ env: expect.any(Object),
37
+ }));
37
38
  expect(result).toEqual(expectedResult);
38
39
  });
39
40
  it('should create directory if it does not exist', async () => {
@@ -47,9 +48,10 @@ describe('mcp-server/utils/project', () => {
47
48
  expect(mockExistsSync).toHaveBeenCalledWith(mockDirectory);
48
49
  expect(mockMkdirSync).toHaveBeenCalledWith(mockDirectory);
49
50
  expect(mockResolve).toHaveBeenCalledWith(mockDirectory);
50
- expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, {
51
+ expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, expect.objectContaining({
51
52
  cwd: mockResolvedPath,
52
- });
53
+ env: expect.any(Object),
54
+ }));
53
55
  expect(result).toEqual(expectedResult);
54
56
  });
55
57
  it('should propagate execAsync errors', async () => {
@@ -57,9 +59,10 @@ describe('mcp-server/utils/project', () => {
57
59
  mockExistsSync.mockReturnValue(true);
58
60
  mockExecAsync.mockRejectedValue(error);
59
61
  await expect(runCommandInDir(mockDirectory, mockCommand)).rejects.toThrow('Command failed');
60
- expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, {
62
+ expect(mockExecAsync).toHaveBeenCalledWith(mockCommand, expect.objectContaining({
61
63
  cwd: mockResolvedPath,
62
- });
64
+ env: expect.any(Object),
65
+ }));
63
66
  });
64
67
  it('should handle stderr in results', async () => {
65
68
  const expectedResult = {
@@ -7,5 +7,8 @@ export async function runCommandInDir(directory, command) {
7
7
  }
8
8
  return execAsync(command, {
9
9
  cwd: path.resolve(directory),
10
+ env: {
11
+ ...process.env,
12
+ },
10
13
  });
11
14
  }
@@ -0,0 +1 @@
1
+ export declare function trackToolUsage(toolName: string): Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { trackUsage } from '@hubspot/local-dev-lib/trackUsage';
2
+ import { logger } from '@hubspot/local-dev-lib/logger';
3
+ import { EventClass, getNodeVersionData, getPlatform, } from '../../lib/usageTracking.js';
4
+ import { getAccountId, isTrackingAllowed } from '@hubspot/local-dev-lib/config';
5
+ export async function trackToolUsage(toolName) {
6
+ if (!isTrackingAllowed()) {
7
+ return;
8
+ }
9
+ const usageTrackingEvent = {
10
+ action: 'cli-mcp-tool-invocation',
11
+ os: getPlatform(),
12
+ ...getNodeVersionData(),
13
+ command: toolName,
14
+ type: process.env.HUBSPOT_MCP_AI_AGENT,
15
+ };
16
+ const accountId = getAccountId() || undefined;
17
+ try {
18
+ logger.info('Tracking tool usage');
19
+ await trackUsage('cli-interaction', EventClass.INTERACTION, usageTrackingEvent, accountId);
20
+ }
21
+ catch (error) { }
22
+ }
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "7.7.21-experimental.0",
3
+ "version": "7.7.22-experimental.0",
4
4
  "description": "The official CLI for developing on HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/HubSpot/hubspot-cli",
7
7
  "type": "module",
8
8
  "dependencies": {
9
- "@hubspot/local-dev-lib": "3.12.0",
10
- "@hubspot/project-parsing-lib": "0.5.1",
9
+ "@hubspot/local-dev-lib": "3.14.0",
10
+ "@hubspot/project-parsing-lib": "0.0.21-experimental.1",
11
11
  "@hubspot/serverless-dev-runtime": "7.0.6",
12
12
  "@hubspot/theme-preview-dev-server": "0.0.10",
13
- "@hubspot/ui-extensions-dev-server": "0.9.2",
13
+ "@hubspot/ui-extensions-dev-server": "0.9.4",
14
14
  "archiver": "7.0.1",
15
15
  "boxen": "8.0.1",
16
16
  "chalk": "5.4.1",
File without changes
File without changes
File without changes
File without changes