@rigstate/mcp 0.7.5 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigstate/mcp",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Rigstate MCP Server - Model Context Protocol for AI Editors",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,171 @@
1
+ import { GitCommit, DiscoveredFeature } from './types.js';
2
+
3
+ /**
4
+ * Parse git log output into structured commits
5
+ */
6
+ export function parseGitLog(logOutput: string): GitCommit[] {
7
+ const commits: GitCommit[] = [];
8
+ const entries = logOutput.split('\n---COMMIT---\n').filter(Boolean);
9
+
10
+ for (const entry of entries) {
11
+ const lines = entry.trim().split('\n');
12
+ if (lines.length >= 3) {
13
+ commits.push({
14
+ hash: lines[0]?.replace('hash:', '').trim() || '',
15
+ date: lines[1]?.replace('date:', '').trim() || '',
16
+ author: lines[2]?.replace('author:', '').trim() || '',
17
+ message: lines.slice(3).join('\n').trim()
18
+ });
19
+ }
20
+ }
21
+
22
+ return commits;
23
+ }
24
+
25
+ /**
26
+ * Analyze commits to identify major milestones
27
+ */
28
+ export function identifyMilestones(commits: GitCommit[]): { date: string; summary: string; commits: string[] }[] {
29
+ const milestones: { date: string; summary: string; commits: string[] }[] = [];
30
+
31
+ // Keywords that indicate significant features
32
+ const featurePatterns = [
33
+ { pattern: /\b(auth|authentication|login|signup|oauth)\b/i, category: 'Authentication System' },
34
+ { pattern: /\b(database|schema|migration|supabase|postgres)\b/i, category: 'Database Setup' },
35
+ { pattern: /\b(api|endpoint|route)\b/i, category: 'API Development' },
36
+ { pattern: /\b(ui|component|layout|design|tailwind)\b/i, category: 'UI/Component Development' },
37
+ { pattern: /\b(test|spec|jest|vitest)\b/i, category: 'Testing Infrastructure' },
38
+ { pattern: /\b(deploy|ci|cd|github|vercel|docker)\b/i, category: 'DevOps & Deployment' },
39
+ { pattern: /\b(feature|implement|add|create|build)\b/i, category: 'Feature Implementation' },
40
+ { pattern: /\b(fix|bug|patch|resolve)\b/i, category: 'Bug Fixes & Patches' },
41
+ { pattern: /\b(refactor|clean|optimize|improve)\b/i, category: 'Code Quality Improvements' },
42
+ { pattern: /\b(docs|readme|documentation)\b/i, category: 'Documentation' },
43
+ { pattern: /\b(config|setup|init|scaffold)\b/i, category: 'Project Configuration' },
44
+ { pattern: /\b(agent|mcp|ai|llm|openai)\b/i, category: 'AI/Agent Integration' },
45
+ { pattern: /\b(roadmap|milestone|chunk)\b/i, category: 'Roadmap System' },
46
+ { pattern: /\b(report|pdf|manifest|governance)\b/i, category: 'Reporting & Governance' },
47
+ ];
48
+
49
+ // Group commits by category
50
+ const categoryMap = new Map<string, { commits: GitCommit[]; latestDate: string }>();
51
+
52
+ for (const commit of commits) {
53
+ for (const { pattern, category } of featurePatterns) {
54
+ if (pattern.test(commit.message)) {
55
+ if (!categoryMap.has(category)) {
56
+ categoryMap.set(category, { commits: [], latestDate: commit.date });
57
+ }
58
+ const entry = categoryMap.get(category)!;
59
+ entry.commits.push(commit);
60
+ if (new Date(commit.date) > new Date(entry.latestDate)) {
61
+ entry.latestDate = commit.date;
62
+ }
63
+ break; // Only categorize each commit once
64
+ }
65
+ }
66
+ }
67
+
68
+ // Convert to milestones (only include categories with 2+ commits)
69
+ for (const [category, data] of categoryMap.entries()) {
70
+ if (data.commits.length >= 2) {
71
+ milestones.push({
72
+ date: data.latestDate,
73
+ summary: `${category} (${data.commits.length} commits)`,
74
+ commits: data.commits.slice(0, 5).map(c => c.message.split('\n')[0].substring(0, 80))
75
+ });
76
+ }
77
+ }
78
+
79
+ // Sort by date descending
80
+ milestones.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
81
+
82
+ return milestones;
83
+ }
84
+
85
+ /**
86
+ * Map directory structure to potential features
87
+ */
88
+ export function analyzeFilesystem(tree: string[]): { featureDirectories: string[]; configFiles: string[] } {
89
+ const featurePatterns = [
90
+ /^(apps|packages)\/[^/]+\/src\/(components|features|modules)\/[^/]+$/,
91
+ /^(apps|packages)\/[^/]+\/src\/app\/[^/]+$/,
92
+ /^src\/(components|features|modules|pages)\/[^/]+$/,
93
+ /^(apps|packages)\/[^/]+$/,
94
+ ];
95
+
96
+ const configPatterns = [
97
+ /package\.json$/,
98
+ /tsconfig.*\.json$/,
99
+ /\.env.*$/,
100
+ /next\.config\./,
101
+ /tailwind\.config\./,
102
+ /supabase.*\.toml$/,
103
+ ];
104
+
105
+ const featureDirectories = tree.filter(path =>
106
+ featurePatterns.some(pattern => pattern.test(path))
107
+ );
108
+
109
+ const configFiles = tree.filter(path =>
110
+ configPatterns.some(pattern => pattern.test(path))
111
+ );
112
+
113
+ return {
114
+ featureDirectories: [...new Set(featureDirectories)].slice(0, 20),
115
+ configFiles: [...new Set(configFiles)].slice(0, 10)
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Generate discovered features from milestones and filesystem
121
+ */
122
+ export function generateDiscoveredFeatures(
123
+ milestones: { date: string; summary: string; commits: string[] }[],
124
+ filesystemAnalysis: { featureDirectories: string[]; configFiles: string[] }
125
+ ): DiscoveredFeature[] {
126
+ const features: DiscoveredFeature[] = [];
127
+ let priority = 1;
128
+
129
+ // From Git milestones
130
+ for (const milestone of milestones.slice(0, 10)) {
131
+ const id = `ghost-${Date.now()}-${priority}`;
132
+ features.push({
133
+ id,
134
+ title: milestone.summary.split('(')[0].trim(),
135
+ description: `Reconstructed from ${milestone.commits.length} commits. Last activity: ${new Date(milestone.date).toLocaleDateString()}`,
136
+ status: 'COMPLETED',
137
+ source: 'git',
138
+ evidence: milestone.commits,
139
+ estimatedCompletionDate: milestone.date,
140
+ priority: priority++
141
+ });
142
+ }
143
+
144
+ // From filesystem (major directories as features)
145
+ const directoryFeatures = filesystemAnalysis.featureDirectories
146
+ .filter(dir => dir.includes('src/') || dir.startsWith('apps/') || dir.startsWith('packages/'))
147
+ .slice(0, 5);
148
+
149
+ for (const dir of directoryFeatures) {
150
+ const name = dir.split('/').pop() || dir;
151
+ const id = `ghost-fs-${Date.now()}-${priority}`;
152
+
153
+ // Skip if we already have a similar feature from git
154
+ if (features.some(f => f.title.toLowerCase().includes(name.toLowerCase()))) {
155
+ continue;
156
+ }
157
+
158
+ features.push({
159
+ id,
160
+ title: `${name.charAt(0).toUpperCase() + name.slice(1)} Module`,
161
+ description: `Detected from directory structure: ${dir}`,
162
+ status: 'COMPLETED',
163
+ source: 'filesystem',
164
+ evidence: [dir],
165
+ estimatedCompletionDate: new Date().toISOString(),
166
+ priority: priority++
167
+ });
168
+ }
169
+
170
+ return features;
171
+ }
@@ -11,15 +11,14 @@ export async function submitSignal(
11
11
  userId: string,
12
12
  input: z.infer<typeof SubmitSignalSchema>
13
13
  ) {
14
- // 1. Verify project ownership
15
- const { data: project, error: projectError } = await supabase
16
- .from('projects')
17
- .select('id')
18
- .eq('id', input.projectId)
19
- .eq('owner_id', userId)
20
- .single();
21
-
22
- if (projectError || !project) {
14
+ // 1. Verify project access
15
+ const { data: hasAccess, error: accessError } = await supabase
16
+ .rpc('check_project_access_secure', {
17
+ p_project_id: input.projectId,
18
+ p_user_id: userId
19
+ });
20
+
21
+ if (accessError || !hasAccess) {
23
22
  throw new Error('Project not found or access denied');
24
23
  }
25
24
 
@@ -0,0 +1,148 @@
1
+ import { TechStackInfo } from '../lib/types.js';
2
+
3
+ export async function buildProjectSummary(
4
+ project: any,
5
+ techStack: TechStackInfo,
6
+ activeTask: any,
7
+ nextTask: any,
8
+ agentTasks: any[],
9
+ roadmapItems: any[],
10
+ stackDef: any,
11
+ supabase: any,
12
+ userId: string
13
+ ): Promise<string> {
14
+ const summaryParts: string[] = [];
15
+
16
+ summaryParts.push(`Project Type: ${project.project_type?.toUpperCase() || 'UNKNOWN'}`);
17
+
18
+ // Active Mission Parameters
19
+ if (stackDef || activeTask || nextTask) {
20
+ summaryParts.push('\n=== ACTIVE MISSION PARAMETERS ===');
21
+ if (activeTask) {
22
+ summaryParts.push(`⚠️ CURRENT OBJECTIVE: T-${activeTask.step_number}: ${activeTask.title}`);
23
+ summaryParts.push(` Role: ${activeTask.role || 'Developer'}`);
24
+
25
+ const detailedInstructions = activeTask.prompt_content || activeTask.instruction_set;
26
+ if (detailedInstructions) {
27
+ summaryParts.push(` Instructions: ${detailedInstructions.substring(0, 1000)}...`);
28
+ }
29
+ if (activeTask.architectural_brief) {
30
+ summaryParts.push(`\n Architectural Brief: ${activeTask.architectural_brief}`);
31
+ }
32
+ if (activeTask.context_summary) {
33
+ summaryParts.push(`\n Context: ${activeTask.context_summary}`);
34
+ }
35
+ if (activeTask.checklist && activeTask.checklist.length > 0) {
36
+ summaryParts.push('\n Checklist (DoD):');
37
+ activeTask.checklist.forEach((item: any) => {
38
+ summaryParts.push(` [ ] ${typeof item === 'string' ? item : item.task}`);
39
+ });
40
+ }
41
+ if (activeTask.metadata && Object.keys(activeTask.metadata).length > 0) {
42
+ summaryParts.push(`\n Technical Metadata: ${JSON.stringify(activeTask.metadata)}`);
43
+ }
44
+ if (activeTask.tags && activeTask.tags.length > 0) {
45
+ summaryParts.push(` Tags: ${activeTask.tags.join(', ')}`);
46
+ }
47
+
48
+ // Enhanced Feature Context (Secure)
49
+ if (activeTask.feature_id) {
50
+ try {
51
+ const { data: dbFeatures } = await supabase
52
+ .rpc('get_project_features_secure', {
53
+ p_project_id: project.id,
54
+ p_user_id: userId
55
+ });
56
+
57
+ const feature = dbFeatures?.find((f: any) => f.id === activeTask.feature_id);
58
+
59
+ if (feature) {
60
+ summaryParts.push(`\n Parent Feature: ${feature.name}`);
61
+ summaryParts.push(` Feature Vision: ${feature.description}`);
62
+ }
63
+ } catch (e) {
64
+ console.warn('Feature context fetch failed', e);
65
+ }
66
+ }
67
+
68
+ summaryParts.push('\n ACTION: Focus ALL coding efforts on completing this task.');
69
+ } else if (nextTask) {
70
+ summaryParts.push(`⏸ SYSTEM IDLE (Waiting for command)`);
71
+ summaryParts.push(` Suggested Next Mission: T-${nextTask.step_number}: ${nextTask.title}`);
72
+ if (nextTask.tags && nextTask.tags.length > 0) {
73
+ summaryParts.push(` Scope: ${nextTask.tags.join(', ')}`);
74
+ }
75
+ summaryParts.push(` ACTION: Ask the user "Shall we start T-${nextTask.step_number}?"`);
76
+ } else {
77
+ summaryParts.push('✅ ALL MISSIONS COMPLETE. Awaiting new roadmap items.');
78
+ }
79
+
80
+ summaryParts.push('\n=== AI BEHAVIORAL INSTRUCTIONS ===');
81
+ if (activeTask) {
82
+ summaryParts.push(`1. FOCUS: The user is working on T-${activeTask.step_number}. Help them complete it.`);
83
+ summaryParts.push(`2. COMPLIANCE: Ensure all code follows project standards.`);
84
+ } else if (nextTask) {
85
+ summaryParts.push(`1. NUDGE: No active task found. Suggest starting T-${nextTask.step_number} (${nextTask.title}).`);
86
+ summaryParts.push(`2. PROACTIVE: Instead of asking "How can I help?", ask "Shall we start on T-${nextTask.step_number}?"`);
87
+ }
88
+
89
+ summaryParts.push('\n=== CURRENT STACK ===');
90
+ if (stackDef) {
91
+ if (stackDef.frontend) summaryParts.push(`Frontend: ${stackDef.frontend.framework} (${stackDef.frontend.language})`);
92
+ if (stackDef.backend) summaryParts.push(`Backend: ${stackDef.backend.service} (${stackDef.backend.database})`);
93
+ if (stackDef.styling) summaryParts.push(`Styling: ${stackDef.styling.framework} ${stackDef.styling.library || ''}`);
94
+ if (stackDef.hosting) summaryParts.push(`Infrastructure: ${stackDef.hosting.provider}`);
95
+ } else {
96
+ if (techStack.framework) summaryParts.push(`Framework: ${techStack.framework}`);
97
+ if (techStack.orm) summaryParts.push(`ORM: ${techStack.orm}`);
98
+ }
99
+ }
100
+
101
+ if (project.description) {
102
+ summaryParts.push(`\nDescription: ${project.description}`);
103
+ }
104
+
105
+ if (project.functional_spec) {
106
+ summaryParts.push('\n=== STRATEGIC PROJECT SPECIFICATION (NUANCES) ===');
107
+ const spec = typeof project.functional_spec === 'string' ? JSON.parse(project.functional_spec) : project.functional_spec;
108
+
109
+ if (spec.projectDescription) summaryParts.push(`Vision: ${spec.projectDescription}`);
110
+ if (spec.targetAudience) summaryParts.push(`Audience: ${spec.targetAudience}`);
111
+ if (spec.coreProblem) summaryParts.push(`Core Problem: ${spec.coreProblem}`);
112
+
113
+ if (spec.featureList && Array.isArray(spec.featureList)) {
114
+ summaryParts.push('\nKey Features & Nuances:');
115
+ spec.featureList.filter((f: any) => f.priority === 'MVP' || f.priority === 'HIGH').slice(0, 10).forEach((f: any) => {
116
+ summaryParts.push(`- ${f.name}: ${f.description?.substring(0, 200)}`);
117
+ });
118
+ }
119
+ }
120
+
121
+ summaryParts.push('\n=== RIGSTATE TOOLING GUIDELINES ===');
122
+ summaryParts.push('You have access to specialized MCP tools. USE THEM TO SUCCEED:');
123
+ summaryParts.push('1. NEVER guess about architecture. Use `query_brain` to search project documentation.');
124
+ summaryParts.push('2. BEFORE coding, check `get_learned_instructions` to see if you have been corrected before.');
125
+ summaryParts.push('3. When finishing a task, ALWAYS update the roadmap using `update_roadmap`.');
126
+ summaryParts.push('4. If you discover a reusable pattern, submit it with `submit_curator_signal`.');
127
+ summaryParts.push('5. For large refactors, use `run_architecture_audit` to check against rules.');
128
+ summaryParts.push('6. Store major decisions using `save_decision` (ADR).');
129
+
130
+ summaryParts.push('\n=== RECENT ACTIVITY DIGEST ===');
131
+
132
+ if (agentTasks && agentTasks.length > 0) {
133
+ summaryParts.push('\nLatest AI Executions:');
134
+ agentTasks.forEach((t: any) => {
135
+ const time = t.completed_at ? new Date(t.completed_at).toLocaleString() : 'Recently';
136
+ summaryParts.push(`- [${time}] ${t.roadmap_title || 'Task'}: ${t.execution_summary?.substring(0, 100) || 'Completed'}`);
137
+ });
138
+ }
139
+
140
+ if (roadmapItems && roadmapItems.length > 0) {
141
+ summaryParts.push('\nRoadmap Updates:');
142
+ roadmapItems.forEach((i: any) => {
143
+ summaryParts.push(`- ${i.title} is now ${i.status}`);
144
+ });
145
+ }
146
+
147
+ return summaryParts.join('\n') || 'No project context available.';
148
+ }
@@ -0,0 +1,43 @@
1
+ export interface RoadmapChunk {
2
+ id: string;
3
+ project_id: string;
4
+ feature_id: string | null;
5
+ title: string;
6
+ description: string | null;
7
+ status: string;
8
+ priority: string | null;
9
+ step_number: number;
10
+ prompt_content: string | null;
11
+ architectural_brief?: string | null;
12
+ context_summary?: string | null;
13
+ checklist?: any[] | null;
14
+ metadata?: any | null;
15
+ tags?: string[] | null;
16
+ created_at: string;
17
+ completed_at: string | null;
18
+ }
19
+
20
+ export interface ListRoadmapTasksResponse {
21
+ tasks: Array<{
22
+ id: string;
23
+ title: string;
24
+ priority: string | null;
25
+ status: string;
26
+ step_number: number;
27
+ prompt_content: string | null;
28
+ architectural_brief?: string | null;
29
+ context_summary?: string | null;
30
+ metadata?: any | null;
31
+ checklist?: any[] | null;
32
+ tags?: string[] | null;
33
+ }>;
34
+ formatted: string;
35
+ }
36
+
37
+ export interface RoadmapStep {
38
+ id: string;
39
+ stepNumber: number;
40
+ title: string;
41
+ status: string;
42
+ sprintFocus: string | null;
43
+ }
package/src/lib/types.ts CHANGED
@@ -176,31 +176,7 @@ export interface SecurityIntegrityResponse {
176
176
  // ROADMAP & TASK TYPES
177
177
  // =============================================================================
178
178
 
179
- export interface RoadmapChunk {
180
- id: string;
181
- project_id: string;
182
- feature_id: string | null;
183
- title: string;
184
- description: string | null;
185
- status: string;
186
- priority: string | null;
187
- step_number: number;
188
- prompt_content: string | null;
189
- created_at: string;
190
- completed_at: string | null;
191
- }
192
-
193
- export interface ListRoadmapTasksResponse {
194
- tasks: Array<{
195
- id: string;
196
- title: string;
197
- priority: string | null;
198
- status: string;
199
- step_number: number;
200
- prompt_content: string | null;
201
- }>;
202
- formatted: string;
203
- }
179
+ export * from './types-roadmap.js';
204
180
 
205
181
  // =============================================================================
206
182
  // AGENT BRIDGE & RULES TYPES
@@ -254,3 +230,43 @@ export interface ReleaseManifest {
254
230
  };
255
231
  timestamp: string;
256
232
  }
233
+
234
+
235
+ // =============================================================================
236
+ // ARCHAEOLOGICAL SCAN TYPES
237
+ // =============================================================================
238
+
239
+ export interface GitCommit {
240
+ hash: string;
241
+ message: string;
242
+ date: string;
243
+ author: string;
244
+ }
245
+
246
+ export interface DiscoveredFeature {
247
+ id: string;
248
+ title: string;
249
+ description: string;
250
+ status: 'COMPLETED';
251
+ source: 'git' | 'filesystem' | 'combined';
252
+ evidence: string[];
253
+ estimatedCompletionDate: string;
254
+ priority: number;
255
+ }
256
+
257
+ export interface ArchaeologicalReport {
258
+ projectId: string;
259
+ scanDate: string;
260
+ gitAnalysis: {
261
+ totalCommits: number;
262
+ analyzedCommits: number;
263
+ milestones: { date: string; summary: string; commits: string[] }[];
264
+ };
265
+ filesystemAnalysis: {
266
+ totalDirectories: number;
267
+ featureDirectories: string[];
268
+ configFiles: string[];
269
+ };
270
+ discoveredFeatures: DiscoveredFeature[];
271
+ recommendations: string[];
272
+ }
@@ -13,7 +13,7 @@ export interface McpServerConfig {
13
13
  }
14
14
 
15
15
  export const SERVER_NAME = 'rigstate-mcp';
16
- export const SERVER_VERSION = '0.5.0'; // Evolutionary Update
16
+ export const SERVER_VERSION = '0.7.5';
17
17
 
18
18
  export interface AuthContext {
19
19
  supabase: SupabaseClient;
@@ -26,8 +26,20 @@ interface TableMetadata {
26
26
 
27
27
  export async function analyzeDatabasePerformance(
28
28
  supabase: SupabaseClient,
29
+ userId: string,
29
30
  input: AnalyzeDatabasePerformanceInput
30
31
  ): Promise<{ issues: PerformanceIssue[], summary: string }> {
32
+ // 0. Verify project access
33
+ const { data: hasAccess, error: accessError } = await supabase
34
+ .rpc('check_project_access_secure', {
35
+ p_project_id: input.projectId,
36
+ p_user_id: userId
37
+ });
38
+
39
+ if (accessError || !hasAccess) {
40
+ throw new Error('Project not found or access denied');
41
+ }
42
+
31
43
  const issues: PerformanceIssue[] = [];
32
44
 
33
45
  // 1. Fetch Database Metadata