@eldrforge/kodrdriv 1.2.19 → 1.2.21

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.
Files changed (56) hide show
  1. package/GITHUB-TOOLS-INTEGRATION.md +323 -0
  2. package/INTEGRATION-SUMMARY.md +232 -0
  3. package/TEST-STATUS.md +168 -0
  4. package/dist/application.js +7 -0
  5. package/dist/application.js.map +1 -1
  6. package/dist/arguments.js +1 -1
  7. package/dist/arguments.js.map +1 -1
  8. package/dist/commands/commit.js +3 -3
  9. package/dist/commands/commit.js.map +1 -1
  10. package/dist/commands/development.js +1 -2
  11. package/dist/commands/development.js.map +1 -1
  12. package/dist/commands/link.js +1 -2
  13. package/dist/commands/link.js.map +1 -1
  14. package/dist/commands/publish.js +15 -17
  15. package/dist/commands/publish.js.map +1 -1
  16. package/dist/commands/release.js +4 -4
  17. package/dist/commands/release.js.map +1 -1
  18. package/dist/commands/review.js +3 -4
  19. package/dist/commands/review.js.map +1 -1
  20. package/dist/commands/tree.js +38 -10
  21. package/dist/commands/tree.js.map +1 -1
  22. package/dist/commands/unlink.js +1 -2
  23. package/dist/commands/unlink.js.map +1 -1
  24. package/dist/commands/updates.js +1 -1
  25. package/dist/commands/updates.js.map +1 -1
  26. package/dist/commands/versions.js +1 -1
  27. package/dist/commands/versions.js.map +1 -1
  28. package/dist/constants.js +1 -1
  29. package/dist/content/diff.js +1 -1
  30. package/dist/content/diff.js.map +1 -1
  31. package/dist/content/log.js +1 -1
  32. package/dist/content/log.js.map +1 -1
  33. package/dist/error/CommandErrors.js +1 -65
  34. package/dist/error/CommandErrors.js.map +1 -1
  35. package/dist/util/general.js +2 -3
  36. package/dist/util/general.js.map +1 -1
  37. package/dist/util/openai.js +1 -1
  38. package/dist/util/openai.js.map +1 -1
  39. package/dist/util/performance.js +1 -1
  40. package/dist/util/performance.js.map +1 -1
  41. package/dist/util/safety.js +1 -1
  42. package/dist/util/safety.js.map +1 -1
  43. package/dist/util/validation.js +4 -39
  44. package/dist/util/validation.js.map +1 -1
  45. package/package.json +4 -2
  46. package/test_output.txt +3 -3
  47. package/dist/content/issues.js +0 -331
  48. package/dist/content/issues.js.map +0 -1
  49. package/dist/content/releaseNotes.js +0 -90
  50. package/dist/content/releaseNotes.js.map +0 -1
  51. package/dist/util/child.js +0 -174
  52. package/dist/util/child.js.map +0 -1
  53. package/dist/util/git.js +0 -836
  54. package/dist/util/git.js.map +0 -1
  55. package/dist/util/github.js +0 -1071
  56. package/dist/util/github.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"safety.js","sources":["../../src/util/safety.ts"],"sourcesContent":["import path from 'path';\nimport { getLogger } from '../logging';\nimport { safeJsonParse, validatePackageJson } from './validation';\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\ninterface PackageJsonLocation {\n path: string;\n packageJson: PackageJson;\n relativePath: string;\n}\n\ninterface FileDependencyIssue {\n packagePath: string;\n dependencies: Array<{\n name: string;\n version: string;\n dependencyType: 'dependencies' | 'devDependencies' | 'peerDependencies';\n }>;\n}\n\nconst EXCLUDED_DIRECTORIES = [\n 'node_modules',\n 'dist',\n 'build',\n 'coverage',\n '.git',\n '.next',\n '.nuxt',\n 'out',\n 'public',\n 'static',\n 'assets'\n];\n\nconst findAllPackageJsonFiles = async (rootDir: string, storage: any): Promise<PackageJsonLocation[]> => {\n const logger = getLogger();\n const packageJsonFiles: PackageJsonLocation[] = [];\n\n const scanDirectory = async (currentDir: string, depth: number = 0): Promise<void> => {\n // Prevent infinite recursion and overly deep scanning\n if (depth > 5) {\n return;\n }\n\n try {\n if (!await storage.exists(currentDir) || !await storage.isDirectory(currentDir)) {\n return;\n }\n\n const items = await storage.listFiles(currentDir);\n\n // Check for package.json in current directory\n if (items.includes('package.json')) {\n const packageJsonPath = path.join(currentDir, 'package.json');\n try {\n const packageJsonContent = await storage.readFile(packageJsonPath, 'utf-8');\n const parsed = safeJsonParse(packageJsonContent, packageJsonPath);\n const packageJson = validatePackageJson(parsed, packageJsonPath);\n const relativePath = path.relative(rootDir, currentDir);\n\n packageJsonFiles.push({\n path: packageJsonPath,\n packageJson,\n relativePath: relativePath || '.'\n });\n\n logger.debug(`Found package.json at: ${relativePath || '.'}`);\n } catch (error: any) {\n logger.debug(`Skipped invalid package.json at ${packageJsonPath}: ${error.message}`);\n }\n }\n\n // Scan subdirectories, excluding build/generated directories\n for (const item of items) {\n if (EXCLUDED_DIRECTORIES.includes(item)) {\n continue;\n }\n\n const itemPath = path.join(currentDir, item);\n try {\n if (await storage.isDirectory(itemPath)) {\n await scanDirectory(itemPath, depth + 1);\n }\n } catch (error: any) {\n // Skip directories that can't be accessed\n logger.debug(`Skipped directory ${itemPath}: ${error.message}`);\n continue;\n }\n }\n } catch (error: any) {\n logger.debug(`Failed to scan directory ${currentDir}: ${error.message}`);\n }\n };\n\n await scanDirectory(rootDir);\n\n logger.debug(`Found ${packageJsonFiles.length} package.json file(s) in directory tree`);\n return packageJsonFiles;\n};\n\n/**\n * Checks for file: dependencies in package.json files that should not be committed\n * @param storage Storage utility instance\n * @param rootDir Root directory to scan (defaults to current working directory)\n * @returns Array of issues found, empty array if no issues\n */\nexport const checkForFileDependencies = async (storage: any, rootDir: string = process.cwd()): Promise<FileDependencyIssue[]> => {\n const logger = getLogger();\n const issues: FileDependencyIssue[] = [];\n\n try {\n const packageJsonFiles = await findAllPackageJsonFiles(rootDir, storage);\n\n for (const { packageJson, relativePath } of packageJsonFiles) {\n const fileDeps: Array<{name: string, version: string, dependencyType: 'dependencies' | 'devDependencies' | 'peerDependencies'}> = [];\n\n // Check all dependency types for file: paths\n const dependencyChecks = [\n { deps: packageJson.dependencies, type: 'dependencies' as const },\n { deps: packageJson.devDependencies, type: 'devDependencies' as const },\n { deps: packageJson.peerDependencies, type: 'peerDependencies' as const }\n ];\n\n for (const { deps, type } of dependencyChecks) {\n if (deps) {\n for (const [name, version] of Object.entries(deps)) {\n if (version.startsWith('file:')) {\n fileDeps.push({ name, version, dependencyType: type });\n }\n }\n }\n }\n\n if (fileDeps.length > 0) {\n issues.push({\n packagePath: relativePath,\n dependencies: fileDeps\n });\n }\n }\n } catch (error: any) {\n logger.debug(`Failed to check for file dependencies: ${error.message}`);\n }\n\n return issues;\n};\n\n/**\n * Logs file dependency issues in a user-friendly format\n * @param issues Array of file dependency issues\n * @param context Context for the warning (e.g., 'commit', 'link check')\n */\nexport const logFileDependencyWarning = (issues: FileDependencyIssue[], context: string = 'operation'): void => {\n const logger = getLogger();\n\n if (issues.length === 0) {\n return;\n }\n\n logger.warn(`⚠️ WARNING: Found file: dependencies that should not be committed during ${context}:`);\n for (const issue of issues) {\n logger.warn(` 📄 ${issue.packagePath}:`);\n for (const dep of issue.dependencies) {\n logger.warn(` - ${dep.name}: ${dep.version} (${dep.dependencyType})`);\n }\n }\n logger.warn('');\n};\n\n/**\n * Provides suggestions for resolving file dependency issues\n * @param hasUnlinkCapability Whether the current context supports unlinking\n */\nexport const logFileDependencySuggestions = (hasUnlinkCapability: boolean = true): void => {\n const logger = getLogger();\n\n logger.warn('💡 To resolve this:');\n if (hasUnlinkCapability) {\n logger.warn(' 1. Run \"kodrdriv unlink\" to restore registry versions');\n logger.warn(' 2. Complete your commit');\n logger.warn(' 3. Run \"kodrdriv link\" again for local development');\n } else {\n logger.warn(' 1. Manually restore registry versions in package.json files');\n logger.warn(' 2. Complete your commit');\n logger.warn(' 3. Re-link your local dependencies');\n }\n logger.warn('');\n logger.warn(' Or to bypass this check:');\n logger.warn(' - Add --skip-file-check flag to your command');\n logger.warn(' - Or use git commit --no-verify to skip all hooks');\n logger.warn('');\n};\n"],"names":["EXCLUDED_DIRECTORIES","findAllPackageJsonFiles","rootDir","storage","logger","getLogger","packageJsonFiles","scanDirectory","currentDir","depth","exists","isDirectory","items","listFiles","includes","packageJsonPath","path","join","packageJsonContent","readFile","parsed","safeJsonParse","packageJson","validatePackageJson","relativePath","relative","push","debug","error","message","item","itemPath","length","checkForFileDependencies","process","cwd","issues","fileDeps","dependencyChecks","deps","dependencies","type","devDependencies","peerDependencies","name","version","Object","entries","startsWith","dependencyType","packagePath","logFileDependencyWarning","context","warn","issue","dep","logFileDependencySuggestions","hasUnlinkCapability"],"mappings":"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"}
1
+ {"version":3,"file":"safety.js","sources":["../../src/util/safety.ts"],"sourcesContent":["import path from 'path';\nimport { getLogger } from '../logging';\nimport { safeJsonParse, validatePackageJson } from '@eldrforge/git-tools';\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\ninterface PackageJsonLocation {\n path: string;\n packageJson: PackageJson;\n relativePath: string;\n}\n\ninterface FileDependencyIssue {\n packagePath: string;\n dependencies: Array<{\n name: string;\n version: string;\n dependencyType: 'dependencies' | 'devDependencies' | 'peerDependencies';\n }>;\n}\n\nconst EXCLUDED_DIRECTORIES = [\n 'node_modules',\n 'dist',\n 'build',\n 'coverage',\n '.git',\n '.next',\n '.nuxt',\n 'out',\n 'public',\n 'static',\n 'assets'\n];\n\nconst findAllPackageJsonFiles = async (rootDir: string, storage: any): Promise<PackageJsonLocation[]> => {\n const logger = getLogger();\n const packageJsonFiles: PackageJsonLocation[] = [];\n\n const scanDirectory = async (currentDir: string, depth: number = 0): Promise<void> => {\n // Prevent infinite recursion and overly deep scanning\n if (depth > 5) {\n return;\n }\n\n try {\n if (!await storage.exists(currentDir) || !await storage.isDirectory(currentDir)) {\n return;\n }\n\n const items = await storage.listFiles(currentDir);\n\n // Check for package.json in current directory\n if (items.includes('package.json')) {\n const packageJsonPath = path.join(currentDir, 'package.json');\n try {\n const packageJsonContent = await storage.readFile(packageJsonPath, 'utf-8');\n const parsed = safeJsonParse(packageJsonContent, packageJsonPath);\n const packageJson = validatePackageJson(parsed, packageJsonPath);\n const relativePath = path.relative(rootDir, currentDir);\n\n packageJsonFiles.push({\n path: packageJsonPath,\n packageJson,\n relativePath: relativePath || '.'\n });\n\n logger.debug(`Found package.json at: ${relativePath || '.'}`);\n } catch (error: any) {\n logger.debug(`Skipped invalid package.json at ${packageJsonPath}: ${error.message}`);\n }\n }\n\n // Scan subdirectories, excluding build/generated directories\n for (const item of items) {\n if (EXCLUDED_DIRECTORIES.includes(item)) {\n continue;\n }\n\n const itemPath = path.join(currentDir, item);\n try {\n if (await storage.isDirectory(itemPath)) {\n await scanDirectory(itemPath, depth + 1);\n }\n } catch (error: any) {\n // Skip directories that can't be accessed\n logger.debug(`Skipped directory ${itemPath}: ${error.message}`);\n continue;\n }\n }\n } catch (error: any) {\n logger.debug(`Failed to scan directory ${currentDir}: ${error.message}`);\n }\n };\n\n await scanDirectory(rootDir);\n\n logger.debug(`Found ${packageJsonFiles.length} package.json file(s) in directory tree`);\n return packageJsonFiles;\n};\n\n/**\n * Checks for file: dependencies in package.json files that should not be committed\n * @param storage Storage utility instance\n * @param rootDir Root directory to scan (defaults to current working directory)\n * @returns Array of issues found, empty array if no issues\n */\nexport const checkForFileDependencies = async (storage: any, rootDir: string = process.cwd()): Promise<FileDependencyIssue[]> => {\n const logger = getLogger();\n const issues: FileDependencyIssue[] = [];\n\n try {\n const packageJsonFiles = await findAllPackageJsonFiles(rootDir, storage);\n\n for (const { packageJson, relativePath } of packageJsonFiles) {\n const fileDeps: Array<{name: string, version: string, dependencyType: 'dependencies' | 'devDependencies' | 'peerDependencies'}> = [];\n\n // Check all dependency types for file: paths\n const dependencyChecks = [\n { deps: packageJson.dependencies, type: 'dependencies' as const },\n { deps: packageJson.devDependencies, type: 'devDependencies' as const },\n { deps: packageJson.peerDependencies, type: 'peerDependencies' as const }\n ];\n\n for (const { deps, type } of dependencyChecks) {\n if (deps) {\n for (const [name, version] of Object.entries(deps)) {\n if (version.startsWith('file:')) {\n fileDeps.push({ name, version, dependencyType: type });\n }\n }\n }\n }\n\n if (fileDeps.length > 0) {\n issues.push({\n packagePath: relativePath,\n dependencies: fileDeps\n });\n }\n }\n } catch (error: any) {\n logger.debug(`Failed to check for file dependencies: ${error.message}`);\n }\n\n return issues;\n};\n\n/**\n * Logs file dependency issues in a user-friendly format\n * @param issues Array of file dependency issues\n * @param context Context for the warning (e.g., 'commit', 'link check')\n */\nexport const logFileDependencyWarning = (issues: FileDependencyIssue[], context: string = 'operation'): void => {\n const logger = getLogger();\n\n if (issues.length === 0) {\n return;\n }\n\n logger.warn(`⚠️ WARNING: Found file: dependencies that should not be committed during ${context}:`);\n for (const issue of issues) {\n logger.warn(` 📄 ${issue.packagePath}:`);\n for (const dep of issue.dependencies) {\n logger.warn(` - ${dep.name}: ${dep.version} (${dep.dependencyType})`);\n }\n }\n logger.warn('');\n};\n\n/**\n * Provides suggestions for resolving file dependency issues\n * @param hasUnlinkCapability Whether the current context supports unlinking\n */\nexport const logFileDependencySuggestions = (hasUnlinkCapability: boolean = true): void => {\n const logger = getLogger();\n\n logger.warn('💡 To resolve this:');\n if (hasUnlinkCapability) {\n logger.warn(' 1. Run \"kodrdriv unlink\" to restore registry versions');\n logger.warn(' 2. Complete your commit');\n logger.warn(' 3. Run \"kodrdriv link\" again for local development');\n } else {\n logger.warn(' 1. Manually restore registry versions in package.json files');\n logger.warn(' 2. Complete your commit');\n logger.warn(' 3. Re-link your local dependencies');\n }\n logger.warn('');\n logger.warn(' Or to bypass this check:');\n logger.warn(' - Add --skip-file-check flag to your command');\n logger.warn(' - Or use git commit --no-verify to skip all hooks');\n logger.warn('');\n};\n"],"names":["EXCLUDED_DIRECTORIES","findAllPackageJsonFiles","rootDir","storage","logger","getLogger","packageJsonFiles","scanDirectory","currentDir","depth","exists","isDirectory","items","listFiles","includes","packageJsonPath","path","join","packageJsonContent","readFile","parsed","safeJsonParse","packageJson","validatePackageJson","relativePath","relative","push","debug","error","message","item","itemPath","length","checkForFileDependencies","process","cwd","issues","fileDeps","dependencyChecks","deps","dependencies","type","devDependencies","peerDependencies","name","version","Object","entries","startsWith","dependencyType","packagePath","logFileDependencyWarning","context","warn","issue","dep","logFileDependencySuggestions","hasUnlinkCapability"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Runtime validation utilities for safe type handling
3
+ *
4
+ * Note: Generic validation functions (safeJsonParse, validateString, etc.)
5
+ * have been moved to @eldrforge/git-tools
3
6
  */ /**
4
7
  * Validates and safely casts data to ReleaseSummary type
5
8
  */ const validateReleaseSummary = (data)=>{
@@ -14,31 +17,6 @@
14
17
  }
15
18
  return data;
16
19
  };
17
- /**
18
- * Safely parses JSON with error handling
19
- */ const safeJsonParse = (jsonString, context)=>{
20
- try {
21
- const parsed = JSON.parse(jsonString);
22
- if (parsed === null || parsed === undefined) {
23
- throw new Error('Parsed JSON is null or undefined');
24
- }
25
- return parsed;
26
- } catch (error) {
27
- const contextStr = context ? ` (${context})` : '';
28
- throw new Error(`Failed to parse JSON${contextStr}: ${error instanceof Error ? error.message : 'Unknown error'}`);
29
- }
30
- };
31
- /**
32
- * Validates that a value is a non-empty string
33
- */ const validateString = (value, fieldName)=>{
34
- if (typeof value !== 'string') {
35
- throw new Error(`${fieldName} must be a string, got ${typeof value}`);
36
- }
37
- if (value.trim() === '') {
38
- throw new Error(`${fieldName} cannot be empty`);
39
- }
40
- return value;
41
- };
42
20
  /**
43
21
  * Sanitizes and truncates direction parameter for safe use in prompts
44
22
  * @param direction The direction string to sanitize
@@ -62,19 +40,6 @@
62
40
  }
63
41
  return sanitized;
64
42
  };
65
- /**
66
- * Validates package.json structure has basic required fields
67
- */ const validatePackageJson = (data, context, requireName = true)=>{
68
- if (!data || typeof data !== 'object') {
69
- const contextStr = context ? ` (${context})` : '';
70
- throw new Error(`Invalid package.json${contextStr}: not an object`);
71
- }
72
- if (requireName && typeof data.name !== 'string') {
73
- const contextStr = context ? ` (${context})` : '';
74
- throw new Error(`Invalid package.json${contextStr}: name must be a string`);
75
- }
76
- return data;
77
- };
78
43
 
79
- export { safeJsonParse, sanitizeDirection, validatePackageJson, validateReleaseSummary, validateString };
44
+ export { sanitizeDirection, validateReleaseSummary };
80
45
  //# sourceMappingURL=validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sources":["../../src/util/validation.ts"],"sourcesContent":["/**\n * Runtime validation utilities for safe type handling\n */\n\nexport interface ReleaseSummary {\n title: string;\n body: string;\n}\n\n\n\nexport interface TranscriptionResult {\n text: string;\n [key: string]: any;\n}\n\n/**\n * Validates and safely casts data to ReleaseSummary type\n */\nexport const validateReleaseSummary = (data: any): ReleaseSummary => {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid release summary: not an object');\n }\n if (typeof data.title !== 'string') {\n throw new Error('Invalid release summary: title must be a string');\n }\n if (typeof data.body !== 'string') {\n throw new Error('Invalid release summary: body must be a string');\n }\n return data as ReleaseSummary;\n};\n\n\n\n/**\n * Validates transcription result has required text property\n */\nexport const validateTranscriptionResult = (data: any): TranscriptionResult => {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid transcription result: not an object');\n }\n if (typeof data.text !== 'string') {\n throw new Error('Invalid transcription result: text property must be a string');\n }\n return data as TranscriptionResult;\n};\n\n/**\n * Safely parses JSON with error handling\n */\nexport const safeJsonParse = <T = any>(jsonString: string, context?: string): T => {\n try {\n const parsed = JSON.parse(jsonString);\n if (parsed === null || parsed === undefined) {\n throw new Error('Parsed JSON is null or undefined');\n }\n return parsed;\n } catch (error) {\n const contextStr = context ? ` (${context})` : '';\n throw new Error(`Failed to parse JSON${contextStr}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n};\n\n/**\n * Validates that a value is a non-empty string\n */\nexport const validateString = (value: any, fieldName: string): string => {\n if (typeof value !== 'string') {\n throw new Error(`${fieldName} must be a string, got ${typeof value}`);\n }\n if (value.trim() === '') {\n throw new Error(`${fieldName} cannot be empty`);\n }\n return value;\n};\n\n/**\n * Sanitizes and truncates direction parameter for safe use in prompts\n * @param direction The direction string to sanitize\n * @param maxLength Maximum length before truncation (default: 2000)\n * @returns Sanitized and truncated direction string\n */\nexport const sanitizeDirection = (direction: string | undefined, maxLength: number = 2000): string | undefined => {\n if (!direction) {\n return undefined;\n }\n\n // Remove newlines and excessive whitespace to prevent template breakage\n const sanitized = direction\n .replace(/\\r?\\n/g, ' ') // Replace newlines with spaces\n .replace(/\\s+/g, ' ') // Replace multiple whitespace with single space\n .trim();\n\n // Truncate if too long\n if (sanitized.length > maxLength) {\n const truncated = sanitized.substring(0, maxLength - 3) + '...';\n // Log truncation for debugging\n // eslint-disable-next-line no-console\n console.warn(`Direction truncated from ${sanitized.length} to ${truncated.length} characters`);\n return truncated;\n }\n\n return sanitized;\n};\n\n/**\n * Validates that a value exists and has a specific property\n */\nexport const validateHasProperty = (obj: any, property: string, context?: string): void => {\n if (!obj || typeof obj !== 'object') {\n const contextStr = context ? ` in ${context}` : '';\n throw new Error(`Object is null or not an object${contextStr}`);\n }\n if (!(property in obj)) {\n const contextStr = context ? ` in ${context}` : '';\n throw new Error(`Missing required property '${property}'${contextStr}`);\n }\n};\n\n/**\n * Validates package.json structure has basic required fields\n */\nexport const validatePackageJson = (data: any, context?: string, requireName: boolean = true): any => {\n if (!data || typeof data !== 'object') {\n const contextStr = context ? ` (${context})` : '';\n throw new Error(`Invalid package.json${contextStr}: not an object`);\n }\n if (requireName && typeof data.name !== 'string') {\n const contextStr = context ? ` (${context})` : '';\n throw new Error(`Invalid package.json${contextStr}: name must be a string`);\n }\n return data;\n};\n"],"names":["validateReleaseSummary","data","Error","title","body","safeJsonParse","jsonString","context","parsed","JSON","parse","undefined","error","contextStr","message","validateString","value","fieldName","trim","sanitizeDirection","direction","maxLength","sanitized","replace","length","truncated","substring","console","warn","validatePackageJson","requireName","name"],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","sources":["../../src/util/validation.ts"],"sourcesContent":["/**\n * Runtime validation utilities for safe type handling\n *\n * Note: Generic validation functions (safeJsonParse, validateString, etc.)\n * have been moved to @eldrforge/git-tools\n */\n\nexport interface ReleaseSummary {\n title: string;\n body: string;\n}\n\nexport interface TranscriptionResult {\n text: string;\n [key: string]: any;\n}\n\n/**\n * Validates and safely casts data to ReleaseSummary type\n */\nexport const validateReleaseSummary = (data: any): ReleaseSummary => {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid release summary: not an object');\n }\n if (typeof data.title !== 'string') {\n throw new Error('Invalid release summary: title must be a string');\n }\n if (typeof data.body !== 'string') {\n throw new Error('Invalid release summary: body must be a string');\n }\n return data as ReleaseSummary;\n};\n\n/**\n * Validates transcription result has required text property\n */\nexport const validateTranscriptionResult = (data: any): TranscriptionResult => {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid transcription result: not an object');\n }\n if (typeof data.text !== 'string') {\n throw new Error('Invalid transcription result: text property must be a string');\n }\n return data as TranscriptionResult;\n};\n\n/**\n * Sanitizes and truncates direction parameter for safe use in prompts\n * @param direction The direction string to sanitize\n * @param maxLength Maximum length before truncation (default: 2000)\n * @returns Sanitized and truncated direction string\n */\nexport const sanitizeDirection = (direction: string | undefined, maxLength: number = 2000): string | undefined => {\n if (!direction) {\n return undefined;\n }\n\n // Remove newlines and excessive whitespace to prevent template breakage\n const sanitized = direction\n .replace(/\\r?\\n/g, ' ') // Replace newlines with spaces\n .replace(/\\s+/g, ' ') // Replace multiple whitespace with single space\n .trim();\n\n // Truncate if too long\n if (sanitized.length > maxLength) {\n const truncated = sanitized.substring(0, maxLength - 3) + '...';\n // Log truncation for debugging\n // eslint-disable-next-line no-console\n console.warn(`Direction truncated from ${sanitized.length} to ${truncated.length} characters`);\n return truncated;\n }\n\n return sanitized;\n};\n"],"names":["validateReleaseSummary","data","Error","title","body","sanitizeDirection","direction","maxLength","undefined","sanitized","replace","trim","length","truncated","substring","console","warn"],"mappings":"AAAA;;;;;;;IAoBO,MAAMA,sBAAAA,GAAyB,CAACC,IAAAA,GAAAA;AACnC,IAAA,IAAI,CAACA,IAAAA,IAAQ,OAAOA,IAAAA,KAAS,QAAA,EAAU;AACnC,QAAA,MAAM,IAAIC,KAAAA,CAAM,wCAAA,CAAA;AACpB,IAAA;AACA,IAAA,IAAI,OAAOD,IAAAA,CAAKE,KAAK,KAAK,QAAA,EAAU;AAChC,QAAA,MAAM,IAAID,KAAAA,CAAM,iDAAA,CAAA;AACpB,IAAA;AACA,IAAA,IAAI,OAAOD,IAAAA,CAAKG,IAAI,KAAK,QAAA,EAAU;AAC/B,QAAA,MAAM,IAAIF,KAAAA,CAAM,gDAAA,CAAA;AACpB,IAAA;IACA,OAAOD,IAAAA;AACX;AAeA;;;;;AAKC,IACM,MAAMI,iBAAAA,GAAoB,CAACC,SAAAA,EAA+BC,YAAoB,IAAI,GAAA;AACrF,IAAA,IAAI,CAACD,SAAAA,EAAW;QACZ,OAAOE,SAAAA;AACX,IAAA;;AAGA,IAAA,MAAMC,YAAYH,SAAAA,CACbI,OAAO,CAAC,QAAA,EAAU;KAClBA,OAAO,CAAC,MAAA,EAAQ,GAAA,CAAA;KAChBC,IAAI,EAAA;;IAGT,IAAIF,SAAAA,CAAUG,MAAM,GAAGL,SAAAA,EAAW;AAC9B,QAAA,MAAMM,YAAYJ,SAAAA,CAAUK,SAAS,CAAC,CAAA,EAAGP,YAAY,CAAA,CAAA,GAAK,KAAA;;;AAG1DQ,QAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,yBAAyB,EAAEP,SAAAA,CAAUG,MAAM,CAAC,IAAI,EAAEC,SAAAA,CAAUD,MAAM,CAAC,WAAW,CAAC,CAAA;QAC7F,OAAOC,SAAAA;AACX,IAAA;IAEA,OAAOJ,SAAAA;AACX;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eldrforge/kodrdriv",
3
- "version": "1.2.19",
3
+ "version": "1.2.21",
4
4
  "description": "Create Intelligent Release Notes or Change Logs from Git",
5
5
  "main": "dist/main.js",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "url": "git+https://github.com/calenvarek/kodrdriv.git"
13
13
  },
14
14
  "scripts": {
15
- "build": "npm run lint && tsc --noEmit && vite build && copyfiles -u 1 \"src/**/*.md\" dist && chmod 755 ./dist/main.js",
15
+ "build": "npm run lint && tsc --noEmit && vite build && copyfiles -u 1 \"src/**/*.md\" dist && chmod 755 ./dist/main.js 2>/dev/null || chmod 755 ./dist/kodrdriv/src/main.js",
16
16
  "start": "dist/main.js",
17
17
  "dev": "vite",
18
18
  "watch": "vite build --watch",
@@ -38,6 +38,8 @@
38
38
  "author": "Calen Varek <calenvarek@gmail.com>",
39
39
  "license": "Apache-2.0",
40
40
  "dependencies": {
41
+ "@eldrforge/git-tools": "^0.1.3",
42
+ "@eldrforge/github-tools": "^0.1.4",
41
43
  "@octokit/rest": "^22.0.0",
42
44
  "@riotprompt/riotprompt": "^0.0.8",
43
45
  "@theunwalked/cardigantime": "^0.0.16",
package/test_output.txt CHANGED
@@ -3,7 +3,7 @@
3
3
  > vitest run --coverage tests/commands/tree.test.ts
4
4
 
5
5
 
6
- RUN v3.2.4 /Users/tobrien/gitw/calenvarek/kodrdriv
6
+ RUN v3.2.4 kodrdriv
7
7
  Coverage enabled with v8
8
8
 
9
9
  ❯ tests/commands/tree.test.ts (60 tests | 6 failed) 57ms
@@ -105,12 +105,12 @@ Error: Failed to analyze workspace: Command failed in package package-a
105
105
  FAIL tests/commands/tree.test.ts > tree > built-in command execution > should propagate global options to built-in commands
106
106
  AssertionError: expected "spy" to be called at least once
107
107
  ❯ tests/commands/tree.test.ts:1105:37
108
- 1103|
108
+ 1103|
109
109
  1104| // Verify the command was executed (basic check)
110
110
  1105| expect(mockExecPromise).toHaveBeenCalled();
111
111
  | ^
112
112
  1106| });
113
- 1107|
113
+ 1107|
114
114
 
115
115
  ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/6]⎯
116
116
 
@@ -1,331 +0,0 @@
1
- import { getLogger } from '../logging.js';
2
- import { getUserChoice as getUserChoice$1 } from '../util/interactive.js';
3
- import { createIssue, getOpenIssues } from '../util/github.js';
4
- import path__default from 'path';
5
- import os__default from 'os';
6
- import { spawnSync } from 'child_process';
7
- import fs__default from 'fs/promises';
8
-
9
- // Get GitHub issues content
10
- const get = async (options = {})=>{
11
- const logger = getLogger();
12
- const { limit = 20 } = options;
13
- try {
14
- logger.debug('Fetching open GitHub issues...');
15
- const issuesLimit = Math.min(limit, 20); // Cap at 20
16
- const githubIssues = await getOpenIssues(issuesLimit);
17
- if (githubIssues.trim()) {
18
- logger.debug('Added GitHub issues to context (%d characters)', githubIssues.length);
19
- return githubIssues;
20
- } else {
21
- logger.debug('No open GitHub issues found');
22
- return '';
23
- }
24
- } catch (error) {
25
- logger.warn('Failed to fetch GitHub issues: %s', error.message);
26
- return '';
27
- }
28
- };
29
- // Helper function to get user choice interactively
30
- async function getUserChoice(prompt, choices) {
31
- return await getUserChoice$1(prompt, choices);
32
- }
33
- // Helper function to serialize issue to structured text format
34
- function serializeIssue(issue) {
35
- const lines = [
36
- '# Issue Editor',
37
- '',
38
- '# Edit the issue details below. Lines starting with "#" are comments and will be ignored.',
39
- '# Valid priorities: low, medium, high',
40
- '# Valid categories: ui, content, functionality, accessibility, performance, other',
41
- '# Suggestions should be one per line, preceded by a "-" or "•"',
42
- '',
43
- `Title: ${issue.title}`,
44
- '',
45
- `Priority: ${issue.priority}`,
46
- '',
47
- `Category: ${issue.category}`,
48
- '',
49
- 'Description:',
50
- issue.description,
51
- '',
52
- 'Suggestions:'
53
- ];
54
- if (issue.suggestions && issue.suggestions.length > 0) {
55
- issue.suggestions.forEach((suggestion)=>{
56
- lines.push(`- ${suggestion}`);
57
- });
58
- } else {
59
- lines.push('# Add suggestions here, one per line with "-" or "•"');
60
- }
61
- return lines.join('\n');
62
- }
63
- // Helper function to deserialize issue from structured text format
64
- function deserializeIssue(content) {
65
- const lines = content.split('\n');
66
- // Parse the structured format
67
- let title = '';
68
- let priority = 'medium';
69
- let category = 'other';
70
- let description = '';
71
- const suggestions = [];
72
- let currentSection = '';
73
- let descriptionLines = [];
74
- for(let i = 0; i < lines.length; i++){
75
- const line = lines[i].trim();
76
- // Skip comment lines
77
- if (line.startsWith('#')) {
78
- continue;
79
- }
80
- // Parse field lines
81
- if (line.startsWith('Title:')) {
82
- title = line.substring(6).trim();
83
- } else if (line.startsWith('Priority:')) {
84
- const priorityValue = line.substring(9).trim().toLowerCase();
85
- if (priorityValue === 'low' || priorityValue === 'medium' || priorityValue === 'high') {
86
- priority = priorityValue;
87
- }
88
- } else if (line.startsWith('Category:')) {
89
- const categoryValue = line.substring(9).trim().toLowerCase();
90
- if ([
91
- 'ui',
92
- 'content',
93
- 'functionality',
94
- 'accessibility',
95
- 'performance',
96
- 'other'
97
- ].includes(categoryValue)) {
98
- category = categoryValue;
99
- }
100
- } else if (line === 'Description:') {
101
- currentSection = 'description';
102
- descriptionLines = [];
103
- } else if (line === 'Suggestions:') {
104
- currentSection = 'suggestions';
105
- // Process accumulated description lines
106
- description = descriptionLines.join('\n').trim();
107
- } else if (currentSection === 'description' && line !== '') {
108
- descriptionLines.push(lines[i]); // Keep original line with spacing
109
- } else if (currentSection === 'suggestions' && line !== '') {
110
- // Parse suggestion line
111
- const suggestionLine = line.replace(/^[-•]\s*/, '').trim();
112
- if (suggestionLine) {
113
- suggestions.push(suggestionLine);
114
- }
115
- }
116
- }
117
- // If we didn't encounter suggestions section, description might still be accumulating
118
- if (currentSection === 'description') {
119
- description = descriptionLines.join('\n').trim();
120
- }
121
- return {
122
- title: title || 'Untitled Issue',
123
- priority,
124
- category,
125
- description: description || 'No description provided',
126
- suggestions: suggestions.length > 0 ? suggestions : undefined
127
- };
128
- }
129
- // Helper function to edit issue using editor
130
- async function editIssueInteractively(issue) {
131
- const logger = getLogger();
132
- const editor = process.env.EDITOR || process.env.VISUAL || 'vi';
133
- // Create a temporary file for the user to edit
134
- const tmpDir = os__default.tmpdir();
135
- const tmpFilePath = path__default.join(tmpDir, `kodrdriv_issue_${Date.now()}.txt`);
136
- // Serialize the issue to structured text format
137
- const issueContent = serializeIssue(issue);
138
- await fs__default.writeFile(tmpFilePath, issueContent, 'utf8');
139
- logger.info(`📝 Opening ${editor} to edit issue...`);
140
- // Open the editor synchronously so execution resumes after the user closes it
141
- const result = spawnSync(editor, [
142
- tmpFilePath
143
- ], {
144
- stdio: 'inherit'
145
- });
146
- if (result.error) {
147
- throw new Error(`Failed to launch editor '${editor}': ${result.error.message}`);
148
- }
149
- // Read the file back and deserialize it
150
- const editedContent = await fs__default.readFile(tmpFilePath, 'utf8');
151
- // Clean up the temporary file with proper error handling
152
- try {
153
- await fs__default.unlink(tmpFilePath);
154
- } catch (error) {
155
- // Only log if it's not a "file not found" error
156
- if (error.code !== 'ENOENT') {
157
- logger.warn(`Failed to cleanup temporary file ${tmpFilePath}: ${error.message}`);
158
- }
159
- }
160
- // Deserialize the edited content back to an Issue object
161
- const editedIssue = deserializeIssue(editedContent);
162
- logger.info('✅ Issue updated successfully');
163
- logger.debug('Updated issue: %s', JSON.stringify(editedIssue, null, 2));
164
- return editedIssue;
165
- }
166
- // Helper function to format issue body for GitHub
167
- function formatIssueBody(issue) {
168
- let body = `## Description\n\n${issue.description}\n\n`;
169
- body += `## Details\n\n`;
170
- body += `- **Priority:** ${issue.priority}\n`;
171
- body += `- **Category:** ${issue.category}\n`;
172
- body += `- **Source:** Review\n\n`;
173
- if (issue.suggestions && issue.suggestions.length > 0) {
174
- body += `## Suggestions\n\n`;
175
- issue.suggestions.forEach((suggestion)=>{
176
- body += `- ${suggestion}\n`;
177
- });
178
- body += '\n';
179
- }
180
- body += `---\n\n`;
181
- body += `*This issue was automatically created from a review session.*`;
182
- return body;
183
- }
184
- // Helper function to format results with created GitHub issues
185
- function formatReviewResultsWithIssues(result, createdIssues) {
186
- let output = `📝 Review Results\n\n`;
187
- output += `📋 Summary: ${result.summary}\n`;
188
- output += `📊 Total Issues Found: ${result.totalIssues}\n`;
189
- output += `🚀 GitHub Issues Created: ${createdIssues.length}\n\n`;
190
- if (result.issues && result.issues.length > 0) {
191
- output += `📝 Issues Identified:\n\n`;
192
- result.issues.forEach((issue, index)=>{
193
- const priorityEmoji = issue.priority === 'high' ? '🔴' : issue.priority === 'medium' ? '🟡' : '🟢';
194
- const categoryEmoji = issue.category === 'ui' ? '🎨' : issue.category === 'content' ? '📝' : issue.category === 'functionality' ? '⚙️' : issue.category === 'accessibility' ? '♿' : issue.category === 'performance' ? '⚡' : '🔧';
195
- output += `${index + 1}. ${priorityEmoji} ${issue.title}\n`;
196
- output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\n`;
197
- output += ` 📖 Description: ${issue.description}\n`;
198
- // Check if this issue was created as a GitHub issue
199
- const createdIssue = createdIssues.find((ci)=>ci.issue === issue);
200
- if (createdIssue) {
201
- output += ` 🔗 GitHub Issue: #${createdIssue.number} - ${createdIssue.githubUrl}\n`;
202
- }
203
- if (issue.suggestions && issue.suggestions.length > 0) {
204
- output += ` 💡 Suggestions:\n`;
205
- issue.suggestions.forEach((suggestion)=>{
206
- output += ` • ${suggestion}\n`;
207
- });
208
- }
209
- output += `\n`;
210
- });
211
- } else {
212
- output += `✅ No specific issues identified from the review.\n\n`;
213
- }
214
- if (createdIssues.length > 0) {
215
- output += `\n🎯 Created GitHub Issues:\n`;
216
- createdIssues.forEach((createdIssue)=>{
217
- output += `• #${createdIssue.number}: ${createdIssue.issue.title} - ${createdIssue.githubUrl}\n`;
218
- });
219
- output += `\n`;
220
- }
221
- output += `🚀 Next Steps: Review the created GitHub issues and prioritize them in your development workflow.`;
222
- return output;
223
- }
224
- function formatReviewResults(result) {
225
- let output = `📝 Review Results\n\n`;
226
- output += `📋 Summary: ${result.summary}\n`;
227
- output += `📊 Total Issues Found: ${result.totalIssues}\n\n`;
228
- if (result.issues && result.issues.length > 0) {
229
- output += `📝 Issues Identified:\n\n`;
230
- result.issues.forEach((issue, index)=>{
231
- const priorityEmoji = issue.priority === 'high' ? '🔴' : issue.priority === 'medium' ? '🟡' : '🟢';
232
- const categoryEmoji = issue.category === 'ui' ? '🎨' : issue.category === 'content' ? '📝' : issue.category === 'functionality' ? '⚙️' : issue.category === 'accessibility' ? '♿' : issue.category === 'performance' ? '⚡' : '🔧';
233
- output += `${index + 1}. ${priorityEmoji} ${issue.title}\n`;
234
- output += ` ${categoryEmoji} Category: ${issue.category} | Priority: ${issue.priority}\n`;
235
- output += ` 📖 Description: ${issue.description}\n`;
236
- if (issue.suggestions && issue.suggestions.length > 0) {
237
- output += ` 💡 Suggestions:\n`;
238
- issue.suggestions.forEach((suggestion)=>{
239
- output += ` • ${suggestion}\n`;
240
- });
241
- }
242
- output += `\n`;
243
- });
244
- } else {
245
- output += `✅ No specific issues identified from the review.\n\n`;
246
- }
247
- output += `🚀 Next Steps: Review the identified issues and prioritize them for your development workflow.`;
248
- return output;
249
- }
250
- // Handle GitHub issue creation workflow
251
- const handleIssueCreation = async (result, senditMode = false)=>{
252
- const logger = getLogger();
253
- const createdIssues = [];
254
- if (!result.issues || result.issues.length === 0) {
255
- return formatReviewResults(result);
256
- }
257
- logger.info(`🔍 Found ${result.issues.length} issues to potentially create as GitHub issues`);
258
- for(let i = 0; i < result.issues.length; i++){
259
- let issue = result.issues[i];
260
- let shouldCreateIssue = senditMode;
261
- if (!senditMode) {
262
- // Interactive confirmation for each issue - keep looping until user decides
263
- let userChoice = '';
264
- while(userChoice !== 'c' && userChoice !== 's'){
265
- // Display issue details
266
- logger.info(`\n📋 Issue ${i + 1} of ${result.issues.length}:`);
267
- logger.info(` Title: ${issue.title}`);
268
- logger.info(` Priority: ${issue.priority} | Category: ${issue.category}`);
269
- logger.info(` Description: ${issue.description}`);
270
- if (issue.suggestions && issue.suggestions.length > 0) {
271
- logger.info(` Suggestions: ${issue.suggestions.join(', ')}`);
272
- }
273
- // Get user choice
274
- userChoice = await getUserChoice('\nWhat would you like to do with this issue?', [
275
- {
276
- key: 'c',
277
- label: 'Create GitHub issue'
278
- },
279
- {
280
- key: 's',
281
- label: 'Skip this issue'
282
- },
283
- {
284
- key: 'e',
285
- label: 'Edit issue details'
286
- }
287
- ]);
288
- if (userChoice === 'c') {
289
- shouldCreateIssue = true;
290
- } else if (userChoice === 'e') {
291
- // Allow user to edit the issue
292
- issue = await editIssueInteractively(issue);
293
- result.issues[i] = issue; // Update the issue in the result
294
- // Continue the loop to show the updated issue and ask again
295
- }
296
- // If choice is 's', loop will exit and shouldCreateIssue remains false
297
- }
298
- }
299
- if (shouldCreateIssue) {
300
- try {
301
- logger.info(`🚀 Creating GitHub issue: "${issue.title}"`);
302
- // Format issue body with additional details
303
- const issueBody = formatIssueBody(issue);
304
- // Create labels based on priority and category
305
- const labels = [
306
- `priority-${issue.priority}`,
307
- `category-${issue.category}`,
308
- 'review'
309
- ];
310
- const createdIssue = await createIssue(issue.title, issueBody, labels);
311
- createdIssues.push({
312
- issue,
313
- githubUrl: createdIssue.html_url,
314
- number: createdIssue.number
315
- });
316
- logger.info(`✅ Created GitHub issue #${createdIssue.number}: ${createdIssue.html_url}`);
317
- } catch (error) {
318
- logger.error(`❌ Failed to create GitHub issue for "${issue.title}": ${error.message}`);
319
- }
320
- }
321
- }
322
- // Return formatted results
323
- if (createdIssues.length > 0) {
324
- return formatReviewResultsWithIssues(result, createdIssues);
325
- } else {
326
- return formatReviewResults(result);
327
- }
328
- };
329
-
330
- export { get, handleIssueCreation };
331
- //# sourceMappingURL=issues.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"issues.js","sources":["../../src/content/issues.ts"],"sourcesContent":["import { getLogger } from '../logging';\nimport { getUserChoice as getUserChoiceInteractive } from '../util/interactive';\nimport { getOpenIssues, createIssue } from '../util/github';\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 (%d characters)', githubIssues.length);\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: %s', 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 return await getUserChoiceInteractive(prompt, choices);\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: %s', 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","getUserChoiceInteractive","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","key","label","issueBody","labels","createIssue","html_url"],"mappings":"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"}