vibecodingmachine-cli 2026.2.20-438 → 2026.2.26-1739
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/bin/auth/auth-compliance.js +126 -0
- package/bin/cli-program.js +104 -0
- package/bin/cli-setup.js +52 -0
- package/bin/commands/agent-commands.js +310 -0
- package/bin/commands/auto-commands.js +70 -0
- package/bin/commands/command-aliases.js +118 -0
- package/bin/commands/repo-commands.js +39 -0
- package/bin/commands/rui-commands.js +152 -0
- package/bin/config/cli-config.js +394 -0
- package/bin/init/environment-setup.js +84 -0
- package/bin/update/update-checker.js +126 -0
- package/bin/vibecodingmachine-new.js +50 -0
- package/bin/vibecodingmachine.js +29 -663
- package/package.json +8 -2
- package/src/commands/agents/add.js +277 -0
- package/src/commands/agents/check.js +380 -0
- package/src/commands/agents/list.js +471 -0
- package/src/commands/agents/remove.js +351 -0
- package/src/commands/analyze-file-sizes.js +428 -0
- package/src/commands/auto-direct/code-processor.js +282 -0
- package/src/commands/auto-direct/file-scanner.js +266 -0
- package/src/commands/auto-direct/provider-config.js +178 -0
- package/src/commands/auto-direct/provider-manager.js +219 -0
- package/src/commands/auto-direct/requirement-manager.js +172 -0
- package/src/commands/auto-direct/status-display.js +91 -0
- package/src/commands/auto-direct/utils.js +106 -0
- package/src/commands/auto-direct.js +875 -488
- package/src/commands/auto-execution.js +342 -0
- package/src/commands/auto-provider-management.js +102 -0
- package/src/commands/auto-requirement-management.js +161 -0
- package/src/commands/auto-status-helpers.js +141 -0
- package/src/commands/auto.js +105 -5155
- package/src/commands/check-compliance.js +536 -0
- package/src/commands/continuous-scan.js +119 -0
- package/src/commands/ide.js +16 -4
- package/src/commands/refactor-file.js +486 -0
- package/src/commands/requirements.js +301 -2
- package/src/commands/timeout.js +290 -0
- package/src/trui/TruiInterface.js +108 -0
- package/src/trui/agents/AgentInterface.js +580 -0
- package/src/utils/antigravity-installer.js +60 -6
- package/src/utils/clarification-actions.js +290 -0
- package/src/utils/config.js +123 -2
- package/src/utils/first-run.js +5 -5
- package/src/utils/ide-handlers.js +212 -0
- package/src/utils/interactive/clarification-actions.js +348 -0
- package/src/utils/interactive/core-ui.js +265 -0
- package/src/utils/interactive/file-backup.js +237 -0
- package/src/utils/interactive/file-import-export.js +305 -0
- package/src/utils/interactive/file-operations.js +49 -0
- package/src/utils/interactive/file-validation.js +276 -0
- package/src/utils/interactive/interactive-prompts.js +480 -0
- package/src/utils/interactive/requirement-actions.js +127 -0
- package/src/utils/interactive/requirement-crud.js +356 -0
- package/src/utils/interactive/requirements-navigation.js +286 -0
- package/src/utils/interactive.js +390 -3459
- package/src/utils/provider-checker/agent-checker.js +250 -0
- package/src/utils/provider-checker/agent-runner.js +450 -0
- package/src/utils/provider-checker/cli-installer.js +123 -0
- package/src/utils/provider-checker/cli-utils.js +15 -0
- package/src/utils/provider-checker/format-utils.js +32 -0
- package/src/utils/provider-checker/ide-manager.js +72 -0
- package/src/utils/provider-checker/ide-utils.js +71 -0
- package/src/utils/provider-checker/node-detector.js +56 -0
- package/src/utils/provider-checker/node-utils.js +61 -0
- package/src/utils/provider-checker/process-spawn.js +22 -0
- package/src/utils/provider-checker/process-utils.js +37 -0
- package/src/utils/provider-checker/provider-validator.js +160 -0
- package/src/utils/provider-checker/quota-checker.js +54 -0
- package/src/utils/provider-checker/quota-detector.js +44 -0
- package/src/utils/provider-checker/requirements-manager.js +94 -0
- package/src/utils/provider-checker/test-requirements.js +95 -0
- package/src/utils/provider-checker/time-formatter.js +18 -0
- package/src/utils/provider-checker-new.js +14 -0
- package/src/utils/provider-checker.js +12 -407
- package/src/utils/provider-checkers/ide-manager.js +128 -0
- package/src/utils/provider-checkers/node-executable-finder.js +51 -0
- package/src/utils/provider-checkers/provider-checker-core.js +172 -0
- package/src/utils/provider-checkers/provider-checker-main.js +107 -0
- package/src/utils/provider-manager.js +60 -4
- package/src/utils/provider-registry.js +26 -3
- package/src/utils/provider-utils.js +173 -0
- package/src/utils/quota-detectors.js +212 -0
- package/src/utils/requirement-action-handlers.js +288 -0
- package/src/utils/requirement-actions/clarification-actions.js +229 -0
- package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
- package/src/utils/requirement-actions/file-operations.js +92 -0
- package/src/utils/requirement-actions/helpers.js +40 -0
- package/src/utils/requirement-actions/requirement-operations.js +335 -0
- package/src/utils/requirement-actions.js +46 -856
- package/src/utils/requirement-file-operations.js +259 -0
- package/src/utils/requirement-helpers.js +128 -0
- package/src/utils/requirement-management.js +279 -0
- package/src/utils/requirement-navigation.js +146 -0
- package/src/utils/requirement-organization.js +271 -0
- package/src/utils/simple-trui.js +75 -1
- package/src/utils/trui-navigation.js +28 -2
- package/src/utils/trui-req-tree.js +196 -11
- package/src/utils/trui-specifications.js +31 -1
- package/src/utils/interactive-backup.js +0 -5664
- package/src/utils/trui-provider-manager.js +0 -182
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Detectors Module
|
|
3
|
+
*
|
|
4
|
+
* Handles quota limit detection for various AI providers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check for quota limit indicators in process output and error messages
|
|
11
|
+
*/
|
|
12
|
+
function checkQuotaInOutput(providerId, output, errorMessage) {
|
|
13
|
+
const debugLog = (msg) => {
|
|
14
|
+
const timestamp = new Date().toISOString();
|
|
15
|
+
const logLine = `[${timestamp}] ${msg}\n`;
|
|
16
|
+
try {
|
|
17
|
+
fs.appendFileSync(`/tmp/vibe-${providerId}-quota-debug.log`, logLine);
|
|
18
|
+
} catch (_) {}
|
|
19
|
+
console.log(`[AGENT CHECK] ${msg}`);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
debugLog(`Checking for ${providerId} quota limit...`);
|
|
23
|
+
|
|
24
|
+
// Check process output first for quota error keywords
|
|
25
|
+
const lowerOutput = output.toLowerCase();
|
|
26
|
+
const lowerErrorMsg = errorMessage.toLowerCase();
|
|
27
|
+
debugLog('Checking process output length: ' + output.length);
|
|
28
|
+
debugLog('Process output sample: ' + output.substring(0, 300));
|
|
29
|
+
|
|
30
|
+
// Check both output and error message for quota keywords
|
|
31
|
+
const quotaKeywords = [
|
|
32
|
+
'quota',
|
|
33
|
+
'rate limit',
|
|
34
|
+
'resource_exhausted',
|
|
35
|
+
'usage limit',
|
|
36
|
+
'model quota',
|
|
37
|
+
'limit exceeded',
|
|
38
|
+
'spending cap',
|
|
39
|
+
'usage cap',
|
|
40
|
+
'you\'ve reached your monthly chat messages quota',
|
|
41
|
+
'upgrade to copilot pro',
|
|
42
|
+
'wait for your allowance to renew'
|
|
43
|
+
];
|
|
44
|
+
const hasQuotaKeyword = quotaKeywords.some(kw => lowerOutput.includes(kw) || lowerErrorMsg.includes(kw));
|
|
45
|
+
|
|
46
|
+
if (hasQuotaKeyword) {
|
|
47
|
+
debugLog(`🚨 Quota keywords found in process output or message for ${providerId}`);
|
|
48
|
+
return {
|
|
49
|
+
rateLimited: true,
|
|
50
|
+
rateLimitMessage: output || errorMessage,
|
|
51
|
+
providerSpecific: setProviderSpecificFlags(providerId, {})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
debugLog(`No quota keywords in process output or message for ${providerId}`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set provider-specific rate limit flags for compatibility
|
|
61
|
+
*/
|
|
62
|
+
function setProviderSpecificFlags(providerId, result) {
|
|
63
|
+
switch (providerId) {
|
|
64
|
+
case 'antigravity':
|
|
65
|
+
result.antigravityRateLimited = true;
|
|
66
|
+
break;
|
|
67
|
+
case 'windsurf':
|
|
68
|
+
result.windsurfRateLimited = true;
|
|
69
|
+
break;
|
|
70
|
+
case 'cursor':
|
|
71
|
+
result.cursorRateLimited = true;
|
|
72
|
+
break;
|
|
73
|
+
case 'github-copilot':
|
|
74
|
+
result.githubCopilotRateLimited = true;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check quota limit using AppleScript UI scraping (macOS only)
|
|
82
|
+
*/
|
|
83
|
+
async function checkQuotaWithAppleScript(providerId) {
|
|
84
|
+
if (process.platform !== 'darwin') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const debugLog = (msg) => {
|
|
89
|
+
const timestamp = new Date().toISOString();
|
|
90
|
+
const logLine = `[${timestamp}] ${msg}\n`;
|
|
91
|
+
try {
|
|
92
|
+
fs.appendFileSync(`/tmp/vibe-${providerId}-quota-debug.log`, logLine);
|
|
93
|
+
} catch (_) {}
|
|
94
|
+
console.log(`[AGENT CHECK] ${msg}`);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const { AppleScriptManager } = require('vibecodingmachine-core');
|
|
99
|
+
const appleScriptManager = new AppleScriptManager();
|
|
100
|
+
let quotaCheck = null;
|
|
101
|
+
|
|
102
|
+
// Use specific quota detection methods for each IDE
|
|
103
|
+
switch (providerId) {
|
|
104
|
+
case 'antigravity':
|
|
105
|
+
quotaCheck = await appleScriptManager.checkAntigravityQuotaLimit();
|
|
106
|
+
break;
|
|
107
|
+
case 'windsurf':
|
|
108
|
+
quotaCheck = await appleScriptManager.checkWindsurfQuotaLimit();
|
|
109
|
+
break;
|
|
110
|
+
case 'cursor':
|
|
111
|
+
quotaCheck = await appleScriptManager.checkCursorQuotaLimit();
|
|
112
|
+
break;
|
|
113
|
+
case 'github-copilot':
|
|
114
|
+
// GitHub Copilot uses the same detection as Cursor (both are VS Code extensions)
|
|
115
|
+
quotaCheck = await appleScriptManager.checkCursorQuotaLimit();
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
debugLog(`No specific quota detection method available for ${providerId}`);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
debugLog(`${providerId} quota check result: ` + JSON.stringify(quotaCheck));
|
|
123
|
+
|
|
124
|
+
if (quotaCheck && (quotaCheck.isRateLimited || quotaCheck.hasQuotaWarning)) {
|
|
125
|
+
debugLog(`🚨 ${providerId} quota limit detected via AppleScript`);
|
|
126
|
+
const result = {
|
|
127
|
+
rateLimited: true,
|
|
128
|
+
rateLimitMessage: quotaCheck.message || quotaCheck.matchedText || `${providerId} quota limit detected`,
|
|
129
|
+
providerSpecific: {}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (quotaCheck.resumeAt) {
|
|
133
|
+
result.rateLimitResume = quotaCheck.resumeAt;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setProviderSpecificFlags(providerId, result.providerSpecific);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
debugLog(`No quota limit detected via AppleScript for ${providerId}`);
|
|
141
|
+
return null;
|
|
142
|
+
|
|
143
|
+
} catch (error) {
|
|
144
|
+
debugLog(`AppleScript quota check failed for ${providerId}: ${error.message}`);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Main quota detection function that combines multiple detection methods
|
|
151
|
+
*/
|
|
152
|
+
async function detectQuotaLimit(providerId, output, errorMessage) {
|
|
153
|
+
// First check output and error messages for quota keywords
|
|
154
|
+
const outputCheck = checkQuotaInOutput(providerId, output, errorMessage);
|
|
155
|
+
if (outputCheck) {
|
|
156
|
+
return outputCheck;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Then try AppleScript UI scraping as fallback (macOS only)
|
|
160
|
+
const appleScriptCheck = await checkQuotaWithAppleScript(providerId);
|
|
161
|
+
if (appleScriptCheck) {
|
|
162
|
+
return appleScriptCheck;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// No quota limit detected
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check if an error result indicates rate limiting
|
|
171
|
+
*/
|
|
172
|
+
function isRateLimited(errorResult) {
|
|
173
|
+
return !!(errorResult && (
|
|
174
|
+
errorResult.rateLimited ||
|
|
175
|
+
errorResult.antigravityRateLimited ||
|
|
176
|
+
errorResult.windsurfRateLimited ||
|
|
177
|
+
errorResult.cursorRateLimited ||
|
|
178
|
+
errorResult.githubCopilotRateLimited
|
|
179
|
+
));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get rate limit message from error result
|
|
184
|
+
*/
|
|
185
|
+
function getRateLimitMessage(errorResult) {
|
|
186
|
+
if (!errorResult) return null;
|
|
187
|
+
|
|
188
|
+
return errorResult.rateLimitMessage ||
|
|
189
|
+
errorResult.message ||
|
|
190
|
+
'Rate limit detected';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get rate limit resume time from error result
|
|
195
|
+
*/
|
|
196
|
+
function getRateLimitResume(errorResult) {
|
|
197
|
+
if (!errorResult) return null;
|
|
198
|
+
|
|
199
|
+
return errorResult.rateLimitResume ||
|
|
200
|
+
errorResult.resumeAt ||
|
|
201
|
+
null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = {
|
|
205
|
+
checkQuotaInOutput,
|
|
206
|
+
setProviderSpecificFlags,
|
|
207
|
+
checkQuotaWithAppleScript,
|
|
208
|
+
detectQuotaLimit,
|
|
209
|
+
isRateLimited,
|
|
210
|
+
getRateLimitMessage,
|
|
211
|
+
getRateLimitResume
|
|
212
|
+
};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement Action Handlers Module
|
|
3
|
+
*
|
|
4
|
+
* Contains main action handlers for requirements.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const inquirer = require('inquirer');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const { t, getRequirementsPath } = require('vibecodingmachine-core');
|
|
11
|
+
const {
|
|
12
|
+
getRequirementList,
|
|
13
|
+
getSectionTitle,
|
|
14
|
+
confirmAction,
|
|
15
|
+
confirmAndExit,
|
|
16
|
+
validateRequirementTitle
|
|
17
|
+
} = require('./requirement-helpers');
|
|
18
|
+
const {
|
|
19
|
+
editClarificationResponses,
|
|
20
|
+
moveClarificationToTodo,
|
|
21
|
+
deleteClarification
|
|
22
|
+
} = require('./requirement-file-operations');
|
|
23
|
+
const {
|
|
24
|
+
moveRequirementDown,
|
|
25
|
+
moveRequirementUp,
|
|
26
|
+
promoteRequirement,
|
|
27
|
+
demoteRequirement,
|
|
28
|
+
moveRequirementToRecycled
|
|
29
|
+
} = require('./requirement-navigation');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper to show actions for a clarification requirement
|
|
33
|
+
*/
|
|
34
|
+
async function showClarificationActions(req, tree, loadClarification) {
|
|
35
|
+
const actions = [
|
|
36
|
+
{ label: '✍️ Add/Edit Responses', value: 'edit-responses' },
|
|
37
|
+
{ label: '↩️ Move back to TODO (after clarification)', value: 'move-to-todo' },
|
|
38
|
+
{ label: '🗑️ Delete', value: 'delete' },
|
|
39
|
+
{ label: '❌ Cancel', value: 'cancel' }
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const { action } = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: 'list',
|
|
45
|
+
name: 'action',
|
|
46
|
+
message: `What would you like to do with "${req.title}"?`,
|
|
47
|
+
choices: actions
|
|
48
|
+
}
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
switch (action) {
|
|
52
|
+
case 'edit-responses':
|
|
53
|
+
await editClarificationResponses(req, tree);
|
|
54
|
+
if (loadClarification) await loadClarification();
|
|
55
|
+
break;
|
|
56
|
+
case 'move-to-todo':
|
|
57
|
+
await moveClarificationToTodo(req, tree);
|
|
58
|
+
if (loadClarification) await loadClarification();
|
|
59
|
+
break;
|
|
60
|
+
case 'delete':
|
|
61
|
+
await deleteClarification(req, tree);
|
|
62
|
+
if (loadClarification) await loadClarification();
|
|
63
|
+
break;
|
|
64
|
+
case 'cancel':
|
|
65
|
+
console.log(chalk.gray('Cancelled.'));
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Show requirement actions menu
|
|
72
|
+
*/
|
|
73
|
+
async function showRequirementActions(req, sectionKey, tree) {
|
|
74
|
+
const actions = [
|
|
75
|
+
{ label: '✏️ Rename/Edit', value: 'rename' },
|
|
76
|
+
{ label: '👍 Thumbs up (promote to Verified)', value: 'thumbs-up' },
|
|
77
|
+
{ label: '👎 Thumbs down (demote to TODO)', value: 'thumbs-down' },
|
|
78
|
+
{ label: '⬆️ Move up', value: 'move-up' },
|
|
79
|
+
{ label: '⬇️ Move down', value: 'move-down' },
|
|
80
|
+
{ label: '🗑️ Delete', value: 'delete' },
|
|
81
|
+
{ label: '❌ Cancel', value: 'cancel' }
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const { action } = await inquirer.prompt([
|
|
85
|
+
{
|
|
86
|
+
type: 'list',
|
|
87
|
+
name: 'action',
|
|
88
|
+
message: `What would you like to do with "${req.title}"?`,
|
|
89
|
+
choices: actions
|
|
90
|
+
}
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
await performRequirementAction(action, req, sectionKey, tree);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Helper to perform action on requirement
|
|
98
|
+
*/
|
|
99
|
+
async function performRequirementAction(action, req, sectionKey, tree, loadSection, loadVerified) {
|
|
100
|
+
const reqList = getRequirementList(tree, sectionKey);
|
|
101
|
+
const sectionTitle = getSectionTitle(sectionKey);
|
|
102
|
+
const reqIndex = reqList.findIndex(r => r.title === req.title);
|
|
103
|
+
|
|
104
|
+
switch (action) {
|
|
105
|
+
case 'rename':
|
|
106
|
+
await renameRequirement(req, sectionKey, tree, loadSection);
|
|
107
|
+
break;
|
|
108
|
+
case 'thumbs-up':
|
|
109
|
+
await promoteRequirement(req, sectionKey, tree, loadSection, loadVerified);
|
|
110
|
+
break;
|
|
111
|
+
case 'thumbs-down':
|
|
112
|
+
await demoteRequirement(req.title, sectionKey, tree, loadSection, loadVerified);
|
|
113
|
+
break;
|
|
114
|
+
case 'move-up':
|
|
115
|
+
await moveRequirementUp(req, sectionKey, tree);
|
|
116
|
+
break;
|
|
117
|
+
case 'move-down':
|
|
118
|
+
await moveRequirementDown(req, sectionKey, tree);
|
|
119
|
+
break;
|
|
120
|
+
case 'delete':
|
|
121
|
+
await deleteRequirement(req, sectionKey, tree, loadSection);
|
|
122
|
+
break;
|
|
123
|
+
case 'cancel':
|
|
124
|
+
console.log(chalk.gray('Cancelled.'));
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Helper to rename requirement (title and description)
|
|
131
|
+
*/
|
|
132
|
+
async function renameRequirement(req, sectionKey, tree, loadSection) {
|
|
133
|
+
const reqPath = await getRequirementsPath();
|
|
134
|
+
|
|
135
|
+
console.log(chalk.cyan('\n✏️ Rename/Edit Requirement\n'));
|
|
136
|
+
|
|
137
|
+
const { newTitle } = await inquirer.prompt([
|
|
138
|
+
{
|
|
139
|
+
type: 'input',
|
|
140
|
+
name: 'newTitle',
|
|
141
|
+
message: 'Enter new title:',
|
|
142
|
+
default: req.title
|
|
143
|
+
}
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
const validationError = validateRequirementTitle(newTitle);
|
|
147
|
+
if (validationError) {
|
|
148
|
+
console.log(chalk.red(`Error: ${validationError}`));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
153
|
+
const lines = content.split('\n');
|
|
154
|
+
|
|
155
|
+
// Find and update the requirement
|
|
156
|
+
for (let i = 0; i < lines.length; i++) {
|
|
157
|
+
if (lines[i].includes(`### ${req.title}`)) {
|
|
158
|
+
lines[i] = lines[i].replace(req.title, newTitle);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
await fs.writeFile(reqPath, lines.join('\n'));
|
|
164
|
+
console.log(chalk.green('\n✓ Requirement renamed!'));
|
|
165
|
+
|
|
166
|
+
if (loadSection) await loadSection();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Helper to move requirement to recycled section (used to delete)
|
|
171
|
+
*/
|
|
172
|
+
async function deleteRequirement(req, sectionKey, tree, loadSection) {
|
|
173
|
+
const reqList = getRequirementList(tree, sectionKey);
|
|
174
|
+
const sectionTitle = getSectionTitle(sectionKey);
|
|
175
|
+
const reqIndex = reqList.findIndex(r => r.title === req.title);
|
|
176
|
+
|
|
177
|
+
if (reqIndex === -1) return;
|
|
178
|
+
|
|
179
|
+
const confirmed = await confirmAction(`Delete "${req.title}"? This cannot be undone. (r/y/N)`);
|
|
180
|
+
if (!confirmed) {
|
|
181
|
+
console.log(chalk.gray('Cancelled.'));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const reqPath = await getRequirementsPath();
|
|
186
|
+
await moveRequirementToRecycled(reqPath, req.title, sectionTitle);
|
|
187
|
+
|
|
188
|
+
console.log(chalk.green('\n✓ Requirement moved to recycled!'));
|
|
189
|
+
|
|
190
|
+
if (loadSection) await loadSection();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Helper to permanently delete requirement from file (used for recycled items)
|
|
195
|
+
*/
|
|
196
|
+
async function permanentlyDeleteRequirement(req, sectionKey, tree, loadSection) {
|
|
197
|
+
const reqList = getRequirementList(tree, sectionKey);
|
|
198
|
+
const reqIndex = reqList.findIndex(r => r.title === req.title);
|
|
199
|
+
|
|
200
|
+
if (reqIndex === -1) return;
|
|
201
|
+
|
|
202
|
+
const confirmed = await confirmAction(`Permanently delete "${req.title}"? This cannot be undone. (r/y/N)`);
|
|
203
|
+
if (!confirmed) {
|
|
204
|
+
console.log(chalk.gray('Cancelled.'));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const reqPath = await getRequirementsPath();
|
|
209
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
210
|
+
const lines = content.split('\n');
|
|
211
|
+
|
|
212
|
+
// Find and remove the requirement
|
|
213
|
+
let startIdx = -1;
|
|
214
|
+
let endIdx = -1;
|
|
215
|
+
|
|
216
|
+
for (let i = 0; i < lines.length; i++) {
|
|
217
|
+
if (lines[i].includes(`### ${req.title}`)) {
|
|
218
|
+
startIdx = i;
|
|
219
|
+
// Find the end of this requirement
|
|
220
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
221
|
+
if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
|
|
222
|
+
endIdx = j;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (endIdx === -1) endIdx = lines.length;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (startIdx !== -1) {
|
|
232
|
+
lines.splice(startIdx, endIdx - startIdx);
|
|
233
|
+
await fs.writeFile(reqPath, lines.join('\n'));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(chalk.green('\n✓ Requirement permanently deleted!'));
|
|
237
|
+
|
|
238
|
+
if (loadSection) await loadSection();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Helper to handle adding requirements
|
|
243
|
+
*/
|
|
244
|
+
async function handleAddRequirement(type) {
|
|
245
|
+
const reqCommands = require('../commands/requirements');
|
|
246
|
+
const packages = ['all', 'cli', 'core', 'electron-app', 'web', 'mobile'];
|
|
247
|
+
|
|
248
|
+
if (type === 'single') {
|
|
249
|
+
const { package: pkg } = await inquirer.prompt([
|
|
250
|
+
{
|
|
251
|
+
type: 'list',
|
|
252
|
+
name: 'package',
|
|
253
|
+
message: 'Which package?',
|
|
254
|
+
choices: packages
|
|
255
|
+
}
|
|
256
|
+
]);
|
|
257
|
+
|
|
258
|
+
await reqCommands.add({ package: pkg, interactive: true });
|
|
259
|
+
} else if (type === 'bulk') {
|
|
260
|
+
const { selectedPackages } = await inquirer.prompt([
|
|
261
|
+
{
|
|
262
|
+
type: 'checkbox',
|
|
263
|
+
name: 'selectedPackages',
|
|
264
|
+
message: 'Select packages to add requirements to:',
|
|
265
|
+
choices: packages.map(pkg => ({ name: pkg, value: pkg }))
|
|
266
|
+
}
|
|
267
|
+
]);
|
|
268
|
+
|
|
269
|
+
if (selectedPackages.length === 0) {
|
|
270
|
+
console.log(chalk.yellow('No packages selected.'));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const pkg of selectedPackages) {
|
|
275
|
+
await reqCommands.add({ package: pkg, interactive: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = {
|
|
281
|
+
showClarificationActions,
|
|
282
|
+
showRequirementActions,
|
|
283
|
+
performRequirementAction,
|
|
284
|
+
renameRequirement,
|
|
285
|
+
deleteRequirement,
|
|
286
|
+
permanentlyDeleteRequirement,
|
|
287
|
+
handleAddRequirement
|
|
288
|
+
};
|