@mintlify/cli 4.0.1099 → 4.0.1101
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 +9 -14
- package/__test__/telemetry.test.ts +2 -2
- package/bin/analytics/index.js +24 -39
- package/bin/analytics/output.js +3 -2
- package/bin/cli.js +5 -5
- package/bin/login.js +42 -2
- package/bin/middlewares/subdomainMiddleware.js +28 -0
- package/bin/{telemetry/middleware.js → middlewares/telemetryMiddleware.js} +1 -1
- package/bin/status.js +8 -9
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/analytics/index.tsx +28 -43
- package/src/analytics/output.ts +4 -2
- package/src/cli.tsx +3 -3
- package/src/login.tsx +48 -2
- package/src/middlewares/subdomainMiddleware.ts +16 -0
- package/src/{telemetry/middleware.ts → middlewares/telemetryMiddleware.ts} +1 -1
- package/src/status.tsx +7 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mintlify/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1101",
|
|
4
4
|
"description": "The Mintlify CLI",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@inquirer/prompts": "7.9.0",
|
|
48
|
-
"@mintlify/common": "1.0.
|
|
49
|
-
"@mintlify/link-rot": "3.0.
|
|
50
|
-
"@mintlify/prebuild": "1.0.
|
|
51
|
-
"@mintlify/previewing": "4.0.
|
|
52
|
-
"@mintlify/validation": "0.1.
|
|
48
|
+
"@mintlify/common": "1.0.842",
|
|
49
|
+
"@mintlify/link-rot": "3.0.1017",
|
|
50
|
+
"@mintlify/prebuild": "1.0.984",
|
|
51
|
+
"@mintlify/previewing": "4.0.1045",
|
|
52
|
+
"@mintlify/validation": "0.1.658",
|
|
53
53
|
"adm-zip": "0.5.16",
|
|
54
54
|
"chalk": "5.2.0",
|
|
55
55
|
"color": "4.2.3",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"vitest": "2.1.9",
|
|
94
94
|
"vitest-mock-process": "1.0.4"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "322e55f3486b66c5f308778b91d56c721bc10822"
|
|
97
97
|
}
|
package/src/analytics/index.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import type { Argv } from 'yargs';
|
|
|
5
5
|
|
|
6
6
|
import { getConfigValue } from '../config.js';
|
|
7
7
|
import { terminate } from '../helpers.js';
|
|
8
|
+
import { subdomainMiddleware } from '../middlewares/subdomainMiddleware.js';
|
|
8
9
|
import {
|
|
9
10
|
getBucketThreads,
|
|
10
11
|
getBuckets,
|
|
@@ -21,7 +22,6 @@ import type { Conversation } from './types.js';
|
|
|
21
22
|
const withSubdomain = <T extends object>(yargs: Argv<T>) =>
|
|
22
23
|
yargs.option('subdomain', {
|
|
23
24
|
type: 'string' as const,
|
|
24
|
-
default: getConfigValue('subdomain'),
|
|
25
25
|
description: 'Documentation subdomain (default: mint config set subdomain)',
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -51,16 +51,11 @@ const withDates = <T extends object>(yargs: Argv<T>) =>
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
const withFormat = <T extends object>(yargs: Argv<T>) =>
|
|
54
|
-
yargs
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
})
|
|
60
|
-
.option('agent', {
|
|
61
|
-
type: 'boolean' as const,
|
|
62
|
-
description: 'Agent-friendly output (equivalent to --format json)',
|
|
63
|
-
});
|
|
54
|
+
yargs.option('format', {
|
|
55
|
+
type: 'string' as const,
|
|
56
|
+
choices: ['table', 'plain', 'json', 'graph'] as const,
|
|
57
|
+
description: 'Output format (table=pretty, plain=pipeable, json=raw)',
|
|
58
|
+
});
|
|
64
59
|
|
|
65
60
|
const withAll = <T extends object>(yargs: Argv<T>) => withFormat(withDates(withSubdomain(yargs)));
|
|
66
61
|
|
|
@@ -73,15 +68,16 @@ function output(format: OutputFormat, text: string) {
|
|
|
73
68
|
}
|
|
74
69
|
|
|
75
70
|
export const analyticsBuilder = (yargs: Argv) =>
|
|
76
|
-
yargs
|
|
71
|
+
withAll(yargs)
|
|
72
|
+
.middleware(subdomainMiddleware)
|
|
77
73
|
.command(
|
|
78
74
|
'stats',
|
|
79
75
|
'display KPI numbers (views, visitors, searches)',
|
|
80
76
|
(yargs) =>
|
|
81
|
-
withAll(yargs)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
withAll(yargs).option('page', {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description: 'Filter to a specific page path',
|
|
80
|
+
}),
|
|
85
81
|
async (argv) => {
|
|
86
82
|
const format = resolveFormat(argv);
|
|
87
83
|
try {
|
|
@@ -123,7 +119,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
123
119
|
}
|
|
124
120
|
|
|
125
121
|
if (format === 'graph') {
|
|
126
|
-
const label = argv.subdomain ?? '
|
|
122
|
+
const label = argv.subdomain ?? '';
|
|
127
123
|
const lines: string[] = [];
|
|
128
124
|
lines.push(chalk.bold(`\nAnalytics \u2014 ${label} (${argv.from} to ${argv.to})\n`));
|
|
129
125
|
lines.push(chalk.bold(' Human vs Agent\n'));
|
|
@@ -149,14 +145,8 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
149
145
|
return;
|
|
150
146
|
}
|
|
151
147
|
|
|
152
|
-
const agentOnly = argv.agents && !argv.humans;
|
|
153
|
-
const humanOnly = argv.humans && !argv.agents;
|
|
154
|
-
const showHuman = !agentOnly;
|
|
155
|
-
const showAgent = !humanOnly;
|
|
156
|
-
const showTotal = showHuman && showAgent;
|
|
157
|
-
|
|
158
148
|
const lines: string[] = [];
|
|
159
|
-
const label = argv.subdomain ?? '
|
|
149
|
+
const label = argv.subdomain ?? '';
|
|
160
150
|
lines.push(chalk.bold(`\nAnalytics \u2014 ${label} (${argv.from} to ${argv.to})\n`));
|
|
161
151
|
|
|
162
152
|
if (argv.page) {
|
|
@@ -164,19 +154,14 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
164
154
|
}
|
|
165
155
|
|
|
166
156
|
lines.push(chalk.bold(' Views'));
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (showTotal)
|
|
171
|
-
lines.push(` Total: ${num(kpi.humanViews + kpi.agentViews).padStart(8)}`);
|
|
157
|
+
lines.push(` Human: ${chalk.cyan(num(kpi.humanViews).padStart(8))}`);
|
|
158
|
+
lines.push(` Agent: ${chalk.magenta(num(kpi.agentViews).padStart(8))}`);
|
|
159
|
+
lines.push(` Total: ${num(kpi.humanViews + kpi.agentViews).padStart(8)}`);
|
|
172
160
|
|
|
173
161
|
lines.push(chalk.bold('\n Visitors'));
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
lines.push(` Agent: ${chalk.magenta(num(kpi.agentVisitors).padStart(8))}`);
|
|
178
|
-
if (showTotal)
|
|
179
|
-
lines.push(` Total: ${num(kpi.humanVisitors + kpi.agentVisitors).padStart(8)}`);
|
|
162
|
+
lines.push(` Human: ${chalk.cyan(num(kpi.humanVisitors).padStart(8))}`);
|
|
163
|
+
lines.push(` Agent: ${chalk.magenta(num(kpi.agentVisitors).padStart(8))}`);
|
|
164
|
+
lines.push(` Total: ${num(kpi.humanVisitors + kpi.agentVisitors).padStart(8)}`);
|
|
180
165
|
|
|
181
166
|
lines.push(`\n Searches: ${chalk.bold(num(kpi.humanSearches))}`);
|
|
182
167
|
lines.push(` Feedback: ${chalk.bold(num(kpi.humanFeedback))}`);
|
|
@@ -228,7 +213,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
228
213
|
if (format === 'json') {
|
|
229
214
|
output(format, JSON.stringify(data, null, 2));
|
|
230
215
|
} else if (format === 'graph') {
|
|
231
|
-
const label = argv.subdomain ?? '
|
|
216
|
+
const label = argv.subdomain ?? '';
|
|
232
217
|
const lines: string[] = [];
|
|
233
218
|
lines.push(
|
|
234
219
|
chalk.bold(`\nSearch Queries \u2014 ${label} (${argv.from} to ${argv.to})\n`)
|
|
@@ -246,7 +231,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
246
231
|
} else if (format === 'plain') {
|
|
247
232
|
output(format, formatOutput(format, headers, tableRows, data));
|
|
248
233
|
} else {
|
|
249
|
-
const label = argv.subdomain ?? '
|
|
234
|
+
const label = argv.subdomain ?? '';
|
|
250
235
|
const lines: string[] = [];
|
|
251
236
|
lines.push(
|
|
252
237
|
chalk.bold(`\nSearch Analytics \u2014 ${label} (${argv.from} to ${argv.to})`)
|
|
@@ -301,7 +286,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
301
286
|
if (format === 'json') {
|
|
302
287
|
output(format, JSON.stringify(data, null, 2));
|
|
303
288
|
} else if (format === 'graph') {
|
|
304
|
-
const label = argv.subdomain ?? '
|
|
289
|
+
const label = argv.subdomain ?? '';
|
|
305
290
|
const lines: string[] = [];
|
|
306
291
|
lines.push(
|
|
307
292
|
chalk.bold(`\nFeedback by Page \u2014 ${label} (${argv.from} to ${argv.to})\n`)
|
|
@@ -317,7 +302,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
317
302
|
);
|
|
318
303
|
output('table', lines.join('\n'));
|
|
319
304
|
} else {
|
|
320
|
-
const label = argv.subdomain ?? '
|
|
305
|
+
const label = argv.subdomain ?? '';
|
|
321
306
|
const lines: string[] = [];
|
|
322
307
|
if (format === 'table')
|
|
323
308
|
lines.push(chalk.bold(`\nFeedback \u2014 ${label} (${argv.from} to ${argv.to})\n`));
|
|
@@ -350,7 +335,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
350
335
|
if (format === 'json') {
|
|
351
336
|
output(format, JSON.stringify(data, null, 2));
|
|
352
337
|
} else {
|
|
353
|
-
const label = argv.subdomain ?? '
|
|
338
|
+
const label = argv.subdomain ?? '';
|
|
354
339
|
const lines: string[] = [];
|
|
355
340
|
if (format === 'table')
|
|
356
341
|
lines.push(chalk.bold(`\nFeedback \u2014 ${label} (${argv.from} to ${argv.to})\n`));
|
|
@@ -406,7 +391,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
406
391
|
if (format === 'json') {
|
|
407
392
|
output(format, JSON.stringify(data, null, 2));
|
|
408
393
|
} else {
|
|
409
|
-
const label = argv.subdomain ?? '
|
|
394
|
+
const label = argv.subdomain ?? '';
|
|
410
395
|
const lines: string[] = [];
|
|
411
396
|
if (format === 'table')
|
|
412
397
|
lines.push(
|
|
@@ -523,7 +508,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
523
508
|
if (format === 'json') {
|
|
524
509
|
output(format, JSON.stringify(data, null, 2));
|
|
525
510
|
} else if (format === 'graph') {
|
|
526
|
-
const label = argv.subdomain ?? '
|
|
511
|
+
const label = argv.subdomain ?? '';
|
|
527
512
|
const lines: string[] = [];
|
|
528
513
|
lines.push(
|
|
529
514
|
chalk.bold(
|
|
@@ -541,7 +526,7 @@ export const analyticsBuilder = (yargs: Argv) =>
|
|
|
541
526
|
);
|
|
542
527
|
output('table', lines.join('\n'));
|
|
543
528
|
} else {
|
|
544
|
-
const label = argv.subdomain ?? '
|
|
529
|
+
const label = argv.subdomain ?? '';
|
|
545
530
|
const lines: string[] = [];
|
|
546
531
|
if (format === 'table')
|
|
547
532
|
lines.push(
|
package/src/analytics/output.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
|
|
3
|
+
import { isAI } from '../helpers.js';
|
|
4
|
+
|
|
3
5
|
export type OutputFormat = 'table' | 'plain' | 'json' | 'graph';
|
|
4
6
|
|
|
5
|
-
export function resolveFormat(argv: { format?: string
|
|
6
|
-
if (argv.agent || process.env.CLAUDECODE === '1') return 'json';
|
|
7
|
+
export function resolveFormat(argv: { format?: string }): OutputFormat {
|
|
7
8
|
if (
|
|
8
9
|
argv.format === 'table' ||
|
|
9
10
|
argv.format === 'plain' ||
|
|
@@ -11,6 +12,7 @@ export function resolveFormat(argv: { format?: string; agent?: boolean }): Outpu
|
|
|
11
12
|
argv.format === 'graph'
|
|
12
13
|
)
|
|
13
14
|
return argv.format;
|
|
15
|
+
if (isAI()) return 'json';
|
|
14
16
|
return 'plain';
|
|
15
17
|
}
|
|
16
18
|
|
package/src/cli.tsx
CHANGED
|
@@ -38,9 +38,9 @@ import { getAccessToken } from './keyring.js';
|
|
|
38
38
|
import { login } from './login.js';
|
|
39
39
|
import { logout } from './logout.js';
|
|
40
40
|
import { mdxLinter } from './mdxLinter.js';
|
|
41
|
+
import { createTelemetryMiddleware } from './middlewares/telemetryMiddleware.js';
|
|
41
42
|
import { checkOpenApiFile, getOpenApiFilenamesFromDocsConfig } from './openApiCheck.js';
|
|
42
|
-
import { status,
|
|
43
|
-
import { createTelemetryMiddleware } from './telemetry/middleware.js';
|
|
43
|
+
import { status, getCliSubdomains } from './status.js';
|
|
44
44
|
import { trackTelemetryPreferenceChange } from './telemetry/track.js';
|
|
45
45
|
import { update } from './update.js';
|
|
46
46
|
import { addWorkflow } from './workflow.js';
|
|
@@ -119,7 +119,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
|
|
|
119
119
|
const configuredSubdomain = getConfigValue('subdomain');
|
|
120
120
|
subdomain =
|
|
121
121
|
configuredSubdomain ??
|
|
122
|
-
(accessToken ? (await
|
|
122
|
+
(accessToken ? (await getCliSubdomains(accessToken))[0] : undefined);
|
|
123
123
|
} catch {}
|
|
124
124
|
if (port != undefined) {
|
|
125
125
|
await dev({
|
package/src/login.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { input } from '@inquirer/prompts';
|
|
2
|
-
import { addLog, ErrorLog, SuccessLog } from '@mintlify/previewing';
|
|
1
|
+
import { input, search } from '@inquirer/prompts';
|
|
2
|
+
import { addLog, ErrorLog, InfoLog, SuccessLog } from '@mintlify/previewing';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { Box, Text } from 'ink';
|
|
5
5
|
import open from 'open';
|
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
} from 'openid-client';
|
|
12
12
|
|
|
13
13
|
import { startCallbackServer } from './callbackServer.js';
|
|
14
|
+
import { setConfigValue } from './config.js';
|
|
14
15
|
import { DASHBOARD_URL, STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
|
|
15
16
|
import { storeCredentials } from './keyring.js';
|
|
17
|
+
import { getCliSubdomains } from './status.js';
|
|
16
18
|
import { trackLoginAttempt, trackLoginFailed, trackLoginSuccess } from './telemetry/track.js';
|
|
17
19
|
|
|
18
20
|
interface TokenResponse {
|
|
@@ -114,4 +116,48 @@ export async function login(): Promise<void> {
|
|
|
114
116
|
await storeCredentials(token.access_token, token.refresh_token);
|
|
115
117
|
void trackLoginSuccess();
|
|
116
118
|
addLog(<SuccessLog message="logged in successfully" />);
|
|
119
|
+
await promptSubdomainSelection(token.access_token);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isPromptCancellationError(error: unknown): boolean {
|
|
123
|
+
return error instanceof Error && error.name === 'ExitPromptError';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function promptSubdomainSelection(accessToken: string): Promise<void> {
|
|
127
|
+
const subdomains = await getCliSubdomains(accessToken);
|
|
128
|
+
if (subdomains.length === 0) return;
|
|
129
|
+
|
|
130
|
+
if (subdomains.length === 1) {
|
|
131
|
+
await setConfigValue('subdomain', subdomains[0]!);
|
|
132
|
+
addLog(<InfoLog message={`default project set to ${subdomains[0]}`} />);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
137
|
+
|
|
138
|
+
let chosen: string;
|
|
139
|
+
try {
|
|
140
|
+
chosen = await search<string>({
|
|
141
|
+
message: 'Select a default project',
|
|
142
|
+
source: (term) => {
|
|
143
|
+
const results = term
|
|
144
|
+
? subdomains.filter((s) => s.toLowerCase().includes(term.toLowerCase()))
|
|
145
|
+
: subdomains;
|
|
146
|
+
return results.map((s) => ({ name: s, value: s }));
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (isPromptCancellationError(error)) {
|
|
151
|
+
addLog(
|
|
152
|
+
<InfoLog
|
|
153
|
+
message={`No project set. To set a default project, run ${chalk.bold('mintlify config set subdomain <subdomain>')}`}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
await setConfigValue('subdomain', chosen);
|
|
162
|
+
addLog(<InfoLog message={`default project set to ${chosen}`} />);
|
|
117
163
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getConfigValue } from '../config.js';
|
|
2
|
+
import { getAccessToken } from '../keyring.js';
|
|
3
|
+
import { getCliSubdomains } from '../status.js';
|
|
4
|
+
|
|
5
|
+
export async function subdomainMiddleware(argv: { subdomain?: string }): Promise<void> {
|
|
6
|
+
if (argv.subdomain) return;
|
|
7
|
+
const fromConfig = getConfigValue('subdomain');
|
|
8
|
+
if (fromConfig) {
|
|
9
|
+
argv.subdomain = fromConfig;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const accessToken = await getAccessToken();
|
|
13
|
+
if (!accessToken) return;
|
|
14
|
+
const subdomains = await getCliSubdomains(accessToken);
|
|
15
|
+
argv.subdomain = subdomains[0];
|
|
16
|
+
}
|
package/src/status.tsx
CHANGED
|
@@ -11,20 +11,20 @@ import { getAccessToken } from './keyring.js';
|
|
|
11
11
|
const StatusResponseSchema = z.object({
|
|
12
12
|
user: z.object({ email: z.string() }),
|
|
13
13
|
org: z.object({ name: z.string() }),
|
|
14
|
-
|
|
14
|
+
subdomains: z.array(z.string()).default([]),
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
export async function
|
|
17
|
+
export async function getCliSubdomains(accessToken: string): Promise<string[]> {
|
|
18
18
|
try {
|
|
19
19
|
const res = await fetch(`${API_URL}/api/cli/status`, {
|
|
20
20
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
21
21
|
});
|
|
22
|
-
if (!res.ok) return
|
|
22
|
+
if (!res.ok) return [];
|
|
23
23
|
const json = await res.json().catch(() => null);
|
|
24
24
|
const parsed = StatusResponseSchema.safeParse(json);
|
|
25
|
-
return parsed.success ? parsed.data.
|
|
25
|
+
return parsed.success ? parsed.data.subdomains : [];
|
|
26
26
|
} catch {
|
|
27
|
-
return
|
|
27
|
+
return [];
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -52,9 +52,9 @@ export async function status(): Promise<void> {
|
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const { user, org,
|
|
55
|
+
const { user, org, subdomains } = parsed.data;
|
|
56
56
|
const version = getCliVersion();
|
|
57
|
-
const subdomain = getConfigValue('subdomain') ??
|
|
57
|
+
const subdomain = getConfigValue('subdomain') ?? subdomains[0] ?? null;
|
|
58
58
|
addLog(
|
|
59
59
|
<Box flexDirection="column" paddingY={1}>
|
|
60
60
|
{version && (
|