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
@@ -0,0 +1,312 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { logger } = require('./logger.cjs');
4
+ const { parseRequirementLine } = require('./requirement-text-utils');
5
+
6
+ /**
7
+ * Requirement movement and section management utilities
8
+ */
9
+
10
+ /**
11
+ * Promote requirement to verified section
12
+ * @param {string} reqPath - Path to requirements file
13
+ * @param {string} requirementTitle - Title of requirement to move
14
+ * @returns {Promise<boolean>} Success status
15
+ */
16
+ async function promoteToVerified(reqPath, requirementTitle) {
17
+ try {
18
+ const content = await fs.readFile(reqPath, 'utf-8');
19
+ const lines = content.split('\n');
20
+
21
+ let inRequirementsSection = false;
22
+ let inVerifiedSection = false;
23
+ let requirementLine = -1;
24
+ let verifiedInsertIndex = -1;
25
+
26
+ // Find requirement and verified section
27
+ for (let i = 0; i < lines.length; i++) {
28
+ const line = lines[i];
29
+
30
+ // Track sections
31
+ if (line.includes('Requirements not yet completed')) {
32
+ inRequirementsSection = true;
33
+ inVerifiedSection = false;
34
+ } else if (line.includes('Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG')) {
35
+ inRequirementsSection = false;
36
+ inVerifiedSection = true;
37
+ verifiedInsertIndex = i + 2; // After header and empty line
38
+ } else if (line.startsWith('# ') && !line.includes('Requirements not yet completed') &&
39
+ !line.includes('Verified by AI')) {
40
+ inRequirementsSection = false;
41
+ inVerifiedSection = false;
42
+ }
43
+
44
+ // Find the requirement to move
45
+ if (inRequirementsSection && line.includes(requirementTitle)) {
46
+ requirementLine = i;
47
+ }
48
+ }
49
+
50
+ if (requirementLine === -1) {
51
+ logger.error(`❌ Requirement not found: ${requirementTitle}`);
52
+ return false;
53
+ }
54
+
55
+ if (verifiedInsertIndex === -1) {
56
+ logger.error('❌ Verified section not found');
57
+ return false;
58
+ }
59
+
60
+ // Move the requirement
61
+ const requirementText = lines[requirementLine];
62
+ lines.splice(requirementLine, 1); // Remove from original location
63
+ lines.splice(verifiedInsertIndex, 0, requirementText); // Insert in verified section
64
+
65
+ // Write back to file
66
+ await fs.writeFile(reqPath, lines.join('\n'));
67
+
68
+ logger.log(`✅ Promoted to verified: ${requirementTitle}`);
69
+ return true;
70
+ } catch (error) {
71
+ logger.error('❌ Error promoting to verified:', error);
72
+ return false;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Demote requirement from verified back to todo
78
+ * @param {string} reqPath - Path to requirements file
79
+ * @param {string} requirementTitle - Title of requirement to move
80
+ * @returns {Promise<boolean>} Success status
81
+ */
82
+ async function demoteFromVerifiedToTodo(reqPath, requirementTitle) {
83
+ try {
84
+ // CHANGELOG.md should be at repository root, not in .vibecodingmachine directory
85
+ const allnightDir = path.dirname(reqPath); // .vibecodingmachine directory
86
+ const repoPath = path.dirname(allnightDir); // Repository root
87
+ const changelogPath = path.join(repoPath, 'CHANGELOG.md');
88
+
89
+ // First remove from CHANGELOG.md if present
90
+ if (await fs.pathExists(changelogPath)) {
91
+ const changelogContent = await fs.readFile(changelogPath, 'utf-8');
92
+ const changelogLines = changelogContent.split('\n');
93
+
94
+ let changelogRequirementLine = -1;
95
+ for (let i = 0; i < changelogLines.length; i++) {
96
+ if (changelogLines[i].includes(requirementTitle)) {
97
+ changelogRequirementLine = i;
98
+ break;
99
+ }
100
+ }
101
+
102
+ if (changelogRequirementLine !== -1) {
103
+ changelogLines.splice(changelogRequirementLine, 1);
104
+ await fs.writeFile(changelogPath, changelogLines.join('\n'));
105
+ logger.log(`✅ Removed from CHANGELOG.md: ${requirementTitle}`);
106
+ }
107
+ }
108
+
109
+ // Now move from verified back to requirements section
110
+ const content = await fs.readFile(reqPath, 'utf-8');
111
+ const lines = content.split('\n');
112
+
113
+ let inRequirementsSection = false;
114
+ let inVerifiedSection = false;
115
+ let requirementLine = -1;
116
+ let todoInsertIndex = -1;
117
+
118
+ // Find requirement in verified section and todo section
119
+ for (let i = 0; i < lines.length; i++) {
120
+ const line = lines[i];
121
+
122
+ // Track sections
123
+ if (line.includes('Requirements not yet completed')) {
124
+ inRequirementsSection = true;
125
+ inVerifiedSection = false;
126
+ todoInsertIndex = i + 2; // After header and empty line
127
+ } else if (line.includes('Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG')) {
128
+ inRequirementsSection = false;
129
+ inVerifiedSection = true;
130
+ } else if (line.startsWith('# ') && !line.includes('Requirements not yet completed') &&
131
+ !line.includes('Verified by AI')) {
132
+ inRequirementsSection = false;
133
+ inVerifiedSection = false;
134
+ }
135
+
136
+ // Find the requirement to move in verified section
137
+ if (inVerifiedSection && line.includes(requirementTitle)) {
138
+ requirementLine = i;
139
+ }
140
+ }
141
+
142
+ if (requirementLine === -1) {
143
+ logger.error(`❌ Requirement not found in verified section: ${requirementTitle}`);
144
+ return false;
145
+ }
146
+
147
+ if (todoInsertIndex === -1) {
148
+ logger.error('❌ Todo section not found');
149
+ return false;
150
+ }
151
+
152
+ // Move the requirement
153
+ const requirementText = lines[requirementLine];
154
+ lines.splice(requirementLine, 1); // Remove from verified section
155
+ lines.splice(todoInsertIndex, 0, requirementText); // Insert in todo section
156
+
157
+ // Write back to file
158
+ await fs.writeFile(reqPath, lines.join('\n'));
159
+
160
+ logger.log(`✅ Demoted from verified to todo: ${requirementTitle}`);
161
+ return true;
162
+ } catch (error) {
163
+ logger.error('❌ Error demoting from verified to todo:', error);
164
+ return false;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Promote requirement from todo to verify section
170
+ * @param {string} reqPath - Path to requirements file
171
+ * @param {string} requirementTitle - Title of requirement to move
172
+ * @returns {Promise<boolean>} Success status
173
+ */
174
+ async function promoteTodoToVerify(reqPath, requirementTitle) {
175
+ try {
176
+ const content = await fs.readFile(reqPath, 'utf-8');
177
+ const lines = content.split('\n');
178
+
179
+ let inRequirementsSection = false;
180
+ let inVerifySection = false;
181
+ let requirementLine = -1;
182
+ let verifyInsertIndex = -1;
183
+
184
+ // Find requirement and verify section
185
+ for (let i = 0; i < lines.length; i++) {
186
+ const line = lines[i];
187
+
188
+ // Track sections
189
+ if (line.includes('Requirements not yet completed')) {
190
+ inRequirementsSection = true;
191
+ inVerifySection = false;
192
+ } else if (line.includes('Requirements ready for verification')) {
193
+ inRequirementsSection = false;
194
+ inVerifySection = true;
195
+ verifyInsertIndex = i + 2; // After header and empty line
196
+ } else if (line.startsWith('# ') && !line.includes('Requirements not yet completed') &&
197
+ !line.includes('Requirements ready for verification')) {
198
+ inRequirementsSection = false;
199
+ inVerifySection = false;
200
+ }
201
+
202
+ // Find the requirement to move
203
+ if (inRequirementsSection && line.includes(requirementTitle)) {
204
+ requirementLine = i;
205
+ }
206
+ }
207
+
208
+ if (requirementLine === -1) {
209
+ logger.error(`❌ Requirement not found: ${requirementTitle}`);
210
+ return false;
211
+ }
212
+
213
+ if (verifyInsertIndex === -1) {
214
+ logger.error('❌ Verify section not found');
215
+ return false;
216
+ }
217
+
218
+ // Move the requirement
219
+ const requirementText = lines[requirementLine];
220
+ lines.splice(requirementLine, 1); // Remove from original location
221
+ lines.splice(verifyInsertIndex, 0, requirementText); // Insert in verify section
222
+
223
+ // Write back to file
224
+ await fs.writeFile(reqPath, lines.join('\n'));
225
+
226
+ logger.log(`✅ Promoted to verify: ${requirementTitle}`);
227
+ return true;
228
+ } catch (error) {
229
+ logger.error('❌ Error promoting to verify:', error);
230
+ return false;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Demote requirement from verify back to todo
236
+ * @param {string} reqPath - Path to requirements file
237
+ * @param {string} requirementTitle - Title of requirement to move
238
+ * @param {string} explanation - Optional explanation of what went wrong
239
+ * @returns {Promise<boolean>} Success status
240
+ */
241
+ async function demoteVerifyToTodo(reqPath, requirementTitle, explanation = '') {
242
+ try {
243
+ const content = await fs.readFile(reqPath, 'utf-8');
244
+ const lines = content.split('\n');
245
+
246
+ let inRequirementsSection = false;
247
+ let inVerifySection = false;
248
+ let requirementLine = -1;
249
+ let todoInsertIndex = -1;
250
+
251
+ // Find requirement in verify section and todo section
252
+ for (let i = 0; i < lines.length; i++) {
253
+ const line = lines[i];
254
+
255
+ // Track sections
256
+ if (line.includes('Requirements not yet completed')) {
257
+ inRequirementsSection = true;
258
+ inVerifySection = false;
259
+ todoInsertIndex = i + 2; // After header and empty line
260
+ } else if (line.includes('Requirements ready for verification')) {
261
+ inRequirementsSection = false;
262
+ inVerifySection = true;
263
+ } else if (line.startsWith('# ') && !line.includes('Requirements not yet completed') &&
264
+ !line.includes('Requirements ready for verification')) {
265
+ inRequirementsSection = false;
266
+ inVerifySection = false;
267
+ }
268
+
269
+ // Find the requirement to move in verify section
270
+ if (inVerifySection && line.includes(requirementTitle)) {
271
+ requirementLine = i;
272
+ }
273
+ }
274
+
275
+ if (requirementLine === -1) {
276
+ logger.error(`❌ Requirement not found in verify section: ${requirementTitle}`);
277
+ return false;
278
+ }
279
+
280
+ if (todoInsertIndex === -1) {
281
+ logger.error('❌ Todo section not found');
282
+ return false;
283
+ }
284
+
285
+ // Move the requirement
286
+ let requirementText = lines[requirementLine];
287
+
288
+ // Add explanation if provided
289
+ if (explanation) {
290
+ requirementText += ` (ISSUE: ${explanation})`;
291
+ }
292
+
293
+ lines.splice(requirementLine, 1); // Remove from verify section
294
+ lines.splice(todoInsertIndex, 0, requirementText); // Insert in todo section
295
+
296
+ // Write back to file
297
+ await fs.writeFile(reqPath, lines.join('\n'));
298
+
299
+ logger.log(`✅ Demoted from verify to todo: ${requirementTitle}`);
300
+ return true;
301
+ } catch (error) {
302
+ logger.error('❌ Error demoting from verify to todo:', error);
303
+ return false;
304
+ }
305
+ }
306
+
307
+ module.exports = {
308
+ promoteToVerified,
309
+ demoteFromVerifiedToTodo,
310
+ promoteTodoToVerify,
311
+ demoteVerifyToTodo
312
+ };
@@ -0,0 +1,56 @@
1
+ const { logger } = require('./logger.cjs');
2
+
3
+ /**
4
+ * Get ordinal suffix for numbers (1st, 2nd, 3rd, 4th, etc.)
5
+ * @param {number} num - The number
6
+ * @returns {string} The ordinal suffix
7
+ */
8
+ function getOrdinalSuffix(num) {
9
+ const j = num % 10;
10
+ const k = num % 100;
11
+ if (j === 1 && k !== 11) {
12
+ return 'st';
13
+ }
14
+ if (j === 2 && k !== 12) {
15
+ return 'nd';
16
+ }
17
+ if (j === 3 && k !== 13) {
18
+ return 'rd';
19
+ }
20
+ return 'th';
21
+ }
22
+
23
+ /**
24
+ * Add or increment TRY AGAIN prefix to requirement text
25
+ * @param {string} requirementText - The requirement text
26
+ * @returns {string} Requirement text with TRY AGAIN prefix
27
+ */
28
+ function addTryAgainPrefix(requirementText) {
29
+ const tryAgainMatch = requirementText.match(/^TRY AGAIN \((\d+)(?:st|nd|rd|th) time\): (.+)$/);
30
+
31
+ if (tryAgainMatch) {
32
+ const currentCount = parseInt(tryAgainMatch[1]);
33
+ const baseRequirement = tryAgainMatch[2];
34
+ return `TRY AGAIN (${currentCount + 1}${getOrdinalSuffix(currentCount + 1)} time): ${baseRequirement}`;
35
+ } else {
36
+ return `TRY AGAIN (1st time): ${requirementText}`;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Parse requirement from markdown line
42
+ * @param {string} line - Markdown line (e.g., "- Requirement text")
43
+ * @returns {string} Requirement text without markdown prefix
44
+ */
45
+ function parseRequirementLine(line) {
46
+ if (line.startsWith('- ')) {
47
+ return line.substring(2);
48
+ }
49
+ return line;
50
+ }
51
+
52
+ module.exports = {
53
+ getOrdinalSuffix,
54
+ addTryAgainPrefix,
55
+ parseRequirementLine
56
+ };
@@ -0,0 +1,200 @@
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
+ const { parseRequirementLine } = require('./requirement-parsing-helpers');
7
+
8
+ /**
9
+ * Requirement statistics and progress tracking utilities
10
+ */
11
+
12
+ /**
13
+ * Load verified requirements from CHANGELOG.md
14
+ * @param {string} repoPath - Repository root path
15
+ * @returns {Promise<string[]>} List of verified requirement titles
16
+ */
17
+ async function loadVerifiedFromChangelog(repoPath) {
18
+ try {
19
+ const changelogPath = path.join(repoPath, 'CHANGELOG.md');
20
+ if (!(await fs.pathExists(changelogPath))) {
21
+ return [];
22
+ }
23
+
24
+ const content = await fs.readFile(changelogPath, 'utf8');
25
+ const lines = content.split('\n');
26
+ const requirements = [];
27
+ let inVerifiedSection = false;
28
+
29
+ for (const line of lines) {
30
+ const trimmed = line.trim();
31
+
32
+ if (trimmed.includes('## Verified Requirements')) {
33
+ inVerifiedSection = true;
34
+ continue;
35
+ }
36
+
37
+ if (inVerifiedSection && trimmed.startsWith('##') && !trimmed.includes('Verified Requirements')) {
38
+ break;
39
+ }
40
+
41
+ // Collect items starting with "- " as verified requirements
42
+ if (inVerifiedSection && trimmed.startsWith('- ') && trimmed.length > 5) {
43
+ let reqText = trimmed.substring(2);
44
+ // Extract title part (before timestamp in parentheses if present)
45
+ const titleMatch = reqText.match(/^(.+?)\s*\([\d-]+\)$/);
46
+ if (titleMatch) {
47
+ reqText = titleMatch[1];
48
+ }
49
+ requirements.push(reqText.trim());
50
+ }
51
+ }
52
+
53
+ return requirements;
54
+ } catch (error) {
55
+ logger.error('❌ Error loading verified requirements from CHANGELOG.md:', error);
56
+ return [];
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Get unified project requirement statistics (TODO, TO VERIFY, VERIFIED)
62
+ * @param {string} repoPath - Repository root path
63
+ * @returns {Promise<Object>} Statistics with counts and formatted percentages
64
+ */
65
+ async function getProjectRequirementStats(repoPath) {
66
+ try {
67
+ const hostname = os.hostname();
68
+ const { getRequirementsPath } = require('./repo-helpers.cjs');
69
+ const reqPath = await getRequirementsPath(repoPath, hostname);
70
+
71
+ let todoCount = 0;
72
+ let toVerifyCount = 0;
73
+ let verifiedCount = 0;
74
+ let clarificationCount = 0;
75
+ let recycledCount = 0;
76
+
77
+ if (reqPath && await fs.pathExists(reqPath)) {
78
+ const content = await fs.readFile(reqPath, 'utf8');
79
+ const lines = content.split('\n');
80
+ let currentSection = '';
81
+
82
+ const verifySectionVariants = [
83
+ '🔍 TO VERIFY BY HUMAN',
84
+ 'TO VERIFY BY HUMAN',
85
+ '🔍 TO VERIFY',
86
+ 'TO VERIFY',
87
+ '✅ Verified by AI screenshot',
88
+ 'Verified by AI screenshot'
89
+ ];
90
+
91
+ const clarificationVariants = [
92
+ 'NEEDING CLARIFICATION',
93
+ 'Requirements that need information',
94
+ 'need information'
95
+ ];
96
+
97
+ const recycledVariants = [
98
+ '♻️ Recycled',
99
+ 'Recycled'
100
+ ];
101
+
102
+ for (const line of lines) {
103
+ const trimmed = line.trim();
104
+
105
+ if (trimmed.startsWith('###')) {
106
+ if (currentSection) {
107
+ // Remove ALL leading ### markers including spaces between them (handles "###", "### ###", "#### ####", etc.)
108
+ const requirementText = trimmed.replace(/^(#{1,}\s*)+/, '').trim();
109
+ // Filter out empty titles and package names
110
+ const packageNames = ['cli', 'core', 'electron-app', 'web', 'mobile', 'vscode-extension', 'sync-server'];
111
+ if (requirementText && requirementText.length > 0 && !packageNames.includes(requirementText.toLowerCase())) {
112
+ if (currentSection === 'todo') todoCount++;
113
+ else if (currentSection === 'toverify') toVerifyCount++;
114
+ else if (currentSection === 'clarification') clarificationCount++;
115
+ else if (currentSection === 'recycled') recycledCount++;
116
+ }
117
+ }
118
+ } else if (trimmed.startsWith('##') && !trimmed.startsWith('###')) {
119
+ if (trimmed.includes('⏳ Requirements not yet completed') ||
120
+ trimmed.includes('Requirements not yet completed')) {
121
+ currentSection = 'todo';
122
+ } else if (verifySectionVariants.some(v => trimmed.includes(v))) {
123
+ currentSection = 'toverify';
124
+ } else if (clarificationVariants.some(v => trimmed.includes(v))) {
125
+ currentSection = 'clarification';
126
+ } else if (recycledVariants.some(v => trimmed.includes(v))) {
127
+ currentSection = 'recycled';
128
+ } else {
129
+ currentSection = '';
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ // Load verified counts from CHANGELOG.md
136
+ const verifiedReqs = await loadVerifiedFromChangelog(repoPath);
137
+ verifiedCount = verifiedReqs.length;
138
+
139
+ const total = todoCount + toVerifyCount + verifiedCount + clarificationCount + recycledCount;
140
+ const todoPercent = total > 0 ? Math.round((todoCount / total) * 100) : 0;
141
+ const toVerifyPercent = total > 0 ? Math.round((toVerifyCount / total) * 100) : 0;
142
+ const verifiedPercent = total > 0 ? Math.round((verifiedCount / total) * 100) : 0;
143
+ const clarificationPercent = total > 0 ? Math.round((clarificationCount / total) * 100) : 0;
144
+ const recycledPercent = total > 0 ? Math.round((recycledCount / total) * 100) : 0;
145
+
146
+ return {
147
+ todoCount,
148
+ toVerifyCount,
149
+ verifiedCount,
150
+ clarificationCount,
151
+ recycledCount,
152
+ total,
153
+ todoPercent,
154
+ toVerifyPercent,
155
+ verifiedPercent,
156
+ clarificationPercent,
157
+ recycledPercent,
158
+ todoLabel: `TODO (${todoCount} - ${todoPercent}%)`,
159
+ toVerifyLabel: `TO VERIFY (${toVerifyCount} - ${toVerifyPercent}%)`,
160
+ verifiedLabel: `VERIFIED (${verifiedCount} - ${verifiedPercent}%)`,
161
+ clarificationLabel: `CLARIFICATION (${clarificationCount} - ${clarificationPercent}%)`,
162
+ recycledLabel: `RECYCLED (${recycledCount} - ${recycledPercent}%)`
163
+ };
164
+ } catch (error) {
165
+ logger.error('❌ Error getting project requirement stats:', error);
166
+ return null;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Get current requirement progress numbers
172
+ * @param {string} repoPath - Repository path
173
+ * @returns {Promise<Object>} Progress information
174
+ */
175
+ async function getCurrentRequirementProgress(repoPath) {
176
+ try {
177
+ const stats = await getProjectRequirementStats(repoPath);
178
+ if (!stats) {
179
+ return { currentNumber: 1, totalRequirements: 1 };
180
+ }
181
+
182
+ // currentNumber = verified + toVerify + 1 (the one we're on)
183
+ const currentNumber = stats.verifiedCount + stats.toVerifyCount + 1;
184
+ const totalRequirements = stats.total;
185
+
186
+ // Ensure currentNumber doesn't exceed total
187
+ const sanitizedCurrent = Math.min(currentNumber, totalRequirements || 1);
188
+
189
+ return { currentNumber: sanitizedCurrent, totalRequirements: totalRequirements || 1 };
190
+ } catch (error) {
191
+ logger.error('❌ Error getting current requirement progress:', error);
192
+ return { currentNumber: 1, totalRequirements: 1 };
193
+ }
194
+ }
195
+
196
+ module.exports = {
197
+ loadVerifiedFromChangelog,
198
+ getProjectRequirementStats,
199
+ getCurrentRequirementProgress
200
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Text processing utilities for requirements
3
+ */
4
+
5
+ /**
6
+ * Get ordinal suffix for numbers (1st, 2nd, 3rd, 4th, etc.)
7
+ * @param {number} num - The number
8
+ * @returns {string} The ordinal suffix
9
+ */
10
+ function getOrdinalSuffix(num) {
11
+ const j = num % 10;
12
+ const k = num % 100;
13
+ if (j === 1 && k !== 11) {
14
+ return 'st';
15
+ }
16
+ if (j === 2 && k !== 12) {
17
+ return 'nd';
18
+ }
19
+ if (j === 3 && k !== 13) {
20
+ return 'rd';
21
+ }
22
+ return 'th';
23
+ }
24
+
25
+ /**
26
+ * Add or increment TRY AGAIN prefix to requirement text
27
+ * @param {string} requirementText - The requirement text
28
+ * @returns {string} Requirement text with TRY AGAIN prefix
29
+ */
30
+ function addTryAgainPrefix(requirementText) {
31
+ const tryAgainMatch = requirementText.match(/^TRY AGAIN \((\d+)(?:st|nd|rd|th) time\): (.+)$/);
32
+
33
+ if (tryAgainMatch) {
34
+ const currentCount = parseInt(tryAgainMatch[1]);
35
+ const baseRequirement = tryAgainMatch[2];
36
+ return `TRY AGAIN (${currentCount + 1}${getOrdinalSuffix(currentCount + 1)} time): ${baseRequirement}`;
37
+ } else {
38
+ return `TRY AGAIN (1st time): ${requirementText}`;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Parse requirement from markdown line
44
+ * @param {string} line - Markdown line (e.g., "- Requirement text")
45
+ * @returns {string} Requirement text without markdown prefix
46
+ */
47
+ function parseRequirementLine(line) {
48
+ if (line.startsWith('- ')) {
49
+ return line.substring(2);
50
+ }
51
+ return line;
52
+ }
53
+
54
+ module.exports = {
55
+ getOrdinalSuffix,
56
+ addTryAgainPrefix,
57
+ parseRequirementLine
58
+ };