@cachly-dev/mcp-server 0.10.47 → 0.10.49

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 (309) hide show
  1. package/.github/workflows/eas-build-android.yml +58 -0
  2. package/.github/workflows/eas-update.yml +55 -0
  3. package/STRATEGY.md +209 -0
  4. package/apps/travel-chaos-organizer/.env.example +49 -0
  5. package/apps/travel-chaos-organizer/DEPLOY.md +328 -0
  6. package/apps/travel-chaos-organizer/Makefile +57 -0
  7. package/apps/travel-chaos-organizer/README.md +159 -0
  8. package/apps/travel-chaos-organizer/backend/.env.example +10 -0
  9. package/apps/travel-chaos-organizer/backend/Dockerfile +25 -0
  10. package/apps/travel-chaos-organizer/backend/alembic/env.py +56 -0
  11. package/apps/travel-chaos-organizer/backend/alembic/script.py.mako +24 -0
  12. package/apps/travel-chaos-organizer/backend/alembic/versions/.gitkeep +0 -0
  13. package/apps/travel-chaos-organizer/backend/alembic/versions/0001_stripe_customer_id.py +24 -0
  14. package/apps/travel-chaos-organizer/backend/alembic/versions/0002_telegram_chat_id.py +24 -0
  15. package/apps/travel-chaos-organizer/backend/alembic.ini +39 -0
  16. package/apps/travel-chaos-organizer/backend/app/__init__.py +0 -0
  17. package/apps/travel-chaos-organizer/backend/app/auth/__init__.py +0 -0
  18. package/apps/travel-chaos-organizer/backend/app/auth/keycloak.py +81 -0
  19. package/apps/travel-chaos-organizer/backend/app/config.py +66 -0
  20. package/apps/travel-chaos-organizer/backend/app/db/__init__.py +0 -0
  21. package/apps/travel-chaos-organizer/backend/app/db/database.py +20 -0
  22. package/apps/travel-chaos-organizer/backend/app/db/migrations/001_init.sql +71 -0
  23. package/apps/travel-chaos-organizer/backend/app/db/migrations/002_telemetry_freemium.sql +31 -0
  24. package/apps/travel-chaos-organizer/backend/app/db/migrations/003_telegram_chat_id.sql +4 -0
  25. package/apps/travel-chaos-organizer/backend/app/db/migrations/004_stripe_and_email.sql +5 -0
  26. package/apps/travel-chaos-organizer/backend/app/limiter.py +4 -0
  27. package/apps/travel-chaos-organizer/backend/app/logging_config.py +25 -0
  28. package/apps/travel-chaos-organizer/backend/app/main.py +77 -0
  29. package/apps/travel-chaos-organizer/backend/app/models/__init__.py +0 -0
  30. package/apps/travel-chaos-organizer/backend/app/models/schemas.py +142 -0
  31. package/apps/travel-chaos-organizer/backend/app/routers/__init__.py +0 -0
  32. package/apps/travel-chaos-organizer/backend/app/routers/admin.py +237 -0
  33. package/apps/travel-chaos-organizer/backend/app/routers/cache.py +13 -0
  34. package/apps/travel-chaos-organizer/backend/app/routers/events.py +29 -0
  35. package/apps/travel-chaos-organizer/backend/app/routers/export.py +122 -0
  36. package/apps/travel-chaos-organizer/backend/app/routers/inbox.py +122 -0
  37. package/apps/travel-chaos-organizer/backend/app/routers/items.py +130 -0
  38. package/apps/travel-chaos-organizer/backend/app/routers/mail.py +108 -0
  39. package/apps/travel-chaos-organizer/backend/app/routers/parse.py +303 -0
  40. package/apps/travel-chaos-organizer/backend/app/routers/payments.py +179 -0
  41. package/apps/travel-chaos-organizer/backend/app/routers/trips.py +134 -0
  42. package/apps/travel-chaos-organizer/backend/app/routers/users.py +169 -0
  43. package/apps/travel-chaos-organizer/backend/app/routers/waitlist.py +37 -0
  44. package/apps/travel-chaos-organizer/backend/app/services/__init__.py +0 -0
  45. package/apps/travel-chaos-organizer/backend/app/services/cache.py +131 -0
  46. package/apps/travel-chaos-organizer/backend/app/services/drip.py +128 -0
  47. package/apps/travel-chaos-organizer/backend/app/services/email.py +61 -0
  48. package/apps/travel-chaos-organizer/backend/app/services/errors.py +44 -0
  49. package/apps/travel-chaos-organizer/backend/app/services/notifier.py +10 -0
  50. package/apps/travel-chaos-organizer/backend/app/services/ollama.py +101 -0
  51. package/apps/travel-chaos-organizer/backend/app/services/parser.py +22 -0
  52. package/apps/travel-chaos-organizer/backend/app/services/quota.py +85 -0
  53. package/apps/travel-chaos-organizer/backend/app/services/sentry.py +11 -0
  54. package/apps/travel-chaos-organizer/backend/app/services/telemetry.py +35 -0
  55. package/apps/travel-chaos-organizer/backend/pytest.ini +4 -0
  56. package/apps/travel-chaos-organizer/backend/requirements-dev.txt +6 -0
  57. package/apps/travel-chaos-organizer/backend/requirements.txt +25 -0
  58. package/apps/travel-chaos-organizer/backend/tests/__init__.py +0 -0
  59. package/apps/travel-chaos-organizer/backend/tests/conftest.py +223 -0
  60. package/apps/travel-chaos-organizer/backend/tests/test_admin.py +99 -0
  61. package/apps/travel-chaos-organizer/backend/tests/test_cache.py +142 -0
  62. package/apps/travel-chaos-organizer/backend/tests/test_drip.py +32 -0
  63. package/apps/travel-chaos-organizer/backend/tests/test_e2e_chain.py +121 -0
  64. package/apps/travel-chaos-organizer/backend/tests/test_export.py +48 -0
  65. package/apps/travel-chaos-organizer/backend/tests/test_inbox.py +107 -0
  66. package/apps/travel-chaos-organizer/backend/tests/test_items.py +138 -0
  67. package/apps/travel-chaos-organizer/backend/tests/test_mail.py +113 -0
  68. package/apps/travel-chaos-organizer/backend/tests/test_ollama.py +145 -0
  69. package/apps/travel-chaos-organizer/backend/tests/test_parse_url.py +98 -0
  70. package/apps/travel-chaos-organizer/backend/tests/test_parser.py +72 -0
  71. package/apps/travel-chaos-organizer/backend/tests/test_payments.py +163 -0
  72. package/apps/travel-chaos-organizer/backend/tests/test_quota.py +46 -0
  73. package/apps/travel-chaos-organizer/backend/tests/test_search.py +67 -0
  74. package/apps/travel-chaos-organizer/backend/tests/test_trips.py +123 -0
  75. package/apps/travel-chaos-organizer/backend/tests/test_users.py +52 -0
  76. package/apps/travel-chaos-organizer/backups/.gitkeep +0 -0
  77. package/apps/travel-chaos-organizer/caddy/Caddyfile +27 -0
  78. package/apps/travel-chaos-organizer/docker-compose.node1.yml +31 -0
  79. package/apps/travel-chaos-organizer/docker-compose.override.yml +14 -0
  80. package/apps/travel-chaos-organizer/docker-compose.yml +128 -0
  81. package/apps/travel-chaos-organizer/frontend/.env.example +13 -0
  82. package/apps/travel-chaos-organizer/frontend/app/(app)/_layout.tsx +80 -0
  83. package/apps/travel-chaos-organizer/frontend/app/(app)/inbox.tsx +166 -0
  84. package/apps/travel-chaos-organizer/frontend/app/(app)/search.tsx +130 -0
  85. package/apps/travel-chaos-organizer/frontend/app/(app)/settings.tsx +381 -0
  86. package/apps/travel-chaos-organizer/frontend/app/(app)/trips/[id].tsx +346 -0
  87. package/apps/travel-chaos-organizer/frontend/app/(app)/trips.tsx +363 -0
  88. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/cancel.tsx +34 -0
  89. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/success.tsx +35 -0
  90. package/apps/travel-chaos-organizer/frontend/app/(auth)/login.tsx +91 -0
  91. package/apps/travel-chaos-organizer/frontend/app/_layout.tsx +71 -0
  92. package/apps/travel-chaos-organizer/frontend/app/auth.tsx +29 -0
  93. package/apps/travel-chaos-organizer/frontend/app/index.tsx +16 -0
  94. package/apps/travel-chaos-organizer/frontend/app/onboarding.tsx +119 -0
  95. package/apps/travel-chaos-organizer/frontend/app.config.ts +54 -0
  96. package/apps/travel-chaos-organizer/frontend/assets/adaptive-icon.svg +66 -0
  97. package/apps/travel-chaos-organizer/frontend/assets/icon.svg +79 -0
  98. package/apps/travel-chaos-organizer/frontend/assets/splash.svg +15 -0
  99. package/apps/travel-chaos-organizer/frontend/components/BottomSheet.tsx +102 -0
  100. package/apps/travel-chaos-organizer/frontend/components/ConfettiCannon.tsx +107 -0
  101. package/apps/travel-chaos-organizer/frontend/components/ConfirmDialog.tsx +109 -0
  102. package/apps/travel-chaos-organizer/frontend/components/ErrorBoundary.tsx +45 -0
  103. package/apps/travel-chaos-organizer/frontend/components/FileUploadButton.tsx +19 -0
  104. package/apps/travel-chaos-organizer/frontend/components/ImportSheet.tsx +155 -0
  105. package/apps/travel-chaos-organizer/frontend/components/OfflineBadge.tsx +55 -0
  106. package/apps/travel-chaos-organizer/frontend/components/QRCodeViewer.tsx +80 -0
  107. package/apps/travel-chaos-organizer/frontend/components/ScoreRing.tsx +39 -0
  108. package/apps/travel-chaos-organizer/frontend/components/Screen.tsx +39 -0
  109. package/apps/travel-chaos-organizer/frontend/components/Skeleton.tsx +70 -0
  110. package/apps/travel-chaos-organizer/frontend/components/SwipeableInboxItem.tsx +121 -0
  111. package/apps/travel-chaos-organizer/frontend/components/SwipeableTimelineItem.tsx +70 -0
  112. package/apps/travel-chaos-organizer/frontend/components/TimelineItem.tsx +73 -0
  113. package/apps/travel-chaos-organizer/frontend/components/TimelineItemDetail.tsx +130 -0
  114. package/apps/travel-chaos-organizer/frontend/components/Toast.tsx +60 -0
  115. package/apps/travel-chaos-organizer/frontend/components/ToastContext.tsx +42 -0
  116. package/apps/travel-chaos-organizer/frontend/components/TripCard.tsx +146 -0
  117. package/apps/travel-chaos-organizer/frontend/components/TripQRModal.tsx +70 -0
  118. package/apps/travel-chaos-organizer/frontend/components/UpgradeBanner.tsx +44 -0
  119. package/apps/travel-chaos-organizer/frontend/eas.json +22 -0
  120. package/apps/travel-chaos-organizer/frontend/hooks/useInbox.ts +24 -0
  121. package/apps/travel-chaos-organizer/frontend/hooks/useNetworkSync.ts +60 -0
  122. package/apps/travel-chaos-organizer/frontend/hooks/useTrips.ts +112 -0
  123. package/apps/travel-chaos-organizer/frontend/lib/api.ts +223 -0
  124. package/apps/travel-chaos-organizer/frontend/lib/auth.ts +93 -0
  125. package/apps/travel-chaos-organizer/frontend/lib/db.ts +86 -0
  126. package/apps/travel-chaos-organizer/frontend/lib/fileCache.ts +54 -0
  127. package/apps/travel-chaos-organizer/frontend/lib/haptics.ts +13 -0
  128. package/apps/travel-chaos-organizer/frontend/lib/notifications.ts +112 -0
  129. package/apps/travel-chaos-organizer/frontend/lib/offlineQueue.ts +145 -0
  130. package/apps/travel-chaos-organizer/frontend/lib/quota.tsx +43 -0
  131. package/apps/travel-chaos-organizer/frontend/lib/sentry.ts +28 -0
  132. package/apps/travel-chaos-organizer/frontend/lib/shareIntent.ts +44 -0
  133. package/apps/travel-chaos-organizer/frontend/package-lock.json +13037 -0
  134. package/apps/travel-chaos-organizer/frontend/package.json +44 -0
  135. package/apps/travel-chaos-organizer/frontend/tsconfig.json +23 -0
  136. package/apps/travel-chaos-organizer/keycloak/realm-export.json +59 -0
  137. package/apps/travel-chaos-organizer/landing/index.html +773 -0
  138. package/apps/travel-chaos-organizer/scripts/backup.sh +14 -0
  139. package/apps/travel-chaos-organizer/scripts/configure-env.sh +82 -0
  140. package/apps/travel-chaos-organizer/scripts/deploy.sh +54 -0
  141. package/apps/travel-chaos-organizer/scripts/health-check.sh +36 -0
  142. package/apps/travel-chaos-organizer/scripts/migrate.sh +7 -0
  143. package/apps/travel-chaos-organizer/scripts/server-setup.sh +85 -0
  144. package/apps/travel-chaos-organizer/scripts/smoke-test.sh +29 -0
  145. package/apps/travel-chaos-organizer/scripts/verify-tracking.sh +71 -0
  146. package/apps/travel-chaos-organizer/telegram-bot/.env.example +3 -0
  147. package/apps/travel-chaos-organizer/telegram-bot/Dockerfile +6 -0
  148. package/apps/travel-chaos-organizer/telegram-bot/bot.py +504 -0
  149. package/apps/travel-chaos-organizer/telegram-bot/requirements.txt +3 -0
  150. package/dist/packages/telegram-notify/client.d.ts +19 -0
  151. package/dist/packages/telegram-notify/client.js +75 -0
  152. package/dist/packages/telegram-notify/client.js.map +1 -0
  153. package/dist/src/__tests__/auth.test.js.map +1 -0
  154. package/dist/{__tests__ → src/__tests__}/brain-flow.test.js +143 -2
  155. package/dist/src/__tests__/brain-flow.test.js.map +1 -0
  156. package/dist/src/__tests__/confidence.test.js.map +1 -0
  157. package/dist/src/__tests__/e2e/api-auth.test.js.map +1 -0
  158. package/dist/src/__tests__/e2e/api-health.test.js.map +1 -0
  159. package/dist/src/__tests__/e2e/cli.test.js.map +1 -0
  160. package/dist/src/__tests__/e2e/config.js.map +1 -0
  161. package/dist/src/__tests__/e2e/funnel.test.js.map +1 -0
  162. package/dist/src/__tests__/e2e/mcp-tools.test.js.map +1 -0
  163. package/dist/src/__tests__/e2e/provisioning.test.js.map +1 -0
  164. package/dist/{__tests__ → src/__tests__}/handlers-unit.test.js +1 -1
  165. package/dist/src/__tests__/handlers-unit.test.js.map +1 -0
  166. package/dist/src/__tests__/namespace.test.js.map +1 -0
  167. package/dist/src/auth.js.map +1 -0
  168. package/dist/src/ckg.js.map +1 -0
  169. package/dist/src/confidence.js.map +1 -0
  170. package/dist/src/embeddings.js.map +1 -0
  171. package/dist/src/handlers/advanced.js.map +1 -0
  172. package/dist/{handlers → src/handlers}/brain.js +135 -31
  173. package/dist/src/handlers/brain.js.map +1 -0
  174. package/dist/src/handlers/cache.js.map +1 -0
  175. package/dist/{handlers → src/handlers}/context.js +9 -4
  176. package/dist/src/handlers/context.js.map +1 -0
  177. package/dist/{handlers → src/handlers}/fedbrain.d.ts +6 -0
  178. package/dist/{handlers → src/handlers}/fedbrain.js +15 -2
  179. package/dist/src/handlers/fedbrain.js.map +1 -0
  180. package/dist/src/handlers/instances.js.map +1 -0
  181. package/dist/{handlers → src/handlers}/roadmap.js +8 -4
  182. package/dist/src/handlers/roadmap.js.map +1 -0
  183. package/dist/src/handlers/syndicate.js.map +1 -0
  184. package/dist/src/handlers/tco.d.ts +16 -0
  185. package/dist/src/handlers/tco.js +303 -0
  186. package/dist/src/handlers/tco.js.map +1 -0
  187. package/dist/{handlers → src/handlers}/team.js +1 -1
  188. package/dist/src/handlers/team.js.map +1 -0
  189. package/dist/{index.js → src/index.js} +145 -97
  190. package/dist/src/index.js.map +1 -0
  191. package/dist/src/namespace.js.map +1 -0
  192. package/dist/src/notifier.d.ts +5 -0
  193. package/dist/src/notifier.js +6 -0
  194. package/dist/src/notifier.js.map +1 -0
  195. package/dist/{search.js → src/search.js} +3 -3
  196. package/dist/src/search.js.map +1 -0
  197. package/dist/src/search.test.js.map +1 -0
  198. package/dist/{tools.d.ts → src/tools.d.ts} +196 -0
  199. package/dist/{tools.js → src/tools.js} +178 -0
  200. package/dist/src/tools.js.map +1 -0
  201. package/dist/src/utils.js.map +1 -0
  202. package/package.json +3 -2
  203. package/packages/telegram-notify/SPLIT_PLAN.md +106 -0
  204. package/packages/telegram-notify/client.ts +88 -0
  205. package/packages/telegram-notify/emojis.json +22 -0
  206. package/packages/telegram-notify/pyproject.toml +17 -0
  207. package/packages/telegram-notify/telegram_notify/__init__.py +3 -0
  208. package/packages/telegram-notify/telegram_notify/client.py +87 -0
  209. package/packages/telegram-notify/telegram_notify/emojis.json +22 -0
  210. package/scripts/generate-icons.js +28 -0
  211. package/smithery.yaml +21 -10
  212. package/src/__tests__/brain-flow.test.ts +176 -2
  213. package/src/__tests__/handlers-unit.test.ts +1 -1
  214. package/src/handlers/brain.ts +139 -32
  215. package/src/handlers/context.ts +9 -4
  216. package/src/handlers/fedbrain.ts +17 -2
  217. package/src/handlers/roadmap.ts +8 -4
  218. package/src/handlers/tco.ts +347 -0
  219. package/src/handlers/team.ts +1 -1
  220. package/src/index.ts +137 -147
  221. package/src/notifier.ts +5 -0
  222. package/src/search.ts +3 -3
  223. package/src/tools.ts +191 -0
  224. package/tsconfig.json +2 -3
  225. package/dist/__tests__/auth.test.js.map +0 -1
  226. package/dist/__tests__/brain-flow.test.js.map +0 -1
  227. package/dist/__tests__/brain-predict-failures.test.d.ts +0 -17
  228. package/dist/__tests__/brain-predict-failures.test.js +0 -339
  229. package/dist/__tests__/brain-predict-failures.test.js.map +0 -1
  230. package/dist/__tests__/confidence.test.js.map +0 -1
  231. package/dist/__tests__/e2e/api-auth.test.js.map +0 -1
  232. package/dist/__tests__/e2e/api-health.test.js.map +0 -1
  233. package/dist/__tests__/e2e/cli.test.js.map +0 -1
  234. package/dist/__tests__/e2e/config.js.map +0 -1
  235. package/dist/__tests__/e2e/funnel.test.js.map +0 -1
  236. package/dist/__tests__/e2e/mcp-tools.test.js.map +0 -1
  237. package/dist/__tests__/e2e/provisioning.test.js.map +0 -1
  238. package/dist/__tests__/handlers-unit.test.js.map +0 -1
  239. package/dist/__tests__/namespace.test.js.map +0 -1
  240. package/dist/auth.js.map +0 -1
  241. package/dist/ckg.js.map +0 -1
  242. package/dist/confidence.js.map +0 -1
  243. package/dist/embeddings.js.map +0 -1
  244. package/dist/handlers/advanced.js.map +0 -1
  245. package/dist/handlers/brain.js.map +0 -1
  246. package/dist/handlers/cache.js.map +0 -1
  247. package/dist/handlers/context.js.map +0 -1
  248. package/dist/handlers/fedbrain.js.map +0 -1
  249. package/dist/handlers/instances.js.map +0 -1
  250. package/dist/handlers/roadmap.js.map +0 -1
  251. package/dist/handlers/syndicate.js.map +0 -1
  252. package/dist/handlers/team.js.map +0 -1
  253. package/dist/index.js.map +0 -1
  254. package/dist/namespace.js.map +0 -1
  255. package/dist/search.js.map +0 -1
  256. package/dist/search.test.js.map +0 -1
  257. package/dist/tools.js.map +0 -1
  258. package/dist/utils.js.map +0 -1
  259. package/src/__tests__/brain-predict-failures.test.ts +0 -430
  260. /package/dist/{__tests__ → src/__tests__}/auth.test.d.ts +0 -0
  261. /package/dist/{__tests__ → src/__tests__}/auth.test.js +0 -0
  262. /package/dist/{__tests__ → src/__tests__}/brain-flow.test.d.ts +0 -0
  263. /package/dist/{__tests__ → src/__tests__}/confidence.test.d.ts +0 -0
  264. /package/dist/{__tests__ → src/__tests__}/confidence.test.js +0 -0
  265. /package/dist/{__tests__ → src/__tests__}/e2e/api-auth.test.d.ts +0 -0
  266. /package/dist/{__tests__ → src/__tests__}/e2e/api-auth.test.js +0 -0
  267. /package/dist/{__tests__ → src/__tests__}/e2e/api-health.test.d.ts +0 -0
  268. /package/dist/{__tests__ → src/__tests__}/e2e/api-health.test.js +0 -0
  269. /package/dist/{__tests__ → src/__tests__}/e2e/cli.test.d.ts +0 -0
  270. /package/dist/{__tests__ → src/__tests__}/e2e/cli.test.js +0 -0
  271. /package/dist/{__tests__ → src/__tests__}/e2e/config.d.ts +0 -0
  272. /package/dist/{__tests__ → src/__tests__}/e2e/config.js +0 -0
  273. /package/dist/{__tests__ → src/__tests__}/e2e/funnel.test.d.ts +0 -0
  274. /package/dist/{__tests__ → src/__tests__}/e2e/funnel.test.js +0 -0
  275. /package/dist/{__tests__ → src/__tests__}/e2e/mcp-tools.test.d.ts +0 -0
  276. /package/dist/{__tests__ → src/__tests__}/e2e/mcp-tools.test.js +0 -0
  277. /package/dist/{__tests__ → src/__tests__}/e2e/provisioning.test.d.ts +0 -0
  278. /package/dist/{__tests__ → src/__tests__}/e2e/provisioning.test.js +0 -0
  279. /package/dist/{__tests__ → src/__tests__}/handlers-unit.test.d.ts +0 -0
  280. /package/dist/{__tests__ → src/__tests__}/namespace.test.d.ts +0 -0
  281. /package/dist/{__tests__ → src/__tests__}/namespace.test.js +0 -0
  282. /package/dist/{auth.d.ts → src/auth.d.ts} +0 -0
  283. /package/dist/{auth.js → src/auth.js} +0 -0
  284. /package/dist/{ckg.d.ts → src/ckg.d.ts} +0 -0
  285. /package/dist/{ckg.js → src/ckg.js} +0 -0
  286. /package/dist/{confidence.d.ts → src/confidence.d.ts} +0 -0
  287. /package/dist/{confidence.js → src/confidence.js} +0 -0
  288. /package/dist/{embeddings.d.ts → src/embeddings.d.ts} +0 -0
  289. /package/dist/{embeddings.js → src/embeddings.js} +0 -0
  290. /package/dist/{handlers → src/handlers}/advanced.d.ts +0 -0
  291. /package/dist/{handlers → src/handlers}/advanced.js +0 -0
  292. /package/dist/{handlers → src/handlers}/brain.d.ts +0 -0
  293. /package/dist/{handlers → src/handlers}/cache.d.ts +0 -0
  294. /package/dist/{handlers → src/handlers}/cache.js +0 -0
  295. /package/dist/{handlers → src/handlers}/context.d.ts +0 -0
  296. /package/dist/{handlers → src/handlers}/instances.d.ts +0 -0
  297. /package/dist/{handlers → src/handlers}/instances.js +0 -0
  298. /package/dist/{handlers → src/handlers}/roadmap.d.ts +0 -0
  299. /package/dist/{handlers → src/handlers}/syndicate.d.ts +0 -0
  300. /package/dist/{handlers → src/handlers}/syndicate.js +0 -0
  301. /package/dist/{handlers → src/handlers}/team.d.ts +0 -0
  302. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  303. /package/dist/{namespace.d.ts → src/namespace.d.ts} +0 -0
  304. /package/dist/{namespace.js → src/namespace.js} +0 -0
  305. /package/dist/{search.d.ts → src/search.d.ts} +0 -0
  306. /package/dist/{search.test.d.ts → src/search.test.d.ts} +0 -0
  307. /package/dist/{search.test.js → src/search.test.js} +0 -0
  308. /package/dist/{utils.d.ts → src/utils.d.ts} +0 -0
  309. /package/dist/{utils.js → src/utils.js} +0 -0
@@ -12,15 +12,18 @@ import { computeEmbedding, hasEmbedProvider, embedProviderHint, EMBED_PROVIDER }
12
12
  import { detectNamespace } from '../namespace.js';
13
13
 
14
14
  // ── Changelog (shown once per version in session_start) ──────────────────────
15
- const MCP_VERSION = '0.10.0';
15
+ const MCP_VERSION = '0.10.49';
16
16
  const WHATS_NEW: Record<string, string[]> = {
17
- '0.10.0': [
17
+ '0.10.49': [
18
18
  `🆕 **What's new in v${MCP_VERSION}:**`,
19
- ` ✅ Zero-friction setup — auto-provisions your Brain, no manual config needed`,
20
- ` ✅ 10× faster briefings — batch Redis fetches replace per-key loops`,
21
- ` ✅ Crash-proof data reads — corrupted cache entries no longer break tools`,
22
- ` ✅ \`session_end\` warns when called without an active session`,
23
- ` ✅ \`get_api_status\` now shows live Redis ping + all instance statuses`,
19
+ ` ✅ \`brain_from_git\` — auto-seed your Brain from git history in seconds`,
20
+ ` ✅ \`brain_predict_failures\` — predict CI/build failures before they happen`,
21
+ ` ✅ \`smart_recall\` — semantic + keyword hybrid recall, now in every CLAUDE.md`,
22
+ ` ✅ VS Code extension — Brain status bar, ambient learning, CodeLens hints`,
23
+ ` ✅ Team Brain — share lessons across your whole engineering team`,
24
+ ` ✅ 89 MCP tools — roadmap, A/B tests, cache, index, predict, syndicate`,
25
+ ` 🔧 Stability — auto-expiring memory keys, longer provisioning wait, robust recall`,
26
+ ` 💡 Run \`brain_from_git\` to seed your Brain from existing commits instantly`,
24
27
  ],
25
28
  };
26
29
 
@@ -183,7 +186,7 @@ export async function handleBrainTool(
183
186
  const existing = await redis.get(depKey);
184
187
  const depTopics: string[] = safeJsonParse<string[]>(existing, []);
185
188
  if (!depTopics.includes(topic)) depTopics.push(topic);
186
- await redis.set(depKey, JSON.stringify(depTopics));
189
+ await redis.set(depKey, JSON.stringify(depTopics), 'EX', 90 * 86400);
187
190
  }
188
191
 
189
192
  const lessonObj = {
@@ -207,9 +210,11 @@ export async function handleBrainTool(
207
210
  };
208
211
  const lesson = JSON.stringify(lessonObj);
209
212
 
210
- // Always append to the history list (audit log)
213
+ // Always append to the history list (audit log); keep last 100 entries, 90-day TTL
211
214
  const listKey = `cachly:lessons:${topic}`;
212
215
  await redis.rpush(listKey, lesson);
216
+ await redis.ltrim(listKey, -100, -1);
217
+ await redis.expire(listKey, 90 * 86400);
213
218
 
214
219
  // Update best key for success/partial; for failure only update if no success exists
215
220
  if (outcome === 'success' || outcome === 'partial') {
@@ -417,8 +422,27 @@ export async function handleBrainTool(
417
422
  ? `📌 **You've looked this up 3 times.** Consider pinning it for instant access: add \`pinned: true\` via \`learn_from_attempts\` to always surface it first.`
418
423
  : '';
419
424
 
425
+ // ── Trust signal (today-safe consensus layer) ───────────────────────
426
+ // A lesson recalled many times — or confirmed by multiple distinct
427
+ // authors — has proven its value. Surface that as social proof.
428
+ const lessonAuthors = (lesson as { authors?: string[]; author?: string }).authors
429
+ ?? ((lesson as { author?: string }).author ? [(lesson as { author?: string }).author!] : []);
430
+ const distinctAuthors = [...new Set(lessonAuthors.filter(Boolean))];
431
+ const rc = updatedLesson.recall_count;
432
+ let trustBadge = '';
433
+ if (distinctAuthors.length >= 2 && rc >= 5) {
434
+ trustBadge = `🏆 **Battle-tested** — recalled ${rc}× · verified by ${distinctAuthors.length} developers. Trust this.`;
435
+ } else if (rc >= 10) {
436
+ trustBadge = `🏆 **Battle-tested** — recalled ${rc}×. This is one of your most-proven solutions.`;
437
+ } else if (distinctAuthors.length >= 2) {
438
+ trustBadge = `✅ **Team-verified** — confirmed by ${distinctAuthors.length} developers.`;
439
+ } else if (rc >= 5) {
440
+ trustBadge = `✅ **Proven** — recalled ${rc}× without contradiction.`;
441
+ }
442
+
420
443
  return [
421
444
  rememberWhen,
445
+ trustBadge,
422
446
  `${badge} **Best solution for \`${topic}\`** ${sevEmoji}${lesson.severity ? ` (${lesson.severity})` : ''} · recalled ${updatedLesson.recall_count}×`,
423
447
  ``,
424
448
  `**What worked:** ${lesson.what_worked}`,
@@ -483,6 +507,22 @@ export async function handleBrainTool(
483
507
  10,
484
508
  );
485
509
 
510
+ // Increment recall_count on matched lessons (fire-and-forget — same as recall_best_solution).
511
+ // This ensures the dashboard metric, Proven Laws, and trust badges reflect real smart_recall usage.
512
+ const lessonMatches = kwMatches.filter(m => m.key.startsWith('cachly:lesson:best:'));
513
+ for (const m of lessonMatches.slice(0, 5)) {
514
+ const existing = await redis.get(m.key).catch(() => null);
515
+ if (existing) {
516
+ const lesson = safeJsonParse(existing, null as null | { recall_count?: number; [k: string]: unknown });
517
+ if (lesson) {
518
+ const updated = { ...lesson, recall_count: (lesson.recall_count ?? 0) + 1, verified_at: new Date().toISOString() };
519
+ redis.set(m.key, JSON.stringify(updated)).catch(() => {});
520
+ const savedMins = (lesson.severity as string) === 'critical' ? 240 : (lesson.severity as string) === 'major' ? 60 : 30;
521
+ redis.incrbyfloat(`cachly:stats:time_saved_mins:${instance_id}`, savedMins).catch(() => {});
522
+ }
523
+ }
524
+ }
525
+
486
526
  const lines: string[] = [`🧠 **Smart Recall** for: _"${query}"_\n`];
487
527
 
488
528
  // Show sub-query info if multi-topic was detected
@@ -778,7 +818,7 @@ export async function handleBrainTool(
778
818
  lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
779
819
  lines.push('🤝 **Your team\'s AI brain has been briefing you.**');
780
820
  lines.push('');
781
- lines.push(`Your teammates have already solved problems you\'re about to hit:`);
821
+ lines.push(`Your teammates have already solved problems you're about to hit:`);
782
822
  lines.push('');
783
823
  for (const [teamAuthor, tls] of byAuthor) {
784
824
  lines.push(` 👤 **${teamAuthor}** fixed ${tls.length} thing${tls.length > 1 ? 's' : ''}:`);
@@ -897,6 +937,31 @@ export async function handleBrainTool(
897
937
  // Brain health
898
938
  lines.push(`📊 **Brain:** ${lessons.length} lessons · ${ctxCount} context entries`, '');
899
939
 
940
+ // ── 📌 Proven Laws — auto-crystallized lessons (quick win 3) ─────────────
941
+ // A lesson that has proven itself (recalled ≥ CRYSTALLIZE_RECALLS times) or
942
+ // was explicitly pinned becomes a "law" — surfaced at the top of every
943
+ // briefing so the most battle-tested knowledge is never buried. This is
944
+ // the today-safe version of swarm crystallization: enough confirmations
945
+ // auto-promote a lesson without any manual step.
946
+ {
947
+ type LessonPin = typeof lessons[0] & { pinned?: boolean };
948
+ const CRYSTALLIZE_RECALLS = 5;
949
+ const laws = (lessons as LessonPin[])
950
+ .filter(l => l.outcome === 'success' && (l.pinned === true || (l.recall_count ?? 0) >= CRYSTALLIZE_RECALLS))
951
+ .sort((a, b) => (b.recall_count ?? 0) - (a.recall_count ?? 0))
952
+ .slice(0, 5);
953
+ if (laws.length > 0) {
954
+ lines.push(`📌 **Proven Laws** (auto-crystallized — your most-trusted knowledge):`);
955
+ for (const l of laws) {
956
+ const sev = l.severity === 'critical' ? '🔴' : l.severity === 'major' ? '🟡' : '';
957
+ const rc = l.recall_count ?? 0;
958
+ const why = l.pinned === true ? 'pinned' : `recalled ${rc}×`;
959
+ lines.push(` 🏆${sev} \`${l.topic}\` _(${why})_ — ${l.what_worked.slice(0, 100)}`);
960
+ }
961
+ lines.push('');
962
+ }
963
+ }
964
+
900
965
  // ── Layer 7: MCM Domain Coverage Map ────────────────────────────────────
901
966
  if (lessons.length >= 3) {
902
967
  const domainMap = new Map<string, { total: number; success: number; critical: number }>();
@@ -996,8 +1061,14 @@ export async function handleBrainTool(
996
1061
  for (const l of topRecalled) {
997
1062
  const emoji = l.outcome === 'success' ? '✅' : l.outcome === 'partial' ? '⚠️' : '❌';
998
1063
  const sev = l.severity === 'critical' ? '🔴' : l.severity === 'major' ? '🟡' : '';
999
- const rct = l.recall_count && l.recall_count > 1 ? ` _(${l.recall_count}× recalled)_` : '';
1000
- lines.push(` ${emoji}${sev} \`${l.topic}\`${rct} — ${l.what_worked.slice(0, 100)}`);
1064
+ const rc = l.recall_count ?? 0;
1065
+ const la = (l as { authors?: string[]; author?: string }).authors
1066
+ ?? ((l as { author?: string }).author ? [(l as { author?: string }).author!] : []);
1067
+ const nAuthors = new Set(la.filter(Boolean)).size;
1068
+ const trust = (nAuthors >= 2 && rc >= 5) || rc >= 10 ? ' 🏆'
1069
+ : nAuthors >= 2 || rc >= 5 ? ' ✅' : '';
1070
+ const rct = rc > 1 ? ` _(${rc}× recalled)_` : '';
1071
+ lines.push(` ${emoji}${sev}${trust} \`${l.topic}\`${rct} — ${l.what_worked.slice(0, 100)}`);
1001
1072
  }
1002
1073
  lines.push('');
1003
1074
  }
@@ -1065,27 +1136,63 @@ export async function handleBrainTool(
1065
1136
  }
1066
1137
 
1067
1138
  // ── 🔮 Predictive Pre-Warning — intent-based danger detection ────────────
1068
- // Fires BEFORE work starts. If focus area has known failure patterns → warn loudly.
1069
- if (focusTerms.length > 0) {
1139
+ // Fires BEFORE work starts. Uses explicit focus when given; otherwise
1140
+ // derives the likely work area from the last session's changed files +
1141
+ // summary (you usually keep working where you left off). This makes the
1142
+ // warning fire even when the caller forgets to pass `focus`.
1143
+ {
1070
1144
  type LessonAny = typeof lessons[0] & { author?: string; tags?: string[] };
1071
- const dangerLessons = (lessons as LessonAny[]).filter(l => {
1072
- if (l.outcome === 'success') return false;
1073
- const topicCategory = l.topic.split(':')[0];
1074
- return focusTerms.some(term =>
1075
- l.topic.toLowerCase().includes(term) ||
1076
- topicCategory === term ||
1077
- (l.tags ?? []).some((t: string) => t.toLowerCase() === term),
1078
- );
1079
- });
1080
- if (dangerLessons.length >= 1) {
1081
- // Insert warning block right after the title line (index 1 = blank line after title)
1082
- const warning = [
1083
- `🚨 **PRE-WARNING** — Read this BEFORE starting:`,
1084
- ` Known pitfalls for **"${focus}"** (${dangerLessons.length} past failure${dangerLessons.length > 1 ? 's' : ''}):`,
1085
- ...dangerLessons.slice(0, 3).map(l => ` ❌ \`${l.topic}\` — ${(l.what_failed ?? l.what_worked).slice(0, 80)}`),
1086
- '',
1087
- ];
1088
- lines.splice(2, 0, ...warning); // after '🧠 **Session Briefing**' + empty line
1145
+
1146
+ // Common path noise / extensions to drop when deriving terms from files.
1147
+ const PATH_NOISE = new Set([
1148
+ 'src', 'lib', 'test', 'tests', 'dist', 'index', 'main', 'app',
1149
+ 'internal', 'pkg', 'cmd', 'node_modules', 'components', 'utils',
1150
+ 'ts', 'tsx', 'js', 'jsx', 'go', 'py', 'rs', 'java', 'json', 'yaml', 'yml',
1151
+ ]);
1152
+ const deriveTermsFromFiles = (files: string[]): string[] => {
1153
+ const terms = new Set<string>();
1154
+ for (const f of files) {
1155
+ for (const seg of f.toLowerCase().split(/[/\\._-]/)) {
1156
+ if (seg.length > 3 && !PATH_NOISE.has(seg)) terms.add(seg);
1157
+ }
1158
+ }
1159
+ return [...terms];
1160
+ };
1161
+
1162
+ let warnTerms = focusTerms;
1163
+ let warnLabel = focus;
1164
+ let derived = false;
1165
+ if (warnTerms.length === 0 && lastSession) {
1166
+ const fromFiles = deriveTermsFromFiles(lastSession.files_changed ?? []);
1167
+ const fromSummary = (lastSession.summary ?? '').toLowerCase()
1168
+ .replace(/[^a-z0-9\s:_-]/g, ' ').split(/\s+/).filter(t => t.length > 3 && !PATH_NOISE.has(t));
1169
+ warnTerms = [...new Set([...fromFiles, ...fromSummary])];
1170
+ warnLabel = 'where you left off last session';
1171
+ derived = true;
1172
+ }
1173
+
1174
+ if (warnTerms.length > 0) {
1175
+ const dangerLessons = (lessons as LessonAny[]).filter(l => {
1176
+ if (l.outcome === 'success') return false;
1177
+ const topicCategory = l.topic.split(':')[0];
1178
+ return warnTerms.some(term =>
1179
+ l.topic.toLowerCase().includes(term) ||
1180
+ topicCategory === term ||
1181
+ (l.tags ?? []).some((t: string) => t.toLowerCase() === term),
1182
+ );
1183
+ });
1184
+ if (dangerLessons.length >= 1) {
1185
+ const headline = derived
1186
+ ? ` You're likely to continue **${warnLabel}** — ${dangerLessons.length} known pitfall${dangerLessons.length > 1 ? 's' : ''} there:`
1187
+ : ` Known pitfalls for **"${warnLabel}"** (${dangerLessons.length} past failure${dangerLessons.length > 1 ? 's' : ''}):`;
1188
+ const warning = [
1189
+ `🚨 **PRE-WARNING** — Read this BEFORE starting:`,
1190
+ headline,
1191
+ ...dangerLessons.slice(0, 3).map(l => ` ❌ \`${l.topic}\` — ${(l.what_failed ?? l.what_worked).slice(0, 80)}`),
1192
+ '',
1193
+ ];
1194
+ lines.splice(2, 0, ...warning); // after '🧠 **Session Briefing**' + empty line
1195
+ }
1089
1196
  }
1090
1197
  }
1091
1198
 
@@ -64,13 +64,18 @@ export async function handleContextTool(
64
64
  if (ttl && ttl > 0) {
65
65
  body['expires_at'] = new Date(Date.now() + ttl * 1000).toISOString();
66
66
  }
67
- await fetch(`${vectorUrl}/entries`, {
67
+ const res = await fetch(`${vectorUrl}/entries`, {
68
68
  method: 'POST',
69
69
  headers: { 'Content-Type': 'application/json' },
70
70
  body: JSON.stringify(body),
71
- }).catch(() => undefined);
72
- } catch {
73
- // Embedding optional — continue silently
71
+ signal: AbortSignal.timeout(8000),
72
+ });
73
+ if (!res.ok) {
74
+ process.stderr.write(`[cachly] semantic index skipped (HTTP ${res.status}) — smart_recall on this context will be keyword-only\n`);
75
+ }
76
+ } catch (e) {
77
+ // Embedding is optional — keyword recall still works. Log so it's debuggable.
78
+ process.stderr.write(`[cachly] semantic index failed: ${e instanceof Error ? e.message : String(e)} — smart_recall on this context will be keyword-only\n`);
74
79
  }
75
80
  }
76
81
 
@@ -9,6 +9,9 @@ import { keywordSearch, tokenize } from '../search.js';
9
9
  import { safeJsonParse } from '../utils.js';
10
10
  import { computeEmbedding, hasEmbedProvider } from '../embeddings.js';
11
11
 
12
+ // Last brain_from_git category counts — set after each run so index.ts can include them in telemetry
13
+ export let _lastBrainFromGitCounts: { fixes: number; features: number; refactors: number; total: number } | null = null;
14
+
12
15
  // Git concurrency semaphore (for brain_from_git parallel workers)
13
16
  let _gitSemCount = 0;
14
17
  const _GIT_SEM_MAX = 10;
@@ -374,7 +377,7 @@ export async function handleFedbrainTool(
374
377
  lines.push(` status:'\${{ job.status }}',prev_status:'unknown',job:'\${{ github.job }}',`);
375
378
  lines.push(` context:'github-actions run \${{ github.run_number }}'}});`);
376
379
  lines.push(` r.request({hostname:'api.cachly.dev',path:'/api/v1/cls/ingest',method:'POST',`);
377
- lines.push(` headers:{'Content-Type':'application/json','Authorization':'Bearer \$CACHLY_JWT',`);
380
+ lines.push(` headers:{'Content-Type':'application/json','Authorization':'Bearer $CACHLY_JWT',`);
378
381
  lines.push(` 'Content-Length':d.length}},()=>{}).end(d);`);
379
382
  lines.push(` " 2>/dev/null || true`);
380
383
  lines.push(` env:`);
@@ -1012,11 +1015,16 @@ export async function handleFedbrainTool(
1012
1015
  // Only store if no existing lesson for this topic (avoid overwriting higher-confidence lessons)
1013
1016
  const existing = await redis.get(`cachly:lesson:best:${topic}`);
1014
1017
  if (!existing) {
1015
- await redis.set(`cachly:lesson:best:${topic}`, JSON.stringify(lessonObj));
1018
+ // Auto-inferred git lessons get a 90-day TTL — they self-refresh on the next
1019
+ // brain_from_git run, and shouldn't pin memory forever if the repo goes stale.
1020
+ await redis.set(`cachly:lesson:best:${topic}`, JSON.stringify(lessonObj), 'EX', 90 * 86400);
1016
1021
  await redis.rpush(`cachly:lessons:${topic}`, JSON.stringify(lessonObj));
1022
+ await redis.ltrim(`cachly:lessons:${topic}`, -100, -1);
1023
+ await redis.expire(`cachly:lessons:${topic}`, 90 * 86400);
1017
1024
  }
1018
1025
  await redis.rpush('cachly:lessons:brain_from_git:all', JSON.stringify({ topic, sha: commit.sha.slice(0, 8), subject: commit.subject.slice(0, 60) }));
1019
1026
  await redis.ltrim('cachly:lessons:brain_from_git:all', -500, -1);
1027
+ await redis.expire('cachly:lessons:brain_from_git:all', 90 * 86400);
1020
1028
 
1021
1029
  // Update CKG
1022
1030
  const conceptId = ckgSlug(topic);
@@ -1033,6 +1041,13 @@ export async function handleFedbrainTool(
1033
1041
 
1034
1042
  const categoryBreakdown = [...categoryCount.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => ` • **${k}** (${v})`).join('\n');
1035
1043
 
1044
+ _lastBrainFromGitCounts = {
1045
+ fixes: categoryCount.get('fix') ?? 0,
1046
+ features: categoryCount.get('feat') ?? 0,
1047
+ refactors: categoryCount.get('refactor') ?? 0,
1048
+ total: ingested,
1049
+ };
1050
+
1036
1051
  return [
1037
1052
  `🔁 **brain_from_git: ${repoDir}**`,
1038
1053
  isIncremental ? `🔄 Incremental mode — only new commits since \`${lastSha.slice(0, 8)}\` were processed` : '',
@@ -156,10 +156,13 @@ export async function handleRoadmapTool(
156
156
  }
157
157
  const PRIORITY_ORDER: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 };
158
158
  const PRIORITY_ICON: Record<string, string> = { critical: '🔴', high: '🟠', medium: '🟡', low: '🔵' };
159
- let items = Object.values(all)
160
- .map(v => JSON.parse(v as string) as Record<string, unknown>)
159
+ const items = Object.values(all)
160
+ .flatMap(v => {
161
+ const item = safeJsonParse<Record<string, unknown> | null>(v as string, null);
162
+ return item ? [item] : [];
163
+ })
161
164
  .filter(i => i.status === 'in-progress' || i.status === 'planned')
162
- .filter(i => !filterTag || (i.tags as string[]).includes(filterTag));
165
+ .filter(i => !filterTag || (Array.isArray(i.tags) ? i.tags : []).includes(filterTag));
163
166
  if (items.length === 0) return '🎉 **No open roadmap items!** All tasks are done (or use `roadmap_list` to check).';
164
167
  // in-progress first, then by priority
165
168
  items.sort((a, b) => {
@@ -169,7 +172,8 @@ export async function handleRoadmapTool(
169
172
  });
170
173
  const next = items[0];
171
174
  const remaining = items.length - 1;
172
- const tags = (next.tags as string[]).length ? `\nTags: ${(next.tags as string[]).join(', ')}` : '';
175
+ const nextTags = Array.isArray(next.tags) ? next.tags as string[] : [];
176
+ const tags = nextTags.length ? `\nTags: ${nextTags.join(', ')}` : '';
173
177
  const milestone = next.milestone ? `\nMilestone: ${next.milestone}` : '';
174
178
  const notes = next.notes ? `\nNotes: ${(next.notes as string).split('\n').pop()?.slice(0, 120)}` : '';
175
179
  return [