@hubspot/cli 8.15.0-beta.1 → 8.15.0-beta.2
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 -1
- package/bin/hs.js +1 -0
- package/bin/hscms.js +1 -0
- package/bin/setupColor.d.ts +2 -0
- package/bin/setupColor.js +10 -0
- package/lang/en.d.ts +2 -0
- package/lang/en.js +2 -0
- package/lib/mcp/setup.js +11 -1
- package/lib/testUtils.d.ts +1 -0
- package/lib/testUtils.js +14 -0
- package/lib/theme/cmsDevServerProcess.js +1 -1
- package/lib/ui/SpinniesManager.d.ts +1 -0
- package/lib/ui/SpinniesManager.js +14 -4
- package/lib/ui/index.js +2 -2
- package/lib/ui/supportsColor.d.ts +4 -0
- package/lib/ui/supportsColor.js +25 -6
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -33,6 +33,7 @@ import mcpCommand from '../commands/mcp.js';
|
|
|
33
33
|
import upgradeCommand from '../commands/upgrade.js';
|
|
34
34
|
import apiCommand from '../commands/api.js';
|
|
35
35
|
import { uiLogger } from '../lib/ui/logger.js';
|
|
36
|
+
import { lib } from '../lang/en.js';
|
|
36
37
|
import { initializeSpinniesManager } from '../lib/middleware/spinniesMiddleware.js';
|
|
37
38
|
import { addCommandSuggestions } from '../lib/commandSuggestion.js';
|
|
38
39
|
import { pkg } from '../lib/jsonLoader.js';
|
|
@@ -80,10 +81,14 @@ const argv = yargs(process.argv.slice(2))
|
|
|
80
81
|
describe: 'prevent hyperlinks from displaying in the ui',
|
|
81
82
|
hidden: true,
|
|
82
83
|
type: 'boolean',
|
|
84
|
+
})
|
|
85
|
+
.option('color', {
|
|
86
|
+
default: true,
|
|
87
|
+
describe: lib.commonOpts.options.color,
|
|
88
|
+
type: 'boolean',
|
|
83
89
|
})
|
|
84
90
|
.option('noColor', {
|
|
85
91
|
default: false,
|
|
86
|
-
describe: 'prevent color from displaying in the ui',
|
|
87
92
|
hidden: true,
|
|
88
93
|
type: 'boolean',
|
|
89
94
|
})
|
package/bin/hs.js
CHANGED
package/bin/hscms.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { hasColorDisableSignal } from '../lib/ui/supportsColor.js';
|
|
3
|
+
// Runs before cli.js so it executes before chalk is imported. chalk reads
|
|
4
|
+
// FORCE_COLOR (but not NO_COLOR / COLOR) once at load and caches its color
|
|
5
|
+
// level, and lang/en.ts bakes chalk styling into strings at import time. So
|
|
6
|
+
// translating a no-color request into FORCE_COLOR=0 here, ahead of those
|
|
7
|
+
// imports, is what makes NO_COLOR / COLOR actually disable color everywhere.
|
|
8
|
+
if (hasColorDisableSignal()) {
|
|
9
|
+
process.env.FORCE_COLOR = '0';
|
|
10
|
+
}
|
package/lang/en.d.ts
CHANGED
|
@@ -1376,6 +1376,7 @@ export declare const commands: {
|
|
|
1376
1376
|
failedToConfigureVsCode: string;
|
|
1377
1377
|
configuredVsCode: string;
|
|
1378
1378
|
vsCodeNotFound: string;
|
|
1379
|
+
vsCodeVersionUnsupported: string;
|
|
1379
1380
|
};
|
|
1380
1381
|
otherInstructions: {
|
|
1381
1382
|
header: string;
|
|
@@ -3838,6 +3839,7 @@ export declare const lib: {
|
|
|
3838
3839
|
jsonOutput: string;
|
|
3839
3840
|
jsonSchema: string;
|
|
3840
3841
|
debug: string;
|
|
3842
|
+
color: string;
|
|
3841
3843
|
};
|
|
3842
3844
|
};
|
|
3843
3845
|
configMigrate: {
|
package/lang/en.js
CHANGED
|
@@ -1392,6 +1392,7 @@ export const commands = {
|
|
|
1392
1392
|
failedToConfigureVsCode: 'Failed to configure VSCode',
|
|
1393
1393
|
configuredVsCode: 'Configured VSCode',
|
|
1394
1394
|
vsCodeNotFound: "VSCode CLI is not installed (missing 'code' command). Install it and re-run hs mcp setup.",
|
|
1395
|
+
vsCodeVersionUnsupported: 'VSCode 1.99 or later is required for MCP server support. Please update VSCode and try again.',
|
|
1395
1396
|
},
|
|
1396
1397
|
otherInstructions: {
|
|
1397
1398
|
header: 'To connect the HubSpot MCP server to another tool, add the following MCP server configuration.',
|
|
@@ -3877,6 +3878,7 @@ export const lib = {
|
|
|
3877
3878
|
jsonOutput: 'Format output as JSON',
|
|
3878
3879
|
jsonSchema: 'Print the JSON output schema and exit',
|
|
3879
3880
|
debug: 'Set log level to debug',
|
|
3881
|
+
color: 'Enable colored output (use --no-color to disable)',
|
|
3880
3882
|
},
|
|
3881
3883
|
},
|
|
3882
3884
|
configMigrate: {
|
package/lib/mcp/setup.js
CHANGED
|
@@ -9,6 +9,7 @@ import path from 'path';
|
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import fs from 'fs-extra';
|
|
11
11
|
import { existsSync } from 'fs';
|
|
12
|
+
import semver from 'semver';
|
|
12
13
|
const mcpServerName = MCP_SERVER_NAME;
|
|
13
14
|
const claudeCode = 'claude';
|
|
14
15
|
const cursor = 'cursor';
|
|
@@ -18,6 +19,7 @@ const codex = 'codex';
|
|
|
18
19
|
const gemini = 'gemini';
|
|
19
20
|
const opencode = 'opencode';
|
|
20
21
|
const OTHER_TOOL = 'other';
|
|
22
|
+
const MINIMUM_VSCODE_VERSION = '1.99.0';
|
|
21
23
|
const clientLabels = {
|
|
22
24
|
codex: commands.mcp.setup.codex,
|
|
23
25
|
claude: commands.mcp.setup.claudeCode,
|
|
@@ -204,11 +206,19 @@ function setupMcpConfigFile(config) {
|
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
208
|
export async function setupVsCode(mcpCommand = defaultMcpCommand) {
|
|
209
|
+
const commandWithAgent = buildCommandWithAgentString(mcpCommand, vscode);
|
|
207
210
|
try {
|
|
208
211
|
SpinniesManager.add('vsCode', {
|
|
209
212
|
text: commands.mcp.setup.spinners.configuringVsCode,
|
|
210
213
|
});
|
|
211
|
-
const
|
|
214
|
+
const { stdout } = await execAsync('code --version');
|
|
215
|
+
const version = stdout.trim().split('\n')[0];
|
|
216
|
+
if (!semver.gte(version, MINIMUM_VSCODE_VERSION)) {
|
|
217
|
+
SpinniesManager.fail('vsCode', {
|
|
218
|
+
text: commands.mcp.setup.spinners.vsCodeVersionUnsupported,
|
|
219
|
+
});
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
212
222
|
const configObject = {
|
|
213
223
|
name: mcpServerName,
|
|
214
224
|
...commandWithAgent,
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ type MockErrorResponse = {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function mockHubSpotHttpResponse<T>(data?: any): HubSpotPromise<T>;
|
|
13
13
|
export declare function mockHubSpotHttpError(message: string, response: MockErrorResponse): HubSpotHttpError;
|
|
14
|
+
export declare function stubColorEnv(): void;
|
|
14
15
|
export {};
|
package/lib/testUtils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
1
2
|
import { HubSpotHttpError } from '@hubspot/local-dev-lib/models/HubSpotHttpError';
|
|
2
3
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3
4
|
export function mockHubSpotHttpResponse(data) {
|
|
@@ -16,3 +17,16 @@ export function mockHubSpotHttpError(message, response) {
|
|
|
16
17
|
cause: { isAxiosError: true, response },
|
|
17
18
|
});
|
|
18
19
|
}
|
|
20
|
+
// Stubs the color-detection env to a color-capable interactive baseline.
|
|
21
|
+
// Call vi.unstubAllEnvs() in afterEach to restore.
|
|
22
|
+
export function stubColorEnv() {
|
|
23
|
+
[
|
|
24
|
+
'CI',
|
|
25
|
+
'NO_COLOR',
|
|
26
|
+
'COLOR',
|
|
27
|
+
'FORCE_COLOR',
|
|
28
|
+
'COLORTERM',
|
|
29
|
+
'TERM_PROGRAM',
|
|
30
|
+
].forEach(key => vi.stubEnv(key, undefined));
|
|
31
|
+
vi.stubEnv('TERM', 'xterm-256color');
|
|
32
|
+
}
|
|
@@ -10,7 +10,7 @@ import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
const __dirname = path.dirname(__filename);
|
|
12
12
|
// cms-dev-server version to install to isolated cache
|
|
13
|
-
const TARGET_CMS_DEV_SERVER_VERSION = '1.2.
|
|
13
|
+
const TARGET_CMS_DEV_SERVER_VERSION = '1.2.70';
|
|
14
14
|
/**
|
|
15
15
|
* Ensures cms-dev-server is installed in an isolated cache directory.
|
|
16
16
|
* This prevents React version conflicts with the CLI.
|
|
@@ -12,6 +12,7 @@ import chalk from 'chalk';
|
|
|
12
12
|
import cliCursor from 'cli-cursor';
|
|
13
13
|
import { breakText, cleanStream, colorOptions, getLinesLength, prefixOptions, purgeSpinnerOptions, purgeSpinnersOptions, SPINNERS, writeStream, } from './spinniesUtils.js';
|
|
14
14
|
import { isUnicodeSupported } from '@hubspot/local-dev-lib/isUnicodeSupported';
|
|
15
|
+
import { hasColorDisableSignal } from './supportsColor.js';
|
|
15
16
|
import { uiLogger } from './logger.js';
|
|
16
17
|
function safeColor(text, color) {
|
|
17
18
|
const chalkFn = chalk[color];
|
|
@@ -31,6 +32,7 @@ class SpinniesManager {
|
|
|
31
32
|
currentFrameIndex = 0;
|
|
32
33
|
spin;
|
|
33
34
|
sigintHandler = null;
|
|
35
|
+
rawOutputCache = {};
|
|
34
36
|
constructor() {
|
|
35
37
|
this.resetState();
|
|
36
38
|
}
|
|
@@ -46,8 +48,8 @@ class SpinniesManager {
|
|
|
46
48
|
this.spin =
|
|
47
49
|
!this.options.disableSpins &&
|
|
48
50
|
!process.env.CI &&
|
|
49
|
-
|
|
50
|
-
process.stderr
|
|
51
|
+
!hasColorDisableSignal() &&
|
|
52
|
+
Boolean(process.stderr?.isTTY);
|
|
51
53
|
if (!this.hasAnySpinners()) {
|
|
52
54
|
this.resetState();
|
|
53
55
|
}
|
|
@@ -64,6 +66,7 @@ class SpinniesManager {
|
|
|
64
66
|
this.stream = process.stderr;
|
|
65
67
|
this.lineCount = 0;
|
|
66
68
|
this.currentFrameIndex = 0;
|
|
69
|
+
this.rawOutputCache = {};
|
|
67
70
|
}
|
|
68
71
|
setDisableOutput(disableOutput) {
|
|
69
72
|
this.disableOutput = disableOutput;
|
|
@@ -105,6 +108,7 @@ class SpinniesManager {
|
|
|
105
108
|
return;
|
|
106
109
|
}
|
|
107
110
|
delete this.spinners[name];
|
|
111
|
+
delete this.rawOutputCache[name];
|
|
108
112
|
// Update the spinner state to clean up the deleted spinner
|
|
109
113
|
this.updateSpinnerState();
|
|
110
114
|
}
|
|
@@ -230,8 +234,13 @@ class SpinniesManager {
|
|
|
230
234
|
this.lineCount = linesLength.length;
|
|
231
235
|
}
|
|
232
236
|
setRawStreamOutput() {
|
|
233
|
-
Object.
|
|
234
|
-
|
|
237
|
+
Object.entries(this.spinners).forEach(([name, spinner]) => {
|
|
238
|
+
const line = `- ${spinner.text ?? ''}\n`;
|
|
239
|
+
if (this.rawOutputCache[name] === line) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.rawOutputCache[name] = line;
|
|
243
|
+
process.stderr.write(line);
|
|
235
244
|
});
|
|
236
245
|
}
|
|
237
246
|
checkIfActiveSpinners() {
|
|
@@ -246,6 +255,7 @@ class SpinniesManager {
|
|
|
246
255
|
cliCursor.show();
|
|
247
256
|
}
|
|
248
257
|
this.spinners = {};
|
|
258
|
+
this.rawOutputCache = {};
|
|
249
259
|
}
|
|
250
260
|
}
|
|
251
261
|
bindSigint() {
|
package/lib/ui/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { getConfigAccountIfExists, globalConfigFileExists, } from '@hubspot/local-dev-lib/config';
|
|
3
3
|
import { uiLogger } from './logger.js';
|
|
4
4
|
import { supportsHyperlinkModule } from './supportHyperlinks.js';
|
|
5
|
-
import {
|
|
5
|
+
import { isColorEnabled } from './supportsColor.js';
|
|
6
6
|
import { uiMessages } from './uiMessages.js';
|
|
7
7
|
import { HUBSPOT_ACCOUNT_TYPE_STRINGS } from '@hubspot/local-dev-lib/constants/config';
|
|
8
8
|
export const UI_COLORS = {
|
|
@@ -16,7 +16,7 @@ export function uiLine() {
|
|
|
16
16
|
export function getTerminalUISupport() {
|
|
17
17
|
return {
|
|
18
18
|
hyperlinks: supportsHyperlinkModule.stdout,
|
|
19
|
-
color:
|
|
19
|
+
color: isColorEnabled(),
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
export function uiLink(linkText, url) {
|
|
@@ -4,6 +4,7 @@ interface ColorSupportLevel {
|
|
|
4
4
|
has256: boolean;
|
|
5
5
|
has16m: boolean;
|
|
6
6
|
}
|
|
7
|
+
export declare function hasColorDisableSignal(): boolean;
|
|
7
8
|
declare function createSupportsColor(stream: {
|
|
8
9
|
isTTY?: boolean;
|
|
9
10
|
} | null, options?: {
|
|
@@ -14,4 +15,7 @@ export declare const supportsColor: {
|
|
|
14
15
|
stdout: ColorSupportLevel;
|
|
15
16
|
stderr: ColorSupportLevel;
|
|
16
17
|
};
|
|
18
|
+
export declare function isColorEnabled(stream?: {
|
|
19
|
+
isTTY?: boolean;
|
|
20
|
+
} | null): boolean;
|
|
17
21
|
export {};
|
package/lib/ui/supportsColor.js
CHANGED
|
@@ -19,17 +19,29 @@ function translateLevel(level) {
|
|
|
19
19
|
has16m: level >= 3,
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
+
function resolveColorPreference() {
|
|
23
|
+
const { NO_COLOR, COLOR, FORCE_COLOR, TERM } = env;
|
|
24
|
+
if (hasFlag('no-color') || hasFlag('noColor'))
|
|
25
|
+
return 'never';
|
|
26
|
+
if (NO_COLOR)
|
|
27
|
+
return 'never';
|
|
28
|
+
if (COLOR === 'false' || COLOR === '0')
|
|
29
|
+
return 'never';
|
|
30
|
+
if (FORCE_COLOR !== undefined) {
|
|
31
|
+
return FORCE_COLOR === '0' || FORCE_COLOR === 'false' ? 'never' : 'always';
|
|
32
|
+
}
|
|
33
|
+
if (TERM === 'dumb')
|
|
34
|
+
return 'never';
|
|
35
|
+
return 'auto';
|
|
36
|
+
}
|
|
37
|
+
export function hasColorDisableSignal() {
|
|
38
|
+
return resolveColorPreference() === 'never';
|
|
39
|
+
}
|
|
22
40
|
function _supportsColor(haveStream, { streamIsTTY } = {}) {
|
|
23
41
|
if (haveStream && !streamIsTTY) {
|
|
24
42
|
return 0;
|
|
25
43
|
}
|
|
26
44
|
const min = 0;
|
|
27
|
-
if (env.TERM === 'dumb') {
|
|
28
|
-
return min;
|
|
29
|
-
}
|
|
30
|
-
if (hasFlag('noColor')) {
|
|
31
|
-
return 0;
|
|
32
|
-
}
|
|
33
45
|
if (process.platform === 'win32') {
|
|
34
46
|
// Windows 10 build 10586 is the first Windows release that supports 256 colors.
|
|
35
47
|
// Windows 10 build 14931 is the first release that supports 16m/TrueColor.
|
|
@@ -95,3 +107,10 @@ export const supportsColor = {
|
|
|
95
107
|
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
96
108
|
stderr: createSupportsColor({ isTTY: tty.isatty(2) }),
|
|
97
109
|
};
|
|
110
|
+
export function isColorEnabled(stream = process.stdout) {
|
|
111
|
+
const preference = resolveColorPreference();
|
|
112
|
+
if (preference !== 'auto') {
|
|
113
|
+
return preference === 'always';
|
|
114
|
+
}
|
|
115
|
+
return createSupportsColor(stream, { streamIsTTY: stream?.isTTY }).hasBasic;
|
|
116
|
+
}
|