@cachly-dev/mcp-server 0.10.92 β†’ 0.10.94

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/README.md CHANGED
@@ -22,7 +22,7 @@
22
22
  <img src="https://img.shields.io/badge/GDPR-EU%20servers-green" alt="GDPR: EU servers" />
23
23
  </a>
24
24
  &nbsp;
25
- <img src="https://img.shields.io/badge/114%20MCP%20tools-violet" alt="114 MCP tools" />
25
+ <img src="https://img.shields.io/badge/116%20MCP%20tools-violet" alt="116 MCP tools" />
26
26
  &nbsp;
27
27
  <img src="https://img.shields.io/badge/License-Apache--2.0-yellow" alt="License: Apache-2.0" />
28
28
  </p>
@@ -190,6 +190,7 @@ close without breaking its own lock-in. **That gap is where cachly wins.**
190
190
  | **`brain_who_knows`** | *"Who on my team knows about Kubernetes deploys?"* β†’ ranked experts πŸ₯‡πŸ₯ˆπŸ₯‰, built automatically from authorship. |
191
191
  | **`brain_file_map`** | Before you touch a file: who's worked on it and which lessons reference it. |
192
192
  | **`team_expertise_map`** | The whole team's skills matrix in one table β€” onboarding and bus-factor insurance. |
193
+ | **`brain_collab_pairs`** | Person↔Person Collaboration Graph β€” *"Frag X und Y, die haben das zusammen gelΓΆst."* Bus-factor alerts included. |
193
194
  | **`brain_from_git`** | Reads your entire git history and populates the team knowledge graph (people + files + lessons) β€” zero setup, retroactively. |
194
195
  | **`brain_coverage` / `skill_gaps`** | A 0–100 health score for your knowledge + a ranked list of blind spots to fix. |
195
196
  | **`brain_predict`** | Predicts likely failures *before* they happen, from past incident patterns. |
@@ -244,7 +245,7 @@ npx @cachly-dev/mcp-server@latest learn-git # Auto-learn lessons from recent git
244
245
 
245
246
  ---
246
247
 
247
- ## MCP Tools (114 total)
248
+ ## MCP Tools (116 total)
248
249
 
249
250
  ### 🧠 Session & Memory (most used)
250
251
 
@@ -267,6 +268,7 @@ npx @cachly-dev/mcp-server@latest learn-git # Auto-learn lessons from recent git
267
268
  | **`brain_who_knows`** | Find your team's experts on any topic β€” ranked πŸ₯‡πŸ₯ˆπŸ₯‰ |
268
269
  | **`brain_file_map`** | Experts + lessons per file, before you touch it |
269
270
  | **`team_expertise_map`** | Full team skills matrix in one table |
271
+ | **`brain_collab_pairs`** | Person↔Person Collaboration Graph β€” who collaborates with whom, bus-factor alerts |
270
272
  | **`skill_gaps`** | Knowledge blind spots: unresolved failures, missing attribution |
271
273
  | **`brain_coverage`** | 0–100 knowledge-health score for your codebase |
272
274
  | `madc_deliberate` | Specialist AI agents vote to resolve contradictory lessons |
@@ -7,28 +7,41 @@ import { keywordSearch, tokenize, splitMultiQuery, levenshtein, indexVocab as _i
7
7
  import { rerankByQuality } from '../rerank.js';
8
8
  import { computeEmbedding, hasEmbedProvider } from '../embeddings.js';
9
9
  // ── Changelog (shown once per version in session_start) ──────────────────────
10
- const MCP_VERSION = '0.10.92';
10
+ const MCP_VERSION = '0.10.94';
11
11
  const WHATS_NEW = {
12
+ '0.10.94': [
13
+ `🀝 **Person↔Person Collaboration Graph (W5) β€” "Frag X und Y, die haben das zusammen gelΓΆst"**`,
14
+ ` πŸ•ΈοΈ New \`brain_collab_pairs()\` tool: shows every contributor pair who've touched the same files or recalled each other's lessons β€” ideal for onboarding and bus-factor analysis`,
15
+ ` πŸ“‘ \`smart_recall\` now wires CKG \`collaborates\` edges live when cross-author reuse fires β€” collaboration graph grows with every team recall`,
16
+ ` ⚠️ Bus-factor section: flags solo contributors whose knowledge no teammate has yet recalled`,
17
+ ` πŸ“Š 116 MCP tools (new: \`brain_collab_pairs\`)`,
18
+ ],
19
+ '0.10.93': [
20
+ `πŸ—ΊοΈ **\`brain_plan\` β€” your Brain goes from "what did we learn?" to "what should I do?"**`,
21
+ ` 🧭 Give it a task you're about to start ("upgrade Postgres 14β†’16") and it returns an ordered, grounded action plan: ranked failure modes to avoid, proven fix steps (dependency-aware, with commands), and a pre-flight checklist β€” all from your own lessons`,
22
+ ` πŸ”¬ Generative layer on the CKG: where \`brain_predict\` answers "what might fail?", \`brain_plan\` answers "what, in what order?"`,
23
+ ` πŸ“Š 115 MCP tools (new: \`brain_plan\`)`,
24
+ ],
12
25
  '0.10.92': [
13
26
  `πŸ‘‹ **Welcome-back digest β€” re-entry after a week away now leads with what changed**`,
14
27
  ` 🌱 \`session_start\` detects a gap β‰₯ 7 days and surfaces how many lessons your Brain gained while you were gone (git, CI & teammates kept it learning), with the freshest topics`,
15
28
  ` 🧠 Zero extra latency β€” the digest is computed from data session_start already loads`,
16
29
  ` πŸ”Œ New gRPC \`Learn\` RPC (M2M write path) β€” agents & CI can now teach the Brain directly, byte-compatible with the MCP lesson format`,
17
- ` πŸ“Š 114 MCP tools`,
30
+ ` πŸ“Š 115 MCP tools`,
18
31
  ],
19
32
  '0.10.91': [
20
33
  `πŸ• **Lesson-anchored time attribution β€” every recall shows when it was learned and how much it saves**`,
21
34
  ` πŸ’‘ "Brain saved you" banner now includes: when the lesson was learned (e.g. "12 May"), estimated original debug cost by severity (critical=2h, major=1h, minor=20min), and team attribution when a teammate's lesson fires`,
22
35
  ` πŸ“… Origin date formatted as "12 May" (same year) or "12 May 2024" (different year) β€” no clutter`,
23
36
  ` πŸ‘₯ Cross-author recalls now show "@author" on the same banner line β€” the "team knowledge reuse" value is front-and-center`,
24
- ` πŸ“Š 114 MCP tools`,
37
+ ` πŸ“Š 115 MCP tools`,
25
38
  ],
26
39
  '0.10.90': [
27
40
  `πŸ“Š **External benchmark corpus v2 β€” the proof is now statistically solid**`,
28
41
  ` πŸ§ͺ Expanded from 8 queries β†’ 61 lessons / 56 queries across 10 real-world engineering domains (k8s, DB, auth, CI, frontend, API, payments, observability, network, Node.js, security, infra)`,
29
42
  ` βš”οΈ 10 adversarial distractors added β€” failure lessons that share the exact same vocabulary as the query, forcing the quality reranker to earn its lift`,
30
43
  ` πŸ“ˆ Results on the larger corpus: cachly +2.9% Precision@1 vs flat-file, +12.5% vs raw BM25 baseline β€” on a harder dataset, not an easy one`,
31
- ` πŸ“Š 114 MCP tools`,
44
+ ` πŸ“Š 115 MCP tools`,
32
45
  ],
33
46
  '0.10.89': [
34
47
  `⚑ **One-command onboarding β€” \`autopilot\` is now the single canonical setup**`,
@@ -36,14 +49,14 @@ const WHATS_NEW = {
36
49
  ` 🧹 Retired the split-brain instructions (legacy \`@cachly-dev/init\` wrapper + the old "three steps") so there's exactly one thing to copy-paste`,
37
50
  ` πŸ”§ Fixed a build-breaking duplicate \`export\` on buildClaudeMdBlock that failed CI on v0.10.88`,
38
51
  ` πŸ”’ Version hygiene β€” package.json, server.json, lockfile and MCP_VERSION resynced (server.json/lockfile were stuck at 0.10.85)`,
39
- ` πŸ“Š 114 MCP tools`,
52
+ ` πŸ“Š 115 MCP tools`,
40
53
  ],
41
54
  '0.10.88': [
42
55
  `βœ… **Honest setup + tested config writer (v0.10.88)**`,
43
56
  ` πŸ”’ setup/autopilot now report the truth: if no editor config could be written it exits non-zero with the exact failures instead of falsely claiming "Brain is ready"`,
44
57
  ` πŸ“Š New setup_config_write_failed telemetry β€” permission/path failures that block activation are now visible in reporting`,
45
58
  ` πŸ§ͺ 24 new unit tests for the config writer (buildServerEnv, buildMcpConfig, mergeMcpConfig, buildClaudeMdBlock) β€” the merge logic that must never clobber your other MCP servers is now regression-guarded`,
46
- ` πŸ“Š 114 MCP tools`,
59
+ ` πŸ“Š 115 MCP tools`,
47
60
  ],
48
61
  '0.10.87': [
49
62
  `🌐 **Multi-editor auth persistence + full activation telemetry (v0.10.87)**`,
@@ -53,7 +66,7 @@ const WHATS_NEW = {
53
66
  ` πŸ“‘ \`brain_from_git_failed\` fires with error reason when auto-bootstrap throws β€” no more empty brain with no explanation`,
54
67
  ` ✨ Git bootstrap shows lesson count in session_start: "Brain bootstrapped β€” 23 lessons loaded" β€” the WOW moment`,
55
68
  ` πŸ”§ API: McpEvent stores brain quality metrics (fixes/features/refactors/total) β€” git learning quality now measurable`,
56
- ` πŸ“Š 114 MCP tools`,
69
+ ` πŸ“Š 115 MCP tools`,
57
70
  ],
58
71
  '0.10.86': [
59
72
  `πŸ›‘οΈ **Zero-friction activation β€” your Brain self-heals into existence**`,
@@ -61,7 +74,7 @@ const WHATS_NEW = {
61
74
  ` 🀝 Parallel tool calls on startup are coalesced into one resolve (no more duplicate-instance races)`,
62
75
  ` πŸ’¬ Clearer "instance still starting" message β€” leads with "just retry", no manual config needed`,
63
76
  ` πŸ“ˆ New activation-funnel telemetry: install β†’ sign-in β†’ provision, so silent churn is visible`,
64
- ` πŸ“Š 114 MCP tools`,
77
+ ` πŸ“Š 115 MCP tools`,
65
78
  ],
66
79
  '0.10.85': [
67
80
  `πŸš€ **One-command onboarding β€” \`npx @cachly-dev/mcp-server@latest autopilot\`**`,
@@ -72,7 +85,7 @@ const WHATS_NEW = {
72
85
  '0.10.84': [
73
86
  `πŸ€– **M2M & agent-ecosystem reach β€” cachly for every caller, human or machine**`,
74
87
  ` πŸ”‘ OAuth2 \`client_credentials\` grant β€” set CACHLY_CLIENT_ID + CACHLY_CLIENT_SECRET for fully headless auth (CI, agents, AI-to-AI)`,
75
- ` πŸ—‚οΈ \`npx ... tool-specs --format=openai|anthropic|langchain\` β€” export all 114 tools in any framework's dialect`,
88
+ ` πŸ—‚οΈ \`npx ... tool-specs --format=openai|anthropic|langchain\` β€” export all 116 tools in any framework's dialect`,
76
89
  ` 🌐 \`npx ... openapi\` β€” OpenAPI 3.1 doc (1 POST path per tool) for Assistants / codegen / Postman`,
77
90
  ` πŸ§ͺ 14 new tests: client_credentials helpers, all four spec dialects, OpenAPI required-body inference`,
78
91
  ],
@@ -83,7 +96,7 @@ const WHATS_NEW = {
83
96
  ` πŸ–₯️ Consumed verbatim by the 3D frontend (react-force-graph-3d / three.js) β€” the visual brain map`,
84
97
  ` πŸ”Ž Filters: \`domain\`, \`min_confidence\`, \`max_nodes\` (with truncation flag), \`format="summary"\``,
85
98
  ` πŸ§ͺ 10 tests: kind detection, dangling-edge pruning, confidence/domain filters, schema contract`,
86
- ` πŸ“Š 114 MCP tools`,
99
+ ` πŸ“Š 115 MCP tools`,
87
100
  ],
88
101
  '0.10.82': [
89
102
  `πŸ“‘ **Telemetry API contracts β€” dashboard ingest pipeline prepared**`,
@@ -767,6 +780,12 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
767
780
  crossAuthorThisCall++;
768
781
  redis.incr(`cachly:stats:cross_author_recalls:${instance_id}`).catch(() => { });
769
782
  redis.sadd(`cachly:stats:reuse_pairs:${instance_id}`, `${requester}<-${lesson.author}`).catch(() => { });
783
+ // W5: wire person↔person CKG collaborates edges from knowledge-reuse events.
784
+ // This feeds brain_collab_pairs and enriches brain_who_knows with reuse-based edges.
785
+ const reqPersonId = `person:${ckgSlug(requester)}`;
786
+ const authPersonId = `person:${ckgSlug(lesson.author)}`;
787
+ ckgUpdateEdge(redis, reqPersonId, 'collaborates', authPersonId, true).catch(() => { });
788
+ ckgUpdateEdge(redis, authPersonId, 'collaborates', reqPersonId, true).catch(() => { });
770
789
  }
771
790
  // Surface banner for proven successes (recall_count >= 1 means it's been validated)
772
791
  if (lesson.outcome === 'success' && (lesson.recall_count ?? 0) >= 1) {
@@ -2790,6 +2809,100 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2790
2809
  lines.push(`---`, `_Tag lessons with \`service="${service}"\` to keep this map current. For infra, pass \`service_kind="system"\`._`);
2791
2810
  return lines.join('\n');
2792
2811
  }
2812
+ // ── brain_collab_pairs ───────────────────────────────────────────────────
2813
+ // W5: Person↔Person Collaboration Graph. Shows who works with whom on the
2814
+ // team β€” built from (a) shared file-touches during learn_from_attempts and
2815
+ // (b) cross-author knowledge-reuse events from smart_recall. Answers the
2816
+ // onboarding question: "Frag X und Y β€” they solved that together."
2817
+ case 'brain_collab_pairs': {
2818
+ const { instance_id, min_weight = 1 } = args;
2819
+ const redis = await getConnection(instance_id);
2820
+ const minW = typeof min_weight === 'number' && min_weight >= 1 ? Math.floor(min_weight) : 1;
2821
+ // Collect all person nodes.
2822
+ const personKeys = await scanKeys(redis, 'cachly:ckg:node:person:*', { max: 500 });
2823
+ const persons = new Map();
2824
+ for (const k of personKeys) {
2825
+ const raw = await redis.get(k);
2826
+ if (!raw)
2827
+ continue;
2828
+ const pn = safeJsonParse(raw, null);
2829
+ if (!pn || pn.type !== 'person')
2830
+ continue;
2831
+ persons.set(pn.id, { id: pn.id, handle: pn.handle, domain: pn.domain, count: pn.count });
2832
+ }
2833
+ if (persons.size === 0) {
2834
+ return [
2835
+ `## 🀝 Team Collaboration Graph`,
2836
+ ``,
2837
+ `No contributors found yet.`,
2838
+ ``,
2839
+ `The graph builds automatically as teammates store lessons with \`author="name"\`:`,
2840
+ `\`learn_from_attempts(topic="...", author="alice", file_paths=["src/auth.ts"], ...)\``,
2841
+ ].join('\n');
2842
+ }
2843
+ const pairMap = new Map();
2844
+ for (const [personId, pInfo] of persons) {
2845
+ const edgeKeys = await redis.smembers(`cachly:ckg:idx:from:${personId}`);
2846
+ for (const ek of edgeKeys) {
2847
+ const er = await redis.get(ek);
2848
+ if (!er)
2849
+ continue;
2850
+ const edge = safeJsonParse(er, null);
2851
+ if (!edge || edge.edgeType !== 'collaborates')
2852
+ continue;
2853
+ const otherInfo = persons.get(edge.to);
2854
+ if (!otherInfo)
2855
+ continue;
2856
+ // Canonical pair key: alphabetically smaller id first.
2857
+ const [idA, idB] = personId < edge.to ? [personId, edge.to] : [edge.to, personId];
2858
+ const pairKey = `${idA}||${idB}`;
2859
+ const existing = pairMap.get(pairKey);
2860
+ if (existing) {
2861
+ existing.trials += edge.trials;
2862
+ }
2863
+ else {
2864
+ const [pA, pB] = personId < edge.to ? [pInfo, otherInfo] : [otherInfo, pInfo];
2865
+ pairMap.set(pairKey, { a: pA, b: pB, trials: edge.trials, confidence: edge.confidence });
2866
+ }
2867
+ }
2868
+ }
2869
+ const pairs = [...pairMap.values()]
2870
+ .filter(p => p.trials >= minW)
2871
+ .sort((a, b) => b.trials - a.trials);
2872
+ // Find solo contributors (no collaborators).
2873
+ const connectedIds = new Set();
2874
+ for (const p of pairs) {
2875
+ connectedIds.add(p.a.id);
2876
+ connectedIds.add(p.b.id);
2877
+ }
2878
+ const soloPersons = [...persons.values()].filter(p => !connectedIds.has(p.id));
2879
+ const lines = [
2880
+ `## 🀝 Team Collaboration Graph`,
2881
+ ``,
2882
+ ];
2883
+ if (pairs.length === 0) {
2884
+ lines.push(`No collaboration pairs yet (min weight: ${minW}).`, ``, `Pairs appear when two contributors touch the same file in \`learn_from_attempts\``, `or when someone recalls a teammate's lesson via \`smart_recall(requester="...")\`.`);
2885
+ }
2886
+ else {
2887
+ lines.push(`**${pairs.length} collaboration pair${pairs.length !== 1 ? 's' : ''}** across ${connectedIds.size} contributor${connectedIds.size !== 1 ? 's' : ''}:`, ``);
2888
+ for (const p of pairs.slice(0, 20)) {
2889
+ const conf = (p.confidence * 100).toFixed(0);
2890
+ const sharedDomains = [p.a.domain, p.b.domain]
2891
+ .filter((d, i, arr) => d && arr.indexOf(d) === i)
2892
+ .map(d => `\`${d}\``)
2893
+ .join(', ');
2894
+ lines.push(`### @${p.a.handle} ↔ @${p.b.handle}`, `- **${p.trials} collaboration event${p.trials !== 1 ? 's' : ''}** Β· ${conf}% confidence`, `- Domains: ${sharedDomains || '_unknown_'}`, `> πŸ’¬ _"Frag **@${p.a.handle}** und **@${p.b.handle}** β€” they've solved problems together in these areas."_`, ``);
2895
+ }
2896
+ if (pairs.length > 20) {
2897
+ lines.push(`_...and ${pairs.length - 20} more pairs. Use \`min_weight\` to filter._`, ``);
2898
+ }
2899
+ }
2900
+ if (soloPersons.length > 0) {
2901
+ lines.push(`---`, `### ⚠️ Bus Factor Alert β€” No Collaborators Yet`, ``, `${soloPersons.length} contributor${soloPersons.length !== 1 ? 's have' : ' has'} knowledge that no teammate has recalled or co-touched:`, ``, ...soloPersons.slice(0, 10).map(p => `- **@${p.handle}** β€” ${p.count} lesson${p.count !== 1 ? 's' : ''} Β· domain: \`${p.domain}\``), ``, `_Tip: pair these contributors with teammates on shared files to reduce bus factor._`);
2902
+ }
2903
+ lines.push(``, `---`, `_Collaboration edges build from \`learn_from_attempts(author=..., file_paths=[...])\` and \`smart_recall(requester=...)\` cross-author reuse._`);
2904
+ return lines.join('\n');
2905
+ }
2793
2906
  // ── sync_file_changes ─────────────────────────────────────────────────────
2794
2907
  default:
2795
2908
  return null;