@hubspot/cli 7.6.0-beta.11 → 7.6.0-beta.13
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/__tests__/migrate.test.js +1 -0
- package/commands/getStarted.js +7 -20
- package/commands/mcp/setup.d.ts +0 -1
- package/commands/mcp/setup.js +11 -11
- package/commands/project/__tests__/add.test.js +64 -0
- package/commands/project/__tests__/create.test.js +57 -0
- package/commands/project/__tests__/deploy.test.js +3 -2
- package/commands/project/add.d.ts +1 -1
- package/commands/project/add.js +3 -5
- package/commands/project/create.js +7 -2
- package/commands/project/deploy.js +9 -61
- package/commands/project/dev/index.js +1 -1
- package/commands/project/dev/unifiedFlow.js +4 -1
- package/commands/project/migrate.js +26 -7
- package/commands/project/upload.js +2 -2
- package/commands/project/validate.js +1 -1
- package/commands/project/watch.js +2 -2
- package/lang/en.d.ts +20 -5
- package/lang/en.js +38 -22
- package/lang/en.lyaml +12 -12
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/__tests__/importData.test.js +1 -1
- package/lib/app/__tests__/migrate.test.js +14 -51
- package/lib/app/migrate.d.ts +2 -8
- package/lib/app/migrate.js +5 -73
- package/lib/constants.d.ts +4 -0
- package/lib/constants.js +4 -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/links.d.ts +1 -0
- package/lib/links.js +10 -3
- package/lib/mcp/setup.d.ts +0 -2
- package/lib/mcp/setup.js +4 -29
- package/lib/projects/__tests__/AppDevModeInterface.test.js +71 -44
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/components.test.js +164 -7
- package/lib/projects/__tests__/deploy.test.js +164 -0
- package/lib/projects/__tests__/platformVersion.test.d.ts +1 -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 +142 -8
- package/lib/projects/add/legacyAddComponent.d.ts +1 -1
- package/lib/projects/add/legacyAddComponent.js +5 -1
- package/lib/projects/add/v3AddComponent.d.ts +2 -1
- package/lib/projects/add/v3AddComponent.js +22 -5
- package/lib/projects/components.d.ts +1 -0
- package/lib/projects/components.js +27 -1
- 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 +5 -3
- package/lib/projects/localDev/AppDevModeInterface.js +110 -47
- 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.d.ts +2 -2
- package/lib/projects/localDev/helpers/project.js +6 -8
- 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/upload.js +1 -1
- 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/promptUtils.d.ts +5 -0
- package/lib/prompts/promptUtils.js +9 -0
- package/lib/prompts/selectProjectTemplatePrompt.js +1 -1
- package/lib/theme/__tests__/migrate.test.d.ts +1 -0
- package/lib/theme/__tests__/migrate.test.js +233 -0
- package/lib/theme/migrate.d.ts +13 -0
- package/lib/theme/migrate.js +90 -0
- package/lib/ui/index.js +3 -6
- package/lib/usageTracking.js +2 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +96 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +38 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.js +118 -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/HsListTool.js +1 -1
- 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__/HsCreateModuleTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +224 -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/cms/__tests__/HsListTool.test.js +1 -1
- package/mcp-server/tools/index.js +13 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +3 -3
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +5 -5
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +2 -2
- package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocsSearchTool.js +7 -7
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +14 -8
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +2 -2
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +14 -12
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +9 -8
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -1
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/tools/project/constants.js +14 -6
- package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
- package/mcp-server/utils/cliConfig.d.ts +1 -0
- package/mcp-server/utils/cliConfig.js +12 -0
- package/package.json +4 -3
- package/types/LocalDev.d.ts +2 -1
- package/types/Projects.d.ts +1 -0
- 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/lib/projects/__tests__/{buildAndDeploy.test.d.ts → deploy.test.d.ts} +0 -0
|
@@ -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
|
}
|
|
@@ -103,6 +105,7 @@ function handleRawListPrompt(config) {
|
|
|
103
105
|
pageSize: config.pageSize,
|
|
104
106
|
default: config.default,
|
|
105
107
|
loop: config.loop,
|
|
108
|
+
theme: PROMPT_THEME,
|
|
106
109
|
}).then(resp => ({ [config.name]: resp }));
|
|
107
110
|
}
|
|
108
111
|
function handleNumberPrompt(config) {
|
|
@@ -110,6 +113,7 @@ function handleNumberPrompt(config) {
|
|
|
110
113
|
message: config.message,
|
|
111
114
|
default: config.default,
|
|
112
115
|
validate: config.validate,
|
|
116
|
+
theme: PROMPT_THEME,
|
|
113
117
|
}).then(resp => ({ [config.name]: resp }));
|
|
114
118
|
}
|
|
115
119
|
function handlePasswordPrompt(config) {
|
|
@@ -117,6 +121,7 @@ function handlePasswordPrompt(config) {
|
|
|
117
121
|
message: config.message,
|
|
118
122
|
mask: '*',
|
|
119
123
|
validate: config.validate,
|
|
124
|
+
theme: PROMPT_THEME,
|
|
120
125
|
}).then(resp => ({ [config.name]: resp }));
|
|
121
126
|
}
|
|
122
127
|
function handleCheckboxPrompt(config) {
|
|
@@ -127,6 +132,7 @@ function handleCheckboxPrompt(config) {
|
|
|
127
132
|
pageSize: config.pageSize,
|
|
128
133
|
validate: config.validate,
|
|
129
134
|
loop: config.loop,
|
|
135
|
+
theme: PROMPT_THEME,
|
|
130
136
|
}).then(resp => ({ [config.name]: resp }));
|
|
131
137
|
}
|
|
132
138
|
function handleConfirmPrompt(config) {
|
|
@@ -140,6 +146,7 @@ function handleInputPrompt(config) {
|
|
|
140
146
|
default: config.default,
|
|
141
147
|
validate: config.validate,
|
|
142
148
|
transformer: config.transformer,
|
|
149
|
+
theme: PROMPT_THEME,
|
|
143
150
|
}).then(resp => ({ [config.name]: resp }));
|
|
144
151
|
}
|
|
145
152
|
function handleSelectPrompt(config) {
|
|
@@ -150,6 +157,7 @@ function handleSelectPrompt(config) {
|
|
|
150
157
|
default: config.default,
|
|
151
158
|
pageSize: config.pageSize,
|
|
152
159
|
loop: config.loop,
|
|
160
|
+
theme: PROMPT_THEME,
|
|
153
161
|
}).then(resp => ({ [config.name]: resp }));
|
|
154
162
|
}
|
|
155
163
|
export async function confirmPrompt(message, options = {}) {
|
|
@@ -157,6 +165,7 @@ export async function confirmPrompt(message, options = {}) {
|
|
|
157
165
|
const choice = await confirm({
|
|
158
166
|
message,
|
|
159
167
|
default: defaultAnswer,
|
|
168
|
+
theme: PROMPT_THEME,
|
|
160
169
|
});
|
|
161
170
|
return choice;
|
|
162
171
|
}
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { getProjectThemeDetails, migrateThemes, } from '@hubspot/project-parsing-lib';
|
|
2
|
+
import { confirmPrompt } from '../../prompts/promptUtils.js';
|
|
3
|
+
import { writeProjectConfig, } from '../../projects/config.js';
|
|
4
|
+
import { ensureProjectExists } from '../../projects/ensureProjectExists.js';
|
|
5
|
+
import { useV3Api } from '../../projects/platformVersion.js';
|
|
6
|
+
import { fetchMigrationApps } from '../../app/migrate.js';
|
|
7
|
+
import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration, migrateThemes2025_2, } from '../migrate.js';
|
|
8
|
+
import { lib } from '../../../lang/en.js';
|
|
9
|
+
vi.mock('@hubspot/local-dev-lib/logger');
|
|
10
|
+
vi.mock('@hubspot/project-parsing-lib');
|
|
11
|
+
vi.mock('../../prompts/promptUtils');
|
|
12
|
+
vi.mock('../../projects/config');
|
|
13
|
+
vi.mock('../../projects/ensureProjectExists');
|
|
14
|
+
vi.mock('../../projects/platformVersion');
|
|
15
|
+
vi.mock('../../app/migrate');
|
|
16
|
+
const mockedGetProjectThemeDetails = getProjectThemeDetails;
|
|
17
|
+
const mockedMigrateThemes = migrateThemes;
|
|
18
|
+
const mockedConfirmPrompt = confirmPrompt;
|
|
19
|
+
const mockedWriteProjectConfig = writeProjectConfig;
|
|
20
|
+
const mockedEnsureProjectExists = ensureProjectExists;
|
|
21
|
+
const mockedUseV3Api = useV3Api;
|
|
22
|
+
const mockedFetchMigrationApps = fetchMigrationApps;
|
|
23
|
+
const ACCOUNT_ID = 123;
|
|
24
|
+
const PROJECT_NAME = 'Test Project';
|
|
25
|
+
const PLATFORM_VERSION = '2025.2';
|
|
26
|
+
const MOCK_PROJECT_DIR = '/mock/project/dir';
|
|
27
|
+
const createLoadedProjectConfig = (name) => ({
|
|
28
|
+
projectConfig: { name, srcDir: 'src', platformVersion: '2024.1' },
|
|
29
|
+
projectDir: MOCK_PROJECT_DIR,
|
|
30
|
+
});
|
|
31
|
+
describe('lib/theme/migrate', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
mockedUseV3Api.mockReturnValue(false);
|
|
34
|
+
});
|
|
35
|
+
describe('getHasMigratableThemes', () => {
|
|
36
|
+
it('should return false when no projectConfig is provided', async () => {
|
|
37
|
+
const result = await getHasMigratableThemes();
|
|
38
|
+
expect(result).toEqual({
|
|
39
|
+
hasMigratableThemes: false,
|
|
40
|
+
migratableThemesCount: 0,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it('should return false when projectConfig is missing required properties', async () => {
|
|
44
|
+
const invalidProjectConfig = {
|
|
45
|
+
projectConfig: { name: undefined, srcDir: 'src' },
|
|
46
|
+
projectDir: undefined,
|
|
47
|
+
};
|
|
48
|
+
const result = await getHasMigratableThemes(invalidProjectConfig);
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
hasMigratableThemes: false,
|
|
51
|
+
migratableThemesCount: 0,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('should return true when there are legacy themes', async () => {
|
|
55
|
+
mockedGetProjectThemeDetails.mockResolvedValue({
|
|
56
|
+
legacyThemeDetails: [
|
|
57
|
+
{
|
|
58
|
+
configFilepath: 'src/theme.json',
|
|
59
|
+
themePath: 'src/theme',
|
|
60
|
+
themeConfig: {
|
|
61
|
+
secret_names: ['my-secret'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
legacyReactThemeDetails: [],
|
|
66
|
+
});
|
|
67
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
68
|
+
const result = await getHasMigratableThemes(projectConfig);
|
|
69
|
+
expect(result).toEqual({
|
|
70
|
+
hasMigratableThemes: true,
|
|
71
|
+
migratableThemesCount: 1,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it('should return true when there are legacy React themes', async () => {
|
|
75
|
+
mockedGetProjectThemeDetails.mockResolvedValue({
|
|
76
|
+
legacyThemeDetails: [],
|
|
77
|
+
legacyReactThemeDetails: [
|
|
78
|
+
{
|
|
79
|
+
configFilepath: 'src/react-theme.json',
|
|
80
|
+
themePath: 'src/react-theme',
|
|
81
|
+
themeConfig: {
|
|
82
|
+
secretNames: ['my-secret'],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
88
|
+
const result = await getHasMigratableThemes(projectConfig);
|
|
89
|
+
expect(result).toEqual({
|
|
90
|
+
hasMigratableThemes: true,
|
|
91
|
+
migratableThemesCount: 1,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
it('should return true when there are both legacy and React themes', async () => {
|
|
95
|
+
mockedGetProjectThemeDetails.mockResolvedValue({
|
|
96
|
+
legacyThemeDetails: [
|
|
97
|
+
{
|
|
98
|
+
configFilepath: 'src/theme.json',
|
|
99
|
+
themePath: 'src/theme',
|
|
100
|
+
themeConfig: {
|
|
101
|
+
secret_names: ['my-secret'],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
legacyReactThemeDetails: [
|
|
106
|
+
{
|
|
107
|
+
configFilepath: 'src/react-theme.json',
|
|
108
|
+
themePath: 'src/react-theme',
|
|
109
|
+
themeConfig: {
|
|
110
|
+
secretNames: ['my-secret'],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
116
|
+
const result = await getHasMigratableThemes(projectConfig);
|
|
117
|
+
expect(result).toEqual({
|
|
118
|
+
hasMigratableThemes: true,
|
|
119
|
+
migratableThemesCount: 2,
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe('validateMigrationAppsAndThemes', () => {
|
|
124
|
+
it('should throw an error when themes are already migrated (v3 API)', async () => {
|
|
125
|
+
mockedUseV3Api.mockReturnValue(true);
|
|
126
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
127
|
+
await expect(validateMigrationAppsAndThemes(0, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAlreadyMigrated);
|
|
128
|
+
});
|
|
129
|
+
it('should throw an error when apps and themes are both present', async () => {
|
|
130
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
131
|
+
await expect(validateMigrationAppsAndThemes(1, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAndAppsNotAllowed);
|
|
132
|
+
});
|
|
133
|
+
it('should throw an error when no project config is provided', async () => {
|
|
134
|
+
await expect(validateMigrationAppsAndThemes(0)).rejects.toThrow(lib.migrate.errors.project.noProjectForThemesMigration);
|
|
135
|
+
});
|
|
136
|
+
it('should not throw an error when validation passes', async () => {
|
|
137
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
138
|
+
await expect(validateMigrationAppsAndThemes(0, projectConfig)).resolves.not.toThrow();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe('handleThemesMigration', () => {
|
|
142
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
mockedMigrateThemes.mockResolvedValue({
|
|
145
|
+
migrated: true,
|
|
146
|
+
failureReason: undefined,
|
|
147
|
+
legacyThemeDetails: [],
|
|
148
|
+
legacyReactThemeDetails: [],
|
|
149
|
+
});
|
|
150
|
+
mockedWriteProjectConfig.mockReturnValue(true);
|
|
151
|
+
});
|
|
152
|
+
it('should throw an error when project config is invalid', async () => {
|
|
153
|
+
const invalidProjectConfig = {
|
|
154
|
+
projectConfig: { name: PROJECT_NAME, srcDir: undefined },
|
|
155
|
+
projectDir: undefined,
|
|
156
|
+
};
|
|
157
|
+
await expect(handleThemesMigration(invalidProjectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.invalidConfig);
|
|
158
|
+
});
|
|
159
|
+
it('should successfully migrate themes and update project config', async () => {
|
|
160
|
+
await handleThemesMigration(projectConfig, PLATFORM_VERSION);
|
|
161
|
+
expect(mockedMigrateThemes).toHaveBeenCalledWith(MOCK_PROJECT_DIR, `${MOCK_PROJECT_DIR}/src`);
|
|
162
|
+
expect(mockedWriteProjectConfig).toHaveBeenCalledWith(`${MOCK_PROJECT_DIR}/hsproject.json`, expect.objectContaining({
|
|
163
|
+
platformVersion: PLATFORM_VERSION,
|
|
164
|
+
}));
|
|
165
|
+
});
|
|
166
|
+
it('should throw an error when theme migration fails', async () => {
|
|
167
|
+
mockedMigrateThemes.mockResolvedValue({
|
|
168
|
+
migrated: false,
|
|
169
|
+
failureReason: 'Migration failed',
|
|
170
|
+
legacyThemeDetails: [],
|
|
171
|
+
legacyReactThemeDetails: [],
|
|
172
|
+
});
|
|
173
|
+
await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow('Migration failed');
|
|
174
|
+
});
|
|
175
|
+
it('should throw an error when project config write fails', async () => {
|
|
176
|
+
mockedWriteProjectConfig.mockReturnValue(false);
|
|
177
|
+
await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.failedToUpdateProjectConfig);
|
|
178
|
+
});
|
|
179
|
+
it('should throw an error when migrateThemes throws an exception', async () => {
|
|
180
|
+
mockedMigrateThemes.mockRejectedValue(new Error('Unexpected error'));
|
|
181
|
+
await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.failedToMigrateThemes);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe('migrateThemes2025_2', () => {
|
|
185
|
+
const options = {
|
|
186
|
+
platformVersion: PLATFORM_VERSION,
|
|
187
|
+
};
|
|
188
|
+
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
189
|
+
const themeCount = 2;
|
|
190
|
+
beforeEach(() => {
|
|
191
|
+
mockedEnsureProjectExists.mockResolvedValue({ projectExists: true });
|
|
192
|
+
mockedFetchMigrationApps.mockResolvedValue({
|
|
193
|
+
migratableApps: [],
|
|
194
|
+
unmigratableApps: [],
|
|
195
|
+
});
|
|
196
|
+
mockedConfirmPrompt.mockResolvedValue(true);
|
|
197
|
+
mockedMigrateThemes.mockResolvedValue({
|
|
198
|
+
migrated: true,
|
|
199
|
+
failureReason: undefined,
|
|
200
|
+
legacyThemeDetails: [],
|
|
201
|
+
legacyReactThemeDetails: [],
|
|
202
|
+
});
|
|
203
|
+
mockedWriteProjectConfig.mockReturnValue(true);
|
|
204
|
+
});
|
|
205
|
+
it('should throw an error when project config is invalid', async () => {
|
|
206
|
+
const invalidProjectConfig = {
|
|
207
|
+
projectConfig: undefined,
|
|
208
|
+
projectDir: MOCK_PROJECT_DIR,
|
|
209
|
+
};
|
|
210
|
+
await expect(migrateThemes2025_2(ACCOUNT_ID, options, themeCount, invalidProjectConfig)).rejects.toThrow(lib.migrate.errors.project.invalidConfig);
|
|
211
|
+
});
|
|
212
|
+
it('should throw an error when project does not exist', async () => {
|
|
213
|
+
mockedEnsureProjectExists.mockResolvedValue({ projectExists: false });
|
|
214
|
+
await expect(migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig)).rejects.toThrow(lib.migrate.errors.project.doesNotExist(ACCOUNT_ID));
|
|
215
|
+
});
|
|
216
|
+
it('should proceed with migration when user confirms', async () => {
|
|
217
|
+
await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
218
|
+
expect(mockedFetchMigrationApps).toHaveBeenCalledWith(ACCOUNT_ID, PLATFORM_VERSION, projectConfig);
|
|
219
|
+
expect(mockedConfirmPrompt).toHaveBeenCalledWith(lib.migrate.prompt.proceed, { defaultAnswer: false });
|
|
220
|
+
expect(mockedMigrateThemes).toHaveBeenCalledWith(MOCK_PROJECT_DIR, `${MOCK_PROJECT_DIR}/src`);
|
|
221
|
+
});
|
|
222
|
+
it('should exit without migrating when user cancels', async () => {
|
|
223
|
+
mockedConfirmPrompt.mockResolvedValue(false);
|
|
224
|
+
await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
225
|
+
expect(mockedMigrateThemes).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
it('should validate migration apps and themes', async () => {
|
|
228
|
+
await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
229
|
+
// The validation is called internally, so we verify it through the error handling
|
|
230
|
+
expect(mockedFetchMigrationApps).toHaveBeenCalled();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ArgumentsCamelCase } from 'yargs';
|
|
2
|
+
import { LoadedProjectConfig } from '../projects/config.js';
|
|
3
|
+
import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../types/Yargs.js';
|
|
4
|
+
export type MigrateThemesArgs = CommonArgs & AccountArgs & EnvironmentArgs & ConfigArgs & {
|
|
5
|
+
platformVersion: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function getHasMigratableThemes(projectConfig?: LoadedProjectConfig): Promise<{
|
|
8
|
+
hasMigratableThemes: boolean;
|
|
9
|
+
migratableThemesCount: number;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function validateMigrationAppsAndThemes(hasApps: number, projectConfig?: LoadedProjectConfig): Promise<void>;
|
|
12
|
+
export declare function handleThemesMigration(projectConfig: LoadedProjectConfig, platformVersion: string): Promise<void>;
|
|
13
|
+
export declare function migrateThemes2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateThemesArgs>, themeCount: number, projectConfig: LoadedProjectConfig): Promise<void>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { migrateThemes, getProjectThemeDetails, } from '@hubspot/project-parsing-lib';
|
|
3
|
+
import { writeProjectConfig } from '../projects/config.js';
|
|
4
|
+
import { ensureProjectExists } from '../projects/ensureProjectExists.js';
|
|
5
|
+
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
6
|
+
import { lib } from '../../lang/en.js';
|
|
7
|
+
import { PROJECT_CONFIG_FILE } from '../constants.js';
|
|
8
|
+
import { uiLogger } from '../ui/logger.js';
|
|
9
|
+
import { debugError } from '../errorHandlers/index.js';
|
|
10
|
+
import { useV3Api } from '../projects/platformVersion.js';
|
|
11
|
+
import { confirmPrompt } from '../prompts/promptUtils.js';
|
|
12
|
+
import { fetchMigrationApps } from '../app/migrate.js';
|
|
13
|
+
export async function getHasMigratableThemes(projectConfig) {
|
|
14
|
+
if (!projectConfig?.projectConfig?.name || !projectConfig?.projectDir) {
|
|
15
|
+
return { hasMigratableThemes: false, migratableThemesCount: 0 };
|
|
16
|
+
}
|
|
17
|
+
const projectSrcDir = path.resolve(projectConfig.projectDir, projectConfig.projectConfig.srcDir);
|
|
18
|
+
const { legacyThemeDetails, legacyReactThemeDetails } = await getProjectThemeDetails(projectSrcDir);
|
|
19
|
+
return {
|
|
20
|
+
hasMigratableThemes: legacyThemeDetails.length > 0 || legacyReactThemeDetails.length > 0,
|
|
21
|
+
migratableThemesCount: legacyThemeDetails.length + legacyReactThemeDetails.length,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function validateMigrationAppsAndThemes(hasApps, projectConfig) {
|
|
25
|
+
if (useV3Api(projectConfig?.projectConfig?.platformVersion)) {
|
|
26
|
+
throw new Error(lib.migrate.errors.project.themesAlreadyMigrated);
|
|
27
|
+
}
|
|
28
|
+
if (hasApps > 0 && projectConfig) {
|
|
29
|
+
throw new Error(lib.migrate.errors.project.themesAndAppsNotAllowed);
|
|
30
|
+
}
|
|
31
|
+
if (!projectConfig) {
|
|
32
|
+
throw new Error(lib.migrate.errors.project.noProjectForThemesMigration);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function handleThemesMigration(projectConfig, platformVersion) {
|
|
36
|
+
if (!projectConfig?.projectDir || !projectConfig?.projectConfig?.srcDir) {
|
|
37
|
+
throw new Error(lib.migrate.errors.project.invalidConfig);
|
|
38
|
+
}
|
|
39
|
+
const projectSrcDir = path.resolve(projectConfig.projectDir, projectConfig.projectConfig.srcDir);
|
|
40
|
+
let migrated = false;
|
|
41
|
+
let failureReason;
|
|
42
|
+
try {
|
|
43
|
+
const migrationResult = await migrateThemes(projectConfig.projectDir, projectSrcDir);
|
|
44
|
+
migrated = migrationResult.migrated;
|
|
45
|
+
failureReason = migrationResult.failureReason;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
debugError(error);
|
|
49
|
+
throw new Error(lib.migrate.errors.project.failedToMigrateThemes);
|
|
50
|
+
}
|
|
51
|
+
if (!migrated) {
|
|
52
|
+
throw new Error(failureReason || lib.migrate.errors.project.failedToMigrateThemes);
|
|
53
|
+
}
|
|
54
|
+
const newProjectConfig = { ...projectConfig.projectConfig };
|
|
55
|
+
newProjectConfig.platformVersion = platformVersion;
|
|
56
|
+
const projectConfigPath = path.join(projectConfig.projectDir, PROJECT_CONFIG_FILE);
|
|
57
|
+
const success = writeProjectConfig(projectConfigPath, newProjectConfig);
|
|
58
|
+
if (!success) {
|
|
59
|
+
throw new Error(lib.migrate.errors.project.failedToUpdateProjectConfig);
|
|
60
|
+
}
|
|
61
|
+
uiLogger.log('');
|
|
62
|
+
uiLogger.log(lib.migrate.success.themesMigrationSuccess(platformVersion));
|
|
63
|
+
}
|
|
64
|
+
export async function migrateThemes2025_2(derivedAccountId, options, themeCount, projectConfig) {
|
|
65
|
+
SpinniesManager.init();
|
|
66
|
+
if (!projectConfig?.projectConfig || !projectConfig?.projectDir) {
|
|
67
|
+
throw new Error(lib.migrate.errors.project.invalidConfig);
|
|
68
|
+
}
|
|
69
|
+
const { projectExists } = await ensureProjectExists(derivedAccountId, projectConfig.projectConfig.name, { allowCreate: false, noLogs: true });
|
|
70
|
+
if (!projectExists) {
|
|
71
|
+
throw new Error(lib.migrate.errors.project.doesNotExist(derivedAccountId));
|
|
72
|
+
}
|
|
73
|
+
SpinniesManager.add('checkingForMigratableComponents', {
|
|
74
|
+
text: lib.migrate.spinners.checkingForMigratableComponents,
|
|
75
|
+
});
|
|
76
|
+
const { migratableApps, unmigratableApps } = await fetchMigrationApps(derivedAccountId, options.platformVersion, projectConfig);
|
|
77
|
+
const hasApps = [...migratableApps, ...unmigratableApps].length;
|
|
78
|
+
SpinniesManager.remove('checkingForMigratableComponents');
|
|
79
|
+
await validateMigrationAppsAndThemes(hasApps, projectConfig);
|
|
80
|
+
uiLogger.log(lib.migrate.prompt.themesMigration(themeCount));
|
|
81
|
+
const proceed = await confirmPrompt(lib.migrate.prompt.proceed, {
|
|
82
|
+
defaultAnswer: false,
|
|
83
|
+
});
|
|
84
|
+
if (proceed) {
|
|
85
|
+
await handleThemesMigration(projectConfig, options.platformVersion);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
uiLogger.log(lib.migrate.exitWithoutMigrating);
|
|
89
|
+
}
|
|
90
|
+
}
|
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
|
}
|
package/lib/usageTracking.js
CHANGED
|
@@ -44,7 +44,7 @@ export async function trackCommandUsage(command, meta = {}, accountId) {
|
|
|
44
44
|
action: 'cli-command',
|
|
45
45
|
command,
|
|
46
46
|
authType,
|
|
47
|
-
|
|
47
|
+
meta,
|
|
48
48
|
accountId,
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -133,12 +133,12 @@ async function trackCliInteraction({ action, accountId, command, authType, meta
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
try {
|
|
136
|
+
logger.debug('Sent usage tracking command event: %o', usageTrackingEvent);
|
|
136
137
|
return trackUsage('cli-interaction', EventClass.INTERACTION, usageTrackingEvent, accountId);
|
|
137
138
|
}
|
|
138
139
|
catch (error) {
|
|
139
140
|
debugError(error);
|
|
140
141
|
}
|
|
141
|
-
logger.debug('Sent usage tracking command event: %o', usageTrackingEvent);
|
|
142
142
|
}
|
|
143
143
|
catch (e) {
|
|
144
144
|
debugError(e);
|
|
@@ -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-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,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 {};
|