vibecodingmachine-core 2026.3.9-907 → 2026.3.10-1547
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/package.json +1 -1
- package/src/auth/access-denied.html +119 -119
- package/src/auth/shared-auth-storage.js +267 -267
- package/src/autonomous-mode/feature-implementer.cjs +70 -70
- package/src/autonomous-mode/feature-implementer.js +425 -425
- package/src/beta-request.js +160 -160
- package/src/chat-management/chat-manager.cjs +71 -71
- package/src/chat-management/chat-manager.js +342 -342
- package/src/compliance/compliance-prompt.js +183 -183
- package/src/ide-integration/aider-cli-manager.cjs +850 -850
- package/src/ide-integration/applescript-manager.cjs +3215 -3215
- package/src/ide-integration/applescript-utils.js +314 -314
- package/src/ide-integration/cdp-manager.cjs +221 -221
- package/src/ide-integration/claude-code-cli-manager.cjs +456 -456
- package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
- package/src/ide-integration/continue-cli-manager.js +431 -431
- package/src/ide-integration/provider-manager.cjs +595 -595
- package/src/ide-integration/quota-detector.cjs +399 -399
- package/src/ide-integration/windows-automation-manager.js +532 -4
- package/src/ide-integration/windows-ide-manager.js +12 -3
- package/src/index.cjs +142 -142
- package/src/llm/direct-llm-manager.cjs +1299 -1299
- package/src/localization/index.js +147 -147
- package/src/quota-management/index.js +108 -108
- package/src/requirement-numbering.js +164 -164
- package/src/sync/aws-setup.js +445 -445
- package/src/ui/ButtonComponents.js +247 -247
- package/src/ui/ChatInterface.js +499 -499
- package/src/ui/StateManager.js +259 -259
- package/src/utils/audit-logger.cjs +116 -116
- package/src/utils/config-helpers.cjs +94 -94
- package/src/utils/config-helpers.js +94 -94
- package/src/utils/env-helpers.js +54 -54
- package/src/utils/error-reporter.js +117 -117
- package/src/utils/gcloud-auth.cjs +394 -394
- package/src/utils/git-branch-manager.js +278 -278
- package/src/utils/logger.cjs +193 -193
- package/src/utils/logger.js +191 -191
- package/src/utils/repo-helpers.cjs +120 -120
- package/src/utils/repo-helpers.js +120 -120
- package/src/utils/update-checker.js +246 -246
- package/src/utils/version-checker.js +170 -170
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { createBranchName, extractRequirementNumber } = require('../requirement-numbering');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Check if a directory is a git repository
|
|
7
|
-
* @param {string} repoPath - Path to check
|
|
8
|
-
* @returns {boolean} True if it's a git repo
|
|
9
|
-
*/
|
|
10
|
-
function isGitRepo(repoPath) {
|
|
11
|
-
try {
|
|
12
|
-
execSync('git rev-parse --git-dir', {
|
|
13
|
-
cwd: repoPath,
|
|
14
|
-
stdio: 'ignore'
|
|
15
|
-
});
|
|
16
|
-
return true;
|
|
17
|
-
} catch (error) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get current git branch name
|
|
24
|
-
* @param {string} repoPath - Path to repository
|
|
25
|
-
* @returns {string|null} Current branch name or null
|
|
26
|
-
*/
|
|
27
|
-
function getCurrentBranch(repoPath) {
|
|
28
|
-
try {
|
|
29
|
-
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
30
|
-
cwd: repoPath,
|
|
31
|
-
encoding: 'utf8'
|
|
32
|
-
}).trim();
|
|
33
|
-
return branch;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Create a feature branch for a requirement
|
|
41
|
-
* @param {string} repoPath - Path to repository
|
|
42
|
-
* @param {string} requirementTitle - Full requirement title (e.g., "R1: Email System")
|
|
43
|
-
* @returns {Promise<{success: boolean, branchName: string|null, parentBranch: string|null, error: string|null}>}
|
|
44
|
-
*/
|
|
45
|
-
async function createRequirementBranch(repoPath, requirementTitle) {
|
|
46
|
-
try {
|
|
47
|
-
if (!isGitRepo(repoPath)) {
|
|
48
|
-
return {
|
|
49
|
-
success: false,
|
|
50
|
-
branchName: null,
|
|
51
|
-
parentBranch: null,
|
|
52
|
-
error: 'Not a git repository'
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Extract requirement number from title
|
|
57
|
-
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
58
|
-
if (!reqNumber) {
|
|
59
|
-
return {
|
|
60
|
-
success: false,
|
|
61
|
-
branchName: null,
|
|
62
|
-
parentBranch: null,
|
|
63
|
-
error: 'Requirement number not found in title'
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Get parent branch (current branch before creating new one)
|
|
68
|
-
const parentBranch = getCurrentBranch(repoPath);
|
|
69
|
-
if (!parentBranch) {
|
|
70
|
-
return {
|
|
71
|
-
success: false,
|
|
72
|
-
branchName: null,
|
|
73
|
-
parentBranch: null,
|
|
74
|
-
error: 'Could not determine current branch'
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Create branch name
|
|
79
|
-
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
80
|
-
|
|
81
|
-
// Check if branch already exists
|
|
82
|
-
try {
|
|
83
|
-
execSync(`git rev-parse --verify ${branchName}`, {
|
|
84
|
-
cwd: repoPath,
|
|
85
|
-
stdio: 'ignore'
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Branch exists, check it out
|
|
89
|
-
execSync(`git checkout ${branchName}`, {
|
|
90
|
-
cwd: repoPath,
|
|
91
|
-
stdio: 'ignore'
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
success: true,
|
|
96
|
-
branchName,
|
|
97
|
-
parentBranch,
|
|
98
|
-
error: null,
|
|
99
|
-
alreadyExists: true
|
|
100
|
-
};
|
|
101
|
-
} catch (error) {
|
|
102
|
-
// Branch doesn't exist, create it
|
|
103
|
-
execSync(`git checkout -b ${branchName}`, {
|
|
104
|
-
cwd: repoPath,
|
|
105
|
-
stdio: 'ignore'
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
success: true,
|
|
110
|
-
branchName,
|
|
111
|
-
parentBranch,
|
|
112
|
-
error: null,
|
|
113
|
-
alreadyExists: false
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
} catch (error) {
|
|
117
|
-
return {
|
|
118
|
-
success: false,
|
|
119
|
-
branchName: null,
|
|
120
|
-
parentBranch: null,
|
|
121
|
-
error: error.message
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Merge a requirement branch back to parent and delete it
|
|
128
|
-
* @param {string} repoPath - Path to repository
|
|
129
|
-
* @param {string} requirementTitle - Full requirement title
|
|
130
|
-
* @param {string} parentBranch - Parent branch to merge into
|
|
131
|
-
* @returns {Promise<{success: boolean, error: string|null}>}
|
|
132
|
-
*/
|
|
133
|
-
async function mergeRequirementBranch(repoPath, requirementTitle, parentBranch = 'main') {
|
|
134
|
-
try {
|
|
135
|
-
if (!isGitRepo(repoPath)) {
|
|
136
|
-
return { success: false, error: 'Not a git repository' };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Extract requirement number
|
|
140
|
-
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
141
|
-
if (!reqNumber) {
|
|
142
|
-
return { success: false, error: 'Requirement number not found in title' };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Create branch name
|
|
146
|
-
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
147
|
-
|
|
148
|
-
// Checkout parent branch
|
|
149
|
-
execSync(`git checkout ${parentBranch}`, {
|
|
150
|
-
cwd: repoPath,
|
|
151
|
-
stdio: 'ignore'
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Merge the feature branch
|
|
155
|
-
execSync(`git merge --no-ff ${branchName} -m "Merge ${branchName}"`, {
|
|
156
|
-
cwd: repoPath,
|
|
157
|
-
stdio: 'ignore'
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Delete the feature branch
|
|
161
|
-
execSync(`git branch -d ${branchName}`, {
|
|
162
|
-
cwd: repoPath,
|
|
163
|
-
stdio: 'ignore'
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
return { success: true, error: null };
|
|
167
|
-
} catch (error) {
|
|
168
|
-
return { success: false, error: error.message };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Remove a feature by reverting its merge commit
|
|
174
|
-
* @param {string} repoPath - Path to repository
|
|
175
|
-
* @param {string} requirementTitle - Full requirement title
|
|
176
|
-
* @returns {Promise<{success: boolean, error: string|null}>}
|
|
177
|
-
*/
|
|
178
|
-
async function removeRequirementFeature(repoPath, requirementTitle) {
|
|
179
|
-
try {
|
|
180
|
-
if (!isGitRepo(repoPath)) {
|
|
181
|
-
return { success: false, error: 'Not a git repository' };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Extract requirement number
|
|
185
|
-
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
186
|
-
if (!reqNumber) {
|
|
187
|
-
return { success: false, error: 'Requirement number not found in title' };
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Create branch name to search for
|
|
191
|
-
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
192
|
-
|
|
193
|
-
// Find the merge commit for this branch
|
|
194
|
-
const mergeCommit = execSync(
|
|
195
|
-
`git log --grep="Merge ${branchName}" --oneline --format="%H" -1`,
|
|
196
|
-
{
|
|
197
|
-
cwd: repoPath,
|
|
198
|
-
encoding: 'utf8'
|
|
199
|
-
}
|
|
200
|
-
).trim();
|
|
201
|
-
|
|
202
|
-
if (!mergeCommit) {
|
|
203
|
-
return { success: false, error: 'Merge commit not found for this requirement' };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Revert the merge commit
|
|
207
|
-
execSync(`git revert -m 1 ${mergeCommit} --no-edit`, {
|
|
208
|
-
cwd: repoPath,
|
|
209
|
-
stdio: 'ignore'
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
return { success: true, error: null };
|
|
213
|
-
} catch (error) {
|
|
214
|
-
return { success: false, error: error.message };
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Get list of all requirement branches
|
|
220
|
-
* @param {string} repoPath - Path to repository
|
|
221
|
-
* @returns {Array<{branchName: string, reqNumber: number}>}
|
|
222
|
-
*/
|
|
223
|
-
function listRequirementBranches(repoPath) {
|
|
224
|
-
try {
|
|
225
|
-
if (!isGitRepo(repoPath)) {
|
|
226
|
-
return [];
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const branches = execSync('git branch --list "R*"', {
|
|
230
|
-
cwd: repoPath,
|
|
231
|
-
encoding: 'utf8'
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
return branches
|
|
235
|
-
.split('\n')
|
|
236
|
-
.map(b => b.trim().replace(/^\*\s*/, ''))
|
|
237
|
-
.filter(b => b && b.startsWith('R'))
|
|
238
|
-
.map(b => {
|
|
239
|
-
const match = b.match(/^R(\d+)/);
|
|
240
|
-
return {
|
|
241
|
-
branchName: b,
|
|
242
|
-
reqNumber: match ? parseInt(match[1], 10) : 0
|
|
243
|
-
};
|
|
244
|
-
})
|
|
245
|
-
.filter(b => b.reqNumber > 0)
|
|
246
|
-
.sort((a, b) => a.reqNumber - b.reqNumber);
|
|
247
|
-
} catch (error) {
|
|
248
|
-
return [];
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Check if there are any uncommitted changes in the repository
|
|
254
|
-
* @param {string} repoPath - Path to repository
|
|
255
|
-
* @returns {boolean} True if there are uncommitted changes
|
|
256
|
-
*/
|
|
257
|
-
function hasUncommittedChanges(repoPath) {
|
|
258
|
-
try {
|
|
259
|
-
// Check for staged and unstaged changes
|
|
260
|
-
const status = execSync('git status --porcelain', {
|
|
261
|
-
cwd: repoPath,
|
|
262
|
-
encoding: 'utf8'
|
|
263
|
-
}).trim();
|
|
264
|
-
return status.length > 0;
|
|
265
|
-
} catch (error) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
module.exports = {
|
|
271
|
-
isGitRepo,
|
|
272
|
-
getCurrentBranch,
|
|
273
|
-
hasUncommittedChanges,
|
|
274
|
-
createRequirementBranch,
|
|
275
|
-
mergeRequirementBranch,
|
|
276
|
-
removeRequirementFeature,
|
|
277
|
-
listRequirementBranches
|
|
278
|
-
};
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { createBranchName, extractRequirementNumber } = require('../requirement-numbering');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if a directory is a git repository
|
|
7
|
+
* @param {string} repoPath - Path to check
|
|
8
|
+
* @returns {boolean} True if it's a git repo
|
|
9
|
+
*/
|
|
10
|
+
function isGitRepo(repoPath) {
|
|
11
|
+
try {
|
|
12
|
+
execSync('git rev-parse --git-dir', {
|
|
13
|
+
cwd: repoPath,
|
|
14
|
+
stdio: 'ignore'
|
|
15
|
+
});
|
|
16
|
+
return true;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get current git branch name
|
|
24
|
+
* @param {string} repoPath - Path to repository
|
|
25
|
+
* @returns {string|null} Current branch name or null
|
|
26
|
+
*/
|
|
27
|
+
function getCurrentBranch(repoPath) {
|
|
28
|
+
try {
|
|
29
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
30
|
+
cwd: repoPath,
|
|
31
|
+
encoding: 'utf8'
|
|
32
|
+
}).trim();
|
|
33
|
+
return branch;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a feature branch for a requirement
|
|
41
|
+
* @param {string} repoPath - Path to repository
|
|
42
|
+
* @param {string} requirementTitle - Full requirement title (e.g., "R1: Email System")
|
|
43
|
+
* @returns {Promise<{success: boolean, branchName: string|null, parentBranch: string|null, error: string|null}>}
|
|
44
|
+
*/
|
|
45
|
+
async function createRequirementBranch(repoPath, requirementTitle) {
|
|
46
|
+
try {
|
|
47
|
+
if (!isGitRepo(repoPath)) {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
branchName: null,
|
|
51
|
+
parentBranch: null,
|
|
52
|
+
error: 'Not a git repository'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Extract requirement number from title
|
|
57
|
+
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
58
|
+
if (!reqNumber) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
branchName: null,
|
|
62
|
+
parentBranch: null,
|
|
63
|
+
error: 'Requirement number not found in title'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Get parent branch (current branch before creating new one)
|
|
68
|
+
const parentBranch = getCurrentBranch(repoPath);
|
|
69
|
+
if (!parentBranch) {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
branchName: null,
|
|
73
|
+
parentBranch: null,
|
|
74
|
+
error: 'Could not determine current branch'
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create branch name
|
|
79
|
+
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
80
|
+
|
|
81
|
+
// Check if branch already exists
|
|
82
|
+
try {
|
|
83
|
+
execSync(`git rev-parse --verify ${branchName}`, {
|
|
84
|
+
cwd: repoPath,
|
|
85
|
+
stdio: 'ignore'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Branch exists, check it out
|
|
89
|
+
execSync(`git checkout ${branchName}`, {
|
|
90
|
+
cwd: repoPath,
|
|
91
|
+
stdio: 'ignore'
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
branchName,
|
|
97
|
+
parentBranch,
|
|
98
|
+
error: null,
|
|
99
|
+
alreadyExists: true
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
// Branch doesn't exist, create it
|
|
103
|
+
execSync(`git checkout -b ${branchName}`, {
|
|
104
|
+
cwd: repoPath,
|
|
105
|
+
stdio: 'ignore'
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
branchName,
|
|
111
|
+
parentBranch,
|
|
112
|
+
error: null,
|
|
113
|
+
alreadyExists: false
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
branchName: null,
|
|
120
|
+
parentBranch: null,
|
|
121
|
+
error: error.message
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Merge a requirement branch back to parent and delete it
|
|
128
|
+
* @param {string} repoPath - Path to repository
|
|
129
|
+
* @param {string} requirementTitle - Full requirement title
|
|
130
|
+
* @param {string} parentBranch - Parent branch to merge into
|
|
131
|
+
* @returns {Promise<{success: boolean, error: string|null}>}
|
|
132
|
+
*/
|
|
133
|
+
async function mergeRequirementBranch(repoPath, requirementTitle, parentBranch = 'main') {
|
|
134
|
+
try {
|
|
135
|
+
if (!isGitRepo(repoPath)) {
|
|
136
|
+
return { success: false, error: 'Not a git repository' };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Extract requirement number
|
|
140
|
+
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
141
|
+
if (!reqNumber) {
|
|
142
|
+
return { success: false, error: 'Requirement number not found in title' };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Create branch name
|
|
146
|
+
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
147
|
+
|
|
148
|
+
// Checkout parent branch
|
|
149
|
+
execSync(`git checkout ${parentBranch}`, {
|
|
150
|
+
cwd: repoPath,
|
|
151
|
+
stdio: 'ignore'
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Merge the feature branch
|
|
155
|
+
execSync(`git merge --no-ff ${branchName} -m "Merge ${branchName}"`, {
|
|
156
|
+
cwd: repoPath,
|
|
157
|
+
stdio: 'ignore'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Delete the feature branch
|
|
161
|
+
execSync(`git branch -d ${branchName}`, {
|
|
162
|
+
cwd: repoPath,
|
|
163
|
+
stdio: 'ignore'
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return { success: true, error: null };
|
|
167
|
+
} catch (error) {
|
|
168
|
+
return { success: false, error: error.message };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Remove a feature by reverting its merge commit
|
|
174
|
+
* @param {string} repoPath - Path to repository
|
|
175
|
+
* @param {string} requirementTitle - Full requirement title
|
|
176
|
+
* @returns {Promise<{success: boolean, error: string|null}>}
|
|
177
|
+
*/
|
|
178
|
+
async function removeRequirementFeature(repoPath, requirementTitle) {
|
|
179
|
+
try {
|
|
180
|
+
if (!isGitRepo(repoPath)) {
|
|
181
|
+
return { success: false, error: 'Not a git repository' };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Extract requirement number
|
|
185
|
+
const reqNumber = extractRequirementNumber(requirementTitle);
|
|
186
|
+
if (!reqNumber) {
|
|
187
|
+
return { success: false, error: 'Requirement number not found in title' };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Create branch name to search for
|
|
191
|
+
const branchName = createBranchName(reqNumber, requirementTitle);
|
|
192
|
+
|
|
193
|
+
// Find the merge commit for this branch
|
|
194
|
+
const mergeCommit = execSync(
|
|
195
|
+
`git log --grep="Merge ${branchName}" --oneline --format="%H" -1`,
|
|
196
|
+
{
|
|
197
|
+
cwd: repoPath,
|
|
198
|
+
encoding: 'utf8'
|
|
199
|
+
}
|
|
200
|
+
).trim();
|
|
201
|
+
|
|
202
|
+
if (!mergeCommit) {
|
|
203
|
+
return { success: false, error: 'Merge commit not found for this requirement' };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Revert the merge commit
|
|
207
|
+
execSync(`git revert -m 1 ${mergeCommit} --no-edit`, {
|
|
208
|
+
cwd: repoPath,
|
|
209
|
+
stdio: 'ignore'
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return { success: true, error: null };
|
|
213
|
+
} catch (error) {
|
|
214
|
+
return { success: false, error: error.message };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get list of all requirement branches
|
|
220
|
+
* @param {string} repoPath - Path to repository
|
|
221
|
+
* @returns {Array<{branchName: string, reqNumber: number}>}
|
|
222
|
+
*/
|
|
223
|
+
function listRequirementBranches(repoPath) {
|
|
224
|
+
try {
|
|
225
|
+
if (!isGitRepo(repoPath)) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const branches = execSync('git branch --list "R*"', {
|
|
230
|
+
cwd: repoPath,
|
|
231
|
+
encoding: 'utf8'
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return branches
|
|
235
|
+
.split('\n')
|
|
236
|
+
.map(b => b.trim().replace(/^\*\s*/, ''))
|
|
237
|
+
.filter(b => b && b.startsWith('R'))
|
|
238
|
+
.map(b => {
|
|
239
|
+
const match = b.match(/^R(\d+)/);
|
|
240
|
+
return {
|
|
241
|
+
branchName: b,
|
|
242
|
+
reqNumber: match ? parseInt(match[1], 10) : 0
|
|
243
|
+
};
|
|
244
|
+
})
|
|
245
|
+
.filter(b => b.reqNumber > 0)
|
|
246
|
+
.sort((a, b) => a.reqNumber - b.reqNumber);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check if there are any uncommitted changes in the repository
|
|
254
|
+
* @param {string} repoPath - Path to repository
|
|
255
|
+
* @returns {boolean} True if there are uncommitted changes
|
|
256
|
+
*/
|
|
257
|
+
function hasUncommittedChanges(repoPath) {
|
|
258
|
+
try {
|
|
259
|
+
// Check for staged and unstaged changes
|
|
260
|
+
const status = execSync('git status --porcelain', {
|
|
261
|
+
cwd: repoPath,
|
|
262
|
+
encoding: 'utf8'
|
|
263
|
+
}).trim();
|
|
264
|
+
return status.length > 0;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
module.exports = {
|
|
271
|
+
isGitRepo,
|
|
272
|
+
getCurrentBranch,
|
|
273
|
+
hasUncommittedChanges,
|
|
274
|
+
createRequirementBranch,
|
|
275
|
+
mergeRequirementBranch,
|
|
276
|
+
removeRequirementFeature,
|
|
277
|
+
listRequirementBranches
|
|
278
|
+
};
|