@rigstate/mcp 0.7.6 → 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
@@ -1903,10 +1903,10 @@ var CompleteRoadmapTaskInputSchema = z4.object({
1903
1903
 
1904
1904
  // src/lib/project-context-utils.ts
1905
1905
  init_esm_shims();
1906
- async function buildProjectSummary(project, techStack, activeTask, nextTask, agentTasks, roadmapItems, stackDef, supabase) {
1906
+ async function buildProjectSummary(project, techStack, activeTask, nextTask, agentTasks, roadmapItems, stackDef, supabase, userId) {
1907
1907
  const summaryParts = [];
1908
1908
  summaryParts.push(`Project Type: ${project.project_type?.toUpperCase() || "UNKNOWN"}`);
1909
- if (stackDef) {
1909
+ if (stackDef || activeTask || nextTask) {
1910
1910
  summaryParts.push("\n=== ACTIVE MISSION PARAMETERS ===");
1911
1911
  if (activeTask) {
1912
1912
  summaryParts.push(`\u26A0\uFE0F CURRENT OBJECTIVE: T-${activeTask.step_number}: ${activeTask.title}`);
@@ -1937,11 +1937,19 @@ async function buildProjectSummary(project, techStack, activeTask, nextTask, age
1937
1937
  summaryParts.push(` Tags: ${activeTask.tags.join(", ")}`);
1938
1938
  }
1939
1939
  if (activeTask.feature_id) {
1940
- const { data: feature } = await supabase.from("project_features").select("name, description").eq("id", activeTask.feature_id).single();
1941
- if (feature) {
1942
- summaryParts.push(`
1940
+ try {
1941
+ const { data: dbFeatures } = await supabase.rpc("get_project_features_secure", {
1942
+ p_project_id: project.id,
1943
+ p_user_id: userId
1944
+ });
1945
+ const feature = dbFeatures?.find((f) => f.id === activeTask.feature_id);
1946
+ if (feature) {
1947
+ summaryParts.push(`
1943
1948
  Parent Feature: ${feature.name}`);
1944
- summaryParts.push(` Feature Vision: ${feature.description}`);
1949
+ summaryParts.push(` Feature Vision: ${feature.description}`);
1950
+ }
1951
+ } catch (e) {
1952
+ console.warn("Feature context fetch failed", e);
1945
1953
  }
1946
1954
  }
1947
1955
  summaryParts.push("\n ACTION: Focus ALL coding efforts on completing this task.");
@@ -1964,13 +1972,15 @@ async function buildProjectSummary(project, techStack, activeTask, nextTask, age
1964
1972
  summaryParts.push(`2. PROACTIVE: Instead of asking "How can I help?", ask "Shall we start on T-${nextTask.step_number}?"`);
1965
1973
  }
1966
1974
  summaryParts.push("\n=== CURRENT STACK ===");
1967
- if (stackDef.frontend) summaryParts.push(`Frontend: ${stackDef.frontend.framework} (${stackDef.frontend.language})`);
1968
- if (stackDef.backend) summaryParts.push(`Backend: ${stackDef.backend.service} (${stackDef.backend.database})`);
1969
- if (stackDef.styling) summaryParts.push(`Styling: ${stackDef.styling.framework} ${stackDef.styling.library || ""}`);
1970
- if (stackDef.hosting) summaryParts.push(`Infrastructure: ${stackDef.hosting.provider}`);
1971
- } else {
1972
- if (techStack.framework) summaryParts.push(`Framework: ${techStack.framework}`);
1973
- if (techStack.orm) summaryParts.push(`ORM: ${techStack.orm}`);
1975
+ if (stackDef) {
1976
+ if (stackDef.frontend) summaryParts.push(`Frontend: ${stackDef.frontend.framework} (${stackDef.frontend.language})`);
1977
+ if (stackDef.backend) summaryParts.push(`Backend: ${stackDef.backend.service} (${stackDef.backend.database})`);
1978
+ if (stackDef.styling) summaryParts.push(`Styling: ${stackDef.styling.framework} ${stackDef.styling.library || ""}`);
1979
+ if (stackDef.hosting) summaryParts.push(`Infrastructure: ${stackDef.hosting.provider}`);
1980
+ } else {
1981
+ if (techStack.framework) summaryParts.push(`Framework: ${techStack.framework}`);
1982
+ if (techStack.orm) summaryParts.push(`ORM: ${techStack.orm}`);
1983
+ }
1974
1984
  }
1975
1985
  if (project.description) {
1976
1986
  summaryParts.push(`
@@ -1984,8 +1994,8 @@ Description: ${project.description}`);
1984
1994
  if (spec.coreProblem) summaryParts.push(`Core Problem: ${spec.coreProblem}`);
1985
1995
  if (spec.featureList && Array.isArray(spec.featureList)) {
1986
1996
  summaryParts.push("\nKey Features & Nuances:");
1987
- spec.featureList.filter((f) => f.priority === "MVP").forEach((f) => {
1988
- summaryParts.push(`- ${f.name}: ${f.description}`);
1997
+ spec.featureList.filter((f) => f.priority === "MVP" || f.priority === "HIGH").slice(0, 10).forEach((f) => {
1998
+ summaryParts.push(`- ${f.name}: ${f.description?.substring(0, 200)}`);
1989
1999
  });
1990
2000
  }
1991
2001
  }
@@ -2002,7 +2012,7 @@ Description: ${project.description}`);
2002
2012
  summaryParts.push("\nLatest AI Executions:");
2003
2013
  agentTasks.forEach((t) => {
2004
2014
  const time = t.completed_at ? new Date(t.completed_at).toLocaleString() : "Recently";
2005
- summaryParts.push(`- [${time}] ${t.roadmap_title || "Task"}: ${t.execution_summary || "Completed"}`);
2015
+ summaryParts.push(`- [${time}] ${t.roadmap_title || "Task"}: ${t.execution_summary?.substring(0, 100) || "Completed"}`);
2006
2016
  });
2007
2017
  }
2008
2018
  if (roadmapItems && roadmapItems.length > 0) {
@@ -2042,26 +2052,38 @@ var KEY_LIBS = {
2042
2052
  "ai": "Vercel AI"
2043
2053
  };
2044
2054
  async function getProjectContext(supabase, userId, projectId) {
2045
- const { data: rawData, error: projectError } = await supabase.rpc("get_project_context_secure", {
2046
- p_project_id: projectId,
2047
- p_user_id: userId
2048
- }).single();
2049
- const projectRow = rawData;
2050
- if (projectError || !projectRow) {
2051
- console.error("Project fetch failed:", projectError);
2052
- 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
+ }
2053
2085
  }
2054
- const project = {
2055
- id: projectRow.id,
2056
- name: projectRow.name,
2057
- description: projectRow.description,
2058
- project_type: projectRow.project_type,
2059
- created_at: projectRow.created_at,
2060
- last_indexed_at: projectRow.last_indexed_at,
2061
- detected_stack: projectRow.detected_stack,
2062
- repository_tree: projectRow.repository_tree,
2063
- functional_spec: projectRow.functional_spec
2064
- };
2086
+ const project = projectRow;
2065
2087
  const stackDef = projectRow.architectural_dna?.stack_definition;
2066
2088
  const { data: allChunks } = await supabase.rpc("get_roadmap_chunks_secure", {
2067
2089
  p_project_id: projectId,
@@ -2089,13 +2111,9 @@ async function getProjectContext(supabase, userId, projectId) {
2089
2111
  for (const [name, version] of Object.entries(allDeps)) {
2090
2112
  const cleanVersion = version.replace(/[\^~]/g, "");
2091
2113
  if (name === "next" || name === "react" || name === "vue" || name === "angular" || name === "svelte") {
2092
- if (!techStack.framework) {
2093
- techStack.framework = `${KEY_LIBS[name] || name} ${cleanVersion}`;
2094
- }
2114
+ if (!techStack.framework) techStack.framework = `${KEY_LIBS[name] || name} ${cleanVersion}`;
2095
2115
  } else if (name.includes("prisma") || name.includes("drizzle") || name.includes("typeorm")) {
2096
- if (!techStack.orm) {
2097
- techStack.orm = `${KEY_LIBS[name] || name} ${cleanVersion}`;
2098
- }
2116
+ if (!techStack.orm) techStack.orm = `${KEY_LIBS[name] || name} ${cleanVersion}`;
2099
2117
  } else if (KEY_LIBS[name]) {
2100
2118
  techStack.keyLibraries.push(`${KEY_LIBS[name]} ${cleanVersion}`);
2101
2119
  }
@@ -2114,7 +2132,8 @@ async function getProjectContext(supabase, userId, projectId) {
2114
2132
  agentTasks || [],
2115
2133
  roadmapItems || [],
2116
2134
  stackDef,
2117
- supabase
2135
+ supabase,
2136
+ userId
2118
2137
  );
2119
2138
  const response = {
2120
2139
  project: {
@@ -2133,13 +2152,10 @@ async function getProjectContext(supabase, userId, projectId) {
2133
2152
  frameworks: techStack.framework ? [techStack.framework] : [],
2134
2153
  libraries: techStack.keyLibraries
2135
2154
  });
2136
- if (curatorContext) {
2137
- response.summary += `
2155
+ if (curatorContext) response.summary += `
2138
2156
 
2139
2157
  === CURATOR INTELLIGENCE ===${curatorContext}`;
2140
- }
2141
2158
  } catch (e) {
2142
- console.error("Failed to inject global context:", e);
2143
2159
  response.summary += `
2144
2160
 
2145
2161
  (Curator Context Unavailable: ${e.message})`;
@@ -2151,102 +2167,60 @@ async function getProjectContext(supabase, userId, projectId) {
2151
2167
  init_esm_shims();
2152
2168
  registry.register({
2153
2169
  name: "query_brain",
2154
- description: `Takes a natural language query and performs semantic search
2155
- against the project's memories (RAG), returning relevant
2156
- architecture rules, decisions, and constraints.`,
2170
+ description: `Takes a natural language query and performs semantic search against the project's memories (RAG).`,
2157
2171
  schema: QueryBrainInputSchema,
2158
2172
  handler: async (args, context) => {
2159
- const result = await queryBrain(
2160
- context.supabase,
2161
- context.userId,
2162
- args.projectId,
2163
- args.query,
2164
- args.limit,
2165
- args.threshold
2166
- );
2173
+ const result = await queryBrain(context.supabase, context.userId, args.projectId, args.query, args.limit);
2167
2174
  return { content: [{ type: "text", text: result.formatted }] };
2168
2175
  }
2169
2176
  });
2170
- async function generateQueryEmbedding(query) {
2171
- const apiKey = process.env.RIGSTATE_API_KEY;
2172
- const apiUrl = process.env.RIGSTATE_API_URL || "http://localhost:3000/api/v1";
2173
- if (!apiKey) {
2174
- return null;
2175
- }
2177
+ async function queryBrain(supabase, userId, projectId, query, limit = 8) {
2178
+ let memories = [];
2179
+ let searchType = "SECURE-GATEWAY";
2176
2180
  try {
2177
- const response = await fetch(`${apiUrl}/intelligence/embed`, {
2178
- method: "POST",
2179
- headers: {
2180
- "Content-Type": "application/json",
2181
- "Authorization": `Bearer ${apiKey}`
2182
- },
2183
- 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
2184
2186
  });
2185
- if (!response.ok) {
2186
- const errorText = await response.text();
2187
- console.error(`Embedding API error (${response.status}):`, errorText);
2188
- 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");
2189
2198
  }
2190
- const result = await response.json();
2191
- return result.data?.embedding || null;
2192
- } catch (error) {
2193
- console.error("Failed to generate embedding via Proxy:", error);
2194
- return null;
2195
- }
2196
- }
2197
- async function queryBrain(supabase, userId, projectId, query, limit = 8, threshold = 0.5) {
2198
- const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
2199
- p_project_id: projectId,
2200
- p_user_id: userId
2201
- });
2202
- if (accessError || !hasAccess) {
2203
- throw new Error("Project not found or access denied");
2204
- }
2205
- const embedding = await generateQueryEmbedding(query);
2206
- let memories = [];
2207
- const { data: searchResults, error: searchError } = await supabase.rpc("hybrid_search_memories", {
2208
- p_project_id: projectId,
2209
- p_query: query,
2210
- p_embedding: embedding || null,
2211
- p_limit: limit,
2212
- p_similarity_threshold: threshold || 0.1
2213
- });
2214
- if (searchError) {
2215
- const { data: recentMemories } = await supabase.from("project_memories").select("id, content, category, tags, importance, created_at").eq("project_id", projectId).eq("is_active", true).order("created_at", { ascending: false }).limit(limit);
2216
- if (recentMemories) {
2217
- memories = recentMemories.map((m) => ({
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) => ({
2218
2204
  id: m.id,
2219
2205
  content: m.content,
2220
- category: m.category || "general",
2221
- tags: m.tags || [],
2222
- netVotes: m.importance || 0,
2206
+ category: m.category,
2207
+ tags: m.tags,
2208
+ netVotes: m.importance,
2223
2209
  createdAt: m.created_at
2224
2210
  }));
2225
2211
  }
2226
- } else if (searchResults) {
2227
- memories = searchResults.map((m) => ({
2228
- id: m.id,
2229
- content: m.content,
2230
- category: m.category,
2231
- tags: m.tags,
2232
- netVotes: m.importance,
2233
- createdAt: m.created_at
2234
- }));
2235
2212
  }
2236
2213
  let relevantFeatures = [];
2237
2214
  try {
2238
- const { data: features } = await supabase.from("project_features").select("name, status, description").eq("project_id", projectId).or(`name.ilike.%${query}%,description.ilike.%${query}%`).limit(3);
2239
- if (features) relevantFeatures = features;
2215
+ const { data: projectRow } = await supabase.from("projects").select("functional_spec").eq("id", projectId).single();
2216
+ if (projectRow?.functional_spec) {
2217
+ const spec = projectRow.functional_spec;
2218
+ const features = spec.featureList || spec.features || [];
2219
+ relevantFeatures = features.filter((f) => (f.name || f.title)?.toLowerCase().includes(query.toLowerCase())).slice(0, 3);
2220
+ }
2240
2221
  } catch (e) {
2241
- console.warn("Feature fetch failed in brain query", e);
2242
2222
  }
2243
- const contextLines = memories.map((m) => {
2244
- const voteIndicator = m.netVotes && m.netVotes < 0 ? ` [\u26A0\uFE0F POORLY RATED: ${m.netVotes}]` : "";
2245
- const tagStr = m.tags && m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
2246
- const category = m.category ? m.category.toUpperCase() : "GENERAL";
2247
- return `- [${category}]${tagStr}${voteIndicator}: ${m.content}`;
2248
- });
2249
- const searchType = embedding ? "TRIPLE-HYBRID (Vector + FTS + Fuzzy)" : "HYBRID (FTS + Fuzzy)";
2223
+ const contextLines = memories.map((m) => `- [${(m.category || "GENERAL").toUpperCase()}]: ${m.content}`);
2250
2224
  let formatted = `=== PROJECT BRAIN: RELEVANT MEMORIES ===
2251
2225
  Search Mode: ${searchType}
2252
2226
  Query: "${query}"`;
@@ -2254,26 +2228,18 @@ Query: "${query}"`;
2254
2228
  formatted += `
2255
2229
 
2256
2230
  === RELATED FEATURES ===
2257
- ` + relevantFeatures.map((f) => `- ${f.name} [${f.status}]`).join("\n");
2231
+ ` + relevantFeatures.map((f) => `- ${f.name || f.title} [${f.status || "Active"}]`).join("\n");
2258
2232
  }
2259
2233
  formatted += `
2260
2234
 
2261
2235
  Found ${memories.length} relevant memories:
2262
2236
 
2263
- ${contextLines.join("\n")}
2264
-
2265
- ==========================================`;
2237
+ ${contextLines.join("\n")}`;
2266
2238
  if (memories.length === 0 && relevantFeatures.length === 0) {
2267
2239
  formatted = `=== PROJECT BRAIN ===
2268
- Query: "${query}"
2269
- No relevant memories or features found.
2270
- =======================`;
2240
+ No relevant info found for "${query}".`;
2271
2241
  }
2272
- return {
2273
- query,
2274
- memories,
2275
- formatted
2276
- };
2242
+ return { query, memories, formatted };
2277
2243
  }
2278
2244
 
2279
2245
  // src/tools/get-latest-decisions.ts
@@ -2818,32 +2784,33 @@ var listFeaturesTool = {
2818
2784
  Useful for understanding the strategic context and major milestones.`,
2819
2785
  schema: InputSchema,
2820
2786
  handler: async ({ projectId }, { supabase, userId }) => {
2821
- const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
2822
- p_project_id: projectId,
2823
- p_user_id: userId
2824
- });
2825
- if (accessError || !hasAccess) {
2826
- throw new Error("Project 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;
2827
2796
  }
2828
- const { data: project, error: projectError } = await supabase.from("projects").select("id, functional_spec").eq("id", projectId).single();
2829
- if (projectError || !project) {
2830
- throw new Error("Project details not found");
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 || [];
2831
2804
  }
2832
- const { data: dbFeatures, error: dbError } = await supabase.from("project_features").select("id, name, description, status").eq("project_id", projectId).neq("status", "shadow").order("created_at", { ascending: false });
2833
2805
  let featuresList = [];
2834
- let source = "DB";
2835
- if (!dbError && dbFeatures && dbFeatures.length > 0) {
2836
- featuresList = dbFeatures.map((f) => ({
2837
- ...f,
2838
- title: f.name
2839
- // Map back to title specifically for uniform handling below
2840
- }));
2806
+ if (dbFeatures && dbFeatures.length > 0) {
2807
+ featuresList = dbFeatures.map((f) => ({ ...f, title: f.name }));
2841
2808
  } else {
2842
2809
  source = "FALLBACK_SPEC";
2843
- console.error(`[WARN] Project ${projectId}: 'project_features' empty or missing. Falling back to 'functional_spec'.`);
2844
- const spec = project.functional_spec;
2845
- if (spec && typeof spec === "object" && Array.isArray(spec.features)) {
2846
- featuresList = spec.features.map((f) => ({
2810
+ const spec = projectRow.functional_spec;
2811
+ const features = spec?.featureList || spec?.features;
2812
+ if (Array.isArray(features)) {
2813
+ featuresList = features.map((f) => ({
2847
2814
  id: "legacy",
2848
2815
  title: f.name || f.title,
2849
2816
  description: f.description,
@@ -2852,15 +2819,11 @@ Useful for understanding the strategic context and major milestones.`,
2852
2819
  }
2853
2820
  }
2854
2821
  if (featuresList.length === 0) {
2855
- return { content: [{ type: "text", text: "No active features found (checked DB and Spec)." }] };
2822
+ return { content: [{ type: "text", text: "No active features found." }] };
2856
2823
  }
2857
2824
  const formatted = `=== PROJECT FEATURES (Source: ${source}) ===
2858
- ` + featuresList.map((f) => {
2859
- return `- ${f.title} [${f.status}]`;
2860
- }).join("\n");
2861
- return {
2862
- content: [{ type: "text", text: formatted }]
2863
- };
2825
+ ` + featuresList.map((f) => `- ${f.title} [${f.status}]`).join("\n");
2826
+ return { content: [{ type: "text", text: formatted }] };
2864
2827
  }
2865
2828
  };
2866
2829
  registry.register(listFeaturesTool);
@@ -3807,19 +3770,46 @@ async function saveToProjectBrain(supabase, userId, input) {
3807
3770
  const fullContent = `# ${title}
3808
3771
 
3809
3772
  ${content}`;
3810
- const { data, error } = await supabase.from("project_memories").insert({
3811
- project_id: projectId,
3812
- content: fullContent,
3813
- category: category.toLowerCase(),
3814
- tags,
3815
- importance: category === "DECISION" || category === "ARCHITECTURE" ? 9 : 5,
3816
- is_active: true,
3817
- source_type: "chat_manual"
3818
- }).select("id").single();
3819
- 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
+ }
3820
3810
  return {
3821
3811
  success: true,
3822
- memoryId: data.id,
3812
+ memoryId,
3823
3813
  message: `\u2705 Saved [${category}] "${title}" to Project Brain.`
3824
3814
  };
3825
3815
  }