@cachly-dev/mcp-server 0.10.48 → 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.
- package/.github/workflows/eas-build-android.yml +58 -0
- package/.github/workflows/eas-update.yml +55 -0
- package/README.md +5 -33
- package/STRATEGY.md +209 -0
- package/apps/travel-chaos-organizer/.env.example +49 -0
- package/apps/travel-chaos-organizer/DEPLOY.md +328 -0
- package/apps/travel-chaos-organizer/Makefile +57 -0
- package/apps/travel-chaos-organizer/README.md +159 -0
- package/apps/travel-chaos-organizer/backend/.env.example +10 -0
- package/apps/travel-chaos-organizer/backend/Dockerfile +25 -0
- package/apps/travel-chaos-organizer/backend/alembic/env.py +56 -0
- package/apps/travel-chaos-organizer/backend/alembic/script.py.mako +24 -0
- package/apps/travel-chaos-organizer/backend/alembic/versions/.gitkeep +0 -0
- package/apps/travel-chaos-organizer/backend/alembic/versions/0001_stripe_customer_id.py +24 -0
- package/apps/travel-chaos-organizer/backend/alembic/versions/0002_telegram_chat_id.py +24 -0
- package/apps/travel-chaos-organizer/backend/alembic.ini +39 -0
- package/apps/travel-chaos-organizer/backend/app/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/auth/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/auth/keycloak.py +81 -0
- package/apps/travel-chaos-organizer/backend/app/config.py +66 -0
- package/apps/travel-chaos-organizer/backend/app/db/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/db/database.py +20 -0
- package/apps/travel-chaos-organizer/backend/app/db/migrations/001_init.sql +71 -0
- package/apps/travel-chaos-organizer/backend/app/db/migrations/002_telemetry_freemium.sql +31 -0
- package/apps/travel-chaos-organizer/backend/app/db/migrations/003_telegram_chat_id.sql +4 -0
- package/apps/travel-chaos-organizer/backend/app/db/migrations/004_stripe_and_email.sql +5 -0
- package/apps/travel-chaos-organizer/backend/app/limiter.py +4 -0
- package/apps/travel-chaos-organizer/backend/app/logging_config.py +25 -0
- package/apps/travel-chaos-organizer/backend/app/main.py +77 -0
- package/apps/travel-chaos-organizer/backend/app/models/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/models/schemas.py +142 -0
- package/apps/travel-chaos-organizer/backend/app/routers/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/routers/admin.py +237 -0
- package/apps/travel-chaos-organizer/backend/app/routers/cache.py +13 -0
- package/apps/travel-chaos-organizer/backend/app/routers/events.py +29 -0
- package/apps/travel-chaos-organizer/backend/app/routers/export.py +122 -0
- package/apps/travel-chaos-organizer/backend/app/routers/inbox.py +122 -0
- package/apps/travel-chaos-organizer/backend/app/routers/items.py +130 -0
- package/apps/travel-chaos-organizer/backend/app/routers/mail.py +108 -0
- package/apps/travel-chaos-organizer/backend/app/routers/parse.py +303 -0
- package/apps/travel-chaos-organizer/backend/app/routers/payments.py +179 -0
- package/apps/travel-chaos-organizer/backend/app/routers/trips.py +134 -0
- package/apps/travel-chaos-organizer/backend/app/routers/users.py +169 -0
- package/apps/travel-chaos-organizer/backend/app/routers/waitlist.py +37 -0
- package/apps/travel-chaos-organizer/backend/app/services/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/app/services/cache.py +131 -0
- package/apps/travel-chaos-organizer/backend/app/services/drip.py +128 -0
- package/apps/travel-chaos-organizer/backend/app/services/email.py +61 -0
- package/apps/travel-chaos-organizer/backend/app/services/errors.py +44 -0
- package/apps/travel-chaos-organizer/backend/app/services/notifier.py +10 -0
- package/apps/travel-chaos-organizer/backend/app/services/ollama.py +101 -0
- package/apps/travel-chaos-organizer/backend/app/services/parser.py +22 -0
- package/apps/travel-chaos-organizer/backend/app/services/quota.py +85 -0
- package/apps/travel-chaos-organizer/backend/app/services/sentry.py +11 -0
- package/apps/travel-chaos-organizer/backend/app/services/telemetry.py +35 -0
- package/apps/travel-chaos-organizer/backend/pytest.ini +4 -0
- package/apps/travel-chaos-organizer/backend/requirements-dev.txt +6 -0
- package/apps/travel-chaos-organizer/backend/requirements.txt +25 -0
- package/apps/travel-chaos-organizer/backend/tests/__init__.py +0 -0
- package/apps/travel-chaos-organizer/backend/tests/conftest.py +223 -0
- package/apps/travel-chaos-organizer/backend/tests/test_admin.py +99 -0
- package/apps/travel-chaos-organizer/backend/tests/test_cache.py +142 -0
- package/apps/travel-chaos-organizer/backend/tests/test_drip.py +32 -0
- package/apps/travel-chaos-organizer/backend/tests/test_e2e_chain.py +121 -0
- package/apps/travel-chaos-organizer/backend/tests/test_export.py +48 -0
- package/apps/travel-chaos-organizer/backend/tests/test_inbox.py +107 -0
- package/apps/travel-chaos-organizer/backend/tests/test_items.py +138 -0
- package/apps/travel-chaos-organizer/backend/tests/test_mail.py +113 -0
- package/apps/travel-chaos-organizer/backend/tests/test_ollama.py +145 -0
- package/apps/travel-chaos-organizer/backend/tests/test_parse_url.py +98 -0
- package/apps/travel-chaos-organizer/backend/tests/test_parser.py +72 -0
- package/apps/travel-chaos-organizer/backend/tests/test_payments.py +163 -0
- package/apps/travel-chaos-organizer/backend/tests/test_quota.py +46 -0
- package/apps/travel-chaos-organizer/backend/tests/test_search.py +67 -0
- package/apps/travel-chaos-organizer/backend/tests/test_trips.py +123 -0
- package/apps/travel-chaos-organizer/backend/tests/test_users.py +52 -0
- package/apps/travel-chaos-organizer/backups/.gitkeep +0 -0
- package/apps/travel-chaos-organizer/caddy/Caddyfile +27 -0
- package/apps/travel-chaos-organizer/docker-compose.node1.yml +31 -0
- package/apps/travel-chaos-organizer/docker-compose.override.yml +14 -0
- package/apps/travel-chaos-organizer/docker-compose.yml +128 -0
- package/apps/travel-chaos-organizer/frontend/.env.example +13 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/_layout.tsx +80 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/inbox.tsx +166 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/search.tsx +130 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/settings.tsx +381 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/trips/[id].tsx +346 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/trips.tsx +363 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/cancel.tsx +34 -0
- package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/success.tsx +35 -0
- package/apps/travel-chaos-organizer/frontend/app/(auth)/login.tsx +91 -0
- package/apps/travel-chaos-organizer/frontend/app/_layout.tsx +71 -0
- package/apps/travel-chaos-organizer/frontend/app/auth.tsx +29 -0
- package/apps/travel-chaos-organizer/frontend/app/index.tsx +16 -0
- package/apps/travel-chaos-organizer/frontend/app/onboarding.tsx +119 -0
- package/apps/travel-chaos-organizer/frontend/app.config.ts +54 -0
- package/apps/travel-chaos-organizer/frontend/assets/adaptive-icon.svg +66 -0
- package/apps/travel-chaos-organizer/frontend/assets/icon.svg +79 -0
- package/apps/travel-chaos-organizer/frontend/assets/splash.svg +15 -0
- package/apps/travel-chaos-organizer/frontend/components/BottomSheet.tsx +102 -0
- package/apps/travel-chaos-organizer/frontend/components/ConfettiCannon.tsx +107 -0
- package/apps/travel-chaos-organizer/frontend/components/ConfirmDialog.tsx +109 -0
- package/apps/travel-chaos-organizer/frontend/components/ErrorBoundary.tsx +45 -0
- package/apps/travel-chaos-organizer/frontend/components/FileUploadButton.tsx +19 -0
- package/apps/travel-chaos-organizer/frontend/components/ImportSheet.tsx +155 -0
- package/apps/travel-chaos-organizer/frontend/components/OfflineBadge.tsx +55 -0
- package/apps/travel-chaos-organizer/frontend/components/QRCodeViewer.tsx +80 -0
- package/apps/travel-chaos-organizer/frontend/components/ScoreRing.tsx +39 -0
- package/apps/travel-chaos-organizer/frontend/components/Screen.tsx +39 -0
- package/apps/travel-chaos-organizer/frontend/components/Skeleton.tsx +70 -0
- package/apps/travel-chaos-organizer/frontend/components/SwipeableInboxItem.tsx +121 -0
- package/apps/travel-chaos-organizer/frontend/components/SwipeableTimelineItem.tsx +70 -0
- package/apps/travel-chaos-organizer/frontend/components/TimelineItem.tsx +73 -0
- package/apps/travel-chaos-organizer/frontend/components/TimelineItemDetail.tsx +130 -0
- package/apps/travel-chaos-organizer/frontend/components/Toast.tsx +60 -0
- package/apps/travel-chaos-organizer/frontend/components/ToastContext.tsx +42 -0
- package/apps/travel-chaos-organizer/frontend/components/TripCard.tsx +146 -0
- package/apps/travel-chaos-organizer/frontend/components/TripQRModal.tsx +70 -0
- package/apps/travel-chaos-organizer/frontend/components/UpgradeBanner.tsx +44 -0
- package/apps/travel-chaos-organizer/frontend/eas.json +22 -0
- package/apps/travel-chaos-organizer/frontend/hooks/useInbox.ts +24 -0
- package/apps/travel-chaos-organizer/frontend/hooks/useNetworkSync.ts +60 -0
- package/apps/travel-chaos-organizer/frontend/hooks/useTrips.ts +112 -0
- package/apps/travel-chaos-organizer/frontend/lib/api.ts +223 -0
- package/apps/travel-chaos-organizer/frontend/lib/auth.ts +93 -0
- package/apps/travel-chaos-organizer/frontend/lib/db.ts +86 -0
- package/apps/travel-chaos-organizer/frontend/lib/fileCache.ts +54 -0
- package/apps/travel-chaos-organizer/frontend/lib/haptics.ts +13 -0
- package/apps/travel-chaos-organizer/frontend/lib/notifications.ts +112 -0
- package/apps/travel-chaos-organizer/frontend/lib/offlineQueue.ts +145 -0
- package/apps/travel-chaos-organizer/frontend/lib/quota.tsx +43 -0
- package/apps/travel-chaos-organizer/frontend/lib/sentry.ts +28 -0
- package/apps/travel-chaos-organizer/frontend/lib/shareIntent.ts +44 -0
- package/apps/travel-chaos-organizer/frontend/package-lock.json +13037 -0
- package/apps/travel-chaos-organizer/frontend/package.json +44 -0
- package/apps/travel-chaos-organizer/frontend/tsconfig.json +23 -0
- package/apps/travel-chaos-organizer/keycloak/realm-export.json +59 -0
- package/apps/travel-chaos-organizer/landing/index.html +773 -0
- package/apps/travel-chaos-organizer/scripts/backup.sh +14 -0
- package/apps/travel-chaos-organizer/scripts/configure-env.sh +82 -0
- package/apps/travel-chaos-organizer/scripts/deploy.sh +54 -0
- package/apps/travel-chaos-organizer/scripts/health-check.sh +36 -0
- package/apps/travel-chaos-organizer/scripts/migrate.sh +7 -0
- package/apps/travel-chaos-organizer/scripts/server-setup.sh +85 -0
- package/apps/travel-chaos-organizer/scripts/smoke-test.sh +29 -0
- package/apps/travel-chaos-organizer/scripts/verify-tracking.sh +71 -0
- package/apps/travel-chaos-organizer/telegram-bot/.env.example +3 -0
- package/apps/travel-chaos-organizer/telegram-bot/Dockerfile +6 -0
- package/apps/travel-chaos-organizer/telegram-bot/bot.py +504 -0
- package/apps/travel-chaos-organizer/telegram-bot/requirements.txt +3 -0
- package/dist/packages/telegram-notify/client.d.ts +19 -0
- package/dist/packages/telegram-notify/client.js +75 -0
- package/dist/packages/telegram-notify/client.js.map +1 -0
- package/dist/src/__tests__/auth.test.js.map +1 -0
- package/dist/{__tests__ → src/__tests__}/brain-flow.test.js +141 -0
- package/dist/src/__tests__/brain-flow.test.js.map +1 -0
- package/dist/src/__tests__/confidence.test.js.map +1 -0
- package/dist/src/__tests__/e2e/api-auth.test.js.map +1 -0
- package/dist/src/__tests__/e2e/api-health.test.js.map +1 -0
- package/dist/src/__tests__/e2e/cli.test.js.map +1 -0
- package/dist/src/__tests__/e2e/config.js.map +1 -0
- package/dist/src/__tests__/e2e/funnel.test.js.map +1 -0
- package/dist/src/__tests__/e2e/mcp-tools.test.js.map +1 -0
- package/dist/src/__tests__/e2e/provisioning.test.js.map +1 -0
- package/dist/{__tests__ → src/__tests__}/handlers-unit.test.js +0 -2
- package/dist/src/__tests__/handlers-unit.test.js.map +1 -0
- package/dist/src/__tests__/namespace.test.js.map +1 -0
- package/dist/src/auth.js.map +1 -0
- package/dist/src/ckg.js.map +1 -0
- package/dist/src/confidence.js.map +1 -0
- package/dist/src/embeddings.js.map +1 -0
- package/dist/src/handlers/advanced.js.map +1 -0
- package/dist/{handlers → src/handlers}/brain.js +134 -30
- package/dist/src/handlers/brain.js.map +1 -0
- package/dist/src/handlers/cache.js.map +1 -0
- package/dist/{handlers → src/handlers}/context.js +9 -4
- package/dist/src/handlers/context.js.map +1 -0
- package/dist/{handlers → src/handlers}/fedbrain.d.ts +6 -0
- package/dist/{handlers → src/handlers}/fedbrain.js +19 -7
- package/dist/src/handlers/fedbrain.js.map +1 -0
- package/dist/src/handlers/instances.js.map +1 -0
- package/dist/{handlers → src/handlers}/roadmap.js +7 -3
- package/dist/src/handlers/roadmap.js.map +1 -0
- package/dist/src/handlers/syndicate.js.map +1 -0
- package/dist/src/handlers/tco.d.ts +16 -0
- package/dist/src/handlers/tco.js +303 -0
- package/dist/src/handlers/tco.js.map +1 -0
- package/dist/src/handlers/team.js.map +1 -0
- package/dist/{index.js → src/index.js} +153 -218
- package/dist/src/index.js.map +1 -0
- package/dist/src/namespace.js.map +1 -0
- package/dist/src/notifier.d.ts +5 -0
- package/dist/src/notifier.js +6 -0
- package/dist/src/notifier.js.map +1 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/search.test.js.map +1 -0
- package/dist/{tools.d.ts → src/tools.d.ts} +196 -0
- package/dist/{tools.js → src/tools.js} +178 -0
- package/dist/src/tools.js.map +1 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +3 -3
- package/packages/telegram-notify/SPLIT_PLAN.md +106 -0
- package/packages/telegram-notify/client.ts +88 -0
- package/packages/telegram-notify/emojis.json +22 -0
- package/packages/telegram-notify/pyproject.toml +17 -0
- package/packages/telegram-notify/telegram_notify/__init__.py +3 -0
- package/packages/telegram-notify/telegram_notify/client.py +87 -0
- package/packages/telegram-notify/telegram_notify/emojis.json +22 -0
- package/scripts/generate-icons.js +28 -0
- package/smithery.yaml +21 -8
- package/src/__tests__/brain-flow.test.ts +174 -0
- package/src/__tests__/handlers-unit.test.ts +1 -2
- package/src/handlers/brain.ts +138 -31
- package/src/handlers/context.ts +9 -4
- package/src/handlers/fedbrain.ts +21 -7
- package/src/handlers/roadmap.ts +7 -3
- package/src/handlers/tco.ts +347 -0
- package/src/index.ts +139 -220
- package/src/notifier.ts +5 -0
- package/src/tools.ts +191 -0
- package/tsconfig.json +2 -3
- package/dist/__tests__/auth.test.js.map +0 -1
- package/dist/__tests__/brain-flow.test.js.map +0 -1
- package/dist/__tests__/brain-predict-failures.test.d.ts +0 -17
- package/dist/__tests__/brain-predict-failures.test.js +0 -339
- package/dist/__tests__/brain-predict-failures.test.js.map +0 -1
- package/dist/__tests__/confidence.test.js.map +0 -1
- package/dist/__tests__/e2e/api-auth.test.js.map +0 -1
- package/dist/__tests__/e2e/api-health.test.js.map +0 -1
- package/dist/__tests__/e2e/cli.test.js.map +0 -1
- package/dist/__tests__/e2e/config.js.map +0 -1
- package/dist/__tests__/e2e/funnel.test.js.map +0 -1
- package/dist/__tests__/e2e/mcp-tools.test.js.map +0 -1
- package/dist/__tests__/e2e/provisioning.test.js.map +0 -1
- package/dist/__tests__/handlers-unit.test.js.map +0 -1
- package/dist/__tests__/namespace.test.js.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/ckg.js.map +0 -1
- package/dist/confidence.js.map +0 -1
- package/dist/embeddings.js.map +0 -1
- package/dist/handlers/advanced.js.map +0 -1
- package/dist/handlers/brain.js.map +0 -1
- package/dist/handlers/cache.js.map +0 -1
- package/dist/handlers/context.js.map +0 -1
- package/dist/handlers/fedbrain.js.map +0 -1
- package/dist/handlers/instances.js.map +0 -1
- package/dist/handlers/roadmap.js.map +0 -1
- package/dist/handlers/syndicate.js.map +0 -1
- package/dist/handlers/team.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/namespace.js.map +0 -1
- package/dist/search.js.map +0 -1
- package/dist/search.test.js.map +0 -1
- package/dist/tools.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/src/__tests__/brain-predict-failures.test.ts +0 -430
- /package/dist/{__tests__ → src/__tests__}/auth.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/auth.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/brain-flow.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/confidence.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/confidence.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/api-auth.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/api-auth.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/api-health.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/api-health.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/cli.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/cli.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/config.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/config.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/funnel.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/funnel.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/mcp-tools.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/mcp-tools.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/provisioning.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/e2e/provisioning.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/handlers-unit.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/namespace.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/namespace.test.js +0 -0
- /package/dist/{auth.d.ts → src/auth.d.ts} +0 -0
- /package/dist/{auth.js → src/auth.js} +0 -0
- /package/dist/{ckg.d.ts → src/ckg.d.ts} +0 -0
- /package/dist/{ckg.js → src/ckg.js} +0 -0
- /package/dist/{confidence.d.ts → src/confidence.d.ts} +0 -0
- /package/dist/{confidence.js → src/confidence.js} +0 -0
- /package/dist/{embeddings.d.ts → src/embeddings.d.ts} +0 -0
- /package/dist/{embeddings.js → src/embeddings.js} +0 -0
- /package/dist/{handlers → src/handlers}/advanced.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/advanced.js +0 -0
- /package/dist/{handlers → src/handlers}/brain.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/cache.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/cache.js +0 -0
- /package/dist/{handlers → src/handlers}/context.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/instances.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/instances.js +0 -0
- /package/dist/{handlers → src/handlers}/roadmap.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/syndicate.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/syndicate.js +0 -0
- /package/dist/{handlers → src/handlers}/team.d.ts +0 -0
- /package/dist/{handlers → src/handlers}/team.js +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{namespace.d.ts → src/namespace.d.ts} +0 -0
- /package/dist/{namespace.js → src/namespace.js} +0 -0
- /package/dist/{search.d.ts → src/search.d.ts} +0 -0
- /package/dist/{search.js → src/search.js} +0 -0
- /package/dist/{search.test.d.ts → src/search.test.d.ts} +0 -0
- /package/dist/{search.test.js → src/search.test.js} +0 -0
- /package/dist/{utils.d.ts → src/utils.d.ts} +0 -0
- /package/dist/{utils.js → src/utils.js} +0 -0
package/src/handlers/brain.ts
CHANGED
|
@@ -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.
|
|
15
|
+
const MCP_VERSION = '0.10.49';
|
|
16
16
|
const WHATS_NEW: Record<string, string[]> = {
|
|
17
|
-
'0.10.
|
|
17
|
+
'0.10.49': [
|
|
18
18
|
`🆕 **What's new in v${MCP_VERSION}:**`,
|
|
19
|
-
` ✅
|
|
20
|
-
` ✅
|
|
21
|
-
` ✅
|
|
22
|
-
` ✅
|
|
23
|
-
` ✅
|
|
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
|
|
@@ -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
|
|
1000
|
-
|
|
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.
|
|
1069
|
-
|
|
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
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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
|
|
package/src/handlers/context.ts
CHANGED
|
@@ -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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
package/src/handlers/fedbrain.ts
CHANGED
|
@@ -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;
|
|
@@ -363,8 +366,6 @@ export async function handleFedbrainTool(
|
|
|
363
366
|
|
|
364
367
|
if (hooksArr.includes('ci')) {
|
|
365
368
|
lines.push(`### GitHub Actions CI outcome hook`);
|
|
366
|
-
lines.push(`**Setup:** add a repo secret \`CACHLY_CACHE_TOKEN\` = your instance's cache token`);
|
|
367
|
-
lines.push(`(find it via \`get_connection_string\` — the token in the cache URL).`);
|
|
368
369
|
lines.push(`**Add at the end of each job** (after build/test steps):`);
|
|
369
370
|
lines.push('```yaml');
|
|
370
371
|
lines.push(`- name: cachly CLS — record CI outcome`);
|
|
@@ -372,14 +373,15 @@ export async function handleFedbrainTool(
|
|
|
372
373
|
lines.push(` run: |`);
|
|
373
374
|
lines.push(` node -e "`);
|
|
374
375
|
lines.push(` const r=require('https');`);
|
|
375
|
-
lines.push(` const d=JSON.stringify({source:'ci_outcome',payload:{`);
|
|
376
|
+
lines.push(` const d=JSON.stringify({instance_id:'${instance_id}',source:'ci_outcome',payload:{`);
|
|
376
377
|
lines.push(` status:'\${{ job.status }}',prev_status:'unknown',job:'\${{ github.job }}',`);
|
|
377
378
|
lines.push(` context:'github-actions run \${{ github.run_number }}'}});`);
|
|
378
|
-
lines.push(` r.request({hostname:'api.cachly.dev',path:'/v1/
|
|
379
|
-
lines.push(` headers:{'Content-Type':'application/json','
|
|
379
|
+
lines.push(` r.request({hostname:'api.cachly.dev',path:'/api/v1/cls/ingest',method:'POST',`);
|
|
380
|
+
lines.push(` headers:{'Content-Type':'application/json','Authorization':'Bearer $CACHLY_JWT',`);
|
|
381
|
+
lines.push(` 'Content-Length':d.length}},()=>{}).end(d);`);
|
|
380
382
|
lines.push(` " 2>/dev/null || true`);
|
|
381
383
|
lines.push(` env:`);
|
|
382
|
-
lines.push(`
|
|
384
|
+
lines.push(` CACHLY_JWT: \${{ secrets.CACHLY_JWT }}`);
|
|
383
385
|
lines.push('```');
|
|
384
386
|
lines.push('');
|
|
385
387
|
}
|
|
@@ -1013,11 +1015,16 @@ export async function handleFedbrainTool(
|
|
|
1013
1015
|
// Only store if no existing lesson for this topic (avoid overwriting higher-confidence lessons)
|
|
1014
1016
|
const existing = await redis.get(`cachly:lesson:best:${topic}`);
|
|
1015
1017
|
if (!existing) {
|
|
1016
|
-
|
|
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);
|
|
1017
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);
|
|
1018
1024
|
}
|
|
1019
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) }));
|
|
1020
1026
|
await redis.ltrim('cachly:lessons:brain_from_git:all', -500, -1);
|
|
1027
|
+
await redis.expire('cachly:lessons:brain_from_git:all', 90 * 86400);
|
|
1021
1028
|
|
|
1022
1029
|
// Update CKG
|
|
1023
1030
|
const conceptId = ckgSlug(topic);
|
|
@@ -1034,6 +1041,13 @@ export async function handleFedbrainTool(
|
|
|
1034
1041
|
|
|
1035
1042
|
const categoryBreakdown = [...categoryCount.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => ` • **${k}** (${v})`).join('\n');
|
|
1036
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
|
+
|
|
1037
1051
|
return [
|
|
1038
1052
|
`🔁 **brain_from_git: ${repoDir}**`,
|
|
1039
1053
|
isIncremental ? `🔄 Incremental mode — only new commits since \`${lastSha.slice(0, 8)}\` were processed` : '',
|
package/src/handlers/roadmap.ts
CHANGED
|
@@ -157,9 +157,12 @@ export async function handleRoadmapTool(
|
|
|
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
159
|
const items = Object.values(all)
|
|
160
|
-
.
|
|
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
|
|
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
|
|
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 [
|