wadi 1.0.0

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 (294) hide show
  1. package/.agent/workflows/auto_sync.md +19 -0
  2. package/.agent/workflows/kivo_pipeline.md +27 -0
  3. package/.devcontainer/devcontainer.json +27 -0
  4. package/.github/workflows/kivo-cicd.yml +45 -0
  5. package/.github/workflows/monorepo-ci.yml +51 -0
  6. package/.github/workflows/wadi-ci.yml +38 -0
  7. package/.husky/pre-commit +2 -0
  8. package/.prettierignore +12 -0
  9. package/.prettierrc +9 -0
  10. package/.vscode/settings.json +19 -0
  11. package/CHANGELOG.md +56 -0
  12. package/CODE_OF_CONDUCT.md +43 -0
  13. package/CONTRIBUTING.md +42 -0
  14. package/DEPLOY_GUIDE.md +143 -0
  15. package/GO_LIVE_CHECKLIST.md +41 -0
  16. package/GO_LIVE_COMPLETE_REPORT.md +58 -0
  17. package/GO_LIVE_VALIDATION.md +39 -0
  18. package/LEGAL.md +38 -0
  19. package/MANIFESTO.md +40 -0
  20. package/MANUAL.md +82 -0
  21. package/OPS_PLAN.md +90 -0
  22. package/README.md +126 -0
  23. package/RELEASE_NOTES.md +51 -0
  24. package/ROADMAP.md +51 -0
  25. package/api_listado.txt +2197 -0
  26. package/apps/api/WADI_PROTOCOL.md +52 -0
  27. package/apps/api/debug-brain.js +11 -0
  28. package/apps/api/package.json +21 -0
  29. package/apps/api/src/core/analisis.js +17 -0
  30. package/apps/api/src/core/errors.js +31 -0
  31. package/apps/api/src/core/logger.js +32 -0
  32. package/apps/api/src/core/prompt-kivo.js +62 -0
  33. package/apps/api/src/index.js +212 -0
  34. package/apps/api/src/layers/human_pattern/composeResponse.js +35 -0
  35. package/apps/api/src/layers/human_pattern/detectPattern.js +39 -0
  36. package/apps/api/src/layers/human_pattern/heuristics.js +28 -0
  37. package/apps/api/src/layers/human_pattern/index.js +28 -0
  38. package/apps/api/src/layers/human_pattern/socialMemory.js +35 -0
  39. package/apps/api/src/middleware/errorHandler.js +24 -0
  40. package/apps/api/src/middleware/rateLimiter.js +38 -0
  41. package/apps/api/src/middleware/requestLogger.js +31 -0
  42. package/apps/api/src/middleware/upload.js +21 -0
  43. package/apps/api/src/middleware/validation.js +70 -0
  44. package/apps/api/src/modules/data.js +25 -0
  45. package/apps/api/src/modules/marketing.js +54 -0
  46. package/apps/api/src/modules/projects.js +40 -0
  47. package/apps/api/src/openai.js +16 -0
  48. package/apps/api/src/preferences/index.js +20 -0
  49. package/apps/api/src/register_user.js +22 -0
  50. package/apps/api/src/routes/kivo.js +58 -0
  51. package/apps/api/src/routes/monitoring.js +55 -0
  52. package/apps/api/src/routes.js +656 -0
  53. package/apps/api/src/supabase.js +17 -0
  54. package/apps/api/src/tools/index.js +57 -0
  55. package/apps/api/src/wadi-brain.js +171 -0
  56. package/apps/api/supabase/migrations/20251218_audit_logs.sql +27 -0
  57. package/apps/api/supabase/migrations/v2-chat-persistence.sql +83 -0
  58. package/apps/api/supabase/migrations/v3-cascade-delete.sql +11 -0
  59. package/apps/api/supabase/migrations/v3-security-fix.sql +90 -0
  60. package/apps/api/supabase/migrations/v3-storage.sql +36 -0
  61. package/apps/api/supabase/migrations/v4-gamification.sql +83 -0
  62. package/apps/api/supabase/migrations/v5-smoke-index.sql +6 -0
  63. package/apps/api/supabase/migrations/v6-schema-integrity-fix.sql +98 -0
  64. package/apps/api/supabase/migrations/v7-performance-indexes.sql +5 -0
  65. package/apps/api/supabase/migrations/v7-security-hardening.sql +132 -0
  66. package/apps/api/supabase/migrations/v8-security-hardening.sql +79 -0
  67. package/apps/api/test_human_pattern.js +30 -0
  68. package/apps/api/test_human_pattern_vague.js +30 -0
  69. package/apps/api/test_output.txt +76 -0
  70. package/apps/api/test_vague.js +30 -0
  71. package/apps/api/test_vague_block.js +30 -0
  72. package/apps/api/test_wadi.js +31 -0
  73. package/apps/api/tsconfig.json +13 -0
  74. package/apps/frontend/.env.local +3 -0
  75. package/apps/frontend/README.md +73 -0
  76. package/apps/frontend/eslint.config.js +27 -0
  77. package/apps/frontend/index.html +49 -0
  78. package/apps/frontend/package.json +41 -0
  79. package/apps/frontend/postcss.config.cjs +6 -0
  80. package/apps/frontend/public/cursors/wadi-neutral.svg +1 -0
  81. package/apps/frontend/public/cursors/wadi-select.svg +1 -0
  82. package/apps/frontend/public/icon-192.svg +1 -0
  83. package/apps/frontend/public/icon-512.svg +1 -0
  84. package/apps/frontend/public/manifest.webmanifest +23 -0
  85. package/apps/frontend/public/sw.js +57 -0
  86. package/apps/frontend/public/vite.svg +1 -0
  87. package/apps/frontend/public/wadi.svg +5 -0
  88. package/apps/frontend/src/assets/react.svg +1 -0
  89. package/apps/frontend/src/components/AuthLoader.tsx +50 -0
  90. package/apps/frontend/src/components/ChatInput.tsx +272 -0
  91. package/apps/frontend/src/components/ChatInterface.tsx +202 -0
  92. package/apps/frontend/src/components/ErrorBoundary.tsx +52 -0
  93. package/apps/frontend/src/components/InputArea.tsx +201 -0
  94. package/apps/frontend/src/components/Layout.tsx +73 -0
  95. package/apps/frontend/src/components/MessageBubble.tsx +66 -0
  96. package/apps/frontend/src/components/OnboardingModal.tsx +108 -0
  97. package/apps/frontend/src/components/SettingsModal.tsx +187 -0
  98. package/apps/frontend/src/components/Sidebar.tsx +171 -0
  99. package/apps/frontend/src/components/WadiOnboarding.tsx +71 -0
  100. package/apps/frontend/src/components/auditor/AuditReport.tsx +166 -0
  101. package/apps/frontend/src/components/auditor/AuditorHeader.tsx +34 -0
  102. package/apps/frontend/src/components/auditor/ContextPanel.tsx +138 -0
  103. package/apps/frontend/src/components/auditor/DataDeconstructor.tsx +85 -0
  104. package/apps/frontend/src/components/auditor/DecisionWall.tsx +65 -0
  105. package/apps/frontend/src/components/auditor/Dropzone.tsx +137 -0
  106. package/apps/frontend/src/components/common/Button.tsx +97 -0
  107. package/apps/frontend/src/components/common/Card.tsx +43 -0
  108. package/apps/frontend/src/components/common/Input.tsx +73 -0
  109. package/apps/frontend/src/components/common/Modal.tsx +53 -0
  110. package/apps/frontend/src/components/ui/Button.tsx +68 -0
  111. package/apps/frontend/src/components/ui/Card.tsx +86 -0
  112. package/apps/frontend/src/components/ui/Input.tsx +28 -0
  113. package/apps/frontend/src/components/ui/LogItem.tsx +64 -0
  114. package/apps/frontend/src/components/ui/MondayButton.tsx +40 -0
  115. package/apps/frontend/src/components/ui/MondayCard.tsx +24 -0
  116. package/apps/frontend/src/components/ui/Scouter.tsx +208 -0
  117. package/apps/frontend/src/components/ui/TerminalInput.tsx +202 -0
  118. package/apps/frontend/src/components/ui/Tooltip.tsx +67 -0
  119. package/apps/frontend/src/config/chatShortcuts.ts +20 -0
  120. package/apps/frontend/src/config/supabase.ts +6 -0
  121. package/apps/frontend/src/final_status.txt +3 -0
  122. package/apps/frontend/src/hooks/useScouter.ts +28 -0
  123. package/apps/frontend/src/hooks/useStoreHydration.ts +24 -0
  124. package/apps/frontend/src/improvement_status.txt +5 -0
  125. package/apps/frontend/src/index.css +88 -0
  126. package/apps/frontend/src/main.tsx +62 -0
  127. package/apps/frontend/src/monday_status.txt +7 -0
  128. package/apps/frontend/src/pages/ChatPage.tsx +201 -0
  129. package/apps/frontend/src/pages/DashboardPage.tsx +375 -0
  130. package/apps/frontend/src/pages/IntroWadi.tsx +114 -0
  131. package/apps/frontend/src/pages/LandingPage.tsx +103 -0
  132. package/apps/frontend/src/pages/Login.tsx +190 -0
  133. package/apps/frontend/src/pages/PrivacyPage.tsx +213 -0
  134. package/apps/frontend/src/pages/ProjectDetail.tsx +80 -0
  135. package/apps/frontend/src/pages/Projects.tsx +247 -0
  136. package/apps/frontend/src/pages/TermsPage.tsx +202 -0
  137. package/apps/frontend/src/router.tsx +83 -0
  138. package/apps/frontend/src/store/authStore.ts +152 -0
  139. package/apps/frontend/src/store/chatStore.ts +837 -0
  140. package/apps/frontend/src/store/documentStore.ts +89 -0
  141. package/apps/frontend/src/store/projectsStore.ts +111 -0
  142. package/apps/frontend/src/store/runsStore.ts +98 -0
  143. package/apps/frontend/src/utils/api.ts +34 -0
  144. package/apps/frontend/src/vite-env.d.ts +7 -0
  145. package/apps/frontend/tailwind.config.cjs +32 -0
  146. package/apps/frontend/tsconfig.app.json +27 -0
  147. package/apps/frontend/tsconfig.json +7 -0
  148. package/apps/frontend/tsconfig.node.json +26 -0
  149. package/apps/frontend/vite.config.ts +25 -0
  150. package/apps/kivo/.firebase/hosting.d3d3.cache +11 -0
  151. package/apps/kivo/.firebaserc +5 -0
  152. package/apps/kivo/BRANDING_GUIDE.md +71 -0
  153. package/apps/kivo/DEPLOYMENT_READY.md +46 -0
  154. package/apps/kivo/DEPLOY_URL.md +12 -0
  155. package/apps/kivo/IMPLEMENTATION_REPORT.md +35 -0
  156. package/apps/kivo/IMPLEMENTATION_REPORT_FINAL.md +49 -0
  157. package/apps/kivo/PLAN_MOBILE_2.0.md +44 -0
  158. package/apps/kivo/PWA_VERIFICATION_GUIDE.md +77 -0
  159. package/apps/kivo/README.md +28 -0
  160. package/apps/kivo/REBUILD_REPORT.md +34 -0
  161. package/apps/kivo/UPGRADE_REPORT.md +35 -0
  162. package/apps/kivo/android/app/build.gradle +54 -0
  163. package/apps/kivo/android/app/capacitor.build.gradle +19 -0
  164. package/apps/kivo/android/app/proguard-rules.pro +21 -0
  165. package/apps/kivo/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +26 -0
  166. package/apps/kivo/android/app/src/main/AndroidManifest.xml +35 -0
  167. package/apps/kivo/android/app/src/main/java/com/kivo/app/MainActivity.java +5 -0
  168. package/apps/kivo/android/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  169. package/apps/kivo/android/app/src/main/res/drawable/splash.png +0 -0
  170. package/apps/kivo/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
  171. package/apps/kivo/android/app/src/main/res/drawable-land-ldpi/splash.png +0 -0
  172. package/apps/kivo/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
  173. package/apps/kivo/android/app/src/main/res/drawable-land-night-hdpi/splash.png +0 -0
  174. package/apps/kivo/android/app/src/main/res/drawable-land-night-ldpi/splash.png +0 -0
  175. package/apps/kivo/android/app/src/main/res/drawable-land-night-mdpi/splash.png +0 -0
  176. package/apps/kivo/android/app/src/main/res/drawable-land-night-xhdpi/splash.png +0 -0
  177. package/apps/kivo/android/app/src/main/res/drawable-land-night-xxhdpi/splash.png +0 -0
  178. package/apps/kivo/android/app/src/main/res/drawable-land-night-xxxhdpi/splash.png +0 -0
  179. package/apps/kivo/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
  180. package/apps/kivo/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
  181. package/apps/kivo/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
  182. package/apps/kivo/android/app/src/main/res/drawable-night/splash.png +0 -0
  183. package/apps/kivo/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
  184. package/apps/kivo/android/app/src/main/res/drawable-port-ldpi/splash.png +0 -0
  185. package/apps/kivo/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
  186. package/apps/kivo/android/app/src/main/res/drawable-port-night-hdpi/splash.png +0 -0
  187. package/apps/kivo/android/app/src/main/res/drawable-port-night-ldpi/splash.png +0 -0
  188. package/apps/kivo/android/app/src/main/res/drawable-port-night-mdpi/splash.png +0 -0
  189. package/apps/kivo/android/app/src/main/res/drawable-port-night-xhdpi/splash.png +0 -0
  190. package/apps/kivo/android/app/src/main/res/drawable-port-night-xxhdpi/splash.png +0 -0
  191. package/apps/kivo/android/app/src/main/res/drawable-port-night-xxxhdpi/splash.png +0 -0
  192. package/apps/kivo/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
  193. package/apps/kivo/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
  194. package/apps/kivo/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
  195. package/apps/kivo/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +34 -0
  196. package/apps/kivo/android/app/src/main/res/layout/activity_main.xml +12 -0
  197. package/apps/kivo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +9 -0
  198. package/apps/kivo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +9 -0
  199. package/apps/kivo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  200. package/apps/kivo/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png +0 -0
  201. package/apps/kivo/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  202. package/apps/kivo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  203. package/apps/kivo/android/app/src/main/res/mipmap-ldpi/ic_launcher.png +0 -0
  204. package/apps/kivo/android/app/src/main/res/mipmap-ldpi/ic_launcher_background.png +0 -0
  205. package/apps/kivo/android/app/src/main/res/mipmap-ldpi/ic_launcher_foreground.png +0 -0
  206. package/apps/kivo/android/app/src/main/res/mipmap-ldpi/ic_launcher_round.png +0 -0
  207. package/apps/kivo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  208. package/apps/kivo/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png +0 -0
  209. package/apps/kivo/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  210. package/apps/kivo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  211. package/apps/kivo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  212. package/apps/kivo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png +0 -0
  213. package/apps/kivo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  214. package/apps/kivo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  215. package/apps/kivo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  216. package/apps/kivo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png +0 -0
  217. package/apps/kivo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  218. package/apps/kivo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  219. package/apps/kivo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  220. package/apps/kivo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png +0 -0
  221. package/apps/kivo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  222. package/apps/kivo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  223. package/apps/kivo/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
  224. package/apps/kivo/android/app/src/main/res/values/strings.xml +7 -0
  225. package/apps/kivo/android/app/src/main/res/values/styles.xml +22 -0
  226. package/apps/kivo/android/app/src/main/res/xml/file_paths.xml +5 -0
  227. package/apps/kivo/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +18 -0
  228. package/apps/kivo/android/build.gradle +29 -0
  229. package/apps/kivo/android/capacitor.settings.gradle +3 -0
  230. package/apps/kivo/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  231. package/apps/kivo/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  232. package/apps/kivo/android/gradle.properties +22 -0
  233. package/apps/kivo/android/gradlew +252 -0
  234. package/apps/kivo/android/gradlew.bat +94 -0
  235. package/apps/kivo/android/settings.gradle +5 -0
  236. package/apps/kivo/android/variables.gradle +16 -0
  237. package/apps/kivo/assets/icon.png +0 -0
  238. package/apps/kivo/assets/splash.png +0 -0
  239. package/apps/kivo/capacitor.config.json +16 -0
  240. package/apps/kivo/firebase.json +6 -0
  241. package/apps/kivo/jest.config.js +4 -0
  242. package/apps/kivo/package.json +26 -0
  243. package/apps/kivo/tests_disabled/logic.test.js +34 -0
  244. package/apps/kivo/www/assets/icon-192.png +0 -0
  245. package/apps/kivo/www/assets/icon-512.png +0 -0
  246. package/apps/kivo/www/assets/kivo-icon.png +0 -0
  247. package/apps/kivo/www/assets/pop.mp3 +0 -0
  248. package/apps/kivo/www/favicon.ico +0 -0
  249. package/apps/kivo/www/firebase-config.js +75 -0
  250. package/apps/kivo/www/index.html +38 -0
  251. package/apps/kivo/www/manifest.json +29 -0
  252. package/apps/kivo/www/script.js +72 -0
  253. package/apps/kivo/www/style.css +82 -0
  254. package/apps/kivo/www/sw.js +46 -0
  255. package/apps/kivo-brain-api/.env.example +2 -0
  256. package/apps/kivo-brain-api/KIVO_BACKEND_SETUP.md +27 -0
  257. package/apps/kivo-brain-api/controllers/kivoController.js +31 -0
  258. package/apps/kivo-brain-api/index.js +24 -0
  259. package/apps/kivo-brain-api/package.json +17 -0
  260. package/apps/kivo-brain-api/routes/message.js +8 -0
  261. package/apps/kivo-brain-api/services/openaiService.js +64 -0
  262. package/apps/tests/wadi-tests.js +155 -0
  263. package/apps/wadi-brain/docs/README_REMOVE_OPTIONS.md +26 -0
  264. package/cli/commands/deploy.js +10 -0
  265. package/cli/commands/docs.js +16 -0
  266. package/cli/commands/explain.js +29 -0
  267. package/cli/commands/lint.js +14 -0
  268. package/cli/index.js +26 -0
  269. package/cli/package.json +12 -0
  270. package/docs/CNAME +1 -0
  271. package/docs/README.md +38 -0
  272. package/docs/USO.md +30 -0
  273. package/docs/index.html +46 -0
  274. package/eslint.config.js +101 -0
  275. package/final_validation.json +27 -0
  276. package/frontend_listado.txt +33387 -0
  277. package/listado.txt +12591 -0
  278. package/package.json +46 -0
  279. package/packages/logger/index.js +43 -0
  280. package/packages/logger/package.json +19 -0
  281. package/packages/logger/test-logger.js +7 -0
  282. package/packages_listado.txt +801 -0
  283. package/pnpm-workspace.yaml +6 -0
  284. package/reseteador_existencial.ps1 +40 -0
  285. package/scripts/bump-version.js +26 -0
  286. package/scripts/env.ps1 +13 -0
  287. package/scripts/setup_android.ps1 +25 -0
  288. package/scripts/setup_virtual_env.ps1 +77 -0
  289. package/scripts/smoke-test.js +84 -0
  290. package/scripts/trigger_render_deploy.ps1 +3 -0
  291. package/scripts/validate-release.js +34 -0
  292. package/temp_check.js +57 -0
  293. package/tsconfig.json +5 -0
  294. package/validation_report.json +27 -0
@@ -0,0 +1,247 @@
1
+ import { useEffect, useState } from "react";
2
+ import type { FormEvent } from "react";
3
+ import { Link } from "react-router-dom";
4
+ import { useProjectsStore } from "../store/projectsStore";
5
+ import { Layout } from "../components/Layout";
6
+ import { Button } from "../components/common/Button";
7
+ import { Input } from "../components/common/Input";
8
+ import { Modal } from "../components/common/Modal";
9
+
10
+ // Define interface for project with extra fields if not in store type
11
+ interface ProjectWithMetrics {
12
+ id: string;
13
+ name: string;
14
+ description?: string;
15
+ created_at: string;
16
+ noise_count?: number;
17
+ total_items_audited?: number;
18
+ }
19
+
20
+ export default function Projects() {
21
+ const { projects, fetchProjects, createProject, loading } =
22
+ useProjectsStore();
23
+ // ...
24
+ const [name, setName] = useState("");
25
+ const [desc, setDesc] = useState("");
26
+ const [isCreating, setIsCreating] = useState(false);
27
+ const [nameError, setNameError] = useState("");
28
+
29
+ useEffect(() => {
30
+ fetchProjects();
31
+ }, [fetchProjects]);
32
+
33
+ const handleCreate = async (e: FormEvent) => {
34
+ e.preventDefault();
35
+ if (!name.trim()) {
36
+ setNameError("El nombre es obligatorio");
37
+ return;
38
+ }
39
+
40
+ setNameError("");
41
+
42
+ try {
43
+ await createProject(name, desc);
44
+ setName("");
45
+ setDesc("");
46
+ setIsCreating(false);
47
+ } catch (err) {
48
+ console.error("Error creating project:", err);
49
+ }
50
+ };
51
+
52
+ const openCreateModal = () => {
53
+ setNameError("");
54
+ setIsCreating(true);
55
+ };
56
+
57
+ return (
58
+ <Layout>
59
+ <div className="w-full max-w-5xl mx-auto p-8 min-h-full">
60
+ {/* Header simple */}
61
+ <header className="flex justify-end mb-8"></header>
62
+
63
+ {/* Hero Section */}
64
+ <div className="text-center mb-12">
65
+ <div className="w-16 h-16 bg-gradient-to-tr from-[#38bdf8] to-[#84cc16] rounded-full mx-auto mb-6 flex items-center justify-center text-3xl shadow-[0_0_30px_rgba(56,189,248,0.3)] animate-in zoom-in duration-500">
66
+ 🚀
67
+ </div>
68
+ <h1 className="text-3xl font-bold mb-2 bg-clip-text text-transparent bg-gradient-to-r from-slate-800 to-slate-500">
69
+ Punto de Control
70
+ </h1>
71
+ <p className="text-slate-500 text-lg">¿En qué trabajamos hoy?</p>
72
+ </div>
73
+
74
+ {/* Action Grid */}
75
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-12">
76
+ {/* Card 1: New Project */}
77
+ <button
78
+ onClick={openCreateModal}
79
+ className="flex flex-col gap-4 items-start text-left p-8 rounded-3xl border border-purple-100 bg-white/60 backdrop-blur-md shadow-sm transition-all hover:scale-[1.02] hover:shadow-lg hover:border-purple-200 group"
80
+ >
81
+ <div className="text-3xl p-3 bg-purple-50 rounded-2xl group-hover:bg-purple-100 transition-colors">
82
+
83
+ </div>
84
+ <div>
85
+ <span className="block text-xl font-bold text-slate-800 mb-2">
86
+ Crear nuevo proyecto
87
+ </span>
88
+ <span className="text-sm text-slate-500 leading-relaxed">
89
+ Inicia una nueva sesión de trabajo desde cero.
90
+ </span>
91
+ </div>
92
+ </button>
93
+
94
+ {/* Card 2: Explore */}
95
+ <div className="flex flex-col gap-4 items-start text-left p-8 rounded-3xl border border-slate-100 bg-white/40 backdrop-blur-sm opacity-80">
96
+ <div className="text-3xl p-3 bg-slate-50 rounded-2xl grayscale">
97
+ 📚
98
+ </div>
99
+ <div>
100
+ <span className="block text-xl font-bold text-slate-700 mb-2">
101
+ Explorar recursos
102
+ </span>
103
+ <span className="text-sm text-slate-500 leading-relaxed">
104
+ Documentación y guías (Próximamente).
105
+ </span>
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ {/* Recent Projects List */}
111
+ <div>
112
+ <h3 className="text-xs font-bold text-slate-400 mb-4 uppercase tracking-widest pl-2">
113
+ Recientes
114
+ </h3>
115
+
116
+ {loading && (
117
+ <p className="text-slate-400 pl-2 animate-pulse">
118
+ Sincronizando...
119
+ </p>
120
+ )}
121
+
122
+ <div className="flex flex-col gap-4">
123
+ {projects.map((p) => (
124
+ <Link
125
+ key={p.id}
126
+ to={`/projects/${p.id}`}
127
+ className="no-underline"
128
+ >
129
+ <div className="group p-6 flex items-center justify-between rounded-3xl border border-white/50 bg-white/70 backdrop-blur-md shadow-sm transition-all hover:shadow-md hover:bg-white hover:scale-[1.01]">
130
+ <div className="flex items-center gap-4">
131
+ <div className="w-12 h-12 bg-slate-100 rounded-2xl flex items-center justify-center text-xl group-hover:bg-purple-50 group-hover:text-purple-500 transition-colors">
132
+ 📄
133
+ </div>
134
+ <div>
135
+ <div className="font-semibold text-base text-slate-800 mb-1 group-hover:text-purple-600 transition-colors">
136
+ {p.name}
137
+ </div>
138
+ {p.description && (
139
+ <div className="text-sm text-slate-500">
140
+ {p.description}
141
+ </div>
142
+ )}
143
+ </div>
144
+ </div>
145
+
146
+ <div className="flex items-center gap-3">
147
+ <span className="text-xs text-slate-400 bg-slate-50 px-3 py-1 rounded-full">
148
+ {new Date(p.created_at).toLocaleDateString()}
149
+ </span>
150
+
151
+ {/* Smoke Index Calculation */}
152
+ {(() => {
153
+ const pWithMetrics = p as unknown as ProjectWithMetrics;
154
+ const noise = pWithMetrics.noise_count || 0;
155
+ const total = pWithMetrics.total_items_audited || 0;
156
+ const percentage =
157
+ total > 0 ? Math.round((noise / total) * 100) : 0;
158
+
159
+ let colorClass = "text-purple-500 bg-purple-50";
160
+
161
+ if (percentage > 50) {
162
+ colorClass = "text-red-500 bg-red-50 animate-pulse";
163
+ } else if (percentage > 20) {
164
+ colorClass = "text-amber-500 bg-amber-50";
165
+ }
166
+
167
+ return (
168
+ <span
169
+ className={`text-[10px] font-mono px-3 py-1 rounded-full ${colorClass}`}
170
+ >
171
+ HUMO: {percentage}%
172
+ </span>
173
+ );
174
+ })()}
175
+ </div>
176
+ </div>
177
+ </Link>
178
+ ))}
179
+
180
+ {projects.length === 0 && !loading && (
181
+ <div className="text-center py-16 px-8 bg-white/30 rounded-3xl border border-dashed border-slate-200 flex flex-col items-center gap-4">
182
+ <div className="text-4xl">🌱</div>
183
+ <h3 className="text-lg font-medium text-slate-700">
184
+ Tu espacio está limpio
185
+ </h3>
186
+ <p className="text-slate-500 max-w-xs mx-auto">
187
+ Aún no tienes proyectos. ¡Es hora de empezar algo nuevo!
188
+ </p>
189
+ <Button
190
+ onClick={openCreateModal}
191
+ variant="primary"
192
+ className="mt-4 shadow-lg shadow-purple-200"
193
+ >
194
+ 🚀 Creá tu primer proyecto
195
+ </Button>
196
+ </div>
197
+ )}
198
+ </div>
199
+ </div>
200
+
201
+ {/* Modal for Creating Project */}
202
+ <Modal
203
+ isOpen={isCreating}
204
+ onClose={() => setIsCreating(false)}
205
+ title="Nuevo Proyecto"
206
+ >
207
+ <form onSubmit={handleCreate} className="flex flex-col gap-4">
208
+ <Input
209
+ label="Nombre del proyecto"
210
+ placeholder="Ej. Análisis de datos"
211
+ value={name}
212
+ onChange={(e) => {
213
+ setName(e.target.value);
214
+ if (e.target.value.trim()) setNameError("");
215
+ }}
216
+ error={nameError}
217
+ autoFocus
218
+ />
219
+ <Input
220
+ label="Descripción (opcional)"
221
+ placeholder="Breve descripción del objetivo"
222
+ value={desc}
223
+ onChange={(e) => setDesc(e.target.value)}
224
+ />
225
+
226
+ <div className="flex justify-end gap-2 mt-4">
227
+ <Button
228
+ type="button"
229
+ variant="ghost"
230
+ onClick={() => setIsCreating(false)}
231
+ >
232
+ Cancelar
233
+ </Button>
234
+ <Button
235
+ type="submit"
236
+ variant="primary"
237
+ className="bg-purple-600 hover:bg-purple-700 text-white shadow-lg shadow-purple-200"
238
+ >
239
+ Crear Proyecto
240
+ </Button>
241
+ </div>
242
+ </form>
243
+ </Modal>
244
+ </div>
245
+ </Layout>
246
+ );
247
+ }
@@ -0,0 +1,202 @@
1
+ import { useNavigate } from "react-router-dom";
2
+
3
+ export default function TermsPage() {
4
+ const navigate = useNavigate();
5
+
6
+ return (
7
+ <div
8
+ style={{
9
+ fontFamily: "'Inter', sans-serif",
10
+ color: "#111827",
11
+ backgroundColor: "#F5F7FB",
12
+ minHeight: "100vh",
13
+ padding: "4rem 2rem",
14
+ }}
15
+ >
16
+ <main
17
+ style={{
18
+ maxWidth: "700px",
19
+ margin: "0 auto",
20
+ background: "#fff",
21
+ padding: "2rem",
22
+ borderRadius: "24px",
23
+ boxShadow: "0 10px 40px rgba(0,0,0,0.05)",
24
+ }}
25
+ >
26
+ <button
27
+ onClick={() => navigate("/")}
28
+ style={{
29
+ marginBottom: "2rem",
30
+ background: "transparent",
31
+ border: "none",
32
+ color: "#7C6CFF",
33
+ fontWeight: 600,
34
+ cursor: "pointer",
35
+ }}
36
+ >
37
+ ← Volver al inicio
38
+ </button>
39
+
40
+ <h1
41
+ style={{
42
+ fontSize: "2rem",
43
+ fontWeight: 800,
44
+ marginBottom: "2rem",
45
+ color: "#111827",
46
+ }}
47
+ >
48
+ Términos de uso de WADI
49
+ </h1>
50
+
51
+ <section style={{ marginBottom: "2rem" }}>
52
+ <h2
53
+ style={{
54
+ fontSize: "1.25rem",
55
+ fontWeight: 700,
56
+ marginBottom: "1rem",
57
+ }}
58
+ >
59
+ 1. Descripción del servicio
60
+ </h2>
61
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
62
+ WADI es una herramienta de asistencia basada en inteligencia
63
+ artificial diseñada para potenciar la productividad personal y la
64
+ gestión de proyectos, ofreciendo funcionalidades de chat,
65
+ planificación y tutoría adaptativa.
66
+ </p>
67
+ </section>
68
+
69
+ <section style={{ marginBottom: "2rem" }}>
70
+ <h2
71
+ style={{
72
+ fontSize: "1.25rem",
73
+ fontWeight: 700,
74
+ marginBottom: "1rem",
75
+ }}
76
+ >
77
+ 2. Uso permitido
78
+ </h2>
79
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
80
+ El usuario se compromete a no utilizar el servicio para fines
81
+ ilegales, dañinos o que violen derechos de terceros, ni para generar
82
+ contenido discriminatorio, violento o engañoso.
83
+ </p>
84
+ </section>
85
+
86
+ <section style={{ marginBottom: "2rem" }}>
87
+ <h2
88
+ style={{
89
+ fontSize: "1.25rem",
90
+ fontWeight: 700,
91
+ marginBottom: "1rem",
92
+ }}
93
+ >
94
+ 3. Contenido generado por IA
95
+ </h2>
96
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
97
+ El contenido generado por WADI es orientativo y automatizado. La
98
+ inteligencia artificial puede cometer errores. El usuario es el
99
+ único responsable de verificar la exactitud y adecuación de la
100
+ información antes de tomar decisiones. No garantizamos la exactitud
101
+ absoluta de las respuestas.
102
+ </p>
103
+ </section>
104
+
105
+ <section style={{ marginBottom: "2rem" }}>
106
+ <h2
107
+ style={{
108
+ fontSize: "1.25rem",
109
+ fontWeight: 700,
110
+ marginBottom: "1rem",
111
+ }}
112
+ >
113
+ 4. Propiedad Intelectual
114
+ </h2>
115
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
116
+ La marca WADI y el software de la plataforma son propiedad de sus
117
+ desarrolladores. El usuario conserva la propiedad de los datos de
118
+ entrada y el contenido generado para su uso en sus propios
119
+ proyectos, en la medida en que la ley aplicable lo permita.
120
+ </p>
121
+ </section>
122
+
123
+ <section style={{ marginBottom: "2rem" }}>
124
+ <h2
125
+ style={{
126
+ fontSize: "1.25rem",
127
+ fontWeight: 700,
128
+ marginBottom: "1rem",
129
+ }}
130
+ >
131
+ 5. Cuentas y acceso
132
+ </h2>
133
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
134
+ El usuario es responsable de mantener la seguridad de sus
135
+ credenciales. WADI no se hace responsable por accesos no autorizados
136
+ derivados de negligencia del usuario. Nos reservamos el derecho de
137
+ suspender cuentas que violen estos términos.
138
+ </p>
139
+ </section>
140
+
141
+ <section style={{ marginBottom: "2rem" }}>
142
+ <h2
143
+ style={{
144
+ fontSize: "1.25rem",
145
+ fontWeight: 700,
146
+ marginBottom: "1rem",
147
+ }}
148
+ >
149
+ 6. Limitación de responsabilidad
150
+ </h2>
151
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
152
+ En la máxima medida permitida por la ley, WADI y sus desarrolladores
153
+ no serán responsables por daños directos, indirectos o consecuentes
154
+ que surjan del uso o la imposibilidad de uso del servicio.
155
+ </p>
156
+ </section>
157
+
158
+ <section style={{ marginBottom: "2rem" }}>
159
+ <h2
160
+ style={{
161
+ fontSize: "1.25rem",
162
+ fontWeight: 700,
163
+ marginBottom: "1rem",
164
+ }}
165
+ >
166
+ 7. Contacto
167
+ </h2>
168
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
169
+ Para cualquier consulta sobre estos términos, puede contactarnos en:{" "}
170
+ <a
171
+ href="mailto:contacto@wadi.app"
172
+ style={{ color: "#7C6CFF", fontWeight: 600 }}
173
+ >
174
+ contacto@wadi.app
175
+ </a>
176
+ </p>
177
+ </section>
178
+
179
+ <section>
180
+ <h2
181
+ style={{
182
+ fontSize: "1.25rem",
183
+ fontWeight: 700,
184
+ marginBottom: "1rem",
185
+ }}
186
+ >
187
+ 8. Cambios en los términos
188
+ </h2>
189
+ <p style={{ lineHeight: 1.6, color: "#4B5563" }}>
190
+ Nos reservamos el derecho de modificar estos términos. Se
191
+ notificarán los cambios actualizando la fecha al pie de esta página.
192
+ </p>
193
+ <p
194
+ style={{ marginTop: "1rem", fontSize: "0.9rem", color: "#6B7280" }}
195
+ >
196
+ Última actualización: Diciembre 2025
197
+ </p>
198
+ </section>
199
+ </main>
200
+ </div>
201
+ );
202
+ }
@@ -0,0 +1,83 @@
1
+ import { createBrowserRouter } from "react-router-dom";
2
+ import { AuthLoader } from "./components/AuthLoader";
3
+ import Login from "./pages/Login";
4
+ import Projects from "./pages/Projects";
5
+ import ProjectDetail from "./pages/ProjectDetail";
6
+ import ChatPage from "./pages/ChatPage";
7
+ import { AuditReport } from "./components/auditor/AuditReport";
8
+
9
+ import IntroWadi from "./pages/IntroWadi";
10
+ import TermsPage from "./pages/TermsPage";
11
+ import PrivacyPage from "./pages/PrivacyPage";
12
+ import DashboardPage from "./pages/DashboardPage";
13
+
14
+ export const router = createBrowserRouter([
15
+ {
16
+ path: "/",
17
+ element: <IntroWadi />,
18
+ },
19
+ {
20
+ path: "/terminos",
21
+ element: <TermsPage />,
22
+ },
23
+ {
24
+ path: "/privacidad",
25
+ element: <PrivacyPage />,
26
+ },
27
+ {
28
+ path: "/login",
29
+ element: (
30
+ <AuthLoader>
31
+ <Login />
32
+ </AuthLoader>
33
+ ),
34
+ },
35
+ {
36
+ path: "/projects",
37
+ element: (
38
+ <AuthLoader>
39
+ <Projects />
40
+ </AuthLoader>
41
+ ),
42
+ },
43
+ {
44
+ path: "/projects/:id",
45
+ element: (
46
+ <AuthLoader>
47
+ <ProjectDetail />
48
+ </AuthLoader>
49
+ ),
50
+ },
51
+ {
52
+ path: "/chat",
53
+ element: (
54
+ <AuthLoader>
55
+ <ChatPage />
56
+ </AuthLoader>
57
+ ),
58
+ },
59
+ {
60
+ path: "/chat/:conversationId",
61
+ element: (
62
+ <AuthLoader>
63
+ <ChatPage />
64
+ </AuthLoader>
65
+ ),
66
+ },
67
+ {
68
+ path: "/chat/:conversationId/audit",
69
+ element: (
70
+ <AuthLoader>
71
+ <AuditReport />
72
+ </AuthLoader>
73
+ ),
74
+ },
75
+ {
76
+ path: "/dashboard",
77
+ element: (
78
+ <AuthLoader>
79
+ <DashboardPage />
80
+ </AuthLoader>
81
+ ),
82
+ },
83
+ ]);
@@ -0,0 +1,152 @@
1
+ import { create } from "zustand";
2
+ import type { User } from "@supabase/supabase-js";
3
+ import { supabase } from "../config/supabase";
4
+
5
+ interface AuthResponse {
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ data: any;
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ error: any;
10
+ }
11
+
12
+ interface AuthState {
13
+ user: User | null;
14
+ loading: boolean;
15
+ signIn: (email: string, password: string) => Promise<AuthResponse>;
16
+ signUp: (
17
+ email: string,
18
+ password: string,
19
+ captchaToken?: string
20
+ ) => Promise<AuthResponse>;
21
+ loginAsGuest: () => Promise<AuthResponse>;
22
+ convertGuestToUser: (
23
+ email: string,
24
+ password: string
25
+ ) => Promise<AuthResponse>;
26
+ signOut: () => Promise<void>;
27
+ setUser: (user: User | null) => void;
28
+ }
29
+
30
+ export const useAuthStore = create<AuthState>((set) => ({
31
+ user: null,
32
+ loading: false,
33
+
34
+ setUser: (user) => set({ user }),
35
+
36
+ signIn: async (email, password) => {
37
+ set({ loading: true });
38
+
39
+ const { data, error } = await supabase.auth.signInWithPassword({
40
+ email,
41
+ password,
42
+ });
43
+
44
+ set({ user: data.user, loading: false });
45
+ return { data, error };
46
+ },
47
+
48
+ signUp: async (email, password, captchaToken) => {
49
+ set({ loading: true });
50
+
51
+ const { data, error } = await supabase.auth.signUp({
52
+ email,
53
+ password,
54
+ options: { captchaToken },
55
+ });
56
+
57
+ set({ user: data.user, loading: false });
58
+ return { data, error };
59
+ },
60
+
61
+ loginAsGuest: async () => {
62
+ set({ loading: true });
63
+ const { data, error } = await supabase.auth.signInAnonymously();
64
+ if (error) console.error("Error login anónimo:", error);
65
+ set({ user: data.user, loading: false });
66
+ return { data, error };
67
+ },
68
+
69
+ convertGuestToUser: async (email, password) => {
70
+ set({ loading: true });
71
+
72
+ // 1. Capture current anon ID
73
+ const {
74
+ data: { session: anonSession },
75
+ } = await supabase.auth.getSession();
76
+ const anonUserId = anonSession?.user?.id;
77
+
78
+ // 2. Attempt to convert (Update User)
79
+ const { data, error } = await supabase.auth.updateUser({
80
+ email: email,
81
+ password: password,
82
+ });
83
+
84
+ if (error) {
85
+ // 3. Handle "User already exists" conflict
86
+ // Note: Error message content may vary, checking for common indicators
87
+ if (
88
+ error.message.includes("already registered") ||
89
+ error.message.includes("unique constraint") ||
90
+ error.status === 422
91
+ ) {
92
+ console.log("Email exists. Attempting to link/merge account...");
93
+
94
+ // 4. Sign in to the existing account
95
+ const { data: signInData, error: signInError } =
96
+ await supabase.auth.signInWithPassword({
97
+ email,
98
+ password,
99
+ });
100
+
101
+ if (signInError) {
102
+ set({ loading: false });
103
+ throw new Error(
104
+ "El usuario ya existe y la contraseña es incorrecta."
105
+ );
106
+ }
107
+
108
+ if (signInData.user && anonUserId) {
109
+ console.log(
110
+ `Merging data from ${anonUserId} to ${signInData.user.id}`
111
+ );
112
+
113
+ // 5. Reassign entities (Projects & Runs)
114
+ // Note: This relies on RLS policies allowing the new user to update the old user's rows
115
+ // OR the backend handling this. We attempt client-side update here as per request.
116
+
117
+ const { error: projectError } = await supabase
118
+ .from("projects")
119
+ .update({ user_id: signInData.user.id }) // Assuming 'user_id' column exists
120
+ .eq("user_id", anonUserId); // Assuming logical 'owner' link
121
+
122
+ if (projectError)
123
+ console.warn("Project merge warning:", projectError);
124
+
125
+ const { error: runError } = await supabase
126
+ .from("runs")
127
+ .update({ user_id: signInData.user.id })
128
+ .eq("user_id", anonUserId);
129
+
130
+ if (runError) console.warn("Run merge warning:", runError);
131
+ }
132
+
133
+ set({ user: signInData.user, loading: false });
134
+ // Return null error to indicate success in handling
135
+ return { data: signInData, error: null };
136
+ }
137
+
138
+ // Real error
139
+ set({ loading: false });
140
+ return { data, error };
141
+ }
142
+
143
+ // Success (New User Conversion)
144
+ set({ user: data.user, loading: false });
145
+ return { data, error };
146
+ },
147
+
148
+ signOut: async () => {
149
+ await supabase.auth.signOut();
150
+ set({ user: null });
151
+ },
152
+ }));