@rigstate/mcp 0.7.4 → 0.7.6
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 +285 -115
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/arch-analysis.ts +171 -0
- package/src/lib/curator/actions/submit.ts +8 -9
- package/src/lib/curator/schemas.ts +10 -4
- package/src/lib/project-context-utils.ts +139 -0
- package/src/lib/schemas.ts +10 -10
- package/src/lib/types-roadmap.ts +43 -0
- package/src/lib/types.ts +41 -25
- package/src/server/types.ts +1 -1
- package/src/tools/analyze-database-performance.ts +12 -0
- package/src/tools/archaeological-scan.ts +37 -214
- package/src/tools/audit-integrity-gate.ts +16 -4
- package/src/tools/check-agent-bridge.ts +11 -0
- package/src/tools/check-rules-sync.ts +13 -0
- package/src/tools/complete-roadmap-task.ts +12 -0
- package/src/tools/generate-professional-pdf.ts +17 -2
- package/src/tools/get-next-roadmap-step.ts +5 -1
- package/src/tools/get-project-context.ts +17 -79
- package/src/tools/list-features.ts +13 -3
- package/src/tools/list-roadmap-tasks.ts +6 -1
- package/src/tools/pending-tasks.ts +22 -0
- package/src/tools/query-brain.ts +8 -9
- package/src/tools/research-tools.ts +9 -8
- package/src/tools/run-architecture-audit.ts +8 -9
- package/src/tools/save-decision.ts +15 -9
- package/src/tools/security-tools.ts +26 -2
- package/src/tools/submit-idea.ts +15 -9
- package/src/tools/sync-ide-rules.ts +16 -3
- package/src/tools/teacher-mode.ts +6 -7
- package/src/tools/update-roadmap.ts +14 -8
package/dist/index.js
CHANGED
|
@@ -1102,7 +1102,7 @@ import { ListToolsRequestSchema, ListResourcesRequestSchema } from "@modelcontex
|
|
|
1102
1102
|
// src/server/types.ts
|
|
1103
1103
|
init_esm_shims();
|
|
1104
1104
|
var SERVER_NAME = "rigstate-mcp";
|
|
1105
|
-
var SERVER_VERSION = "0.5
|
|
1105
|
+
var SERVER_VERSION = "0.7.5";
|
|
1106
1106
|
|
|
1107
1107
|
// src/lib/tool-registry.ts
|
|
1108
1108
|
init_esm_shims();
|
|
@@ -1192,10 +1192,13 @@ import { z as z2 } from "zod";
|
|
|
1192
1192
|
var QueryGlobalAntidotesSchema = z2.object({
|
|
1193
1193
|
categories: z2.array(z2.string()).optional().describe("Filter by categories (SECURITY, ARCHITECTURE, UX, PERFORMANCE, ACCESSIBILITY, MAINTAINABILITY)"),
|
|
1194
1194
|
severities: z2.array(z2.string()).optional().describe("Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)"),
|
|
1195
|
-
framework_tags: z2.
|
|
1196
|
-
|
|
1195
|
+
framework_tags: z2.preprocess(
|
|
1196
|
+
(val) => typeof val === "string" ? JSON.parse(val) : val,
|
|
1197
|
+
z2.array(z2.string())
|
|
1198
|
+
).optional().describe('Filter by framework tags (e.g., ["nextjs", "react", "supabase"])'),
|
|
1199
|
+
min_trust_score: z2.coerce.number().optional().describe("Minimum trust score (0-100)"),
|
|
1197
1200
|
search_text: z2.string().optional().describe("Search in title and instruction"),
|
|
1198
|
-
limit: z2.number().optional().describe("Max results (default: 20)")
|
|
1201
|
+
limit: z2.coerce.number().optional().describe("Max results (default: 20)")
|
|
1199
1202
|
});
|
|
1200
1203
|
var SubmitSignalSchema = z2.object({
|
|
1201
1204
|
projectId: z2.string().describe("The UUID of the Rigstate project"),
|
|
@@ -1205,7 +1208,10 @@ var SubmitSignalSchema = z2.object({
|
|
|
1205
1208
|
severity: z2.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW"]).describe("Severity level"),
|
|
1206
1209
|
example: z2.string().optional().describe("Good example demonstrating the instruction"),
|
|
1207
1210
|
anti_example: z2.string().optional().describe("Bad example showing what NOT to do"),
|
|
1208
|
-
framework_tags: z2.
|
|
1211
|
+
framework_tags: z2.preprocess(
|
|
1212
|
+
(val) => typeof val === "string" ? [val] : val,
|
|
1213
|
+
z2.array(z2.string())
|
|
1214
|
+
).optional().describe("Relevant framework tags"),
|
|
1209
1215
|
reasoning: z2.string().optional().describe("Why this signal should be added"),
|
|
1210
1216
|
source_type: z2.string().optional().describe("Internal source type override (e.g. TEACHER_MODE)")
|
|
1211
1217
|
});
|
|
@@ -1269,8 +1275,11 @@ ${formatted}
|
|
|
1269
1275
|
// src/lib/curator/actions/submit.ts
|
|
1270
1276
|
init_esm_shims();
|
|
1271
1277
|
async function submitSignal(supabase, userId, input) {
|
|
1272
|
-
const { data:
|
|
1273
|
-
|
|
1278
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
1279
|
+
p_project_id: input.projectId,
|
|
1280
|
+
p_user_id: userId
|
|
1281
|
+
});
|
|
1282
|
+
if (accessError || !hasAccess) {
|
|
1274
1283
|
throw new Error("Project not found or access denied");
|
|
1275
1284
|
}
|
|
1276
1285
|
const fingerprintBase = `${input.instruction}::${input.category}`.toLowerCase();
|
|
@@ -1555,8 +1564,11 @@ var GetLearnedInstructionsSchema = z3.object({
|
|
|
1555
1564
|
async function refineLogic(supabase, userId, args) {
|
|
1556
1565
|
const { projectId, originalReasoning, userCorrection, scope } = args;
|
|
1557
1566
|
const traceId = uuidv4();
|
|
1558
|
-
const { data:
|
|
1559
|
-
|
|
1567
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
1568
|
+
p_project_id: projectId,
|
|
1569
|
+
p_user_id: userId
|
|
1570
|
+
});
|
|
1571
|
+
if (accessError || !hasAccess) {
|
|
1560
1572
|
throw new Error(`Project access denied or not found: ${projectId}`);
|
|
1561
1573
|
}
|
|
1562
1574
|
const { data: instruction, error: insertError } = await supabase.from("ai_instructions").insert({
|
|
@@ -1739,15 +1751,15 @@ import { z as z4 } from "zod";
|
|
|
1739
1751
|
var QueryBrainInputSchema = z4.object({
|
|
1740
1752
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
1741
1753
|
query: z4.string().min(1, "Query is required"),
|
|
1742
|
-
limit: z4.number().min(1).max(20).optional().default(8),
|
|
1743
|
-
threshold: z4.number().min(0).max(1).optional().default(0.1)
|
|
1754
|
+
limit: z4.coerce.number().min(1).max(20).optional().default(8),
|
|
1755
|
+
threshold: z4.coerce.number().min(0).max(1).optional().default(0.1)
|
|
1744
1756
|
});
|
|
1745
1757
|
var GetProjectContextInputSchema = z4.object({
|
|
1746
1758
|
projectId: z4.string().uuid("Invalid project ID")
|
|
1747
1759
|
});
|
|
1748
1760
|
var GetLatestDecisionsInputSchema = z4.object({
|
|
1749
1761
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
1750
|
-
limit: z4.number().min(1).max(10).optional().default(5)
|
|
1762
|
+
limit: z4.coerce.number().min(1).max(10).optional().default(5)
|
|
1751
1763
|
});
|
|
1752
1764
|
var SaveDecisionInputSchema = z4.object({
|
|
1753
1765
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
@@ -1755,14 +1767,14 @@ var SaveDecisionInputSchema = z4.object({
|
|
|
1755
1767
|
decision: z4.string().min(1, "Decision content is required"),
|
|
1756
1768
|
rationale: z4.string().optional(),
|
|
1757
1769
|
category: z4.enum(["decision", "architecture", "constraint", "tech_stack", "design_rule"]).optional().default("decision"),
|
|
1758
|
-
tags: z4.array(z4.string()).optional().default([])
|
|
1770
|
+
tags: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).optional().default([])
|
|
1759
1771
|
});
|
|
1760
1772
|
var SubmitIdeaInputSchema = z4.object({
|
|
1761
1773
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
1762
1774
|
title: z4.string().min(1, "Title is required").max(200, "Title too long"),
|
|
1763
1775
|
description: z4.string().min(1, "Description is required"),
|
|
1764
1776
|
category: z4.enum(["feature", "improvement", "experiment", "pivot"]).optional().default("feature"),
|
|
1765
|
-
tags: z4.array(z4.string()).optional().default([])
|
|
1777
|
+
tags: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).optional().default([])
|
|
1766
1778
|
});
|
|
1767
1779
|
var UpdateRoadmapInputSchema = z4.object({
|
|
1768
1780
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
@@ -1820,7 +1832,7 @@ var GenerateProfessionalPDFInputSchema = z4.object({
|
|
|
1820
1832
|
var ArchaeologicalScanInputSchema = z4.object({
|
|
1821
1833
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
1822
1834
|
gitLog: z4.string().describe("Git log output"),
|
|
1823
|
-
fileTree: z4.array(z4.string()).describe("File paths")
|
|
1835
|
+
fileTree: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).describe("File paths")
|
|
1824
1836
|
});
|
|
1825
1837
|
var ImportGhostFeaturesInputSchema = z4.object({
|
|
1826
1838
|
projectId: z4.string().uuid("Invalid project ID"),
|
|
@@ -1836,7 +1848,7 @@ var AuditSecurityIntegrityInputSchema = z4.object({
|
|
|
1836
1848
|
projectId: z4.string().uuid(),
|
|
1837
1849
|
filePath: z4.string().min(1),
|
|
1838
1850
|
content: z4.string().min(1),
|
|
1839
|
-
rules: z4.array(z4.string()).optional()
|
|
1851
|
+
rules: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).optional()
|
|
1840
1852
|
});
|
|
1841
1853
|
var FetchPackageHealthInputSchema = z4.object({
|
|
1842
1854
|
packageName: z4.string().min(1)
|
|
@@ -1846,7 +1858,7 @@ var SaveToProjectBrainInputSchema = z4.object({
|
|
|
1846
1858
|
title: z4.string().min(1),
|
|
1847
1859
|
content: z4.string().min(1),
|
|
1848
1860
|
category: z4.enum(["DECISION", "ARCHITECTURE", "NOTE", "LESSON_LEARNED"]).default("NOTE"),
|
|
1849
|
-
tags: z4.array(z4.string()).optional().default([])
|
|
1861
|
+
tags: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).optional().default([])
|
|
1850
1862
|
});
|
|
1851
1863
|
var UpdateRoadmapStatusInputSchema = z4.object({
|
|
1852
1864
|
projectId: z4.string().uuid(),
|
|
@@ -1875,11 +1887,11 @@ var GenerateCursorRulesInputSchema = z4.object({
|
|
|
1875
1887
|
});
|
|
1876
1888
|
var AnalyzeDatabasePerformanceInputSchema = z4.object({
|
|
1877
1889
|
projectId: z4.string().uuid(),
|
|
1878
|
-
filePaths: z4.array(z4.string())
|
|
1890
|
+
filePaths: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string()))
|
|
1879
1891
|
});
|
|
1880
1892
|
var AuditIntegrityGateInputSchema = z4.object({
|
|
1881
1893
|
projectId: z4.string().uuid(),
|
|
1882
|
-
filePaths: z4.array(z4.string()).optional().default([])
|
|
1894
|
+
filePaths: z4.preprocess((val) => typeof val === "string" ? [val] : val, z4.array(z4.string())).optional().default([])
|
|
1883
1895
|
});
|
|
1884
1896
|
var CompleteRoadmapTaskInputSchema = z4.object({
|
|
1885
1897
|
projectId: z4.string().uuid(),
|
|
@@ -1889,6 +1901,119 @@ var CompleteRoadmapTaskInputSchema = z4.object({
|
|
|
1889
1901
|
integrityGate: z4.any().optional()
|
|
1890
1902
|
});
|
|
1891
1903
|
|
|
1904
|
+
// src/lib/project-context-utils.ts
|
|
1905
|
+
init_esm_shims();
|
|
1906
|
+
async function buildProjectSummary(project, techStack, activeTask, nextTask, agentTasks, roadmapItems, stackDef, supabase) {
|
|
1907
|
+
const summaryParts = [];
|
|
1908
|
+
summaryParts.push(`Project Type: ${project.project_type?.toUpperCase() || "UNKNOWN"}`);
|
|
1909
|
+
if (stackDef) {
|
|
1910
|
+
summaryParts.push("\n=== ACTIVE MISSION PARAMETERS ===");
|
|
1911
|
+
if (activeTask) {
|
|
1912
|
+
summaryParts.push(`\u26A0\uFE0F CURRENT OBJECTIVE: T-${activeTask.step_number}: ${activeTask.title}`);
|
|
1913
|
+
summaryParts.push(` Role: ${activeTask.role || "Developer"}`);
|
|
1914
|
+
const detailedInstructions = activeTask.prompt_content || activeTask.instruction_set;
|
|
1915
|
+
if (detailedInstructions) {
|
|
1916
|
+
summaryParts.push(` Instructions: ${detailedInstructions.substring(0, 1e3)}...`);
|
|
1917
|
+
}
|
|
1918
|
+
if (activeTask.architectural_brief) {
|
|
1919
|
+
summaryParts.push(`
|
|
1920
|
+
Architectural Brief: ${activeTask.architectural_brief}`);
|
|
1921
|
+
}
|
|
1922
|
+
if (activeTask.context_summary) {
|
|
1923
|
+
summaryParts.push(`
|
|
1924
|
+
Context: ${activeTask.context_summary}`);
|
|
1925
|
+
}
|
|
1926
|
+
if (activeTask.checklist && activeTask.checklist.length > 0) {
|
|
1927
|
+
summaryParts.push("\n Checklist (DoD):");
|
|
1928
|
+
activeTask.checklist.forEach((item) => {
|
|
1929
|
+
summaryParts.push(` [ ] ${typeof item === "string" ? item : item.task}`);
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
if (activeTask.metadata && Object.keys(activeTask.metadata).length > 0) {
|
|
1933
|
+
summaryParts.push(`
|
|
1934
|
+
Technical Metadata: ${JSON.stringify(activeTask.metadata)}`);
|
|
1935
|
+
}
|
|
1936
|
+
if (activeTask.tags && activeTask.tags.length > 0) {
|
|
1937
|
+
summaryParts.push(` Tags: ${activeTask.tags.join(", ")}`);
|
|
1938
|
+
}
|
|
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(`
|
|
1943
|
+
Parent Feature: ${feature.name}`);
|
|
1944
|
+
summaryParts.push(` Feature Vision: ${feature.description}`);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
summaryParts.push("\n ACTION: Focus ALL coding efforts on completing this task.");
|
|
1948
|
+
} else if (nextTask) {
|
|
1949
|
+
summaryParts.push(`\u23F8 SYSTEM IDLE (Waiting for command)`);
|
|
1950
|
+
summaryParts.push(` Suggested Next Mission: T-${nextTask.step_number}: ${nextTask.title}`);
|
|
1951
|
+
if (nextTask.tags && nextTask.tags.length > 0) {
|
|
1952
|
+
summaryParts.push(` Scope: ${nextTask.tags.join(", ")}`);
|
|
1953
|
+
}
|
|
1954
|
+
summaryParts.push(` ACTION: Ask the user "Shall we start T-${nextTask.step_number}?"`);
|
|
1955
|
+
} else {
|
|
1956
|
+
summaryParts.push("\u2705 ALL MISSIONS COMPLETE. Awaiting new roadmap items.");
|
|
1957
|
+
}
|
|
1958
|
+
summaryParts.push("\n=== AI BEHAVIORAL INSTRUCTIONS ===");
|
|
1959
|
+
if (activeTask) {
|
|
1960
|
+
summaryParts.push(`1. FOCUS: The user is working on T-${activeTask.step_number}. Help them complete it.`);
|
|
1961
|
+
summaryParts.push(`2. COMPLIANCE: Ensure all code follows project standards.`);
|
|
1962
|
+
} else if (nextTask) {
|
|
1963
|
+
summaryParts.push(`1. NUDGE: No active task found. Suggest starting T-${nextTask.step_number} (${nextTask.title}).`);
|
|
1964
|
+
summaryParts.push(`2. PROACTIVE: Instead of asking "How can I help?", ask "Shall we start on T-${nextTask.step_number}?"`);
|
|
1965
|
+
}
|
|
1966
|
+
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}`);
|
|
1974
|
+
}
|
|
1975
|
+
if (project.description) {
|
|
1976
|
+
summaryParts.push(`
|
|
1977
|
+
Description: ${project.description}`);
|
|
1978
|
+
}
|
|
1979
|
+
if (project.functional_spec) {
|
|
1980
|
+
summaryParts.push("\n=== STRATEGIC PROJECT SPECIFICATION (NUANCES) ===");
|
|
1981
|
+
const spec = typeof project.functional_spec === "string" ? JSON.parse(project.functional_spec) : project.functional_spec;
|
|
1982
|
+
if (spec.projectDescription) summaryParts.push(`Vision: ${spec.projectDescription}`);
|
|
1983
|
+
if (spec.targetAudience) summaryParts.push(`Audience: ${spec.targetAudience}`);
|
|
1984
|
+
if (spec.coreProblem) summaryParts.push(`Core Problem: ${spec.coreProblem}`);
|
|
1985
|
+
if (spec.featureList && Array.isArray(spec.featureList)) {
|
|
1986
|
+
summaryParts.push("\nKey Features & Nuances:");
|
|
1987
|
+
spec.featureList.filter((f) => f.priority === "MVP").forEach((f) => {
|
|
1988
|
+
summaryParts.push(`- ${f.name}: ${f.description}`);
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
summaryParts.push("\n=== RIGSTATE TOOLING GUIDELINES ===");
|
|
1993
|
+
summaryParts.push("You have access to specialized MCP tools. USE THEM TO SUCCEED:");
|
|
1994
|
+
summaryParts.push("1. NEVER guess about architecture. Use `query_brain` to search project documentation.");
|
|
1995
|
+
summaryParts.push("2. BEFORE coding, check `get_learned_instructions` to see if you have been corrected before.");
|
|
1996
|
+
summaryParts.push("3. When finishing a task, ALWAYS update the roadmap using `update_roadmap`.");
|
|
1997
|
+
summaryParts.push("4. If you discover a reusable pattern, submit it with `submit_curator_signal`.");
|
|
1998
|
+
summaryParts.push("5. For large refactors, use `run_architecture_audit` to check against rules.");
|
|
1999
|
+
summaryParts.push("6. Store major decisions using `save_decision` (ADR).");
|
|
2000
|
+
summaryParts.push("\n=== RECENT ACTIVITY DIGEST ===");
|
|
2001
|
+
if (agentTasks && agentTasks.length > 0) {
|
|
2002
|
+
summaryParts.push("\nLatest AI Executions:");
|
|
2003
|
+
agentTasks.forEach((t) => {
|
|
2004
|
+
const time = t.completed_at ? new Date(t.completed_at).toLocaleString() : "Recently";
|
|
2005
|
+
summaryParts.push(`- [${time}] ${t.roadmap_title || "Task"}: ${t.execution_summary || "Completed"}`);
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
if (roadmapItems && roadmapItems.length > 0) {
|
|
2009
|
+
summaryParts.push("\nRoadmap Updates:");
|
|
2010
|
+
roadmapItems.forEach((i) => {
|
|
2011
|
+
summaryParts.push(`- ${i.title} is now ${i.status}`);
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
return summaryParts.join("\n") || "No project context available.";
|
|
2015
|
+
}
|
|
2016
|
+
|
|
1892
2017
|
// src/tools/get-project-context.ts
|
|
1893
2018
|
registry.register({
|
|
1894
2019
|
name: "get_project_context",
|
|
@@ -1934,10 +2059,11 @@ async function getProjectContext(supabase, userId, projectId) {
|
|
|
1934
2059
|
created_at: projectRow.created_at,
|
|
1935
2060
|
last_indexed_at: projectRow.last_indexed_at,
|
|
1936
2061
|
detected_stack: projectRow.detected_stack,
|
|
1937
|
-
repository_tree: projectRow.repository_tree
|
|
2062
|
+
repository_tree: projectRow.repository_tree,
|
|
2063
|
+
functional_spec: projectRow.functional_spec
|
|
1938
2064
|
};
|
|
1939
2065
|
const stackDef = projectRow.architectural_dna?.stack_definition;
|
|
1940
|
-
const { data: allChunks
|
|
2066
|
+
const { data: allChunks } = await supabase.rpc("get_roadmap_chunks_secure", {
|
|
1941
2067
|
p_project_id: projectId,
|
|
1942
2068
|
p_user_id: userId
|
|
1943
2069
|
});
|
|
@@ -1980,67 +2106,16 @@ async function getProjectContext(supabase, userId, projectId) {
|
|
|
1980
2106
|
project.repository_tree.filter((t) => t.type === "tree" && !t.path.includes("/")).map((t) => t.path)
|
|
1981
2107
|
)].slice(0, 10);
|
|
1982
2108
|
}
|
|
1983
|
-
const
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
summaryParts.push(" ACTION: Focus ALL coding efforts on completing this task.");
|
|
1994
|
-
} else if (nextTask) {
|
|
1995
|
-
summaryParts.push(`\u23F8 SYSTEM IDLE (Waiting for command)`);
|
|
1996
|
-
summaryParts.push(` Suggested Next Mission: T-${nextTask.step_number}: ${nextTask.title}`);
|
|
1997
|
-
summaryParts.push(` ACTION: Ask the user "Shall we start T-${nextTask.step_number}?"`);
|
|
1998
|
-
} else {
|
|
1999
|
-
summaryParts.push("\u2705 ALL MISSIONS COMPLETE. Awaiting new roadmap items.");
|
|
2000
|
-
}
|
|
2001
|
-
summaryParts.push("\n=== AI BEHAVIORAL INSTRUCTIONS ===");
|
|
2002
|
-
if (activeTask) {
|
|
2003
|
-
summaryParts.push(`1. FOCUS: The user is working on T-${activeTask.step_number}. Help them complete it.`);
|
|
2004
|
-
summaryParts.push(`2. COMPLIANCE: Ensure all code follows project standards.`);
|
|
2005
|
-
} else if (nextTask) {
|
|
2006
|
-
summaryParts.push(`1. NUDGE: No active task found. Suggest starting T-${nextTask.step_number} (${nextTask.title}).`);
|
|
2007
|
-
summaryParts.push(`2. PROACTIVE: Instead of asking "How can I help?", ask "Shall we start on T-${nextTask.step_number}?"`);
|
|
2008
|
-
}
|
|
2009
|
-
summaryParts.push("\n=== CURRENT STACK ===");
|
|
2010
|
-
if (stackDef.frontend) summaryParts.push(`Frontend: ${stackDef.frontend.framework} (${stackDef.frontend.language})`);
|
|
2011
|
-
if (stackDef.backend) summaryParts.push(`Backend: ${stackDef.backend.service} (${stackDef.backend.database})`);
|
|
2012
|
-
if (stackDef.styling) summaryParts.push(`Styling: ${stackDef.styling.framework} ${stackDef.styling.library || ""}`);
|
|
2013
|
-
if (stackDef.hosting) summaryParts.push(`Infrastructure: ${stackDef.hosting.provider}`);
|
|
2014
|
-
} else {
|
|
2015
|
-
if (techStack.framework) summaryParts.push(`Framework: ${techStack.framework}`);
|
|
2016
|
-
if (techStack.orm) summaryParts.push(`ORM: ${techStack.orm}`);
|
|
2017
|
-
}
|
|
2018
|
-
if (project.description) {
|
|
2019
|
-
summaryParts.push(`
|
|
2020
|
-
Description: ${project.description}`);
|
|
2021
|
-
}
|
|
2022
|
-
summaryParts.push("\n=== RIGSTATE TOOLING GUIDELINES ===");
|
|
2023
|
-
summaryParts.push("You have access to specialized MCP tools. USE THEM TO SUCCEED:");
|
|
2024
|
-
summaryParts.push("1. NEVER guess about architecture. Use `query_brain` to search project documentation.");
|
|
2025
|
-
summaryParts.push("2. BEFORE coding, check `get_learned_instructions` to see if you have been corrected before.");
|
|
2026
|
-
summaryParts.push("3. When finishing a task, ALWAYS update the roadmap using `update_roadmap`.");
|
|
2027
|
-
summaryParts.push("4. If you discover a reusable pattern, submit it with `submit_curator_signal`.");
|
|
2028
|
-
summaryParts.push("5. For large refactors, use `run_architecture_audit` to check against rules.");
|
|
2029
|
-
summaryParts.push("6. Store major decisions using `save_decision` (ADR).");
|
|
2030
|
-
summaryParts.push("\n=== RECENT ACTIVITY DIGEST ===");
|
|
2031
|
-
if (agentTasks && agentTasks.length > 0) {
|
|
2032
|
-
summaryParts.push("\nLatest AI Executions:");
|
|
2033
|
-
agentTasks.forEach((t) => {
|
|
2034
|
-
const time = t.completed_at ? new Date(t.completed_at).toLocaleString() : "Recently";
|
|
2035
|
-
summaryParts.push(`- [${time}] ${t.roadmap_title || "Task"}: ${t.execution_summary || "Completed"}`);
|
|
2036
|
-
});
|
|
2037
|
-
}
|
|
2038
|
-
if (roadmapItems && roadmapItems.length > 0) {
|
|
2039
|
-
summaryParts.push("\nRoadmap Updates:");
|
|
2040
|
-
roadmapItems.forEach((i) => {
|
|
2041
|
-
summaryParts.push(`- ${i.title} is now ${i.status}`);
|
|
2042
|
-
});
|
|
2043
|
-
}
|
|
2109
|
+
const summary = await buildProjectSummary(
|
|
2110
|
+
project,
|
|
2111
|
+
techStack,
|
|
2112
|
+
activeTask,
|
|
2113
|
+
nextTask,
|
|
2114
|
+
agentTasks || [],
|
|
2115
|
+
roadmapItems || [],
|
|
2116
|
+
stackDef,
|
|
2117
|
+
supabase
|
|
2118
|
+
);
|
|
2044
2119
|
const response = {
|
|
2045
2120
|
project: {
|
|
2046
2121
|
id: project.id,
|
|
@@ -2051,7 +2126,7 @@ Description: ${project.description}`);
|
|
|
2051
2126
|
lastIndexedAt: project.last_indexed_at
|
|
2052
2127
|
},
|
|
2053
2128
|
techStack,
|
|
2054
|
-
summary
|
|
2129
|
+
summary
|
|
2055
2130
|
};
|
|
2056
2131
|
try {
|
|
2057
2132
|
const curatorContext = await injectGlobalContext(supabase, userId, {
|
|
@@ -2120,8 +2195,11 @@ async function generateQueryEmbedding(query) {
|
|
|
2120
2195
|
}
|
|
2121
2196
|
}
|
|
2122
2197
|
async function queryBrain(supabase, userId, projectId, query, limit = 8, threshold = 0.5) {
|
|
2123
|
-
const { data:
|
|
2124
|
-
|
|
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) {
|
|
2125
2203
|
throw new Error("Project not found or access denied");
|
|
2126
2204
|
}
|
|
2127
2205
|
const embedding = await generateQueryEmbedding(query);
|
|
@@ -2314,10 +2392,14 @@ High-importance memory for architectural decisions.`,
|
|
|
2314
2392
|
}
|
|
2315
2393
|
});
|
|
2316
2394
|
async function saveDecision(supabase, userId, projectId, title, decision, rationale, category = "decision", tags = []) {
|
|
2317
|
-
const { data:
|
|
2318
|
-
|
|
2395
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2396
|
+
p_project_id: projectId,
|
|
2397
|
+
p_user_id: userId
|
|
2398
|
+
});
|
|
2399
|
+
if (accessError || !hasAccess) {
|
|
2319
2400
|
throw new Error("Project not found or access denied");
|
|
2320
2401
|
}
|
|
2402
|
+
const { data: project } = await supabase.from("projects").select("name").eq("id", projectId).single();
|
|
2321
2403
|
const contentParts = [`# ${title}`, "", decision];
|
|
2322
2404
|
if (rationale) {
|
|
2323
2405
|
contentParts.push("", "## Rationale", rationale);
|
|
@@ -2348,7 +2430,7 @@ async function saveDecision(supabase, userId, projectId, title, decision, ration
|
|
|
2348
2430
|
return {
|
|
2349
2431
|
success: true,
|
|
2350
2432
|
memoryId: memory.id,
|
|
2351
|
-
message: `\u2705 Decision "${title}" saved to project "${project
|
|
2433
|
+
message: `\u2705 Decision "${title}" saved to project "${project?.name || projectId}" with importance 9/10`
|
|
2352
2434
|
};
|
|
2353
2435
|
}
|
|
2354
2436
|
|
|
@@ -2373,10 +2455,14 @@ Ideas can later be reviewed, analyzed, and promoted to features.`,
|
|
|
2373
2455
|
}
|
|
2374
2456
|
});
|
|
2375
2457
|
async function submitIdea(supabase, userId, projectId, title, description, category = "feature", tags = []) {
|
|
2376
|
-
const { data:
|
|
2377
|
-
|
|
2458
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2459
|
+
p_project_id: projectId,
|
|
2460
|
+
p_user_id: userId
|
|
2461
|
+
});
|
|
2462
|
+
if (accessError || !hasAccess) {
|
|
2378
2463
|
throw new Error("Project not found or access denied");
|
|
2379
2464
|
}
|
|
2465
|
+
const { data: project } = await supabase.from("projects").select("name").eq("id", projectId).single();
|
|
2380
2466
|
const { data: idea, error: insertError } = await supabase.from("saved_ideas").insert({
|
|
2381
2467
|
project_id: projectId,
|
|
2382
2468
|
title,
|
|
@@ -2402,7 +2488,7 @@ async function submitIdea(supabase, userId, projectId, title, description, categ
|
|
|
2402
2488
|
return {
|
|
2403
2489
|
success: true,
|
|
2404
2490
|
ideaId: idea.id,
|
|
2405
|
-
message: `\u{1F4A1} Idea "${title}" submitted to Idea Lab for project "${project
|
|
2491
|
+
message: `\u{1F4A1} Idea "${title}" submitted to Idea Lab for project "${project?.name || projectId}". Status: Draft (awaiting review)`
|
|
2406
2492
|
};
|
|
2407
2493
|
}
|
|
2408
2494
|
|
|
@@ -2426,10 +2512,14 @@ Can search by chunk ID or by title.`,
|
|
|
2426
2512
|
}
|
|
2427
2513
|
});
|
|
2428
2514
|
async function updateRoadmap(supabase, userId, projectId, status, chunkId, title) {
|
|
2429
|
-
const { data:
|
|
2430
|
-
|
|
2515
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2516
|
+
p_project_id: projectId,
|
|
2517
|
+
p_user_id: userId
|
|
2518
|
+
});
|
|
2519
|
+
if (accessError || !hasAccess) {
|
|
2431
2520
|
throw new Error("Project not found or access denied");
|
|
2432
2521
|
}
|
|
2522
|
+
const { data: project } = await supabase.from("projects").select("name").eq("id", projectId).single();
|
|
2433
2523
|
let targetChunk = null;
|
|
2434
2524
|
if (chunkId) {
|
|
2435
2525
|
const { data, error } = await supabase.from("roadmap_chunks").select("id, title, status").eq("id", chunkId).eq("project_id", projectId).single();
|
|
@@ -2558,8 +2648,11 @@ Returns violations or "Pass" status.`,
|
|
|
2558
2648
|
}
|
|
2559
2649
|
});
|
|
2560
2650
|
async function runArchitectureAudit(supabase, userId, projectId, filePath, content) {
|
|
2561
|
-
const { data:
|
|
2562
|
-
|
|
2651
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2652
|
+
p_project_id: projectId,
|
|
2653
|
+
p_user_id: userId
|
|
2654
|
+
});
|
|
2655
|
+
if (accessError || !hasAccess) {
|
|
2563
2656
|
throw new Error("Project not found or access denied");
|
|
2564
2657
|
}
|
|
2565
2658
|
const violations = [];
|
|
@@ -2650,7 +2743,7 @@ registry.register({
|
|
|
2650
2743
|
based on project context and user settings.`,
|
|
2651
2744
|
schema: GenerateCursorRulesInputSchema,
|
|
2652
2745
|
handler: async (args, context) => {
|
|
2653
|
-
const result = await syncIdeRules(context.supabase, args.projectId);
|
|
2746
|
+
const result = await syncIdeRules(context.supabase, context.userId, args.projectId);
|
|
2654
2747
|
let responseText = `FileName: ${result.fileName}
|
|
2655
2748
|
|
|
2656
2749
|
Content:
|
|
@@ -2668,10 +2761,17 @@ Note: Please ensure these modular files are also updated if your IDE is followin
|
|
|
2668
2761
|
return { content: [{ type: "text", text: responseText }] };
|
|
2669
2762
|
}
|
|
2670
2763
|
});
|
|
2671
|
-
async function syncIdeRules(supabase, projectId) {
|
|
2764
|
+
async function syncIdeRules(supabase, userId, projectId) {
|
|
2765
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
2766
|
+
p_project_id: projectId,
|
|
2767
|
+
p_user_id: userId
|
|
2768
|
+
});
|
|
2769
|
+
if (accessError || !hasAccess) {
|
|
2770
|
+
throw new Error("Project not found or access denied");
|
|
2771
|
+
}
|
|
2672
2772
|
const { data: project, error: projectError } = await supabase.from("projects").select("*").eq("id", projectId).single();
|
|
2673
2773
|
if (projectError || !project) {
|
|
2674
|
-
throw new Error(`Project ${projectId} not found.`);
|
|
2774
|
+
throw new Error(`Project ${projectId} details not found.`);
|
|
2675
2775
|
}
|
|
2676
2776
|
const ide = project.preferred_ide || "cursor";
|
|
2677
2777
|
const [stack, roadmapRes, legacyStats, activeAgents, dbMetadataRes] = await Promise.all([
|
|
@@ -2718,10 +2818,17 @@ var listFeaturesTool = {
|
|
|
2718
2818
|
Useful for understanding the strategic context and major milestones.`,
|
|
2719
2819
|
schema: InputSchema,
|
|
2720
2820
|
handler: async ({ projectId }, { supabase, userId }) => {
|
|
2721
|
-
const { data:
|
|
2722
|
-
|
|
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) {
|
|
2723
2826
|
throw new Error("Project not found or access denied");
|
|
2724
2827
|
}
|
|
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");
|
|
2831
|
+
}
|
|
2725
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 });
|
|
2726
2833
|
let featuresList = [];
|
|
2727
2834
|
let source = "DB";
|
|
@@ -2804,7 +2911,12 @@ async function listRoadmapTasks(supabase, userId, projectId) {
|
|
|
2804
2911
|
priority: t.priority,
|
|
2805
2912
|
status: t.status,
|
|
2806
2913
|
step_number: t.step_number,
|
|
2807
|
-
prompt_content: t.prompt_content
|
|
2914
|
+
prompt_content: t.prompt_content,
|
|
2915
|
+
architectural_brief: t.architectural_brief,
|
|
2916
|
+
context_summary: t.context_summary,
|
|
2917
|
+
metadata: t.metadata,
|
|
2918
|
+
checklist: t.checklist,
|
|
2919
|
+
tags: t.tags
|
|
2808
2920
|
})),
|
|
2809
2921
|
formatted
|
|
2810
2922
|
};
|
|
@@ -2859,7 +2971,11 @@ async function getNextRoadmapStep(supabase, userId, projectId, currentStepId) {
|
|
|
2859
2971
|
};
|
|
2860
2972
|
}
|
|
2861
2973
|
return {
|
|
2862
|
-
nextStep
|
|
2974
|
+
nextStep: {
|
|
2975
|
+
...nextStep,
|
|
2976
|
+
architectural_brief: nextStep.architectural_brief,
|
|
2977
|
+
context_summary: nextStep.context_summary
|
|
2978
|
+
},
|
|
2863
2979
|
message: `Next step found: [Step ${nextStep.step_number}] ${nextStep.title}`
|
|
2864
2980
|
};
|
|
2865
2981
|
}
|
|
@@ -2873,6 +2989,7 @@ registry.register({
|
|
|
2873
2989
|
handler: async (args, context) => {
|
|
2874
2990
|
const result = await checkRulesSync(
|
|
2875
2991
|
context.supabase,
|
|
2992
|
+
context.userId,
|
|
2876
2993
|
args.projectId,
|
|
2877
2994
|
args.currentRulesContent
|
|
2878
2995
|
);
|
|
@@ -2889,7 +3006,7 @@ var SAFETY_CACHE_RULES = `
|
|
|
2889
3006
|
4. **Error Handling**: Use try/catch blocks for all external API calls.
|
|
2890
3007
|
5. **No Blind Deletes**: Never delete data without explicit confirmation or soft-deletes.
|
|
2891
3008
|
`;
|
|
2892
|
-
async function checkRulesSync(supabase, projectId, currentRulesContent) {
|
|
3009
|
+
async function checkRulesSync(supabase, userId, projectId, currentRulesContent) {
|
|
2893
3010
|
if (!currentRulesContent) {
|
|
2894
3011
|
return {
|
|
2895
3012
|
synced: false,
|
|
@@ -2909,6 +3026,13 @@ async function checkRulesSync(supabase, projectId, currentRulesContent) {
|
|
|
2909
3026
|
};
|
|
2910
3027
|
}
|
|
2911
3028
|
try {
|
|
3029
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3030
|
+
p_project_id: projectId,
|
|
3031
|
+
p_user_id: userId
|
|
3032
|
+
});
|
|
3033
|
+
if (accessError || !hasAccess) {
|
|
3034
|
+
throw new Error("Project not found or access denied");
|
|
3035
|
+
}
|
|
2912
3036
|
const { data: project, error } = await supabase.from("projects").select("name").eq("id", projectId).single();
|
|
2913
3037
|
if (error) throw error;
|
|
2914
3038
|
if (project) {
|
|
@@ -2945,7 +3069,14 @@ init_esm_shims();
|
|
|
2945
3069
|
init_esm_shims();
|
|
2946
3070
|
import fs from "fs/promises";
|
|
2947
3071
|
import path2 from "path";
|
|
2948
|
-
async function analyzeDatabasePerformance(supabase, input) {
|
|
3072
|
+
async function analyzeDatabasePerformance(supabase, userId, input) {
|
|
3073
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3074
|
+
p_project_id: input.projectId,
|
|
3075
|
+
p_user_id: userId
|
|
3076
|
+
});
|
|
3077
|
+
if (accessError || !hasAccess) {
|
|
3078
|
+
throw new Error("Project not found or access denied");
|
|
3079
|
+
}
|
|
2949
3080
|
const issues = [];
|
|
2950
3081
|
const { data: rawMetadata, error } = await supabase.rpc("get_table_metadata", {
|
|
2951
3082
|
p_project_id: input.projectId
|
|
@@ -3296,7 +3427,7 @@ registry.register({
|
|
|
3296
3427
|
description: `Sven's Tool: Security Shield. Audits the database to ensure Row Level Security (RLS) is enforced.`,
|
|
3297
3428
|
schema: AuditRlsStatusInputSchema,
|
|
3298
3429
|
handler: async (args, context) => {
|
|
3299
|
-
const result = await auditRlsStatus(context.supabase, args);
|
|
3430
|
+
const result = await auditRlsStatus(context.supabase, context.userId, args);
|
|
3300
3431
|
return { content: [{ type: "text", text: result.summary || "No summary available" }] };
|
|
3301
3432
|
}
|
|
3302
3433
|
});
|
|
@@ -3305,11 +3436,18 @@ registry.register({
|
|
|
3305
3436
|
description: `Frank's Tool: Security Oracle. Performs a diagnostic security audit against the Fortress Matrix.`,
|
|
3306
3437
|
schema: AuditSecurityIntegrityInputSchema,
|
|
3307
3438
|
handler: async (args, context) => {
|
|
3308
|
-
const result = await auditSecurityIntegrity(context.supabase, args);
|
|
3439
|
+
const result = await auditSecurityIntegrity(context.supabase, context.userId, args);
|
|
3309
3440
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3310
3441
|
}
|
|
3311
3442
|
});
|
|
3312
|
-
async function auditRlsStatus(supabase, input) {
|
|
3443
|
+
async function auditRlsStatus(supabase, userId, input) {
|
|
3444
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3445
|
+
p_project_id: input.projectId,
|
|
3446
|
+
p_user_id: userId
|
|
3447
|
+
});
|
|
3448
|
+
if (accessError || !hasAccess) {
|
|
3449
|
+
throw new Error("Project not found or access denied");
|
|
3450
|
+
}
|
|
3313
3451
|
try {
|
|
3314
3452
|
const { data, error } = await supabase.rpc("execute_sql", {
|
|
3315
3453
|
query: `
|
|
@@ -3352,7 +3490,14 @@ async function auditRlsStatus(supabase, input) {
|
|
|
3352
3490
|
};
|
|
3353
3491
|
}
|
|
3354
3492
|
}
|
|
3355
|
-
async function auditSecurityIntegrity(supabase, input) {
|
|
3493
|
+
async function auditSecurityIntegrity(supabase, userId, input) {
|
|
3494
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3495
|
+
p_project_id: input.projectId,
|
|
3496
|
+
p_user_id: userId
|
|
3497
|
+
});
|
|
3498
|
+
if (accessError || !hasAccess) {
|
|
3499
|
+
throw new Error("Project not found or access denied");
|
|
3500
|
+
}
|
|
3356
3501
|
const violations = [];
|
|
3357
3502
|
const { content, filePath } = input;
|
|
3358
3503
|
const sqlViolation = checkSqlInjection(content);
|
|
@@ -3399,15 +3544,22 @@ registry.register({
|
|
|
3399
3544
|
Can trigger a SOFT LOCK if critical issues are found.`,
|
|
3400
3545
|
schema: AuditIntegrityGateInputSchema,
|
|
3401
3546
|
handler: async (args, context) => {
|
|
3402
|
-
const result = await runAuditIntegrityGate(context.supabase, args);
|
|
3547
|
+
const result = await runAuditIntegrityGate(context.supabase, context.userId, args);
|
|
3403
3548
|
return { content: [{ type: "text", text: result.summary }] };
|
|
3404
3549
|
}
|
|
3405
3550
|
});
|
|
3406
|
-
async function runAuditIntegrityGate(supabase, input) {
|
|
3551
|
+
async function runAuditIntegrityGate(supabase, userId, input) {
|
|
3552
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3553
|
+
p_project_id: input.projectId,
|
|
3554
|
+
p_user_id: userId
|
|
3555
|
+
});
|
|
3556
|
+
if (accessError || !hasAccess) {
|
|
3557
|
+
throw new Error("Project not found or access denied");
|
|
3558
|
+
}
|
|
3407
3559
|
const checks = [];
|
|
3408
3560
|
let isSoftLocked = false;
|
|
3409
3561
|
try {
|
|
3410
|
-
const rlsResult = await auditRlsStatus(supabase, { projectId: input.projectId });
|
|
3562
|
+
const rlsResult = await auditRlsStatus(supabase, userId, { projectId: input.projectId });
|
|
3411
3563
|
const unsecuredTables = rlsResult.unsecuredTables || [];
|
|
3412
3564
|
if (unsecuredTables.length > 0) {
|
|
3413
3565
|
isSoftLocked = true;
|
|
@@ -3436,7 +3588,7 @@ async function runAuditIntegrityGate(supabase, input) {
|
|
|
3436
3588
|
try {
|
|
3437
3589
|
const fs3 = await import("fs/promises");
|
|
3438
3590
|
const content = await fs3.readFile(path4, "utf-8");
|
|
3439
|
-
const securityResult = await auditSecurityIntegrity(supabase, {
|
|
3591
|
+
const securityResult = await auditSecurityIntegrity(supabase, userId, {
|
|
3440
3592
|
projectId: input.projectId,
|
|
3441
3593
|
filePath: path4,
|
|
3442
3594
|
content
|
|
@@ -3467,7 +3619,7 @@ async function runAuditIntegrityGate(supabase, input) {
|
|
|
3467
3619
|
}
|
|
3468
3620
|
if (input.filePaths && input.filePaths.length > 0) {
|
|
3469
3621
|
try {
|
|
3470
|
-
const perfResult = await analyzeDatabasePerformance(supabase, {
|
|
3622
|
+
const perfResult = await analyzeDatabasePerformance(supabase, userId, {
|
|
3471
3623
|
projectId: input.projectId,
|
|
3472
3624
|
filePaths: input.filePaths
|
|
3473
3625
|
});
|
|
@@ -3526,6 +3678,7 @@ registry.register({
|
|
|
3526
3678
|
handler: async (args, context) => {
|
|
3527
3679
|
const result = await completeRoadmapTask(
|
|
3528
3680
|
context.supabase,
|
|
3681
|
+
context.userId,
|
|
3529
3682
|
args.projectId,
|
|
3530
3683
|
args.summary,
|
|
3531
3684
|
args.taskId,
|
|
@@ -3535,7 +3688,14 @@ registry.register({
|
|
|
3535
3688
|
return { content: [{ type: "text", text: result.message }] };
|
|
3536
3689
|
}
|
|
3537
3690
|
});
|
|
3538
|
-
async function completeRoadmapTask(supabase, projectId, summary, taskId, gitDiff, integrityGate) {
|
|
3691
|
+
async function completeRoadmapTask(supabase, userId, projectId, summary, taskId, gitDiff, integrityGate) {
|
|
3692
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
3693
|
+
p_project_id: projectId,
|
|
3694
|
+
p_user_id: userId
|
|
3695
|
+
});
|
|
3696
|
+
if (accessError || !hasAccess) {
|
|
3697
|
+
throw new Error("Project not found or access denied");
|
|
3698
|
+
}
|
|
3539
3699
|
let targetTaskId = taskId;
|
|
3540
3700
|
if (!targetTaskId) {
|
|
3541
3701
|
const { data: activeTask } = await supabase.from("roadmap_chunks").select("id, title").eq("project_id", projectId).in("status", ["IN_PROGRESS", "ACTIVE"]).order("step_number", { ascending: true }).limit(1).single();
|
|
@@ -3952,8 +4112,18 @@ function interpolateScribePrompt(basePrompt, vars) {
|
|
|
3952
4112
|
// src/tools/generate-professional-pdf.ts
|
|
3953
4113
|
async function generateProfessionalPdf(supabase, userId, projectId, reportType) {
|
|
3954
4114
|
console.error(`\u{1F58B}\uFE0F The Scribe is preparing a ${reportType} briefing for project ${projectId}...`);
|
|
4115
|
+
const { data: hasAccess, error: accessError } = await supabase.rpc("check_project_access_secure", {
|
|
4116
|
+
p_project_id: projectId,
|
|
4117
|
+
p_user_id: userId
|
|
4118
|
+
});
|
|
4119
|
+
if (accessError || !hasAccess) {
|
|
4120
|
+
throw new Error("Project not found or access denied");
|
|
4121
|
+
}
|
|
3955
4122
|
const persona = await getScribePersona(supabase);
|
|
3956
|
-
const { data: project } = await supabase.from("projects").select("name, description, project_type, detected_stack").eq("id", projectId).single();
|
|
4123
|
+
const { data: project, error: projectError } = await supabase.from("projects").select("name, description, project_type, detected_stack").eq("id", projectId).single();
|
|
4124
|
+
if (projectError || !project) {
|
|
4125
|
+
throw new Error("Project details not found");
|
|
4126
|
+
}
|
|
3957
4127
|
const projectName = project?.name || "Rigstate Project";
|
|
3958
4128
|
const projectDescription = project?.description || "A cutting-edge software project built with modern architecture.";
|
|
3959
4129
|
const projectType = project?.project_type || "Web Application";
|