@lastbrain/app 0.1.47 → 1.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 (51) hide show
  1. package/dist/app-shell/layout.d.ts +1 -1
  2. package/dist/app-shell/layout.d.ts.map +1 -1
  3. package/dist/app-shell/layout.js +1 -1
  4. package/dist/components/NotificationContainer.js +1 -1
  5. package/dist/index.d.ts +19 -19
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +19 -19
  8. package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -2
  9. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
  10. package/dist/layouts/AdminLayoutWithSidebar.js +5 -5
  11. package/dist/layouts/AppProviders.d.ts +1 -1
  12. package/dist/layouts/AppProviders.d.ts.map +1 -1
  13. package/dist/layouts/AppProviders.js +3 -3
  14. package/dist/layouts/AuthLayoutWithSidebar.d.ts +7 -4
  15. package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -1
  16. package/dist/layouts/AuthLayoutWithSidebar.js +5 -5
  17. package/dist/layouts/PublicLayoutWithSidebar.js +2 -2
  18. package/dist/layouts/RootLayout.js +1 -1
  19. package/dist/scripts/init-app.d.ts.map +1 -1
  20. package/dist/scripts/init-app.js +457 -39
  21. package/dist/scripts/module-add.js +1 -1
  22. package/dist/scripts/module-build.d.ts.map +1 -1
  23. package/dist/scripts/module-build.js +36 -15
  24. package/dist/scripts/module-create.js +8 -8
  25. package/dist/scripts/module-delete.d.ts.map +1 -1
  26. package/dist/scripts/module-delete.js +1 -1
  27. package/dist/templates/DefaultDoc.d.ts.map +1 -1
  28. package/dist/templates/DefaultDoc.js +1 -1
  29. package/dist/templates/DocPage.js +1 -1
  30. package/dist/templates/DocsPageWithModules.js +1 -1
  31. package/dist/types/menu.d.ts +23 -0
  32. package/dist/types/menu.d.ts.map +1 -0
  33. package/dist/types/menu.js +1 -0
  34. package/package.json +9 -1
  35. package/src/app-shell/layout.tsx +1 -1
  36. package/src/components/NotificationContainer.tsx +1 -1
  37. package/src/index.ts +24 -19
  38. package/src/layouts/AdminLayoutWithSidebar.tsx +11 -3
  39. package/src/layouts/AppProviders.tsx +4 -4
  40. package/src/layouts/AuthLayoutWithSidebar.tsx +18 -4
  41. package/src/layouts/PublicLayoutWithSidebar.tsx +2 -2
  42. package/src/layouts/RootLayout.tsx +1 -1
  43. package/src/scripts/init-app.ts +479 -49
  44. package/src/scripts/module-add.ts +1 -1
  45. package/src/scripts/module-build.ts +46 -22
  46. package/src/scripts/module-create.ts +8 -8
  47. package/src/scripts/module-delete.ts +1 -4
  48. package/src/templates/DefaultDoc.tsx +264 -0
  49. package/src/templates/DocPage.tsx +1 -1
  50. package/src/templates/DocsPageWithModules.tsx +1 -1
  51. package/src/types/menu.ts +18 -0
@@ -4,10 +4,7 @@ import { fileURLToPath } from "url";
4
4
  import chalk from "chalk";
5
5
  import inquirer from "inquirer";
6
6
  import { execSync } from "child_process";
7
- import {
8
- AVAILABLE_MODULES,
9
- type ModuleMetadata,
10
- } from "@lastbrain/core/config/modules";
7
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
11
8
 
12
9
  const __filename = fileURLToPath(import.meta.url);
13
10
  const __dirname = path.dirname(__filename);
@@ -196,20 +193,31 @@ export async function initApp(options: InitAppOptions) {
196
193
  stdio: "inherit",
197
194
  });
198
195
  console.log(chalk.green("\n✓ Migrations synchronisées\n"));
199
- } catch (error) {
196
+ } catch (_error) {
200
197
  console.log(
201
198
  chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n")
202
199
  );
203
200
  }
204
201
 
205
- console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
206
- try {
207
- execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
208
- console.log(chalk.green("\n✓ Base de données initialisée\n"));
209
- } catch {
202
+ // Ne pas initialiser la BDD en mode monorepo
203
+ if (!isMonorepoProject) {
210
204
  console.log(
211
- chalk.yellow(
212
- "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
205
+ chalk.yellow("🗄️ Initialisation de la base de données...\n")
206
+ );
207
+ try {
208
+ execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
209
+ console.log(chalk.green("\n✓ Base de données initialisée\n"));
210
+ } catch {
211
+ console.log(
212
+ chalk.yellow(
213
+ "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
214
+ )
215
+ );
216
+ }
217
+ } else {
218
+ console.log(
219
+ chalk.cyan(
220
+ "⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"
213
221
  )
214
222
  );
215
223
  }
@@ -227,14 +235,20 @@ export async function initApp(options: InitAppOptions) {
227
235
  console.log(
228
236
  chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil")
229
237
  );
230
- console.log(chalk.white(" 2. Lancez Docker Desktop"));
231
- console.log(
232
- chalk.white(
233
- " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
234
- )
235
- );
236
- console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
237
- console.log(chalk.white(" 5. Rechargez la page\n"));
238
+ if (isMonorepoProject) {
239
+ console.log(
240
+ chalk.white(" 2. La BDD est centralisée dans le monorepo\n")
241
+ );
242
+ } else {
243
+ console.log(chalk.white(" 2. Lancez Docker Desktop"));
244
+ console.log(
245
+ chalk.white(
246
+ " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
247
+ )
248
+ );
249
+ console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
250
+ console.log(chalk.white(" 5. Rechargez la page\n"));
251
+ }
238
252
 
239
253
  // Ouvrir le navigateur
240
254
  const openCommand =
@@ -252,7 +266,7 @@ export async function initApp(options: InitAppOptions) {
252
266
  }, 2000);
253
267
 
254
268
  // Lancer pnpm dev
255
- execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
269
+ execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
256
270
  } catch {
257
271
  console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
258
272
  console.log(chalk.cyan("\nVous pouvez lancer manuellement avec :"));
@@ -260,7 +274,9 @@ export async function initApp(options: InitAppOptions) {
260
274
  console.log(chalk.white(" pnpm install"));
261
275
  console.log(chalk.white(" pnpm build:modules"));
262
276
  console.log(chalk.white(" pnpm db:migrations:sync"));
263
- console.log(chalk.white(" pnpm db:init"));
277
+ if (!isMonorepoProject) {
278
+ console.log(chalk.white(" pnpm db:init"));
279
+ }
264
280
  console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
265
281
  }
266
282
  } else {
@@ -411,10 +427,10 @@ function getLastBrainVersions(targetDir: string): {
411
427
  moduleAi: moduleAiVersion,
412
428
  };
413
429
  }
414
- } catch (error) {
430
+ } catch (_error) {
415
431
  console.warn(
416
432
  chalk.yellow(
417
- `⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`
433
+ `⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`
418
434
  )
419
435
  );
420
436
  }
@@ -917,17 +933,56 @@ async function createAppHeader(targetDir: string, force: boolean) {
917
933
  if (!fs.existsSync(headerPath) || force) {
918
934
  const headerContent = `"use client";
919
935
 
920
- import { Header } from "@lastbrain/ui";
936
+ import { Header, type MenuItem } from "@lastbrain/ui";
921
937
  import { menuConfig } from "../config/menu";
922
938
  import { supabaseBrowserClient } from "@lastbrain/core";
923
939
  import { useRouter } from "next/navigation";
924
940
  import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
941
+ import { useState, useEffect } from "react";
942
+
943
+ interface MenuIgnored {
944
+ public: { title: string; path: string }[];
945
+ auth: { title: string; path: string }[];
946
+ }
925
947
 
926
948
  export function AppHeader() {
927
949
  const router = useRouter();
928
950
  const { user, isSuperAdmin } = useAuthSession();
929
951
  const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
930
952
  useNotificationsContext();
953
+ const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
954
+ const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
955
+ const [isLoading, setIsLoading] = useState(true);
956
+
957
+ // Charger menuIgnored et menuCustom s'ils existent
958
+ useEffect(() => {
959
+ let loadedIgnored = false;
960
+ let loadedCustom = false;
961
+
962
+ // Charger menu-ignored
963
+ import("../config/menu-ignored")
964
+ .then((mod) => setMenuIgnored(mod.menuIgnored))
965
+ .catch(() => setMenuIgnored(undefined))
966
+ .finally(() => {
967
+ loadedIgnored = true;
968
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
969
+ });
970
+
971
+ // Charger menu-custom
972
+ import("../config/menu-custom")
973
+ .then((mod) => {
974
+ // Combiner les menus custom publics et auth
975
+ const customMenus: MenuItem[] = [];
976
+ if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
977
+ if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
978
+ setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
979
+ })
980
+ .catch(() => setMenuCustom(undefined))
981
+ .finally(() => {
982
+ loadedCustom = true;
983
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
984
+ });
985
+ }, []);
931
986
 
932
987
  const handleLogout = async () => {
933
988
  await supabaseBrowserClient.auth.signOut();
@@ -950,6 +1005,9 @@ export function AppHeader() {
950
1005
  onMarkAsRead={markAsRead}
951
1006
  onMarkAllAsRead={markAllAsRead}
952
1007
  onDeleteNotification={deleteNotification}
1008
+ {...(menuIgnored ? { menuIgnored } : {})}
1009
+ {...(menuCustom ? { menuCustom } : {})}
1010
+ {...{ isLoadingMenus: isLoading }}
953
1011
  />
954
1012
  );
955
1013
  }
@@ -1047,7 +1105,58 @@ async function createConfigFiles(
1047
1105
  const middlewarePath = path.join(targetDir, "middleware.ts");
1048
1106
  if (!fs.existsSync(middlewarePath) || force) {
1049
1107
  const middleware = `import { type NextRequest, NextResponse } from "next/server";
1050
- import { createMiddlewareClient } from "@lastbrain/core/server";
1108
+ import { createServerClient, type CookieOptions } from "@supabase/ssr";
1109
+
1110
+ /**
1111
+ * Crée un client Supabase pour le middleware
1112
+ */
1113
+ function createMiddlewareClient(request: NextRequest) {
1114
+ let response = NextResponse.next({
1115
+ request: {
1116
+ headers: request.headers,
1117
+ },
1118
+ });
1119
+
1120
+ const supabase = createServerClient(
1121
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
1122
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
1123
+ {
1124
+ cookies: {
1125
+ get(name: string) {
1126
+ return request.cookies.get(name)?.value;
1127
+ },
1128
+ set(name: string, value: string, options: CookieOptions) {
1129
+ request.cookies.set({
1130
+ name,
1131
+ value,
1132
+ ...options,
1133
+ });
1134
+ response = NextResponse.next({
1135
+ request: {
1136
+ headers: request.headers,
1137
+ },
1138
+ });
1139
+ response.cookies.set({
1140
+ name,
1141
+ value,
1142
+ ...options,
1143
+ });
1144
+ },
1145
+ remove(name: string, options: CookieOptions) {
1146
+ request.cookies.delete(name);
1147
+ response = NextResponse.next({
1148
+ request: {
1149
+ headers: request.headers,
1150
+ },
1151
+ });
1152
+ response.cookies.delete(name);
1153
+ },
1154
+ },
1155
+ }
1156
+ );
1157
+
1158
+ return { supabase, response };
1159
+ }
1051
1160
 
1052
1161
  export async function middleware(request: NextRequest) {
1053
1162
  const { pathname } = request.nextUrl;
@@ -1195,9 +1304,9 @@ export const config = {
1195
1304
  const nextConfig = `/** @type {import('next').NextConfig} */
1196
1305
  const nextConfig = {
1197
1306
  reactStrictMode: true,
1198
- devIndicators: {
1307
+ devIndicators: {
1199
1308
  position: 'bottom-right',
1200
- },
1309
+ }
1201
1310
  };
1202
1311
 
1203
1312
  export default nextConfig;
@@ -1212,7 +1321,7 @@ export default nextConfig;
1212
1321
  let tailwindConfig = "";
1213
1322
 
1214
1323
  if (useHeroUI) {
1215
- // Configuration avec HeroUI
1324
+ // Configuration avec HeroUI - complète avec thèmes
1216
1325
  tailwindConfig = `import { heroui } from "@heroui/theme";
1217
1326
 
1218
1327
  /** @type {import('tailwindcss').Config} */
@@ -1224,8 +1333,195 @@ const config = {
1224
1333
  "./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
1225
1334
  ],
1226
1335
  darkMode: "class",
1227
- plugins: [heroui()],
1228
- }
1336
+ plugins: [
1337
+ heroui({
1338
+ themes: {
1339
+ light: {
1340
+ colors: {
1341
+ default: {
1342
+ 950: "#0d0d0e",
1343
+ 900: "#19191c",
1344
+ 800: "#26262a",
1345
+ 700: "#323238",
1346
+ 600: "#3f3f46",
1347
+ 500: "#65656b",
1348
+ 400: "#8c8c90",
1349
+ 300: "#b2b2b5",
1350
+ 200: "#d9d9da",
1351
+ 100: "#ffffff",
1352
+ foreground: "#000000",
1353
+ DEFAULT: "#d4d4d8",
1354
+ },
1355
+ primary: {
1356
+ 50: "#eef2ff",
1357
+ 100: "#e0e7ff",
1358
+ 200: "#c7d2fe",
1359
+ 300: "#a5b4fc",
1360
+ 400: "#818cf8",
1361
+ 500: "#6366f1",
1362
+ 600: "#4f46e5",
1363
+ 700: "#4338ca",
1364
+ 800: "#3730a3",
1365
+ 900: "#312e81",
1366
+ foreground: "#ffffff",
1367
+ DEFAULT: "#6366f1",
1368
+ },
1369
+ secondary: {
1370
+ 50: "#f5e8ff",
1371
+ 100: "#e8ccff",
1372
+ 200: "#d7a6ff",
1373
+ 300: "#c57fff",
1374
+ 400: "#b359ff",
1375
+ 500: "#9b37ff",
1376
+ 600: "#7d1fcc",
1377
+ 700: "#5f1799",
1378
+ 800: "#410f66",
1379
+ 900: "#240833",
1380
+ foreground: "#ffffff",
1381
+ DEFAULT: "#9b37ff",
1382
+ },
1383
+ success: {
1384
+ 50: "#e7fff7",
1385
+ 100: "#c3ffec",
1386
+ 200: "#9affdf",
1387
+ 300: "#70ffd2",
1388
+ 400: "#4bffca",
1389
+ 500: "#22e6b0",
1390
+ 600: "#18b38a",
1391
+ 700: "#108066",
1392
+ 800: "#074d40",
1393
+ 900: "#012b22",
1394
+ foreground: "#000",
1395
+ DEFAULT: "#22e6b0",
1396
+ },
1397
+ warning: {
1398
+ 50: "#fff8e1",
1399
+ 100: "#ffecb3",
1400
+ 200: "#ffe082",
1401
+ 300: "#ffd54f",
1402
+ 400: "#ffca28",
1403
+ 500: "#ffc107",
1404
+ 600: "#ffb300",
1405
+ 700: "#ffa000",
1406
+ 800: "#ff8f00",
1407
+ 900: "#ff6f00",
1408
+ foreground: "#000",
1409
+ DEFAULT: "#ffca28",
1410
+ },
1411
+ danger: {
1412
+ 50: "#ffe6e9",
1413
+ 100: "#ffbac1",
1414
+ 200: "#ff8f99",
1415
+ 300: "#ff6471",
1416
+ 400: "#ff3949",
1417
+ 500: "#ff112a",
1418
+ 600: "#d80c22",
1419
+ 700: "#b1081b",
1420
+ 800: "#890514",
1421
+ 900: "#62020d",
1422
+ foreground: "#fff",
1423
+ DEFAULT: "#ff112a",
1424
+ },
1425
+ background: "#f7f8fc",
1426
+ foreground: "#0e0e10",
1427
+ content1: "#ffffff",
1428
+ },
1429
+ },
1430
+ dark: {
1431
+ colors: {
1432
+ default: {
1433
+ 50: "#1a1c1f",
1434
+ 100: "#232529",
1435
+ 200: "#2c2f34",
1436
+ 300: "#363940",
1437
+ 400: "#40444d",
1438
+ 500: "#4b4f59",
1439
+ 600: "#6c707b",
1440
+ 700: "#8d919b",
1441
+ 800: "#afb2bb",
1442
+ 900: "#d1d3d9",
1443
+ foreground: "#ffffff",
1444
+ DEFAULT: "#363940",
1445
+ },
1446
+ primary: {
1447
+ 50: "#312e81",
1448
+ 100: "#3730a3",
1449
+ 200: "#4338ca",
1450
+ 300: "#4f46e5",
1451
+ 400: "#6366f1",
1452
+ 500: "#818cf8",
1453
+ 600: "#a5b4fc",
1454
+ 700: "#c7d2fe",
1455
+ 800: "#e0e7ff",
1456
+ 900: "#eef2ff",
1457
+ foreground: "#ffffff",
1458
+ DEFAULT: "#6366f1",
1459
+ },
1460
+ secondary: {
1461
+ 50: "#240833",
1462
+ 100: "#410f66",
1463
+ 200: "#5f1799",
1464
+ 300: "#7d1fcc",
1465
+ 400: "#9b37ff",
1466
+ 500: "#b359ff",
1467
+ 600: "#c57fff",
1468
+ 700: "#d7a6ff",
1469
+ 800: "#e8ccff",
1470
+ 900: "#f5e8ff",
1471
+ foreground: "#ffffff",
1472
+ DEFAULT: "#9b37ff",
1473
+ },
1474
+ success: {
1475
+ 50: "#012b22",
1476
+ 100: "#074d40",
1477
+ 200: "#108066",
1478
+ 300: "#18b38a",
1479
+ 400: "#22e6b0",
1480
+ 500: "#4bffca",
1481
+ 600: "#70ffd2",
1482
+ 700: "#9affdf",
1483
+ 800: "#c3ffec",
1484
+ 900: "#e7fff7",
1485
+ foreground: "#0e0e0e",
1486
+ DEFAULT: "#22e6b0",
1487
+ },
1488
+ warning: {
1489
+ 50: "#3a2c00",
1490
+ 100: "#5e4700",
1491
+ 200: "#836300",
1492
+ 300: "#a77e00",
1493
+ 400: "#cc9900",
1494
+ 500: "#ffc107",
1495
+ 600: "#ffd54f",
1496
+ 700: "#ffe082",
1497
+ 800: "#ffecb3",
1498
+ 900: "#fff8e1",
1499
+ foreground: "#000",
1500
+ DEFAULT: "#ffc107",
1501
+ },
1502
+ danger: {
1503
+ 50: "#4a000a",
1504
+ 100: "#6e000f",
1505
+ 200: "#920014",
1506
+ 300: "#b60019",
1507
+ 400: "#da001f",
1508
+ 500: "#ff112a",
1509
+ 600: "#ff3949",
1510
+ 700: "#ff6471",
1511
+ 800: "#ff8f99",
1512
+ 900: "#ffbac1",
1513
+ foreground: "#ffffff",
1514
+ DEFAULT: "#ff112a",
1515
+ },
1516
+ background: "#0f1114",
1517
+ foreground: "#f8f8f8",
1518
+ content1: "#15181d",
1519
+ },
1520
+ },
1521
+ },
1522
+ }),
1523
+ ],
1524
+ };
1229
1525
 
1230
1526
  export default config;
1231
1527
  `;
@@ -1284,8 +1580,56 @@ export default config;
1284
1580
  // tsconfig.json
1285
1581
  const tsconfigPath = path.join(targetDir, "tsconfig.json");
1286
1582
  if (!fs.existsSync(tsconfigPath) || force) {
1287
- const tsconfig = {
1288
- extends: "../../tsconfig.base.json",
1583
+ // Détecter si le projet cible est dans un monorepo
1584
+ const targetIsInMonorepo =
1585
+ fs.existsSync(
1586
+ path.join(targetDir, "../../../packages/core/package.json")
1587
+ ) ||
1588
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1589
+
1590
+ // Générer les chemins en fonction du contexte
1591
+ const paths: Record<string, string[]> = {
1592
+ "@/*": ["./*"],
1593
+ };
1594
+
1595
+ if (targetIsInMonorepo) {
1596
+ // En monorepo, pointer sur les sources locales
1597
+ paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
1598
+ paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
1599
+ paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
1600
+ paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
1601
+ paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
1602
+ paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
1603
+ paths["@lastbrain/module-auth"] = [
1604
+ "../../packages/module-auth/src/index.ts",
1605
+ ];
1606
+ paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
1607
+ paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
1608
+ paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
1609
+ paths["@lastbrain/module-legal"] = [
1610
+ "../../packages/module-legal/src/index.ts",
1611
+ ];
1612
+ paths["@lastbrain/module-legal/*"] = [
1613
+ "../../packages/module-legal/src/*",
1614
+ ];
1615
+ paths["@lastbrain/module-project-board"] = [
1616
+ "../../packages/module-project-board/src/index.ts",
1617
+ ];
1618
+ paths["@lastbrain/module-project-board/*"] = [
1619
+ "../../packages/module-project-board/src/*",
1620
+ ];
1621
+ paths["@lastbrain/module-tasks"] = [
1622
+ "../../packages/module-tasks/src/index.ts",
1623
+ ];
1624
+ paths["@lastbrain/module-tasks/*"] = [
1625
+ "../../packages/module-tasks/src/*",
1626
+ ];
1627
+ } else {
1628
+ // Hors monorepo (npm install), ne pas utiliser de paths aliases
1629
+ delete paths["@/*"];
1630
+ }
1631
+
1632
+ const tsconfig: any = {
1289
1633
  compilerOptions: {
1290
1634
  target: "ES2020",
1291
1635
  lib: ["ES2020", "DOM", "DOM.Iterable"],
@@ -1302,14 +1646,18 @@ export default config;
1302
1646
  incremental: true,
1303
1647
  isolatedModules: true,
1304
1648
  plugins: [{ name: "next" }],
1305
- paths: {
1306
- "@/*": ["./*"],
1307
- },
1649
+ paths,
1308
1650
  types: [],
1309
1651
  },
1310
1652
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
1311
1653
  exclude: ["node_modules", "dist", ".next", "out"],
1312
1654
  };
1655
+
1656
+ // Ajouter extends seulement en monorepo
1657
+ if (targetIsInMonorepo) {
1658
+ tsconfig.extends = "../../tsconfig.base.json";
1659
+ }
1660
+
1313
1661
  await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
1314
1662
  console.log(chalk.green("✓ tsconfig.json créé"));
1315
1663
  }
@@ -1340,6 +1688,69 @@ export const menuConfig: MenuConfig = {
1340
1688
  console.log(chalk.green("✓ config/menu.ts créé"));
1341
1689
  }
1342
1690
 
1691
+ // config/menu-ignored.ts - Optional file to hide menus and block routes
1692
+ const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
1693
+ if (!fs.existsSync(menuIgnoredPath) || force) {
1694
+ const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
1695
+
1696
+ /**
1697
+ * Menu items to hide and routes to block
1698
+ * This file is optional - if it doesn't exist, all menus are shown
1699
+ *
1700
+ * Example:
1701
+ * export const menuIgnored: MenuIgnored = {
1702
+ * public: [
1703
+ * { title: "Documentation", path: "/docs" }
1704
+ * ],
1705
+ * auth: [
1706
+ * { title: "Profile", path: "/auth/profile" }
1707
+ * ]
1708
+ * };
1709
+ */
1710
+
1711
+ export const menuIgnored: MenuIgnored = {
1712
+ public: [],
1713
+ auth: [],
1714
+ };
1715
+ `;
1716
+ await fs.writeFile(menuIgnoredPath, menuIgnored);
1717
+ console.log(chalk.green("✓ config/menu-ignored.ts créé"));
1718
+ }
1719
+
1720
+ // config/menu-custom.ts - Optional file to add custom menus
1721
+ const menuCustomPath = path.join(configDir, "menu-custom.ts");
1722
+ if (!fs.existsSync(menuCustomPath) || force) {
1723
+ const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
1724
+
1725
+ /**
1726
+ * Custom menu items to add without creating a module
1727
+ * This file is optional - if it doesn't exist, no custom menus are added
1728
+ *
1729
+ * Example:
1730
+ * export const menuCustom: MenuCustom = {
1731
+ * public: [
1732
+ * { label: "Blog", href: "/blog" },
1733
+ * { label: "Pricing", href: "/pricing" }
1734
+ * ],
1735
+ * auth: [
1736
+ * { label: "Invoices", href: "/auth/invoices" }
1737
+ * ],
1738
+ * admin: [
1739
+ * { label: "Reports", href: "/admin/reports" }
1740
+ * ]
1741
+ * };
1742
+ */
1743
+
1744
+ export const menuCustom: MenuCustom = {
1745
+ public: [],
1746
+ auth: [],
1747
+ admin: [],
1748
+ };
1749
+ `;
1750
+ await fs.writeFile(menuCustomPath, menuCustom);
1751
+ console.log(chalk.green("✓ config/menu-custom.ts créé"));
1752
+ }
1753
+
1343
1754
  // config/footer.ts
1344
1755
  const footerConfigPath = path.join(configDir, "footer.ts");
1345
1756
  if (!fs.existsSync(footerConfigPath) || force) {
@@ -1360,6 +1771,29 @@ export const footerConfig: FooterConfig = {
1360
1771
  console.log(chalk.green("✓ config/footer.ts créé"));
1361
1772
  }
1362
1773
 
1774
+ // config/user-tabs.ts - User detail page tabs configuration
1775
+ const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
1776
+ if (!fs.existsSync(userTabsConfigPath) || force) {
1777
+ const userTabsConfig = `// User tabs configuration
1778
+ // This file is generated and can be regenerated by running: pnpm build:modules
1779
+ "use client";
1780
+
1781
+ import type React from "react";
1782
+
1783
+ export interface ModuleUserTab {
1784
+ id: string;
1785
+ label: string;
1786
+ component: React.ComponentType<{ userId: string }>;
1787
+ }
1788
+
1789
+ // Module user tabs - dynamically imported from active modules
1790
+ // To add tabs from modules, import them here and add to the array below
1791
+ export const moduleUserTabs: ModuleUserTab[] = [];
1792
+ `;
1793
+ await fs.writeFile(userTabsConfigPath, userTabsConfig);
1794
+ console.log(chalk.green("✓ config/user-tabs.ts créé"));
1795
+ }
1796
+
1363
1797
  // Créer les hooks
1364
1798
  await createHooksDirectory(targetDir, force);
1365
1799
  }
@@ -1666,10 +2100,10 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
1666
2100
  )
1667
2101
  );
1668
2102
  }
1669
- } catch (error) {
2103
+ } catch (_error) {
1670
2104
  console.error(
1671
2105
  chalk.red("✗ Erreur lors de la création de la migration:"),
1672
- error
2106
+ _error
1673
2107
  );
1674
2108
  }
1675
2109
  } else {
@@ -1694,26 +2128,22 @@ async function addScriptsToPackageJson(targetDir: string) {
1694
2128
  ) ||
1695
2129
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1696
2130
 
1697
- let scriptsPrefix = "lastbrain";
1698
-
1699
- if (!targetIsInMonorepo) {
1700
- // Hors monorepo, utiliser le chemin direct vers le CLI
1701
- scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
1702
- }
2131
+ // Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
2132
+ const scriptsPrefix = targetIsInMonorepo
2133
+ ? "node ../../packages/app/dist/cli.js"
2134
+ : "node node_modules/@lastbrain/app/dist/cli.js";
1703
2135
 
1704
2136
  const scripts = {
1705
2137
  predev: targetIsInMonorepo
1706
- ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
1707
- : "echo 'No prebuild needed outside monorepo'",
2138
+ ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/app build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
2139
+ : "echo 'No prebuild needed'",
1708
2140
  dev: "next dev",
1709
2141
  "dev:local": "env-cmd -f .env.local next dev",
1710
2142
  "dev:prod": "env-cmd -f .env.prod next dev",
1711
2143
  build: "next build",
1712
2144
  start: "next start",
1713
2145
  lint: "next lint",
1714
- lastbrain: targetIsInMonorepo
1715
- ? "lastbrain"
1716
- : "node node_modules/@lastbrain/app/dist/cli.js",
2146
+ lastbrain: scriptsPrefix,
1717
2147
  "build:modules": `${scriptsPrefix} module:build`,
1718
2148
  "db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
1719
2149
  "db:init": `${scriptsPrefix} db:init`,
@@ -237,7 +237,7 @@ export async function addModule(moduleName: string, targetDir: string) {
237
237
  `✓ ${migrationFiles.length} migration(s) appliquée(s)`
238
238
  )
239
239
  );
240
- } catch (error: any) {
240
+ } catch (_error) {
241
241
  console.error(
242
242
  chalk.red("❌ Erreur lors de l'application des migrations")
243
243
  );