goodiffer 1.0.0 → 1.0.1

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.
@@ -1,155 +1,154 @@
1
1
  import chalk from 'chalk';
2
2
  import logger from '../utils/logger.js';
3
3
 
4
- export function parseAIResponse(content) {
4
+ export function generateReport(aiResponse, commitInfo) {
5
+ console.log();
6
+ console.log(chalk.cyan('╭──────────────────────────────────────────────────────────╮'));
7
+ console.log(chalk.cyan('│ ') + chalk.bold.white('Goodiffer Analysis Report') + chalk.cyan(' │'));
8
+ console.log(chalk.cyan('╰──────────────────────────────────────────────────────────╯'));
9
+ console.log();
10
+
11
+ // 显示 commit 信息
12
+ console.log(chalk.blue('📝 Commit:'), commitInfo.message);
13
+ console.log();
14
+
15
+ // 尝试解析 JSON 响应
16
+ let result;
5
17
  try {
6
- // 尝试从响应中提取 JSON
7
- const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/);
18
+ // 提取 JSON 部分 (可能包含在 markdown 代码块中)
19
+ let jsonStr = aiResponse;
20
+ const jsonMatch = aiResponse.match(/```(?:json)?\s*([\s\S]*?)```/);
8
21
  if (jsonMatch) {
9
- return JSON.parse(jsonMatch[1]);
22
+ jsonStr = jsonMatch[1].trim();
10
23
  }
11
-
12
- // 尝试直接解析
13
- const trimmed = content.trim();
14
- if (trimmed.startsWith('{')) {
15
- return JSON.parse(trimmed);
16
- }
17
-
18
- throw new Error('无法解析 AI 响应');
19
- } catch (error) {
20
- logger.error(`解析 AI 响应失败: ${error.message}`);
21
- return null;
24
+ result = JSON.parse(jsonStr);
25
+ } catch {
26
+ // 如果无法解析为 JSON,直接显示原始响应
27
+ console.log(chalk.yellow('📊 分析结果:'));
28
+ console.log();
29
+ console.log(aiResponse);
30
+ return;
22
31
  }
23
- }
24
-
25
- export function printReport(commitInfo, report) {
26
- console.log('\n');
27
32
 
28
- // 标题
29
- console.log(chalk.cyan('╭' + '─'.repeat(58) + '╮'));
30
- console.log(chalk.cyan('│') + chalk.bold.white(' Goodiffer Analysis Report').padEnd(66) + chalk.cyan('│'));
31
- console.log(chalk.cyan('╰' + '─'.repeat(58) + '╯'));
32
-
33
- // Commit 信息
34
- console.log(chalk.blue('\n📝 Commit: ') + chalk.white(commitInfo.message.split('\n')[0]));
35
- console.log(chalk.gray(` SHA: ${commitInfo.sha.substring(0, 8)} | ${commitInfo.author} | ${commitInfo.date}`));
36
-
37
- // Summary
38
- if (report.summary) {
39
- console.log(chalk.green('\n📊 Summary: ') + chalk.white(report.summary));
33
+ // 显示摘要
34
+ if (result.summary) {
35
+ console.log(chalk.green('📊 Summary:'), result.summary);
36
+ console.log();
40
37
  }
41
38
 
42
- // Commit Alignment
43
- if (report.commitAlignment) {
44
- const aligned = report.commitAlignment.aligned;
45
- const icon = aligned ? chalk.green('') : chalk.red('');
46
- console.log(chalk.yellow('\n🎯 Commit 匹配: ') + icon + ' ' + report.commitAlignment.comment);
39
+ // 显示 commit 匹配情况
40
+ if (result.commitMatch !== undefined) {
41
+ const matchIcon = result.commitMatch ? chalk.green('✓') : chalk.red('✗');
42
+ console.log(chalk.blue('🎯 Commit 匹配:'), matchIcon, result.commitMatchReason || '');
43
+ console.log();
47
44
  }
48
45
 
49
46
  logger.divider();
50
47
 
51
- // Issues
52
- const issues = report.issues || [];
48
+ // 按级别分组显示问题
49
+ const issues = result.issues || [];
53
50
  const errors = issues.filter(i => i.level === 'error');
54
51
  const warnings = issues.filter(i => i.level === 'warning');
55
52
  const infos = issues.filter(i => i.level === 'info');
56
53
 
54
+ // 显示错误
57
55
  if (errors.length > 0) {
58
- console.log(chalk.red.bold(`\n🔴 ERRORS (${errors.length})`));
59
- errors.forEach((issue, idx) => printIssue(issue, `E${String(idx + 1).padStart(3, '0')}`));
56
+ console.log();
57
+ console.log(chalk.red.bold(`🔴 ERRORS (${errors.length})`));
58
+ console.log();
59
+ errors.forEach((issue, index) => {
60
+ printIssue(issue, `E${String(index + 1).padStart(3, '0')}`, chalk.red);
61
+ });
60
62
  }
61
63
 
64
+ // 显示警告
62
65
  if (warnings.length > 0) {
63
- console.log(chalk.yellow.bold(`\n🟡 WARNINGS (${warnings.length})`));
64
- warnings.forEach((issue, idx) => printIssue(issue, `W${String(idx + 1).padStart(3, '0')}`));
66
+ console.log();
67
+ console.log(chalk.yellow.bold(`🟡 WARNINGS (${warnings.length})`));
68
+ console.log();
69
+ warnings.forEach((issue, index) => {
70
+ printIssue(issue, `W${String(index + 1).padStart(3, '0')}`, chalk.yellow);
71
+ });
65
72
  }
66
73
 
74
+ // 显示信息
67
75
  if (infos.length > 0) {
68
- console.log(chalk.blue.bold(`\n🔵 INFO (${infos.length})`));
69
- infos.forEach((issue, idx) => printIssue(issue, `I${String(idx + 1).padStart(3, '0')}`));
70
- }
71
-
72
- if (issues.length === 0) {
73
- console.log(chalk.green.bold('\n✅ 未发现代码问题'));
76
+ console.log();
77
+ console.log(chalk.blue.bold(`🔵 INFO (${infos.length})`));
78
+ console.log();
79
+ infos.forEach((issue, index) => {
80
+ printIssue(issue, `I${String(index + 1).padStart(3, '0')}`, chalk.blue);
81
+ });
74
82
  }
75
83
 
76
- // Association Risks
77
- const risks = report.associationRisks || [];
84
+ // 显示关联风险
85
+ const risks = result.associationRisks || [];
78
86
  if (risks.length > 0) {
79
87
  logger.divider();
80
- console.log(chalk.magenta.bold(`\n🔗 ASSOCIATION RISKS (${risks.length})`));
81
- risks.forEach(printRisk);
82
- }
83
-
84
- // Suggestions
85
- const suggestions = report.suggestions || [];
86
- if (suggestions.length > 0) {
87
- logger.divider();
88
- console.log(chalk.cyan.bold('\n💡 建议'));
89
- suggestions.forEach((s, idx) => {
90
- console.log(chalk.gray(` ${idx + 1}. `) + chalk.white(s));
88
+ console.log();
89
+ console.log(chalk.magenta.bold(`🔗 ASSOCIATION RISKS (${risks.length})`));
90
+ console.log();
91
+ risks.forEach((risk, index) => {
92
+ printRisk(risk, index + 1);
91
93
  });
92
94
  }
93
95
 
94
- // 统计
96
+ // 统计摘要
95
97
  logger.divider();
96
- console.log(chalk.gray('\n📈 统计: ') +
97
- chalk.red(`${errors.length} errors `) +
98
- chalk.yellow(`${warnings.length} warnings `) +
99
- chalk.blue(`${infos.length} info `) +
100
- chalk.magenta(`${risks.length} risks`));
101
-
102
- console.log('');
98
+ console.log();
99
+ console.log(
100
+ chalk.gray('📈 统计:'),
101
+ chalk.red(`${errors.length} errors`),
102
+ chalk.yellow(`${warnings.length} warnings`),
103
+ chalk.blue(`${infos.length} info`),
104
+ chalk.magenta(`${risks.length} risks`)
105
+ );
106
+ console.log();
103
107
  }
104
108
 
105
- function printIssue(issue, code) {
106
- console.log('');
107
- console.log(chalk.gray(`[${code}] `) + chalk.white(`${issue.file}:${issue.line}`));
108
- console.log(chalk.gray('类型: ') + chalk.white(issue.type));
109
- console.log(chalk.gray('问题: ') + chalk.white(issue.description));
109
+ function printIssue(issue, id, colorFn) {
110
+ console.log(colorFn(`[${id}]`), chalk.gray(`${issue.file}:${issue.line || '?'}`));
111
+ console.log(chalk.white('问题:'), issue.description);
110
112
 
111
113
  if (issue.code) {
112
114
  console.log(chalk.gray('代码:'));
113
- console.log(chalk.gray(' ┌─'));
114
- issue.code.split('\n').forEach(line => {
115
- console.log(chalk.gray(' │ ') + chalk.red(line));
116
- });
117
- console.log(chalk.gray(' └─'));
115
+ console.log(chalk.gray(' ') + issue.code.split('\n').join('\n '));
118
116
  }
119
117
 
120
118
  if (issue.suggestion) {
121
- console.log(chalk.gray('建议: ') + chalk.green(issue.suggestion));
119
+ console.log(chalk.green('建议:'), issue.suggestion);
122
120
  }
123
121
 
124
122
  if (issue.fixPrompt) {
125
- console.log(chalk.magenta('\n📋 修复提示词 (复制到 cc/codex):'));
123
+ console.log();
124
+ console.log(chalk.cyan('📋 修复提示词 (复制到 cc/codex):'));
126
125
  console.log(chalk.gray('┌' + '─'.repeat(56) + '┐'));
127
- issue.fixPrompt.split('\n').forEach(line => {
128
- const paddedLine = line.length > 54 ? line.substring(0, 51) + '...' : line;
129
- console.log(chalk.gray('│ ') + chalk.yellow(paddedLine.padEnd(54)) + chalk.gray(' │'));
126
+ const lines = issue.fixPrompt.split('\n');
127
+ lines.forEach(line => {
128
+ console.log(chalk.gray('│ ') + line.padEnd(54) + chalk.gray(' │'));
130
129
  });
131
130
  console.log(chalk.gray('└' + '─'.repeat(56) + '┘'));
132
131
  }
132
+ console.log();
133
133
  }
134
134
 
135
- function printRisk(risk) {
136
- console.log('');
137
- console.log(chalk.white('修改文件: ') + chalk.cyan(risk.changedFile));
138
- console.log(chalk.white('可能影响: ') + chalk.yellow(risk.relatedFiles?.join(', ') || '(未知)'));
139
- console.log(chalk.white('风险: ') + chalk.red(risk.risk));
135
+ function printRisk(risk, index) {
136
+ console.log(chalk.magenta(`[R${String(index).padStart(3, '0')}]`));
137
+ console.log(chalk.white('修改文件:'), risk.changedFile);
138
+ console.log(chalk.white('可能影响:'), (risk.relatedFiles || []).join(', '));
139
+ console.log(chalk.white('风险:'), risk.risk);
140
140
 
141
141
  if (risk.checkPrompt) {
142
- console.log(chalk.magenta('\n📋 检查提示词:'));
142
+ console.log();
143
+ console.log(chalk.cyan('📋 检查提示词:'));
143
144
  console.log(chalk.gray('┌' + '─'.repeat(56) + '┐'));
144
- risk.checkPrompt.split('\n').forEach(line => {
145
- const paddedLine = line.length > 54 ? line.substring(0, 51) + '...' : line;
146
- console.log(chalk.gray('│ ') + chalk.yellow(paddedLine.padEnd(54)) + chalk.gray(' │'));
145
+ const lines = risk.checkPrompt.split('\n');
146
+ lines.forEach(line => {
147
+ console.log(chalk.gray('│ ') + line.padEnd(54) + chalk.gray(' │'));
147
148
  });
148
149
  console.log(chalk.gray('└' + '─'.repeat(56) + '┘'));
149
150
  }
151
+ console.log();
150
152
  }
151
153
 
152
- export default {
153
- parseAIResponse,
154
- printReport
155
- };
154
+ export default generateReport;
@@ -1,12 +1,12 @@
1
1
  import Conf from 'conf';
2
2
 
3
3
  const config = new Conf({
4
- projectName: 'goodiffer',
4
+ projectName: 'goodiffer-nodejs',
5
5
  schema: {
6
6
  provider: {
7
7
  type: 'string',
8
8
  enum: ['claude', 'openai', 'custom'],
9
- default: 'custom'
9
+ default: 'claude'
10
10
  },
11
11
  apiHost: {
12
12
  type: 'string',
@@ -36,19 +36,13 @@ export function setConfig(key, value) {
36
36
  config.set(key, value);
37
37
  }
38
38
 
39
- export function setAllConfig(settings) {
40
- for (const [key, value] of Object.entries(settings)) {
41
- config.set(key, value);
42
- }
39
+ export function clearConfig() {
40
+ config.clear();
43
41
  }
44
42
 
45
43
  export function isConfigured() {
46
- const apiKey = config.get('apiKey');
47
- return apiKey && apiKey.length > 0;
48
- }
49
-
50
- export function clearConfig() {
51
- config.clear();
44
+ const cfg = getConfig();
45
+ return cfg.apiKey && cfg.apiHost && cfg.model;
52
46
  }
53
47
 
54
48
  export default config;
@@ -1,44 +1,44 @@
1
1
  import chalk from 'chalk';
2
2
 
3
- export const logger = {
4
- info: (msg) => console.log(chalk.blue('ℹ'), msg),
5
- success: (msg) => console.log(chalk.green(''), msg),
6
- warn: (msg) => console.log(chalk.yellow('⚠'), msg),
7
- error: (msg) => console.log(chalk.red('✖'), msg),
8
-
9
- title: (msg) => console.log(chalk.bold.cyan(`\n${msg}\n`)),
10
-
11
- box: (title, content) => {
12
- const width = 50;
13
- const top = '╭' + '─'.repeat(width - 2) + '╮';
14
- const bottom = '╰' + '─'.repeat(width - 2) + '╯';
15
- const line = (text) => '│ ' + text.padEnd(width - 4) + ' │';
16
-
17
- console.log(chalk.cyan(top));
18
- console.log(chalk.cyan(line(chalk.bold(title))));
19
- console.log(chalk.cyan(bottom));
20
- if (content) {
21
- console.log(content);
22
- }
3
+ const logger = {
4
+ info(message) {
5
+ console.log(chalk.blue(''), message);
23
6
  },
24
7
 
25
- divider: () => console.log(chalk.gray('━'.repeat(50))),
8
+ success(message) {
9
+ console.log(chalk.green('✔'), message);
10
+ },
26
11
 
27
- code: (code, language = '') => {
28
- console.log(chalk.gray('' + '─'.repeat(48) + '┐'));
29
- code.split('\n').forEach(line => {
30
- console.log(chalk.gray('│ ') + chalk.white(line));
31
- });
32
- console.log(chalk.gray('└' + '─'.repeat(48) + '┘'));
12
+ warning(message) {
13
+ console.log(chalk.yellow(''), message);
33
14
  },
34
15
 
35
- prompt: (text) => {
36
- console.log(chalk.magenta('\n📋 修复提示词 (复制到 cc/codex):'));
37
- console.log(chalk.gray('┌' + '─'.repeat(48) + '┐'));
38
- text.split('\n').forEach(line => {
39
- console.log(chalk.gray('│ ') + chalk.yellow(line));
16
+ error(message) {
17
+ console.log(chalk.red(''), message);
18
+ },
19
+
20
+ title(message) {
21
+ console.log();
22
+ console.log(chalk.bold.cyan(`━━━ ${message} ━━━`));
23
+ console.log();
24
+ },
25
+
26
+ box(title, content) {
27
+ const lines = content.split('\n');
28
+ const maxLen = Math.max(title.length, ...lines.map(l => l.length));
29
+ const border = '─'.repeat(maxLen + 2);
30
+
31
+ console.log(chalk.gray(`┌${border}┐`));
32
+ console.log(chalk.gray('│'), chalk.bold(title.padEnd(maxLen)), chalk.gray('│'));
33
+ console.log(chalk.gray(`├${border}┤`));
34
+ lines.forEach(line => {
35
+ console.log(chalk.gray('│'), line.padEnd(maxLen), chalk.gray('│'));
40
36
  });
41
- console.log(chalk.gray('└' + '─'.repeat(48) + '┘'));
37
+ console.log(chalk.gray(`└${border}┘`));
38
+ },
39
+
40
+ divider() {
41
+ console.log(chalk.gray('━'.repeat(50)));
42
42
  }
43
43
  };
44
44