vibecodingmachine-cli 2026.3.14-1537 → 2026.6.17-1956
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 +7 -7
- package/bin/commands/agent-commands.js +15 -15
- package/bin/commands/auto-commands.js +3 -3
- package/bin/commands/command-aliases.js +13 -4
- package/bin/config/cli-config.js +15 -5
- package/bin/update/update-checker.js +5 -5
- package/bin/vibecodingmachine.js +2 -2
- package/package.json +2 -2
- package/src/commands/agents/add.js +5 -5
- package/src/commands/agents/check.js +19 -19
- package/src/commands/agents/list.js +24 -24
- package/src/commands/agents/remove.js +4 -4
- package/src/commands/agents-check.js +1 -1
- package/src/commands/analyze-file-sizes.js +43 -43
- package/src/commands/auto-direct/auto-provider-manager.js +19 -19
- package/src/commands/auto-direct/auto-start-phases.js +493 -0
- package/src/commands/auto-direct/auto-status-display.js +35 -35
- package/src/commands/auto-direct/auto-utils.js +50 -50
- package/src/commands/auto-direct/cline-installer.js +56 -0
- package/src/commands/auto-direct/code-processor.js +27 -27
- package/src/commands/auto-direct/file-scanner.js +19 -19
- package/src/commands/auto-direct/ide-completion-waiter.js +485 -0
- package/src/commands/auto-direct/ide-fallback-runner.js +226 -0
- package/src/commands/auto-direct/ide-provider-runner.js +103 -0
- package/src/commands/auto-direct/iteration-handlers.js +189 -0
- package/src/commands/auto-direct/iteration-runner.js +485 -0
- package/src/commands/auto-direct/provider-config.js +38 -7
- package/src/commands/auto-direct/provider-manager.js +132 -6
- package/src/commands/auto-direct/requirement-manager.js +169 -104
- package/src/commands/auto-direct/requirement-mover.js +350 -0
- package/src/commands/auto-direct/spec-handlers.js +155 -0
- package/src/commands/auto-direct/spec-ide-runner.js +318 -0
- package/src/commands/auto-direct/spec-processing.js +203 -0
- package/src/commands/auto-direct/status-display.js +9 -9
- package/src/commands/auto-direct/utils.js +83 -1
- package/src/commands/auto-direct-refactored.js +1 -413
- package/src/commands/auto-direct.js +127 -4119
- package/src/commands/auto-execution.js +21 -21
- package/src/commands/auto-status-helpers.js +0 -2
- package/src/commands/auto.js +22 -22
- package/src/commands/check-compliance.js +65 -65
- package/src/commands/computers.js +39 -39
- package/src/commands/continuous-scan.js +19 -19
- package/src/commands/ide.js +4 -4
- package/src/commands/locale.js +7 -7
- package/src/commands/refactor-file.js +59 -59
- package/src/commands/requirements/commands.js +17 -17
- package/src/commands/requirements/default-handlers.js +30 -30
- package/src/commands/requirements/disable.js +3 -3
- package/src/commands/requirements/enable.js +3 -3
- package/src/commands/requirements/utils.js +6 -6
- package/src/commands/requirements-refactored.js +3 -3
- package/src/commands/requirements-remote.js +38 -38
- package/src/commands/requirements.js +3 -3
- package/src/commands/settings.js +111 -0
- package/src/commands/specs/count.js +60 -0
- package/src/commands/specs/disable.js +3 -3
- package/src/commands/specs/enable.js +3 -3
- package/src/commands/status.js +10 -10
- package/src/commands/sync.js +25 -25
- package/src/commands/timeout.js +35 -35
- package/src/trui/TruiInterface.js +2 -2
- package/src/trui/agents/AgentInterface.js +4 -4
- package/src/trui/agents/handlers/CommandHandler.js +4 -4
- package/src/trui/agents/handlers/ContextManager.js +1 -1
- package/src/trui/agents/handlers/DisplayHandler.js +11 -11
- package/src/trui/agents/handlers/HelpHandler.js +1 -1
- package/src/utils/agent-selector.js +6 -6
- package/src/utils/antigravity-installer.js +4 -4
- package/src/utils/asset-cleanup.js +1 -1
- package/src/utils/auth.js +9 -12
- package/src/utils/clarification-actions.js +4 -4
- package/src/utils/cline-js-handler.js +5 -5
- package/src/utils/compliance-check.js +6 -6
- package/src/utils/config.js +12 -12
- package/src/utils/display-formatters-complete.js +2 -2
- package/src/utils/display-formatters-extracted.js +2 -2
- package/src/utils/display-formatters.js +2 -2
- package/src/utils/feedback-handler.js +2 -2
- package/src/utils/first-run.js +7 -7
- package/src/utils/ide-detection.js +1 -1
- package/src/utils/ide-handlers.js +6 -6
- package/src/utils/interactive/clarification-actions.js +3 -3
- package/src/utils/interactive/core-ui.js +7 -7
- package/src/utils/interactive/file-backup.js +6 -6
- package/src/utils/interactive/file-import-export.js +49 -49
- package/src/utils/interactive/file-operations.js +3 -3
- package/src/utils/interactive/file-validation.js +41 -41
- package/src/utils/interactive/interactive-prompts.js +41 -41
- package/src/utils/interactive/requirement-actions.js +5 -5
- package/src/utils/interactive/requirement-crud.js +4 -4
- package/src/utils/interactive/requirements-navigation.js +10 -10
- package/src/utils/interactive-broken.js +6 -6
- package/src/utils/interactive.js +37 -37
- package/src/utils/keyboard-handler.js +4 -4
- package/src/utils/prompt-helper.js +6 -6
- package/src/utils/provider-checker/agent-checker.js +1 -1
- package/src/utils/provider-checker/agent-runner.js +203 -314
- package/src/utils/provider-checker/agents-file-lock.js +134 -0
- package/src/utils/provider-checker/agents-manager.js +224 -36
- package/src/utils/provider-checker/cli-installer.js +28 -28
- package/src/utils/provider-checker/cli-utils.js +2 -2
- package/src/utils/provider-checker/cursor-approval-clicker.js +108 -0
- package/src/utils/provider-checker/format-utils.js +4 -4
- package/src/utils/provider-checker/ide-installer-helper.js +96 -0
- package/src/utils/provider-checker/ide-manager.js +19 -8
- package/src/utils/provider-checker/ide-quota-checker.js +120 -0
- package/src/utils/provider-checker/ide-utils.js +2 -2
- package/src/utils/provider-checker/node-detector.js +4 -4
- package/src/utils/provider-checker/node-utils.js +5 -5
- package/src/utils/provider-checker/opencode-checker.js +107 -73
- package/src/utils/provider-checker/process-utils.js +1 -1
- package/src/utils/provider-checker/provider-validator.js +11 -11
- package/src/utils/provider-checker/quota-checker.js +5 -5
- package/src/utils/provider-checker/quota-detector.js +5 -5
- package/src/utils/provider-checker/requirements-manager.js +6 -6
- package/src/utils/provider-checker/test-requirements.js +1 -1
- package/src/utils/provider-checker/vscode-approval-clicker.js +328 -0
- package/src/utils/provider-checker-new.js +6 -6
- package/src/utils/provider-checker.js +6 -6
- package/src/utils/provider-checkers/ide-manager.js +13 -13
- package/src/utils/provider-checkers/node-executable-finder.js +4 -4
- package/src/utils/provider-checkers/provider-checker-core.js +5 -5
- package/src/utils/provider-checkers/provider-checker-main.js +17 -17
- package/src/utils/provider-registry.js +5 -6
- package/src/utils/provider-utils.js +12 -12
- package/src/utils/quota-detectors.js +32 -32
- package/src/utils/requirement-action-handlers.js +12 -12
- package/src/utils/requirement-actions/requirement-operations.js +3 -3
- package/src/utils/requirement-actions.js +1 -1
- package/src/utils/requirement-file-operations.js +5 -5
- package/src/utils/requirement-helpers.js +1 -1
- package/src/utils/requirement-management.js +5 -5
- package/src/utils/requirement-navigation.js +2 -2
- package/src/utils/requirement-organization.js +3 -3
- package/src/utils/rui-trui-adapter.js +14 -14
- package/src/utils/simple-trui.js +3 -3
- package/src/utils/status-helpers-extracted.js +3 -3
- package/src/utils/trui-clarifications.js +11 -11
- package/src/utils/trui-debug.js +3 -2
- package/src/utils/trui-devin.js +217 -0
- package/src/utils/trui-feedback.js +7 -7
- package/src/utils/trui-kiro-integration.js +34 -34
- package/src/utils/trui-main-handlers.js +20 -21
- package/src/utils/trui-main-menu.js +19 -19
- package/src/utils/trui-nav-agents.js +59 -8
- package/src/utils/trui-nav-requirements.js +3 -3
- package/src/utils/trui-nav-settings.js +10 -10
- package/src/utils/trui-nav-specifications.js +1 -1
- package/src/utils/trui-navigation-backup.js +11 -11
- package/src/utils/trui-navigation.js +9 -9
- package/src/utils/trui-provider-health.js +25 -25
- package/src/utils/trui-provider-manager.js +28 -28
- package/src/utils/trui-quick-menu.js +2 -2
- package/src/utils/trui-req-actions-backup.js +21 -21
- package/src/utils/trui-req-actions.js +20 -20
- package/src/utils/trui-req-editor.js +10 -10
- package/src/utils/trui-req-file-ops.js +3 -3
- package/src/utils/trui-req-tree.js +7 -7
- package/src/utils/trui-windsurf.js +103 -103
- package/src/utils/user-tracking.js +15 -15
- package/src/utils/trui-req-tree-old.js +0 -719
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement Moving Functions
|
|
3
|
+
* Extracted from requirement-manager.js for constitutional compliance
|
|
4
|
+
* Handles moving requirements between sections (TO VERIFY, Recycled, etc.)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
10
|
+
const { t } = require('vibecodingmachine-core');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Move requirement from TODO to TO VERIFY BY HUMAN section
|
|
14
|
+
* @param {string} repoPath - Repository path
|
|
15
|
+
* @param {string} requirementText - Requirement text to move
|
|
16
|
+
* @returns {Promise<boolean>} - Success status
|
|
17
|
+
*/
|
|
18
|
+
async function moveRequirementToVerify(repoPath, requirementText) {
|
|
19
|
+
try {
|
|
20
|
+
const reqPath = await getRequirementsPath(repoPath);
|
|
21
|
+
if (!reqPath || !await fs.pathExists(reqPath)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
|
|
28
|
+
// Find the requirement by its title (in ### header format)
|
|
29
|
+
// Only look in TODO section
|
|
30
|
+
const normalizedRequirement = requirementText.trim();
|
|
31
|
+
const snippet = normalizedRequirement.substring(0, 80);
|
|
32
|
+
let requirementStartIndex = -1;
|
|
33
|
+
let requirementEndIndex = -1;
|
|
34
|
+
let inTodoSection = false;
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const line = lines[i];
|
|
38
|
+
const trimmed = line.trim();
|
|
39
|
+
|
|
40
|
+
// Check if we're entering TODO section
|
|
41
|
+
if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
|
|
42
|
+
inTodoSection = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check if we're leaving TODO section
|
|
47
|
+
if (inTodoSection && trimmed.startsWith('##') && !trimmed.startsWith('###') && !trimmed.includes('Requirements not yet completed')) {
|
|
48
|
+
inTodoSection = false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Only look for requirements in TODO section
|
|
52
|
+
if (inTodoSection && trimmed.startsWith('###')) {
|
|
53
|
+
const title = trimmed.replace(/^###\s*/, '').trim();
|
|
54
|
+
if (title) {
|
|
55
|
+
// Try multiple matching strategies
|
|
56
|
+
const normalizedTitle = title.trim();
|
|
57
|
+
|
|
58
|
+
// Exact match
|
|
59
|
+
if (normalizedTitle === normalizedRequirement) {
|
|
60
|
+
requirementStartIndex = i;
|
|
61
|
+
}
|
|
62
|
+
// Check if either contains the other (for partial matches)
|
|
63
|
+
else if (normalizedTitle.includes(normalizedRequirement) || normalizedRequirement.includes(normalizedTitle)) {
|
|
64
|
+
requirementStartIndex = i;
|
|
65
|
+
}
|
|
66
|
+
// Check snippet matches
|
|
67
|
+
else if (normalizedTitle.includes(snippet) || snippet.includes(normalizedTitle.substring(0, 80))) {
|
|
68
|
+
requirementStartIndex = i;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (requirementStartIndex !== -1) {
|
|
72
|
+
// Find the end of this requirement (next ### or ## header)
|
|
73
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
74
|
+
const nextLine = lines[j].trim();
|
|
75
|
+
if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
|
|
76
|
+
requirementEndIndex = j;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (requirementEndIndex === -1) {
|
|
81
|
+
requirementEndIndex = lines.length;
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (requirementStartIndex === -1) {
|
|
90
|
+
console.log(chalk.yellow(`⚠️ ${t('auto.direct.requirement.not.found.todo', { requirement: requirementText.substring(0, 60) + '...' })}`));
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Extract the entire requirement block
|
|
95
|
+
const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
|
|
96
|
+
|
|
97
|
+
// Remove the requirement from its current location
|
|
98
|
+
lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
|
|
99
|
+
|
|
100
|
+
// Check if there are any more requirements in TODO section after removal
|
|
101
|
+
let hasMoreTodoRequirements = false;
|
|
102
|
+
inTodoSection = false; // Reset the existing variable
|
|
103
|
+
for (let i = 0; i < lines.length; i++) {
|
|
104
|
+
const line = lines[i].trim();
|
|
105
|
+
|
|
106
|
+
// Check if we're entering TODO section
|
|
107
|
+
if (line.startsWith('##') && line.includes('Requirements not yet completed')) {
|
|
108
|
+
inTodoSection = true;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check if we're leaving TODO section
|
|
113
|
+
if (inTodoSection && line.startsWith('##') && !line.startsWith('###') && !line.includes('Requirements not yet completed')) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check if we found a requirement in TODO section
|
|
118
|
+
if (inTodoSection && line.startsWith('###')) {
|
|
119
|
+
const title = line.replace(/^###\s*/, '').trim();
|
|
120
|
+
if (title) {
|
|
121
|
+
hasMoreTodoRequirements = true;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// If no more TODO requirements, log message
|
|
128
|
+
if (!hasMoreTodoRequirements) {
|
|
129
|
+
console.log(chalk.green(`🎉 ${t('auto.direct.requirement.no.more.todo')}`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Find or create TO VERIFY BY HUMAN section with conflict resolution
|
|
133
|
+
// IMPORTANT: Do NOT match VERIFIED sections - only match TO VERIFY sections
|
|
134
|
+
const verifySectionVariants = [
|
|
135
|
+
'## 🔍 TO VERIFY BY HUMAN',
|
|
136
|
+
'## 🔍 TO VERIFY',
|
|
137
|
+
'## TO VERIFY',
|
|
138
|
+
'## ✅ TO VERIFY',
|
|
139
|
+
'## ✅ Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG',
|
|
140
|
+
'## 📊 CROSS-COMPUTER REQUIREMENT ASSIGNMENT',
|
|
141
|
+
'## 🖥️ COMPUTER FOCUS AREA MANAGEMENT',
|
|
142
|
+
'## 🔍 spec-kit: TO VERIFY BY HUMAN'
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
let verifyIndex = -1;
|
|
146
|
+
for (let i = 0; i < lines.length; i++) {
|
|
147
|
+
const line = lines[i];
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
|
|
150
|
+
// Check each variant more carefully
|
|
151
|
+
for (const variant of verifySectionVariants) {
|
|
152
|
+
const variantTrimmed = variant.trim();
|
|
153
|
+
// Exact match or line starts with variant
|
|
154
|
+
if (trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed)) {
|
|
155
|
+
// Double-check: make sure it's NOT a VERIFIED section (without TO VERIFY)
|
|
156
|
+
if (!trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i) &&
|
|
157
|
+
(trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot') || trimmed.includes('CROSS-COMPUTER REQUIREMENT ASSIGNMENT') || trimmed.includes('COMPUTER FOCUS AREA MANAGEMENT') || trimmed.includes('spec-kit'))) {
|
|
158
|
+
verifyIndex = i;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (verifyIndex !== -1) break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (verifyIndex === -1) {
|
|
167
|
+
// Create TO VERIFY section - place it BEFORE VERIFIED section if one exists, otherwise before CHANGELOG
|
|
168
|
+
const verifiedIndex = lines.findIndex(line => {
|
|
169
|
+
const trimmed = line.trim();
|
|
170
|
+
return trimmed === '## 📝 VERIFIED' || trimmed.startsWith('## 📝 VERIFIED') ||
|
|
171
|
+
(trimmed.startsWith('##') && trimmed.includes('VERIFIED') && !trimmed.includes('TO VERIFY'));
|
|
172
|
+
});
|
|
173
|
+
const changelogIndex = lines.findIndex(line => line.includes('## CHANGELOG'));
|
|
174
|
+
const manualFeedbackIndex = lines.findIndex(line => line.trim().startsWith('## ❓'));
|
|
175
|
+
|
|
176
|
+
// Prefer: before VERIFIED > before CHANGELOG > before manual feedback > at end
|
|
177
|
+
let insertionIndex = lines.length;
|
|
178
|
+
if (verifiedIndex > 0) {
|
|
179
|
+
insertionIndex = verifiedIndex;
|
|
180
|
+
} else if (changelogIndex > 0) {
|
|
181
|
+
insertionIndex = changelogIndex;
|
|
182
|
+
} else if (manualFeedbackIndex > 0) {
|
|
183
|
+
insertionIndex = manualFeedbackIndex;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const block = [];
|
|
187
|
+
if (insertionIndex > 0 && lines[insertionIndex - 1].trim() !== '') {
|
|
188
|
+
block.push('');
|
|
189
|
+
}
|
|
190
|
+
block.push('## 🔍 spec-kit: TO VERIFY BY HUMAN', '');
|
|
191
|
+
lines.splice(insertionIndex, 0, ...block);
|
|
192
|
+
verifyIndex = lines.findIndex(line => {
|
|
193
|
+
const trimmed = line.trim();
|
|
194
|
+
return trimmed === '## 🔍 spec-kit: TO VERIFY BY HUMAN' || trimmed.startsWith('## 🔍 spec-kit: TO VERIFY BY HUMAN');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Safety check: verifyIndex should be valid
|
|
198
|
+
if (verifyIndex === -1) {
|
|
199
|
+
console.error(t('auto.direct.verify.section.create.failed'));
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Safety check: verify we're not inserting into a VERIFIED section
|
|
205
|
+
const verifyLine = lines[verifyIndex] || '';
|
|
206
|
+
if (verifyLine.includes('## 📝 VERIFIED') || (verifyLine.trim().startsWith('##') && verifyLine.includes('VERIFIED') && !verifyLine.includes('TO VERIFY'))) {
|
|
207
|
+
console.error('ERROR: Attempted to insert into VERIFIED section instead of TO VERIFY');
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Remove any existing duplicate of this requirement in TO VERIFY section
|
|
212
|
+
// Find the next section header after TO VERIFY
|
|
213
|
+
let nextSectionIndex = lines.length;
|
|
214
|
+
for (let i = verifyIndex + 1; i < lines.length; i++) {
|
|
215
|
+
const trimmed = lines[i].trim();
|
|
216
|
+
if (trimmed.startsWith('##') && !trimmed.startsWith('###')) {
|
|
217
|
+
nextSectionIndex = i;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Search for duplicate requirement in TO VERIFY section
|
|
223
|
+
const requirementTitle = requirementBlock[0].trim().replace(/^###\s*/, '').trim();
|
|
224
|
+
for (let i = verifyIndex + 1; i < nextSectionIndex; i++) {
|
|
225
|
+
const line = lines[i];
|
|
226
|
+
const trimmed = line.trim();
|
|
227
|
+
|
|
228
|
+
if (trimmed.startsWith('###')) {
|
|
229
|
+
const existingTitle = trimmed.replace(/^###\s*/, '').trim();
|
|
230
|
+
|
|
231
|
+
// Check if this is a duplicate (exact match or contains/contained by)
|
|
232
|
+
if (existingTitle === requirementTitle ||
|
|
233
|
+
existingTitle.includes(requirementTitle) ||
|
|
234
|
+
requirementTitle.includes(existingTitle)) {
|
|
235
|
+
|
|
236
|
+
// Find the end of this existing requirement
|
|
237
|
+
let existingEndIndex = nextSectionIndex;
|
|
238
|
+
for (let j = i + 1; j < nextSectionIndex; j++) {
|
|
239
|
+
const nextLine = lines[j].trim();
|
|
240
|
+
if (nextLine.startsWith('###') || nextLine.startsWith('##')) {
|
|
241
|
+
existingEndIndex = j;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Remove the duplicate
|
|
247
|
+
lines.splice(i, existingEndIndex - i);
|
|
248
|
+
|
|
249
|
+
// Adjust nextSectionIndex if needed
|
|
250
|
+
nextSectionIndex -= (existingEndIndex - i);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Insert requirement block at TOP of TO VERIFY section (right after section header)
|
|
257
|
+
let insertIndex = verifyIndex + 1;
|
|
258
|
+
|
|
259
|
+
// Ensure there's a blank line after the section header
|
|
260
|
+
if (lines[insertIndex]?.trim() !== '') {
|
|
261
|
+
lines.splice(insertIndex, 0, '');
|
|
262
|
+
insertIndex++;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Insert the requirement block
|
|
266
|
+
lines.splice(insertIndex, 0, ...requirementBlock);
|
|
267
|
+
|
|
268
|
+
// Ensure there's a blank line after the requirement block
|
|
269
|
+
const afterIndex = insertIndex + requirementBlock.length;
|
|
270
|
+
if (afterIndex < lines.length && lines[afterIndex]?.trim() !== '') {
|
|
271
|
+
lines.splice(afterIndex, 0, '');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Write the file
|
|
275
|
+
await fs.writeFile(reqPath, lines.join('\n'));
|
|
276
|
+
console.log(chalk.green(`✅ Moved requirement to TO VERIFY BY HUMAN: ${requirementText.substring(0, 80)}...`));
|
|
277
|
+
return true;
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error(t('auto.direct.requirement.move.verify.error'), err.message);
|
|
280
|
+
console.error('⚠️ Requirement may have been lost. Please check the requirements file.');
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Move requirement to recycled section
|
|
287
|
+
* @param {string} repoPath - Repository path
|
|
288
|
+
* @param {string} requirementText - Requirement text to recycle
|
|
289
|
+
* @returns {Promise<boolean>} - Success status
|
|
290
|
+
*/
|
|
291
|
+
async function moveRequirementToRecycle(repoPath, requirementText) {
|
|
292
|
+
try {
|
|
293
|
+
const reqPath = await getRequirementsPath(repoPath);
|
|
294
|
+
if (!reqPath || !await fs.pathExists(reqPath)) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let content = await fs.readFile(reqPath, 'utf8');
|
|
299
|
+
|
|
300
|
+
// Find and remove from any section
|
|
301
|
+
const lines = content.split('\n');
|
|
302
|
+
let requirementIndex = -1;
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < lines.length; i++) {
|
|
305
|
+
if (lines[i].includes(requirementText.substring(0, 50))) {
|
|
306
|
+
requirementIndex = i;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (requirementIndex === -1) {
|
|
312
|
+
console.log(chalk.yellow(`⚠️ ${t('auto.direct.requirement.not.found')}`));
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Remove from any section
|
|
317
|
+
const requirementLine = lines[requirementIndex];
|
|
318
|
+
lines.splice(requirementIndex, 1);
|
|
319
|
+
|
|
320
|
+
// Add to Recycled section (after "## ♻️ Recycled")
|
|
321
|
+
let recycledIndex = -1;
|
|
322
|
+
for (let i = 0; i < lines.length; i++) {
|
|
323
|
+
if (lines[i].includes('## ♻️ Recycled')) {
|
|
324
|
+
recycledIndex = i; // Move to the line of the header
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (recycledIndex === -1) {
|
|
330
|
+
lines.push('## ♻️ Recycled');
|
|
331
|
+
recycledIndex = lines.length - 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Add timestamp and insert at TOP of Recycled list
|
|
335
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
336
|
+
lines.splice(recycledIndex + 1, 0, `- ${timestamp}: ${requirementLine.replace(/^- /, '')}`);
|
|
337
|
+
|
|
338
|
+
// Save
|
|
339
|
+
await fs.writeFile(reqPath, lines.join('\n'));
|
|
340
|
+
return true;
|
|
341
|
+
} catch (err) {
|
|
342
|
+
console.error(t('auto.direct.requirement.move.error'), err.message);
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
module.exports = {
|
|
348
|
+
moveRequirementToVerify,
|
|
349
|
+
moveRequirementToRecycle
|
|
350
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specification Handlers Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions for managing and processing specifications,
|
|
5
|
+
* including task counting, task retrieval, and requirement processing.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from auto-direct.js to improve modularity and maintainability.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs-extra');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const chalk = require('chalk');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Count checked and total checkboxes in a spec's tasks.md file.
|
|
16
|
+
* @param {string} specPath - Path to the spec directory
|
|
17
|
+
* @returns {{done: number, total: number}} - Checkbox counts
|
|
18
|
+
*/
|
|
19
|
+
function countSpecCheckboxes(specPath) {
|
|
20
|
+
try {
|
|
21
|
+
const tasksFile = path.join(specPath, 'tasks.md');
|
|
22
|
+
if (!fs.existsSync(tasksFile)) return { done: 0, total: 0 };
|
|
23
|
+
const content = fs.readFileSync(tasksFile, 'utf8');
|
|
24
|
+
const totalMatches = content.match(/^- \[[ x]\]/gmi) || [];
|
|
25
|
+
const doneMatches = content.match(/^- \[x\]/gmi) || [];
|
|
26
|
+
return { done: doneMatches.length, total: totalMatches.length };
|
|
27
|
+
} catch (_) {
|
|
28
|
+
return { done: 0, total: 0 };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the next unchecked task line from tasks.md.
|
|
34
|
+
* Returns { text, line } or null when all done.
|
|
35
|
+
*/
|
|
36
|
+
function getNextSpecTask(specPath) {
|
|
37
|
+
try {
|
|
38
|
+
const tasksFile = path.join(specPath, 'tasks.md');
|
|
39
|
+
if (!fs.existsSync(tasksFile)) return null;
|
|
40
|
+
const content = fs.readFileSync(tasksFile, 'utf8');
|
|
41
|
+
for (const line of content.split('\n')) {
|
|
42
|
+
if (/^- \[ \]/.test(line)) {
|
|
43
|
+
return { text: line.replace(/^- \[ \]\s*/, '').trim(), line: line.trim() };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
} catch (_) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load all enabled specs that have incomplete tasks (or no tasks.md yet).
|
|
54
|
+
*/
|
|
55
|
+
async function loadEnabledIncompleteSpecs(repoPath) {
|
|
56
|
+
try {
|
|
57
|
+
const { getAllSpecifications } = require('vibecodingmachine-core');
|
|
58
|
+
const specs = await getAllSpecifications(repoPath, { skipDisabled: true });
|
|
59
|
+
return specs.filter(spec => {
|
|
60
|
+
if (!spec.hasTasks) return true; // No tasks.md = needs planning + implementation
|
|
61
|
+
const counts = countSpecCheckboxes(spec.path);
|
|
62
|
+
return counts.total === 0 || counts.done < counts.total;
|
|
63
|
+
});
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.log(chalk.yellow(`⚠️ Error loading specs: ${err.message}`));
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Process default requirement until completion
|
|
72
|
+
* @param {RequirementSequencer} sequencer - Requirement sequencer
|
|
73
|
+
* @param {DefaultRequirementManager} defaultManager - Default requirement manager
|
|
74
|
+
* @param {Object} providerConfig - Provider configuration
|
|
75
|
+
* @param {string} repoPath - Repository path
|
|
76
|
+
*/
|
|
77
|
+
async function processDefaultRequirement(sequencer, defaultManager, providerConfig, repoPath) {
|
|
78
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
79
|
+
const requirementsPath = await getRequirementsPath(repoPath);
|
|
80
|
+
let iterationCount = 0;
|
|
81
|
+
|
|
82
|
+
// Import runIteration from parent module - will be injected when called
|
|
83
|
+
const { runIteration } = require('../auto-direct');
|
|
84
|
+
|
|
85
|
+
while (true) {
|
|
86
|
+
// Check if default requirement should stop
|
|
87
|
+
const shouldStop = await defaultManager.shouldStop();
|
|
88
|
+
if (shouldStop) {
|
|
89
|
+
const status = await defaultManager.getStatus();
|
|
90
|
+
console.log(chalk.bold.green(`\n✅ Default Requirement Complete`));
|
|
91
|
+
console.log(chalk.gray(`Status: ${status.completionReason || 'Completed'}\n`));
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if regular requirements were added (should pause default)
|
|
96
|
+
const currentState = await sequencer.getCurrentState(requirementsPath);
|
|
97
|
+
if (currentState.hasRegularRequirements) {
|
|
98
|
+
console.log(chalk.bold.yellow('\n⏸️ Default Requirement Paused'));
|
|
99
|
+
console.log(chalk.gray('New regular requirements detected, pausing default requirement...\n'));
|
|
100
|
+
await defaultManager.pause();
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Get current default requirement status
|
|
105
|
+
const defaultStatus = await defaultManager.getStatus();
|
|
106
|
+
iterationCount = defaultStatus.iterationCount + 1;
|
|
107
|
+
|
|
108
|
+
console.log(chalk.bold.cyan(`\n${'━'.repeat(80)}`));
|
|
109
|
+
console.log(chalk.bold.cyan(` ⭐ DEFAULT REQUIREMENT - Iteration ${iterationCount}/${defaultStatus.maxIterations}`));
|
|
110
|
+
console.log(chalk.bold.cyan(` ${defaultStatus.title}`));
|
|
111
|
+
console.log(chalk.bold.cyan(`${'━'.repeat(80)}\n`));
|
|
112
|
+
|
|
113
|
+
// Create a synthetic requirement object for the default requirement
|
|
114
|
+
const defaultRequirement = {
|
|
115
|
+
text: defaultStatus.description,
|
|
116
|
+
number: iterationCount,
|
|
117
|
+
isDefault: true
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Run iteration with default requirement
|
|
121
|
+
const result = await runIteration(defaultRequirement, providerConfig, repoPath);
|
|
122
|
+
|
|
123
|
+
if (result.success) {
|
|
124
|
+
// Increment iteration count
|
|
125
|
+
await defaultManager.incrementIteration();
|
|
126
|
+
console.log(chalk.bold.green(`✅ Default Requirement Iteration ${iterationCount}/${defaultStatus.maxIterations} COMPLETE`));
|
|
127
|
+
|
|
128
|
+
// Small delay between iterations
|
|
129
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
130
|
+
} else {
|
|
131
|
+
// Record failure
|
|
132
|
+
await defaultManager.recordFailure();
|
|
133
|
+
console.log(chalk.bold.red(`❌ Default Requirement Iteration ${iterationCount}/${defaultStatus.maxIterations} FAILED`));
|
|
134
|
+
console.log(chalk.red(`Error: ${result.error}\n`));
|
|
135
|
+
|
|
136
|
+
// Check consecutive failures
|
|
137
|
+
const updatedStatus = await defaultManager.getStatus();
|
|
138
|
+
if (updatedStatus.consecutiveFailures >= 5) {
|
|
139
|
+
console.log(chalk.bold.yellow('\n⚠️ Maximum consecutive failures reached'));
|
|
140
|
+
await defaultManager.markDone('Stopped due to consecutive failures');
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Delay longer after failure
|
|
145
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
countSpecCheckboxes,
|
|
152
|
+
getNextSpecTask,
|
|
153
|
+
loadEnabledIncompleteSpecs,
|
|
154
|
+
processDefaultRequirement
|
|
155
|
+
};
|