@lastbrain/app 0.1.37 → 0.1.40

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.
@@ -19,6 +19,9 @@ const monorepoRoot = projectRoot.includes("/apps/")
19
19
  : projectRoot;
20
20
  const appDirectory = path.join(projectRoot, "app");
21
21
 
22
+ // Mode debug activé via --debug
23
+ const isDebugMode = process.argv.includes("--debug");
24
+
22
25
  // Créer un require dans le contexte de l'application pour résoudre les modules installés dans l'app
23
26
  const projectRequire = createRequire(path.join(projectRoot, "package.json"));
24
27
 
@@ -161,7 +164,9 @@ function buildPage(moduleConfig: ModuleBuildConfig, page: ModulePageConfig) {
161
164
  .replace(/^@lastbrain\/module-/, "")
162
165
  .toLowerCase();
163
166
 
164
- console.log(`🔄 Building page for module ${modulePrefix}: ${page.path}`);
167
+ if (isDebugMode) {
168
+ console.log(`🔄 Building page for module ${modulePrefix}: ${page.path}`);
169
+ }
165
170
 
166
171
  // Ajouter le préfixe du module au path pour les sections admin et auth,
167
172
  // MAIS seulement quand la section ne correspond PAS au module lui-même
@@ -173,11 +178,17 @@ function buildPage(moduleConfig: ModuleBuildConfig, page: ModulePageConfig) {
173
178
  // Éviter les doublons si le préfixe est déjà présent
174
179
  if (!page.path.startsWith(`/${modulePrefix}/`)) {
175
180
  effectivePath = `/${modulePrefix}${page.path}`;
176
- console.log(`📂 Added module prefix: ${page.path} -> ${effectivePath}`);
177
- } else {
181
+ if (isDebugMode) {
182
+ console.log(`📂 Added module prefix: ${page.path} -> ${effectivePath}`);
183
+ }
184
+ } else if (isDebugMode) {
178
185
  console.log(`✅ Module prefix already present: ${page.path}`);
179
186
  }
180
- } else if (page.section === "auth" && modulePrefix === "auth") {
187
+ } else if (
188
+ page.section === "auth" &&
189
+ modulePrefix === "auth" &&
190
+ isDebugMode
191
+ ) {
181
192
  console.log(
182
193
  `🏠 Auth module in auth section, no prefix needed: ${page.path}`,
183
194
  );
@@ -270,7 +281,9 @@ export default function ${wrapperName}${hasDynamicParams ? "(props: any)" : "()"
270
281
  }
271
282
 
272
283
  fs.writeFileSync(filePath, content);
273
- console.log(`⭐ Generated page: ${filePath}`);
284
+ if (isDebugMode) {
285
+ console.log(`⭐ Generated page: ${filePath}`);
286
+ }
274
287
  const entry: MenuEntry = {
275
288
  label: `Module:${moduleConfig.moduleName} ${page.componentExport}`,
276
289
  path: effectivePath,
@@ -294,7 +307,9 @@ export const navigation = ${JSON.stringify(navigation, null, 2)};
294
307
  export const userMenu = ${JSON.stringify(userMenu, null, 2)};
295
308
  `;
296
309
  fs.writeFileSync(navPath, content);
297
- console.log(`🧭 Generated navigation metadata: ${navPath}`);
310
+ if (isDebugMode) {
311
+ console.log(`🧭 Generated navigation metadata: ${navPath}`);
312
+ }
298
313
  }
299
314
 
300
315
  /**
@@ -369,7 +384,9 @@ export const menuConfig: MenuConfig = {
369
384
  `;
370
385
 
371
386
  fs.writeFileSync(menuPath, content);
372
- console.log(`🍔 Generated menu configuration: ${menuPath}`);
387
+ if (isDebugMode) {
388
+ console.log(`🍔 Generated menu configuration: ${menuPath}`);
389
+ }
373
390
  }
374
391
 
375
392
  function copyModuleMigrations(moduleConfigs: ModuleBuildConfig[]) {
@@ -557,7 +574,9 @@ ${moduleConfigurations.join(",\n")}
557
574
  `;
558
575
 
559
576
  fs.writeFileSync(docsPagePath, docsContent);
560
- console.log(`📚 Generated docs page: ${docsPagePath}`);
577
+ if (isDebugMode) {
578
+ console.log(`📚 Generated docs page: ${docsPagePath}`);
579
+ }
561
580
  }
562
581
 
563
582
  function buildGroupedApi(
@@ -595,7 +614,9 @@ function buildGroupedApi(
595
614
  ${content}`;
596
615
 
597
616
  fs.writeFileSync(filePath, contentWithMarker);
598
- console.log(`🔌 Generated API route: ${filePath}`);
617
+ if (isDebugMode) {
618
+ console.log(`🔌 Generated API route: ${filePath}`);
619
+ }
599
620
  }
600
621
 
601
622
  function getModuleDescription(moduleConfig: ModuleBuildConfig): string {
@@ -663,7 +684,9 @@ function cleanGeneratedFiles() {
663
684
  try {
664
685
  if (!isProtected(itemPath) && fs.readdirSync(itemPath).length === 0) {
665
686
  fs.rmdirSync(itemPath);
666
- console.log(`🗑️ Removed empty directory: ${itemPath}`);
687
+ if (isDebugMode) {
688
+ console.log(`📁 Removed empty directory: ${itemPath}`);
689
+ }
667
690
  }
668
691
  } catch {
669
692
  // Ignorer les erreurs de suppression de fichiers
@@ -681,12 +704,14 @@ function cleanGeneratedFiles() {
681
704
  content.includes('} from "@lastbrain/module-'))
682
705
  ) {
683
706
  fs.unlinkSync(itemPath);
684
- console.log(`🗑️ Cleaned generated file: ${itemPath}`);
707
+ if (isDebugMode) {
708
+ console.log(`🗑️ Removed: ${itemPath}`);
709
+ }
685
710
  }
686
711
  } catch {
687
712
  // Ignorer les erreurs de lecture/suppression
688
713
  }
689
- } else {
714
+ } else if (isDebugMode) {
690
715
  console.log(`🔒 Protected file skipped: ${itemPath}`);
691
716
  }
692
717
  }
@@ -708,11 +733,15 @@ function cleanGeneratedFiles() {
708
733
  const filePath = path.join(appDirectory, file);
709
734
  if (fs.existsSync(filePath)) {
710
735
  fs.unlinkSync(filePath);
711
- console.log(`🗑️ Cleaned root file: ${filePath}`);
736
+ if (isDebugMode) {
737
+ console.log(`🗑️ Removed: ${filePath}`);
738
+ }
712
739
  }
713
740
  });
714
741
 
715
- console.log("🧹 Cleanup completed");
742
+ if (isDebugMode) {
743
+ console.log("🧹 Cleanup completed");
744
+ }
716
745
  }
717
746
 
718
747
  function generateAppAside() {
@@ -720,7 +749,9 @@ function generateAppAside() {
720
749
 
721
750
  // Ne pas écraser si le fichier existe déjà
722
751
  if (fs.existsSync(targetPath)) {
723
- console.log(`⏭️ AppAside already exists, skipping: ${targetPath}`);
752
+ if (isDebugMode) {
753
+ console.log(`⏭️ AppAside already exists, skipping: ${targetPath}`);
754
+ }
724
755
  return;
725
756
  }
726
757
 
@@ -751,7 +782,9 @@ export function AppAside({ className = "", isVisible = true }: AppAsideProps) {
751
782
  try {
752
783
  ensureDirectory(path.dirname(targetPath));
753
784
  fs.writeFileSync(targetPath, templateContent, "utf-8");
754
- console.log(`✅ Generated AppAside component: ${targetPath}`);
785
+ if (isDebugMode) {
786
+ console.log(`✅ Generated AppAside component: ${targetPath}`);
787
+ }
755
788
  } catch (error) {
756
789
  console.error(`❌ Error generating AppAside component: ${error}`);
757
790
  }
@@ -779,11 +812,13 @@ export default function SectionLayout({
779
812
  try {
780
813
  ensureDirectory(path.dirname(authLayoutPath));
781
814
  fs.writeFileSync(authLayoutPath, authLayoutContent, "utf-8");
782
- console.log(`✅ Generated auth layout with sidebar: ${authLayoutPath}`);
815
+ if (isDebugMode) {
816
+ console.log(`✅ Generated auth layout with sidebar: ${authLayoutPath}`);
817
+ }
783
818
  } catch (error) {
784
819
  console.error(`❌ Error generating auth layout: ${error}`);
785
820
  }
786
- } else {
821
+ } else if (isDebugMode) {
787
822
  console.log(`⏭️ Auth layout already exists, skipping: ${authLayoutPath}`);
788
823
  }
789
824
 
@@ -808,11 +843,15 @@ export default function AdminLayout({
808
843
  try {
809
844
  ensureDirectory(path.dirname(adminLayoutPath));
810
845
  fs.writeFileSync(adminLayoutPath, adminLayoutContent, "utf-8");
811
- console.log(`✅ Generated admin layout with sidebar: ${adminLayoutPath}`);
846
+ if (isDebugMode) {
847
+ console.log(
848
+ `✅ Generated admin layout with sidebar: ${adminLayoutPath}`,
849
+ );
850
+ }
812
851
  } catch (error) {
813
852
  console.error(`❌ Error generating admin layout: ${error}`);
814
853
  }
815
- } else {
854
+ } else if (isDebugMode) {
816
855
  console.log(`⏭️ Admin layout already exists, skipping: ${adminLayoutPath}`);
817
856
  }
818
857
  }
@@ -860,16 +899,20 @@ export default realtimeConfig;
860
899
  // Écrire le fichier TypeScript
861
900
  fs.writeFileSync(outputPath, content);
862
901
 
863
- console.log(`✅ Generated realtime configuration: ${outputPath}`);
864
- console.log(`📊 Modules with realtime: ${realtimeConfigs.length}`);
902
+ if (isDebugMode) {
903
+ console.log(`✅ Generated realtime configuration: ${outputPath}`);
904
+ console.log(`📊 Modules with realtime: ${realtimeConfigs.length}`);
865
905
 
866
- // Afficher un résumé
867
- realtimeConfigs.forEach((module) => {
868
- console.log(` - ${module.moduleId}: ${module.tables.length} table(s)`);
869
- module.tables.forEach((table) => {
870
- console.log(` • ${table.schema}.${table.table} (${table.event})`);
906
+ // Afficher un résumé
907
+ realtimeConfigs.forEach((module) => {
908
+ console.log(
909
+ ` - ${module.moduleId}: ${module.tables.length} table(s)`,
910
+ );
911
+ module.tables.forEach((table) => {
912
+ console.log(` • ${table.schema}.${table.table} (${table.event})`);
913
+ });
871
914
  });
872
- });
915
+ }
873
916
  } catch (error) {
874
917
  console.error("❌ Error generating realtime configuration:", error);
875
918
  }
@@ -928,13 +971,15 @@ async function generateUserTabsConfig(moduleConfigs: ModuleBuildConfig[]) {
928
971
  // Écrire le fichier TypeScript
929
972
  fs.writeFileSync(outputPath, appContent);
930
973
 
931
- console.log(`✅ Generated user tabs configuration: ${outputPath}`);
932
- console.log(`📊 User tabs count: ${userTabsConfigs.length}`);
974
+ if (isDebugMode) {
975
+ console.log(`✅ Generated user tabs configuration: ${outputPath}`);
976
+ console.log(`📊 User tabs count: ${userTabsConfigs.length}`);
933
977
 
934
- // Afficher un résumé
935
- userTabsConfigs.forEach((tab) => {
936
- console.log(` - ${tab.title} (${tab.moduleName})`);
937
- });
978
+ // Afficher un résumé
979
+ userTabsConfigs.forEach((tab) => {
980
+ console.log(` - ${tab.title} (${tab.moduleName})`);
981
+ });
982
+ }
938
983
 
939
984
  // Plus de copie vers app/config ni stub core
940
985
  } catch (error) {
@@ -946,21 +991,33 @@ export async function runModuleBuild() {
946
991
  ensureDirectory(appDirectory);
947
992
 
948
993
  // Nettoyer les fichiers générés précédemment
949
- console.log("🧹 Cleaning previously generated files...");
994
+ if (isDebugMode) {
995
+ console.log("🧹 Cleaning previously generated files...");
996
+ }
950
997
  cleanGeneratedFiles();
951
998
 
952
999
  const moduleConfigs = await loadModuleConfigs();
953
- console.log(`🔍 Loaded ${moduleConfigs.length} module configurations`);
1000
+ if (isDebugMode) {
1001
+ console.log(`🔍 Loaded ${moduleConfigs.length} module configurations`);
1002
+ }
954
1003
 
955
1004
  // Générer les pages
1005
+ if (isDebugMode) {
1006
+ console.log("\n📝 Generating pages...");
1007
+ }
956
1008
  moduleConfigs.forEach((moduleConfig) => {
957
- console.log(
958
- `📦 Processing module: ${moduleConfig.moduleName} with ${moduleConfig.pages.length} pages`,
959
- );
1009
+ if (isDebugMode) {
1010
+ console.log(
1011
+ `📦 Processing module: ${moduleConfig.moduleName} with ${moduleConfig.pages.length} pages`,
1012
+ );
1013
+ }
960
1014
  moduleConfig.pages.forEach((page) => buildPage(moduleConfig, page));
961
1015
  });
962
1016
 
963
1017
  // Grouper les APIs par chemin pour éviter les écrasements de fichier
1018
+ if (isDebugMode) {
1019
+ console.log("\n🔌 Generating API routes...");
1020
+ }
964
1021
  const apisByPath = new Map<
965
1022
  string,
966
1023
  Array<{ moduleConfig: ModuleBuildConfig; api: ModuleApiConfig }>
@@ -988,10 +1045,23 @@ export async function runModuleBuild() {
988
1045
  copyModuleMigrations(moduleConfigs);
989
1046
 
990
1047
  // Générer la configuration realtime
991
- console.log("🔄 Generating realtime configuration...");
1048
+ if (isDebugMode) {
1049
+ console.log("🔄 Generating realtime configuration...");
1050
+ }
992
1051
  await generateRealtimeConfig(moduleConfigs);
993
1052
 
994
1053
  // Générer la configuration des user tabs
995
- console.log("📑 Generating user tabs configuration...");
1054
+ if (isDebugMode) {
1055
+ console.log("📑 Generating user tabs configuration...");
1056
+ }
996
1057
  await generateUserTabsConfig(moduleConfigs);
1058
+
1059
+ // Message de succès final
1060
+ if (!isDebugMode) {
1061
+ console.log("\n✅ Module build completed successfully!");
1062
+ console.log(`📦 ${moduleConfigs.length} module(s) processed`);
1063
+ console.log("💡 Use --debug flag for detailed logs\n");
1064
+ } else {
1065
+ console.log("\n✅ Module build completed (debug mode)\n");
1066
+ }
997
1067
  }
@@ -11,19 +11,40 @@ export async function listModules(targetDir: string) {
11
11
 
12
12
  // Lire la config des modules installés
13
13
  const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
14
- let installedModules: string[] = [];
14
+ let installedPackages: string[] = [];
15
+ let inactivePackages: string[] = [];
15
16
 
16
17
  if (fs.existsSync(modulesConfigPath)) {
17
18
  const modulesConfig = await fs.readJson(modulesConfigPath);
18
- installedModules = modulesConfig.modules || [];
19
+ const modules = modulesConfig.modules || [];
20
+
21
+ // Supporte deux formats:
22
+ // - Ancien: string[] des noms de packages
23
+ // - Actuel: { package: string; active?: boolean; migrations?: string[] }[]
24
+ if (Array.isArray(modules)) {
25
+ if (modules.length > 0 && typeof modules[0] === "string") {
26
+ installedPackages = modules as string[];
27
+ } else {
28
+ const entries = modules as Array<{ package: string; active?: boolean }>;
29
+ installedPackages = entries
30
+ .filter((m) => m && m.package && m.active !== false)
31
+ .map((m) => m.package);
32
+ inactivePackages = entries
33
+ .filter((m) => m && m.package && m.active === false)
34
+ .map((m) => m.package);
35
+ }
36
+ }
19
37
  }
20
38
 
21
39
  // Afficher tous les modules disponibles
22
40
  AVAILABLE_MODULES.forEach((module) => {
23
- const isInstalled = installedModules.includes(module.package);
41
+ const isInstalled = installedPackages.includes(module.package);
42
+ const isInactive = inactivePackages.includes(module.package);
24
43
  const status = isInstalled
25
44
  ? chalk.green("✓ installé")
26
- : chalk.gray(" disponible");
45
+ : isInactive
46
+ ? chalk.yellow("⤳ inactif")
47
+ : chalk.gray(" disponible");
27
48
 
28
49
  console.log(
29
50
  chalk.bold(
@@ -34,11 +55,27 @@ export async function listModules(targetDir: string) {
34
55
  console.log(chalk.gray(` Package: ${module.package}`));
35
56
  console.log(chalk.gray(` Description: ${module.description}`));
36
57
  console.log(` Statut: ${status}`);
58
+
59
+ // Afficher la commande appropriée selon le statut
60
+ if (isInstalled) {
61
+ console.log(
62
+ chalk.cyan(` → pnpm lastbrain remove-module ${module.name}`),
63
+ );
64
+ } else if (isInactive || !isInstalled) {
65
+ console.log(chalk.cyan(` → pnpm lastbrain add-module ${module.name}`));
66
+ }
67
+
37
68
  console.log();
38
69
  });
39
70
 
40
- console.log(chalk.gray("Pour ajouter un module:"));
41
- console.log(chalk.cyan(" pnpm lastbrain add-module <nom>\n"));
42
- console.log(chalk.gray("Pour supprimer un module:"));
43
- console.log(chalk.cyan(" pnpm lastbrain remove-module <nom>\n"));
71
+ console.log(chalk.gray("".repeat(50)));
72
+ console.log(chalk.gray("\nCommandes disponibles:"));
73
+ console.log(
74
+ chalk.cyan(" pnpm lastbrain add-module <nom> ") +
75
+ chalk.gray("- Ajouter un module"),
76
+ );
77
+ console.log(
78
+ chalk.cyan(" pnpm lastbrain remove-module <nom> ") +
79
+ chalk.gray("- Supprimer un module\n"),
80
+ );
44
81
  }
@@ -1356,6 +1356,34 @@ export function DocUsageCustom() {
1356
1356
  </a>
1357
1357
  </p>
1358
1358
  <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">---</p>
1359
+ <h4 className="font-medium mb-2">
1360
+ [module-recipes](../packages/module-recipes/README.md)
1361
+ </h4>
1362
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
1363
+ @lastbrain/module-recipes
1364
+ </p>
1365
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
1366
+ <strong>Pages</strong>: 4 auth
1367
+ </p>
1368
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
1369
+ <strong>Tables</strong>: recipes, recipe_favorites, recipe_comments,
1370
+ recipe_image_queue, recipe_embeddings
1371
+ </p>
1372
+ <h4 className="font-medium mb-2">Installation du module recipes</h4>
1373
+ <Snippet symbol="" hideSymbol className="text-sm mb-2">
1374
+ {`pnpm lastbrain add-module recipes`}
1375
+ </Snippet>
1376
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
1377
+ <a
1378
+ href="../packages/module-recipes/README.md"
1379
+ className="text-blue-600 hover:underline"
1380
+ target="_blank"
1381
+ rel="noopener noreferrer"
1382
+ >
1383
+ 📖 Documentation complète →
1384
+ </a>
1385
+ </p>
1386
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">---</p>
1359
1387
  <h4 className="font-medium mb-2">
1360
1388
  [module-tasks](../packages/module-tasks/README.md)
1361
1389
  </h4>