@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 CHANGED
@@ -2052,26 +2052,38 @@ var KEY_LIBS = {
2052
2052
  "ai": "Vercel AI"
2053
2053
  };
2054
2054
  async function getProjectContext(supabase, userId, projectId) {
2055
- const { data: rawData, error: projectError } = await supabase.rpc("get_project_context_secure", {
2056
- p_project_id: projectId,
2057
- p_user_id: userId
2058
- }).single();
2059
- const projectRow = rawData;
2060
- if (projectError || !projectRow) {
2061
- console.error("Project fetch failed:", projectError);
2062
- throw new Error("Project not found or access denied");
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 generateQueryEmbedding(query) {
2182
- const apiKey = process.env.RIGSTATE_API_KEY;
2183
- const apiUrl = process.env.RIGSTATE_API_URL || "http://localhost:3000/api/v1";
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 response = await fetch(`${apiUrl}/intelligence/embed`, {
2189
- method: "POST",
2190
- headers: {
2191
- "Content-Type": "application/json",
2192
- "Authorization": `Bearer ${apiKey}`
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 (!response.ok) {
2197
- const errorText = await response.text();
2198
- console.error(`Embedding API error (${response.status}):`, errorText);
2199
- return null;
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.warn("Feature fetch failed in brain query", e);
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
- Query: "${query}"
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
- const { data: projectRow, error: projectError } = await supabase.rpc("get_project_context_secure", {
2830
- p_project_id: projectId,
2831
- p_user_id: userId
2832
- }).single();
2833
- if (projectError || !projectRow) {
2834
- throw new Error("Project details not found or access denied");
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
- let source = "DB";
2842
- if (!dbError && dbFeatures && dbFeatures.length > 0) {
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 (checked DB and Spec)." }] };
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
- return `- ${f.title} [${f.status}]`;
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
- const { data: memoryId, error } = await supabase.rpc("save_project_memory_secure", {
3817
- p_project_id: projectId,
3818
- p_user_id: userId,
3819
- p_content: fullContent,
3820
- p_category: category.toLowerCase(),
3821
- p_tags: tags || [],
3822
- p_importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5
3823
- });
3824
- if (error) throw new Error(`Failed to save memory: ${error.message}`);
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,