diff --git a/.github/issue_template/ai-refinement.md b/.github/issue_template/ai-refinement.md index f56a7a5..f701b7d 100644 --- a/.github/issue_template/ai-refinement.md +++ b/.github/issue_template/ai-refinement.md @@ -8,46 +8,12 @@ labels: --- -# [Module] - [Add/Change/Fix/Refactor/Remove] [Feature/Component] +Describe your request: -## Type: [Bug/DevOps/Enhancement/Refactor/Security] +What are you trying to do and what's happening? -| | Score | -|------------|----------| -| Size | 0-5 | -| Complexity | 0-5 | -| Unknowns | 0-5 | -| **Total** | **0-15** | +How can it be fixed or improved? -## Description +Steps to reproduce? -A clear explanation of the issue, feature, or change needed - -## Current Behavior - -For bugs: what's happening now -For refactors: what exists today -For enhancements: current state/gap - -## Expected Behavior - -What should happen instead - -## Steps to Reproduce - -1. First step -2. Second step -3. Third step - -## Additional Context - -Logs, screenshots, links, related issues - -## Acceptance Criteria - -- [ ] Todo requirement -- [X] Completed requirement - -## Technical Notes - -Implementation details, constraints, dependencies, design decisions +Anything other useful information, logs or screenshots? diff --git a/src/refine.mjs b/src/refine.mjs index bedcfa2..c1b7155 100644 --- a/src/refine.mjs +++ b/src/refine.mjs @@ -14,8 +14,6 @@ dotenv.config({path: '.env.local', override: true, quiet: true}); if(p === 'refine' || p.endsWith('refine.mjs')) p = null; if(!/^(\/|[A-Z]:)/m.test(p)) p = path.join(process.cwd(), p); - if(!p || !fs.existsSync(p)) throw new Error('Please provide a template'); - const git = process.env['GIT_HOST'], owner = process.env['GIT_OWNER'], repo = process.env['GIT_REPO'], @@ -38,9 +36,49 @@ dotenv.config({path: '.env.local', override: true, quiet: true}); return process.exit(); } - let readme = '', readmeP = path.join(process.cwd(), 'README.md'); + let title = '', type = '', readme = '', readmeP = path.join(process.cwd(), 'README.md'); if(fs.existsSync(readmeP)) readme = fs.readFileSync(readmeP, 'utf-8'); - const template = fs.readFileSync(p, 'utf-8'); + const template = p ? fs.readFileSync(p, 'utf-8') : `## Description + +A clear explanation of the request + +--- + +## Current Behavior + +what's happening now or the current state/gap + +## Expected Behavior + +What should happen instead + +## Steps to Reproduce + +1. First step +2. Second step +3. Third step + +## Additional Context + +Logs, screenshots, links, related issues + +## Acceptance Criteria + +- [ ] Todo requirement +- [X] Completed requirement + +## Technical Notes + +Implementation details, constraints, dependencies, design decisions + + +| Effort / Weight | Score | +|-----------------|----------| +| Size | 0-5 | +| Complexity | 0-5 | +| Unknowns | 0-5 | +| **Total** | **0-15** | +`; let options = {ollama: {model, host}}; if(host === 'anthropic') options = {anthropic: {model, token}}; @@ -49,18 +87,30 @@ dotenv.config({path: '.env.local', override: true, quiet: true}); ...options, model: [host, model], path: process.env['path'] || os.tmpdir(), + tools: [{ + name: 'title', + description: 'Set the ticket title, must be called EXACTLY ONCE', + args: {value: {type: 'string', description: 'Ticket title, must match format: [Module] - [Verb] [noun]', required: true}}, + fn: (args) => title = args.title + }, { + name: 'type', + description: 'Set the ticket type, must be called EXACTLY ONCE', + args: {type: {type: 'string', description: 'Ticket type', enum: ['Bug', 'DevOps', 'Document', 'Enhancement', 'Refactor', 'Security'], required: true}}, + fn: (args) => type = args.type + }], system: `You are a ticket formatter. Transform raw issue descriptions into structured tickets. **CRITICAL RULES:** 1. Identify the ticket type (Bug, DevOps, Enhancement, Refactor, Security) 2. Output MUST only contain the new ticket information in markdown, no extra fluff 3. Follow the template structure EXACTLY: - - Title format: [Module] - [Verb] [noun] + - You must call the \`title\` tool EXACTLY ONCE with the title matching this format: [Module] - [Verb] [noun] Example: Storage - Fix file uploads - - Fill in the identified ticket type + - You must call the \`type\` tool EXACTLY ONCE with the identified ticket type - Write a clear description - For bugs: fill Steps to Reproduce with numbered list - For enhancements/refactors: REMOVE the Steps to Reproduce section entirely + - For documentation: REMOVE the Current Behavior, Expected Behavior and Steps to Reproduce sections entirely - Acceptance Criteria: convert requirements into checkboxes (- [ ]) - Weight scoring (0-5 each): * Size: Number of modules, layers & files affected by change @@ -81,18 +131,14 @@ ${template.trim()} \`\`\` Output ONLY the formatted ticket, no explanation.` - }) + }); const messages = await ai.language.ask(`Title: ${issueData.title}\n\nDescription:\n${issueData.body || 'No description provided'}`).catch(() => []); - const content = messages?.pop()?.content; - if(!content) { + const body = messages?.pop()?.content; + if(!body) { console.log('Invalid response from AI'); return process.exit(1); } - const title = /^# (.+)$/m.exec(content)?.[1] || issueData.title; - const typeMatch = /^## Type:\s*(.+)$/m.exec(content); - const type = typeMatch?.[1]?.split('/')[0]?.trim() || 'Unassigned'; - const body = content.replace(/^# .+$/m, '').replace(/^## Type:.+$/m, '').trim(); const updateRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, { method: 'PATCH', headers: { @@ -102,9 +148,17 @@ Output ONLY the formatted ticket, no explanation.` body: JSON.stringify({ title, body, - labels: type?.length ? [`Kind/${type[0].toUpperCase() + type.slice(1).toLowerCase()}`] : [] }) }); if(!updateRes.ok) throw new Error(`${updateRes.status} ${await updateRes.text()}`); + if(type) fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}/labels`, { + method: 'POST', + headers: { + 'Authorization': `token ${auth}`, + 'Content-Type': 'application/json' + }, + body: `["Kind/${type[0].toUpperCase() + type.slice(1).toLowerCase()}"]` + }) + console.log(body); })();