@cachly-dev/mcp-server 0.10.49 → 0.10.56

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 (310) hide show
  1. package/.github/workflows/publish.yml +2 -2
  2. package/README.md +33 -5
  3. package/dist/__tests__/auth.test.js.map +1 -0
  4. package/dist/{src/__tests__ → __tests__}/brain-flow.test.js +0 -141
  5. package/dist/__tests__/brain-flow.test.js.map +1 -0
  6. package/dist/__tests__/brain-predict-failures.test.d.ts +17 -0
  7. package/dist/__tests__/brain-predict-failures.test.js +339 -0
  8. package/dist/__tests__/brain-predict-failures.test.js.map +1 -0
  9. package/dist/__tests__/confidence.test.js.map +1 -0
  10. package/dist/__tests__/e2e/api-auth.test.js.map +1 -0
  11. package/dist/__tests__/e2e/api-health.test.js.map +1 -0
  12. package/dist/__tests__/e2e/cli.test.js.map +1 -0
  13. package/dist/__tests__/e2e/config.js.map +1 -0
  14. package/dist/__tests__/e2e/funnel.test.js.map +1 -0
  15. package/dist/__tests__/e2e/mcp-tools.test.js.map +1 -0
  16. package/dist/__tests__/e2e/provisioning.test.js.map +1 -0
  17. package/dist/{src/__tests__ → __tests__}/handlers-unit.test.js +2 -0
  18. package/dist/__tests__/handlers-unit.test.js.map +1 -0
  19. package/dist/__tests__/namespace.test.js.map +1 -0
  20. package/dist/auth.js.map +1 -0
  21. package/dist/ckg.js.map +1 -0
  22. package/dist/confidence.js.map +1 -0
  23. package/dist/embeddings.js.map +1 -0
  24. package/dist/handlers/advanced.js.map +1 -0
  25. package/dist/{src/handlers → handlers}/brain.js +141 -135
  26. package/dist/handlers/brain.js.map +1 -0
  27. package/dist/handlers/cache.js.map +1 -0
  28. package/dist/{src/handlers → handlers}/context.js +4 -9
  29. package/dist/handlers/context.js.map +1 -0
  30. package/dist/{src/handlers → handlers}/fedbrain.d.ts +0 -6
  31. package/dist/{src/handlers → handlers}/fedbrain.js +7 -19
  32. package/dist/handlers/fedbrain.js.map +1 -0
  33. package/dist/handlers/instances.js.map +1 -0
  34. package/dist/{src/handlers → handlers}/roadmap.js +3 -7
  35. package/dist/handlers/roadmap.js.map +1 -0
  36. package/dist/handlers/syndicate.js.map +1 -0
  37. package/dist/{src/handlers → handlers}/team.js +3 -1
  38. package/dist/handlers/team.js.map +1 -0
  39. package/dist/{src/index.js → index.js} +428 -206
  40. package/dist/index.js.map +1 -0
  41. package/dist/namespace.js.map +1 -0
  42. package/dist/search.js.map +1 -0
  43. package/dist/search.test.js.map +1 -0
  44. package/dist/{src/tools.d.ts → tools.d.ts} +0 -196
  45. package/dist/{src/tools.js → tools.js} +0 -178
  46. package/dist/tools.js.map +1 -0
  47. package/dist/utils.js.map +1 -0
  48. package/package.json +3 -3
  49. package/smithery.yaml +16 -27
  50. package/src/__tests__/brain-flow.test.ts +0 -174
  51. package/src/__tests__/brain-predict-failures.test.ts +430 -0
  52. package/src/__tests__/handlers-unit.test.ts +2 -1
  53. package/src/handlers/brain.ts +142 -142
  54. package/src/handlers/context.ts +4 -9
  55. package/src/handlers/fedbrain.ts +7 -21
  56. package/src/handlers/roadmap.ts +3 -7
  57. package/src/handlers/team.ts +3 -1
  58. package/src/index.ts +415 -221
  59. package/src/tools.ts +0 -191
  60. package/tsconfig.json +3 -2
  61. package/.github/workflows/eas-build-android.yml +0 -58
  62. package/.github/workflows/eas-update.yml +0 -55
  63. package/STRATEGY.md +0 -209
  64. package/apps/travel-chaos-organizer/.env.example +0 -49
  65. package/apps/travel-chaos-organizer/DEPLOY.md +0 -328
  66. package/apps/travel-chaos-organizer/Makefile +0 -57
  67. package/apps/travel-chaos-organizer/README.md +0 -159
  68. package/apps/travel-chaos-organizer/backend/.env.example +0 -10
  69. package/apps/travel-chaos-organizer/backend/Dockerfile +0 -25
  70. package/apps/travel-chaos-organizer/backend/alembic/env.py +0 -56
  71. package/apps/travel-chaos-organizer/backend/alembic/script.py.mako +0 -24
  72. package/apps/travel-chaos-organizer/backend/alembic/versions/.gitkeep +0 -0
  73. package/apps/travel-chaos-organizer/backend/alembic/versions/0001_stripe_customer_id.py +0 -24
  74. package/apps/travel-chaos-organizer/backend/alembic/versions/0002_telegram_chat_id.py +0 -24
  75. package/apps/travel-chaos-organizer/backend/alembic.ini +0 -39
  76. package/apps/travel-chaos-organizer/backend/app/__init__.py +0 -0
  77. package/apps/travel-chaos-organizer/backend/app/auth/__init__.py +0 -0
  78. package/apps/travel-chaos-organizer/backend/app/auth/keycloak.py +0 -81
  79. package/apps/travel-chaos-organizer/backend/app/config.py +0 -66
  80. package/apps/travel-chaos-organizer/backend/app/db/__init__.py +0 -0
  81. package/apps/travel-chaos-organizer/backend/app/db/database.py +0 -20
  82. package/apps/travel-chaos-organizer/backend/app/db/migrations/001_init.sql +0 -71
  83. package/apps/travel-chaos-organizer/backend/app/db/migrations/002_telemetry_freemium.sql +0 -31
  84. package/apps/travel-chaos-organizer/backend/app/db/migrations/003_telegram_chat_id.sql +0 -4
  85. package/apps/travel-chaos-organizer/backend/app/db/migrations/004_stripe_and_email.sql +0 -5
  86. package/apps/travel-chaos-organizer/backend/app/limiter.py +0 -4
  87. package/apps/travel-chaos-organizer/backend/app/logging_config.py +0 -25
  88. package/apps/travel-chaos-organizer/backend/app/main.py +0 -77
  89. package/apps/travel-chaos-organizer/backend/app/models/__init__.py +0 -0
  90. package/apps/travel-chaos-organizer/backend/app/models/schemas.py +0 -142
  91. package/apps/travel-chaos-organizer/backend/app/routers/__init__.py +0 -0
  92. package/apps/travel-chaos-organizer/backend/app/routers/admin.py +0 -237
  93. package/apps/travel-chaos-organizer/backend/app/routers/cache.py +0 -13
  94. package/apps/travel-chaos-organizer/backend/app/routers/events.py +0 -29
  95. package/apps/travel-chaos-organizer/backend/app/routers/export.py +0 -122
  96. package/apps/travel-chaos-organizer/backend/app/routers/inbox.py +0 -122
  97. package/apps/travel-chaos-organizer/backend/app/routers/items.py +0 -130
  98. package/apps/travel-chaos-organizer/backend/app/routers/mail.py +0 -108
  99. package/apps/travel-chaos-organizer/backend/app/routers/parse.py +0 -303
  100. package/apps/travel-chaos-organizer/backend/app/routers/payments.py +0 -179
  101. package/apps/travel-chaos-organizer/backend/app/routers/trips.py +0 -134
  102. package/apps/travel-chaos-organizer/backend/app/routers/users.py +0 -169
  103. package/apps/travel-chaos-organizer/backend/app/routers/waitlist.py +0 -37
  104. package/apps/travel-chaos-organizer/backend/app/services/__init__.py +0 -0
  105. package/apps/travel-chaos-organizer/backend/app/services/cache.py +0 -131
  106. package/apps/travel-chaos-organizer/backend/app/services/drip.py +0 -128
  107. package/apps/travel-chaos-organizer/backend/app/services/email.py +0 -61
  108. package/apps/travel-chaos-organizer/backend/app/services/errors.py +0 -44
  109. package/apps/travel-chaos-organizer/backend/app/services/notifier.py +0 -10
  110. package/apps/travel-chaos-organizer/backend/app/services/ollama.py +0 -101
  111. package/apps/travel-chaos-organizer/backend/app/services/parser.py +0 -22
  112. package/apps/travel-chaos-organizer/backend/app/services/quota.py +0 -85
  113. package/apps/travel-chaos-organizer/backend/app/services/sentry.py +0 -11
  114. package/apps/travel-chaos-organizer/backend/app/services/telemetry.py +0 -35
  115. package/apps/travel-chaos-organizer/backend/pytest.ini +0 -4
  116. package/apps/travel-chaos-organizer/backend/requirements-dev.txt +0 -6
  117. package/apps/travel-chaos-organizer/backend/requirements.txt +0 -25
  118. package/apps/travel-chaos-organizer/backend/tests/__init__.py +0 -0
  119. package/apps/travel-chaos-organizer/backend/tests/conftest.py +0 -223
  120. package/apps/travel-chaos-organizer/backend/tests/test_admin.py +0 -99
  121. package/apps/travel-chaos-organizer/backend/tests/test_cache.py +0 -142
  122. package/apps/travel-chaos-organizer/backend/tests/test_drip.py +0 -32
  123. package/apps/travel-chaos-organizer/backend/tests/test_e2e_chain.py +0 -121
  124. package/apps/travel-chaos-organizer/backend/tests/test_export.py +0 -48
  125. package/apps/travel-chaos-organizer/backend/tests/test_inbox.py +0 -107
  126. package/apps/travel-chaos-organizer/backend/tests/test_items.py +0 -138
  127. package/apps/travel-chaos-organizer/backend/tests/test_mail.py +0 -113
  128. package/apps/travel-chaos-organizer/backend/tests/test_ollama.py +0 -145
  129. package/apps/travel-chaos-organizer/backend/tests/test_parse_url.py +0 -98
  130. package/apps/travel-chaos-organizer/backend/tests/test_parser.py +0 -72
  131. package/apps/travel-chaos-organizer/backend/tests/test_payments.py +0 -163
  132. package/apps/travel-chaos-organizer/backend/tests/test_quota.py +0 -46
  133. package/apps/travel-chaos-organizer/backend/tests/test_search.py +0 -67
  134. package/apps/travel-chaos-organizer/backend/tests/test_trips.py +0 -123
  135. package/apps/travel-chaos-organizer/backend/tests/test_users.py +0 -52
  136. package/apps/travel-chaos-organizer/backups/.gitkeep +0 -0
  137. package/apps/travel-chaos-organizer/caddy/Caddyfile +0 -27
  138. package/apps/travel-chaos-organizer/docker-compose.node1.yml +0 -31
  139. package/apps/travel-chaos-organizer/docker-compose.override.yml +0 -14
  140. package/apps/travel-chaos-organizer/docker-compose.yml +0 -128
  141. package/apps/travel-chaos-organizer/frontend/.env.example +0 -13
  142. package/apps/travel-chaos-organizer/frontend/app/(app)/_layout.tsx +0 -80
  143. package/apps/travel-chaos-organizer/frontend/app/(app)/inbox.tsx +0 -166
  144. package/apps/travel-chaos-organizer/frontend/app/(app)/search.tsx +0 -130
  145. package/apps/travel-chaos-organizer/frontend/app/(app)/settings.tsx +0 -381
  146. package/apps/travel-chaos-organizer/frontend/app/(app)/trips/[id].tsx +0 -346
  147. package/apps/travel-chaos-organizer/frontend/app/(app)/trips.tsx +0 -363
  148. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/cancel.tsx +0 -34
  149. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/success.tsx +0 -35
  150. package/apps/travel-chaos-organizer/frontend/app/(auth)/login.tsx +0 -91
  151. package/apps/travel-chaos-organizer/frontend/app/_layout.tsx +0 -71
  152. package/apps/travel-chaos-organizer/frontend/app/auth.tsx +0 -29
  153. package/apps/travel-chaos-organizer/frontend/app/index.tsx +0 -16
  154. package/apps/travel-chaos-organizer/frontend/app/onboarding.tsx +0 -119
  155. package/apps/travel-chaos-organizer/frontend/app.config.ts +0 -54
  156. package/apps/travel-chaos-organizer/frontend/assets/adaptive-icon.svg +0 -66
  157. package/apps/travel-chaos-organizer/frontend/assets/icon.svg +0 -79
  158. package/apps/travel-chaos-organizer/frontend/assets/splash.svg +0 -15
  159. package/apps/travel-chaos-organizer/frontend/components/BottomSheet.tsx +0 -102
  160. package/apps/travel-chaos-organizer/frontend/components/ConfettiCannon.tsx +0 -107
  161. package/apps/travel-chaos-organizer/frontend/components/ConfirmDialog.tsx +0 -109
  162. package/apps/travel-chaos-organizer/frontend/components/ErrorBoundary.tsx +0 -45
  163. package/apps/travel-chaos-organizer/frontend/components/FileUploadButton.tsx +0 -19
  164. package/apps/travel-chaos-organizer/frontend/components/ImportSheet.tsx +0 -155
  165. package/apps/travel-chaos-organizer/frontend/components/OfflineBadge.tsx +0 -55
  166. package/apps/travel-chaos-organizer/frontend/components/QRCodeViewer.tsx +0 -80
  167. package/apps/travel-chaos-organizer/frontend/components/ScoreRing.tsx +0 -39
  168. package/apps/travel-chaos-organizer/frontend/components/Screen.tsx +0 -39
  169. package/apps/travel-chaos-organizer/frontend/components/Skeleton.tsx +0 -70
  170. package/apps/travel-chaos-organizer/frontend/components/SwipeableInboxItem.tsx +0 -121
  171. package/apps/travel-chaos-organizer/frontend/components/SwipeableTimelineItem.tsx +0 -70
  172. package/apps/travel-chaos-organizer/frontend/components/TimelineItem.tsx +0 -73
  173. package/apps/travel-chaos-organizer/frontend/components/TimelineItemDetail.tsx +0 -130
  174. package/apps/travel-chaos-organizer/frontend/components/Toast.tsx +0 -60
  175. package/apps/travel-chaos-organizer/frontend/components/ToastContext.tsx +0 -42
  176. package/apps/travel-chaos-organizer/frontend/components/TripCard.tsx +0 -146
  177. package/apps/travel-chaos-organizer/frontend/components/TripQRModal.tsx +0 -70
  178. package/apps/travel-chaos-organizer/frontend/components/UpgradeBanner.tsx +0 -44
  179. package/apps/travel-chaos-organizer/frontend/eas.json +0 -22
  180. package/apps/travel-chaos-organizer/frontend/hooks/useInbox.ts +0 -24
  181. package/apps/travel-chaos-organizer/frontend/hooks/useNetworkSync.ts +0 -60
  182. package/apps/travel-chaos-organizer/frontend/hooks/useTrips.ts +0 -112
  183. package/apps/travel-chaos-organizer/frontend/lib/api.ts +0 -223
  184. package/apps/travel-chaos-organizer/frontend/lib/auth.ts +0 -93
  185. package/apps/travel-chaos-organizer/frontend/lib/db.ts +0 -86
  186. package/apps/travel-chaos-organizer/frontend/lib/fileCache.ts +0 -54
  187. package/apps/travel-chaos-organizer/frontend/lib/haptics.ts +0 -13
  188. package/apps/travel-chaos-organizer/frontend/lib/notifications.ts +0 -112
  189. package/apps/travel-chaos-organizer/frontend/lib/offlineQueue.ts +0 -145
  190. package/apps/travel-chaos-organizer/frontend/lib/quota.tsx +0 -43
  191. package/apps/travel-chaos-organizer/frontend/lib/sentry.ts +0 -28
  192. package/apps/travel-chaos-organizer/frontend/lib/shareIntent.ts +0 -44
  193. package/apps/travel-chaos-organizer/frontend/package-lock.json +0 -13037
  194. package/apps/travel-chaos-organizer/frontend/package.json +0 -44
  195. package/apps/travel-chaos-organizer/frontend/tsconfig.json +0 -23
  196. package/apps/travel-chaos-organizer/keycloak/realm-export.json +0 -59
  197. package/apps/travel-chaos-organizer/landing/index.html +0 -773
  198. package/apps/travel-chaos-organizer/scripts/backup.sh +0 -14
  199. package/apps/travel-chaos-organizer/scripts/configure-env.sh +0 -82
  200. package/apps/travel-chaos-organizer/scripts/deploy.sh +0 -54
  201. package/apps/travel-chaos-organizer/scripts/health-check.sh +0 -36
  202. package/apps/travel-chaos-organizer/scripts/migrate.sh +0 -7
  203. package/apps/travel-chaos-organizer/scripts/server-setup.sh +0 -85
  204. package/apps/travel-chaos-organizer/scripts/smoke-test.sh +0 -29
  205. package/apps/travel-chaos-organizer/scripts/verify-tracking.sh +0 -71
  206. package/apps/travel-chaos-organizer/telegram-bot/.env.example +0 -3
  207. package/apps/travel-chaos-organizer/telegram-bot/Dockerfile +0 -6
  208. package/apps/travel-chaos-organizer/telegram-bot/bot.py +0 -504
  209. package/apps/travel-chaos-organizer/telegram-bot/requirements.txt +0 -3
  210. package/dist/packages/telegram-notify/client.d.ts +0 -19
  211. package/dist/packages/telegram-notify/client.js +0 -75
  212. package/dist/packages/telegram-notify/client.js.map +0 -1
  213. package/dist/src/__tests__/auth.test.js.map +0 -1
  214. package/dist/src/__tests__/brain-flow.test.js.map +0 -1
  215. package/dist/src/__tests__/confidence.test.js.map +0 -1
  216. package/dist/src/__tests__/e2e/api-auth.test.js.map +0 -1
  217. package/dist/src/__tests__/e2e/api-health.test.js.map +0 -1
  218. package/dist/src/__tests__/e2e/cli.test.js.map +0 -1
  219. package/dist/src/__tests__/e2e/config.js.map +0 -1
  220. package/dist/src/__tests__/e2e/funnel.test.js.map +0 -1
  221. package/dist/src/__tests__/e2e/mcp-tools.test.js.map +0 -1
  222. package/dist/src/__tests__/e2e/provisioning.test.js.map +0 -1
  223. package/dist/src/__tests__/handlers-unit.test.js.map +0 -1
  224. package/dist/src/__tests__/namespace.test.js.map +0 -1
  225. package/dist/src/auth.js.map +0 -1
  226. package/dist/src/ckg.js.map +0 -1
  227. package/dist/src/confidence.js.map +0 -1
  228. package/dist/src/embeddings.js.map +0 -1
  229. package/dist/src/handlers/advanced.js.map +0 -1
  230. package/dist/src/handlers/brain.js.map +0 -1
  231. package/dist/src/handlers/cache.js.map +0 -1
  232. package/dist/src/handlers/context.js.map +0 -1
  233. package/dist/src/handlers/fedbrain.js.map +0 -1
  234. package/dist/src/handlers/instances.js.map +0 -1
  235. package/dist/src/handlers/roadmap.js.map +0 -1
  236. package/dist/src/handlers/syndicate.js.map +0 -1
  237. package/dist/src/handlers/tco.d.ts +0 -16
  238. package/dist/src/handlers/tco.js +0 -303
  239. package/dist/src/handlers/tco.js.map +0 -1
  240. package/dist/src/handlers/team.js.map +0 -1
  241. package/dist/src/index.js.map +0 -1
  242. package/dist/src/namespace.js.map +0 -1
  243. package/dist/src/notifier.d.ts +0 -5
  244. package/dist/src/notifier.js +0 -6
  245. package/dist/src/notifier.js.map +0 -1
  246. package/dist/src/search.js.map +0 -1
  247. package/dist/src/search.test.js.map +0 -1
  248. package/dist/src/tools.js.map +0 -1
  249. package/dist/src/utils.js.map +0 -1
  250. package/packages/telegram-notify/SPLIT_PLAN.md +0 -106
  251. package/packages/telegram-notify/client.ts +0 -88
  252. package/packages/telegram-notify/emojis.json +0 -22
  253. package/packages/telegram-notify/pyproject.toml +0 -17
  254. package/packages/telegram-notify/telegram_notify/__init__.py +0 -3
  255. package/packages/telegram-notify/telegram_notify/client.py +0 -87
  256. package/packages/telegram-notify/telegram_notify/emojis.json +0 -22
  257. package/scripts/generate-icons.js +0 -28
  258. package/src/handlers/tco.ts +0 -347
  259. package/src/notifier.ts +0 -5
  260. /package/dist/{src/__tests__ → __tests__}/auth.test.d.ts +0 -0
  261. /package/dist/{src/__tests__ → __tests__}/auth.test.js +0 -0
  262. /package/dist/{src/__tests__ → __tests__}/brain-flow.test.d.ts +0 -0
  263. /package/dist/{src/__tests__ → __tests__}/confidence.test.d.ts +0 -0
  264. /package/dist/{src/__tests__ → __tests__}/confidence.test.js +0 -0
  265. /package/dist/{src/__tests__ → __tests__}/e2e/api-auth.test.d.ts +0 -0
  266. /package/dist/{src/__tests__ → __tests__}/e2e/api-auth.test.js +0 -0
  267. /package/dist/{src/__tests__ → __tests__}/e2e/api-health.test.d.ts +0 -0
  268. /package/dist/{src/__tests__ → __tests__}/e2e/api-health.test.js +0 -0
  269. /package/dist/{src/__tests__ → __tests__}/e2e/cli.test.d.ts +0 -0
  270. /package/dist/{src/__tests__ → __tests__}/e2e/cli.test.js +0 -0
  271. /package/dist/{src/__tests__ → __tests__}/e2e/config.d.ts +0 -0
  272. /package/dist/{src/__tests__ → __tests__}/e2e/config.js +0 -0
  273. /package/dist/{src/__tests__ → __tests__}/e2e/funnel.test.d.ts +0 -0
  274. /package/dist/{src/__tests__ → __tests__}/e2e/funnel.test.js +0 -0
  275. /package/dist/{src/__tests__ → __tests__}/e2e/mcp-tools.test.d.ts +0 -0
  276. /package/dist/{src/__tests__ → __tests__}/e2e/mcp-tools.test.js +0 -0
  277. /package/dist/{src/__tests__ → __tests__}/e2e/provisioning.test.d.ts +0 -0
  278. /package/dist/{src/__tests__ → __tests__}/e2e/provisioning.test.js +0 -0
  279. /package/dist/{src/__tests__ → __tests__}/handlers-unit.test.d.ts +0 -0
  280. /package/dist/{src/__tests__ → __tests__}/namespace.test.d.ts +0 -0
  281. /package/dist/{src/__tests__ → __tests__}/namespace.test.js +0 -0
  282. /package/dist/{src/auth.d.ts → auth.d.ts} +0 -0
  283. /package/dist/{src/auth.js → auth.js} +0 -0
  284. /package/dist/{src/ckg.d.ts → ckg.d.ts} +0 -0
  285. /package/dist/{src/ckg.js → ckg.js} +0 -0
  286. /package/dist/{src/confidence.d.ts → confidence.d.ts} +0 -0
  287. /package/dist/{src/confidence.js → confidence.js} +0 -0
  288. /package/dist/{src/embeddings.d.ts → embeddings.d.ts} +0 -0
  289. /package/dist/{src/embeddings.js → embeddings.js} +0 -0
  290. /package/dist/{src/handlers → handlers}/advanced.d.ts +0 -0
  291. /package/dist/{src/handlers → handlers}/advanced.js +0 -0
  292. /package/dist/{src/handlers → handlers}/brain.d.ts +0 -0
  293. /package/dist/{src/handlers → handlers}/cache.d.ts +0 -0
  294. /package/dist/{src/handlers → handlers}/cache.js +0 -0
  295. /package/dist/{src/handlers → handlers}/context.d.ts +0 -0
  296. /package/dist/{src/handlers → handlers}/instances.d.ts +0 -0
  297. /package/dist/{src/handlers → handlers}/instances.js +0 -0
  298. /package/dist/{src/handlers → handlers}/roadmap.d.ts +0 -0
  299. /package/dist/{src/handlers → handlers}/syndicate.d.ts +0 -0
  300. /package/dist/{src/handlers → handlers}/syndicate.js +0 -0
  301. /package/dist/{src/handlers → handlers}/team.d.ts +0 -0
  302. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
  303. /package/dist/{src/namespace.d.ts → namespace.d.ts} +0 -0
  304. /package/dist/{src/namespace.js → namespace.js} +0 -0
  305. /package/dist/{src/search.d.ts → search.d.ts} +0 -0
  306. /package/dist/{src/search.js → search.js} +0 -0
  307. /package/dist/{src/search.test.d.ts → search.test.d.ts} +0 -0
  308. /package/dist/{src/search.test.js → search.test.js} +0 -0
  309. /package/dist/{src/utils.d.ts → utils.d.ts} +0 -0
  310. /package/dist/{src/utils.js → utils.js} +0 -0
@@ -1,166 +0,0 @@
1
- import { useRef, useState } from "react";
2
- import {
3
- ActivityIndicator, FlatList, ScrollView, StyleSheet, Text,
4
- TouchableOpacity, View,
5
- } from "react-native";
6
- import { useSafeAreaInsets } from "react-native-safe-area-context";
7
- import { useTrips } from "../../hooks/useTrips";
8
- import { ApiError, inboxApi, InboxItem } from "../../lib/api";
9
- import { useInbox } from "../../hooks/useInbox";
10
- import SwipeableInboxItem from "../../components/SwipeableInboxItem";
11
- import BottomSheet from "../../components/BottomSheet";
12
- import { haptics } from "../../lib/haptics";
13
- import { TripCardSkeleton } from "../../components/Skeleton";
14
- import { useToast } from "../../components/ToastContext";
15
- import { scheduleItemReminder } from "../../lib/notifications";
16
-
17
- export default function InboxScreen() {
18
- const { showToast } = useToast();
19
- const insets = useSafeAreaInsets();
20
- const { items, loading, refresh } = useInbox();
21
- const { trips } = useTrips();
22
- const [selected, setSelected] = useState<InboxItem | null>(null);
23
- const [assigning, setAssigning] = useState(false);
24
- const assigningRef = useRef<boolean>(false);
25
-
26
- async function openAssign(item: InboxItem) {
27
- await haptics.tap();
28
- setSelected(item);
29
- }
30
-
31
- async function assign(tripId: string) {
32
- if (!selected) return;
33
- if (assigningRef.current) return;
34
- assigningRef.current = true;
35
- setAssigning(true);
36
- try {
37
- const result = await inboxApi.assign(selected.id, tripId, (selected.parsed_data?.type as string) ?? "other");
38
- await haptics.success();
39
- // Schedule a reminder for the newly assigned item if it has a date.
40
- // Find the trip name for a meaningful notification text.
41
- if (result.event_at) {
42
- const tripName = trips.find((t) => t.id === tripId)?.name ?? "Dein Trip";
43
- await scheduleItemReminder(tripId, tripName, result.trip_item_id, result.title, result.event_at);
44
- }
45
- showToast("Dem Trip zugeordnet ✓", "success");
46
- setSelected(null);
47
- await refresh();
48
- } catch (err) {
49
- await haptics.error();
50
- if (err instanceof ApiError && err.status === 429) {
51
- showToast("Tageslimit erreicht (50 Parses). Upgrade auf Pro.", "warning");
52
- } else {
53
- showToast("Zuordnung fehlgeschlagen", "error");
54
- }
55
- setSelected(null);
56
- } finally {
57
- setAssigning(false);
58
- assigningRef.current = false;
59
- }
60
- }
61
-
62
- async function reject(id: string) {
63
- await haptics.warning();
64
- try {
65
- await inboxApi.reject(id);
66
- showToast("Eintrag abgelehnt", "warning");
67
- await refresh();
68
- } catch {
69
- showToast("Ablehnen fehlgeschlagen", "error");
70
- }
71
- }
72
-
73
- if (loading && items.length === 0) {
74
- return (
75
- <View style={s.container}>
76
- <View style={{ padding: 16, gap: 10 }}>
77
- {[1, 2, 3].map((k) => <TripCardSkeleton key={k} />)}
78
- </View>
79
- </View>
80
- );
81
- }
82
-
83
- return (
84
- <View style={s.container}>
85
- <FlatList
86
- data={items}
87
- keyExtractor={(i) => i.id}
88
- contentContainerStyle={[
89
- s.list,
90
- { paddingBottom: insets.bottom + 24 },
91
- items.length === 0 && s.emptyFlex,
92
- ]}
93
- refreshing={loading}
94
- onRefresh={refresh}
95
- ListHeaderComponent={
96
- items.length > 0
97
- ? <Text style={s.hint}>→ Wischen zum Zuweisen · Ablehnen ←</Text>
98
- : null
99
- }
100
- ListEmptyComponent={
101
- <View style={s.empty}>
102
- <Text style={s.emptyIcon}>🎉</Text>
103
- <Text style={s.emptyTitle}>Inbox leer!</Text>
104
- <Text style={s.emptySub}>Alle Dokumente sind sortiert.</Text>
105
- </View>
106
- }
107
- renderItem={({ item }) => (
108
- <SwipeableInboxItem
109
- item={item}
110
- onAssign={() => openAssign(item)}
111
- onReject={() => reject(item.id)}
112
- />
113
- )}
114
- />
115
-
116
- <BottomSheet visible={!!selected} onClose={() => setSelected(null)} heightFraction={0.55}>
117
- <Text style={s.sheetTitle}>Welchem Trip zuweisen?</Text>
118
-
119
- {trips.length === 0 ? (
120
- <Text style={s.noTrips}>Noch keine Trips vorhanden.</Text>
121
- ) : (
122
- <ScrollView showsVerticalScrollIndicator={false} style={{ flex: 1 }}>
123
- {trips.map((trip) => (
124
- <TouchableOpacity
125
- key={trip.id}
126
- style={[s.tripRow, { opacity: assigning ? 0.5 : 1 }]}
127
- onPress={() => assign(trip.id)}
128
- disabled={assigning}
129
- activeOpacity={0.7}
130
- >
131
- <View style={s.tripRowInner}>
132
- <Text style={s.tripName}>{trip.name}</Text>
133
- {trip.start_date && <Text style={s.tripDate}>{trip.start_date}</Text>}
134
- </View>
135
- {assigning ? <ActivityIndicator color="#4f46e5" /> : <Text style={s.arrow}>›</Text>}
136
- </TouchableOpacity>
137
- ))}
138
- </ScrollView>
139
- )}
140
- </BottomSheet>
141
- </View>
142
- );
143
- }
144
-
145
- const s = StyleSheet.create({
146
- container: { flex: 1, backgroundColor: "#0f0f1a" },
147
- list: { padding: 16, gap: 0 },
148
- emptyFlex: { flex: 1 },
149
- hint: { color: "#3a3a5e", fontSize: 12, textAlign: "center", marginBottom: 12 },
150
- empty: { flex: 1, alignItems: "center", justifyContent: "center", padding: 48, gap: 12 },
151
- emptyIcon: { fontSize: 64 },
152
- emptyTitle: { fontSize: 22, fontWeight: "700", color: "#fff" },
153
- emptySub: { fontSize: 15, color: "#6666aa" },
154
- sheetTitle: { fontSize: 18, fontWeight: "700", color: "#fff", marginBottom: 16 },
155
- noTrips: { color: "#6666aa", fontSize: 14, textAlign: "center", padding: 24 },
156
- tripRow: {
157
- flexDirection: "row", alignItems: "center",
158
- paddingVertical: 16, paddingHorizontal: 4,
159
- borderBottomWidth: 1, borderBottomColor: "#2a2a4e",
160
- minHeight: 56,
161
- },
162
- tripRowInner: { flex: 1, gap: 2 },
163
- tripName: { color: "#fff", fontSize: 16, fontWeight: "500" },
164
- tripDate: { color: "#6666aa", fontSize: 13 },
165
- arrow: { color: "#4f46e5", fontSize: 22, fontWeight: "300" },
166
- });
@@ -1,130 +0,0 @@
1
- import { useRef, useState } from "react";
2
- import {
3
- FlatList, StyleSheet, Text, TextInput, TouchableOpacity, View,
4
- } from "react-native";
5
- import { useRouter } from "expo-router";
6
- import { useSafeAreaInsets } from "react-native-safe-area-context";
7
- import { getLocalTrips, getLocalItems } from "../../lib/db";
8
- import { TripItem } from "../../lib/api";
9
- import TimelineItem from "../../components/TimelineItem";
10
- import { haptics } from "../../lib/haptics";
11
-
12
- type Result = TripItem & { trip_name: string };
13
-
14
- export default function SearchScreen() {
15
- const router = useRouter();
16
- const insets = useSafeAreaInsets();
17
- const [query, setQuery] = useState("");
18
- const [results, setResults] = useState<Result[]>([]);
19
- const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
20
-
21
- function onQueryChange(text: string) {
22
- setQuery(text);
23
-
24
- if (debounceRef.current) clearTimeout(debounceRef.current);
25
- debounceRef.current = setTimeout(() => {
26
- if (text.trim().length < 2) {
27
- setResults([]);
28
- return;
29
- }
30
- const q = text.toLowerCase();
31
- const trips = getLocalTrips();
32
- const matched: Result[] = [];
33
-
34
- for (const trip of trips) {
35
- const items = getLocalItems(trip.id);
36
- for (const item of items) {
37
- const searchable = [
38
- item.title,
39
- item.booking_ref,
40
- item.provider,
41
- item.raw_text,
42
- JSON.stringify(item.parsed_data),
43
- ].filter(Boolean).join(" ").toLowerCase();
44
-
45
- if (searchable.includes(q)) {
46
- matched.push({ ...item, trip_name: trip.name });
47
- }
48
- }
49
- }
50
- setResults(matched);
51
- }, 250);
52
- }
53
-
54
- const showResults = query.trim().length >= 2;
55
-
56
- return (
57
- <View style={[s.container, { paddingTop: insets.top > 0 ? 0 : 8 }]}>
58
- <View style={s.searchBar}>
59
- <Text style={s.searchIcon} accessibilityElementsHidden>🔍</Text>
60
- <TextInput
61
- style={s.input}
62
- placeholder="Buchungsref, Airline, Hotel…"
63
- placeholderTextColor="#4a4a7a"
64
- value={query}
65
- onChangeText={onQueryChange}
66
- autoFocus
67
- returnKeyType="search"
68
- clearButtonMode="while-editing"
69
- accessibilityLabel="Suche"
70
- accessibilityHint="Mindestens 2 Zeichen eingeben"
71
- />
72
- </View>
73
-
74
- {showResults && results.length > 0 && (
75
- <Text style={s.resultCount}>{results.length} Ergebnis{results.length !== 1 ? "se" : ""}</Text>
76
- )}
77
-
78
- <FlatList
79
- data={results}
80
- keyExtractor={(i) => i.id}
81
- contentContainerStyle={results.length === 0 ? s.emptyContainer : s.list}
82
- keyboardShouldPersistTaps="handled"
83
- ListEmptyComponent={
84
- showResults
85
- ? <View style={s.empty}><Text style={s.emptyText}>Keine Ergebnisse für „{query}"</Text></View>
86
- : <View style={s.empty}>
87
- <Text style={s.emptyHint}>Tippe mindestens 2 Zeichen{"\n"}um in deinen Trips zu suchen</Text>
88
- </View>
89
- }
90
- renderItem={({ item }) => (
91
- <TouchableOpacity
92
- onPress={async () => {
93
- await haptics.tap();
94
- router.push(`/(app)/trips/${item.trip_id}`);
95
- }}
96
- activeOpacity={0.75}
97
- accessibilityLabel={`${item.title} in Trip ${item.trip_name}`}
98
- accessibilityRole="button"
99
- >
100
- <View style={s.tripLabelRow}>
101
- <Text style={s.tripLabel}>🗺️ {item.trip_name}</Text>
102
- </View>
103
- <TimelineItem item={item} />
104
- </TouchableOpacity>
105
- )}
106
- />
107
- </View>
108
- );
109
- }
110
-
111
- const s = StyleSheet.create({
112
- container: { flex: 1, backgroundColor: "#0f0f1a" },
113
- searchBar: {
114
- flexDirection: "row", alignItems: "center", gap: 10,
115
- margin: 16, marginBottom: 8,
116
- backgroundColor: "#1a1a2e", borderRadius: 14,
117
- paddingHorizontal: 14, paddingVertical: 2,
118
- borderWidth: 1, borderColor: "#2a2a4e",
119
- },
120
- searchIcon: { fontSize: 16 },
121
- input: { flex: 1, color: "#fff", fontSize: 16, paddingVertical: 12 },
122
- resultCount: { color: "#4f46e5", fontSize: 12, fontWeight: "600", paddingHorizontal: 20, marginBottom: 4 },
123
- list: { paddingHorizontal: 16, paddingBottom: 32 },
124
- emptyContainer: { flex: 1 },
125
- empty: { flex: 1, alignItems: "center", justifyContent: "center", padding: 48 },
126
- emptyText: { color: "#6666aa", fontSize: 15, textAlign: "center" },
127
- emptyHint: { color: "#3a3a5e", fontSize: 14, textAlign: "center", lineHeight: 22 },
128
- tripLabelRow: { flexDirection: "row", alignItems: "center", marginTop: 12, marginBottom: 4, paddingHorizontal: 4 },
129
- tripLabel: { color: "#4f46e5", fontSize: 12, fontWeight: "600" },
130
- });
@@ -1,381 +0,0 @@
1
- import { useState, useEffect } from "react";
2
- import {
3
- ActivityIndicator, Linking, ScrollView, StyleSheet, Text,
4
- TouchableOpacity, View,
5
- } from "react-native";import { useSafeAreaInsets } from "react-native-safe-area-context";
6
- import { useRouter } from "expo-router";
7
- import { logout } from "../../lib/auth";
8
- import { clearCache, cacheSizeBytes } from "../../lib/fileCache";
9
- import { purgeFailed, getPending } from "../../lib/offlineQueue";
10
- import { haptics } from "../../lib/haptics";
11
- import { useQuota } from "../../lib/quota";
12
- import { usersApi, cacheApi, type CacheStats } from "../../lib/api";
13
- import { useToast } from "../../components/ToastContext";
14
- import ConfirmDialog from "../../components/ConfirmDialog";
15
-
16
- export default function SettingsScreen() {
17
- const router = useRouter();
18
- const insets = useSafeAreaInsets();
19
- const { plan, isPro } = useQuota();
20
- const { showToast } = useToast();
21
- const [cacheSize, setCacheSize] = useState(0);
22
- const [queueSize, setQueueSize] = useState(0);
23
- const [loggingOut, setLoggingOut] = useState(false);
24
- const [dialog, setDialog] = useState<{ title: string; message?: string; onConfirm: () => void } | null>(null);
25
- const [telegramPin, setTelegramPin] = useState<string | null>(null);
26
- const [generatingPin, setGeneratingPin] = useState(false);
27
- const [cachlyStats, setCachlyStats] = useState<CacheStats | null>(null);
28
-
29
- async function handleGeneratePin() {
30
- setGeneratingPin(true);
31
- try {
32
- const { pin } = await usersApi.telegramPin();
33
- setTelegramPin(pin);
34
- setTimeout(() => setTelegramPin(null), 600_000);
35
- } catch {
36
- showToast('Fehler beim Generieren des PINs', 'error');
37
- } finally {
38
- setGeneratingPin(false);
39
- }
40
- }
41
-
42
- useEffect(() => {
43
- cacheSizeBytes().then(setCacheSize);
44
- setQueueSize(getPending().length);
45
- cacheApi.stats().then(setCachlyStats).catch(() => {});
46
- }, []);
47
-
48
- async function handleClearCache() {
49
- await haptics.warning();
50
- setDialog({
51
- title: "Cache leeren?",
52
- message: "Alle lokal gespeicherten Tickets und PDFs werden gelöscht.",
53
- onConfirm: async () => {
54
- await clearCache();
55
- setCacheSize(0);
56
- await haptics.success();
57
- },
58
- });
59
- }
60
-
61
- async function handlePurgeQueue() {
62
- purgeFailed(0);
63
- setQueueSize(0);
64
- await haptics.confirm();
65
- }
66
-
67
- function handleLogout() {
68
- setDialog({
69
- title: "Abmelden",
70
- message: "Wirklich abmelden?",
71
- onConfirm: async () => {
72
- setLoggingOut(true);
73
- await haptics.tap();
74
- try {
75
- await logout();
76
- router.replace("/(auth)/login");
77
- } catch {
78
- setLoggingOut(false);
79
- showToast("Abmelden fehlgeschlagen", "error");
80
- }
81
- },
82
- });
83
- }
84
-
85
- return (
86
- <ScrollView
87
- style={s.container}
88
- contentContainerStyle={[s.content, { paddingBottom: insets.bottom + 32 }]}
89
- >
90
- {/* Plan section */}
91
- <Text style={s.sectionTitle}>Mein Plan</Text>
92
- <View style={s.planCard}>
93
- <View style={s.planRow}>
94
- <Text style={s.planName}>{isPro ? "✦ Pro" : "Free"}</Text>
95
- {plan?.plan_expires_at && (
96
- <Text style={s.planExpiry}>
97
- bis {new Date(plan.plan_expires_at).toLocaleDateString("de")}
98
- </Text>
99
- )}
100
- </View>
101
- {!isPro && (
102
- <View style={s.limits}>
103
- <Text style={s.limitText}>
104
- {plan?.free_daily_parses ?? 50} KI-Parses / Tag
105
- </Text>
106
- <Text style={s.limitText}>
107
- max. {plan?.free_max_trips ?? 3} Trips
108
- </Text>
109
- </View>
110
- )}
111
- {!isPro && (
112
- <TouchableOpacity
113
- style={s.upgradeBtn}
114
- onPress={() => Linking.openURL(process.env.EXPO_PUBLIC_UPGRADE_URL ?? "https://tco.app/upgrade")}
115
- activeOpacity={0.8}
116
- >
117
- <Text style={s.upgradeBtnText}>Auf Pro upgraden ✦</Text>
118
- </TouchableOpacity>
119
- )}
120
- </View>
121
-
122
- <Text style={s.sectionTitle}>KI Modell</Text>
123
- <View style={s.card}>
124
- <View style={s.infoRow}>
125
- <Text style={s.rowText}>Aktives Modell</Text>
126
- <Text style={s.rowValue}>{process.env.EXPO_PUBLIC_OLLAMA_MODEL ?? "llama3.2-vision"}</Text>
127
- </View>
128
- <Text style={s.hint}>
129
- Das Modell wird auf dem Server konfiguriert (OLLAMA_MODEL).{"\n"}
130
- Für Screenshot-Parsing wird ein Vision-Modell benötigt.
131
- </Text>
132
- </View>
133
-
134
- <Text style={s.sectionTitle}>Telegram</Text>
135
- <View style={s.card}>
136
- {/* Linked status badge */}
137
- <View style={s.infoRow}>
138
- <Text style={s.rowText}>Status</Text>
139
- <Text style={[s.rowValue, plan?.telegram_linked ? s.telegramLinked : s.telegramUnlinked]}>
140
- {plan?.telegram_linked ? "● Verknüpft" : "○ Nicht verknüpft"}
141
- </Text>
142
- </View>
143
-
144
- {telegramPin ? (
145
- <View style={s.pinBox}>
146
- <Text style={s.pinLabel}>Dein PIN (gültig 10 Min.)</Text>
147
- <Text style={s.pinCode}>{telegramPin}</Text>
148
- <Text style={s.pinHint}>Sende diesen PIN an @TCOBot:{"\n"}/link {telegramPin}</Text>
149
- </View>
150
- ) : plan?.telegram_linked ? (
151
- <>
152
- <View style={s.infoRow}>
153
- <Text style={[s.rowText, { color: "#6666aa" }]}>Bot</Text>
154
- <Text style={s.rowValue}>@TCOBot</Text>
155
- </View>
156
- <TouchableOpacity
157
- style={[s.row, { borderBottomWidth: 0 }]}
158
- onPress={() => setDialog({
159
- title: "Telegram trennen?",
160
- message: "Du erhältst dann keine Bot-Nachrichten mehr.",
161
- onConfirm: async () => {
162
- try {
163
- await usersApi.telegramUnlink();
164
- showToast("Telegram-Verknüpfung aufgehoben", "success");
165
- } catch {
166
- showToast("Trennen fehlgeschlagen", "error");
167
- }
168
- },
169
- })}
170
- accessibilityRole="button"
171
- >
172
- <Text style={[s.rowText, s.danger]}>Telegram trennen</Text>
173
- </TouchableOpacity>
174
- </>
175
- ) : (
176
- <TouchableOpacity
177
- style={[s.row, { borderBottomWidth: 0 }]}
178
- onPress={handleGeneratePin}
179
- accessibilityRole="button"
180
- >
181
- <Text style={s.rowText}>Mit Telegram verknüpfen</Text>
182
- {generatingPin ? <ActivityIndicator size="small" color="#4f46e5" /> : <Text style={s.rowChevron}>›</Text>}
183
- </TouchableOpacity>
184
- )}
185
- </View>
186
-
187
- <Text style={s.sectionTitle}>Offline & Cache</Text>
188
- <View style={s.card}>
189
- <View style={s.infoRow}>
190
- <Text style={s.rowText}>Cache-Größe</Text>
191
- <Text style={s.rowValue}>{(cacheSize / 1024 / 1024).toFixed(1)} MB</Text>
192
- </View>
193
- <TouchableOpacity
194
- style={s.row}
195
- onPress={handleClearCache}
196
- accessibilityLabel="Cache leeren"
197
- accessibilityRole="button"
198
- >
199
- <Text style={[s.rowText, s.danger]}>Cache leeren</Text>
200
- </TouchableOpacity>
201
-
202
- <View style={[s.infoRow, { marginTop: 0 }]}>
203
- <Text style={s.rowText}>Offline Queue</Text>
204
- <Text style={s.rowValue}>{queueSize} Einträge</Text>
205
- </View>
206
- {queueSize > 0 && (
207
- <TouchableOpacity
208
- style={s.row}
209
- onPress={handlePurgeQueue}
210
- accessibilityLabel="Offline-Queue zurücksetzen"
211
- accessibilityRole="button"
212
- >
213
- <Text style={[s.rowText, s.danger]}>Queue zurücksetzen</Text>
214
- </TouchableOpacity>
215
- )}
216
- </View>
217
-
218
- {/* Links section */}
219
- <Text style={s.sectionTitle}>Info</Text>
220
- <View style={s.card}>
221
- <TouchableOpacity
222
- style={s.row}
223
- onPress={() => Linking.openURL(process.env.EXPO_PUBLIC_PRIVACY_URL ?? "https://tco.app/privacy")}
224
- accessibilityRole="link"
225
- >
226
- <Text style={s.rowText}>Datenschutz</Text>
227
- <Text style={s.rowChevron}>›</Text>
228
- </TouchableOpacity>
229
- <TouchableOpacity
230
- style={s.row}
231
- onPress={() => Linking.openURL(process.env.EXPO_PUBLIC_TERMS_URL ?? "https://tco.app/terms")}
232
- accessibilityRole="link"
233
- >
234
- <Text style={s.rowText}>Nutzungsbedingungen</Text>
235
- <Text style={s.rowChevron}>›</Text>
236
- </TouchableOpacity>
237
- <TouchableOpacity
238
- style={[s.row, { borderBottomWidth: 0 }]}
239
- onPress={() => Linking.openURL(`mailto:${process.env.EXPO_PUBLIC_SUPPORT_EMAIL ?? "hello@tco.app"}`)}
240
- accessibilityRole="link"
241
- >
242
- <Text style={s.rowText}>Support kontaktieren</Text>
243
- <Text style={s.rowChevron}>›</Text>
244
- </TouchableOpacity>
245
- </View>
246
-
247
- <Text style={s.sectionTitle}>Account</Text>
248
- <View style={s.card}>
249
- <TouchableOpacity
250
- style={[s.row, s.dangerRow, { borderBottomWidth: 0 }]}
251
- onPress={handleLogout}
252
- disabled={loggingOut}
253
- accessibilityLabel="Abmelden"
254
- accessibilityRole="button"
255
- >
256
- <Text style={s.dangerText}>Abmelden</Text>
257
- </TouchableOpacity>
258
- </View>
259
-
260
- {/* Cachly badge — cross-promotion + live stats */}
261
- <TouchableOpacity
262
- style={s.cachlyBadge}
263
- onPress={() => Linking.openURL("https://cachly.dev")}
264
- activeOpacity={0.75}
265
- accessibilityLabel="Powered by Cachly — cachly.dev besuchen"
266
- accessibilityRole="link"
267
- >
268
- <View style={s.cachlyInner}>
269
- <View style={[s.cachlyDot, cachlyStats?.configured ? s.cachlyDotActive : s.cachlyDotOff]} />
270
- <Text style={s.cachlyText}>Powered by</Text>
271
- <Text style={s.cachlyBrand}>Cachly</Text>
272
- <Text style={[s.cachlyStatus, cachlyStats?.configured ? s.cachlyStatusOn : s.cachlyStatusOff]}>
273
- {cachlyStats ? (cachlyStats.configured ? "● aktiv" : "○ nicht verbunden") : ""}
274
- </Text>
275
- </View>
276
- {cachlyStats?.configured ? (
277
- <View style={s.cachlyStatsRow}>
278
- <View style={s.cachlyStatCell}>
279
- <Text style={s.cachlyStatValue}>{cachlyStats.hits}</Text>
280
- <Text style={s.cachlyStatLabel}>Cache Hits</Text>
281
- </View>
282
- <View style={s.cachlyStatDivider} />
283
- <View style={s.cachlyStatCell}>
284
- <Text style={s.cachlyStatValue}>{Math.round(cachlyStats.hit_rate * 100)}%</Text>
285
- <Text style={s.cachlyStatLabel}>Hit Rate</Text>
286
- </View>
287
- <View style={s.cachlyStatDivider} />
288
- <View style={s.cachlyStatCell}>
289
- <Text style={s.cachlyStatValue}>{cachlyStats.key_count}</Text>
290
- <Text style={s.cachlyStatLabel}>Gecacht</Text>
291
- </View>
292
- </View>
293
- ) : (
294
- <Text style={s.cachlySubtext}>
295
- KI-Ergebnisse werden per Cachly Redis gecacht —{"\n"}
296
- kein zweiter AI-Call für dasselbe Dokument.
297
- </Text>
298
- )}
299
- </TouchableOpacity>
300
-
301
- <Text style={s.version}>Travel Chaos Organizer v0.1.0</Text>
302
-
303
- <ConfirmDialog
304
- visible={!!dialog}
305
- title={dialog?.title ?? ""}
306
- message={dialog?.message}
307
- actions={[
308
- { label: "Ja", style: "destructive", onPress: () => { setDialog(null); dialog?.onConfirm(); } },
309
- { label: "Abbrechen", style: "cancel", onPress: () => setDialog(null) },
310
- ]}
311
- />
312
- </ScrollView>
313
- );
314
- }
315
-
316
- const s = StyleSheet.create({
317
- container: { flex: 1, backgroundColor: "#0f0f1a" },
318
- content: { padding: 20, gap: 8 },
319
- sectionTitle: {
320
- color: "#6666aa", fontSize: 12, fontWeight: "600",
321
- letterSpacing: 0.8, textTransform: "uppercase",
322
- marginTop: 16, marginBottom: 4, paddingHorizontal: 4,
323
- },
324
- planCard: { backgroundColor: "#1a1a2e", borderRadius: 16, padding: 20, gap: 12, borderWidth: 1, borderColor: "#2a2a4e" },
325
- planRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" },
326
- planName: { fontSize: 22, fontWeight: "800", color: "#fff" },
327
- planExpiry: { fontSize: 12, color: "#6666aa" },
328
- limits: { gap: 4 },
329
- limitText: { fontSize: 13, color: "#6666aa" },
330
- upgradeBtn: { backgroundColor: "#4f46e5", paddingVertical: 14, borderRadius: 12, alignItems: "center", marginTop: 4 },
331
- upgradeBtnText: { color: "#fff", fontWeight: "700", fontSize: 15 },
332
- card: { backgroundColor: "#1a1a2e", borderRadius: 16, borderWidth: 1, borderColor: "#2a2a4e", overflow: "hidden" },
333
- row: { paddingVertical: 14, paddingHorizontal: 18, borderBottomWidth: 1, borderBottomColor: "#2a2a4e", flexDirection: "row", justifyContent: "space-between", alignItems: "center" },
334
- infoRow: {
335
- paddingVertical: 14, paddingHorizontal: 18,
336
- flexDirection: "row", justifyContent: "space-between", alignItems: "center",
337
- borderBottomWidth: 1, borderBottomColor: "#2a2a4e",
338
- },
339
- rowText: { color: "#e2e8f0", fontSize: 15 },
340
- rowValue: { color: "#6666aa", fontSize: 14 },
341
- rowChevron: { color: "#6666aa", fontSize: 18 },
342
- check: { color: "#4f46e5", fontSize: 16, fontWeight: "700" },
343
- danger: { color: "#f87171" },
344
- dangerRow: { borderWidth: 1, borderColor: "#ff6b6b22", backgroundColor: "#ff6b6b11" },
345
- dangerText: { color: "#ff8888", fontSize: 15, fontWeight: "600" },
346
- hint: { color: "#4a4a7a", fontSize: 12, padding: 16, lineHeight: 18 },
347
- pinBox: { padding: 18, alignItems: 'center', gap: 8 },
348
- pinLabel: { color: '#6666aa', fontSize: 12 },
349
- pinCode: { color: '#fff', fontSize: 40, fontWeight: '800', letterSpacing: 8 },
350
- pinHint: { color: '#3a3a5e', fontSize: 12, textAlign: 'center' },
351
- telegramLinked: { color: '#10b981', fontWeight: '600' },
352
- telegramUnlinked: { color: '#3a3a5e' },
353
-
354
- // Cachly badge
355
- cachlyBadge: {
356
- marginTop: 32,
357
- backgroundColor: "#1a1a2e",
358
- borderRadius: 16,
359
- borderWidth: 1,
360
- borderColor: "#4f46e533",
361
- padding: 16,
362
- gap: 8,
363
- },
364
- cachlyInner: { flexDirection: "row", alignItems: "center", gap: 8 },
365
- cachlyDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: "#4f46e5" },
366
- cachlyDotActive: { backgroundColor: "#10b981" },
367
- cachlyDotOff: { backgroundColor: "#3a3a5e" },
368
- cachlyText: { color: "#6666aa", fontSize: 13 },
369
- cachlyBrand: { color: "#a5b4fc", fontSize: 14, fontWeight: "700" },
370
- cachlyStatus: { fontSize: 11, marginLeft: "auto" as const },
371
- cachlyStatusOn: { color: "#10b981" },
372
- cachlyStatusOff: { color: "#3a3a5e" },
373
- cachlySubtext: { color: "#3a3a5e", fontSize: 12, lineHeight: 18 },
374
- cachlyStatsRow: { flexDirection: "row", alignItems: "center", marginTop: 4 },
375
- cachlyStatCell: { flex: 1, alignItems: "center", gap: 2 },
376
- cachlyStatValue: { color: "#a5b4fc", fontSize: 20, fontWeight: "800" },
377
- cachlyStatLabel: { color: "#3a3a5e", fontSize: 11 },
378
- cachlyStatDivider: { width: 1, height: 32, backgroundColor: "#2a2a4e" },
379
-
380
- version: { color: "#3a3a5e", fontSize: 12, textAlign: "center", marginTop: 20 },
381
- });