git-ai-shen 1.0.3 → 1.0.4

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,5 +1,6 @@
1
1
  const simpleGit = require('simple-git');
2
- const fs = require('fs').promises;
2
+ const fs = require('fs'); // 导入同步版本的 fs
3
+ const fsPromises = require('fs').promises; // 如果需要 promise 版本,单独命名
3
4
  const path = require('path');
4
5
  const { exec } = require('child_process');
5
6
  const util = require('util');
@@ -10,6 +11,7 @@ class GitOperations {
10
11
  this.git = simpleGit(repoPath);
11
12
  this.repoPath = repoPath;
12
13
  }
14
+
13
15
  /**
14
16
  * 获取文件的详细变更信息(哪些行被修改)
15
17
  * @param {string} filePath 文件路径
@@ -17,22 +19,22 @@ class GitOperations {
17
19
  */
18
20
  async getFileDiff(filePath) {
19
21
  try {
20
- // 方案一:使用 -- 分隔符明确指定是文件路径
22
+ // 使用 -- 分隔符明确指定是文件路径
21
23
  const diff = await this.git.diff(['--', filePath]);
22
24
 
23
- // 如果返回空,可能是因为文件没被 git 跟踪,试试用 --no-index
25
+ // 如果返回空,可能是因为文件没被 git 跟踪
24
26
  if (!diff) {
25
27
  const fullPath = path.join(this.repoPath, filePath);
28
+ // 使用同步的 fs.existsSync
26
29
  if (fs.existsSync(fullPath)) {
27
- // 文件存在但没被跟踪,用 --no-index 比较
28
- const noIndexDiff = await this.git.diff(['--no-index', '--', '/dev/null', filePath]);
30
+ // Windows 上用 NUL 代替 /dev/null
31
+ const noIndexDiff = await this.git.diff(['--no-index', '--', 'NUL', filePath]);
29
32
  return this.parseDiff(noIndexDiff, filePath);
30
33
  }
31
34
  }
32
35
 
33
36
  return this.parseDiff(diff, filePath);
34
37
  } catch (error) {
35
- // 如果出错,返回一个空的 diff 对象而不是 null
36
38
  console.log(`获取 diff 失败: ${error.message}`);
37
39
  return {
38
40
  file: filePath,
@@ -43,35 +45,43 @@ class GitOperations {
43
45
  };
44
46
  }
45
47
  }
48
+
46
49
  /**
47
- * 获取已暂存文件的详细变更信息
48
- * @param {string} filePath 文件路径
49
- * @returns {Promise<Object>} 变更详情
50
- */
50
+ * 获取已暂存文件的详细变更信息
51
+ * @param {string} filePath 文件路径
52
+ * @returns {Promise<Object>} 变更详情
53
+ */
51
54
  async getStagedDiff(filePath) {
52
55
  try {
53
- // 获取已暂存的变更
54
- const diff = await this.git.diff(['--cached', filePath]);
55
-
56
- // 解析 diff 信息
56
+ // 使用 -- 分隔符
57
+ const diff = await this.git.diff(['--cached', '--', filePath]);
57
58
  return this.parseDiff(diff, filePath);
58
59
  } catch (error) {
59
60
  console.error(`获取暂存 diff 失败: ${error.message}`);
60
- return null;
61
+ return {
62
+ file: filePath,
63
+ changes: [],
64
+ summary: '获取失败',
65
+ addCount: 0,
66
+ deleteCount: 0
67
+ };
61
68
  }
62
69
  }
70
+
63
71
  /**
64
- * 解析 git diff 输出
65
- * @param {string} diff git diff 的输出
66
- * @param {string} filePath 文件路径
67
- * @returns {Object} 解析后的变更信息
68
- */
72
+ * 解析 git diff 输出
73
+ * @param {string} diff git diff 的输出
74
+ * @param {string} filePath 文件路径
75
+ * @returns {Object} 解析后的变更信息
76
+ */
69
77
  parseDiff(diff, filePath) {
70
78
  if (!diff) {
71
79
  return {
72
80
  file: filePath,
73
81
  changes: [],
74
- summary: '无变更'
82
+ summary: '无变更',
83
+ addCount: 0,
84
+ deleteCount: 0
75
85
  };
76
86
  }
77
87
 
@@ -79,9 +89,7 @@ class GitOperations {
79
89
  const changes = [];
80
90
  let currentHunk = null;
81
91
 
82
- // 解析 diff 的每一行
83
92
  for (const line of lines) {
84
- // 匹配 hunk 头信息,例如:@@ -1,4 +1,5 @@
85
93
  const hunkMatch = line.match(/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
86
94
  if (hunkMatch) {
87
95
  currentHunk = {
@@ -97,21 +105,18 @@ class GitOperations {
97
105
 
98
106
  if (currentHunk) {
99
107
  if (line.startsWith('+')) {
100
- // 新增的行
101
108
  currentHunk.changes.push({
102
109
  type: 'add',
103
110
  content: line.substring(1),
104
111
  lineNumber: currentHunk.newStart + currentHunk.changes.filter(c => c.type !== 'delete').length
105
112
  });
106
113
  } else if (line.startsWith('-')) {
107
- // 删除的行
108
114
  currentHunk.changes.push({
109
115
  type: 'delete',
110
116
  content: line.substring(1),
111
117
  lineNumber: currentHunk.oldStart + currentHunk.changes.filter(c => c.type !== 'add').length
112
118
  });
113
119
  } else if (!line.startsWith('\\')) {
114
- // 上下文行
115
120
  currentHunk.changes.push({
116
121
  type: 'context',
117
122
  content: line.substring(1)
@@ -120,7 +125,6 @@ class GitOperations {
120
125
  }
121
126
  }
122
127
 
123
- // 生成变更摘要
124
128
  const addCount = changes.flatMap(h => h.changes).filter(c => c.type === 'add').length;
125
129
  const deleteCount = changes.flatMap(h => h.changes).filter(c => c.type === 'delete').length;
126
130
 
@@ -132,6 +136,7 @@ class GitOperations {
132
136
  deleteCount
133
137
  };
134
138
  }
139
+
135
140
  /**
136
141
  * 获取所有变更文件的详细 diff
137
142
  * @param {Array<string>} files 文件列表
@@ -140,7 +145,6 @@ class GitOperations {
140
145
  */
141
146
  async getDiffs(files, staged = false) {
142
147
  const diffs = {};
143
-
144
148
  for (const file of files) {
145
149
  if (staged) {
146
150
  diffs[file] = await this.getStagedDiff(file);
@@ -148,9 +152,9 @@ class GitOperations {
148
152
  diffs[file] = await this.getFileDiff(file);
149
153
  }
150
154
  }
151
-
152
155
  return diffs;
153
156
  }
157
+
154
158
  async isGitRepo() {
155
159
  try {
156
160
  return await this.git.checkIsRepo();
@@ -190,29 +194,15 @@ class GitOperations {
190
194
 
191
195
  async pull(remote = 'origin', branch = null, sshPassword = null) {
192
196
  try {
193
- if (!branch) {
194
- branch = await this.getCurrentBranch();
195
- }
196
-
197
- // 如果有 SSH 密码,使用 expect 脚本处理
198
- if (sshPassword) {
199
- return await this.pullWithPassword(remote, branch, sshPassword);
200
- }
201
-
202
- // 正常拉取
197
+ if (!branch) branch = await this.getCurrentBranch();
198
+ if (sshPassword) return await this.pullWithPassword(remote, branch, sshPassword);
203
199
  await this.git.pull(remote, branch);
204
200
  return { success: true };
205
-
206
201
  } catch (error) {
207
- // 检查是否是 SSH 密钥密码错误
208
202
  if (error.message.includes('Permission denied') ||
209
203
  error.message.includes('authenticity') ||
210
204
  error.message.includes('password')) {
211
- return {
212
- success: false,
213
- needPassword: true,
214
- error: error.message
215
- };
205
+ return { success: false, needPassword: true, error: error.message };
216
206
  }
217
207
  return { success: false, error: error.message };
218
208
  }
@@ -220,7 +210,6 @@ class GitOperations {
220
210
 
221
211
  async pullWithPassword(remote, branch, password) {
222
212
  try {
223
- // 使用 expect 脚本自动输入 SSH 密码
224
213
  const command = `
225
214
  expect << 'EOF'
226
215
  spawn git pull ${remote} ${branch}
@@ -231,7 +220,6 @@ class GitOperations {
231
220
  expect eof
232
221
  EOF
233
222
  `;
234
-
235
223
  await execAsync(command);
236
224
  return { success: true };
237
225
  } catch (error) {
@@ -241,28 +229,15 @@ class GitOperations {
241
229
 
242
230
  async push(remote = 'origin', branch = null, sshPassword = null) {
243
231
  try {
244
- if (!branch) {
245
- branch = await this.getCurrentBranch();
246
- }
247
-
248
- // 如果有 SSH 密码,使用 expect 脚本处理
249
- if (sshPassword) {
250
- return await this.pushWithPassword(remote, branch, sshPassword);
251
- }
252
-
232
+ if (!branch) branch = await this.getCurrentBranch();
233
+ if (sshPassword) return await this.pushWithPassword(remote, branch, sshPassword);
253
234
  await this.git.push(remote, branch);
254
235
  return { success: true };
255
-
256
236
  } catch (error) {
257
- // 检查是否是 SSH 密钥密码错误
258
237
  if (error.message.includes('Permission denied') ||
259
238
  error.message.includes('authenticity') ||
260
239
  error.message.includes('password')) {
261
- return {
262
- success: false,
263
- needPassword: true,
264
- error: error.message
265
- };
240
+ return { success: false, needPassword: true, error: error.message };
266
241
  }
267
242
  return { success: false, error: error.message };
268
243
  }
@@ -280,7 +255,6 @@ class GitOperations {
280
255
  expect eof
281
256
  EOF
282
257
  `;
283
-
284
258
  await execAsync(command);
285
259
  return { success: true };
286
260
  } catch (error) {
@@ -291,7 +265,8 @@ class GitOperations {
291
265
  async getFileContent(filePath) {
292
266
  try {
293
267
  const fullPath = path.join(this.repoPath, filePath);
294
- return await fs.readFile(fullPath, 'utf-8');
268
+ // 使用 fsPromises 读取文件内容
269
+ return await fsPromises.readFile(fullPath, 'utf-8');
295
270
  } catch {
296
271
  return null;
297
272
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-ai-shen",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "智能Git提交工具,支持行级代码审查和AI生成提交信息",
5
5
  "main": "bin/git-ai.js",
6
6
  "bin": {