@rigstate/mcp 0.5.5 → 0.5.7
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 +163 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +0 -2
- package/src/lib/tool-registry.ts +1 -1
- package/src/server/telemetry.ts +0 -4
- package/src/tools/analyze-database-performance.ts +1 -1
- package/src/tools/arch-tools.ts +60 -45
- package/src/tools/complete-roadmap-task.ts +1 -1
- package/src/tools/list-features.ts +40 -27
- package/src/tools/query-brain.ts +49 -31
- package/src/tools/security-checks-arch.ts +85 -0
- package/src/tools/security-checks.ts +1 -0
- package/src/tools/security-tools.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
2
|
|
|
9
3
|
// src/index.ts
|
|
10
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -67,7 +61,7 @@ var ToolRegistry = class {
|
|
|
67
61
|
*/
|
|
68
62
|
register(tool) {
|
|
69
63
|
if (this.tools.has(tool.name)) {
|
|
70
|
-
console.
|
|
64
|
+
console.error(`Tool '${tool.name}' is already registered. Overwriting.`);
|
|
71
65
|
}
|
|
72
66
|
this.tools.set(tool.name, tool);
|
|
73
67
|
}
|
|
@@ -974,30 +968,29 @@ architecture rules, decisions, and constraints.`,
|
|
|
974
968
|
}
|
|
975
969
|
});
|
|
976
970
|
async function generateQueryEmbedding(query) {
|
|
977
|
-
const
|
|
978
|
-
const
|
|
979
|
-
if (!
|
|
971
|
+
const apiKey = process.env.RIGSTATE_API_KEY;
|
|
972
|
+
const apiUrl = process.env.RIGSTATE_API_URL || "http://localhost:3000/api/v1";
|
|
973
|
+
if (!apiKey) {
|
|
980
974
|
return null;
|
|
981
975
|
}
|
|
982
976
|
try {
|
|
983
|
-
const
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
model: google.embedding("text-embedding-004"),
|
|
996
|
-
value: query.replace(/\n/g, " ")
|
|
997
|
-
});
|
|
998
|
-
return embedding;
|
|
977
|
+
const response = await fetch(`${apiUrl}/intelligence/embed`, {
|
|
978
|
+
method: "POST",
|
|
979
|
+
headers: {
|
|
980
|
+
"Content-Type": "application/json",
|
|
981
|
+
"Authorization": `Bearer ${apiKey}`
|
|
982
|
+
},
|
|
983
|
+
body: JSON.stringify({ text: query })
|
|
984
|
+
});
|
|
985
|
+
if (!response.ok) {
|
|
986
|
+
const errorText = await response.text();
|
|
987
|
+
console.error(`Embedding API error (${response.status}):`, errorText);
|
|
988
|
+
return null;
|
|
999
989
|
}
|
|
990
|
+
const result = await response.json();
|
|
991
|
+
return result.data?.embedding || null;
|
|
1000
992
|
} catch (error) {
|
|
993
|
+
console.error("Failed to generate embedding via Proxy:", error);
|
|
1001
994
|
return null;
|
|
1002
995
|
}
|
|
1003
996
|
}
|
|
@@ -1037,6 +1030,13 @@ async function queryBrain(supabase, userId, projectId, query, limit = 8, thresho
|
|
|
1037
1030
|
createdAt: m.created_at
|
|
1038
1031
|
}));
|
|
1039
1032
|
}
|
|
1033
|
+
let relevantFeatures = [];
|
|
1034
|
+
try {
|
|
1035
|
+
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);
|
|
1036
|
+
if (features) relevantFeatures = features;
|
|
1037
|
+
} catch (e) {
|
|
1038
|
+
console.warn("Feature fetch failed in brain query", e);
|
|
1039
|
+
}
|
|
1040
1040
|
const contextLines = memories.map((m) => {
|
|
1041
1041
|
const voteIndicator = m.netVotes && m.netVotes < 0 ? ` [\u26A0\uFE0F POORLY RATED: ${m.netVotes}]` : "";
|
|
1042
1042
|
const tagStr = m.tags && m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
|
|
@@ -1044,17 +1044,28 @@ async function queryBrain(supabase, userId, projectId, query, limit = 8, thresho
|
|
|
1044
1044
|
return `- [${category}]${tagStr}${voteIndicator}: ${m.content}`;
|
|
1045
1045
|
});
|
|
1046
1046
|
const searchType = embedding ? "TRIPLE-HYBRID (Vector + FTS + Fuzzy)" : "HYBRID (FTS + Fuzzy)";
|
|
1047
|
-
|
|
1047
|
+
let formatted = `=== PROJECT BRAIN: RELEVANT MEMORIES ===
|
|
1048
1048
|
Search Mode: ${searchType}
|
|
1049
|
-
Query: "${query}"
|
|
1049
|
+
Query: "${query}"`;
|
|
1050
|
+
if (relevantFeatures.length > 0) {
|
|
1051
|
+
formatted += `
|
|
1052
|
+
|
|
1053
|
+
=== RELATED FEATURES ===
|
|
1054
|
+
` + relevantFeatures.map((f) => `- ${f.name} [${f.status}]`).join("\n");
|
|
1055
|
+
}
|
|
1056
|
+
formatted += `
|
|
1057
|
+
|
|
1050
1058
|
Found ${memories.length} relevant memories:
|
|
1051
1059
|
|
|
1052
1060
|
${contextLines.join("\n")}
|
|
1053
1061
|
|
|
1054
|
-
|
|
1062
|
+
==========================================`;
|
|
1063
|
+
if (memories.length === 0 && relevantFeatures.length === 0) {
|
|
1064
|
+
formatted = `=== PROJECT BRAIN ===
|
|
1055
1065
|
Query: "${query}"
|
|
1056
|
-
No relevant memories
|
|
1066
|
+
No relevant memories or features found.
|
|
1057
1067
|
=======================`;
|
|
1068
|
+
}
|
|
1058
1069
|
return {
|
|
1059
1070
|
query,
|
|
1060
1071
|
memories,
|
|
@@ -1579,25 +1590,41 @@ var listFeaturesTool = {
|
|
|
1579
1590
|
Useful for understanding the strategic context and major milestones.`,
|
|
1580
1591
|
schema: InputSchema,
|
|
1581
1592
|
handler: async ({ projectId }, { supabase, userId }) => {
|
|
1582
|
-
const { data: project, error: projectError } = await supabase.from("projects").select("id").eq("id", projectId).eq("owner_id", userId).single();
|
|
1593
|
+
const { data: project, error: projectError } = await supabase.from("projects").select("id, functional_spec").eq("id", projectId).eq("owner_id", userId).single();
|
|
1583
1594
|
if (projectError || !project) {
|
|
1584
1595
|
throw new Error("Project not found or access denied");
|
|
1585
1596
|
}
|
|
1586
|
-
const { data:
|
|
1587
|
-
|
|
1588
|
-
|
|
1597
|
+
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 });
|
|
1598
|
+
let featuresList = [];
|
|
1599
|
+
let source = "DB";
|
|
1600
|
+
if (!dbError && dbFeatures && dbFeatures.length > 0) {
|
|
1601
|
+
featuresList = dbFeatures.map((f) => ({
|
|
1602
|
+
...f,
|
|
1603
|
+
title: f.name
|
|
1604
|
+
// Map back to title specifically for uniform handling below
|
|
1605
|
+
}));
|
|
1606
|
+
} else {
|
|
1607
|
+
source = "FALLBACK_SPEC";
|
|
1608
|
+
console.error(`[WARN] Project ${projectId}: 'project_features' empty or missing. Falling back to 'functional_spec'.`);
|
|
1609
|
+
const spec = project.functional_spec;
|
|
1610
|
+
if (spec && typeof spec === "object" && Array.isArray(spec.features)) {
|
|
1611
|
+
featuresList = spec.features.map((f) => ({
|
|
1612
|
+
id: "legacy",
|
|
1613
|
+
title: f.name || f.title,
|
|
1614
|
+
description: f.description,
|
|
1615
|
+
status: f.status || "proposed"
|
|
1616
|
+
}));
|
|
1617
|
+
}
|
|
1589
1618
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1619
|
+
if (featuresList.length === 0) {
|
|
1620
|
+
return { content: [{ type: "text", text: "No active features found (checked DB and Spec)." }] };
|
|
1621
|
+
}
|
|
1622
|
+
const formatted = `=== PROJECT FEATURES (Source: ${source}) ===
|
|
1623
|
+
` + featuresList.map((f) => {
|
|
1624
|
+
return `- ${f.title} [${f.status}]`;
|
|
1625
|
+
}).join("\n");
|
|
1594
1626
|
return {
|
|
1595
|
-
content: [
|
|
1596
|
-
{
|
|
1597
|
-
type: "text",
|
|
1598
|
-
text: formatted
|
|
1599
|
-
}
|
|
1600
|
-
]
|
|
1627
|
+
content: [{ type: "text", text: formatted }]
|
|
1601
1628
|
};
|
|
1602
1629
|
}
|
|
1603
1630
|
};
|
|
@@ -1831,7 +1858,7 @@ async function analyzeDatabasePerformance(supabase, input) {
|
|
|
1831
1858
|
}
|
|
1832
1859
|
}
|
|
1833
1860
|
} catch (e) {
|
|
1834
|
-
console.
|
|
1861
|
+
console.error(`Skipping file ${filePath}: ${e}`);
|
|
1835
1862
|
}
|
|
1836
1863
|
}
|
|
1837
1864
|
const highSev = issues.filter((i) => i.severity === "HIGH").length;
|
|
@@ -2054,6 +2081,58 @@ function checkAntiLazy(filePath, content) {
|
|
|
2054
2081
|
return violations;
|
|
2055
2082
|
}
|
|
2056
2083
|
|
|
2084
|
+
// src/tools/security-checks-arch.ts
|
|
2085
|
+
function checkArchitectureIntegrity(filePath, content) {
|
|
2086
|
+
const violations = [];
|
|
2087
|
+
const isUI = filePath.includes("/components/") || filePath.includes("/hooks/") || filePath.includes("/app/") && !filePath.includes("/api/") && !filePath.includes("actions.ts") && !filePath.includes("route.ts");
|
|
2088
|
+
if (isUI) {
|
|
2089
|
+
const illegalImportRegex = /(import.*from\s+['"]@supabase\/supabase-js['"])/g;
|
|
2090
|
+
if (illegalImportRegex.test(content)) {
|
|
2091
|
+
violations.push({
|
|
2092
|
+
id: "SEC-ARCH-01",
|
|
2093
|
+
type: "ARCHITECTURE_VIOLATION",
|
|
2094
|
+
severity: "FATAL",
|
|
2095
|
+
title: "Illegal Supabase Client in UI",
|
|
2096
|
+
description: "Direct import of @supabase/supabase-js in a UI component/hook is strictly forbidden. It bypasses the server boundary.",
|
|
2097
|
+
recommendation: "Use the `createClient` helper from our utils or Server Actions for data access."
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
if (isUI) {
|
|
2102
|
+
const dbActionRegex = /\.(from|select|insert|update|delete|rpc)\s*\(/g;
|
|
2103
|
+
const matches = content.match(dbActionRegex);
|
|
2104
|
+
if (matches) {
|
|
2105
|
+
const suspicious = matches.some((m) => !m.includes(".from") || m.includes(".from") && content.includes("supabase.from"));
|
|
2106
|
+
if (suspicious || matches.length > 0 && content.includes("supabase")) {
|
|
2107
|
+
violations.push({
|
|
2108
|
+
id: "SEC-ARCH-02",
|
|
2109
|
+
type: "ARCHITECTURE_VIOLATION",
|
|
2110
|
+
severity: "FATAL",
|
|
2111
|
+
title: "Direct Database Query in UI",
|
|
2112
|
+
description: "Detected direct database query pattern (select/insert/update/delete) in a UI component. This exposes logic to the client.",
|
|
2113
|
+
recommendation: "Move all data fetching logic to Server Components or Server Actions."
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
const isActionFile = filePath.includes("/actions/") || filePath.includes("actions.ts");
|
|
2119
|
+
if (isActionFile) {
|
|
2120
|
+
const header = content.slice(0, 200);
|
|
2121
|
+
const hasUseServer = /['"]use server['"]/.test(header);
|
|
2122
|
+
if (!hasUseServer) {
|
|
2123
|
+
violations.push({
|
|
2124
|
+
id: "SEC-ARCH-03",
|
|
2125
|
+
type: "ARCHITECTURE_VIOLATION",
|
|
2126
|
+
severity: "FATAL",
|
|
2127
|
+
title: 'Missing "use server" Directive',
|
|
2128
|
+
description: 'File appears to be a Server Action module but lacks the "use server" directive.',
|
|
2129
|
+
recommendation: 'Add "use server" at the very top of the file.'
|
|
2130
|
+
});
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
return violations;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2057
2136
|
// src/tools/security-tools.ts
|
|
2058
2137
|
registry.register({
|
|
2059
2138
|
name: "audit_rls_status",
|
|
@@ -2141,6 +2220,8 @@ async function auditSecurityIntegrity(supabase, input) {
|
|
|
2141
2220
|
if (depViolation) violations.push(depViolation);
|
|
2142
2221
|
const lazyViolations = checkAntiLazy(filePath, content);
|
|
2143
2222
|
violations.push(...lazyViolations);
|
|
2223
|
+
const archViolations = checkArchitectureIntegrity(filePath, content);
|
|
2224
|
+
violations.push(...archViolations);
|
|
2144
2225
|
const score = Math.max(0, 100 - violations.length * 10);
|
|
2145
2226
|
const passed = !violations.some((v) => v.severity === "HIGH" || v.severity === "FATAL");
|
|
2146
2227
|
return {
|
|
@@ -2341,7 +2422,7 @@ async function completeRoadmapTask(supabase, projectId, summary, taskId, gitDiff
|
|
|
2341
2422
|
metadata
|
|
2342
2423
|
});
|
|
2343
2424
|
if (reportError) {
|
|
2344
|
-
console.
|
|
2425
|
+
console.error("Failed to save mission report:", reportError.message);
|
|
2345
2426
|
}
|
|
2346
2427
|
try {
|
|
2347
2428
|
const apiKey = process.env.RIGSTATE_API_KEY;
|
|
@@ -2460,7 +2541,7 @@ async function addRoadmapChunk(supabase, userId, input) {
|
|
|
2460
2541
|
}
|
|
2461
2542
|
|
|
2462
2543
|
// src/tools/arch-tools.ts
|
|
2463
|
-
import { promises as fs2 } from "fs";
|
|
2544
|
+
import { promises as fs2, existsSync, statSync } from "fs";
|
|
2464
2545
|
import * as path2 from "path";
|
|
2465
2546
|
registry.register({
|
|
2466
2547
|
name: "analyze_dependency_graph",
|
|
@@ -2480,22 +2561,38 @@ async function analyzeDependencyGraph(input) {
|
|
|
2480
2561
|
error: `Directory not found: ${searchPath}. Ensure you are running the MCP server in the project root or provide an absolute path.`
|
|
2481
2562
|
};
|
|
2482
2563
|
}
|
|
2564
|
+
let externalDeps = {};
|
|
2565
|
+
const pkgPath = path2.join(process.cwd(), "package.json");
|
|
2566
|
+
if (existsSync(pkgPath)) {
|
|
2567
|
+
try {
|
|
2568
|
+
const pkgContent = await fs2.readFile(pkgPath, "utf-8");
|
|
2569
|
+
const pkg = JSON.parse(pkgContent);
|
|
2570
|
+
externalDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2571
|
+
} catch (e) {
|
|
2572
|
+
console.error("Failed to parse package.json", e);
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2483
2575
|
const allFiles = await getAllFiles(searchPath);
|
|
2484
|
-
const tsFiles = allFiles.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f) && !f.includes("node_modules") && !f.includes("
|
|
2576
|
+
const tsFiles = allFiles.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f) && !f.includes("node_modules") && !f.includes("dist") && !f.includes(".next"));
|
|
2485
2577
|
const graph = {};
|
|
2486
|
-
const fileSet = new Set(tsFiles);
|
|
2487
2578
|
for (const file of tsFiles) {
|
|
2488
2579
|
const content = await fs2.readFile(file, "utf-8");
|
|
2489
2580
|
const imports = extractImports(content);
|
|
2490
2581
|
const validDeps = [];
|
|
2582
|
+
const fileDir = path2.dirname(file);
|
|
2491
2583
|
for (const imp of imports) {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2584
|
+
if (Object.keys(externalDeps).some((d) => imp === d || imp.startsWith(d + "/"))) {
|
|
2585
|
+
continue;
|
|
2586
|
+
}
|
|
2587
|
+
if (imp.startsWith(".") || imp.startsWith("@/")) {
|
|
2588
|
+
const resolved = resolveImportString(file, imp, searchPath);
|
|
2589
|
+
if (resolved && tsFiles.includes(resolved)) {
|
|
2590
|
+
validDeps.push(path2.relative(searchPath, resolved));
|
|
2591
|
+
}
|
|
2495
2592
|
}
|
|
2496
2593
|
}
|
|
2497
2594
|
const relFile = path2.relative(searchPath, file);
|
|
2498
|
-
graph[relFile] = validDeps
|
|
2595
|
+
graph[relFile] = validDeps;
|
|
2499
2596
|
}
|
|
2500
2597
|
const cycles = detectCycles(graph);
|
|
2501
2598
|
return {
|
|
@@ -2503,11 +2600,12 @@ async function analyzeDependencyGraph(input) {
|
|
|
2503
2600
|
analyzedPath: searchPath,
|
|
2504
2601
|
metrics: {
|
|
2505
2602
|
totalFiles: tsFiles.length,
|
|
2506
|
-
circularDependencies: cycles.length
|
|
2603
|
+
circularDependencies: cycles.length,
|
|
2604
|
+
externalDependencies: Object.keys(externalDeps).length
|
|
2507
2605
|
},
|
|
2508
2606
|
cycles,
|
|
2509
2607
|
status: cycles.length > 0 ? "VIOLATION" : "PASS",
|
|
2510
|
-
summary: cycles.length > 0 ? `FAILED. Detected ${cycles.length} circular dependencies.
|
|
2608
|
+
summary: cycles.length > 0 ? `FAILED. Detected ${cycles.length} circular dependencies. Einar demands resolution!` : `PASSED. Architecture is sound. No circular dependencies in ${tsFiles.length} files.`
|
|
2511
2609
|
};
|
|
2512
2610
|
}
|
|
2513
2611
|
async function getAllFiles(dir) {
|
|
@@ -2527,24 +2625,24 @@ function extractImports(content) {
|
|
|
2527
2625
|
}
|
|
2528
2626
|
return imports;
|
|
2529
2627
|
}
|
|
2530
|
-
function
|
|
2531
|
-
|
|
2532
|
-
return null;
|
|
2533
|
-
}
|
|
2534
|
-
let searchDir = path2.dirname(importer);
|
|
2628
|
+
function resolveImportString(importer, importPath, root) {
|
|
2629
|
+
let targetDir = path2.dirname(importer);
|
|
2535
2630
|
let target = importPath;
|
|
2536
2631
|
if (importPath.startsWith("@/")) {
|
|
2537
2632
|
target = importPath.replace("@/", "");
|
|
2538
|
-
|
|
2633
|
+
targetDir = root;
|
|
2539
2634
|
}
|
|
2540
|
-
const
|
|
2541
|
-
const extensions = [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx"
|
|
2635
|
+
const naivePath = path2.resolve(targetDir, target);
|
|
2636
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx"];
|
|
2542
2637
|
for (const ext of extensions) {
|
|
2543
|
-
const candidate =
|
|
2544
|
-
if (
|
|
2638
|
+
const candidate = naivePath + ext;
|
|
2639
|
+
if (existsSync(candidate) && !statSync(candidate).isDirectory()) {
|
|
2545
2640
|
return candidate;
|
|
2546
2641
|
}
|
|
2547
2642
|
}
|
|
2643
|
+
if (existsSync(naivePath) && !statSync(naivePath).isDirectory()) {
|
|
2644
|
+
return naivePath;
|
|
2645
|
+
}
|
|
2548
2646
|
return null;
|
|
2549
2647
|
}
|
|
2550
2648
|
function detectCycles(graph) {
|
|
@@ -2876,7 +2974,6 @@ var watcherState = {
|
|
|
2876
2974
|
async function startFrankWatcher(supabase, userId) {
|
|
2877
2975
|
if (watcherState.isRunning) return;
|
|
2878
2976
|
watcherState.isRunning = true;
|
|
2879
|
-
console.error(`\u{1F916} Frank Watcher started for user ${userId}`);
|
|
2880
2977
|
const checkTasks = async () => {
|
|
2881
2978
|
try {
|
|
2882
2979
|
watcherState.lastCheck = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2886,8 +2983,6 @@ async function startFrankWatcher(supabase, userId) {
|
|
|
2886
2983
|
const task = tasks[0];
|
|
2887
2984
|
watcherState.tasksFound++;
|
|
2888
2985
|
if (task.proposal?.startsWith("ping") || task.task_id === null && !task.proposal?.startsWith("report")) {
|
|
2889
|
-
console.error(`
|
|
2890
|
-
\u26A1 HEARTBEAT: Frank received REAL-TIME PING for project ${task.project_id}. Response: PONG`);
|
|
2891
2986
|
await supabase.from("agent_bridge").update({
|
|
2892
2987
|
status: "COMPLETED",
|
|
2893
2988
|
summary: "Pong! Frank is active and listening.",
|
|
@@ -2899,8 +2994,6 @@ async function startFrankWatcher(supabase, userId) {
|
|
|
2899
2994
|
const parts = task.proposal.split(":");
|
|
2900
2995
|
const signalType = parts[1];
|
|
2901
2996
|
const reportType = signalType === "MANIFEST" ? "SYSTEM_MANIFEST" : "INVESTOR_REPORT";
|
|
2902
|
-
console.error(`
|
|
2903
|
-
\u{1F4C4} Frank is generating ${reportType} report...`);
|
|
2904
2997
|
try {
|
|
2905
2998
|
const result = await generateProfessionalPdf(supabase, userId, task.project_id, reportType);
|
|
2906
2999
|
await supabase.from("agent_bridge").update({
|
|
@@ -2919,8 +3012,6 @@ async function startFrankWatcher(supabase, userId) {
|
|
|
2919
3012
|
return;
|
|
2920
3013
|
}
|
|
2921
3014
|
if (task.status === "APPROVED") {
|
|
2922
|
-
console.error(`
|
|
2923
|
-
\u{1F3D7}\uFE0F Worker: EXECUTING approved task: [${task.id}]`);
|
|
2924
3015
|
await supabase.from("agent_bridge").update({ status: "EXECUTING", updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", task.id);
|
|
2925
3016
|
await new Promise((resolve2) => setTimeout(resolve2, 2e3));
|
|
2926
3017
|
const taskTitle2 = task.roadmap_chunks?.title || "manual objective";
|
|
@@ -3006,7 +3097,6 @@ async function main() {
|
|
|
3006
3097
|
setupToolHandlers(server, { supabase, userId });
|
|
3007
3098
|
const transport = new StdioServerTransport();
|
|
3008
3099
|
await server.connect(transport);
|
|
3009
|
-
console.error("\u{1F6F0}\uFE0F Rigstate MCP Server (Evolutionary) running on stdio");
|
|
3010
3100
|
}
|
|
3011
3101
|
main().catch((error) => {
|
|
3012
3102
|
console.error("FATAL ERROR:", error);
|