@grunnverk/github-tools 1.0.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/dist/issues.js ADDED
@@ -0,0 +1,332 @@
1
+ import { getLogger } from './logger.js';
2
+ import { getOpenIssues, createIssue } from './github.js';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { spawnSync } from 'child_process';
6
+ import fs from 'fs/promises';
7
+
8
+ // Get GitHub issues content
9
+ const get = async (options = {})=>{
10
+ const logger = getLogger();
11
+ const { limit = 20 } = options;
12
+ try {
13
+ logger.debug('Fetching open GitHub issues...');
14
+ const issuesLimit = Math.min(limit, 20); // Cap at 20
15
+ const githubIssues = await getOpenIssues(issuesLimit);
16
+ if (githubIssues.trim()) {
17
+ logger.debug(`Added GitHub issues to context (${githubIssues.length} characters)`);
18
+ return githubIssues;
19
+ } else {
20
+ logger.debug('No open GitHub issues found');
21
+ return '';
22
+ }
23
+ } catch (error) {
24
+ logger.warn(`Failed to fetch GitHub issues: ${error.message}`);
25
+ return '';
26
+ }
27
+ };
28
+ // Helper function to get user choice interactively
29
+ async function getUserChoice(_prompt, _choices) {
30
+ var _choices_;
31
+ // Placeholder - always returns first choice
32
+ return ((_choices_ = _choices[0]) === null || _choices_ === void 0 ? void 0 : _choices_.key) || '';
33
+ }
34
+ // Helper function to serialize issue to structured text format
35
+ function serializeIssue(issue) {
36
+ const lines = [
37
+ '# Issue Editor',
38
+ '',
39
+ '# Edit the issue details below. Lines starting with "#" are comments and will be ignored.',
40
+ '# Valid priorities: low, medium, high',
41
+ '# Valid categories: ui, content, functionality, accessibility, performance, other',
42
+ '# Suggestions should be one per line, preceded by a "-" or "•"',
43
+ '',
44
+ `Title: ${issue.title}`,
45
+ '',
46
+ `Priority: ${issue.priority}`,
47
+ '',
48
+ `Category: ${issue.category}`,
49
+ '',
50
+ 'Description:',
51
+ issue.description,
52
+ '',
53
+ 'Suggestions:'
54
+ ];
55
+ if (issue.suggestions && issue.suggestions.length > 0) {
56
+ issue.suggestions.forEach((suggestion)=>{
57
+ lines.push(`- ${suggestion}`);
58
+ });
59
+ } else {
60
+ lines.push('# Add suggestions here, one per line with "-" or "•"');
61
+ }
62
+ return lines.join('\n');
63
+ }
64
+ // Helper function to deserialize issue from structured text format
65
+ function deserializeIssue(content) {
66
+ const lines = content.split('\n');
67
+ // Parse the structured format
68
+ let title = '';
69
+ let priority = 'medium';
70
+ let category = 'other';
71
+ let description = '';
72
+ const suggestions = [];
73
+ let currentSection = '';
74
+ let descriptionLines = [];
75
+ for(let i = 0; i < lines.length; i++){
76
+ const line = lines[i].trim();
77
+ // Skip comment lines
78
+ if (line.startsWith('#')) {
79
+ continue;
80
+ }
81
+ // Parse field lines
82
+ if (line.startsWith('Title:')) {
83
+ title = line.substring(6).trim();
84
+ } else if (line.startsWith('Priority:')) {
85
+ const priorityValue = line.substring(9).trim().toLowerCase();
86
+ if (priorityValue === 'low' || priorityValue === 'medium' || priorityValue === 'high') {
87
+ priority = priorityValue;
88
+ }
89
+ } else if (line.startsWith('Category:')) {
90
+ const categoryValue = line.substring(9).trim().toLowerCase();
91
+ if ([
92
+ 'ui',
93
+ 'content',
94
+ 'functionality',
95
+ 'accessibility',
96
+ 'performance',
97
+ 'other'
98
+ ].includes(categoryValue)) {
99
+ category = categoryValue;
100
+ }
101
+ } else if (line === 'Description:') {
102
+ currentSection = 'description';
103
+ descriptionLines = [];
104
+ } else if (line === 'Suggestions:') {
105
+ currentSection = 'suggestions';
106
+ // Process accumulated description lines
107
+ description = descriptionLines.join('\n').trim();
108
+ } else if (currentSection === 'description' && line !== '') {
109
+ descriptionLines.push(lines[i]); // Keep original line with spacing
110
+ } else if (currentSection === 'suggestions' && line !== '') {
111
+ // Parse suggestion line
112
+ const suggestionLine = line.replace(/^[-•]\s*/, '').trim();
113
+ if (suggestionLine) {
114
+ suggestions.push(suggestionLine);
115
+ }
116
+ }
117
+ }
118
+ // If we didn't encounter suggestions section, description might still be accumulating
119
+ if (currentSection === 'description') {
120
+ description = descriptionLines.join('\n').trim();
121
+ }
122
+ return {
123
+ title: title || 'Untitled Issue',
124
+ priority,
125
+ category,
126
+ description: description || 'No description provided',
127
+ suggestions: suggestions.length > 0 ? suggestions : undefined
128
+ };
129
+ }
130
+ // Helper function to edit issue using editor
131
+ async function editIssueInteractively(issue) {
132
+ const logger = getLogger();
133
+ const editor = process.env.EDITOR || process.env.VISUAL || 'vi';
134
+ // Create a temporary file for the user to edit
135
+ const tmpDir = os.tmpdir();
136
+ const tmpFilePath = path.join(tmpDir, `kodrdriv_issue_${Date.now()}.txt`);
137
+ // Serialize the issue to structured text format
138
+ const issueContent = serializeIssue(issue);
139
+ await fs.writeFile(tmpFilePath, issueContent, 'utf8');
140
+ logger.info(`📝 Opening ${editor} to edit issue...`);
141
+ // Open the editor synchronously so execution resumes after the user closes it
142
+ const result = spawnSync(editor, [
143
+ tmpFilePath
144
+ ], {
145
+ stdio: 'inherit'
146
+ });
147
+ if (result.error) {
148
+ throw new Error(`Failed to launch editor '${editor}': ${result.error.message}`);
149
+ }
150
+ // Read the file back and deserialize it
151
+ const editedContent = await fs.readFile(tmpFilePath, 'utf8');
152
+ // Clean up the temporary file with proper error handling
153
+ try {
154
+ await fs.unlink(tmpFilePath);
155
+ } catch (error) {
156
+ // Only log if it's not a "file not found" error
157
+ if (error.code !== 'ENOENT') {
158
+ logger.warn(`Failed to cleanup temporary file ${tmpFilePath}: ${error.message}`);
159
+ }
160
+ }
161
+ // Deserialize the edited content back to an Issue object
162
+ const editedIssue = deserializeIssue(editedContent);
163
+ logger.info('✅ Issue updated successfully');
164
+ logger.debug(`Updated issue: ${JSON.stringify(editedIssue, null, 2)}`);
165
+ return editedIssue;
166
+ }
167
+ // Helper function to format issue body for GitHub
168
+ function formatIssueBody(issue) {
169
+ let body = `## Description\n\n${issue.description}\n\n`;
170
+ body += `## Details\n\n`;
171
+ body += `- **Priority:** ${issue.priority}\n`;
172
+ body += `- **Category:** ${issue.category}\n`;
173
+ body += `- **Source:** Review\n\n`;
174
+ if (issue.suggestions && issue.suggestions.length > 0) {
175
+ body += `## Suggestions\n\n`;
176
+ issue.suggestions.forEach((suggestion)=>{
177
+ body += `- ${suggestion}\n`;
178
+ });
179
+ body += '\n';
180
+ }
181
+ body += `---\n\n`;
182
+ body += `*This issue was automatically created from a review session.*`;
183
+ return body;
184
+ }
185
+ // Helper function to format results with created GitHub issues
186
+ function formatReviewResultsWithIssues(result, createdIssues) {
187
+ let output = `📝 Review Results\n\n`;
188
+ output += `📋 Summary: ${result.summary}\n`;
189
+ output += `📊 Total Issues Found: ${result.totalIssues}\n`;
190
+ output += `🚀 GitHub Issues Created: ${createdIssues.length}\n\n`;
191
+ if (result.issues && result.issues.length > 0) {
192
+ output += `📝 Issues Identified:\n\n`;
193
+ result.issues.forEach((issue, index)=>{
194
+ const priorityEmoji = issue.priority === 'high' ? '🔴' : issue.priority === 'medium' ? '🟡' : '🟢';
195
+ const categoryEmoji = issue.category === 'ui' ? '🎨' : issue.category === 'content' ? '📝' : issue.category === 'functionality' ? '⚙️' : issue.category === 'accessibility' ? '♿' : issue.category === 'performance' ? '⚡' : '🔧';
196
+ output += `${index + 1}. ${priorityEmoji} ${issue.title}\n`;
197
+ output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\n`;
198
+ output += ` 📖 Description: ${issue.description}\n`;
199
+ // Check if this issue was created as a GitHub issue
200
+ const createdIssue = createdIssues.find((ci)=>ci.issue === issue);
201
+ if (createdIssue) {
202
+ output += ` 🔗 GitHub Issue: #${createdIssue.number} - ${createdIssue.githubUrl}\n`;
203
+ }
204
+ if (issue.suggestions && issue.suggestions.length > 0) {
205
+ output += ` 💡 Suggestions:\n`;
206
+ issue.suggestions.forEach((suggestion)=>{
207
+ output += ` • ${suggestion}\n`;
208
+ });
209
+ }
210
+ output += `\n`;
211
+ });
212
+ } else {
213
+ output += `✅ No specific issues identified from the review.\n\n`;
214
+ }
215
+ if (createdIssues.length > 0) {
216
+ output += `\n🎯 Created GitHub Issues:\n`;
217
+ createdIssues.forEach((createdIssue)=>{
218
+ output += `• #${createdIssue.number}: ${createdIssue.issue.title} - ${createdIssue.githubUrl}\n`;
219
+ });
220
+ output += `\n`;
221
+ }
222
+ output += `🚀 Next Steps: Review the created GitHub issues and prioritize them in your development workflow.`;
223
+ return output;
224
+ }
225
+ function formatReviewResults(result) {
226
+ let output = `📝 Review Results\n\n`;
227
+ output += `📋 Summary: ${result.summary}\n`;
228
+ output += `📊 Total Issues Found: ${result.totalIssues}\n\n`;
229
+ if (result.issues && result.issues.length > 0) {
230
+ output += `📝 Issues Identified:\n\n`;
231
+ result.issues.forEach((issue, index)=>{
232
+ const priorityEmoji = issue.priority === 'high' ? '🔴' : issue.priority === 'medium' ? '🟡' : '🟢';
233
+ const categoryEmoji = issue.category === 'ui' ? '🎨' : issue.category === 'content' ? '📝' : issue.category === 'functionality' ? '⚙️' : issue.category === 'accessibility' ? '♿' : issue.category === 'performance' ? '⚡' : '🔧';
234
+ output += `${index + 1}. ${priorityEmoji} ${issue.title}\n`;
235
+ output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\n`;
236
+ output += ` 📖 Description: ${issue.description}\n`;
237
+ if (issue.suggestions && issue.suggestions.length > 0) {
238
+ output += ` 💡 Suggestions:\n`;
239
+ issue.suggestions.forEach((suggestion)=>{
240
+ output += ` • ${suggestion}\n`;
241
+ });
242
+ }
243
+ output += `\n`;
244
+ });
245
+ } else {
246
+ output += `✅ No specific issues identified from the review.\n\n`;
247
+ }
248
+ output += `🚀 Next Steps: Review the identified issues and prioritize them for your development workflow.`;
249
+ return output;
250
+ }
251
+ // Handle GitHub issue creation workflow
252
+ const handleIssueCreation = async (result, senditMode = false)=>{
253
+ const logger = getLogger();
254
+ const createdIssues = [];
255
+ if (!result.issues || result.issues.length === 0) {
256
+ return formatReviewResults(result);
257
+ }
258
+ logger.info(`🔍 Found ${result.issues.length} issues to potentially create as GitHub issues`);
259
+ for(let i = 0; i < result.issues.length; i++){
260
+ let issue = result.issues[i];
261
+ let shouldCreateIssue = senditMode;
262
+ if (!senditMode) {
263
+ // Interactive confirmation for each issue - keep looping until user decides
264
+ let userChoice = '';
265
+ while(userChoice !== 'c' && userChoice !== 's'){
266
+ // Display issue details
267
+ logger.info(`\n📋 Issue ${i + 1} of ${result.issues.length}:`);
268
+ logger.info(` Title: ${issue.title}`);
269
+ logger.info(` Priority: ${issue.priority} | Category: ${issue.category}`);
270
+ logger.info(` Description: ${issue.description}`);
271
+ if (issue.suggestions && issue.suggestions.length > 0) {
272
+ logger.info(` Suggestions: ${issue.suggestions.join(', ')}`);
273
+ }
274
+ // Get user choice
275
+ userChoice = await getUserChoice('\nWhat would you like to do with this issue?', [
276
+ {
277
+ key: 'c',
278
+ label: 'Create GitHub issue'
279
+ },
280
+ {
281
+ key: 's',
282
+ label: 'Skip this issue'
283
+ },
284
+ {
285
+ key: 'e',
286
+ label: 'Edit issue details'
287
+ }
288
+ ]);
289
+ if (userChoice === 'c') {
290
+ shouldCreateIssue = true;
291
+ } else if (userChoice === 'e') {
292
+ // Allow user to edit the issue
293
+ issue = await editIssueInteractively(issue);
294
+ result.issues[i] = issue; // Update the issue in the result
295
+ // Continue the loop to show the updated issue and ask again
296
+ }
297
+ // If choice is 's', loop will exit and shouldCreateIssue remains false
298
+ }
299
+ }
300
+ if (shouldCreateIssue) {
301
+ try {
302
+ logger.info(`🚀 Creating GitHub issue: "${issue.title}"`);
303
+ // Format issue body with additional details
304
+ const issueBody = formatIssueBody(issue);
305
+ // Create labels based on priority and category
306
+ const labels = [
307
+ `priority-${issue.priority}`,
308
+ `category-${issue.category}`,
309
+ 'review'
310
+ ];
311
+ const createdIssue = await createIssue(issue.title, issueBody, labels);
312
+ createdIssues.push({
313
+ issue,
314
+ githubUrl: createdIssue.html_url,
315
+ number: createdIssue.number
316
+ });
317
+ logger.info(`✅ Created GitHub issue #${createdIssue.number}: ${createdIssue.html_url}`);
318
+ } catch (error) {
319
+ logger.error(`❌ Failed to create GitHub issue for "${issue.title}": ${error.message}`);
320
+ }
321
+ }
322
+ }
323
+ // Return formatted results
324
+ if (createdIssues.length > 0) {
325
+ return formatReviewResultsWithIssues(result, createdIssues);
326
+ } else {
327
+ return formatReviewResults(result);
328
+ }
329
+ };
330
+
331
+ export { get, handleIssueCreation };
332
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sources":["../src/issues.ts"],"sourcesContent":["import { getLogger } from './logger';\nimport { getOpenIssues, createIssue } from './github';\n\nimport path from 'path';\nimport os from 'os';\nimport { spawnSync } from 'child_process';\nimport fs from 'fs/promises';\n\nexport interface Issue {\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high';\n category: 'ui' | 'content' | 'functionality' | 'accessibility' | 'performance' | 'other';\n suggestions?: string[];\n}\n\nexport interface ReviewResult {\n summary: string;\n totalIssues: number;\n issues: Issue[];\n}\n\n// Get GitHub issues content\nexport const get = async (options: { limit?: number } = {}): Promise<string> => {\n const logger = getLogger();\n const { limit = 20 } = options;\n\n try {\n logger.debug('Fetching open GitHub issues...');\n const issuesLimit = Math.min(limit, 20); // Cap at 20\n const githubIssues = await getOpenIssues(issuesLimit);\n\n if (githubIssues.trim()) {\n logger.debug(`Added GitHub issues to context (${githubIssues.length} characters)`);\n return githubIssues;\n } else {\n logger.debug('No open GitHub issues found');\n return '';\n }\n } catch (error: any) {\n logger.warn(`Failed to fetch GitHub issues: ${error.message}`);\n return '';\n }\n};\n\n// Helper function to get user choice interactively\nasync function getUserChoice(_prompt: string, _choices: Array<{ key: string, label: string }>): Promise<string> {\n // Placeholder - always returns first choice\n return _choices[0]?.key || '';\n}\n\n// Helper function to serialize issue to structured text format\nfunction serializeIssue(issue: Issue): string {\n const lines = [\n '# Issue Editor',\n '',\n '# Edit the issue details below. Lines starting with \"#\" are comments and will be ignored.',\n '# Valid priorities: low, medium, high',\n '# Valid categories: ui, content, functionality, accessibility, performance, other',\n '# Suggestions should be one per line, preceded by a \"-\" or \"•\"',\n '',\n `Title: ${issue.title}`,\n '',\n `Priority: ${issue.priority}`,\n '',\n `Category: ${issue.category}`,\n '',\n 'Description:',\n issue.description,\n '',\n 'Suggestions:',\n ];\n\n if (issue.suggestions && issue.suggestions.length > 0) {\n issue.suggestions.forEach(suggestion => {\n lines.push(`- ${suggestion}`);\n });\n } else {\n lines.push('# Add suggestions here, one per line with \"-\" or \"•\"');\n }\n\n return lines.join('\\n');\n}\n\n// Helper function to deserialize issue from structured text format\nfunction deserializeIssue(content: string): Issue {\n const lines = content.split('\\n');\n\n // Parse the structured format\n let title = '';\n let priority: 'low' | 'medium' | 'high' = 'medium';\n let category: 'ui' | 'content' | 'functionality' | 'accessibility' | 'performance' | 'other' = 'other';\n let description = '';\n const suggestions: string[] = [];\n\n let currentSection = '';\n let descriptionLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip comment lines\n if (line.startsWith('#')) {\n continue;\n }\n\n // Parse field lines\n if (line.startsWith('Title:')) {\n title = line.substring(6).trim();\n } else if (line.startsWith('Priority:')) {\n const priorityValue = line.substring(9).trim().toLowerCase();\n if (priorityValue === 'low' || priorityValue === 'medium' || priorityValue === 'high') {\n priority = priorityValue;\n }\n } else if (line.startsWith('Category:')) {\n const categoryValue = line.substring(9).trim().toLowerCase();\n if (['ui', 'content', 'functionality', 'accessibility', 'performance', 'other'].includes(categoryValue)) {\n category = categoryValue as any;\n }\n } else if (line === 'Description:') {\n currentSection = 'description';\n descriptionLines = [];\n } else if (line === 'Suggestions:') {\n currentSection = 'suggestions';\n // Process accumulated description lines\n description = descriptionLines.join('\\n').trim();\n } else if (currentSection === 'description' && line !== '') {\n descriptionLines.push(lines[i]); // Keep original line with spacing\n } else if (currentSection === 'suggestions' && line !== '') {\n // Parse suggestion line\n const suggestionLine = line.replace(/^[-•]\\s*/, '').trim();\n if (suggestionLine) {\n suggestions.push(suggestionLine);\n }\n }\n }\n\n // If we didn't encounter suggestions section, description might still be accumulating\n if (currentSection === 'description') {\n description = descriptionLines.join('\\n').trim();\n }\n\n return {\n title: title || 'Untitled Issue',\n priority,\n category,\n description: description || 'No description provided',\n suggestions: suggestions.length > 0 ? suggestions : undefined\n };\n}\n\n// Helper function to edit issue using editor\nasync function editIssueInteractively(issue: Issue): Promise<Issue> {\n const logger = getLogger();\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi';\n\n // Create a temporary file for the user to edit\n const tmpDir = os.tmpdir();\n const tmpFilePath = path.join(tmpDir, `kodrdriv_issue_${Date.now()}.txt`);\n\n // Serialize the issue to structured text format\n const issueContent = serializeIssue(issue);\n\n await fs.writeFile(tmpFilePath, issueContent, 'utf8');\n\n logger.info(`📝 Opening ${editor} to edit issue...`);\n\n // Open the editor synchronously so execution resumes after the user closes it\n const result = spawnSync(editor, [tmpFilePath], { stdio: 'inherit' });\n\n if (result.error) {\n throw new Error(`Failed to launch editor '${editor}': ${result.error.message}`);\n }\n\n // Read the file back and deserialize it\n const editedContent = await fs.readFile(tmpFilePath, 'utf8');\n\n // Clean up the temporary file with proper error handling\n try {\n await fs.unlink(tmpFilePath);\n } catch (error: any) {\n // Only log if it's not a \"file not found\" error\n if (error.code !== 'ENOENT') {\n logger.warn(`Failed to cleanup temporary file ${tmpFilePath}: ${error.message}`);\n }\n }\n\n // Deserialize the edited content back to an Issue object\n const editedIssue = deserializeIssue(editedContent);\n\n logger.info('✅ Issue updated successfully');\n logger.debug(`Updated issue: ${JSON.stringify(editedIssue, null, 2)}`);\n\n return editedIssue;\n}\n\n// Helper function to format issue body for GitHub\nfunction formatIssueBody(issue: Issue): string {\n let body = `## Description\\n\\n${issue.description}\\n\\n`;\n\n body += `## Details\\n\\n`;\n body += `- **Priority:** ${issue.priority}\\n`;\n body += `- **Category:** ${issue.category}\\n`;\n body += `- **Source:** Review\\n\\n`;\n\n if (issue.suggestions && issue.suggestions.length > 0) {\n body += `## Suggestions\\n\\n`;\n issue.suggestions.forEach(suggestion => {\n body += `- ${suggestion}\\n`;\n });\n body += '\\n';\n }\n\n body += `---\\n\\n`;\n body += `*This issue was automatically created from a review session.*`;\n\n return body;\n}\n\n// Helper function to format results with created GitHub issues\nfunction formatReviewResultsWithIssues(\n result: ReviewResult,\n createdIssues: Array<{ issue: Issue, githubUrl: string, number: number }>\n): string {\n let output = `📝 Review Results\\n\\n`;\n output += `📋 Summary: ${result.summary}\\n`;\n output += `📊 Total Issues Found: ${result.totalIssues}\\n`;\n output += `🚀 GitHub Issues Created: ${createdIssues.length}\\n\\n`;\n\n if (result.issues && result.issues.length > 0) {\n output += `📝 Issues Identified:\\n\\n`;\n\n result.issues.forEach((issue, index) => {\n const priorityEmoji = issue.priority === 'high' ? '🔴' :\n issue.priority === 'medium' ? '🟡' : '🟢';\n const categoryEmoji = issue.category === 'ui' ? '🎨' :\n issue.category === 'content' ? '📝' :\n issue.category === 'functionality' ? '⚙️' :\n issue.category === 'accessibility' ? '♿' :\n issue.category === 'performance' ? '⚡' : '🔧';\n\n output += `${index + 1}. ${priorityEmoji} ${issue.title}\\n`;\n output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\\n`;\n output += ` 📖 Description: ${issue.description}\\n`;\n\n // Check if this issue was created as a GitHub issue\n const createdIssue = createdIssues.find(ci => ci.issue === issue);\n if (createdIssue) {\n output += ` 🔗 GitHub Issue: #${createdIssue.number} - ${createdIssue.githubUrl}\\n`;\n }\n\n if (issue.suggestions && issue.suggestions.length > 0) {\n output += ` 💡 Suggestions:\\n`;\n issue.suggestions.forEach(suggestion => {\n output += ` • ${suggestion}\\n`;\n });\n }\n output += `\\n`;\n });\n } else {\n output += `✅ No specific issues identified from the review.\\n\\n`;\n }\n\n if (createdIssues.length > 0) {\n output += `\\n🎯 Created GitHub Issues:\\n`;\n createdIssues.forEach(createdIssue => {\n output += `• #${createdIssue.number}: ${createdIssue.issue.title} - ${createdIssue.githubUrl}\\n`;\n });\n output += `\\n`;\n }\n\n output += `🚀 Next Steps: Review the created GitHub issues and prioritize them in your development workflow.`;\n\n return output;\n}\n\nfunction formatReviewResults(result: ReviewResult): string {\n let output = `📝 Review Results\\n\\n`;\n output += `📋 Summary: ${result.summary}\\n`;\n output += `📊 Total Issues Found: ${result.totalIssues}\\n\\n`;\n\n if (result.issues && result.issues.length > 0) {\n output += `📝 Issues Identified:\\n\\n`;\n\n result.issues.forEach((issue, index) => {\n const priorityEmoji = issue.priority === 'high' ? '🔴' :\n issue.priority === 'medium' ? '🟡' : '🟢';\n const categoryEmoji = issue.category === 'ui' ? '🎨' :\n issue.category === 'content' ? '📝' :\n issue.category === 'functionality' ? '⚙️' :\n issue.category === 'accessibility' ? '♿' :\n issue.category === 'performance' ? '⚡' : '🔧';\n\n output += `${index + 1}. ${priorityEmoji} ${issue.title}\\n`;\n output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\\n`;\n output += ` 📖 Description: ${issue.description}\\n`;\n\n if (issue.suggestions && issue.suggestions.length > 0) {\n output += ` 💡 Suggestions:\\n`;\n issue.suggestions.forEach(suggestion => {\n output += ` • ${suggestion}\\n`;\n });\n }\n output += `\\n`;\n });\n } else {\n output += `✅ No specific issues identified from the review.\\n\\n`;\n }\n\n output += `🚀 Next Steps: Review the identified issues and prioritize them for your development workflow.`;\n\n return output;\n}\n\n// Handle GitHub issue creation workflow\nexport const handleIssueCreation = async (\n result: ReviewResult,\n senditMode: boolean = false\n): Promise<string> => {\n const logger = getLogger();\n const createdIssues: Array<{ issue: Issue, githubUrl: string, number: number }> = [];\n\n if (!result.issues || result.issues.length === 0) {\n return formatReviewResults(result);\n }\n\n logger.info(`🔍 Found ${result.issues.length} issues to potentially create as GitHub issues`);\n\n for (let i = 0; i < result.issues.length; i++) {\n let issue = result.issues[i];\n let shouldCreateIssue = senditMode;\n\n if (!senditMode) {\n // Interactive confirmation for each issue - keep looping until user decides\n let userChoice = '';\n while (userChoice !== 'c' && userChoice !== 's') {\n // Display issue details\n logger.info(`\\n📋 Issue ${i + 1} of ${result.issues.length}:`);\n logger.info(` Title: ${issue.title}`);\n logger.info(` Priority: ${issue.priority} | Category: ${issue.category}`);\n logger.info(` Description: ${issue.description}`);\n if (issue.suggestions && issue.suggestions.length > 0) {\n logger.info(` Suggestions: ${issue.suggestions.join(', ')}`);\n }\n\n // Get user choice\n userChoice = await getUserChoice('\\nWhat would you like to do with this issue?', [\n { key: 'c', label: 'Create GitHub issue' },\n { key: 's', label: 'Skip this issue' },\n { key: 'e', label: 'Edit issue details' }\n ]);\n\n if (userChoice === 'c') {\n shouldCreateIssue = true;\n } else if (userChoice === 'e') {\n // Allow user to edit the issue\n issue = await editIssueInteractively(issue);\n result.issues[i] = issue; // Update the issue in the result\n // Continue the loop to show the updated issue and ask again\n }\n // If choice is 's', loop will exit and shouldCreateIssue remains false\n }\n }\n\n if (shouldCreateIssue) {\n try {\n logger.info(`🚀 Creating GitHub issue: \"${issue.title}\"`);\n\n // Format issue body with additional details\n const issueBody = formatIssueBody(issue);\n\n // Create labels based on priority and category\n const labels = [\n `priority-${issue.priority}`,\n `category-${issue.category}`,\n 'review'\n ];\n\n const createdIssue = await createIssue(issue.title, issueBody, labels);\n createdIssues.push({\n issue,\n githubUrl: createdIssue.html_url,\n number: createdIssue.number\n });\n\n logger.info(`✅ Created GitHub issue #${createdIssue.number}: ${createdIssue.html_url}`);\n } catch (error: any) {\n logger.error(`❌ Failed to create GitHub issue for \"${issue.title}\": ${error.message}`);\n }\n }\n }\n\n // Return formatted results\n if (createdIssues.length > 0) {\n return formatReviewResultsWithIssues(result, createdIssues);\n } else {\n return formatReviewResults(result);\n }\n};\n"],"names":["get","options","logger","getLogger","limit","debug","issuesLimit","Math","min","githubIssues","getOpenIssues","trim","length","error","warn","message","getUserChoice","_prompt","_choices","key","serializeIssue","issue","lines","title","priority","category","description","suggestions","forEach","suggestion","push","join","deserializeIssue","content","split","currentSection","descriptionLines","i","line","startsWith","substring","priorityValue","toLowerCase","categoryValue","includes","suggestionLine","replace","undefined","editIssueInteractively","editor","process","env","EDITOR","VISUAL","tmpDir","os","tmpdir","tmpFilePath","path","Date","now","issueContent","fs","writeFile","info","result","spawnSync","stdio","Error","editedContent","readFile","unlink","code","editedIssue","JSON","stringify","formatIssueBody","body","formatReviewResultsWithIssues","createdIssues","output","summary","totalIssues","issues","index","priorityEmoji","categoryEmoji","createdIssue","find","ci","number","githubUrl","formatReviewResults","handleIssueCreation","senditMode","shouldCreateIssue","userChoice","label","issueBody","labels","createIssue","html_url"],"mappings":"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"}
package/dist/logger.js ADDED
@@ -0,0 +1,15 @@
1
+ // Default console logger if winston isn't provided
2
+ /* eslint-disable no-console */ const defaultLogger = {
3
+ info: (message)=>console.log(message),
4
+ warn: (message)=>console.warn(message),
5
+ error: (message)=>console.error(message),
6
+ debug: (message)=>console.debug(message)
7
+ };
8
+ /* eslint-enable no-console */ let currentLogger = defaultLogger;
9
+ const setLogger = (logger)=>{
10
+ currentLogger = logger;
11
+ };
12
+ const getLogger = ()=>currentLogger;
13
+
14
+ export { getLogger, setLogger };
15
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sources":["../src/logger.ts"],"sourcesContent":["import type { Logger } from './types';\n\n// Default console logger if winston isn't provided\n/* eslint-disable no-console */\nconst defaultLogger: Logger = {\n info: (message: string) => console.log(message),\n warn: (message: string) => console.warn(message),\n error: (message: string) => console.error(message),\n debug: (message: string) => console.debug(message),\n};\n/* eslint-enable no-console */\n\nlet currentLogger: Logger = defaultLogger;\n\nexport const setLogger = (logger: Logger): void => {\n currentLogger = logger;\n};\n\nexport const getLogger = (): Logger => currentLogger;\n\n"],"names":["defaultLogger","info","message","console","log","warn","error","debug","currentLogger","setLogger","logger","getLogger"],"mappings":"AAEA;AACA,gCACA,MAAMA,aAAAA,GAAwB;AAC1BC,IAAAA,IAAAA,EAAM,CAACC,OAAAA,GAAoBC,OAAAA,CAAQC,GAAG,CAACF,OAAAA,CAAAA;AACvCG,IAAAA,IAAAA,EAAM,CAACH,OAAAA,GAAoBC,OAAAA,CAAQE,IAAI,CAACH,OAAAA,CAAAA;AACxCI,IAAAA,KAAAA,EAAO,CAACJ,OAAAA,GAAoBC,OAAAA,CAAQG,KAAK,CAACJ,OAAAA,CAAAA;AAC1CK,IAAAA,KAAAA,EAAO,CAACL,OAAAA,GAAoBC,OAAAA,CAAQI,KAAK,CAACL,OAAAA;AAC9C,CAAA;AACA,+BAEA,IAAIM,aAAAA,GAAwBR,aAAAA;AAErB,MAAMS,YAAY,CAACC,MAAAA,GAAAA;IACtBF,aAAAA,GAAgBE,MAAAA;AACpB;AAEO,MAAMC,SAAAA,GAAY,IAAcH;;;;"}
@@ -0,0 +1,90 @@
1
+ import { getLogger } from './logger.js';
2
+ import { getOctokit, getRepoDetails } from './github.js';
3
+
4
+ // Function to truncate overly large content while preserving structure
5
+ const truncateContent = (content, maxLength = 3000)=>{
6
+ if (content.length <= maxLength) {
7
+ return content;
8
+ }
9
+ const lines = content.split('\n');
10
+ const truncatedLines = [];
11
+ let currentLength = 0;
12
+ for (const line of lines){
13
+ if (currentLength + line.length + 1 > maxLength) {
14
+ break;
15
+ }
16
+ truncatedLines.push(line);
17
+ currentLength += line.length + 1; // +1 for newline
18
+ }
19
+ truncatedLines.push('');
20
+ truncatedLines.push(`... [TRUNCATED: Original content was ${content.length} characters, showing first ${currentLength}] ...`);
21
+ return truncatedLines.join('\n');
22
+ };
23
+ // Function to fetch recent releases from GitHub API
24
+ const findRecentReleaseNotes = async (limit)=>{
25
+ const logger = getLogger();
26
+ const releaseNotes = [];
27
+ if (limit <= 0) {
28
+ return releaseNotes;
29
+ }
30
+ try {
31
+ const octokit = getOctokit();
32
+ const { owner, repo } = await getRepoDetails();
33
+ logger.debug(`Fetching up to ${limit} recent releases from GitHub...`);
34
+ const response = await octokit.repos.listReleases({
35
+ owner,
36
+ repo,
37
+ per_page: Math.min(limit, 100)
38
+ });
39
+ const releases = response.data;
40
+ if (releases.length === 0) {
41
+ logger.debug('No releases found in GitHub repository');
42
+ return releaseNotes;
43
+ }
44
+ for (const release of releases.slice(0, limit)){
45
+ const releaseContent = [
46
+ `# ${release.name || release.tag_name}`,
47
+ `**Tag:** ${release.tag_name}`,
48
+ `**Published:** ${release.published_at}`,
49
+ release.prerelease ? '**Type:** Pre-release' : '**Type:** Release',
50
+ release.draft ? '**Status:** Draft' : '**Status:** Published',
51
+ '',
52
+ release.body || 'No release notes provided'
53
+ ].join('\n');
54
+ const truncatedContent = truncateContent(releaseContent);
55
+ releaseNotes.push(`=== GitHub Release: ${release.tag_name} ===\n${truncatedContent}`);
56
+ if (truncatedContent.length < releaseContent.length) {
57
+ logger.debug(`Found release ${release.tag_name} (${truncatedContent.length} characters, truncated from ${releaseContent.length})`);
58
+ } else {
59
+ logger.debug(`Found release ${release.tag_name} (${releaseContent.length} characters)`);
60
+ }
61
+ }
62
+ logger.debug(`Fetched ${releaseNotes.length} releases from GitHub`);
63
+ } catch (error) {
64
+ logger.warn(`Error fetching releases from GitHub API: ${error.message}`);
65
+ // If we have a GitHub API error, we could fall back to checking for local release notes
66
+ // This maintains some backward compatibility
67
+ logger.debug('Falling back to local RELEASE_NOTES.md file...');
68
+ try {
69
+ const fs = await import('fs/promises');
70
+ const content = await fs.readFile('RELEASE_NOTES.md', 'utf-8');
71
+ if (content.trim()) {
72
+ const truncatedContent = truncateContent(content);
73
+ releaseNotes.push(`=== Local RELEASE_NOTES.md ===\n${truncatedContent}`);
74
+ logger.debug(`Found local release notes (${content.length} characters)`);
75
+ }
76
+ } catch {
77
+ // No local file either, return empty array
78
+ logger.debug('No local RELEASE_NOTES.md file found either');
79
+ }
80
+ }
81
+ return releaseNotes.slice(0, limit);
82
+ };
83
+ const get = async (options = {})=>{
84
+ const { limit = 3 } = options;
85
+ const releaseNotes = await findRecentReleaseNotes(limit);
86
+ return releaseNotes.join('\n\n');
87
+ };
88
+
89
+ export { findRecentReleaseNotes, get };
90
+ //# sourceMappingURL=releaseNotes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"releaseNotes.js","sources":["../src/releaseNotes.ts"],"sourcesContent":["import { getLogger } from './logger';\nimport { getOctokit, getRepoDetails } from './github';\n\n// Function to truncate overly large content while preserving structure\nconst truncateContent = (content: string, maxLength: number = 3000): string => {\n if (content.length <= maxLength) {\n return content;\n }\n\n const lines = content.split('\\n');\n const truncatedLines: string[] = [];\n let currentLength = 0;\n\n for (const line of lines) {\n if (currentLength + line.length + 1 > maxLength) {\n break;\n }\n truncatedLines.push(line);\n currentLength += line.length + 1; // +1 for newline\n }\n\n truncatedLines.push('');\n truncatedLines.push(`... [TRUNCATED: Original content was ${content.length} characters, showing first ${currentLength}] ...`);\n\n return truncatedLines.join('\\n');\n};\n\n// Function to fetch recent releases from GitHub API\nexport const findRecentReleaseNotes = async (limit: number): Promise<string[]> => {\n const logger = getLogger();\n const releaseNotes: string[] = [];\n\n if (limit <= 0) {\n return releaseNotes;\n }\n\n try {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n\n logger.debug(`Fetching up to ${limit} recent releases from GitHub...`);\n\n const response = await octokit.repos.listReleases({\n owner,\n repo,\n per_page: Math.min(limit, 100), // GitHub API limit\n });\n\n const releases = response.data;\n\n if (releases.length === 0) {\n logger.debug('No releases found in GitHub repository');\n return releaseNotes;\n }\n\n for (const release of releases.slice(0, limit)) {\n const releaseContent = [\n `# ${release.name || release.tag_name}`,\n `**Tag:** ${release.tag_name}`,\n `**Published:** ${release.published_at}`,\n release.prerelease ? '**Type:** Pre-release' : '**Type:** Release',\n release.draft ? '**Status:** Draft' : '**Status:** Published',\n '',\n release.body || 'No release notes provided'\n ].join('\\n');\n\n const truncatedContent = truncateContent(releaseContent);\n releaseNotes.push(`=== GitHub Release: ${release.tag_name} ===\\n${truncatedContent}`);\n\n if (truncatedContent.length < releaseContent.length) {\n logger.debug(`Found release ${release.tag_name} (${truncatedContent.length} characters, truncated from ${releaseContent.length})`);\n } else {\n logger.debug(`Found release ${release.tag_name} (${releaseContent.length} characters)`);\n }\n }\n\n logger.debug(`Fetched ${releaseNotes.length} releases from GitHub`);\n\n } catch (error: any) {\n logger.warn(`Error fetching releases from GitHub API: ${error.message}`);\n\n // If we have a GitHub API error, we could fall back to checking for local release notes\n // This maintains some backward compatibility\n logger.debug('Falling back to local RELEASE_NOTES.md file...');\n try {\n const fs = await import('fs/promises');\n const content = await fs.readFile('RELEASE_NOTES.md', 'utf-8');\n if (content.trim()) {\n const truncatedContent = truncateContent(content);\n releaseNotes.push(`=== Local RELEASE_NOTES.md ===\\n${truncatedContent}`);\n logger.debug(`Found local release notes (${content.length} characters)`);\n }\n } catch {\n // No local file either, return empty array\n logger.debug('No local RELEASE_NOTES.md file found either');\n }\n }\n\n return releaseNotes.slice(0, limit);\n};\n\nexport const get = async (options: { limit?: number } = {}): Promise<string> => {\n const { limit = 3 } = options;\n const releaseNotes = await findRecentReleaseNotes(limit);\n return releaseNotes.join('\\n\\n');\n};\n"],"names":["truncateContent","content","maxLength","length","lines","split","truncatedLines","currentLength","line","push","join","findRecentReleaseNotes","limit","logger","getLogger","releaseNotes","octokit","getOctokit","owner","repo","getRepoDetails","debug","response","repos","listReleases","per_page","Math","min","releases","data","release","slice","releaseContent","name","tag_name","published_at","prerelease","draft","body","truncatedContent","error","warn","message","fs","readFile","trim","get","options"],"mappings":"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"}
package/guide/index.md ADDED
@@ -0,0 +1,78 @@
1
+ # @grunnverk/github-tools - Agentic Guide
2
+
3
+ ## Purpose
4
+
5
+ GitHub API utilities for automation. Provides PR management, issue tracking, workflow monitoring, and release note generation.
6
+
7
+ ## Key Features
8
+
9
+ - **Pull Request Management** - Create, update, and merge PRs
10
+ - **Issue Tracking** - Create and manage GitHub issues
11
+ - **Release Notes** - Generate and publish release notes
12
+ - **Workflow Monitoring** - Check CI/CD status
13
+ - **Authentication** - GitHub token management
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import {
19
+ createPullRequest,
20
+ createIssue,
21
+ publishReleaseNotes,
22
+ getPRStatus
23
+ } from '@grunnverk/github-tools';
24
+
25
+ // Create pull request
26
+ const pr = await createPullRequest({
27
+ owner: 'myorg',
28
+ repo: 'myrepo',
29
+ title: 'Feature: Add new command',
30
+ body: 'Description...',
31
+ head: 'feature-branch',
32
+ base: 'main'
33
+ });
34
+
35
+ // Create issue
36
+ const issue = await createIssue({
37
+ owner: 'myorg',
38
+ repo: 'myrepo',
39
+ title: 'Bug: Fix validation',
40
+ body: 'Details...'
41
+ });
42
+
43
+ // Publish release notes
44
+ await publishReleaseNotes({
45
+ owner: 'myorg',
46
+ repo: 'myrepo',
47
+ tag: 'v1.0.0',
48
+ notes: 'Release notes...'
49
+ });
50
+ ```
51
+
52
+ ## Dependencies
53
+
54
+ - @grunnverk/git-tools - Git operations
55
+ - @octokit/rest - GitHub API client
56
+
57
+ ## Package Structure
58
+
59
+ ```
60
+ src/
61
+ ├── github.ts # GitHub API client
62
+ ├── issues.ts # Issue management
63
+ ├── releaseNotes.ts # Release note publishing
64
+ ├── errors.ts # Error types
65
+ ├── types.ts # Type definitions
66
+ ├── logger.ts # Logging utilities
67
+ └── index.ts
68
+ ```
69
+
70
+ ## Key Exports
71
+
72
+ - `createPullRequest()` - Create GitHub PR
73
+ - `mergePullRequest()` - Merge PR
74
+ - `createIssue()` - Create issue
75
+ - `publishReleaseNotes()` - Publish release notes
76
+ - `getPRStatus()` - Check PR CI status
77
+ - `getLatestRelease()` - Get latest release info
78
+