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,836 @@
1
+ /**
2
+ * Shared Auto Mode Business Logic
3
+ * Common auto mode functionality used by both CLI and GUI
4
+ */
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ // Try to require the actual modules, fall back to mocks if not available
10
+ let AppleScriptManager, ClineCLIManager, AiderCLIManager, ClaudeCodeCLIManager, logIDEMessage, runContinueCLIAutoMode, CDPManager, QuotaDetector, ChatManager;
11
+
12
+ try {
13
+ const applescriptManager = require('../ide-integration/applescript-manager.cjs');
14
+ AppleScriptManager = applescriptManager.AppleScriptManager;
15
+ ClineCLIManager = applescriptManager.ClineCLIManager;
16
+ AiderCLIManager = applescriptManager.AiderCLIManager;
17
+ ClaudeCodeCLIManager = applescriptManager.ClaudeCodeCLIManager;
18
+ logIDEMessage = applescriptManager.logIDEMessage;
19
+ runContinueCLIAutoMode = applescriptManager.runContinueCLIAutoMode;
20
+ } catch (e) {
21
+ // Mock implementations
22
+ AppleScriptManager = class MockAppleScriptManager {};
23
+ ClineCLIManager = class MockClineCLIManager {};
24
+ AiderCLIManager = class MockAiderCLIManager {};
25
+ ClaudeCodeCLIManager = class MockClaudeCodeCLIManager {};
26
+ logIDEMessage = () => {};
27
+ runContinueCLIAutoMode = () => {};
28
+ }
29
+
30
+ try {
31
+ CDPManager = require('../ide-integration/cdp-manager.cjs').CDPManager;
32
+ } catch (e) {
33
+ CDPManager = class MockCDPManager {};
34
+ }
35
+
36
+ try {
37
+ QuotaDetector = require('../ide-integration/quota-detector.cjs').QuotaDetector;
38
+ } catch (e) {
39
+ QuotaDetector = class MockQuotaDetector {};
40
+ }
41
+
42
+ try {
43
+ ChatManager = require('../chat-management/chat-manager.cjs').ChatManager;
44
+ } catch (e) {
45
+ ChatManager = class MockChatManager {};
46
+ }
47
+
48
+ class AutoModeBusinessLogic {
49
+ constructor() {
50
+ this.state = {
51
+ isAutoMode: false,
52
+ currentIDE: 'vscode',
53
+ chatCounter: 0,
54
+ maxChats: 100,
55
+ neverStop: false,
56
+ autoModeEvent: null,
57
+ currentMode: 'requirements', // 'spec' | 'requirements'
58
+ currentSpecPath: null,
59
+ currentSpecId: null,
60
+ specsList: null,
61
+ currentSpecIndex: 0,
62
+ powerSaveBlockerId: null
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Get available LLM providers from config and environment variables
68
+ * @param {Object} savedConfig - Config object
69
+ * @returns {Array<{provider: string, model: string, apiKey?: string}>}
70
+ */
71
+ getAvailableProviders(savedConfig) {
72
+ const providers = [];
73
+
74
+ // Check for Groq (current primary)
75
+ const groqApiKey = process.env.GROQ_API_KEY || savedConfig.groqApiKey;
76
+ if (groqApiKey && groqApiKey.trim()) {
77
+ providers.push({
78
+ provider: 'groq',
79
+ model: savedConfig.aiderModel || 'groq/llama-3.3-70b-versatile',
80
+ apiKey: groqApiKey
81
+ });
82
+ }
83
+
84
+ // Check for Anthropic (Claude)
85
+ const anthropicApiKey = process.env.ANTHROPIC_API_KEY || savedConfig.anthropicApiKey;
86
+ if (anthropicApiKey && anthropicApiKey.trim()) {
87
+ providers.push({
88
+ provider: 'anthropic',
89
+ model: 'claude-3-5-sonnet-20241022',
90
+ apiKey: anthropicApiKey
91
+ });
92
+ }
93
+
94
+ // Check for OpenAI
95
+ const openaiApiKey = process.env.OPENAI_API_KEY || savedConfig.openaiApiKey;
96
+ if (openaiApiKey && openaiApiKey.trim()) {
97
+ providers.push({
98
+ provider: 'openai',
99
+ model: 'gpt-4-turbo-2024-04-09',
100
+ apiKey: openaiApiKey
101
+ });
102
+ }
103
+
104
+ // Always add Ollama as fallback (local, no API key needed)
105
+ providers.push({
106
+ provider: 'ollama',
107
+ model: 'qwen2.5-coder:32b'
108
+ });
109
+
110
+ return providers;
111
+ }
112
+
113
+ /**
114
+ * Check if current requirement is DONE and actually completed
115
+ * @param {string} repoPath - Repository path
116
+ * @returns {Promise<{isDone: boolean, actuallyComplete: boolean, reason?: string}>}
117
+ */
118
+ async isRequirementDone(repoPath) {
119
+ try {
120
+ const { getRequirementsPath } = require('../index');
121
+ const reqPath = await getRequirementsPath(repoPath);
122
+
123
+ if (!reqPath || !await fs.pathExists(reqPath)) {
124
+ return { isDone: false, actuallyComplete: false };
125
+ }
126
+
127
+ const content = await fs.readFile(reqPath, 'utf8');
128
+ const lines = content.split('\n');
129
+
130
+ // Check RESPONSE section for "Status updated from VERIFY to DONE"
131
+ let inResponseSection = false;
132
+ let responseContent = '';
133
+ let statusIsDone = false;
134
+
135
+ for (const line of lines) {
136
+ const trimmed = line.trim();
137
+
138
+ if (trimmed.includes('## RESPONSE FROM LAST CHAT')) {
139
+ inResponseSection = true;
140
+ continue;
141
+ }
142
+
143
+ if (inResponseSection) {
144
+ if (trimmed.startsWith('##') && !trimmed.includes('RESPONSE')) {
145
+ break;
146
+ }
147
+ if (trimmed && !trimmed.startsWith('###')) {
148
+ responseContent += trimmed + ' ';
149
+
150
+ // Check for status progression completion
151
+ const upperLine = trimmed.toUpperCase();
152
+ if (upperLine.includes('STATUS UPDATED FROM VERIFY TO DONE') ||
153
+ upperLine.includes('STATUS: DONE') ||
154
+ upperLine.includes('MOVED TO VERIFIED')) {
155
+ statusIsDone = true;
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ if (!statusIsDone) {
162
+ return { isDone: false, actuallyComplete: false };
163
+ }
164
+
165
+ // Check if response shows actual work was done
166
+ const responseUpper = responseContent.toUpperCase();
167
+ const hasSubstantialResponse = responseContent.length > 100 && (
168
+ responseUpper.includes('COMPLETE') ||
169
+ responseUpper.includes('IMPLEMENTED') ||
170
+ responseUpper.includes('CREATED') ||
171
+ responseUpper.includes('UPDATED') ||
172
+ responseUpper.includes('ADDED') ||
173
+ responseUpper.includes('FIXED') ||
174
+ responseUpper.includes('VERIFIED') ||
175
+ responseUpper.match(/DONE.*-.*completed/i) ||
176
+ responseUpper.includes('100') && responseUpper.includes('REQUIREMENT') // For "create 100 requirements"
177
+ );
178
+
179
+ // Also check for vague responses that indicate incomplete work
180
+ const isVagueResponse = responseUpper.includes('I WILL') ||
181
+ responseUpper.includes('I\'LL') ||
182
+ responseUpper.includes('LET ME') ||
183
+ responseUpper.includes('I CAN') ||
184
+ responseUpper.includes('I SHOULD') ||
185
+ (responseUpper.includes('READ') && !responseUpper.includes('CREATED')) ||
186
+ (responseUpper.includes('UNDERSTAND') && !responseUpper.includes('IMPLEMENTED'));
187
+
188
+ if (statusIsDone && hasSubstantialResponse && !isVagueResponse) {
189
+ return { isDone: true, actuallyComplete: true };
190
+ }
191
+
192
+ if (statusIsDone && (!hasSubstantialResponse || isVagueResponse)) {
193
+ return {
194
+ isDone: true,
195
+ actuallyComplete: false,
196
+ reason: isVagueResponse ? 'Vague response detected' : 'No substantial work in response'
197
+ };
198
+ }
199
+
200
+ return { isDone: false, actuallyComplete: false };
201
+ } catch (error) {
202
+ return { isDone: false, actuallyComplete: false };
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Move a requirement from Verified back to Requirements not yet completed
208
+ * @param {string} repoPath - Repository path
209
+ * @param {string} requirementText - The requirement text to move back
210
+ * @returns {Promise<{success: boolean, error?: string}>}
211
+ */
212
+ async moveRequirementBackToTodo(repoPath, requirementText) {
213
+ try {
214
+ const { getRequirementsPath } = require('../index');
215
+ const reqPath = await getRequirementsPath(repoPath);
216
+
217
+ if (!reqPath || !await fs.pathExists(reqPath)) {
218
+ return { success: false, error: 'Requirements file not found' };
219
+ }
220
+
221
+ const content = await fs.readFile(reqPath, 'utf8');
222
+ const lines = content.split('\n');
223
+ const updatedLines = [];
224
+
225
+ let inVerifiedSection = false;
226
+ let requirementFound = false;
227
+ let inNotYetCompleted = false;
228
+
229
+ for (let i = 0; i < lines.length; i++) {
230
+ const line = lines[i];
231
+ const trimmed = line.trim();
232
+
233
+ // Find verified section
234
+ if (line.includes('## ✅ Verified by AI screenshot')) {
235
+ inVerifiedSection = true;
236
+ updatedLines.push(line);
237
+ continue;
238
+ }
239
+
240
+ // Find not yet completed section
241
+ if (line.includes('## ⏳ Requirements not yet completed')) {
242
+ inNotYetCompleted = true;
243
+ inVerifiedSection = false;
244
+ updatedLines.push(line);
245
+ continue;
246
+ }
247
+
248
+ // Check if we're in verified section and this is requirement to move
249
+ if (inVerifiedSection && trimmed.startsWith('- ')) {
250
+ const lineRequirement = line.substring(2).trim();
251
+ // Remove date prefix if present (format: "2025-11-05: **requirement**")
252
+ const cleanRequirement = lineRequirement.replace(/^\d{4}-\d{2}-\d{2}:\s*\*\*/, '').replace(/\*\*$/, '').trim();
253
+ const cleanRequirementText = requirementText.replace(/\*\*/g, '').trim();
254
+
255
+ if (lineRequirement.includes(requirementText) || cleanRequirement === cleanRequirementText) {
256
+ // Skip this line (don't add it to updatedLines)
257
+ requirementFound = true;
258
+ continue;
259
+ }
260
+ }
261
+
262
+ // If we're in not yet completed section and haven't added requirement yet, add it at the top
263
+ if (inNotYetCompleted && !requirementFound && trimmed.startsWith('- ')) {
264
+ // Add the requirement before the first existing requirement
265
+ const newUpdatedLines = lines.slice(0, i);
266
+ newUpdatedLines.push(`- ${requirementText}`);
267
+ newUpdatedLines.push('');
268
+ newUpdatedLines.push(...lines.slice(i));
269
+ await fs.writeFile(reqPath, newUpdatedLines.join('\n'));
270
+ return { success: true };
271
+ }
272
+
273
+ // Reset section flags when hitting new sections
274
+ if (trimmed.startsWith('##')) {
275
+ inVerifiedSection = false;
276
+ inNotYetCompleted = false;
277
+ }
278
+
279
+ updatedLines.push(line);
280
+ }
281
+
282
+ // If requirement wasn't found in verified section, try to add it to not yet completed anyway
283
+ if (!requirementFound) {
284
+ // Find the not yet completed section and add requirement at the top
285
+ const newUpdatedLines = lines.slice();
286
+ for (let i = 0; i < updatedLines.length; i++) {
287
+ if (updatedLines[i].includes('## ⏳ Requirements not yet completed')) {
288
+ // Find the first requirement line after this section
289
+ let insertIndex = i + 1;
290
+ while (insertIndex < updatedLines.length &&
291
+ (updatedLines[insertIndex].trim() === '' || updatedLines[insertIndex].trim().startsWith('#'))) {
292
+ insertIndex++;
293
+ }
294
+ updatedLines.splice(insertIndex, 0, `- ${requirementText}`, '');
295
+ await fs.writeFile(reqPath, updatedLines.join('\n'));
296
+ return { success: true };
297
+ }
298
+ }
299
+ }
300
+
301
+ return { success: false, error: 'Requirement not found in verified section' };
302
+ } catch (error) {
303
+ return { success: false, error: error.message };
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Move a requirement from TODO to "Requirements needing manual feedback" section
309
+ * @param {string} repoPath - Repository path
310
+ * @param {string} requirementText - The requirement text to move
311
+ * @param {string} questions - Clarifying questions to add
312
+ * @returns {Promise<{success: boolean, error?: string}>}
313
+ */
314
+ async moveRequirementToFeedback(repoPath, requirementText, questions, findings = null) {
315
+ try {
316
+ const { getRequirementsPath } = require('../index');
317
+ const reqPath = await getRequirementsPath(repoPath);
318
+
319
+ if (!reqPath || !await fs.pathExists(reqPath)) {
320
+ return { success: false, error: 'Requirements file not found' };
321
+ }
322
+
323
+ const content = await fs.readFile(reqPath, 'utf8');
324
+ const lines = content.split('\n');
325
+
326
+ let inTodoSection = false;
327
+ let requirementRemoved = false;
328
+ let feedbackAdded = false;
329
+
330
+ for (const line of lines) {
331
+ const trimmed = line.trim();
332
+
333
+ // Find TODO section
334
+ if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
335
+ inTodoSection = true;
336
+ continue;
337
+ }
338
+
339
+ // Find "Requirements needing manual feedback" section
340
+ if (trimmed.startsWith('##') && (trimmed.includes('Requirements needing manual feedback') || trimmed.includes('❓ Requirements needing'))) {
341
+ inTodoSection = false;
342
+ const updatedLines = lines.slice(0, lines.indexOf(line));
343
+ updatedLines.push(line);
344
+
345
+ // Add blank line if not already present
346
+ if (updatedLines[updatedLines.length - 2]?.trim() !== '') {
347
+ updatedLines.push('');
348
+ }
349
+
350
+ // Add requirement with findings and questions at the top of feedback section
351
+ if (!feedbackAdded) {
352
+ const today = new Date().toISOString().split('T')[0];
353
+ updatedLines.push(`- ${today}: **${requirementText}**`);
354
+
355
+ // Add AI findings if available
356
+ if (findings) {
357
+ updatedLines.push(' **AI found in codebase:**');
358
+ updatedLines.push(` ${findings}`);
359
+ updatedLines.push('');
360
+ }
361
+
362
+ updatedLines.push(' **Clarifying questions:**');
363
+ const questionLines = questions.split('\n');
364
+ for (const q of questionLines) {
365
+ updatedLines.push(` ${q}`);
366
+ }
367
+ updatedLines.push('');
368
+ feedbackAdded = true;
369
+ }
370
+
371
+ updatedLines.push(...lines.slice(lines.indexOf(line) + 1));
372
+ await fs.writeFile(reqPath, updatedLines.join('\n'));
373
+ return { success: true };
374
+ }
375
+
376
+ // Stop sections at next header
377
+ if (trimmed.startsWith('##')) {
378
+ inTodoSection = false;
379
+ }
380
+
381
+ // Remove requirement from TODO section (match first occurrence)
382
+ if (inTodoSection && !requirementRemoved && trimmed.startsWith('- ')) {
383
+ const reqText = trimmed.substring(2).trim();
384
+ // Clean both for comparison
385
+ const cleanReq = reqText.replace(/\*\*/g, '').replace(/^\d{4}-\d{2}-\d{2}:\s*/, '').trim();
386
+ const cleanTarget = requirementText.replace(/\*\*/g, '').trim();
387
+
388
+ if (cleanReq === cleanTarget || reqText.includes(requirementText) || requirementText.includes(cleanReq)) {
389
+ requirementRemoved = true;
390
+ continue; // Skip this line
391
+ }
392
+ }
393
+
394
+ updatedLines.push(line);
395
+ }
396
+
397
+ // If feedback section doesn't exist, create it
398
+ if (!feedbackAdded) {
399
+ // Find where to insert the feedback section (after TODO, before VERIFIED)
400
+ let insertIndex = -1;
401
+ for (let i = 0; i < updatedLines.length; i++) {
402
+ if (updatedLines[i].includes('## ✅ Verified by AI') || updatedLines[i].includes('---')) {
403
+ insertIndex = i;
404
+ break;
405
+ }
406
+ }
407
+
408
+ if (insertIndex === -1) {
409
+ insertIndex = updatedLines.length;
410
+ }
411
+
412
+ const today = new Date().toISOString().split('T')[0];
413
+ const feedbackSection = [
414
+ '',
415
+ '## ❓ Requirements needing manual feedback',
416
+ '',
417
+ `- ${today}: **${requirementText}**`
418
+ ];
419
+
420
+ // Add AI findings if available
421
+ if (findings) {
422
+ feedbackSection.push(' **AI found in codebase:**');
423
+ feedbackSection.push(` ${findings}`);
424
+ feedbackSection.push('');
425
+ }
426
+
427
+ feedbackSection.push(' **Clarifying questions:**');
428
+
429
+ const questionLines = questions.split('\n');
430
+ for (const q of questionLines) {
431
+ feedbackSection.push(` ${q}`);
432
+ }
433
+ feedbackSection.push('');
434
+
435
+ updatedLines.splice(insertIndex, 0, ...feedbackSection);
436
+ feedbackAdded = true;
437
+ }
438
+
439
+ await fs.writeFile(reqPath, updatedLines.join('\n'));
440
+ return { success: true };
441
+ } catch (error) {
442
+ return { success: false, error: error.message };
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Move completed requirement from TODO to TO VERIFY section (for human verification)
448
+ * @param {string} repoPath - Repository path
449
+ * @param {string} completedRequirement - The completed requirement text
450
+ * @returns {Promise<{success: boolean, error?: string}>}
451
+ */
452
+ async moveCompletedRequirement(repoPath, completedRequirement) {
453
+ try {
454
+ const { getRequirementsPath } = require('../index');
455
+ const reqPath = await getRequirementsPath(repoPath);
456
+
457
+ if (!reqPath || !await fs.pathExists(reqPath)) {
458
+ return { success: false, error: 'Requirements file not found' };
459
+ }
460
+
461
+ const content = await fs.readFile(reqPath, 'utf8');
462
+ const lines = content.split('\n');
463
+
464
+ // First, check if requirement is already in TO VERIFY section
465
+ const verifySectionVariants = [
466
+ '## 🔍 TO VERIFY BY HUMAN',
467
+ '## 🔍 TO VERIFY',
468
+ '## TO VERIFY',
469
+ '## ✅ TO VERIFY',
470
+ '## ✅ Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG'
471
+ ];
472
+
473
+ let inVerifySection = false;
474
+ let alreadyInVerify = false;
475
+ const normalizedCompleted = completedRequirement.trim();
476
+ const snippet = normalizedCompleted.substring(0, 80);
477
+
478
+ for (let i = 0; i < lines.length; i++) {
479
+ const line = lines[i];
480
+ const trimmed = line.trim();
481
+
482
+ // Check if we're entering TO VERIFY section
483
+ if (trimmed.startsWith('##')) {
484
+ inVerifySection = verifySectionVariants.some(variant => {
485
+ const variantTrimmed = variant.trim();
486
+ return trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed);
487
+ }) && !trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i);
488
+
489
+ if (inVerifySection && (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot'))) {
490
+ continue;
491
+ }
492
+ }
493
+
494
+ // Check if we're leaving TO VERIFY section
495
+ if (inVerifySection && trimmed.startsWith('##') && !trimmed.startsWith('###')) {
496
+ const isVerifyHeader = verifySectionVariants.some(variant => {
497
+ const variantTrimmed = variant.trim();
498
+ return trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed);
499
+ });
500
+ if (!isVerifyHeader) {
501
+ inVerifySection = false;
502
+ }
503
+ }
504
+
505
+ // Check if requirement is already in TO VERIFY
506
+ if (inVerifySection && trimmed.startsWith('###')) {
507
+ const title = trimmed.replace(/^###\s*/, '').trim();
508
+ if (title) {
509
+ const normalizedTitle = title.trim();
510
+ if (normalizedTitle === normalizedCompleted ||
511
+ normalizedTitle.includes(normalizedCompleted) ||
512
+ normalizedCompleted.includes(normalizedTitle) ||
513
+ normalizedTitle.includes(snippet) ||
514
+ snippet.includes(normalizedTitle.substring(0, 80))) {
515
+ alreadyInVerify = true;
516
+ break;
517
+ }
518
+ }
519
+ }
520
+ }
521
+
522
+ if (alreadyInVerify) {
523
+ return { success: true }; // Already in TO VERIFY, nothing to do
524
+ }
525
+
526
+ // Find requirement by its title (in ### header format)
527
+ // Normalize completed requirement text for matching
528
+ let requirementStartIndex = -1;
529
+ let requirementEndIndex = -1;
530
+
531
+ // Try to find the requirement in TODO section first
532
+ let inTodoSection = false;
533
+ for (let i = 0; i < lines.length; i++) {
534
+ const line = lines[i];
535
+ const trimmed = line.trim();
536
+
537
+ // Check if we're entering TODO section
538
+ if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
539
+ inTodoSection = true;
540
+ continue;
541
+ }
542
+
543
+ // Check if we're leaving TODO section
544
+ if (inTodoSection && trimmed.startsWith('##') && !trimmed.startsWith('###') && !trimmed.includes('Requirements not yet completed')) {
545
+ inTodoSection = false;
546
+ }
547
+
548
+ // Only look for requirements in TODO section
549
+ if (inTodoSection && trimmed.startsWith('###')) {
550
+ const title = trimmed.replace(/^###\s*/, '').trim();
551
+ if (title) {
552
+ // Try multiple matching strategies
553
+ const normalizedTitle = title.trim();
554
+ const titleSnippet = normalizedTitle.substring(0, 80);
555
+
556
+ // Exact match
557
+ if (normalizedTitle === normalizedCompleted) {
558
+ requirementStartIndex = i;
559
+ }
560
+ // Check if either contains the other (for partial matches)
561
+ else if (normalizedTitle.includes(normalizedCompleted) || normalizedCompleted.includes(normalizedTitle)) {
562
+ requirementStartIndex = i;
563
+ }
564
+ // Check snippet matches
565
+ else if (normalizedTitle.includes(snippet) || snippet.includes(titleSnippet)) {
566
+ requirementStartIndex = i;
567
+ }
568
+ // Check if they start with the same (for REGRESSION: prefix issues)
569
+ else if (normalizedTitle.replace(/^REGRESSION:\s*/i, '') === normalizedCompleted.replace(/^REGRESSION:\s*/i, '') ||
570
+ normalizedTitle.replace(/^REGRESSION:\s*/i, '').includes(snippet.replace(/^REGRESSION:\s*/i, '')) ||
571
+ snippet.replace(/^REGRESSION:\s*/i, '').includes(normalizedTitle.replace(/^REGRESSION:\s*/i, ''))) {
572
+ requirementStartIndex = i;
573
+ }
574
+
575
+ if (requirementStartIndex !== -1) {
576
+ // Find the end of this requirement (next ### or ## header)
577
+ for (let j = i + 1; j < lines.length; j++) {
578
+ const nextLine = lines[j].trim();
579
+ if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
580
+ requirementEndIndex = j;
581
+ break;
582
+ }
583
+ }
584
+ if (requirementEndIndex === -1) {
585
+ requirementEndIndex = lines.length;
586
+ }
587
+ break;
588
+ }
589
+ }
590
+ }
591
+ }
592
+
593
+ if (requirementStartIndex === -1) {
594
+ return { success: false, error: `Could not find requirement "${completedRequirement.substring(0, 60)}..." in TODO section` };
595
+ }
596
+
597
+ // Extract the entire requirement block
598
+ const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
599
+
600
+ // Remove the requirement from its current location
601
+ lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
602
+
603
+ // Find or create TO VERIFY BY HUMAN section (reuse the variants we defined earlier)
604
+ let verifyIndex = -1;
605
+ for (let i = 0; i < lines.length; i++) {
606
+ const line = lines[i];
607
+ const trimmed = line.trim();
608
+
609
+ // Check each variant more carefully
610
+ for (const variant of verifySectionVariants) {
611
+ const variantTrimmed = variant.trim();
612
+ // Exact match or line starts with variant
613
+ if (trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed)) {
614
+ // Double-check: make sure it's NOT a VERIFIED section (without TO VERIFY)
615
+ if (!trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i) &&
616
+ (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot'))) {
617
+ verifyIndex = i;
618
+ break;
619
+ }
620
+ }
621
+ }
622
+ if (verifyIndex !== -1) break;
623
+ }
624
+
625
+ if (verifyIndex === -1) {
626
+ // Create TO VERIFY section - place it BEFORE VERIFIED section if one exists, otherwise before CHANGELOG
627
+ const verifiedIndex = lines.findIndex(line => {
628
+ const trimmed = line.trim();
629
+ return trimmed === '## 📝 VERIFIED' || trimmed.startsWith('## 📝 VERIFIED') ||
630
+ (trimmed.startsWith('##') && trimmed.includes('VERIFIED') && !trimmed.includes('TO VERIFY'));
631
+ });
632
+ const changelogIndex = lines.findIndex(line => line.includes('## CHANGELOG'));
633
+ const manualFeedbackIndex = lines.findIndex(line => line.trim().startsWith('## ❓'));
634
+
635
+ // Prefer: before VERIFIED > before CHANGELOG > before manual feedback > at end
636
+ let insertionIndex = lines.length;
637
+ if (verifiedIndex > 0) {
638
+ insertionIndex = verifiedIndex;
639
+ } else if (changelogIndex > 0) {
640
+ insertionIndex = changelogIndex;
641
+ } else if (manualFeedbackIndex > 0) {
642
+ insertionIndex = manualFeedbackIndex;
643
+ }
644
+
645
+ const block = [];
646
+ if (insertionIndex > 0 && lines[insertionIndex - 1].trim() !== '') {
647
+ block.push('');
648
+ }
649
+ block.push('## 🔍 TO VERIFY BY HUMAN', '');
650
+ lines.splice(insertionIndex, 0, ...block);
651
+ verifyIndex = lines.findIndex(line => {
652
+ const trimmed = line.trim();
653
+ return trimmed === '## 🔍 TO VERIFY BY HUMAN' || trimmed.startsWith('## 🔍 TO VERIFY BY HUMAN');
654
+ });
655
+
656
+ if (verifyIndex === -1) {
657
+ return { success: false, error: 'Failed to create TO VERIFY BY HUMAN section' };
658
+ }
659
+ }
660
+
661
+ // Safety check: verify we're not inserting into a VERIFIED section
662
+ const verifyLine = lines[verifyIndex] || '';
663
+ if (verifyLine.includes('## 📝 VERIFIED') || (verifyLine.trim().startsWith('##') && verifyLine.includes('VERIFIED') && !verifyLine.includes('TO VERIFY'))) {
664
+ return { success: false, error: 'Attempted to insert into VERIFIED section instead of TO VERIFY' };
665
+ }
666
+
667
+ // Insert requirement block at the TOP of TO VERIFY section (right after section header)
668
+ let insertIndex = verifyIndex + 1;
669
+
670
+ // Ensure there's a blank line after the section header
671
+ if (lines[insertIndex]?.trim() !== '') {
672
+ lines.splice(insertIndex, 0, '');
673
+ insertIndex++;
674
+ }
675
+
676
+ // Insert the requirement block
677
+ lines.splice(insertIndex, 0, ...requirementBlock);
678
+
679
+ // Ensure there's a blank line after the requirement block
680
+ const afterIndex = insertIndex + requirementBlock.length;
681
+ if (afterIndex < lines.length && lines[afterIndex]?.trim() !== '') {
682
+ lines.splice(afterIndex, 0, '');
683
+ }
684
+
685
+ // Write the file
686
+ await fs.writeFile(reqPath, lines.join('\n'));
687
+ return { success: true };
688
+ } catch (error) {
689
+ return { success: false, error: error.message };
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Handle sending text to IDE with proper error handling and session limits
695
+ * @param {Object} event - Event object
696
+ * @param {string} ide - IDE name
697
+ * @param {string} text - Text to send
698
+ * @param {string} extension - Extension name
699
+ * @returns {Promise<Object>} Send result
700
+ */
701
+ async handleSendText(event, ide, text, extension) {
702
+ try {
703
+ const manager = new AppleScriptManager();
704
+
705
+ // IMPORTANT: Distinguish between 'windsurf' IDE and 'vscode' with windsurf extension
706
+ // If ide is 'windsurf', use the standalone Windsurf IDE, NOT VS Code with extension
707
+ // Only route to VS Code if ide is explicitly 'vscode' with windsurf extension
708
+ let result;
709
+ if (ide === 'vscode' && extension === 'windsurf') {
710
+ // Use VS Code with Windsurf extension
711
+ result = await manager.sendText(text, 'vscode', global.currentRepoPath);
712
+ } else if (ide === 'windsurf') {
713
+ // For standalone Windsurf IDE, send directly to Windsurf
714
+ result = await manager.sendText(text, 'windsurf', global.currentRepoPath);
715
+ } else {
716
+ result = await manager.sendText(text, ide, global.currentRepoPath);
717
+ }
718
+
719
+ // Handle Claude session limit
720
+ if (ide === 'claude' && result.success) {
721
+ // Wait a moment for Claude to respond
722
+ await new Promise(resolve => setTimeout(resolve, 3000));
723
+
724
+ const sessionCheck = await manager.checkClaudeSessionLimit();
725
+
726
+ if (sessionCheck.sessionLimitReached) {
727
+ // Notify renderer process
728
+ if (global.mainWindow && global.mainWindow.webContents) {
729
+ global.mainWindow.webContents.send('claude-session-limit-reached', {
730
+ message: sessionCheck.message,
731
+ note: sessionCheck.note,
732
+ resetTime: sessionCheck.resetTime, // Pass reset time to UI
733
+ recentOutput: sessionCheck.recentOutput
734
+ });
735
+ }
736
+
737
+ // Pause auto mode if it's running
738
+ if (this.state.isAutoMode) {
739
+ this.state.isAutoMode = false;
740
+ }
741
+
742
+ return {
743
+ success: false,
744
+ sessionLimitReached: true,
745
+ error: 'Claude session limit reached',
746
+ ...sessionCheck
747
+ };
748
+ }
749
+ }
750
+
751
+ // Handle other IDE quota limits
752
+ if (result.success) {
753
+ const quotaChecks = [
754
+ { ide: 'antigravity', checkMethod: 'checkAntigravityQuotaLimit', eventName: 'antigravity-quota-limit-reached' },
755
+ { ide: 'cursor', checkMethod: 'checkCursorQuotaLimit', eventName: 'cursor-quota-limit-reached' },
756
+ { ide: 'kiro', checkMethod: 'checkKiroQuotaLimit', eventName: 'kiro-quota-limit-reached' },
757
+ { ide: 'windsurf', checkMethod: 'checkWindsurfRateLimit', eventName: 'windsurf-rate-limit-reached' }
758
+ ];
759
+
760
+ for (const { ide: targetIde, checkMethod, eventName } of quotaChecks) {
761
+ if (ide === targetIde) {
762
+ try {
763
+ await new Promise(resolve => setTimeout(resolve, 2000));
764
+ const quotaCheck = await manager[checkMethod]();
765
+
766
+ if (quotaCheck && quotaCheck.isRateLimited) {
767
+ // Notify renderer process
768
+ if (global.mainWindow && global.mainWindow.webContents) {
769
+ global.mainWindow.webContents.send(eventName, {
770
+ message: quotaCheck.message,
771
+ resumeAt: quotaCheck.resumeAt || null
772
+ });
773
+ }
774
+
775
+ // Pause auto mode if it's running
776
+ if (this.state.isAutoMode) {
777
+ this.state.isAutoMode = false;
778
+ }
779
+
780
+ return {
781
+ success: false,
782
+ rateLimited: true,
783
+ error: `${targetIde} quota limit reached`,
784
+ ...quotaCheck
785
+ };
786
+ }
787
+ } catch (quotaErr) {
788
+ // Continue on quota check errors
789
+ }
790
+ }
791
+ }
792
+ }
793
+
794
+ return result;
795
+ } catch (error) {
796
+ return { success: false, error: error.message };
797
+ }
798
+ }
799
+
800
+ /**
801
+ * Update auto mode state
802
+ * @param {Object} newState - New state to merge
803
+ */
804
+ updateState(newState) {
805
+ Object.assign(this.state, newState);
806
+ }
807
+
808
+ /**
809
+ * Get current auto mode state
810
+ * @returns {Object} Current state
811
+ */
812
+ getState() {
813
+ return { ...this.state };
814
+ }
815
+
816
+ /**
817
+ * Reset auto mode state
818
+ */
819
+ resetState() {
820
+ this.state = {
821
+ isAutoMode: false,
822
+ currentIDE: 'vscode',
823
+ chatCounter: 0,
824
+ maxChats: 100,
825
+ neverStop: false,
826
+ autoModeEvent: null,
827
+ currentMode: 'requirements',
828
+ currentSpecPath: null,
829
+ currentSpecId: null,
830
+ specsList: null,
831
+ currentSpecIndex: 0
832
+ };
833
+ }
834
+ }
835
+
836
+ module.exports = AutoModeBusinessLogic;