vibecodingmachine-core 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.
Files changed (202) hide show
  1. package/README.md +240 -0
  2. package/package.json +10 -2
  3. package/src/agents/Agent.js +300 -0
  4. package/src/agents/AgentAdditionService.js +311 -0
  5. package/src/agents/AgentCheckService.js +690 -0
  6. package/src/agents/AgentInstallationService.js +140 -0
  7. package/src/agents/AgentSetupService.js +467 -0
  8. package/src/agents/AgentStatus.js +183 -0
  9. package/src/agents/AgentVerificationService.js +634 -0
  10. package/src/agents/ConfigurationSchemaValidator.js +543 -0
  11. package/src/agents/EnvironmentConfigurationManager.js +602 -0
  12. package/src/agents/InstallationErrorHandler.js +372 -0
  13. package/src/agents/InstallationLog.js +363 -0
  14. package/src/agents/InstallationMethod.js +510 -0
  15. package/src/agents/InstallationOrchestrator.js +352 -0
  16. package/src/agents/InstallationProgressReporter.js +372 -0
  17. package/src/agents/InstallationRetryManager.js +322 -0
  18. package/src/agents/InstallationType.js +254 -0
  19. package/src/agents/OperationTypes.js +310 -0
  20. package/src/agents/PerformanceMetricsCollector.js +493 -0
  21. package/src/agents/SecurityValidationService.js +534 -0
  22. package/src/agents/VerificationTest.js +354 -0
  23. package/src/agents/VerificationType.js +226 -0
  24. package/src/agents/WindowsPermissionHandler.js +518 -0
  25. package/src/agents/config/AgentConfigManager.js +393 -0
  26. package/src/agents/config/AgentDefaultsRegistry.js +373 -0
  27. package/src/agents/config/ConfigValidator.js +281 -0
  28. package/src/agents/discovery/AgentDiscoveryService.js +707 -0
  29. package/src/agents/logging/AgentLogger.js +511 -0
  30. package/src/agents/status/AgentStatusManager.js +481 -0
  31. package/src/agents/storage/FileManager.js +454 -0
  32. package/src/agents/verification/AgentCommunicationTester.js +474 -0
  33. package/src/agents/verification/BaseVerifier.js +430 -0
  34. package/src/agents/verification/CommandVerifier.js +480 -0
  35. package/src/agents/verification/FileOperationVerifier.js +453 -0
  36. package/src/agents/verification/ResultAnalyzer.js +707 -0
  37. package/src/agents/verification/TestRequirementManager.js +495 -0
  38. package/src/agents/verification/VerificationRunner.js +433 -0
  39. package/src/agents/windows/BaseWindowsInstaller.js +441 -0
  40. package/src/agents/windows/ChocolateyInstaller.js +509 -0
  41. package/src/agents/windows/DirectInstaller.js +443 -0
  42. package/src/agents/windows/InstallerFactory.js +391 -0
  43. package/src/agents/windows/NpmInstaller.js +505 -0
  44. package/src/agents/windows/PowerShellInstaller.js +458 -0
  45. package/src/agents/windows/WinGetInstaller.js +390 -0
  46. package/src/analysis/analysis-reporter.js +132 -0
  47. package/src/analysis/boundary-detector.js +712 -0
  48. package/src/analysis/categorizer.js +340 -0
  49. package/src/analysis/codebase-scanner.js +384 -0
  50. package/src/analysis/line-counter.js +513 -0
  51. package/src/analysis/priority-calculator.js +679 -0
  52. package/src/analysis/report/analysis-report.js +250 -0
  53. package/src/analysis/report/package-analyzer.js +278 -0
  54. package/src/analysis/report/recommendation-generator.js +382 -0
  55. package/src/analysis/report/statistics-generator.js +515 -0
  56. package/src/analysis/reports/analysis-report-model.js +101 -0
  57. package/src/analysis/reports/recommendation-generator.js +283 -0
  58. package/src/analysis/reports/report-generators.js +191 -0
  59. package/src/analysis/reports/statistics-calculator.js +231 -0
  60. package/src/analysis/reports/trend-analyzer.js +219 -0
  61. package/src/analysis/strategy-generator.js +814 -0
  62. package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
  63. package/src/config/refactoring-config.js +307 -0
  64. package/src/health-tracking/json-storage.js +38 -2
  65. package/src/ide-integration/applescript-manager-core.js +233 -0
  66. package/src/ide-integration/applescript-manager.cjs +357 -28
  67. package/src/ide-integration/applescript-manager.js +89 -3599
  68. package/src/ide-integration/cdp-manager.js +306 -0
  69. package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
  70. package/src/ide-integration/continuation-handler.js +337 -0
  71. package/src/ide-integration/ide-status-checker.js +292 -0
  72. package/src/ide-integration/macos-ide-manager.js +627 -0
  73. package/src/ide-integration/macos-text-sender.js +528 -0
  74. package/src/ide-integration/response-reader.js +548 -0
  75. package/src/ide-integration/windows-automation-manager.js +121 -0
  76. package/src/ide-integration/windows-ide-manager.js +373 -0
  77. package/src/index.cjs +25 -3
  78. package/src/index.js +15 -1
  79. package/src/llm/direct-llm-manager.cjs +90 -2
  80. package/src/models/compliance-report.js +538 -0
  81. package/src/models/file-analysis.js +681 -0
  82. package/src/models/refactoring-plan.js +770 -0
  83. package/src/monitoring/alert-system.js +834 -0
  84. package/src/monitoring/compliance-progress-tracker.js +437 -0
  85. package/src/monitoring/continuous-scan-notifications.js +661 -0
  86. package/src/monitoring/continuous-scanner.js +279 -0
  87. package/src/monitoring/file-monitor/file-analyzer.js +262 -0
  88. package/src/monitoring/file-monitor/file-monitor.js +237 -0
  89. package/src/monitoring/file-monitor/watcher.js +194 -0
  90. package/src/monitoring/file-monitor.js +17 -0
  91. package/src/monitoring/notification-manager.js +437 -0
  92. package/src/monitoring/scanner-core.js +368 -0
  93. package/src/monitoring/scanner-events.js +214 -0
  94. package/src/monitoring/violation-notification-system.js +515 -0
  95. package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
  96. package/src/refactoring/boundaries/extraction-result.js +285 -0
  97. package/src/refactoring/boundaries/extraction-strategies.js +392 -0
  98. package/src/refactoring/boundaries/module-boundary.js +209 -0
  99. package/src/refactoring/boundary/boundary-detector.js +741 -0
  100. package/src/refactoring/boundary/boundary-types.js +405 -0
  101. package/src/refactoring/boundary/extraction-strategies.js +554 -0
  102. package/src/refactoring/boundary-extraction-result.js +77 -0
  103. package/src/refactoring/boundary-extraction-strategies.js +330 -0
  104. package/src/refactoring/boundary-extractor.js +384 -0
  105. package/src/refactoring/boundary-types.js +46 -0
  106. package/src/refactoring/circular/circular-dependency.js +88 -0
  107. package/src/refactoring/circular/cycle-detection.js +147 -0
  108. package/src/refactoring/circular/dependency-node.js +82 -0
  109. package/src/refactoring/circular/dependency-result.js +107 -0
  110. package/src/refactoring/circular/dependency-types.js +58 -0
  111. package/src/refactoring/circular/graph-builder.js +213 -0
  112. package/src/refactoring/circular/resolution-strategy.js +72 -0
  113. package/src/refactoring/circular/strategy-generator.js +229 -0
  114. package/src/refactoring/circular-dependency-resolver-original.js +809 -0
  115. package/src/refactoring/circular-dependency-resolver.js +200 -0
  116. package/src/refactoring/code-mover.js +761 -0
  117. package/src/refactoring/file-splitter.js +696 -0
  118. package/src/refactoring/functionality-validator.js +816 -0
  119. package/src/refactoring/import-manager.js +774 -0
  120. package/src/refactoring/module-boundary.js +107 -0
  121. package/src/refactoring/refactoring-executor.js +672 -0
  122. package/src/refactoring/refactoring-rollback.js +614 -0
  123. package/src/refactoring/test-validator.js +631 -0
  124. package/src/requirement-management/default-requirement-manager.js +321 -0
  125. package/src/requirement-management/requirement-file-parser.js +159 -0
  126. package/src/requirement-management/requirement-sequencer.js +221 -0
  127. package/src/rui/commands/AgentCommandParser.js +600 -0
  128. package/src/rui/commands/AgentCommands.js +487 -0
  129. package/src/rui/commands/AgentResponseFormatter.js +832 -0
  130. package/src/scripts/verify-full-compliance.js +269 -0
  131. package/src/sync/sync-engine-core.js +1 -0
  132. package/src/sync/sync-engine-remote-handlers.js +135 -0
  133. package/src/task-generation/automated-task-generator.js +351 -0
  134. package/src/task-generation/prioritizer.js +287 -0
  135. package/src/task-generation/task-list-updater.js +215 -0
  136. package/src/task-generation/task-management-integration.js +480 -0
  137. package/src/task-generation/task-manager-integration.js +270 -0
  138. package/src/task-generation/violation-task-generator.js +474 -0
  139. package/src/task-management/continuous-scan-integration.js +342 -0
  140. package/src/timeout-management/index.js +12 -3
  141. package/src/timeout-management/response-time-tracker.js +167 -0
  142. package/src/timeout-management/timeout-calculator.js +159 -0
  143. package/src/timeout-management/timeout-config-manager.js +172 -0
  144. package/src/utils/ast-analyzer.js +417 -0
  145. package/src/utils/current-requirement-manager.js +276 -0
  146. package/src/utils/current-requirement-operations.js +472 -0
  147. package/src/utils/dependency-mapper.js +456 -0
  148. package/src/utils/download-with-progress.js +4 -2
  149. package/src/utils/electron-update-checker.js +4 -1
  150. package/src/utils/file-size-analyzer.js +272 -0
  151. package/src/utils/import-updater.js +280 -0
  152. package/src/utils/refactoring-tools.js +512 -0
  153. package/src/utils/report-generator.js +569 -0
  154. package/src/utils/reports/report-analysis.js +218 -0
  155. package/src/utils/reports/report-types.js +55 -0
  156. package/src/utils/reports/summary-generators.js +102 -0
  157. package/src/utils/requirement-file-management.js +157 -0
  158. package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
  159. package/src/utils/requirement-helpers/requirement-mover.js +414 -0
  160. package/src/utils/requirement-helpers/requirement-parser.js +326 -0
  161. package/src/utils/requirement-helpers/requirement-status.js +320 -0
  162. package/src/utils/requirement-helpers-new.js +55 -0
  163. package/src/utils/requirement-helpers-refactored.js +367 -0
  164. package/src/utils/requirement-helpers.js +291 -1191
  165. package/src/utils/requirement-movement-operations.js +450 -0
  166. package/src/utils/requirement-movement.js +312 -0
  167. package/src/utils/requirement-parsing-helpers.js +56 -0
  168. package/src/utils/requirement-statistics.js +200 -0
  169. package/src/utils/requirement-text-utils.js +58 -0
  170. package/src/utils/rollback/rollback-handlers.js +125 -0
  171. package/src/utils/rollback/rollback-operation.js +63 -0
  172. package/src/utils/rollback/rollback-recorder.js +166 -0
  173. package/src/utils/rollback/rollback-state-manager.js +175 -0
  174. package/src/utils/rollback/rollback-types.js +33 -0
  175. package/src/utils/rollback/rollback-utils.js +110 -0
  176. package/src/utils/rollback-manager-original.js +569 -0
  177. package/src/utils/rollback-manager.js +202 -0
  178. package/src/utils/smoke-test-cli.js +362 -0
  179. package/src/utils/smoke-test-gui.js +351 -0
  180. package/src/utils/smoke-test-orchestrator.js +321 -0
  181. package/src/utils/smoke-test-runner.js +60 -0
  182. package/src/utils/smoke-test-web.js +347 -0
  183. package/src/utils/specification-helpers.js +39 -13
  184. package/src/utils/specification-migration.js +97 -0
  185. package/src/utils/test-runner.js +579 -0
  186. package/src/utils/validation-framework.js +518 -0
  187. package/src/validation/compliance-analyzer.js +197 -0
  188. package/src/validation/compliance-report-generator.js +343 -0
  189. package/src/validation/compliance-reporter.js +711 -0
  190. package/src/validation/compliance-rules.js +127 -0
  191. package/src/validation/constitution-validator-new.js +196 -0
  192. package/src/validation/constitution-validator.js +17 -0
  193. package/src/validation/file-validators.js +170 -0
  194. package/src/validation/line-limit/file-analyzer.js +201 -0
  195. package/src/validation/line-limit/line-limit-validator.js +208 -0
  196. package/src/validation/line-limit/validation-result.js +144 -0
  197. package/src/validation/line-limit-core.js +225 -0
  198. package/src/validation/line-limit-reporter.js +134 -0
  199. package/src/validation/line-limit-result.js +125 -0
  200. package/src/validation/line-limit-validator.js +41 -0
  201. package/src/validation/metrics-calculator.js +660 -0
  202. package/src/sync/sync-engine-backup.js +0 -559
@@ -1,1267 +1,367 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const os = require('os');
4
- const { getRequirementsPath } = require('./repo-helpers.cjs');
5
- const { logger } = require('./logger.cjs');
6
-
7
- // Default instruction text
8
- const DEFAULT_INSTRUCTION_TEXT = 'Follow INSTRUCTIONS.md from .vibecodingmachine directory. CRITICAL: You MUST work through ALL status stages (PREPARE → ACT → CLEAN UP → VERIFY → DONE) and set the status to DONE in the REQUIREMENTS file before stopping. DO NOT stop working until the "🚦 Current Status" section shows "DONE". The VibeCodingMachine app is running in autonomous mode and depends on you completing the requirement fully.';
9
-
10
1
  /**
11
- * Get ordinal suffix for numbers (1st, 2nd, 3rd, 4th, etc.)
12
- * @param {number} num - The number
13
- * @returns {string} The ordinal suffix
2
+ * Requirement Helpers (Refactored)
3
+ * Main entry point for all requirement-related operations
4
+ * Original file was 1,267 lines, now split into focused modules under 555 lines each
14
5
  */
15
- function getOrdinalSuffix(num) {
16
- const j = num % 10;
17
- const k = num % 100;
18
- if (j === 1 && k !== 11) {
19
- return 'st';
20
- }
21
- if (j === 2 && k !== 12) {
22
- return 'nd';
23
- }
24
- if (j === 3 && k !== 13) {
25
- return 'rd';
26
- }
27
- return 'th';
28
- }
29
6
 
30
- /**
31
- * Add or increment TRY AGAIN prefix to requirement text
32
- * @param {string} requirementText - The requirement text
33
- * @returns {string} Requirement text with TRY AGAIN prefix
34
- */
35
- function addTryAgainPrefix(requirementText) {
36
- const tryAgainMatch = requirementText.match(/^TRY AGAIN \((\d+)(?:st|nd|rd|th) time\): (.+)$/);
7
+ // Import all sub-modules
8
+ const requirementParser = require('./requirement-helpers/requirement-parser.js');
9
+ const requirementMover = require('./requirement-helpers/requirement-mover.js');
10
+ const requirementStatus = require('./requirement-helpers/requirement-status.js');
11
+ const requirementFileOps = require('./requirement-helpers/requirement-file-ops.js');
37
12
 
38
- if (tryAgainMatch) {
39
- const currentCount = parseInt(tryAgainMatch[1]);
40
- const baseRequirement = tryAgainMatch[2];
41
- return `TRY AGAIN (${currentCount + 1}${getOrdinalSuffix(currentCount + 1)} time): ${baseRequirement}`;
42
- } else {
43
- return `TRY AGAIN (1st time): ${requirementText}`;
44
- }
45
- }
13
+ // Re-export parser utilities
14
+ const {
15
+ DEFAULT_INSTRUCTION_TEXT,
16
+ getOrdinalSuffix,
17
+ addTryAgainPrefix,
18
+ parseRequirementLine,
19
+ extractRequirementTitle,
20
+ isRequirementMatch,
21
+ parseRequirementBlock,
22
+ findRequirementBlock,
23
+ findAllRequirementsInSection,
24
+ validateRequirementFormat,
25
+ formatRequirementForDisplay
26
+ } = requirementParser;
27
+
28
+ // Re-export movement operations
29
+ const {
30
+ promoteToVerified,
31
+ demoteFromVerifiedToTodo,
32
+ promoteTodoToVerify,
33
+ demoteFromVerifyToTodo,
34
+ moveToCurrent,
35
+ getRequirementsInSection,
36
+ getRequirementStatistics
37
+ } = requirementMover;
38
+
39
+ // Re-export status management
40
+ const {
41
+ extractCurrentStatus,
42
+ updateCurrentStatus,
43
+ getCurrentStatus,
44
+ isStatusDone,
45
+ isStatusInProgress,
46
+ getStatusStage,
47
+ validateStatus,
48
+ getNextStatus,
49
+ getPreviousStatus,
50
+ isValidStatusTransition,
51
+ getStatusHistory,
52
+ formatStatusForDisplay,
53
+ getStatusSummary
54
+ } = requirementStatus;
55
+
56
+ // Re-export file operations
57
+ const {
58
+ getRequirementsFilePath,
59
+ requirementsFileExists,
60
+ createRequirementsFile,
61
+ readRequirementsFile,
62
+ writeRequirementsFile,
63
+ backupRequirementsFile,
64
+ getRequirementsFileStats,
65
+ validateRequirementsFile,
66
+ getAllRequirementsFiles,
67
+ cleanupBackupFiles
68
+ } = requirementFileOps;
46
69
 
47
70
  /**
48
- * Parse requirement from markdown line
49
- * @param {string} line - Markdown line (e.g., "- Requirement text")
50
- * @returns {string} Requirement text without markdown prefix
71
+ * Get comprehensive requirement system information
72
+ * @param {string} repoPath - Repository path (optional)
73
+ * @returns {Promise<Object>} System information
51
74
  */
52
- function parseRequirementLine(line) {
53
- if (line.startsWith('- ')) {
54
- return line.substring(2);
75
+ async function getRequirementSystemInfo(repoPath = null) {
76
+ try {
77
+ const fileStats = await getRequirementsFileStats(repoPath);
78
+ const validation = await validateRequirementsFile(repoPath);
79
+ const statusSummary = await getStatusSummary(getRequirementsFilePath(repoPath));
80
+ const requirementStats = await getRequirementStatistics(getRequirementsFilePath(repoPath));
81
+ const allFiles = await getAllRequirementsFiles(repoPath || process.cwd());
82
+
83
+ return {
84
+ file: fileStats,
85
+ validation,
86
+ status: statusSummary,
87
+ statistics: requirementStats,
88
+ allFiles,
89
+ timestamp: new Date().toISOString()
90
+ };
91
+ } catch (error) {
92
+ return {
93
+ error: error.message,
94
+ timestamp: new Date().toISOString()
95
+ };
55
96
  }
56
- return line;
57
97
  }
58
98
 
59
99
  /**
60
- * Move requirement from TO VERIFY section to VERIFIED (CHANGELOG)
61
- * @param {string} reqPath - Path to REQUIREMENTS file
62
- * @param {string} requirementTitle - Title of requirement to move
63
- * @returns {Promise<boolean>} Success status
100
+ * Initialize requirements system
101
+ * @param {string} repoPath - Repository path
102
+ * @returns {Promise<Object>} Initialization result
64
103
  */
65
- async function promoteToVerified(reqPath, requirementTitle) {
104
+ async function initializeRequirementsSystem(repoPath) {
66
105
  try {
67
- const content = await fs.readFile(reqPath, 'utf-8');
68
- const lines = content.split('\n');
69
- let inVerifySection = false;
70
- let requirementStartIndex = -1;
71
- let requirementEndIndex = -1;
72
- const normalizedTitle = requirementTitle.trim();
73
-
74
- // Find the requirement in TO VERIFY section (new ### format)
75
- for (let i = 0; i < lines.length; i++) {
76
- const line = lines[i];
77
- const trimmed = line.trim();
78
-
79
- // Check if we're entering TO VERIFY section (multiple variants)
80
- if (trimmed.startsWith('##') && !trimmed.startsWith('###') &&
81
- (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot'))) {
82
- inVerifySection = true;
83
- continue;
84
- }
85
-
86
- // Check if we're leaving TO VERIFY section
87
- if (inVerifySection && trimmed.startsWith('##') && !trimmed.startsWith('###')) {
88
- inVerifySection = false;
89
- }
90
-
91
- // Look for requirement in TO VERIFY section (### header format)
92
- if (inVerifySection && trimmed.startsWith('###')) {
93
- const title = trimmed.replace(/^###\s*/, '').trim();
94
- if (title === normalizedTitle || title.includes(normalizedTitle) || normalizedTitle.includes(title)) {
95
- requirementStartIndex = i;
106
+ const result = {
107
+ success: false,
108
+ actions: [],
109
+ warnings: [],
110
+ errors: []
111
+ };
96
112
 
97
- // Find the end of this requirement block
98
- for (let j = i + 1; j < lines.length; j++) {
99
- const nextLine = lines[j].trim();
100
- if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
101
- requirementEndIndex = j;
102
- break;
103
- }
104
- }
105
- if (requirementEndIndex === -1) {
106
- requirementEndIndex = lines.length;
107
- }
108
- break;
109
- }
113
+ // Check if requirements file exists
114
+ if (!requirementsFileExists(repoPath)) {
115
+ result.actions.push('Creating requirements file...');
116
+ const created = await createRequirementsFile(repoPath);
117
+ if (created) {
118
+ result.actions.push('✅ Requirements file created');
119
+ } else {
120
+ result.errors.push('❌ Failed to create requirements file');
121
+ return result;
110
122
  }
123
+ } else {
124
+ result.actions.push('✅ Requirements file already exists');
111
125
  }
112
126
 
113
- if (requirementStartIndex === -1) {
114
- return false;
127
+ // Validate existing file
128
+ const validation = await validateRequirementsFile(repoPath);
129
+ if (!validation.isValid) {
130
+ result.warnings.push('⚠️ Requirements file has validation issues');
131
+ result.warnings.push(...validation.errors);
132
+ }
133
+ if (validation.warnings.length > 0) {
134
+ result.warnings.push('⚠️ Requirements file has warnings');
135
+ result.warnings.push(...validation.warnings);
115
136
  }
116
137
 
117
- // Extract requirement block
118
- const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
119
- const extractedTitle = lines[requirementStartIndex].replace(/^###\s*/, '').trim();
120
-
121
- // Remove requirement from TO VERIFY section
122
- lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
123
-
124
- // Add to CHANGELOG.md
125
- const allnightDir = path.dirname(reqPath);
126
- const repoRoot = path.dirname(allnightDir);
127
- const changelogPath = path.join(repoRoot, 'CHANGELOG.md');
128
- const timestamp = new Date().toISOString().split('T')[0];
129
- const changelogEntry = `- ${extractedTitle} (${timestamp})`;
130
-
131
- let changelogContent = '';
132
- if (await fs.pathExists(changelogPath)) {
133
- changelogContent = await fs.readFile(changelogPath, 'utf-8');
134
- } else {
135
- changelogContent = '# Changelog\n\n## Verified Requirements\n\n';
138
+ // Create backup
139
+ const backupPath = await backupRequirementsFile(repoPath);
140
+ if (backupPath) {
141
+ result.actions.push(`✅ Backup created: ${backupPath}`);
136
142
  }
137
143
 
138
- if (changelogContent.includes('## Verified Requirements')) {
139
- changelogContent = changelogContent.replace(
140
- '## Verified Requirements\n',
141
- `## Verified Requirements\n${changelogEntry}\n`
142
- );
143
- } else {
144
- changelogContent += `\n## Verified Requirements\n${changelogEntry}\n`;
144
+ // Clean up old backups
145
+ const cleanedCount = await cleanupBackupFiles(repoPath);
146
+ if (cleanedCount > 0) {
147
+ result.actions.push(`🗑️ Cleaned up ${cleanedCount} old backup files`);
145
148
  }
146
149
 
147
- await fs.writeFile(changelogPath, changelogContent);
148
- await fs.writeFile(reqPath, lines.join('\n'));
149
- return true;
150
+ result.success = true;
151
+ return result;
152
+
150
153
  } catch (error) {
151
- throw new Error(`Failed to promote requirement to verified: ${error.message}`);
154
+ return {
155
+ success: false,
156
+ actions: [],
157
+ warnings: [],
158
+ errors: [`Initialization failed: ${error.message}`]
159
+ };
152
160
  }
153
161
  }
154
162
 
155
163
  /**
156
- * Move requirement from VERIFIED (CHANGELOG) back to TODO with TRY AGAIN prefix
157
- * @param {string} reqPath - Path to REQUIREMENTS file
158
- * @param {string} requirementTitle - Title of requirement to move
159
- * @returns {Promise<boolean>} Success status
164
+ * Get requirement workflow status
165
+ * @param {string} repoPath - Repository path (optional)
166
+ * @returns {Promise<Object>} Workflow status
160
167
  */
161
- async function demoteFromVerifiedToTodo(reqPath, requirementTitle) {
168
+ async function getWorkflowStatus(repoPath = null) {
162
169
  try {
163
- // CHANGELOG.md should be at repository root, not in .vibecodingmachine directory
164
- const allnightDir = path.dirname(reqPath); // .vibecodingmachine directory
165
- const repoRoot = path.dirname(allnightDir); // repository root (one level up)
166
- const changelogPath = path.join(repoRoot, 'CHANGELOG.md');
167
-
168
- if (!(await fs.pathExists(changelogPath))) {
169
- return false;
170
- }
171
-
172
- let changelogContent = await fs.readFile(changelogPath, 'utf-8');
173
- const changelogLines = changelogContent.split('\n');
174
- const updatedChangelogLines = [];
175
- let requirementToMove = null;
176
-
177
- for (const line of changelogLines) {
178
- if (line.startsWith('- ')) {
179
- const lineText = parseRequirementLine(line);
180
- // Extract title part (before timestamp in parentheses)
181
- const titleMatch = lineText.match(/^(.+?)\s*\([\d-]+\)$/);
182
- const lineTitle = titleMatch ? titleMatch[1] : lineText;
183
-
184
- // Check if this line matches the requirement title
185
- // Handle both cases: requirementTitle might include timestamp or not
186
- const reqTitleMatch = requirementTitle.match(/^(.+?)\s*\([\d-]+\)$/);
187
- const reqTitleOnly = reqTitleMatch ? reqTitleMatch[1] : requirementTitle;
188
-
189
- if (lineTitle === reqTitleOnly || lineTitle.includes(reqTitleOnly) || reqTitleOnly.includes(lineTitle)) {
190
- requirementToMove = lineTitle;
191
- continue;
192
- }
193
- }
194
- updatedChangelogLines.push(line);
195
- }
196
-
197
- if (!requirementToMove) {
198
- return false;
199
- }
200
-
201
- await fs.writeFile(changelogPath, updatedChangelogLines.join('\n'));
202
-
203
- const content = await fs.readFile(reqPath, 'utf-8');
204
- const lines = content.split('\n');
205
- const updatedLines = [];
206
- let foundTodoSection = false;
170
+ const status = await getCurrentStatus(repoPath);
171
+ const stage = getStatusStage(status);
172
+ const isDone = isStatusDone(status);
173
+ const nextStatus = getNextStatus(status);
174
+ const stats = await getRequirementStatistics(getRequirementsFilePath(repoPath));
207
175
 
208
- for (let i = 0; i < lines.length; i++) {
209
- const line = lines[i];
210
-
211
- if (line.includes('## ⏳ Requirements not yet completed')) {
212
- foundTodoSection = true;
213
- updatedLines.push(line);
214
- const requirementText = addTryAgainPrefix(requirementToMove);
215
- updatedLines.push(`- ${requirementText}`);
216
- continue;
217
- }
218
-
219
- updatedLines.push(line);
220
- }
221
-
222
- if (!foundTodoSection) {
223
- updatedLines.push('## ⏳ Requirements not yet completed');
224
- const requirementText = addTryAgainPrefix(requirementToMove);
225
- updatedLines.push(`- ${requirementText}`);
226
- }
227
-
228
- await fs.writeFile(reqPath, updatedLines.join('\n'));
229
- return true;
176
+ return {
177
+ current: status,
178
+ stage,
179
+ isDone,
180
+ nextStatus,
181
+ canProceed: !isDone && nextStatus !== null,
182
+ requirementsCount: stats.total,
183
+ todoCount: stats.todo,
184
+ verifyCount: stats.verify,
185
+ currentCount: stats.current,
186
+ timestamp: new Date().toISOString()
187
+ };
230
188
  } catch (error) {
231
- throw new Error(`Failed to demote requirement from verified: ${error.message}`);
189
+ return {
190
+ error: error.message,
191
+ timestamp: new Date().toISOString()
192
+ };
232
193
  }
233
194
  }
234
195
 
235
196
  /**
236
- * Move requirement from TODO to TO VERIFY section
237
- * @param {string} reqPath - Path to REQUIREMENTS file
238
- * @param {string} requirementTitle - Title of requirement to move
239
- * @returns {Promise<boolean>} Success status
197
+ * Advance requirement workflow to next status
198
+ * @param {string} repoPath - Repository path (optional)
199
+ * @returns {Promise<Object>} Result of advancement
240
200
  */
241
- async function promoteTodoToVerify(reqPath, requirementTitle) {
201
+ async function advanceWorkflow(repoPath = null) {
242
202
  try {
243
- const content = await fs.readFile(reqPath, 'utf-8');
244
- const lines = content.split('\n');
245
-
246
- // Find the requirement block (### header format)
247
- let requirementStartIndex = -1;
248
- let requirementEndIndex = -1;
249
- let inTodoSection = false;
250
-
251
- for (let i = 0; i < lines.length; i++) {
252
- const line = lines[i].trim();
253
-
254
- if (line.includes('## ⏳ Requirements not yet completed')) {
255
- inTodoSection = true;
256
- continue;
257
- }
258
-
259
- if (inTodoSection && line.startsWith('##') && !line.startsWith('###')) {
260
- break;
261
- }
262
-
263
- if (inTodoSection && line.startsWith('###')) {
264
- const title = line.replace(/^###\s*/, '').trim();
265
- if (title && (title === requirementTitle || title.includes(requirementTitle) || requirementTitle.includes(title))) {
266
- requirementStartIndex = i;
267
- // Find the end of this requirement (next ### or ## header)
268
- for (let j = i + 1; j < lines.length; j++) {
269
- const nextLine = lines[j].trim();
270
- if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
271
- requirementEndIndex = j;
272
- break;
273
- }
274
- }
275
- if (requirementEndIndex === -1) {
276
- requirementEndIndex = lines.length;
277
- }
278
- break;
279
- }
280
- }
281
- }
282
-
283
- if (requirementStartIndex === -1) {
284
- return false;
285
- }
286
-
287
- // Extract the requirement block
288
- const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
289
-
290
- // Remove the requirement from its current location
291
- const updatedLines = [
292
- ...lines.slice(0, requirementStartIndex),
293
- ...lines.slice(requirementEndIndex)
294
- ];
295
-
296
- // Find or create TO VERIFY section
297
- const verifySectionVariants = [
298
- '## 🔍 TO VERIFY BY HUMAN',
299
- '## 🔍 TO VERIFY',
300
- '## TO VERIFY',
301
- '## ✅ TO VERIFY',
302
- '## ✅ Verified by AI screenshot'
303
- ];
304
-
305
- let verifyIndex = -1;
306
- for (let i = 0; i < updatedLines.length; i++) {
307
- if (verifySectionVariants.some(variant => updatedLines[i].includes(variant))) {
308
- verifyIndex = i;
309
- break;
310
- }
311
- }
312
-
313
- if (verifyIndex === -1) {
314
- // Create TO VERIFY section before CHANGELOG or at end
315
- const changelogIndex = updatedLines.findIndex(line => line.includes('## CHANGELOG'));
316
- const insertIndex = changelogIndex > 0 ? changelogIndex : updatedLines.length;
317
- updatedLines.splice(insertIndex, 0, '', '## 🔍 TO VERIFY BY HUMAN', '');
318
- verifyIndex = insertIndex + 1;
319
- }
203
+ const currentStatus = await getCurrentStatus(repoPath);
204
+ const nextStatus = getNextStatus(currentStatus);
320
205
 
321
- // Insert requirement block after section header
322
- let insertIndex = verifyIndex + 1;
323
- while (insertIndex < updatedLines.length && updatedLines[insertIndex].trim() === '') {
324
- insertIndex++;
325
- }
326
- updatedLines.splice(insertIndex, 0, ...requirementBlock);
327
- // Add blank line after if needed
328
- if (insertIndex + requirementBlock.length < updatedLines.length && updatedLines[insertIndex + requirementBlock.length].trim() !== '') {
329
- updatedLines.splice(insertIndex + requirementBlock.length, 0, '');
206
+ if (!nextStatus) {
207
+ return {
208
+ success: false,
209
+ message: 'Already at DONE status or invalid current status',
210
+ currentStatus,
211
+ nextStatus: null
212
+ };
330
213
  }
331
214
 
332
- await fs.writeFile(reqPath, updatedLines.join('\n'));
333
- return true;
215
+ const updated = await updateCurrentStatus(repoPath, nextStatus);
216
+
217
+ return {
218
+ success: updated,
219
+ message: updated ? `Status advanced from ${currentStatus} to ${nextStatus}` : 'Failed to update status',
220
+ previousStatus: currentStatus,
221
+ currentStatus: nextStatus
222
+ };
334
223
  } catch (error) {
335
- throw new Error(`Failed to promote requirement from TODO to TO VERIFY: ${error.message}`);
224
+ return {
225
+ success: false,
226
+ message: `Error advancing workflow: ${error.message}`,
227
+ error: error.message
228
+ };
336
229
  }
337
230
  }
338
231
 
339
232
  /**
340
- * Move requirement from TO VERIFY back to TODO section
341
- * @param {string} reqPath - Path to REQUIREMENTS file
342
- * @param {string} requirementTitle - Title of requirement to move
343
- * @param {string} explanation - Optional explanation of what went wrong
344
- * @returns {Promise<boolean>} Success status
233
+ * Get requirement health check
234
+ * @param {string} repoPath - Repository path (optional)
235
+ * @returns {Promise<Object>} Health check results
345
236
  */
346
- async function demoteVerifyToTodo(reqPath, requirementTitle, explanation = '') {
237
+ async function getHealthCheck(repoPath = null) {
347
238
  try {
348
- const content = await fs.readFile(reqPath, 'utf-8');
349
- const lines = content.split('\n');
350
-
351
- // Find ALL matching requirements in TO VERIFY section and remove them
352
- // We'll collect all requirement blocks to remove, then process them
353
- const requirementsToRemove = [];
354
- let inVerifySection = false;
355
-
356
- const verifySectionVariants = [
357
- '## 🔍 TO VERIFY BY HUMAN',
358
- '## 🔍 TO VERIFY',
359
- '## TO VERIFY',
360
- '## ✅ TO VERIFY',
361
- '## ✅ Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG',
362
- '## ✅ Verified by AI screenshot'
363
- ];
364
-
365
- // First pass: find all matching requirements in TO VERIFY section
366
- for (let i = 0; i < lines.length; i++) {
367
- const line = lines[i];
368
- const trimmed = line.trim();
369
-
370
- // Check if this is a TO VERIFY section header
371
- if (trimmed.startsWith('##') && !trimmed.startsWith('###')) {
372
- const isToVerifyHeader = verifySectionVariants.some(variant => {
373
- return trimmed === variant || trimmed.startsWith(variant) ||
374
- (trimmed.includes('Verified by AI screenshot') && trimmed.includes('Needs Human to Verify'));
375
- });
376
-
377
- if (isToVerifyHeader) {
378
- // Make sure it's not a VERIFIED section (without TO VERIFY)
379
- if (!trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i) && !trimmed.includes('📝 VERIFIED')) {
380
- inVerifySection = true;
381
- continue;
382
- }
383
- } else if (inVerifySection) {
384
- // Check if we're leaving TO VERIFY section (hit a different section)
385
- if (trimmed.includes('⏳ Requirements not yet completed') ||
386
- trimmed.includes('## 📝 VERIFIED') ||
387
- trimmed.includes('## ♻️ RECYCLED') ||
388
- trimmed.includes('## 📦 RECYCLED') ||
389
- trimmed.includes('## ❓ Requirements needing')) {
390
- // We've left the TO VERIFY section
391
- inVerifySection = false;
392
- }
393
- }
394
- }
395
-
396
- // Look for requirement in TO VERIFY section
397
- if (inVerifySection && trimmed.startsWith('###')) {
398
- const title = trimmed.replace(/^###\s*/, '').trim();
399
- // Normalize titles for matching (handle TRY AGAIN prefixes)
400
- const normalizedTitle = title.replace(/^TRY AGAIN \(\d+(st|nd|rd|th) time\):\s*/i, '').trim();
401
- const normalizedRequirementTitle = requirementTitle.replace(/^TRY AGAIN \(\d+(st|nd|rd|th) time\):\s*/i, '').trim();
402
-
403
- if (title && (title === requirementTitle ||
404
- normalizedTitle === normalizedRequirementTitle ||
405
- title.includes(requirementTitle) ||
406
- requirementTitle.includes(title) ||
407
- normalizedTitle.includes(normalizedRequirementTitle) ||
408
- normalizedRequirementTitle.includes(normalizedTitle))) {
409
- // Find the end of this requirement (next ### or ## header)
410
- let requirementEndIndex = lines.length;
411
- for (let j = i + 1; j < lines.length; j++) {
412
- const nextLine = lines[j].trim();
413
- if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
414
- requirementEndIndex = j;
415
- break;
416
- }
417
- }
418
-
419
- // Store this requirement to remove (we'll use the first one for moving to TODO)
420
- requirementsToRemove.push({
421
- start: i,
422
- end: requirementEndIndex,
423
- block: lines.slice(i, requirementEndIndex)
424
- });
425
- }
426
- }
427
- }
239
+ const fileStats = await getRequirementsFileStats(repoPath);
240
+ const validation = await validateRequirementsFile(repoPath);
241
+ const statusSummary = await getStatusSummary(getRequirementsFilePath(repoPath));
242
+ const stats = await getRequirementStatistics(getRequirementsFilePath(repoPath));
243
+
244
+ const health = {
245
+ status: 'healthy',
246
+ issues: [],
247
+ recommendations: [],
248
+ score: 100
249
+ };
428
250
 
429
- if (requirementsToRemove.length === 0) {
430
- return false;
251
+ // Check file existence
252
+ if (!fileStats.exists) {
253
+ health.status = 'critical';
254
+ health.issues.push('Requirements file does not exist');
255
+ health.recommendations.push('Create a requirements file');
256
+ health.score -= 50;
431
257
  }
432
258
 
433
- // Use the first matching requirement for moving to TODO (with TRY AGAIN prefix)
434
- const firstRequirement = requirementsToRemove[0];
435
- const requirementBlock = [...firstRequirement.block];
436
-
437
- // Update title with TRY AGAIN prefix
438
- const originalTitle = requirementBlock[0].replace(/^###\s*/, '').trim();
439
- const titleWithPrefix = addTryAgainPrefix(originalTitle);
440
- requirementBlock[0] = `### ${titleWithPrefix}`;
441
-
442
- // Add explanation to the requirement description if provided
443
- if (explanation && explanation.trim()) {
444
- // Find where to insert the explanation (after the title, before any existing content)
445
- // Insert after first line (title) with a blank line and "What went wrong:" section
446
- const explanationLines = [
447
- '',
448
- '**What went wrong (from previous attempt):**',
449
- explanation.trim(),
450
- ''
451
- ];
452
- requirementBlock.splice(1, 0, ...explanationLines);
259
+ // Check validation
260
+ if (!validation.isValid) {
261
+ health.status = 'warning';
262
+ health.issues.push('Requirements file has validation errors');
263
+ health.recommendations.push('Fix validation errors');
264
+ health.score -= 20;
453
265
  }
454
266
 
455
- // Remove ALL matching requirements from TO VERIFY section (work backwards to preserve indices)
456
- const updatedLines = [...lines];
457
- for (let i = requirementsToRemove.length - 1; i >= 0; i--) {
458
- const req = requirementsToRemove[i];
459
- updatedLines.splice(req.start, req.end - req.start);
267
+ // Check status
268
+ if (!statusSummary.current) {
269
+ health.issues.push('No current status set');
270
+ health.recommendations.push('Set a current status');
271
+ health.score -= 10;
460
272
  }
461
273
 
462
- // Find or create TODO section
463
- let todoIndex = -1;
464
- for (let i = 0; i < updatedLines.length; i++) {
465
- if (updatedLines[i].includes('## Requirements not yet completed')) {
466
- todoIndex = i;
467
- break;
468
- }
274
+ // Check for stuck requirements
275
+ if (stats.verify > 10) {
276
+ health.issues.push('Many requirements waiting for verification');
277
+ health.recommendations.push('Review and verify pending requirements');
278
+ health.score -= 5;
469
279
  }
470
280
 
471
- if (todoIndex === -1) {
472
- // Create TODO section at the top (after initial headers)
473
- const firstSectionIndex = updatedLines.findIndex(line => line.startsWith('##') && !line.startsWith('###'));
474
- const insertIndex = firstSectionIndex > 0 ? firstSectionIndex : updatedLines.length;
475
- updatedLines.splice(insertIndex, 0, '## ⏳ Requirements not yet completed', '');
476
- todoIndex = insertIndex;
281
+ // Check file size
282
+ if (fileStats.size > 50000) { // 50KB
283
+ health.issues.push('Requirements file is large');
284
+ health.recommendations.push('Consider archiving old requirements');
285
+ health.score -= 5;
477
286
  }
478
287
 
479
- // Insert requirement block after section header
480
- let insertIndex = todoIndex + 1;
481
- while (insertIndex < updatedLines.length && updatedLines[insertIndex].trim() === '') {
482
- insertIndex++;
483
- }
484
- updatedLines.splice(insertIndex, 0, ...requirementBlock);
485
- // Add blank line after if needed
486
- if (insertIndex + requirementBlock.length < updatedLines.length && updatedLines[insertIndex + requirementBlock.length].trim() !== '') {
487
- updatedLines.splice(insertIndex + requirementBlock.length, 0, '');
488
- }
489
-
490
- await fs.writeFile(reqPath, updatedLines.join('\n'));
491
- return true;
492
- } catch (error) {
493
- throw new Error(`Failed to demote requirement from TO VERIFY to TODO: ${error.message}`);
494
- }
495
- }
496
-
497
- /**
498
- * Load verified requirements from CHANGELOG.md
499
- * @param {string} repoPath - Repository root path
500
- * @returns {Promise<string[]>} List of verified requirement titles
501
- */
502
- async function loadVerifiedFromChangelog(repoPath) {
503
- try {
504
- const changelogPath = path.join(repoPath, 'CHANGELOG.md');
505
- if (!(await fs.pathExists(changelogPath))) {
506
- return [];
288
+ // Determine final status
289
+ if (health.score >= 90) {
290
+ health.status = 'healthy';
291
+ } else if (health.score >= 70) {
292
+ health.status = 'warning';
293
+ } else {
294
+ health.status = 'critical';
507
295
  }
508
296
 
509
- const content = await fs.readFile(changelogPath, 'utf8');
510
- const lines = content.split('\n');
511
- const requirements = [];
512
- let inVerifiedSection = false;
297
+ return health;
513
298
 
514
- for (const line of lines) {
515
- const trimmed = line.trim();
516
-
517
- if (trimmed.includes('## Verified Requirements')) {
518
- inVerifiedSection = true;
519
- continue;
520
- }
521
-
522
- if (inVerifiedSection && trimmed.startsWith('##') && !trimmed.includes('Verified Requirements')) {
523
- break;
524
- }
525
-
526
- // Collect items starting with "- " as verified requirements
527
- if (inVerifiedSection && trimmed.startsWith('- ') && trimmed.length > 5) {
528
- let reqText = trimmed.substring(2);
529
- // Extract title part (before timestamp in parentheses if present)
530
- const titleMatch = reqText.match(/^(.+?)\s*\([\d-]+\)$/);
531
- if (titleMatch) {
532
- reqText = titleMatch[1];
533
- }
534
- requirements.push(reqText.trim());
535
- }
536
- }
537
-
538
- return requirements;
539
299
  } catch (error) {
540
- logger.error('❌ Error loading verified requirements from CHANGELOG.md:', error);
541
- return [];
542
- }
543
- }
544
-
545
- /**
546
- * Get unified project requirement statistics (TODO, TO VERIFY, VERIFIED)
547
- * @param {string} repoPath - Repository root path
548
- * @returns {Promise<Object>} Statistics with counts and formatted percentages
549
- */
550
- async function getProjectRequirementStats(repoPath) {
551
- try {
552
- const hostname = os.hostname();
553
- const { getRequirementsPath } = require('./repo-helpers.cjs');
554
- const reqPath = await getRequirementsPath(repoPath, hostname);
555
-
556
- let todoCount = 0;
557
- let toVerifyCount = 0;
558
- let verifiedCount = 0;
559
- let clarificationCount = 0;
560
- let recycledCount = 0;
561
-
562
- if (reqPath && await fs.pathExists(reqPath)) {
563
- const content = await fs.readFile(reqPath, 'utf8');
564
- const lines = content.split('\n');
565
- let currentSection = '';
566
-
567
- const verifySectionVariants = [
568
- '🔍 TO VERIFY BY HUMAN',
569
- 'TO VERIFY BY HUMAN',
570
- '🔍 TO VERIFY',
571
- 'TO VERIFY',
572
- '✅ Verified by AI screenshot',
573
- 'Verified by AI screenshot'
574
- ];
575
-
576
- const clarificationVariants = [
577
- 'NEEDING CLARIFICATION',
578
- 'Requirements that need information',
579
- 'need information'
580
- ];
581
-
582
- const recycledVariants = [
583
- '♻️ Recycled',
584
- 'Recycled'
585
- ];
586
-
587
- for (const line of lines) {
588
- const trimmed = line.trim();
589
-
590
- if (trimmed.startsWith('###')) {
591
- if (currentSection) {
592
- // Remove ALL leading ### markers including spaces between them (handles "###", "### ###", "#### ####", etc.)
593
- const requirementText = trimmed.replace(/^(#{1,}\s*)+/, '').trim();
594
- // Filter out empty titles and package names
595
- const packageNames = ['cli', 'core', 'electron-app', 'web', 'mobile', 'vscode-extension', 'sync-server'];
596
- if (requirementText && requirementText.length > 0 && !packageNames.includes(requirementText.toLowerCase())) {
597
- if (currentSection === 'todo') todoCount++;
598
- else if (currentSection === 'toverify') toVerifyCount++;
599
- else if (currentSection === 'clarification') clarificationCount++;
600
- else if (currentSection === 'recycled') recycledCount++;
601
- }
602
- }
603
- } else if (trimmed.startsWith('##') && !trimmed.startsWith('###')) {
604
- if (trimmed.includes('⏳ Requirements not yet completed') ||
605
- trimmed.includes('Requirements not yet completed')) {
606
- currentSection = 'todo';
607
- } else if (verifySectionVariants.some(v => trimmed.includes(v))) {
608
- currentSection = 'toverify';
609
- } else if (clarificationVariants.some(v => trimmed.includes(v))) {
610
- currentSection = 'clarification';
611
- } else if (recycledVariants.some(v => trimmed.includes(v))) {
612
- currentSection = 'recycled';
613
- } else {
614
- currentSection = '';
615
- }
616
- }
617
- }
618
- }
619
-
620
- // Load verified counts from CHANGELOG.md
621
- const verifiedReqs = await loadVerifiedFromChangelog(repoPath);
622
- verifiedCount = verifiedReqs.length;
623
-
624
- const total = todoCount + toVerifyCount + verifiedCount + clarificationCount + recycledCount;
625
- const todoPercent = total > 0 ? Math.round((todoCount / total) * 100) : 0;
626
- const toVerifyPercent = total > 0 ? Math.round((toVerifyCount / total) * 100) : 0;
627
- const verifiedPercent = total > 0 ? Math.round((verifiedCount / total) * 100) : 0;
628
- const clarificationPercent = total > 0 ? Math.round((clarificationCount / total) * 100) : 0;
629
- const recycledPercent = total > 0 ? Math.round((recycledCount / total) * 100) : 0;
630
-
631
300
  return {
632
- todoCount,
633
- toVerifyCount,
634
- verifiedCount,
635
- clarificationCount,
636
- recycledCount,
637
- total,
638
- todoPercent,
639
- toVerifyPercent,
640
- verifiedPercent,
641
- clarificationPercent,
642
- recycledPercent,
643
- todoLabel: `TODO (${todoCount} - ${todoPercent}%)`,
644
- toVerifyLabel: `TO VERIFY (${toVerifyCount} - ${toVerifyPercent}%)`,
645
- verifiedLabel: `VERIFIED (${verifiedCount} - ${verifiedPercent}%)`,
646
- clarificationLabel: `CLARIFICATION (${clarificationCount} - ${clarificationPercent}%)`,
647
- recycledLabel: `RECYCLED (${recycledCount} - ${recycledPercent}%)`
301
+ status: 'error',
302
+ issues: [`Health check failed: ${error.message}`],
303
+ recommendations: ['Check file permissions and paths'],
304
+ score: 0,
305
+ error: error.message
648
306
  };
649
- } catch (error) {
650
- logger.error('❌ Error getting project requirement stats:', error);
651
- return null;
652
307
  }
653
308
  }
654
309
 
310
+ // Export everything
655
311
  module.exports = {
312
+ // Parser utilities
313
+ DEFAULT_INSTRUCTION_TEXT,
656
314
  getOrdinalSuffix,
657
315
  addTryAgainPrefix,
658
316
  parseRequirementLine,
317
+ extractRequirementTitle,
318
+ isRequirementMatch,
319
+ parseRequirementBlock,
320
+ findRequirementBlock,
321
+ findAllRequirementsInSection,
322
+ validateRequirementFormat,
323
+ formatRequirementForDisplay,
324
+
325
+ // Movement operations
659
326
  promoteToVerified,
660
327
  demoteFromVerifiedToTodo,
661
328
  promoteTodoToVerify,
662
- demoteVerifyToTodo,
663
- // New shared functions
664
- getCurrentRequirement,
665
- getCurrentRequirementName,
666
- getCurrentRequirementProgress,
667
- isCurrentRequirementDone,
668
- moveToNextRequirement,
669
- createDefaultRequirementsFile,
670
- getOrCreateRequirementsFilePath,
671
- loadVerifiedFromChangelog,
672
- getProjectRequirementStats,
673
- DEFAULT_INSTRUCTION_TEXT
329
+ demoteFromVerifyToTodo,
330
+ moveToCurrent,
331
+ getRequirementsInSection,
332
+ getRequirementStatistics,
333
+
334
+ // Status management
335
+ extractCurrentStatus,
336
+ updateCurrentStatus,
337
+ getCurrentStatus,
338
+ isStatusDone,
339
+ isStatusInProgress,
340
+ getStatusStage,
341
+ validateStatus,
342
+ getNextStatus,
343
+ getPreviousStatus,
344
+ isValidStatusTransition,
345
+ getStatusHistory,
346
+ formatStatusForDisplay,
347
+ getStatusSummary,
348
+
349
+ // File operations
350
+ getRequirementsFilePath,
351
+ requirementsFileExists,
352
+ createRequirementsFile,
353
+ readRequirementsFile,
354
+ writeRequirementsFile,
355
+ backupRequirementsFile,
356
+ getRequirementsFileStats,
357
+ validateRequirementsFile,
358
+ getAllRequirementsFiles,
359
+ cleanupBackupFiles,
360
+
361
+ // High-level operations
362
+ getRequirementSystemInfo,
363
+ initializeRequirementsSystem,
364
+ getWorkflowStatus,
365
+ advanceWorkflow,
366
+ getHealthCheck
674
367
  };
675
-
676
- // --- Ported Functions from Electron App ---
677
-
678
- // Function to create a default requirements file
679
- function createDefaultRequirementsFile(repoPath) {
680
- try {
681
- const hostname = os.hostname();
682
- // Use the core logic to find the .vibecodingmachine directory
683
- // Note: This logic assumes we want to create it INSIDE the repo if it doesn't exist?
684
- // Electron app logic was: path.join(repoPath, '.vibecodingmachine')
685
- // We'll stick to that for creation.
686
- const vibecodingmachineDir = path.join(repoPath, '.vibecodingmachine');
687
-
688
- // Ensure .vibecodingmachine directory exists
689
- if (!fs.existsSync(vibecodingmachineDir)) {
690
- fs.mkdirSync(vibecodingmachineDir, { recursive: true });
691
- logger.log('📁 Created .vibecodingmachine directory');
692
- }
693
-
694
- // Create hostname-specific requirements file
695
- const requirementsFilePath = path.join(vibecodingmachineDir, `REQUIREMENTS-${hostname}.md`);
696
-
697
- const defaultContent = `# 🌙 VibeCodingMachine – Requirements File
698
-
699
- This is a Markdown (.md) file.
700
-
701
- You should not need to modify this file, as VibeCodingMachine will modify it for you, but you can add requirements and move them around either here directly, or via AI.
702
-
703
- This file contains the requirements to complete the project. Each item in a list is a self contained requirement that should be able to stand on its own, and not require reference to other requirements. Each requirement starts in the section of requirements to complete, then it moved to the section with the current requirement being worked on. VibeCodingMachine will then, after implementing the requirement, move it to the completed requirements list in the CHANGELOG.md file, or to the section in this file for requirements that need attention. These will be available for you to review. They should have options to choose, and you decide which option to take, and VibeCodingMachine will work on that again the next time it is run.
704
-
705
- ## RESPONSE FROM LAST CHAT
706
-
707
- ### ONE LINE STATUS: READY
708
-
709
- ### ONE LINE SUMMARY: New requirements file created
710
-
711
- ### MULTILINE DETAILS: (1-20 lines max)
712
-
713
- **REQUIREMENT:**
714
- - Initial setup complete
715
-
716
- **ALL PHASES COMPLETED:**
717
- - ✅ Requirements file created
718
- - ✅ Ready for new requirements
719
-
720
- ## 🔨 Current In Progress Requirement
721
-
722
- *No current requirement in progress*
723
-
724
- ## 📋 Requirements to Complete
725
-
726
- *No requirements to complete*
727
-
728
- ## ⚠️ Requirements That Need Attention
729
-
730
- *No requirements need attention*
731
-
732
- ## ✅ Completed Requirements
733
-
734
- *No completed requirements yet*
735
-
736
- ---
737
-
738
- *This file was automatically created by VibeCodingMachine*
739
- `;
740
-
741
- fs.writeFileSync(requirementsFilePath, defaultContent, 'utf8');
742
- logger.log(`📄 Created default requirements file: ${requirementsFilePath}`);
743
-
744
- return requirementsFilePath;
745
- } catch (error) {
746
- logger.error('❌ Error creating default requirements file:', error);
747
- throw error;
748
- }
749
- }
750
-
751
- // Function to get or create requirements file path
752
- async function getOrCreateRequirementsFilePath(repoPath) {
753
- try {
754
- const hostname = os.hostname();
755
-
756
- // Use shared logic to find existing path first
757
- let requirementsFilePath = await getRequirementsPath(repoPath, hostname);
758
-
759
- if (requirementsFilePath && await fs.pathExists(requirementsFilePath)) {
760
- return requirementsFilePath;
761
- } else {
762
- // Create a new hostname-specific requirements file
763
- // We default to creating it inside the repo under .vibecodingmachine
764
- requirementsFilePath = path.join(repoPath, '.vibecodingmachine', `REQUIREMENTS-${hostname}.md`);
765
-
766
- const fs = require('fs-extra');
767
- const defaultRequirementsContent = `# 🌙 VibeCodingMachine – Requirements File
768
-
769
- This is a Markdown (.md) file.
770
-
771
- You should not need to modify this file, as VibeCodingMachine will modify it for you, but you can add requirements and move them around either here directly, or via AI.
772
-
773
- This file contains the requirements to complete the project. Each item in a list is a self contained requirement that should be able to stand on its own, and not require reference to other requirements. Each requirement starts in the section of requirements to complete, then it moved to the section with the current requirement being worked on. VibeCodingMachine will then, after implementing the requirement, move it to the completed requirements list in the CHANGELOG.md file, or to the section in this file for requirements that need attention. These will be available for you to review. They should have options to choose, and you decide which option to take, and VibeCodingMachine will work on that again the next time it is run.
774
-
775
- ## RESPONSE FROM LAST CHAT
776
-
777
- ### ONE LINE STATUS:
778
-
779
- ### ONE LINE SUMMARY:
780
-
781
- ### MULTILINE DETAILS: (1-20 lines max)
782
-
783
- ## 🔨 Current In Progress Requirement
784
-
785
- -
786
-
787
- ## 🚦 Current Status
788
-
789
- PREPARE
790
-
791
- ## ⏳ Requirements not yet completed
792
-
793
- -
794
-
795
- ## ✅ Verified by AI screenshot
796
-
797
- `;
798
- fs.ensureDirSync(path.join(repoPath, '.vibecodingmachine'));
799
- fs.writeFileSync(requirementsFilePath, defaultRequirementsContent, 'utf8');
800
- }
801
-
802
- return requirementsFilePath;
803
- } catch (error) {
804
- logger.error('❌ Error getting or creating requirements file path:', error);
805
- throw error;
806
- }
807
- }
808
-
809
- // Function to get current requirement being worked on
810
- async function getCurrentRequirement(repoPath) {
811
- try {
812
- const rPath = repoPath || process.cwd();
813
- // Get the requirements file path (create if doesn't exist)
814
- const requirementsFilePath = await getOrCreateRequirementsFilePath(rPath);
815
-
816
- // Read the requirements file content
817
- const content = await fs.readFile(requirementsFilePath, 'utf8');
818
- const lines = content.split('\n');
819
-
820
- // Look for the current in progress requirement
821
- for (let i = 0; i < lines.length; i++) {
822
- if (lines[i].includes('## 🔨 Current In Progress Requirement')) {
823
- // Look for the next requirement line
824
- for (let j = i + 1; j < lines.length; j++) {
825
- if (lines[j].trim().startsWith('- ')) {
826
- let requirementText = lines[j].substring(2).trim();
827
-
828
- // Extract the requirement title (remove FAILED prefix if present)
829
- if (requirementText.startsWith('FAILED ')) {
830
- const failedMatch = requirementText.match(/^FAILED \d+ TIMES?: (.+)$/);
831
- if (failedMatch) {
832
- requirementText = failedMatch[1];
833
- }
834
- }
835
-
836
- // Extract just the title part (before the colon)
837
- const colonIndex = requirementText.indexOf(':');
838
- if (colonIndex !== -1) {
839
- requirementText = requirementText.substring(0, colonIndex).trim();
840
- }
841
-
842
- // Remove markdown formatting
843
- requirementText = requirementText.replace(/\*\*/g, '');
844
-
845
- return `Working on: ${requirementText}`;
846
- }
847
- }
848
- break;
849
- }
850
- }
851
-
852
- return DEFAULT_INSTRUCTION_TEXT;
853
- } catch (error) {
854
- logger.error('❌ Error getting current requirement:', error);
855
- return DEFAULT_INSTRUCTION_TEXT;
856
- }
857
- }
858
-
859
- // Function to check if the current requirement status is DONE
860
- async function isCurrentRequirementDone(repoPath) {
861
- try {
862
- const rPath = repoPath || process.cwd();
863
- const hostname = os.hostname();
864
-
865
- // Use shared logic to find the file
866
- const requirementsFilePath = await getRequirementsPath(rPath, hostname);
867
-
868
- if (!requirementsFilePath || !(await fs.pathExists(requirementsFilePath))) {
869
- return false;
870
- }
871
-
872
- // Read the requirements file content
873
- const content = await fs.readFile(requirementsFilePath, 'utf8');
874
- const lines = content.split('\n');
875
-
876
- // First pass: check if "Current Status" section contains DONE
877
- let inStatusSection = false;
878
- for (let i = 0; i < lines.length; i++) {
879
- const line = lines[i].trim();
880
-
881
- if (line.includes('## 🚦 Current Status')) {
882
- inStatusSection = true;
883
- continue;
884
- }
885
-
886
- // If we're in the status section
887
- if (inStatusSection) {
888
- // Hit another section header, exit
889
- if (line.startsWith('##')) {
890
- break;
891
- }
892
-
893
- // Check if this line contains DONE (case-insensitive, exact word match)
894
- if (line) {
895
- const upperLine = line.toUpperCase();
896
- // Match DONE as a standalone word or at the start of the line
897
- if (upperLine === 'DONE' || upperLine.startsWith('DONE:') || upperLine.startsWith('DONE ')) {
898
- logger.log('✅ DONE status detected in Current Status section:', line);
899
- return true;
900
- }
901
- }
902
- }
903
- }
904
-
905
- // Second pass: check if "Current In Progress Requirement" section is empty
906
- let inCurrentSection = false;
907
- let foundRequirement = false;
908
- for (let i = 0; i < lines.length; i++) {
909
- const line = lines[i].trim();
910
-
911
- if (line.includes('## 🔨 Current In Progress Requirement')) {
912
- inCurrentSection = true;
913
- continue;
914
- }
915
-
916
- // If we're in the current section and hit another section header, exit
917
- if (inCurrentSection && line.startsWith('##')) {
918
- // If section was empty (no requirement found), it's done
919
- if (!foundRequirement) {
920
- logger.log('✅ Current requirement section is empty - considering as done');
921
- return true;
922
- }
923
- break;
924
- }
925
-
926
- // Track if we found a requirement in the current section
927
- if (inCurrentSection && line.startsWith('- ')) {
928
- foundRequirement = true;
929
- }
930
- }
931
-
932
- // If we found a requirement but no DONE status, it's not done yet
933
- if (foundRequirement) {
934
- logger.log('❌ Found requirement but status is not DONE');
935
- return false;
936
- }
937
-
938
- // Default: not done
939
- return false;
940
- } catch (error) {
941
- logger.error('❌ Error checking requirement status:', error);
942
- return false;
943
- }
944
- }
945
-
946
- // Shared function to move to next requirement (used by both IPC and auto mode)
947
- let isMovingToNextRequirement = false; // Prevent duplicate calls
948
- let lastMoveTime = 0; // Track when last move happened
949
-
950
- async function moveToNextRequirement(repoPath) {
951
- const now = Date.now();
952
- const rPath = repoPath || process.cwd();
953
-
954
- // Prevent duplicate calls within 5 seconds
955
- if (isMovingToNextRequirement || (now - lastMoveTime < 5000)) {
956
- logger.log('⚠️ moveToNextRequirement already in progress or called too recently, skipping duplicate call');
957
- return { success: false, error: 'Already moving to next requirement or called too recently' };
958
- }
959
-
960
- isMovingToNextRequirement = true;
961
- lastMoveTime = now;
962
-
963
- try {
964
- logger.log('🔄 Moving to next requirement');
965
-
966
- const hostname = os.hostname();
967
- // Use shared logic
968
- const requirementsFilePath = await getRequirementsPath(rPath, hostname);
969
-
970
- if (!requirementsFilePath || !(await fs.pathExists(requirementsFilePath))) {
971
- return { success: false, error: 'Requirements file not found' };
972
- }
973
-
974
- // Get auto mode config to check skipDisabled setting
975
- let skipDisabled = false;
976
- try {
977
- const { getAutoConfig } = require('../../../cli/src/utils/config');
978
- const autoConfig = await getAutoConfig();
979
- skipDisabled = autoConfig.skipDisabled || false;
980
- } catch (error) {
981
- // If CLI config is not available, default to false
982
- logger.log('⚠️ Could not get auto config, using skipDisabled = false');
983
- }
984
-
985
- // Read current content
986
- const content = await fs.readFile(requirementsFilePath, 'utf8');
987
- const lines = content.split('\n');
988
-
989
- // Extract current requirement and remove from "Current In Progress"
990
- let currentRequirement = null;
991
- let inCurrentSection = false;
992
- for (let i = 0; i < lines.length; i++) {
993
- if (lines[i].includes('## 🔨 Current In Progress Requirement')) {
994
- inCurrentSection = true;
995
- continue;
996
- }
997
- if (inCurrentSection && lines[i].trim().startsWith('- ')) {
998
- currentRequirement = lines[i].substring(2).trim();
999
- break;
1000
- }
1001
- if (inCurrentSection && lines[i].trim().startsWith('##')) {
1002
- break;
1003
- }
1004
- }
1005
-
1006
- // Get first non-disabled requirement from "Requirements not yet completed"
1007
- let nextRequirement = null;
1008
- let inNotYetCompleted = false;
1009
- for (let i = 0; i < lines.length; i++) {
1010
- if (lines[i].includes('## ⏳ Requirements not yet completed')) {
1011
- inNotYetCompleted = true;
1012
- continue;
1013
- }
1014
- if (inNotYetCompleted && lines[i].trim().startsWith('- ')) {
1015
- const requirementText = lines[i].substring(2).trim();
1016
-
1017
- // Check if requirement is disabled (starts with 'DISABLED:')
1018
- const isDisabled = requirementText.startsWith('DISABLED:');
1019
-
1020
- // Skip disabled requirements if skipDisabled is enabled
1021
- if (skipDisabled && isDisabled) {
1022
- logger.log(`⏭️ Skipping disabled requirement: ${requirementText}`);
1023
- continue;
1024
- }
1025
-
1026
- nextRequirement = requirementText;
1027
- break;
1028
- }
1029
- if (inNotYetCompleted && lines[i].trim().startsWith('##')) {
1030
- break;
1031
- }
1032
- }
1033
-
1034
- if (!nextRequirement) {
1035
- return { success: false, error: 'No more requirements to process' };
1036
- }
1037
-
1038
- // Count requirements in "not yet completed" (before moving)
1039
- let totalRequirementsNotYetCompleted = 0;
1040
- inNotYetCompleted = false;
1041
- for (const line of lines) {
1042
- if (line.includes('## ⏳ Requirements not yet completed')) {
1043
- inNotYetCompleted = true;
1044
- continue;
1045
- }
1046
- if (inNotYetCompleted && line.trim().startsWith('##')) {
1047
- break;
1048
- }
1049
- if (inNotYetCompleted && line.trim().startsWith('- ')) {
1050
- const requirementText = line.substring(2).trim();
1051
- const isDisabled = requirementText.startsWith('DISABLED:');
1052
-
1053
- // Don't count disabled requirements if skipDisabled is enabled
1054
- if (!skipDisabled || !isDisabled) {
1055
- totalRequirementsNotYetCompleted++;
1056
- }
1057
- }
1058
- }
1059
-
1060
- // Count completed requirements in "Verified by AI" section
1061
- let completedCount = 0;
1062
- let inVerifiedSection = false;
1063
- for (const line of lines) {
1064
- if (line.includes('## ✅ Verified by AI screenshot')) {
1065
- inVerifiedSection = true;
1066
- continue;
1067
- }
1068
- if (inVerifiedSection && line.trim().startsWith('##')) {
1069
- break;
1070
- }
1071
- if (inVerifiedSection && line.trim().startsWith('- ')) {
1072
- completedCount++;
1073
- }
1074
- }
1075
-
1076
- // Update the file: move current to "Verified by AI", move next to "Current In Progress"
1077
- const updatedLines = [];
1078
- inCurrentSection = false;
1079
- inNotYetCompleted = false;
1080
- inVerifiedSection = false;
1081
- let addedCurrentToVerified = false;
1082
- let addedNextToCurrent = false;
1083
- let removedNextFromNotYetCompleted = false;
1084
-
1085
- for (let i = 0; i < lines.length; i++) {
1086
- const line = lines[i];
1087
-
1088
- // Handle "Current In Progress Requirement" section
1089
- if (line.includes('## 🔨 Current In Progress Requirement')) {
1090
- inCurrentSection = true;
1091
- updatedLines.push(line);
1092
- updatedLines.push('');
1093
- updatedLines.push(`- ${nextRequirement}`);
1094
- updatedLines.push('');
1095
- addedNextToCurrent = true;
1096
- continue;
1097
- }
1098
-
1099
- // Skip old current requirement and any text in the current section
1100
- if (inCurrentSection && !line.trim().startsWith('##')) {
1101
- // Skip lines until we hit the next section header
1102
- continue;
1103
- }
1104
- if (inCurrentSection && line.trim().startsWith('##')) {
1105
- inCurrentSection = false;
1106
- // Don't continue - we want to process this section header
1107
- }
1108
-
1109
- // Handle "Current Status" section
1110
- if (line.includes('## 🚦 Current Status')) {
1111
- updatedLines.push(line);
1112
- updatedLines.push('');
1113
- updatedLines.push('PREPARE');
1114
- updatedLines.push('');
1115
-
1116
- // Skip all old status lines until we hit the next section
1117
- let j = i + 1;
1118
- while (j < lines.length && !lines[j].trim().startsWith('##')) {
1119
- j++;
1120
- }
1121
- i = j - 1; // Set i to the line before the next section (loop will increment)
1122
- continue;
1123
- }
1124
-
1125
- // Handle "Requirements not yet completed" section
1126
- if (line.includes('## ⏳ Requirements not yet completed')) {
1127
- inNotYetCompleted = true;
1128
- updatedLines.push(line);
1129
- continue;
1130
- }
1131
-
1132
- // Remove the next requirement from "not yet completed"
1133
- if (inNotYetCompleted && line.trim().startsWith('- ') && !removedNextFromNotYetCompleted) {
1134
- const requirementText = line.substring(2).trim();
1135
- if (requirementText === nextRequirement) {
1136
- inNotYetCompleted = false;
1137
- removedNextFromNotYetCompleted = true;
1138
- continue; // Skip this line
1139
- }
1140
- }
1141
-
1142
- // Handle "Verified by AI" section
1143
- if (line.includes('## ✅ Verified by AI screenshot')) {
1144
- inNotYetCompleted = false;
1145
- if (currentRequirement && !addedCurrentToVerified) {
1146
- // Check if this requirement is already in the verified section
1147
- const requirementAlreadyExists = updatedLines.some(existingLine =>
1148
- existingLine.includes(currentRequirement) && existingLine.trim().startsWith('- ')
1149
- );
1150
-
1151
- if (!requirementAlreadyExists) {
1152
- updatedLines.push(line);
1153
- updatedLines.push('');
1154
- // Don't add date prefix - just add the requirement as-is to avoid nesting
1155
- updatedLines.push(`- ${currentRequirement}`);
1156
- updatedLines.push('');
1157
- addedCurrentToVerified = true;
1158
- continue;
1159
- } else {
1160
- logger.log(`⚠️ Requirement "${currentRequirement}" already exists in verified section, skipping duplicate`);
1161
- addedCurrentToVerified = true;
1162
- }
1163
- }
1164
- updatedLines.push(line);
1165
- continue;
1166
- }
1167
-
1168
- updatedLines.push(line);
1169
- }
1170
-
1171
- // Write updated content
1172
- await fs.writeFile(requirementsFilePath, updatedLines.join('\n'), 'utf8');
1173
-
1174
- // Calculate current number:
1175
- // - We just completed 1 requirement (moved to "Verified by AI")
1176
- // - completedCount already includes previously completed requirements
1177
- // - So current number = completedCount + 1 (the one we just completed) + 1 (the new current one)
1178
- // - Which simplifies to: completedCount + 2
1179
- const currentNumber = completedCount + 2; // +1 for the one we just completed, +1 for the new current one we're starting
1180
-
1181
- // Total requirements = completedCount + 1 (current) + totalRequirementsNotYetCompleted
1182
- const totalRequirements = completedCount + 1 + totalRequirementsNotYetCompleted;
1183
-
1184
- logger.log(`✅ Moved to next requirement: ${nextRequirement}`);
1185
- logger.log(`📊 Progress: ${currentNumber}/${totalRequirements} (completed: ${completedCount + 1}, remaining: ${totalRequirementsNotYetCompleted - 1})`);
1186
- logger.log(`📝 Moved to requirement: ${nextRequirement}`);
1187
-
1188
- return {
1189
- success: true,
1190
- nextRequirement: nextRequirement,
1191
- currentNumber: currentNumber,
1192
- totalRemaining: totalRequirementsNotYetCompleted - 1
1193
- };
1194
- } catch (error) {
1195
- logger.error('❌ Error moving to next requirement:', error);
1196
- return { success: false, error: error.message };
1197
- } finally {
1198
- // Always reset the flag, even if there was an error
1199
- isMovingToNextRequirement = false;
1200
- }
1201
- }
1202
-
1203
- // Function to get current requirement progress numbers
1204
- async function getCurrentRequirementProgress(repoPath) {
1205
- try {
1206
- const stats = await getProjectRequirementStats(repoPath);
1207
- if (!stats) {
1208
- return { currentNumber: 1, totalRequirements: 1 };
1209
- }
1210
-
1211
- // currentNumber = verified + toVerify + 1 (the one we're on)
1212
- const currentNumber = stats.verifiedCount + stats.toVerifyCount + 1;
1213
- const totalRequirements = stats.total;
1214
-
1215
- // Ensure currentNumber doesn't exceed total
1216
- const sanitizedCurrent = Math.min(currentNumber, totalRequirements || 1);
1217
-
1218
- return { currentNumber: sanitizedCurrent, totalRequirements: totalRequirements || 1 };
1219
- } catch (error) {
1220
- logger.error('❌ Error getting current requirement progress:', error);
1221
- return { currentNumber: 1, totalRequirements: 1 };
1222
- }
1223
- }
1224
-
1225
- // Function to get current requirement name only (without "Working on:" prefix)
1226
- async function getCurrentRequirementName(repoPath) {
1227
- try {
1228
- const rPath = repoPath || process.cwd();
1229
- const hostname = os.hostname();
1230
-
1231
- const requirementsFilePath = await getRequirementsPath(rPath, hostname);
1232
-
1233
- if (!requirementsFilePath || !(await fs.pathExists(requirementsFilePath))) {
1234
- return null;
1235
- }
1236
-
1237
- // Read the requirements file content
1238
- const content = await fs.readFile(requirementsFilePath, 'utf8');
1239
- const lines = content.split('\n');
1240
-
1241
- // Look for the current in progress requirement
1242
- for (let i = 0; i < lines.length; i++) {
1243
- if (lines[i].includes('## 🔨 Current In Progress Requirement')) {
1244
- // Look for the next requirement line
1245
- for (let j = i + 1; j < lines.length; j++) {
1246
- if (lines[j].trim().startsWith('- ')) {
1247
- let requirementText = lines[j].substring(2).trim();
1248
-
1249
- // Remove markdown formatting (bold **)
1250
- requirementText = requirementText.replace(/\*\*/g, '');
1251
-
1252
- // Return the full requirement text without any prefix
1253
- return requirementText;
1254
- }
1255
- }
1256
- break;
1257
- }
1258
- }
1259
-
1260
- return null;
1261
- } catch (error) {
1262
- logger.error('❌ Error getting current requirement name:', error);
1263
- return null;
1264
- }
1265
- }
1266
-
1267
-