@cachly-dev/mcp-server 0.10.6 โ 0.10.7
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/dist/__tests__/brain-predict-failures.test.d.ts +17 -0
- package/dist/__tests__/brain-predict-failures.test.js +339 -0
- package/dist/__tests__/brain-predict-failures.test.js.map +1 -0
- package/dist/handlers/fedbrain.js +38 -55
- package/dist/handlers/fedbrain.js.map +1 -1
- package/dist/handlers/roadmap.js +2 -8
- package/dist/handlers/roadmap.js.map +1 -1
- package/dist/handlers/syndicate.js +7 -15
- package/dist/handlers/syndicate.js.map +1 -1
- package/dist/handlers/team.js +50 -62
- package/dist/handlers/team.js.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +8 -0
- package/dist/tools.js +15 -5
- package/dist/tools.js.map +1 -1
- package/package.json +13 -29
- package/scripts/postinstall.js +19 -12
- package/server.json +9 -3
- package/smithery.yaml +8 -6
- package/src/__tests__/brain-predict-failures.test.ts +430 -0
- package/src/handlers/fedbrain.ts +31 -43
- package/src/handlers/roadmap.ts +2 -7
- package/src/handlers/syndicate.ts +7 -13
- package/src/handlers/team.ts +33 -57
- package/src/index.ts +27 -0
- package/src/tools.ts +16 -5
- package/.github/workflows/publish.yml +0 -45
- package/LAUNCH_TEXTS.md +0 -182
- package/LICENSE +0 -202
- package/dist/__tests__/auth.test.d.ts +0 -1
- package/dist/__tests__/auth.test.js +0 -107
- package/dist/__tests__/auth.test.js.map +0 -1
- package/glama.json +0 -29
- package/llms.txt +0 -155
- package/src/__tests__/auth.test.ts +0 -147
|
@@ -4,7 +4,6 @@ import { calculateConfidence } from '../confidence.js';
|
|
|
4
4
|
import { ckgSlug, ckgUpdateEdge } from '../ckg.js';
|
|
5
5
|
import type { CKGEdge, CKGNode } from '../ckg.js';
|
|
6
6
|
import { keywordSearch, tokenize } from '../search.js';
|
|
7
|
-
import { safeJsonParse } from '../utils.js';
|
|
8
7
|
|
|
9
8
|
type GetConnection = (instanceId: string) => Promise<Redis>;
|
|
10
9
|
type ApiFetch = <T>(path: string, options?: RequestInit) => Promise<T>;
|
|
@@ -293,8 +292,7 @@ export async function handleSyndicateTool(
|
|
|
293
292
|
for (const ek of [...fromKeys, ...toKeys].slice(0, 50)) {
|
|
294
293
|
const raw = await redis.get(ek);
|
|
295
294
|
if (!raw) continue;
|
|
296
|
-
const edge
|
|
297
|
-
if (!edge) continue;
|
|
295
|
+
const edge: CKGEdge = JSON.parse(raw);
|
|
298
296
|
allEdges.push(edge);
|
|
299
297
|
if (hop < max_hops) {
|
|
300
298
|
if (!visited.has(edge.from)) queue.push({ id: edge.from, hop: hop + 1 });
|
|
@@ -368,18 +366,16 @@ export async function handleSyndicateTool(
|
|
|
368
366
|
for (const nk of nodeKeys.slice(0, 5)) {
|
|
369
367
|
const nodeRaw = await redis.get(nk);
|
|
370
368
|
if (!nodeRaw) continue;
|
|
371
|
-
const node
|
|
372
|
-
if (!node) continue;
|
|
369
|
+
const node: CKGNode = JSON.parse(nodeRaw);
|
|
373
370
|
const edgeKeys = await redis.smembers(`cachly:ckg:idx:from:${node.id}`);
|
|
374
371
|
for (const ek of edgeKeys.slice(0, 20)) {
|
|
375
372
|
const edgeRaw = await redis.get(ek);
|
|
376
373
|
if (!edgeRaw) continue;
|
|
377
|
-
const edge
|
|
378
|
-
if (!edge) continue;
|
|
374
|
+
const edge: CKGEdge = JSON.parse(edgeRaw);
|
|
379
375
|
// Only interested in fixes and co-occurs for prediction
|
|
380
376
|
if (edge.edgeType !== 'fixes' && edge.edgeType !== 'co-occurs' && edge.edgeType !== 'causes') continue;
|
|
381
377
|
const lessonRaw = await redis.get(`cachly:lesson:best:${edge.from}`);
|
|
382
|
-
const lesson = lessonRaw ?
|
|
378
|
+
const lesson = lessonRaw ? JSON.parse(lessonRaw) : undefined;
|
|
383
379
|
predictions.push({ concept: node.id, edgeType: edge.edgeType, target: edge.to, confidence: edge.confidence, lesson });
|
|
384
380
|
}
|
|
385
381
|
}
|
|
@@ -393,17 +389,15 @@ export async function handleSyndicateTool(
|
|
|
393
389
|
for (const k of lessonKeys) {
|
|
394
390
|
const raw = await redis.get(k);
|
|
395
391
|
if (!raw) continue;
|
|
396
|
-
{
|
|
397
|
-
|
|
398
|
-
const l = safeJsonParse<PredLesson | null>(raw, null);
|
|
399
|
-
if (!l) continue;
|
|
392
|
+
try {
|
|
393
|
+
const l = JSON.parse(raw) as { topic: string; what_worked?: string; what_failed?: string; outcome: string; severity?: string; ts: string; verified_at?: string; recall_count?: number };
|
|
400
394
|
const haystack = [l.topic, l.what_failed ?? '', l.what_worked ?? ''].join(' ').toLowerCase();
|
|
401
395
|
const score = ctxTokens.reduce((s, t) => s + (haystack.includes(t) ? 1 : 0), 0);
|
|
402
396
|
if (score >= 1 && l.outcome !== 'failure') {
|
|
403
397
|
const conf = calculateConfidence(l);
|
|
404
398
|
textPredictions.push({ ...l, confidence: conf });
|
|
405
399
|
}
|
|
406
|
-
}
|
|
400
|
+
} catch { /* skip */ }
|
|
407
401
|
}
|
|
408
402
|
textPredictions.sort((a, b) => b.confidence - a.confidence);
|
|
409
403
|
|
package/src/handlers/team.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type { Redis } from 'ioredis';
|
|
|
5
5
|
import { calculateConfidence, confidenceBadge, CONFIDENCE_STALE_VALUE, CONFIDENCE_WARN_VALUE,
|
|
6
6
|
CONFIDENCE_WARN_DAYS, CONFIDENCE_STALE_DAYS, simpleHash } from '../confidence.js';
|
|
7
7
|
import type { Instance } from './brain.js';
|
|
8
|
-
import { safeJsonParse } from '../utils.js';
|
|
9
8
|
|
|
10
9
|
type GetConnection = (instanceId: string) => Promise<Redis>;
|
|
11
10
|
type ApiFetch = <T>(path: string, options?: RequestInit) => Promise<T>;
|
|
@@ -54,11 +53,10 @@ export async function handleTeamTool(
|
|
|
54
53
|
|
|
55
54
|
type Lesson = { topic: string; what_worked: string; outcome: string; file_paths?: string[] };
|
|
56
55
|
const relevant: string[] = [];
|
|
57
|
-
const
|
|
58
|
-
|
|
56
|
+
for (const k of lessonKeys) {
|
|
57
|
+
const raw = await redis.get(k);
|
|
59
58
|
if (!raw) continue;
|
|
60
|
-
const lesson =
|
|
61
|
-
if (!lesson) continue;
|
|
59
|
+
const lesson = JSON.parse(raw) as Lesson;
|
|
62
60
|
// Match by file_paths stored in lesson OR by topic keywords matching file name
|
|
63
61
|
const topicWords = lesson.topic.toLowerCase().split(/[:\-_]/);
|
|
64
62
|
const fileMatches = changed_files.some(f => {
|
|
@@ -148,12 +146,10 @@ export async function handleTeamTool(
|
|
|
148
146
|
author?: string; tags?: string[];
|
|
149
147
|
};
|
|
150
148
|
let lessons: TeamLesson[] = [];
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (l) lessons.push(l);
|
|
156
|
-
}
|
|
149
|
+
for (const k of lessonKeys) {
|
|
150
|
+
const raw = await redis.get(k);
|
|
151
|
+
if (!raw) continue;
|
|
152
|
+
try { lessons.push(JSON.parse(raw) as TeamLesson); } catch { /* skip */ }
|
|
157
153
|
}
|
|
158
154
|
|
|
159
155
|
// Filter
|
|
@@ -282,12 +278,10 @@ export async function handleTeamTool(
|
|
|
282
278
|
|
|
283
279
|
type RawLesson = { topic: string; outcome: string; what_worked: string; severity?: string; ts: string; auto_learned?: boolean };
|
|
284
280
|
const allLessons: RawLesson[] = [];
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (l) allLessons.push(l);
|
|
290
|
-
}
|
|
281
|
+
for (const k of allLessonKeys) {
|
|
282
|
+
const raw = await redis.get(k);
|
|
283
|
+
if (!raw) continue;
|
|
284
|
+
try { allLessons.push(JSON.parse(raw) as RawLesson); } catch { /* skip */ }
|
|
291
285
|
}
|
|
292
286
|
|
|
293
287
|
// Group lessons by top-level category
|
|
@@ -373,17 +367,18 @@ export async function handleTeamTool(
|
|
|
373
367
|
verified_at?: string; severity?: string; audit_trail?: unknown[];
|
|
374
368
|
};
|
|
375
369
|
const lessons: DrLesson[] = [];
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (l) lessons.push(l);
|
|
381
|
-
}
|
|
370
|
+
for (const k of lessonKeys) {
|
|
371
|
+
const raw = await redis.get(k);
|
|
372
|
+
if (!raw) continue;
|
|
373
|
+
try { lessons.push(JSON.parse(raw) as DrLesson); } catch { /* skip */ }
|
|
382
374
|
}
|
|
383
375
|
|
|
384
376
|
// Last session
|
|
385
377
|
const lastSessionRaw = await redis.get('cachly:session:last');
|
|
386
|
-
|
|
378
|
+
let lastSession: { ts: string; summary: string } | null = null;
|
|
379
|
+
if (lastSessionRaw) {
|
|
380
|
+
try { lastSession = JSON.parse(lastSessionRaw); } catch { /* ignore */ }
|
|
381
|
+
}
|
|
387
382
|
|
|
388
383
|
// Open failures
|
|
389
384
|
const openFailures = lessons.filter(l => l.outcome === 'failure' || l.outcome === 'partial');
|
|
@@ -514,24 +509,13 @@ export async function handleTeamTool(
|
|
|
514
509
|
issues.push(`๐ก ${unusedLessons.length} lessons never recalled โ verify topics match your workflow`);
|
|
515
510
|
}
|
|
516
511
|
|
|
517
|
-
const
|
|
518
|
-
const lines = [
|
|
519
|
-
`๐ฉบ **Brain Doctor**`,
|
|
520
|
-
`\`${divider}\``,
|
|
521
|
-
'',
|
|
522
|
-
'**๐ Health Checks**',
|
|
523
|
-
...checks.map(c => ' ' + c),
|
|
524
|
-
'',
|
|
525
|
-
];
|
|
512
|
+
const lines = ['๐ฉบ **Brain Doctor Report**', '', ...checks.map(c => ' ' + c), ''];
|
|
526
513
|
if (issues.length > 0) {
|
|
527
|
-
lines.push(
|
|
528
|
-
|
|
514
|
+
lines.push('**Issues to fix:**');
|
|
515
|
+
for (const i of issues) lines.push(' ' + i);
|
|
529
516
|
lines.push('');
|
|
530
|
-
lines.push(`_Fix the action items above, then re-run \`brain_doctor\` to verify._`);
|
|
531
517
|
} else {
|
|
532
|
-
lines.push('
|
|
533
|
-
lines.push('');
|
|
534
|
-
lines.push('_Keep the brain sharp: `session_start` โ work โ `learn_from_attempts` โ `session_end`_');
|
|
518
|
+
lines.push(' ๐ Brain looks healthy! Keep calling session_start/session_end.');
|
|
535
519
|
}
|
|
536
520
|
return lines.join('\n');
|
|
537
521
|
}
|
|
@@ -552,11 +536,7 @@ export async function handleTeamTool(
|
|
|
552
536
|
.filter((l): l is NonNullable<typeof l> => l !== null && new Date(l.ts).getTime() <= cutoff)
|
|
553
537
|
.sort((a, b) => new Date(a.ts).getTime() - new Date(b.ts).getTime());
|
|
554
538
|
|
|
555
|
-
if (before.length === 0) {
|
|
556
|
-
const first = safeJsonParse(all[0] ?? null, null as null | { ts?: string });
|
|
557
|
-
const earliest = first?.ts ? new Date(first.ts).toLocaleDateString('de-DE') : 'unknown';
|
|
558
|
-
return `๐ญ No entries for \`${topic}\` found before **${date}**. Earliest entry: ${earliest}.`;
|
|
559
|
-
}
|
|
539
|
+
if (before.length === 0) return `๐ญ No entries for \`${topic}\` found before **${date}**. Earliest entry: ${new Date(JSON.parse(all[0]).ts).toLocaleDateString('de-DE')}.`;
|
|
560
540
|
|
|
561
541
|
const lines = [
|
|
562
542
|
`๐บ **Brain Archaeology: \`${topic}\` before ${date}**`,
|
|
@@ -583,7 +563,7 @@ export async function handleTeamTool(
|
|
|
583
563
|
const raw = await redis.get(depKey);
|
|
584
564
|
if (!raw) return `๐ญ No lessons found that depend on \`${dependency}\`.\n\nAdd dependencies via: \`learn_from_attempts(..., depends_on=["${dependency}"])\``;
|
|
585
565
|
|
|
586
|
-
const topics: string[] =
|
|
566
|
+
const topics: string[] = JSON.parse(raw);
|
|
587
567
|
const lines = [
|
|
588
568
|
`๐ **Causal Chain: \`${dependency}\`** โ ${topics.length} dependent lesson${topics.length === 1 ? '' : 's'}`,
|
|
589
569
|
'',
|
|
@@ -592,8 +572,7 @@ export async function handleTeamTool(
|
|
|
592
572
|
for (const t of topics) {
|
|
593
573
|
const lessonRaw = await redis.get(`cachly:lesson:best:${t}`);
|
|
594
574
|
if (!lessonRaw) { lines.push(` โข \`${t}\` _(lesson deleted)_`); continue; }
|
|
595
|
-
const lesson =
|
|
596
|
-
if (!lesson) { lines.push(` โข \`${t}\` _(lesson corrupted)_`); continue; }
|
|
575
|
+
const lesson = JSON.parse(lessonRaw) as { outcome?: string; severity?: string; needs_review?: boolean };
|
|
597
576
|
const emoji = lesson.outcome === 'success' ? 'โ
' : lesson.outcome === 'partial' ? 'โ ๏ธ' : 'โ';
|
|
598
577
|
const reviewBadge = lesson.needs_review ? ' ๐ **needs_review**' : '';
|
|
599
578
|
lines.push(` ${emoji} \`${t}\` (${lesson.severity ?? 'major'})${reviewBadge}`);
|
|
@@ -635,8 +614,8 @@ export async function handleTeamTool(
|
|
|
635
614
|
// Preserve recall_count on update
|
|
636
615
|
const existing = await redis.get(key);
|
|
637
616
|
if (existing) {
|
|
638
|
-
const prev =
|
|
639
|
-
record.recall_count = prev
|
|
617
|
+
const prev = JSON.parse(existing) as { recall_count?: number };
|
|
618
|
+
record.recall_count = prev.recall_count ?? 0;
|
|
640
619
|
}
|
|
641
620
|
await redis.set(key, JSON.stringify(record));
|
|
642
621
|
return `๐ **Global lesson stored**: \`${topic}\`\n\n${lesson}\n\nRecallable from any project via \`global_recall(topic="${topic}")\`.`;
|
|
@@ -656,12 +635,10 @@ export async function handleTeamTool(
|
|
|
656
635
|
|
|
657
636
|
type GlobalLesson = { topic: string; lesson: string; severity?: string; ts: string; recall_count?: number };
|
|
658
637
|
let lessons: GlobalLesson[] = [];
|
|
659
|
-
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
if (l) lessons.push(l);
|
|
664
|
-
}
|
|
638
|
+
for (const k of keys) {
|
|
639
|
+
const raw = await redis.get(k);
|
|
640
|
+
if (!raw) continue;
|
|
641
|
+
try { lessons.push(JSON.parse(raw) as GlobalLesson); } catch { /* skip */ }
|
|
665
642
|
}
|
|
666
643
|
|
|
667
644
|
if (topic) {
|
|
@@ -678,8 +655,7 @@ export async function handleTeamTool(
|
|
|
678
655
|
const k = `cachly:global:lesson:${l.topic}`;
|
|
679
656
|
const raw = await redis.get(k);
|
|
680
657
|
if (raw) {
|
|
681
|
-
const rec =
|
|
682
|
-
if (!rec) continue;
|
|
658
|
+
const rec = JSON.parse(raw) as { recall_count?: number };
|
|
683
659
|
rec.recall_count = (rec.recall_count ?? 0) + 1;
|
|
684
660
|
await redis.set(k, JSON.stringify(rec));
|
|
685
661
|
}
|
package/src/index.ts
CHANGED
|
@@ -1274,6 +1274,33 @@ if (process.argv[2] === 'setup') {
|
|
|
1274
1274
|
console.log('โ โข A session summary for next time โ');
|
|
1275
1275
|
}
|
|
1276
1276
|
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
1277
|
+
|
|
1278
|
+
// โโ Step 6b: brain_predict preview (only if we have real lessons) โโโโโโโ
|
|
1279
|
+
if (lessons >= 5) {
|
|
1280
|
+
process.stdout.write('\nโณ Running predictive risk scan...');
|
|
1281
|
+
try {
|
|
1282
|
+
const predictResult = await handleTool('brain_predict', {
|
|
1283
|
+
instance_id: instance.id,
|
|
1284
|
+
context: 'starting a new development session',
|
|
1285
|
+
});
|
|
1286
|
+
const predictLines = predictResult
|
|
1287
|
+
.split('\n')
|
|
1288
|
+
.filter((l: string) => l.trim())
|
|
1289
|
+
.slice(0, 6);
|
|
1290
|
+
if (predictLines.length > 0) {
|
|
1291
|
+
console.log(' โ\n');
|
|
1292
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
1293
|
+
console.log('โ ๐ฎ Brain Risk Preview (brain_predict) โ');
|
|
1294
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค');
|
|
1295
|
+
for (const pl of predictLines) {
|
|
1296
|
+
console.log(`โ ${pl.slice(0, 51).padEnd(51)} โ`);
|
|
1297
|
+
}
|
|
1298
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
1299
|
+
} else {
|
|
1300
|
+
console.log(' (no risks found โ clean slate!)');
|
|
1301
|
+
}
|
|
1302
|
+
} catch { console.log(' (skipped)'); }
|
|
1303
|
+
}
|
|
1277
1304
|
} else {
|
|
1278
1305
|
console.log(' (skipped)');
|
|
1279
1306
|
}
|
package/src/tools.ts
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
// โโ Tools โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
4
4
|
|
|
5
5
|
const TOOLS = [
|
|
6
|
+
// โโ Auth / Onboarding โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
7
|
+
{
|
|
8
|
+
name: 'sign_in',
|
|
9
|
+
description:
|
|
10
|
+
'Sign in to cachly AI Brain. Call this FIRST if no CACHLY_JWT is configured. ' +
|
|
11
|
+
'Starts an OAuth 2.0 Device Flow: you visit a short URL in your browser, approve in one click, ' +
|
|
12
|
+
'and the brain is ready instantly โ no copy-paste, no dashboard required. ' +
|
|
13
|
+
'After sign-in, a free Brain instance is auto-provisioned if you don\'t have one yet. ' +
|
|
14
|
+
'Once authenticated, all 63 brain tools become available. ' +
|
|
15
|
+
'IMPORTANT: AI assistants should call this tool proactively at session start when CACHLY_JWT is not set.',
|
|
16
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
17
|
+
},
|
|
6
18
|
// โโ Instance Management โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
7
19
|
{
|
|
8
20
|
name: 'list_instances',
|
|
@@ -437,11 +449,10 @@ const TOOLS = [
|
|
|
437
449
|
{
|
|
438
450
|
name: 'get_api_status',
|
|
439
451
|
description:
|
|
440
|
-
'
|
|
441
|
-
'Returns
|
|
442
|
-
'
|
|
443
|
-
'
|
|
444
|
-
'Workflow: run get_api_status โ read the issue it flags โ fix it โ retry your tool.',
|
|
452
|
+
'Check the cachly API health and your authentication status. ' +
|
|
453
|
+
'Returns whether the JWT is valid, your user ID (sub claim), ' +
|
|
454
|
+
'token expiry, and the auth provider (keycloak). ' +
|
|
455
|
+
'Use this to debug connection issues or verify your CACHLY_JWT is correct.',
|
|
445
456
|
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
446
457
|
},
|
|
447
458
|
// โโ Thinking/Context Cache (for AI assistants) โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
publish:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- uses: actions/setup-node@v4
|
|
15
|
-
with:
|
|
16
|
-
node-version: '20'
|
|
17
|
-
registry-url: 'https://registry.npmjs.org'
|
|
18
|
-
|
|
19
|
-
- name: Install dependencies
|
|
20
|
-
run: npm install --ignore-scripts
|
|
21
|
-
|
|
22
|
-
- name: Test
|
|
23
|
-
run: npm test
|
|
24
|
-
|
|
25
|
-
- name: Build
|
|
26
|
-
run: npm run build
|
|
27
|
-
|
|
28
|
-
- name: Check if version is already published
|
|
29
|
-
id: version_check
|
|
30
|
-
run: |
|
|
31
|
-
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
32
|
-
echo "version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
|
33
|
-
if npm view "@cachly-dev/mcp-server@$PKG_VERSION" version &>/dev/null; then
|
|
34
|
-
echo "skip=true" >> $GITHUB_OUTPUT
|
|
35
|
-
echo "Version $PKG_VERSION already published โ skipping."
|
|
36
|
-
else
|
|
37
|
-
echo "skip=false" >> $GITHUB_OUTPUT
|
|
38
|
-
echo "Version $PKG_VERSION is new โ will publish."
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
- name: Publish
|
|
42
|
-
if: steps.version_check.outputs.skip == 'false'
|
|
43
|
-
run: npm publish --access public
|
|
44
|
-
env:
|
|
45
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/LAUNCH_TEXTS.md
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# Launch Texts โ cachly AI Brain
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## Product Hunt
|
|
6
|
-
|
|
7
|
-
### Tagline (60 chars max)
|
|
8
|
-
Persistent memory + causal AI for Claude, Cursor & Copilot
|
|
9
|
-
|
|
10
|
-
### Description (260 chars)
|
|
11
|
-
Your AI forgets everything between sessions. cachly fixes that permanently. One command sets it up: detects your editors, writes all configs, bootstraps lessons from your git history. Free forever. No credentials required.
|
|
12
|
-
|
|
13
|
-
### Full Description
|
|
14
|
-
|
|
15
|
-
**The problem:** Every morning you re-explain your architecture to your AI. Every bug gets re-researched. Every fix gets re-discovered. The average developer wastes 45 minutes/day on this.
|
|
16
|
-
|
|
17
|
-
**The fix:** `npx @cachly-dev/mcp-server@latest setup`
|
|
18
|
-
|
|
19
|
-
One command. It signs you in (one browser click), detects every editor you have (Claude Code, Cursor, Windsurf, VS Code, Copilot, Cline, Zed), writes the correct config for each, bootstraps your Brain from your git history, and installs a git hook that learns from every future commit automatically.
|
|
20
|
-
|
|
21
|
-
**What your AI gets:**
|
|
22
|
-
- A briefing at every session start: last session, open failures, relevant past fixes
|
|
23
|
-
- Causal root cause analysis: `causal_trace("auth breaks after restart")` โ Root cause โ Chain โ Exact fix from 3 months ago with the command that worked
|
|
24
|
-
- Failure prediction before it happens: `brain_predict` reads your history before every deploy
|
|
25
|
-
- A running "time saved" counter โ so you can see the ROI
|
|
26
|
-
|
|
27
|
-
**What makes it different from mem0, MemGPT, etc.:**
|
|
28
|
-
The `causal_trace` tool. No other memory system builds a Causal Knowledge Graph. Most systems store facts. cachly stores WHY things broke and HOW they were fixed โ with the full chain of cause and effect. 30 minutes of git blame in one call.
|
|
29
|
-
|
|
30
|
-
**Free forever:** 25 MB, German servers, GDPR-compliant, no credit card.
|
|
31
|
-
|
|
32
|
-
### First Comment (post immediately after launch)
|
|
33
|
-
Hey PH! ๐
|
|
34
|
-
|
|
35
|
-
I built cachly after watching my AI re-research the same deployment bug for the third time in a month. It had no memory. I did.
|
|
36
|
-
|
|
37
|
-
The thing I'm most proud of: `causal_trace`. You describe a problem in plain English, and it walks your Brain's Causal Knowledge Graph to find: the root cause, the intermediate failure chain, and the exact fix that worked last time โ including the date and the command. Nothing else does this.
|
|
38
|
-
|
|
39
|
-
5000+ developers are already using the npm package. Would love your feedback on what's missing.
|
|
40
|
-
|
|
41
|
-
**Commands to try after setup:**
|
|
42
|
-
- `causal_trace(problem="[your last bug]")` โ see if it already knows the answer
|
|
43
|
-
- `brain_predict(context="about to deploy")` โ what will go wrong?
|
|
44
|
-
- `brain_doctor` โ Brain health check
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Hacker News โ Show HN
|
|
49
|
-
|
|
50
|
-
**Title:**
|
|
51
|
-
Show HN: cachly โ causal memory for AI coding assistants (MCP server, free)
|
|
52
|
-
|
|
53
|
-
**Text:**
|
|
54
|
-
I built cachly after noticing that my AI re-researched the same bug three times in a month. The context window empties, the memory vanishes.
|
|
55
|
-
|
|
56
|
-
cachly is an MCP server that gives Claude Code, Cursor, Copilot, and Windsurf persistent memory with one command:
|
|
57
|
-
|
|
58
|
-
npx @cachly-dev/mcp-server@latest setup
|
|
59
|
-
|
|
60
|
-
It detects your editors, writes all the MCP configs, bootstraps from your git history, and installs a git hook that learns from every future commit. No credentials needed in any config file โ OAuth Device Flow handles auth inline on the first tool call.
|
|
61
|
-
|
|
62
|
-
The part I think is technically interesting: `causal_trace`. Instead of just storing facts like most memory systems, cachly builds a Causal Knowledge Graph โ typed edges: `fixes`, `requires`, `co-occurs`, `causes`, `contradicts`. When you describe a problem, it walks the graph to reconstruct the failure chain and surface the exact fix.
|
|
63
|
-
|
|
64
|
-
causal_trace(problem="auth breaks after restart")
|
|
65
|
-
โ Root: k8s:namespace-terminating
|
|
66
|
-
โ Via: keycloak:jwks-race
|
|
67
|
-
โ Fix: PollUntilContextTimeout 3min โ worked March 12
|
|
68
|
-
|
|
69
|
-
Sessions start and end automatically (no manual session_start/session_end). Everything runs in the background.
|
|
70
|
-
|
|
71
|
-
Free tier: 25 MB, German servers, GDPR. Apache-2.0.
|
|
72
|
-
|
|
73
|
-
GitHub: https://github.com/cachly-dev/cachly-mcp
|
|
74
|
-
npm: https://www.npmjs.com/package/@cachly-dev/mcp-server
|
|
75
|
-
|
|
76
|
-
Happy to answer questions about the architecture.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Reddit โ r/ClaudeAI
|
|
81
|
-
|
|
82
|
-
**Title:**
|
|
83
|
-
I built persistent memory for Claude Code โ no credentials, no config, one command
|
|
84
|
-
|
|
85
|
-
**Text:**
|
|
86
|
-
After the 10th time explaining my project architecture to Claude, I built cachly.
|
|
87
|
-
|
|
88
|
-
**What it does:**
|
|
89
|
-
Run `npx @cachly-dev/mcp-server@latest setup` once. It:
|
|
90
|
-
1. Signs you in with one browser click (no credentials in config)
|
|
91
|
-
2. Detects Claude Code, Cursor, Windsurf, VS Code, Cline โ writes all configs automatically
|
|
92
|
-
3. Bootstraps your Brain from your git history right away
|
|
93
|
-
4. Installs a git hook so every future commit feeds the brain automatically
|
|
94
|
-
|
|
95
|
-
From that point, your AI arrives pre-briefed every session. No `session_start` needed โ it's automatic.
|
|
96
|
-
|
|
97
|
-
**The feature I'm most excited about:**
|
|
98
|
-
`causal_trace("auth breaks after restart")` โ it doesn't just search for similar lessons, it walks a Causal Knowledge Graph to reconstruct the failure chain and return the exact fix you used before, with commands and file paths.
|
|
99
|
-
|
|
100
|
-
**Free forever** โ 25 MB, German servers, GDPR, no credit card.
|
|
101
|
-
|
|
102
|
-
GitHub: https://github.com/cachly-dev/cachly-mcp
|
|
103
|
-
|
|
104
|
-
Would love feedback from this community โ what memory features would you most want?
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## Reddit โ r/LocalLLaMA
|
|
109
|
-
|
|
110
|
-
**Title:**
|
|
111
|
-
MCP server that learns from your git history automatically โ causal memory for AI coding
|
|
112
|
-
|
|
113
|
-
**Text:**
|
|
114
|
-
Built this for the problem of AI context loss between sessions. Technical highlights:
|
|
115
|
-
|
|
116
|
-
- **Causal Knowledge Graph (CKG):** Typed edges (fixes, requires, co-occurs, causes, contradicts). `causal_trace` walks the graph instead of just doing text similarity.
|
|
117
|
-
- **Continuous Learning Stream:** git post-commit hook + GitHub Actions step. Every commit โ lessons extracted automatically. Zero `session_end` calls needed.
|
|
118
|
-
- **brain_predict:** Before deploys, reads your CKG for patterns that match past failures and returns probability-weighted warnings.
|
|
119
|
-
- **Memory Crystals:** Compresses 30-50 sessions into a dense snapshot injected at every session start.
|
|
120
|
-
- **11-language BM25+ search:** EN, DE, FR, ES, IT, PT, ZH, JA, KO, AR, HE โ cross-lingual retrieval (e.g. `smart_recall("deploy")` finds ใใใญใค, ้จ็ฝฒ, ๋ฐฐํฌ).
|
|
121
|
-
|
|
122
|
-
Works with any MCP host: Claude Code, Cursor, Windsurf, VS Code, Cline, Zed, Continue.dev.
|
|
123
|
-
|
|
124
|
-
Free tier: 25 MB. Apache-2.0. German servers.
|
|
125
|
-
|
|
126
|
-
GitHub: https://github.com/cachly-dev/cachly-mcp
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Twitter/X Thread
|
|
131
|
-
|
|
132
|
-
**Tweet 1:**
|
|
133
|
-
Your AI forgets everything between sessions.
|
|
134
|
-
I built the fix.
|
|
135
|
-
|
|
136
|
-
`npx @cachly-dev/mcp-server@latest setup`
|
|
137
|
-
|
|
138
|
-
One command โ persistent AI memory across Claude, Cursor, Copilot, Windsurf.
|
|
139
|
-
Free forever. ๐งต
|
|
140
|
-
|
|
141
|
-
**Tweet 2:**
|
|
142
|
-
The part that took the longest to build: `causal_trace`
|
|
143
|
-
|
|
144
|
-
You type: "auth breaks after restart"
|
|
145
|
-
|
|
146
|
-
It returns:
|
|
147
|
-
โ Root: k8s:namespace-terminating
|
|
148
|
-
โ Via: keycloak:jwks-race
|
|
149
|
-
โ Fix: PollUntilContextTimeout 3min โ you used this March 12, it worked
|
|
150
|
-
|
|
151
|
-
30 minutes of git blame. One call.
|
|
152
|
-
|
|
153
|
-
**Tweet 3:**
|
|
154
|
-
How setup works:
|
|
155
|
-
1. Run the command
|
|
156
|
-
2. Browser opens โ one click sign-in (no password)
|
|
157
|
-
3. It detects every editor you have
|
|
158
|
-
4. Writes MCP config for each automatically
|
|
159
|
-
5. Bootstraps Brain from your git history
|
|
160
|
-
6. Installs git hook for automatic future learning
|
|
161
|
-
|
|
162
|
-
Restart editor. Done.
|
|
163
|
-
|
|
164
|
-
**Tweet 4:**
|
|
165
|
-
What your AI sees every morning:
|
|
166
|
-
|
|
167
|
-
๐ง Session Briefing
|
|
168
|
-
โฑ๏ธ Brain saved you ~4h 30m total
|
|
169
|
-
โ
api:auth โ Bearer in header, not cookie
|
|
170
|
-
โ
docker:build โ ARG changes bust cache
|
|
171
|
-
โ ๏ธ k8s:deploy โ namespace terminating race condition
|
|
172
|
-
|
|
173
|
-
๐ค Your team has 3 new lessons since yesterday
|
|
174
|
-
|
|
175
|
-
**Tweet 5:**
|
|
176
|
-
Free tier: 25 MB, German servers, GDPR-compliant, no credit card.
|
|
177
|
-
Open source: Apache-2.0
|
|
178
|
-
|
|
179
|
-
GitHub: github.com/cachly-dev/cachly-mcp
|
|
180
|
-
npm: @cachly-dev/mcp-server
|
|
181
|
-
|
|
182
|
-
If this saves you time, a โญ means a lot.
|