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.
- package/README.md +240 -0
- package/package.json +10 -2
- package/src/agents/Agent.js +300 -0
- package/src/agents/AgentAdditionService.js +311 -0
- package/src/agents/AgentCheckService.js +690 -0
- package/src/agents/AgentInstallationService.js +140 -0
- package/src/agents/AgentSetupService.js +467 -0
- package/src/agents/AgentStatus.js +183 -0
- package/src/agents/AgentVerificationService.js +634 -0
- package/src/agents/ConfigurationSchemaValidator.js +543 -0
- package/src/agents/EnvironmentConfigurationManager.js +602 -0
- package/src/agents/InstallationErrorHandler.js +372 -0
- package/src/agents/InstallationLog.js +363 -0
- package/src/agents/InstallationMethod.js +510 -0
- package/src/agents/InstallationOrchestrator.js +352 -0
- package/src/agents/InstallationProgressReporter.js +372 -0
- package/src/agents/InstallationRetryManager.js +322 -0
- package/src/agents/InstallationType.js +254 -0
- package/src/agents/OperationTypes.js +310 -0
- package/src/agents/PerformanceMetricsCollector.js +493 -0
- package/src/agents/SecurityValidationService.js +534 -0
- package/src/agents/VerificationTest.js +354 -0
- package/src/agents/VerificationType.js +226 -0
- package/src/agents/WindowsPermissionHandler.js +518 -0
- package/src/agents/config/AgentConfigManager.js +393 -0
- package/src/agents/config/AgentDefaultsRegistry.js +373 -0
- package/src/agents/config/ConfigValidator.js +281 -0
- package/src/agents/discovery/AgentDiscoveryService.js +707 -0
- package/src/agents/logging/AgentLogger.js +511 -0
- package/src/agents/status/AgentStatusManager.js +481 -0
- package/src/agents/storage/FileManager.js +454 -0
- package/src/agents/verification/AgentCommunicationTester.js +474 -0
- package/src/agents/verification/BaseVerifier.js +430 -0
- package/src/agents/verification/CommandVerifier.js +480 -0
- package/src/agents/verification/FileOperationVerifier.js +453 -0
- package/src/agents/verification/ResultAnalyzer.js +707 -0
- package/src/agents/verification/TestRequirementManager.js +495 -0
- package/src/agents/verification/VerificationRunner.js +433 -0
- package/src/agents/windows/BaseWindowsInstaller.js +441 -0
- package/src/agents/windows/ChocolateyInstaller.js +509 -0
- package/src/agents/windows/DirectInstaller.js +443 -0
- package/src/agents/windows/InstallerFactory.js +391 -0
- package/src/agents/windows/NpmInstaller.js +505 -0
- package/src/agents/windows/PowerShellInstaller.js +458 -0
- package/src/agents/windows/WinGetInstaller.js +390 -0
- package/src/analysis/analysis-reporter.js +132 -0
- package/src/analysis/boundary-detector.js +712 -0
- package/src/analysis/categorizer.js +340 -0
- package/src/analysis/codebase-scanner.js +384 -0
- package/src/analysis/line-counter.js +513 -0
- package/src/analysis/priority-calculator.js +679 -0
- package/src/analysis/report/analysis-report.js +250 -0
- package/src/analysis/report/package-analyzer.js +278 -0
- package/src/analysis/report/recommendation-generator.js +382 -0
- package/src/analysis/report/statistics-generator.js +515 -0
- package/src/analysis/reports/analysis-report-model.js +101 -0
- package/src/analysis/reports/recommendation-generator.js +283 -0
- package/src/analysis/reports/report-generators.js +191 -0
- package/src/analysis/reports/statistics-calculator.js +231 -0
- package/src/analysis/reports/trend-analyzer.js +219 -0
- package/src/analysis/strategy-generator.js +814 -0
- package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
- package/src/config/refactoring-config.js +307 -0
- package/src/health-tracking/json-storage.js +38 -2
- package/src/ide-integration/applescript-manager-core.js +233 -0
- package/src/ide-integration/applescript-manager.cjs +357 -28
- package/src/ide-integration/applescript-manager.js +89 -3599
- package/src/ide-integration/cdp-manager.js +306 -0
- package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
- package/src/ide-integration/continuation-handler.js +337 -0
- package/src/ide-integration/ide-status-checker.js +292 -0
- package/src/ide-integration/macos-ide-manager.js +627 -0
- package/src/ide-integration/macos-text-sender.js +528 -0
- package/src/ide-integration/response-reader.js +548 -0
- package/src/ide-integration/windows-automation-manager.js +121 -0
- package/src/ide-integration/windows-ide-manager.js +373 -0
- package/src/index.cjs +25 -3
- package/src/index.js +15 -1
- package/src/llm/direct-llm-manager.cjs +90 -2
- package/src/models/compliance-report.js +538 -0
- package/src/models/file-analysis.js +681 -0
- package/src/models/refactoring-plan.js +770 -0
- package/src/monitoring/alert-system.js +834 -0
- package/src/monitoring/compliance-progress-tracker.js +437 -0
- package/src/monitoring/continuous-scan-notifications.js +661 -0
- package/src/monitoring/continuous-scanner.js +279 -0
- package/src/monitoring/file-monitor/file-analyzer.js +262 -0
- package/src/monitoring/file-monitor/file-monitor.js +237 -0
- package/src/monitoring/file-monitor/watcher.js +194 -0
- package/src/monitoring/file-monitor.js +17 -0
- package/src/monitoring/notification-manager.js +437 -0
- package/src/monitoring/scanner-core.js +368 -0
- package/src/monitoring/scanner-events.js +214 -0
- package/src/monitoring/violation-notification-system.js +515 -0
- package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
- package/src/refactoring/boundaries/extraction-result.js +285 -0
- package/src/refactoring/boundaries/extraction-strategies.js +392 -0
- package/src/refactoring/boundaries/module-boundary.js +209 -0
- package/src/refactoring/boundary/boundary-detector.js +741 -0
- package/src/refactoring/boundary/boundary-types.js +405 -0
- package/src/refactoring/boundary/extraction-strategies.js +554 -0
- package/src/refactoring/boundary-extraction-result.js +77 -0
- package/src/refactoring/boundary-extraction-strategies.js +330 -0
- package/src/refactoring/boundary-extractor.js +384 -0
- package/src/refactoring/boundary-types.js +46 -0
- package/src/refactoring/circular/circular-dependency.js +88 -0
- package/src/refactoring/circular/cycle-detection.js +147 -0
- package/src/refactoring/circular/dependency-node.js +82 -0
- package/src/refactoring/circular/dependency-result.js +107 -0
- package/src/refactoring/circular/dependency-types.js +58 -0
- package/src/refactoring/circular/graph-builder.js +213 -0
- package/src/refactoring/circular/resolution-strategy.js +72 -0
- package/src/refactoring/circular/strategy-generator.js +229 -0
- package/src/refactoring/circular-dependency-resolver-original.js +809 -0
- package/src/refactoring/circular-dependency-resolver.js +200 -0
- package/src/refactoring/code-mover.js +761 -0
- package/src/refactoring/file-splitter.js +696 -0
- package/src/refactoring/functionality-validator.js +816 -0
- package/src/refactoring/import-manager.js +774 -0
- package/src/refactoring/module-boundary.js +107 -0
- package/src/refactoring/refactoring-executor.js +672 -0
- package/src/refactoring/refactoring-rollback.js +614 -0
- package/src/refactoring/test-validator.js +631 -0
- package/src/requirement-management/default-requirement-manager.js +321 -0
- package/src/requirement-management/requirement-file-parser.js +159 -0
- package/src/requirement-management/requirement-sequencer.js +221 -0
- package/src/rui/commands/AgentCommandParser.js +600 -0
- package/src/rui/commands/AgentCommands.js +487 -0
- package/src/rui/commands/AgentResponseFormatter.js +832 -0
- package/src/scripts/verify-full-compliance.js +269 -0
- package/src/sync/sync-engine-core.js +1 -0
- package/src/sync/sync-engine-remote-handlers.js +135 -0
- package/src/task-generation/automated-task-generator.js +351 -0
- package/src/task-generation/prioritizer.js +287 -0
- package/src/task-generation/task-list-updater.js +215 -0
- package/src/task-generation/task-management-integration.js +480 -0
- package/src/task-generation/task-manager-integration.js +270 -0
- package/src/task-generation/violation-task-generator.js +474 -0
- package/src/task-management/continuous-scan-integration.js +342 -0
- package/src/timeout-management/index.js +12 -3
- package/src/timeout-management/response-time-tracker.js +167 -0
- package/src/timeout-management/timeout-calculator.js +159 -0
- package/src/timeout-management/timeout-config-manager.js +172 -0
- package/src/utils/ast-analyzer.js +417 -0
- package/src/utils/current-requirement-manager.js +276 -0
- package/src/utils/current-requirement-operations.js +472 -0
- package/src/utils/dependency-mapper.js +456 -0
- package/src/utils/download-with-progress.js +4 -2
- package/src/utils/electron-update-checker.js +4 -1
- package/src/utils/file-size-analyzer.js +272 -0
- package/src/utils/import-updater.js +280 -0
- package/src/utils/refactoring-tools.js +512 -0
- package/src/utils/report-generator.js +569 -0
- package/src/utils/reports/report-analysis.js +218 -0
- package/src/utils/reports/report-types.js +55 -0
- package/src/utils/reports/summary-generators.js +102 -0
- package/src/utils/requirement-file-management.js +157 -0
- package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
- package/src/utils/requirement-helpers/requirement-mover.js +414 -0
- package/src/utils/requirement-helpers/requirement-parser.js +326 -0
- package/src/utils/requirement-helpers/requirement-status.js +320 -0
- package/src/utils/requirement-helpers-new.js +55 -0
- package/src/utils/requirement-helpers-refactored.js +367 -0
- package/src/utils/requirement-helpers.js +291 -1191
- package/src/utils/requirement-movement-operations.js +450 -0
- package/src/utils/requirement-movement.js +312 -0
- package/src/utils/requirement-parsing-helpers.js +56 -0
- package/src/utils/requirement-statistics.js +200 -0
- package/src/utils/requirement-text-utils.js +58 -0
- package/src/utils/rollback/rollback-handlers.js +125 -0
- package/src/utils/rollback/rollback-operation.js +63 -0
- package/src/utils/rollback/rollback-recorder.js +166 -0
- package/src/utils/rollback/rollback-state-manager.js +175 -0
- package/src/utils/rollback/rollback-types.js +33 -0
- package/src/utils/rollback/rollback-utils.js +110 -0
- package/src/utils/rollback-manager-original.js +569 -0
- package/src/utils/rollback-manager.js +202 -0
- package/src/utils/smoke-test-cli.js +362 -0
- package/src/utils/smoke-test-gui.js +351 -0
- package/src/utils/smoke-test-orchestrator.js +321 -0
- package/src/utils/smoke-test-runner.js +60 -0
- package/src/utils/smoke-test-web.js +347 -0
- package/src/utils/specification-helpers.js +39 -13
- package/src/utils/specification-migration.js +97 -0
- package/src/utils/test-runner.js +579 -0
- package/src/utils/validation-framework.js +518 -0
- package/src/validation/compliance-analyzer.js +197 -0
- package/src/validation/compliance-report-generator.js +343 -0
- package/src/validation/compliance-reporter.js +711 -0
- package/src/validation/compliance-rules.js +127 -0
- package/src/validation/constitution-validator-new.js +196 -0
- package/src/validation/constitution-validator.js +17 -0
- package/src/validation/file-validators.js +170 -0
- package/src/validation/line-limit/file-analyzer.js +201 -0
- package/src/validation/line-limit/line-limit-validator.js +208 -0
- package/src/validation/line-limit/validation-result.js +144 -0
- package/src/validation/line-limit-core.js +225 -0
- package/src/validation/line-limit-reporter.js +134 -0
- package/src/validation/line-limit-result.js +125 -0
- package/src/validation/line-limit-validator.js +41 -0
- package/src/validation/metrics-calculator.js +660 -0
- 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
|
+
};
|