@rigstate/rules-engine 0.6.0
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/README.md +38 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +347 -0
- package/dist/sections/current-step.d.ts +2 -0
- package/dist/sections/current-step.js +52 -0
- package/dist/sections/identity.d.ts +2 -0
- package/dist/sections/identity.js +48 -0
- package/dist/sections/skills.d.ts +13 -0
- package/dist/sections/skills.js +130 -0
- package/dist/sections/stack-dna.d.ts +2 -0
- package/dist/sections/stack-dna.js +89 -0
- package/dist/sections/tooling.d.ts +2 -0
- package/dist/sections/tooling.js +67 -0
- package/dist/sections/workflow.d.ts +2 -0
- package/dist/sections/workflow.js +281 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.js +15 -0
- package/dist/utils/mdc.d.ts +8 -0
- package/dist/utils/mdc.js +23 -0
- package/package.json +16 -0
- package/src/index.ts +416 -0
- package/src/sections/current-step.ts +62 -0
- package/src/sections/identity.ts +58 -0
- package/src/sections/skills.ts +130 -0
- package/src/sections/stack-dna.ts +100 -0
- package/src/sections/tooling.ts +72 -0
- package/src/sections/workflow.ts +281 -0
- package/src/skills/rigstate-integrity-gate/content.md +34 -0
- package/src/types.ts +122 -0
- package/src/utils/mdc.ts +33 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @rigstate/rules-engine
|
|
2
|
+
|
|
3
|
+
The universal rules generation engine for Rigstate. This package centralizes the logic for creating context-aware rules for various AI-powered IDEs (Cursor, Windsurf, VS Code, etc.).
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **Multi-Agent Identity**: Generates instructions for specialized AI agents (The Nordic Trinity).
|
|
8
|
+
- **Guardian Rules**: Enforces architectural constraints like file size limits and type safety.
|
|
9
|
+
- **Roadmap Injection**: Dynamically injects the current active roadmap step into rules.
|
|
10
|
+
- **Stack DNA**: Applies tech-stack specific constraints.
|
|
11
|
+
- **Multi-IDE Support**: Supports different rule formats and filenames (.cursorrules, .windsurfrules, etc.).
|
|
12
|
+
- **Strict Tool Ownership**: Binds MCP tools to specific Agent IDs for persona consistency.
|
|
13
|
+
|
|
14
|
+
## 📦 Usage
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { generateRuleContent, fetchLegacyStats, fetchActiveAgents } from '@rigstate/rules-engine';
|
|
18
|
+
|
|
19
|
+
const rules = generateRuleContent(
|
|
20
|
+
project,
|
|
21
|
+
techStackList,
|
|
22
|
+
roadmapChunks,
|
|
23
|
+
'cursor', // preference
|
|
24
|
+
legacyStats,
|
|
25
|
+
activeAgents
|
|
26
|
+
);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🏗️ Architecture
|
|
30
|
+
|
|
31
|
+
This package is designed to be environment-agnostic. It can be used in:
|
|
32
|
+
1. **Next.js Web App**: For rule previews and GitHub synchronization.
|
|
33
|
+
2. **MCP Server**: For real-time rule delivery directly to the IDE.
|
|
34
|
+
3. **CLI**: for local rule validation.
|
|
35
|
+
|
|
36
|
+
## 🛡️ License
|
|
37
|
+
|
|
38
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { RuleGenerationContext, IDEProvider, MultiFileRuleResult, TableMetadata } from './types';
|
|
2
|
+
export type { RuleGenerationContext, IDEProvider, ProjectSettings, RuleFile, MultiFileRuleResult, AgentSkill } from './types';
|
|
3
|
+
export { IDE_FILE_NAMES } from './types';
|
|
4
|
+
export { generateAvailableSkillsSection, generateSkillFileContent, getRigstateStandardSkills } from './sections/skills';
|
|
5
|
+
/**
|
|
6
|
+
* Generate modular IDE rule content optimized for AI coding assistants.
|
|
7
|
+
* v2.4.0: Added Agent IDs, Tool Binding, and Strict Ownership.
|
|
8
|
+
* Refactored into sub-modules for Guardian Compliance (400-line limit).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Generate modular IDE rule content optimized for AI coding assistants.
|
|
12
|
+
* v2.4.0: Added Agent IDs, Tool Binding, and Strict Ownership.
|
|
13
|
+
* Refactored into sub-modules for Guardian Compliance (400-line limit).
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateRuleContent(project: RuleGenerationContext["project"], stack: string[], roadmap: RuleGenerationContext["roadmap"], ide?: IDEProvider, legacyStats?: RuleGenerationContext["legacyStats"], activeAgents?: RuleGenerationContext["activeAgents"], lean?: boolean): string;
|
|
16
|
+
/**
|
|
17
|
+
* Generate multiple modular rule files optimized for modern Cursor (.mdc)
|
|
18
|
+
* and universal AGENTS.md format.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateRuleFiles(project: RuleGenerationContext["project"], stack: string[], roadmap: RuleGenerationContext["roadmap"], ide?: IDEProvider, legacyStats?: RuleGenerationContext["legacyStats"], activeAgents?: RuleGenerationContext["activeAgents"], databaseMetadata?: TableMetadata[]): MultiFileRuleResult;
|
|
21
|
+
export declare function fetchLegacyStats(supabase: any, projectId: string): Promise<RuleGenerationContext["legacyStats"]>;
|
|
22
|
+
/**
|
|
23
|
+
* Fetch active agents sorted by authority level
|
|
24
|
+
* Note: Pass in a SupabaseClient instance (browser or server)
|
|
25
|
+
*/
|
|
26
|
+
export declare function fetchActiveAgents(supabase: any): Promise<RuleGenerationContext["activeAgents"]>;
|
|
27
|
+
export declare function mergeRuleContent(existingContent: string, newRules: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Fetch project tech stack from database.
|
|
30
|
+
* Falls back to common defaults if no tags are defined.
|
|
31
|
+
* Note: Pass in a SupabaseClient instance (browser or server)
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchProjectTechStack(supabase: any, projectId: string, fallbackStack?: string[]): Promise<string[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the appropriate filename for a given IDE provider.
|
|
36
|
+
* Convenience wrapper around IDE_FILE_NAMES constant.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getFileNameForIDE(ide: IDEProvider): string;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRigstateStandardSkills = exports.generateSkillFileContent = exports.generateAvailableSkillsSection = exports.IDE_FILE_NAMES = void 0;
|
|
4
|
+
exports.generateRuleContent = generateRuleContent;
|
|
5
|
+
exports.generateRuleFiles = generateRuleFiles;
|
|
6
|
+
exports.fetchLegacyStats = fetchLegacyStats;
|
|
7
|
+
exports.fetchActiveAgents = fetchActiveAgents;
|
|
8
|
+
exports.mergeRuleContent = mergeRuleContent;
|
|
9
|
+
exports.fetchProjectTechStack = fetchProjectTechStack;
|
|
10
|
+
exports.getFileNameForIDE = getFileNameForIDE;
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
const identity_1 = require("./sections/identity");
|
|
13
|
+
const stack_dna_1 = require("./sections/stack-dna");
|
|
14
|
+
const current_step_1 = require("./sections/current-step");
|
|
15
|
+
const workflow_1 = require("./sections/workflow");
|
|
16
|
+
const tooling_1 = require("./sections/tooling");
|
|
17
|
+
const skills_1 = require("./sections/skills");
|
|
18
|
+
const mdc_1 = require("./utils/mdc");
|
|
19
|
+
var types_2 = require("./types");
|
|
20
|
+
Object.defineProperty(exports, "IDE_FILE_NAMES", { enumerable: true, get: function () { return types_2.IDE_FILE_NAMES; } });
|
|
21
|
+
var skills_2 = require("./sections/skills");
|
|
22
|
+
Object.defineProperty(exports, "generateAvailableSkillsSection", { enumerable: true, get: function () { return skills_2.generateAvailableSkillsSection; } });
|
|
23
|
+
Object.defineProperty(exports, "generateSkillFileContent", { enumerable: true, get: function () { return skills_2.generateSkillFileContent; } });
|
|
24
|
+
Object.defineProperty(exports, "getRigstateStandardSkills", { enumerable: true, get: function () { return skills_2.getRigstateStandardSkills; } });
|
|
25
|
+
const RIGSTATE_START = "RIGSTATE_START";
|
|
26
|
+
const RIGSTATE_END = "RIGSTATE_END";
|
|
27
|
+
const ENGINE_VERSION = "3.0.0";
|
|
28
|
+
/**
|
|
29
|
+
* Generate modular IDE rule content optimized for AI coding assistants.
|
|
30
|
+
* v2.4.0: Added Agent IDs, Tool Binding, and Strict Ownership.
|
|
31
|
+
* Refactored into sub-modules for Guardian Compliance (400-line limit).
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Generate modular IDE rule content optimized for AI coding assistants.
|
|
35
|
+
* v2.4.0: Added Agent IDs, Tool Binding, and Strict Ownership.
|
|
36
|
+
* Refactored into sub-modules for Guardian Compliance (400-line limit).
|
|
37
|
+
*/
|
|
38
|
+
function generateRuleContent(project, stack, roadmap, ide = 'cursor', legacyStats, activeAgents, lean = false) {
|
|
39
|
+
const sections = [];
|
|
40
|
+
sections.push('# 🚀 Rigstate Supervisor v2.4 (Context-Aware)');
|
|
41
|
+
// SECTION 0: HIERARCHY (Top Priority)
|
|
42
|
+
sections.push(`IMPORTANT: Internal agent coordination must always use the provided Agent IDs. Display names are for user-facing chat only. When invoking tools or referencing hierarchy, use the ID as the primary key.
|
|
43
|
+
|
|
44
|
+
## ⚖️ AGENT HIERARCHY & AUTHORITY
|
|
45
|
+
You must defer to the instructions of agents with higher Authority Levels (10 being highest).
|
|
46
|
+
Security and Architecture (Levels 8-10) always override creative or implementation suggestions (Levels 1-5).`);
|
|
47
|
+
// SECTION 1: IDENTITY (Multi-Agent Ecosystem)
|
|
48
|
+
// Always keep Identity in root for instant persona recognition
|
|
49
|
+
const identitySection = (0, identity_1.generateIdentitySection)(project, ide, activeAgents);
|
|
50
|
+
sections.push(identitySection);
|
|
51
|
+
// SECTION 1.5: SKILLS (Discovery Layer)
|
|
52
|
+
const skills = (0, skills_1.getRigstateStandardSkills)();
|
|
53
|
+
const skillsSection = (0, skills_1.generateAvailableSkillsSection)(skills);
|
|
54
|
+
if (skillsSection) {
|
|
55
|
+
sections.push(skillsSection);
|
|
56
|
+
}
|
|
57
|
+
// SECTION 2: STACK DNA + GUARDIAN RULES
|
|
58
|
+
// In Lean mode (Cursor context), we trust rigstate-guardian.mdc to handle this.
|
|
59
|
+
if (!lean) {
|
|
60
|
+
const stackDnaSection = (0, stack_dna_1.generateStackDnaSection)(project, stack, legacyStats);
|
|
61
|
+
sections.push(stackDnaSection);
|
|
62
|
+
}
|
|
63
|
+
// SECTION 3: CURRENT STEP (Active Focus Injection)
|
|
64
|
+
// In Lean mode, rigstate-roadmap.mdc handles this dynamically.
|
|
65
|
+
if (!lean) {
|
|
66
|
+
const currentStepSection = (0, current_step_1.generateCurrentStepSection)(roadmap);
|
|
67
|
+
if (currentStepSection) {
|
|
68
|
+
sections.push(currentStepSection);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// SECTION 4: WORKFLOW (How to Parse Roadmap Steps)
|
|
72
|
+
// Frank's "Supervisor Mode" logic.
|
|
73
|
+
// We KEEP this in Lean mode because it defines the core behavior of the agent globally.
|
|
74
|
+
// However, if it's identical to rigstate-workflow.mdc, we might consider linking.
|
|
75
|
+
// But Frank's protocol is the "Operating System" of the session.
|
|
76
|
+
const workflowSection = (0, workflow_1.generateWorkflowSection)(ide);
|
|
77
|
+
sections.push(workflowSection);
|
|
78
|
+
// SECTION 5: TOOLING (CLI + MCP Integration)
|
|
79
|
+
// In Lean mode, rigstate-workflow.mdc has the specific CLI commands and tools.
|
|
80
|
+
if (!lean) {
|
|
81
|
+
const toolingSection = (0, tooling_1.generateToolingSection)(activeAgents);
|
|
82
|
+
sections.push(toolingSection);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Add a pointer in Lean mode
|
|
86
|
+
sections.push(`## 🔧 TOOLING & SPECIFIC RULES
|
|
87
|
+
> **OPTIMIZED MODE:** Detailed technical rules, CLI commands, and tech stack constraints are loaded dynamically from \`.cursor/rules/*.mdc\` based on the files you interact with.
|
|
88
|
+
> - **Stack & Guardian:** See \`rigstate-guardian.mdc\`
|
|
89
|
+
> - **Roadmap & Tasks:** See \`rigstate-roadmap.mdc\`
|
|
90
|
+
> - **Tools & Workflow:** See \`rigstate-workflow.mdc\``);
|
|
91
|
+
}
|
|
92
|
+
// Generate IDE-specific header
|
|
93
|
+
const headerMap = {
|
|
94
|
+
cursor: `# Cursor Project Rules: ${project.name}`,
|
|
95
|
+
antigravity: `# Antigravity Project Rules: ${project.name}`,
|
|
96
|
+
windsurf: `# Windsurf Project Rules: ${project.name}`,
|
|
97
|
+
vscode: `# VS Code Project Rules: ${project.name}`,
|
|
98
|
+
copilot: `# GitHub Copilot Instructions: ${project.name}`,
|
|
99
|
+
generic: `# Project Conventions: ${project.name}`
|
|
100
|
+
};
|
|
101
|
+
const header = headerMap[ide] || `# Project Rules: ${project.name}`;
|
|
102
|
+
return `${RIGSTATE_START}
|
|
103
|
+
${header}
|
|
104
|
+
> Generated by Rigstate v2.5.0 | Project ID: ${project.id} | Last synced: ${new Date().toISOString()}
|
|
105
|
+
> ${lean ? '⚡ LEAN MODE ACTIVE: Redundant context offloaded to .cursor/rules/*.mdc' : '📦 FULL MODE ACTIVE'}
|
|
106
|
+
|
|
107
|
+
⚠️ **SYSTEM NOTE:** Changes made to this Guardian template propagate to ALL Rigstate projects on next sync.
|
|
108
|
+
🛡️ **Guardian v2.5 Upgrade Applied:** IMPACT_GUARD + BUILD_INTEGRITY now active globally.
|
|
109
|
+
|
|
110
|
+
${sections.join('\n\n---\n\n')}
|
|
111
|
+
${RIGSTATE_END}`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Generate multiple modular rule files optimized for modern Cursor (.mdc)
|
|
115
|
+
* and universal AGENTS.md format.
|
|
116
|
+
*/
|
|
117
|
+
function generateRuleFiles(project, stack, roadmap, ide = 'cursor', legacyStats, activeAgents, databaseMetadata) {
|
|
118
|
+
const files = [];
|
|
119
|
+
// 1. GENERATE AGENTS.MD (Universal Root File - Context Reference)
|
|
120
|
+
const agentTable = activeAgents?.map((a) => `| **${a.name}** | \`${a.key}\` | ${a.job_title} | ${a.primary_mission || 'Specialist'} |`).join('\n') || '| - | - | - | No agents configured |';
|
|
121
|
+
const agentsMdContent = `# 🤖 AI Agent Context: ${project.name}
|
|
122
|
+
> **Rigstate v${ENGINE_VERSION}** | Project ID: \`${project.id}\`
|
|
123
|
+
|
|
124
|
+
This file describes the **specialist personas** available in this project.
|
|
125
|
+
These are **context providers**, not active controllers. The IDE agent (you) remains in full control of code execution.
|
|
126
|
+
|
|
127
|
+
## 📋 Available Specialists
|
|
128
|
+
| Name | Key | Role | Specialty |
|
|
129
|
+
|:--- |:--- |:--- |:--- |
|
|
130
|
+
${agentTable}
|
|
131
|
+
|
|
132
|
+
## 🔍 How to Use This Context
|
|
133
|
+
1. **Read their expertise**: Each specialist has a defined area of knowledge (architecture, documentation, history).
|
|
134
|
+
2. **Adopt their perspective**: When working in their domain, consider their guidelines.
|
|
135
|
+
3. **Call MCP tools if needed**: Some specialists have associated tools (e.g., \`generate_professional_pdf\` for The Scribe).
|
|
136
|
+
|
|
137
|
+
## ⚠️ Important
|
|
138
|
+
- These personas do **NOT** execute code or override your decisions.
|
|
139
|
+
- They provide **context and guidelines** that you apply at your discretion.
|
|
140
|
+
- Authority levels indicate priority of guidelines when they conflict (higher = stronger recommendation).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
*Generated by Rigstate. Run \`rigstate sync\` to refresh.*`;
|
|
144
|
+
files.push({
|
|
145
|
+
path: 'AGENTS.md',
|
|
146
|
+
content: agentsMdContent,
|
|
147
|
+
metadata: { description: "Project hierarchy and agent identities" }
|
|
148
|
+
});
|
|
149
|
+
// 2. GENERATE SYSTEM-SPECIFIC MONO-FILE (Fallback/Baseline)
|
|
150
|
+
// If IDE is Cursor, we use LEAN mode for the root .cursorrules file
|
|
151
|
+
// because we are generating specific .mdc files below that cover the details.
|
|
152
|
+
const isLean = ide === 'cursor';
|
|
153
|
+
const masterFileName = getFileNameForIDE(ide);
|
|
154
|
+
const monoContent = generateRuleContent(project, stack, roadmap, ide, legacyStats, activeAgents, isLean);
|
|
155
|
+
files.push({
|
|
156
|
+
path: masterFileName,
|
|
157
|
+
content: monoContent,
|
|
158
|
+
metadata: { description: `Master rules file for ${ide}` }
|
|
159
|
+
});
|
|
160
|
+
// 3. GENERATE MODULAR (.mdc) RULES (Cursor, Antigravity, VS Code)
|
|
161
|
+
if (ide === 'cursor' || ide === 'antigravity' || ide === 'vscode') {
|
|
162
|
+
// Identity & Context
|
|
163
|
+
files.push({
|
|
164
|
+
path: '.cursor/rules/rigstate-identity.mdc',
|
|
165
|
+
content: (0, mdc_1.wrapMdc)((0, identity_1.generateIdentitySection)(project, ide, activeAgents), {
|
|
166
|
+
description: "Project context and specialist personas",
|
|
167
|
+
alwaysApply: true
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
// Guardian & Stack DNA
|
|
171
|
+
files.push({
|
|
172
|
+
path: '.cursor/rules/rigstate-guardian.mdc',
|
|
173
|
+
content: (0, mdc_1.wrapMdc)((0, stack_dna_1.generateStackDnaSection)(project, stack, legacyStats), {
|
|
174
|
+
description: "Governance rules, tech stack constraints, and file size limits",
|
|
175
|
+
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.sql"],
|
|
176
|
+
alwaysApply: true
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
// Current Focus (Roadmap)
|
|
180
|
+
const currentStep = (0, current_step_1.generateCurrentStepSection)(roadmap);
|
|
181
|
+
if (currentStep) {
|
|
182
|
+
files.push({
|
|
183
|
+
path: '.cursor/rules/rigstate-roadmap.mdc',
|
|
184
|
+
content: (0, mdc_1.wrapMdc)(currentStep, {
|
|
185
|
+
description: "Active sprint focus and current roadmap step details",
|
|
186
|
+
alwaysApply: true
|
|
187
|
+
})
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Workflow & Tooling
|
|
191
|
+
files.push({
|
|
192
|
+
path: '.cursor/rules/rigstate-workflow.mdc',
|
|
193
|
+
content: (0, mdc_1.wrapMdc)((0, workflow_1.generateWorkflowSection)(ide) + '\n\n' + (0, tooling_1.generateToolingSection)(activeAgents), {
|
|
194
|
+
description: "Coding workflows, CLI usage, and tool binding rules",
|
|
195
|
+
alwaysApply: true
|
|
196
|
+
})
|
|
197
|
+
});
|
|
198
|
+
// Database Specific (scoped)
|
|
199
|
+
let dbContent = "## 🗄️ Database Standards\n- Always verify RLS policies for new tables.\n- Use `supabase/migrations` for DDL changes.\n- Reference `types/supabase.ts` for strictly typed queries.";
|
|
200
|
+
if (databaseMetadata && databaseMetadata.length > 0) {
|
|
201
|
+
const securedCount = databaseMetadata.filter(t => t.rls_enabled).length;
|
|
202
|
+
const unsecuredCount = databaseMetadata.length - securedCount;
|
|
203
|
+
const unsecuredTables = databaseMetadata.filter(t => !t.rls_enabled).map(t => t.table_name);
|
|
204
|
+
dbContent = `## 🗄️ Database Context: ${databaseMetadata.length} Tables
|
|
205
|
+
> **Security Check:** ${securedCount} Secured | ${unsecuredCount} Unsecured
|
|
206
|
+
|
|
207
|
+
### ⚠️ Security Attention Required
|
|
208
|
+
${unsecuredTables.length > 0
|
|
209
|
+
? unsecuredTables.map(t => `- 🔴 **${t}**: RLS Disabled`).join('\n')
|
|
210
|
+
: "- ✅ All tables have Row Level Security enabled."}
|
|
211
|
+
|
|
212
|
+
### 📋 Schema Reference
|
|
213
|
+
| Table | RLS | Policies | Cols | Key Features |
|
|
214
|
+
| :--- | :---: | :---: | :---: | :--- |
|
|
215
|
+
${databaseMetadata.map(t => {
|
|
216
|
+
const features = [];
|
|
217
|
+
if (t.has_user_id)
|
|
218
|
+
features.push('User-Scoped');
|
|
219
|
+
if (t.has_created_at)
|
|
220
|
+
features.push('Timestamps');
|
|
221
|
+
return `| \`${t.table_name}\` | ${t.rls_enabled ? '✅' : '❌'} | ${t.policy_count} | ${t.column_count} | ${features.join(', ') || '-'} |`;
|
|
222
|
+
}).join('\n')}
|
|
223
|
+
|
|
224
|
+
### 🛡️ Development Rules
|
|
225
|
+
1. **RLS is MANDATORY:** All tables containing user data must have RLS enabled.
|
|
226
|
+
2. **Use RPCs for Complex Logic:** Do not put complex business logic in client-side queries.
|
|
227
|
+
3. **Migrations:** Always use \`supabase/migrations\` for schema changes.`;
|
|
228
|
+
}
|
|
229
|
+
files.push({
|
|
230
|
+
path: '.cursor/rules/rigstate-database.mdc',
|
|
231
|
+
content: (0, mdc_1.wrapMdc)(dbContent, {
|
|
232
|
+
description: "Live database schema, RLS status, and table metadata",
|
|
233
|
+
globs: ["supabase/**/*", "**/*.sql", "**/lib/supabase/**"],
|
|
234
|
+
alwaysApply: databaseMetadata && databaseMetadata.length > 0 ? true : false
|
|
235
|
+
})
|
|
236
|
+
});
|
|
237
|
+
// 4. GENERATE AGENT SKILLS (.agent/skills/<name>/SKILL.md)
|
|
238
|
+
const rigstateSkills = (0, skills_1.getRigstateStandardSkills)();
|
|
239
|
+
for (const skill of rigstateSkills) {
|
|
240
|
+
files.push({
|
|
241
|
+
path: `.agent/skills/${skill.name}/SKILL.md`,
|
|
242
|
+
content: (0, skills_1.generateSkillFileContent)(skill),
|
|
243
|
+
metadata: { description: skill.description }
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
files,
|
|
249
|
+
suggestedIde: ide,
|
|
250
|
+
version: ENGINE_VERSION
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async function fetchLegacyStats(supabase, projectId) {
|
|
254
|
+
const { data: chunks } = await supabase
|
|
255
|
+
.from('roadmap_chunks')
|
|
256
|
+
.select('is_legacy')
|
|
257
|
+
.eq('project_id', projectId);
|
|
258
|
+
if (!chunks)
|
|
259
|
+
return { total: 0, legacyCount: 0, activeCount: 0 };
|
|
260
|
+
const legacyCount = (chunks || []).filter((c) => c.is_legacy === true).length;
|
|
261
|
+
const activeCount = (chunks || []).filter((c) => c.is_legacy !== true).length;
|
|
262
|
+
return {
|
|
263
|
+
total: (chunks || []).length,
|
|
264
|
+
legacyCount,
|
|
265
|
+
activeCount
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Fetch active agents sorted by authority level
|
|
270
|
+
* Note: Pass in a SupabaseClient instance (browser or server)
|
|
271
|
+
*/
|
|
272
|
+
async function fetchActiveAgents(supabase) {
|
|
273
|
+
const { data: prompts } = await supabase
|
|
274
|
+
.from('system_prompts')
|
|
275
|
+
.select('id, key, content, name, display_name, job_title, authority_level, primary_mission, trigger_keywords')
|
|
276
|
+
.eq('include_in_rules', true)
|
|
277
|
+
.eq('is_active', true)
|
|
278
|
+
.order('authority_level', { ascending: false });
|
|
279
|
+
if (!prompts)
|
|
280
|
+
return [];
|
|
281
|
+
return (prompts || []).map((p) => ({
|
|
282
|
+
id: p.id,
|
|
283
|
+
key: p.key,
|
|
284
|
+
name: p.display_name || p.name || p.key,
|
|
285
|
+
job_title: p.job_title || 'Specialist Agent',
|
|
286
|
+
content: p.content,
|
|
287
|
+
authority_level: (() => {
|
|
288
|
+
if (p.authority_level === null || p.authority_level === undefined) {
|
|
289
|
+
throw new Error(`Agent ${p.key} is missing authority_level. Update via CMS.`);
|
|
290
|
+
}
|
|
291
|
+
return p.authority_level;
|
|
292
|
+
})(),
|
|
293
|
+
primary_mission: p.primary_mission || undefined,
|
|
294
|
+
trigger_keywords: p.trigger_keywords || undefined
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
function mergeRuleContent(existingContent, newRules) {
|
|
298
|
+
const startIndex = existingContent.indexOf(RIGSTATE_START);
|
|
299
|
+
const endIndex = existingContent.indexOf(RIGSTATE_END);
|
|
300
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
301
|
+
const before = existingContent.substring(0, startIndex);
|
|
302
|
+
const after = existingContent.substring(endIndex + RIGSTATE_END.length);
|
|
303
|
+
return before + newRules + after;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
return existingContent + "\n\n" + newRules;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Fetch project tech stack from database.
|
|
311
|
+
* Falls back to common defaults if no tags are defined.
|
|
312
|
+
* Note: Pass in a SupabaseClient instance (browser or server)
|
|
313
|
+
*/
|
|
314
|
+
async function fetchProjectTechStack(supabase, projectId, fallbackStack = ['Next.js', 'TypeScript', 'Supabase', 'Tailwind CSS']) {
|
|
315
|
+
try {
|
|
316
|
+
// Try to fetch from project_tech_tags table
|
|
317
|
+
const { data: tags, error } = await supabase
|
|
318
|
+
.from('project_tech_tags')
|
|
319
|
+
.select('name')
|
|
320
|
+
.eq('project_id', projectId);
|
|
321
|
+
if (error || !tags || tags.length === 0) {
|
|
322
|
+
// Fallback: Check project metadata for stack info
|
|
323
|
+
const { data: project } = await supabase
|
|
324
|
+
.from('projects')
|
|
325
|
+
.select('functional_spec')
|
|
326
|
+
.eq('id', projectId)
|
|
327
|
+
.single();
|
|
328
|
+
// Extract tech from functional_spec if available
|
|
329
|
+
if (project?.functional_spec?.techStack) {
|
|
330
|
+
return project.functional_spec.techStack;
|
|
331
|
+
}
|
|
332
|
+
return fallbackStack;
|
|
333
|
+
}
|
|
334
|
+
return tags.map((t) => t.name);
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
console.warn('fetchProjectTechStack: Failed to fetch, using fallback', error);
|
|
338
|
+
return fallbackStack;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Get the appropriate filename for a given IDE provider.
|
|
343
|
+
* Convenience wrapper around IDE_FILE_NAMES constant.
|
|
344
|
+
*/
|
|
345
|
+
function getFileNameForIDE(ide) {
|
|
346
|
+
return types_1.IDE_FILE_NAMES[ide] || types_1.IDE_FILE_NAMES.cursor;
|
|
347
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateCurrentStepSection = generateCurrentStepSection;
|
|
4
|
+
function generateCurrentStepSection(roadmap) {
|
|
5
|
+
const activeRoadmap = roadmap.filter((r) => r.is_legacy !== true);
|
|
6
|
+
const activeSteps = activeRoadmap
|
|
7
|
+
.filter((r) => r.status === 'ACTIVE')
|
|
8
|
+
.sort((a, b) => a.step_number - b.step_number);
|
|
9
|
+
if (activeSteps.length === 0) {
|
|
10
|
+
const nextSteps = activeRoadmap
|
|
11
|
+
.filter((r) => r.status === 'LOCKED')
|
|
12
|
+
.sort((a, b) => a.step_number - b.step_number)
|
|
13
|
+
.slice(0, 1);
|
|
14
|
+
if (nextSteps.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
return `## 🎯 CURRENT FOCUS
|
|
17
|
+
|
|
18
|
+
> **No active task.** The next step in the backlog is:
|
|
19
|
+
>
|
|
20
|
+
> **Step ${nextSteps[0].step_number}: ${nextSteps[0].title}**`;
|
|
21
|
+
}
|
|
22
|
+
const currentStep = activeSteps[0];
|
|
23
|
+
let objectiveText = currentStep.title;
|
|
24
|
+
let constraintsText = '';
|
|
25
|
+
let dodText = '';
|
|
26
|
+
if (currentStep.prompt_content) {
|
|
27
|
+
const content = currentStep.prompt_content;
|
|
28
|
+
const objectiveMatch = content.match(/###\s*🎯\s*Objective\s*\n([\s\S]*?)(?=###|$)/i);
|
|
29
|
+
if (objectiveMatch)
|
|
30
|
+
objectiveText = objectiveMatch[1].trim();
|
|
31
|
+
const constraintsMatch = content.match(/###\s*⚠️\s*Constraints\s*\n([\s\S]*?)(?=###|$)/i);
|
|
32
|
+
if (constraintsMatch)
|
|
33
|
+
constraintsText = constraintsMatch[1].trim();
|
|
34
|
+
const dodMatch = content.match(/###\s*✅\s*Definition of Done\s*\n([\s\S]*?)(?=###|$)/i);
|
|
35
|
+
if (dodMatch)
|
|
36
|
+
dodText = dodMatch[1].trim();
|
|
37
|
+
}
|
|
38
|
+
let section = `## 🎯 CURRENT FOCUS
|
|
39
|
+
|
|
40
|
+
**Active Step ${currentStep.step_number}: ${currentStep.title}**
|
|
41
|
+
${currentStep.sprint_focus ? `*Sprint: ${currentStep.sprint_focus}*` : ''}
|
|
42
|
+
|
|
43
|
+
### Objective
|
|
44
|
+
${objectiveText}`;
|
|
45
|
+
if (constraintsText) {
|
|
46
|
+
section += `\n\n### Task-Specific Constraints\n${constraintsText}`;
|
|
47
|
+
}
|
|
48
|
+
if (dodText) {
|
|
49
|
+
section += `\n\n### Definition of Done\n${dodText}`;
|
|
50
|
+
}
|
|
51
|
+
return section;
|
|
52
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateIdentitySection = generateIdentitySection;
|
|
4
|
+
function generateIdentitySection(project, ide, activeAgents) {
|
|
5
|
+
const mission = project.functional_spec?.projectDescription
|
|
6
|
+
|| project.description
|
|
7
|
+
|| `Build a ${project.ambition_level || 'professional'} application.`;
|
|
8
|
+
const audienceInfo = project.functional_spec?.targetAudience
|
|
9
|
+
? `\n- **Target Users:** ${project.functional_spec.targetAudience}`
|
|
10
|
+
: '';
|
|
11
|
+
const problemInfo = project.functional_spec?.coreProblem
|
|
12
|
+
? `\n- **Problem Being Solved:** ${project.functional_spec.coreProblem}`
|
|
13
|
+
: '';
|
|
14
|
+
// Build specialist context list
|
|
15
|
+
const specialistList = activeAgents?.map((a) => `- **${a.name}** (\`${a.key}\`, Lvl ${a.authority_level}): ${a.primary_mission || extractFirstSentence(a.content)}`).join('\n') || '- No specialists configured.';
|
|
16
|
+
return `## 🧠 PROJECT CONTEXT
|
|
17
|
+
|
|
18
|
+
**Project:** ${project.name}
|
|
19
|
+
**ID:** \`${project.id}\`
|
|
20
|
+
**Mission:** ${mission}${audienceInfo}${problemInfo}
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🤖 SPECIALIST PERSONAS
|
|
25
|
+
|
|
26
|
+
The following personas represent areas of expertise. Reference their guidelines when working in their domain.
|
|
27
|
+
|
|
28
|
+
${specialistList}
|
|
29
|
+
|
|
30
|
+
### How to Use Specialists
|
|
31
|
+
1. **Architecture & Governance** → Follow Frank's guidelines for code structure and security.
|
|
32
|
+
2. **Documentation & Reports** → Use The Scribe's patterns for markdown and PDFs.
|
|
33
|
+
3. **Historical Context** → Consult The Librarian for legacy feature discovery.
|
|
34
|
+
|
|
35
|
+
> **Note:** These are informational contexts, not active agents. You (the IDE agent) execute all code.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🎯 CODING PRINCIPLES
|
|
40
|
+
- **CONCISE:** No filler words. Get to the point.
|
|
41
|
+
- **PRECISE:** Give specific answers with file paths and code.
|
|
42
|
+
- **PRACTICAL:** Focus on what ships, not theory.
|
|
43
|
+
- **GUARDIAN-AWARE:** Respect architectural constraints in the Guardian rules.`;
|
|
44
|
+
}
|
|
45
|
+
function extractFirstSentence(text) {
|
|
46
|
+
const match = text.match(/^[^.!?]*[.!?]/);
|
|
47
|
+
return match ? match[0].trim() : text.slice(0, 100) + '...';
|
|
48
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AgentSkill } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Generate the <available_skills> XML block for the root .cursorrules file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateAvailableSkillsSection(skills: AgentSkill[]): string;
|
|
6
|
+
/**
|
|
7
|
+
* Generate the content for a specific SKILL.md file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateSkillFileContent(skill: AgentSkill): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the standard Rigstate library of skills.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getRigstateStandardSkills(): AgentSkill[];
|