@lastbrain/app 0.1.47 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) 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.js +1 -1
  28. package/dist/templates/DocPage.js +1 -1
  29. package/dist/templates/DocsPageWithModules.js +1 -1
  30. package/dist/types/menu.d.ts +23 -0
  31. package/dist/types/menu.d.ts.map +1 -0
  32. package/dist/types/menu.js +1 -0
  33. package/package.json +9 -1
  34. package/src/app-shell/layout.tsx +1 -1
  35. package/src/components/NotificationContainer.tsx +1 -1
  36. package/src/index.ts +24 -19
  37. package/src/layouts/AdminLayoutWithSidebar.tsx +11 -3
  38. package/src/layouts/AppProviders.tsx +4 -4
  39. package/src/layouts/AuthLayoutWithSidebar.tsx +18 -4
  40. package/src/layouts/PublicLayoutWithSidebar.tsx +2 -2
  41. package/src/layouts/RootLayout.tsx +1 -1
  42. package/src/scripts/init-app.ts +479 -49
  43. package/src/scripts/module-add.ts +1 -1
  44. package/src/scripts/module-build.ts +46 -22
  45. package/src/scripts/module-create.ts +8 -8
  46. package/src/scripts/module-delete.ts +1 -4
  47. package/src/templates/DefaultDoc.tsx +1 -1
  48. package/src/templates/DocPage.tsx +1 -1
  49. package/src/templates/DocsPageWithModules.tsx +1 -1
  50. package/src/types/menu.ts +18 -0
@@ -4,7 +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 { AVAILABLE_MODULES, } from "@lastbrain/core/config/modules";
7
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
  export async function initApp(options) {
@@ -131,16 +131,22 @@ export async function initApp(options) {
131
131
  });
132
132
  console.log(chalk.green("\n✓ Migrations synchronisées\n"));
133
133
  }
134
- catch (error) {
134
+ catch (_error) {
135
135
  console.log(chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n"));
136
136
  }
137
- console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
138
- try {
139
- execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
140
- console.log(chalk.green("\n✓ Base de données initialisée\n"));
137
+ // Ne pas initialiser la BDD en mode monorepo
138
+ if (!isMonorepoProject) {
139
+ console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
140
+ try {
141
+ execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
142
+ console.log(chalk.green("\n✓ Base de données initialisée\n"));
143
+ }
144
+ catch {
145
+ console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
146
+ }
141
147
  }
142
- catch {
143
- console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
148
+ else {
149
+ console.log(chalk.cyan("⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"));
144
150
  }
145
151
  // Détecter le port (par défaut 3000 pour Next.js)
146
152
  const port = 3000;
@@ -149,10 +155,15 @@ export async function initApp(options) {
149
155
  console.log(chalk.cyan(`📱 Ouvrez votre navigateur sur : ${url}\n`));
150
156
  console.log(chalk.blue("\n📋 Prochaines étapes après le démarrage :"));
151
157
  console.log(chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"));
152
- console.log(chalk.white(" 2. Lancez Docker Desktop"));
153
- console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
154
- console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
155
- console.log(chalk.white(" 5. Rechargez la page\n"));
158
+ if (isMonorepoProject) {
159
+ console.log(chalk.white(" 2. La BDD est centralisée dans le monorepo\n"));
160
+ }
161
+ else {
162
+ console.log(chalk.white(" 2. Lancez Docker Desktop"));
163
+ console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
164
+ console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
165
+ console.log(chalk.white(" 5. Rechargez la page\n"));
166
+ }
156
167
  // Ouvrir le navigateur
157
168
  const openCommand = process.platform === "darwin"
158
169
  ? "open"
@@ -168,7 +179,7 @@ export async function initApp(options) {
168
179
  }
169
180
  }, 2000);
170
181
  // Lancer pnpm dev
171
- execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
182
+ execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
172
183
  }
173
184
  catch {
174
185
  console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
@@ -177,7 +188,9 @@ export async function initApp(options) {
177
188
  console.log(chalk.white(" pnpm install"));
178
189
  console.log(chalk.white(" pnpm build:modules"));
179
190
  console.log(chalk.white(" pnpm db:migrations:sync"));
180
- console.log(chalk.white(" pnpm db:init"));
191
+ if (!isMonorepoProject) {
192
+ console.log(chalk.white(" pnpm db:init"));
193
+ }
181
194
  console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
182
195
  }
183
196
  }
@@ -288,8 +301,8 @@ function getLastBrainVersions(targetDir) {
288
301
  };
289
302
  }
290
303
  }
291
- catch (error) {
292
- console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`));
304
+ catch (_error) {
305
+ console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`));
293
306
  }
294
307
  // Fallback: utiliser "latest"
295
308
  return {
@@ -722,17 +735,56 @@ async function createAppHeader(targetDir, force) {
722
735
  if (!fs.existsSync(headerPath) || force) {
723
736
  const headerContent = `"use client";
724
737
 
725
- import { Header } from "@lastbrain/ui";
738
+ import { Header, type MenuItem } from "@lastbrain/ui";
726
739
  import { menuConfig } from "../config/menu";
727
740
  import { supabaseBrowserClient } from "@lastbrain/core";
728
741
  import { useRouter } from "next/navigation";
729
742
  import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
743
+ import { useState, useEffect } from "react";
744
+
745
+ interface MenuIgnored {
746
+ public: { title: string; path: string }[];
747
+ auth: { title: string; path: string }[];
748
+ }
730
749
 
731
750
  export function AppHeader() {
732
751
  const router = useRouter();
733
752
  const { user, isSuperAdmin } = useAuthSession();
734
753
  const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
735
754
  useNotificationsContext();
755
+ const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
756
+ const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
757
+ const [isLoading, setIsLoading] = useState(true);
758
+
759
+ // Charger menuIgnored et menuCustom s'ils existent
760
+ useEffect(() => {
761
+ let loadedIgnored = false;
762
+ let loadedCustom = false;
763
+
764
+ // Charger menu-ignored
765
+ import("../config/menu-ignored")
766
+ .then((mod) => setMenuIgnored(mod.menuIgnored))
767
+ .catch(() => setMenuIgnored(undefined))
768
+ .finally(() => {
769
+ loadedIgnored = true;
770
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
771
+ });
772
+
773
+ // Charger menu-custom
774
+ import("../config/menu-custom")
775
+ .then((mod) => {
776
+ // Combiner les menus custom publics et auth
777
+ const customMenus: MenuItem[] = [];
778
+ if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
779
+ if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
780
+ setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
781
+ })
782
+ .catch(() => setMenuCustom(undefined))
783
+ .finally(() => {
784
+ loadedCustom = true;
785
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
786
+ });
787
+ }, []);
736
788
 
737
789
  const handleLogout = async () => {
738
790
  await supabaseBrowserClient.auth.signOut();
@@ -755,6 +807,9 @@ export function AppHeader() {
755
807
  onMarkAsRead={markAsRead}
756
808
  onMarkAllAsRead={markAllAsRead}
757
809
  onDeleteNotification={deleteNotification}
810
+ {...(menuIgnored ? { menuIgnored } : {})}
811
+ {...(menuCustom ? { menuCustom } : {})}
812
+ {...{ isLoadingMenus: isLoading }}
758
813
  />
759
814
  );
760
815
  }
@@ -832,7 +887,58 @@ async function createConfigFiles(targetDir, force, useHeroUI, projectName) {
832
887
  const middlewarePath = path.join(targetDir, "middleware.ts");
833
888
  if (!fs.existsSync(middlewarePath) || force) {
834
889
  const middleware = `import { type NextRequest, NextResponse } from "next/server";
835
- import { createMiddlewareClient } from "@lastbrain/core/server";
890
+ import { createServerClient, type CookieOptions } from "@supabase/ssr";
891
+
892
+ /**
893
+ * Crée un client Supabase pour le middleware
894
+ */
895
+ function createMiddlewareClient(request: NextRequest) {
896
+ let response = NextResponse.next({
897
+ request: {
898
+ headers: request.headers,
899
+ },
900
+ });
901
+
902
+ const supabase = createServerClient(
903
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
904
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
905
+ {
906
+ cookies: {
907
+ get(name: string) {
908
+ return request.cookies.get(name)?.value;
909
+ },
910
+ set(name: string, value: string, options: CookieOptions) {
911
+ request.cookies.set({
912
+ name,
913
+ value,
914
+ ...options,
915
+ });
916
+ response = NextResponse.next({
917
+ request: {
918
+ headers: request.headers,
919
+ },
920
+ });
921
+ response.cookies.set({
922
+ name,
923
+ value,
924
+ ...options,
925
+ });
926
+ },
927
+ remove(name: string, options: CookieOptions) {
928
+ request.cookies.delete(name);
929
+ response = NextResponse.next({
930
+ request: {
931
+ headers: request.headers,
932
+ },
933
+ });
934
+ response.cookies.delete(name);
935
+ },
936
+ },
937
+ }
938
+ );
939
+
940
+ return { supabase, response };
941
+ }
836
942
 
837
943
  export async function middleware(request: NextRequest) {
838
944
  const { pathname } = request.nextUrl;
@@ -975,9 +1081,9 @@ export const config = {
975
1081
  const nextConfig = `/** @type {import('next').NextConfig} */
976
1082
  const nextConfig = {
977
1083
  reactStrictMode: true,
978
- devIndicators: {
1084
+ devIndicators: {
979
1085
  position: 'bottom-right',
980
- },
1086
+ }
981
1087
  };
982
1088
 
983
1089
  export default nextConfig;
@@ -990,7 +1096,7 @@ export default nextConfig;
990
1096
  if (!fs.existsSync(tailwindConfigPath) || force) {
991
1097
  let tailwindConfig = "";
992
1098
  if (useHeroUI) {
993
- // Configuration avec HeroUI
1099
+ // Configuration avec HeroUI - complète avec thèmes
994
1100
  tailwindConfig = `import { heroui } from "@heroui/theme";
995
1101
 
996
1102
  /** @type {import('tailwindcss').Config} */
@@ -1002,8 +1108,195 @@ const config = {
1002
1108
  "./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
1003
1109
  ],
1004
1110
  darkMode: "class",
1005
- plugins: [heroui()],
1006
- }
1111
+ plugins: [
1112
+ heroui({
1113
+ themes: {
1114
+ light: {
1115
+ colors: {
1116
+ default: {
1117
+ 950: "#0d0d0e",
1118
+ 900: "#19191c",
1119
+ 800: "#26262a",
1120
+ 700: "#323238",
1121
+ 600: "#3f3f46",
1122
+ 500: "#65656b",
1123
+ 400: "#8c8c90",
1124
+ 300: "#b2b2b5",
1125
+ 200: "#d9d9da",
1126
+ 100: "#ffffff",
1127
+ foreground: "#000000",
1128
+ DEFAULT: "#d4d4d8",
1129
+ },
1130
+ primary: {
1131
+ 50: "#eef2ff",
1132
+ 100: "#e0e7ff",
1133
+ 200: "#c7d2fe",
1134
+ 300: "#a5b4fc",
1135
+ 400: "#818cf8",
1136
+ 500: "#6366f1",
1137
+ 600: "#4f46e5",
1138
+ 700: "#4338ca",
1139
+ 800: "#3730a3",
1140
+ 900: "#312e81",
1141
+ foreground: "#ffffff",
1142
+ DEFAULT: "#6366f1",
1143
+ },
1144
+ secondary: {
1145
+ 50: "#f5e8ff",
1146
+ 100: "#e8ccff",
1147
+ 200: "#d7a6ff",
1148
+ 300: "#c57fff",
1149
+ 400: "#b359ff",
1150
+ 500: "#9b37ff",
1151
+ 600: "#7d1fcc",
1152
+ 700: "#5f1799",
1153
+ 800: "#410f66",
1154
+ 900: "#240833",
1155
+ foreground: "#ffffff",
1156
+ DEFAULT: "#9b37ff",
1157
+ },
1158
+ success: {
1159
+ 50: "#e7fff7",
1160
+ 100: "#c3ffec",
1161
+ 200: "#9affdf",
1162
+ 300: "#70ffd2",
1163
+ 400: "#4bffca",
1164
+ 500: "#22e6b0",
1165
+ 600: "#18b38a",
1166
+ 700: "#108066",
1167
+ 800: "#074d40",
1168
+ 900: "#012b22",
1169
+ foreground: "#000",
1170
+ DEFAULT: "#22e6b0",
1171
+ },
1172
+ warning: {
1173
+ 50: "#fff8e1",
1174
+ 100: "#ffecb3",
1175
+ 200: "#ffe082",
1176
+ 300: "#ffd54f",
1177
+ 400: "#ffca28",
1178
+ 500: "#ffc107",
1179
+ 600: "#ffb300",
1180
+ 700: "#ffa000",
1181
+ 800: "#ff8f00",
1182
+ 900: "#ff6f00",
1183
+ foreground: "#000",
1184
+ DEFAULT: "#ffca28",
1185
+ },
1186
+ danger: {
1187
+ 50: "#ffe6e9",
1188
+ 100: "#ffbac1",
1189
+ 200: "#ff8f99",
1190
+ 300: "#ff6471",
1191
+ 400: "#ff3949",
1192
+ 500: "#ff112a",
1193
+ 600: "#d80c22",
1194
+ 700: "#b1081b",
1195
+ 800: "#890514",
1196
+ 900: "#62020d",
1197
+ foreground: "#fff",
1198
+ DEFAULT: "#ff112a",
1199
+ },
1200
+ background: "#f7f8fc",
1201
+ foreground: "#0e0e10",
1202
+ content1: "#ffffff",
1203
+ },
1204
+ },
1205
+ dark: {
1206
+ colors: {
1207
+ default: {
1208
+ 50: "#1a1c1f",
1209
+ 100: "#232529",
1210
+ 200: "#2c2f34",
1211
+ 300: "#363940",
1212
+ 400: "#40444d",
1213
+ 500: "#4b4f59",
1214
+ 600: "#6c707b",
1215
+ 700: "#8d919b",
1216
+ 800: "#afb2bb",
1217
+ 900: "#d1d3d9",
1218
+ foreground: "#ffffff",
1219
+ DEFAULT: "#363940",
1220
+ },
1221
+ primary: {
1222
+ 50: "#312e81",
1223
+ 100: "#3730a3",
1224
+ 200: "#4338ca",
1225
+ 300: "#4f46e5",
1226
+ 400: "#6366f1",
1227
+ 500: "#818cf8",
1228
+ 600: "#a5b4fc",
1229
+ 700: "#c7d2fe",
1230
+ 800: "#e0e7ff",
1231
+ 900: "#eef2ff",
1232
+ foreground: "#ffffff",
1233
+ DEFAULT: "#6366f1",
1234
+ },
1235
+ secondary: {
1236
+ 50: "#240833",
1237
+ 100: "#410f66",
1238
+ 200: "#5f1799",
1239
+ 300: "#7d1fcc",
1240
+ 400: "#9b37ff",
1241
+ 500: "#b359ff",
1242
+ 600: "#c57fff",
1243
+ 700: "#d7a6ff",
1244
+ 800: "#e8ccff",
1245
+ 900: "#f5e8ff",
1246
+ foreground: "#ffffff",
1247
+ DEFAULT: "#9b37ff",
1248
+ },
1249
+ success: {
1250
+ 50: "#012b22",
1251
+ 100: "#074d40",
1252
+ 200: "#108066",
1253
+ 300: "#18b38a",
1254
+ 400: "#22e6b0",
1255
+ 500: "#4bffca",
1256
+ 600: "#70ffd2",
1257
+ 700: "#9affdf",
1258
+ 800: "#c3ffec",
1259
+ 900: "#e7fff7",
1260
+ foreground: "#0e0e0e",
1261
+ DEFAULT: "#22e6b0",
1262
+ },
1263
+ warning: {
1264
+ 50: "#3a2c00",
1265
+ 100: "#5e4700",
1266
+ 200: "#836300",
1267
+ 300: "#a77e00",
1268
+ 400: "#cc9900",
1269
+ 500: "#ffc107",
1270
+ 600: "#ffd54f",
1271
+ 700: "#ffe082",
1272
+ 800: "#ffecb3",
1273
+ 900: "#fff8e1",
1274
+ foreground: "#000",
1275
+ DEFAULT: "#ffc107",
1276
+ },
1277
+ danger: {
1278
+ 50: "#4a000a",
1279
+ 100: "#6e000f",
1280
+ 200: "#920014",
1281
+ 300: "#b60019",
1282
+ 400: "#da001f",
1283
+ 500: "#ff112a",
1284
+ 600: "#ff3949",
1285
+ 700: "#ff6471",
1286
+ 800: "#ff8f99",
1287
+ 900: "#ffbac1",
1288
+ foreground: "#ffffff",
1289
+ DEFAULT: "#ff112a",
1290
+ },
1291
+ background: "#0f1114",
1292
+ foreground: "#f8f8f8",
1293
+ content1: "#15181d",
1294
+ },
1295
+ },
1296
+ },
1297
+ }),
1298
+ ],
1299
+ };
1007
1300
 
1008
1301
  export default config;
1009
1302
  `;
@@ -1060,8 +1353,51 @@ export default config;
1060
1353
  // tsconfig.json
1061
1354
  const tsconfigPath = path.join(targetDir, "tsconfig.json");
1062
1355
  if (!fs.existsSync(tsconfigPath) || force) {
1356
+ // Détecter si le projet cible est dans un monorepo
1357
+ const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
1358
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1359
+ // Générer les chemins en fonction du contexte
1360
+ const paths = {
1361
+ "@/*": ["./*"],
1362
+ };
1363
+ if (targetIsInMonorepo) {
1364
+ // En monorepo, pointer sur les sources locales
1365
+ paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
1366
+ paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
1367
+ paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
1368
+ paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
1369
+ paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
1370
+ paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
1371
+ paths["@lastbrain/module-auth"] = [
1372
+ "../../packages/module-auth/src/index.ts",
1373
+ ];
1374
+ paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
1375
+ paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
1376
+ paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
1377
+ paths["@lastbrain/module-legal"] = [
1378
+ "../../packages/module-legal/src/index.ts",
1379
+ ];
1380
+ paths["@lastbrain/module-legal/*"] = [
1381
+ "../../packages/module-legal/src/*",
1382
+ ];
1383
+ paths["@lastbrain/module-project-board"] = [
1384
+ "../../packages/module-project-board/src/index.ts",
1385
+ ];
1386
+ paths["@lastbrain/module-project-board/*"] = [
1387
+ "../../packages/module-project-board/src/*",
1388
+ ];
1389
+ paths["@lastbrain/module-tasks"] = [
1390
+ "../../packages/module-tasks/src/index.ts",
1391
+ ];
1392
+ paths["@lastbrain/module-tasks/*"] = [
1393
+ "../../packages/module-tasks/src/*",
1394
+ ];
1395
+ }
1396
+ else {
1397
+ // Hors monorepo (npm install), ne pas utiliser de paths aliases
1398
+ delete paths["@/*"];
1399
+ }
1063
1400
  const tsconfig = {
1064
- extends: "../../tsconfig.base.json",
1065
1401
  compilerOptions: {
1066
1402
  target: "ES2020",
1067
1403
  lib: ["ES2020", "DOM", "DOM.Iterable"],
@@ -1078,14 +1414,16 @@ export default config;
1078
1414
  incremental: true,
1079
1415
  isolatedModules: true,
1080
1416
  plugins: [{ name: "next" }],
1081
- paths: {
1082
- "@/*": ["./*"],
1083
- },
1417
+ paths,
1084
1418
  types: [],
1085
1419
  },
1086
1420
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
1087
1421
  exclude: ["node_modules", "dist", ".next", "out"],
1088
1422
  };
1423
+ // Ajouter extends seulement en monorepo
1424
+ if (targetIsInMonorepo) {
1425
+ tsconfig.extends = "../../tsconfig.base.json";
1426
+ }
1089
1427
  await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
1090
1428
  console.log(chalk.green("✓ tsconfig.json créé"));
1091
1429
  }
@@ -1114,6 +1452,67 @@ export const menuConfig: MenuConfig = {
1114
1452
  await fs.writeFile(menuConfigPath, menuConfig);
1115
1453
  console.log(chalk.green("✓ config/menu.ts créé"));
1116
1454
  }
1455
+ // config/menu-ignored.ts - Optional file to hide menus and block routes
1456
+ const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
1457
+ if (!fs.existsSync(menuIgnoredPath) || force) {
1458
+ const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
1459
+
1460
+ /**
1461
+ * Menu items to hide and routes to block
1462
+ * This file is optional - if it doesn't exist, all menus are shown
1463
+ *
1464
+ * Example:
1465
+ * export const menuIgnored: MenuIgnored = {
1466
+ * public: [
1467
+ * { title: "Documentation", path: "/docs" }
1468
+ * ],
1469
+ * auth: [
1470
+ * { title: "Profile", path: "/auth/profile" }
1471
+ * ]
1472
+ * };
1473
+ */
1474
+
1475
+ export const menuIgnored: MenuIgnored = {
1476
+ public: [],
1477
+ auth: [],
1478
+ };
1479
+ `;
1480
+ await fs.writeFile(menuIgnoredPath, menuIgnored);
1481
+ console.log(chalk.green("✓ config/menu-ignored.ts créé"));
1482
+ }
1483
+ // config/menu-custom.ts - Optional file to add custom menus
1484
+ const menuCustomPath = path.join(configDir, "menu-custom.ts");
1485
+ if (!fs.existsSync(menuCustomPath) || force) {
1486
+ const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
1487
+
1488
+ /**
1489
+ * Custom menu items to add without creating a module
1490
+ * This file is optional - if it doesn't exist, no custom menus are added
1491
+ *
1492
+ * Example:
1493
+ * export const menuCustom: MenuCustom = {
1494
+ * public: [
1495
+ * { label: "Blog", href: "/blog" },
1496
+ * { label: "Pricing", href: "/pricing" }
1497
+ * ],
1498
+ * auth: [
1499
+ * { label: "Invoices", href: "/auth/invoices" }
1500
+ * ],
1501
+ * admin: [
1502
+ * { label: "Reports", href: "/admin/reports" }
1503
+ * ]
1504
+ * };
1505
+ */
1506
+
1507
+ export const menuCustom: MenuCustom = {
1508
+ public: [],
1509
+ auth: [],
1510
+ admin: [],
1511
+ };
1512
+ `;
1513
+ await fs.writeFile(menuCustomPath, menuCustom);
1514
+ console.log(chalk.green("✓ config/menu-custom.ts créé"));
1515
+ }
1117
1516
  // config/footer.ts
1118
1517
  const footerConfigPath = path.join(configDir, "footer.ts");
1119
1518
  if (!fs.existsSync(footerConfigPath) || force) {
@@ -1133,6 +1532,28 @@ export const footerConfig: FooterConfig = {
1133
1532
  await fs.writeFile(footerConfigPath, footerConfig);
1134
1533
  console.log(chalk.green("✓ config/footer.ts créé"));
1135
1534
  }
1535
+ // config/user-tabs.ts - User detail page tabs configuration
1536
+ const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
1537
+ if (!fs.existsSync(userTabsConfigPath) || force) {
1538
+ const userTabsConfig = `// User tabs configuration
1539
+ // This file is generated and can be regenerated by running: pnpm build:modules
1540
+ "use client";
1541
+
1542
+ import type React from "react";
1543
+
1544
+ export interface ModuleUserTab {
1545
+ id: string;
1546
+ label: string;
1547
+ component: React.ComponentType<{ userId: string }>;
1548
+ }
1549
+
1550
+ // Module user tabs - dynamically imported from active modules
1551
+ // To add tabs from modules, import them here and add to the array below
1552
+ export const moduleUserTabs: ModuleUserTab[] = [];
1553
+ `;
1554
+ await fs.writeFile(userTabsConfigPath, userTabsConfig);
1555
+ console.log(chalk.green("✓ config/user-tabs.ts créé"));
1556
+ }
1136
1557
  // Créer les hooks
1137
1558
  await createHooksDirectory(targetDir, force);
1138
1559
  }
@@ -1395,8 +1816,8 @@ async function createSupabaseStructure(targetDir, force) {
1395
1816
  console.log(chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé (vide)"));
1396
1817
  }
1397
1818
  }
1398
- catch (error) {
1399
- console.error(chalk.red("✗ Erreur lors de la création de la migration:"), error);
1819
+ catch (_error) {
1820
+ console.error(chalk.red("✗ Erreur lors de la création de la migration:"), _error);
1400
1821
  }
1401
1822
  }
1402
1823
  else {
@@ -1410,24 +1831,21 @@ async function addScriptsToPackageJson(targetDir) {
1410
1831
  // Détecter si le projet cible est dans un workspace
1411
1832
  const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
1412
1833
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1413
- let scriptsPrefix = "lastbrain";
1414
- if (!targetIsInMonorepo) {
1415
- // Hors monorepo, utiliser le chemin direct vers le CLI
1416
- scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
1417
- }
1834
+ // Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
1835
+ const scriptsPrefix = targetIsInMonorepo
1836
+ ? "node ../../packages/app/dist/cli.js"
1837
+ : "node node_modules/@lastbrain/app/dist/cli.js";
1418
1838
  const scripts = {
1419
1839
  predev: targetIsInMonorepo
1420
- ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
1421
- : "echo 'No prebuild needed outside monorepo'",
1840
+ ? "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"
1841
+ : "echo 'No prebuild needed'",
1422
1842
  dev: "next dev",
1423
1843
  "dev:local": "env-cmd -f .env.local next dev",
1424
1844
  "dev:prod": "env-cmd -f .env.prod next dev",
1425
1845
  build: "next build",
1426
1846
  start: "next start",
1427
1847
  lint: "next lint",
1428
- lastbrain: targetIsInMonorepo
1429
- ? "lastbrain"
1430
- : "node node_modules/@lastbrain/app/dist/cli.js",
1848
+ lastbrain: scriptsPrefix,
1431
1849
  "build:modules": `${scriptsPrefix} module:build`,
1432
1850
  "db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
1433
1851
  "db:init": `${scriptsPrefix} db:init`,
@@ -168,7 +168,7 @@ export async function addModule(moduleName, targetDir) {
168
168
  }
169
169
  console.log(chalk.green(`✓ ${migrationFiles.length} migration(s) appliquée(s)`));
170
170
  }
171
- catch (error) {
171
+ catch (_error) {
172
172
  console.error(chalk.red("❌ Erreur lors de l'application des migrations"));
173
173
  console.log(chalk.gray("\nVous pouvez essayer manuellement:\n supabase db reset\n"));
174
174
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AAy4CA,wBAAsB,cAAc,kBA+FnC"}
1
+ {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AAi6CA,wBAAsB,cAAc,kBA+FnC"}