@hubspot/cli 7.7.27-experimental.2 → 7.7.29-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/README.md +0 -4
- package/api/__tests__/migrate.test.js +5 -5
- package/api/migrate.d.ts +10 -4
- package/api/migrate.js +2 -2
- package/commands/__tests__/create.test.js +20 -0
- package/commands/__tests__/testAccount.test.js +2 -0
- package/commands/app/__tests__/migrate.test.js +1 -0
- package/commands/create/function.js +2 -2
- package/commands/create/module.js +2 -2
- package/commands/create/template.js +2 -2
- package/commands/create.js +47 -0
- package/commands/getStarted.js +66 -4
- package/commands/mcp/setup.d.ts +0 -1
- package/commands/mcp/setup.js +3 -11
- package/commands/project/__tests__/create.test.js +57 -0
- package/commands/project/__tests__/devUnifiedFlow.test.js +18 -30
- package/commands/project/create.js +6 -1
- package/commands/project/deploy.js +31 -1
- package/commands/project/dev/deprecatedFlow.js +2 -1
- package/commands/project/dev/index.js +32 -12
- package/commands/project/dev/unifiedFlow.d.ts +1 -1
- package/commands/project/dev/unifiedFlow.js +10 -16
- package/commands/project/profile/delete.js +26 -14
- package/commands/testAccount/__tests__/importData.test.d.ts +1 -0
- package/commands/testAccount/__tests__/importData.test.js +93 -0
- package/commands/testAccount/create.js +23 -13
- package/commands/testAccount/importData.d.ts +9 -0
- package/commands/testAccount/importData.js +61 -0
- package/commands/testAccount.js +2 -0
- package/lang/en.d.ts +162 -46
- package/lang/en.js +177 -59
- package/lang/en.lyaml +35 -14
- package/lib/__tests__/importData.test.d.ts +1 -0
- package/lib/__tests__/importData.test.js +89 -0
- package/lib/accountTypes.js +2 -3
- package/lib/app/__tests__/migrate.test.js +81 -36
- package/lib/app/migrate.d.ts +17 -4
- package/lib/app/migrate.js +97 -19
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +1 -0
- package/lib/hasFeature.d.ts +1 -0
- package/lib/hasFeature.js +7 -0
- package/lib/importData.d.ts +3 -0
- package/lib/importData.js +50 -0
- package/lib/mcp/setup.d.ts +3 -5
- package/lib/mcp/setup.js +39 -139
- package/lib/process.js +15 -4
- package/lib/projects/__tests__/AppDevModeInterface.test.js +3 -3
- package/lib/projects/__tests__/LocalDevProcess.test.js +5 -95
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +6 -6
- package/lib/projects/__tests__/components.test.js +164 -7
- package/lib/projects/__tests__/localDevProjectHelpers.test.d.ts +1 -0
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +118 -0
- package/lib/projects/add/v3AddComponent.js +16 -4
- package/lib/projects/components.d.ts +1 -0
- package/lib/projects/components.js +27 -1
- package/lib/projects/localDev/AppDevModeInterface.js +35 -3
- package/lib/projects/localDev/LocalDevLogger.d.ts +0 -4
- package/lib/projects/localDev/LocalDevLogger.js +2 -19
- package/lib/projects/localDev/LocalDevManager.js +1 -1
- package/lib/projects/localDev/LocalDevProcess.d.ts +1 -2
- package/lib/projects/localDev/LocalDevProcess.js +3 -26
- package/lib/projects/localDev/LocalDevState.d.ts +6 -7
- package/lib/projects/localDev/LocalDevState.js +16 -15
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +1 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +17 -2
- package/lib/projects/localDev/{helpers.d.ts → helpers/account.d.ts} +1 -7
- package/lib/projects/localDev/{helpers.js → helpers/account.js} +44 -144
- package/lib/projects/localDev/helpers/project.d.ts +12 -0
- package/lib/projects/localDev/helpers/project.js +173 -0
- package/lib/projects/urls.d.ts +1 -0
- package/lib/projects/urls.js +4 -0
- package/lib/prompts/__tests__/createFunctionPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createFunctionPrompt.test.js +129 -0
- package/lib/prompts/__tests__/createModulePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createModulePrompt.test.js +187 -0
- package/lib/prompts/__tests__/createTemplatePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createTemplatePrompt.test.js +102 -0
- package/lib/prompts/confirmImportDataPrompt.d.ts +1 -0
- package/lib/prompts/confirmImportDataPrompt.js +12 -0
- package/lib/prompts/createFunctionPrompt.d.ts +2 -1
- package/lib/prompts/createFunctionPrompt.js +36 -7
- package/lib/prompts/createModulePrompt.d.ts +2 -1
- package/lib/prompts/createModulePrompt.js +48 -1
- package/lib/prompts/createTemplatePrompt.d.ts +3 -24
- package/lib/prompts/createTemplatePrompt.js +9 -1
- package/lib/prompts/importDataFilePathPrompt.d.ts +1 -0
- package/lib/prompts/importDataFilePathPrompt.js +24 -0
- package/lib/prompts/importDataTestAccountSelectPrompt.d.ts +3 -0
- package/lib/prompts/importDataTestAccountSelectPrompt.js +29 -0
- package/lib/prompts/projectDevTargetAccountPrompt.js +1 -0
- package/lib/prompts/promptUtils.d.ts +7 -1
- package/lib/prompts/promptUtils.js +14 -1
- package/lib/ui/__tests__/removeAnsiCodes.test.d.ts +1 -0
- package/lib/ui/__tests__/removeAnsiCodes.test.js +84 -0
- package/lib/ui/index.js +3 -6
- package/lib/ui/removeAnsiCodes.d.ts +1 -0
- package/lib/ui/removeAnsiCodes.js +4 -0
- package/mcp-server/server.js +2 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +38 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.js +118 -0
- package/mcp-server/tools/cms/HsListTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListTool.js +58 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +224 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +120 -0
- package/mcp-server/tools/index.d.ts +1 -0
- package/mcp-server/tools/index.js +12 -0
- package/mcp-server/tools/project/DocFetchTool.d.ts +17 -0
- package/mcp-server/tools/project/DocFetchTool.js +49 -0
- package/mcp-server/tools/project/DocsSearchTool.d.ts +26 -0
- package/mcp-server/tools/project/DocsSearchTool.js +62 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +3 -2
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +117 -0
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +190 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +2 -0
- package/mcp-server/tools/project/constants.js +6 -0
- package/mcp-server/utils/toolUsageTracking.d.ts +3 -1
- package/mcp-server/utils/toolUsageTracking.js +2 -1
- package/package.json +9 -6
- package/types/Cms.d.ts +16 -0
- package/types/Cms.js +25 -1
- package/types/LocalDev.d.ts +0 -3
- package/types/Prompts.d.ts +1 -0
- package/ui/index.d.ts +1 -0
- package/ui/index.js +6 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountIdentifier';
|
|
2
|
+
import { promptUser } from './promptUtils.js';
|
|
3
|
+
import { getConfigAccounts } from '@hubspot/local-dev-lib/config';
|
|
4
|
+
import { uiAccountDescription } from '../ui/index.js';
|
|
5
|
+
import { lib } from '../../lang/en.js';
|
|
6
|
+
export async function importDataTestAccountSelectPrompt(parentAccountId) {
|
|
7
|
+
const accounts = getConfigAccounts();
|
|
8
|
+
if (!accounts) {
|
|
9
|
+
throw new Error(lib.prompts.importDataTestAccountSelectPrompt.errors.noAccountsFound);
|
|
10
|
+
}
|
|
11
|
+
const childAccounts = accounts
|
|
12
|
+
.filter(account => account.parentAccountId === parentAccountId)
|
|
13
|
+
.map(account => {
|
|
14
|
+
return {
|
|
15
|
+
name: uiAccountDescription(getAccountIdentifier(account)),
|
|
16
|
+
value: getAccountIdentifier(account),
|
|
17
|
+
};
|
|
18
|
+
})
|
|
19
|
+
.filter(account => account.value !== undefined && account.name !== undefined);
|
|
20
|
+
if (childAccounts.length === 0) {
|
|
21
|
+
throw new Error(lib.prompts.importDataTestAccountSelectPrompt.errors.noChildTestAccountsFound(parentAccountId));
|
|
22
|
+
}
|
|
23
|
+
return promptUser({
|
|
24
|
+
type: 'list',
|
|
25
|
+
name: 'selectedAccountId',
|
|
26
|
+
message: '[--account] Select a developer test account:',
|
|
27
|
+
choices: childAccounts,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { Separator as _Separator } from '@inquirer/prompts';
|
|
2
2
|
import { PromptConfig, GenericPromptResponse, PromptWhen, PromptChoices } from '../../types/Prompts.js';
|
|
3
3
|
export declare const Separator: _Separator;
|
|
4
|
+
export declare const PROMPT_THEME: {
|
|
5
|
+
prefix: {
|
|
6
|
+
idle: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
4
9
|
export declare function promptUser<T extends GenericPromptResponse>(config: PromptConfig<T> | PromptConfig<T>[]): Promise<T>;
|
|
5
10
|
export declare function confirmPrompt(message: string, options?: {
|
|
6
11
|
defaultAnswer?: boolean;
|
|
7
12
|
}): Promise<boolean>;
|
|
8
|
-
export declare function listPrompt<T = string>(message: string, { choices, when, defaultAnswer, validate, }: {
|
|
13
|
+
export declare function listPrompt<T = string>(message: string, { choices, when, defaultAnswer, validate, loop, }: {
|
|
9
14
|
choices: PromptChoices<T>;
|
|
10
15
|
when?: PromptWhen;
|
|
11
16
|
defaultAnswer?: string | number | boolean;
|
|
12
17
|
validate?: (input: T[]) => (boolean | string) | Promise<boolean | string>;
|
|
18
|
+
loop?: boolean;
|
|
13
19
|
}): Promise<T>;
|
|
14
20
|
export declare function inputPrompt(message: string, { when, validate, defaultAnswer, }?: {
|
|
15
21
|
when?: boolean | (() => boolean);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { confirm, Separator as _Separator, select, input, checkbox, password, number, } from '@inquirer/prompts';
|
|
2
2
|
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
3
4
|
export const Separator = new _Separator();
|
|
5
|
+
export const PROMPT_THEME = { prefix: { idle: chalk.green('?') } };
|
|
4
6
|
function isUserCancellationError(error) {
|
|
5
7
|
return error instanceof Error && error.name === 'ExitPromptError';
|
|
6
8
|
}
|
|
@@ -102,6 +104,8 @@ function handleRawListPrompt(config) {
|
|
|
102
104
|
choices: choices,
|
|
103
105
|
pageSize: config.pageSize,
|
|
104
106
|
default: config.default,
|
|
107
|
+
loop: config.loop,
|
|
108
|
+
theme: PROMPT_THEME,
|
|
105
109
|
}).then(resp => ({ [config.name]: resp }));
|
|
106
110
|
}
|
|
107
111
|
function handleNumberPrompt(config) {
|
|
@@ -109,6 +113,7 @@ function handleNumberPrompt(config) {
|
|
|
109
113
|
message: config.message,
|
|
110
114
|
default: config.default,
|
|
111
115
|
validate: config.validate,
|
|
116
|
+
theme: PROMPT_THEME,
|
|
112
117
|
}).then(resp => ({ [config.name]: resp }));
|
|
113
118
|
}
|
|
114
119
|
function handlePasswordPrompt(config) {
|
|
@@ -116,6 +121,7 @@ function handlePasswordPrompt(config) {
|
|
|
116
121
|
message: config.message,
|
|
117
122
|
mask: '*',
|
|
118
123
|
validate: config.validate,
|
|
124
|
+
theme: PROMPT_THEME,
|
|
119
125
|
}).then(resp => ({ [config.name]: resp }));
|
|
120
126
|
}
|
|
121
127
|
function handleCheckboxPrompt(config) {
|
|
@@ -125,6 +131,8 @@ function handleCheckboxPrompt(config) {
|
|
|
125
131
|
choices: choices,
|
|
126
132
|
pageSize: config.pageSize,
|
|
127
133
|
validate: config.validate,
|
|
134
|
+
loop: config.loop,
|
|
135
|
+
theme: PROMPT_THEME,
|
|
128
136
|
}).then(resp => ({ [config.name]: resp }));
|
|
129
137
|
}
|
|
130
138
|
function handleConfirmPrompt(config) {
|
|
@@ -138,6 +146,7 @@ function handleInputPrompt(config) {
|
|
|
138
146
|
default: config.default,
|
|
139
147
|
validate: config.validate,
|
|
140
148
|
transformer: config.transformer,
|
|
149
|
+
theme: PROMPT_THEME,
|
|
141
150
|
}).then(resp => ({ [config.name]: resp }));
|
|
142
151
|
}
|
|
143
152
|
function handleSelectPrompt(config) {
|
|
@@ -147,6 +156,8 @@ function handleSelectPrompt(config) {
|
|
|
147
156
|
choices: choices,
|
|
148
157
|
default: config.default,
|
|
149
158
|
pageSize: config.pageSize,
|
|
159
|
+
loop: config.loop,
|
|
160
|
+
theme: PROMPT_THEME,
|
|
150
161
|
}).then(resp => ({ [config.name]: resp }));
|
|
151
162
|
}
|
|
152
163
|
export async function confirmPrompt(message, options = {}) {
|
|
@@ -154,10 +165,11 @@ export async function confirmPrompt(message, options = {}) {
|
|
|
154
165
|
const choice = await confirm({
|
|
155
166
|
message,
|
|
156
167
|
default: defaultAnswer,
|
|
168
|
+
theme: PROMPT_THEME,
|
|
157
169
|
});
|
|
158
170
|
return choice;
|
|
159
171
|
}
|
|
160
|
-
export async function listPrompt(message, { choices, when, defaultAnswer, validate, }) {
|
|
172
|
+
export async function listPrompt(message, { choices, when, defaultAnswer, validate, loop, }) {
|
|
161
173
|
const { choice } = await promptUser({
|
|
162
174
|
name: 'choice',
|
|
163
175
|
type: 'list',
|
|
@@ -166,6 +178,7 @@ export async function listPrompt(message, { choices, when, defaultAnswer, valida
|
|
|
166
178
|
when,
|
|
167
179
|
default: defaultAnswer,
|
|
168
180
|
validate,
|
|
181
|
+
loop,
|
|
169
182
|
});
|
|
170
183
|
return choice;
|
|
171
184
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { removeAnsiCodes } from '../removeAnsiCodes.js';
|
|
4
|
+
describe('removeAnsiCodes', () => {
|
|
5
|
+
describe('basic functionality', () => {
|
|
6
|
+
it('should remove ANSI codes from colored text', () => {
|
|
7
|
+
const coloredText = chalk.red('Error message');
|
|
8
|
+
const cleanText = removeAnsiCodes(coloredText);
|
|
9
|
+
expect(cleanText).toBe('Error message');
|
|
10
|
+
});
|
|
11
|
+
it('should return unchanged text when no ANSI codes are present', () => {
|
|
12
|
+
const plainText = 'This is plain text';
|
|
13
|
+
const result = removeAnsiCodes(plainText);
|
|
14
|
+
expect(result).toBe('This is plain text');
|
|
15
|
+
});
|
|
16
|
+
it('should handle empty strings', () => {
|
|
17
|
+
const result = removeAnsiCodes('');
|
|
18
|
+
expect(result).toBe('');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('background colors', () => {
|
|
22
|
+
it('should remove background color codes', () => {
|
|
23
|
+
const text = chalk.bgRed('Text with red background');
|
|
24
|
+
expect(removeAnsiCodes(text)).toBe('Text with red background');
|
|
25
|
+
});
|
|
26
|
+
it('should remove multiple background colors', () => {
|
|
27
|
+
const text = chalk.bgBlue('Blue bg') + ' ' + chalk.bgYellow('Yellow bg');
|
|
28
|
+
expect(removeAnsiCodes(text)).toBe('Blue bg Yellow bg');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('text formatting', () => {
|
|
32
|
+
it('should remove bold formatting', () => {
|
|
33
|
+
const text = chalk.bold('Bold text');
|
|
34
|
+
expect(removeAnsiCodes(text)).toBe('Bold text');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('combined styles', () => {
|
|
38
|
+
it('should remove multiple formatting styles', () => {
|
|
39
|
+
const text = chalk.bold.red('Bold red text');
|
|
40
|
+
expect(removeAnsiCodes(text)).toBe('Bold red text');
|
|
41
|
+
});
|
|
42
|
+
it('should remove complex combinations', () => {
|
|
43
|
+
const text = chalk.bold.underline.red.bgYellow('Complex styling');
|
|
44
|
+
expect(removeAnsiCodes(text)).toBe('Complex styling');
|
|
45
|
+
});
|
|
46
|
+
it('should handle chained styles', () => {
|
|
47
|
+
const text = chalk.red('Red') + chalk.green(' Green') + chalk.blue(' Blue');
|
|
48
|
+
expect(removeAnsiCodes(text)).toBe('Red Green Blue');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('multiline text', () => {
|
|
52
|
+
it('should remove ANSI codes from multiline text', () => {
|
|
53
|
+
const text = chalk.red('Line 1\n') + chalk.green('Line 2\n') + chalk.blue('Line 3');
|
|
54
|
+
const expected = 'Line 1\nLine 2\nLine 3';
|
|
55
|
+
expect(removeAnsiCodes(text)).toBe(expected);
|
|
56
|
+
});
|
|
57
|
+
it('should handle mixed formatted and plain lines', () => {
|
|
58
|
+
const text = chalk.bold('Formatted line\n') +
|
|
59
|
+
'Plain line\n' +
|
|
60
|
+
chalk.italic('Another formatted line');
|
|
61
|
+
const expected = 'Formatted line\nPlain line\nAnother formatted line';
|
|
62
|
+
expect(removeAnsiCodes(text)).toBe(expected);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('edge cases', () => {
|
|
66
|
+
it('should handle text with only ANSI codes (no visible text)', () => {
|
|
67
|
+
const text = chalk.red('');
|
|
68
|
+
expect(removeAnsiCodes(text)).toBe('');
|
|
69
|
+
});
|
|
70
|
+
it('should handle multiple consecutive ANSI codes', () => {
|
|
71
|
+
// Create text with multiple style applications
|
|
72
|
+
const text = chalk.red(chalk.bold(chalk.underline('Heavily styled')));
|
|
73
|
+
expect(removeAnsiCodes(text)).toBe('Heavily styled');
|
|
74
|
+
});
|
|
75
|
+
it('should handle mixed content with spaces and special characters', () => {
|
|
76
|
+
const text = chalk.green('Success:') + ' ' + chalk.red('Error!') + ' @#$%^&*()';
|
|
77
|
+
expect(removeAnsiCodes(text)).toBe('Success: Error! @#$%^&*()');
|
|
78
|
+
});
|
|
79
|
+
it('should handle text with tabs and newlines', () => {
|
|
80
|
+
const text = chalk.yellow('\tTabbed text\n') + chalk.cyan('New line text');
|
|
81
|
+
expect(removeAnsiCodes(text)).toBe('\tTabbed text\nNew line text');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
package/lib/ui/index.js
CHANGED
|
@@ -65,16 +65,13 @@ export function uiCommandReference(command, withQuotes = true) {
|
|
|
65
65
|
}
|
|
66
66
|
export function uiFeatureHighlight(features, title) {
|
|
67
67
|
uiInfoSection(title ? title : i18n(`lib.ui.featureHighlight.defaultTitle`), () => {
|
|
68
|
-
features.forEach(
|
|
69
|
-
const featureKey = `lib.ui.featureHighlight.featureKeys.${
|
|
68
|
+
features.forEach(feature => {
|
|
69
|
+
const featureKey = `lib.ui.featureHighlight.featureKeys.${feature}`;
|
|
70
70
|
const message = i18n(`${featureKey}.message`, {
|
|
71
71
|
command: uiCommandReference(i18n(`${featureKey}.command`)),
|
|
72
72
|
link: uiLink(i18n(`${featureKey}.linkText`), i18n(`${featureKey}.url`)),
|
|
73
73
|
});
|
|
74
|
-
|
|
75
|
-
logger.log('');
|
|
76
|
-
}
|
|
77
|
-
logger.log(message);
|
|
74
|
+
logger.log(` - ${message}`);
|
|
78
75
|
});
|
|
79
76
|
});
|
|
80
77
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function removeAnsiCodes(str: string): string;
|
package/mcp-server/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { registerProjectTools } from './tools/index.js';
|
|
3
|
+
import { registerProjectTools, registerCmsTools } from './tools/index.js';
|
|
4
4
|
const server = new McpServer({
|
|
5
5
|
name: 'HubSpot CLI MCP Server',
|
|
6
6
|
version: '0.0.1',
|
|
@@ -11,6 +11,7 @@ const server = new McpServer({
|
|
|
11
11
|
},
|
|
12
12
|
});
|
|
13
13
|
registerProjectTools(server);
|
|
14
|
+
registerCmsTools(server);
|
|
14
15
|
// Start receiving messages on stdin and sending messages on stdout
|
|
15
16
|
const transport = new StdioServerTransport();
|
|
16
17
|
server.connect(transport);
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
moduleLabel: z.ZodOptional<z.ZodString>;
|
|
9
|
+
reactType: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
contentTypes: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
11
|
+
global: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
availableForNewContent: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
absoluteCurrentWorkingDirectory: string;
|
|
15
|
+
dest?: string | undefined;
|
|
16
|
+
global?: boolean | undefined;
|
|
17
|
+
moduleLabel?: string | undefined;
|
|
18
|
+
reactType?: boolean | undefined;
|
|
19
|
+
contentTypes?: string | undefined;
|
|
20
|
+
availableForNewContent?: boolean | undefined;
|
|
21
|
+
userSuppliedName?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
absoluteCurrentWorkingDirectory: string;
|
|
24
|
+
dest?: string | undefined;
|
|
25
|
+
global?: boolean | undefined;
|
|
26
|
+
moduleLabel?: string | undefined;
|
|
27
|
+
reactType?: boolean | undefined;
|
|
28
|
+
contentTypes?: string | undefined;
|
|
29
|
+
availableForNewContent?: boolean | undefined;
|
|
30
|
+
userSuppliedName?: string | undefined;
|
|
31
|
+
}>;
|
|
32
|
+
export type HsCreateModuleInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
33
|
+
export declare class HsCreateModuleTool extends Tool<HsCreateModuleInputSchema> {
|
|
34
|
+
constructor(mcpServer: McpServer);
|
|
35
|
+
handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }: HsCreateModuleInputSchema): Promise<TextContentResponse>;
|
|
36
|
+
register(): RegisteredTool;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
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 { CONTENT_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 module they want to create.')
|
|
14
|
+
.optional(),
|
|
15
|
+
dest: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe('The destination path where the module should be created on the current computer.')
|
|
18
|
+
.optional(),
|
|
19
|
+
moduleLabel: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe('Label for module creation. Required for non-interactive module creation. If not provided, ask the user to provide it.')
|
|
22
|
+
.optional(),
|
|
23
|
+
reactType: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.describe('Whether to create a React module. If the user has not specified that they want a React module, DO NOT choose for them, ask them what type of module they want to create HubL or React.')
|
|
26
|
+
.optional(),
|
|
27
|
+
contentTypes: z
|
|
28
|
+
.string()
|
|
29
|
+
.refine(val => {
|
|
30
|
+
if (!val)
|
|
31
|
+
return true; // optional
|
|
32
|
+
const types = val.split(',').map(t => t.trim().toUpperCase());
|
|
33
|
+
return types.every(type => CONTENT_TYPES.includes(type));
|
|
34
|
+
}, {
|
|
35
|
+
message: `Content types must be a comma-separated list of valid values: ${CONTENT_TYPES.join(', ')}`,
|
|
36
|
+
})
|
|
37
|
+
.describe(`Content types where the module can be used. Comma-separated list. Valid values: ${CONTENT_TYPES.join(', ')}. Defaults to "ANY".`)
|
|
38
|
+
.optional(),
|
|
39
|
+
global: z
|
|
40
|
+
.boolean()
|
|
41
|
+
.describe('Whether the module is global. Defaults to false.')
|
|
42
|
+
.optional(),
|
|
43
|
+
availableForNewContent: z
|
|
44
|
+
.boolean()
|
|
45
|
+
.describe('Whether the module is available for new content. Defaults to true.')
|
|
46
|
+
.optional(),
|
|
47
|
+
};
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
49
|
+
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
50
|
+
const toolName = 'create-hubspot-cms-module';
|
|
51
|
+
export class HsCreateModuleTool extends Tool {
|
|
52
|
+
constructor(mcpServer) {
|
|
53
|
+
super(mcpServer);
|
|
54
|
+
}
|
|
55
|
+
async handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }) {
|
|
56
|
+
await trackToolUsage(toolName);
|
|
57
|
+
const content = [];
|
|
58
|
+
// Always require a name
|
|
59
|
+
if (!userSuppliedName) {
|
|
60
|
+
content.push(formatTextContent(`Ask the user to specify the name of the module they want to create.`));
|
|
61
|
+
}
|
|
62
|
+
// Require module label
|
|
63
|
+
if (!moduleLabel) {
|
|
64
|
+
content.push(formatTextContent(`Ask the user to provide a label for the module.`));
|
|
65
|
+
}
|
|
66
|
+
// Ask about React vs HubL if not specified
|
|
67
|
+
if (reactType === undefined) {
|
|
68
|
+
content.push(formatTextContent(`Ask the user what type of module they want to create: HubL or React?`));
|
|
69
|
+
}
|
|
70
|
+
// If we have missing required information, return the prompts
|
|
71
|
+
if (content.length > 0) {
|
|
72
|
+
return {
|
|
73
|
+
content,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Build the command
|
|
77
|
+
let command = 'hs create module';
|
|
78
|
+
if (userSuppliedName) {
|
|
79
|
+
command += ` "${userSuppliedName}"`;
|
|
80
|
+
}
|
|
81
|
+
if (dest) {
|
|
82
|
+
command += ` "${dest}"`;
|
|
83
|
+
}
|
|
84
|
+
// Add module-specific flags
|
|
85
|
+
if (moduleLabel) {
|
|
86
|
+
command = addFlag(command, 'module-label', moduleLabel);
|
|
87
|
+
}
|
|
88
|
+
if (reactType !== undefined) {
|
|
89
|
+
command = addFlag(command, 'react-type', reactType);
|
|
90
|
+
}
|
|
91
|
+
if (contentTypes) {
|
|
92
|
+
command = addFlag(command, 'content-types', contentTypes);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
command = addFlag(command, 'content-types', 'ANY');
|
|
96
|
+
}
|
|
97
|
+
if (global !== undefined) {
|
|
98
|
+
command = addFlag(command, 'global', global);
|
|
99
|
+
}
|
|
100
|
+
if (availableForNewContent !== undefined) {
|
|
101
|
+
command = addFlag(command, 'available-for-new-content', availableForNewContent);
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
|
|
105
|
+
return formatTextContents(stdout, stderr);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return formatTextContents(error instanceof Error ? error.message : `${error}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
register() {
|
|
112
|
+
return this.mcpServer.registerTool(toolName, {
|
|
113
|
+
title: 'Create HubSpot CMS Module',
|
|
114
|
+
description: 'Creates a new HubSpot CMS module using the hs create module command. Modules can be created non-interactively by specifying moduleLabel and other module options. You can create either HubL or React modules by setting the reactType parameter.',
|
|
115
|
+
inputSchema,
|
|
116
|
+
}, this.handler);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -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
|
+
path: z.ZodOptional<z.ZodString>;
|
|
7
|
+
account: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
absoluteCurrentWorkingDirectory: string;
|
|
10
|
+
account?: string | undefined;
|
|
11
|
+
path?: string | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
absoluteCurrentWorkingDirectory: string;
|
|
14
|
+
account?: string | undefined;
|
|
15
|
+
path?: string | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export type HsListInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
18
|
+
export declare class HsListTool extends Tool<HsListInputSchema> {
|
|
19
|
+
constructor(mcpServer: McpServer);
|
|
20
|
+
handler({ path, account, absoluteCurrentWorkingDirectory, }: HsListInputSchema): 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
|
+
path: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('The remote directory path in the HubSpot CMS to list contents. If not specified, lists the root directory.')
|
|
13
|
+
.optional(),
|
|
14
|
+
account: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe('The HubSpot account id or name from the HubSpot config file to use for the operation.')
|
|
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-remote-contents';
|
|
22
|
+
export class HsListTool extends Tool {
|
|
23
|
+
constructor(mcpServer) {
|
|
24
|
+
super(mcpServer);
|
|
25
|
+
}
|
|
26
|
+
async handler({ path, account, absoluteCurrentWorkingDirectory, }) {
|
|
27
|
+
await trackToolUsage(toolName);
|
|
28
|
+
let command = 'hs list';
|
|
29
|
+
if (path) {
|
|
30
|
+
command += ` ${path}`;
|
|
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 list command: ${errorMessage}`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
register() {
|
|
52
|
+
return this.mcpServer.registerTool(toolName, {
|
|
53
|
+
title: 'List HubSpot CMS Directory Contents',
|
|
54
|
+
description: 'List remote contents of a HubSpot CMS directory.',
|
|
55
|
+
inputSchema,
|
|
56
|
+
}, this.handler);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|