@hubspot/cli 7.7.31-experimental.0 → 7.7.33-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/app.js +1 -6
- package/commands/getStarted.js +5 -4
- package/commands/project/__tests__/add.test.js +3 -5
- package/commands/project/__tests__/deploy.test.js +3 -2
- package/commands/project/add.js +2 -4
- package/commands/project/deploy.js +9 -61
- package/commands/project/dev/index.js +1 -1
- package/commands/project/dev/unifiedFlow.js +3 -0
- package/commands/project/upload.d.ts +2 -2
- package/commands/project/upload.js +3 -3
- package/commands/project/validate.js +1 -1
- package/commands/project/watch.js +2 -2
- package/commands/testAccount/create.js +0 -3
- package/lang/en.d.ts +8 -26
- package/lang/en.js +9 -27
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/__tests__/importData.test.js +1 -1
- package/lib/app/migrate.js +9 -2
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +2 -0
- package/lib/errorHandlers/index.d.ts +4 -0
- package/lib/errorHandlers/index.js +1 -1
- package/lib/hasFeature.js +6 -0
- package/lib/importData.js +1 -1
- package/lib/mcp/setup.js +1 -1
- package/lib/projectProfiles.d.ts +1 -1
- package/lib/projectProfiles.js +2 -10
- package/lib/projects/__tests__/AppDevModeInterface.test.js +61 -44
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/deploy.test.js +164 -0
- package/lib/projects/__tests__/{buildAndDeploy.test.js → platformVersion.test.js} +2 -2
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +49 -6
- package/lib/projects/add/__tests__/v3AddComponent.test.js +71 -1
- package/lib/projects/add/legacyAddComponent.d.ts +1 -1
- package/lib/projects/add/legacyAddComponent.js +5 -1
- package/lib/projects/add/v3AddComponent.d.ts +1 -0
- package/lib/projects/add/v3AddComponent.js +2 -2
- package/lib/projects/create/__tests__/v3.test.js +97 -9
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/legacy.js +1 -1
- package/lib/projects/create/v3.d.ts +2 -2
- package/lib/projects/create/v3.js +35 -12
- package/lib/projects/deploy.d.ts +13 -0
- package/lib/projects/deploy.js +63 -0
- package/lib/projects/localDev/AppDevModeInterface.d.ts +0 -2
- package/lib/projects/localDev/AppDevModeInterface.js +65 -36
- package/lib/projects/localDev/DevServerManagerV2.js +1 -0
- package/lib/projects/localDev/LocalDevProcess.js +3 -1
- package/lib/projects/localDev/LocalDevState.d.ts +5 -2
- package/lib/projects/localDev/LocalDevState.js +9 -1
- package/lib/projects/localDev/helpers/project.js +1 -1
- package/lib/projects/platformVersion.d.ts +1 -0
- package/lib/projects/platformVersion.js +10 -0
- package/lib/projects/{buildAndDeploy.d.ts → pollProjectBuildAndDeploy.d.ts} +0 -1
- package/lib/projects/{buildAndDeploy.js → pollProjectBuildAndDeploy.js} +0 -10
- package/lib/projects/structure.d.ts +2 -2
- package/lib/projects/upload.d.ts +1 -2
- package/lib/projects/upload.js +1 -2
- package/lib/projects/urls.d.ts +1 -0
- package/lib/projects/urls.js +3 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.js +143 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.js +160 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +1 -0
- package/lib/prompts/importDataFilePathPrompt.js +4 -2
- package/lib/prompts/installAppPrompt.d.ts +6 -1
- package/lib/prompts/installAppPrompt.js +6 -1
- package/lib/prompts/projectAddPrompt.js +1 -1
- package/lib/prompts/selectProjectTemplatePrompt.js +1 -1
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +96 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +26 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +75 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +76 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.js +58 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +251 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +206 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +183 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +120 -0
- package/mcp-server/tools/index.js +8 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/GetConfigValuesTool.js +3 -3
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/tools/project/constants.js +6 -4
- package/package.json +4 -3
- package/types/LocalDev.d.ts +2 -1
- package/types/Projects.d.ts +1 -0
- package/types/Yargs.d.ts +1 -1
- package/ui/components/BoxWithTitle.d.ts +8 -0
- package/ui/components/BoxWithTitle.js +9 -0
- package/ui/components/HorizontalSelectPrompt.d.ts +8 -0
- package/ui/components/HorizontalSelectPrompt.js +30 -0
- package/ui/components/StatusMessageBoxes.d.ts +12 -0
- package/ui/components/StatusMessageBoxes.js +31 -0
- package/ui/lib/ui-testing-utils.d.ts +9 -0
- package/ui/lib/ui-testing-utils.js +47 -0
- package/ui/lib/useTerminalSize.d.ts +13 -0
- package/ui/lib/useTerminalSize.js +31 -0
- package/ui/styles.d.ts +18 -0
- package/ui/styles.js +18 -0
- package/ui/views/UiSandbox.d.ts +5 -0
- package/ui/views/UiSandbox.js +25 -0
- package/commands/app/__tests__/install.test.js +0 -47
- package/commands/app/install.d.ts +0 -8
- package/commands/app/install.js +0 -122
- /package/{commands/app/__tests__/install.test.d.ts → lib/projects/__tests__/deploy.test.d.ts} +0 -0
- /package/lib/projects/__tests__/{buildAndDeploy.test.d.ts → platformVersion.test.d.ts} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Separator } from '@inquirer/prompts';
|
|
2
|
+
import { selectProjectTemplatePrompt } from '../selectProjectTemplatePrompt.js';
|
|
3
|
+
import { promptUser } from '../promptUtils.js';
|
|
4
|
+
vi.mock('../promptUtils');
|
|
5
|
+
const mockedPromptUser = vi.mocked(promptUser);
|
|
6
|
+
describe('lib/prompts/selectProjectTemplatePrompt', () => {
|
|
7
|
+
const mockComponentTemplate = {
|
|
8
|
+
label: 'Test Module',
|
|
9
|
+
path: 'test-module',
|
|
10
|
+
type: 'module',
|
|
11
|
+
supportedAuthTypes: ['oauth'],
|
|
12
|
+
supportedDistributions: ['private'],
|
|
13
|
+
};
|
|
14
|
+
const mockComponentTemplateWithCliSelector = {
|
|
15
|
+
label: 'Workflow Action Tool',
|
|
16
|
+
path: 'workflow-action-tool',
|
|
17
|
+
type: 'workflow-action',
|
|
18
|
+
cliSelector: 'workflow-action-tool',
|
|
19
|
+
supportedAuthTypes: ['oauth'],
|
|
20
|
+
supportedDistributions: ['private'],
|
|
21
|
+
};
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
mockedPromptUser.mockResolvedValue({});
|
|
24
|
+
});
|
|
25
|
+
describe('selectProjectTemplatePrompt with component templates', () => {
|
|
26
|
+
it('should select component based on cliSelector when provided', async () => {
|
|
27
|
+
const templateChoice = {
|
|
28
|
+
name: 'Workflow Action Tool',
|
|
29
|
+
value: mockComponentTemplateWithCliSelector,
|
|
30
|
+
};
|
|
31
|
+
const componentTemplates = [templateChoice];
|
|
32
|
+
const promptOptions = {
|
|
33
|
+
features: ['workflow-action-tool'],
|
|
34
|
+
};
|
|
35
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
36
|
+
expect(result.componentTemplates).toEqual([
|
|
37
|
+
mockComponentTemplateWithCliSelector,
|
|
38
|
+
]);
|
|
39
|
+
expect(mockedPromptUser).toHaveBeenCalledWith([
|
|
40
|
+
expect.objectContaining({ name: 'projectTemplate' }),
|
|
41
|
+
expect.objectContaining({ name: 'componentTemplates' }),
|
|
42
|
+
]);
|
|
43
|
+
});
|
|
44
|
+
it('should select component based on type when cliSelector not provided', async () => {
|
|
45
|
+
const templateChoice = {
|
|
46
|
+
name: 'Test Module',
|
|
47
|
+
value: mockComponentTemplate,
|
|
48
|
+
};
|
|
49
|
+
const componentTemplates = [templateChoice];
|
|
50
|
+
const promptOptions = {
|
|
51
|
+
features: ['module'],
|
|
52
|
+
};
|
|
53
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
54
|
+
expect(result.componentTemplates).toEqual([mockComponentTemplate]);
|
|
55
|
+
});
|
|
56
|
+
it('should prefer cliSelector over type when both are available', async () => {
|
|
57
|
+
const templateChoice = {
|
|
58
|
+
name: 'Workflow Action Tool',
|
|
59
|
+
value: mockComponentTemplateWithCliSelector,
|
|
60
|
+
};
|
|
61
|
+
const componentTemplates = [templateChoice];
|
|
62
|
+
const promptOptions = {
|
|
63
|
+
features: ['workflow-action-tool'], // matches cliSelector, not type
|
|
64
|
+
};
|
|
65
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
66
|
+
expect(result.componentTemplates).toEqual([
|
|
67
|
+
mockComponentTemplateWithCliSelector,
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
it('should not select component when neither cliSelector nor type matches', async () => {
|
|
71
|
+
const templateChoice = {
|
|
72
|
+
name: 'Test Module',
|
|
73
|
+
value: mockComponentTemplate,
|
|
74
|
+
};
|
|
75
|
+
const componentTemplates = [templateChoice];
|
|
76
|
+
const promptOptions = {
|
|
77
|
+
features: ['non-matching-feature'],
|
|
78
|
+
};
|
|
79
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
80
|
+
expect(result.componentTemplates).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
it('should throw error when selected feature component is disabled', async () => {
|
|
83
|
+
const disabledTemplateChoice = {
|
|
84
|
+
name: 'Disabled Component',
|
|
85
|
+
value: mockComponentTemplateWithCliSelector,
|
|
86
|
+
disabled: 'Component is disabled for testing',
|
|
87
|
+
};
|
|
88
|
+
const componentTemplates = [disabledTemplateChoice];
|
|
89
|
+
const promptOptions = {
|
|
90
|
+
features: ['workflow-action-tool'],
|
|
91
|
+
};
|
|
92
|
+
await expect(selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates)).rejects.toThrow(/Cannot create project with template.*workflow-action/);
|
|
93
|
+
});
|
|
94
|
+
it('should handle multiple components with mixed cliSelector availability', async () => {
|
|
95
|
+
const choice1 = {
|
|
96
|
+
name: 'Test Module',
|
|
97
|
+
value: mockComponentTemplate,
|
|
98
|
+
};
|
|
99
|
+
const choice2 = {
|
|
100
|
+
name: 'Workflow Action Tool',
|
|
101
|
+
value: mockComponentTemplateWithCliSelector,
|
|
102
|
+
};
|
|
103
|
+
const componentTemplates = [choice1, choice2];
|
|
104
|
+
const promptOptions = {
|
|
105
|
+
features: ['module', 'workflow-action-tool'],
|
|
106
|
+
};
|
|
107
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
108
|
+
expect(result.componentTemplates).toEqual([
|
|
109
|
+
mockComponentTemplate,
|
|
110
|
+
mockComponentTemplateWithCliSelector,
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
it('should skip Separator instances when processing components', async () => {
|
|
114
|
+
const separator = new Separator();
|
|
115
|
+
const templateChoice = {
|
|
116
|
+
name: 'Test Module',
|
|
117
|
+
value: mockComponentTemplate,
|
|
118
|
+
};
|
|
119
|
+
const componentTemplates = [separator, templateChoice];
|
|
120
|
+
const promptOptions = {
|
|
121
|
+
features: ['module'],
|
|
122
|
+
};
|
|
123
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
124
|
+
expect(result.componentTemplates).toEqual([mockComponentTemplate]);
|
|
125
|
+
});
|
|
126
|
+
it('should prompt user when no features provided', async () => {
|
|
127
|
+
const templateChoice = {
|
|
128
|
+
name: 'Test Module',
|
|
129
|
+
value: mockComponentTemplate,
|
|
130
|
+
};
|
|
131
|
+
const componentTemplates = [templateChoice];
|
|
132
|
+
const promptOptions = {};
|
|
133
|
+
mockedPromptUser.mockResolvedValue({
|
|
134
|
+
componentTemplates: [mockComponentTemplate],
|
|
135
|
+
});
|
|
136
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
137
|
+
expect(mockedPromptUser).toHaveBeenCalledWith([
|
|
138
|
+
expect.objectContaining({ name: 'projectTemplate' }),
|
|
139
|
+
expect.objectContaining({
|
|
140
|
+
name: 'componentTemplates',
|
|
141
|
+
type: 'checkbox',
|
|
142
|
+
choices: componentTemplates,
|
|
143
|
+
}),
|
|
144
|
+
]);
|
|
145
|
+
expect(result.componentTemplates).toEqual([mockComponentTemplate]);
|
|
146
|
+
});
|
|
147
|
+
it('should handle empty componentTemplates selection', async () => {
|
|
148
|
+
const templateChoice = {
|
|
149
|
+
name: 'Test Module',
|
|
150
|
+
value: mockComponentTemplate,
|
|
151
|
+
};
|
|
152
|
+
const componentTemplates = [templateChoice];
|
|
153
|
+
const promptOptions = {
|
|
154
|
+
features: ['non-matching-feature'],
|
|
155
|
+
};
|
|
156
|
+
const result = await selectProjectTemplatePrompt(promptOptions, undefined, componentTemplates);
|
|
157
|
+
expect(result.componentTemplates).toEqual([]);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -101,6 +101,7 @@ export async function createDeveloperTestAccountConfigPrompt(args = {}, supportF
|
|
|
101
101
|
type: 'checkbox',
|
|
102
102
|
pageSize: 13,
|
|
103
103
|
choices: TEST_ACCOUNT_TIERS,
|
|
104
|
+
loop: false,
|
|
104
105
|
validate: choices => {
|
|
105
106
|
if (choices?.length < Object.keys(hubs).length) {
|
|
106
107
|
return lib.prompts.createDeveloperTestAccountConfigPrompt.errors
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { validateImportRequestFile } from '@hubspot/local-dev-lib/crm';
|
|
2
2
|
import { promptUser } from './promptUtils.js';
|
|
3
3
|
import { lib } from '../../lang/en.js';
|
|
4
|
-
import { logError } from '../errorHandlers/index.js';
|
|
5
4
|
import { uiLogger } from '../ui/logger.js';
|
|
5
|
+
import { isErrorWithMessageOrReason } from '../errorHandlers/index.js';
|
|
6
6
|
export async function importDataFilePathPrompt() {
|
|
7
7
|
uiLogger.log(lib.prompts.importDataFilePathPrompt.promptContext);
|
|
8
8
|
const { filePath } = await promptUser({
|
|
@@ -15,7 +15,9 @@ export async function importDataFilePathPrompt() {
|
|
|
15
15
|
return true;
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
18
|
-
|
|
18
|
+
if (isErrorWithMessageOrReason(error) && error.message) {
|
|
19
|
+
return error.message;
|
|
20
|
+
}
|
|
19
21
|
return false;
|
|
20
22
|
}
|
|
21
23
|
},
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export declare function installAppBrowserPrompt(installUrl: string, isReinstall?: boolean
|
|
1
|
+
export declare function installAppBrowserPrompt(installUrl: string, isReinstall?: boolean, staticAuthInstallOptions?: {
|
|
2
|
+
testingAccountId: number;
|
|
3
|
+
projectAccountId: number;
|
|
4
|
+
projectName: string;
|
|
5
|
+
appUid: string;
|
|
6
|
+
}): Promise<void>;
|
|
2
7
|
export declare function installAppAutoPrompt(): Promise<boolean>;
|
|
@@ -3,7 +3,7 @@ import { promptUser } from './promptUtils.js';
|
|
|
3
3
|
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
4
4
|
import { lib } from '../../lang/en.js';
|
|
5
5
|
import { uiLogger } from '../ui/logger.js';
|
|
6
|
-
export async function installAppBrowserPrompt(installUrl, isReinstall = false) {
|
|
6
|
+
export async function installAppBrowserPrompt(installUrl, isReinstall = false, staticAuthInstallOptions) {
|
|
7
7
|
uiLogger.log('');
|
|
8
8
|
if (isReinstall) {
|
|
9
9
|
uiLogger.log(lib.prompts.installAppPrompt.reinstallExplanation);
|
|
@@ -11,6 +11,11 @@ export async function installAppBrowserPrompt(installUrl, isReinstall = false) {
|
|
|
11
11
|
else {
|
|
12
12
|
uiLogger.log(lib.prompts.installAppPrompt.explanation);
|
|
13
13
|
}
|
|
14
|
+
if (staticAuthInstallOptions) {
|
|
15
|
+
const { testingAccountId, projectAccountId, projectName, appUid } = staticAuthInstallOptions;
|
|
16
|
+
uiLogger.log(lib.prompts.installAppPrompt.staticAuthExplanation(projectAccountId, testingAccountId, projectName, appUid));
|
|
17
|
+
uiLogger.log('');
|
|
18
|
+
}
|
|
14
19
|
const { shouldOpenBrowser } = await promptUser({
|
|
15
20
|
name: 'shouldOpenBrowser',
|
|
16
21
|
type: 'confirm',
|
|
@@ -51,7 +51,7 @@ export async function projectAddPromptV3(components, selectedFeatures) {
|
|
|
51
51
|
if (template instanceof Separator || !template.value) {
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
if (selectedFeatures?.includes(template.value.type)) {
|
|
54
|
+
if (selectedFeatures?.includes(template.value.cliSelector || template.value.type)) {
|
|
55
55
|
if (template.disabled) {
|
|
56
56
|
throw new Error(lib.prompts.projectAddPrompt.errors.cannotAddFeature(template.value.type, template.disabled));
|
|
57
57
|
}
|
|
@@ -13,7 +13,7 @@ export async function selectProjectTemplatePrompt(promptOptions, projectTemplate
|
|
|
13
13
|
if (template instanceof Separator || !template.value) {
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
if (promptOptions.features?.includes(template.value.type)) {
|
|
16
|
+
if (promptOptions.features?.includes(template.value.cliSelector || template.value.type)) {
|
|
17
17
|
if (template.disabled) {
|
|
18
18
|
throw new Error(`Cannot create project with template '${template.value.type}'. Reasons: ${template.disabled}`);
|
|
19
19
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
6
|
+
dest: z.ZodOptional<z.ZodString>;
|
|
7
|
+
functionsFolder: z.ZodOptional<z.ZodString>;
|
|
8
|
+
filename: z.ZodOptional<z.ZodString>;
|
|
9
|
+
endpointMethod: z.ZodOptional<z.ZodEnum<["DELETE", "GET", "PATCH", "POST", "PUT"]>>;
|
|
10
|
+
endpointPath: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
absoluteCurrentWorkingDirectory: string;
|
|
13
|
+
dest?: string | undefined;
|
|
14
|
+
functionsFolder?: string | undefined;
|
|
15
|
+
filename?: string | undefined;
|
|
16
|
+
endpointMethod?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | undefined;
|
|
17
|
+
endpointPath?: string | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
absoluteCurrentWorkingDirectory: string;
|
|
20
|
+
dest?: string | undefined;
|
|
21
|
+
functionsFolder?: string | undefined;
|
|
22
|
+
filename?: string | undefined;
|
|
23
|
+
endpointMethod?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | undefined;
|
|
24
|
+
endpointPath?: string | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
export type HsCreateFunctionInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
27
|
+
export declare class HsCreateFunctionTool extends Tool<HsCreateFunctionInputSchema> {
|
|
28
|
+
constructor(mcpServer: McpServer);
|
|
29
|
+
handler({ dest, functionsFolder, filename, endpointMethod, endpointPath, absoluteCurrentWorkingDirectory, }: HsCreateFunctionInputSchema): Promise<TextContentResponse>;
|
|
30
|
+
register(): RegisteredTool;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
+
import { runCommandInDir } from '../../utils/project.js';
|
|
5
|
+
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
|
+
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
|
+
import { addFlag } from '../../utils/command.js';
|
|
8
|
+
import { HTTP_METHODS } from '../../../types/Cms.js';
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
absoluteCurrentWorkingDirectory,
|
|
11
|
+
dest: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe('The destination path where the function should be created on the current computer.')
|
|
14
|
+
.optional(),
|
|
15
|
+
functionsFolder: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe('Folder name for function creation. Required for non-interactive function creation. If the user has not specified the folder name, ask them to provide it.')
|
|
18
|
+
.optional(),
|
|
19
|
+
filename: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe('Function filename. Required for non-interactive function creation. If the user has not specified the filename, ask them to provide it.')
|
|
22
|
+
.optional(),
|
|
23
|
+
endpointMethod: z
|
|
24
|
+
.enum(HTTP_METHODS)
|
|
25
|
+
.describe(`HTTP method for the function endpoint. Must be one of: ${HTTP_METHODS.join(', ')}. Defaults to GET.`)
|
|
26
|
+
.optional(),
|
|
27
|
+
endpointPath: z
|
|
28
|
+
.string()
|
|
29
|
+
.describe('API endpoint path for the function. Required for non-interactive function creation. If the user has not specified the endpoint path, ask them to provide it.')
|
|
30
|
+
.optional(),
|
|
31
|
+
};
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
33
|
+
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
34
|
+
const toolName = 'create-hubspot-cms-function';
|
|
35
|
+
export class HsCreateFunctionTool extends Tool {
|
|
36
|
+
constructor(mcpServer) {
|
|
37
|
+
super(mcpServer);
|
|
38
|
+
}
|
|
39
|
+
async handler({ dest, functionsFolder, filename, endpointMethod, endpointPath, absoluteCurrentWorkingDirectory, }) {
|
|
40
|
+
await trackToolUsage(toolName);
|
|
41
|
+
const content = [];
|
|
42
|
+
// Require functions folder
|
|
43
|
+
if (!functionsFolder) {
|
|
44
|
+
content.push(formatTextContent(`Ask the user to provide the folder name for the function.`));
|
|
45
|
+
}
|
|
46
|
+
// Require filename
|
|
47
|
+
if (!filename) {
|
|
48
|
+
content.push(formatTextContent(`Ask the user to provide the filename for the function.`));
|
|
49
|
+
}
|
|
50
|
+
// Require endpoint path
|
|
51
|
+
if (!endpointPath) {
|
|
52
|
+
content.push(formatTextContent(`Ask the user to provide the API endpoint path for the function.`));
|
|
53
|
+
}
|
|
54
|
+
// If we have missing required information, return the prompts
|
|
55
|
+
if (content.length > 0) {
|
|
56
|
+
return {
|
|
57
|
+
content,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Build the command
|
|
61
|
+
let command = 'hs create function';
|
|
62
|
+
if (dest) {
|
|
63
|
+
command += ` "${dest}"`;
|
|
64
|
+
}
|
|
65
|
+
// Add function-specific flags
|
|
66
|
+
if (functionsFolder) {
|
|
67
|
+
command = addFlag(command, 'functions-folder', functionsFolder);
|
|
68
|
+
}
|
|
69
|
+
if (filename) {
|
|
70
|
+
command = addFlag(command, 'filename', filename);
|
|
71
|
+
}
|
|
72
|
+
if (endpointMethod) {
|
|
73
|
+
command = addFlag(command, 'endpoint-method', endpointMethod);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
command = addFlag(command, 'endpoint-method', 'GET');
|
|
77
|
+
}
|
|
78
|
+
if (endpointPath) {
|
|
79
|
+
command = addFlag(command, 'endpoint-path', endpointPath);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
|
|
83
|
+
return formatTextContents(stdout, stderr);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return formatTextContents(error instanceof Error ? error.message : `${error}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
register() {
|
|
90
|
+
return this.mcpServer.registerTool(toolName, {
|
|
91
|
+
title: 'Create HubSpot CMS Serverless Function',
|
|
92
|
+
description: `Creates a new HubSpot CMS serverless function using the hs create function command. Functions can be created non-interactively by specifying functionsFolder, filename, and endpointPath. Supports all HTTP methods (${HTTP_METHODS.join(', ')}).`,
|
|
93
|
+
inputSchema,
|
|
94
|
+
}, this.handler);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -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
|
+
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
6
|
+
userSuppliedName: z.ZodOptional<z.ZodString>;
|
|
7
|
+
dest: z.ZodOptional<z.ZodString>;
|
|
8
|
+
templateType: z.ZodOptional<z.ZodEnum<["page-template", "email-template", "partial", "global-partial", "blog-listing-template", "blog-post-template", "search-template", "section"]>>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
absoluteCurrentWorkingDirectory: string;
|
|
11
|
+
dest?: string | undefined;
|
|
12
|
+
templateType?: "page-template" | "email-template" | "partial" | "global-partial" | "blog-listing-template" | "blog-post-template" | "search-template" | "section" | undefined;
|
|
13
|
+
userSuppliedName?: string | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
absoluteCurrentWorkingDirectory: string;
|
|
16
|
+
dest?: string | undefined;
|
|
17
|
+
templateType?: "page-template" | "email-template" | "partial" | "global-partial" | "blog-listing-template" | "blog-post-template" | "search-template" | "section" | undefined;
|
|
18
|
+
userSuppliedName?: string | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export type HsCreateTemplateInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
21
|
+
export declare class HsCreateTemplateTool extends Tool<HsCreateTemplateInputSchema> {
|
|
22
|
+
constructor(mcpServer: McpServer);
|
|
23
|
+
handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }: HsCreateTemplateInputSchema): Promise<TextContentResponse>;
|
|
24
|
+
register(): RegisteredTool;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
+
import { runCommandInDir } from '../../utils/project.js';
|
|
5
|
+
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
|
+
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
|
+
import { addFlag } from '../../utils/command.js';
|
|
8
|
+
import { TEMPLATE_TYPES } from '../../../types/Cms.js';
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
absoluteCurrentWorkingDirectory,
|
|
11
|
+
userSuppliedName: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe('REQUIRED - If not specified by the user, DO NOT choose. Ask the user to specify the name of the template they want to create.')
|
|
14
|
+
.optional(),
|
|
15
|
+
dest: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe('The destination path where the template should be created on the current computer.')
|
|
18
|
+
.optional(),
|
|
19
|
+
templateType: z
|
|
20
|
+
.enum(TEMPLATE_TYPES)
|
|
21
|
+
.describe(`Template type for template creation. Must be one of: ${TEMPLATE_TYPES.join(', ')}`)
|
|
22
|
+
.optional(),
|
|
23
|
+
};
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
+
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
26
|
+
const toolName = 'create-hubspot-cms-template';
|
|
27
|
+
export class HsCreateTemplateTool extends Tool {
|
|
28
|
+
constructor(mcpServer) {
|
|
29
|
+
super(mcpServer);
|
|
30
|
+
}
|
|
31
|
+
async handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }) {
|
|
32
|
+
await trackToolUsage(toolName);
|
|
33
|
+
const content = [];
|
|
34
|
+
// Always require a name
|
|
35
|
+
if (!userSuppliedName) {
|
|
36
|
+
content.push(formatTextContent(`Ask the user to specify the name of the template they want to create.`));
|
|
37
|
+
}
|
|
38
|
+
// Require template type
|
|
39
|
+
if (!templateType) {
|
|
40
|
+
content.push(formatTextContent(`Ask the user what template type they want to create. Options are: ${TEMPLATE_TYPES.join(', ')}`));
|
|
41
|
+
}
|
|
42
|
+
// If we have missing required information, return the prompts
|
|
43
|
+
if (content.length > 0) {
|
|
44
|
+
return {
|
|
45
|
+
content,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Build the command
|
|
49
|
+
let command = 'hs create template';
|
|
50
|
+
if (userSuppliedName) {
|
|
51
|
+
command += ` "${userSuppliedName}"`;
|
|
52
|
+
}
|
|
53
|
+
if (dest) {
|
|
54
|
+
command += ` "${dest}"`;
|
|
55
|
+
}
|
|
56
|
+
// Add template type flag
|
|
57
|
+
if (templateType) {
|
|
58
|
+
command = addFlag(command, 'template-type', templateType);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
|
|
62
|
+
return formatTextContents(stdout, stderr);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return formatTextContents(error instanceof Error ? error.message : `${error}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
register() {
|
|
69
|
+
return this.mcpServer.registerTool(toolName, {
|
|
70
|
+
title: 'Create HubSpot CMS Template',
|
|
71
|
+
description: `Creates a new HubSpot CMS template using the hs create template command. Templates can be created non-interactively by specifying templateType. Supports all template types including: ${TEMPLATE_TYPES.join(', ')}.`,
|
|
72
|
+
inputSchema,
|
|
73
|
+
}, this.handler);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
6
|
+
endpoint: z.ZodString;
|
|
7
|
+
account: z.ZodOptional<z.ZodString>;
|
|
8
|
+
latest: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
compact: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
endpoint: string;
|
|
13
|
+
absoluteCurrentWorkingDirectory: string;
|
|
14
|
+
account?: string | undefined;
|
|
15
|
+
limit?: number | undefined;
|
|
16
|
+
compact?: boolean | undefined;
|
|
17
|
+
latest?: boolean | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
endpoint: string;
|
|
20
|
+
absoluteCurrentWorkingDirectory: string;
|
|
21
|
+
account?: string | undefined;
|
|
22
|
+
limit?: number | undefined;
|
|
23
|
+
compact?: boolean | undefined;
|
|
24
|
+
latest?: boolean | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
export type HsFunctionLogsInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
27
|
+
export declare class HsFunctionLogsTool extends Tool<HsFunctionLogsInputSchema> {
|
|
28
|
+
constructor(mcpServer: McpServer);
|
|
29
|
+
handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }: HsFunctionLogsInputSchema): Promise<TextContentResponse>;
|
|
30
|
+
register(): RegisteredTool;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { addFlag } from '../../utils/command.js';
|
|
4
|
+
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
5
|
+
import { runCommandInDir } from '../../utils/project.js';
|
|
6
|
+
import { formatTextContents } from '../../utils/content.js';
|
|
7
|
+
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
|
+
const inputSchema = {
|
|
9
|
+
absoluteCurrentWorkingDirectory,
|
|
10
|
+
endpoint: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('The function endpoint/path to get logs for. Required. Example: "my-function" or "api/my-endpoint" (leading slash will be automatically removed)'),
|
|
13
|
+
account: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe('The HubSpot account id or name from the HubSpot config file to use for the operation.')
|
|
16
|
+
.optional(),
|
|
17
|
+
latest: z
|
|
18
|
+
.boolean()
|
|
19
|
+
.describe('Get only the latest log entry for the function.')
|
|
20
|
+
.optional(),
|
|
21
|
+
compact: z.boolean().describe('Display logs in compact format.').optional(),
|
|
22
|
+
limit: z
|
|
23
|
+
.number()
|
|
24
|
+
.describe('Maximum number of log entries to retrieve.')
|
|
25
|
+
.optional(),
|
|
26
|
+
};
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
29
|
+
const toolName = 'get-hubspot-cms-serverless-function-logs';
|
|
30
|
+
export class HsFunctionLogsTool extends Tool {
|
|
31
|
+
constructor(mcpServer) {
|
|
32
|
+
super(mcpServer);
|
|
33
|
+
}
|
|
34
|
+
async handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }) {
|
|
35
|
+
await trackToolUsage(toolName);
|
|
36
|
+
// Ensure endpoint doesn't start with '/'
|
|
37
|
+
const normalizedEndpoint = endpoint.startsWith('/')
|
|
38
|
+
? endpoint.slice(1)
|
|
39
|
+
: endpoint;
|
|
40
|
+
let command = `hs logs ${normalizedEndpoint}`;
|
|
41
|
+
if (latest) {
|
|
42
|
+
command = addFlag(command, 'latest', latest);
|
|
43
|
+
}
|
|
44
|
+
if (compact) {
|
|
45
|
+
command = addFlag(command, 'compact', compact);
|
|
46
|
+
}
|
|
47
|
+
if (limit) {
|
|
48
|
+
command = addFlag(command, 'limit', limit);
|
|
49
|
+
}
|
|
50
|
+
if (account) {
|
|
51
|
+
command = addFlag(command, 'account', account);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
|
|
55
|
+
return formatTextContents(stdout, stderr);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: `Error executing hs logs command: ${errorMessage}`,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
register() {
|
|
70
|
+
return this.mcpServer.registerTool(toolName, {
|
|
71
|
+
title: 'Get HubSpot CMS serverless function logs for an endpoint',
|
|
72
|
+
description: 'Retrieve logs for HubSpot CMS serverless functions. Use this tool to help debug issues with serverless functions by reading the production logs. Supports various options like latest, compact, and limiting results. Use after listing functions with list-hubspot-cms-serverless-functions to get the endpoint path.',
|
|
73
|
+
inputSchema,
|
|
74
|
+
}, this.handler);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
6
|
+
account: z.ZodOptional<z.ZodString>;
|
|
7
|
+
json: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
absoluteCurrentWorkingDirectory: string;
|
|
10
|
+
account?: string | undefined;
|
|
11
|
+
json?: boolean | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
absoluteCurrentWorkingDirectory: string;
|
|
14
|
+
account?: string | undefined;
|
|
15
|
+
json?: boolean | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export type HsListFunctionsInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
18
|
+
export declare class HsListFunctionsTool extends Tool<HsListFunctionsInputSchema> {
|
|
19
|
+
constructor(mcpServer: McpServer);
|
|
20
|
+
handler({ account, json, absoluteCurrentWorkingDirectory, }: HsListFunctionsInputSchema): Promise<TextContentResponse>;
|
|
21
|
+
register(): RegisteredTool;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { addFlag } from '../../utils/command.js';
|
|
4
|
+
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
5
|
+
import { runCommandInDir } from '../../utils/project.js';
|
|
6
|
+
import { formatTextContents } from '../../utils/content.js';
|
|
7
|
+
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
|
+
const inputSchema = {
|
|
9
|
+
absoluteCurrentWorkingDirectory,
|
|
10
|
+
account: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('The HubSpot account id or name from the HubSpot config file to use for the operation.')
|
|
13
|
+
.optional(),
|
|
14
|
+
json: z
|
|
15
|
+
.boolean()
|
|
16
|
+
.describe('Return raw JSON output instead of formatted table. Useful for programmatic access.')
|
|
17
|
+
.optional(),
|
|
18
|
+
};
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
21
|
+
const toolName = 'list-hubspot-cms-serverless-functions';
|
|
22
|
+
export class HsListFunctionsTool extends Tool {
|
|
23
|
+
constructor(mcpServer) {
|
|
24
|
+
super(mcpServer);
|
|
25
|
+
}
|
|
26
|
+
async handler({ account, json, absoluteCurrentWorkingDirectory, }) {
|
|
27
|
+
await trackToolUsage(toolName);
|
|
28
|
+
let command = 'hs function list';
|
|
29
|
+
if (json) {
|
|
30
|
+
command += ' --json';
|
|
31
|
+
}
|
|
32
|
+
if (account) {
|
|
33
|
+
command = addFlag(command, 'account', account);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
|
|
37
|
+
return formatTextContents(stdout, stderr);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: 'text',
|
|
45
|
+
text: `Error executing hs function list command: ${errorMessage}`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
register() {
|
|
52
|
+
return this.mcpServer.registerTool(toolName, {
|
|
53
|
+
title: 'List HubSpot CMS Serverless Functions',
|
|
54
|
+
description: 'Get a list of all serverless functions deployed in a HubSpot portal/account. Shows function routes, HTTP methods, secrets, and timestamps.',
|
|
55
|
+
inputSchema,
|
|
56
|
+
}, this.handler);
|
|
57
|
+
}
|
|
58
|
+
}
|