@lastbrain/app 2.0.1 → 2.0.2

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.
Files changed (131) hide show
  1. package/dist/config/version.d.ts +7 -0
  2. package/dist/config/version.d.ts.map +1 -0
  3. package/dist/config/version.js +25 -0
  4. package/dist/src/__tests__/module-registry.test.d.ts +2 -0
  5. package/dist/src/__tests__/module-registry.test.d.ts.map +1 -0
  6. package/dist/src/__tests__/module-registry.test.js +53 -0
  7. package/dist/src/app-shell/(admin)/layout.d.ts +4 -0
  8. package/dist/src/app-shell/(admin)/layout.d.ts.map +1 -0
  9. package/dist/src/app-shell/(admin)/layout.js +5 -0
  10. package/dist/src/app-shell/(auth)/layout.d.ts +4 -0
  11. package/dist/src/app-shell/(auth)/layout.d.ts.map +1 -0
  12. package/dist/src/app-shell/(auth)/layout.js +5 -0
  13. package/dist/src/app-shell/(public)/page.d.ts +2 -0
  14. package/dist/src/app-shell/(public)/page.d.ts.map +1 -0
  15. package/dist/src/app-shell/(public)/page.js +5 -0
  16. package/dist/src/app-shell/layout.d.ts +3 -0
  17. package/dist/src/app-shell/layout.d.ts.map +1 -0
  18. package/dist/src/app-shell/layout.js +3 -0
  19. package/dist/src/app-shell/not-found.d.ts +2 -0
  20. package/dist/src/app-shell/not-found.d.ts.map +1 -0
  21. package/dist/src/app-shell/not-found.js +10 -0
  22. package/dist/src/auth/authHelpers.d.ts +7 -0
  23. package/dist/src/auth/authHelpers.d.ts.map +1 -0
  24. package/dist/src/auth/authHelpers.js +19 -0
  25. package/dist/src/auth/useAuthSession.d.ts +7 -0
  26. package/dist/src/auth/useAuthSession.d.ts.map +1 -0
  27. package/dist/src/auth/useAuthSession.js +49 -0
  28. package/dist/src/cli.d.ts +3 -0
  29. package/dist/src/cli.d.ts.map +1 -0
  30. package/dist/src/cli.js +143 -0
  31. package/dist/src/components/NotificationContainer.d.ts +2 -0
  32. package/dist/src/components/NotificationContainer.d.ts.map +1 -0
  33. package/dist/src/components/NotificationContainer.js +8 -0
  34. package/dist/src/hooks/useNotifications.d.ts +30 -0
  35. package/dist/src/hooks/useNotifications.d.ts.map +1 -0
  36. package/dist/src/hooks/useNotifications.js +165 -0
  37. package/dist/src/index.d.ts +22 -0
  38. package/dist/src/index.d.ts.map +1 -0
  39. package/dist/src/index.js +22 -0
  40. package/dist/src/layouts/AdminLayout.d.ts +4 -0
  41. package/dist/src/layouts/AdminLayout.d.ts.map +1 -0
  42. package/dist/src/layouts/AdminLayout.js +4 -0
  43. package/dist/src/layouts/AdminLayoutWithSidebar.d.ts +10 -0
  44. package/dist/src/layouts/AdminLayoutWithSidebar.d.ts.map +1 -0
  45. package/dist/src/layouts/AdminLayoutWithSidebar.js +62 -0
  46. package/dist/src/layouts/AppProviders.d.ts +27 -0
  47. package/dist/src/layouts/AppProviders.d.ts.map +1 -0
  48. package/dist/src/layouts/AppProviders.js +48 -0
  49. package/dist/src/layouts/AuthLayout.d.ts +4 -0
  50. package/dist/src/layouts/AuthLayout.d.ts.map +1 -0
  51. package/dist/src/layouts/AuthLayout.js +4 -0
  52. package/dist/src/layouts/AuthLayoutWithSidebar.d.ts +12 -0
  53. package/dist/src/layouts/AuthLayoutWithSidebar.d.ts.map +1 -0
  54. package/dist/src/layouts/AuthLayoutWithSidebar.js +60 -0
  55. package/dist/src/layouts/PublicLayout.d.ts +8 -0
  56. package/dist/src/layouts/PublicLayout.d.ts.map +1 -0
  57. package/dist/src/layouts/PublicLayout.js +6 -0
  58. package/dist/src/layouts/PublicLayoutWithSidebar.d.ts +9 -0
  59. package/dist/src/layouts/PublicLayoutWithSidebar.d.ts.map +1 -0
  60. package/dist/src/layouts/PublicLayoutWithSidebar.js +60 -0
  61. package/dist/src/layouts/RootLayout.d.ts +6 -0
  62. package/dist/src/layouts/RootLayout.d.ts.map +1 -0
  63. package/dist/src/layouts/RootLayout.js +9 -0
  64. package/dist/src/modules/module-loader.d.ts +5 -0
  65. package/dist/src/modules/module-loader.d.ts.map +1 -0
  66. package/dist/src/modules/module-loader.js +10 -0
  67. package/dist/src/scripts/db-init.d.ts +2 -0
  68. package/dist/src/scripts/db-init.d.ts.map +1 -0
  69. package/dist/src/scripts/db-init.js +300 -0
  70. package/dist/src/scripts/db-migrations-sync.d.ts +2 -0
  71. package/dist/src/scripts/db-migrations-sync.d.ts.map +1 -0
  72. package/dist/src/scripts/db-migrations-sync.js +84 -0
  73. package/dist/src/scripts/dev-sync.d.ts +2 -0
  74. package/dist/src/scripts/dev-sync.d.ts.map +1 -0
  75. package/dist/src/scripts/dev-sync.js +194 -0
  76. package/dist/src/scripts/init-app.d.ts +12 -0
  77. package/dist/src/scripts/init-app.d.ts.map +1 -0
  78. package/dist/src/scripts/init-app.js +2175 -0
  79. package/dist/src/scripts/module-add.d.ts +2 -0
  80. package/dist/src/scripts/module-add.d.ts.map +1 -0
  81. package/dist/src/scripts/module-add.js +232 -0
  82. package/dist/src/scripts/module-build.d.ts +2 -0
  83. package/dist/src/scripts/module-build.d.ts.map +1 -0
  84. package/dist/src/scripts/module-build.js +1280 -0
  85. package/dist/src/scripts/module-create.d.ts +28 -0
  86. package/dist/src/scripts/module-create.d.ts.map +1 -0
  87. package/dist/src/scripts/module-create.js +1429 -0
  88. package/dist/src/scripts/module-delete.d.ts +6 -0
  89. package/dist/src/scripts/module-delete.d.ts.map +1 -0
  90. package/dist/src/scripts/module-delete.js +147 -0
  91. package/dist/src/scripts/module-list.d.ts +2 -0
  92. package/dist/src/scripts/module-list.d.ts.map +1 -0
  93. package/dist/src/scripts/module-list.js +61 -0
  94. package/dist/src/scripts/module-remove.d.ts +2 -0
  95. package/dist/src/scripts/module-remove.d.ts.map +1 -0
  96. package/dist/src/scripts/module-remove.js +311 -0
  97. package/dist/src/scripts/readme-build.d.ts +2 -0
  98. package/dist/src/scripts/readme-build.d.ts.map +1 -0
  99. package/dist/src/scripts/readme-build.js +39 -0
  100. package/dist/src/scripts/script-runner.d.ts +5 -0
  101. package/dist/src/scripts/script-runner.d.ts.map +1 -0
  102. package/dist/src/scripts/script-runner.js +25 -0
  103. package/dist/src/templates/AuthGuidePage.d.ts +2 -0
  104. package/dist/src/templates/AuthGuidePage.d.ts.map +1 -0
  105. package/dist/src/templates/AuthGuidePage.js +9 -0
  106. package/dist/src/templates/DefaultDoc.d.ts +2 -0
  107. package/dist/src/templates/DefaultDoc.d.ts.map +1 -0
  108. package/dist/src/templates/DefaultDoc.js +240 -0
  109. package/dist/src/templates/DocPage.d.ts +17 -0
  110. package/dist/src/templates/DocPage.d.ts.map +1 -0
  111. package/dist/src/templates/DocPage.js +193 -0
  112. package/dist/src/templates/DocsPageWithModules.d.ts +2 -0
  113. package/dist/src/templates/DocsPageWithModules.d.ts.map +1 -0
  114. package/dist/src/templates/DocsPageWithModules.js +8 -0
  115. package/dist/src/templates/MigrationsGuidePage.d.ts +2 -0
  116. package/dist/src/templates/MigrationsGuidePage.d.ts.map +1 -0
  117. package/dist/src/templates/MigrationsGuidePage.js +11 -0
  118. package/dist/src/templates/ModuleGuidePage.d.ts +2 -0
  119. package/dist/src/templates/ModuleGuidePage.d.ts.map +1 -0
  120. package/dist/src/templates/ModuleGuidePage.js +14 -0
  121. package/dist/src/templates/SimpleDocPage.d.ts +2 -0
  122. package/dist/src/templates/SimpleDocPage.d.ts.map +1 -0
  123. package/dist/src/templates/SimpleDocPage.js +28 -0
  124. package/dist/src/templates/SimpleHomePage.d.ts +6 -0
  125. package/dist/src/templates/SimpleHomePage.d.ts.map +1 -0
  126. package/dist/src/templates/SimpleHomePage.js +7 -0
  127. package/dist/src/types/menu.d.ts +23 -0
  128. package/dist/src/types/menu.d.ts.map +1 -0
  129. package/dist/src/types/menu.js +1 -0
  130. package/package.json +4 -5
  131. package/src/scripts/init-app.ts +7 -76
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Supprime un module du monorepo (physiquement)
3
+ * Cette commande est réservée aux développeurs du framework
4
+ */
5
+ export declare function deleteModule(): Promise<void>;
6
+ //# sourceMappingURL=module-delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-delete.d.ts","sourceRoot":"","sources":["../../../src/scripts/module-delete.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAsB,YAAY,kBAkLjC"}
@@ -0,0 +1,147 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import inquirer from "inquirer";
5
+ import { fileURLToPath } from "url";
6
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ /**
10
+ * Supprime un module du monorepo (physiquement)
11
+ * Cette commande est réservée aux développeurs du framework
12
+ */
13
+ export async function deleteModule() {
14
+ const rootDir = path.resolve(__dirname, "../../../..");
15
+ console.log(chalk.blue("\n🗑️ Suppression d'un module du monorepo LastBrain\n"));
16
+ console.log(chalk.yellow("⚠️ ATTENTION: Cette opération supprime physiquement le module du monorepo!"));
17
+ console.log(chalk.gray("Cette commande est réservée aux développeurs du framework.\n"));
18
+ // Lister les modules disponibles
19
+ if (AVAILABLE_MODULES.length === 0) {
20
+ console.log(chalk.red("❌ Aucun module disponible dans le registre"));
21
+ process.exit(1);
22
+ }
23
+ const answers = await inquirer.prompt([
24
+ {
25
+ type: "select",
26
+ name: "moduleName",
27
+ message: "Quel module voulez-vous supprimer du monorepo ?",
28
+ choices: AVAILABLE_MODULES.map((m) => ({
29
+ name: `${m.emoji} ${m.name} - ${m.description}`,
30
+ value: m.name,
31
+ })),
32
+ },
33
+ {
34
+ type: "confirm",
35
+ name: "confirm",
36
+ message: (answers) => `Êtes-vous sûr de vouloir supprimer le module "${answers.moduleName}" ? Cette action est irréversible.`,
37
+ default: false,
38
+ },
39
+ ]);
40
+ if (!answers.confirm) {
41
+ console.log(chalk.gray("\n❌ Opération annulée"));
42
+ process.exit(0);
43
+ }
44
+ const moduleName = answers.moduleName;
45
+ const moduleMeta = AVAILABLE_MODULES.find((m) => m.name === moduleName);
46
+ if (!moduleMeta) {
47
+ console.log(chalk.red(`❌ Module ${moduleName} non trouvé`));
48
+ process.exit(1);
49
+ }
50
+ console.log(chalk.blue(`\n🗑️ Suppression du module ${moduleMeta.package}...\n`));
51
+ // 1. Supprimer le répertoire du module
52
+ // Extraire le nom du package correctement (gérer @lastbrain et @lastbrain-labs)
53
+ const packageName = moduleMeta.package
54
+ .replace("@lastbrain-labs/", "")
55
+ .replace("@lastbrain/", "");
56
+ const moduleDir = path.join(rootDir, "packages", packageName);
57
+ if (fs.existsSync(moduleDir)) {
58
+ console.log(chalk.yellow(`📁 Suppression du répertoire: ${moduleDir}`));
59
+ await fs.remove(moduleDir);
60
+ console.log(chalk.green(" ✓ Répertoire supprimé"));
61
+ }
62
+ else {
63
+ console.log(chalk.yellow(` ⚠️ Répertoire non trouvé: ${moduleDir}`));
64
+ }
65
+ // 2. Supprimer du registre central
66
+ console.log(chalk.yellow("\n📝 Mise à jour du registre central..."));
67
+ const moduleRegistryPath = path.join(rootDir, "packages", "core", "src", "config", "modules.ts");
68
+ if (fs.existsSync(moduleRegistryPath)) {
69
+ try {
70
+ let content = await fs.readFile(moduleRegistryPath, "utf-8");
71
+ // Vérifier si le module est dans le registre
72
+ if (!content.includes(`name: "${moduleName}"`)) {
73
+ console.log(chalk.yellow(` ⚠️ Module ${moduleName} n'est pas dans le registre`));
74
+ }
75
+ else {
76
+ // Parser et reconstruire le tableau proprement
77
+ const arrayMatch = content.match(/export const AVAILABLE_MODULES: ModuleMetadata\[\] = \[([\s\S]*?)\];/);
78
+ if (arrayMatch) {
79
+ const arrayContent = arrayMatch[1];
80
+ const modules = [];
81
+ let currentModule = "";
82
+ let braceDepth = 0;
83
+ // Parser chaque module
84
+ for (const line of arrayContent.split("\n")) {
85
+ if (line.trim().startsWith("{")) {
86
+ braceDepth++;
87
+ }
88
+ currentModule += line + "\n";
89
+ if (line.includes("},")) {
90
+ braceDepth--;
91
+ if (braceDepth === 0) {
92
+ // Module complet trouvé
93
+ if (!currentModule.includes(`name: "${moduleName}"`)) {
94
+ modules.push(currentModule.trim());
95
+ }
96
+ currentModule = "";
97
+ }
98
+ }
99
+ }
100
+ // Reconstruire le tableau
101
+ const newArrayContent = modules.length > 0 ? "\n " + modules.join("\n ") + "\n" : "\n";
102
+ content = content.replace(/export const AVAILABLE_MODULES: ModuleMetadata\[\] = \[([\s\S]*?)\];/, `export const AVAILABLE_MODULES: ModuleMetadata[] = [${newArrayContent}];`);
103
+ await fs.writeFile(moduleRegistryPath, content, "utf-8");
104
+ console.log(chalk.green(` ✓ Module ${moduleName} supprimé du registre`));
105
+ }
106
+ else {
107
+ console.log(chalk.yellow(" ⚠️ Format du registre non reconnu"));
108
+ }
109
+ }
110
+ }
111
+ catch (error) {
112
+ console.log(chalk.red(` ❌ Erreur lors de la mise à jour du registre: ${error}`));
113
+ }
114
+ }
115
+ // 3. Supprimer des scripts de publication
116
+ console.log(chalk.yellow("\n📝 Mise à jour du package.json racine..."));
117
+ const rootPackageJson = path.join(rootDir, "package.json");
118
+ if (fs.existsSync(rootPackageJson)) {
119
+ try {
120
+ const pkg = await fs.readJson(rootPackageJson);
121
+ const publishScript = `publish:${moduleName}`;
122
+ if (pkg.scripts && pkg.scripts[publishScript]) {
123
+ delete pkg.scripts[publishScript];
124
+ await fs.writeJson(rootPackageJson, pkg, { spaces: 2 });
125
+ console.log(chalk.green(` ✓ Script de publication supprimé`));
126
+ }
127
+ else {
128
+ console.log(chalk.gray(` ℹ️ Aucun script de publication trouvé`));
129
+ }
130
+ }
131
+ catch (error) {
132
+ console.log(chalk.yellow(` ⚠️ Erreur lors de la mise à jour: ${error}`));
133
+ }
134
+ }
135
+ console.log(chalk.green(`\n✅ Module ${moduleName} supprimé avec succès!\n`));
136
+ console.log(chalk.yellow("Prochaines étapes:"));
137
+ console.log(chalk.gray(" 1. cd packages/core && pnpm build"));
138
+ console.log(chalk.gray(" 2. Vérifier les projets qui utilisaient ce module"));
139
+ console.log(chalk.gray(" 3. Commiter les changements\n"));
140
+ }
141
+ // Point d'entrée CLI
142
+ if (import.meta.url === `file://${process.argv[1]}`) {
143
+ deleteModule().catch((error) => {
144
+ console.error(chalk.red("\n❌ Erreur:"), error);
145
+ process.exit(1);
146
+ });
147
+ }
@@ -0,0 +1,2 @@
1
+ export declare function listModules(targetDir: string): Promise<void>;
2
+ //# sourceMappingURL=module-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-list.d.ts","sourceRoot":"","sources":["../../../src/scripts/module-list.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,iBAwElD"}
@@ -0,0 +1,61 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
5
+ export async function listModules(targetDir) {
6
+ console.log(chalk.blue("\n📦 Modules disponibles:\n"));
7
+ // Lire la config des modules installés
8
+ const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
9
+ let installedPackages = [];
10
+ let inactivePackages = [];
11
+ if (fs.existsSync(modulesConfigPath)) {
12
+ const modulesConfig = await fs.readJson(modulesConfigPath);
13
+ const modules = modulesConfig.modules || [];
14
+ // Supporte deux formats:
15
+ // - Ancien: string[] des noms de packages
16
+ // - Actuel: { package: string; active?: boolean; migrations?: string[] }[]
17
+ if (Array.isArray(modules)) {
18
+ if (modules.length > 0 && typeof modules[0] === "string") {
19
+ installedPackages = modules;
20
+ }
21
+ else {
22
+ const entries = modules;
23
+ installedPackages = entries
24
+ .filter((m) => m && m.package && m.active !== false)
25
+ .map((m) => m.package);
26
+ inactivePackages = entries
27
+ .filter((m) => m && m.package && m.active === false)
28
+ .map((m) => m.package);
29
+ }
30
+ }
31
+ }
32
+ // Afficher tous les modules disponibles
33
+ AVAILABLE_MODULES.forEach((module) => {
34
+ const isInstalled = installedPackages.includes(module.package);
35
+ const isInactive = inactivePackages.includes(module.package);
36
+ const status = isInstalled
37
+ ? chalk.green("✓ installé")
38
+ : isInactive
39
+ ? chalk.yellow("⤳ inactif")
40
+ : chalk.gray(" disponible");
41
+ console.log(chalk.bold(`${module.emoji} ${module.name.charAt(0).toUpperCase() + module.name.slice(1)}`));
42
+ console.log(chalk.gray(` Nom: ${module.name}`));
43
+ console.log(chalk.gray(` Package: ${module.package}`));
44
+ console.log(chalk.gray(` Description: ${module.description}`));
45
+ console.log(` Statut: ${status}`);
46
+ // Afficher la commande appropriée selon le statut
47
+ if (isInstalled) {
48
+ console.log(chalk.cyan(` → pnpm lastbrain remove-module ${module.name}`));
49
+ }
50
+ else if (isInactive || !isInstalled) {
51
+ console.log(chalk.cyan(` → pnpm lastbrain add-module ${module.name}`));
52
+ }
53
+ console.log();
54
+ });
55
+ console.log(chalk.gray("─".repeat(50)));
56
+ console.log(chalk.gray("\nCommandes disponibles:"));
57
+ console.log(chalk.cyan(" pnpm lastbrain add-module <nom> ") +
58
+ chalk.gray("- Ajouter un module"));
59
+ console.log(chalk.cyan(" pnpm lastbrain remove-module <nom> ") +
60
+ chalk.gray("- Supprimer un module\n"));
61
+ }
@@ -0,0 +1,2 @@
1
+ export declare function removeModule(moduleName: string, targetDir: string): Promise<void>;
2
+ //# sourceMappingURL=module-remove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-remove.d.ts","sourceRoot":"","sources":["../../../src/scripts/module-remove.ts"],"names":[],"mappings":"AA6FA,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBA4WvE"}
@@ -0,0 +1,311 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { execSync } from "child_process";
5
+ import inquirer from "inquirer";
6
+ import { AVAILABLE_MODULES, } from "@lastbrain/core/config/modules";
7
+ // Convert core module metadata to local module definition
8
+ function toModuleDefinition(meta) {
9
+ return {
10
+ name: meta.name,
11
+ package: meta.package,
12
+ displayName: `${meta.emoji} ${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`,
13
+ description: meta.description,
14
+ hasMigrations: true,
15
+ migrationsPath: "supabase/migrations",
16
+ migrationsDownPath: "supabase/migrations-down",
17
+ };
18
+ }
19
+ async function removeGeneratedFiles(moduleName, modulePackage, targetDir) {
20
+ console.log(chalk.yellow("\n🗑️ Suppression des pages générées..."));
21
+ const appDirectory = path.join(targetDir, "app");
22
+ if (!fs.existsSync(appDirectory)) {
23
+ return;
24
+ }
25
+ // Fonction récursive pour trouver les fichiers
26
+ async function findAndRemoveFiles(dir) {
27
+ if (!fs.existsSync(dir))
28
+ return;
29
+ const entries = await fs.readdir(dir, { withFileTypes: true });
30
+ for (const entry of entries) {
31
+ const fullPath = path.join(dir, entry.name);
32
+ if (entry.isDirectory()) {
33
+ await findAndRemoveFiles(fullPath);
34
+ }
35
+ else if (entry.name === "page.tsx" || entry.name === "route.ts") {
36
+ try {
37
+ const content = await fs.readFile(fullPath, "utf-8");
38
+ // Vérifier si le fichier importe depuis le module (y compris sous-chemins)
39
+ if (content.includes(`"${modulePackage}`) ||
40
+ content.includes(`'${modulePackage}`)) {
41
+ await fs.remove(fullPath);
42
+ console.log(chalk.gray(` ✓ Supprimé ${path.relative(targetDir, fullPath)}`));
43
+ // Supprimer le dossier parent si vide
44
+ const parentDir = path.dirname(fullPath);
45
+ const remainingFiles = await fs.readdir(parentDir);
46
+ if (remainingFiles.length === 0) {
47
+ await fs.remove(parentDir);
48
+ }
49
+ }
50
+ }
51
+ catch {
52
+ // Ignorer les erreurs de lecture
53
+ }
54
+ }
55
+ }
56
+ }
57
+ await findAndRemoveFiles(appDirectory);
58
+ // Supprimer le fichier navigation.generated.ts pour qu'il soit regénéré au prochain build
59
+ const navPath = path.join(appDirectory, "navigation.generated.ts");
60
+ if (fs.existsSync(navPath)) {
61
+ await fs.remove(navPath);
62
+ console.log(chalk.gray(" ✓ Navigation réinitialisée"));
63
+ }
64
+ }
65
+ export async function removeModule(moduleName, targetDir) {
66
+ console.log(chalk.blue(`\n🗑️ Suppression du module: ${moduleName}\n`));
67
+ const moduleMeta = AVAILABLE_MODULES.find((m) => m.name === moduleName);
68
+ if (!moduleMeta) {
69
+ console.error(chalk.red(`❌ Module "${moduleName}" non trouvé. Modules disponibles:`));
70
+ AVAILABLE_MODULES.forEach((m) => {
71
+ console.log(chalk.gray(` - ${m.emoji} ${m.name}: ${m.description}`));
72
+ });
73
+ process.exit(1);
74
+ }
75
+ const module = toModuleDefinition(moduleMeta);
76
+ // 1. Vérifier qu'on est dans un projet LastBrain
77
+ const pkgPath = path.join(targetDir, "package.json");
78
+ if (!fs.existsSync(pkgPath)) {
79
+ console.error(chalk.red("❌ package.json non trouvé"));
80
+ process.exit(1);
81
+ }
82
+ const pkg = await fs.readJson(pkgPath);
83
+ // Vérifier si le module est installé (dans package.json OU modules.json)
84
+ const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
85
+ let isInstalledInConfig = false;
86
+ if (fs.existsSync(modulesConfigPath)) {
87
+ const modulesConfig = await fs.readJson(modulesConfigPath);
88
+ isInstalledInConfig = modulesConfig.modules?.includes(module.package);
89
+ }
90
+ const isInstalledInPackage = pkg.dependencies?.[module.package] || pkg.devDependencies?.[module.package];
91
+ if (!isInstalledInPackage && !isInstalledInConfig) {
92
+ console.log(chalk.yellow(`⚠️ Module ${module.package} n'est pas installé`));
93
+ return;
94
+ }
95
+ // 2. Retirer la dépendance du package.json
96
+ console.log(chalk.yellow(`📦 Suppression de ${module.package} des dépendances...`));
97
+ if (pkg.dependencies?.[module.package]) {
98
+ delete pkg.dependencies[module.package];
99
+ }
100
+ if (pkg.devDependencies?.[module.package]) {
101
+ delete pkg.devDependencies[module.package];
102
+ }
103
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
104
+ // 3. Retirer de la configuration
105
+ if (fs.existsSync(modulesConfigPath)) {
106
+ const modulesConfig = await fs.readJson(modulesConfigPath);
107
+ modulesConfig.modules = modulesConfig.modules.filter((m) => m !== module.package);
108
+ await fs.writeJson(modulesConfigPath, modulesConfig, { spaces: 2 });
109
+ }
110
+ // 3.5 Supprimer les pages/APIs générées
111
+ await removeGeneratedFiles(module.name, module.package, targetDir);
112
+ // 4. Gérer les migrations
113
+ if (module.hasMigrations) {
114
+ console.log(chalk.yellow("\n🗄️ Gestion des migrations du module\n"));
115
+ const projectMigrationsDir = path.join(targetDir, "supabase", "migrations");
116
+ // Récupérer la liste des migrations depuis modules.json
117
+ const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
118
+ let migrationFiles = [];
119
+ if (fs.existsSync(modulesConfigPath)) {
120
+ const modulesConfig = await fs.readJson(modulesConfigPath);
121
+ const moduleEntry = modulesConfig.modules.find((m) => (typeof m === "string" ? m : m.package) === module.package);
122
+ if (moduleEntry &&
123
+ typeof moduleEntry === "object" &&
124
+ moduleEntry.migrations) {
125
+ migrationFiles = moduleEntry.migrations;
126
+ console.log(chalk.gray(`DEBUG: Migrations from config: ${migrationFiles.join(", ")}`));
127
+ }
128
+ }
129
+ // Fallback: essayer de lire depuis node_modules si disponible
130
+ if (migrationFiles.length === 0) {
131
+ const modulePackagePath = path.join(targetDir, "node_modules", ...module.package.split("/"));
132
+ const moduleMigrationsDir = path.join(modulePackagePath, module.migrationsPath || "supabase/migrations");
133
+ if (fs.existsSync(moduleMigrationsDir)) {
134
+ migrationFiles = fs
135
+ .readdirSync(moduleMigrationsDir)
136
+ .filter((f) => f.endsWith(".sql"));
137
+ console.log(chalk.gray(`DEBUG: Found ${migrationFiles.length} migration files from node_modules: ${migrationFiles.join(", ")}`));
138
+ }
139
+ else {
140
+ console.log(chalk.gray(`DEBUG: No migrations found in config or node_modules`));
141
+ }
142
+ }
143
+ // Trouver le chemin du module pour les migrations down
144
+ const modulePackagePath = path.join(targetDir, "node_modules", ...module.package.split("/"));
145
+ const moduleMigrationsDownDir = path.join(modulePackagePath, module.migrationsDownPath || "supabase/migrations-down");
146
+ let hasDownMigrations = false;
147
+ // Vérifier si des fichiers down existent dans le dossier séparé
148
+ if (fs.existsSync(moduleMigrationsDownDir)) {
149
+ hasDownMigrations = fs
150
+ .readdirSync(moduleMigrationsDownDir)
151
+ .some((f) => f.endsWith(".sql"));
152
+ }
153
+ const choices = [
154
+ {
155
+ name: "🔄 Reset complet (supabase db reset) - Recommandé",
156
+ value: "reset",
157
+ },
158
+ ];
159
+ if (hasDownMigrations) {
160
+ choices.unshift({
161
+ name: "⬇️ Exécuter les migrations down du module",
162
+ value: "down",
163
+ });
164
+ }
165
+ choices.push({
166
+ name: "⏭️ Ignorer (garder les données en base)",
167
+ value: "skip",
168
+ });
169
+ const { migrationAction } = await inquirer.prompt([
170
+ {
171
+ type: "rawlist",
172
+ name: "migrationAction",
173
+ message: "Comment gérer les données du module en base ?",
174
+ choices,
175
+ },
176
+ ]);
177
+ if (migrationAction === "down" && hasDownMigrations) {
178
+ console.log(chalk.yellow("\n⬇️ Exécution des migrations down..."));
179
+ // Exécuter les fichiers .sql du dossier migrations-down dans l'ordre inverse
180
+ const downFiles = fs
181
+ .readdirSync(moduleMigrationsDownDir)
182
+ .filter((f) => f.endsWith(".sql"))
183
+ .sort()
184
+ .reverse();
185
+ for (const downFile of downFiles) {
186
+ const downFilePath = path.join(moduleMigrationsDownDir, downFile);
187
+ // Extraire le timestamp de la migration (14 premiers caractères)
188
+ const migrationVersion = downFile.split("_")[0]; // Prend la partie avant le premier underscore
189
+ try {
190
+ console.log(chalk.gray(` Exécution de ${downFile}...`));
191
+ execSync(`psql "postgresql://postgres:postgres@127.0.0.1:54322/postgres" -f "${downFilePath}"`, {
192
+ cwd: targetDir,
193
+ stdio: "inherit",
194
+ });
195
+ // Supprimer l'entrée de supabase_migrations.schema_migrations
196
+ try {
197
+ const deleteQuery = `DELETE FROM supabase_migrations.schema_migrations WHERE version = '${migrationVersion}';`;
198
+ const result = execSync(`psql "postgresql://postgres:postgres@127.0.0.1:54322/postgres" -c "${deleteQuery}"`, {
199
+ cwd: targetDir,
200
+ encoding: "utf-8",
201
+ });
202
+ console.log(chalk.gray(` ✓ Supprimé ${migrationVersion} de schema_migrations (${result.trim()})`));
203
+ }
204
+ catch (error) {
205
+ console.error(chalk.red(` ❌ Erreur lors de la suppression de ${migrationVersion}: ${error.message}`));
206
+ }
207
+ console.log(chalk.green(` ✓ ${downFile}`));
208
+ }
209
+ catch {
210
+ console.error(chalk.red(` ❌ Erreur avec ${downFile}`));
211
+ }
212
+ }
213
+ }
214
+ else if (migrationAction === "reset") {
215
+ console.log(chalk.yellow("\n🔄 Reset de la base de données..."));
216
+ // D'abord supprimer les fichiers de migration du projet
217
+ console.log(chalk.yellow("\n📋 Suppression des fichiers de migration..."));
218
+ for (const file of migrationFiles) {
219
+ const filePath = path.join(projectMigrationsDir, file);
220
+ if (fs.existsSync(filePath)) {
221
+ await fs.remove(filePath);
222
+ console.log(chalk.gray(` ✓ Supprimé ${file}`));
223
+ }
224
+ }
225
+ try {
226
+ execSync("supabase db reset", { cwd: targetDir, stdio: "inherit" });
227
+ console.log(chalk.green("✓ Base de données réinitialisée"));
228
+ }
229
+ catch {
230
+ console.error(chalk.red("❌ Erreur lors du reset"));
231
+ }
232
+ }
233
+ else {
234
+ console.log(chalk.gray("\n⚠️ Données conservées en base. Nettoyez manuellement si nécessaire.\n"));
235
+ }
236
+ // Supprimer les fichiers de migration du projet (si pas déjà fait)
237
+ if (migrationAction !== "reset") {
238
+ console.log(chalk.yellow("\n📋 Suppression des fichiers de migration..."));
239
+ for (const file of migrationFiles) {
240
+ const filePath = path.join(projectMigrationsDir, file);
241
+ if (fs.existsSync(filePath)) {
242
+ await fs.remove(filePath);
243
+ console.log(chalk.gray(` ✓ ${file}`));
244
+ }
245
+ }
246
+ // Supprimer les entrées de supabase_migrations.schema_migrations
247
+ if (migrationFiles.length > 0) {
248
+ console.log(chalk.yellow("\n🗄️ Nettoyage de schema_migrations..."));
249
+ // Extraire uniquement les timestamps (14 premiers caractères) de chaque fichier de migration
250
+ const versions = migrationFiles
251
+ .map((f) => {
252
+ const timestamp = f.split("_")[0]; // Prend la partie avant le premier underscore
253
+ return `'${timestamp}'`;
254
+ })
255
+ .join(", ");
256
+ const deleteQuery = `DELETE FROM supabase_migrations.schema_migrations WHERE version IN (${versions});`;
257
+ try {
258
+ const result = execSync(`psql "postgresql://postgres:postgres@127.0.0.1:54322/postgres" -c "${deleteQuery}"`, {
259
+ cwd: targetDir,
260
+ encoding: "utf-8",
261
+ });
262
+ console.log(chalk.gray(` ✓ Supprimé ${migrationFiles.length} entrées de schema_migrations`));
263
+ console.log(chalk.gray(` ${result.trim()}`));
264
+ }
265
+ catch (error) {
266
+ console.error(chalk.red(` ❌ Erreur: ${error.message}`));
267
+ }
268
+ }
269
+ }
270
+ }
271
+ // 5. Marquer le module comme inactif dans modules.json
272
+ const modulesJsonPath = path.join(targetDir, ".lastbrain", "modules.json");
273
+ if (fs.existsSync(modulesJsonPath)) {
274
+ try {
275
+ const modulesConfig = JSON.parse(fs.readFileSync(modulesJsonPath, "utf-8"));
276
+ const moduleEntry = modulesConfig.modules.find((m) => m.package === module.package);
277
+ if (moduleEntry) {
278
+ moduleEntry.active = false;
279
+ moduleEntry.migrations = [];
280
+ }
281
+ fs.writeFileSync(modulesJsonPath, JSON.stringify(modulesConfig, null, 2));
282
+ console.log(chalk.gray("\n✓ Module marqué comme inactif dans modules.json"));
283
+ }
284
+ catch {
285
+ console.error(chalk.red("❌ Erreur lors de la mise à jour de modules.json"));
286
+ }
287
+ }
288
+ // 5.5. Note: On ne supprime PAS le module du registre central
289
+ // car cette commande est pour les utilisateurs finaux qui n'ont pas accès à core/config/modules.ts
290
+ // Pour supprimer un module du monorepo, utiliser: pnpm delete-module
291
+ // 6. Nettoyer les dépendances
292
+ console.log(chalk.yellow("\n🧹 Nettoyage des dépendances..."));
293
+ try {
294
+ execSync("pnpm install", { cwd: targetDir, stdio: "inherit" });
295
+ }
296
+ catch {
297
+ console.error(chalk.red("❌ Erreur lors du nettoyage"));
298
+ process.exit(1);
299
+ }
300
+ console.log(chalk.green(`\n✅ Module ${module.displayName} supprimé avec succès!\n`));
301
+ // 7. Rebuilder les modules pour mettre à jour les fichiers générés
302
+ console.log(chalk.yellow("🔧 Mise à jour des modules..."));
303
+ try {
304
+ execSync("pnpm run build:modules", { cwd: targetDir, stdio: "inherit" });
305
+ console.log(chalk.green("✓ Modules mis à jour"));
306
+ }
307
+ catch {
308
+ console.warn(chalk.yellow("⚠️ Erreur lors de la mise à jour des modules"));
309
+ }
310
+ console.log(chalk.gray("Le serveur de développement redémarrera automatiquement.\n"));
311
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=readme-build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readme-build.d.ts","sourceRoot":"","sources":["../../../src/scripts/readme-build.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { getModuleConfigs } from "../modules/module-loader.js";
5
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
6
+ const packageRoot = path.join(scriptDir, "..", "..");
7
+ const projectRoot = path.join(packageRoot, "..", "..");
8
+ const webAppRoot = path.join(projectRoot, "apps/web");
9
+ const outputPath = path.join(webAppRoot, "README.md");
10
+ function resolveModuleReadme(moduleName) {
11
+ const fallbackPaths = [
12
+ path.join(projectRoot, "packages", moduleName.replace("@lastbrain/", ""), "README.md"),
13
+ path.join(projectRoot, "node_modules", ...moduleName.split("/"), "README.md"),
14
+ ];
15
+ for (const candidate of fallbackPaths) {
16
+ if (fs.existsSync(candidate)) {
17
+ return fs.readFileSync(candidate, "utf-8");
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+ function buildGeneratedReadme() {
23
+ const baseReadmePath = path.join(projectRoot, "packages/app/README.md");
24
+ const baseReadme = fs.existsSync(baseReadmePath)
25
+ ? fs.readFileSync(baseReadmePath, "utf-8")
26
+ : "";
27
+ const modules = getModuleConfigs();
28
+ const moduleSections = modules
29
+ .map((module) => {
30
+ const readme = resolveModuleReadme(module.moduleName) ||
31
+ "Aucun README disponible pour ce module.";
32
+ return `## Module ${module.moduleName}\n\n${readme}\n`;
33
+ })
34
+ .join("\n");
35
+ const content = `# LastBrain App Docs\n\n${baseReadme}\n\n---\n\n## Modules\n\n${moduleSections}\n\n## Commandes clés\n\n- pnpm build:modules\n- pnpm db:migrations:sync\n- pnpm db:init\n- pnpm dev\n`;
36
+ fs.writeFileSync(outputPath, content);
37
+ console.log(`📝 Generated aggregated README: ${outputPath}`);
38
+ }
39
+ buildGeneratedReadme();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Exécute un script via node en ajustant le chemin
3
+ */
4
+ export declare function runScript(scriptName: string, args?: string[]): Promise<void>;
5
+ //# sourceMappingURL=script-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-runner.d.ts","sourceRoot":"","sources":["../../../src/scripts/script-runner.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,iBAqBtE"}
@@ -0,0 +1,25 @@
1
+ import { spawn } from "child_process";
2
+ import path from "path";
3
+ /**
4
+ * Exécute un script via node en ajustant le chemin
5
+ */
6
+ export async function runScript(scriptName, args = []) {
7
+ return new Promise((resolve, reject) => {
8
+ const scriptPath = path.join(__dirname, `${scriptName}.js`);
9
+ const child = spawn("node", [scriptPath, ...args], {
10
+ stdio: "inherit",
11
+ env: { ...process.env, PROJECT_ROOT: process.cwd() },
12
+ });
13
+ child.on("close", (code) => {
14
+ if (code === 0) {
15
+ resolve();
16
+ }
17
+ else {
18
+ reject(new Error(`Script ${scriptName} exited with code ${code}`));
19
+ }
20
+ });
21
+ child.on("error", (error) => {
22
+ reject(error);
23
+ });
24
+ });
25
+ }
@@ -0,0 +1,2 @@
1
+ export declare function AuthGuidePage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=AuthGuidePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthGuidePage.d.ts","sourceRoot":"","sources":["../../../src/templates/AuthGuidePage.tsx"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,4CA+D5B"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card, Code, Divider, Chip } from "@lastbrain/ui";
3
+ export function AuthGuidePage() {
4
+ return (_jsxs("div", { className: "max-w-5xl mx-auto px-6 py-10 space-y-10", children: [_jsxs("header", { className: "space-y-3", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Guide Authentification" }), _jsx("p", { className: "text-slate-600 dark:text-slate-300 text-sm", children: "Pages publiques signin/signup/reset et endpoints API associ\u00E9s." }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx(Chip, { color: "primary", children: "Pages" }), _jsx(Chip, { color: "secondary", children: "API" }), _jsx(Chip, { color: "success", children: "Sessions" })] })] }), _jsx(Divider, {}), _jsxs(Card, { className: "p-6 space-y-3", children: [_jsx("h2", { className: "text-lg font-semibold", children: "Pages disponibles" }), _jsxs("ul", { className: "list-disc pl-5 text-sm space-y-1 text-slate-600 dark:text-slate-400", children: [_jsxs("li", { children: [_jsx("code", { children: "/signin" }), " : connexion"] }), _jsxs("li", { children: [_jsx("code", { children: "/signup" }), " : inscription"] }), _jsxs("li", { children: [_jsx("code", { children: "/reset-password" }), " (exemple)"] })] }), _jsx(Code, { className: "text-xs block", children: `import { SignInPage } from "@lastbrain/module-auth";` })] }), _jsxs(Card, { className: "p-6 space-y-3", children: [_jsx("h2", { className: "text-lg font-semibold", children: "API Route" }), _jsx(Code, { className: "text-xs block", children: "/api/auth/signin (POST)" }), _jsx(Code, { className: "text-xs block", children: `export { POST } from "@lastbrain/module-auth/api/public/signin";` })] }), _jsxs(Card, { className: "p-6 space-y-4", children: [_jsx("h2", { className: "text-lg font-semibold", children: "Personnalisation" }), _jsxs("ol", { className: "list-decimal pl-5 text-sm space-y-1 text-slate-600 dark:text-slate-400", children: [_jsx("li", { children: "Override wrapper route si besoin" }), _jsxs("li", { children: ["Modifier composant dans", " ", _jsx("code", { children: "packages/module-auth/src/web/public" })] }), _jsxs("li", { children: ["Recompiler module (", _jsx(Code, { className: "text-xs inline", children: "pnpm dev" }), ")"] }), _jsx("li", { children: "Hot reload c\u00F4t\u00E9 app" })] })] }), _jsxs(Card, { className: "p-6 space-y-2", children: [_jsx("h2", { className: "text-lg font-semibold", children: "Exemple d'int\u00E9gration" }), _jsx(Code, { className: "text-xs whitespace-pre-wrap", children: `import { SignInPage } from "@lastbrain/module-auth";
5
+
6
+ export default function SignIn() {
7
+ return <SignInPage />
8
+ }` })] }), _jsx("footer", { className: "text-center text-xs text-slate-500 dark:text-slate-500", children: "Pour ajouter un autre provider OAuth: \u00E9tendre module-auth ou cr\u00E9er module s\u00E9par\u00E9." })] }));
9
+ }
@@ -0,0 +1,2 @@
1
+ export declare function DefaultDocumentation(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=DefaultDoc.d.ts.map