@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 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,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 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.from("projects").select("functional_spec").eq("id", projectId).single();
2243
2216
  if (projectRow?.functional_spec) {
2244
- const spec = typeof projectRow.functional_spec === "string" ? JSON.parse(projectRow.functional_spec) : projectRow.functional_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
- Query: "${query}"
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
- 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");
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
- let source = "DB";
2842
- if (!dbError && dbFeatures && dbFeatures.length > 0) {
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 (checked DB and Spec)." }] };
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
- return `- ${f.title} [${f.status}]`;
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
- 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}`);
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,