@mintlify/cli 4.0.1812 → 4.1.1
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/dist/assets/export-scripts/README.classic.md +15 -0
- package/dist/assets/export-scripts/README.md +14 -0
- package/dist/assets/export-scripts/serve.js +114 -0
- package/dist/assets/export-scripts/start-docs.bat +10 -0
- package/dist/assets/export-scripts/start-docs.sh +9 -0
- package/dist/assets/og/Inter-Bold.ttf +0 -0
- package/dist/assets/og/Inter-Medium.ttf +0 -0
- package/dist/assets/og/Inter-Regular.ttf +0 -0
- package/dist/assets/og/Inter-SemiBold.ttf +0 -0
- package/dist/assets/og/PaperMono-Regular.ttf +0 -0
- package/dist/assets/og/index_bg.wasm +0 -0
- package/dist/assets/openChrome.applescript +94 -0
- package/dist/assets/socket.io/socket.io.esm.min.js +7 -0
- package/dist/assets/socket.io/socket.io.esm.min.js.map +1 -0
- package/dist/assets/socket.io/socket.io.js +4907 -0
- package/dist/assets/socket.io/socket.io.js.map +1 -0
- package/dist/assets/socket.io/socket.io.min.js +7 -0
- package/dist/assets/socket.io/socket.io.min.js.map +1 -0
- package/dist/assets/socket.io/socket.io.msgpack.min.js +7 -0
- package/dist/assets/socket.io/socket.io.msgpack.min.js.map +1 -0
- package/dist/assets/xdg-open +1066 -0
- package/dist/assets/yargs-locales/be.json +46 -0
- package/dist/assets/yargs-locales/cs.json +51 -0
- package/dist/assets/yargs-locales/de.json +46 -0
- package/dist/assets/yargs-locales/en.json +55 -0
- package/dist/assets/yargs-locales/es.json +46 -0
- package/dist/assets/yargs-locales/fi.json +49 -0
- package/dist/assets/yargs-locales/fr.json +53 -0
- package/dist/assets/yargs-locales/hi.json +49 -0
- package/dist/assets/yargs-locales/hu.json +46 -0
- package/dist/assets/yargs-locales/id.json +50 -0
- package/dist/assets/yargs-locales/it.json +46 -0
- package/dist/assets/yargs-locales/ja.json +51 -0
- package/dist/assets/yargs-locales/ko.json +49 -0
- package/dist/assets/yargs-locales/nb.json +44 -0
- package/dist/assets/yargs-locales/nl.json +49 -0
- package/dist/assets/yargs-locales/nn.json +44 -0
- package/dist/assets/yargs-locales/pirate.json +13 -0
- package/dist/assets/yargs-locales/pl.json +49 -0
- package/dist/assets/yargs-locales/pt.json +45 -0
- package/dist/assets/yargs-locales/pt_BR.json +48 -0
- package/dist/assets/yargs-locales/ru.json +51 -0
- package/dist/assets/yargs-locales/th.json +46 -0
- package/dist/assets/yargs-locales/tr.json +48 -0
- package/dist/assets/yargs-locales/uk_UA.json +51 -0
- package/dist/assets/yargs-locales/uz.json +52 -0
- package/dist/assets/yargs-locales/zh_CN.json +48 -0
- package/dist/assets/yargs-locales/zh_TW.json +51 -0
- package/dist/converter-d8O3xkdU.js +102 -0
- package/dist/devtools-CGNZQKFV.js +24 -0
- package/dist/index.js +8 -0
- package/dist/rolldown-runtime-CEAe2Uac.js +7 -0
- package/dist/schemas-CBsmCNpK.js +372 -0
- package/dist/start.js +2310 -0
- package/package.json +43 -36
- package/.oxlintrc.json +0 -5
- package/.prettierignore +0 -2
- package/.turbo/turbo-build.log +0 -1
- package/CONTRIBUTING.md +0 -45
- package/__test__/agent-auth.test.ts +0 -114
- package/__test__/agent-claim.test.ts +0 -164
- package/__test__/agent-credentials.test.ts +0 -149
- package/__test__/agent-deployment.test.ts +0 -106
- package/__test__/agent-setup-config.test.ts +0 -324
- package/__test__/agent-setup.test.ts +0 -207
- package/__test__/agent.test.ts +0 -64
- package/__test__/analytics/client.test.ts +0 -180
- package/__test__/analytics/dates.test.ts +0 -12
- package/__test__/analytics/filters.test.ts +0 -116
- package/__test__/analytics/format.test.ts +0 -137
- package/__test__/authenticatedFetch.test.ts +0 -182
- package/__test__/brokenLinks.test.ts +0 -283
- package/__test__/checkPort.test.ts +0 -92
- package/__test__/deploy-github-actions.test.ts +0 -202
- package/__test__/deploy-github-setup.test.ts +0 -240
- package/__test__/deploy-instructions.test.ts +0 -155
- package/__test__/deploy.test.ts +0 -202
- package/__test__/feedback.test.ts +0 -34
- package/__test__/foreignSyntax.test.ts +0 -73
- package/__test__/format.test.ts +0 -72
- package/__test__/helpers.test.ts +0 -52
- package/__test__/init.test.ts +0 -119
- package/__test__/instructions.test.ts +0 -53
- package/__test__/keyring.test.ts +0 -82
- package/__test__/mdxAccessibility.test.ts +0 -81
- package/__test__/migrate.test.ts +0 -186
- package/__test__/openApiCheck.test.ts +0 -185
- package/__test__/pathValidation.test.ts +0 -25
- package/__test__/resolveFiles.test.ts +0 -70
- package/__test__/sessionId.test.ts +0 -46
- package/__test__/signup.test.ts +0 -36
- package/__test__/update.test.ts +0 -117
- package/__test__/utils.ts +0 -25
- package/__test__/validateCommand.test.ts +0 -647
- package/__test__/validateEngine.test.ts +0 -245
- package/__test__/validateRules.test.ts +0 -1275
- package/__test__/welcome.test.ts +0 -15
- package/__test__/workflows/client.test.ts +0 -126
- package/bin/accessibility.js +0 -111
- package/bin/accessibilityCheck.js +0 -82
- package/bin/addDomain.js +0 -130
- package/bin/agent-auth.js +0 -104
- package/bin/agent-claim.js +0 -97
- package/bin/agent-credentials.js +0 -124
- package/bin/agent-deployment.js +0 -96
- package/bin/agent-http.js +0 -45
- package/bin/agent-setup-config.js +0 -141
- package/bin/agent-setup.js +0 -146
- package/bin/agent.js +0 -42
- package/bin/analytics/client.js +0 -60
- package/bin/analytics/dates.js +0 -6
- package/bin/analytics/filters.js +0 -27
- package/bin/analytics/format.js +0 -13
- package/bin/analytics/index.js +0 -496
- package/bin/analytics/output.js +0 -75
- package/bin/analytics/types.js +0 -1
- package/bin/authenticatedFetch.js +0 -46
- package/bin/brokenLinks.js +0 -122
- package/bin/callbackServer.js +0 -65
- package/bin/cli.js +0 -813
- package/bin/comingSoon.js +0 -26
- package/bin/config.js +0 -78
- package/bin/constants.js +0 -16
- package/bin/deploy-base.js +0 -20
- package/bin/deploy-github-actions.js +0 -102
- package/bin/deploy-github-setup.js +0 -165
- package/bin/deploy-instructions.js +0 -71
- package/bin/deploy.js +0 -123
- package/bin/feedback.js +0 -36
- package/bin/format.js +0 -121
- package/bin/helpers.js +0 -238
- package/bin/idToken.js +0 -14
- package/bin/index.js +0 -102
- package/bin/init.js +0 -182
- package/bin/instructions.js +0 -101
- package/bin/keyring.js +0 -78
- package/bin/login.js +0 -123
- package/bin/logout.js +0 -18
- package/bin/mdxAccessibility.js +0 -113
- package/bin/mdxLinter.js +0 -55
- package/bin/middlewares/subdomainMiddleware.js +0 -28
- package/bin/middlewares/telemetryMiddleware.js +0 -61
- package/bin/migrate.js +0 -54
- package/bin/og.js +0 -145
- package/bin/openApiCheck.js +0 -99
- package/bin/resolveFiles.js +0 -114
- package/bin/score/client.js +0 -40
- package/bin/score/index.js +0 -211
- package/bin/score/types.js +0 -1
- package/bin/signup.js +0 -118
- package/bin/start.js +0 -36
- package/bin/status.js +0 -106
- package/bin/telemetry/client.js +0 -53
- package/bin/telemetry/distinctId.js +0 -68
- package/bin/telemetry/sessionId.js +0 -36
- package/bin/telemetry/track.js +0 -149
- package/bin/templates.js +0 -127
- package/bin/tokenRefresh.js +0 -50
- package/bin/tsconfig.build.tsbuildinfo +0 -1
- package/bin/update.js +0 -65
- package/bin/validate/command.js +0 -127
- package/bin/validate/engine.js +0 -154
- package/bin/validate/files.js +0 -163
- package/bin/validate/mdx.js +0 -238
- package/bin/validate/output.js +0 -44
- package/bin/validate/report.js +0 -11
- package/bin/validate/rules/build.js +0 -102
- package/bin/validate/rules/content/duplicateH1.js +0 -57
- package/bin/validate/rules/content/foreignSyntax.js +0 -120
- package/bin/validate/rules/content/katex.js +0 -34
- package/bin/validate/rules/content/missingSnippet.js +0 -34
- package/bin/validate/rules/content/undefinedVariable.js +0 -13
- package/bin/validate/rules/content/unknownComponent.js +0 -121
- package/bin/validate/rules/content/voidTags.js +0 -38
- package/bin/validate/rules/index.js +0 -21
- package/bin/validate/rules/openapi.js +0 -50
- package/bin/validate/rules/parseError.js +0 -7
- package/bin/validate/site.js +0 -57
- package/bin/validate/types.js +0 -1
- package/bin/vendor/converter.js +0 -30882
- package/bin/welcome.js +0 -108
- package/bin/workflows/client.js +0 -34
- package/bin/workflows/index.js +0 -269
- package/bin/workflows/types.js +0 -11
- package/scripts/bundle-converter.mjs +0 -26
- package/scripts/generate-logo.mjs +0 -79
- package/src/accessibility.ts +0 -180
- package/src/accessibilityCheck.tsx +0 -150
- package/src/addDomain.tsx +0 -206
- package/src/agent-auth.ts +0 -119
- package/src/agent-claim.ts +0 -124
- package/src/agent-credentials.ts +0 -104
- package/src/agent-deployment.ts +0 -116
- package/src/agent-http.ts +0 -34
- package/src/agent-setup-config.ts +0 -144
- package/src/agent-setup.ts +0 -165
- package/src/agent.ts +0 -56
- package/src/analytics/client.ts +0 -153
- package/src/analytics/dates.ts +0 -6
- package/src/analytics/filters.ts +0 -50
- package/src/analytics/format.ts +0 -13
- package/src/analytics/index.tsx +0 -599
- package/src/analytics/output.ts +0 -99
- package/src/analytics/types.ts +0 -145
- package/src/authenticatedFetch.ts +0 -42
- package/src/brokenLinks.tsx +0 -152
- package/src/callbackServer.ts +0 -64
- package/src/cli.tsx +0 -1105
- package/src/comingSoon.tsx +0 -29
- package/src/config.ts +0 -75
- package/src/constants.ts +0 -28
- package/src/deploy-base.ts +0 -18
- package/src/deploy-github-actions.ts +0 -139
- package/src/deploy-github-setup.ts +0 -189
- package/src/deploy-instructions.ts +0 -76
- package/src/deploy.ts +0 -165
- package/src/feedback.tsx +0 -31
- package/src/format.tsx +0 -82
- package/src/helpers.tsx +0 -279
- package/src/idToken.ts +0 -17
- package/src/index.ts +0 -109
- package/src/init.tsx +0 -237
- package/src/instructions.ts +0 -99
- package/src/keyring.ts +0 -65
- package/src/login.tsx +0 -166
- package/src/logout.tsx +0 -8
- package/src/mdxAccessibility.ts +0 -134
- package/src/mdxLinter.tsx +0 -88
- package/src/middlewares/subdomainMiddleware.ts +0 -20
- package/src/middlewares/telemetryMiddleware.ts +0 -55
- package/src/migrate.ts +0 -76
- package/src/og.tsx +0 -185
- package/src/openApiCheck.tsx +0 -125
- package/src/resolveFiles.ts +0 -101
- package/src/score/client.ts +0 -36
- package/src/score/index.tsx +0 -205
- package/src/score/types.ts +0 -15
- package/src/signup.tsx +0 -172
- package/src/start.ts +0 -27
- package/src/status.tsx +0 -129
- package/src/telemetry/client.ts +0 -46
- package/src/telemetry/distinctId.ts +0 -70
- package/src/telemetry/sessionId.ts +0 -40
- package/src/telemetry/track.ts +0 -163
- package/src/templates.tsx +0 -143
- package/src/tokenRefresh.ts +0 -53
- package/src/update.tsx +0 -89
- package/src/validate/command.tsx +0 -135
- package/src/validate/engine.ts +0 -210
- package/src/validate/files.ts +0 -249
- package/src/validate/mdx.ts +0 -290
- package/src/validate/output.tsx +0 -76
- package/src/validate/report.ts +0 -40
- package/src/validate/rules/build.ts +0 -146
- package/src/validate/rules/content/duplicateH1.ts +0 -78
- package/src/validate/rules/content/foreignSyntax.ts +0 -144
- package/src/validate/rules/content/katex.ts +0 -33
- package/src/validate/rules/content/missingSnippet.ts +0 -36
- package/src/validate/rules/content/undefinedVariable.ts +0 -20
- package/src/validate/rules/content/unknownComponent.ts +0 -130
- package/src/validate/rules/content/voidTags.ts +0 -43
- package/src/validate/rules/index.ts +0 -23
- package/src/validate/rules/openapi.ts +0 -59
- package/src/validate/rules/parseError.ts +0 -9
- package/src/validate/site.ts +0 -53
- package/src/validate/types.ts +0 -102
- package/src/vendor/converter.ts +0 -1
- package/src/welcome.ts +0 -154
- package/src/workflows/client.ts +0 -39
- package/src/workflows/index.tsx +0 -287
- package/src/workflows/types.ts +0 -73
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -10
- package/vitest.config.ts +0 -9
package/src/agent-claim.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
agentIdentityAssertionSchema,
|
|
5
|
-
discoverAgentAuth,
|
|
6
|
-
exchangeAgentToken,
|
|
7
|
-
} from './agent-auth.js';
|
|
8
|
-
import {
|
|
9
|
-
loadAgentCredentials,
|
|
10
|
-
saveAgentCredentials,
|
|
11
|
-
type AgentCredentials,
|
|
12
|
-
} from './agent-credentials.js';
|
|
13
|
-
import { AgentApiError, agentRequest, agentResponse } from './agent-http.js';
|
|
14
|
-
import { DASHBOARD_URL } from './constants.js';
|
|
15
|
-
import { trackEvent } from './telemetry/track.js';
|
|
16
|
-
|
|
17
|
-
const claimAttemptSchema = z.object({ attempt: z.object({ verification_uri: z.url() }) });
|
|
18
|
-
|
|
19
|
-
export async function createAgentClaimLink(
|
|
20
|
-
apiUrl: string,
|
|
21
|
-
credentials: AgentCredentials,
|
|
22
|
-
email: string
|
|
23
|
-
): Promise<string> {
|
|
24
|
-
const loginHint = z.email().parse(email);
|
|
25
|
-
const discovery = await discoverAgentAuth(apiUrl);
|
|
26
|
-
if (new URL(discovery.issuer).origin !== new URL(credentials.issuer).origin) {
|
|
27
|
-
throw new Error('Saved agent credentials belong to another issuer.');
|
|
28
|
-
}
|
|
29
|
-
const claim = await agentResponse(
|
|
30
|
-
await agentRequest(discovery.agent_auth.claim_endpoint, {
|
|
31
|
-
method: 'POST',
|
|
32
|
-
headers: { 'Content-Type': 'application/json' },
|
|
33
|
-
body: JSON.stringify({
|
|
34
|
-
type: 'service_auth',
|
|
35
|
-
claim_token: credentials.claimToken,
|
|
36
|
-
login_hint: loginHint,
|
|
37
|
-
}),
|
|
38
|
-
}),
|
|
39
|
-
claimAttemptSchema
|
|
40
|
-
).catch((error: unknown) => {
|
|
41
|
-
if (error instanceof AgentApiError && error.code === 'too_many_attempts') {
|
|
42
|
-
throw new Error(
|
|
43
|
-
'Too many claim links are still pending. Send the user the last claim link, or wait 5 minutes and retry.'
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
throw error;
|
|
47
|
-
});
|
|
48
|
-
const token = z
|
|
49
|
-
.string()
|
|
50
|
-
.min(1)
|
|
51
|
-
.parse(new URL(claim.attempt.verification_uri).searchParams.get('token'));
|
|
52
|
-
const claimUrl = new URL('/agent-claim', DASHBOARD_URL);
|
|
53
|
-
claimUrl.searchParams.set('token', token);
|
|
54
|
-
claimUrl.searchParams.set('registration', credentials.registrationId);
|
|
55
|
-
void trackEvent('agent_signup.claim_started', { registration_id: credentials.registrationId });
|
|
56
|
-
return claimUrl.toString();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const completedClaimSchema = z.object({
|
|
60
|
-
identity: agentIdentityAssertionSchema,
|
|
61
|
-
});
|
|
62
|
-
const signupSchema = z.object({ orgId: z.string().min(1), claimed: z.literal(true) });
|
|
63
|
-
|
|
64
|
-
export async function claimDeployment(
|
|
65
|
-
options: { apiUrl: string; directory: string; code?: string; email?: string },
|
|
66
|
-
progress: (message: string) => void = () => {}
|
|
67
|
-
): Promise<string> {
|
|
68
|
-
const { apiUrl, directory } = options;
|
|
69
|
-
const code = options.code?.trim();
|
|
70
|
-
const email = options.email?.trim();
|
|
71
|
-
if ((!code && !email) || (code && email)) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
'Provide either --email <email> for a claim link or --code <code> to finish the claim.'
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
let credentials = await loadAgentCredentials(apiUrl, directory);
|
|
77
|
-
if (!credentials)
|
|
78
|
-
throw new Error(
|
|
79
|
-
'No saved agent registration. Run from the directory used for mint deploy, or pass --directory.'
|
|
80
|
-
);
|
|
81
|
-
if (email && !credentials.claimVerified) {
|
|
82
|
-
progress('Creating the claim link...');
|
|
83
|
-
const link = await createAgentClaimLink(apiUrl, credentials, email);
|
|
84
|
-
return `Claim link for the user: ${link}\nAsk the user to open it, sign in, and return the displayed code. Then run mint claim --code <code> from the same directory (or repeat --directory).`;
|
|
85
|
-
}
|
|
86
|
-
const discovery = await discoverAgentAuth(apiUrl);
|
|
87
|
-
if (new URL(discovery.issuer).origin !== new URL(credentials.issuer).origin) {
|
|
88
|
-
throw new Error('Saved agent credentials belong to another issuer.');
|
|
89
|
-
}
|
|
90
|
-
const save = (value: AgentCredentials) => saveAgentCredentials(apiUrl, directory, value);
|
|
91
|
-
if (!credentials.claimVerified) {
|
|
92
|
-
progress('Completing the WorkOS claim...');
|
|
93
|
-
const completed = await agentResponse(
|
|
94
|
-
await agentRequest(`${discovery.agent_auth.claim_endpoint.replace(/\/$/, '')}/complete`, {
|
|
95
|
-
method: 'POST',
|
|
96
|
-
headers: { 'Content-Type': 'application/json' },
|
|
97
|
-
body: JSON.stringify({ claim_token: credentials.claimToken, user_code: code }),
|
|
98
|
-
}),
|
|
99
|
-
completedClaimSchema
|
|
100
|
-
);
|
|
101
|
-
void trackEvent('agent_signup.claim_completed', {
|
|
102
|
-
registration_id: credentials.registrationId,
|
|
103
|
-
});
|
|
104
|
-
credentials = {
|
|
105
|
-
...credentials,
|
|
106
|
-
assertion: completed.identity.assertion,
|
|
107
|
-
claimVerified: true,
|
|
108
|
-
accessToken: undefined,
|
|
109
|
-
accessTokenExpiresAt: undefined,
|
|
110
|
-
};
|
|
111
|
-
await save(credentials);
|
|
112
|
-
}
|
|
113
|
-
progress('Finishing the site claim...');
|
|
114
|
-
const authenticated = await exchangeAgentToken(discovery, credentials);
|
|
115
|
-
await agentResponse(
|
|
116
|
-
await agentRequest(`${apiUrl}/api/agent/signup`, {
|
|
117
|
-
method: 'POST',
|
|
118
|
-
headers: { Authorization: `Bearer ${authenticated.accessToken}` },
|
|
119
|
-
}),
|
|
120
|
-
signupSchema
|
|
121
|
-
);
|
|
122
|
-
await save(authenticated);
|
|
123
|
-
return 'Site claimed successfully. The user can now manage it in the Mintlify dashboard.';
|
|
124
|
-
}
|
package/src/agent-credentials.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
|
|
6
|
-
import { CONFIG_DIR } from './constants.js';
|
|
7
|
-
import { getKeytar } from './keyring.js';
|
|
8
|
-
|
|
9
|
-
const service = 'mintlify-agent';
|
|
10
|
-
const fallbackFile = () => path.join(CONFIG_DIR, 'agent-credentials.json');
|
|
11
|
-
|
|
12
|
-
export const agentCredentialsSchema = z.object({
|
|
13
|
-
registrationId: z.string().min(1),
|
|
14
|
-
issuer: z.url(),
|
|
15
|
-
assertion: z.string().min(1),
|
|
16
|
-
claimToken: z.string().min(1),
|
|
17
|
-
claimVerified: z.boolean().optional(),
|
|
18
|
-
accessToken: z.string().min(1).optional(),
|
|
19
|
-
accessTokenExpiresAt: z.number().optional(),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
export type AgentCredentials = z.infer<typeof agentCredentialsSchema>;
|
|
23
|
-
|
|
24
|
-
function projectAccount(apiUrl: string, directory: string): string {
|
|
25
|
-
return `project:${createHash('sha256')
|
|
26
|
-
.update(JSON.stringify([new URL(apiUrl).origin, path.resolve(directory)]))
|
|
27
|
-
.digest('hex')}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function registrationAccount(apiUrl: string, registrationId: string): string {
|
|
31
|
-
return `${new URL(apiUrl).origin}:${registrationId}`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function readFallback(): Promise<Record<string, string>> {
|
|
35
|
-
try {
|
|
36
|
-
return z
|
|
37
|
-
.record(z.string(), z.string())
|
|
38
|
-
.parse(JSON.parse(await fs.readFile(fallbackFile(), 'utf-8')));
|
|
39
|
-
} catch {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function writeFallback(entries: Record<string, string>): Promise<void> {
|
|
45
|
-
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
46
|
-
const temp = `${fallbackFile()}.${process.pid}.tmp`;
|
|
47
|
-
await fs.writeFile(temp, JSON.stringify(entries, null, 2), { mode: 0o600 });
|
|
48
|
-
await fs.chmod(temp, 0o600);
|
|
49
|
-
await fs.rename(temp, fallbackFile());
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function getSecret(account: string): Promise<string | null> {
|
|
53
|
-
let keyringError: unknown;
|
|
54
|
-
try {
|
|
55
|
-
const value = await (await getKeytar()).getPassword(service, account);
|
|
56
|
-
if (value) return value;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
keyringError = error;
|
|
59
|
-
}
|
|
60
|
-
const value = (await readFallback())[account];
|
|
61
|
-
if (value) return value;
|
|
62
|
-
if (keyringError) throw keyringError;
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function setSecret(account: string, value: string): Promise<void> {
|
|
67
|
-
try {
|
|
68
|
-
await (await getKeytar()).setPassword(service, account, value);
|
|
69
|
-
} catch {
|
|
70
|
-
await writeFallback({ ...(await readFallback()), [account]: value });
|
|
71
|
-
await getKeytar()
|
|
72
|
-
.then((keytar) => keytar.deletePassword(service, account))
|
|
73
|
-
.catch(() => {});
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const { [account]: stale, ...rest } = await readFallback();
|
|
77
|
-
if (stale) await writeFallback(rest).catch(() => {});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function loadAgentCredentials(
|
|
81
|
-
apiUrl: string,
|
|
82
|
-
directory: string
|
|
83
|
-
): Promise<AgentCredentials | null> {
|
|
84
|
-
const registrationId = await getSecret(projectAccount(apiUrl, directory));
|
|
85
|
-
if (!registrationId) return null;
|
|
86
|
-
const value = await getSecret(registrationAccount(apiUrl, registrationId));
|
|
87
|
-
if (!value)
|
|
88
|
-
throw new Error('Saved agent credentials are missing. Use --new to create another site.');
|
|
89
|
-
const credentials = agentCredentialsSchema.parse(JSON.parse(value));
|
|
90
|
-
if (credentials.registrationId !== registrationId) {
|
|
91
|
-
throw new Error('Saved agent credentials do not match this project.');
|
|
92
|
-
}
|
|
93
|
-
return credentials;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export async function saveAgentCredentials(
|
|
97
|
-
apiUrl: string,
|
|
98
|
-
directory: string,
|
|
99
|
-
credentials: AgentCredentials
|
|
100
|
-
): Promise<void> {
|
|
101
|
-
const value = agentCredentialsSchema.parse(credentials);
|
|
102
|
-
await setSecret(registrationAccount(apiUrl, value.registrationId), JSON.stringify(value));
|
|
103
|
-
await setSecret(projectAccount(apiUrl, directory), value.registrationId);
|
|
104
|
-
}
|
package/src/agent-deployment.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { setTimeout } from 'node:timers/promises';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
import { agentRequest, agentResponse } from './agent-http.js';
|
|
5
|
-
|
|
6
|
-
const readySchema = z.object({
|
|
7
|
-
status: z.literal('ready'),
|
|
8
|
-
deploymentId: z.string().min(1),
|
|
9
|
-
subdomain: z.string().min(1),
|
|
10
|
-
remote: z.url(),
|
|
11
|
-
branch: z.literal('main'),
|
|
12
|
-
expiresAt: z.iso.datetime(),
|
|
13
|
-
orgSlug: z.string().min(1).optional(),
|
|
14
|
-
});
|
|
15
|
-
const existingSchema = z.discriminatedUnion('status', [
|
|
16
|
-
readySchema.extend({ code: z.literal('deployment_already_exists') }),
|
|
17
|
-
z.object({
|
|
18
|
-
status: z.literal('provisioning'),
|
|
19
|
-
code: z.literal('deployment_already_exists'),
|
|
20
|
-
deploymentId: z.string().optional(),
|
|
21
|
-
subdomain: z.string().optional(),
|
|
22
|
-
}),
|
|
23
|
-
z.object({
|
|
24
|
-
status: z.literal('expired'),
|
|
25
|
-
code: z.enum(['deployment_already_exists', 'deployment_claim_expired']),
|
|
26
|
-
deploymentId: z.string(),
|
|
27
|
-
subdomain: z.string(),
|
|
28
|
-
expiresAt: z.iso.datetime().optional(),
|
|
29
|
-
}),
|
|
30
|
-
]);
|
|
31
|
-
const writeTokenSchema = z.object({
|
|
32
|
-
remote: z.url(),
|
|
33
|
-
branch: z.literal('main'),
|
|
34
|
-
token: z.string().min(1),
|
|
35
|
-
tokenExpiresAt: z.iso.datetime(),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const trustedReposSchema = z.object({
|
|
39
|
-
subdomain: z.string().min(1),
|
|
40
|
-
trustedRepos: z.array(
|
|
41
|
-
z.object({ repositoryId: z.string(), repository: z.string(), branch: z.string() })
|
|
42
|
-
),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
export type AgentSite = z.infer<typeof readySchema>;
|
|
46
|
-
export type AgentWriteToken = z.infer<typeof writeTokenSchema>;
|
|
47
|
-
export type AgentProjectType = 'site' | 'workspace';
|
|
48
|
-
export type AgentSiteSettings = {
|
|
49
|
-
subdomain: string;
|
|
50
|
-
orgName?: string;
|
|
51
|
-
projectType?: AgentProjectType;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export async function provisionAgentSite(
|
|
55
|
-
apiUrl: string,
|
|
56
|
-
accessToken: string,
|
|
57
|
-
settings: AgentSiteSettings
|
|
58
|
-
) {
|
|
59
|
-
for (let attempt = 0; attempt < 4; attempt++) {
|
|
60
|
-
const response = await agentRequest(`${apiUrl}/api/agent/deployments/provision`, {
|
|
61
|
-
method: 'POST',
|
|
62
|
-
headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
|
|
63
|
-
body: JSON.stringify({ ...settings, docsPath: '' }),
|
|
64
|
-
});
|
|
65
|
-
if (response.status !== 409) {
|
|
66
|
-
return { ...(await agentResponse(response, readySchema)), created: true };
|
|
67
|
-
}
|
|
68
|
-
const body: unknown = await response.json().catch(() => null);
|
|
69
|
-
const parsed = existingSchema.safeParse(body);
|
|
70
|
-
if (!parsed.success) throw new Error('The deployment service returned an unexpected response.');
|
|
71
|
-
if (parsed.data.status !== 'provisioning') return { ...parsed.data, created: false };
|
|
72
|
-
if (attempt < 3) await setTimeout(1000 * (attempt + 1));
|
|
73
|
-
}
|
|
74
|
-
throw new Error('Your site is still provisioning. Run the same command again.');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export async function getAgentWriteToken(
|
|
78
|
-
apiUrl: string,
|
|
79
|
-
accessToken: string
|
|
80
|
-
): Promise<AgentWriteToken> {
|
|
81
|
-
return agentResponse(
|
|
82
|
-
await agentRequest(`${apiUrl}/api/agent/deployments/token`, {
|
|
83
|
-
method: 'POST',
|
|
84
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
85
|
-
}),
|
|
86
|
-
writeTokenSchema
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export async function getGithubActionsWriteToken(
|
|
91
|
-
apiUrl: string,
|
|
92
|
-
oidcToken: string,
|
|
93
|
-
subdomain: string
|
|
94
|
-
): Promise<AgentWriteToken> {
|
|
95
|
-
return agentResponse(
|
|
96
|
-
await agentRequest(`${apiUrl}/api/agent/deployments/github-actions/token`, {
|
|
97
|
-
method: 'POST',
|
|
98
|
-
headers: { Authorization: `Bearer ${oidcToken}`, 'Content-Type': 'application/json' },
|
|
99
|
-
body: JSON.stringify({ subdomain }),
|
|
100
|
-
}),
|
|
101
|
-
writeTokenSchema
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export type TrustedRepo = { repositoryId: string; repository: string; branch: string };
|
|
106
|
-
|
|
107
|
-
export async function trustGithubRepo(apiUrl: string, accessToken: string, repo: TrustedRepo) {
|
|
108
|
-
return agentResponse(
|
|
109
|
-
await agentRequest(`${apiUrl}/api/agent/deployments/trusted-repos`, {
|
|
110
|
-
method: 'POST',
|
|
111
|
-
headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
|
|
112
|
-
body: JSON.stringify(repo),
|
|
113
|
-
}),
|
|
114
|
-
trustedReposSchema
|
|
115
|
-
);
|
|
116
|
-
}
|
package/src/agent-http.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
const errorSchema = z.object({ code: z.string().optional(), error: z.string().optional() });
|
|
4
|
-
|
|
5
|
-
export class AgentApiError extends Error {
|
|
6
|
-
constructor(
|
|
7
|
-
public readonly status: number,
|
|
8
|
-
public readonly code?: string
|
|
9
|
-
) {
|
|
10
|
-
super(`Agent request failed (HTTP ${status}).${code ? ` Code: ${code}.` : ''}`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function agentRequest(url: string, init?: RequestInit): Promise<Response> {
|
|
15
|
-
try {
|
|
16
|
-
const timeout = AbortSignal.timeout(30_000);
|
|
17
|
-
const signal = init?.signal ? AbortSignal.any([init.signal, timeout]) : timeout;
|
|
18
|
-
return await fetch(url, { ...init, redirect: 'error', signal });
|
|
19
|
-
} catch {
|
|
20
|
-
throw new Error('Could not reach the agent service. Retry the same command.');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function agentResponse<T>(response: Response, schema: z.ZodType<T>): Promise<T> {
|
|
25
|
-
const body: unknown = await response.json().catch(() => null);
|
|
26
|
-
if (!response.ok) {
|
|
27
|
-
const error = errorSchema.safeParse(body);
|
|
28
|
-
const code = error.success ? (error.data.code ?? error.data.error) : undefined;
|
|
29
|
-
throw new AgentApiError(response.status, code?.match(/^[a-z_]{1,80}$/)?.[0]);
|
|
30
|
-
}
|
|
31
|
-
const parsed = schema.safeParse(body);
|
|
32
|
-
if (!parsed.success) throw new Error('The agent service returned an unexpected response.');
|
|
33
|
-
return parsed.data;
|
|
34
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { applyEdits, modify, parse, type ParseError } from 'jsonc-parser';
|
|
2
|
-
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import fs from 'node:fs/promises';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { parse as parseToml } from 'smol-toml';
|
|
6
|
-
|
|
7
|
-
export type SetupAgent = 'claude-code' | 'codex' | 'cursor';
|
|
8
|
-
|
|
9
|
-
export const ADMIN_MCP_NAME = 'mintlify-admin';
|
|
10
|
-
export const ADMIN_MCP_URL = 'https://mcp.mintlify.com';
|
|
11
|
-
|
|
12
|
-
type ConfigLocation = {
|
|
13
|
-
cwd: string;
|
|
14
|
-
homeDir: string;
|
|
15
|
-
global: boolean;
|
|
16
|
-
env?: NodeJS.ProcessEnv;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type McpConfigPlan = {
|
|
20
|
-
path: string;
|
|
21
|
-
original: string | undefined;
|
|
22
|
-
contents: string | undefined;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
26
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function readConfig(file: string): Promise<string | undefined> {
|
|
30
|
-
try {
|
|
31
|
-
return await fs.readFile(file, 'utf8');
|
|
32
|
-
} catch (error) {
|
|
33
|
-
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return undefined;
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function configPath(agent: SetupAgent, options: ConfigLocation): string {
|
|
39
|
-
const env = options.env ?? process.env;
|
|
40
|
-
if (agent === 'codex') {
|
|
41
|
-
let directory = path.join(options.cwd, '.codex');
|
|
42
|
-
if (options.global) directory = env.CODEX_HOME || path.join(options.homeDir, '.codex');
|
|
43
|
-
return path.join(directory, 'config.toml');
|
|
44
|
-
}
|
|
45
|
-
if (agent === 'cursor') {
|
|
46
|
-
const directory = options.global ? options.homeDir : options.cwd;
|
|
47
|
-
return path.join(directory, '.cursor', 'mcp.json');
|
|
48
|
-
}
|
|
49
|
-
if (options.global) {
|
|
50
|
-
if (env.CLAUDE_CONFIG_DIR) {
|
|
51
|
-
throw new Error(
|
|
52
|
-
'CLAUDE_CONFIG_DIR is set. Configure Claude Code with: claude mcp add --scope user --transport http mintlify-admin https://mcp.mintlify.com'
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
return path.join(options.homeDir, '.claude.json');
|
|
56
|
-
}
|
|
57
|
-
return path.join(options.cwd, '.mcp.json');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export async function prepareMcpConfig(
|
|
61
|
-
agent: SetupAgent,
|
|
62
|
-
options: ConfigLocation
|
|
63
|
-
): Promise<McpConfigPlan> {
|
|
64
|
-
const requestedPath = configPath(agent, options);
|
|
65
|
-
const file = await fs.realpath(requestedPath).catch((error: unknown) => {
|
|
66
|
-
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return requestedPath;
|
|
67
|
-
throw error;
|
|
68
|
-
});
|
|
69
|
-
const original = await readConfig(file);
|
|
70
|
-
const source = original ?? '';
|
|
71
|
-
const key = agent === 'codex' ? 'mcp_servers' : 'mcpServers';
|
|
72
|
-
let config: unknown;
|
|
73
|
-
try {
|
|
74
|
-
if (agent === 'codex') {
|
|
75
|
-
config = parseToml(source);
|
|
76
|
-
} else {
|
|
77
|
-
const errors: ParseError[] = [];
|
|
78
|
-
config = parse(source || '{}', errors, { allowTrailingComma: true });
|
|
79
|
-
if (errors.length > 0) throw new Error('Invalid JSON');
|
|
80
|
-
}
|
|
81
|
-
} catch {
|
|
82
|
-
throw new Error(`Cannot parse ${file}. Fix its configuration before running setup.`);
|
|
83
|
-
}
|
|
84
|
-
if (!isRecord(config)) throw new Error(`Expected an object in ${file}.`);
|
|
85
|
-
const servers = config[key];
|
|
86
|
-
if (servers !== undefined && !isRecord(servers)) {
|
|
87
|
-
throw new Error(`Expected ${key} to be an object in ${file}.`);
|
|
88
|
-
}
|
|
89
|
-
const existing = servers?.[ADMIN_MCP_NAME];
|
|
90
|
-
if (existing !== undefined) {
|
|
91
|
-
if (!isRecord(existing) || existing.url !== ADMIN_MCP_URL || existing.command !== undefined) {
|
|
92
|
-
throw new Error(
|
|
93
|
-
`${ADMIN_MCP_NAME} already has a different configuration in ${file}. Rename or remove that entry before running setup.`
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
if (agent === 'claude-code' && existing.type !== 'http') {
|
|
97
|
-
throw new Error(`Set type to "http" for ${ADMIN_MCP_NAME} in ${file} before running setup.`);
|
|
98
|
-
}
|
|
99
|
-
return { path: file, original, contents: undefined };
|
|
100
|
-
}
|
|
101
|
-
const newline = source.includes('\r\n') ? '\r\n' : '\n';
|
|
102
|
-
let contents: string;
|
|
103
|
-
if (agent === 'codex') {
|
|
104
|
-
contents = `${source}${newline}[mcp_servers.${ADMIN_MCP_NAME}]${newline}url = "${ADMIN_MCP_URL}"${newline}`;
|
|
105
|
-
try {
|
|
106
|
-
parseToml(contents);
|
|
107
|
-
} catch {
|
|
108
|
-
throw new Error(
|
|
109
|
-
`Cannot safely extend ${file}. Add a ${ADMIN_MCP_NAME} entry with url = "${ADMIN_MCP_URL}" to mcp_servers manually.`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
const server: Record<string, string> = { url: ADMIN_MCP_URL };
|
|
114
|
-
if (agent === 'claude-code') server.type = 'http';
|
|
115
|
-
contents = applyEdits(
|
|
116
|
-
source || '{}',
|
|
117
|
-
modify(source || '{}', [key, ADMIN_MCP_NAME], server, {
|
|
118
|
-
formattingOptions: { insertSpaces: true, tabSize: 2, eol: newline },
|
|
119
|
-
})
|
|
120
|
-
);
|
|
121
|
-
if (!contents.endsWith(newline)) contents += newline;
|
|
122
|
-
}
|
|
123
|
-
return { path: file, original, contents };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export async function writeMcpConfig(plan: McpConfigPlan): Promise<void> {
|
|
127
|
-
if ((await readConfig(plan.path)) !== plan.original) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`${plan.path} changed during setup. Run setup again to preserve those changes.`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
if (plan.contents === undefined) return;
|
|
133
|
-
await fs.mkdir(path.dirname(plan.path), { recursive: true, mode: 0o700 });
|
|
134
|
-
let mode = 0o600;
|
|
135
|
-
if (plan.original !== undefined) mode = (await fs.stat(plan.path)).mode;
|
|
136
|
-
const temporaryPath = `${plan.path}.${randomUUID()}.tmp`;
|
|
137
|
-
try {
|
|
138
|
-
await fs.writeFile(temporaryPath, plan.contents, { mode, flag: 'wx' });
|
|
139
|
-
if (plan.original !== undefined) await fs.chmod(temporaryPath, mode);
|
|
140
|
-
await fs.rename(temporaryPath, plan.path);
|
|
141
|
-
} finally {
|
|
142
|
-
await fs.rm(temporaryPath, { force: true });
|
|
143
|
-
}
|
|
144
|
-
}
|
package/src/agent-setup.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { checkbox } from '@inquirer/prompts';
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { stripVTControlCharacters } from 'node:util';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
ADMIN_MCP_NAME,
|
|
10
|
-
ADMIN_MCP_URL,
|
|
11
|
-
prepareMcpConfig,
|
|
12
|
-
writeMcpConfig,
|
|
13
|
-
type SetupAgent,
|
|
14
|
-
} from './agent-setup-config.js';
|
|
15
|
-
import { detectAgent } from './agent.js';
|
|
16
|
-
|
|
17
|
-
export const SETUP_AGENTS: SetupAgent[] = ['claude-code', 'codex', 'cursor'];
|
|
18
|
-
|
|
19
|
-
const AGENT_LABELS: Record<SetupAgent, string> = {
|
|
20
|
-
'claude-code': 'Claude Code',
|
|
21
|
-
codex: 'Codex',
|
|
22
|
-
cursor: 'Cursor',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type SetupOptions = {
|
|
26
|
-
agents?: string[];
|
|
27
|
-
global: boolean;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function isSetupAgent(value: string): value is SetupAgent {
|
|
31
|
-
return SETUP_AGENTS.some((agent) => agent === value);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function detectedAgents(): SetupAgent[] {
|
|
35
|
-
const homeDir = os.homedir();
|
|
36
|
-
const current = detectAgent();
|
|
37
|
-
return SETUP_AGENTS.filter((agent) => {
|
|
38
|
-
if (agent === 'codex') {
|
|
39
|
-
return (
|
|
40
|
-
current === 'codex_cli' ||
|
|
41
|
-
existsSync(process.env.CODEX_HOME || path.join(homeDir, '.codex'))
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
if (agent === 'claude-code') {
|
|
45
|
-
return (
|
|
46
|
-
current === 'claude_code' ||
|
|
47
|
-
existsSync(process.env.CLAUDE_CONFIG_DIR || path.join(homeDir, '.claude'))
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return (
|
|
51
|
-
current === 'cursor' || current === 'cursor-cli' || existsSync(path.join(homeDir, '.cursor'))
|
|
52
|
-
);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function installSkills(agents: SetupAgent[], global: boolean): Promise<void> {
|
|
57
|
-
const args = [
|
|
58
|
-
'--yes',
|
|
59
|
-
'skills@1.7.4',
|
|
60
|
-
'add',
|
|
61
|
-
'https://mintlify.com/docs',
|
|
62
|
-
'--agent',
|
|
63
|
-
...agents,
|
|
64
|
-
'--yes',
|
|
65
|
-
];
|
|
66
|
-
if (global) args.push('--global');
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const child = spawn('npx', args, {
|
|
69
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
70
|
-
shell: process.platform === 'win32',
|
|
71
|
-
});
|
|
72
|
-
let output = '';
|
|
73
|
-
const recordOutput = (chunk: Buffer) => {
|
|
74
|
-
output = (output + chunk.toString()).slice(-65_536);
|
|
75
|
-
};
|
|
76
|
-
child.stdout.on('data', (chunk: Buffer) => {
|
|
77
|
-
recordOutput(chunk);
|
|
78
|
-
process.stdout.write(chunk.toString());
|
|
79
|
-
});
|
|
80
|
-
child.stderr.on('data', (chunk: Buffer) => {
|
|
81
|
-
recordOutput(chunk);
|
|
82
|
-
process.stderr.write(chunk.toString());
|
|
83
|
-
});
|
|
84
|
-
child.on('error', () =>
|
|
85
|
-
reject(new Error('Could not run npx. Install npm and run setup again.'))
|
|
86
|
-
);
|
|
87
|
-
child.on('close', (code, signal) => {
|
|
88
|
-
if (code !== 0 || /Failed to install\s+\d+/.test(stripVTControlCharacters(output))) {
|
|
89
|
-
reject(
|
|
90
|
-
new Error(
|
|
91
|
-
`Skills installation failed (${signal ?? code}). Review the installer output and run setup again.`
|
|
92
|
-
)
|
|
93
|
-
);
|
|
94
|
-
} else {
|
|
95
|
-
resolve();
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function setupAgent(options: SetupOptions): Promise<void> {
|
|
102
|
-
const [major = 0, minor = 0] = process.versions.node.split('.').map(Number);
|
|
103
|
-
if (major < 22 || (major === 22 && minor < 20)) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
'mint agent setup requires Node.js 22.20 or later to install skills. Upgrade Node.js and try again.'
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
109
|
-
let agents: SetupAgent[] = [];
|
|
110
|
-
for (const agent of options.agents ?? []) {
|
|
111
|
-
if (!isSetupAgent(agent)) throw new Error(`Unsupported agent: ${agent}`);
|
|
112
|
-
if (!agents.includes(agent)) agents.push(agent);
|
|
113
|
-
}
|
|
114
|
-
if (agents.length === 0) {
|
|
115
|
-
const detected = detectedAgents();
|
|
116
|
-
if (!interactive) {
|
|
117
|
-
agents = detected;
|
|
118
|
-
} else {
|
|
119
|
-
agents = await checkbox({
|
|
120
|
-
message: 'Which agents should use Mintlify?',
|
|
121
|
-
choices: SETUP_AGENTS.map((agent) => ({
|
|
122
|
-
name: AGENT_LABELS[agent],
|
|
123
|
-
value: agent,
|
|
124
|
-
checked: detected.includes(agent),
|
|
125
|
-
})),
|
|
126
|
-
required: true,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (agents.length === 0) {
|
|
131
|
-
throw new Error('No supported agents detected. Pass --agent claude-code, codex, or cursor.');
|
|
132
|
-
}
|
|
133
|
-
const location = { cwd: process.cwd(), homeDir: os.homedir(), global: options.global };
|
|
134
|
-
const plans = await Promise.all(agents.map((agent) => prepareMcpConfig(agent, location)));
|
|
135
|
-
const scope = options.global ? 'your user account' : 'this project';
|
|
136
|
-
process.stdout.write(`Setting up Mintlify skills and Admin MCP for ${scope}.\n`);
|
|
137
|
-
await installSkills(agents, options.global);
|
|
138
|
-
for (const plan of plans) {
|
|
139
|
-
await writeMcpConfig(plan);
|
|
140
|
-
const action = plan.contents === undefined ? 'Already configured' : 'Configured';
|
|
141
|
-
process.stdout.write(`${action}: ${plan.path}\n`);
|
|
142
|
-
}
|
|
143
|
-
process.stdout.write(
|
|
144
|
-
'\nAdmin MCP is configured. Complete OAuth sign-in to grant account and project access:\n'
|
|
145
|
-
);
|
|
146
|
-
for (const agent of agents) {
|
|
147
|
-
if (agent === 'codex') {
|
|
148
|
-
let command = `codex mcp login ${ADMIN_MCP_NAME}`;
|
|
149
|
-
if (!options.global) {
|
|
150
|
-
const config = `mcp_servers.${ADMIN_MCP_NAME}.url='${ADMIN_MCP_URL}'`;
|
|
151
|
-
command = `codex -c "${config}" mcp login ${ADMIN_MCP_NAME}`;
|
|
152
|
-
}
|
|
153
|
-
process.stdout.write(
|
|
154
|
-
` Codex: run ${command}. Trust the project before using its MCP configuration.\n`
|
|
155
|
-
);
|
|
156
|
-
} else if (agent === 'claude-code') {
|
|
157
|
-
process.stdout.write(
|
|
158
|
-
` Claude Code: open /mcp and authenticate ${ADMIN_MCP_NAME}. Approve the project server if prompted.\n`
|
|
159
|
-
);
|
|
160
|
-
} else {
|
|
161
|
-
process.stdout.write(` Cursor: open MCP settings and connect ${ADMIN_MCP_NAME}.\n`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
process.stdout.write('Setup: https://mintlify.com/docs/ai/mintlify-mcp\n');
|
|
165
|
-
}
|