@lyrra/mcp-server 1.1.3 → 1.1.7
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/README.md +80 -250
- package/dist/auth-session.js +171 -0
- package/dist/eduflow-block-docs.js +438 -0
- package/dist/http-incoming-auth.js +48 -0
- package/dist/http-main.js +104 -0
- package/dist/index.js +16 -12
- package/dist/lyrra-http.js +80 -0
- package/dist/lyrra-mcp-core.js +174 -0
- package/dist/openapi-parse.js +61 -0
- package/dist/register-eduflow-block-tools.js +31 -0
- package/package.json +41 -13
- package/Dockerfile +0 -16
- package/dist/client.d.ts +0 -23
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -92
- package/dist/client.js.map +0 -1
- package/dist/config.d.ts +0 -8
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -8
- package/dist/config.js.map +0 -1
- package/dist/http-server.d.ts +0 -8
- package/dist/http-server.d.ts.map +0 -1
- package/dist/http-server.js +0 -481
- package/dist/http-server.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/resources/block-types.d.ts +0 -318
- package/dist/resources/block-types.d.ts.map +0 -1
- package/dist/resources/block-types.js +0 -297
- package/dist/resources/block-types.js.map +0 -1
- package/dist/resources/flow-schema.d.ts +0 -147
- package/dist/resources/flow-schema.d.ts.map +0 -1
- package/dist/resources/flow-schema.js +0 -143
- package/dist/resources/flow-schema.js.map +0 -1
- package/dist/server-factory.d.ts +0 -8
- package/dist/server-factory.d.ts.map +0 -1
- package/dist/server-factory.js +0 -82
- package/dist/server-factory.js.map +0 -1
- package/dist/tools/admin.d.ts +0 -265
- package/dist/tools/admin.d.ts.map +0 -1
- package/dist/tools/admin.js +0 -118
- package/dist/tools/admin.js.map +0 -1
- package/dist/tools/ai-designer.d.ts +0 -297
- package/dist/tools/ai-designer.d.ts.map +0 -1
- package/dist/tools/ai-designer.js +0 -89
- package/dist/tools/ai-designer.js.map +0 -1
- package/dist/tools/analytics.d.ts +0 -95
- package/dist/tools/analytics.d.ts.map +0 -1
- package/dist/tools/analytics.js +0 -44
- package/dist/tools/analytics.js.map +0 -1
- package/dist/tools/auth.d.ts +0 -61
- package/dist/tools/auth.d.ts.map +0 -1
- package/dist/tools/auth.js +0 -36
- package/dist/tools/auth.js.map +0 -1
- package/dist/tools/blocks.d.ts +0 -457
- package/dist/tools/blocks.d.ts.map +0 -1
- package/dist/tools/blocks.js +0 -173
- package/dist/tools/blocks.js.map +0 -1
- package/dist/tools/connections.d.ts +0 -173
- package/dist/tools/connections.d.ts.map +0 -1
- package/dist/tools/connections.js +0 -81
- package/dist/tools/connections.js.map +0 -1
- package/dist/tools/eduflow.d.ts +0 -409
- package/dist/tools/eduflow.d.ts.map +0 -1
- package/dist/tools/eduflow.js +0 -139
- package/dist/tools/eduflow.js.map +0 -1
- package/dist/tools/participants.d.ts +0 -221
- package/dist/tools/participants.d.ts.map +0 -1
- package/dist/tools/participants.js +0 -70
- package/dist/tools/participants.js.map +0 -1
- package/dist/tools/presentation.d.ts +0 -233
- package/dist/tools/presentation.d.ts.map +0 -1
- package/dist/tools/presentation.js +0 -57
- package/dist/tools/presentation.js.map +0 -1
- package/dist/tools/projects.d.ts +0 -131
- package/dist/tools/projects.d.ts.map +0 -1
- package/dist/tools/projects.js +0 -55
- package/dist/tools/projects.js.map +0 -1
- package/dist/tools/resources.d.ts +0 -93
- package/dist/tools/resources.d.ts.map +0 -1
- package/dist/tools/resources.js +0 -37
- package/dist/tools/resources.js.map +0 -1
- package/dist/tools/store.d.ts +0 -125
- package/dist/tools/store.d.ts.map +0 -1
- package/dist/tools/store.js +0 -66
- package/dist/tools/store.js.map +0 -1
- package/mcp-config.example.json +0 -14
- package/src/client.ts +0 -106
- package/src/config.ts +0 -7
- package/src/http-server.ts +0 -591
- package/src/index.ts +0 -23
- package/src/resources/block-types.ts +0 -298
- package/src/resources/flow-schema.ts +0 -148
- package/src/server-factory.ts +0 -109
- package/src/tools/admin.ts +0 -128
- package/src/tools/ai-designer.ts +0 -97
- package/src/tools/analytics.ts +0 -49
- package/src/tools/auth.ts +0 -39
- package/src/tools/blocks.ts +0 -186
- package/src/tools/connections.ts +0 -83
- package/src/tools/eduflow.ts +0 -150
- package/src/tools/participants.ts +0 -77
- package/src/tools/presentation.ts +0 -61
- package/src/tools/projects.ts +0 -61
- package/src/tools/resources.ts +0 -41
- package/src/tools/store.ts +0 -67
- package/tsconfig.json +0 -19
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { LyrraClient } from '../client.js';
|
|
3
|
-
import { client as defaultClient } from '../client.js';
|
|
4
|
-
|
|
5
|
-
export function createParticipantsTools(c: LyrraClient) {
|
|
6
|
-
return {
|
|
7
|
-
participant_list: {
|
|
8
|
-
description: 'Lister tous les participants/étudiants inscrits à un parcours EduFlow avec leur progression.',
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
11
|
-
}),
|
|
12
|
-
handler: async ({ flowId }: { flowId: string }) => {
|
|
13
|
-
return c.get(`/flows/${flowId}/students`, 'eduflow');
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
participant_add: {
|
|
18
|
-
description: 'Ajouter un ou plusieurs participants à un parcours EduFlow. Chaque participant reçoit un lien unique.',
|
|
19
|
-
inputSchema: z.object({
|
|
20
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
21
|
-
participants: z.array(z.object({
|
|
22
|
-
email: z.string().email().describe('Email du participant'),
|
|
23
|
-
firstName: z.string().optional().describe('Prénom'),
|
|
24
|
-
lastName: z.string().optional().describe('Nom'),
|
|
25
|
-
})).describe('Liste des participants à ajouter'),
|
|
26
|
-
}),
|
|
27
|
-
handler: async ({ flowId, participants }: any) => {
|
|
28
|
-
return c.post(`/flows/${flowId}/students`, { students: participants }, 'eduflow');
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
participant_remove: {
|
|
33
|
-
description: 'Retirer un participant d\'un parcours EduFlow.',
|
|
34
|
-
inputSchema: z.object({
|
|
35
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
36
|
-
studentId: z.string().uuid().describe('ID de l\'inscription étudiant'),
|
|
37
|
-
}),
|
|
38
|
-
handler: async ({ flowId, studentId }: { flowId: string; studentId: string }) => {
|
|
39
|
-
return c.delete(`/flows/${flowId}/students/${studentId}`, 'eduflow');
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
participant_get_progress: {
|
|
44
|
-
description: 'Récupérer la progression détaillée d\'un participant : blocs complétés, scores, temps passé par bloc.',
|
|
45
|
-
inputSchema: z.object({
|
|
46
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
47
|
-
studentToken: z.string().describe('Token unique du participant'),
|
|
48
|
-
}),
|
|
49
|
-
handler: async ({ flowId, studentToken }: { flowId: string; studentToken: string }) => {
|
|
50
|
-
return c.get(`/eduflow/progress/stats/${flowId}/${studentToken}`);
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
participant_get_overview: {
|
|
55
|
-
description: 'Vue d\'ensemble d\'un participant global : tous les parcours suivis, certifications, progression globale.',
|
|
56
|
-
inputSchema: z.object({
|
|
57
|
-
participantId: z.string().uuid().describe('ID global du participant'),
|
|
58
|
-
}),
|
|
59
|
-
handler: async ({ participantId }: { participantId: string }) => {
|
|
60
|
-
return c.get(`/participants/${participantId}/overview`, 'eduflow');
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
participant_get_flow_stats: {
|
|
65
|
-
description: 'Récupérer les statistiques de tous les participants d\'un parcours (taux de complétion, scores moyens, temps moyen).',
|
|
66
|
-
inputSchema: z.object({
|
|
67
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
68
|
-
}),
|
|
69
|
-
handler: async ({ flowId }: { flowId: string }) => {
|
|
70
|
-
return c.get(`/eduflow/progress/stats/flow/${flowId}`);
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Backward compatibility for stdio mode
|
|
77
|
-
export const participantsTools = createParticipantsTools(defaultClient);
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { LyrraClient } from '../client.js';
|
|
3
|
-
import { client as defaultClient } from '../client.js';
|
|
4
|
-
|
|
5
|
-
export function createPresentationTools(c: LyrraClient) {
|
|
6
|
-
return {
|
|
7
|
-
presentation_get: {
|
|
8
|
-
description: 'Récupérer la page de présentation d\'un parcours EduFlow (description, objectifs, image de couverture, structure affichée).',
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
11
|
-
}),
|
|
12
|
-
handler: async ({ flowId }: { flowId: string }) => {
|
|
13
|
-
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
14
|
-
return {
|
|
15
|
-
presentationEnabled: flow.presentationEnabled,
|
|
16
|
-
presentationData: flow.presentationData,
|
|
17
|
-
objectives: flow.objectives,
|
|
18
|
-
title: flow.title,
|
|
19
|
-
description: flow.description,
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
presentation_update: {
|
|
25
|
-
description: `Mettre à jour la page de présentation d'un parcours. La présentation est la page publique visible par les futurs participants.
|
|
26
|
-
Structure de presentationData : { heroTitle, heroSubtitle, heroImage, sections[{ type, title, content }], ctaText, ctaUrl }`,
|
|
27
|
-
inputSchema: z.object({
|
|
28
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
29
|
-
presentationData: z.object({
|
|
30
|
-
heroTitle: z.string().optional().describe('Titre principal de la page'),
|
|
31
|
-
heroSubtitle: z.string().optional().describe('Sous-titre'),
|
|
32
|
-
heroImage: z.string().optional().describe('URL de l\'image de couverture'),
|
|
33
|
-
sections: z.array(z.object({
|
|
34
|
-
type: z.string().describe('Type de section (text, objectives, structure, testimonials)'),
|
|
35
|
-
title: z.string().describe('Titre de la section'),
|
|
36
|
-
content: z.any().describe('Contenu de la section'),
|
|
37
|
-
})).optional().describe('Sections de la page'),
|
|
38
|
-
ctaText: z.string().optional().describe('Texte du bouton d\'action'),
|
|
39
|
-
ctaUrl: z.string().optional().describe('URL du bouton d\'action'),
|
|
40
|
-
}).describe('Données de la page de présentation'),
|
|
41
|
-
}),
|
|
42
|
-
handler: async ({ flowId, presentationData }: any) => {
|
|
43
|
-
return c.put(`/flows/${flowId}`, { presentationData }, 'eduflow');
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
presentation_toggle: {
|
|
48
|
-
description: 'Activer ou désactiver la page de présentation publique d\'un parcours.',
|
|
49
|
-
inputSchema: z.object({
|
|
50
|
-
flowId: z.string().uuid().describe('ID du parcours'),
|
|
51
|
-
enabled: z.boolean().describe('true pour activer, false pour désactiver'),
|
|
52
|
-
}),
|
|
53
|
-
handler: async ({ flowId, enabled }: { flowId: string; enabled: boolean }) => {
|
|
54
|
-
return c.put(`/flows/${flowId}`, { presentationEnabled: enabled }, 'eduflow');
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Backward compatibility for stdio mode
|
|
61
|
-
export const presentationTools = createPresentationTools(defaultClient);
|
package/src/tools/projects.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { LyrraClient } from '../client.js';
|
|
3
|
-
import { client as defaultClient } from '../client.js';
|
|
4
|
-
|
|
5
|
-
export function createProjectsTools(c: LyrraClient) {
|
|
6
|
-
return {
|
|
7
|
-
project_list: {
|
|
8
|
-
description: 'Lister tous les projets audio de l\'utilisateur (PDF convertis en audio).',
|
|
9
|
-
inputSchema: z.object({}),
|
|
10
|
-
handler: async () => {
|
|
11
|
-
return c.get('/projects');
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
project_get: {
|
|
16
|
-
description: 'Détails d\'un projet audio : titre, chapitres, voix, durée, statut, fichiers générés.',
|
|
17
|
-
inputSchema: z.object({
|
|
18
|
-
projectId: z.string().uuid().describe('ID du projet'),
|
|
19
|
-
}),
|
|
20
|
-
handler: async ({ projectId }: { projectId: string }) => {
|
|
21
|
-
return c.get(`/projects/${projectId}`);
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
project_create: {
|
|
26
|
-
description: 'Créer un nouveau projet audio.',
|
|
27
|
-
inputSchema: z.object({
|
|
28
|
-
title: z.string().describe('Titre du projet'),
|
|
29
|
-
description: z.string().optional().describe('Description'),
|
|
30
|
-
}),
|
|
31
|
-
handler: async (data: any) => {
|
|
32
|
-
return c.post('/projects', data);
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
project_update: {
|
|
37
|
-
description: 'Mettre à jour un projet audio (titre, description, paramètres de voix).',
|
|
38
|
-
inputSchema: z.object({
|
|
39
|
-
projectId: z.string().uuid().describe('ID du projet'),
|
|
40
|
-
title: z.string().optional().describe('Nouveau titre'),
|
|
41
|
-
description: z.string().optional().describe('Nouvelle description'),
|
|
42
|
-
}),
|
|
43
|
-
handler: async ({ projectId, ...data }: any) => {
|
|
44
|
-
return c.put(`/projects/${projectId}`, data);
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
project_delete: {
|
|
49
|
-
description: 'Supprimer un projet audio et tous ses fichiers associés.',
|
|
50
|
-
inputSchema: z.object({
|
|
51
|
-
projectId: z.string().uuid().describe('ID du projet à supprimer'),
|
|
52
|
-
}),
|
|
53
|
-
handler: async ({ projectId }: { projectId: string }) => {
|
|
54
|
-
return c.delete(`/projects/${projectId}`);
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Backward compatibility for stdio mode
|
|
61
|
-
export const projectsTools = createProjectsTools(defaultClient);
|
package/src/tools/resources.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { LyrraClient } from '../client.js';
|
|
3
|
-
import { client as defaultClient } from '../client.js';
|
|
4
|
-
|
|
5
|
-
export function createResourcesTools(c: LyrraClient) {
|
|
6
|
-
return {
|
|
7
|
-
resource_list: {
|
|
8
|
-
description: 'Lister les ressources de l\'utilisateur (images, documents, sons, vidéos) avec pagination.',
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
type: z.enum(['images', 'documents', 'sounds', 'videos']).describe('Type de ressource'),
|
|
11
|
-
}),
|
|
12
|
-
handler: async ({ type }: { type: string }) => {
|
|
13
|
-
return c.get(`/user-resources/${type}`);
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
resource_delete: {
|
|
18
|
-
description: 'Supprimer une ressource uploadée.',
|
|
19
|
-
inputSchema: z.object({
|
|
20
|
-
type: z.enum(['images', 'documents', 'sounds', 'videos']).describe('Type de ressource'),
|
|
21
|
-
resourceId: z.string().uuid().describe('ID de la ressource'),
|
|
22
|
-
}),
|
|
23
|
-
handler: async ({ type, resourceId }: { type: string; resourceId: string }) => {
|
|
24
|
-
return c.delete(`/user-resources/${type}/${resourceId}`);
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
resource_list_categories: {
|
|
29
|
-
description: 'Lister les catégories disponibles pour un type de ressource.',
|
|
30
|
-
inputSchema: z.object({
|
|
31
|
-
type: z.enum(['images', 'documents', 'sounds', 'videos']).describe('Type de ressource'),
|
|
32
|
-
}),
|
|
33
|
-
handler: async ({ type }: { type: string }) => {
|
|
34
|
-
return c.get(`/categories/${type}`);
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Backward compatibility for stdio mode
|
|
41
|
-
export const resourcesTools = createResourcesTools(defaultClient);
|
package/src/tools/store.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { LyrraClient } from '../client.js';
|
|
3
|
-
import { client as defaultClient } from '../client.js';
|
|
4
|
-
|
|
5
|
-
export function createStoreTools(c: LyrraClient) {
|
|
6
|
-
return {
|
|
7
|
-
store_list_audiobooks: {
|
|
8
|
-
description: 'Lister les audiobooks disponibles dans le store LYRRA. Supporte la pagination, recherche et filtres.',
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
page: z.number().optional().describe('Page (défaut: 1)'),
|
|
11
|
-
limit: z.number().optional().describe('Nombre par page (défaut: 20)'),
|
|
12
|
-
search: z.string().optional().describe('Recherche par titre/auteur'),
|
|
13
|
-
category: z.string().optional().describe('Filtrer par catégorie'),
|
|
14
|
-
featured: z.boolean().optional().describe('Uniquement les audiobooks mis en avant'),
|
|
15
|
-
}),
|
|
16
|
-
handler: async ({ page, limit, search, category, featured }: any) => {
|
|
17
|
-
const params = new URLSearchParams();
|
|
18
|
-
if (page) params.set('page', String(page));
|
|
19
|
-
if (limit) params.set('limit', String(limit));
|
|
20
|
-
if (search) params.set('search', search);
|
|
21
|
-
if (category) params.set('category', category);
|
|
22
|
-
if (featured) params.set('featured', 'true');
|
|
23
|
-
const query = params.toString() ? `?${params}` : '';
|
|
24
|
-
return c.post(`/store/public/audiobooks${query}`, {});
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
store_get_audiobook: {
|
|
29
|
-
description: 'Détails complets d\'un audiobook : chapitres, auteur, avis, prix en crédits, statistiques.',
|
|
30
|
-
inputSchema: z.object({
|
|
31
|
-
audiobookId: z.string().describe('ID de l\'audiobook'),
|
|
32
|
-
}),
|
|
33
|
-
handler: async ({ audiobookId }: { audiobookId: string }) => {
|
|
34
|
-
return c.get(`/store/public/audiobooks/${audiobookId}`);
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
store_list_authors: {
|
|
39
|
-
description: 'Lister les auteurs mis en avant sur le store.',
|
|
40
|
-
inputSchema: z.object({}),
|
|
41
|
-
handler: async () => {
|
|
42
|
-
return c.get('/store/public/authors/featured');
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
store_my_library: {
|
|
47
|
-
description: 'Récupérer ma bibliothèque d\'audiobooks achetés.',
|
|
48
|
-
inputSchema: z.object({}),
|
|
49
|
-
handler: async () => {
|
|
50
|
-
return c.get('/store/my-library');
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
store_search: {
|
|
55
|
-
description: 'Rechercher des audiobooks dans le store par mot-clé.',
|
|
56
|
-
inputSchema: z.object({
|
|
57
|
-
query: z.string().describe('Terme de recherche'),
|
|
58
|
-
}),
|
|
59
|
-
handler: async ({ query }: { query: string }) => {
|
|
60
|
-
return c.post('/store/public/audiobooks', { search: query });
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Backward compatibility for stdio mode
|
|
67
|
-
export const storeTools = createStoreTools(defaultClient);
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"declarationMap": true,
|
|
15
|
-
"sourceMap": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
19
|
-
}
|