@rigstate/mcp 0.7.7 → 0.7.8
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/index.js +133 -148
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/tools/get-project-context.ts +50 -64
- package/src/tools/list-features.ts +31 -32
- package/src/tools/planning-tools.ts +38 -3
- package/src/tools/query-brain.ts +52 -122
package/dist/index.js
CHANGED
|
@@ -2052,26 +2052,38 @@ var KEY_LIBS = {
|
|
|
2052
2052
|
"ai": "Vercel AI"
|
|
2053
2053
|
};
|
|
2054
2054
|
async function getProjectContext(supabase, userId, projectId) {
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2055
|
+
let projectRow = null;
|
|
2056
|
+
let projectError = null;
|
|
2057
|
+
try {
|
|
2058
|
+
const { data, error } = await supabase.rpc("get_project_context_secure", {
|
|
2059
|
+
p_project_id: projectId,
|
|
2060
|
+
p_user_id: userId
|
|
2061
|
+
}).single();
|
|
2062
|
+
if (data && !error) {
|
|
2063
|
+
projectRow = data;
|
|
2064
|
+
} else {
|
|
2065
|
+
projectError = error;
|
|
2066
|
+
}
|
|
2067
|
+
} catch (e) {
|
|
2068
|
+
projectError = e;
|
|
2069
|
+
}
|
|
2070
|
+
if (!projectRow) {
|
|
2071
|
+
console.error(`RPC get_project_context_secure failed for ${projectId}, falling back to direct query. Error:`, projectError);
|
|
2072
|
+
const { data, error } = await supabase.from("projects").select(`
|
|
2073
|
+
id, name, description, project_type, created_at, last_indexed_at, detected_stack, repository_tree, functional_spec,
|
|
2074
|
+
architectural_dna(stack_definition)
|
|
2075
|
+
`).eq("id", projectId).single();
|
|
2076
|
+
if (data) {
|
|
2077
|
+
projectRow = {
|
|
2078
|
+
...data,
|
|
2079
|
+
architectural_dna: Array.isArray(data.architectural_dna) ? data.architectural_dna[0] : data.architectural_dna
|
|
2080
|
+
};
|
|
2081
|
+
} else {
|
|
2082
|
+
console.error("Project fetch failed completely:", error);
|
|
2083
|
+
throw new Error(`Project ${projectId} not found or access denied. (User: ${userId})`);
|
|
2084
|
+
}
|
|
2063
2085
|
}
|
|
2064
|
-
const project =
|
|
2065
|
-
id: projectRow.id,
|
|
2066
|
-
name: projectRow.name,
|
|
2067
|
-
description: projectRow.description,
|
|
2068
|
-
project_type: projectRow.project_type,
|
|
2069
|
-
created_at: projectRow.created_at,
|
|
2070
|
-
last_indexed_at: projectRow.last_indexed_at,
|
|
2071
|
-
detected_stack: projectRow.detected_stack,
|
|
2072
|
-
repository_tree: projectRow.repository_tree,
|
|
2073
|
-
functional_spec: projectRow.functional_spec
|
|
2074
|
-
};
|
|
2086
|
+
const project = projectRow;
|
|
2075
2087
|
const stackDef = projectRow.architectural_dna?.stack_definition;
|
|
2076
2088
|
const { data: allChunks } = await supabase.rpc("get_roadmap_chunks_secure", {
|
|
2077
2089
|
p_project_id: projectId,
|
|
@@ -2099,13 +2111,9 @@ async function getProjectContext(supabase, userId, projectId) {
|
|
|
2099
2111
|
for (const [name, version] of Object.entries(allDeps)) {
|
|
2100
2112
|
const cleanVersion = version.replace(/[\^~]/g, "");
|
|
2101
2113
|
if (name === "next" || name === "react" || name === "vue" || name === "angular" || name === "svelte") {
|
|
2102
|
-
if (!techStack.framework) {
|
|
2103
|
-
techStack.framework = `${KEY_LIBS[name] || name} ${cleanVersion}`;
|
|
2104
|
-
}
|
|
2114
|
+
if (!techStack.framework) techStack.framework = `${KEY_LIBS[name] || name} ${cleanVersion}`;
|
|
2105
2115
|
} else if (name.includes("prisma") || name.includes("drizzle") || name.includes("typeorm")) {
|
|
2106
|
-
if (!techStack.orm) {
|
|
2107
|
-
techStack.orm = `${KEY_LIBS[name] || name} ${cleanVersion}`;
|
|
2108
|
-
}
|
|
2116
|
+
if (!techStack.orm) techStack.orm = `${KEY_LIBS[name] || name} ${cleanVersion}`;
|
|
2109
2117
|
} else if (KEY_LIBS[name]) {
|
|
2110
2118
|
techStack.keyLibraries.push(`${KEY_LIBS[name]} ${cleanVersion}`);
|
|
2111
2119
|
}
|
|
@@ -2144,13 +2152,10 @@ async function getProjectContext(supabase, userId, projectId) {
|
|
|
2144
2152
|
frameworks: techStack.framework ? [techStack.framework] : [],
|
|
2145
2153
|
libraries: techStack.keyLibraries
|
|
2146
2154
|
});
|
|
2147
|
-
if (curatorContext)
|
|
2148
|
-
response.summary += `
|
|
2155
|
+
if (curatorContext) response.summary += `
|
|
2149
2156
|
|
|
2150
2157
|
=== CURATOR INTELLIGENCE ===${curatorContext}`;
|
|
2151
|
-
}
|
|
2152
2158
|
} catch (e) {
|
|
2153
|
-
console.error("Failed to inject global context:", e);
|
|
2154
2159
|
response.summary += `
|
|
2155
2160
|
|
|
2156
2161
|
(Curator Context Unavailable: ${e.message})`;
|
|
@@ -2162,99 +2167,60 @@ async function getProjectContext(supabase, userId, projectId) {
|
|
|
2162
2167
|
init_esm_shims();
|
|
2163
2168
|
registry.register({
|
|
2164
2169
|
name: "query_brain",
|
|
2165
|
-
description: `Takes a natural language query and performs semantic search
|
|
2166
|
-
against the project's memories (RAG), returning relevant
|
|
2167
|
-
architecture rules, decisions, and constraints.`,
|
|
2170
|
+
description: `Takes a natural language query and performs semantic search against the project's memories (RAG).`,
|
|
2168
2171
|
schema: QueryBrainInputSchema,
|
|
2169
2172
|
handler: async (args, context) => {
|
|
2170
|
-
const result = await queryBrain(
|
|
2171
|
-
context.supabase,
|
|
2172
|
-
context.userId,
|
|
2173
|
-
args.projectId,
|
|
2174
|
-
args.query,
|
|
2175
|
-
args.limit,
|
|
2176
|
-
args.threshold
|
|
2177
|
-
);
|
|
2173
|
+
const result = await queryBrain(context.supabase, context.userId, args.projectId, args.query, args.limit);
|
|
2178
2174
|
return { content: [{ type: "text", text: result.formatted }] };
|
|
2179
2175
|
}
|
|
2180
2176
|
});
|
|
2181
|
-
async function
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
if (!apiKey) {
|
|
2185
|
-
return null;
|
|
2186
|
-
}
|
|
2177
|
+
async function queryBrain(supabase, userId, projectId, query, limit = 8) {
|
|
2178
|
+
let memories = [];
|
|
2179
|
+
let searchType = "SECURE-GATEWAY";
|
|
2187
2180
|
try {
|
|
2188
|
-
const
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
},
|
|
2194
|
-
body: JSON.stringify({ text: query })
|
|
2181
|
+
const { data, error } = await supabase.rpc("query_project_brain_secure", {
|
|
2182
|
+
p_project_id: projectId,
|
|
2183
|
+
p_user_id: userId,
|
|
2184
|
+
p_query: query,
|
|
2185
|
+
p_limit: limit
|
|
2195
2186
|
});
|
|
2196
|
-
if (!
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2187
|
+
if (!error && data) {
|
|
2188
|
+
memories = data.map((m) => ({
|
|
2189
|
+
id: m.id,
|
|
2190
|
+
content: m.content,
|
|
2191
|
+
category: m.category,
|
|
2192
|
+
tags: m.tags,
|
|
2193
|
+
netVotes: m.importance,
|
|
2194
|
+
createdAt: m.created_at
|
|
2195
|
+
}));
|
|
2196
|
+
} else {
|
|
2197
|
+
throw error || new Error("No data");
|
|
2198
|
+
}
|
|
2199
|
+
} catch (e) {
|
|
2200
|
+
searchType = "DIRECT-FALLBACK";
|
|
2201
|
+
const { data } = await supabase.from("project_memories").select("id, content, category, tags, importance, created_at").eq("project_id", projectId).eq("is_active", true).or(`content.ilike.%${query}%,category.ilike.%${query}%`).order("created_at", { ascending: false }).limit(limit);
|
|
2202
|
+
if (data) {
|
|
2203
|
+
memories = data.map((m) => ({
|
|
2204
|
+
id: m.id,
|
|
2205
|
+
content: m.content,
|
|
2206
|
+
category: m.category,
|
|
2207
|
+
tags: m.tags,
|
|
2208
|
+
netVotes: m.importance,
|
|
2209
|
+
createdAt: m.created_at
|
|
2210
|
+
}));
|
|
2200
2211
|
}
|
|
2201
|
-
const result = await response.json();
|
|
2202
|
-
return result.data?.embedding || null;
|
|
2203
|
-
} catch (error) {
|
|
2204
|
-
console.error("Failed to generate embedding via Proxy:", error);
|
|
2205
|
-
return null;
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
async function queryBrain(supabase, userId, projectId, query, limit = 8, threshold = 0.5) {
|
|
2209
|
-
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2210
|
-
p_project_id: projectId,
|
|
2211
|
-
p_user_id: userId
|
|
2212
|
-
});
|
|
2213
|
-
if (accessError || !hasAccess) {
|
|
2214
|
-
throw new Error("Project not found or access denied");
|
|
2215
|
-
}
|
|
2216
|
-
const embedding = await generateQueryEmbedding(query);
|
|
2217
|
-
let memories = [];
|
|
2218
|
-
const { data: searchResults, error: searchError } = await supabase.rpc("query_project_brain_secure", {
|
|
2219
|
-
p_project_id: projectId,
|
|
2220
|
-
p_user_id: userId,
|
|
2221
|
-
p_query: query,
|
|
2222
|
-
p_limit: limit
|
|
2223
|
-
});
|
|
2224
|
-
if (searchError || !searchResults) {
|
|
2225
|
-
console.error("Brain query failed:", searchError);
|
|
2226
|
-
memories = [];
|
|
2227
|
-
} else {
|
|
2228
|
-
memories = searchResults.map((m) => ({
|
|
2229
|
-
id: m.id,
|
|
2230
|
-
content: m.content,
|
|
2231
|
-
category: m.category,
|
|
2232
|
-
tags: m.tags,
|
|
2233
|
-
netVotes: m.importance,
|
|
2234
|
-
createdAt: m.created_at
|
|
2235
|
-
}));
|
|
2236
2212
|
}
|
|
2237
2213
|
let relevantFeatures = [];
|
|
2238
2214
|
try {
|
|
2239
|
-
const { data: projectRow } = await supabase.
|
|
2240
|
-
p_project_id: projectId,
|
|
2241
|
-
p_user_id: userId
|
|
2242
|
-
}).single();
|
|
2215
|
+
const { data: projectRow } = await supabase.from("projects").select("functional_spec").eq("id", projectId).single();
|
|
2243
2216
|
if (projectRow?.functional_spec) {
|
|
2244
|
-
const spec =
|
|
2217
|
+
const spec = projectRow.functional_spec;
|
|
2245
2218
|
const features = spec.featureList || spec.features || [];
|
|
2246
2219
|
relevantFeatures = features.filter((f) => (f.name || f.title)?.toLowerCase().includes(query.toLowerCase())).slice(0, 3);
|
|
2247
2220
|
}
|
|
2248
2221
|
} catch (e) {
|
|
2249
|
-
console.warn("Feature fetch failed in brain query", e);
|
|
2250
2222
|
}
|
|
2251
|
-
const contextLines = memories.map((m) => {
|
|
2252
|
-
const voteIndicator = m.netVotes && m.netVotes < 0 ? ` [\u26A0\uFE0F POORLY RATED: ${m.netVotes}]` : "";
|
|
2253
|
-
const tagStr = m.tags && m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
|
|
2254
|
-
const category = m.category ? m.category.toUpperCase() : "GENERAL";
|
|
2255
|
-
return `- [${category}]${tagStr}${voteIndicator}: ${m.content}`;
|
|
2256
|
-
});
|
|
2257
|
-
const searchType = embedding ? "TRIPLE-HYBRID (Vector + FTS + Fuzzy)" : "SECURE-GATEWAY (Fuzzy)";
|
|
2223
|
+
const contextLines = memories.map((m) => `- [${(m.category || "GENERAL").toUpperCase()}]: ${m.content}`);
|
|
2258
2224
|
let formatted = `=== PROJECT BRAIN: RELEVANT MEMORIES ===
|
|
2259
2225
|
Search Mode: ${searchType}
|
|
2260
2226
|
Query: "${query}"`;
|
|
@@ -2268,20 +2234,12 @@ Query: "${query}"`;
|
|
|
2268
2234
|
|
|
2269
2235
|
Found ${memories.length} relevant memories:
|
|
2270
2236
|
|
|
2271
|
-
${contextLines.join("\n")}
|
|
2272
|
-
|
|
2273
|
-
==========================================`;
|
|
2237
|
+
${contextLines.join("\n")}`;
|
|
2274
2238
|
if (memories.length === 0 && relevantFeatures.length === 0) {
|
|
2275
2239
|
formatted = `=== PROJECT BRAIN ===
|
|
2276
|
-
|
|
2277
|
-
No relevant memories or features found.
|
|
2278
|
-
=======================`;
|
|
2240
|
+
No relevant info found for "${query}".`;
|
|
2279
2241
|
}
|
|
2280
|
-
return {
|
|
2281
|
-
query,
|
|
2282
|
-
memories,
|
|
2283
|
-
formatted
|
|
2284
|
-
};
|
|
2242
|
+
return { query, memories, formatted };
|
|
2285
2243
|
}
|
|
2286
2244
|
|
|
2287
2245
|
// src/tools/get-latest-decisions.ts
|
|
@@ -2826,24 +2784,27 @@ var listFeaturesTool = {
|
|
|
2826
2784
|
Useful for understanding the strategic context and major milestones.`,
|
|
2827
2785
|
schema: InputSchema,
|
|
2828
2786
|
handler: async ({ projectId }, { supabase, userId }) => {
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2787
|
+
let projectRow = null;
|
|
2788
|
+
let dbFeatures = [];
|
|
2789
|
+
let source = "DB";
|
|
2790
|
+
try {
|
|
2791
|
+
const { data } = await supabase.rpc("get_project_context_secure", { p_project_id: projectId, p_user_id: userId }).single();
|
|
2792
|
+
projectRow = data;
|
|
2793
|
+
} catch (e) {
|
|
2794
|
+
const { data } = await supabase.from("projects").select("id, functional_spec").eq("id", projectId).single();
|
|
2795
|
+
projectRow = data;
|
|
2796
|
+
}
|
|
2797
|
+
if (!projectRow) throw new Error(`Project ${projectId} not found or access denied.`);
|
|
2798
|
+
try {
|
|
2799
|
+
const { data } = await supabase.rpc("get_project_features_secure", { p_project_id: projectId, p_user_id: userId });
|
|
2800
|
+
dbFeatures = data || [];
|
|
2801
|
+
} catch (e) {
|
|
2802
|
+
const { data } = await supabase.from("project_features").select("id, name, description, status").eq("project_id", projectId);
|
|
2803
|
+
dbFeatures = data || [];
|
|
2835
2804
|
}
|
|
2836
|
-
const { data: dbFeatures, error: dbError } = await supabase.rpc("get_project_features_secure", {
|
|
2837
|
-
p_project_id: projectId,
|
|
2838
|
-
p_user_id: userId
|
|
2839
|
-
});
|
|
2840
2805
|
let featuresList = [];
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
featuresList = dbFeatures.map((f) => ({
|
|
2844
|
-
...f,
|
|
2845
|
-
title: f.name
|
|
2846
|
-
}));
|
|
2806
|
+
if (dbFeatures && dbFeatures.length > 0) {
|
|
2807
|
+
featuresList = dbFeatures.map((f) => ({ ...f, title: f.name }));
|
|
2847
2808
|
} else {
|
|
2848
2809
|
source = "FALLBACK_SPEC";
|
|
2849
2810
|
const spec = projectRow.functional_spec;
|
|
@@ -2858,15 +2819,11 @@ Useful for understanding the strategic context and major milestones.`,
|
|
|
2858
2819
|
}
|
|
2859
2820
|
}
|
|
2860
2821
|
if (featuresList.length === 0) {
|
|
2861
|
-
return { content: [{ type: "text", text: "No active features found
|
|
2822
|
+
return { content: [{ type: "text", text: "No active features found." }] };
|
|
2862
2823
|
}
|
|
2863
2824
|
const formatted = `=== PROJECT FEATURES (Source: ${source}) ===
|
|
2864
|
-
` + featuresList.map((f) => {
|
|
2865
|
-
|
|
2866
|
-
}).join("\n");
|
|
2867
|
-
return {
|
|
2868
|
-
content: [{ type: "text", text: formatted }]
|
|
2869
|
-
};
|
|
2825
|
+
` + featuresList.map((f) => `- ${f.title} [${f.status}]`).join("\n");
|
|
2826
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
2870
2827
|
}
|
|
2871
2828
|
};
|
|
2872
2829
|
registry.register(listFeaturesTool);
|
|
@@ -3813,15 +3770,43 @@ async function saveToProjectBrain(supabase, userId, input) {
|
|
|
3813
3770
|
const fullContent = `# ${title}
|
|
3814
3771
|
|
|
3815
3772
|
${content}`;
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3773
|
+
let memoryId = null;
|
|
3774
|
+
let saveError = null;
|
|
3775
|
+
try {
|
|
3776
|
+
const { data, error } = await supabase.rpc("save_project_memory_secure", {
|
|
3777
|
+
p_project_id: projectId,
|
|
3778
|
+
p_user_id: userId,
|
|
3779
|
+
p_content: fullContent,
|
|
3780
|
+
p_category: category.toLowerCase(),
|
|
3781
|
+
p_tags: tags || [],
|
|
3782
|
+
p_importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5
|
|
3783
|
+
});
|
|
3784
|
+
if (data && !error) {
|
|
3785
|
+
memoryId = data;
|
|
3786
|
+
} else {
|
|
3787
|
+
saveError = error;
|
|
3788
|
+
}
|
|
3789
|
+
} catch (e) {
|
|
3790
|
+
saveError = e;
|
|
3791
|
+
}
|
|
3792
|
+
if (!memoryId) {
|
|
3793
|
+
console.warn("RPC save_project_memory_secure failed, trying direct insert. Error:", saveError);
|
|
3794
|
+
const { data, error } = await supabase.from("project_memories").insert({
|
|
3795
|
+
project_id: projectId,
|
|
3796
|
+
content: fullContent,
|
|
3797
|
+
category: category.toLowerCase(),
|
|
3798
|
+
tags: tags || [],
|
|
3799
|
+
importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5,
|
|
3800
|
+
is_active: true,
|
|
3801
|
+
source_type: "chat_manual"
|
|
3802
|
+
}).select("id").single();
|
|
3803
|
+
if (data) {
|
|
3804
|
+
memoryId = data.id;
|
|
3805
|
+
} else {
|
|
3806
|
+
console.error("Direct insert failed:", error);
|
|
3807
|
+
throw new Error(`Failed to save memory: ${error?.message || "Unknown error"}`);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3825
3810
|
return {
|
|
3826
3811
|
success: true,
|
|
3827
3812
|
memoryId,
|