@hubspot/cli 7.7.22-experimental.0 → 7.7.24-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.
- package/commands/account/auth.js +15 -4
- package/commands/auth.js +1 -1
- package/commands/config/set.d.ts +1 -0
- package/commands/config/set.js +19 -9
- package/commands/mcp/start.d.ts +1 -0
- package/commands/mcp/start.js +12 -4
- package/commands/project/create.js +2 -2
- package/commands/project/validate.js +1 -0
- package/commands/sandbox/__tests__/create.test.js +207 -0
- package/commands/sandbox/create.d.ts +1 -1
- package/commands/sandbox/create.js +31 -16
- package/commands/testAccount/createConfig.js +1 -1
- package/lang/en.d.ts +17 -4
- package/lang/en.js +22 -6
- package/lang/en.lyaml +4 -2
- package/lib/__tests__/buildAccount.test.js +62 -4
- package/lib/__tests__/yargsUtils.test.js +12 -1
- package/lib/buildAccount.d.ts +4 -1
- package/lib/buildAccount.js +57 -2
- package/lib/commonOpts.js +25 -0
- package/lib/configOptions.d.ts +5 -0
- package/lib/configOptions.js +11 -1
- package/lib/constants.d.ts +8 -0
- package/lib/constants.js +8 -0
- package/lib/errorHandlers/index.js +1 -3
- package/lib/errors/ProjectValidationError.d.ts +4 -0
- package/lib/errors/ProjectValidationError.js +9 -0
- package/lib/mcp/setup.d.ts +4 -0
- package/lib/mcp/setup.js +36 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +35 -0
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +170 -1
- package/lib/projects/add/legacyAddComponent.js +1 -1
- package/lib/projects/add/v3AddComponent.js +3 -2
- package/lib/projects/create/index.js +3 -3
- package/lib/projects/create/legacy.js +2 -2
- package/lib/projects/create/v3.d.ts +0 -2
- package/lib/projects/create/v3.js +1 -3
- package/lib/projects/localDev/LocalDevLogger.js +11 -2
- package/lib/projects/localDev/LocalDevProcess.d.ts +2 -0
- package/lib/projects/localDev/LocalDevProcess.js +15 -0
- package/lib/projects/localDev/LocalDevState.d.ts +1 -0
- package/lib/projects/localDev/LocalDevState.js +5 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -2
- package/lib/projects/localDev/LocalDevWebsocketServer.js +40 -30
- package/lib/projects/upload.js +5 -12
- package/lib/projects/urls.d.ts +1 -1
- package/lib/projects/urls.js +2 -2
- package/lib/sandboxes.d.ts +4 -0
- package/lib/sandboxes.js +4 -0
- package/lib/ui/index.d.ts +6 -0
- package/lib/ui/index.js +3 -5
- package/lib/yargsUtils.d.ts +1 -0
- package/lib/yargsUtils.js +6 -0
- package/mcp-server/tools/index.js +6 -4
- package/mcp-server/tools/project/{AddFeatureToProject.d.ts → AddFeatureToProjectTool.d.ts} +4 -4
- package/mcp-server/tools/project/{AddFeatureToProject.js → AddFeatureToProjectTool.js} +6 -14
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +4 -14
- package/mcp-server/tools/project/{DeployProject.d.ts → DeployProjectTool.d.ts} +1 -1
- package/mcp-server/tools/project/{DeployProject.js → DeployProjectTool.js} +2 -2
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +20 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +51 -0
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.js → AddFeatureToProjectTool.test.js} +7 -7
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +3 -4
- package/mcp-server/tools/project/__tests__/{DeployProject.test.js → DeployProjectTool.test.js} +4 -4
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +198 -0
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +2 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -0
- package/mcp-server/tools/project/constants.js +11 -0
- package/mcp-server/utils/__tests__/command.test.js +76 -3
- package/mcp-server/utils/command.d.ts +6 -0
- package/mcp-server/utils/command.js +19 -0
- package/package.json +3 -3
- package/mcp-server/utils/__tests__/project.test.js +0 -79
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -14
- /package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.d.ts → AddFeatureToProjectTool.test.d.ts} +0 -0
- /package/mcp-server/tools/project/__tests__/{DeployProject.test.d.ts → DeployProjectTool.test.d.ts} +0 -0
- /package/mcp-server/{utils/__tests__/project.test.d.ts → tools/project/__tests__/GetConfigValuesTool.test.d.ts} +0 -0
package/lib/ui/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
type TerminalSupport = {
|
|
2
|
+
hyperlinks: boolean;
|
|
3
|
+
color: boolean;
|
|
4
|
+
};
|
|
1
5
|
export declare const UI_COLORS: {
|
|
2
6
|
SORBET: string;
|
|
3
7
|
MARIGOLD: string;
|
|
4
8
|
MARIGOLD_DARK: string;
|
|
5
9
|
};
|
|
6
10
|
export declare function uiLine(): void;
|
|
11
|
+
export declare function getTerminalUISupport(): TerminalSupport;
|
|
7
12
|
export declare function uiLink(linkText: string, url: string): string;
|
|
8
13
|
export declare function uiAccountDescription(accountId?: number | null, bold?: boolean): string;
|
|
9
14
|
export declare function uiInfoSection(title: string, logContent: () => void): void;
|
|
@@ -17,3 +22,4 @@ export declare function uiCommandDisabledBanner(command: string, url?: string, m
|
|
|
17
22
|
export declare function uiDeprecatedDescription(message: string, command: string, url?: string): undefined;
|
|
18
23
|
export declare function uiDeprecatedMessage(command: string, url?: string, message?: string): void;
|
|
19
24
|
export declare function indent(level: number): string;
|
|
25
|
+
export {};
|
package/lib/ui/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export const UI_COLORS = {
|
|
|
13
13
|
export function uiLine() {
|
|
14
14
|
logger.log('-'.repeat(50));
|
|
15
15
|
}
|
|
16
|
-
function getTerminalUISupport() {
|
|
16
|
+
export function getTerminalUISupport() {
|
|
17
17
|
return {
|
|
18
18
|
hyperlinks: supportsHyperlinkModule.stdout,
|
|
19
19
|
color: supportsColor.stdout.hasBasic,
|
|
@@ -79,9 +79,8 @@ export function uiFeatureHighlight(features, title) {
|
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
export function uiBetaTag(message, log = true) {
|
|
82
|
-
const terminalUISupport = getTerminalUISupport();
|
|
83
82
|
const tag = i18n(`lib.ui.betaTag`);
|
|
84
|
-
const result = `${
|
|
83
|
+
const result = `${tag} ${message}`;
|
|
85
84
|
if (log) {
|
|
86
85
|
logger.log(result);
|
|
87
86
|
return;
|
|
@@ -89,9 +88,8 @@ export function uiBetaTag(message, log = true) {
|
|
|
89
88
|
return result;
|
|
90
89
|
}
|
|
91
90
|
export function uiDeprecatedTag(message, log = true) {
|
|
92
|
-
const terminalUISupport = getTerminalUISupport();
|
|
93
91
|
const tag = i18n(`lib.ui.deprecatedTag`);
|
|
94
|
-
const result = `${
|
|
92
|
+
const result = `${tag} ${message}`;
|
|
95
93
|
if (log) {
|
|
96
94
|
logger.log(result);
|
|
97
95
|
return;
|
package/lib/yargsUtils.d.ts
CHANGED
package/lib/yargsUtils.js
CHANGED
|
@@ -34,3 +34,9 @@ export function makeYargsBuilder(callback, command, describe, options = {}) {
|
|
|
34
34
|
return result;
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
export function getExclusiveConflicts(options) {
|
|
38
|
+
return options.reduce((acc, curr) => {
|
|
39
|
+
acc[curr] = options.filter(s => s !== curr);
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { UploadProjectTools } from './project/UploadProjectTools.js';
|
|
2
2
|
import { CreateProjectTool } from './project/CreateProjectTool.js';
|
|
3
3
|
import { GuidedWalkthroughTool } from './project/GuidedWalkthroughTool.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { DeployProjectTool } from './project/DeployProjectTool.js';
|
|
5
|
+
import { AddFeatureToProjectTool } from './project/AddFeatureToProjectTool.js';
|
|
6
6
|
import { ValidateProjectTool } from './project/ValidateProjectTool.js';
|
|
7
|
+
import { GetConfigValuesTool } from './project/GetConfigValuesTool.js';
|
|
7
8
|
export function registerProjectTools(mcpServer) {
|
|
8
9
|
return [
|
|
9
10
|
new UploadProjectTools(mcpServer).register(),
|
|
10
11
|
new CreateProjectTool(mcpServer).register(),
|
|
11
12
|
new GuidedWalkthroughTool(mcpServer).register(),
|
|
12
|
-
new
|
|
13
|
-
new
|
|
13
|
+
new DeployProjectTool(mcpServer).register(),
|
|
14
|
+
new AddFeatureToProjectTool(mcpServer).register(),
|
|
14
15
|
new ValidateProjectTool(mcpServer).register(),
|
|
16
|
+
new GetConfigValuesTool(mcpServer).register(),
|
|
15
17
|
];
|
|
16
18
|
}
|
|
@@ -6,22 +6,22 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
6
6
|
addApp: z.ZodBoolean;
|
|
7
7
|
distribution: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"marketplace">, z.ZodLiteral<"private">]>>;
|
|
8
8
|
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"oauth">]>>;
|
|
9
|
-
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">]>, "many">>;
|
|
9
|
+
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">]>, "many">>;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
absoluteProjectPath: string;
|
|
12
12
|
addApp: boolean;
|
|
13
13
|
auth?: "oauth" | "static" | undefined;
|
|
14
14
|
distribution?: "marketplace" | "private" | undefined;
|
|
15
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
15
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
16
16
|
}, {
|
|
17
17
|
absoluteProjectPath: string;
|
|
18
18
|
addApp: boolean;
|
|
19
19
|
auth?: "oauth" | "static" | undefined;
|
|
20
20
|
distribution?: "marketplace" | "private" | undefined;
|
|
21
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
21
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
22
22
|
}>;
|
|
23
23
|
export type AddFeatureInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
24
|
-
export declare class
|
|
24
|
+
export declare class AddFeatureToProjectTool extends Tool<AddFeatureInputSchema> {
|
|
25
25
|
constructor(mcpServer: McpServer);
|
|
26
26
|
handler({ absoluteProjectPath, distribution, auth, features, addApp, }: AddFeatureInputSchema): Promise<TextContentResponse>;
|
|
27
27
|
register(): RegisteredTool;
|
|
@@ -2,8 +2,8 @@ import { Tool } from '../../types.js';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../lib/constants.js';
|
|
4
4
|
import { addFlag } from '../../utils/command.js';
|
|
5
|
-
import { absoluteProjectPath } from './constants.js';
|
|
6
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { absoluteProjectPath, features } from './constants.js';
|
|
6
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
7
7
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
8
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
9
9
|
const inputSchema = {
|
|
@@ -23,23 +23,14 @@ const inputSchema = {
|
|
|
23
23
|
z.literal(APP_AUTH_TYPES.OAUTH),
|
|
24
24
|
]))
|
|
25
25
|
.describe('Static uses a static non changing authentication token, and is only available for private distribution. If not specified by the user, do not choose for them. This cannot be changed after a project is uploaded.'),
|
|
26
|
-
features
|
|
27
|
-
.array(z
|
|
28
|
-
.union([
|
|
29
|
-
z.literal('card'),
|
|
30
|
-
z.literal('settings'),
|
|
31
|
-
z.literal('app-function'),
|
|
32
|
-
z.literal('webhooks'),
|
|
33
|
-
])
|
|
34
|
-
.describe('The features to include in the project, multiple options can be selected'))
|
|
35
|
-
.optional(),
|
|
26
|
+
features,
|
|
36
27
|
};
|
|
37
28
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
38
29
|
const inputSchemaZodObject = z.object({
|
|
39
30
|
...inputSchema,
|
|
40
31
|
});
|
|
41
32
|
const toolName = 'add-feature-to-hubspot-project';
|
|
42
|
-
export class
|
|
33
|
+
export class AddFeatureToProjectTool extends Tool {
|
|
43
34
|
constructor(mcpServer) {
|
|
44
35
|
super(mcpServer);
|
|
45
36
|
}
|
|
@@ -77,7 +68,8 @@ export class AddFeatureToProject extends Tool {
|
|
|
77
68
|
register() {
|
|
78
69
|
return this.mcpServer.registerTool(toolName, {
|
|
79
70
|
title: 'Add feature to HubSpot Project',
|
|
80
|
-
description:
|
|
71
|
+
description: `Adds a feature to an existing HubSpot project.
|
|
72
|
+
Only works for projects with platformVersion '2025.2' and beyond`,
|
|
81
73
|
inputSchema,
|
|
82
74
|
}, this.handler);
|
|
83
75
|
}
|
|
@@ -8,7 +8,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
8
8
|
projectBase: z.ZodUnion<[z.ZodLiteral<"empty">, z.ZodLiteral<"app">]>;
|
|
9
9
|
distribution: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"marketplace">, z.ZodLiteral<"private">]>>;
|
|
10
10
|
auth: z.ZodOptional<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"oauth">]>>>;
|
|
11
|
-
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">]>, "many">>;
|
|
11
|
+
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">]>, "many">>;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
13
13
|
projectBase: "app" | "empty";
|
|
14
14
|
absoluteCurrentWorkingDirectory: string;
|
|
@@ -16,7 +16,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
16
16
|
name?: string | undefined;
|
|
17
17
|
auth?: "oauth" | "static" | undefined;
|
|
18
18
|
distribution?: "marketplace" | "private" | undefined;
|
|
19
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
19
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
20
20
|
}, {
|
|
21
21
|
projectBase: "app" | "empty";
|
|
22
22
|
absoluteCurrentWorkingDirectory: string;
|
|
@@ -24,7 +24,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
24
24
|
name?: string | undefined;
|
|
25
25
|
auth?: "oauth" | "static" | undefined;
|
|
26
26
|
distribution?: "marketplace" | "private" | undefined;
|
|
27
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
27
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
28
28
|
}>;
|
|
29
29
|
export type CreateProjectInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
30
30
|
export declare class CreateProjectTool extends Tool<CreateProjectInputSchema> {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../lib/constants.js';
|
|
3
|
+
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../lib/constants.js';
|
|
4
4
|
import { addFlag } from '../../utils/command.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { runCommandInDir } from '../../utils/project.js';
|
|
5
|
+
import { absoluteCurrentWorkingDirectory, features } from './constants.js';
|
|
6
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
8
7
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
9
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
10
9
|
const inputSchema = {
|
|
@@ -32,16 +31,7 @@ const inputSchema = {
|
|
|
32
31
|
]))
|
|
33
32
|
.describe('Static uses a static non changing authentication token, and is only available for private distribution. If not specified by the user, do not choose for them. This cannot be changed after a project is uploaded.')
|
|
34
33
|
.optional(),
|
|
35
|
-
features
|
|
36
|
-
.array(z
|
|
37
|
-
.union([
|
|
38
|
-
z.literal('card'),
|
|
39
|
-
z.literal('settings'),
|
|
40
|
-
z.literal('app-function'),
|
|
41
|
-
z.literal('webhooks'),
|
|
42
|
-
])
|
|
43
|
-
.describe('The features to include in the project, multiple options can be selected'))
|
|
44
|
-
.optional(),
|
|
34
|
+
features,
|
|
45
35
|
};
|
|
46
36
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
47
37
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
@@ -12,7 +12,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
12
12
|
buildNumber?: number | undefined;
|
|
13
13
|
}>;
|
|
14
14
|
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
15
|
-
export declare class
|
|
15
|
+
export declare class DeployProjectTool extends Tool<InputSchemaType> {
|
|
16
16
|
constructor(mcpServer: McpServer);
|
|
17
17
|
handler({ absoluteProjectPath, buildNumber, }: InputSchemaType): Promise<TextContentResponse>;
|
|
18
18
|
register(): RegisteredTool;
|
|
@@ -2,7 +2,7 @@ import { Tool } from '../../types.js';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { addFlag } from '../../utils/command.js';
|
|
4
4
|
import { absoluteProjectPath } from './constants.js';
|
|
5
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
6
6
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
7
7
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
8
|
const inputSchema = {
|
|
@@ -16,7 +16,7 @@ const inputSchemaZodObject = z.object({
|
|
|
16
16
|
...inputSchema,
|
|
17
17
|
});
|
|
18
18
|
const toolName = 'deploy-hubspot-project';
|
|
19
|
-
export class
|
|
19
|
+
export class DeployProjectTool extends Tool {
|
|
20
20
|
constructor(mcpServer) {
|
|
21
21
|
super(mcpServer);
|
|
22
22
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
platformVersion: z.ZodString;
|
|
6
|
+
featureType: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
platformVersion: string;
|
|
9
|
+
featureType: string;
|
|
10
|
+
}, {
|
|
11
|
+
platformVersion: string;
|
|
12
|
+
featureType: string;
|
|
13
|
+
}>;
|
|
14
|
+
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
15
|
+
export declare class GetConfigValuesTool extends Tool<InputSchemaType> {
|
|
16
|
+
constructor(mcpServer: McpServer);
|
|
17
|
+
handler({ platformVersion, featureType, }: InputSchemaType): Promise<TextContentResponse>;
|
|
18
|
+
register(): RegisteredTool;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { formatTextContents } from '../../utils/content.js';
|
|
4
|
+
import { getIntermediateRepresentationSchema, mapToInternalType, } from '@hubspot/project-parsing-lib';
|
|
5
|
+
import { getAccountId } from '@hubspot/local-dev-lib/config';
|
|
6
|
+
import { useV3Api } from '../../../lib/projects/buildAndDeploy.js';
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
platformVersion: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe('The platform version for the project. Located in the hsproject.json file.'),
|
|
11
|
+
featureType: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe('The type of the component to fetch the JSON schema for. This will be the `type` field in the -hsmeta.json file'),
|
|
14
|
+
};
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
16
|
+
const inputSchemaZodObject = z.object({
|
|
17
|
+
...inputSchema,
|
|
18
|
+
});
|
|
19
|
+
const toolName = 'get-hubspot-project-feature-config-schema';
|
|
20
|
+
export class GetConfigValuesTool extends Tool {
|
|
21
|
+
constructor(mcpServer) {
|
|
22
|
+
super(mcpServer);
|
|
23
|
+
}
|
|
24
|
+
async handler({ platformVersion, featureType, }) {
|
|
25
|
+
try {
|
|
26
|
+
if (!useV3Api(platformVersion)) {
|
|
27
|
+
return formatTextContents(`Can only be used on projects with a minimum platformVersion of 2025.2`);
|
|
28
|
+
}
|
|
29
|
+
const schema = await getIntermediateRepresentationSchema({
|
|
30
|
+
platformVersion,
|
|
31
|
+
projectSourceDir: '',
|
|
32
|
+
accountId: getAccountId(),
|
|
33
|
+
});
|
|
34
|
+
const internalComponentType = mapToInternalType(featureType);
|
|
35
|
+
if (schema[internalComponentType]) {
|
|
36
|
+
return formatTextContents(JSON.stringify({ config: schema[internalComponentType] }));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) { }
|
|
40
|
+
return formatTextContents(`Unable to locate JSON schema for type ${featureType}`);
|
|
41
|
+
}
|
|
42
|
+
register() {
|
|
43
|
+
return this.mcpServer.registerTool(toolName, {
|
|
44
|
+
title: 'Fetch the JSON Schema for component',
|
|
45
|
+
description: `Fetches and returns the JSON schema for the provided feature 'type' found in -hsmeta.json file.
|
|
46
|
+
This should be called before editing a '-hsmeta.json' file to get the list of possible values and restrictions on those values.
|
|
47
|
+
This will only work for projects with platformVersion 2025.2 and beyond`,
|
|
48
|
+
inputSchema,
|
|
49
|
+
}, this.handler);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
|
-
import { runCommandInDir } from '../../utils/
|
|
2
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
3
3
|
import { absoluteProjectPath } from './constants.js';
|
|
4
4
|
import z from 'zod';
|
|
5
5
|
import { formatTextContents } from '../../utils/content.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteProjectPath } from './constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
const inputSchema = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
1
|
+
import { AddFeatureToProjectTool, } from '../AddFeatureToProjectTool.js';
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
import { addFlag } from '../../../utils/command.js';
|
|
4
4
|
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../../lib/constants.js';
|
|
5
5
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
|
-
vi.mock('../../../utils/
|
|
6
|
+
vi.mock('../../../utils/command');
|
|
7
7
|
vi.mock('../../../utils/command');
|
|
8
8
|
vi.mock('../../../../lib/constants');
|
|
9
9
|
vi.mock('../../../utils/toolUsageTracking');
|
|
@@ -21,18 +21,18 @@ describe('mcp-server/tools/project/AddFeatureToProject', () => {
|
|
|
21
21
|
};
|
|
22
22
|
mockRegisteredTool = {};
|
|
23
23
|
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
24
|
-
tool = new
|
|
24
|
+
tool = new AddFeatureToProjectTool(mockMcpServer);
|
|
25
25
|
// Mock addFlag to simulate command building
|
|
26
26
|
mockAddFlag.mockImplementation((command, flag, value) => `${command} --${flag} "${value}"`);
|
|
27
27
|
});
|
|
28
28
|
describe('register', () => {
|
|
29
29
|
it('should register tool with correct parameters', () => {
|
|
30
30
|
const result = tool.register();
|
|
31
|
-
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('add-feature-to-hubspot-project', {
|
|
31
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('add-feature-to-hubspot-project', expect.objectContaining({
|
|
32
32
|
title: 'Add feature to HubSpot Project',
|
|
33
|
-
description: 'Adds a feature to an existing HubSpot project',
|
|
33
|
+
description: expect.stringContaining('Adds a feature to an existing HubSpot project'),
|
|
34
34
|
inputSchema: expect.any(Object),
|
|
35
|
-
}, tool.handler);
|
|
35
|
+
}), tool.handler);
|
|
36
36
|
expect(result).toBe(mockRegisteredTool);
|
|
37
37
|
});
|
|
38
38
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { CreateProjectTool, } from '../CreateProjectTool.js';
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
import { addFlag } from '../../../utils/command.js';
|
|
4
|
-
import { APP_DISTRIBUTION_TYPES } from '../../../../lib/constants.js';
|
|
5
|
-
import { EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../../lib/projects/create/v3.js';
|
|
4
|
+
import { APP_DISTRIBUTION_TYPES, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../../lib/constants.js';
|
|
6
5
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
7
|
-
vi.mock('../../../utils/
|
|
6
|
+
vi.mock('../../../utils/command');
|
|
8
7
|
vi.mock('../../../utils/command');
|
|
9
8
|
vi.mock('../../../../lib/constants');
|
|
10
9
|
vi.mock('../../../../lib/projects/create/v3');
|
package/mcp-server/tools/project/__tests__/{DeployProject.test.js → DeployProjectTool.test.js}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
1
|
+
import { DeployProjectTool } from '../DeployProjectTool.js';
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
import { addFlag } from '../../../utils/command.js';
|
|
4
4
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
5
|
-
vi.mock('../../../utils/
|
|
5
|
+
vi.mock('../../../utils/command');
|
|
6
6
|
vi.mock('../../../utils/command');
|
|
7
7
|
vi.mock('../../../utils/toolUsageTracking');
|
|
8
8
|
const mockRunCommandInDir = runCommandInDir;
|
|
@@ -19,7 +19,7 @@ describe('mcp-server/tools/project/DeployProject', () => {
|
|
|
19
19
|
};
|
|
20
20
|
mockRegisteredTool = {};
|
|
21
21
|
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
22
|
-
tool = new
|
|
22
|
+
tool = new DeployProjectTool(mockMcpServer);
|
|
23
23
|
// Mock addFlag to simulate command building
|
|
24
24
|
mockAddFlag.mockImplementation((command, flag, value) => `${command} --${flag} "${value}"`);
|
|
25
25
|
});
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { GetConfigValuesTool } from '../GetConfigValuesTool.js';
|
|
2
|
+
import { getIntermediateRepresentationSchema, mapToInternalType, } from '@hubspot/project-parsing-lib';
|
|
3
|
+
import { getAccountId } from '@hubspot/local-dev-lib/config';
|
|
4
|
+
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
5
|
+
vi.mock('@hubspot/project-parsing-lib');
|
|
6
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
7
|
+
vi.mock('../../../utils/toolUsageTracking');
|
|
8
|
+
const mockGetIntermediateRepresentationSchema = getIntermediateRepresentationSchema;
|
|
9
|
+
const mockMapToInternalType = mapToInternalType;
|
|
10
|
+
const mockGetAccountId = getAccountId;
|
|
11
|
+
describe('mcp-server/tools/project/GetConfigValuesTool', () => {
|
|
12
|
+
let mockMcpServer;
|
|
13
|
+
let tool;
|
|
14
|
+
let mockRegisteredTool;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
// @ts-expect-error Not mocking the whole thing
|
|
18
|
+
mockMcpServer = {
|
|
19
|
+
registerTool: vi.fn(),
|
|
20
|
+
};
|
|
21
|
+
mockRegisteredTool = {};
|
|
22
|
+
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
23
|
+
tool = new GetConfigValuesTool(mockMcpServer);
|
|
24
|
+
});
|
|
25
|
+
describe('register', () => {
|
|
26
|
+
it('should register tool with correct parameters', () => {
|
|
27
|
+
const result = tool.register();
|
|
28
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('get-hubspot-project-feature-config-schema', {
|
|
29
|
+
title: 'Fetch the JSON Schema for component',
|
|
30
|
+
description: expect.stringContaining('Fetches and returns the JSON schema for the provided feature'),
|
|
31
|
+
inputSchema: expect.objectContaining({
|
|
32
|
+
platformVersion: expect.objectContaining({
|
|
33
|
+
describe: expect.any(Function),
|
|
34
|
+
}),
|
|
35
|
+
featureType: expect.objectContaining({
|
|
36
|
+
describe: expect.any(Function),
|
|
37
|
+
}),
|
|
38
|
+
}),
|
|
39
|
+
}, tool.handler);
|
|
40
|
+
expect(result).toBe(mockRegisteredTool);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('handler', () => {
|
|
44
|
+
const input = {
|
|
45
|
+
platformVersion: '2025.2',
|
|
46
|
+
featureType: 'card',
|
|
47
|
+
};
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
mockGetAccountId.mockReturnValue(123456789);
|
|
50
|
+
});
|
|
51
|
+
it('should return config schema when component type exists', async () => {
|
|
52
|
+
const mockSchema = {
|
|
53
|
+
'internal-card-type': {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
title: { type: 'string' },
|
|
57
|
+
description: { type: 'string' },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
mockGetIntermediateRepresentationSchema.mockResolvedValue(mockSchema);
|
|
62
|
+
mockMapToInternalType.mockReturnValue('internal-card-type');
|
|
63
|
+
const result = await tool.handler(input);
|
|
64
|
+
expect(mockGetIntermediateRepresentationSchema).toHaveBeenCalledWith({
|
|
65
|
+
platformVersion: '2025.2',
|
|
66
|
+
projectSourceDir: '',
|
|
67
|
+
accountId: 123456789,
|
|
68
|
+
});
|
|
69
|
+
expect(mockMapToInternalType).toHaveBeenCalledWith('card');
|
|
70
|
+
expect(result).toEqual({
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: JSON.stringify({
|
|
75
|
+
config: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
title: { type: 'string' },
|
|
79
|
+
description: { type: 'string' },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
it('should return error message when component type does not exist in schema', async () => {
|
|
88
|
+
const mockSchema = {
|
|
89
|
+
'other-type': {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
mockGetIntermediateRepresentationSchema.mockResolvedValue(mockSchema);
|
|
95
|
+
mockMapToInternalType.mockReturnValue('internal-card-type');
|
|
96
|
+
const result = await tool.handler(input);
|
|
97
|
+
expect(result).toEqual({
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: 'Unable to locate JSON schema for type card',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
it('should return error message when getIntermediateRepresentationSchema throws', async () => {
|
|
107
|
+
mockGetIntermediateRepresentationSchema.mockRejectedValue(new Error('Schema fetch failed'));
|
|
108
|
+
mockMapToInternalType.mockReturnValue('internal-card-type');
|
|
109
|
+
const result = await tool.handler(input);
|
|
110
|
+
expect(result).toEqual({
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: 'text',
|
|
114
|
+
text: 'Unable to locate JSON schema for type card',
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
it('should return error message when mapToInternalType throws', async () => {
|
|
120
|
+
const mockSchema = {};
|
|
121
|
+
mockGetIntermediateRepresentationSchema.mockResolvedValue(mockSchema);
|
|
122
|
+
mockMapToInternalType.mockImplementation(() => {
|
|
123
|
+
throw new Error('Mapping failed');
|
|
124
|
+
});
|
|
125
|
+
const result = await tool.handler(input);
|
|
126
|
+
expect(result).toEqual({
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: 'text',
|
|
130
|
+
text: 'Unable to locate JSON schema for type card',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
it('should handle null account id', async () => {
|
|
136
|
+
mockGetAccountId.mockReturnValue(null);
|
|
137
|
+
mockGetIntermediateRepresentationSchema.mockRejectedValue(new Error('No account ID'));
|
|
138
|
+
const result = await tool.handler(input);
|
|
139
|
+
expect(result).toEqual({
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: 'Unable to locate JSON schema for type card',
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
it('should handle empty schema object', async () => {
|
|
149
|
+
const mockSchema = {};
|
|
150
|
+
mockGetIntermediateRepresentationSchema.mockResolvedValue(mockSchema);
|
|
151
|
+
mockMapToInternalType.mockReturnValue('internal-card-type');
|
|
152
|
+
const result = await tool.handler(input);
|
|
153
|
+
expect(result).toEqual({
|
|
154
|
+
content: [
|
|
155
|
+
{
|
|
156
|
+
type: 'text',
|
|
157
|
+
text: 'Unable to locate JSON schema for type card',
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
it('should handle complex nested schema structures', async () => {
|
|
163
|
+
const complexSchema = {
|
|
164
|
+
'internal-card-type': {
|
|
165
|
+
type: 'object',
|
|
166
|
+
properties: {
|
|
167
|
+
title: { type: 'string', maxLength: 100 },
|
|
168
|
+
metadata: {
|
|
169
|
+
type: 'object',
|
|
170
|
+
properties: {
|
|
171
|
+
author: { type: 'string' },
|
|
172
|
+
tags: {
|
|
173
|
+
type: 'array',
|
|
174
|
+
items: { type: 'string' },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
required: ['author'],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
required: ['title'],
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
mockGetIntermediateRepresentationSchema.mockResolvedValue(complexSchema);
|
|
184
|
+
mockMapToInternalType.mockReturnValue('internal-card-type');
|
|
185
|
+
const result = await tool.handler(input);
|
|
186
|
+
expect(result).toEqual({
|
|
187
|
+
content: [
|
|
188
|
+
{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: JSON.stringify({
|
|
191
|
+
config: complexSchema['internal-card-type'],
|
|
192
|
+
}),
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UploadProjectTools } from '../UploadProjectTools.js';
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
4
|
-
vi.mock('../../../utils/
|
|
4
|
+
vi.mock('../../../utils/command');
|
|
5
5
|
vi.mock('../../../utils/toolUsageTracking');
|
|
6
6
|
const mockRunCommandInDir = runCommandInDir;
|
|
7
7
|
describe('mcp-server/tools/project/UploadProjectTools', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ValidateProjectTool, } from '../ValidateProjectTool.js';
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
4
|
-
vi.mock('../../../utils/
|
|
4
|
+
vi.mock('../../../utils/command');
|
|
5
5
|
vi.mock('../../../utils/toolUsageTracking');
|
|
6
6
|
const mockRunCommandInDir = runCommandInDir;
|
|
7
7
|
describe('mcp-server/tools/project/ValidateProjectTool', () => {
|