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,16 @@
1
+ {
2
+ "appId": "com.kivo.chat",
3
+ "appName": "Kivo",
4
+ "webDir": "www",
5
+ "bundledWebRuntime": false,
6
+ "server": {
7
+ "androidScheme": "https"
8
+ },
9
+ "plugins": {
10
+ "SplashScreen": {
11
+ "launchShowDuration": 1500,
12
+ "backgroundColor": "#ffffff",
13
+ "showSpinner": false
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hosting": {
3
+ "public": "www",
4
+ "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
5
+ }
6
+ }
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ testEnvironment: "jsdom",
3
+ verbose: true,
4
+ };
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "kivo",
3
+ "version": "1.0.0",
4
+ "description": "Kivo - Tu compañero emocional inteligente",
5
+ "main": "script.js",
6
+ "scripts": {
7
+ "test": "echo tests disabled",
8
+ "build": "echo 'No build step required for Kivo PWA'",
9
+ "start": "npx serve www"
10
+ },
11
+ "keywords": [],
12
+ "author": "",
13
+ "license": "ISC",
14
+ "dependencies": {
15
+ "@capacitor/android": "^7.4.4",
16
+ "@capacitor/cli": "^7.4.4",
17
+ "@capacitor/core": "^7.4.4",
18
+ "firebase": "^9.23.0"
19
+ },
20
+ "devDependencies": {
21
+ "@capacitor/assets": "^3.0.5",
22
+ "jest": "^30.2.0",
23
+ "jest-environment-jsdom": "^30.2.0",
24
+ "serve": "^14.2.0"
25
+ }
26
+ }
@@ -0,0 +1,34 @@
1
+ /* eslint-env jest */
2
+ const { detectarModo, detectarSubmodo } = require("../www/script.js");
3
+
4
+ describe("Kivo Logic Tests", () => {
5
+ describe("detectarModo", () => {
6
+ test("should detect technical mode", () => {
7
+ expect(detectarModo("validar sistema")).toBe("tecnico");
8
+ expect(detectarModo("debug error")).toBe("tecnico");
9
+ });
10
+
11
+ test("should detect emotional mode", () => {
12
+ expect(detectarModo("me siento triste")).toBe("emocional");
13
+ expect(detectarModo("tengo ansiedad")).toBe("emocional");
14
+ });
15
+
16
+ test("should return neutral for other inputs", () => {
17
+ expect(detectarModo("hola que tal")).toBe("neutro");
18
+ });
19
+ });
20
+
21
+ describe("detectarSubmodo", () => {
22
+ test("should detect reflexive submode", () => {
23
+ expect(detectarSubmodo("estuve pensando mucho")).toBe("reflexivo");
24
+ });
25
+
26
+ test("should detect creative submode", () => {
27
+ expect(detectarSubmodo("tengo una idea nueva")).toBe("creativo");
28
+ });
29
+
30
+ test("should return null for other inputs", () => {
31
+ expect(detectarSubmodo("nada especial")).toBeNull();
32
+ });
33
+ });
34
+ });
File without changes
Binary file
@@ -0,0 +1,75 @@
1
+ // =============================
2
+ // CONFIGURACIÓN DE FIREBASE
3
+ // =============================
4
+ const firebaseConfig = {
5
+ apiKey: "AIzaSyAweaSvXfHYyArsnjI-G7NhP82YP5Azu-g",
6
+ authDomain: "kivo-8c62e.firebaseapp.com",
7
+ projectId: "kivo-8c62e",
8
+ storageBucket: "kivo-8c62e.appspot.com",
9
+ messagingSenderId: "118749642871",
10
+ appId: "1:118749642871:web:28a152eccf323981c64672",
11
+ measurementId: "G-HQ4WK0N2XT",
12
+ };
13
+
14
+ // Inicializar Firebase
15
+ firebase.initializeApp(firebaseConfig);
16
+
17
+ // Firestore y Auth
18
+ const db = firebase.firestore();
19
+ const auth = firebase.auth();
20
+
21
+ // =============================
22
+ // AUTENTICACIÓN ANÓNIMA
23
+ // =============================
24
+ auth.signInAnonymously().catch((error) => {
25
+ console.error("Error en autenticación anónima:", error);
26
+ });
27
+
28
+ // =============================
29
+ // INICIALIZACIÓN FIRESTORE
30
+ // =============================
31
+ async function inicializarFirestore(uid) {
32
+ try {
33
+ const docRef = db.collection("usuarios").doc(uid);
34
+
35
+ await docRef.set(
36
+ {
37
+ perfil: { voz: "emocional" },
38
+ historialEmocional: [
39
+ {
40
+ mensaje: "Inicio de historial emocional.",
41
+ emocion: "neutral",
42
+ modo: "emocional",
43
+ etiqueta: "normal",
44
+ timestamp: new Date().toISOString(),
45
+ },
46
+ ],
47
+ },
48
+ { merge: true }
49
+ );
50
+
51
+ console.log("Documento inicial creado correctamente.");
52
+ } catch (err) {
53
+ console.error("Error inicializando Firestore:", err);
54
+ }
55
+ }
56
+
57
+ // =============================
58
+ // LISTENER DE AUTH
59
+ // =============================
60
+ auth.onAuthStateChanged((user) => {
61
+ if (user) {
62
+ console.log("Usuario autenticado:", user.uid);
63
+
64
+ db.collection("usuarios")
65
+ .doc(user.uid)
66
+ .get()
67
+ .then((doc) => {
68
+ if (!doc.exists) inicializarFirestore(user.uid);
69
+ });
70
+
71
+ if (typeof cargarUsuario === "function") {
72
+ cargarUsuario(user.uid);
73
+ }
74
+ }
75
+ });
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Kivo</title>
7
+ <link rel="stylesheet" href="./style.css" />
8
+ </head>
9
+
10
+ <body>
11
+
12
+ <!-- Pantalla de Inicio -->
13
+ <div id="intro-screen" class="inicio-container">
14
+ <h1>Kivo</h1>
15
+ <p>Del caos al orden.</p>
16
+ <button id="start-btn">Empezar</button>
17
+ <a href="#">Política de Privacidad</a>
18
+ </div>
19
+
20
+ <!-- Pantalla del Chat -->
21
+ <div id="chat-screen" class="chat-section-container" style="display: none;">
22
+ <div id="chat-window" class="chat-window"></div>
23
+
24
+ <div class="input-section">
25
+ <input id="user-input" type="text" placeholder="Escribe algo..." />
26
+ <button id="send-btn">➤</button>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Firebase -->
31
+ <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
32
+ <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js"></script>
33
+ <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-firestore.js"></script>
34
+
35
+ <script src="./firebase-config.js"></script>
36
+ <script src="./script.js"></script>
37
+ </body>
38
+ </html>
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "Kivo",
3
+ "short_name": "Kivo",
4
+ "start_url": "./index.html",
5
+ "display": "standalone",
6
+ "background_color": "#F7F6F2",
7
+ "theme_color": "#F7F6F2",
8
+ "orientation": "portrait",
9
+ "icons": [
10
+ {
11
+ "src": "./assets/icon-192.png",
12
+ "sizes": "192x192",
13
+ "type": "image/png",
14
+ "purpose": "any maskable"
15
+ },
16
+ {
17
+ "src": "./assets/icon-512.png",
18
+ "sizes": "512x512",
19
+ "type": "image/png",
20
+ "purpose": "any maskable"
21
+ },
22
+ {
23
+ "src": "./assets/kivo-icon.png",
24
+ "sizes": "192x192",
25
+ "type": "image/png",
26
+ "purpose": "any"
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,72 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+ const API_ENDPOINT = "https://wadi-wxg7.onrender.com/api/kivo/chat";
3
+
4
+ const startBtn = document.getElementById("start-btn");
5
+ const introScreen = document.getElementById("intro-screen");
6
+ const chatScreen = document.getElementById("chat-screen");
7
+
8
+ const chatWindow = document.getElementById("chat-window");
9
+ const sendBtn = document.getElementById("send-btn");
10
+ const userInput = document.getElementById("user-input");
11
+
12
+ if (!startBtn || !introScreen || !chatScreen) {
13
+ console.error("ERROR: elementos esenciales no encontrados en DOM.");
14
+ return;
15
+ }
16
+
17
+ startBtn.onclick = () => {
18
+ introScreen.style.display = "none";
19
+ chatScreen.style.display = "flex";
20
+ };
21
+
22
+ sendBtn.onclick = sendMessage;
23
+ userInput.addEventListener("keypress", (e) => {
24
+ if (e.key === "Enter") sendMessage();
25
+ });
26
+
27
+ function addMessage(text, sender = "user") {
28
+ const msg = document.createElement("div");
29
+ msg.classList.add("message", sender);
30
+ msg.textContent = text;
31
+ chatWindow.appendChild(msg);
32
+ chatWindow.scrollTop = chatWindow.scrollHeight;
33
+ }
34
+
35
+ async function sendMessage() {
36
+ const text = userInput.value.trim();
37
+ if (!text) return;
38
+
39
+ addMessage(text, "user");
40
+ userInput.value = "";
41
+
42
+ try {
43
+ const response = await fetch(API_ENDPOINT, {
44
+ method: "POST",
45
+ headers: { "Content-Type": "application/json" },
46
+ body: JSON.stringify({ message: text }),
47
+ });
48
+
49
+ const data = await response.json().catch(() => ({}));
50
+
51
+ if (!response.ok) throw new Error(data.error || "Error en el servidor");
52
+ addMessage(data.reply || "Sin respuesta del servidor", "kivo");
53
+ } catch (err) {
54
+ addMessage(`Error: ${err.message}`, "kivo");
55
+ console.error(err);
56
+ }
57
+ }
58
+
59
+ if ("serviceWorker" in navigator) {
60
+ navigator.serviceWorker.register("./sw.js").catch(console.error);
61
+ }
62
+ // Keep-alive pinger due to Render free tier sleep
63
+ const KEEP_ALIVE_URL = "https://wadi-wxg7.onrender.com/system/health";
64
+ setInterval(
65
+ () => {
66
+ fetch(KEEP_ALIVE_URL)
67
+ .then((res) => console.log(`Keep-alive ping: ${res.status}`))
68
+ .catch((err) => console.error("Keep-alive failed", err));
69
+ },
70
+ 4 * 60 * 1000
71
+ ); // 4 minutes
72
+ });
@@ -0,0 +1,82 @@
1
+ body {
2
+ margin: 0;
3
+ padding: 0;
4
+ font-family: Arial, sans-serif;
5
+ background: #111;
6
+ color: #fff;
7
+ }
8
+
9
+ .screen {
10
+ width: 100%;
11
+ height: 100vh;
12
+ display: flex;
13
+ flex-direction: column;
14
+ justify-content: center;
15
+ align-items: center;
16
+ }
17
+
18
+ #start-btn {
19
+ margin-top: 20px;
20
+ padding: 12px 25px;
21
+ font-size: 18px;
22
+ border: none;
23
+ background: #0af;
24
+ color: #000;
25
+ border-radius: 8px;
26
+ cursor: pointer;
27
+ }
28
+
29
+ #chat-window {
30
+ width: 100%;
31
+ height: calc(100vh - 70px);
32
+ padding: 20px;
33
+ overflow-y: auto;
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: 12px;
37
+ box-sizing: border-box;
38
+ background: #1b1b1b;
39
+ }
40
+
41
+ .message {
42
+ max-width: 75%;
43
+ padding: 12px 15px;
44
+ border-radius: 10px;
45
+ font-size: 16px;
46
+ }
47
+
48
+ .message.user {
49
+ align-self: flex-end;
50
+ background: #0af;
51
+ color: #000;
52
+ }
53
+
54
+ .message.kivo {
55
+ align-self: flex-start;
56
+ background: #333;
57
+ color: #fff;
58
+ }
59
+
60
+ #input-box {
61
+ width: 100%;
62
+ height: 70px;
63
+ display: flex;
64
+ border-top: 2px solid #222;
65
+ }
66
+
67
+ #user-input {
68
+ flex: 1;
69
+ padding: 10px;
70
+ background: #222;
71
+ color: white;
72
+ border: none;
73
+ font-size: 16px;
74
+ }
75
+
76
+ #send-btn {
77
+ width: 80px;
78
+ background: #0af;
79
+ color: #000;
80
+ border: none;
81
+ cursor: pointer;
82
+ }
@@ -0,0 +1,46 @@
1
+ const CACHE_NAME = "kivo-v9";
2
+ const urlsToCache = [
3
+ "./",
4
+ "./index.html",
5
+ "./style.css",
6
+ "./script.js",
7
+ "./firebase-config.js",
8
+ "./manifest.json",
9
+ "./favicon.ico",
10
+ "./assets/icon-192.png",
11
+ "./assets/icon-512.png",
12
+ "./assets/kivo-icon.png",
13
+ "./assets/pop.mp3",
14
+ ];
15
+
16
+ self.addEventListener("install", (event) => {
17
+ self.skipWaiting(); // Force waiting service worker to become active
18
+ event.waitUntil(
19
+ caches.open(CACHE_NAME).then((cache) => {
20
+ return cache.addAll(urlsToCache);
21
+ })
22
+ );
23
+ });
24
+
25
+ self.addEventListener("fetch", (event) => {
26
+ event.respondWith(
27
+ caches.match(event.request).then((response) => {
28
+ return response || fetch(event.request);
29
+ })
30
+ );
31
+ });
32
+
33
+ self.addEventListener("activate", (event) => {
34
+ const cacheWhitelist = [CACHE_NAME];
35
+ event.waitUntil(
36
+ caches.keys().then((cacheNames) => {
37
+ return Promise.all(
38
+ cacheNames.map((cacheName) => {
39
+ if (cacheWhitelist.indexOf(cacheName) === -1) {
40
+ return caches.delete(cacheName);
41
+ }
42
+ })
43
+ ).then(() => self.clients.claim()); // Take control of all clients immediately
44
+ })
45
+ );
46
+ });
@@ -0,0 +1,2 @@
1
+ OPENAI_API_KEY=sk-...
2
+ PORT=3000
@@ -0,0 +1,27 @@
1
+ # Kivo Backend Setup
2
+
3
+ ## Configuración Local
4
+
5
+ 1. Copiar `.env.example` a `.env`
6
+ 2. Agregar `OPENAI_API_KEY`
7
+ 3. `npm install`
8
+ 4. `npm start`
9
+
10
+ ## Testear Backend
11
+
12
+ ```bash
13
+ curl -X POST http://localhost:3000/kivo/message \
14
+ -H "Content-Type: application/json" \
15
+ -d '{"mensajeUsuario": "Hola Kivo", "personalidad": "barrio"}'
16
+ ```
17
+
18
+ ## Personalidades
19
+
20
+ - normal
21
+ - barrio
22
+ - tecnico
23
+ - reflexivo
24
+
25
+ ## Deploy
26
+
27
+ El proyecto está configurado para desplegarse automáticamente en Railway al hacer push a la rama principal.
@@ -0,0 +1,31 @@
1
+ import { generateResponse } from "../services/openaiService.js";
2
+
3
+ export const handleMessage = async (req, res) => {
4
+ try {
5
+ const { mensajeUsuario, historial, tono, personalidad } = req.body;
6
+
7
+ if (!mensajeUsuario) {
8
+ return res.json({
9
+ respuestaKivo: "Hola, soy Kivo. ¿En qué puedo ayudarte hoy?",
10
+ emocion: "neutral",
11
+ modo: "normal",
12
+ });
13
+ }
14
+
15
+ const response = await generateResponse({
16
+ message: mensajeUsuario,
17
+ history: historial || [],
18
+ tone: tono || "neutral",
19
+ personality: personalidad || "normal",
20
+ });
21
+
22
+ res.json(response);
23
+ } catch (error) {
24
+ console.error("Error in kivoController:", error);
25
+ res.status(500).json({
26
+ error: "Error interno del cerebro de Kivo",
27
+ respuestaKivo:
28
+ "Lo siento, tuve un problema procesando eso. ¿Podemos intentar de nuevo?",
29
+ });
30
+ }
31
+ };
@@ -0,0 +1,24 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import dotenv from "dotenv";
4
+ import messageRoutes from "./routes/message.js";
5
+
6
+ dotenv.config();
7
+
8
+ const app = express();
9
+ const PORT = process.env.PORT || 3000;
10
+
11
+ app.use(cors());
12
+ app.use(express.json());
13
+
14
+ // Routes
15
+ app.use("/kivo", messageRoutes);
16
+
17
+ // Health check
18
+ app.get("/", (req, res) => {
19
+ res.json({ status: "online", service: "kivo-brain-api" });
20
+ });
21
+
22
+ app.listen(PORT, () => {
23
+ console.log(`Kivo Brain API running on port ${PORT}`);
24
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "kivo-brain-api",
3
+ "version": "1.0.0",
4
+ "description": "Backend API for Kivo AI",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node index.js",
9
+ "dev": "node --watch index.js"
10
+ },
11
+ "dependencies": {
12
+ "cors": "^2.8.5",
13
+ "dotenv": "^16.4.5",
14
+ "express": "^4.19.2",
15
+ "openai": "^4.28.4"
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ import express from "express";
2
+ import { handleMessage } from "../controllers/kivoController.js";
3
+
4
+ const router = express.Router();
5
+
6
+ router.post("/message", handleMessage);
7
+
8
+ export default router;
@@ -0,0 +1,64 @@
1
+ import OpenAI from "openai";
2
+ import dotenv from "dotenv";
3
+
4
+ dotenv.config();
5
+
6
+ const openai = new OpenAI({
7
+ apiKey: process.env.OPENAI_API_KEY,
8
+ });
9
+
10
+ const SYSTEM_PROMPTS = {
11
+ normal: "Eres Kivo, un asistente emocional inteligente, empático y claro.",
12
+ barrio:
13
+ "Eres Kivo, un amigo del barrio, usas jerga argentina suave (che, viste, tranqui), sos cercano y directo.",
14
+ tecnico:
15
+ "Eres Kivo, un asistente técnico preciso, lógico y analítico. Usas terminología de sistemas.",
16
+ reflexivo:
17
+ "Eres Kivo, un pensador profundo. Ayudas al usuario a cuestionar sus creencias y reflexionar.",
18
+ };
19
+
20
+ export const generateResponse = async ({
21
+ message,
22
+ history,
23
+ tone,
24
+ personality,
25
+ }) => {
26
+ const systemPrompt = SYSTEM_PROMPTS[personality] || SYSTEM_PROMPTS.normal;
27
+
28
+ const messages = [
29
+ {
30
+ role: "system",
31
+ content: `${systemPrompt} Tono actual: ${tone}. Responde de forma concisa.`,
32
+ },
33
+ ...history.map((msg) => ({
34
+ role: msg.role || "user",
35
+ content: msg.content || msg.mensaje || "",
36
+ })),
37
+ { role: "user", content: message },
38
+ ];
39
+
40
+ const completion = await openai.chat.completions.create({
41
+ model: "gpt-4o-mini",
42
+ messages: messages,
43
+ temperature: 0.7,
44
+ max_tokens: 150,
45
+ });
46
+
47
+ const reply = completion.choices[0].message.content;
48
+
49
+ // Simple emotion detection based on reply content
50
+ let emotion = "neutral";
51
+ if (reply.includes("?")) emotion = "curioso";
52
+ if (reply.includes("!")) emotion = "contento";
53
+ if (
54
+ reply.toLowerCase().includes("lo siento") ||
55
+ reply.toLowerCase().includes("triste")
56
+ )
57
+ emotion = "empatico";
58
+
59
+ return {
60
+ respuestaKivo: reply,
61
+ emocion: emotion,
62
+ modo: personality,
63
+ };
64
+ };