vibecodingmachine-core 2026.3.14-1537 → 2026.6.17-1835
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/package.json +7 -2
- package/src/agents/Agent.js +1 -1
- package/src/agents/AgentAdditionService.js +1 -1
- package/src/agents/AgentCheckDiscoveryService.js +2 -2
- package/src/agents/AgentCheckService.js +16 -16
- package/src/agents/AgentCheckStatisticsService.js +11 -11
- package/src/agents/AgentInstallationService.js +6 -6
- package/src/agents/AgentSetupService.js +15 -15
- package/src/agents/AgentStatus.js +8 -8
- package/src/agents/AgentVerificationService.js +39 -39
- package/src/agents/ConfigurationSchemaValidator.js +8 -8
- package/src/agents/EnvironmentConfigurationManager.js +28 -28
- package/src/agents/InstallationErrorHandler.js +11 -11
- package/src/agents/InstallationLog.js +18 -18
- package/src/agents/InstallationMethod.js +1 -1
- package/src/agents/InstallationOrchestrator.js +37 -37
- package/src/agents/InstallationProgressReporter.js +13 -13
- package/src/agents/InstallationRetryManager.js +20 -20
- package/src/agents/InstallationType.js +14 -14
- package/src/agents/OperationTypes.js +12 -12
- package/src/agents/PerformanceMetricsCollector.js +59 -59
- package/src/agents/SecurityValidationService.js +17 -17
- package/src/agents/SimpleAgentCheckService.js +79 -74
- package/src/agents/VerificationTest.js +26 -26
- package/src/agents/VerificationType.js +5 -5
- package/src/agents/WindowsPermissionHandler.js +30 -30
- package/src/agents/config/AgentDefaultsRegistry.js +3 -3
- package/src/agents/config-managers/ConfigUtils.js +5 -5
- package/src/agents/config-managers/DefaultConfig.js +1 -1
- package/src/agents/config-managers/EnvVarLoader.js +7 -7
- package/src/agents/config-managers/FileConfigLoader.js +22 -22
- package/src/agents/config-managers/TypeConverters.js +1 -1
- package/src/agents/config-managers/VariableMappings.js +7 -7
- package/src/agents/discovery/AgentDiscoveryService-refactored.js +8 -8
- package/src/agents/discovery/AgentDiscoveryService.js +14 -14
- package/src/agents/discovery/agent-validator.js +4 -4
- package/src/agents/discovery/discovery-results.js +1 -1
- package/src/agents/discovery/discovery-scanner.js +29 -29
- package/src/agents/discovery/discovery-utils.js +6 -6
- package/src/agents/discovery/executable-analyzer.js +27 -27
- package/src/agents/discovery/history-manager.js +2 -2
- package/src/agents/logging/AgentLogger.js +20 -20
- package/src/agents/status/AgentStatusManager.js +30 -30
- package/src/agents/storage/FileManager.js +15 -15
- package/src/agents/validation.js +4 -4
- package/src/agents/verification/AgentCommunicationTester.js +46 -46
- package/src/agents/verification/BaseVerifier.js +31 -31
- package/src/agents/verification/CommandVerifier.js +34 -34
- package/src/agents/verification/FileOperationVerifier.js +14 -14
- package/src/agents/verification/ResultAnalyzer-refactored.js +7 -7
- package/src/agents/verification/ResultAnalyzer.js +29 -29
- package/src/agents/verification/TestRequirementManager.js +49 -49
- package/src/agents/verification/VerificationRunner.js +18 -18
- package/src/agents/verification/analysis-utils.js +27 -27
- package/src/agents/verification/batch-analyzer.js +55 -55
- package/src/agents/verification/pattern-recognizer.js +49 -49
- package/src/agents/verification/report-generator.js +9 -9
- package/src/agents/verification/test-analyzer.js +29 -29
- package/src/agents/windows/BaseWindowsInstaller.js +22 -22
- package/src/agents/windows/ChocolateyInstaller.js +31 -31
- package/src/agents/windows/DirectInstaller.js +23 -23
- package/src/agents/windows/InstallerFactory.js +16 -16
- package/src/agents/windows/NpmInstaller.js +39 -39
- package/src/agents/windows/PowerShellInstaller.js +27 -27
- package/src/agents/windows/VSCodeExtensionInstaller.js +10 -10
- package/src/agents/windows/WinGetInstaller.js +23 -23
- package/src/analysis/analysis-engine.js +35 -35
- package/src/analysis/analysis-reporter.js +7 -7
- package/src/analysis/ast-analyzer.js +28 -28
- package/src/analysis/boundary-detector-refactored.js +35 -35
- package/src/analysis/boundary-detector.js +35 -35
- package/src/analysis/boundary-scanner.js +52 -52
- package/src/analysis/boundary-types.js +3 -3
- package/src/analysis/boundary-utils.js +33 -33
- package/src/analysis/categorizer.js +20 -20
- package/src/analysis/codebase-scanner.js +22 -22
- package/src/analysis/detection-methods.js +25 -25
- package/src/analysis/line-counter.js +14 -14
- package/src/analysis/report/analysis-report.js +9 -9
- package/src/analysis/report/package-analyzer.js +33 -33
- package/src/analysis/report/recommendation-generator.js +29 -29
- package/src/analysis/report/statistics-generator.js +53 -53
- package/src/analysis/reports/analysis-report-model.js +4 -4
- package/src/analysis/reports/recommendation-generator.js +25 -25
- package/src/analysis/reports/report-generators.js +9 -9
- package/src/analysis/reports/statistics-calculator.js +23 -23
- package/src/analysis/reports/trend-analyzer.js +19 -19
- package/src/analysis/strategy-generator.js +5 -5
- package/src/auth/shared-auth-storage.js +15 -7
- package/src/auto-mode/AutoModeBusinessLogic.js +9 -15
- package/src/auto-mode/auto-mode-streaks.js +104 -0
- package/src/auto-mode/direct-run-recovery.js +99 -0
- package/src/auto-mode/rate-limit-budget.js +169 -0
- package/src/auto-mode/rate-limit-handler.js +218 -0
- package/src/auto-mode/rate-limit-store.js +174 -0
- package/src/auto-mode/stage-change-log.js +60 -0
- package/src/auto-mode/stage-stall-tracker.js +123 -0
- package/src/auto-mode-error-detector/error-detector.js +135 -0
- package/src/autonomous-mode/feature-implementer.js +20 -24
- package/src/beta-request.js +1 -1
- package/src/chat-management/chat-manager.js +3 -3
- package/src/commands/base.js +8 -8
- package/src/commands/disable-requirement.js +2 -2
- package/src/commands/disable-spec.js +2 -2
- package/src/commands/enable-requirement.js +2 -2
- package/src/commands/enable-spec.js +2 -2
- package/src/commands/help.js +5 -5
- package/src/commands/registry.js +12 -12
- package/src/commands/requirements.js +2 -2
- package/src/commands/resolver.js +7 -7
- package/src/commands/settings.js +79 -4
- package/src/compliance/compliance-manager.js +10 -10
- package/src/compliance/compliance-prompt.js +6 -6
- package/src/config/refactoring-config.js +6 -6
- package/src/database/migrations.js +1 -1
- package/src/database/user-database-client.js +1 -1
- package/src/database/user-schema.js +2 -2
- package/src/feedback/feedback-config-manager.js +95 -0
- package/src/feedback/feedback-manager.js +501 -0
- package/src/feedback/ui-preferences-manager.js +87 -0
- package/src/git/commit-manager.js +475 -0
- package/src/health-tracking/health-reporter.js +14 -14
- package/src/health-tracking/ide-health-tracker.js +17 -3
- package/src/health-tracking/json-storage.js +4 -4
- package/src/ide-integration/agent-test-runner.js +275 -0
- package/src/ide-integration/aider/commands/configuration-manager.js +39 -0
- package/src/ide-integration/aider/commands/installation-manager.js +111 -0
- package/src/ide-integration/aider/processes/process-manager.js +37 -0
- package/src/ide-integration/aider/utils/ollama-manager.js +154 -0
- package/src/ide-integration/aider-cli-manager.cjs +16 -241
- package/src/ide-integration/applescript-antigravity-quota.cjs +515 -0
- package/src/ide-integration/applescript-cursor-quota.cjs +351 -0
- package/src/ide-integration/applescript-ide-opener.cjs +489 -0
- package/src/ide-integration/applescript-kiro-quota.cjs +549 -0
- package/src/ide-integration/applescript-manager-core.js +30 -12
- package/src/ide-integration/applescript-manager.cjs +45 -3201
- package/src/ide-integration/applescript-manager.js +34 -16
- package/src/ide-integration/applescript-response-reader.cjs +658 -0
- package/src/ide-integration/applescript-send-text.cjs +307 -0
- package/src/ide-integration/applescript-status-continuation.cjs +581 -0
- package/src/ide-integration/applescript-utils.js +203 -192
- package/src/ide-integration/cdp-handlers/connection-handler.js +2 -2
- package/src/ide-integration/cdp-handlers/continuation-handler.js +7 -7
- package/src/ide-integration/cdp-handlers/text-sender.js +1 -1
- package/src/ide-integration/cdp-manager.js +2 -2
- package/src/ide-integration/cli-direct-runner.js +483 -0
- package/src/ide-integration/cli-session-manager.js +180 -0
- package/src/ide-integration/cline-cli-manager.js +24 -24
- package/src/ide-integration/continuation-handler.js +18 -18
- package/src/ide-integration/continue-cli-manager.js +14 -14
- package/src/ide-integration/ide-openers/claude-opener.js +23 -7
- package/src/ide-integration/ide-openers/other-ides-opener.js +17 -63
- package/src/ide-integration/ide-status-checker.js +20 -20
- package/src/ide-integration/macos-ide-manager.js +55 -4
- package/src/ide-integration/macos-quota-checker.js +1 -1
- package/src/ide-integration/macos-text-sender.js +204 -68
- package/src/ide-integration/quota-detector.cjs +11 -11
- package/src/ide-integration/quota-detector.js +11 -11
- package/src/ide-integration/response-reader.js +10 -10
- package/src/ide-integration/windows/cursor-automation.js +304 -0
- package/src/ide-integration/windows/ide-automation.js +735 -0
- package/src/ide-integration/windows/window-operations.js +183 -0
- package/src/ide-integration/windows-automation-manager.js +92 -865
- package/src/ide-integration/windows-ide-manager.js +13 -13
- package/src/index.cjs +87 -6
- package/src/index.js +56 -41
- package/src/installation/config-manager.js +247 -0
- package/src/installation/config-paths.js +64 -0
- package/src/installation/fs-validators.js +166 -0
- package/src/installation/index.js +30 -0
- package/src/installation/path-resolver.js +73 -0
- package/src/installation/types.js +57 -0
- package/src/installation/version-detector.js +233 -0
- package/src/items/item-conversation.js +101 -0
- package/src/items/items-migrator.js +358 -0
- package/src/items/items-slug.js +55 -0
- package/src/items/items-store-io.js +257 -0
- package/src/items/items-store.js +541 -0
- package/src/localization/index.js +3 -3
- package/src/localization/translations/en-part1.js +1 -1
- package/src/localization/translations/en-part2.js +1 -1
- package/src/localization/translations/es-part1.js +1 -1
- package/src/localization/translations/es-part2.js +1 -1
- package/src/models/compliance-report.js +44 -44
- package/src/models/file-analysis.js +33 -33
- package/src/models/plan-manager.js +44 -44
- package/src/models/refactoring-models.js +4 -4
- package/src/models/refactoring-plan-refactored.js +2 -2
- package/src/models/refactoring-plan.js +5 -5
- package/src/monitoring/alert-system.js +84 -84
- package/src/monitoring/compliance-progress-tracker.js +19 -19
- package/src/monitoring/continuous-scan-notifications.js +54 -54
- package/src/monitoring/continuous-scanner.js +24 -24
- package/src/monitoring/file-monitor/file-analyzer.js +23 -23
- package/src/monitoring/file-monitor/file-monitor.js +20 -20
- package/src/monitoring/file-monitor/watcher.js +18 -18
- package/src/monitoring/file-monitor.js +1 -1
- package/src/monitoring/notification-handlers/base-handler.js +3 -3
- package/src/monitoring/notification-handlers/error-handler.js +1 -1
- package/src/monitoring/notification-handlers/index.js +1 -1
- package/src/monitoring/notification-handlers/new-violation-handler.js +5 -5
- package/src/monitoring/notification-handlers/progress-handler.js +2 -2
- package/src/monitoring/notification-handlers/resolved-violation-handler.js +4 -4
- package/src/monitoring/notification-handlers/threshold-handler.js +1 -1
- package/src/monitoring/notification-manager.js +36 -36
- package/src/monitoring/scanner-core.js +43 -43
- package/src/monitoring/scanner-events.js +26 -26
- package/src/monitoring/violation-notification-system.js +10 -10
- package/src/progress/metrics-aggregator.js +194 -0
- package/src/progress/metrics-store.js +263 -0
- package/src/provider-registry.js +5 -5
- package/src/quota-management/index.js +2 -2
- package/src/refactoring/boundaries/cohesion-analyzer.js +21 -21
- package/src/refactoring/boundaries/extraction-result.js +1 -1
- package/src/refactoring/boundaries/extraction-strategies.js +27 -27
- package/src/refactoring/boundaries/module-boundary.js +8 -8
- package/src/refactoring/boundary/boundary-detector-refactored.js +1 -1
- package/src/refactoring/boundary/boundary-detector.js +26 -26
- package/src/refactoring/boundary/boundary-types.js +21 -21
- package/src/refactoring/boundary/detectors/boundary-analyzers.js +34 -34
- package/src/refactoring/boundary/detectors/boundary-core.js +14 -14
- package/src/refactoring/boundary/detectors/class-detector.js +28 -28
- package/src/refactoring/boundary/detectors/config-detector.js +28 -28
- package/src/refactoring/boundary/detectors/constant-detector.js +28 -28
- package/src/refactoring/boundary/detectors/function-detector.js +28 -28
- package/src/refactoring/boundary/detectors/module-detector.js +29 -29
- package/src/refactoring/boundary/detectors/object-detector.js +28 -28
- package/src/refactoring/boundary/detectors/type-detectors.js +34 -34
- package/src/refactoring/boundary/detectors/utility-detector.js +28 -28
- package/src/refactoring/boundary/extraction-strategies.js +61 -61
- package/src/refactoring/boundary-extraction-result.js +3 -3
- package/src/refactoring/boundary-extraction-strategies.js +28 -28
- package/src/refactoring/boundary-extractor.js +13 -13
- package/src/refactoring/boundary-types.js +1 -1
- package/src/refactoring/circular/circular-dependency.js +4 -4
- package/src/refactoring/circular/cycle-detection.js +10 -10
- package/src/refactoring/circular/dependency-node.js +1 -1
- package/src/refactoring/circular/dependency-result.js +1 -1
- package/src/refactoring/circular/dependency-types.js +2 -2
- package/src/refactoring/circular/graph-builder.js +25 -25
- package/src/refactoring/circular/resolution-strategy.js +1 -1
- package/src/refactoring/circular/strategy-generator.js +28 -28
- package/src/refactoring/circular-dependency-resolver-original.js +70 -70
- package/src/refactoring/circular-dependency-resolver.js +19 -19
- package/src/refactoring/code-mover-refactored.js +31 -31
- package/src/refactoring/code-mover.js +53 -53
- package/src/refactoring/execution-status.js +1 -1
- package/src/refactoring/execution-strategies.js +28 -28
- package/src/refactoring/file-splitter-core.js +58 -58
- package/src/refactoring/file-splitter-types.js +1 -1
- package/src/refactoring/file-splitter.js +1 -1
- package/src/refactoring/functionality-validator.js +90 -90
- package/src/refactoring/import-manager-refactored.js +42 -42
- package/src/refactoring/import-manager.js +57 -57
- package/src/refactoring/import-models.js +1 -1
- package/src/refactoring/import-parser.js +41 -41
- package/src/refactoring/module-boundary.js +3 -3
- package/src/refactoring/move-executor.js +45 -45
- package/src/refactoring/move-utils.js +27 -27
- package/src/refactoring/operation-executor.js +7 -7
- package/src/refactoring/plan-creator.js +3 -3
- package/src/refactoring/plan-executor.js +21 -21
- package/src/refactoring/plan-validator.js +10 -10
- package/src/refactoring/refactoring-executor-result.js +1 -1
- package/src/refactoring/refactoring-executor.js +5 -5
- package/src/refactoring/refactoring-operation.js +3 -3
- package/src/refactoring/refactoring-plan.js +2 -2
- package/src/refactoring/refactoring-rollback.js +1 -1
- package/src/refactoring/rollback-handlers/RollbackExecutor.js +12 -12
- package/src/refactoring/rollback-handlers/RollbackManager.js +34 -34
- package/src/refactoring/rollback-handlers/RollbackOperation.js +2 -2
- package/src/refactoring/rollback-handlers/RollbackResult.js +5 -5
- package/src/refactoring/rollback-handlers/RollbackStatistics.js +8 -8
- package/src/refactoring/test-validator.js +19 -19
- package/src/refactoring/validation/baseline-runner.js +10 -10
- package/src/refactoring/validation/report-generator.js +16 -16
- package/src/refactoring/validation/result-comparator.js +10 -10
- package/src/refactoring/validation/test-suite.js +2 -2
- package/src/refactoring/validation/test-validation-result.js +2 -2
- package/src/refactoring/validation/validation-runner.js +16 -16
- package/src/refactoring/validation/validation-status.js +1 -1
- package/src/repos/repos-store.js +220 -0
- package/src/requirement-management/default-requirement-manager.js +20 -20
- package/src/requirement-management/requirement-file-parser.js +3 -3
- package/src/requirement-management/requirement-sequencer.js +17 -17
- package/src/rui/base.js +6 -6
- package/src/rui/commands/AgentCommandParser.js +6 -6
- package/src/rui/commands/AgentCommands.js +26 -26
- package/src/rui/commands/AgentResponseFormatter.js +12 -12
- package/src/rui/commands/parsers/CommandMapper.js +5 -5
- package/src/rui/commands/parsers/CommandValidator.js +5 -5
- package/src/rui/commands/parsers/ComponentExtractor.js +4 -4
- package/src/rui/commands/parsers/TokenParser.js +6 -6
- package/src/rui/commands/parsers/tokenizer.js +9 -9
- package/src/rui/index.js +5 -5
- package/src/rui/registry.js +5 -5
- package/src/rui/resolver.js +3 -3
- package/src/screenshot/analysis-engine.js +249 -0
- package/src/screenshot/capture-engine.js +251 -0
- package/src/screenshot/verification-loop.js +191 -0
- package/src/scripts/verify-full-compliance.js +32 -32
- package/src/spec-management/queue-storage.js +320 -0
- package/src/spec-management/retry-manager.js +243 -0
- package/src/spec-management/spec-counter.js +301 -0
- package/src/spec-management/spec-fingerprint.js +148 -0
- package/src/spec-management/spec-logger.js +329 -0
- package/src/spec-management/spec-scanner.js +313 -0
- package/src/sync/aws-setup.js +41 -41
- package/src/sync/remote-control-server.js +50 -50
- package/src/sync/sync-engine-conflicts.js +10 -10
- package/src/sync/sync-engine-core.js +9 -9
- package/src/sync/sync-engine-file-ops.js +7 -7
- package/src/sync/sync-engine.js +12 -12
- package/src/task-generation/automated-task-generator.js +20 -20
- package/src/task-generation/prioritizer.js +39 -39
- package/src/task-generation/task-list-updater.js +29 -29
- package/src/task-generation/task-management-integration.js +92 -92
- package/src/task-generation/task-manager-integration.js +18 -18
- package/src/task-generation/violation-task-generator.js +54 -54
- package/src/task-management/continuous-scan-integration.js +25 -25
- package/src/ui/ChatInterface.js +1 -1
- package/src/ui/ChromeExtensionAdapter.js +309 -0
- package/src/ui/FeedbackComponent.js +334 -0
- package/src/utils/analyzer.js +18 -18
- package/src/utils/cleanup.js +28 -28
- package/src/utils/config-helpers.js +64 -4
- package/src/utils/constants.js +19 -0
- package/src/utils/current-requirement-operations.js +63 -11
- package/src/utils/dependency-mapper.js +8 -8
- package/src/utils/duplicate-detector.js +29 -29
- package/src/utils/error-reporter.js +6 -6
- package/src/utils/file-monitor.js +20 -20
- package/src/utils/git-branch-manager.js +157 -1
- package/src/utils/import-updater.js +10 -10
- package/src/utils/refactor-plan.js +22 -22
- package/src/utils/refactoring-tools.js +7 -7
- package/src/utils/repo-helpers.cjs +16 -11
- package/src/utils/repo-helpers.js +15 -8
- package/src/utils/report-generator.js +1 -1
- package/src/utils/report-generators/analysis-generator.js +4 -4
- package/src/utils/report-generators/base-generator.js +7 -7
- package/src/utils/report-generators/compliance-generator.js +2 -2
- package/src/utils/report-generators/format-handlers.js +16 -16
- package/src/utils/report-generators/refactoring-generator.js +1 -1
- package/src/utils/report-generators/validation-generator.js +3 -3
- package/src/utils/reports/report-analysis.js +13 -13
- package/src/utils/reports/report-types.js +1 -1
- package/src/utils/reports/summary-generators.js +4 -4
- package/src/utils/requirement-enable-disable.js +69 -44
- package/src/utils/requirement-file-management.js +10 -28
- package/src/utils/requirement-helpers/requirement-file-ops.js +22 -17
- package/src/utils/requirement-helpers/requirement-mover.js +13 -13
- package/src/utils/requirement-helpers/requirement-parser.js +6 -10
- package/src/utils/requirement-helpers/requirement-status.js +20 -18
- package/src/utils/requirement-helpers-new.js +8 -8
- package/src/utils/requirement-helpers-refactored.js +1 -1
- package/src/utils/requirement-helpers.js +1 -1
- package/src/utils/requirement-loader.js +238 -0
- package/src/utils/requirement-movement.js +46 -46
- package/src/utils/requirement-writer.js +466 -0
- package/src/utils/rollback/rollback-handlers.js +2 -2
- package/src/utils/rollback/rollback-operation.js +1 -1
- package/src/utils/rollback/rollback-recorder.js +4 -4
- package/src/utils/rollback/rollback-state-manager.js +5 -5
- package/src/utils/rollback/rollback-types.js +1 -1
- package/src/utils/rollback/rollback-utils.js +4 -4
- package/src/utils/rollback-manager-original.js +14 -14
- package/src/utils/rollback-manager.js +4 -4
- package/src/utils/smoke-test-cli.js +20 -20
- package/src/utils/smoke-test-gui.js +34 -34
- package/src/utils/smoke-test-orchestrator.js +24 -24
- package/src/utils/smoke-test-runner.js +5 -5
- package/src/utils/smoke-test-web.js +22 -22
- package/src/utils/spec-loader.js +308 -0
- package/src/utils/spec-writer.js +295 -0
- package/src/utils/specification-enable-disable.js +10 -10
- package/src/utils/task-parser.js +141 -0
- package/src/utils/test-comparator.js +2 -2
- package/src/utils/test-config.js +1 -1
- package/src/utils/test-executor.js +7 -7
- package/src/utils/test-parser.js +4 -4
- package/src/utils/test-runner-baseline.js +5 -5
- package/src/utils/test-runner-core.js +2 -2
- package/src/utils/test-runner-report.js +1 -1
- package/src/utils/test-runner-validation.js +9 -9
- package/src/utils/test-runner.js +1 -1
- package/src/utils/validation-framework.js +27 -27
- package/src/utils/verification-summary-validator.js +51 -0
- package/src/validation/comparison-analyzer.js +34 -34
- package/src/validation/compliance-analyzer.js +23 -23
- package/src/validation/compliance-report-generator.js +23 -23
- package/src/validation/compliance-reporter-new.js +18 -18
- package/src/validation/compliance-reporter-refactored.js +18 -18
- package/src/validation/compliance-reporter.js +45 -30
- package/src/validation/compliance-rules.js +12 -12
- package/src/validation/compliance-utils.js +20 -20
- package/src/validation/constitution-validator-new.js +16 -16
- package/src/validation/constitution-validator.js +1 -1
- package/src/validation/file-validators.js +13 -13
- package/src/validation/html-generator.js +27 -27
- package/src/validation/line-limit/file-analyzer.js +15 -15
- package/src/validation/line-limit/line-limit-validator.js +10 -10
- package/src/validation/line-limit/validation-result.js +6 -6
- package/src/validation/line-limit-core.js +29 -29
- package/src/validation/line-limit-reporter.js +20 -20
- package/src/validation/line-limit-result.js +3 -3
- package/src/validation/line-limit-validator.js +5 -5
- package/src/validation/metrics/category-calculator.js +9 -9
- package/src/validation/metrics/metrics-helpers.js +16 -16
- package/src/validation/metrics/overview-calculator.js +2 -2
- package/src/validation/metrics/overview-metrics.js +1 -1
- package/src/validation/metrics/quality-calculator.js +22 -22
- package/src/validation/metrics/size-calculator.js +3 -3
- package/src/validation/metrics-calculator.js +2 -2
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
// @vibecodingmachine/core - Direct CLI Runner
|
|
2
|
+
//
|
|
3
|
+
// Runs a CLI agent (e.g. Claude Code) as a hidden child process of VCM,
|
|
4
|
+
// streaming stdout/stderr to a caller-supplied logger so the output lands
|
|
5
|
+
// in the VCM Console panel without opening a Terminal window, stealing
|
|
6
|
+
// foreground focus, or pasting into whatever the user happens to be typing
|
|
7
|
+
// in.
|
|
8
|
+
//
|
|
9
|
+
// Replaces the older "wt.exe cmd /k claude" + PowerShell SetForegroundWindow +
|
|
10
|
+
// SendKeys Ctrl+V/Enter pipeline for Auto Mode invocations.
|
|
11
|
+
|
|
12
|
+
const { spawn } = require('child_process');
|
|
13
|
+
|
|
14
|
+
// Billing errors — need human action (add credits), NOT a time-based reset.
|
|
15
|
+
// Detected the same as rate limits (stop retrying) but flagged separately so
|
|
16
|
+
// the UI shows the raw message with no countdown timer.
|
|
17
|
+
const BILLING_PATTERNS = [
|
|
18
|
+
/credit balance is too low/i,
|
|
19
|
+
/credit limit reached/i,
|
|
20
|
+
/insufficient.*credit/i,
|
|
21
|
+
/payment.*required/i,
|
|
22
|
+
/billing.*error/i,
|
|
23
|
+
/add.*credit/i,
|
|
24
|
+
/top.*up.*account/i,
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Strong patterns — verbatim system-error markers that don't appear in
|
|
28
|
+
// assistant prose. A hit on any of these is sufficient to flag the line.
|
|
29
|
+
const RATE_LIMIT_STRONG_PATTERNS = [
|
|
30
|
+
/Claude usage limit reached/i,
|
|
31
|
+
/weekly Claude limit/i,
|
|
32
|
+
/spending cap reached/i,
|
|
33
|
+
/you'?ve hit your limit/i,
|
|
34
|
+
/session limit reached/i,
|
|
35
|
+
/account limit reached/i,
|
|
36
|
+
/approaching weekly limit/i,
|
|
37
|
+
/weekly limit reached/i,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// Weaker phrases that ALSO appear in assistant-generated content. We only
|
|
41
|
+
// flag these when the same line also contains an "Error:" or "HTTP 429"
|
|
42
|
+
// marker (FR-015 / SC-006 false-positive guard).
|
|
43
|
+
const RATE_LIMIT_WEAK_PATTERNS = [
|
|
44
|
+
/rate limit reached/i,
|
|
45
|
+
/quota limit/i,
|
|
46
|
+
/too many requests/i,
|
|
47
|
+
/limit exceeded/i
|
|
48
|
+
];
|
|
49
|
+
const SYSTEM_ERROR_MARKER = /(?:^|\s)(?:Error:|ERROR:|HTTP\s+429|\b429\b|\bClaude\b)/;
|
|
50
|
+
|
|
51
|
+
const { parseResetTime } = require('../auto-mode/rate-limit-handler');
|
|
52
|
+
|
|
53
|
+
function _findBillingLine(output) {
|
|
54
|
+
if (typeof output !== 'string') return null;
|
|
55
|
+
const lines = output.split('\n');
|
|
56
|
+
for (const line of lines) {
|
|
57
|
+
for (const pat of BILLING_PATTERNS) {
|
|
58
|
+
if (pat.test(line)) return line.trim();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _findRateLimitLine(output) {
|
|
65
|
+
if (typeof output !== 'string') return null;
|
|
66
|
+
const lines = output.split('\n');
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
for (const pat of RATE_LIMIT_STRONG_PATTERNS) {
|
|
69
|
+
if (pat.test(line)) return line.trim();
|
|
70
|
+
}
|
|
71
|
+
for (const pat of RATE_LIMIT_WEAK_PATTERNS) {
|
|
72
|
+
if (pat.test(line) && SYSTEM_ERROR_MARKER.test(line)) return line.trim();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function detectRateLimit(output) {
|
|
79
|
+
// Check billing errors first — they share the "stop retrying" behaviour but
|
|
80
|
+
// must never show a countdown timer (only adding credits fixes them).
|
|
81
|
+
const billingLine = _findBillingLine(output);
|
|
82
|
+
if (billingLine) {
|
|
83
|
+
return {
|
|
84
|
+
isRateLimited: true,
|
|
85
|
+
isBillingError: true,
|
|
86
|
+
rawMessage: billingLine,
|
|
87
|
+
resetTime: null,
|
|
88
|
+
resetAt: null,
|
|
89
|
+
source: 'billing',
|
|
90
|
+
message: billingLine
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const line = _findRateLimitLine(output);
|
|
95
|
+
if (!line) return { isRateLimited: false };
|
|
96
|
+
|
|
97
|
+
// Legacy hour-of-day "resets at 3pm" parse, kept for back-compat with
|
|
98
|
+
// call sites that read result.resetTime as a string.
|
|
99
|
+
const legacy = line.match(/resets?\s+(?:at\s+)?(\d+)\s*([ap]m)/i);
|
|
100
|
+
const resetTime = legacy ? `${legacy[1]}${legacy[2].toLowerCase()}` : null;
|
|
101
|
+
|
|
102
|
+
// New broader parse — returns an absolute Date when extractable.
|
|
103
|
+
const parsed = parseResetTime(line);
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
isRateLimited: true,
|
|
107
|
+
isBillingError: false,
|
|
108
|
+
rawMessage: line,
|
|
109
|
+
resetTime,
|
|
110
|
+
resetAt: parsed.resetAt,
|
|
111
|
+
source: parsed.source,
|
|
112
|
+
message: 'Rate limit detected in CLI output'
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function resolveDefaultCommand(ide, options) {
|
|
117
|
+
if (options && options.command) return options.command;
|
|
118
|
+
switch (ide) {
|
|
119
|
+
case 'claude':
|
|
120
|
+
case 'claude-code':
|
|
121
|
+
return process.env.VCM_CLAUDE_CLI || 'claude';
|
|
122
|
+
default:
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function resolveDefaultArgs(ide, text, options) {
|
|
128
|
+
if (options && Array.isArray(options.args)) return options.args;
|
|
129
|
+
switch (ide) {
|
|
130
|
+
case 'claude':
|
|
131
|
+
case 'claude-code':
|
|
132
|
+
// --print runs Claude Code headless. --output-format stream-json
|
|
133
|
+
// emits JSONL events as they happen (assistant message deltas,
|
|
134
|
+
// tool use, tool result, etc.) instead of buffering all output
|
|
135
|
+
// until the final response. --verbose is required for stream-json
|
|
136
|
+
// to actually stream. We humanize each JSONL line in StreamBuffer
|
|
137
|
+
// so the Console panel sees readable text instead of raw JSON.
|
|
138
|
+
// --dangerously-skip-permissions lets the agent edit files
|
|
139
|
+
// without interactive approval.
|
|
140
|
+
return ['--print', '--dangerously-skip-permissions', '--verbose', '--output-format', 'stream-json', text];
|
|
141
|
+
default:
|
|
142
|
+
return [text];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Extract the usage block from a Claude Code stream-json line, if any.
|
|
148
|
+
* Assistant messages carry a `usage` object the Anthropic API returns:
|
|
149
|
+
* { input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens }
|
|
150
|
+
* Returns null when the line has no usage payload (tool_result, system, etc.).
|
|
151
|
+
*/
|
|
152
|
+
function extractClaudeUsage(rawLine) {
|
|
153
|
+
if (!rawLine || typeof rawLine !== 'string') return null;
|
|
154
|
+
let evt;
|
|
155
|
+
try { evt = JSON.parse(rawLine); }
|
|
156
|
+
catch (_) { return null; }
|
|
157
|
+
if (!evt || typeof evt !== 'object') return null;
|
|
158
|
+
const u = evt.message && evt.message.usage;
|
|
159
|
+
if (!u || typeof u !== 'object') return null;
|
|
160
|
+
return {
|
|
161
|
+
input: Number(u.input_tokens) || 0,
|
|
162
|
+
output: Number(u.output_tokens) || 0,
|
|
163
|
+
cacheRead: Number(u.cache_read_input_tokens) || 0,
|
|
164
|
+
cacheWrite: Number(u.cache_creation_input_tokens) || 0
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Convert a single Claude Code stream-json event into one or more
|
|
169
|
+
// human-readable lines for the Console. Returns an array (possibly
|
|
170
|
+
// empty) of strings.
|
|
171
|
+
function humanizeClaudeStreamLine(rawLine) {
|
|
172
|
+
if (!rawLine || !rawLine.trim()) return [];
|
|
173
|
+
let evt;
|
|
174
|
+
try { evt = JSON.parse(rawLine); }
|
|
175
|
+
catch (_) {
|
|
176
|
+
// Not JSON — pass through unchanged so the user still sees it.
|
|
177
|
+
return [rawLine];
|
|
178
|
+
}
|
|
179
|
+
if (!evt || typeof evt !== 'object') return [rawLine];
|
|
180
|
+
|
|
181
|
+
const out = [];
|
|
182
|
+
const t = evt.type;
|
|
183
|
+
|
|
184
|
+
// Assistant message (the model's text + tool-use blocks)
|
|
185
|
+
if (t === 'assistant' && evt.message && Array.isArray(evt.message.content)) {
|
|
186
|
+
for (const block of evt.message.content) {
|
|
187
|
+
if (!block || !block.type) continue;
|
|
188
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
189
|
+
// Split on newlines so each paragraph gets its own console line.
|
|
190
|
+
for (const ln of block.text.split(/\r?\n/)) {
|
|
191
|
+
if (ln.trim()) out.push(`🤖 ${ln}`);
|
|
192
|
+
}
|
|
193
|
+
} else if (block.type === 'tool_use') {
|
|
194
|
+
const name = block.name || 'unknown';
|
|
195
|
+
const summary = _summarizeToolInput(name, block.input);
|
|
196
|
+
out.push(`🔧 ${name}${summary ? ' ' + summary : ''}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Tool result (the user message in stream-json carries it)
|
|
200
|
+
} else if (t === 'user' && evt.message && Array.isArray(evt.message.content)) {
|
|
201
|
+
for (const block of evt.message.content) {
|
|
202
|
+
if (block && block.type === 'tool_result') {
|
|
203
|
+
const content = block.content;
|
|
204
|
+
let txt = '';
|
|
205
|
+
if (typeof content === 'string') txt = content;
|
|
206
|
+
else if (Array.isArray(content)) {
|
|
207
|
+
txt = content.map(c => (c && c.type === 'text' && c.text) ? c.text : '').filter(Boolean).join('\n');
|
|
208
|
+
}
|
|
209
|
+
const firstLine = (txt || '').split(/\r?\n/)[0] || '';
|
|
210
|
+
const preview = firstLine.length > 200 ? firstLine.slice(0, 200) + '…' : firstLine;
|
|
211
|
+
if (preview) out.push(` ↳ ${preview}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Final result event
|
|
215
|
+
} else if (t === 'result') {
|
|
216
|
+
if (evt.is_error) out.push(`❌ Error: ${evt.error || evt.subtype || 'unknown'}`);
|
|
217
|
+
else if (evt.subtype === 'success') out.push(`✅ done in ${evt.duration_ms || '?'}ms`);
|
|
218
|
+
} else if (t === 'system') {
|
|
219
|
+
// Init / metadata — skip silently to keep the Console focused on the
|
|
220
|
+
// actual conversation.
|
|
221
|
+
} else if (typeof evt.text === 'string') {
|
|
222
|
+
// Fallback for any event with a top-level text field.
|
|
223
|
+
out.push(evt.text);
|
|
224
|
+
}
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function _summarizeToolInput(name, input) {
|
|
229
|
+
if (!input || typeof input !== 'object') return '';
|
|
230
|
+
const lc = String(name).toLowerCase();
|
|
231
|
+
if (lc === 'read' && input.file_path) return `(${input.file_path})`;
|
|
232
|
+
if (lc === 'write' && input.file_path) return `(${input.file_path})`;
|
|
233
|
+
if (lc === 'edit' && input.file_path) return `(${input.file_path})`;
|
|
234
|
+
if (lc === 'bash' && input.command) {
|
|
235
|
+
const cmd = String(input.command);
|
|
236
|
+
return `(${cmd.length > 100 ? cmd.slice(0, 100) + '…' : cmd})`;
|
|
237
|
+
}
|
|
238
|
+
if (lc === 'glob' && input.pattern) return `(${input.pattern})`;
|
|
239
|
+
if (lc === 'grep' && input.pattern) return `(${input.pattern})`;
|
|
240
|
+
return '';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function emitLine(logger, level, line) {
|
|
244
|
+
if (!line) return;
|
|
245
|
+
const trimmed = line.replace(/\r$/, '');
|
|
246
|
+
if (!trimmed) return;
|
|
247
|
+
if (!logger) {
|
|
248
|
+
if (level === 'error') process.stderr.write(`${trimmed}\n`);
|
|
249
|
+
else process.stdout.write(`${trimmed}\n`);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const method = level === 'error' ? (logger.error || logger.log) : (logger.log || logger.info);
|
|
253
|
+
if (typeof method === 'function') {
|
|
254
|
+
method.call(logger, trimmed);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
class StreamBuffer {
|
|
259
|
+
constructor(level, logger, onLine, transform) {
|
|
260
|
+
this.level = level;
|
|
261
|
+
this.logger = logger;
|
|
262
|
+
this.onLine = onLine;
|
|
263
|
+
// Optional transform: takes a raw line, returns an array of zero or
|
|
264
|
+
// more output lines. Used to turn Claude's stream-json events into
|
|
265
|
+
// human-readable Console text.
|
|
266
|
+
this.transform = transform || null;
|
|
267
|
+
this.buffer = '';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
_emit(line) {
|
|
271
|
+
if (this.transform) {
|
|
272
|
+
const transformed = this.transform(line);
|
|
273
|
+
if (Array.isArray(transformed)) {
|
|
274
|
+
for (const t of transformed) {
|
|
275
|
+
if (t) emitLine(this.logger, this.level, t);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
emitLine(this.logger, this.level, line);
|
|
280
|
+
}
|
|
281
|
+
if (this.onLine) this.onLine(line);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
write(chunk) {
|
|
285
|
+
this.buffer += chunk.toString('utf8');
|
|
286
|
+
let idx;
|
|
287
|
+
// Treat both \n and \r as line breaks so Claude's TUI progress redraws
|
|
288
|
+
// (which use \r) don't all collapse into one giant unreadable line.
|
|
289
|
+
while ((idx = this.buffer.search(/[\r\n]/)) !== -1) {
|
|
290
|
+
const line = this.buffer.slice(0, idx);
|
|
291
|
+
this.buffer = this.buffer.slice(idx + 1);
|
|
292
|
+
this._emit(line);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
flush() {
|
|
297
|
+
if (this.buffer.length > 0) {
|
|
298
|
+
const line = this.buffer;
|
|
299
|
+
this.buffer = '';
|
|
300
|
+
this._emit(line);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Run a CLI agent directly and stream its output to the caller-supplied
|
|
307
|
+
* logger. Resolves once the child exits.
|
|
308
|
+
*
|
|
309
|
+
* @param {Object} options
|
|
310
|
+
* @param {string} options.ide IDE identifier (e.g. 'claude-code')
|
|
311
|
+
* @param {string} options.text Prompt text for the agent
|
|
312
|
+
* @param {string} [options.repoPath] Working directory for the child
|
|
313
|
+
* @param {string} [options.command] Override the resolved command name
|
|
314
|
+
* @param {string[]} [options.args] Override the resolved argv
|
|
315
|
+
* @param {Object} [options.logger] Logger with .log/.error methods.
|
|
316
|
+
* Defaults to console; in the Electron
|
|
317
|
+
* main process pass safeLogger so the
|
|
318
|
+
* output flows into the Console panel.
|
|
319
|
+
* @param {number} [options.timeoutMs] Kill the child after this many ms.
|
|
320
|
+
* 0/undefined = no timeout.
|
|
321
|
+
* @param {Object} [options.env] Extra env vars merged onto process.env
|
|
322
|
+
* @param {Function} [options.spawnFn] Injected spawn (for tests)
|
|
323
|
+
* @returns {Promise<Object>}
|
|
324
|
+
*/
|
|
325
|
+
async function runCliDirect(options = {}) {
|
|
326
|
+
const {
|
|
327
|
+
ide,
|
|
328
|
+
text,
|
|
329
|
+
repoPath,
|
|
330
|
+
logger = console,
|
|
331
|
+
timeoutMs,
|
|
332
|
+
env: extraEnv,
|
|
333
|
+
spawnFn = spawn,
|
|
334
|
+
// Per-message usage callback. Receives { input, output, cacheRead, cacheWrite }
|
|
335
|
+
// for every stream-json line that carries a `usage` payload. Wired by the
|
|
336
|
+
// electron-app's rate-limit-bridge into the RateLimitBudget tracker so the
|
|
337
|
+
// Agents-tab "X% of 5h limit used" indicator updates live during a run.
|
|
338
|
+
onUsage
|
|
339
|
+
} = options;
|
|
340
|
+
|
|
341
|
+
if (!ide) {
|
|
342
|
+
throw new Error('runCliDirect: ide is required');
|
|
343
|
+
}
|
|
344
|
+
if (typeof text !== 'string' || text.length === 0) {
|
|
345
|
+
throw new Error('runCliDirect: text is required');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const command = resolveDefaultCommand(ide, options);
|
|
349
|
+
if (!command) {
|
|
350
|
+
return {
|
|
351
|
+
success: false,
|
|
352
|
+
method: 'cli-direct',
|
|
353
|
+
error: `No direct-spawn command configured for IDE: ${ide}`
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const args = resolveDefaultArgs(ide, text, options);
|
|
357
|
+
|
|
358
|
+
const preview = text.length > 120 ? `${text.slice(0, 120)}…` : text;
|
|
359
|
+
if (logger && typeof logger.log === 'function') {
|
|
360
|
+
logger.log(`[cli-direct] ${command} (${ide}) ← ${preview.replace(/\s+/g, ' ')}`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return new Promise((resolve) => {
|
|
364
|
+
let child;
|
|
365
|
+
const startedAt = Date.now();
|
|
366
|
+
const combined = [];
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
// Strip ANTHROPIC_API_KEY from the subprocess env so Claude Code uses
|
|
370
|
+
// its saved OAuth/Pro credentials instead of API-key billing. When the
|
|
371
|
+
// key is set in the shell, it overrides the login session and hits the
|
|
372
|
+
// API-account balance (which may be zero) rather than the Pro plan.
|
|
373
|
+
const childEnv = { ...process.env, ...(extraEnv || {}) };
|
|
374
|
+
if ((ide === 'claude' || ide === 'claude-code') && childEnv.ANTHROPIC_API_KEY) {
|
|
375
|
+
delete childEnv.ANTHROPIC_API_KEY;
|
|
376
|
+
}
|
|
377
|
+
child = spawnFn(command, args, {
|
|
378
|
+
cwd: repoPath || process.cwd(),
|
|
379
|
+
env: childEnv,
|
|
380
|
+
// Important: no `shell: true` — we don't want any Terminal popup or
|
|
381
|
+
// shell window. windowsHide ensures the helper console for the
|
|
382
|
+
// child is suppressed on Windows.
|
|
383
|
+
windowsHide: true,
|
|
384
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
385
|
+
});
|
|
386
|
+
} catch (err) {
|
|
387
|
+
resolve({
|
|
388
|
+
success: false,
|
|
389
|
+
method: 'cli-direct',
|
|
390
|
+
error: `Failed to spawn ${command}: ${err.message}`,
|
|
391
|
+
command,
|
|
392
|
+
args
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// For Claude in stream-json mode, transform each raw JSONL line into
|
|
398
|
+
// human-readable Console text before emitting. Non-Claude IDEs (or a
|
|
399
|
+
// future caller that opts out of stream-json) get the raw line.
|
|
400
|
+
const isClaude = ide === 'claude' || ide === 'claude-code';
|
|
401
|
+
const transform = isClaude ? humanizeClaudeStreamLine : null;
|
|
402
|
+
const onStdoutLine = (line) => {
|
|
403
|
+
combined.push(line);
|
|
404
|
+
// Forward per-message Anthropic usage to the caller if Claude printed one.
|
|
405
|
+
if (isClaude && typeof onUsage === 'function') {
|
|
406
|
+
const usage = extractClaudeUsage(line);
|
|
407
|
+
if (usage) {
|
|
408
|
+
try { onUsage(usage); } catch (_) { /* never block the stream on a listener throw */ }
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const stdoutBuf = new StreamBuffer('info', logger, onStdoutLine, transform);
|
|
413
|
+
const stderrBuf = new StreamBuffer('error', logger, (line) => combined.push(line), null);
|
|
414
|
+
|
|
415
|
+
child.stdout.on('data', (chunk) => stdoutBuf.write(chunk));
|
|
416
|
+
child.stderr.on('data', (chunk) => stderrBuf.write(chunk));
|
|
417
|
+
|
|
418
|
+
let killedByTimeout = false;
|
|
419
|
+
let timer = null;
|
|
420
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
421
|
+
timer = setTimeout(() => {
|
|
422
|
+
killedByTimeout = true;
|
|
423
|
+
try { child.kill('SIGTERM'); } catch (_) { /* ignore */ }
|
|
424
|
+
}, timeoutMs);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
child.on('error', (err) => {
|
|
428
|
+
if (timer) clearTimeout(timer);
|
|
429
|
+
resolve({
|
|
430
|
+
success: false,
|
|
431
|
+
method: 'cli-direct',
|
|
432
|
+
error: `Spawn error: ${err.message}`,
|
|
433
|
+
command,
|
|
434
|
+
args
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
child.on('close', (code, signal) => {
|
|
439
|
+
if (timer) clearTimeout(timer);
|
|
440
|
+
stdoutBuf.flush();
|
|
441
|
+
stderrBuf.flush();
|
|
442
|
+
|
|
443
|
+
const output = combined.join('\n');
|
|
444
|
+
const rl = detectRateLimit(output);
|
|
445
|
+
|
|
446
|
+
const durationMs = Date.now() - startedAt;
|
|
447
|
+
if (logger && typeof logger.log === 'function') {
|
|
448
|
+
logger.log(`[cli-direct] ${command} exited code=${code} signal=${signal || 'none'} in ${durationMs}ms`);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const success = !killedByTimeout && code === 0 && !rl.isRateLimited;
|
|
452
|
+
resolve({
|
|
453
|
+
success,
|
|
454
|
+
method: 'cli-direct',
|
|
455
|
+
exitCode: code,
|
|
456
|
+
signal,
|
|
457
|
+
durationMs,
|
|
458
|
+
command,
|
|
459
|
+
args,
|
|
460
|
+
output,
|
|
461
|
+
isRateLimited: rl.isRateLimited,
|
|
462
|
+
resetTime: rl.resetTime || undefined,
|
|
463
|
+
rateLimitMessage: rl.isRateLimited ? rl.message : undefined,
|
|
464
|
+
error: success
|
|
465
|
+
? undefined
|
|
466
|
+
: (killedByTimeout
|
|
467
|
+
? `Killed after ${timeoutMs}ms timeout`
|
|
468
|
+
: rl.isRateLimited
|
|
469
|
+
? rl.message
|
|
470
|
+
: `Exited with code ${code}`)
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
module.exports = {
|
|
477
|
+
runCliDirect,
|
|
478
|
+
detectRateLimit,
|
|
479
|
+
extractClaudeUsage,
|
|
480
|
+
// Exposed for tests
|
|
481
|
+
StreamBuffer,
|
|
482
|
+
humanizeClaudeStreamLine
|
|
483
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// @vibecodingmachine/core - CLI Session Manager
|
|
2
|
+
// Manages persistent terminal sessions for CLI-based agents (Claude, etc.)
|
|
3
|
+
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const { join } = require('path');
|
|
6
|
+
const { homedir } = require('os');
|
|
7
|
+
const { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } = require('fs');
|
|
8
|
+
const { tmpdir } = require('os');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* CLI Session Manager
|
|
12
|
+
* Manages persistent terminal sessions for CLI-based IDEs/agents
|
|
13
|
+
*/
|
|
14
|
+
class CliSessionManager {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.logger = console;
|
|
17
|
+
this.sessionDir = join(homedir(), '.vibecodingmachine', 'cli-sessions');
|
|
18
|
+
this._ensureSessionDir();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Ensure session directory exists
|
|
23
|
+
*/
|
|
24
|
+
_ensureSessionDir() {
|
|
25
|
+
try {
|
|
26
|
+
mkdirSync(this.sessionDir, { recursive: true });
|
|
27
|
+
} catch (error) {
|
|
28
|
+
this.logger.error('Failed to create session directory:', error.message);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get or create a session for a CLI IDE
|
|
34
|
+
* @param {string} ide - IDE name (e.g., 'claude', 'cursor')
|
|
35
|
+
* @param {string} repoPath - Repository path
|
|
36
|
+
* @returns {Object} Session info with status
|
|
37
|
+
*/
|
|
38
|
+
getOrCreateSession(ide, repoPath) {
|
|
39
|
+
const sessionFile = join(this.sessionDir, `${ide}.json`);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Try to load existing session
|
|
43
|
+
const sessionData = JSON.parse(readFileSync(sessionFile, 'utf8'));
|
|
44
|
+
|
|
45
|
+
// Verify the session is still valid (terminal still running the CLI)
|
|
46
|
+
if (this._isSessionActive(sessionData)) {
|
|
47
|
+
this.logger.log(`✅ [${ide}] Reusing existing session`);
|
|
48
|
+
return sessionData;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.logger.log(`⚠️ [${ide}] Previous session is no longer active, creating new one`);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
this.logger.log(`📝 [${ide}] No existing session found, creating new one`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Create new session
|
|
57
|
+
const newSession = this._createNewSession(ide, repoPath);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
writeFileSync(sessionFile, JSON.stringify(newSession, null, 2), 'utf8');
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.logger.error('Failed to save session:', error.message);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return newSession;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if a session is still active by looking for the CLI process
|
|
70
|
+
* @param {Object} sessionData - Session data
|
|
71
|
+
* @returns {boolean} True if session is active
|
|
72
|
+
*/
|
|
73
|
+
_isSessionActive(sessionData) {
|
|
74
|
+
if (!sessionData.ide) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Check if the CLI process is still running
|
|
80
|
+
const command = sessionData.ide === 'claude' ? 'claude' : sessionData.ide === 'cursor' ? 'cursor' : null;
|
|
81
|
+
|
|
82
|
+
if (!command) return false;
|
|
83
|
+
|
|
84
|
+
const processCheck = execSync(`ps aux | grep "${command} --dangerously" | grep -v grep | wc -l`, {
|
|
85
|
+
encoding: 'utf8',
|
|
86
|
+
timeout: 5000
|
|
87
|
+
}).trim();
|
|
88
|
+
|
|
89
|
+
const isActive = parseInt(processCheck) > 0;
|
|
90
|
+
this.logger.log(`🔍 [${sessionData.ide}] Session active check: ${isActive ? 'YES' : 'NO'}`);
|
|
91
|
+
return isActive;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this.logger.log(`⚠️ Session check failed: ${error.message}`);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create a new terminal session for a CLI IDE
|
|
100
|
+
* @param {string} ide - IDE name
|
|
101
|
+
* @param {string} repoPath - Repository path
|
|
102
|
+
* @returns {Object} New session object
|
|
103
|
+
*/
|
|
104
|
+
_createNewSession(ide, repoPath) {
|
|
105
|
+
const sessionId = `${ide}-${Date.now()}`;
|
|
106
|
+
|
|
107
|
+
this.logger.log(`🚀 [${ide}] Launching ${ide} in terminal...`);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const command = ide === 'claude' ? 'claude' : ide === 'cursor' ? 'cursor' : null;
|
|
111
|
+
|
|
112
|
+
if (!command) {
|
|
113
|
+
throw new Error(`Unsupported CLI IDE: ${ide}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Create AppleScript to launch terminal and CLI
|
|
117
|
+
// Use simple script that activates Terminal and runs commands in active window
|
|
118
|
+
const escapedPath = repoPath.replace(/'/g, "'\\''");
|
|
119
|
+
const launchScript = `tell application "Terminal"
|
|
120
|
+
activate
|
|
121
|
+
delay 0.5
|
|
122
|
+
do script "cd '${escapedPath}' && ${command} --dangerously-skip-permissions"
|
|
123
|
+
delay 3
|
|
124
|
+
end tell`;
|
|
125
|
+
|
|
126
|
+
const tempFile = join(tmpdir(), `cli_launch_${ide}_${Date.now()}.scpt`);
|
|
127
|
+
writeFileSync(tempFile, launchScript, 'utf8');
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
execSync(`osascript "${tempFile}"`, {
|
|
131
|
+
encoding: 'utf8',
|
|
132
|
+
timeout: 20000,
|
|
133
|
+
stdio: 'pipe'
|
|
134
|
+
});
|
|
135
|
+
} finally {
|
|
136
|
+
try { unlinkSync(tempFile); } catch (e) { /* ignore */ }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.logger.log(`✅ [${ide}] Terminal activated and ${command} launched`);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
ide,
|
|
143
|
+
sessionId,
|
|
144
|
+
repoPath,
|
|
145
|
+
command,
|
|
146
|
+
createdAt: new Date().toISOString(),
|
|
147
|
+
status: 'active'
|
|
148
|
+
};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
this.logger.error(`❌ [${ide}] Failed to launch session: ${error.message}`);
|
|
151
|
+
return {
|
|
152
|
+
ide,
|
|
153
|
+
sessionId,
|
|
154
|
+
repoPath,
|
|
155
|
+
createdAt: new Date().toISOString(),
|
|
156
|
+
status: 'error',
|
|
157
|
+
error: error.message
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Clear a session (for cleanup or reset)
|
|
164
|
+
* @param {string} ide - IDE name
|
|
165
|
+
*/
|
|
166
|
+
clearSession(ide) {
|
|
167
|
+
const sessionFile = join(this.sessionDir, `${ide}.json`);
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
if (existsSync(sessionFile)) {
|
|
171
|
+
unlinkSync(sessionFile);
|
|
172
|
+
this.logger.log(`🧹 [${ide}] Session cleared`);
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
this.logger.error(`Failed to clear session: ${error.message}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = CliSessionManager;
|