@hubspot/cli 8.12.0 → 8.13.0-beta.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/config/set.js +24 -5
- package/commands/customObject/createSchema.js +2 -3
- package/commands/customObject/updateSchema.js +2 -3
- package/commands/hubdb/list.js +7 -8
- package/commands/project/listBuilds.d.ts +1 -1
- package/commands/project/listBuilds.js +8 -6
- package/commands/project/logs.js +2 -4
- package/commands/project/release/list.js +1 -1
- package/commands/sandbox/delete.js +2 -3
- package/lang/en.d.ts +17 -5
- package/lang/en.js +19 -6
- package/lib/app/urls.js +2 -3
- package/lib/configOptions.d.ts +10 -10
- package/lib/configOptions.js +10 -11
- package/lib/dependencyManagement.js +7 -7
- package/lib/importData.js +3 -4
- package/lib/links.js +6 -5
- package/lib/mcp/clients.d.ts +1 -1
- package/lib/mcp/clients.js +8 -1
- package/lib/mcp/setup.d.ts +3 -3
- package/lib/mcp/setup.js +87 -18
- package/lib/npm/npmCli.d.ts +1 -0
- package/lib/npm/npmCli.js +13 -0
- package/lib/projects/urls.d.ts +0 -1
- package/lib/projects/urls.js +6 -13
- package/mcp-server/tools/project/DocsSearchTool.js +7 -12
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +2 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +7 -11
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +2 -1
- package/mcp-server/tools/project/GetApplicationInfoTool.js +10 -12
- package/mcp-server/tools/project/GetBuildLogsTool.js +9 -11
- package/mcp-server/tools/project/GetBuildStatusTool.js +9 -11
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +2 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +7 -11
- package/mcp-server/utils/config.js +5 -0
- package/mcp-server/utils/toolUsageTracking.js +10 -2
- package/package.json +4 -4
package/commands/config/set.js
CHANGED
|
@@ -2,6 +2,7 @@ import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
|
2
2
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
3
3
|
import { setDefaultCmsPublishMode, setHttpTimeout, setAllowUsageTracking, setAllowAutoUpdates, setAutoOpenBrowser, } from '../../lib/configOptions.js';
|
|
4
4
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
5
|
+
import { trackCommandMetadataUsage } from '../../lib/usageTracking.js';
|
|
5
6
|
import { commands } from '../../lang/en.js';
|
|
6
7
|
import { makeYargsBuilder, strictEnforceBoolean, } from '../../lib/yargsUtils.js';
|
|
7
8
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
@@ -30,21 +31,39 @@ async function selectOptions() {
|
|
|
30
31
|
}
|
|
31
32
|
async function handleConfigUpdate(accountId, args) {
|
|
32
33
|
const { allowAutoUpdates, allowUsageTracking, defaultCmsPublishMode, httpTimeout, autoOpenBrowser, } = args;
|
|
34
|
+
// Emit one metadata event per setting so each field:value pair surfaces as its
|
|
35
|
+
// own entry in Amplitude instead of a combined string that fragments the charts.
|
|
36
|
+
const trackingRequests = [];
|
|
37
|
+
const trackAction = (action) => {
|
|
38
|
+
trackingRequests.push(trackCommandMetadataUsage('config-set', { action }, accountId));
|
|
39
|
+
};
|
|
33
40
|
if (allowAutoUpdates !== undefined) {
|
|
34
|
-
await setAllowAutoUpdates({ allowAutoUpdates, accountId });
|
|
41
|
+
const value = await setAllowAutoUpdates({ allowAutoUpdates, accountId });
|
|
42
|
+
trackAction(`allowAutoUpdates:${value}`);
|
|
35
43
|
}
|
|
36
44
|
if (allowUsageTracking !== undefined) {
|
|
37
|
-
await setAllowUsageTracking({
|
|
45
|
+
const value = await setAllowUsageTracking({
|
|
46
|
+
allowUsageTracking,
|
|
47
|
+
accountId,
|
|
48
|
+
});
|
|
49
|
+
trackAction(`allowUsageTracking:${value}`);
|
|
38
50
|
}
|
|
39
51
|
if (autoOpenBrowser !== undefined) {
|
|
40
|
-
await setAutoOpenBrowser({ autoOpenBrowser, accountId });
|
|
52
|
+
const value = await setAutoOpenBrowser({ autoOpenBrowser, accountId });
|
|
53
|
+
trackAction(`autoOpenBrowser:${value}`);
|
|
41
54
|
}
|
|
42
55
|
if (defaultCmsPublishMode !== undefined) {
|
|
43
|
-
await setDefaultCmsPublishMode({
|
|
56
|
+
const value = await setDefaultCmsPublishMode({
|
|
57
|
+
defaultCmsPublishMode,
|
|
58
|
+
accountId,
|
|
59
|
+
});
|
|
60
|
+
trackAction(`defaultCmsPublishMode:${value}`);
|
|
44
61
|
}
|
|
45
62
|
if (httpTimeout !== undefined) {
|
|
46
|
-
await setHttpTimeout({ httpTimeout, accountId });
|
|
63
|
+
const value = await setHttpTimeout({ httpTimeout, accountId });
|
|
64
|
+
trackAction(`httpTimeout:${value}`);
|
|
47
65
|
}
|
|
66
|
+
await Promise.all(trackingRequests);
|
|
48
67
|
}
|
|
49
68
|
async function handler(args) {
|
|
50
69
|
const { derivedAccountId, allowAutoUpdates, allowUsageTracking, defaultCmsPublishMode, httpTimeout, autoOpenBrowser, exit, } = args;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
2
|
-
import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
|
|
3
2
|
import { getAbsoluteFilePath } from '@hubspot/local-dev-lib/path';
|
|
4
3
|
import { createObjectSchema } from '@hubspot/local-dev-lib/api/customObjects';
|
|
5
|
-
import {
|
|
4
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
6
5
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
7
6
|
import { checkAndConvertToJson } from '../../lib/validation.js';
|
|
8
7
|
import { commands } from '../../lang/en.js';
|
|
@@ -22,7 +21,7 @@ async function handler(args) {
|
|
|
22
21
|
}
|
|
23
22
|
try {
|
|
24
23
|
const { data } = await createObjectSchema(derivedAccountId, schemaJson);
|
|
25
|
-
uiLogger.success(commands.customObject.subcommands.createSchema.success.schemaViewable(`${
|
|
24
|
+
uiLogger.success(commands.customObject.subcommands.createSchema.success.schemaViewable(`${getHubSpotWebsiteOriginByAccountId(derivedAccountId)}/contacts/${derivedAccountId}/objects/${data.objectTypeId}`));
|
|
26
25
|
}
|
|
27
26
|
catch (e) {
|
|
28
27
|
logError(e, { accountId: derivedAccountId });
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { fetchObjectSchemas, updateObjectSchema, } from '@hubspot/local-dev-lib/api/customObjects';
|
|
2
2
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
3
3
|
import { getAbsoluteFilePath } from '@hubspot/local-dev-lib/path';
|
|
4
|
-
import {
|
|
5
|
-
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
4
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
6
5
|
import { listPrompt } from '../../lib/prompts/promptUtils.js';
|
|
7
6
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
8
7
|
import { checkAndConvertToJson } from '../../lib/validation.js';
|
|
@@ -32,7 +31,7 @@ async function handler(args) {
|
|
|
32
31
|
choices: schemaNames,
|
|
33
32
|
});
|
|
34
33
|
const { data } = await updateObjectSchema(derivedAccountId, name, schemaJson);
|
|
35
|
-
uiLogger.success(commands.customObject.subcommands.updateSchema.success.viewAtUrl(`${
|
|
34
|
+
uiLogger.success(commands.customObject.subcommands.updateSchema.success.viewAtUrl(`${getHubSpotWebsiteOriginByAccountId(derivedAccountId)}/contacts/${derivedAccountId}/objects/${data.objectTypeId}`));
|
|
36
35
|
}
|
|
37
36
|
catch (e) {
|
|
38
37
|
logError(e, { accountId: derivedAccountId });
|
package/commands/hubdb/list.js
CHANGED
|
@@ -2,11 +2,12 @@ import { fetchTables } from '@hubspot/local-dev-lib/api/hubdb';
|
|
|
2
2
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
3
3
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
4
4
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
5
|
+
import { uiLine } from '../../lib/ui/index.js';
|
|
5
6
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
6
7
|
import { commands } from '../../lang/en.js';
|
|
7
8
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
8
9
|
import { renderTable } from '../../ui/render.js';
|
|
9
|
-
import {
|
|
10
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
10
11
|
const command = ['list', 'ls'];
|
|
11
12
|
const describe = commands.hubdb.subcommands.list.describe;
|
|
12
13
|
async function getTableData(accountId) {
|
|
@@ -44,22 +45,20 @@ async function handler(args) {
|
|
|
44
45
|
commands.hubdb.subcommands.list.labels.rows,
|
|
45
46
|
];
|
|
46
47
|
uiLogger.success(commands.hubdb.subcommands.list.success(derivedAccountId));
|
|
47
|
-
uiLogger.log(' ');
|
|
48
|
-
// link devs to the hubdb page in hubspot for easy access
|
|
49
|
-
const baseUrl = getBaseHubSpotUrlForAccount(derivedAccountId);
|
|
50
|
-
uiLogger.log(commands.hubdb.subcommands.list.viewTablesLink(baseUrl, derivedAccountId));
|
|
51
48
|
// don't bother showing an empty list of tables
|
|
52
49
|
if (tables.length > 0) {
|
|
50
|
+
uiLogger.log(commands.hubdb.subcommands.list.tables);
|
|
51
|
+
renderTable(tableHeader, tableUIData);
|
|
53
52
|
// if truncated is 0, it will be interpreted as falsy
|
|
54
53
|
const truncated = total - tables.length;
|
|
54
|
+
uiLine();
|
|
55
55
|
uiLogger.log(commands.hubdb.subcommands.list.tablesDisplayed(tables.length, total, truncated));
|
|
56
|
-
uiLogger.log('--------------------------------');
|
|
57
|
-
uiLogger.log(commands.hubdb.subcommands.list.tables);
|
|
58
|
-
renderTable(tableHeader, tableUIData);
|
|
59
56
|
}
|
|
60
57
|
else {
|
|
61
58
|
uiLogger.log(commands.hubdb.subcommands.list.noTables(derivedAccountId));
|
|
62
59
|
}
|
|
60
|
+
// link devs to the hubdb page in hubspot for easy access
|
|
61
|
+
uiLogger.log(commands.hubdb.subcommands.list.viewTablesLink(getHubSpotWebsiteOriginByAccountId(derivedAccountId), derivedAccountId));
|
|
63
62
|
return exit(EXIT_CODES.SUCCESS);
|
|
64
63
|
}
|
|
65
64
|
function hubdbListBuilder(yargs) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
-
type ProjectListBuildsArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
2
|
+
export type ProjectListBuildsArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
3
3
|
project?: string;
|
|
4
4
|
limit?: number;
|
|
5
5
|
};
|
|
@@ -17,12 +17,6 @@ const describe = commands.project.listBuilds.describe;
|
|
|
17
17
|
async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
18
18
|
const { data: { results, paging }, } = await fetchProjectBuilds(accountId, project.name, options);
|
|
19
19
|
const currentDeploy = project.deployedBuildId;
|
|
20
|
-
if (options && options.after) {
|
|
21
|
-
uiLogger.log(commands.project.listBuilds.showingNextBuilds(results.length, project.name));
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
uiLogger.log(commands.project.listBuilds.showingRecentBuilds(results.length, project.name, uiLink(commands.project.listBuilds.viewAllBuildsLink, getProjectDetailUrl(project.name, accountId))));
|
|
25
|
-
}
|
|
26
20
|
if (results.length === 0) {
|
|
27
21
|
uiLogger.log(commands.project.listBuilds.errors.noBuilds);
|
|
28
22
|
}
|
|
@@ -46,6 +40,14 @@ async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
|
46
40
|
});
|
|
47
41
|
renderTable(['Build ID', 'Status', 'Completed', 'Duration', 'Details'], builds);
|
|
48
42
|
}
|
|
43
|
+
if (options && options.after) {
|
|
44
|
+
if (results.length > 0) {
|
|
45
|
+
uiLogger.log(commands.project.listBuilds.showingNextBuilds(results.length, project.name));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
uiLogger.log(commands.project.listBuilds.showingRecentBuilds(results.length, project.name, uiLink(commands.project.listBuilds.viewAllBuildsLink, getProjectDetailUrl(project.name, accountId))));
|
|
50
|
+
}
|
|
49
51
|
if (paging && paging.next) {
|
|
50
52
|
await promptUser({
|
|
51
53
|
name: 'more',
|
package/commands/project/logs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
1
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
3
2
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
4
3
|
import { uiLine } from '../../lib/ui/index.js';
|
|
5
4
|
import { projectLogsPrompt } from '../../lib/prompts/projectsLogsPrompt.js';
|
|
@@ -11,8 +10,7 @@ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler
|
|
|
11
10
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
12
11
|
import { renderTable } from '../../ui/render.js';
|
|
13
12
|
function getPrivateAppsUrl(accountId) {
|
|
14
|
-
|
|
15
|
-
return `${baseUrl}/private-apps/${accountId}`;
|
|
13
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/private-apps/${accountId}`;
|
|
16
14
|
}
|
|
17
15
|
function logPreamble() {
|
|
18
16
|
if (ProjectLogsManager.isPublicFunction) {
|
|
@@ -18,7 +18,6 @@ const describe = undefined;
|
|
|
18
18
|
const verboseDescribe = undefined;
|
|
19
19
|
async function fetchAndDisplayReleases(accountId, projectName, options) {
|
|
20
20
|
const { data: { results, paging }, } = await listReleases(accountId, projectName, options);
|
|
21
|
-
uiLogger.log(commands.project.release.list.showingReleases(results.length, projectName));
|
|
22
21
|
if (results.length === 0) {
|
|
23
22
|
uiLogger.log(commands.project.release.list.noReleases);
|
|
24
23
|
}
|
|
@@ -29,6 +28,7 @@ async function fetchAndDisplayReleases(accountId, projectName, options) {
|
|
|
29
28
|
new Date(release.createdAt).toLocaleString(),
|
|
30
29
|
]);
|
|
31
30
|
renderTable(['Release', 'Build', 'Created'], rows);
|
|
31
|
+
uiLogger.log(commands.project.release.list.showingReleases(results.length, projectName));
|
|
32
32
|
}
|
|
33
33
|
if (paging?.next?.after) {
|
|
34
34
|
await promptUser({
|
|
@@ -2,8 +2,7 @@ import { uiLogger } from '../../lib/ui/logger.js';
|
|
|
2
2
|
import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
|
|
3
3
|
import { deleteSandbox } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
4
4
|
import { getConfigAccountEnvironment, removeAccountFromConfig, setConfigAccountAsDefault, getAllConfigAccounts, getConfigAccountIfExists, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
5
|
-
import {
|
|
6
|
-
import { getValidEnv } from '@hubspot/local-dev-lib/environment';
|
|
5
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
7
6
|
import { logError, debugError } from '../../lib/errorHandlers/index.js';
|
|
8
7
|
import { commands } from '../../lang/en.js';
|
|
9
8
|
import { deleteSandboxPrompt } from '../../lib/prompts/sandboxesPrompt.js';
|
|
@@ -43,7 +42,7 @@ async function handler(args) {
|
|
|
43
42
|
const sandboxAccountId = sandboxAccount.accountId;
|
|
44
43
|
const defaultAccount = getConfigDefaultAccountIfExists();
|
|
45
44
|
const isDefaultAccount = sandboxAccountId === defaultAccount?.accountId;
|
|
46
|
-
const baseUrl =
|
|
45
|
+
const baseUrl = getHubSpotWebsiteOriginByAccountId(sandboxAccountId);
|
|
47
46
|
let parentAccountId;
|
|
48
47
|
const accountsList = getAllConfigAccounts() || [];
|
|
49
48
|
for (const portal of accountsList) {
|
package/lang/en.d.ts
CHANGED
|
@@ -1325,9 +1325,11 @@ export declare const commands: {
|
|
|
1325
1325
|
codex: string;
|
|
1326
1326
|
claudeCode: string;
|
|
1327
1327
|
cursor: string;
|
|
1328
|
+
devin: string;
|
|
1328
1329
|
gemini: string;
|
|
1329
|
-
|
|
1330
|
+
opencode: string;
|
|
1330
1331
|
vsCode: string;
|
|
1332
|
+
other: string;
|
|
1331
1333
|
args: {
|
|
1332
1334
|
client: string;
|
|
1333
1335
|
standalone: string;
|
|
@@ -1362,15 +1364,25 @@ export declare const commands: {
|
|
|
1362
1364
|
geminiNotFound: string;
|
|
1363
1365
|
geminiInstallFailed: string;
|
|
1364
1366
|
alreadyInstalled: string;
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1367
|
+
configuringDevin: string;
|
|
1368
|
+
devinNotFound: string;
|
|
1369
|
+
failedToConfigureDevin: string;
|
|
1370
|
+
configuredDevin: string;
|
|
1371
|
+
configuringOpenCode: string;
|
|
1372
|
+
openCodeNotFound: string;
|
|
1373
|
+
openCodeInstallFailed: string;
|
|
1374
|
+
configuredOpenCode: string;
|
|
1369
1375
|
configuringVsCode: string;
|
|
1370
1376
|
failedToConfigureVsCode: string;
|
|
1371
1377
|
configuredVsCode: string;
|
|
1372
1378
|
vsCodeNotFound: string;
|
|
1373
1379
|
};
|
|
1380
|
+
otherInstructions: {
|
|
1381
|
+
header: string;
|
|
1382
|
+
docsNote: string;
|
|
1383
|
+
commandLabel: string;
|
|
1384
|
+
jsonLabel: string;
|
|
1385
|
+
};
|
|
1374
1386
|
prompts: {
|
|
1375
1387
|
targets: string;
|
|
1376
1388
|
targetsRequired: string;
|
package/lang/en.js
CHANGED
|
@@ -1334,9 +1334,11 @@ export const commands = {
|
|
|
1334
1334
|
codex: 'Codex CLI',
|
|
1335
1335
|
claudeCode: 'Claude Code',
|
|
1336
1336
|
cursor: 'Cursor',
|
|
1337
|
+
devin: 'Devin',
|
|
1337
1338
|
gemini: 'Gemini CLI',
|
|
1338
|
-
|
|
1339
|
+
opencode: 'OpenCode',
|
|
1339
1340
|
vsCode: 'VSCode',
|
|
1341
|
+
other: 'Other (manual setup)',
|
|
1340
1342
|
args: {
|
|
1341
1343
|
client: 'Target apps to configure',
|
|
1342
1344
|
standalone: 'Use npx for all of the hs commands run by the MCP server. This allows you to use the MCP server without having the CLI globally installed.',
|
|
@@ -1375,17 +1377,28 @@ export const commands = {
|
|
|
1375
1377
|
geminiNotFound: "Gemini CLI is not installed (missing 'gemini' command). Install it and re-run hs mcp setup.",
|
|
1376
1378
|
geminiInstallFailed: 'Failed to configure Gemini CLI',
|
|
1377
1379
|
alreadyInstalled: 'HubSpot CLI mcp server already installed, reinstalling',
|
|
1378
|
-
//
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1380
|
+
// Devin
|
|
1381
|
+
configuringDevin: 'Configuring Devin...',
|
|
1382
|
+
devinNotFound: 'Devin is not installed. Install it and re-run hs mcp setup.',
|
|
1383
|
+
failedToConfigureDevin: 'Failed to configure Devin',
|
|
1384
|
+
configuredDevin: 'Configured Devin',
|
|
1385
|
+
// OpenCode
|
|
1386
|
+
configuringOpenCode: 'Configuring OpenCode...',
|
|
1387
|
+
openCodeNotFound: "OpenCode is not installed (missing 'opencode' command). Install it and re-run hs mcp setup.",
|
|
1388
|
+
openCodeInstallFailed: 'Failed to configure OpenCode',
|
|
1389
|
+
configuredOpenCode: 'Configured OpenCode',
|
|
1383
1390
|
// VS Code
|
|
1384
1391
|
configuringVsCode: 'Configuring VSCode...',
|
|
1385
1392
|
failedToConfigureVsCode: 'Failed to configure VSCode',
|
|
1386
1393
|
configuredVsCode: 'Configured VSCode',
|
|
1387
1394
|
vsCodeNotFound: "VSCode CLI is not installed (missing 'code' command). Install it and re-run hs mcp setup.",
|
|
1388
1395
|
},
|
|
1396
|
+
otherInstructions: {
|
|
1397
|
+
header: 'To connect the HubSpot MCP server to another tool, add the following MCP server configuration.',
|
|
1398
|
+
docsNote: "Each tool handles MCP setup differently. Check your tool's documentation for how to add an MCP server using a command or JSON config.",
|
|
1399
|
+
commandLabel: 'Command:',
|
|
1400
|
+
jsonLabel: 'JSON configuration (for tools that use a config file):',
|
|
1401
|
+
},
|
|
1389
1402
|
prompts: {
|
|
1390
1403
|
targets: '[--client] Which tools would you like to add the HubSpot CLI MCP server to?',
|
|
1391
1404
|
targetsRequired: 'Must choose at least one app to configure.',
|
package/lib/app/urls.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
2
|
-
import { getBaseHubSpotUrlForAccount } from '../projects/urls.js';
|
|
1
|
+
import { getHubSpotWebsiteOrigin, getHubSpotWebsiteOriginByAccountId, } from '@hubspot/local-dev-lib/urls';
|
|
3
2
|
export function getOauthAppInstallUrl({ targetAccountId, env, clientId, scopes, redirectUrls, }) {
|
|
4
3
|
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
5
4
|
return (`${websiteOrigin}/oauth/${targetAccountId}/authorize` +
|
|
@@ -16,7 +15,7 @@ export function getAppCardSetupUrl({ targetAccountId, env, appId, }) {
|
|
|
16
15
|
return `${websiteOrigin}/integrations-settings/${targetAccountId}/installed/framework/${appId}/app-cards?tourId=get-started`;
|
|
17
16
|
}
|
|
18
17
|
export function getAppLogsUrl(accountId, appId, systemType) {
|
|
19
|
-
return `${
|
|
18
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/developer-monitoring/${accountId}/?logType=${systemType}&appId=${appId}`;
|
|
20
19
|
}
|
|
21
20
|
export function getAppLogDetailsUrl(accountId, appId, systemType, logId) {
|
|
22
21
|
return `${getAppLogsUrl(accountId, appId, systemType)}&logId=${logId}`;
|
package/lib/configOptions.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { CmsPublishMode } from '@hubspot/local-dev-lib/types/Files';
|
|
2
|
-
export declare function setAllowUsageTracking({
|
|
2
|
+
export declare function setAllowUsageTracking({ allowUsageTracking, }: {
|
|
3
3
|
accountId: number;
|
|
4
4
|
allowUsageTracking?: boolean;
|
|
5
|
-
}): Promise<
|
|
6
|
-
export declare function setAllowAutoUpdates({
|
|
5
|
+
}): Promise<boolean>;
|
|
6
|
+
export declare function setAllowAutoUpdates({ allowAutoUpdates, }: {
|
|
7
7
|
accountId: number;
|
|
8
8
|
allowAutoUpdates?: boolean;
|
|
9
|
-
}): Promise<
|
|
10
|
-
export declare function setDefaultCmsPublishMode({
|
|
9
|
+
}): Promise<boolean>;
|
|
10
|
+
export declare function setDefaultCmsPublishMode({ defaultCmsPublishMode, }: {
|
|
11
11
|
accountId: number;
|
|
12
12
|
defaultCmsPublishMode?: CmsPublishMode;
|
|
13
|
-
}): Promise<
|
|
14
|
-
export declare function setHttpTimeout({
|
|
13
|
+
}): Promise<CmsPublishMode>;
|
|
14
|
+
export declare function setHttpTimeout({ httpTimeout, }: {
|
|
15
15
|
accountId: number;
|
|
16
16
|
httpTimeout?: string;
|
|
17
|
-
}): Promise<
|
|
18
|
-
export declare function setAutoOpenBrowser({
|
|
17
|
+
}): Promise<string>;
|
|
18
|
+
export declare function setAutoOpenBrowser({ autoOpenBrowser, }: {
|
|
19
19
|
accountId: number;
|
|
20
20
|
autoOpenBrowser: boolean;
|
|
21
|
-
}): Promise<
|
|
21
|
+
}): Promise<boolean>;
|
package/lib/configOptions.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { updateAllowUsageTracking, updateAllowAutoUpdates, updateDefaultCmsPublishMode, updateHttpTimeout, updateAutoOpenBrowser, } from '@hubspot/local-dev-lib/config';
|
|
2
2
|
import { CMS_PUBLISH_MODE } from '@hubspot/local-dev-lib/constants/files';
|
|
3
3
|
import { commaSeparatedValues } from '@hubspot/local-dev-lib/text';
|
|
4
|
-
import { trackCommandUsage } from './usageTracking.js';
|
|
5
4
|
import { promptUser, listPrompt } from './prompts/promptUtils.js';
|
|
6
5
|
import { lib } from '../lang/en.js';
|
|
7
6
|
import { uiLogger } from './ui/logger.js';
|
|
@@ -23,8 +22,7 @@ async function enableOrDisableBooleanFieldPrompt(fieldName) {
|
|
|
23
22
|
});
|
|
24
23
|
return isEnabled;
|
|
25
24
|
}
|
|
26
|
-
export async function setAllowUsageTracking({
|
|
27
|
-
trackCommandUsage('config-set-allow-usage-tracking', undefined, accountId);
|
|
25
|
+
export async function setAllowUsageTracking({ allowUsageTracking, }) {
|
|
28
26
|
let isEnabled;
|
|
29
27
|
if (typeof allowUsageTracking === 'boolean') {
|
|
30
28
|
isEnabled = allowUsageTracking;
|
|
@@ -34,9 +32,9 @@ export async function setAllowUsageTracking({ accountId, allowUsageTracking, })
|
|
|
34
32
|
}
|
|
35
33
|
updateAllowUsageTracking(isEnabled);
|
|
36
34
|
uiLogger.success(lib.configOptions.setAllowUsageTracking.success(isEnabled.toString()));
|
|
35
|
+
return isEnabled;
|
|
37
36
|
}
|
|
38
|
-
export async function setAllowAutoUpdates({
|
|
39
|
-
trackCommandUsage('config-set-allow-auto-updates', undefined, accountId);
|
|
37
|
+
export async function setAllowAutoUpdates({ allowAutoUpdates, }) {
|
|
40
38
|
let isEnabled;
|
|
41
39
|
if (typeof allowAutoUpdates === 'boolean') {
|
|
42
40
|
isEnabled = allowAutoUpdates;
|
|
@@ -46,6 +44,7 @@ export async function setAllowAutoUpdates({ accountId, allowAutoUpdates, }) {
|
|
|
46
44
|
}
|
|
47
45
|
updateAllowAutoUpdates(isEnabled);
|
|
48
46
|
uiLogger.success(lib.configOptions.setAllowAutoUpdates.success(isEnabled.toString()));
|
|
47
|
+
return isEnabled;
|
|
49
48
|
}
|
|
50
49
|
const ALL_CMS_PUBLISH_MODES = Object.values(CMS_PUBLISH_MODE);
|
|
51
50
|
async function selectCmsPublishMode() {
|
|
@@ -55,8 +54,7 @@ async function selectCmsPublishMode() {
|
|
|
55
54
|
});
|
|
56
55
|
return cmsPublishMode;
|
|
57
56
|
}
|
|
58
|
-
export async function setDefaultCmsPublishMode({
|
|
59
|
-
trackCommandUsage('config-set-default-mode', undefined, accountId);
|
|
57
|
+
export async function setDefaultCmsPublishMode({ defaultCmsPublishMode, }) {
|
|
60
58
|
let newDefault;
|
|
61
59
|
if (!defaultCmsPublishMode) {
|
|
62
60
|
newDefault = await selectCmsPublishMode();
|
|
@@ -71,6 +69,7 @@ export async function setDefaultCmsPublishMode({ accountId, defaultCmsPublishMod
|
|
|
71
69
|
}
|
|
72
70
|
updateDefaultCmsPublishMode(newDefault);
|
|
73
71
|
uiLogger.success(lib.configOptions.setDefaultCmsPublishMode.success(newDefault));
|
|
72
|
+
return newDefault;
|
|
74
73
|
}
|
|
75
74
|
async function enterTimeout() {
|
|
76
75
|
const { timeout } = await promptUser([
|
|
@@ -90,8 +89,7 @@ async function enterTimeout() {
|
|
|
90
89
|
]);
|
|
91
90
|
return timeout;
|
|
92
91
|
}
|
|
93
|
-
export async function setHttpTimeout({
|
|
94
|
-
trackCommandUsage('config-set-http-timeout', undefined, accountId);
|
|
92
|
+
export async function setHttpTimeout({ httpTimeout, }) {
|
|
95
93
|
let newHttpTimeout;
|
|
96
94
|
if (!httpTimeout) {
|
|
97
95
|
newHttpTimeout = await enterTimeout();
|
|
@@ -101,11 +99,12 @@ export async function setHttpTimeout({ accountId, httpTimeout, }) {
|
|
|
101
99
|
}
|
|
102
100
|
updateHttpTimeout(newHttpTimeout);
|
|
103
101
|
uiLogger.success(lib.configOptions.setHttpTimeout.success(newHttpTimeout));
|
|
102
|
+
return newHttpTimeout;
|
|
104
103
|
}
|
|
105
|
-
export async function setAutoOpenBrowser({
|
|
106
|
-
trackCommandUsage('config-set-auto-open-browser', undefined, accountId);
|
|
104
|
+
export async function setAutoOpenBrowser({ autoOpenBrowser, }) {
|
|
107
105
|
updateAutoOpenBrowser(autoOpenBrowser);
|
|
108
106
|
uiLogger.success(autoOpenBrowser
|
|
109
107
|
? lib.configOptions.setAutoOpenBrowser.enabled
|
|
110
108
|
: lib.configOptions.setAutoOpenBrowser.disabled);
|
|
109
|
+
return autoOpenBrowser;
|
|
111
110
|
}
|
|
@@ -5,7 +5,7 @@ import { exec as execAsync } from 'node:child_process';
|
|
|
5
5
|
import { getProjectConfig } from './projects/config.js';
|
|
6
6
|
import { commands } from '../lang/en.js';
|
|
7
7
|
import SpinniesManager from './ui/SpinniesManager.js';
|
|
8
|
-
import { isGloballyInstalled, executeInstall, executeUpdate, DEFAULT_PACKAGE_MANAGER, } from './npm/npmCli.js';
|
|
8
|
+
import { isGloballyInstalled, executeInstall, executeUpdate, getNpmExecErrorOutput, DEFAULT_PACKAGE_MANAGER, } from './npm/npmCli.js';
|
|
9
9
|
import { findAllPackageJsonFilesInProjectCached, safeGetPackageJsonCached, } from './npm/packageJson.js';
|
|
10
10
|
import { getNpmWorkspaceDirectoryForPackageAtLocationCached } from './npm/workspaces.js';
|
|
11
11
|
class NoPackageJsonFilesError extends Error {
|
|
@@ -106,9 +106,9 @@ async function installPackagesInDirectory({ directory, packages, dev = false, np
|
|
|
106
106
|
SpinniesManager.fail(spinner, {
|
|
107
107
|
text: commands.project.installDeps.installingDependenciesFailed(relativeDir),
|
|
108
108
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
const npmErrorOutput = getNpmExecErrorOutput(e);
|
|
110
|
+
throw new Error(npmErrorOutput ||
|
|
111
|
+
commands.project.installDeps.installingDependenciesFailed(relativeDir), npmErrorOutput ? undefined : { cause: e });
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
export async function updatePackages({ packages, installLocations, }) {
|
|
@@ -176,9 +176,9 @@ async function updatePackagesInDirectory({ directory, packages, npmWorkspaceDire
|
|
|
176
176
|
SpinniesManager.fail(spinner, {
|
|
177
177
|
text: commands.project.updateDeps.updatingDependenciesFailed(relativeDir),
|
|
178
178
|
});
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
const npmErrorOutput = getNpmExecErrorOutput(e);
|
|
180
|
+
throw new Error(npmErrorOutput ||
|
|
181
|
+
commands.project.updateDeps.updatingDependenciesFailed(relativeDir), npmErrorOutput ? undefined : { cause: e });
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
export async function getProjectPackageJsonLocations(dir, isUpdate = false) {
|
package/lib/importData.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { getConfigAccountById,
|
|
1
|
+
import { getConfigAccountById, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
2
2
|
import { createImport } from '@hubspot/local-dev-lib/api/crm';
|
|
3
|
-
import {
|
|
3
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
4
4
|
import { importDataTestAccountSelectPrompt } from './prompts/importDataTestAccountSelectPrompt.js';
|
|
5
5
|
import { lib } from '../lang/en.js';
|
|
6
6
|
import { isAppDeveloperAccount, isDeveloperTestAccount, isStandardAccount, } from './accountTypes.js';
|
|
7
7
|
import { uiLogger } from './ui/logger.js';
|
|
8
8
|
export async function handleImportData(targetAccountId, dataFileNames, importRequest) {
|
|
9
9
|
try {
|
|
10
|
-
const baseUrl = getHubSpotWebsiteOrigin(getConfigAccountEnvironment(targetAccountId));
|
|
11
10
|
const response = await createImport(targetAccountId, importRequest, dataFileNames);
|
|
12
11
|
const importId = response.data.id;
|
|
13
|
-
uiLogger.info(lib.importData.viewImportLink(
|
|
12
|
+
uiLogger.info(lib.importData.viewImportLink(getHubSpotWebsiteOriginByAccountId(targetAccountId), targetAccountId, importId));
|
|
14
13
|
}
|
|
15
14
|
catch (error) {
|
|
16
15
|
uiLogger.error(lib.importData.errors.failedToImportData);
|
package/lib/links.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import open from 'open';
|
|
2
|
-
import {
|
|
3
|
-
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
2
|
+
import { getHubSpotWebsiteOrigin, getHubSpotWebsiteOriginByAccountId, } from '@hubspot/local-dev-lib/urls';
|
|
4
3
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
5
4
|
import { uiLogger } from './ui/logger.js';
|
|
6
5
|
import { renderTable } from '../ui/render.js';
|
|
@@ -75,7 +74,7 @@ const COMMON_SITE_LINKS = {
|
|
|
75
74
|
},
|
|
76
75
|
};
|
|
77
76
|
export function getSiteLinksAsArray(accountId) {
|
|
78
|
-
const baseUrl =
|
|
77
|
+
const baseUrl = getHubSpotWebsiteOriginByAccountId(accountId);
|
|
79
78
|
return Object.values(COMMON_SITE_LINKS)
|
|
80
79
|
.sort((a, b) => (a.shortcut < b.shortcut ? -1 : 1))
|
|
81
80
|
.map(l => ({ ...l, url: l.getUrl(accountId, baseUrl) }));
|
|
@@ -94,12 +93,14 @@ export function openLink(accountId, shortcut) {
|
|
|
94
93
|
uiLogger.error(`We couldn't find a shortcut matching ${shortcut}. Type 'hs open list' to see a list of available shortcuts`);
|
|
95
94
|
return;
|
|
96
95
|
}
|
|
97
|
-
const baseUrl =
|
|
96
|
+
const baseUrl = getHubSpotWebsiteOriginByAccountId(accountId);
|
|
98
97
|
open(match.getUrl(accountId, baseUrl), { url: true });
|
|
99
98
|
uiLogger.success(`We opened ${match.getUrl(accountId, baseUrl)} in your browser`);
|
|
100
99
|
}
|
|
101
100
|
export function getProductUpdatesUrl(rolloutId, accountId) {
|
|
102
|
-
const baseUrl =
|
|
101
|
+
const baseUrl = accountId
|
|
102
|
+
? getHubSpotWebsiteOriginByAccountId(accountId)
|
|
103
|
+
: getHubSpotWebsiteOrigin(ENVIRONMENTS.PROD);
|
|
103
104
|
if (accountId) {
|
|
104
105
|
return `${baseUrl}/product-updates/${accountId}/in-beta?rollout=${rolloutId}`;
|
|
105
106
|
}
|
package/lib/mcp/clients.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const MCP_SERVER_NAME = "HubSpotDev";
|
|
2
|
-
export type McpClientId = 'codex' | 'claude' | 'cursor' | 'gemini' | '
|
|
2
|
+
export type McpClientId = 'codex' | 'claude' | 'cursor' | 'devin' | 'gemini' | 'opencode' | 'vscode';
|
|
3
3
|
type McpClientDetection = {
|
|
4
4
|
type: 'json' | 'text';
|
|
5
5
|
pathSegments: string[];
|
package/lib/mcp/clients.js
CHANGED
|
@@ -39,12 +39,19 @@ export const MCP_CLIENTS = [
|
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
id: '
|
|
42
|
+
id: 'devin',
|
|
43
43
|
detection: {
|
|
44
44
|
type: 'json',
|
|
45
45
|
pathSegments: ['.codeium', 'windsurf', 'mcp_config.json'],
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
|
+
{
|
|
49
|
+
id: 'opencode',
|
|
50
|
+
detection: {
|
|
51
|
+
type: 'json',
|
|
52
|
+
pathSegments: ['.config', 'opencode', 'config.json'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
48
55
|
];
|
|
49
56
|
export function getMcpClientPathSegments(id) {
|
|
50
57
|
const client = MCP_CLIENTS.find(c => c.id === id);
|
package/lib/mcp/setup.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { McpClientId } from './clients.js';
|
|
2
1
|
export declare const supportedTools: {
|
|
3
2
|
name: string;
|
|
4
|
-
value:
|
|
3
|
+
value: string;
|
|
5
4
|
}[];
|
|
6
5
|
interface McpCommand {
|
|
7
6
|
command: string;
|
|
@@ -17,7 +16,8 @@ export declare function configureMcpServer(options: ConfigureMcpServerOptions):
|
|
|
17
16
|
export declare function setupVsCode(mcpCommand?: McpCommand): Promise<boolean>;
|
|
18
17
|
export declare function setupClaudeCode(mcpCommand?: McpCommand): Promise<boolean>;
|
|
19
18
|
export declare function setupCursor(mcpCommand?: McpCommand): boolean;
|
|
20
|
-
export declare function
|
|
19
|
+
export declare function setupDevin(mcpCommand?: McpCommand): boolean;
|
|
21
20
|
export declare function setupCodex(mcpCommand?: McpCommand): Promise<boolean>;
|
|
22
21
|
export declare function setupGemini(mcpCommand?: McpCommand): Promise<boolean>;
|
|
22
|
+
export declare function setupOpenCode(mcpCommand?: McpCommand): Promise<boolean>;
|
|
23
23
|
export {};
|
package/lib/mcp/setup.js
CHANGED
|
@@ -11,23 +11,29 @@ import fs from 'fs-extra';
|
|
|
11
11
|
import { existsSync } from 'fs';
|
|
12
12
|
const mcpServerName = MCP_SERVER_NAME;
|
|
13
13
|
const claudeCode = 'claude';
|
|
14
|
-
const windsurf = 'windsurf';
|
|
15
14
|
const cursor = 'cursor';
|
|
15
|
+
const devin = 'devin';
|
|
16
16
|
const vscode = 'vscode';
|
|
17
17
|
const codex = 'codex';
|
|
18
18
|
const gemini = 'gemini';
|
|
19
|
+
const opencode = 'opencode';
|
|
20
|
+
const OTHER_TOOL = 'other';
|
|
19
21
|
const clientLabels = {
|
|
20
22
|
codex: commands.mcp.setup.codex,
|
|
21
23
|
claude: commands.mcp.setup.claudeCode,
|
|
22
24
|
cursor: commands.mcp.setup.cursor,
|
|
25
|
+
devin: commands.mcp.setup.devin,
|
|
23
26
|
gemini: commands.mcp.setup.gemini,
|
|
27
|
+
opencode: commands.mcp.setup.opencode,
|
|
24
28
|
vscode: commands.mcp.setup.vsCode,
|
|
25
|
-
windsurf: commands.mcp.setup.windsurf,
|
|
26
29
|
};
|
|
27
|
-
export const supportedTools =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
export const supportedTools = [
|
|
31
|
+
...MCP_CLIENTS.map(client => ({
|
|
32
|
+
name: clientLabels[client.id],
|
|
33
|
+
value: client.id,
|
|
34
|
+
})),
|
|
35
|
+
{ name: commands.mcp.setup.other, value: OTHER_TOOL },
|
|
36
|
+
];
|
|
31
37
|
const defaultMcpCommand = {
|
|
32
38
|
command: 'hs',
|
|
33
39
|
args: ['mcp', 'start'],
|
|
@@ -42,6 +48,7 @@ export async function configureMcpServer(options) {
|
|
|
42
48
|
type: 'checkbox',
|
|
43
49
|
message: commands.mcp.setup.prompts.targets,
|
|
44
50
|
choices: supportedTools,
|
|
51
|
+
pageSize: supportedTools.length,
|
|
45
52
|
validate: (choices) => {
|
|
46
53
|
return choices.length === 0
|
|
47
54
|
? commands.mcp.setup.prompts.targetsRequired
|
|
@@ -53,7 +60,8 @@ export async function configureMcpServer(options) {
|
|
|
53
60
|
else {
|
|
54
61
|
derivedTargets = targets;
|
|
55
62
|
}
|
|
56
|
-
|
|
63
|
+
const onlyOther = derivedTargets.length === 1 && derivedTargets[0] === OTHER_TOOL;
|
|
64
|
+
let useStandaloneMode = onlyOther ? false : standalone;
|
|
57
65
|
if (useStandaloneMode === undefined) {
|
|
58
66
|
const response = await promptUser({
|
|
59
67
|
name: 'useStandaloneMode',
|
|
@@ -102,8 +110,8 @@ export async function configureMcpServer(options) {
|
|
|
102
110
|
if (derivedTargets.includes(cursor)) {
|
|
103
111
|
await runSetupFunction(() => setupCursor(mcpCommand));
|
|
104
112
|
}
|
|
105
|
-
if (derivedTargets.includes(
|
|
106
|
-
await runSetupFunction(() =>
|
|
113
|
+
if (derivedTargets.includes(devin)) {
|
|
114
|
+
await runSetupFunction(() => setupDevin(mcpCommand));
|
|
107
115
|
}
|
|
108
116
|
if (derivedTargets.includes(vscode)) {
|
|
109
117
|
await runSetupFunction(() => setupVsCode(mcpCommand));
|
|
@@ -114,8 +122,17 @@ export async function configureMcpServer(options) {
|
|
|
114
122
|
if (derivedTargets.includes(gemini)) {
|
|
115
123
|
await runSetupFunction(() => setupGemini(mcpCommand));
|
|
116
124
|
}
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
if (derivedTargets.includes(opencode)) {
|
|
126
|
+
await runSetupFunction(() => setupOpenCode(mcpCommand));
|
|
127
|
+
}
|
|
128
|
+
if (derivedTargets.includes(OTHER_TOOL)) {
|
|
129
|
+
logOtherToolInstructions(mcpCommand);
|
|
130
|
+
}
|
|
131
|
+
const configuredTargets = derivedTargets.filter(t => t !== OTHER_TOOL);
|
|
132
|
+
if (configuredTargets.length > 0) {
|
|
133
|
+
uiLogger.info(commands.mcp.setup.success(configuredTargets));
|
|
134
|
+
}
|
|
135
|
+
return configuredTargets;
|
|
119
136
|
}
|
|
120
137
|
catch (error) {
|
|
121
138
|
SpinniesManager.fail('mcpSetup', {
|
|
@@ -272,14 +289,14 @@ export function setupCursor(mcpCommand = defaultMcpCommand) {
|
|
|
272
289
|
mcpCommand: buildCommandWithAgentString(mcpCommand, cursor),
|
|
273
290
|
});
|
|
274
291
|
}
|
|
275
|
-
export function
|
|
276
|
-
const
|
|
292
|
+
export function setupDevin(mcpCommand = defaultMcpCommand) {
|
|
293
|
+
const devinConfigPath = path.join(os.homedir(), ...getMcpClientPathSegments(devin));
|
|
277
294
|
return setupMcpConfigFile({
|
|
278
|
-
configPath:
|
|
279
|
-
configuringMessage: commands.mcp.setup.spinners.
|
|
280
|
-
configuredMessage: commands.mcp.setup.spinners.
|
|
281
|
-
failedMessage: commands.mcp.setup.spinners.
|
|
282
|
-
mcpCommand: buildCommandWithAgentString(mcpCommand,
|
|
295
|
+
configPath: devinConfigPath,
|
|
296
|
+
configuringMessage: commands.mcp.setup.spinners.configuringDevin,
|
|
297
|
+
configuredMessage: commands.mcp.setup.spinners.configuredDevin,
|
|
298
|
+
failedMessage: commands.mcp.setup.spinners.failedToConfigureDevin,
|
|
299
|
+
mcpCommand: buildCommandWithAgentString(mcpCommand, devin),
|
|
283
300
|
});
|
|
284
301
|
}
|
|
285
302
|
export async function setupCodex(mcpCommand = defaultMcpCommand) {
|
|
@@ -341,6 +358,58 @@ export async function setupGemini(mcpCommand = defaultMcpCommand) {
|
|
|
341
358
|
return false;
|
|
342
359
|
}
|
|
343
360
|
}
|
|
361
|
+
export async function setupOpenCode(mcpCommand = defaultMcpCommand) {
|
|
362
|
+
try {
|
|
363
|
+
SpinniesManager.add('openCodeSpinner', {
|
|
364
|
+
text: commands.mcp.setup.spinners.configuringOpenCode,
|
|
365
|
+
});
|
|
366
|
+
try {
|
|
367
|
+
await execAsync('opencode --version');
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
SpinniesManager.fail('openCodeSpinner', {
|
|
371
|
+
text: commands.mcp.setup.spinners.openCodeNotFound,
|
|
372
|
+
});
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, opencode);
|
|
376
|
+
await execAsync(`opencode mcp add "${mcpServerName}"${buildEnvFlagString(mcpCommand)} -- ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
|
|
377
|
+
SpinniesManager.succeed('openCodeSpinner', {
|
|
378
|
+
text: commands.mcp.setup.spinners.configuredOpenCode,
|
|
379
|
+
});
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
SpinniesManager.fail('openCodeSpinner', {
|
|
384
|
+
text: commands.mcp.setup.spinners.openCodeInstallFailed,
|
|
385
|
+
});
|
|
386
|
+
logError(error);
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function logOtherToolInstructions(mcpCommand) {
|
|
391
|
+
const { otherInstructions } = commands.mcp.setup;
|
|
392
|
+
uiLogger.log('');
|
|
393
|
+
uiLogger.log(otherInstructions.header);
|
|
394
|
+
uiLogger.log(otherInstructions.docsNote);
|
|
395
|
+
uiLogger.log('');
|
|
396
|
+
uiLogger.log(` ${otherInstructions.commandLabel}`);
|
|
397
|
+
uiLogger.log(` ${mcpCommand.command} ${mcpCommand.args.join(' ')}`);
|
|
398
|
+
uiLogger.log('');
|
|
399
|
+
uiLogger.log(` ${otherInstructions.jsonLabel}`);
|
|
400
|
+
uiLogger.log('');
|
|
401
|
+
const jsonConfig = {
|
|
402
|
+
mcpServers: {
|
|
403
|
+
[mcpServerName]: mcpCommand,
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
const indented = JSON.stringify(jsonConfig, null, 2)
|
|
407
|
+
.split('\n')
|
|
408
|
+
.map(line => ` ${line}`)
|
|
409
|
+
.join('\n');
|
|
410
|
+
uiLogger.log(indented);
|
|
411
|
+
uiLogger.log('');
|
|
412
|
+
}
|
|
344
413
|
function buildCommandWithAgentString(mcpCommand, agent) {
|
|
345
414
|
const mcpCommandCopy = structuredClone(mcpCommand);
|
|
346
415
|
mcpCommandCopy.args.push('--ai-agent', agent);
|
package/lib/npm/npmCli.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare function getLatestPackageVersion(packageName: string): Promise<{
|
|
|
4
4
|
latest: string | null;
|
|
5
5
|
next: string | null;
|
|
6
6
|
}>;
|
|
7
|
+
export declare function getNpmExecErrorOutput(error: unknown): string | null;
|
|
7
8
|
export declare function executeInstall(packages?: string[], flags?: string | null, options?: {
|
|
8
9
|
cwd?: string;
|
|
9
10
|
}): Promise<void>;
|
package/lib/npm/npmCli.js
CHANGED
|
@@ -23,6 +23,19 @@ export async function getLatestPackageVersion(packageName) {
|
|
|
23
23
|
return { latest: null, next: null };
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
function isNpmExecError(error) {
|
|
27
|
+
return (typeof error === 'object' &&
|
|
28
|
+
error !== null &&
|
|
29
|
+
('stderr' in error || 'stdout' in error));
|
|
30
|
+
}
|
|
31
|
+
export function getNpmExecErrorOutput(error) {
|
|
32
|
+
if (!isNpmExecError(error)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const stderr = error.stderr?.trim();
|
|
36
|
+
const stdout = error.stdout?.trim();
|
|
37
|
+
return stderr || stdout || null;
|
|
38
|
+
}
|
|
26
39
|
export async function executeInstall(packages = [], flags, options) {
|
|
27
40
|
const installCommand = `${DEFAULT_PACKAGE_MANAGER} install${flags ? ` ${flags}` : ''} ${packages.join(' ')}`;
|
|
28
41
|
uiLogger.debug('Running', installCommand);
|
package/lib/projects/urls.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare function getBaseHubSpotUrlForAccount(accountId: number): string;
|
|
2
1
|
export declare function getProjectComponentDistributionUrl(projectName: string, componentName: string, accountId: number): string;
|
|
3
2
|
export declare function getDeveloperOverviewUrl(accountId: number): string;
|
|
4
3
|
export declare function getProjectDetailUrl(projectName: string, accountId: number): string | undefined;
|
package/lib/projects/urls.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
|
|
3
|
-
export function getBaseHubSpotUrlForAccount(accountId) {
|
|
4
|
-
return getHubSpotWebsiteOrigin(getConfigAccountEnvironment(accountId));
|
|
5
|
-
}
|
|
1
|
+
import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
|
|
6
2
|
function getProjectHomeUrl(accountId) {
|
|
7
|
-
return `${
|
|
3
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/developer-projects/${accountId}`;
|
|
8
4
|
}
|
|
9
5
|
export function getProjectComponentDistributionUrl(projectName, componentName, accountId) {
|
|
10
|
-
|
|
11
|
-
return `${baseUrl}/developer-projects/${accountId}/project/${projectName}/component/${componentName}/distribution`;
|
|
6
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/developer-projects/${accountId}/project/${projectName}/component/${componentName}/distribution`;
|
|
12
7
|
}
|
|
13
8
|
export function getDeveloperOverviewUrl(accountId) {
|
|
14
|
-
|
|
15
|
-
return `${baseUrl}/developer-overview/${accountId}`;
|
|
9
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/developer-overview/${accountId}`;
|
|
16
10
|
}
|
|
17
11
|
export function getProjectDetailUrl(projectName, accountId) {
|
|
18
12
|
if (!projectName)
|
|
@@ -34,9 +28,8 @@ export function getProjectDeployDetailUrl(projectName, deployId, accountId) {
|
|
|
34
28
|
return `${getProjectActivityUrl(projectName, accountId)}/deploy/${deployId}`;
|
|
35
29
|
}
|
|
36
30
|
export function getLocalDevUiUrl(accountId, showWelcomeScreen) {
|
|
37
|
-
return `${
|
|
31
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/developer-projects-local-dev/${accountId}${showWelcomeScreen ? '?welcome' : ''}`;
|
|
38
32
|
}
|
|
39
33
|
export function getAccountHomeUrl(accountId) {
|
|
40
|
-
|
|
41
|
-
return `${baseUrl}/home?portalId=${accountId}`;
|
|
34
|
+
return `${getHubSpotWebsiteOriginByAccountId(accountId)}/home?portalId=${accountId}`;
|
|
42
35
|
}
|
|
@@ -4,8 +4,8 @@ import { Tool } from '../../Tool.js';
|
|
|
4
4
|
import { formatTextContents } from '../../utils/content.js';
|
|
5
5
|
import { absoluteCurrentWorkingDirectory, docsSearchQuery, } from './constants.js';
|
|
6
6
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
7
|
-
import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
8
7
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
8
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
9
9
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
10
10
|
const docsSearchLimit = z
|
|
11
11
|
.number()
|
|
@@ -33,18 +33,13 @@ export class DocsSearchTool extends Tool {
|
|
|
33
33
|
}
|
|
34
34
|
async handler({ docsSearchQuery, docsSearchLimit, absoluteCurrentWorkingDirectory, }) {
|
|
35
35
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
36
|
-
let accountId;
|
|
37
|
-
try {
|
|
38
|
-
accountId = getConfigDefaultAccountIfExists()?.accountId;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// Config file does not exist
|
|
42
|
-
}
|
|
43
|
-
if (!accountId) {
|
|
44
|
-
const authErrorMessage = `No account ID found. Call the auth-account tool to authenticate a HubSpot account.`;
|
|
45
|
-
return formatTextContents(authErrorMessage);
|
|
46
|
-
}
|
|
47
36
|
try {
|
|
37
|
+
const { recommended } = await discoverAccountTargets();
|
|
38
|
+
const accountId = recommended?.accountId;
|
|
39
|
+
if (!accountId) {
|
|
40
|
+
const authErrorMessage = `No account ID found. Call the auth-account tool to authenticate a HubSpot account.`;
|
|
41
|
+
return formatTextContents(authErrorMessage);
|
|
42
|
+
}
|
|
48
43
|
const response = await http.post(accountId, {
|
|
49
44
|
url: 'dev/docs/llms/v1/docs-search',
|
|
50
45
|
data: {
|
|
@@ -5,6 +5,7 @@ import { McpLogger } from '../../utils/logger.js';
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
7
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
8
|
+
absoluteProjectPath: z.ZodOptional<z.ZodString>;
|
|
8
9
|
appId: z.ZodString;
|
|
9
10
|
startDate: z.ZodOptional<z.ZodString>;
|
|
10
11
|
endDate: z.ZodOptional<z.ZodString>;
|
|
@@ -12,7 +13,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
12
13
|
export type GetApiUsagePatternsByAppIdInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
13
14
|
export declare class GetApiUsagePatternsByAppIdTool extends Tool<GetApiUsagePatternsByAppIdInputSchema> {
|
|
14
15
|
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
15
|
-
handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }: GetApiUsagePatternsByAppIdInputSchema): Promise<TextContentResponse>;
|
|
16
|
+
handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, absoluteProjectPath, }: GetApiUsagePatternsByAppIdInputSchema): Promise<TextContentResponse>;
|
|
16
17
|
register(): RegisteredTool;
|
|
17
18
|
}
|
|
18
19
|
export {};
|
|
@@ -3,12 +3,13 @@ import { z } from 'zod';
|
|
|
3
3
|
import { http } from '@hubspot/local-dev-lib/http';
|
|
4
4
|
import { formatTextContents } from '../../utils/content.js';
|
|
5
5
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
6
|
-
import {
|
|
7
|
-
import { absoluteCurrentWorkingDirectory } from './constants.js';
|
|
6
|
+
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
|
|
8
7
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
8
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
9
9
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
10
10
|
const inputSchema = {
|
|
11
11
|
absoluteCurrentWorkingDirectory,
|
|
12
|
+
absoluteProjectPath: absoluteProjectPath.optional(),
|
|
12
13
|
appId: z
|
|
13
14
|
.string()
|
|
14
15
|
.describe('The numeric app ID as a string (e.g., "3003909"). Must contain only digits. Use get-apps-info to find available app IDs.'),
|
|
@@ -28,16 +29,11 @@ export class GetApiUsagePatternsByAppIdTool extends Tool {
|
|
|
28
29
|
constructor(mcpServer, logger) {
|
|
29
30
|
super(mcpServer, logger, toolName);
|
|
30
31
|
}
|
|
31
|
-
async handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }) {
|
|
32
|
-
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
32
|
+
async handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, absoluteProjectPath, }) {
|
|
33
|
+
setupHubSpotConfig(absoluteProjectPath ?? absoluteCurrentWorkingDirectory);
|
|
33
34
|
try {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
accountId = getConfigDefaultAccountIfExists()?.accountId;
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
// Config file does not exist
|
|
40
|
-
}
|
|
35
|
+
const { recommended } = await discoverAccountTargets();
|
|
36
|
+
const accountId = recommended?.accountId;
|
|
41
37
|
if (!accountId) {
|
|
42
38
|
const authErrorMessage = `No account ID found. Call the auth-account tool to authenticate a HubSpot account.`;
|
|
43
39
|
return formatTextContents(authErrorMessage);
|
|
@@ -5,11 +5,12 @@ import { McpLogger } from '../../utils/logger.js';
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
7
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
8
|
+
absoluteProjectPath: z.ZodOptional<z.ZodString>;
|
|
8
9
|
}, z.core.$strip>;
|
|
9
10
|
export type GetApplicationInfoInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
10
11
|
export declare class GetApplicationInfoTool extends Tool<GetApplicationInfoInputSchema> {
|
|
11
12
|
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
12
|
-
handler({ absoluteCurrentWorkingDirectory, }: GetApplicationInfoInputSchema): Promise<TextContentResponse>;
|
|
13
|
+
handler({ absoluteCurrentWorkingDirectory, absoluteProjectPath, }: GetApplicationInfoInputSchema): Promise<TextContentResponse>;
|
|
13
14
|
register(): RegisteredTool;
|
|
14
15
|
}
|
|
15
16
|
export {};
|
|
@@ -3,11 +3,14 @@ import { z } from 'zod';
|
|
|
3
3
|
import { http } from '@hubspot/local-dev-lib/http';
|
|
4
4
|
import { formatTextContents } from '../../utils/content.js';
|
|
5
5
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
6
|
-
import {
|
|
7
|
-
import { absoluteCurrentWorkingDirectory } from './constants.js';
|
|
6
|
+
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
|
|
8
7
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
8
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
9
9
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
10
|
-
const inputSchema = {
|
|
10
|
+
const inputSchema = {
|
|
11
|
+
absoluteCurrentWorkingDirectory,
|
|
12
|
+
absoluteProjectPath: absoluteProjectPath.optional(),
|
|
13
|
+
};
|
|
11
14
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
12
15
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
13
16
|
const toolName = 'get-apps-info';
|
|
@@ -15,16 +18,11 @@ export class GetApplicationInfoTool extends Tool {
|
|
|
15
18
|
constructor(mcpServer, logger) {
|
|
16
19
|
super(mcpServer, logger, toolName);
|
|
17
20
|
}
|
|
18
|
-
async handler({ absoluteCurrentWorkingDirectory, }) {
|
|
19
|
-
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
21
|
+
async handler({ absoluteCurrentWorkingDirectory, absoluteProjectPath, }) {
|
|
22
|
+
setupHubSpotConfig(absoluteProjectPath ?? absoluteCurrentWorkingDirectory);
|
|
20
23
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
accountId = getConfigDefaultAccountIfExists()?.accountId;
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
// Config file does not exist
|
|
27
|
-
}
|
|
24
|
+
const { recommended } = await discoverAccountTargets();
|
|
25
|
+
const accountId = recommended?.accountId;
|
|
28
26
|
if (!accountId) {
|
|
29
27
|
const authErrorMessage = `No account ID found. Call the auth-account tool to authenticate a HubSpot account.`;
|
|
30
28
|
return formatTextContents(authErrorMessage);
|
|
@@ -5,8 +5,8 @@ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
|
5
5
|
import { http } from '@hubspot/local-dev-lib/http';
|
|
6
6
|
import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
|
|
7
7
|
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
|
|
8
|
-
import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
9
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
9
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
10
10
|
const TOOL_NAME = 'get-build-logs';
|
|
11
11
|
const PROJECTS_LOGS_API_PATH = 'dfs/logging/v1';
|
|
12
12
|
const inputSchema = {
|
|
@@ -62,20 +62,18 @@ export class GetBuildLogsTool extends Tool {
|
|
|
62
62
|
super(mcpServer, logger, TOOL_NAME);
|
|
63
63
|
}
|
|
64
64
|
async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, logLevel, }) {
|
|
65
|
-
setupHubSpotConfig(
|
|
65
|
+
setupHubSpotConfig(absoluteProjectPath);
|
|
66
66
|
try {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
const { projectConfig, projectDir } = await getProjectConfig(absoluteProjectPath);
|
|
68
|
+
validateProjectConfig(projectConfig, projectDir);
|
|
69
|
+
const { recommended } = await discoverAccountTargets({
|
|
70
|
+
projectDir,
|
|
71
|
+
projectConfig,
|
|
72
|
+
});
|
|
73
|
+
const accountId = recommended?.accountId;
|
|
74
74
|
if (!accountId) {
|
|
75
75
|
return formatTextContents(absoluteCurrentWorkingDirectory, 'No account ID found. Call the auth-account tool to authenticate a HubSpot account.');
|
|
76
76
|
}
|
|
77
|
-
const { projectConfig, projectDir } = await getProjectConfig(absoluteProjectPath);
|
|
78
|
-
validateProjectConfig(projectConfig, projectDir);
|
|
79
77
|
const projectName = projectConfig.name;
|
|
80
78
|
const response = await http.get(accountId, {
|
|
81
79
|
url: `${PROJECTS_LOGS_API_PATH}/logs/projects/${encodeURIComponent(projectName)}/builds/${buildId}`,
|
|
@@ -6,8 +6,8 @@ import { fetchProjectBuilds, getBuildStatus, } from '@hubspot/local-dev-lib/api/
|
|
|
6
6
|
import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
|
|
7
7
|
import moment from 'moment';
|
|
8
8
|
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
|
|
9
|
-
import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
10
9
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
10
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
11
11
|
const TOOL_NAME = 'get-build-status';
|
|
12
12
|
const inputSchema = {
|
|
13
13
|
absoluteProjectPath,
|
|
@@ -107,20 +107,18 @@ export class GetBuildStatusTool extends Tool {
|
|
|
107
107
|
super(mcpServer, logger, TOOL_NAME);
|
|
108
108
|
}
|
|
109
109
|
async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, limit, }) {
|
|
110
|
-
setupHubSpotConfig(
|
|
110
|
+
setupHubSpotConfig(absoluteProjectPath);
|
|
111
111
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
const { projectConfig, projectDir } = await getProjectConfig(absoluteProjectPath);
|
|
113
|
+
validateProjectConfig(projectConfig, projectDir);
|
|
114
|
+
const { recommended } = await discoverAccountTargets({
|
|
115
|
+
projectDir,
|
|
116
|
+
projectConfig,
|
|
117
|
+
});
|
|
118
|
+
const accountId = recommended?.accountId;
|
|
119
119
|
if (!accountId) {
|
|
120
120
|
return formatTextContents(absoluteCurrentWorkingDirectory, 'No account ID found. Call the auth-account tool to authenticate a HubSpot account.');
|
|
121
121
|
}
|
|
122
|
-
const { projectConfig, projectDir } = await getProjectConfig(absoluteProjectPath);
|
|
123
|
-
validateProjectConfig(projectConfig, projectDir);
|
|
124
122
|
const projectName = projectConfig.name;
|
|
125
123
|
let output;
|
|
126
124
|
if (buildId) {
|
|
@@ -5,13 +5,14 @@ import { McpLogger } from '../../utils/logger.js';
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
7
7
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
8
|
+
absoluteProjectPath: z.ZodOptional<z.ZodString>;
|
|
8
9
|
platformVersion: z.ZodString;
|
|
9
10
|
featureType: z.ZodString;
|
|
10
11
|
}, z.core.$strip>;
|
|
11
12
|
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
12
13
|
export declare class GetConfigValuesTool extends Tool<InputSchemaType> {
|
|
13
14
|
constructor(mcpServer: McpServer, logger: McpLogger);
|
|
14
|
-
handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, }: InputSchemaType): Promise<TextContentResponse>;
|
|
15
|
+
handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, absoluteProjectPath, }: InputSchemaType): Promise<TextContentResponse>;
|
|
15
16
|
register(): RegisteredTool;
|
|
16
17
|
}
|
|
17
18
|
export {};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Tool } from '../../Tool.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { formatTextContents } from '../../utils/content.js';
|
|
4
|
-
import { absoluteCurrentWorkingDirectory } from './constants.js';
|
|
4
|
+
import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
|
|
5
5
|
import { getIntermediateRepresentationSchema } from '@hubspot/project-parsing-lib/schema';
|
|
6
6
|
import { mapToInternalType } from '@hubspot/project-parsing-lib/transform';
|
|
7
7
|
import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
|
|
8
|
-
import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
9
8
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
9
|
+
import { discoverAccountTargets } from '../../../lib/accountTargetDiscovery.js';
|
|
10
10
|
const inputSchema = {
|
|
11
11
|
absoluteCurrentWorkingDirectory,
|
|
12
|
+
absoluteProjectPath: absoluteProjectPath.optional(),
|
|
12
13
|
platformVersion: z
|
|
13
14
|
.string()
|
|
14
15
|
.describe('The platform version for the project. Located in the hsproject.json file.'),
|
|
@@ -25,19 +26,14 @@ export class GetConfigValuesTool extends Tool {
|
|
|
25
26
|
constructor(mcpServer, logger) {
|
|
26
27
|
super(mcpServer, logger, toolName);
|
|
27
28
|
}
|
|
28
|
-
async handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, }) {
|
|
29
|
-
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
29
|
+
async handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, absoluteProjectPath, }) {
|
|
30
|
+
setupHubSpotConfig(absoluteProjectPath ?? absoluteCurrentWorkingDirectory);
|
|
30
31
|
try {
|
|
31
32
|
if (isLegacyProject(platformVersion)) {
|
|
32
33
|
return formatTextContents(`Can only be used on projects with a minimum platformVersion of 2025.2`);
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
accountId = getConfigDefaultAccountIfExists()?.accountId;
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
// Config file does not exist
|
|
40
|
-
}
|
|
35
|
+
const { recommended } = await discoverAccountTargets();
|
|
36
|
+
const accountId = recommended?.accountId;
|
|
41
37
|
if (!accountId) {
|
|
42
38
|
const authErrorMessage = `No account ID found. Call the auth-account tool to authenticate a HubSpot account.`;
|
|
43
39
|
return formatTextContents(authErrorMessage);
|
|
@@ -8,4 +8,9 @@ export function setupHubSpotConfig(absoluteCurrentWorkingDirectory) {
|
|
|
8
8
|
if (configPath) {
|
|
9
9
|
process.env.HUBSPOT_CONFIG_PATH = configPath;
|
|
10
10
|
}
|
|
11
|
+
else {
|
|
12
|
+
// Clear any value set by a previous tool call so this call doesn't
|
|
13
|
+
// inherit a stale config path from a different project.
|
|
14
|
+
delete process.env.HUBSPOT_CONFIG_PATH;
|
|
15
|
+
}
|
|
11
16
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventClass, getExecutionEnvironmentMeta, } from '../../lib/usageTracking.js';
|
|
2
|
-
import { getConfig
|
|
2
|
+
import { getConfig } from '@hubspot/local-dev-lib/config';
|
|
3
|
+
import { discoverAccountTargets } from '../../lib/accountTargetDiscovery.js';
|
|
3
4
|
import { sendUsageEvent } from '../../lib/api/usageTracking.js';
|
|
4
5
|
export async function trackToolUsage(toolName, meta) {
|
|
5
6
|
let config;
|
|
@@ -20,7 +21,14 @@ export async function trackToolUsage(toolName, meta) {
|
|
|
20
21
|
...getExecutionEnvironmentMeta(),
|
|
21
22
|
...meta,
|
|
22
23
|
};
|
|
23
|
-
|
|
24
|
+
let accountId;
|
|
25
|
+
try {
|
|
26
|
+
const { recommended } = await discoverAccountTargets();
|
|
27
|
+
accountId = recommended?.accountId;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Account discovery failed; continue without account ID
|
|
31
|
+
}
|
|
24
32
|
try {
|
|
25
33
|
await sendUsageEvent({
|
|
26
34
|
eventName: 'cli-interaction',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.13.0-beta.0",
|
|
4
4
|
"description": "The official CLI for developing on HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "https://github.com/HubSpot/hubspot-cli",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"!**/__tests__/**"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@hubspot/local-dev-lib": "5.10.
|
|
13
|
+
"@hubspot/local-dev-lib": "5.10.2",
|
|
14
14
|
"@hubspot/project-parsing-lib": "0.21.0",
|
|
15
15
|
"@hubspot/serverless-dev-runtime": "7.0.7",
|
|
16
|
-
"@hubspot/ui-extensions-dev-server": "2.0
|
|
16
|
+
"@hubspot/ui-extensions-dev-server": "2.1.0",
|
|
17
17
|
"@inquirer/prompts": "7.1.0",
|
|
18
18
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
19
19
|
"archiver": "7.0.1",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"zod": "^4.4.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@hubspot/npm-scripts": "0.3.
|
|
47
|
+
"@hubspot/npm-scripts": "^0.3.3",
|
|
48
48
|
"@types/archiver": "^6.0.3",
|
|
49
49
|
"@types/cli-progress": "^3.11.6",
|
|
50
50
|
"@types/express": "^5.0.0",
|