@hubspot/cli 7.7.23-experimental.0 → 7.7.24-experimental.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/account/auth.js +15 -4
- package/commands/auth.js +1 -1
- package/commands/mcp/start.d.ts +1 -0
- package/commands/mcp/start.js +12 -4
- package/commands/project/create.js +2 -2
- package/commands/project/validate.js +1 -0
- package/commands/sandbox/__tests__/create.test.js +207 -0
- package/commands/sandbox/create.d.ts +1 -1
- package/commands/sandbox/create.js +31 -16
- package/lang/en.d.ts +7 -3
- package/lang/en.js +12 -5
- package/lang/en.lyaml +4 -2
- package/lib/__tests__/buildAccount.test.js +62 -4
- package/lib/buildAccount.d.ts +4 -1
- package/lib/buildAccount.js +57 -2
- package/lib/commonOpts.js +25 -0
- package/lib/constants.d.ts +4 -0
- package/lib/constants.js +4 -0
- package/lib/errorHandlers/index.js +1 -3
- package/lib/errors/ProjectValidationError.d.ts +4 -0
- package/lib/errors/ProjectValidationError.js +9 -0
- package/lib/mcp/setup.d.ts +4 -0
- package/lib/mcp/setup.js +36 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +35 -0
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +170 -1
- package/lib/projects/add/v3AddComponent.js +2 -1
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/v3.d.ts +0 -2
- package/lib/projects/create/v3.js +1 -3
- package/lib/projects/localDev/LocalDevProcess.d.ts +1 -0
- package/lib/projects/localDev/LocalDevProcess.js +3 -0
- package/lib/projects/localDev/LocalDevState.d.ts +1 -0
- package/lib/projects/localDev/LocalDevState.js +5 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -2
- package/lib/projects/localDev/LocalDevWebsocketServer.js +35 -29
- package/lib/projects/upload.js +5 -12
- package/lib/sandboxes.d.ts +4 -0
- package/lib/sandboxes.js +4 -0
- package/lib/ui/index.d.ts +6 -0
- package/lib/ui/index.js +3 -5
- package/mcp-server/tools/index.js +6 -4
- package/mcp-server/tools/project/{AddFeatureToProject.d.ts → AddFeatureToProjectTool.d.ts} +4 -4
- package/mcp-server/tools/project/{AddFeatureToProject.js → AddFeatureToProjectTool.js} +6 -14
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +4 -14
- package/mcp-server/tools/project/{DeployProject.d.ts → DeployProjectTool.d.ts} +1 -1
- package/mcp-server/tools/project/{DeployProject.js → DeployProjectTool.js} +2 -2
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +20 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +51 -0
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.js → AddFeatureToProjectTool.test.js} +7 -7
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +3 -4
- package/mcp-server/tools/project/__tests__/{DeployProject.test.js → DeployProjectTool.test.js} +4 -4
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +198 -0
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +2 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -0
- package/mcp-server/tools/project/constants.js +11 -0
- package/mcp-server/utils/__tests__/command.test.js +76 -3
- package/mcp-server/utils/command.d.ts +6 -0
- package/mcp-server/utils/command.js +19 -0
- package/package.json +2 -2
- package/mcp-server/utils/__tests__/project.test.js +0 -79
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -14
- /package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.d.ts → AddFeatureToProjectTool.test.d.ts} +0 -0
- /package/mcp-server/tools/project/__tests__/{DeployProject.test.d.ts → DeployProjectTool.test.d.ts} +0 -0
- /package/mcp-server/{utils/__tests__/project.test.d.ts → tools/project/__tests__/GetConfigValuesTool.test.d.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Separator } from '@inquirer/prompts';
|
|
2
|
-
import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../constants.js';
|
|
2
|
+
import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../constants.js';
|
|
3
3
|
import { commands, lib } from '../../../lang/en.js';
|
|
4
4
|
import { listPrompt } from '../../prompts/promptUtils.js';
|
|
5
5
|
import chalk from 'chalk';
|
|
@@ -8,8 +8,6 @@ import path from 'path';
|
|
|
8
8
|
import { getConfigForPlatformVersion } from './legacy.js';
|
|
9
9
|
import { logError } from '../../errorHandlers/index.js';
|
|
10
10
|
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
11
|
-
export const EMPTY_PROJECT = 'empty';
|
|
12
|
-
export const PROJECT_WITH_APP = 'app';
|
|
13
11
|
export async function createV3App(providedAuth, providedDistribution) {
|
|
14
12
|
let authType;
|
|
15
13
|
if (providedAuth &&
|
|
@@ -32,5 +32,6 @@ declare class LocalDevProcess {
|
|
|
32
32
|
uploadProject(): Promise<boolean>;
|
|
33
33
|
addStateListener<K extends keyof LocalDevState>(key: K, listener: LocalDevStateListener<K>, callOnInit?: boolean): void;
|
|
34
34
|
sendDevServerMessage(message: LocalDevServerMessage): void;
|
|
35
|
+
removeStateListener<K extends keyof LocalDevState>(key: K, listener: LocalDevStateListener<K>): void;
|
|
35
36
|
}
|
|
36
37
|
export default LocalDevProcess;
|
|
@@ -51,5 +51,6 @@ declare class LocalDevState {
|
|
|
51
51
|
get devServerMessage(): string;
|
|
52
52
|
set devServerMessage(message: LocalDevServerMessage);
|
|
53
53
|
addListener<K extends keyof LocalDevState>(key: K, listener: LocalDevStateListener<K>, callOnInit?: boolean): void;
|
|
54
|
+
removeListener<K extends keyof LocalDevState>(key: K, listener: LocalDevStateListener<K>): void;
|
|
54
55
|
}
|
|
55
56
|
export default LocalDevState;
|
|
@@ -111,5 +111,10 @@ class LocalDevState {
|
|
|
111
111
|
listener(this[key]);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
+
removeListener(key, listener) {
|
|
115
|
+
if (this._listeners[key]) {
|
|
116
|
+
this._listeners[key].splice(this._listeners[key].indexOf(listener), 1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
114
119
|
}
|
|
115
120
|
export default LocalDevState;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import LocalDevProcess from './LocalDevProcess.js';
|
|
2
2
|
declare class LocalDevWebsocketServer {
|
|
3
3
|
private server?;
|
|
4
|
-
private _websocket?;
|
|
5
4
|
private debug?;
|
|
6
5
|
private localDevProcess;
|
|
7
6
|
private ALLOWED_ORIGINS;
|
|
8
7
|
constructor(localDevProcess: LocalDevProcess, debug?: boolean);
|
|
9
|
-
private websocket;
|
|
10
8
|
private log;
|
|
11
9
|
private logError;
|
|
12
10
|
private sendMessage;
|
|
13
11
|
private handleUpload;
|
|
14
12
|
private setupMessageHandlers;
|
|
15
13
|
private sendProjectData;
|
|
14
|
+
private setupProjectNodesListener;
|
|
15
|
+
private setupAppDataListener;
|
|
16
16
|
private setupStateListeners;
|
|
17
17
|
start(): Promise<void>;
|
|
18
18
|
shutdown(): void;
|
|
@@ -8,7 +8,6 @@ const SERVER_INSTANCE_ID = 'local-dev-ui-websocket-server';
|
|
|
8
8
|
const LOG_PREFIX = '[LocalDevWebsocketServer]';
|
|
9
9
|
class LocalDevWebsocketServer {
|
|
10
10
|
server;
|
|
11
|
-
_websocket;
|
|
12
11
|
debug;
|
|
13
12
|
localDevProcess;
|
|
14
13
|
ALLOWED_ORIGINS = [
|
|
@@ -21,12 +20,6 @@ class LocalDevWebsocketServer {
|
|
|
21
20
|
this.localDevProcess = localDevProcess;
|
|
22
21
|
this.debug = debug;
|
|
23
22
|
}
|
|
24
|
-
websocket() {
|
|
25
|
-
if (!this._websocket) {
|
|
26
|
-
throw new Error(lib.LocalDevWebsocketServer.errors.notInitialized(LOG_PREFIX));
|
|
27
|
-
}
|
|
28
|
-
return this._websocket;
|
|
29
|
-
}
|
|
30
23
|
log(message) {
|
|
31
24
|
if (this.debug) {
|
|
32
25
|
logger.log(LOG_PREFIX, message);
|
|
@@ -37,24 +30,24 @@ class LocalDevWebsocketServer {
|
|
|
37
30
|
logger.error(LOG_PREFIX, message);
|
|
38
31
|
}
|
|
39
32
|
}
|
|
40
|
-
sendMessage(message) {
|
|
41
|
-
|
|
33
|
+
sendMessage(websocket, message) {
|
|
34
|
+
websocket.send(JSON.stringify(message));
|
|
42
35
|
}
|
|
43
|
-
async handleUpload() {
|
|
36
|
+
async handleUpload(websocket) {
|
|
44
37
|
const uploadSuccess = await this.localDevProcess.uploadProject();
|
|
45
38
|
if (uploadSuccess) {
|
|
46
|
-
this.sendMessage({
|
|
39
|
+
this.sendMessage(websocket, {
|
|
47
40
|
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPLOAD_SUCCESS,
|
|
48
41
|
});
|
|
49
42
|
}
|
|
50
43
|
else {
|
|
51
|
-
this.sendMessage({
|
|
44
|
+
this.sendMessage(websocket, {
|
|
52
45
|
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPLOAD_FAILURE,
|
|
53
46
|
});
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
|
-
setupMessageHandlers() {
|
|
57
|
-
|
|
49
|
+
setupMessageHandlers(websocket) {
|
|
50
|
+
websocket.on('message', data => {
|
|
58
51
|
try {
|
|
59
52
|
const message = JSON.parse(data.toString());
|
|
60
53
|
if (!message.type) {
|
|
@@ -63,7 +56,7 @@ class LocalDevWebsocketServer {
|
|
|
63
56
|
}
|
|
64
57
|
switch (message.type) {
|
|
65
58
|
case LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES.UPLOAD:
|
|
66
|
-
this.handleUpload();
|
|
59
|
+
this.handleUpload(websocket);
|
|
67
60
|
break;
|
|
68
61
|
case LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES.VIEWED_WELCOME_SCREEN:
|
|
69
62
|
addLocalStateFlag(CONFIG_LOCAL_STATE_FLAGS.LOCAL_DEV_UI_WELCOME);
|
|
@@ -77,8 +70,8 @@ class LocalDevWebsocketServer {
|
|
|
77
70
|
}
|
|
78
71
|
});
|
|
79
72
|
}
|
|
80
|
-
sendProjectData() {
|
|
81
|
-
this.sendMessage({
|
|
73
|
+
sendProjectData(websocket) {
|
|
74
|
+
this.sendMessage(websocket, {
|
|
82
75
|
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_DATA,
|
|
83
76
|
data: {
|
|
84
77
|
projectName: this.localDevProcess.projectName,
|
|
@@ -88,19 +81,33 @@ class LocalDevWebsocketServer {
|
|
|
88
81
|
},
|
|
89
82
|
});
|
|
90
83
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.sendMessage({
|
|
84
|
+
setupProjectNodesListener(websocket) {
|
|
85
|
+
const listener = (nodes) => {
|
|
86
|
+
this.sendMessage(websocket, {
|
|
94
87
|
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_NODES,
|
|
95
88
|
data: nodes,
|
|
96
89
|
});
|
|
97
|
-
}
|
|
98
|
-
this.localDevProcess.addStateListener('
|
|
99
|
-
|
|
90
|
+
};
|
|
91
|
+
this.localDevProcess.addStateListener('projectNodes', listener, true);
|
|
92
|
+
websocket.on('close', () => {
|
|
93
|
+
this.localDevProcess.removeStateListener('projectNodes', listener);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
setupAppDataListener(websocket) {
|
|
97
|
+
const listener = (appData) => {
|
|
98
|
+
this.sendMessage(websocket, {
|
|
100
99
|
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_APP_DATA,
|
|
101
100
|
data: appData,
|
|
102
101
|
});
|
|
103
|
-
}
|
|
102
|
+
};
|
|
103
|
+
this.localDevProcess.addStateListener('appData', listener, true);
|
|
104
|
+
websocket.on('close', () => {
|
|
105
|
+
this.localDevProcess.removeStateListener('appData', listener);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
setupStateListeners(websocket) {
|
|
109
|
+
this.setupProjectNodesListener(websocket);
|
|
110
|
+
this.setupAppDataListener(websocket);
|
|
104
111
|
}
|
|
105
112
|
async start() {
|
|
106
113
|
const portManagerIsRunning = await isPortManagerServerRunning();
|
|
@@ -117,17 +124,16 @@ class LocalDevWebsocketServer {
|
|
|
117
124
|
ws.close(1008, lib.LocalDevWebsocketServer.errors.originNotAllowed(origin));
|
|
118
125
|
return;
|
|
119
126
|
}
|
|
120
|
-
this.
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
123
|
-
this.setupStateListeners();
|
|
127
|
+
this.sendProjectData(ws);
|
|
128
|
+
this.setupMessageHandlers(ws);
|
|
129
|
+
this.setupStateListeners(ws);
|
|
124
130
|
this.localDevProcess.sendDevServerMessage(LOCAL_DEV_SERVER_MESSAGE_TYPES.WEBSOCKET_SERVER_CONNECTED);
|
|
125
131
|
});
|
|
132
|
+
this.server.on('close', () => { });
|
|
126
133
|
}
|
|
127
134
|
shutdown() {
|
|
128
135
|
this.server?.close();
|
|
129
136
|
this.server = undefined;
|
|
130
|
-
this._websocket = undefined;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
139
|
export default LocalDevWebsocketServer;
|
package/lib/projects/upload.js
CHANGED
|
@@ -14,6 +14,7 @@ import { ensureProjectExists } from './ensureProjectExists.js';
|
|
|
14
14
|
import { uiLogger } from '../ui/logger.js';
|
|
15
15
|
import { useV3Api } from './buildAndDeploy.js';
|
|
16
16
|
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
17
|
+
import ProjectValidationError from '../errors/ProjectValidationError.js';
|
|
17
18
|
async function uploadProjectFiles(accountId, projectName, filePath, uploadMessage, platformVersion, intermediateRepresentation) {
|
|
18
19
|
SpinniesManager.init({});
|
|
19
20
|
const accountIdentifier = uiAccountDescription(accountId) || `${accountId}`;
|
|
@@ -107,17 +108,13 @@ export async function handleProjectUpload({ accountId, projectConfig, projectDir
|
|
|
107
108
|
export function validateSourceDirectory(srcDir, projectConfig) {
|
|
108
109
|
const filenames = fs.readdirSync(srcDir);
|
|
109
110
|
if (!filenames || filenames.length === 0) {
|
|
110
|
-
|
|
111
|
-
validationError.name = 'ProjectValidationError';
|
|
112
|
-
throw validationError;
|
|
111
|
+
throw new ProjectValidationError(lib.projectUpload.handleProjectUpload.emptySource(projectConfig.srcDir));
|
|
113
112
|
}
|
|
114
113
|
}
|
|
115
114
|
export async function validateNoHSMetaMismatch(srcDir, projectConfig) {
|
|
116
115
|
const hasHsMetaFiles = await projectContainsHsMetaFiles(srcDir);
|
|
117
116
|
if (!useV3Api(projectConfig.platformVersion) && hasHsMetaFiles) {
|
|
118
|
-
|
|
119
|
-
validationError.name = 'ProjectValidationError';
|
|
120
|
-
throw validationError;
|
|
117
|
+
throw new ProjectValidationError(lib.projectUpload.wrongPlatformVersionMetaFiles);
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
export async function handleTranslate(projectDir, projectConfig, accountId, skipValidation, profile) {
|
|
@@ -132,12 +129,8 @@ export async function handleTranslate(projectDir, projectConfig, accountId, skip
|
|
|
132
129
|
}
|
|
133
130
|
catch (e) {
|
|
134
131
|
if (isTranslationError(e)) {
|
|
135
|
-
|
|
136
|
-
validationError.name = 'ProjectValidationError';
|
|
137
|
-
throw validationError;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
logError(e);
|
|
132
|
+
throw new ProjectValidationError(e.toString(), { cause: e });
|
|
141
133
|
}
|
|
134
|
+
throw e;
|
|
142
135
|
}
|
|
143
136
|
}
|
package/lib/sandboxes.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export declare const SANDBOX_API_TYPE_MAP: {
|
|
|
11
11
|
readonly STANDARD_SANDBOX: 1;
|
|
12
12
|
readonly DEVELOPMENT_SANDBOX: 2;
|
|
13
13
|
};
|
|
14
|
+
export declare const SANDBOX_TYPE_MAP_V2: {
|
|
15
|
+
readonly STANDARD_SANDBOX: "STANDARD";
|
|
16
|
+
readonly DEVELOPMENT_SANDBOX: "DEVELOPER";
|
|
17
|
+
};
|
|
14
18
|
export declare function getSandboxTypeAsString(accountType?: AccountType): string;
|
|
15
19
|
export declare function getHasSandboxesByType(parentAccountConfig: CLIAccount, type: AccountType): boolean;
|
|
16
20
|
export declare function getAvailableSyncTypes(parentAccountConfig: CLIAccount, config: CLIAccount): Promise<Array<SandboxSyncTask>>;
|
package/lib/sandboxes.js
CHANGED
|
@@ -22,6 +22,10 @@ export const SANDBOX_API_TYPE_MAP = {
|
|
|
22
22
|
[HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX]: 1,
|
|
23
23
|
[HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX]: 2,
|
|
24
24
|
};
|
|
25
|
+
export const SANDBOX_TYPE_MAP_V2 = {
|
|
26
|
+
[HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX]: 'STANDARD',
|
|
27
|
+
[HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX]: 'DEVELOPER',
|
|
28
|
+
};
|
|
25
29
|
export function getSandboxTypeAsString(accountType) {
|
|
26
30
|
if (accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX) {
|
|
27
31
|
return 'development'; // Only place we're using this specific name
|
package/lib/ui/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
type TerminalSupport = {
|
|
2
|
+
hyperlinks: boolean;
|
|
3
|
+
color: boolean;
|
|
4
|
+
};
|
|
1
5
|
export declare const UI_COLORS: {
|
|
2
6
|
SORBET: string;
|
|
3
7
|
MARIGOLD: string;
|
|
4
8
|
MARIGOLD_DARK: string;
|
|
5
9
|
};
|
|
6
10
|
export declare function uiLine(): void;
|
|
11
|
+
export declare function getTerminalUISupport(): TerminalSupport;
|
|
7
12
|
export declare function uiLink(linkText: string, url: string): string;
|
|
8
13
|
export declare function uiAccountDescription(accountId?: number | null, bold?: boolean): string;
|
|
9
14
|
export declare function uiInfoSection(title: string, logContent: () => void): void;
|
|
@@ -17,3 +22,4 @@ export declare function uiCommandDisabledBanner(command: string, url?: string, m
|
|
|
17
22
|
export declare function uiDeprecatedDescription(message: string, command: string, url?: string): undefined;
|
|
18
23
|
export declare function uiDeprecatedMessage(command: string, url?: string, message?: string): void;
|
|
19
24
|
export declare function indent(level: number): string;
|
|
25
|
+
export {};
|
package/lib/ui/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export const UI_COLORS = {
|
|
|
13
13
|
export function uiLine() {
|
|
14
14
|
logger.log('-'.repeat(50));
|
|
15
15
|
}
|
|
16
|
-
function getTerminalUISupport() {
|
|
16
|
+
export function getTerminalUISupport() {
|
|
17
17
|
return {
|
|
18
18
|
hyperlinks: supportsHyperlinkModule.stdout,
|
|
19
19
|
color: supportsColor.stdout.hasBasic,
|
|
@@ -79,9 +79,8 @@ export function uiFeatureHighlight(features, title) {
|
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
export function uiBetaTag(message, log = true) {
|
|
82
|
-
const terminalUISupport = getTerminalUISupport();
|
|
83
82
|
const tag = i18n(`lib.ui.betaTag`);
|
|
84
|
-
const result = `${
|
|
83
|
+
const result = `${tag} ${message}`;
|
|
85
84
|
if (log) {
|
|
86
85
|
logger.log(result);
|
|
87
86
|
return;
|
|
@@ -89,9 +88,8 @@ export function uiBetaTag(message, log = true) {
|
|
|
89
88
|
return result;
|
|
90
89
|
}
|
|
91
90
|
export function uiDeprecatedTag(message, log = true) {
|
|
92
|
-
const terminalUISupport = getTerminalUISupport();
|
|
93
91
|
const tag = i18n(`lib.ui.deprecatedTag`);
|
|
94
|
-
const result = `${
|
|
92
|
+
const result = `${tag} ${message}`;
|
|
95
93
|
if (log) {
|
|
96
94
|
logger.log(result);
|
|
97
95
|
return;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { UploadProjectTools } from './project/UploadProjectTools.js';
|
|
2
2
|
import { CreateProjectTool } from './project/CreateProjectTool.js';
|
|
3
3
|
import { GuidedWalkthroughTool } from './project/GuidedWalkthroughTool.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { DeployProjectTool } from './project/DeployProjectTool.js';
|
|
5
|
+
import { AddFeatureToProjectTool } from './project/AddFeatureToProjectTool.js';
|
|
6
6
|
import { ValidateProjectTool } from './project/ValidateProjectTool.js';
|
|
7
|
+
import { GetConfigValuesTool } from './project/GetConfigValuesTool.js';
|
|
7
8
|
export function registerProjectTools(mcpServer) {
|
|
8
9
|
return [
|
|
9
10
|
new UploadProjectTools(mcpServer).register(),
|
|
10
11
|
new CreateProjectTool(mcpServer).register(),
|
|
11
12
|
new GuidedWalkthroughTool(mcpServer).register(),
|
|
12
|
-
new
|
|
13
|
-
new
|
|
13
|
+
new DeployProjectTool(mcpServer).register(),
|
|
14
|
+
new AddFeatureToProjectTool(mcpServer).register(),
|
|
14
15
|
new ValidateProjectTool(mcpServer).register(),
|
|
16
|
+
new GetConfigValuesTool(mcpServer).register(),
|
|
15
17
|
];
|
|
16
18
|
}
|
|
@@ -6,22 +6,22 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
6
6
|
addApp: z.ZodBoolean;
|
|
7
7
|
distribution: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"marketplace">, z.ZodLiteral<"private">]>>;
|
|
8
8
|
auth: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"oauth">]>>;
|
|
9
|
-
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">]>, "many">>;
|
|
9
|
+
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">]>, "many">>;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
absoluteProjectPath: string;
|
|
12
12
|
addApp: boolean;
|
|
13
13
|
auth?: "oauth" | "static" | undefined;
|
|
14
14
|
distribution?: "marketplace" | "private" | undefined;
|
|
15
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
15
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
16
16
|
}, {
|
|
17
17
|
absoluteProjectPath: string;
|
|
18
18
|
addApp: boolean;
|
|
19
19
|
auth?: "oauth" | "static" | undefined;
|
|
20
20
|
distribution?: "marketplace" | "private" | undefined;
|
|
21
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
21
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
22
22
|
}>;
|
|
23
23
|
export type AddFeatureInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
24
|
-
export declare class
|
|
24
|
+
export declare class AddFeatureToProjectTool extends Tool<AddFeatureInputSchema> {
|
|
25
25
|
constructor(mcpServer: McpServer);
|
|
26
26
|
handler({ absoluteProjectPath, distribution, auth, features, addApp, }: AddFeatureInputSchema): Promise<TextContentResponse>;
|
|
27
27
|
register(): RegisteredTool;
|
|
@@ -2,8 +2,8 @@ import { Tool } from '../../types.js';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../lib/constants.js';
|
|
4
4
|
import { addFlag } from '../../utils/command.js';
|
|
5
|
-
import { absoluteProjectPath } from './constants.js';
|
|
6
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { absoluteProjectPath, features } from './constants.js';
|
|
6
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
7
7
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
8
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
9
9
|
const inputSchema = {
|
|
@@ -23,23 +23,14 @@ const inputSchema = {
|
|
|
23
23
|
z.literal(APP_AUTH_TYPES.OAUTH),
|
|
24
24
|
]))
|
|
25
25
|
.describe('Static uses a static non changing authentication token, and is only available for private distribution. If not specified by the user, do not choose for them. This cannot be changed after a project is uploaded.'),
|
|
26
|
-
features
|
|
27
|
-
.array(z
|
|
28
|
-
.union([
|
|
29
|
-
z.literal('card'),
|
|
30
|
-
z.literal('settings'),
|
|
31
|
-
z.literal('app-function'),
|
|
32
|
-
z.literal('webhooks'),
|
|
33
|
-
])
|
|
34
|
-
.describe('The features to include in the project, multiple options can be selected'))
|
|
35
|
-
.optional(),
|
|
26
|
+
features,
|
|
36
27
|
};
|
|
37
28
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
38
29
|
const inputSchemaZodObject = z.object({
|
|
39
30
|
...inputSchema,
|
|
40
31
|
});
|
|
41
32
|
const toolName = 'add-feature-to-hubspot-project';
|
|
42
|
-
export class
|
|
33
|
+
export class AddFeatureToProjectTool extends Tool {
|
|
43
34
|
constructor(mcpServer) {
|
|
44
35
|
super(mcpServer);
|
|
45
36
|
}
|
|
@@ -77,7 +68,8 @@ export class AddFeatureToProject extends Tool {
|
|
|
77
68
|
register() {
|
|
78
69
|
return this.mcpServer.registerTool(toolName, {
|
|
79
70
|
title: 'Add feature to HubSpot Project',
|
|
80
|
-
description:
|
|
71
|
+
description: `Adds a feature to an existing HubSpot project.
|
|
72
|
+
Only works for projects with platformVersion '2025.2' and beyond`,
|
|
81
73
|
inputSchema,
|
|
82
74
|
}, this.handler);
|
|
83
75
|
}
|
|
@@ -8,7 +8,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
8
8
|
projectBase: z.ZodUnion<[z.ZodLiteral<"empty">, z.ZodLiteral<"app">]>;
|
|
9
9
|
distribution: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"marketplace">, z.ZodLiteral<"private">]>>;
|
|
10
10
|
auth: z.ZodOptional<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"oauth">]>>>;
|
|
11
|
-
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">]>, "many">>;
|
|
11
|
+
features: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">]>, "many">>;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
13
13
|
projectBase: "app" | "empty";
|
|
14
14
|
absoluteCurrentWorkingDirectory: string;
|
|
@@ -16,7 +16,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
16
16
|
name?: string | undefined;
|
|
17
17
|
auth?: "oauth" | "static" | undefined;
|
|
18
18
|
distribution?: "marketplace" | "private" | undefined;
|
|
19
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
19
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
20
20
|
}, {
|
|
21
21
|
projectBase: "app" | "empty";
|
|
22
22
|
absoluteCurrentWorkingDirectory: string;
|
|
@@ -24,7 +24,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
24
24
|
name?: string | undefined;
|
|
25
25
|
auth?: "oauth" | "static" | undefined;
|
|
26
26
|
distribution?: "marketplace" | "private" | undefined;
|
|
27
|
-
features?: ("card" | "settings" | "app-function" | "webhooks")[] | undefined;
|
|
27
|
+
features?: ("card" | "settings" | "app-function" | "webhooks" | "workflow-action")[] | undefined;
|
|
28
28
|
}>;
|
|
29
29
|
export type CreateProjectInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
30
30
|
export declare class CreateProjectTool extends Tool<CreateProjectInputSchema> {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../lib/constants.js';
|
|
3
|
+
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../lib/constants.js';
|
|
4
4
|
import { addFlag } from '../../utils/command.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { runCommandInDir } from '../../utils/project.js';
|
|
5
|
+
import { absoluteCurrentWorkingDirectory, features } from './constants.js';
|
|
6
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
8
7
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
9
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
10
9
|
const inputSchema = {
|
|
@@ -32,16 +31,7 @@ const inputSchema = {
|
|
|
32
31
|
]))
|
|
33
32
|
.describe('Static uses a static non changing authentication token, and is only available for private distribution. If not specified by the user, do not choose for them. This cannot be changed after a project is uploaded.')
|
|
34
33
|
.optional(),
|
|
35
|
-
features
|
|
36
|
-
.array(z
|
|
37
|
-
.union([
|
|
38
|
-
z.literal('card'),
|
|
39
|
-
z.literal('settings'),
|
|
40
|
-
z.literal('app-function'),
|
|
41
|
-
z.literal('webhooks'),
|
|
42
|
-
])
|
|
43
|
-
.describe('The features to include in the project, multiple options can be selected'))
|
|
44
|
-
.optional(),
|
|
34
|
+
features,
|
|
45
35
|
};
|
|
46
36
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
47
37
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
@@ -12,7 +12,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
12
12
|
buildNumber?: number | undefined;
|
|
13
13
|
}>;
|
|
14
14
|
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
15
|
-
export declare class
|
|
15
|
+
export declare class DeployProjectTool extends Tool<InputSchemaType> {
|
|
16
16
|
constructor(mcpServer: McpServer);
|
|
17
17
|
handler({ absoluteProjectPath, buildNumber, }: InputSchemaType): Promise<TextContentResponse>;
|
|
18
18
|
register(): RegisteredTool;
|
|
@@ -2,7 +2,7 @@ import { Tool } from '../../types.js';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { addFlag } from '../../utils/command.js';
|
|
4
4
|
import { absoluteProjectPath } from './constants.js';
|
|
5
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
6
6
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
7
7
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
8
|
const inputSchema = {
|
|
@@ -16,7 +16,7 @@ const inputSchemaZodObject = z.object({
|
|
|
16
16
|
...inputSchema,
|
|
17
17
|
});
|
|
18
18
|
const toolName = 'deploy-hubspot-project';
|
|
19
|
-
export class
|
|
19
|
+
export class DeployProjectTool extends Tool {
|
|
20
20
|
constructor(mcpServer) {
|
|
21
21
|
super(mcpServer);
|
|
22
22
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TextContentResponse, Tool } from '../../types.js';
|
|
2
|
+
import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
|
+
platformVersion: z.ZodString;
|
|
6
|
+
featureType: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
platformVersion: string;
|
|
9
|
+
featureType: string;
|
|
10
|
+
}, {
|
|
11
|
+
platformVersion: string;
|
|
12
|
+
featureType: string;
|
|
13
|
+
}>;
|
|
14
|
+
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
15
|
+
export declare class GetConfigValuesTool extends Tool<InputSchemaType> {
|
|
16
|
+
constructor(mcpServer: McpServer);
|
|
17
|
+
handler({ platformVersion, featureType, }: InputSchemaType): Promise<TextContentResponse>;
|
|
18
|
+
register(): RegisteredTool;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Tool } from '../../types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { formatTextContents } from '../../utils/content.js';
|
|
4
|
+
import { getIntermediateRepresentationSchema, mapToInternalType, } from '@hubspot/project-parsing-lib';
|
|
5
|
+
import { getAccountId } from '@hubspot/local-dev-lib/config';
|
|
6
|
+
import { useV3Api } from '../../../lib/projects/buildAndDeploy.js';
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
platformVersion: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe('The platform version for the project. Located in the hsproject.json file.'),
|
|
11
|
+
featureType: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe('The type of the component to fetch the JSON schema for. This will be the `type` field in the -hsmeta.json file'),
|
|
14
|
+
};
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
16
|
+
const inputSchemaZodObject = z.object({
|
|
17
|
+
...inputSchema,
|
|
18
|
+
});
|
|
19
|
+
const toolName = 'get-hubspot-project-feature-config-schema';
|
|
20
|
+
export class GetConfigValuesTool extends Tool {
|
|
21
|
+
constructor(mcpServer) {
|
|
22
|
+
super(mcpServer);
|
|
23
|
+
}
|
|
24
|
+
async handler({ platformVersion, featureType, }) {
|
|
25
|
+
try {
|
|
26
|
+
if (!useV3Api(platformVersion)) {
|
|
27
|
+
return formatTextContents(`Can only be used on projects with a minimum platformVersion of 2025.2`);
|
|
28
|
+
}
|
|
29
|
+
const schema = await getIntermediateRepresentationSchema({
|
|
30
|
+
platformVersion,
|
|
31
|
+
projectSourceDir: '',
|
|
32
|
+
accountId: getAccountId(),
|
|
33
|
+
});
|
|
34
|
+
const internalComponentType = mapToInternalType(featureType);
|
|
35
|
+
if (schema[internalComponentType]) {
|
|
36
|
+
return formatTextContents(JSON.stringify({ config: schema[internalComponentType] }));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) { }
|
|
40
|
+
return formatTextContents(`Unable to locate JSON schema for type ${featureType}`);
|
|
41
|
+
}
|
|
42
|
+
register() {
|
|
43
|
+
return this.mcpServer.registerTool(toolName, {
|
|
44
|
+
title: 'Fetch the JSON Schema for component',
|
|
45
|
+
description: `Fetches and returns the JSON schema for the provided feature 'type' found in -hsmeta.json file.
|
|
46
|
+
This should be called before editing a '-hsmeta.json' file to get the list of possible values and restrictions on those values.
|
|
47
|
+
This will only work for projects with platformVersion 2025.2 and beyond`,
|
|
48
|
+
inputSchema,
|
|
49
|
+
}, this.handler);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
|
-
import { runCommandInDir } from '../../utils/
|
|
2
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
3
3
|
import { absoluteProjectPath } from './constants.js';
|
|
4
4
|
import z from 'zod';
|
|
5
5
|
import { formatTextContents } from '../../utils/content.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteProjectPath } from './constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
const inputSchema = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { runCommandInDir } from '../../../utils/
|
|
1
|
+
import { AddFeatureToProjectTool, } from '../AddFeatureToProjectTool.js';
|
|
2
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
3
3
|
import { addFlag } from '../../../utils/command.js';
|
|
4
4
|
import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../../lib/constants.js';
|
|
5
5
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
|
-
vi.mock('../../../utils/
|
|
6
|
+
vi.mock('../../../utils/command');
|
|
7
7
|
vi.mock('../../../utils/command');
|
|
8
8
|
vi.mock('../../../../lib/constants');
|
|
9
9
|
vi.mock('../../../utils/toolUsageTracking');
|
|
@@ -21,18 +21,18 @@ describe('mcp-server/tools/project/AddFeatureToProject', () => {
|
|
|
21
21
|
};
|
|
22
22
|
mockRegisteredTool = {};
|
|
23
23
|
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
24
|
-
tool = new
|
|
24
|
+
tool = new AddFeatureToProjectTool(mockMcpServer);
|
|
25
25
|
// Mock addFlag to simulate command building
|
|
26
26
|
mockAddFlag.mockImplementation((command, flag, value) => `${command} --${flag} "${value}"`);
|
|
27
27
|
});
|
|
28
28
|
describe('register', () => {
|
|
29
29
|
it('should register tool with correct parameters', () => {
|
|
30
30
|
const result = tool.register();
|
|
31
|
-
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('add-feature-to-hubspot-project', {
|
|
31
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('add-feature-to-hubspot-project', expect.objectContaining({
|
|
32
32
|
title: 'Add feature to HubSpot Project',
|
|
33
|
-
description: 'Adds a feature to an existing HubSpot project',
|
|
33
|
+
description: expect.stringContaining('Adds a feature to an existing HubSpot project'),
|
|
34
34
|
inputSchema: expect.any(Object),
|
|
35
|
-
}, tool.handler);
|
|
35
|
+
}), tool.handler);
|
|
36
36
|
expect(result).toBe(mockRegisteredTool);
|
|
37
37
|
});
|
|
38
38
|
});
|