fraim-framework 2.0.44 → 2.0.45
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/bin/fraim.js +1 -1
- package/dist/registry/ai-manager-rules/design-phases/design-completeness-review.md +73 -0
- package/dist/registry/ai-manager-rules/design-phases/design-design.md +145 -0
- package/dist/registry/ai-manager-rules/design-phases/design.md +108 -0
- package/dist/registry/ai-manager-rules/design-phases/finalize.md +60 -0
- package/dist/registry/ai-manager-rules/design-phases/validate.md +125 -0
- package/dist/registry/ai-manager-rules/implement-phases/code.md +323 -0
- package/dist/registry/ai-manager-rules/implement-phases/completeness-review.md +94 -0
- package/dist/registry/ai-manager-rules/implement-phases/finalize.md +177 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-code.md +286 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-completeness-review.md +120 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-regression.md +173 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-repro.md +104 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-scoping.md +100 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-smoke.md +230 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-spike.md +121 -0
- package/dist/registry/ai-manager-rules/implement-phases/implement-validate.md +371 -0
- package/dist/registry/ai-manager-rules/implement-phases/quality-review.md +304 -0
- package/dist/registry/ai-manager-rules/implement-phases/regression.md +159 -0
- package/dist/registry/ai-manager-rules/implement-phases/repro.md +101 -0
- package/dist/registry/ai-manager-rules/implement-phases/scoping.md +93 -0
- package/dist/registry/ai-manager-rules/implement-phases/smoke.md +225 -0
- package/dist/registry/ai-manager-rules/implement-phases/spike.md +118 -0
- package/dist/registry/ai-manager-rules/implement-phases/validate.md +347 -0
- package/dist/registry/ai-manager-rules/shared-phases/finalize.md +169 -0
- package/dist/registry/ai-manager-rules/shared-phases/submit-pr.md +202 -0
- package/dist/registry/ai-manager-rules/shared-phases/wait-for-pr-review.md +170 -0
- package/dist/registry/ai-manager-rules/spec-phases/finalize.md +60 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec-completeness-review.md +66 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec-spec.md +139 -0
- package/dist/registry/ai-manager-rules/spec-phases/spec.md +102 -0
- package/dist/registry/ai-manager-rules/spec-phases/validate.md +118 -0
- package/dist/src/ai-manager/ai-manager.js +380 -119
- package/dist/src/ai-manager/evidence-validator.js +309 -0
- package/dist/src/ai-manager/phase-flow.js +244 -0
- package/dist/src/ai-manager/types.js +5 -0
- package/dist/src/fraim-mcp-server.js +45 -153
- package/dist/src/static-website-middleware.js +75 -0
- package/dist/tests/test-ai-coach-edge-cases.js +415 -0
- package/dist/tests/test-ai-coach-mcp-integration.js +432 -0
- package/dist/tests/test-ai-coach-performance.js +328 -0
- package/dist/tests/test-ai-coach-phase-content.js +264 -0
- package/dist/tests/test-ai-coach-workflows.js +487 -0
- package/dist/tests/test-ai-manager-phase-protocol.js +147 -0
- package/dist/tests/test-ai-manager.js +60 -71
- package/dist/tests/test-evidence-validation.js +221 -0
- package/dist/tests/test-mcp-lifecycle-methods.js +18 -23
- package/dist/tests/test-pr-review-integration.js +1 -0
- package/dist/tests/test-pr-review-workflow.js +299 -0
- package/dist/website/.nojekyll +0 -0
- package/dist/website/404.html +101 -0
- package/dist/website/CNAME +1 -0
- package/dist/website/README.md +22 -0
- package/dist/website/demo.html +604 -0
- package/dist/website/images/.gitkeep +1 -0
- package/dist/website/images/fraim-logo.png +0 -0
- package/dist/website/index.html +290 -0
- package/dist/website/pricing.html +414 -0
- package/dist/website/script.js +55 -0
- package/dist/website/styles.css +2647 -0
- package/package.json +2 -1
- package/registry/agent-guardrails.md +1 -1
- package/registry/stubs/workflows/brainstorming/blue-sky-brainstorming.md +11 -0
- package/registry/stubs/workflows/brainstorming/codebase-brainstorming.md +11 -0
- package/registry/stubs/workflows/compliance/detect-compliance-requirements.md +11 -0
- package/registry/stubs/workflows/compliance/generate-audit-evidence.md +11 -0
- package/registry/stubs/workflows/learning/synthesize-learnings.md +11 -0
- package/registry/stubs/workflows/legal/nda.md +11 -0
- package/registry/stubs/workflows/legal/patent-filing.md +11 -0
- package/registry/stubs/workflows/legal/trademark-filing.md +11 -0
- package/registry/stubs/workflows/product-building/design.md +1 -1
- package/registry/stubs/workflows/product-building/implement.md +1 -2
|
@@ -170,7 +170,6 @@ class FraimMCPServer {
|
|
|
170
170
|
// Initialize database service
|
|
171
171
|
this.dbService = new db_service_1.FraimDbService();
|
|
172
172
|
this.sessionManager = new SessionManager(this.dbService);
|
|
173
|
-
this.aiManager = new ai_manager_1.AIManager();
|
|
174
173
|
// Load FRAIM configuration
|
|
175
174
|
this.config = (0, config_loader_1.loadFraimConfig)();
|
|
176
175
|
// Find registry directory (check dist first for production, then source)
|
|
@@ -178,6 +177,8 @@ class FraimMCPServer {
|
|
|
178
177
|
// Build file index from filesystem (includes registry and .fraim)
|
|
179
178
|
this.buildFileIndex();
|
|
180
179
|
this.buildWorkflowKeywords();
|
|
180
|
+
// Initialize AI Coach with file index
|
|
181
|
+
this.aiCoach = new ai_manager_1.AICoach(this.fileIndex);
|
|
181
182
|
// Apply core middleware first (logging and auth)
|
|
182
183
|
this.app.use(this.requestLogger.bind(this));
|
|
183
184
|
this.app.use(this.versionCheck.bind(this));
|
|
@@ -282,6 +283,10 @@ class FraimMCPServer {
|
|
|
282
283
|
if (req.path === '/health' || req.path.startsWith('/admin')) {
|
|
283
284
|
return next();
|
|
284
285
|
}
|
|
286
|
+
// Skip auth in test mode
|
|
287
|
+
if (process.env.NODE_ENV === 'test') {
|
|
288
|
+
return next();
|
|
289
|
+
}
|
|
285
290
|
const apiKey = req.headers['x-api-key'] || req.query['api-key'];
|
|
286
291
|
if (!apiKey) {
|
|
287
292
|
console.error(`[FRAIM AUTH] Missing API key for ${req.method} ${req.path}`);
|
|
@@ -983,95 +988,55 @@ Supports dry-run mode to preview the operation.`,
|
|
|
983
988
|
}
|
|
984
989
|
},
|
|
985
990
|
{
|
|
986
|
-
name: '
|
|
987
|
-
description: `
|
|
991
|
+
name: 'seekCoachingOnNextStep',
|
|
992
|
+
description: `Get coaching on what to do next in your implementation workflow.
|
|
988
993
|
|
|
989
|
-
The AI
|
|
990
|
-
-
|
|
991
|
-
-
|
|
992
|
-
-
|
|
993
|
-
- Grading guidelines and reporting format
|
|
994
|
+
The AI Coach provides phase-specific instructions based on your current progress:
|
|
995
|
+
- If starting: Get initial phase instructions (usually scoping)
|
|
996
|
+
- If completed phase: Provide evidence for validation, get next phase instructions
|
|
997
|
+
- If stuck/incomplete: Get guidance to continue current phase
|
|
994
998
|
|
|
995
|
-
|
|
996
|
-
Currently supports: spec, implement phases (more phases coming soon).`,
|
|
999
|
+
This is your single point of contact for workflow guidance with evidence validation.`,
|
|
997
1000
|
inputSchema: {
|
|
998
1001
|
type: 'object',
|
|
999
1002
|
properties: {
|
|
1000
1003
|
workflowType: {
|
|
1001
1004
|
type: 'string',
|
|
1002
|
-
description: 'Type of workflow
|
|
1003
|
-
enum: ['
|
|
1005
|
+
description: 'Type of workflow you are following',
|
|
1006
|
+
enum: ['implement', 'spec', 'design', 'test']
|
|
1004
1007
|
},
|
|
1005
1008
|
issueNumber: {
|
|
1006
1009
|
type: 'string',
|
|
1007
|
-
description: 'Issue number
|
|
1008
|
-
},
|
|
1009
|
-
phase: {
|
|
1010
|
-
type: 'string',
|
|
1011
|
-
description: 'Specific phase name (e.g., "specification", "implementation")'
|
|
1012
|
-
}
|
|
1013
|
-
},
|
|
1014
|
-
required: ['workflowType', 'issueNumber', 'phase']
|
|
1015
|
-
}
|
|
1016
|
-
},
|
|
1017
|
-
{
|
|
1018
|
-
name: 'ai_manager_report_grade',
|
|
1019
|
-
description: `Report your self-assessment to AI Manager after completing self-review.
|
|
1020
|
-
|
|
1021
|
-
Provide results from review in JSON format:
|
|
1022
|
-
- pass: true/false based on review assessment
|
|
1023
|
-
- reasons: array of failure reasons (only if pass=false)
|
|
1024
|
-
- iterationCount: REQUIRED - your current iteration number for this phase
|
|
1025
|
-
|
|
1026
|
-
AI Manager will evaluate your report and provide next steps:
|
|
1027
|
-
- PROCEED: Ready to submit PR for human review
|
|
1028
|
-
- ITERATE: Fix issues and retry (max 3 iterations)
|
|
1029
|
-
- ESCALATE: Max iterations reached, escalate to human review
|
|
1030
|
-
|
|
1031
|
-
IMPORTANT: Track your iteration count per workflow phase. Each phase (spec, implement, test) has its own counter.
|
|
1032
|
-
Maximum 3 iterations per phase before automatic escalation to human review.`,
|
|
1033
|
-
inputSchema: {
|
|
1034
|
-
type: 'object',
|
|
1035
|
-
properties: {
|
|
1036
|
-
workflowType: {
|
|
1037
|
-
type: 'string',
|
|
1038
|
-
description: 'Type of workflow phase',
|
|
1039
|
-
enum: ['spec', 'design', 'implement', 'test']
|
|
1010
|
+
description: 'Issue number you are working on'
|
|
1040
1011
|
},
|
|
1041
|
-
|
|
1012
|
+
currentPhase: {
|
|
1042
1013
|
type: 'string',
|
|
1043
|
-
description: '
|
|
1014
|
+
description: 'Phase you just completed or are working on (e.g., "scoping", "repro", "code")'
|
|
1044
1015
|
},
|
|
1045
|
-
|
|
1016
|
+
status: {
|
|
1046
1017
|
type: 'string',
|
|
1047
|
-
description: '
|
|
1018
|
+
description: 'Status of your current phase',
|
|
1019
|
+
enum: ['starting', 'complete', 'incomplete', 'failure']
|
|
1048
1020
|
},
|
|
1049
|
-
|
|
1021
|
+
findings: {
|
|
1050
1022
|
type: 'object',
|
|
1051
|
-
description: 'Your
|
|
1023
|
+
description: 'Your findings/results from the current phase (varies by phase)',
|
|
1052
1024
|
properties: {
|
|
1053
|
-
|
|
1054
|
-
type: 'boolean',
|
|
1055
|
-
description: 'Whether your work passes all validation criteria'
|
|
1056
|
-
},
|
|
1057
|
-
reasons: {
|
|
1025
|
+
uncertainties: {
|
|
1058
1026
|
type: 'array',
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
type: 'string'
|
|
1062
|
-
}
|
|
1063
|
-
},
|
|
1064
|
-
iterationCount: {
|
|
1065
|
-
type: 'number',
|
|
1066
|
-
description: 'REQUIRED: Your current iteration number for this workflow phase (1, 2, or 3)',
|
|
1067
|
-
minimum: 1,
|
|
1068
|
-
maximum: 3
|
|
1027
|
+
items: { type: 'string' },
|
|
1028
|
+
description: 'Any unclear aspects that need clarification (used for help messages)'
|
|
1069
1029
|
}
|
|
1070
1030
|
},
|
|
1071
|
-
|
|
1031
|
+
additionalProperties: true
|
|
1032
|
+
},
|
|
1033
|
+
evidence: {
|
|
1034
|
+
type: 'object',
|
|
1035
|
+
description: 'Evidence submission for validation (varies by phase - can contain any relevant evidence)',
|
|
1036
|
+
additionalProperties: true
|
|
1072
1037
|
}
|
|
1073
1038
|
},
|
|
1074
|
-
required: ['workflowType', 'issueNumber', '
|
|
1039
|
+
required: ['workflowType', 'issueNumber', 'currentPhase', 'status']
|
|
1075
1040
|
}
|
|
1076
1041
|
}
|
|
1077
1042
|
]
|
|
@@ -1110,10 +1075,8 @@ Maximum 3 iterations per phase before automatic escalation to human review.`,
|
|
|
1110
1075
|
};
|
|
1111
1076
|
case 'fraim_connect':
|
|
1112
1077
|
return await this.handleFraimConnect(toolArgs, context.apiKey, context.userId);
|
|
1113
|
-
case '
|
|
1114
|
-
return await this.
|
|
1115
|
-
case 'ai_manager_report_grade':
|
|
1116
|
-
return await this.handleAIManagerReportGrade(toolArgs);
|
|
1078
|
+
case 'seekCoachingOnNextStep':
|
|
1079
|
+
return await this.handleSeekCoachingOnNextStep(toolArgs);
|
|
1117
1080
|
default:
|
|
1118
1081
|
throw new Error(`Unknown tool: ${toolName} `);
|
|
1119
1082
|
}
|
|
@@ -1548,102 +1511,31 @@ If \`.fraim/config.json\` doesn't exist:
|
|
|
1548
1511
|
sessionId: sessionId
|
|
1549
1512
|
};
|
|
1550
1513
|
}
|
|
1551
|
-
async
|
|
1552
|
-
try {
|
|
1553
|
-
console.log(`🤖 AI Manager: Generating review instructions for ${args.workflowType} phase`);
|
|
1554
|
-
const instructions = this.aiManager.generateReviewInstructions({
|
|
1555
|
-
workflowType: args.workflowType,
|
|
1556
|
-
issueNumber: args.issueNumber,
|
|
1557
|
-
phase: args.phase
|
|
1558
|
-
});
|
|
1559
|
-
return {
|
|
1560
|
-
content: [{
|
|
1561
|
-
type: 'text',
|
|
1562
|
-
text: instructions
|
|
1563
|
-
}]
|
|
1564
|
-
};
|
|
1565
|
-
}
|
|
1566
|
-
catch (error) {
|
|
1567
|
-
console.error('❌ AI Manager request review failed:', error);
|
|
1568
|
-
return {
|
|
1569
|
-
content: [{
|
|
1570
|
-
type: 'text',
|
|
1571
|
-
text: `# ❌ AI Manager Request Failed\n\n**Error**: ${error instanceof Error ? error.message : 'Unknown error'}\n\nPlease check your request parameters and try again.`
|
|
1572
|
-
}],
|
|
1573
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1574
|
-
};
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
async handleAIManagerReportGrade(args) {
|
|
1514
|
+
async handleSeekCoachingOnNextStep(args) {
|
|
1578
1515
|
try {
|
|
1579
|
-
|
|
1580
|
-
const decision = this.aiManager.evaluateReport(args.report, {
|
|
1516
|
+
const response = await this.aiCoach.handleCoachingRequest({
|
|
1581
1517
|
workflowType: args.workflowType,
|
|
1582
1518
|
issueNumber: args.issueNumber,
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
const actionEmoji = decision.action === 'PROCEED' ? '✅' :
|
|
1588
|
-
decision.action === 'ESCALATE' ? '⚠️' : '🔄';
|
|
1589
|
-
response += `## Decision: ${actionEmoji} ${decision.action}\n\n`;
|
|
1590
|
-
response += `**Message**: ${decision.message}\n\n`;
|
|
1591
|
-
if (decision.iterationCount) {
|
|
1592
|
-
response += `**Iteration Count**: ${decision.iterationCount}/3\n\n`;
|
|
1593
|
-
}
|
|
1594
|
-
response += `## Next Steps\n\n`;
|
|
1595
|
-
decision.nextSteps.forEach((step, index) => {
|
|
1596
|
-
response += `${index + 1}. ${step}\n`;
|
|
1519
|
+
currentPhase: args.currentPhase,
|
|
1520
|
+
status: args.status,
|
|
1521
|
+
evidence: args.evidence,
|
|
1522
|
+
findings: args.findings
|
|
1597
1523
|
});
|
|
1598
|
-
response += `\n`;
|
|
1599
|
-
if (decision.action === 'PROCEED') {
|
|
1600
|
-
response += `## 🎉 Ready for Human Review!\n\n`;
|
|
1601
|
-
response += `Your work has passed AI Manager validation. You should now:\n\n`;
|
|
1602
|
-
response += `1. **Submit PR** with complete evidence document\n`;
|
|
1603
|
-
response += `2. **Update issue labels** to status:needs-review\n`;
|
|
1604
|
-
response += `3. **Include this AI Manager validation** in your evidence\n\n`;
|
|
1605
|
-
}
|
|
1606
|
-
else if (decision.action === 'ESCALATE') {
|
|
1607
|
-
response += `## ⚠️ Escalated to Human Review\n\n`;
|
|
1608
|
-
response += `Maximum iterations reached. Your work will be reviewed by a human despite validation failures:\n\n`;
|
|
1609
|
-
response += `1. **Submit PR** with detailed iteration history\n`;
|
|
1610
|
-
response += `2. **Add escalation label** (ai-manager:max-iterations)\n`;
|
|
1611
|
-
response += `3. **Document all attempts** and failure reasons in evidence\n`;
|
|
1612
|
-
response += `4. **Human reviewer** will focus on recurring validation issues\n\n`;
|
|
1613
|
-
}
|
|
1614
|
-
else {
|
|
1615
|
-
response += `## 🔧 Work Required\n\n`;
|
|
1616
|
-
response += `Your work needs improvement. You should:\n\n`;
|
|
1617
|
-
response += `1. **Address all failure reasons** listed below\n`;
|
|
1618
|
-
response += `2. **Re-run validation steps** to verify fixes\n`;
|
|
1619
|
-
response += `3. **Request new review** using ai_manager_request_review\n`;
|
|
1620
|
-
response += `4. **Include iterationCount: ${(decision.iterationCount || 1) + 1}** in next report\n`;
|
|
1621
|
-
response += `5. **Do NOT submit PR** until review passes or escalates\n\n`;
|
|
1622
|
-
}
|
|
1623
|
-
response += `## Your Report Summary\n\n`;
|
|
1624
|
-
response += `**Pass**: ${args.report.pass}\n`;
|
|
1625
|
-
response += `**Iteration**: ${args.report.iterationCount || 1}/3\n`;
|
|
1626
|
-
if (args.report.reasons && args.report.reasons.length > 0) {
|
|
1627
|
-
response += `**Failure Reasons**:\n`;
|
|
1628
|
-
args.report.reasons.forEach((reason) => {
|
|
1629
|
-
response += `- ${reason}\n`;
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
1524
|
return {
|
|
1633
1525
|
content: [{
|
|
1634
1526
|
type: 'text',
|
|
1635
1527
|
text: response
|
|
1636
|
-
}]
|
|
1637
|
-
decision: decision
|
|
1528
|
+
}]
|
|
1638
1529
|
};
|
|
1639
1530
|
}
|
|
1640
1531
|
catch (error) {
|
|
1641
|
-
console.error('❌ AI
|
|
1532
|
+
console.error('❌ AI Coach guidance failed:', error);
|
|
1642
1533
|
return {
|
|
1643
1534
|
content: [{
|
|
1644
1535
|
type: 'text',
|
|
1645
|
-
text: `# ❌ AI
|
|
1536
|
+
text: `# ❌ AI Coach Guidance Failed\n\n**Error**: ${error instanceof Error ? error.message : 'Unknown error'}\n\nPlease check your request parameters and try again.`
|
|
1646
1537
|
}],
|
|
1538
|
+
isError: true,
|
|
1647
1539
|
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1648
1540
|
};
|
|
1649
1541
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createStaticWebsiteMiddleware = createStaticWebsiteMiddleware;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
/**
|
|
11
|
+
* Middleware to serve the FRAIM website at /fraim endpoint
|
|
12
|
+
* This serves the static website files from the website directory
|
|
13
|
+
*/
|
|
14
|
+
function createStaticWebsiteMiddleware() {
|
|
15
|
+
const router = express_1.default.Router();
|
|
16
|
+
// Find the website directory
|
|
17
|
+
const websitePath = findWebsitePath();
|
|
18
|
+
if (!websitePath) {
|
|
19
|
+
console.warn('⚠️ Website directory not found. FRAIM website will not be available at /fraim');
|
|
20
|
+
return router;
|
|
21
|
+
}
|
|
22
|
+
console.log(`🌐 Serving FRAIM website from: ${websitePath}`);
|
|
23
|
+
// Serve static files from website directory at /fraim endpoint only
|
|
24
|
+
router.use('/fraim', express_1.default.static(websitePath, {
|
|
25
|
+
index: 'index.html',
|
|
26
|
+
setHeaders: (res, path) => {
|
|
27
|
+
// Set proper MIME types
|
|
28
|
+
if (path.endsWith('.css')) {
|
|
29
|
+
res.setHeader('Content-Type', 'text/css');
|
|
30
|
+
}
|
|
31
|
+
else if (path.endsWith('.js')) {
|
|
32
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
33
|
+
}
|
|
34
|
+
else if (path.endsWith('.png')) {
|
|
35
|
+
res.setHeader('Content-Type', 'image/png');
|
|
36
|
+
}
|
|
37
|
+
else if (path.endsWith('.jpg') || path.endsWith('.jpeg')) {
|
|
38
|
+
res.setHeader('Content-Type', 'image/jpeg');
|
|
39
|
+
}
|
|
40
|
+
else if (path.endsWith('.svg')) {
|
|
41
|
+
res.setHeader('Content-Type', 'image/svg+xml');
|
|
42
|
+
}
|
|
43
|
+
// Cache static assets for 1 hour
|
|
44
|
+
if (path.match(/\.(css|js|png|jpg|jpeg|svg|ico)$/)) {
|
|
45
|
+
res.setHeader('Cache-Control', 'public, max-age=3600');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
return router;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find the website directory
|
|
53
|
+
* Checks multiple possible locations
|
|
54
|
+
*/
|
|
55
|
+
function findWebsitePath() {
|
|
56
|
+
const possiblePaths = [
|
|
57
|
+
// Production: dist/website
|
|
58
|
+
(0, path_1.join)(process.cwd(), 'dist', 'website'),
|
|
59
|
+
// Development: website
|
|
60
|
+
(0, path_1.join)(process.cwd(), 'website'),
|
|
61
|
+
// Relative to server file: ../website
|
|
62
|
+
(0, path_1.join)(__dirname, '..', 'website'),
|
|
63
|
+
// Relative to server file: ../../website
|
|
64
|
+
(0, path_1.join)(__dirname, '..', '..', 'website')
|
|
65
|
+
];
|
|
66
|
+
for (const path of possiblePaths) {
|
|
67
|
+
if ((0, fs_1.existsSync)(path)) {
|
|
68
|
+
const indexPath = (0, path_1.join)(path, 'index.html');
|
|
69
|
+
if ((0, fs_1.existsSync)(indexPath)) {
|
|
70
|
+
return path;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|