@hubspot/cli 8.0.6-experimental.0 → 8.0.8-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/api/migrate.js +1 -5
- package/commands/cms/__tests__/upload.test.js +0 -4
- package/commands/mcp/__tests__/start.test.js +8 -1
- package/commands/mcp/start.js +0 -1
- package/commands/project/__tests__/migrate.test.js +2 -2
- package/commands/project/migrate.js +4 -4
- package/lang/en.d.ts +4 -2
- package/lang/en.js +4 -2
- package/lib/mcp/__tests__/setup.test.js +15 -0
- package/lib/mcp/setup.d.ts +1 -0
- package/lib/mcp/setup.js +105 -34
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +1 -1
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +2 -2
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -20
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +11 -7
- package/mcp-server/tools/project/CreateProjectTool.d.ts +4 -24
- package/mcp-server/tools/project/CreateProjectTool.js +11 -6
- package/mcp-server/tools/project/CreateTestAccountTool.js +1 -1
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +8 -5
- package/mcp-server/tools/project/GetBuildLogsTool.d.ts +2 -2
- package/mcp-server/tools/project/GetBuildLogsTool.js +7 -6
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +1 -1
- package/mcp-server/tools/project/GetBuildStatusTool.js +4 -3
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -6
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +6 -1
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +32 -0
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +10 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -12
- package/mcp-server/tools/project/constants.js +16 -12
- package/mcp-server/utils/__tests__/command.test.js +233 -3
- package/mcp-server/utils/command.d.ts +5 -0
- package/mcp-server/utils/command.js +24 -0
- package/package.json +2 -2
- package/mcp-server/utils/__tests__/project.test.d.ts +0 -1
- package/mcp-server/utils/__tests__/project.test.js +0 -140
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -18
package/api/migrate.js
CHANGED
|
@@ -23,11 +23,7 @@ function mapPlatformVersionToEnum(platformVersion) {
|
|
|
23
23
|
if (platformVersion === PLATFORM_VERSIONS.unstable) {
|
|
24
24
|
return PLATFORM_VERSIONS.unstable.toUpperCase();
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
.replace('.', '_')
|
|
28
|
-
.replace('-', '_')
|
|
29
|
-
.toUpperCase();
|
|
30
|
-
return `V${reformattedPlatformVersion}`;
|
|
26
|
+
return `V${platformVersion.replace('.', '_')}`;
|
|
31
27
|
}
|
|
32
28
|
export async function initializeAppMigration(accountId, applicationId, platformVersion) {
|
|
33
29
|
return http.post(accountId, {
|
|
@@ -8,7 +8,6 @@ import * as modulesLib from '@hubspot/local-dev-lib/cms/modules';
|
|
|
8
8
|
import * as ignoreRulesLib from '@hubspot/local-dev-lib/ignoreRules';
|
|
9
9
|
import * as themesLib from '@hubspot/local-dev-lib/cms/themes';
|
|
10
10
|
import * as configLib from '@hubspot/local-dev-lib/config';
|
|
11
|
-
import * as handleFieldsJSLib from '@hubspot/local-dev-lib/cms/handleFieldsJS';
|
|
12
11
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
13
12
|
import * as errorHandlers from '../../../lib/errorHandlers/index.js';
|
|
14
13
|
import * as commonOpts from '../../../lib/commonOpts.js';
|
|
@@ -27,7 +26,6 @@ vi.mock('@hubspot/local-dev-lib/cms/modules');
|
|
|
27
26
|
vi.mock('@hubspot/local-dev-lib/ignoreRules');
|
|
28
27
|
vi.mock('@hubspot/local-dev-lib/cms/themes');
|
|
29
28
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
30
|
-
vi.mock('@hubspot/local-dev-lib/cms/handleFieldsJS');
|
|
31
29
|
vi.mock('../../../lib/errorHandlers/index.js');
|
|
32
30
|
vi.mock('../../../lib/commonOpts.js');
|
|
33
31
|
vi.mock('../../../lib/prompts/uploadPrompt.js');
|
|
@@ -55,7 +53,6 @@ const hasUploadErrorsSpy = vi.spyOn(uploadFolderLib, 'hasUploadErrors');
|
|
|
55
53
|
const processExitSpy = vi.spyOn(process, 'exit');
|
|
56
54
|
const logErrorSpy = vi.spyOn(errorHandlers, 'logError');
|
|
57
55
|
const getConfigAccountIfExistsSpy = vi.spyOn(configLib, 'getConfigAccountIfExists');
|
|
58
|
-
const isConvertableFieldJsSpy = vi.spyOn(handleFieldsJSLib, 'isConvertableFieldJs');
|
|
59
56
|
describe('commands/cms/upload', () => {
|
|
60
57
|
beforeEach(() => {
|
|
61
58
|
// @ts-expect-error Mock implementation
|
|
@@ -70,7 +67,6 @@ describe('commands/cms/upload', () => {
|
|
|
70
67
|
getThemePreviewUrlSpy.mockReturnValue(undefined);
|
|
71
68
|
// Mock config to prevent reading actual config file in CI
|
|
72
69
|
getConfigAccountIfExistsSpy.mockReturnValue(undefined);
|
|
73
|
-
isConvertableFieldJsSpy.mockReturnValue(false);
|
|
74
70
|
});
|
|
75
71
|
describe('command', () => {
|
|
76
72
|
it('should have the correct command structure', () => {
|
|
@@ -7,14 +7,20 @@ import * as errorHandlers from '../../../lib/errorHandlers/index.js';
|
|
|
7
7
|
import * as usageTrackingLib from '../../../lib/usageTracking.js';
|
|
8
8
|
import * as processLib from '../../../lib/process.js';
|
|
9
9
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
10
|
-
|
|
10
|
+
// Create a mock execAsync function before importing the module
|
|
11
|
+
const execAsyncMock = vi.fn();
|
|
11
12
|
vi.mock('yargs');
|
|
12
13
|
vi.mock('../../../lib/commonOpts');
|
|
13
14
|
vi.mock('node:child_process');
|
|
15
|
+
vi.mock('node:util', () => ({
|
|
16
|
+
promisify: vi.fn(() => execAsyncMock),
|
|
17
|
+
}));
|
|
14
18
|
vi.mock('fs');
|
|
15
19
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
16
20
|
vi.mock('../../../lib/errorHandlers/index.js');
|
|
17
21
|
vi.mock('../../../lib/process.js');
|
|
22
|
+
// Import after mocks are set up
|
|
23
|
+
const startCommand = await import('../start.js').then(m => m.default);
|
|
18
24
|
const spawnSpy = vi.mocked(spawn);
|
|
19
25
|
const existsSyncSpy = vi.spyOn(fs, 'existsSync');
|
|
20
26
|
const trackCommandUsageSpy = vi.spyOn(usageTrackingLib, 'trackCommandUsage');
|
|
@@ -36,6 +42,7 @@ describe('commands/mcp/start', () => {
|
|
|
36
42
|
processExitSpy.mockImplementation(() => { });
|
|
37
43
|
// Mock config to prevent reading actual config file in CI
|
|
38
44
|
getConfigAccountIfExistsSpy.mockReturnValue(undefined);
|
|
45
|
+
execAsyncMock.mockClear();
|
|
39
46
|
});
|
|
40
47
|
describe('command', () => {
|
|
41
48
|
it('should have the correct command structure', () => {
|
package/commands/mcp/start.js
CHANGED
|
@@ -28,7 +28,6 @@ async function startMcpServer(aiAgent) {
|
|
|
28
28
|
uiLogger.debug(commands.mcp.start.startingServer);
|
|
29
29
|
uiLogger.debug(commands.mcp.start.stopInstructions);
|
|
30
30
|
const args = [serverPath];
|
|
31
|
-
// Start the server using ts-node
|
|
32
31
|
const child = spawn(`node`, args, {
|
|
33
32
|
stdio: 'inherit',
|
|
34
33
|
env: {
|
|
@@ -9,7 +9,7 @@ import { uiBetaTag, uiCommandReference } from '../../../lib/ui/index.js';
|
|
|
9
9
|
vi.mock('../../../lib/app/migrate');
|
|
10
10
|
vi.mock('../../../lib/projects/config');
|
|
11
11
|
vi.mock('../../../lib/ui');
|
|
12
|
-
const { v2025_2
|
|
12
|
+
const { v2025_2 } = PLATFORM_VERSIONS;
|
|
13
13
|
describe('commands/project/migrate', () => {
|
|
14
14
|
const yargsMock = yargs;
|
|
15
15
|
const optionsSpy = vi.spyOn(yargsMock, 'option').mockReturnValue(yargsMock);
|
|
@@ -48,7 +48,7 @@ describe('commands/project/migrate', () => {
|
|
|
48
48
|
migrateCommand.builder(yargsMock);
|
|
49
49
|
expect(optionsSpy).toHaveBeenCalledWith('platform-version', {
|
|
50
50
|
type: 'string',
|
|
51
|
-
choices: [v2025_2
|
|
51
|
+
choices: [v2025_2],
|
|
52
52
|
default: v2025_2,
|
|
53
53
|
});
|
|
54
54
|
expect(optionsSpy).toHaveBeenCalledWith('unstable', {
|
|
@@ -13,7 +13,7 @@ import { getHasMigratableThemes, migrateThemes2025_2, } from '../../lib/theme/mi
|
|
|
13
13
|
import { hasFeature } from '../../lib/hasFeature.js';
|
|
14
14
|
import { FEATURES } from '../../lib/constants.js';
|
|
15
15
|
import { trackCommandMetadataUsage, trackCommandUsage, } from '../../lib/usageTracking.js';
|
|
16
|
-
const { v2025_2
|
|
16
|
+
const { v2025_2 } = PLATFORM_VERSIONS;
|
|
17
17
|
const command = 'migrate';
|
|
18
18
|
const describe = commands.project.migrate.describe;
|
|
19
19
|
async function handler(args) {
|
|
@@ -26,8 +26,8 @@ async function handler(args) {
|
|
|
26
26
|
}
|
|
27
27
|
if (projectConfig?.projectConfig) {
|
|
28
28
|
await renderInline(getWarningBox({
|
|
29
|
-
title: lib.migrate.projectMigrationWarningTitle
|
|
30
|
-
message: lib.migrate.projectMigrationWarning
|
|
29
|
+
title: lib.migrate.projectMigrationWarningTitle,
|
|
30
|
+
message: lib.migrate.projectMigrationWarning,
|
|
31
31
|
}));
|
|
32
32
|
}
|
|
33
33
|
try {
|
|
@@ -67,7 +67,7 @@ function projectMigrateBuilder(yargs) {
|
|
|
67
67
|
yargs
|
|
68
68
|
.option('platform-version', {
|
|
69
69
|
type: 'string',
|
|
70
|
-
choices: [v2025_2
|
|
70
|
+
choices: [v2025_2],
|
|
71
71
|
default: v2025_2,
|
|
72
72
|
})
|
|
73
73
|
.option('unstable', {
|
package/lang/en.d.ts
CHANGED
|
@@ -1295,6 +1295,8 @@ export declare const commands: {
|
|
|
1295
1295
|
prompts: {
|
|
1296
1296
|
targets: string;
|
|
1297
1297
|
targetsRequired: string;
|
|
1298
|
+
standaloneMode: string;
|
|
1299
|
+
cliVersion: string;
|
|
1298
1300
|
};
|
|
1299
1301
|
};
|
|
1300
1302
|
start: {
|
|
@@ -3923,8 +3925,8 @@ export declare const lib: {
|
|
|
3923
3925
|
componentsToBeMigrated: (components: string) => string;
|
|
3924
3926
|
componentsThatWillNotBeMigrated: (components: string) => string;
|
|
3925
3927
|
sourceContentsMoved: (newLocation: string) => string;
|
|
3926
|
-
projectMigrationWarningTitle:
|
|
3927
|
-
projectMigrationWarning:
|
|
3928
|
+
projectMigrationWarningTitle: string;
|
|
3929
|
+
projectMigrationWarning: string;
|
|
3928
3930
|
exitWithoutMigrating: string;
|
|
3929
3931
|
success: {
|
|
3930
3932
|
downloadedProject: (projectName: string, projectDest: string) => string;
|
package/lang/en.js
CHANGED
|
@@ -1311,6 +1311,8 @@ export const commands = {
|
|
|
1311
1311
|
prompts: {
|
|
1312
1312
|
targets: '[--client] Which tools would you like to add the HubSpot CLI MCP server to?',
|
|
1313
1313
|
targetsRequired: 'Must choose at least one app to configure.',
|
|
1314
|
+
standaloneMode: 'Do you want to run in standalone mode? (This will use npx @hubspot/cli instead of the installed hs command)',
|
|
1315
|
+
cliVersion: 'Specify a CLI version to pin (leave blank for latest):',
|
|
1314
1316
|
},
|
|
1315
1317
|
},
|
|
1316
1318
|
start: {
|
|
@@ -3946,8 +3948,8 @@ export const lib = {
|
|
|
3946
3948
|
componentsToBeMigrated: (components) => `The following features will be migrated: ${components}`,
|
|
3947
3949
|
componentsThatWillNotBeMigrated: (components) => `[NOTE] These features are not yet supported for migration but will be available later: ${components}`,
|
|
3948
3950
|
sourceContentsMoved: (newLocation) => `The contents of your old source directory have been moved to ${newLocation}, move any required files to the new source directory.`,
|
|
3949
|
-
projectMigrationWarningTitle:
|
|
3950
|
-
projectMigrationWarning:
|
|
3951
|
+
projectMigrationWarningTitle: 'Important: Migrating to platformVersion 2025.2 is irreversible',
|
|
3952
|
+
projectMigrationWarning: uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion 2025.2. This action cannot be undone. To ensure you have access to your original files, they will be copied to a new directory (archive) for safekeeping.\n\nThis command will guide you through the process, prompting you to enter the required fields and will download the new project source code into your project source directory.`, false),
|
|
3951
3953
|
exitWithoutMigrating: 'Exiting without migrating',
|
|
3952
3954
|
success: {
|
|
3953
3955
|
downloadedProject: (projectName, projectDest) => `Saved ${projectName} to ${projectDest}`,
|
|
@@ -132,6 +132,21 @@ describe('lib/mcp/setup', () => {
|
|
|
132
132
|
});
|
|
133
133
|
expect(mockedLogError).toHaveBeenCalledWith(error);
|
|
134
134
|
});
|
|
135
|
+
it('should pass through environment variables in command', async () => {
|
|
136
|
+
const mockMcpCommandWithEnv = {
|
|
137
|
+
command: 'test-command',
|
|
138
|
+
args: ['--arg1'],
|
|
139
|
+
env: { HUBSPOT_MCP_STANDALONE: 'true' },
|
|
140
|
+
};
|
|
141
|
+
mockedExecAsync.mockResolvedValueOnce({
|
|
142
|
+
stdout: 'codex version 1.0.0',
|
|
143
|
+
stderr: '',
|
|
144
|
+
});
|
|
145
|
+
mockedExecAsync.mockResolvedValueOnce({ stdout: '', stderr: '' });
|
|
146
|
+
const result = await setupCodex(mockMcpCommandWithEnv);
|
|
147
|
+
expect(result).toBe(true);
|
|
148
|
+
expect(mockedExecAsync).toHaveBeenCalledWith('codex mcp add "HubSpotDev" -- test-command --arg1 --ai-agent codex --env HUBSPOT_MCP_STANDALONE=true');
|
|
149
|
+
});
|
|
135
150
|
});
|
|
136
151
|
describe('setupGemini', () => {
|
|
137
152
|
const mockMcpCommand = {
|
package/lib/mcp/setup.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare const supportedTools: {
|
|
|
5
5
|
interface McpCommand {
|
|
6
6
|
command: string;
|
|
7
7
|
args: string[];
|
|
8
|
+
env?: Record<string, string>;
|
|
8
9
|
}
|
|
9
10
|
export declare function addMcpServerToConfig(targets: string[] | undefined): Promise<string[]>;
|
|
10
11
|
export declare function setupVsCode(mcpCommand?: McpCommand): Promise<boolean>;
|
package/lib/mcp/setup.js
CHANGED
|
@@ -47,23 +47,56 @@ export async function addMcpServerToConfig(targets) {
|
|
|
47
47
|
else {
|
|
48
48
|
derivedTargets = targets;
|
|
49
49
|
}
|
|
50
|
+
// Prompt for standalone mode
|
|
51
|
+
const { useStandaloneMode } = await promptUser({
|
|
52
|
+
name: 'useStandaloneMode',
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
message: commands.mcp.setup.prompts.standaloneMode,
|
|
55
|
+
default: false,
|
|
56
|
+
});
|
|
57
|
+
const { cliVersion } = useStandaloneMode
|
|
58
|
+
? await promptUser({
|
|
59
|
+
name: 'cliVersion',
|
|
60
|
+
type: 'input',
|
|
61
|
+
message: commands.mcp.setup.prompts.cliVersion,
|
|
62
|
+
validate: (v) => !v || /^[\d]+\.[\d]+\.[\d]+([-+][\w.]+)?$/.test(v.trim())
|
|
63
|
+
? true
|
|
64
|
+
: 'Please enter a valid semver version (e.g. 8.0.1) or leave blank for latest.',
|
|
65
|
+
})
|
|
66
|
+
: { cliVersion: '' };
|
|
67
|
+
const cliPackage = cliVersion
|
|
68
|
+
? `@hubspot/cli@${cliVersion}`
|
|
69
|
+
: '@hubspot/cli';
|
|
70
|
+
const standaloneEnv = {
|
|
71
|
+
HUBSPOT_MCP_STANDALONE: 'true',
|
|
72
|
+
};
|
|
73
|
+
if (cliVersion) {
|
|
74
|
+
standaloneEnv.HUBSPOT_CLI_VERSION = cliVersion;
|
|
75
|
+
}
|
|
76
|
+
const mcpCommand = useStandaloneMode
|
|
77
|
+
? {
|
|
78
|
+
command: 'npx',
|
|
79
|
+
args: ['-y', '-p', cliPackage, 'hs', 'mcp', 'start'],
|
|
80
|
+
env: standaloneEnv,
|
|
81
|
+
}
|
|
82
|
+
: defaultMcpCommand;
|
|
50
83
|
if (derivedTargets.includes(claudeCode)) {
|
|
51
|
-
await runSetupFunction(setupClaudeCode);
|
|
84
|
+
await runSetupFunction(() => setupClaudeCode(mcpCommand));
|
|
52
85
|
}
|
|
53
86
|
if (derivedTargets.includes(cursor)) {
|
|
54
|
-
await runSetupFunction(setupCursor);
|
|
87
|
+
await runSetupFunction(() => setupCursor(mcpCommand));
|
|
55
88
|
}
|
|
56
89
|
if (derivedTargets.includes(windsurf)) {
|
|
57
|
-
await runSetupFunction(setupWindsurf);
|
|
90
|
+
await runSetupFunction(() => setupWindsurf(mcpCommand));
|
|
58
91
|
}
|
|
59
92
|
if (derivedTargets.includes(vscode)) {
|
|
60
|
-
await runSetupFunction(setupVsCode);
|
|
93
|
+
await runSetupFunction(() => setupVsCode(mcpCommand));
|
|
61
94
|
}
|
|
62
95
|
if (derivedTargets.includes(codex)) {
|
|
63
|
-
await runSetupFunction(setupCodex);
|
|
96
|
+
await runSetupFunction(() => setupCodex(mcpCommand));
|
|
64
97
|
}
|
|
65
98
|
if (derivedTargets.includes(gemini)) {
|
|
66
|
-
await runSetupFunction(setupGemini);
|
|
99
|
+
await runSetupFunction(() => setupGemini(mcpCommand));
|
|
67
100
|
}
|
|
68
101
|
uiLogger.info(commands.mcp.setup.success(derivedTargets));
|
|
69
102
|
return derivedTargets;
|
|
@@ -122,9 +155,14 @@ function setupMcpConfigFile(config) {
|
|
|
122
155
|
mcpConfig.mcpServers = {};
|
|
123
156
|
}
|
|
124
157
|
// Add or update HubSpot CLI MCP server
|
|
125
|
-
|
|
126
|
-
|
|
158
|
+
const serverConfig = {
|
|
159
|
+
command: config.mcpCommand.command,
|
|
160
|
+
args: config.mcpCommand.args,
|
|
127
161
|
};
|
|
162
|
+
if (config.mcpCommand.env) {
|
|
163
|
+
serverConfig.env = config.mcpCommand.env;
|
|
164
|
+
}
|
|
165
|
+
mcpConfig.mcpServers[mcpServerName] = serverConfig;
|
|
128
166
|
// Write the updated config
|
|
129
167
|
fs.writeFileSync(config.configPath, JSON.stringify(mcpConfig, null, 2));
|
|
130
168
|
SpinniesManager.succeed('spinner', {
|
|
@@ -145,10 +183,16 @@ export async function setupVsCode(mcpCommand = defaultMcpCommand) {
|
|
|
145
183
|
SpinniesManager.add('vsCode', {
|
|
146
184
|
text: commands.mcp.setup.spinners.configuringVsCode,
|
|
147
185
|
});
|
|
148
|
-
const
|
|
186
|
+
const commandWithAgent = buildCommandWithAgentString(mcpCommand, vscode);
|
|
187
|
+
const configObject = {
|
|
149
188
|
name: mcpServerName,
|
|
150
|
-
|
|
151
|
-
|
|
189
|
+
command: commandWithAgent.command,
|
|
190
|
+
args: commandWithAgent.args,
|
|
191
|
+
};
|
|
192
|
+
if (commandWithAgent.env) {
|
|
193
|
+
configObject.env = commandWithAgent.env;
|
|
194
|
+
}
|
|
195
|
+
const mcpConfig = JSON.stringify(configObject);
|
|
152
196
|
await execAsync(`code --add-mcp ${JSON.stringify(mcpConfig)}`);
|
|
153
197
|
SpinniesManager.succeed('vsCode', {
|
|
154
198
|
text: commands.mcp.setup.spinners.configuredVsCode,
|
|
@@ -179,30 +223,44 @@ export async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
|
|
|
179
223
|
try {
|
|
180
224
|
// Check if claude command is available
|
|
181
225
|
await execAsync('claude --version');
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
226
|
+
// Run claude mcp add command
|
|
227
|
+
const commandWithAgent = buildCommandWithAgentString(mcpCommand, claudeCode);
|
|
228
|
+
const configObject = {
|
|
229
|
+
type: 'stdio',
|
|
230
|
+
command: commandWithAgent.command,
|
|
231
|
+
args: commandWithAgent.args,
|
|
232
|
+
};
|
|
233
|
+
if (commandWithAgent.env) {
|
|
234
|
+
configObject.env = commandWithAgent.env;
|
|
235
|
+
}
|
|
236
|
+
const mcpConfig = JSON.stringify(configObject);
|
|
237
|
+
const { stdout } = await execAsync('claude mcp list');
|
|
238
|
+
if (stdout.includes(mcpServerName)) {
|
|
239
|
+
SpinniesManager.update('claudeCode', {
|
|
240
|
+
text: commands.mcp.setup.spinners.alreadyInstalled,
|
|
241
|
+
});
|
|
242
|
+
await execAsync(`claude mcp remove "${mcpServerName}" --scope user`);
|
|
243
|
+
}
|
|
244
|
+
await execAsync(`claude mcp add-json "${mcpServerName}" ${JSON.stringify(mcpConfig)} --scope user`);
|
|
245
|
+
SpinniesManager.succeed('claudeCode', {
|
|
246
|
+
text: commands.mcp.setup.spinners.configuredClaudeCode,
|
|
186
247
|
});
|
|
187
|
-
return
|
|
248
|
+
return true;
|
|
188
249
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
250
|
+
catch (error) {
|
|
251
|
+
if (error instanceof Error && error.message.includes('claude')) {
|
|
252
|
+
SpinniesManager.fail('claudeCode', {
|
|
253
|
+
text: commands.mcp.setup.spinners.claudeCodeNotFound,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
SpinniesManager.fail('claudeCode', {
|
|
258
|
+
text: commands.mcp.setup.spinners.claudeCodeInstallFailed,
|
|
259
|
+
});
|
|
260
|
+
logError(error);
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
200
263
|
}
|
|
201
|
-
await execAsync(`claude mcp add-json "${mcpServerName}" ${JSON.stringify(mcpConfig)} --scope user`);
|
|
202
|
-
SpinniesManager.succeed('claudeCode', {
|
|
203
|
-
text: commands.mcp.setup.spinners.configuredClaudeCode,
|
|
204
|
-
});
|
|
205
|
-
return true;
|
|
206
264
|
}
|
|
207
265
|
catch (error) {
|
|
208
266
|
SpinniesManager.fail('claudeCode', {
|
|
@@ -248,7 +306,7 @@ export async function setupCodex(mcpCommand = defaultMcpCommand) {
|
|
|
248
306
|
return false;
|
|
249
307
|
}
|
|
250
308
|
const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, codex);
|
|
251
|
-
await execAsync(`codex mcp add "${mcpServerName}" -- ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
|
|
309
|
+
await execAsync(`codex mcp add "${mcpServerName}" -- ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}${buildEnvFlagString(mcpCommand)}`);
|
|
252
310
|
SpinniesManager.succeed('codexSpinner', {
|
|
253
311
|
text: commands.mcp.setup.spinners.configuredCodex,
|
|
254
312
|
});
|
|
@@ -277,7 +335,7 @@ export async function setupGemini(mcpCommand = defaultMcpCommand) {
|
|
|
277
335
|
return false;
|
|
278
336
|
}
|
|
279
337
|
const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, gemini);
|
|
280
|
-
await execAsync(`gemini mcp add -s user "${mcpServerName}" ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
|
|
338
|
+
await execAsync(`gemini mcp add -s user "${mcpServerName}" ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}${buildEnvFlagString(mcpCommand)}`);
|
|
281
339
|
SpinniesManager.succeed('geminiSpinner', {
|
|
282
340
|
text: commands.mcp.setup.spinners.configuredGemini,
|
|
283
341
|
});
|
|
@@ -296,3 +354,16 @@ function buildCommandWithAgentString(mcpCommand, agent) {
|
|
|
296
354
|
mcpCommandCopy.args.push('--ai-agent', agent);
|
|
297
355
|
return mcpCommandCopy;
|
|
298
356
|
}
|
|
357
|
+
function buildEnvFlagString(mcpCommand) {
|
|
358
|
+
const envFlags = [];
|
|
359
|
+
if (mcpCommand.env) {
|
|
360
|
+
const env = Object.entries(mcpCommand.env);
|
|
361
|
+
env.forEach(([key, value]) => {
|
|
362
|
+
envFlags.push(`--env ${key}=${value}`);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
if (envFlags.length === 0) {
|
|
366
|
+
return '';
|
|
367
|
+
}
|
|
368
|
+
return ` ${envFlags.join(' ')}`;
|
|
369
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|
|
@@ -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 { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
5
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
6
6
|
import { formatTextContents } from '../../utils/content.js';
|
|
7
7
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -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 { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
5
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
6
6
|
import { formatTextContents } from '../../utils/content.js';
|
|
7
7
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -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 { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
5
|
-
import { runCommandInDir } from '../../utils/
|
|
5
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
6
6
|
import { formatTextContents } from '../../utils/content.js';
|
|
7
7
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
8
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsCreateFunctionTool } from '../HsCreateFunctionTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/project');
|
|
9
8
|
vi.mock('../../../utils/command');
|
|
10
9
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
10
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsCreateModuleTool } from '../HsCreateModuleTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/
|
|
8
|
+
vi.mock('../../../utils/command');
|
|
9
9
|
vi.mock('../../../utils/command');
|
|
10
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsCreateTemplateTool } from '../HsCreateTemplateTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/
|
|
8
|
+
vi.mock('../../../utils/command');
|
|
9
9
|
vi.mock('../../../utils/command');
|
|
10
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsFunctionLogsTool } from '../HsFunctionLogsTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/
|
|
8
|
+
vi.mock('../../../utils/command');
|
|
9
9
|
vi.mock('../../../utils/command');
|
|
10
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsListFunctionsTool } from '../HsListFunctionsTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/
|
|
8
|
+
vi.mock('../../../utils/command');
|
|
9
9
|
vi.mock('../../../utils/command');
|
|
10
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { HsListTool } from '../HsListTool.js';
|
|
3
|
-
import { runCommandInDir } from '../../../utils/
|
|
3
|
+
import { runCommandInDir } from '../../../utils/command.js';
|
|
4
4
|
import { addFlag } from '../../../utils/command.js';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
7
7
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
-
vi.mock('../../../utils/
|
|
8
|
+
vi.mock('../../../utils/command');
|
|
9
9
|
vi.mock('../../../utils/command');
|
|
10
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
@@ -5,26 +5,9 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
5
5
|
absoluteProjectPath: z.ZodString;
|
|
6
6
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
7
7
|
addApp: z.ZodBoolean;
|
|
8
|
-
distribution: z.ZodOptional<z.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}>>;
|
|
12
|
-
auth: z.ZodOptional<z.ZodEnum<{
|
|
13
|
-
oauth: "oauth";
|
|
14
|
-
static: "static";
|
|
15
|
-
}>>;
|
|
16
|
-
features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
17
|
-
card: "card";
|
|
18
|
-
settings: "settings";
|
|
19
|
-
"app-event": "app-event";
|
|
20
|
-
page: "page";
|
|
21
|
-
"workflow-action-tool": "workflow-action-tool";
|
|
22
|
-
webhooks: "webhooks";
|
|
23
|
-
"workflow-action": "workflow-action";
|
|
24
|
-
"app-function": "app-function";
|
|
25
|
-
"app-object": "app-object";
|
|
26
|
-
scim: "scim";
|
|
27
|
-
}>>>;
|
|
8
|
+
distribution: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"marketplace">, z.ZodLiteral<"private">]>>;
|
|
9
|
+
auth: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"static">, z.ZodLiteral<"oauth">]>>;
|
|
10
|
+
features: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodLiteral<"card">, z.ZodLiteral<"settings">, z.ZodLiteral<"app-function">, z.ZodLiteral<"webhooks">, z.ZodLiteral<"workflow-action">, z.ZodLiteral<"workflow-action-tool">, z.ZodLiteral<"app-object">, z.ZodLiteral<"app-event">, z.ZodLiteral<"scim">, z.ZodLiteral<"page">]>>>;
|
|
28
11
|
}, z.core.$strip>;
|
|
29
12
|
export type AddFeatureInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
30
13
|
export declare class AddFeatureToProjectTool extends Tool<AddFeatureInputSchema> {
|
|
@@ -3,7 +3,7 @@ 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
5
|
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, features, } from './constants.js';
|
|
6
|
-
import { runCommandInDir } from '../../utils/
|
|
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
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
@@ -15,13 +15,17 @@ const inputSchema = {
|
|
|
15
15
|
.boolean()
|
|
16
16
|
.describe('Should an app be added? If there is no app in the project, an app must be added to add a feature'),
|
|
17
17
|
distribution: z
|
|
18
|
-
.
|
|
19
|
-
.
|
|
20
|
-
.
|
|
18
|
+
.optional(z.union([
|
|
19
|
+
z.literal(APP_DISTRIBUTION_TYPES.MARKETPLACE),
|
|
20
|
+
z.literal(APP_DISTRIBUTION_TYPES.PRIVATE),
|
|
21
|
+
]))
|
|
22
|
+
.describe('If not specified by the user, DO NOT choose for them. This cannot be changed after a project is uploaded. Private is used if you do not wish to distribute your app on the HubSpot marketplace. '),
|
|
21
23
|
auth: z
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.
|
|
24
|
+
.optional(z.union([
|
|
25
|
+
z.literal(APP_AUTH_TYPES.STATIC),
|
|
26
|
+
z.literal(APP_AUTH_TYPES.OAUTH),
|
|
27
|
+
]))
|
|
28
|
+
.describe('If not specified by the user, DO NOT choose for them. This cannot be changed after a project is uploaded. Static uses a static non changing authentication token, and is only available for private distribution. '),
|
|
25
29
|
features,
|
|
26
30
|
};
|
|
27
31
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|