@mintlify/cli 4.0.1106 → 4.0.1108
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__/init.test.ts +35 -3
- package/bin/cli.js +6 -2
- package/bin/init.js +110 -47
- package/bin/templates.js +127 -0
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/cli.tsx +6 -2
- package/src/init.tsx +132 -73
- package/src/templates.tsx +143 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mintlify/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1108",
|
|
4
4
|
"description": "The Mintlify CLI",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -45,10 +45,10 @@
|
|
|
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.
|
|
48
|
+
"@mintlify/common": "1.0.848",
|
|
49
|
+
"@mintlify/link-rot": "3.0.1023",
|
|
50
|
+
"@mintlify/prebuild": "1.0.990",
|
|
51
|
+
"@mintlify/previewing": "4.0.1051",
|
|
52
52
|
"@mintlify/validation": "0.1.662",
|
|
53
53
|
"adm-zip": "0.5.16",
|
|
54
54
|
"chalk": "5.2.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": "3a099d71bfdddd6d05b3366dc0ef3f4f85f04f63"
|
|
97
97
|
}
|
package/src/cli.tsx
CHANGED
|
@@ -532,14 +532,18 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
|
|
|
532
532
|
type: 'string',
|
|
533
533
|
description: 'Name of the documentation project',
|
|
534
534
|
})
|
|
535
|
+
.option('template', {
|
|
536
|
+
type: 'string',
|
|
537
|
+
description: 'Use a template as a starting point',
|
|
538
|
+
})
|
|
535
539
|
.option('force', {
|
|
536
540
|
type: 'boolean',
|
|
537
541
|
default: false,
|
|
538
542
|
description: 'Create the documentation in a subdirectory',
|
|
539
543
|
}),
|
|
540
|
-
async ({ directory, theme, name, force }) => {
|
|
544
|
+
async ({ directory, theme, name, force, template }) => {
|
|
541
545
|
try {
|
|
542
|
-
await init(directory, force, theme, name);
|
|
546
|
+
await init(directory, force, theme, name, template);
|
|
543
547
|
await terminate(0);
|
|
544
548
|
} catch (error) {
|
|
545
549
|
addLog(
|
package/src/init.tsx
CHANGED
|
@@ -6,6 +6,12 @@ import fse from 'fs-extra';
|
|
|
6
6
|
import { Box, Text } from 'ink';
|
|
7
7
|
|
|
8
8
|
import { isAI } from './helpers.js';
|
|
9
|
+
import {
|
|
10
|
+
fetchAvailableTemplates,
|
|
11
|
+
installFromTemplate,
|
|
12
|
+
promptForTemplate,
|
|
13
|
+
validateTemplateName,
|
|
14
|
+
} from './templates.js';
|
|
9
15
|
|
|
10
16
|
const sendOnboardingMessage = (installDir: string) => {
|
|
11
17
|
addLogs(
|
|
@@ -19,129 +25,182 @@ const sendOnboardingMessage = (installDir: string) => {
|
|
|
19
25
|
);
|
|
20
26
|
};
|
|
21
27
|
|
|
22
|
-
const sendUsageMessageForAI = (
|
|
28
|
+
const sendUsageMessageForAI = (
|
|
29
|
+
directory: string,
|
|
30
|
+
contentsOccupied: boolean,
|
|
31
|
+
themes: string[],
|
|
32
|
+
templateNames?: string[]
|
|
33
|
+
) => {
|
|
34
|
+
const templateInfo =
|
|
35
|
+
templateNames === undefined
|
|
36
|
+
? 'Unable to fetch templates — use --template flag if you know the name'
|
|
37
|
+
: templateNames.length > 0
|
|
38
|
+
? `Templates: ${JSON.stringify(templateNames)}`
|
|
39
|
+
: 'No templates are currently available';
|
|
40
|
+
|
|
23
41
|
addLogs(
|
|
24
42
|
<Text>Agent Detected - sending AI friendly prompt</Text>,
|
|
25
43
|
<Text>{'<system-message>'}</Text>,
|
|
26
44
|
<Text>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<Text>This tool will auto create the directory if the directory does not exist.</Text>,
|
|
30
|
-
<Text>
|
|
31
|
-
Ask the user what mintlify theme to use, what directory, and what the name of the Project is.
|
|
45
|
+
Help the user set up a Mintlify docs site with `mint new`. Ask each step one at a time unless
|
|
46
|
+
the user asks you to skip questions or use your best judgment.
|
|
32
47
|
</Text>,
|
|
33
48
|
<Text>
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
{[
|
|
50
|
+
`- [ ] Pick a theme or clone a template? (${templateInfo})`,
|
|
51
|
+
`- [ ] If template: which one? If theme: which one? (Themes: ${JSON.stringify(themes)})`,
|
|
52
|
+
'- [ ] Project name?',
|
|
53
|
+
`- [ ] Directory? (default: "${directory}", auto-created if needed)${contentsOccupied ? ` ⚠️ "${directory}" is occupied — subdirectory, overwrite (--force), or different path?` : ''}`,
|
|
54
|
+
].join('\n')}
|
|
36
55
|
</Text>,
|
|
37
56
|
<Text>
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
Command: `mint new [dir] --theme [theme] --name [name]` or `mint new [dir] --template
|
|
58
|
+
[template] --name [name]`. --theme optionally overrides a template default. --force overwrites
|
|
59
|
+
non-empty dirs. Use AskQuestion to present choices.
|
|
40
60
|
</Text>,
|
|
41
|
-
<Text>
|
|
42
|
-
If the user is asking you to create docs for them then you should use your AskQuestion tool
|
|
43
|
-
</Text>,
|
|
44
|
-
contentsOccupied ? (
|
|
45
|
-
<Text>
|
|
46
|
-
The directory {directory} specified is currently occupied. You will need to either install
|
|
47
|
-
the docs as a subdirectory or as a subdirectory or a different directory. Ask the user if it
|
|
48
|
-
should be installed in a different directory (This cli will create the directory if it
|
|
49
|
-
doesn't exist, or installed at the root level potentially overridding files (pass the
|
|
50
|
-
--force) option for this.
|
|
51
|
-
</Text>
|
|
52
|
-
) : undefined,
|
|
53
61
|
<Text>{'</system-message>'}</Text>
|
|
54
62
|
);
|
|
55
63
|
};
|
|
56
64
|
|
|
65
|
+
async function sendAIUsageMessage(directory: string, contentsOccupied: boolean, themes: string[]) {
|
|
66
|
+
const templateNames = await fetchAvailableTemplates().catch(() => undefined);
|
|
67
|
+
sendUsageMessageForAI(directory, contentsOccupied, themes, templateNames);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function resolveInstallDir(
|
|
71
|
+
installDir: string,
|
|
72
|
+
force: boolean,
|
|
73
|
+
contentsOccupied: boolean
|
|
74
|
+
): Promise<string | undefined> {
|
|
75
|
+
if (!contentsOccupied) return installDir;
|
|
76
|
+
|
|
77
|
+
if (isAI()) {
|
|
78
|
+
if (force) return installDir;
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const choice = await select({
|
|
83
|
+
message: `Directory ${installDir} is not empty. What would you like to do?`,
|
|
84
|
+
choices: [
|
|
85
|
+
{ name: 'Create in a subdirectory', value: 'subdir' as const },
|
|
86
|
+
{ name: 'Overwrite current directory (may lose contents)', value: 'overwrite' as const },
|
|
87
|
+
{ name: 'Cancel', value: 'cancel' as const },
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (choice === 'cancel') return undefined;
|
|
92
|
+
|
|
93
|
+
if (choice === 'subdir') {
|
|
94
|
+
const subdir = await input({
|
|
95
|
+
message: 'Subdirectory name:',
|
|
96
|
+
default: 'docs',
|
|
97
|
+
});
|
|
98
|
+
if (!subdir || subdir.trim() === '') {
|
|
99
|
+
throw new Error('Subdirectory name cannot be empty');
|
|
100
|
+
}
|
|
101
|
+
const resolved = installDir === '.' ? subdir : `${installDir}/${subdir}`;
|
|
102
|
+
validatePathWithinCwd(resolved, process.cwd());
|
|
103
|
+
return resolved;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return installDir;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function promptForProjectName(installDir: string, currentName?: string): Promise<string> {
|
|
110
|
+
if (currentName) return currentName;
|
|
111
|
+
const defaultProject = installDir === '.' ? 'Mintlify' : installDir;
|
|
112
|
+
return input({ message: 'Project Name', default: defaultProject });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function promptForApproach(): Promise<string | undefined> {
|
|
116
|
+
const approach = await select({
|
|
117
|
+
message: 'How would you like to set up your docs?',
|
|
118
|
+
choices: [
|
|
119
|
+
{ name: 'Pick a theme', value: 'theme' as const },
|
|
120
|
+
{ name: 'Clone a template', value: 'template' as const },
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (approach === 'template') return promptForTemplate();
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
57
128
|
export async function init(
|
|
58
129
|
installDir: string,
|
|
59
130
|
force: boolean,
|
|
60
131
|
theme?: string,
|
|
61
|
-
name?: string
|
|
132
|
+
name?: string,
|
|
133
|
+
template?: string
|
|
62
134
|
): Promise<void> {
|
|
63
|
-
// Validate path is within current working directory to prevent path traversal
|
|
64
135
|
validatePathWithinCwd(installDir);
|
|
65
136
|
|
|
66
|
-
let selectedTheme = theme;
|
|
67
|
-
let projectName = name;
|
|
68
|
-
|
|
69
137
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
-
const themes = docsConfigSchema.options.map((option: any) => {
|
|
71
|
-
return option.shape.theme._def.value;
|
|
138
|
+
const themes: string[] = docsConfigSchema.options.map((option: any) => {
|
|
139
|
+
return option.shape.theme._def.value as string;
|
|
72
140
|
});
|
|
73
141
|
|
|
74
|
-
const dirContents = await fse.readdir(installDir).catch(() => []);
|
|
142
|
+
const dirContents = await fse.readdir(installDir).catch(() => [] as string[]);
|
|
75
143
|
const contentsOccupied = dirContents.length > 0;
|
|
76
144
|
|
|
77
|
-
if ((!
|
|
78
|
-
|
|
145
|
+
if (isAI() && (!name || (!template && !theme))) {
|
|
146
|
+
await sendAIUsageMessage(installDir, contentsOccupied, themes);
|
|
79
147
|
return;
|
|
80
148
|
}
|
|
81
149
|
|
|
82
|
-
if (
|
|
83
|
-
|
|
150
|
+
if (isAI() && contentsOccupied && !force) {
|
|
151
|
+
await sendAIUsageMessage(installDir, contentsOccupied, themes);
|
|
84
152
|
return;
|
|
85
153
|
}
|
|
86
154
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
{ name: 'Overwrite current directory (may lose contents)', value: 'overwrite' },
|
|
93
|
-
{ name: 'Cancel', value: 'cancel' },
|
|
94
|
-
],
|
|
95
|
-
});
|
|
155
|
+
const selectedTemplate = template
|
|
156
|
+
? await validateTemplateName(template).then(() => template)
|
|
157
|
+
: !isAI() && !theme
|
|
158
|
+
? await promptForApproach()
|
|
159
|
+
: undefined;
|
|
96
160
|
|
|
97
|
-
|
|
161
|
+
if (selectedTemplate) {
|
|
162
|
+
const resolved = await resolveInstallDir(installDir, force, contentsOccupied);
|
|
163
|
+
if (resolved === undefined) {
|
|
164
|
+
if (isAI()) await sendAIUsageMessage(installDir, contentsOccupied, themes);
|
|
98
165
|
return;
|
|
99
166
|
}
|
|
100
167
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (!subdir || subdir.trim() === '') {
|
|
107
|
-
throw new Error('Subdirectory name cannot be empty');
|
|
108
|
-
}
|
|
109
|
-
installDir = installDir === '.' ? subdir : `${installDir}/${subdir}`;
|
|
110
|
-
// Re-validate after subdirectory is appended
|
|
111
|
-
validatePathWithinCwd(installDir, process.cwd());
|
|
112
|
-
}
|
|
168
|
+
const projectName = await promptForProjectName(resolved, name);
|
|
169
|
+
await fse.ensureDir(resolved);
|
|
170
|
+
await installFromTemplate(resolved, selectedTemplate, projectName, theme);
|
|
171
|
+
sendOnboardingMessage(resolved);
|
|
172
|
+
return;
|
|
113
173
|
}
|
|
114
174
|
|
|
175
|
+
// Standard theme-based path
|
|
176
|
+
const resolved = await resolveInstallDir(installDir, force, contentsOccupied);
|
|
177
|
+
if (resolved === undefined) {
|
|
178
|
+
if (isAI()) await sendAIUsageMessage(installDir, contentsOccupied, themes);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let projectName = name;
|
|
183
|
+
let selectedTheme = theme;
|
|
184
|
+
|
|
115
185
|
if (!isAI() && (!selectedTheme || !projectName)) {
|
|
116
|
-
|
|
117
|
-
projectName !== undefined ? projectName : installDir === '.' ? 'Mintlify' : installDir;
|
|
118
|
-
if (!projectName) {
|
|
119
|
-
projectName = await input({
|
|
120
|
-
message: 'Project Name',
|
|
121
|
-
default: defaultProject,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
186
|
+
projectName = await promptForProjectName(resolved, projectName);
|
|
124
187
|
|
|
125
188
|
if (!selectedTheme) {
|
|
126
189
|
selectedTheme = await select({
|
|
127
190
|
message: 'Theme',
|
|
128
|
-
choices: themes.map((t
|
|
129
|
-
name: t,
|
|
130
|
-
value: t,
|
|
131
|
-
})),
|
|
191
|
+
choices: themes.map((t) => ({ name: t, value: t })),
|
|
132
192
|
});
|
|
133
193
|
}
|
|
134
194
|
}
|
|
135
195
|
|
|
136
196
|
if (projectName === undefined || selectedTheme === undefined) {
|
|
137
|
-
|
|
197
|
+
await sendAIUsageMessage(resolved, contentsOccupied, themes);
|
|
138
198
|
return;
|
|
139
199
|
}
|
|
140
200
|
|
|
141
|
-
await fse.ensureDir(
|
|
142
|
-
await install(
|
|
143
|
-
|
|
144
|
-
sendOnboardingMessage(installDir);
|
|
201
|
+
await fse.ensureDir(resolved);
|
|
202
|
+
await install(resolved, projectName, selectedTheme);
|
|
203
|
+
sendOnboardingMessage(resolved);
|
|
145
204
|
}
|
|
146
205
|
|
|
147
206
|
const install = async (installDir: string, projectName: string, theme: string) => {
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { select } from '@inquirer/prompts';
|
|
2
|
+
import { addLog, SpinnerLog, removeLastLog } from '@mintlify/previewing';
|
|
3
|
+
import AdmZip from 'adm-zip';
|
|
4
|
+
import fse from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
const TEMPLATES_REPO_OWNER = 'mintlify';
|
|
8
|
+
const TEMPLATES_REPO_NAME = 'templates';
|
|
9
|
+
const TEMPLATES_REPO_BRANCH = 'main';
|
|
10
|
+
|
|
11
|
+
interface GitHubContentEntry {
|
|
12
|
+
name: string;
|
|
13
|
+
type: 'file' | 'dir';
|
|
14
|
+
path: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function fetchAvailableTemplates(): Promise<string[]> {
|
|
18
|
+
const url = `https://api.github.com/repos/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/contents/?ref=${TEMPLATES_REPO_BRANCH}`;
|
|
19
|
+
const response = await fetch(url, {
|
|
20
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`Failed to fetch templates: ${response.status} ${response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const entries: GitHubContentEntry[] = (await response.json()) as GitHubContentEntry[];
|
|
28
|
+
return entries.filter((entry) => entry.type === 'dir').map((entry) => entry.name);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function validateTemplateName(templateName: string): Promise<string> {
|
|
32
|
+
if (
|
|
33
|
+
!templateName ||
|
|
34
|
+
templateName === '.' ||
|
|
35
|
+
templateName === '..' ||
|
|
36
|
+
templateName.includes('/')
|
|
37
|
+
) {
|
|
38
|
+
throw new Error(`Invalid template name: "${templateName}".`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const url = `https://api.github.com/repos/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/contents/${encodeURIComponent(templateName)}?ref=${TEMPLATES_REPO_BRANCH}`;
|
|
42
|
+
const response = await fetch(url, {
|
|
43
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const available = await fetchAvailableTemplates().catch(() => []);
|
|
48
|
+
const suggestion = available.length > 0 ? ` Available templates: ${available.join(', ')}` : '';
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Template "${templateName}" not found in ${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}.${suggestion}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const entries: GitHubContentEntry[] = (await response.json()) as GitHubContentEntry[];
|
|
55
|
+
const hasDocsJson = entries.some((entry) => entry.name === 'docs.json');
|
|
56
|
+
if (!hasDocsJson) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Template "${templateName}" is not a valid Mintlify template (missing docs.json).`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return templateName;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function promptForTemplate(): Promise<string> {
|
|
66
|
+
addLog(<SpinnerLog message="fetching available templates..." />);
|
|
67
|
+
let templateNames: string[];
|
|
68
|
+
try {
|
|
69
|
+
templateNames = await fetchAvailableTemplates();
|
|
70
|
+
} catch {
|
|
71
|
+
removeLastLog();
|
|
72
|
+
throw new Error(
|
|
73
|
+
'Failed to fetch templates. Please check your network connection and try again.'
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
removeLastLog();
|
|
77
|
+
|
|
78
|
+
if (templateNames.length === 0) {
|
|
79
|
+
throw new Error('No templates are currently available.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return select({
|
|
83
|
+
message: 'Choose a template',
|
|
84
|
+
choices: templateNames.map((t) => ({ name: t, value: t })),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function installFromTemplate(
|
|
89
|
+
installDir: string,
|
|
90
|
+
templateName: string,
|
|
91
|
+
projectName?: string,
|
|
92
|
+
theme?: string
|
|
93
|
+
): Promise<void> {
|
|
94
|
+
const zipPath = path.join(installDir, '__template__.zip');
|
|
95
|
+
const extractDir = path.join(installDir, '__template_extract__');
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
addLog(<SpinnerLog message={`downloading template "${templateName}"...`} />);
|
|
99
|
+
try {
|
|
100
|
+
const zipUrl = `https://github.com/${TEMPLATES_REPO_OWNER}/${TEMPLATES_REPO_NAME}/archive/refs/heads/${TEMPLATES_REPO_BRANCH}.zip`;
|
|
101
|
+
const response = await fetch(zipUrl);
|
|
102
|
+
if (!response.ok) {
|
|
103
|
+
throw new Error(`Failed to download templates archive: ${response.status}`);
|
|
104
|
+
}
|
|
105
|
+
const buffer = await response.arrayBuffer();
|
|
106
|
+
await fse.writeFile(zipPath, Buffer.from(buffer));
|
|
107
|
+
} finally {
|
|
108
|
+
removeLastLog();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
addLog(<SpinnerLog message="extracting template..." />);
|
|
112
|
+
try {
|
|
113
|
+
const zip = new AdmZip(zipPath);
|
|
114
|
+
zip.extractAllTo(extractDir, true);
|
|
115
|
+
} finally {
|
|
116
|
+
removeLastLog();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const repoRoot = path.join(extractDir, `${TEMPLATES_REPO_NAME}-${TEMPLATES_REPO_BRANCH}`);
|
|
120
|
+
const templateDir = path.join(repoRoot, templateName);
|
|
121
|
+
|
|
122
|
+
if (!(await fse.pathExists(templateDir))) {
|
|
123
|
+
throw new Error(`Template directory "${templateName}" not found in the downloaded archive.`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await fse.copy(templateDir, installDir, { overwrite: true });
|
|
127
|
+
} finally {
|
|
128
|
+
await fse.remove(zipPath).catch(() => {});
|
|
129
|
+
await fse.remove(extractDir).catch(() => {});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const docsJsonPath = path.join(installDir, 'docs.json');
|
|
133
|
+
if (await fse.pathExists(docsJsonPath)) {
|
|
134
|
+
const docsConfig = await fse.readJson(docsJsonPath);
|
|
135
|
+
if (projectName) {
|
|
136
|
+
docsConfig.name = projectName;
|
|
137
|
+
}
|
|
138
|
+
if (theme) {
|
|
139
|
+
docsConfig.theme = theme;
|
|
140
|
+
}
|
|
141
|
+
await fse.writeJson(docsJsonPath, docsConfig, { spaces: 2 });
|
|
142
|
+
}
|
|
143
|
+
}
|