UNPKG

metacoding

Version:

Guided Development Workflow for GitHub Copilot - Transform your coding experience with AI-guided standards, structured workflows, and quality practices

287 lines 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.TemplateManager = void 0; const path = __importStar(require("path")); const fs = __importStar(require("fs-extra")); class TemplateManager { constructor() { this.templatesDir = path.join(__dirname, '../../templates'); this.instructionsDir = this.templatesDir; } async getTemplate(templateName, projectConfig) { const templatePath = path.join(this.templatesDir, templateName); if (!(await fs.pathExists(templatePath))) { throw new Error(`Template '${templateName}' not found`); } const configPath = path.join(templatePath, 'template.json'); if (!(await fs.pathExists(configPath))) { throw new Error(`Template configuration not found for '${templateName}'`); } const config = await fs.readJson(configPath); const filesDir = path.join(templatePath, 'files'); const templateFiles = await this.loadTemplateFiles(filesDir); const instructionFiles = await this.loadInstructionFiles(templateName, projectConfig); const files = [...templateFiles, ...instructionFiles]; return { name: templateName, description: config.description, files, prompts: config.prompts || [], vscodeSettings: config.vscodeSettings || {}, }; } async loadInstructionFiles(templateName, projectConfig) { const files = []; const generalPath = path.join(this.templatesDir, 'general'); const universalFiles = [ 'copilot-instructions.md', 'docs-update.instructions.md', 'release.instructions.md', 'code-review.instructions.md', ]; for (const file of universalFiles) { const filePath = path.join(generalPath, file); if (await fs.pathExists(filePath)) { files.push({ source: `general/${file}`, destination: file === 'copilot-instructions.md' ? '.github/copilot-instructions.md' : `.github/instructions/${file}`, template: file === 'copilot-instructions.md', }); } } const testingFiles = { react: 'react.testing.instructions.md', node: 'nodejs.testing.instructions.md', python: 'python.testing.instructions.md', general: 'test-runner.instructions.md', }; const testingFile = testingFiles[templateName]; if (testingFile) { const templatePath = path.join(this.templatesDir, templateName); const testingFilePath = path.join(templatePath, testingFile); if (await fs.pathExists(testingFilePath)) { files.push({ source: `${templateName}/${testingFile}`, destination: '.github/instructions/test-runner.instructions.md', template: false, }); } } const typescriptTemplates = ['node', 'react']; const useTypeScript = typescriptTemplates.includes(templateName) || projectConfig?.techStack?.includes('TypeScript'); if (useTypeScript) { const typescriptPath = path.join(this.templatesDir, 'typescript'); if (await fs.pathExists(typescriptPath)) { const typescriptFiles = await fs.readdir(typescriptPath); for (const file of typescriptFiles) { if (file === 'template.json') { continue; } if (file.endsWith('.instructions.md')) { files.push({ source: `typescript/${file}`, destination: `.github/instructions/${file}`, template: false, }); } } } } if (templateName !== 'general') { const templatePath = path.join(this.templatesDir, templateName); const templateFiles = await fs.readdir(templatePath); for (const file of templateFiles) { if (file === 'template.json' || universalFiles.includes(file)) { continue; } if (file.endsWith('.instructions.md')) { files.push({ source: `${templateName}/${file}`, destination: `.github/instructions/${file}`, template: false, }); } } } return files; } async processTemplate(template, config) { const processedFiles = []; for (const file of template.files) { let content; let filePath; if (file.source.includes('/')) { filePath = path.join(this.templatesDir, file.source); } else { filePath = path.join(this.templatesDir, template.name, file.source); } if (file.template) { const templateContent = await fs.readFile(filePath, 'utf8'); content = this.processTemplateContent(templateContent, config); } else { content = await fs.readFile(filePath, 'utf8'); } processedFiles.push({ path: file.destination, content, }); } return processedFiles; } async getAvailableTemplates() { if (!(await fs.pathExists(this.templatesDir))) { return []; } const items = await fs.readdir(this.templatesDir); const templates = []; const excludedTemplates = ['typescript']; for (const item of items) { const itemPath = path.join(this.templatesDir, item); const stat = await fs.stat(itemPath); if (stat.isDirectory() && !excludedTemplates.includes(item)) { const configPath = path.join(itemPath, 'template.json'); if (await fs.pathExists(configPath)) { templates.push(item); } } } return templates; } async loadTemplateFiles(filesDir) { const files = []; if (!(await fs.pathExists(filesDir))) { return files; } const templateName = path.basename(path.dirname(filesDir)); const items = await fs.readdir(filesDir, { withFileTypes: true }); for (const item of items) { if (item.isFile()) { const isTemplate = item.name.endsWith('.template'); const source = `${templateName}/files/${item.name}`; let destination = item.name; if (isTemplate) { destination = item.name.replace('.template', ''); } if (destination === 'copilot-instructions.md' || destination.endsWith('.instructions.md')) { continue; } files.push({ source, destination, template: isTemplate, }); } } return files; } processTemplateContent(content, config) { const variables = { PROJECT_NAME: config.name, PROJECT_DESCRIPTION: config.description, TECH_STACK: Array.isArray(config.techStack) ? config.techStack.join(', ') : config.techStack, PROJECT_TYPE: config.projectType, TEST_FRAMEWORK: config.testFramework || 'Jest', BUILD_TOOL: config.buildTool || 'TypeScript Compiler', PROJECT_DOMAIN: this.getProjectDomain(config.projectType), PROJECT_SPECIFIC_GUIDANCE: this.getProjectSpecificGuidance(config.projectType), }; let processedContent = content; for (const [key, value] of Object.entries(variables)) { const placeholder = `{{${key}}}`; processedContent = processedContent.replace(new RegExp(placeholder, 'g'), value); } processedContent = processedContent.replace(/\[short project description\]/g, config.description); processedContent = processedContent.replace(/\[Main goal 1\]/g, 'Provide guided development workflow'); processedContent = processedContent.replace(/\[Main goal 2\]/g, 'Ensure code quality and best practices'); processedContent = processedContent.replace(/\[Main goal 3\]/g, 'Enable efficient team collaboration'); processedContent = processedContent.replace(/\[List primary technologies\]/g, variables.TECH_STACK); processedContent = processedContent.replace(/\[project specific\]/g, variables.PROJECT_DOMAIN); return processedContent; } getProjectDomain(projectType) { switch (projectType) { case 'react': return 'React frontend'; case 'node': return 'Node.js backend'; case 'python': return 'Python'; default: return 'software'; } } getProjectSpecificGuidance(projectType) { switch (projectType) { case 'react': return ` - **React Components:** Follow modern React patterns with hooks and functional components - **JSX Best Practices:** Use semantic HTML elements and proper JSX syntax - **State Management:** Implement efficient state management with React hooks - **Component Architecture:** Build reusable, testable React components - **Frontend Performance:** Optimize rendering and bundle size for better user experience`; case 'node': return ` - **Server Architecture:** Design scalable Node.js server applications - **API Development:** Build robust REST APIs with proper error handling - **Backend Services:** Implement efficient server-side business logic - **Database Integration:** Use appropriate data persistence patterns - **Performance:** Optimize server response times and resource usage`; case 'python': return ` - **Django Development:** Follow Django best practices for web applications - **Flask Applications:** Build lightweight Flask applications when appropriate - **Python Standards:** Adhere to PEP 8 and Python coding conventions - **Backend Development:** Implement scalable Python backend solutions - **Framework Integration:** Use appropriate Python frameworks for different use cases`; default: return ` - **Best Practices:** Follow language-specific coding standards and conventions - **Architecture:** Implement modular and maintainable code structure - **Testing:** Write comprehensive tests for all functionality - **Documentation:** Maintain clear and up-to-date documentation`; } } } exports.TemplateManager = TemplateManager; //# sourceMappingURL=template-manager.js.map