@hubspot/cli 7.7.27-experimental.1 → 7.7.28-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/project/upload.d.ts +2 -2
- package/commands/project/upload.js +1 -1
- 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 +160 -46
- package/lang/en.js +175 -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 +0 -2
- package/lib/mcp/setup.js +0 -24
- package/lib/process.js +15 -4
- package/lib/projectProfiles.d.ts +1 -1
- package/lib/projectProfiles.js +10 -2
- 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/HsListTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListTool.js +58 -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 +8 -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/types/Yargs.d.ts +1 -1
- package/ui/index.d.ts +1 -0
- package/ui/index.js +6 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { DocFetchTool } from '../DocFetchTool.js';
|
|
2
|
+
import { http } from '@hubspot/local-dev-lib/http/unauthed';
|
|
3
|
+
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
4
|
+
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
5
|
+
vi.mock('@hubspot/local-dev-lib/http/unauthed');
|
|
6
|
+
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
7
|
+
vi.mock('../../utils/toolUsageTracking');
|
|
8
|
+
const mockHttp = http;
|
|
9
|
+
const mockIsHubSpotHttpError = vi.mocked(isHubSpotHttpError);
|
|
10
|
+
describe('mcp-server/tools/project/DocFetchTool', () => {
|
|
11
|
+
let mockMcpServer;
|
|
12
|
+
let tool;
|
|
13
|
+
let mockRegisteredTool;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
// @ts-expect-error Not mocking whole server
|
|
17
|
+
mockMcpServer = {
|
|
18
|
+
registerTool: vi.fn(),
|
|
19
|
+
};
|
|
20
|
+
mockRegisteredTool = {};
|
|
21
|
+
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
22
|
+
tool = new DocFetchTool(mockMcpServer);
|
|
23
|
+
});
|
|
24
|
+
describe('register', () => {
|
|
25
|
+
it('should register tool with correct parameters', () => {
|
|
26
|
+
const result = tool.register();
|
|
27
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('fetch-hubspot-doc', {
|
|
28
|
+
title: 'Fetch HubSpot Developer Documentation (single file)',
|
|
29
|
+
description: 'Always use this immediately after `search-hubspot-docs` and before creating a plan, writing code, or answering technical questions. This tool retrieves the full, authoritative content of a HubSpot Developer Documentation page from its URL, ensuring responses are accurate, up-to-date, and grounded in the official docs.',
|
|
30
|
+
inputSchema: expect.any(Object),
|
|
31
|
+
}, tool.handler);
|
|
32
|
+
expect(result).toBe(mockRegisteredTool);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('handler', () => {
|
|
36
|
+
const mockInput = {
|
|
37
|
+
docUrl: 'https://example.com/docs/test-doc',
|
|
38
|
+
};
|
|
39
|
+
it('should successfully fetch and return markdown content', async () => {
|
|
40
|
+
const mockContent = '# Test Document\n\nThis is a test markdown document.';
|
|
41
|
+
// @ts-expect-error - Mocking axios response structure
|
|
42
|
+
mockHttp.get.mockResolvedValue({
|
|
43
|
+
data: mockContent,
|
|
44
|
+
});
|
|
45
|
+
const result = await tool.handler(mockInput);
|
|
46
|
+
expect(mockHttp.get).toHaveBeenCalledWith({
|
|
47
|
+
url: 'https://example.com/docs/test-doc.md',
|
|
48
|
+
});
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: mockContent,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it('should handle HubSpot HTTP errors', async () => {
|
|
59
|
+
const mockError = {
|
|
60
|
+
toString: () => 'HubSpotHttpError: \n- message: The request was not found.\n- status: 404\n- statusText: Not Found\n- method: get\n- code: ERR_BAD_REQUEST\n- derivedContext: {\n "request": "https://example.com/docs/test-doc.md"\n}',
|
|
61
|
+
};
|
|
62
|
+
mockHttp.get.mockRejectedValue(mockError);
|
|
63
|
+
mockIsHubSpotHttpError.mockReturnValue(true);
|
|
64
|
+
const result = await tool.handler(mockInput);
|
|
65
|
+
expect(result).toEqual({
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: 'HubSpotHttpError: \n- message: The request was not found.\n- status: 404\n- statusText: Not Found\n- method: get\n- code: ERR_BAD_REQUEST\n- derivedContext: {\n "request": "https://example.com/docs/test-doc.md"\n}',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it('should handle empty content', async () => {
|
|
75
|
+
// @ts-expect-error - Mocking axios response structure
|
|
76
|
+
mockHttp.get.mockResolvedValue({
|
|
77
|
+
data: ' ',
|
|
78
|
+
});
|
|
79
|
+
const result = await tool.handler(mockInput);
|
|
80
|
+
expect(result).toEqual({
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: 'Document is empty or contains no content.',
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
it('should handle generic errors', async () => {
|
|
90
|
+
const mockError = new Error('Network error');
|
|
91
|
+
mockHttp.get.mockRejectedValue(mockError);
|
|
92
|
+
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
93
|
+
const result = await tool.handler(mockInput);
|
|
94
|
+
expect(result).toEqual({
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: 'Error fetching documentation: Network error',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
it('should handle non-Error rejections', async () => {
|
|
104
|
+
mockHttp.get.mockRejectedValue('String error');
|
|
105
|
+
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
106
|
+
const result = await tool.handler(mockInput);
|
|
107
|
+
expect(result).toEqual({
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: 'Error fetching documentation: String error',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { DocsSearchTool } from '../DocsSearchTool.js';
|
|
2
|
+
import { http } from '@hubspot/local-dev-lib/http';
|
|
3
|
+
import { getAccountId } from '@hubspot/local-dev-lib/config';
|
|
4
|
+
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
5
|
+
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
|
+
vi.mock('@hubspot/local-dev-lib/http');
|
|
7
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
8
|
+
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
9
|
+
vi.mock('../../../utils/toolUsageTracking');
|
|
10
|
+
const mockHttp = http;
|
|
11
|
+
const mockGetAccountId = getAccountId;
|
|
12
|
+
const mockIsHubSpotHttpError = vi.mocked(isHubSpotHttpError);
|
|
13
|
+
describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
14
|
+
let mockMcpServer;
|
|
15
|
+
let tool;
|
|
16
|
+
let mockRegisteredTool;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
// @ts-expect-error Not mocking whole server
|
|
20
|
+
mockMcpServer = {
|
|
21
|
+
registerTool: vi.fn(),
|
|
22
|
+
};
|
|
23
|
+
mockRegisteredTool = {};
|
|
24
|
+
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
25
|
+
tool = new DocsSearchTool(mockMcpServer);
|
|
26
|
+
});
|
|
27
|
+
describe('register', () => {
|
|
28
|
+
it('should register tool with correct parameters', () => {
|
|
29
|
+
const result = tool.register();
|
|
30
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('search-hubspot-docs', {
|
|
31
|
+
title: 'Search HubSpot Developer Documentation',
|
|
32
|
+
description: 'Use this first whenever you need details about HubSpot APIs, SDKs, integrations, or developer platform features. This searches the official HubSpot Developer Documentation and returns the most relevant pages, each with a URL for use in `fetch-hubspot-doc`. Always follow this with a fetch to get the full, authoritative content before making plans or writing answers.',
|
|
33
|
+
inputSchema: expect.any(Object),
|
|
34
|
+
}, tool.handler);
|
|
35
|
+
expect(result).toBe(mockRegisteredTool);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('handler', () => {
|
|
39
|
+
const mockInput = {
|
|
40
|
+
docsSearchQuery: 'test query',
|
|
41
|
+
};
|
|
42
|
+
it('should return auth error message when no account ID is found', async () => {
|
|
43
|
+
mockGetAccountId.mockReturnValue(null);
|
|
44
|
+
const result = await tool.handler(mockInput);
|
|
45
|
+
expect(result).toEqual({
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: 'No account ID found. Please run `hs account auth` to configure an account, or set a default account with `hs account use <account>`',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('should return successful results when docs are found', async () => {
|
|
55
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
56
|
+
const mockResponse = {
|
|
57
|
+
results: [
|
|
58
|
+
{
|
|
59
|
+
title: 'Test Doc 1',
|
|
60
|
+
content: 'Test content 1',
|
|
61
|
+
description: 'Test description 1',
|
|
62
|
+
url: 'https://example.com/doc1',
|
|
63
|
+
score: 0.9,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
title: 'Test Doc 2',
|
|
67
|
+
content: 'Test content 2',
|
|
68
|
+
description: 'Test description 2',
|
|
69
|
+
url: 'https://example.com/doc2',
|
|
70
|
+
score: 0.8,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
// @ts-expect-error - Mocking axios response structure
|
|
75
|
+
mockHttp.post.mockResolvedValue({
|
|
76
|
+
data: mockResponse,
|
|
77
|
+
});
|
|
78
|
+
const result = await tool.handler(mockInput);
|
|
79
|
+
expect(mockHttp.post).toHaveBeenCalledWith(12345, {
|
|
80
|
+
url: 'dev/docs/llms/v1/docs-search',
|
|
81
|
+
data: {
|
|
82
|
+
query: 'test query',
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
expect(result).toEqual({
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: expect.stringContaining('Found 2 documentation results:'),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
const resultText = result.content[0].text;
|
|
94
|
+
expect(resultText).toContain('**Test Doc 1**');
|
|
95
|
+
expect(resultText).toContain('Test description 1');
|
|
96
|
+
expect(resultText).toContain('https://example.com/doc1');
|
|
97
|
+
expect(resultText).toContain('Score: 0.9');
|
|
98
|
+
expect(resultText).toContain('Test content 1');
|
|
99
|
+
expect(resultText).toContain('**Test Doc 2**');
|
|
100
|
+
expect(resultText).toContain('Test description 2');
|
|
101
|
+
expect(resultText).toContain('https://example.com/doc2');
|
|
102
|
+
expect(resultText).toContain('Score: 0.8');
|
|
103
|
+
expect(resultText).toContain('Test content 2');
|
|
104
|
+
});
|
|
105
|
+
it('should return no results message when no documentation is found', async () => {
|
|
106
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
107
|
+
const mockResponse = {
|
|
108
|
+
results: [],
|
|
109
|
+
};
|
|
110
|
+
// @ts-expect-error - Mocking axios response structure
|
|
111
|
+
mockHttp.post.mockResolvedValue({
|
|
112
|
+
data: mockResponse,
|
|
113
|
+
});
|
|
114
|
+
const result = await tool.handler(mockInput);
|
|
115
|
+
expect(result).toEqual({
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: 'text',
|
|
119
|
+
text: 'No documentation found for your query.',
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
it('should return no results message when results is null', async () => {
|
|
125
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
126
|
+
const mockResponse = {
|
|
127
|
+
results: null,
|
|
128
|
+
};
|
|
129
|
+
// @ts-expect-error - Mocking axios response structure
|
|
130
|
+
mockHttp.post.mockResolvedValue({
|
|
131
|
+
data: mockResponse,
|
|
132
|
+
});
|
|
133
|
+
const result = await tool.handler(mockInput);
|
|
134
|
+
expect(result).toEqual({
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: 'text',
|
|
138
|
+
text: 'No documentation found for your query.',
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
it('should handle HubSpot HTTP errors', async () => {
|
|
144
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
145
|
+
const mockError = {
|
|
146
|
+
toString: () => 'HubSpot API Error: 404 Not Found',
|
|
147
|
+
};
|
|
148
|
+
mockHttp.post.mockRejectedValue(mockError);
|
|
149
|
+
mockIsHubSpotHttpError.mockReturnValue(true);
|
|
150
|
+
const result = await tool.handler(mockInput);
|
|
151
|
+
expect(result).toEqual({
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: 'HubSpot API Error: 404 Not Found',
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
it('should handle generic errors', async () => {
|
|
161
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
162
|
+
const mockError = new Error('Network error');
|
|
163
|
+
mockHttp.post.mockRejectedValue(mockError);
|
|
164
|
+
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
165
|
+
const result = await tool.handler(mockInput);
|
|
166
|
+
expect(result).toEqual({
|
|
167
|
+
content: [
|
|
168
|
+
{
|
|
169
|
+
type: 'text',
|
|
170
|
+
text: 'Error searching documentation: Network error',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
it('should handle non-Error rejections', async () => {
|
|
176
|
+
mockGetAccountId.mockReturnValue(12345);
|
|
177
|
+
mockHttp.post.mockRejectedValue('String error');
|
|
178
|
+
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
179
|
+
const result = await tool.handler(mockInput);
|
|
180
|
+
expect(result).toEqual({
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: 'text',
|
|
184
|
+
text: 'Error searching documentation: String error',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -25,7 +25,7 @@ describe('mcp-server/tools/project/GetConfigValuesTool', () => {
|
|
|
25
25
|
describe('register', () => {
|
|
26
26
|
it('should register tool with correct parameters', () => {
|
|
27
27
|
const result = tool.register();
|
|
28
|
-
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('get-hubspot-
|
|
28
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('get-hubspot-feature-config-schema', {
|
|
29
29
|
title: 'Fetch the JSON Schema for component',
|
|
30
30
|
description: expect.stringContaining('Fetches and returns the JSON schema for the provided feature'),
|
|
31
31
|
inputSchema: expect.objectContaining({
|
|
@@ -2,3 +2,5 @@ import z from 'zod';
|
|
|
2
2
|
export declare const absoluteProjectPath: z.ZodString;
|
|
3
3
|
export declare const absoluteCurrentWorkingDirectory: z.ZodString;
|
|
4
4
|
export declare const features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">]>, "many">>;
|
|
5
|
+
export declare const docsSearchQuery: z.ZodString;
|
|
6
|
+
export declare const docUrl: z.ZodString;
|
|
@@ -16,3 +16,9 @@ export const features = z
|
|
|
16
16
|
])
|
|
17
17
|
.describe('The features to include in the project, multiple options can be selected'))
|
|
18
18
|
.optional();
|
|
19
|
+
export const docsSearchQuery = z
|
|
20
|
+
.string()
|
|
21
|
+
.describe('The query to search the HubSpot Developer Documentation for.');
|
|
22
|
+
export const docUrl = z
|
|
23
|
+
.string()
|
|
24
|
+
.describe('The URL of the HubSpot Developer Documentation to fetch.');
|
|
@@ -2,7 +2,7 @@ import { trackUsage } from '@hubspot/local-dev-lib/trackUsage';
|
|
|
2
2
|
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
3
3
|
import { EventClass, getNodeVersionData, getPlatform, } from '../../lib/usageTracking.js';
|
|
4
4
|
import { getAccountId, isTrackingAllowed } from '@hubspot/local-dev-lib/config';
|
|
5
|
-
export async function trackToolUsage(toolName) {
|
|
5
|
+
export async function trackToolUsage(toolName, meta) {
|
|
6
6
|
if (!isTrackingAllowed()) {
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
@@ -12,6 +12,7 @@ export async function trackToolUsage(toolName) {
|
|
|
12
12
|
...getNodeVersionData(),
|
|
13
13
|
command: toolName,
|
|
14
14
|
type: process.env.HUBSPOT_MCP_AI_AGENT,
|
|
15
|
+
...meta,
|
|
15
16
|
};
|
|
16
17
|
const accountId = getAccountId() || undefined;
|
|
17
18
|
try {
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.7.
|
|
3
|
+
"version": "7.7.28-experimental.0",
|
|
4
4
|
"description": "The official CLI for developing on HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "https://github.com/HubSpot/hubspot-cli",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@hubspot/local-dev-lib": "3.
|
|
10
|
-
"@hubspot/project-parsing-lib": "0.
|
|
9
|
+
"@hubspot/local-dev-lib": "3.17.0",
|
|
10
|
+
"@hubspot/project-parsing-lib": "0.8.2",
|
|
11
11
|
"@hubspot/serverless-dev-runtime": "7.0.6",
|
|
12
12
|
"@hubspot/theme-preview-dev-server": "0.0.10",
|
|
13
|
-
"@hubspot/ui-extensions-dev-server": "0.9.
|
|
13
|
+
"@hubspot/ui-extensions-dev-server": "0.9.8",
|
|
14
14
|
"archiver": "7.0.1",
|
|
15
15
|
"boxen": "8.0.1",
|
|
16
16
|
"chalk": "5.4.1",
|
|
@@ -20,11 +20,13 @@
|
|
|
20
20
|
"express": "4.21.2",
|
|
21
21
|
"findup-sync": "4.0.0",
|
|
22
22
|
"fs-extra": "8.1.0",
|
|
23
|
+
"ink": "5.2.1",
|
|
23
24
|
"inquirer": "12.7.0",
|
|
24
25
|
"js-yaml": "4.1.0",
|
|
25
26
|
"moment": "2.30.1",
|
|
26
27
|
"open": "7.4.2",
|
|
27
28
|
"p-queue": "8.1.0",
|
|
29
|
+
"react": "^18.0.0",
|
|
28
30
|
"strip-ansi": "7.1.0",
|
|
29
31
|
"table": "6.9.0",
|
|
30
32
|
"tmp": "0.2.3",
|
|
@@ -42,6 +44,7 @@
|
|
|
42
44
|
"@types/inquirer": "^9.0.8",
|
|
43
45
|
"@types/js-yaml": "^4.0.9",
|
|
44
46
|
"@types/node": "^24.1.0",
|
|
47
|
+
"@types/react": "^18.3.12",
|
|
45
48
|
"@types/semver": "^7.5.8",
|
|
46
49
|
"@types/tmp": "^0.2.6",
|
|
47
50
|
"@types/update-notifier": "^6.0.8",
|
|
@@ -75,7 +78,7 @@
|
|
|
75
78
|
"hs": "yarn build && node ./dist/bin/hs",
|
|
76
79
|
"hs-debug": "yarn build && NODE_DEBUG=http* node --inspect-brk ./dist/bin/hs",
|
|
77
80
|
"lint": "echo 'Linting is disabled for Blazar'",
|
|
78
|
-
"lint:local": "eslint . && prettier --list-different './**/*.{ts,js,json}'",
|
|
81
|
+
"lint:local": "eslint . && prettier --list-different './**/*.{ts,tsx,js,json}'",
|
|
79
82
|
"list-all-commands": "yarn tsx ./scripts/get-all-commands.ts",
|
|
80
83
|
"local-link": "yarn tsx ./scripts/linking.ts",
|
|
81
84
|
"mcp-local": "yarn tsx ./scripts/mcp-local.ts",
|
|
@@ -91,7 +94,7 @@
|
|
|
91
94
|
"view-unreleased-changes": "node ./scripts/unreleasedChanges.js"
|
|
92
95
|
},
|
|
93
96
|
"lint-staged": {
|
|
94
|
-
"**/*.{js,ts,scss,css}": [
|
|
97
|
+
"**/*.{js,ts,tsx,scss,css}": [
|
|
95
98
|
"prettier -l",
|
|
96
99
|
"eslint"
|
|
97
100
|
]
|
package/types/Cms.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import { CommonArgs, ConfigArgs } from './Yargs.js';
|
|
2
|
+
export declare const TEMPLATE_TYPES: readonly ["page-template", "email-template", "partial", "global-partial", "blog-listing-template", "blog-post-template", "search-template", "section"];
|
|
3
|
+
export type TemplateType = (typeof TEMPLATE_TYPES)[number];
|
|
4
|
+
export declare const HTTP_METHODS: readonly ["DELETE", "GET", "PATCH", "POST", "PUT"];
|
|
5
|
+
export type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
6
|
+
export declare const CONTENT_TYPES: readonly ["ANY", "LANDING_PAGE", "SITE_PAGE", "BLOG_POST", "BLOG_LISTING", "EMAIL", "KNOWLEDGE_BASE", "QUOTE_TEMPLATE", "CUSTOMER_PORTAL", "WEB_INTERACTIVE", "SUBSCRIPTION", "MEMBERSHIP"];
|
|
7
|
+
export type ContentType = (typeof CONTENT_TYPES)[number];
|
|
2
8
|
export type CreateArgs = CommonArgs & ConfigArgs & {
|
|
3
9
|
branch?: string;
|
|
4
10
|
type: string;
|
|
5
11
|
dest: string;
|
|
6
12
|
name: string;
|
|
7
13
|
internal?: boolean;
|
|
14
|
+
templateType?: TemplateType;
|
|
15
|
+
moduleLabel?: string;
|
|
16
|
+
reactType?: boolean;
|
|
17
|
+
contentTypes?: string;
|
|
18
|
+
global?: boolean;
|
|
19
|
+
availableForNewContent?: boolean;
|
|
20
|
+
functionsFolder?: string;
|
|
21
|
+
filename?: string;
|
|
22
|
+
endpointMethod?: HttpMethod;
|
|
23
|
+
endpointPath?: string;
|
|
8
24
|
};
|
|
9
25
|
export type CmsAssetOperationArgs = {
|
|
10
26
|
assetType: string;
|
package/types/Cms.js
CHANGED
|
@@ -1 +1,25 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const TEMPLATE_TYPES = [
|
|
2
|
+
'page-template',
|
|
3
|
+
'email-template',
|
|
4
|
+
'partial',
|
|
5
|
+
'global-partial',
|
|
6
|
+
'blog-listing-template',
|
|
7
|
+
'blog-post-template',
|
|
8
|
+
'search-template',
|
|
9
|
+
'section',
|
|
10
|
+
];
|
|
11
|
+
export const HTTP_METHODS = ['DELETE', 'GET', 'PATCH', 'POST', 'PUT'];
|
|
12
|
+
export const CONTENT_TYPES = [
|
|
13
|
+
'ANY',
|
|
14
|
+
'LANDING_PAGE',
|
|
15
|
+
'SITE_PAGE',
|
|
16
|
+
'BLOG_POST',
|
|
17
|
+
'BLOG_LISTING',
|
|
18
|
+
'EMAIL',
|
|
19
|
+
'KNOWLEDGE_BASE',
|
|
20
|
+
'QUOTE_TEMPLATE',
|
|
21
|
+
'CUSTOMER_PORTAL',
|
|
22
|
+
'WEB_INTERACTIVE',
|
|
23
|
+
'SUBSCRIPTION',
|
|
24
|
+
'MEMBERSHIP',
|
|
25
|
+
];
|
package/types/LocalDev.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
|
|
2
|
-
import { Build } from '@hubspot/local-dev-lib/types/Build';
|
|
3
2
|
import { Environment } from '@hubspot/local-dev-lib/types/Config';
|
|
4
3
|
import { ValueOf } from '@hubspot/local-dev-lib/types/Utils';
|
|
5
4
|
import { ProjectConfig } from './Projects.js';
|
|
@@ -14,8 +13,6 @@ export type LocalDevStateConstructorOptions = {
|
|
|
14
13
|
projectId: number;
|
|
15
14
|
projectName: string;
|
|
16
15
|
debug?: boolean;
|
|
17
|
-
deployedBuild?: Build;
|
|
18
|
-
isGithubLinked: boolean;
|
|
19
16
|
initialProjectNodes: {
|
|
20
17
|
[key: string]: IntermediateRepresentationNodeLocalDev;
|
|
21
18
|
};
|
package/types/Prompts.d.ts
CHANGED
package/types/Yargs.d.ts
CHANGED
package/ui/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderInline(component: React.ReactNode): Promise<void>;
|
package/ui/index.js
ADDED