@rigstate/mcp 0.7.7 → 0.7.9
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 +138 -147
- 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 +34 -32
- package/src/tools/planning-tools.ts +42 -3
- package/src/tools/query-brain.ts +51 -113
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,61 @@ 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.rpc("get_project_context_secure", {
|
|
2240
|
-
p_project_id: projectId,
|
|
2241
|
-
p_user_id: userId
|
|
2242
|
-
}).single();
|
|
2215
|
+
const { data: projectRow } = await supabase.rpc("get_project_context_secure", { p_project_id: projectId, p_user_id: userId }).single();
|
|
2243
2216
|
if (projectRow?.functional_spec) {
|
|
2244
2217
|
const spec = typeof projectRow.functional_spec === "string" ? JSON.parse(projectRow.functional_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.
|
|
2222
|
+
console.error("[query_brain] Failed to fetch project spec for features:", e);
|
|
2250
2223
|
}
|
|
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)";
|
|
2224
|
+
const contextLines = memories.map((m) => `- [${(m.category || "GENERAL").toUpperCase()}]: ${m.content}`);
|
|
2258
2225
|
let formatted = `=== PROJECT BRAIN: RELEVANT MEMORIES ===
|
|
2259
2226
|
Search Mode: ${searchType}
|
|
2260
2227
|
Query: "${query}"`;
|
|
@@ -2268,20 +2235,12 @@ Query: "${query}"`;
|
|
|
2268
2235
|
|
|
2269
2236
|
Found ${memories.length} relevant memories:
|
|
2270
2237
|
|
|
2271
|
-
${contextLines.join("\n")}
|
|
2272
|
-
|
|
2273
|
-
==========================================`;
|
|
2238
|
+
${contextLines.join("\n")}`;
|
|
2274
2239
|
if (memories.length === 0 && relevantFeatures.length === 0) {
|
|
2275
2240
|
formatted = `=== PROJECT BRAIN ===
|
|
2276
|
-
|
|
2277
|
-
No relevant memories or features found.
|
|
2278
|
-
=======================`;
|
|
2241
|
+
No relevant info found for "${query}".`;
|
|
2279
2242
|
}
|
|
2280
|
-
return {
|
|
2281
|
-
query,
|
|
2282
|
-
memories,
|
|
2283
|
-
formatted
|
|
2284
|
-
};
|
|
2243
|
+
return { query, memories, formatted };
|
|
2285
2244
|
}
|
|
2286
2245
|
|
|
2287
2246
|
// src/tools/get-latest-decisions.ts
|
|
@@ -2826,24 +2785,29 @@ var listFeaturesTool = {
|
|
|
2826
2785
|
Useful for understanding the strategic context and major milestones.`,
|
|
2827
2786
|
schema: InputSchema,
|
|
2828
2787
|
handler: async ({ projectId }, { supabase, userId }) => {
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
throw new Error("Project
|
|
2788
|
+
let projectRow = null;
|
|
2789
|
+
let dbFeatures = [];
|
|
2790
|
+
let source = "DB";
|
|
2791
|
+
try {
|
|
2792
|
+
const { data, error } = await supabase.rpc("get_project_context_secure", { p_project_id: projectId, p_user_id: userId }).single();
|
|
2793
|
+
if (error || !data) throw error || new Error("Project not found");
|
|
2794
|
+
projectRow = data;
|
|
2795
|
+
} catch (e) {
|
|
2796
|
+
console.error("[list_features] Secure Project RPC failed:", e);
|
|
2797
|
+
const { data } = await supabase.from("projects").select("id, functional_spec").eq("id", projectId).single();
|
|
2798
|
+
projectRow = data;
|
|
2799
|
+
}
|
|
2800
|
+
if (!projectRow) throw new Error(`Project ${projectId} not found or access denied.`);
|
|
2801
|
+
try {
|
|
2802
|
+
const { data } = await supabase.rpc("get_project_features_secure", { p_project_id: projectId, p_user_id: userId });
|
|
2803
|
+
dbFeatures = data || [];
|
|
2804
|
+
} catch (e) {
|
|
2805
|
+
const { data } = await supabase.from("project_features").select("id, name, description, status").eq("project_id", projectId);
|
|
2806
|
+
dbFeatures = data || [];
|
|
2835
2807
|
}
|
|
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
2808
|
let featuresList = [];
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
featuresList = dbFeatures.map((f) => ({
|
|
2844
|
-
...f,
|
|
2845
|
-
title: f.name
|
|
2846
|
-
}));
|
|
2809
|
+
if (dbFeatures && dbFeatures.length > 0) {
|
|
2810
|
+
featuresList = dbFeatures.map((f) => ({ ...f, title: f.name }));
|
|
2847
2811
|
} else {
|
|
2848
2812
|
source = "FALLBACK_SPEC";
|
|
2849
2813
|
const spec = projectRow.functional_spec;
|
|
@@ -2858,15 +2822,11 @@ Useful for understanding the strategic context and major milestones.`,
|
|
|
2858
2822
|
}
|
|
2859
2823
|
}
|
|
2860
2824
|
if (featuresList.length === 0) {
|
|
2861
|
-
return { content: [{ type: "text", text: "No active features found
|
|
2825
|
+
return { content: [{ type: "text", text: "No active features found." }] };
|
|
2862
2826
|
}
|
|
2863
2827
|
const formatted = `=== PROJECT FEATURES (Source: ${source}) ===
|
|
2864
|
-
` + featuresList.map((f) => {
|
|
2865
|
-
|
|
2866
|
-
}).join("\n");
|
|
2867
|
-
return {
|
|
2868
|
-
content: [{ type: "text", text: formatted }]
|
|
2869
|
-
};
|
|
2828
|
+
` + featuresList.map((f) => `- ${f.title} [${f.status}]`).join("\n");
|
|
2829
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
2870
2830
|
}
|
|
2871
2831
|
};
|
|
2872
2832
|
registry.register(listFeaturesTool);
|
|
@@ -3813,15 +3773,46 @@ async function saveToProjectBrain(supabase, userId, input) {
|
|
|
3813
3773
|
const fullContent = `# ${title}
|
|
3814
3774
|
|
|
3815
3775
|
${content}`;
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3776
|
+
let memoryId = null;
|
|
3777
|
+
let saveError = null;
|
|
3778
|
+
try {
|
|
3779
|
+
const { data, error } = await supabase.rpc("save_project_memory_secure", {
|
|
3780
|
+
p_project_id: projectId,
|
|
3781
|
+
p_user_id: userId,
|
|
3782
|
+
p_content: fullContent,
|
|
3783
|
+
p_category: category.toLowerCase(),
|
|
3784
|
+
p_tags: tags || [],
|
|
3785
|
+
p_importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5
|
|
3786
|
+
});
|
|
3787
|
+
if (error) {
|
|
3788
|
+
console.error("[save_to_project_brain] RPC Error:", error);
|
|
3789
|
+
saveError = error;
|
|
3790
|
+
} else if (data) {
|
|
3791
|
+
memoryId = data;
|
|
3792
|
+
}
|
|
3793
|
+
} catch (e) {
|
|
3794
|
+
console.error("[save_to_project_brain] RPC Exception:", e);
|
|
3795
|
+
saveError = e;
|
|
3796
|
+
}
|
|
3797
|
+
if (!memoryId) {
|
|
3798
|
+
console.warn("[save_to_project_brain] Falling back to direct insert. RPC Error/Response was:", saveError);
|
|
3799
|
+
const { data, error } = await supabase.from("project_memories").insert({
|
|
3800
|
+
project_id: projectId,
|
|
3801
|
+
content: fullContent,
|
|
3802
|
+
category: category.toLowerCase(),
|
|
3803
|
+
tags: tags || [],
|
|
3804
|
+
importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5,
|
|
3805
|
+
is_active: true,
|
|
3806
|
+
source_type: "chat_manual"
|
|
3807
|
+
}).select("id").single();
|
|
3808
|
+
if (data) {
|
|
3809
|
+
memoryId = data.id;
|
|
3810
|
+
} else {
|
|
3811
|
+
console.error("[save_to_project_brain] Direct insert failed:", error);
|
|
3812
|
+
const detail = error?.message || saveError?.message || "Unknown error";
|
|
3813
|
+
throw new Error(`Failed to save memory: ${detail}. (Note: secure RPC failed first)`);
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3825
3816
|
return {
|
|
3826
3817
|
success: true,
|
|
3827
3818
|
memoryId,
|