@hubspot/cli 7.7.20-experimental.0 → 7.7.21-experimental.1
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/bin/cli.js +6 -2
- package/commands/__tests__/getStarted.test.js +0 -10
- package/commands/app/__tests__/install.test.d.ts +1 -0
- package/commands/app/__tests__/install.test.js +52 -0
- package/commands/app/install.d.ts +8 -0
- package/commands/app/install.js +127 -0
- package/commands/app.js +6 -1
- package/commands/getStarted.js +12 -27
- package/commands/mcp/setup.js +1 -0
- package/commands/mcp/start.d.ts +4 -1
- package/commands/mcp/start.js +8 -3
- package/commands/project/__tests__/deploy.test.js +27 -25
- package/commands/project/__tests__/devUnifiedFlow.test.js +20 -16
- package/commands/project/create.js +1 -1
- package/commands/project/deploy.d.ts +3 -2
- package/commands/project/deploy.js +61 -55
- package/commands/project/dev/unifiedFlow.js +7 -6
- package/commands/testAccount/__tests__/createConfig.test.js +0 -3
- package/commands/testAccount/create.js +14 -24
- package/commands/testAccount/createConfig.d.ts +0 -2
- package/commands/testAccount/createConfig.js +7 -8
- package/lang/en.d.ts +61 -23
- package/lang/en.js +62 -24
- package/lang/en.lyaml +0 -26
- package/lib/__tests__/buildAccount.test.js +30 -2
- package/lib/__tests__/usageTracking.test.js +8 -14
- package/lib/buildAccount.d.ts +7 -1
- package/lib/buildAccount.js +54 -4
- package/lib/mcp/setup.js +8 -3
- package/lib/projects/add/legacyAddComponent.js +1 -1
- package/lib/projects/add/v3AddComponent.js +1 -1
- package/lib/projects/localDev/DevServerManager.js +0 -2
- package/lib/projects/localDev/DevServerManagerV2.js +0 -2
- package/lib/projects/localDev/helpers.d.ts +1 -1
- package/lib/projects/localDev/helpers.js +2 -2
- package/lib/projects/structure.d.ts +2 -2
- package/lib/projects/upload.d.ts +2 -1
- package/lib/projects/upload.js +2 -1
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +11 -10
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +73 -31
- package/lib/prompts/promptUtils.js +66 -56
- package/lib/ui/index.js +1 -1
- package/lib/usageTracking.d.ts +11 -0
- package/lib/usageTracking.js +67 -73
- package/mcp-server/tools/project/AddFeatureToProject.js +4 -1
- package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
- package/mcp-server/tools/project/CreateProjectTool.js +4 -1
- package/mcp-server/tools/project/DeployProject.js +4 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -1
- package/mcp-server/tools/project/UploadProjectTools.js +4 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +4 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProject.test.js +1 -0
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -0
- package/mcp-server/tools/project/__tests__/DeployProject.test.js +1 -0
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -0
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -0
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -0
- package/mcp-server/utils/__tests__/project.test.js +9 -6
- package/mcp-server/utils/project.js +3 -0
- package/mcp-server/utils/toolUsageTracking.d.ts +1 -0
- package/mcp-server/utils/toolUsageTracking.js +25 -0
- package/package.json +4 -4
package/bin/cli.js
CHANGED
|
@@ -135,8 +135,12 @@ const argv = yargs_1.default
|
|
|
135
135
|
.wrap(getTerminalWidth())
|
|
136
136
|
.strict().argv;
|
|
137
137
|
if ('help' in argv && argv.help !== undefined) {
|
|
138
|
-
(
|
|
138
|
+
(async () => {
|
|
139
|
+
await (0, usageTracking_1.trackHelpUsage)((0, commonOpts_1.getCommandName)(argv));
|
|
140
|
+
})();
|
|
139
141
|
}
|
|
140
142
|
if ('convertFields' in argv && argv.convertFields !== undefined) {
|
|
141
|
-
(
|
|
143
|
+
(async () => {
|
|
144
|
+
await (0, usageTracking_1.trackConvertFieldsUsage)((0, commonOpts_1.getCommandName)(argv));
|
|
145
|
+
})();
|
|
142
146
|
}
|
|
@@ -108,9 +108,6 @@ describe('commands/get-started', () => {
|
|
|
108
108
|
promptUtils_1.promptUser
|
|
109
109
|
.mockResolvedValueOnce({
|
|
110
110
|
default: constants_1.GET_STARTED_OPTIONS.APP,
|
|
111
|
-
})
|
|
112
|
-
.mockResolvedValueOnce({
|
|
113
|
-
shouldInstallDependencies: true,
|
|
114
111
|
})
|
|
115
112
|
.mockResolvedValueOnce({
|
|
116
113
|
shouldUpload: true,
|
|
@@ -149,13 +146,6 @@ describe('commands/get-started', () => {
|
|
|
149
146
|
}),
|
|
150
147
|
]);
|
|
151
148
|
});
|
|
152
|
-
it('should skip upload when user declines', async () => {
|
|
153
|
-
promptUtils_1.promptUser
|
|
154
|
-
.mockResolvedValueOnce({ shouldInstallDependencies: false })
|
|
155
|
-
.mockResolvedValueOnce({ shouldUpload: false });
|
|
156
|
-
await getStarted_1.default.handler(mockArgs);
|
|
157
|
-
expect(process.exit).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
158
|
-
});
|
|
159
149
|
});
|
|
160
150
|
describe('tracking', () => {
|
|
161
151
|
it('should track command usage', async () => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const yargs_1 = __importDefault(require("yargs"));
|
|
7
|
+
const commonOpts_1 = require("../../../lib/commonOpts");
|
|
8
|
+
const install_1 = __importDefault(require("../install"));
|
|
9
|
+
vi.mock('../../../lib/commonOpts');
|
|
10
|
+
describe('commands/app/install', () => {
|
|
11
|
+
const yargsMock = yargs_1.default;
|
|
12
|
+
describe('command', () => {
|
|
13
|
+
it('should have the correct command structure', () => {
|
|
14
|
+
expect(install_1.default.command).toEqual('install <test-account-id>');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe('describe', () => {
|
|
18
|
+
it('should provide a description', () => {
|
|
19
|
+
expect(install_1.default.describe).not.toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('builder', () => {
|
|
23
|
+
it('should support the correct options', () => {
|
|
24
|
+
install_1.default.builder(yargsMock);
|
|
25
|
+
expect(commonOpts_1.addGlobalOptions).toHaveBeenCalledTimes(1);
|
|
26
|
+
expect(commonOpts_1.addGlobalOptions).toHaveBeenCalledWith(yargsMock);
|
|
27
|
+
expect(commonOpts_1.addAccountOptions).toHaveBeenCalledTimes(1);
|
|
28
|
+
expect(commonOpts_1.addAccountOptions).toHaveBeenCalledWith(yargsMock);
|
|
29
|
+
expect(commonOpts_1.addConfigOptions).toHaveBeenCalledTimes(1);
|
|
30
|
+
expect(commonOpts_1.addConfigOptions).toHaveBeenCalledWith(yargsMock);
|
|
31
|
+
expect(commonOpts_1.addUseEnvironmentOptions).toHaveBeenCalledTimes(1);
|
|
32
|
+
expect(commonOpts_1.addUseEnvironmentOptions).toHaveBeenCalledWith(yargsMock);
|
|
33
|
+
expect(commonOpts_1.addJSONOutputOptions).toHaveBeenCalledTimes(1);
|
|
34
|
+
expect(commonOpts_1.addJSONOutputOptions).toHaveBeenCalledWith(yargsMock);
|
|
35
|
+
expect(yargsMock.positional).toHaveBeenCalledTimes(1);
|
|
36
|
+
expect(yargsMock.positional).toHaveBeenCalledWith('test-account-id', expect.objectContaining({
|
|
37
|
+
type: 'number',
|
|
38
|
+
required: true,
|
|
39
|
+
describe: expect.any(String),
|
|
40
|
+
}));
|
|
41
|
+
expect(yargsMock.option).toHaveBeenCalledTimes(2);
|
|
42
|
+
expect(yargsMock.option).toHaveBeenCalledWith('app-uid', expect.objectContaining({
|
|
43
|
+
type: 'string',
|
|
44
|
+
describe: expect.any(String),
|
|
45
|
+
}));
|
|
46
|
+
expect(yargsMock.option).toHaveBeenCalledWith('project-name', expect.objectContaining({
|
|
47
|
+
type: 'string',
|
|
48
|
+
describe: expect.any(String),
|
|
49
|
+
}));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule, JSONOutputArgs } from '../../types/Yargs';
|
|
2
|
+
type InstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
|
|
3
|
+
appUid?: string;
|
|
4
|
+
projectName?: string;
|
|
5
|
+
testAccountId: number;
|
|
6
|
+
};
|
|
7
|
+
declare const installAppCommand: YargsCommandModule<unknown, InstallAppArgs>;
|
|
8
|
+
export default installAppCommand;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const developerTestAccounts_1 = require("@hubspot/local-dev-lib/api/developerTestAccounts");
|
|
7
|
+
const usageTracking_1 = require("../../lib/usageTracking");
|
|
8
|
+
const en_1 = require("../../lang/en");
|
|
9
|
+
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
10
|
+
const yargsUtils_1 = require("../../lib/yargsUtils");
|
|
11
|
+
const constants_1 = require("../../lib/constants");
|
|
12
|
+
const logger_1 = require("../../lib/ui/logger");
|
|
13
|
+
const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
|
|
14
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
15
|
+
const polling_1 = require("../../lib/polling");
|
|
16
|
+
const config_1 = require("../../lib/projects/config");
|
|
17
|
+
const upload_1 = require("../../lib/projects/upload");
|
|
18
|
+
const structure_1 = require("../../lib/projects/structure");
|
|
19
|
+
const command = 'install <test-account-id>';
|
|
20
|
+
const describe = undefined; // commands.app.subcommands.install.describe;
|
|
21
|
+
async function handler(args) {
|
|
22
|
+
const { derivedAccountId, appUid, projectName, testAccountId, formatOutputAsJson, } = args;
|
|
23
|
+
(0, usageTracking_1.trackCommandUsage)('app-install', {}, derivedAccountId);
|
|
24
|
+
const jsonOutput = {};
|
|
25
|
+
let targetProjectName = projectName;
|
|
26
|
+
let targetAppUid = appUid;
|
|
27
|
+
const { projectConfig, projectDir } = await (0, config_1.getProjectConfig)();
|
|
28
|
+
if (!targetProjectName) {
|
|
29
|
+
(0, config_1.validateProjectConfig)(projectConfig, projectDir);
|
|
30
|
+
targetProjectName = projectConfig?.name;
|
|
31
|
+
}
|
|
32
|
+
if (!targetProjectName) {
|
|
33
|
+
logger_1.uiLogger.error(en_1.commands.app.subcommands.install.errors.mustSpecifyProjectName);
|
|
34
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
35
|
+
}
|
|
36
|
+
let isAppOauth = true;
|
|
37
|
+
if (!targetAppUid) {
|
|
38
|
+
const intermediateRepresentation = await (0, upload_1.handleTranslate)(projectDir, projectConfig, derivedAccountId, true, undefined);
|
|
39
|
+
if (intermediateRepresentation) {
|
|
40
|
+
Object.values(intermediateRepresentation.intermediateNodesIndexedByUid).forEach(node => {
|
|
41
|
+
if ((0, structure_1.isAppIRNode)(node)) {
|
|
42
|
+
targetAppUid = node.uid;
|
|
43
|
+
isAppOauth = node.config.auth.type === constants_1.APP_AUTH_TYPES.OAUTH;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!targetAppUid) {
|
|
49
|
+
logger_1.uiLogger.error(en_1.commands.app.subcommands.install.errors.noAppUidFound);
|
|
50
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
51
|
+
}
|
|
52
|
+
if (!isAppOauth) {
|
|
53
|
+
logger_1.uiLogger.error(en_1.commands.app.subcommands.install.errors.appMustBeOauth);
|
|
54
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const { data } = await (0, developerTestAccounts_1.installOauthAppIntoDeveloperTestAccount)(derivedAccountId, testAccountId, targetProjectName, targetAppUid);
|
|
58
|
+
if (data?.authCodes.length > 0) {
|
|
59
|
+
jsonOutput.authCode = data.authCodes[0].authCode;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
(0, errorHandlers_1.logError)(err);
|
|
64
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
65
|
+
}
|
|
66
|
+
SpinniesManager_1.default.init({
|
|
67
|
+
succeedColor: 'white',
|
|
68
|
+
});
|
|
69
|
+
SpinniesManager_1.default.add('installApp', {
|
|
70
|
+
text: en_1.commands.app.subcommands.install.polling.start,
|
|
71
|
+
});
|
|
72
|
+
let appInstallSucceeded = false;
|
|
73
|
+
try {
|
|
74
|
+
await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountOauthAppInstallStatus)(derivedAccountId, targetProjectName, targetAppUid), {
|
|
75
|
+
successStates: ['SUCCESS'],
|
|
76
|
+
errorStates: [],
|
|
77
|
+
});
|
|
78
|
+
appInstallSucceeded = true;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
SpinniesManager_1.default.fail('installApp');
|
|
82
|
+
(0, errorHandlers_1.logError)(err);
|
|
83
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
84
|
+
}
|
|
85
|
+
if (!appInstallSucceeded) {
|
|
86
|
+
SpinniesManager_1.default.fail('installApp');
|
|
87
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
88
|
+
}
|
|
89
|
+
SpinniesManager_1.default.succeed('installApp', {
|
|
90
|
+
text: en_1.commands.app.subcommands.install.polling.success,
|
|
91
|
+
});
|
|
92
|
+
if (formatOutputAsJson) {
|
|
93
|
+
logger_1.uiLogger.json(jsonOutput);
|
|
94
|
+
}
|
|
95
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
96
|
+
}
|
|
97
|
+
function installAppBuilder(yargs) {
|
|
98
|
+
yargs.positional('test-account-id', {
|
|
99
|
+
describe: en_1.commands.app.subcommands.install.positionals.testAccountId,
|
|
100
|
+
required: true,
|
|
101
|
+
type: 'number',
|
|
102
|
+
});
|
|
103
|
+
yargs.option('app-uid', {
|
|
104
|
+
describe: en_1.commands.app.subcommands.install.options.appUid,
|
|
105
|
+
type: 'string',
|
|
106
|
+
});
|
|
107
|
+
yargs.option('project-name', {
|
|
108
|
+
describe: en_1.commands.app.subcommands.install.options.projectName,
|
|
109
|
+
type: 'string',
|
|
110
|
+
});
|
|
111
|
+
yargs.example('install 1234567890 --app-uid=my-app-uid --project-name=my-project', en_1.commands.app.subcommands.install.example);
|
|
112
|
+
return yargs;
|
|
113
|
+
}
|
|
114
|
+
const builder = (0, yargsUtils_1.makeYargsBuilder)(installAppBuilder, command, en_1.commands.app.subcommands.install.describe, {
|
|
115
|
+
useGlobalOptions: true,
|
|
116
|
+
useAccountOptions: true,
|
|
117
|
+
useConfigOptions: true,
|
|
118
|
+
useEnvironmentOptions: true,
|
|
119
|
+
useJSONOutputOptions: true,
|
|
120
|
+
});
|
|
121
|
+
const installAppCommand = {
|
|
122
|
+
command,
|
|
123
|
+
describe,
|
|
124
|
+
handler,
|
|
125
|
+
builder,
|
|
126
|
+
};
|
|
127
|
+
exports.default = installAppCommand;
|
package/commands/app.js
CHANGED
|
@@ -5,12 +5,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const migrate_1 = __importDefault(require("./app/migrate"));
|
|
7
7
|
const secret_1 = __importDefault(require("./app/secret"));
|
|
8
|
+
const install_1 = __importDefault(require("./app/install"));
|
|
8
9
|
const yargsUtils_1 = require("../lib/yargsUtils");
|
|
9
10
|
const command = ['app', 'apps'];
|
|
10
11
|
// Keep the command hidden for now
|
|
11
12
|
const describe = undefined;
|
|
12
13
|
function appBuilder(yargs) {
|
|
13
|
-
yargs
|
|
14
|
+
yargs
|
|
15
|
+
.command(migrate_1.default)
|
|
16
|
+
.command(secret_1.default)
|
|
17
|
+
.command(install_1.default)
|
|
18
|
+
.demandCommand(1, '');
|
|
14
19
|
return yargs;
|
|
15
20
|
}
|
|
16
21
|
const builder = (0, yargsUtils_1.makeYargsBuilder)(appBuilder, command, describe);
|
package/commands/getStarted.js
CHANGED
|
@@ -127,35 +127,20 @@ async function handler(args) {
|
|
|
127
127
|
logger_1.uiLogger.log(' ');
|
|
128
128
|
logger_1.uiLogger.log(en_1.commands.getStarted.prompts.projectCreated.description);
|
|
129
129
|
logger_1.uiLogger.log(' ');
|
|
130
|
-
// 5. Install dependencies
|
|
130
|
+
// 5. Install dependencies
|
|
131
131
|
const installLocations = await (0, dependencyManagement_1.getProjectPackageJsonLocations)(projectDest);
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
]);
|
|
140
|
-
if (shouldInstallDependencies) {
|
|
141
|
-
try {
|
|
142
|
-
await (0, dependencyManagement_1.installPackages)({
|
|
143
|
-
installLocations: installLocations,
|
|
144
|
-
});
|
|
145
|
-
logger_1.uiLogger.log(' ');
|
|
146
|
-
logger_1.uiLogger.success(en_1.commands.getStarted.logs.dependenciesInstalled);
|
|
147
|
-
logger_1.uiLogger.log(' ');
|
|
148
|
-
}
|
|
149
|
-
catch (err) {
|
|
150
|
-
logger_1.uiLogger.log(' ');
|
|
151
|
-
logger_1.uiLogger.error(en_1.commands.getStarted.errors.installDepsFailed);
|
|
152
|
-
(0, errorHandlers_1.logError)(err);
|
|
153
|
-
logger_1.uiLogger.log(' ');
|
|
154
|
-
}
|
|
132
|
+
try {
|
|
133
|
+
await (0, dependencyManagement_1.installPackages)({
|
|
134
|
+
installLocations: installLocations,
|
|
135
|
+
});
|
|
136
|
+
logger_1.uiLogger.log(' ');
|
|
137
|
+
logger_1.uiLogger.success(en_1.commands.getStarted.logs.dependenciesInstalled);
|
|
138
|
+
logger_1.uiLogger.log(' ');
|
|
155
139
|
}
|
|
156
|
-
|
|
140
|
+
catch (err) {
|
|
157
141
|
logger_1.uiLogger.log(' ');
|
|
158
|
-
logger_1.uiLogger.
|
|
142
|
+
logger_1.uiLogger.error(en_1.commands.getStarted.errors.installDepsFailed);
|
|
143
|
+
(0, errorHandlers_1.logError)(err);
|
|
159
144
|
logger_1.uiLogger.log(' ');
|
|
160
145
|
}
|
|
161
146
|
// 6. Ask user if they want to upload the project
|
|
@@ -217,7 +202,7 @@ async function handler(args) {
|
|
|
217
202
|
targetAccountId: derivedAccountId,
|
|
218
203
|
env: env,
|
|
219
204
|
appId: lastCreatedApp.id,
|
|
220
|
-
}), { url: true });
|
|
205
|
+
}) + '&tourId=get-started', { url: true });
|
|
221
206
|
logger_1.uiLogger.log(' ');
|
|
222
207
|
logger_1.uiLogger.success(en_1.commands.getStarted.openedDeveloperOverview);
|
|
223
208
|
}
|
package/commands/mcp/setup.js
CHANGED
package/commands/mcp/start.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { CommonArgs, YargsCommandModule } from '../../types/Yargs';
|
|
2
|
-
|
|
2
|
+
interface McpStartArgs extends CommonArgs {
|
|
3
|
+
aiAgent: string;
|
|
4
|
+
}
|
|
5
|
+
declare const mcpStartCommand: YargsCommandModule<unknown, McpStartArgs>;
|
|
3
6
|
export default mcpStartCommand;
|
package/commands/mcp/start.js
CHANGED
|
@@ -24,9 +24,9 @@ async function handler(args) {
|
|
|
24
24
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
25
25
|
}
|
|
26
26
|
(0, usageTracking_1.trackCommandUsage)('mcp-start', {}, args.derivedAccountId);
|
|
27
|
-
await startMcpServer();
|
|
27
|
+
await startMcpServer(args.aiAgent);
|
|
28
28
|
}
|
|
29
|
-
async function startMcpServer() {
|
|
29
|
+
async function startMcpServer(aiAgent) {
|
|
30
30
|
try {
|
|
31
31
|
const serverPath = path_1.default.join(__dirname, '..', '..', 'mcp-server', 'server.js');
|
|
32
32
|
// Check if server file exists
|
|
@@ -36,11 +36,13 @@ async function startMcpServer() {
|
|
|
36
36
|
}
|
|
37
37
|
logger_1.uiLogger.info(en_1.commands.mcp.start.startingServer);
|
|
38
38
|
logger_1.uiLogger.info(en_1.commands.mcp.start.stopInstructions);
|
|
39
|
+
const args = [serverPath];
|
|
39
40
|
// Start the server using ts-node
|
|
40
|
-
const child = (0, child_process_1.spawn)(
|
|
41
|
+
const child = (0, child_process_1.spawn)(`node`, args, {
|
|
41
42
|
stdio: 'inherit',
|
|
42
43
|
env: {
|
|
43
44
|
...process.env,
|
|
45
|
+
HUBSPOT_MCP_AI_AGENT: aiAgent || 'unknown',
|
|
44
46
|
},
|
|
45
47
|
});
|
|
46
48
|
// Handle server process events
|
|
@@ -63,6 +65,9 @@ async function startMcpServer() {
|
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
function startBuilder(yargs) {
|
|
68
|
+
yargs.option('ai-agent', {
|
|
69
|
+
type: 'string',
|
|
70
|
+
});
|
|
66
71
|
return yargs;
|
|
67
72
|
}
|
|
68
73
|
const builder = (0, yargsUtils_1.makeYargsBuilder)(startBuilder, command, describe, {
|
|
@@ -39,8 +39,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
const axios_1 = require("axios");
|
|
40
40
|
const yargs_1 = __importDefault(require("yargs"));
|
|
41
41
|
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
-
const configUtils = __importStar(require("@hubspot/local-dev-lib/config"));
|
|
43
42
|
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
43
|
+
const configUtils = __importStar(require("@hubspot/local-dev-lib/config"));
|
|
44
44
|
const projectApiUtils = __importStar(require("@hubspot/local-dev-lib/api/projects"));
|
|
45
45
|
const ui = __importStar(require("../../../lib/ui"));
|
|
46
46
|
const commonOpts_1 = require("../../../lib/commonOpts");
|
|
@@ -54,7 +54,7 @@ const exitCodes_1 = require("../../../lib/enums/exitCodes");
|
|
|
54
54
|
const exampleProject_json_1 = __importDefault(require("./fixtures/exampleProject.json"));
|
|
55
55
|
const testUtils_1 = require("../../../lib/testUtils");
|
|
56
56
|
const deploy_1 = __importDefault(require("../deploy"));
|
|
57
|
-
|
|
57
|
+
const logger_2 = require("../../../lib/ui/logger");
|
|
58
58
|
vi.mock('@hubspot/local-dev-lib/api/projects');
|
|
59
59
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
60
60
|
vi.mock('../../../lib/commonOpts');
|
|
@@ -65,8 +65,9 @@ vi.mock('../../../lib/projects/buildAndDeploy');
|
|
|
65
65
|
vi.mock('../../../lib/prompts/projectNamePrompt');
|
|
66
66
|
vi.mock('../../../lib/prompts/promptUtils');
|
|
67
67
|
vi.mock('../../../lib/usageTracking');
|
|
68
|
+
vi.mock('../../../lib/ui/logger');
|
|
69
|
+
vi.mock('@hubspot/local-dev-lib/logger');
|
|
68
70
|
vi.spyOn(ui, 'uiLine');
|
|
69
|
-
const uiLinkSpy = vi.spyOn(ui, 'uiLink').mockImplementation(text => text);
|
|
70
71
|
const uiCommandReferenceSpy = vi.spyOn(ui, 'uiCommandReference');
|
|
71
72
|
const uiAccountDescriptionSpy = vi.spyOn(ui, 'uiAccountDescription');
|
|
72
73
|
const getProjectConfigSpy = vi.spyOn(projectUtils, 'getProjectConfig');
|
|
@@ -89,6 +90,7 @@ const conflictsSpy = vi
|
|
|
89
90
|
describe('commands/project/deploy', () => {
|
|
90
91
|
const projectFlag = 'project';
|
|
91
92
|
const buildFlag = 'build';
|
|
93
|
+
const deployLatestBuildFlag = 'deployLatestBuild';
|
|
92
94
|
const profileFlag = 'profile';
|
|
93
95
|
const forceFlag = 'force';
|
|
94
96
|
describe('command', () => {
|
|
@@ -117,6 +119,11 @@ describe('commands/project/deploy', () => {
|
|
|
117
119
|
alias: ['build-id'],
|
|
118
120
|
type: 'number',
|
|
119
121
|
}),
|
|
122
|
+
[deployLatestBuildFlag]: expect.objectContaining({
|
|
123
|
+
type: 'boolean',
|
|
124
|
+
alias: ['deploy-latest-build'],
|
|
125
|
+
default: false,
|
|
126
|
+
}),
|
|
120
127
|
[profileFlag]: expect.objectContaining({
|
|
121
128
|
type: 'string',
|
|
122
129
|
alias: ['p'],
|
|
@@ -133,6 +140,8 @@ describe('commands/project/deploy', () => {
|
|
|
133
140
|
expect(commonOpts_1.addAccountOptions).toHaveBeenCalledWith(yargs_1.default);
|
|
134
141
|
expect(commonOpts_1.addUseEnvironmentOptions).toHaveBeenCalledTimes(1);
|
|
135
142
|
expect(commonOpts_1.addUseEnvironmentOptions).toHaveBeenCalledWith(yargs_1.default);
|
|
143
|
+
expect(commonOpts_1.addJSONOutputOptions).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(commonOpts_1.addJSONOutputOptions).toHaveBeenCalledWith(yargs_1.default);
|
|
136
145
|
});
|
|
137
146
|
it('should provide examples', () => {
|
|
138
147
|
deploy_1.default.builder(yargs_1.default);
|
|
@@ -146,9 +155,9 @@ describe('commands/project/deploy', () => {
|
|
|
146
155
|
const projectNameFromPrompt = 'project name from prompt';
|
|
147
156
|
const deployDetails = {
|
|
148
157
|
id: 123,
|
|
158
|
+
buildResultType: 'DEPLOY_QUEUED',
|
|
149
159
|
};
|
|
150
160
|
const projectDetailUrl = 'http://project-details-page-url.com';
|
|
151
|
-
const viewProjectsInHubSpot = 'View project builds in HubSpot';
|
|
152
161
|
beforeEach(() => {
|
|
153
162
|
args = {
|
|
154
163
|
project: 'project name from options',
|
|
@@ -168,9 +177,6 @@ describe('commands/project/deploy', () => {
|
|
|
168
177
|
projectName: projectNameFromPrompt,
|
|
169
178
|
});
|
|
170
179
|
getProjectDetailUrlSpy.mockReturnValue(projectDetailUrl);
|
|
171
|
-
uiLinkSpy.mockImplementation(text => {
|
|
172
|
-
return text;
|
|
173
|
-
});
|
|
174
180
|
getAccountConfigSpy.mockReturnValue({ accountType, env: 'qa' });
|
|
175
181
|
fetchProjectSpy.mockReturnValue((0, testUtils_1.mockHubSpotHttpResponse)(exampleProject_json_1.default));
|
|
176
182
|
deployProjectSpy.mockReturnValue((0, testUtils_1.mockHubSpotHttpResponse)(deployDetails));
|
|
@@ -233,28 +239,24 @@ describe('commands/project/deploy', () => {
|
|
|
233
239
|
it('should log an error and exit when latest build is not defined', async () => {
|
|
234
240
|
fetchProjectSpy.mockReturnValue((0, testUtils_1.mockHubSpotHttpResponse)({}));
|
|
235
241
|
await deploy_1.default.handler(args);
|
|
236
|
-
expect(
|
|
237
|
-
expect(
|
|
242
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
243
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith('Deploy error: no builds for this project were found.');
|
|
238
244
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
239
245
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
240
246
|
});
|
|
241
247
|
it('should log an error and exit when buildId option is not a valid build', async () => {
|
|
242
248
|
args.buildId = exampleProject_json_1.default.latestBuild.buildId + 1;
|
|
243
249
|
await deploy_1.default.handler(args);
|
|
244
|
-
expect(
|
|
245
|
-
expect(
|
|
246
|
-
expect(logger_1.logger.error).toHaveBeenCalledTimes(1);
|
|
247
|
-
expect(logger_1.logger.error).toHaveBeenCalledWith(`Build ${args.buildId} does not exist for project ${projectNameFromPrompt}. ${viewProjectsInHubSpot}`);
|
|
250
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
251
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(`Build ${args.buildId} does not exist for project`));
|
|
248
252
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
249
253
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
250
254
|
});
|
|
251
255
|
it('should log an error and exit when buildId option is already deployed', async () => {
|
|
252
256
|
args.buildId = exampleProject_json_1.default.deployedBuildId;
|
|
253
257
|
await deploy_1.default.handler(args);
|
|
254
|
-
expect(
|
|
255
|
-
expect(
|
|
256
|
-
expect(logger_1.logger.error).toHaveBeenCalledTimes(1);
|
|
257
|
-
expect(logger_1.logger.error).toHaveBeenCalledWith(`Build ${args.buildId} is already deployed. ${viewProjectsInHubSpot}`);
|
|
258
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
259
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(`Build ${args.buildId} is already deployed. View project builds in HubSpot.`));
|
|
258
260
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
259
261
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
260
262
|
});
|
|
@@ -271,8 +273,8 @@ describe('commands/project/deploy', () => {
|
|
|
271
273
|
promptUserSpy.mockResolvedValue({});
|
|
272
274
|
await deploy_1.default.handler(args);
|
|
273
275
|
expect(promptUserSpy).toHaveBeenCalledTimes(1);
|
|
274
|
-
expect(
|
|
275
|
-
expect(
|
|
276
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
277
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith('You must specify a build to deploy');
|
|
276
278
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
277
279
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
278
280
|
});
|
|
@@ -285,8 +287,8 @@ describe('commands/project/deploy', () => {
|
|
|
285
287
|
// @ts-expect-error Testing an edge case where the response is empty
|
|
286
288
|
deployProjectSpy.mockResolvedValue({});
|
|
287
289
|
await deploy_1.default.handler(args);
|
|
288
|
-
expect(
|
|
289
|
-
expect(
|
|
290
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
291
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith(`Deploy error: an unknown error occurred.`);
|
|
290
292
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
291
293
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
292
294
|
});
|
|
@@ -307,8 +309,8 @@ describe('commands/project/deploy', () => {
|
|
|
307
309
|
});
|
|
308
310
|
});
|
|
309
311
|
await deploy_1.default.handler(args);
|
|
310
|
-
expect(
|
|
311
|
-
expect(
|
|
312
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
313
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith(`The project ${chalk_1.default.bold(projectNameFromPrompt)} does not exist in account ${accountDescription}. Run ${commandReference} to upload your project files to HubSpot.`);
|
|
312
314
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
313
315
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
314
316
|
});
|
|
@@ -321,8 +323,8 @@ describe('commands/project/deploy', () => {
|
|
|
321
323
|
});
|
|
322
324
|
});
|
|
323
325
|
await deploy_1.default.handler(args);
|
|
324
|
-
expect(
|
|
325
|
-
expect(
|
|
326
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledTimes(1);
|
|
327
|
+
expect(logger_2.uiLogger.error).toHaveBeenCalledWith('The request was bad.');
|
|
326
328
|
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
327
329
|
expect(processExitSpy).toHaveBeenCalledWith(exitCodes_1.EXIT_CODES.ERROR);
|
|
328
330
|
});
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const path_1 = __importDefault(require("path"));
|
|
7
7
|
const config_1 = require("@hubspot/local-dev-lib/constants/config");
|
|
8
8
|
const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
|
|
9
|
+
// import { HsProfileFile } from '@hubspot/project-parsing-lib/src/lib/types';
|
|
9
10
|
const config_2 = require("@hubspot/local-dev-lib/config");
|
|
10
11
|
const environment_1 = require("@hubspot/local-dev-lib/environment");
|
|
11
12
|
const errorHandlers_1 = require("../../../lib/errorHandlers");
|
|
@@ -69,9 +70,9 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
69
70
|
const mockProjectDir = '/test/project';
|
|
70
71
|
const mockTargetProjectAccountId = 123;
|
|
71
72
|
const mockProvidedTargetTestingAccountId = 456;
|
|
72
|
-
const mockProfileConfig = {
|
|
73
|
-
|
|
74
|
-
};
|
|
73
|
+
// const mockProfileConfig: HsProfileFile = {
|
|
74
|
+
// accountId: 789,
|
|
75
|
+
// };
|
|
75
76
|
const mockAccountConfig = {
|
|
76
77
|
accountId: 123,
|
|
77
78
|
name: 'test-account',
|
|
@@ -157,18 +158,21 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
157
158
|
expect(mockLocalDevWatcher.start).toHaveBeenCalled();
|
|
158
159
|
expect(mockWebsocketServer.start).toHaveBeenCalled();
|
|
159
160
|
});
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
161
|
+
// TODO: Restore test once we've switched back to using profile account for testing
|
|
162
|
+
// it('should complete successfully with profile config', async () => {
|
|
163
|
+
// await unifiedProjectDevFlow({
|
|
164
|
+
// args: mockArgs,
|
|
165
|
+
// targetProjectAccountId: mockTargetProjectAccountId,
|
|
166
|
+
// projectConfig: mockProjectConfig,
|
|
167
|
+
// projectDir: mockProjectDir,
|
|
168
|
+
// profileConfig: mockProfileConfig,
|
|
169
|
+
// });
|
|
170
|
+
// expect(LocalDevProcess).toHaveBeenCalledWith(
|
|
171
|
+
// expect.objectContaining({
|
|
172
|
+
// targetTestingAccountId: mockProfileConfig.accountId,
|
|
173
|
+
// })
|
|
174
|
+
// );
|
|
175
|
+
// });
|
|
172
176
|
it('should use target project account as testing account when it is a test account', async () => {
|
|
173
177
|
accountTypes_1.isTestAccountOrSandbox.mockReturnValue(true);
|
|
174
178
|
await (0, unifiedFlow_1.unifiedProjectDevFlow)({
|
|
@@ -258,7 +262,7 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
258
262
|
projectConfig: mockProjectConfig,
|
|
259
263
|
projectDir: mockProjectDir,
|
|
260
264
|
});
|
|
261
|
-
expect(helpers_1.createDeveloperTestAccountForLocalDev).toHaveBeenCalledWith(mockTargetProjectAccountId, mockAccountConfig, environments_1.ENVIRONMENTS.PROD);
|
|
265
|
+
expect(helpers_1.createDeveloperTestAccountForLocalDev).toHaveBeenCalledWith(mockTargetProjectAccountId, mockAccountConfig, environments_1.ENVIRONMENTS.PROD, true);
|
|
262
266
|
expect(LocalDevProcess_1.default).toHaveBeenCalledWith(expect.objectContaining({
|
|
263
267
|
targetTestingAccountId: 999,
|
|
264
268
|
}));
|
|
@@ -68,7 +68,7 @@ async function handler(args) {
|
|
|
68
68
|
await (0, github_1.cloneGithubRepo)(repo, projectDest, {
|
|
69
69
|
sourceDir: selectProjectTemplatePromptResponse.projectTemplate?.path || components,
|
|
70
70
|
hideLogs: true,
|
|
71
|
-
branch:
|
|
71
|
+
branch: constants_1.DEFAULT_PROJECT_TEMPLATE_BRANCH,
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
catch (err) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule } from '../../types/Yargs';
|
|
2
|
-
export type ProjectDeployArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
1
|
+
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs';
|
|
2
|
+
export type ProjectDeployArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
|
|
3
3
|
project?: string;
|
|
4
4
|
build?: number;
|
|
5
5
|
buildId?: number;
|
|
6
6
|
profile?: string;
|
|
7
|
+
deployLatestBuild: boolean;
|
|
7
8
|
force: boolean;
|
|
8
9
|
};
|
|
9
10
|
declare const projectDeployCommand: YargsCommandModule<unknown, ProjectDeployArgs>;
|