@entro314labs/ai-changelog-generator 3.1.1 → 3.2.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/CHANGELOG.md +383 -877
- package/README.md +8 -3
- package/ai-changelog-mcp.sh +0 -0
- package/ai-changelog.sh +0 -0
- package/bin/ai-changelog-dxt.js +9 -9
- package/bin/ai-changelog-mcp.js +19 -17
- package/bin/ai-changelog.js +6 -6
- package/package.json +80 -48
- package/src/ai-changelog-generator.js +83 -81
- package/src/application/orchestrators/changelog.orchestrator.js +791 -516
- package/src/application/services/application.service.js +137 -128
- package/src/cli.js +76 -57
- package/src/domains/ai/ai-analysis.service.js +289 -209
- package/src/domains/analysis/analysis.engine.js +253 -193
- package/src/domains/changelog/changelog.service.js +1062 -784
- package/src/domains/changelog/workspace-changelog.service.js +420 -249
- package/src/domains/git/git-repository.analyzer.js +348 -258
- package/src/domains/git/git.service.js +132 -112
- package/src/infrastructure/cli/cli.controller.js +390 -274
- package/src/infrastructure/config/configuration.manager.js +220 -190
- package/src/infrastructure/interactive/interactive-staging.service.js +154 -135
- package/src/infrastructure/interactive/interactive-workflow.service.js +200 -159
- package/src/infrastructure/mcp/mcp-server.service.js +208 -207
- package/src/infrastructure/metrics/metrics.collector.js +140 -123
- package/src/infrastructure/providers/core/base-provider.js +87 -40
- package/src/infrastructure/providers/implementations/anthropic.js +101 -99
- package/src/infrastructure/providers/implementations/azure.js +124 -101
- package/src/infrastructure/providers/implementations/bedrock.js +136 -126
- package/src/infrastructure/providers/implementations/dummy.js +23 -23
- package/src/infrastructure/providers/implementations/google.js +123 -114
- package/src/infrastructure/providers/implementations/huggingface.js +94 -87
- package/src/infrastructure/providers/implementations/lmstudio.js +75 -60
- package/src/infrastructure/providers/implementations/mock.js +69 -73
- package/src/infrastructure/providers/implementations/ollama.js +89 -66
- package/src/infrastructure/providers/implementations/openai.js +88 -89
- package/src/infrastructure/providers/implementations/vertex.js +227 -197
- package/src/infrastructure/providers/provider-management.service.js +245 -207
- package/src/infrastructure/providers/provider-manager.service.js +145 -125
- package/src/infrastructure/providers/utils/base-provider-helpers.js +308 -302
- package/src/infrastructure/providers/utils/model-config.js +220 -195
- package/src/infrastructure/providers/utils/provider-utils.js +105 -100
- package/src/infrastructure/validation/commit-message-validation.service.js +259 -161
- package/src/shared/constants/colors.js +453 -180
- package/src/shared/utils/cli-demo.js +285 -0
- package/src/shared/utils/cli-entry-utils.js +257 -249
- package/src/shared/utils/cli-ui.js +447 -0
- package/src/shared/utils/diff-processor.js +513 -0
- package/src/shared/utils/error-classes.js +125 -156
- package/src/shared/utils/json-utils.js +93 -89
- package/src/shared/utils/utils.js +1117 -945
- package/types/index.d.ts +353 -344
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import { execSync } from 'child_process'
|
|
2
|
-
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
2
|
+
|
|
3
|
+
import colors from '../../shared/constants/colors.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Interactive Staging Service
|
|
6
|
-
*
|
|
7
|
+
*
|
|
7
8
|
* Provides interactive git staging functionality similar to better-commits
|
|
8
9
|
* Handles file selection, staging, and unstaging operations
|
|
9
10
|
*/
|
|
10
11
|
export class InteractiveStagingService {
|
|
11
12
|
constructor(gitManager) {
|
|
12
|
-
this.gitManager = gitManager
|
|
13
|
+
this.gitManager = gitManager
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Show git status with staged and unstaged changes
|
|
17
18
|
*/
|
|
18
19
|
async showGitStatus() {
|
|
19
|
-
console.log(colors.processingMessage(' Checking Git Status '))
|
|
20
|
+
console.log(colors.processingMessage(' Checking Git Status '))
|
|
21
|
+
|
|
22
|
+
const statusResult = this.getDetailedStatus()
|
|
20
23
|
|
|
21
|
-
const statusResult = this.getDetailedStatus();
|
|
22
|
-
|
|
23
24
|
if (statusResult.staged.length > 0) {
|
|
24
|
-
console.log(colors.successMessage('Changes to be committed:'))
|
|
25
|
-
statusResult.staged.forEach(file => {
|
|
26
|
-
const icon = this.getStatusIcon(file.status)
|
|
27
|
-
console.log(colors.success(` ${icon} ${file.status} ${file.path}`))
|
|
28
|
-
})
|
|
25
|
+
console.log(colors.successMessage('Changes to be committed:'))
|
|
26
|
+
statusResult.staged.forEach((file) => {
|
|
27
|
+
const icon = this.getStatusIcon(file.status)
|
|
28
|
+
console.log(colors.success(` ${icon} ${file.status} ${file.path}`))
|
|
29
|
+
})
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
if (statusResult.unstaged.length > 0) {
|
|
32
|
-
console.log(colors.warningMessage('\nChanges not staged for commit:'))
|
|
33
|
-
statusResult.unstaged.forEach(file => {
|
|
34
|
-
const icon = this.getStatusIcon(file.status)
|
|
35
|
-
console.log(colors.warning(` ${icon} ${file.status} ${file.path}`))
|
|
36
|
-
})
|
|
33
|
+
console.log(colors.warningMessage('\nChanges not staged for commit:'))
|
|
34
|
+
statusResult.unstaged.forEach((file) => {
|
|
35
|
+
const icon = this.getStatusIcon(file.status)
|
|
36
|
+
console.log(colors.warning(` ${icon} ${file.status} ${file.path}`))
|
|
37
|
+
})
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
if (statusResult.untracked.length > 0) {
|
|
40
|
-
console.log(colors.infoMessage('\nUntracked files:'))
|
|
41
|
-
statusResult.untracked.forEach(file => {
|
|
42
|
-
console.log(colors.dim(` ✨ ?? ${file.path}`))
|
|
43
|
-
})
|
|
41
|
+
console.log(colors.infoMessage('\nUntracked files:'))
|
|
42
|
+
statusResult.untracked.forEach((file) => {
|
|
43
|
+
console.log(colors.dim(` ✨ ?? ${file.path}`))
|
|
44
|
+
})
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
return statusResult
|
|
47
|
+
return statusResult
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Interactive file selection for staging
|
|
51
52
|
*/
|
|
52
53
|
async selectFilesToStage(files = null) {
|
|
53
|
-
const { multiselect, confirm } = await import('@clack/prompts')
|
|
54
|
+
const { multiselect, confirm } = await import('@clack/prompts')
|
|
54
55
|
|
|
55
56
|
// Get current status if files not provided
|
|
56
57
|
if (!files) {
|
|
57
|
-
const status = this.getDetailedStatus()
|
|
58
|
-
files = [...status.unstaged, ...status.untracked]
|
|
58
|
+
const status = this.getDetailedStatus()
|
|
59
|
+
files = [...status.unstaged, ...status.untracked]
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
if (files.length === 0) {
|
|
62
|
-
console.log(colors.infoMessage('No files available for staging.'))
|
|
63
|
-
return []
|
|
63
|
+
console.log(colors.infoMessage('No files available for staging.'))
|
|
64
|
+
return []
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
// Create choices for the multiselect prompt
|
|
67
|
-
const choices = files.map(file => ({
|
|
68
|
+
const choices = files.map((file) => ({
|
|
68
69
|
value: file.path,
|
|
69
70
|
label: `${this.getStatusIcon(file.status)} ${file.status} ${file.path}`,
|
|
70
|
-
hint: this.getStatusDescription(file.status)
|
|
71
|
-
}))
|
|
71
|
+
hint: this.getStatusDescription(file.status),
|
|
72
|
+
}))
|
|
72
73
|
|
|
73
74
|
try {
|
|
74
75
|
const selectedFiles = await multiselect({
|
|
75
76
|
message: 'Select files to stage for commit:',
|
|
76
77
|
options: choices,
|
|
77
|
-
required: false
|
|
78
|
-
})
|
|
78
|
+
required: false,
|
|
79
|
+
})
|
|
79
80
|
|
|
80
81
|
if (!selectedFiles || selectedFiles.length === 0) {
|
|
81
|
-
console.log(colors.infoMessage('No files selected for staging.'))
|
|
82
|
-
return []
|
|
82
|
+
console.log(colors.infoMessage('No files selected for staging.'))
|
|
83
|
+
return []
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
// Confirm the selection
|
|
86
87
|
const shouldStage = await confirm({
|
|
87
88
|
message: `Stage ${selectedFiles.length} file(s)?`,
|
|
88
|
-
initialValue: true
|
|
89
|
-
})
|
|
89
|
+
initialValue: true,
|
|
90
|
+
})
|
|
90
91
|
|
|
91
92
|
if (shouldStage) {
|
|
92
|
-
await this.stageFiles(selectedFiles)
|
|
93
|
-
console.log(colors.successMessage(`✅ Staged ${selectedFiles.length} file(s)`))
|
|
94
|
-
return selectedFiles
|
|
95
|
-
} else {
|
|
96
|
-
console.log(colors.infoMessage('Staging cancelled.'));
|
|
97
|
-
return [];
|
|
93
|
+
await this.stageFiles(selectedFiles)
|
|
94
|
+
console.log(colors.successMessage(`✅ Staged ${selectedFiles.length} file(s)`))
|
|
95
|
+
return selectedFiles
|
|
98
96
|
}
|
|
97
|
+
console.log(colors.infoMessage('Staging cancelled.'))
|
|
98
|
+
return []
|
|
99
99
|
} catch (error) {
|
|
100
100
|
if (error.message.includes('cancelled')) {
|
|
101
|
-
console.log(colors.infoMessage('File selection cancelled.'))
|
|
101
|
+
console.log(colors.infoMessage('File selection cancelled.'))
|
|
102
102
|
} else {
|
|
103
|
-
console.error(colors.errorMessage(`Error during file selection: ${error.message}`))
|
|
103
|
+
console.error(colors.errorMessage(`Error during file selection: ${error.message}`))
|
|
104
104
|
}
|
|
105
|
-
return []
|
|
105
|
+
return []
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -110,54 +110,53 @@ export class InteractiveStagingService {
|
|
|
110
110
|
* Interactive unstaging of files
|
|
111
111
|
*/
|
|
112
112
|
async selectFilesToUnstage() {
|
|
113
|
-
const { multiselect, confirm } = await import('@clack/prompts')
|
|
113
|
+
const { multiselect, confirm } = await import('@clack/prompts')
|
|
114
114
|
|
|
115
|
-
const status = this.getDetailedStatus()
|
|
116
|
-
const stagedFiles = status.staged
|
|
115
|
+
const status = this.getDetailedStatus()
|
|
116
|
+
const stagedFiles = status.staged
|
|
117
117
|
|
|
118
118
|
if (stagedFiles.length === 0) {
|
|
119
|
-
console.log(colors.infoMessage('No staged files to unstage.'))
|
|
120
|
-
return []
|
|
119
|
+
console.log(colors.infoMessage('No staged files to unstage.'))
|
|
120
|
+
return []
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const choices = stagedFiles.map(file => ({
|
|
123
|
+
const choices = stagedFiles.map((file) => ({
|
|
124
124
|
value: file.path,
|
|
125
125
|
label: `${this.getStatusIcon(file.status)} ${file.status} ${file.path}`,
|
|
126
|
-
hint: 'Remove from staging area'
|
|
127
|
-
}))
|
|
126
|
+
hint: 'Remove from staging area',
|
|
127
|
+
}))
|
|
128
128
|
|
|
129
129
|
try {
|
|
130
130
|
const selectedFiles = await multiselect({
|
|
131
131
|
message: 'Select files to unstage:',
|
|
132
132
|
options: choices,
|
|
133
|
-
required: false
|
|
134
|
-
})
|
|
133
|
+
required: false,
|
|
134
|
+
})
|
|
135
135
|
|
|
136
136
|
if (!selectedFiles || selectedFiles.length === 0) {
|
|
137
|
-
console.log(colors.infoMessage('No files selected for unstaging.'))
|
|
138
|
-
return []
|
|
137
|
+
console.log(colors.infoMessage('No files selected for unstaging.'))
|
|
138
|
+
return []
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
const shouldUnstage = await confirm({
|
|
142
142
|
message: `Unstage ${selectedFiles.length} file(s)?`,
|
|
143
|
-
initialValue: true
|
|
144
|
-
})
|
|
143
|
+
initialValue: true,
|
|
144
|
+
})
|
|
145
145
|
|
|
146
146
|
if (shouldUnstage) {
|
|
147
|
-
await this.unstageFiles(selectedFiles)
|
|
148
|
-
console.log(colors.successMessage(`✅ Unstaged ${selectedFiles.length} file(s)`))
|
|
149
|
-
return selectedFiles
|
|
150
|
-
} else {
|
|
151
|
-
console.log(colors.infoMessage('Unstaging cancelled.'));
|
|
152
|
-
return [];
|
|
147
|
+
await this.unstageFiles(selectedFiles)
|
|
148
|
+
console.log(colors.successMessage(`✅ Unstaged ${selectedFiles.length} file(s)`))
|
|
149
|
+
return selectedFiles
|
|
153
150
|
}
|
|
151
|
+
console.log(colors.infoMessage('Unstaging cancelled.'))
|
|
152
|
+
return []
|
|
154
153
|
} catch (error) {
|
|
155
154
|
if (error.message.includes('cancelled')) {
|
|
156
|
-
console.log(colors.infoMessage('File unstaging cancelled.'))
|
|
155
|
+
console.log(colors.infoMessage('File unstaging cancelled.'))
|
|
157
156
|
} else {
|
|
158
|
-
console.error(colors.errorMessage(`Error during file unstaging: ${error.message}`))
|
|
157
|
+
console.error(colors.errorMessage(`Error during file unstaging: ${error.message}`))
|
|
159
158
|
}
|
|
160
|
-
return []
|
|
159
|
+
return []
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
162
|
|
|
@@ -166,13 +165,13 @@ export class InteractiveStagingService {
|
|
|
166
165
|
*/
|
|
167
166
|
async stageAllChanges() {
|
|
168
167
|
try {
|
|
169
|
-
console.log(colors.processingMessage('Staging all changes...'))
|
|
170
|
-
execSync('git add .', { stdio: 'pipe' })
|
|
171
|
-
console.log(colors.successMessage('✅ All changes staged'))
|
|
172
|
-
return true
|
|
168
|
+
console.log(colors.processingMessage('Staging all changes...'))
|
|
169
|
+
execSync('git add .', { stdio: 'pipe' })
|
|
170
|
+
console.log(colors.successMessage('✅ All changes staged'))
|
|
171
|
+
return true
|
|
173
172
|
} catch (error) {
|
|
174
|
-
console.error(colors.errorMessage(`Error staging all changes: ${error.message}`))
|
|
175
|
-
return false
|
|
173
|
+
console.error(colors.errorMessage(`Error staging all changes: ${error.message}`))
|
|
174
|
+
return false
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
177
|
|
|
@@ -181,16 +180,25 @@ export class InteractiveStagingService {
|
|
|
181
180
|
*/
|
|
182
181
|
async stageFiles(filePaths) {
|
|
183
182
|
try {
|
|
184
|
-
const files = Array.isArray(filePaths) ? filePaths : [filePaths]
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
const files = Array.isArray(filePaths) ? filePaths : [filePaths]
|
|
184
|
+
|
|
185
|
+
// Use spawn with argument array to avoid command injection
|
|
186
|
+
if (files.length > 0) {
|
|
187
|
+
const { spawnSync } = await import('node:child_process')
|
|
188
|
+
const result = spawnSync('git', ['add', ...files], {
|
|
189
|
+
stdio: 'pipe',
|
|
190
|
+
encoding: 'utf8',
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
if (result.status !== 0) {
|
|
194
|
+
throw new Error(`git add failed: ${result.stderr}`)
|
|
195
|
+
}
|
|
188
196
|
}
|
|
189
|
-
|
|
190
|
-
return true
|
|
197
|
+
|
|
198
|
+
return true
|
|
191
199
|
} catch (error) {
|
|
192
|
-
console.error(colors.errorMessage(`Error staging files: ${error.message}`))
|
|
193
|
-
return false
|
|
200
|
+
console.error(colors.errorMessage(`Error staging files: ${error.message}`))
|
|
201
|
+
return false
|
|
194
202
|
}
|
|
195
203
|
}
|
|
196
204
|
|
|
@@ -199,16 +207,25 @@ export class InteractiveStagingService {
|
|
|
199
207
|
*/
|
|
200
208
|
async unstageFiles(filePaths) {
|
|
201
209
|
try {
|
|
202
|
-
const files = Array.isArray(filePaths) ? filePaths : [filePaths]
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
210
|
+
const files = Array.isArray(filePaths) ? filePaths : [filePaths]
|
|
211
|
+
|
|
212
|
+
// Use spawn with argument array to avoid command injection
|
|
213
|
+
if (files.length > 0) {
|
|
214
|
+
const { spawnSync } = await import('node:child_process')
|
|
215
|
+
const result = spawnSync('git', ['reset', 'HEAD', ...files], {
|
|
216
|
+
stdio: 'pipe',
|
|
217
|
+
encoding: 'utf8',
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
if (result.status !== 0) {
|
|
221
|
+
throw new Error(`git reset failed: ${result.stderr}`)
|
|
222
|
+
}
|
|
206
223
|
}
|
|
207
|
-
|
|
208
|
-
return true
|
|
224
|
+
|
|
225
|
+
return true
|
|
209
226
|
} catch (error) {
|
|
210
|
-
console.error(colors.errorMessage(`Error unstaging files: ${error.message}`))
|
|
211
|
-
return false
|
|
227
|
+
console.error(colors.errorMessage(`Error unstaging files: ${error.message}`))
|
|
228
|
+
return false
|
|
212
229
|
}
|
|
213
230
|
}
|
|
214
231
|
|
|
@@ -217,41 +234,43 @@ export class InteractiveStagingService {
|
|
|
217
234
|
*/
|
|
218
235
|
getDetailedStatus() {
|
|
219
236
|
try {
|
|
220
|
-
const output = execSync('git status --porcelain', { encoding: 'utf8' })
|
|
221
|
-
const lines = output.split('\n').filter(Boolean)
|
|
237
|
+
const output = execSync('git status --porcelain', { encoding: 'utf8' })
|
|
238
|
+
const lines = output.split('\n').filter(Boolean)
|
|
222
239
|
|
|
223
|
-
const staged = []
|
|
224
|
-
const unstaged = []
|
|
225
|
-
const untracked = []
|
|
240
|
+
const staged = []
|
|
241
|
+
const unstaged = []
|
|
242
|
+
const untracked = []
|
|
226
243
|
|
|
227
|
-
lines.forEach(line => {
|
|
228
|
-
if (line.length < 3)
|
|
244
|
+
lines.forEach((line) => {
|
|
245
|
+
if (line.length < 3) {
|
|
246
|
+
return
|
|
247
|
+
}
|
|
229
248
|
|
|
230
|
-
const indexStatus = line.charAt(0)
|
|
231
|
-
const workTreeStatus = line.charAt(1)
|
|
232
|
-
const filePath = line.substring(3).trim()
|
|
249
|
+
const indexStatus = line.charAt(0)
|
|
250
|
+
const workTreeStatus = line.charAt(1)
|
|
251
|
+
const filePath = line.substring(3).trim()
|
|
233
252
|
|
|
234
253
|
// Handle different status combinations
|
|
235
254
|
if (indexStatus === '?' && workTreeStatus === '?') {
|
|
236
255
|
// Untracked file
|
|
237
|
-
untracked.push({ status: '??', path: filePath })
|
|
256
|
+
untracked.push({ status: '??', path: filePath })
|
|
238
257
|
} else {
|
|
239
258
|
// Staged changes (index status)
|
|
240
259
|
if (indexStatus !== ' ') {
|
|
241
|
-
staged.push({ status: indexStatus, path: filePath })
|
|
260
|
+
staged.push({ status: indexStatus, path: filePath })
|
|
242
261
|
}
|
|
243
|
-
|
|
262
|
+
|
|
244
263
|
// Unstaged changes (work tree status)
|
|
245
264
|
if (workTreeStatus !== ' ') {
|
|
246
|
-
unstaged.push({ status: workTreeStatus, path: filePath })
|
|
265
|
+
unstaged.push({ status: workTreeStatus, path: filePath })
|
|
247
266
|
}
|
|
248
267
|
}
|
|
249
|
-
})
|
|
268
|
+
})
|
|
250
269
|
|
|
251
|
-
return { staged, unstaged, untracked }
|
|
270
|
+
return { staged, unstaged, untracked }
|
|
252
271
|
} catch (error) {
|
|
253
|
-
console.error(colors.errorMessage(`Error getting git status: ${error.message}`))
|
|
254
|
-
return { staged: [], unstaged: [], untracked: [] }
|
|
272
|
+
console.error(colors.errorMessage(`Error getting git status: ${error.message}`))
|
|
273
|
+
return { staged: [], unstaged: [], untracked: [] }
|
|
255
274
|
}
|
|
256
275
|
}
|
|
257
276
|
|
|
@@ -260,15 +279,15 @@ export class InteractiveStagingService {
|
|
|
260
279
|
*/
|
|
261
280
|
getStatusIcon(status) {
|
|
262
281
|
const icons = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
'??': '✨' // Untracked
|
|
270
|
-
}
|
|
271
|
-
return icons[status] || '📄'
|
|
282
|
+
M: '📝', // Modified
|
|
283
|
+
A: '✨', // Added
|
|
284
|
+
D: '🗑️', // Deleted
|
|
285
|
+
R: '🔄', // Renamed
|
|
286
|
+
C: '📋', // Copied
|
|
287
|
+
U: '⚠️', // Unmerged
|
|
288
|
+
'??': '✨', // Untracked
|
|
289
|
+
}
|
|
290
|
+
return icons[status] || '📄'
|
|
272
291
|
}
|
|
273
292
|
|
|
274
293
|
/**
|
|
@@ -276,15 +295,15 @@ export class InteractiveStagingService {
|
|
|
276
295
|
*/
|
|
277
296
|
getStatusDescription(status) {
|
|
278
297
|
const descriptions = {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
'??': 'Untracked file'
|
|
286
|
-
}
|
|
287
|
-
return descriptions[status] || 'Changed file'
|
|
298
|
+
M: 'Modified file',
|
|
299
|
+
A: 'New file',
|
|
300
|
+
D: 'Deleted file',
|
|
301
|
+
R: 'Renamed file',
|
|
302
|
+
C: 'Copied file',
|
|
303
|
+
U: 'Unmerged file',
|
|
304
|
+
'??': 'Untracked file',
|
|
305
|
+
}
|
|
306
|
+
return descriptions[status] || 'Changed file'
|
|
288
307
|
}
|
|
289
308
|
|
|
290
309
|
/**
|
|
@@ -292,10 +311,10 @@ export class InteractiveStagingService {
|
|
|
292
311
|
*/
|
|
293
312
|
hasStagedChanges() {
|
|
294
313
|
try {
|
|
295
|
-
const output = execSync('git diff --cached --name-only', { encoding: 'utf8' })
|
|
296
|
-
return output.trim().length > 0
|
|
297
|
-
} catch (
|
|
298
|
-
return false
|
|
314
|
+
const output = execSync('git diff --cached --name-only', { encoding: 'utf8' })
|
|
315
|
+
return output.trim().length > 0
|
|
316
|
+
} catch (_error) {
|
|
317
|
+
return false
|
|
299
318
|
}
|
|
300
319
|
}
|
|
301
320
|
|
|
@@ -304,10 +323,10 @@ export class InteractiveStagingService {
|
|
|
304
323
|
*/
|
|
305
324
|
hasUnstagedChanges() {
|
|
306
325
|
try {
|
|
307
|
-
const output = execSync('git diff --name-only', { encoding: 'utf8' })
|
|
308
|
-
return output.trim().length > 0
|
|
309
|
-
} catch (
|
|
310
|
-
return false
|
|
326
|
+
const output = execSync('git diff --name-only', { encoding: 'utf8' })
|
|
327
|
+
return output.trim().length > 0
|
|
328
|
+
} catch (_error) {
|
|
329
|
+
return false
|
|
311
330
|
}
|
|
312
331
|
}
|
|
313
|
-
}
|
|
332
|
+
}
|