@mintlify/cli 4.0.1094 → 4.0.1096
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/__test__/analytics/format.test.ts +3 -0
- package/__test__/workflow.test.ts +2 -0
- package/bin/helpers.js +3 -0
- package/bin/init.js +5 -7
- package/bin/login.js +6 -1
- package/bin/telemetry/middleware.js +3 -1
- package/bin/telemetry/track.js +30 -2
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/bin/workflow.js +2 -5
- package/package.json +2 -2
- package/src/helpers.tsx +6 -0
- package/src/init.tsx +6 -8
- package/src/login.tsx +7 -5
- package/src/telemetry/middleware.ts +3 -1
- package/src/telemetry/track.ts +35 -2
- package/src/workflow.tsx +2 -6
package/bin/workflow.js
CHANGED
|
@@ -13,7 +13,7 @@ import { addLog, addLogs, SuccessLog } from '@mintlify/previewing';
|
|
|
13
13
|
import fse from 'fs-extra';
|
|
14
14
|
import { Text } from 'ink';
|
|
15
15
|
import path from 'path';
|
|
16
|
-
import { CMD_EXEC_PATH } from './helpers.js';
|
|
16
|
+
import { CMD_EXEC_PATH, isAI } from './helpers.js';
|
|
17
17
|
export function slugify(name) {
|
|
18
18
|
return name
|
|
19
19
|
.toLowerCase()
|
|
@@ -67,10 +67,7 @@ export function addWorkflow() {
|
|
|
67
67
|
if (!(yield fse.pathExists(docsJsonPath))) {
|
|
68
68
|
throw new Error('docs.json not found in the current directory. Please run this command from your docs repository root.');
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
const isClaudeCode = process.env.CLAUDECODE === '1';
|
|
72
|
-
const isAI = !isInteractive || isClaudeCode;
|
|
73
|
-
if (isAI) {
|
|
70
|
+
if (isAI()) {
|
|
74
71
|
sendUsageMessageForAI();
|
|
75
72
|
return;
|
|
76
73
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mintlify/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1096",
|
|
4
4
|
"description": "The Mintlify CLI",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"vitest": "2.1.9",
|
|
94
94
|
"vitest-mock-process": "1.0.4"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "03c44790cda77c434ed44c03ef2130e16195fbf8"
|
|
97
97
|
}
|
package/src/helpers.tsx
CHANGED
|
@@ -205,6 +205,12 @@ export const terminate = async (code: number) => {
|
|
|
205
205
|
|
|
206
206
|
export const execAsync = promisify(exec);
|
|
207
207
|
|
|
208
|
+
export function isAI(): boolean {
|
|
209
|
+
return (
|
|
210
|
+
!process.stdin.isTTY || process.env.CLAUDECODE === '1' || process.env.TERM_PROGRAM === 'claude'
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
208
214
|
export const detectPackageManager = async ({ packageName }: { packageName: string }) => {
|
|
209
215
|
try {
|
|
210
216
|
const { stdout: packagePath } = await execAsync(`which ${packageName}`);
|
package/src/init.tsx
CHANGED
|
@@ -5,6 +5,8 @@ import AdmZip from 'adm-zip';
|
|
|
5
5
|
import fse from 'fs-extra';
|
|
6
6
|
import { Box, Text } from 'ink';
|
|
7
7
|
|
|
8
|
+
import { isAI } from './helpers.js';
|
|
9
|
+
|
|
8
10
|
const sendOnboardingMessage = (installDir: string) => {
|
|
9
11
|
addLogs(
|
|
10
12
|
<Text bold>Documentation Setup!</Text>,
|
|
@@ -61,10 +63,6 @@ export async function init(
|
|
|
61
63
|
// Validate path is within current working directory to prevent path traversal
|
|
62
64
|
validatePathWithinCwd(installDir);
|
|
63
65
|
|
|
64
|
-
const isInteractive = process.stdin.isTTY;
|
|
65
|
-
const isClaudeCode = process.env.CLAUDECODE === '1';
|
|
66
|
-
const isAI = !isInteractive || isClaudeCode;
|
|
67
|
-
|
|
68
66
|
let selectedTheme = theme;
|
|
69
67
|
let projectName = name;
|
|
70
68
|
|
|
@@ -76,17 +74,17 @@ export async function init(
|
|
|
76
74
|
const dirContents = await fse.readdir(installDir).catch(() => []);
|
|
77
75
|
const contentsOccupied = dirContents.length > 0;
|
|
78
76
|
|
|
79
|
-
if ((!theme || !name) && isAI) {
|
|
77
|
+
if ((!theme || !name) && isAI()) {
|
|
80
78
|
sendUsageMessageForAI(installDir, contentsOccupied, themes);
|
|
81
79
|
return;
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
if (contentsOccupied && isAI && !force) {
|
|
82
|
+
if (contentsOccupied && isAI() && !force) {
|
|
85
83
|
sendUsageMessageForAI(installDir, contentsOccupied, themes);
|
|
86
84
|
return;
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
if (contentsOccupied && !isAI) {
|
|
87
|
+
if (contentsOccupied && !isAI()) {
|
|
90
88
|
const choice = await select({
|
|
91
89
|
message: `Directory ${installDir} is not empty. What would you like to do?`,
|
|
92
90
|
choices: [
|
|
@@ -114,7 +112,7 @@ export async function init(
|
|
|
114
112
|
}
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
if (!isAI && (!selectedTheme || !projectName)) {
|
|
115
|
+
if (!isAI() && (!selectedTheme || !projectName)) {
|
|
118
116
|
const defaultProject =
|
|
119
117
|
projectName !== undefined ? projectName : installDir === '.' ? 'Mintlify' : installDir;
|
|
120
118
|
if (!projectName) {
|
package/src/login.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { startCallbackServer } from './callbackServer.js';
|
|
14
14
|
import { DASHBOARD_URL, STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
|
|
15
15
|
import { storeCredentials } from './keyring.js';
|
|
16
|
+
import { trackLoginAttempt, trackLoginFailed, trackLoginSuccess } from './telemetry/track.js';
|
|
16
17
|
|
|
17
18
|
interface TokenResponse {
|
|
18
19
|
access_token: string;
|
|
@@ -37,6 +38,8 @@ export async function login(): Promise<void> {
|
|
|
37
38
|
authorizeUrl.searchParams.set('code_challenge', codeChallenge);
|
|
38
39
|
const url = authorizeUrl.toString();
|
|
39
40
|
|
|
41
|
+
void trackLoginAttempt();
|
|
42
|
+
|
|
40
43
|
const { codePromise, close: closeServer } = await startCallbackServer();
|
|
41
44
|
|
|
42
45
|
addLog(
|
|
@@ -101,15 +104,14 @@ export async function login(): Promise<void> {
|
|
|
101
104
|
const body = await res.json().catch(() => ({}));
|
|
102
105
|
|
|
103
106
|
if (!res.ok) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
</Text>
|
|
108
|
-
);
|
|
107
|
+
const reason = body.error_message ?? body.error ?? 'unknown error';
|
|
108
|
+
void trackLoginFailed(reason);
|
|
109
|
+
addLog(<Text color="red">✖ Login failed: {reason}</Text>);
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
const token = body as TokenResponse;
|
|
113
114
|
await storeCredentials(token.access_token, token.refresh_token);
|
|
115
|
+
void trackLoginSuccess();
|
|
114
116
|
addLog(<Text color="green">✔ Logged in successfully.</Text>);
|
|
115
117
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getConfigValue } from '../config.js';
|
|
1
2
|
import { getVersions } from '../helpers.js';
|
|
2
3
|
import { trackCommand } from './track.js';
|
|
3
4
|
|
|
@@ -23,7 +24,8 @@ export function createTelemetryMiddleware(): (argv: { _: (string | number)[] })
|
|
|
23
24
|
tracked = true;
|
|
24
25
|
const sanitizedCommand = getSanitizedCommandForTelemetry(argv._);
|
|
25
26
|
const { cli: cliVersion } = getVersions();
|
|
26
|
-
|
|
27
|
+
const subdomain = getConfigValue('subdomain');
|
|
28
|
+
void trackCommand({ command: sanitizedCommand, cliVersion, subdomain });
|
|
27
29
|
}
|
|
28
30
|
};
|
|
29
31
|
}
|
package/src/telemetry/track.ts
CHANGED
|
@@ -2,13 +2,14 @@ import os from 'os';
|
|
|
2
2
|
|
|
3
3
|
import { isTelemetryEnabled } from '../config.js';
|
|
4
4
|
import { TELEMETRY_ASYNC_TIMEOUT_MS } from '../constants.js';
|
|
5
|
-
import { getVersions } from '../helpers.js';
|
|
5
|
+
import { getVersions, isAI } from '../helpers.js';
|
|
6
6
|
import { getPostHogClient } from './client.js';
|
|
7
7
|
import { getDistinctId } from './distinctId.js';
|
|
8
8
|
|
|
9
9
|
export interface TrackCommandOptions {
|
|
10
10
|
command: string;
|
|
11
11
|
cliVersion?: string;
|
|
12
|
+
subdomain?: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
async function captureWithTimeout(
|
|
@@ -30,7 +31,11 @@ async function captureWithTimeout(
|
|
|
30
31
|
]);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
export async function trackCommand({
|
|
34
|
+
export async function trackCommand({
|
|
35
|
+
command,
|
|
36
|
+
cliVersion,
|
|
37
|
+
subdomain,
|
|
38
|
+
}: TrackCommandOptions): Promise<void> {
|
|
34
39
|
if (!isTelemetryEnabled()) return;
|
|
35
40
|
|
|
36
41
|
try {
|
|
@@ -40,10 +45,38 @@ export async function trackCommand({ command, cliVersion }: TrackCommandOptions)
|
|
|
40
45
|
os: os.platform(),
|
|
41
46
|
arch: os.arch(),
|
|
42
47
|
node_version: process.version,
|
|
48
|
+
is_ai_agent: isAI(),
|
|
49
|
+
subdomain,
|
|
43
50
|
});
|
|
44
51
|
} catch {}
|
|
45
52
|
}
|
|
46
53
|
|
|
54
|
+
async function trackLoginEvent(event: string, extra?: Record<string, unknown>): Promise<void> {
|
|
55
|
+
if (!isTelemetryEnabled()) return;
|
|
56
|
+
try {
|
|
57
|
+
const { cli: cliVersion } = getVersions();
|
|
58
|
+
await captureWithTimeout(event, {
|
|
59
|
+
...extra,
|
|
60
|
+
cli_version: cliVersion,
|
|
61
|
+
os: os.platform(),
|
|
62
|
+
arch: os.arch(),
|
|
63
|
+
node_version: process.version,
|
|
64
|
+
});
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function trackLoginAttempt(): Promise<void> {
|
|
69
|
+
return trackLoginEvent('cli.login.attempted');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function trackLoginSuccess(): Promise<void> {
|
|
73
|
+
return trackLoginEvent('cli.login.succeeded');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function trackLoginFailed(reason: string): Promise<void> {
|
|
77
|
+
return trackLoginEvent('cli.login.failed', { reason });
|
|
78
|
+
}
|
|
79
|
+
|
|
47
80
|
export async function trackTelemetryPreferenceChange(options: { enabled: boolean }): Promise<void> {
|
|
48
81
|
if (process.env.CLI_TEST_MODE === 'true') return;
|
|
49
82
|
|
package/src/workflow.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import fse from 'fs-extra';
|
|
|
4
4
|
import { Text } from 'ink';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
|
|
7
|
-
import { CMD_EXEC_PATH } from './helpers.js';
|
|
7
|
+
import { CMD_EXEC_PATH, isAI } from './helpers.js';
|
|
8
8
|
|
|
9
9
|
export function slugify(name: string): string {
|
|
10
10
|
return name
|
|
@@ -92,11 +92,7 @@ export async function addWorkflow(): Promise<void> {
|
|
|
92
92
|
);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
const isClaudeCode = process.env.CLAUDECODE === '1';
|
|
97
|
-
const isAI = !isInteractive || isClaudeCode;
|
|
98
|
-
|
|
99
|
-
if (isAI) {
|
|
95
|
+
if (isAI()) {
|
|
100
96
|
sendUsageMessageForAI();
|
|
101
97
|
return;
|
|
102
98
|
}
|