@prajwolkc/stk 0.5.1 → 0.6.1
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/mcp/server.js +155 -1
- package/dist/services/brain.d.ts +13 -0
- package/dist/services/brain.js +87 -0
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -11,7 +11,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { loadConfig, enabledServices } from "../lib/config.js";
|
|
13
13
|
import { getChecker, allCheckerNames, loadPluginCheckers } from "../services/registry.js";
|
|
14
|
-
import { getLocalBrainClient, ingestProject, loadBrainStore, saveBrainStore, syncBrain, pushToCloud, pullFromCloud } from "../services/brain.js";
|
|
14
|
+
import { getLocalBrainClient, ingestProject, loadBrainStore, saveBrainStore, syncBrain, pushToCloud, pullFromCloud, brainCheck, brainDiagnose } from "../services/brain.js";
|
|
15
15
|
import { execSync } from "child_process";
|
|
16
16
|
const server = new McpServer({
|
|
17
17
|
name: "stk",
|
|
@@ -1163,6 +1163,83 @@ server.tool("stk_brain_stats", "Check what the brain knows — total knowledge e
|
|
|
1163
1163
|
};
|
|
1164
1164
|
});
|
|
1165
1165
|
// ──────────────────────────────────────────
|
|
1166
|
+
// Tool: stk_brain_check
|
|
1167
|
+
// ──────────────────────────────────────────
|
|
1168
|
+
server.tool("stk_brain_check", "PROACTIVE GOTCHA DETECTION — Run this BEFORE implementing any feature or fixing any bug. Searches the brain for known gotchas, pitfalls, and patterns related to your task. Returns warnings ranked by relevance so you can avoid repeating past mistakes. Claude should call this automatically before writing code.", {
|
|
1169
|
+
task: z.string().describe("What you're about to implement or fix (e.g., 'add email verification', 'update user model', 'fix auth redirect')"),
|
|
1170
|
+
}, async ({ task }) => {
|
|
1171
|
+
const results = brainCheck(task);
|
|
1172
|
+
if (results.length === 0) {
|
|
1173
|
+
return {
|
|
1174
|
+
content: [{
|
|
1175
|
+
type: "text",
|
|
1176
|
+
text: JSON.stringify({
|
|
1177
|
+
task,
|
|
1178
|
+
warnings: [],
|
|
1179
|
+
message: "No known gotchas found. Proceed with caution — this might be new territory.",
|
|
1180
|
+
}, null, 2),
|
|
1181
|
+
}],
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
const warnings = results.slice(0, 5).map(r => ({
|
|
1185
|
+
title: r.entry.title,
|
|
1186
|
+
content: r.entry.content,
|
|
1187
|
+
relevance: r.score,
|
|
1188
|
+
matchedTerms: r.matchedTerms,
|
|
1189
|
+
source: r.entry.source,
|
|
1190
|
+
category: r.entry.category,
|
|
1191
|
+
}));
|
|
1192
|
+
return {
|
|
1193
|
+
content: [{
|
|
1194
|
+
type: "text",
|
|
1195
|
+
text: JSON.stringify({
|
|
1196
|
+
task,
|
|
1197
|
+
warnings,
|
|
1198
|
+
totalMatches: results.length,
|
|
1199
|
+
message: `Found ${results.length} relevant pattern(s). Review warnings before coding.`,
|
|
1200
|
+
}, null, 2),
|
|
1201
|
+
}],
|
|
1202
|
+
};
|
|
1203
|
+
});
|
|
1204
|
+
// ──────────────────────────────────────────
|
|
1205
|
+
// Tool: stk_brain_diagnose
|
|
1206
|
+
// ──────────────────────────────────────────
|
|
1207
|
+
server.tool("stk_brain_diagnose", "ERROR PATTERN MATCHING — Run this when you encounter an error or bug. Searches the brain for matching patterns from past issues and returns known solutions. Claude should call this automatically when debugging.", {
|
|
1208
|
+
error: z.string().describe("The error message, symptom, or bug description (e.g., 'redirect not working after verification', 'emails not sending', 'prisma field undefined')"),
|
|
1209
|
+
}, async ({ error }) => {
|
|
1210
|
+
const results = brainDiagnose(error);
|
|
1211
|
+
if (results.length === 0) {
|
|
1212
|
+
return {
|
|
1213
|
+
content: [{
|
|
1214
|
+
type: "text",
|
|
1215
|
+
text: JSON.stringify({
|
|
1216
|
+
error,
|
|
1217
|
+
solutions: [],
|
|
1218
|
+
message: "No matching patterns found. This is a new issue — after fixing it, use stk_brain_learn to save the pattern.",
|
|
1219
|
+
}, null, 2),
|
|
1220
|
+
}],
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
const solutions = results.slice(0, 5).map(r => ({
|
|
1224
|
+
title: r.entry.title,
|
|
1225
|
+
solution: r.entry.content,
|
|
1226
|
+
relevance: r.score,
|
|
1227
|
+
matchedTerms: r.matchedTerms,
|
|
1228
|
+
source: r.entry.source,
|
|
1229
|
+
}));
|
|
1230
|
+
return {
|
|
1231
|
+
content: [{
|
|
1232
|
+
type: "text",
|
|
1233
|
+
text: JSON.stringify({
|
|
1234
|
+
error,
|
|
1235
|
+
solutions,
|
|
1236
|
+
totalMatches: results.length,
|
|
1237
|
+
message: `Found ${results.length} matching pattern(s). Apply relevant solutions.`,
|
|
1238
|
+
}, null, 2),
|
|
1239
|
+
}],
|
|
1240
|
+
};
|
|
1241
|
+
});
|
|
1242
|
+
// ──────────────────────────────────────────
|
|
1166
1243
|
// Tool: stk_brain_ingest
|
|
1167
1244
|
// ──────────────────────────────────────────
|
|
1168
1245
|
server.tool("stk_brain_ingest", "Scan the current project and ingest architecture knowledge into the local brain (~/.stk/brain.json). Automatically reads CLAUDE.md, package.json, Prisma schema, Dockerfile, CI config, and route files. Run this when setting up stk in a new project or after major changes.", {
|
|
@@ -1244,6 +1321,83 @@ server.tool("stk_brain_sync", "Sync brain knowledge between local (~/.stk/brain.
|
|
|
1244
1321
|
};
|
|
1245
1322
|
});
|
|
1246
1323
|
// ──────────────────────────────────────────
|
|
1324
|
+
// Tool: stk_brain_check (PROACTIVE — call before writing code)
|
|
1325
|
+
// ──────────────────────────────────────────
|
|
1326
|
+
server.tool("stk_brain_check", "PROACTIVE: Call this BEFORE implementing a feature or making changes. Searches the brain for known gotchas, past bugs, and patterns relevant to what you're about to build. Returns warnings that can prevent mistakes. Use this whenever you start a non-trivial coding task.", {
|
|
1327
|
+
task: z.string().describe("What you're about to implement (e.g., 'add email verification', 'update user model', 'add webhook endpoint')"),
|
|
1328
|
+
}, async ({ task }) => {
|
|
1329
|
+
const results = brainCheck(task);
|
|
1330
|
+
if (results.length === 0) {
|
|
1331
|
+
return {
|
|
1332
|
+
content: [{
|
|
1333
|
+
type: "text",
|
|
1334
|
+
text: JSON.stringify({
|
|
1335
|
+
task,
|
|
1336
|
+
warnings: [],
|
|
1337
|
+
message: "No known gotchas found. Proceed carefully.",
|
|
1338
|
+
}, null, 2),
|
|
1339
|
+
}],
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
const warnings = results.slice(0, 8).map(r => ({
|
|
1343
|
+
title: r.entry.title,
|
|
1344
|
+
warning: r.entry.content,
|
|
1345
|
+
relevance: r.score,
|
|
1346
|
+
matchedTerms: r.matchedTerms,
|
|
1347
|
+
source: r.entry.source,
|
|
1348
|
+
category: r.entry.category,
|
|
1349
|
+
}));
|
|
1350
|
+
return {
|
|
1351
|
+
content: [{
|
|
1352
|
+
type: "text",
|
|
1353
|
+
text: JSON.stringify({
|
|
1354
|
+
task,
|
|
1355
|
+
warnings,
|
|
1356
|
+
totalMatches: results.length,
|
|
1357
|
+
message: `Found ${results.length} relevant entries. Review warnings before coding.`,
|
|
1358
|
+
}, null, 2),
|
|
1359
|
+
}],
|
|
1360
|
+
};
|
|
1361
|
+
});
|
|
1362
|
+
// ──────────────────────────────────────────
|
|
1363
|
+
// Tool: stk_brain_diagnose (REACTIVE — call when you hit an error)
|
|
1364
|
+
// ──────────────────────────────────────────
|
|
1365
|
+
server.tool("stk_brain_diagnose", "REACTIVE: Call this when you encounter an error or bug. Searches the brain for matching patterns from past issues and returns known solutions. Use this before debugging from scratch — the answer may already be in the brain.", {
|
|
1366
|
+
error: z.string().describe("The error message, bug description, or unexpected behavior you're seeing"),
|
|
1367
|
+
}, async ({ error }) => {
|
|
1368
|
+
const results = brainDiagnose(error);
|
|
1369
|
+
if (results.length === 0) {
|
|
1370
|
+
return {
|
|
1371
|
+
content: [{
|
|
1372
|
+
type: "text",
|
|
1373
|
+
text: JSON.stringify({
|
|
1374
|
+
error,
|
|
1375
|
+
solutions: [],
|
|
1376
|
+
message: "No matching patterns found in the brain. This is a new issue — debug it, fix it, then use stk_brain_learn to save the solution.",
|
|
1377
|
+
}, null, 2),
|
|
1378
|
+
}],
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
const solutions = results.slice(0, 5).map(r => ({
|
|
1382
|
+
title: r.entry.title,
|
|
1383
|
+
solution: r.entry.content,
|
|
1384
|
+
relevance: r.score,
|
|
1385
|
+
matchedTerms: r.matchedTerms,
|
|
1386
|
+
source: r.entry.source,
|
|
1387
|
+
}));
|
|
1388
|
+
return {
|
|
1389
|
+
content: [{
|
|
1390
|
+
type: "text",
|
|
1391
|
+
text: JSON.stringify({
|
|
1392
|
+
error,
|
|
1393
|
+
solutions,
|
|
1394
|
+
totalMatches: results.length,
|
|
1395
|
+
message: `Found ${results.length} matching patterns. Apply the most relevant solution.`,
|
|
1396
|
+
}, null, 2),
|
|
1397
|
+
}],
|
|
1398
|
+
};
|
|
1399
|
+
});
|
|
1400
|
+
// ──────────────────────────────────────────
|
|
1247
1401
|
// Tool: stk_brain_claudemd
|
|
1248
1402
|
// ──────────────────────────────────────────
|
|
1249
1403
|
server.tool("stk_brain_claudemd", "Auto-generate a CLAUDE.md file for the current project. Analyzes the tech stack, project structure, services, and brain knowledge to create comprehensive project instructions for Claude Code.", {
|
package/dist/services/brain.d.ts
CHANGED
|
@@ -63,4 +63,17 @@ export declare function pushToCloud(): Promise<SyncResult>;
|
|
|
63
63
|
export declare function pullFromCloud(): Promise<SyncResult>;
|
|
64
64
|
/** Full sync: push local → cloud, then pull cloud → local */
|
|
65
65
|
export declare function syncBrain(): Promise<SyncResult>;
|
|
66
|
+
interface ScoredEntry {
|
|
67
|
+
entry: KnowledgeEntry;
|
|
68
|
+
score: number;
|
|
69
|
+
matchedTerms: string[];
|
|
70
|
+
}
|
|
71
|
+
/** Search brain with relevance scoring — returns entries ranked by how many terms match */
|
|
72
|
+
export declare function smartSearch(terms: string[], category?: string): ScoredEntry[];
|
|
73
|
+
/** Extract relevant terms from a task description */
|
|
74
|
+
export declare function extractTerms(description: string): string[];
|
|
75
|
+
/** Proactive check — find gotchas relevant to a task before coding */
|
|
76
|
+
export declare function brainCheck(taskDescription: string): ScoredEntry[];
|
|
77
|
+
/** Diagnose an error — find matching patterns from past issues */
|
|
78
|
+
export declare function brainDiagnose(error: string): ScoredEntry[];
|
|
66
79
|
export {};
|
package/dist/services/brain.js
CHANGED
|
@@ -524,3 +524,90 @@ export async function syncBrain() {
|
|
|
524
524
|
errors: [...pushResult.errors, ...pullResult.errors],
|
|
525
525
|
};
|
|
526
526
|
}
|
|
527
|
+
/** Search brain with relevance scoring — returns entries ranked by how many terms match */
|
|
528
|
+
export function smartSearch(terms, category) {
|
|
529
|
+
const store = loadBrainStore();
|
|
530
|
+
let entries = getAllEntries(store);
|
|
531
|
+
if (category) {
|
|
532
|
+
entries = entries.filter(e => e.category === category);
|
|
533
|
+
}
|
|
534
|
+
const normalizedTerms = terms.map(t => t.toLowerCase());
|
|
535
|
+
const scored = [];
|
|
536
|
+
for (const entry of entries) {
|
|
537
|
+
const searchText = `${entry.title} ${entry.content} ${entry.tags.join(" ")}`.toLowerCase();
|
|
538
|
+
const matchedTerms = [];
|
|
539
|
+
let score = 0;
|
|
540
|
+
for (const term of normalizedTerms) {
|
|
541
|
+
if (searchText.includes(term)) {
|
|
542
|
+
matchedTerms.push(term);
|
|
543
|
+
// Title match scores higher
|
|
544
|
+
if (entry.title.toLowerCase().includes(term))
|
|
545
|
+
score += 3;
|
|
546
|
+
// Tag match scores high
|
|
547
|
+
else if (entry.tags.some(t => t.toLowerCase().includes(term)))
|
|
548
|
+
score += 2;
|
|
549
|
+
// Content match
|
|
550
|
+
else
|
|
551
|
+
score += 1;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
// Boost gotcha/debugging entries
|
|
555
|
+
if (entry.tags.some(t => ["gotcha", "debugging", "bug", "fix", "issue"].includes(t))) {
|
|
556
|
+
score *= 1.5;
|
|
557
|
+
}
|
|
558
|
+
if (score > 0) {
|
|
559
|
+
scored.push({ entry, score, matchedTerms });
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return scored.sort((a, b) => b.score - a.score);
|
|
563
|
+
}
|
|
564
|
+
/** Extract relevant terms from a task description */
|
|
565
|
+
export function extractTerms(description) {
|
|
566
|
+
const stopWords = new Set([
|
|
567
|
+
"a", "an", "the", "is", "are", "was", "were", "be", "been", "being",
|
|
568
|
+
"have", "has", "had", "do", "does", "did", "will", "would", "could",
|
|
569
|
+
"should", "may", "might", "shall", "can", "need", "must", "to", "of",
|
|
570
|
+
"in", "for", "on", "with", "at", "by", "from", "as", "into", "about",
|
|
571
|
+
"like", "through", "after", "before", "between", "under", "above",
|
|
572
|
+
"and", "but", "or", "not", "no", "so", "if", "then", "than", "too",
|
|
573
|
+
"very", "just", "also", "how", "what", "when", "where", "why", "which",
|
|
574
|
+
"that", "this", "these", "those", "it", "its", "i", "we", "you", "they",
|
|
575
|
+
"me", "us", "my", "our", "your", "add", "implement", "create", "build",
|
|
576
|
+
"make", "want", "get", "set", "use", "new", "update", "change",
|
|
577
|
+
]);
|
|
578
|
+
const words = description.toLowerCase()
|
|
579
|
+
.replace(/[^a-z0-9\s-]/g, " ")
|
|
580
|
+
.split(/\s+/)
|
|
581
|
+
.filter(w => w.length > 2 && !stopWords.has(w));
|
|
582
|
+
// Also extract multi-word phrases
|
|
583
|
+
const phrases = [];
|
|
584
|
+
const desc = description.toLowerCase();
|
|
585
|
+
const commonPhrases = [
|
|
586
|
+
"email verification", "password reset", "auth state", "user select",
|
|
587
|
+
"prisma select", "react context", "protected route", "refresh token",
|
|
588
|
+
"rate limit", "soft delete", "multi-tenant", "org scoping",
|
|
589
|
+
"file upload", "webhook", "cron job", "background job",
|
|
590
|
+
"api key", "role based", "permission", "middleware",
|
|
591
|
+
];
|
|
592
|
+
for (const phrase of commonPhrases) {
|
|
593
|
+
if (desc.includes(phrase))
|
|
594
|
+
phrases.push(phrase);
|
|
595
|
+
}
|
|
596
|
+
return [...new Set([...words, ...phrases])];
|
|
597
|
+
}
|
|
598
|
+
/** Proactive check — find gotchas relevant to a task before coding */
|
|
599
|
+
export function brainCheck(taskDescription) {
|
|
600
|
+
const terms = extractTerms(taskDescription);
|
|
601
|
+
return smartSearch(terms);
|
|
602
|
+
}
|
|
603
|
+
/** Diagnose an error — find matching patterns from past issues */
|
|
604
|
+
export function brainDiagnose(error) {
|
|
605
|
+
const terms = extractTerms(error);
|
|
606
|
+
// Add error-specific terms
|
|
607
|
+
const errorTerms = error.toLowerCase()
|
|
608
|
+
.replace(/[^a-z0-9\s]/g, " ")
|
|
609
|
+
.split(/\s+/)
|
|
610
|
+
.filter(w => w.length > 3);
|
|
611
|
+
const allTerms = [...new Set([...terms, ...errorTerms])];
|
|
612
|
+
return smartSearch(allTerms);
|
|
613
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prajwolkc/stk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "One CLI to deploy, monitor, debug, and learn about your entire stack. Infrastructure monitoring, knowledge base brain, deploy watching, and GitHub issues — all from one command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|