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