erosolar-cli 1.7.195 → 1.7.196
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/dist/StringUtils.d.ts +8 -0
- package/dist/StringUtils.d.ts.map +1 -0
- package/dist/StringUtils.js +11 -0
- package/dist/StringUtils.js.map +1 -0
- package/dist/adapters/browser/index.d.ts +12 -0
- package/dist/adapters/browser/index.d.ts.map +1 -0
- package/dist/adapters/browser/index.js +11 -0
- package/dist/adapters/browser/index.js.map +1 -0
- package/dist/adapters/node/index.d.ts +17 -0
- package/dist/adapters/node/index.d.ts.map +1 -0
- package/dist/adapters/node/index.js +35 -0
- package/dist/adapters/node/index.js.map +1 -0
- package/dist/adapters/remote/index.d.ts +13 -0
- package/dist/adapters/remote/index.d.ts.map +1 -0
- package/dist/adapters/remote/index.js +20 -0
- package/dist/adapters/remote/index.js.map +1 -0
- package/dist/adapters/types.d.ts +14 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/alpha-zero/agentWrapper.d.ts +84 -0
- package/dist/alpha-zero/agentWrapper.d.ts.map +1 -0
- package/dist/alpha-zero/agentWrapper.js +171 -0
- package/dist/alpha-zero/agentWrapper.js.map +1 -0
- package/dist/alpha-zero/codeEvaluator.d.ts +25 -0
- package/dist/alpha-zero/codeEvaluator.d.ts.map +1 -0
- package/dist/alpha-zero/codeEvaluator.js +273 -0
- package/dist/alpha-zero/codeEvaluator.js.map +1 -0
- package/dist/alpha-zero/competitiveRunner.d.ts +66 -0
- package/dist/alpha-zero/competitiveRunner.d.ts.map +1 -0
- package/dist/alpha-zero/competitiveRunner.js +224 -0
- package/dist/alpha-zero/competitiveRunner.js.map +1 -0
- package/dist/alpha-zero/index.d.ts +67 -0
- package/dist/alpha-zero/index.d.ts.map +1 -0
- package/dist/alpha-zero/index.js +99 -0
- package/dist/alpha-zero/index.js.map +1 -0
- package/dist/alpha-zero/introspection.d.ts +128 -0
- package/dist/alpha-zero/introspection.d.ts.map +1 -0
- package/dist/alpha-zero/introspection.js +300 -0
- package/dist/alpha-zero/introspection.js.map +1 -0
- package/dist/alpha-zero/metricsTracker.d.ts +71 -0
- package/dist/alpha-zero/metricsTracker.d.ts.map +1 -0
- package/dist/alpha-zero/metricsTracker.js +209 -0
- package/dist/alpha-zero/metricsTracker.js.map +1 -0
- package/dist/alpha-zero/security/core.d.ts +125 -0
- package/dist/alpha-zero/security/core.d.ts.map +1 -0
- package/dist/alpha-zero/security/core.js +271 -0
- package/dist/alpha-zero/security/core.js.map +1 -0
- package/dist/alpha-zero/security/google.d.ts +125 -0
- package/dist/alpha-zero/security/google.d.ts.map +1 -0
- package/dist/alpha-zero/security/google.js +311 -0
- package/dist/alpha-zero/security/google.js.map +1 -0
- package/dist/alpha-zero/security/googleLoader.d.ts +17 -0
- package/dist/alpha-zero/security/googleLoader.d.ts.map +1 -0
- package/dist/alpha-zero/security/googleLoader.js +41 -0
- package/dist/alpha-zero/security/googleLoader.js.map +1 -0
- package/dist/alpha-zero/security/index.d.ts +29 -0
- package/dist/alpha-zero/security/index.d.ts.map +1 -0
- package/dist/alpha-zero/security/index.js +32 -0
- package/dist/alpha-zero/security/index.js.map +1 -0
- package/dist/alpha-zero/security/simulation.d.ts +124 -0
- package/dist/alpha-zero/security/simulation.d.ts.map +1 -0
- package/dist/alpha-zero/security/simulation.js +277 -0
- package/dist/alpha-zero/security/simulation.js.map +1 -0
- package/dist/alpha-zero/selfModification.d.ts +109 -0
- package/dist/alpha-zero/selfModification.d.ts.map +1 -0
- package/dist/alpha-zero/selfModification.js +233 -0
- package/dist/alpha-zero/selfModification.js.map +1 -0
- package/dist/alpha-zero/types.d.ts +170 -0
- package/dist/alpha-zero/types.d.ts.map +1 -0
- package/dist/alpha-zero/types.js +31 -0
- package/dist/alpha-zero/types.js.map +1 -0
- package/dist/bin/erosolar.d.ts +9 -0
- package/dist/bin/erosolar.d.ts.map +1 -0
- package/dist/bin/erosolar.js +88 -0
- package/dist/bin/erosolar.js.map +1 -0
- package/dist/bin/selfTest.d.ts +14 -0
- package/dist/bin/selfTest.d.ts.map +1 -0
- package/dist/bin/selfTest.js +304 -0
- package/dist/bin/selfTest.js.map +1 -0
- package/dist/browser/BrowserSessionManager.d.ts +307 -0
- package/dist/browser/BrowserSessionManager.d.ts.map +1 -0
- package/dist/browser/BrowserSessionManager.js +713 -0
- package/dist/browser/BrowserSessionManager.js.map +1 -0
- package/dist/capabilities/advancedTestGenerationCapability.d.ts +17 -0
- package/dist/capabilities/advancedTestGenerationCapability.d.ts.map +1 -0
- package/dist/capabilities/advancedTestGenerationCapability.js +28 -0
- package/dist/capabilities/advancedTestGenerationCapability.js.map +1 -0
- package/dist/capabilities/agentSpawningCapability.d.ts +6 -0
- package/dist/capabilities/agentSpawningCapability.d.ts.map +1 -0
- package/dist/capabilities/agentSpawningCapability.js +115 -0
- package/dist/capabilities/agentSpawningCapability.js.map +1 -0
- package/dist/capabilities/askUserCapability.d.ts +21 -0
- package/dist/capabilities/askUserCapability.d.ts.map +1 -0
- package/dist/capabilities/askUserCapability.js +155 -0
- package/dist/capabilities/askUserCapability.js.map +1 -0
- package/dist/capabilities/bashCapability.d.ts +13 -0
- package/dist/capabilities/bashCapability.d.ts.map +1 -0
- package/dist/capabilities/bashCapability.js +24 -0
- package/dist/capabilities/bashCapability.js.map +1 -0
- package/dist/capabilities/browserAutomationCapability.d.ts +37 -0
- package/dist/capabilities/browserAutomationCapability.d.ts.map +1 -0
- package/dist/capabilities/browserAutomationCapability.js +49 -0
- package/dist/capabilities/browserAutomationCapability.js.map +1 -0
- package/dist/capabilities/cloudCapability.d.ts +13 -0
- package/dist/capabilities/cloudCapability.d.ts.map +1 -0
- package/dist/capabilities/cloudCapability.js +38 -0
- package/dist/capabilities/cloudCapability.js.map +1 -0
- package/dist/capabilities/codeAnalysisCapability.d.ts +13 -0
- package/dist/capabilities/codeAnalysisCapability.d.ts.map +1 -0
- package/dist/capabilities/codeAnalysisCapability.js +24 -0
- package/dist/capabilities/codeAnalysisCapability.js.map +1 -0
- package/dist/capabilities/codeGenerationCapability.d.ts +13 -0
- package/dist/capabilities/codeGenerationCapability.d.ts.map +1 -0
- package/dist/capabilities/codeGenerationCapability.js +25 -0
- package/dist/capabilities/codeGenerationCapability.js.map +1 -0
- package/dist/capabilities/codeQualityCapability.d.ts +13 -0
- package/dist/capabilities/codeQualityCapability.d.ts.map +1 -0
- package/dist/capabilities/codeQualityCapability.js +25 -0
- package/dist/capabilities/codeQualityCapability.js.map +1 -0
- package/dist/capabilities/dependencySecurityCapability.d.ts +13 -0
- package/dist/capabilities/dependencySecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/dependencySecurityCapability.js +24 -0
- package/dist/capabilities/dependencySecurityCapability.js.map +1 -0
- package/dist/capabilities/devCapability.d.ts +13 -0
- package/dist/capabilities/devCapability.d.ts.map +1 -0
- package/dist/capabilities/devCapability.js +24 -0
- package/dist/capabilities/devCapability.js.map +1 -0
- package/dist/capabilities/editCapability.d.ts +17 -0
- package/dist/capabilities/editCapability.d.ts.map +1 -0
- package/dist/capabilities/editCapability.js +27 -0
- package/dist/capabilities/editCapability.js.map +1 -0
- package/dist/capabilities/emailCapability.d.ts +12 -0
- package/dist/capabilities/emailCapability.d.ts.map +1 -0
- package/dist/capabilities/emailCapability.js +22 -0
- package/dist/capabilities/emailCapability.js.map +1 -0
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts +17 -0
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts.map +1 -0
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js +28 -0
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js.map +1 -0
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts +17 -0
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts.map +1 -0
- package/dist/capabilities/enhancedDevWorkflowCapability.js +28 -0
- package/dist/capabilities/enhancedDevWorkflowCapability.js.map +1 -0
- package/dist/capabilities/enhancedGitCapability.d.ts +7 -0
- package/dist/capabilities/enhancedGitCapability.d.ts.map +1 -0
- package/dist/capabilities/enhancedGitCapability.js +220 -0
- package/dist/capabilities/enhancedGitCapability.js.map +1 -0
- package/dist/capabilities/filesystemCapability.d.ts +13 -0
- package/dist/capabilities/filesystemCapability.d.ts.map +1 -0
- package/dist/capabilities/filesystemCapability.js +24 -0
- package/dist/capabilities/filesystemCapability.js.map +1 -0
- package/dist/capabilities/frontendTestingCapability.d.ts +13 -0
- package/dist/capabilities/frontendTestingCapability.d.ts.map +1 -0
- package/dist/capabilities/frontendTestingCapability.js +28 -0
- package/dist/capabilities/frontendTestingCapability.js.map +1 -0
- package/dist/capabilities/globCapability.d.ts +17 -0
- package/dist/capabilities/globCapability.d.ts.map +1 -0
- package/dist/capabilities/globCapability.js +27 -0
- package/dist/capabilities/globCapability.js.map +1 -0
- package/dist/capabilities/index.d.ts +25 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +25 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/interactionCapability.d.ts +12 -0
- package/dist/capabilities/interactionCapability.d.ts.map +1 -0
- package/dist/capabilities/interactionCapability.js +22 -0
- package/dist/capabilities/interactionCapability.js.map +1 -0
- package/dist/capabilities/learnCapability.d.ts +13 -0
- package/dist/capabilities/learnCapability.d.ts.map +1 -0
- package/dist/capabilities/learnCapability.js +24 -0
- package/dist/capabilities/learnCapability.js.map +1 -0
- package/dist/capabilities/mcpCapability.d.ts +6 -0
- package/dist/capabilities/mcpCapability.d.ts.map +1 -0
- package/dist/capabilities/mcpCapability.js +19 -0
- package/dist/capabilities/mcpCapability.js.map +1 -0
- package/dist/capabilities/notebookCapability.d.ts +17 -0
- package/dist/capabilities/notebookCapability.d.ts.map +1 -0
- package/dist/capabilities/notebookCapability.js +27 -0
- package/dist/capabilities/notebookCapability.js.map +1 -0
- package/dist/capabilities/performanceMonitoringCapability.d.ts +108 -0
- package/dist/capabilities/performanceMonitoringCapability.d.ts.map +1 -0
- package/dist/capabilities/performanceMonitoringCapability.js +176 -0
- package/dist/capabilities/performanceMonitoringCapability.js.map +1 -0
- package/dist/capabilities/planningCapability.d.ts +16 -0
- package/dist/capabilities/planningCapability.d.ts.map +1 -0
- package/dist/capabilities/planningCapability.js +26 -0
- package/dist/capabilities/planningCapability.js.map +1 -0
- package/dist/capabilities/refactoringCapability.d.ts +13 -0
- package/dist/capabilities/refactoringCapability.d.ts.map +1 -0
- package/dist/capabilities/refactoringCapability.js +25 -0
- package/dist/capabilities/refactoringCapability.js.map +1 -0
- package/dist/capabilities/repoChecksCapability.d.ts +10 -0
- package/dist/capabilities/repoChecksCapability.d.ts.map +1 -0
- package/dist/capabilities/repoChecksCapability.js +24 -0
- package/dist/capabilities/repoChecksCapability.js.map +1 -0
- package/dist/capabilities/searchCapability.d.ts +13 -0
- package/dist/capabilities/searchCapability.d.ts.map +1 -0
- package/dist/capabilities/searchCapability.js +24 -0
- package/dist/capabilities/searchCapability.js.map +1 -0
- package/dist/capabilities/skillCapability.d.ts +3 -0
- package/dist/capabilities/skillCapability.d.ts.map +1 -0
- package/dist/capabilities/skillCapability.js +77 -0
- package/dist/capabilities/skillCapability.js.map +1 -0
- package/dist/capabilities/taskManagementCapability.d.ts +12 -0
- package/dist/capabilities/taskManagementCapability.d.ts.map +1 -0
- package/dist/capabilities/taskManagementCapability.js +22 -0
- package/dist/capabilities/taskManagementCapability.js.map +1 -0
- package/dist/capabilities/testingCapability.d.ts +13 -0
- package/dist/capabilities/testingCapability.d.ts.map +1 -0
- package/dist/capabilities/testingCapability.js +25 -0
- package/dist/capabilities/testingCapability.js.map +1 -0
- package/dist/capabilities/todoCapability.d.ts +19 -0
- package/dist/capabilities/todoCapability.d.ts.map +1 -0
- package/dist/capabilities/todoCapability.js +169 -0
- package/dist/capabilities/todoCapability.js.map +1 -0
- package/dist/capabilities/toolManifest.d.ts +3 -0
- package/dist/capabilities/toolManifest.d.ts.map +1 -0
- package/dist/capabilities/toolManifest.js +160 -0
- package/dist/capabilities/toolManifest.js.map +1 -0
- package/dist/capabilities/toolRegistry.d.ts +22 -0
- package/dist/capabilities/toolRegistry.d.ts.map +1 -0
- package/dist/capabilities/toolRegistry.js +115 -0
- package/dist/capabilities/toolRegistry.js.map +1 -0
- package/dist/capabilities/validationCapability.d.ts +13 -0
- package/dist/capabilities/validationCapability.d.ts.map +1 -0
- package/dist/capabilities/validationCapability.js +24 -0
- package/dist/capabilities/validationCapability.js.map +1 -0
- package/dist/capabilities/webCapability.d.ts +12 -0
- package/dist/capabilities/webCapability.d.ts.map +1 -0
- package/dist/capabilities/webCapability.js +22 -0
- package/dist/capabilities/webCapability.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +140 -0
- package/dist/config.js.map +1 -0
- package/dist/contracts/v1/agent.d.ts +147 -0
- package/dist/contracts/v1/agent.d.ts.map +1 -0
- package/dist/contracts/v1/agent.js +8 -0
- package/dist/contracts/v1/agent.js.map +1 -0
- package/dist/contracts/v1/agentProfileManifest.d.ts +60 -0
- package/dist/contracts/v1/agentProfileManifest.d.ts.map +1 -0
- package/dist/contracts/v1/agentProfileManifest.js +9 -0
- package/dist/contracts/v1/agentProfileManifest.js.map +1 -0
- package/dist/contracts/v1/agentRules.d.ts +60 -0
- package/dist/contracts/v1/agentRules.d.ts.map +1 -0
- package/dist/contracts/v1/agentRules.js +10 -0
- package/dist/contracts/v1/agentRules.js.map +1 -0
- package/dist/contracts/v1/provider.d.ts +149 -0
- package/dist/contracts/v1/provider.d.ts.map +1 -0
- package/dist/contracts/v1/provider.js +7 -0
- package/dist/contracts/v1/provider.js.map +1 -0
- package/dist/contracts/v1/tool.d.ts +136 -0
- package/dist/contracts/v1/tool.d.ts.map +1 -0
- package/dist/contracts/v1/tool.js +7 -0
- package/dist/contracts/v1/tool.js.map +1 -0
- package/dist/contracts/v1/toolAccess.d.ts +43 -0
- package/dist/contracts/v1/toolAccess.d.ts.map +1 -0
- package/dist/contracts/v1/toolAccess.js +9 -0
- package/dist/contracts/v1/toolAccess.js.map +1 -0
- package/dist/core/LazyLoader.d.ts +129 -0
- package/dist/core/LazyLoader.d.ts.map +1 -0
- package/dist/core/LazyLoader.js +240 -0
- package/dist/core/LazyLoader.js.map +1 -0
- package/dist/core/agent.d.ts +150 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +789 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agentProfileManifest.d.ts +3 -0
- package/dist/core/agentProfileManifest.d.ts.map +1 -0
- package/dist/core/agentProfileManifest.js +188 -0
- package/dist/core/agentProfileManifest.js.map +1 -0
- package/dist/core/agentProfiles.d.ts +22 -0
- package/dist/core/agentProfiles.d.ts.map +1 -0
- package/dist/core/agentProfiles.js +35 -0
- package/dist/core/agentProfiles.js.map +1 -0
- package/dist/core/agentRulebook.d.ts +11 -0
- package/dist/core/agentRulebook.d.ts.map +1 -0
- package/dist/core/agentRulebook.js +136 -0
- package/dist/core/agentRulebook.js.map +1 -0
- package/dist/core/agentSchemaLoader.d.ts +131 -0
- package/dist/core/agentSchemaLoader.d.ts.map +1 -0
- package/dist/core/agentSchemaLoader.js +234 -0
- package/dist/core/agentSchemaLoader.js.map +1 -0
- package/dist/core/cliTestHarness.d.ts +200 -0
- package/dist/core/cliTestHarness.d.ts.map +1 -0
- package/dist/core/cliTestHarness.js +549 -0
- package/dist/core/cliTestHarness.js.map +1 -0
- package/dist/core/contextManager.d.ts +259 -0
- package/dist/core/contextManager.d.ts.map +1 -0
- package/dist/core/contextManager.js +1057 -0
- package/dist/core/contextManager.js.map +1 -0
- package/dist/core/contextWindow.d.ts +42 -0
- package/dist/core/contextWindow.d.ts.map +1 -0
- package/dist/core/contextWindow.js +123 -0
- package/dist/core/contextWindow.js.map +1 -0
- package/dist/core/customCommands.d.ts +18 -0
- package/dist/core/customCommands.d.ts.map +1 -0
- package/dist/core/customCommands.js +81 -0
- package/dist/core/customCommands.js.map +1 -0
- package/dist/core/errors/apiKeyErrors.d.ts +11 -0
- package/dist/core/errors/apiKeyErrors.d.ts.map +1 -0
- package/dist/core/errors/apiKeyErrors.js +159 -0
- package/dist/core/errors/apiKeyErrors.js.map +1 -0
- package/dist/core/errors/errorTypes.d.ts +111 -0
- package/dist/core/errors/errorTypes.d.ts.map +1 -0
- package/dist/core/errors/errorTypes.js +348 -0
- package/dist/core/errors/errorTypes.js.map +1 -0
- package/dist/core/errors/errorUtils.d.ts +87 -0
- package/dist/core/errors/errorUtils.d.ts.map +1 -0
- package/dist/core/errors/errorUtils.js +158 -0
- package/dist/core/errors/errorUtils.js.map +1 -0
- package/dist/core/errors/safetyValidator.d.ts +71 -0
- package/dist/core/errors/safetyValidator.d.ts.map +1 -0
- package/dist/core/errors/safetyValidator.js +302 -0
- package/dist/core/errors/safetyValidator.js.map +1 -0
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +33 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/isolatedVerifier.d.ts +40 -0
- package/dist/core/isolatedVerifier.d.ts.map +1 -0
- package/dist/core/isolatedVerifier.js +129 -0
- package/dist/core/isolatedVerifier.js.map +1 -0
- package/dist/core/modelDiscovery.d.ts +101 -0
- package/dist/core/modelDiscovery.d.ts.map +1 -0
- package/dist/core/modelDiscovery.js +780 -0
- package/dist/core/modelDiscovery.js.map +1 -0
- package/dist/core/multilinePasteHandler.d.ts +35 -0
- package/dist/core/multilinePasteHandler.d.ts.map +1 -0
- package/dist/core/multilinePasteHandler.js +80 -0
- package/dist/core/multilinePasteHandler.js.map +1 -0
- package/dist/core/performanceMonitor.d.ts +124 -0
- package/dist/core/performanceMonitor.d.ts.map +1 -0
- package/dist/core/performanceMonitor.js +195 -0
- package/dist/core/performanceMonitor.js.map +1 -0
- package/dist/core/preferences.d.ts +31 -0
- package/dist/core/preferences.d.ts.map +1 -0
- package/dist/core/preferences.js +232 -0
- package/dist/core/preferences.js.map +1 -0
- package/dist/core/responseVerifier.d.ts +98 -0
- package/dist/core/responseVerifier.d.ts.map +1 -0
- package/dist/core/responseVerifier.js +509 -0
- package/dist/core/responseVerifier.js.map +1 -0
- package/dist/core/resultVerification.d.ts +141 -0
- package/dist/core/resultVerification.d.ts.map +1 -0
- package/dist/core/resultVerification.js +482 -0
- package/dist/core/resultVerification.js.map +1 -0
- package/dist/core/schemaValidator.d.ts +44 -0
- package/dist/core/schemaValidator.d.ts.map +1 -0
- package/dist/core/schemaValidator.js +155 -0
- package/dist/core/schemaValidator.js.map +1 -0
- package/dist/core/secretStore.d.ts +47 -0
- package/dist/core/secretStore.d.ts.map +1 -0
- package/dist/core/secretStore.js +364 -0
- package/dist/core/secretStore.js.map +1 -0
- package/dist/core/sessionStore.d.ts +33 -0
- package/dist/core/sessionStore.d.ts.map +1 -0
- package/dist/core/sessionStore.js +188 -0
- package/dist/core/sessionStore.js.map +1 -0
- package/dist/core/testUtils.d.ts +121 -0
- package/dist/core/testUtils.d.ts.map +1 -0
- package/dist/core/testUtils.js +235 -0
- package/dist/core/testUtils.js.map +1 -0
- package/dist/core/toolPreconditions.d.ts +41 -0
- package/dist/core/toolPreconditions.d.ts.map +1 -0
- package/dist/core/toolPreconditions.js +319 -0
- package/dist/core/toolPreconditions.js.map +1 -0
- package/dist/core/toolRuntime.d.ts +137 -0
- package/dist/core/toolRuntime.d.ts.map +1 -0
- package/dist/core/toolRuntime.js +375 -0
- package/dist/core/toolRuntime.js.map +1 -0
- package/dist/core/toolValidation.d.ts +117 -0
- package/dist/core/toolValidation.d.ts.map +1 -0
- package/dist/core/toolValidation.js +282 -0
- package/dist/core/toolValidation.js.map +1 -0
- package/dist/core/types/utilityTypes.d.ts +192 -0
- package/dist/core/types/utilityTypes.d.ts.map +1 -0
- package/dist/core/types/utilityTypes.js +272 -0
- package/dist/core/types/utilityTypes.js.map +1 -0
- package/dist/core/types.d.ts +306 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +76 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/unified/errors.d.ts +189 -0
- package/dist/core/unified/errors.d.ts.map +1 -0
- package/dist/core/unified/errors.js +497 -0
- package/dist/core/unified/errors.js.map +1 -0
- package/dist/core/unified/index.d.ts +19 -0
- package/dist/core/unified/index.d.ts.map +1 -0
- package/dist/core/unified/index.js +68 -0
- package/dist/core/unified/index.js.map +1 -0
- package/dist/core/unified/schema.d.ts +101 -0
- package/dist/core/unified/schema.d.ts.map +1 -0
- package/dist/core/unified/schema.js +350 -0
- package/dist/core/unified/schema.js.map +1 -0
- package/dist/core/unified/toolRuntime.d.ts +179 -0
- package/dist/core/unified/toolRuntime.d.ts.map +1 -0
- package/dist/core/unified/toolRuntime.js +517 -0
- package/dist/core/unified/toolRuntime.js.map +1 -0
- package/dist/core/unified/tools.d.ts +127 -0
- package/dist/core/unified/tools.d.ts.map +1 -0
- package/dist/core/unified/tools.js +1333 -0
- package/dist/core/unified/tools.js.map +1 -0
- package/dist/core/unified/types.d.ts +352 -0
- package/dist/core/unified/types.d.ts.map +1 -0
- package/dist/core/unified/types.js +12 -0
- package/dist/core/unified/types.js.map +1 -0
- package/dist/core/unified/version.d.ts +209 -0
- package/dist/core/unified/version.d.ts.map +1 -0
- package/dist/core/unified/version.js +454 -0
- package/dist/core/unified/version.js.map +1 -0
- package/dist/core/validationRunner.d.ts +93 -0
- package/dist/core/validationRunner.d.ts.map +1 -0
- package/dist/core/validationRunner.js +740 -0
- package/dist/core/validationRunner.js.map +1 -0
- package/dist/headless/headlessApp.d.ts +5 -0
- package/dist/headless/headlessApp.d.ts.map +1 -0
- package/dist/headless/headlessApp.js +189 -0
- package/dist/headless/headlessApp.js.map +1 -0
- package/dist/intelligence/codeIntelligence.d.ts +84 -0
- package/dist/intelligence/codeIntelligence.d.ts.map +1 -0
- package/dist/intelligence/codeIntelligence.js +493 -0
- package/dist/intelligence/codeIntelligence.js.map +1 -0
- package/dist/intelligence/docGenerator.d.ts +86 -0
- package/dist/intelligence/docGenerator.d.ts.map +1 -0
- package/dist/intelligence/docGenerator.js +564 -0
- package/dist/intelligence/docGenerator.js.map +1 -0
- package/dist/intelligence/index.d.ts +51 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +253 -0
- package/dist/intelligence/index.js.map +1 -0
- package/dist/intelligence/refactoring.d.ts +50 -0
- package/dist/intelligence/refactoring.d.ts.map +1 -0
- package/dist/intelligence/refactoring.js +354 -0
- package/dist/intelligence/refactoring.js.map +1 -0
- package/dist/intelligence/testGenerator.d.ts +74 -0
- package/dist/intelligence/testGenerator.d.ts.map +1 -0
- package/dist/intelligence/testGenerator.js +483 -0
- package/dist/intelligence/testGenerator.js.map +1 -0
- package/dist/mcp/config.d.ts +8 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +252 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/sseClient.d.ts +34 -0
- package/dist/mcp/sseClient.d.ts.map +1 -0
- package/dist/mcp/sseClient.js +299 -0
- package/dist/mcp/sseClient.js.map +1 -0
- package/dist/mcp/stdioClient.d.ts +24 -0
- package/dist/mcp/stdioClient.d.ts.map +1 -0
- package/dist/mcp/stdioClient.js +179 -0
- package/dist/mcp/stdioClient.js.map +1 -0
- package/dist/mcp/toolBridge.d.ts +12 -0
- package/dist/mcp/toolBridge.d.ts.map +1 -0
- package/dist/mcp/toolBridge.js +117 -0
- package/dist/mcp/toolBridge.js.map +1 -0
- package/dist/mcp/types.d.ts +60 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/plugins/index.d.ts +49 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +114 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/providers/anthropic/index.d.ts +11 -0
- package/dist/plugins/providers/anthropic/index.d.ts.map +1 -0
- package/dist/plugins/providers/anthropic/index.js +38 -0
- package/dist/plugins/providers/anthropic/index.js.map +1 -0
- package/dist/plugins/providers/deepseek/index.d.ts +11 -0
- package/dist/plugins/providers/deepseek/index.d.ts.map +1 -0
- package/dist/plugins/providers/deepseek/index.js +52 -0
- package/dist/plugins/providers/deepseek/index.js.map +1 -0
- package/dist/plugins/providers/google/index.d.ts +11 -0
- package/dist/plugins/providers/google/index.d.ts.map +1 -0
- package/dist/plugins/providers/google/index.js +40 -0
- package/dist/plugins/providers/google/index.js.map +1 -0
- package/dist/plugins/providers/index.d.ts +2 -0
- package/dist/plugins/providers/index.d.ts.map +1 -0
- package/dist/plugins/providers/index.js +20 -0
- package/dist/plugins/providers/index.js.map +1 -0
- package/dist/plugins/providers/ollama/index.d.ts +21 -0
- package/dist/plugins/providers/ollama/index.d.ts.map +1 -0
- package/dist/plugins/providers/ollama/index.js +69 -0
- package/dist/plugins/providers/ollama/index.js.map +1 -0
- package/dist/plugins/providers/openai/index.d.ts +12 -0
- package/dist/plugins/providers/openai/index.d.ts.map +1 -0
- package/dist/plugins/providers/openai/index.js +39 -0
- package/dist/plugins/providers/openai/index.js.map +1 -0
- package/dist/plugins/providers/xai/index.d.ts +11 -0
- package/dist/plugins/providers/xai/index.d.ts.map +1 -0
- package/dist/plugins/providers/xai/index.js +39 -0
- package/dist/plugins/providers/xai/index.js.map +1 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +3 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +9 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +1 -0
- package/dist/plugins/tools/bash/localBashPlugin.d.ts +3 -0
- package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/bash/localBashPlugin.js +14 -0
- package/dist/plugins/tools/bash/localBashPlugin.js.map +1 -0
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts +14 -0
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/browser/browserAutomationPlugin.js +26 -0
- package/dist/plugins/tools/browser/browserAutomationPlugin.js.map +1 -0
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts +3 -0
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js +14 -0
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js.map +1 -0
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts +3 -0
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/cloud/cloudPlugin.js +14 -0
- package/dist/plugins/tools/cloud/cloudPlugin.js.map +1 -0
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts +3 -0
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +14 -0
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js.map +1 -0
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts +3 -0
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js +14 -0
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js.map +1 -0
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts +3 -0
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/dependency/dependencyPlugin.js +12 -0
- package/dist/plugins/tools/dependency/dependencyPlugin.js.map +1 -0
- package/dist/plugins/tools/development/devPlugin.d.ts +3 -0
- package/dist/plugins/tools/development/devPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/development/devPlugin.js +14 -0
- package/dist/plugins/tools/development/devPlugin.js.map +1 -0
- package/dist/plugins/tools/edit/editPlugin.d.ts +9 -0
- package/dist/plugins/tools/edit/editPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/edit/editPlugin.js +15 -0
- package/dist/plugins/tools/edit/editPlugin.js.map +1 -0
- package/dist/plugins/tools/email/emailPlugin.d.ts +3 -0
- package/dist/plugins/tools/email/emailPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/email/emailPlugin.js +12 -0
- package/dist/plugins/tools/email/emailPlugin.js.map +1 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +3 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +9 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +1 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +3 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +14 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +1 -0
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts +3 -0
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js +14 -0
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js.map +1 -0
- package/dist/plugins/tools/glob/globPlugin.d.ts +9 -0
- package/dist/plugins/tools/glob/globPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/glob/globPlugin.js +15 -0
- package/dist/plugins/tools/glob/globPlugin.js.map +1 -0
- package/dist/plugins/tools/index.d.ts +3 -0
- package/dist/plugins/tools/index.d.ts.map +1 -0
- package/dist/plugins/tools/index.js +3 -0
- package/dist/plugins/tools/index.js.map +1 -0
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts +3 -0
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/interaction/interactionPlugin.js +12 -0
- package/dist/plugins/tools/interaction/interactionPlugin.js.map +1 -0
- package/dist/plugins/tools/learn/learnPlugin.d.ts +3 -0
- package/dist/plugins/tools/learn/learnPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/learn/learnPlugin.js +14 -0
- package/dist/plugins/tools/learn/learnPlugin.js.map +1 -0
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts +3 -0
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/mcp/mcpPlugin.js +9 -0
- package/dist/plugins/tools/mcp/mcpPlugin.js.map +1 -0
- package/dist/plugins/tools/nodeDefaults.d.ts +2 -0
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -0
- package/dist/plugins/tools/nodeDefaults.js +63 -0
- package/dist/plugins/tools/nodeDefaults.js.map +1 -0
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts +9 -0
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/notebook/notebookPlugin.js +15 -0
- package/dist/plugins/tools/notebook/notebookPlugin.js.map +1 -0
- package/dist/plugins/tools/planning/planningPlugin.d.ts +9 -0
- package/dist/plugins/tools/planning/planningPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/planning/planningPlugin.js +15 -0
- package/dist/plugins/tools/planning/planningPlugin.js.map +1 -0
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts +3 -0
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/refactoring/refactoringPlugin.js +12 -0
- package/dist/plugins/tools/refactoring/refactoringPlugin.js.map +1 -0
- package/dist/plugins/tools/registry.d.ts +22 -0
- package/dist/plugins/tools/registry.d.ts.map +1 -0
- package/dist/plugins/tools/registry.js +58 -0
- package/dist/plugins/tools/registry.js.map +1 -0
- package/dist/plugins/tools/search/localSearchPlugin.d.ts +3 -0
- package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/search/localSearchPlugin.js +14 -0
- package/dist/plugins/tools/search/localSearchPlugin.js.map +1 -0
- package/dist/plugins/tools/skills/skillPlugin.d.ts +3 -0
- package/dist/plugins/tools/skills/skillPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/skills/skillPlugin.js +9 -0
- package/dist/plugins/tools/skills/skillPlugin.js.map +1 -0
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts +3 -0
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js +12 -0
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js.map +1 -0
- package/dist/plugins/tools/testing/testingPlugin.d.ts +3 -0
- package/dist/plugins/tools/testing/testingPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/testing/testingPlugin.js +12 -0
- package/dist/plugins/tools/testing/testingPlugin.js.map +1 -0
- package/dist/plugins/tools/validation/validationPlugin.d.ts +3 -0
- package/dist/plugins/tools/validation/validationPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/validation/validationPlugin.js +14 -0
- package/dist/plugins/tools/validation/validationPlugin.js.map +1 -0
- package/dist/plugins/tools/web/webPlugin.d.ts +3 -0
- package/dist/plugins/tools/web/webPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/web/webPlugin.js +12 -0
- package/dist/plugins/tools/web/webPlugin.js.map +1 -0
- package/dist/providers/anthropicProvider.d.ts +41 -0
- package/dist/providers/anthropicProvider.d.ts.map +1 -0
- package/dist/providers/anthropicProvider.js +446 -0
- package/dist/providers/anthropicProvider.js.map +1 -0
- package/dist/providers/googleProvider.d.ts +36 -0
- package/dist/providers/googleProvider.d.ts.map +1 -0
- package/dist/providers/googleProvider.js +312 -0
- package/dist/providers/googleProvider.js.map +1 -0
- package/dist/providers/openaiChatCompletionsProvider.d.ts +43 -0
- package/dist/providers/openaiChatCompletionsProvider.d.ts.map +1 -0
- package/dist/providers/openaiChatCompletionsProvider.js +468 -0
- package/dist/providers/openaiChatCompletionsProvider.js.map +1 -0
- package/dist/providers/openaiResponsesProvider.d.ts +38 -0
- package/dist/providers/openaiResponsesProvider.d.ts.map +1 -0
- package/dist/providers/openaiResponsesProvider.js +364 -0
- package/dist/providers/openaiResponsesProvider.js.map +1 -0
- package/dist/providers/providerFactory.d.ts +18 -0
- package/dist/providers/providerFactory.d.ts.map +1 -0
- package/dist/providers/providerFactory.js +25 -0
- package/dist/providers/providerFactory.js.map +1 -0
- package/dist/providers/resilientProvider.d.ts +94 -0
- package/dist/providers/resilientProvider.d.ts.map +1 -0
- package/dist/providers/resilientProvider.js +370 -0
- package/dist/providers/resilientProvider.js.map +1 -0
- package/dist/runtime/agentController.d.ts +65 -0
- package/dist/runtime/agentController.d.ts.map +1 -0
- package/dist/runtime/agentController.js +353 -0
- package/dist/runtime/agentController.js.map +1 -0
- package/dist/runtime/agentHost.d.ts +61 -0
- package/dist/runtime/agentHost.d.ts.map +1 -0
- package/dist/runtime/agentHost.js +156 -0
- package/dist/runtime/agentHost.js.map +1 -0
- package/dist/runtime/agentSession.d.ts +40 -0
- package/dist/runtime/agentSession.d.ts.map +1 -0
- package/dist/runtime/agentSession.js +206 -0
- package/dist/runtime/agentSession.js.map +1 -0
- package/dist/runtime/browser.d.ts +7 -0
- package/dist/runtime/browser.d.ts.map +1 -0
- package/dist/runtime/browser.js +10 -0
- package/dist/runtime/browser.js.map +1 -0
- package/dist/runtime/cloud.d.ts +7 -0
- package/dist/runtime/cloud.d.ts.map +1 -0
- package/dist/runtime/cloud.js +10 -0
- package/dist/runtime/cloud.js.map +1 -0
- package/dist/runtime/node.d.ts +8 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +11 -0
- package/dist/runtime/node.js.map +1 -0
- package/dist/runtime/universal.d.ts +21 -0
- package/dist/runtime/universal.d.ts.map +1 -0
- package/dist/runtime/universal.js +29 -0
- package/dist/runtime/universal.js.map +1 -0
- package/dist/security/active-stack-security.d.ts +112 -0
- package/dist/security/active-stack-security.d.ts.map +1 -0
- package/dist/security/active-stack-security.js +296 -0
- package/dist/security/active-stack-security.js.map +1 -0
- package/dist/security/advanced-persistence-research.d.ts +92 -0
- package/dist/security/advanced-persistence-research.d.ts.map +1 -0
- package/dist/security/advanced-persistence-research.js +195 -0
- package/dist/security/advanced-persistence-research.js.map +1 -0
- package/dist/security/advanced-targeting.d.ts +119 -0
- package/dist/security/advanced-targeting.d.ts.map +1 -0
- package/dist/security/advanced-targeting.js +233 -0
- package/dist/security/advanced-targeting.js.map +1 -0
- package/dist/security/assessment/vulnerabilityAssessment.d.ts +104 -0
- package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +1 -0
- package/dist/security/assessment/vulnerabilityAssessment.js +315 -0
- package/dist/security/assessment/vulnerabilityAssessment.js.map +1 -0
- package/dist/security/authorization/securityAuthorization.d.ts +88 -0
- package/dist/security/authorization/securityAuthorization.d.ts.map +1 -0
- package/dist/security/authorization/securityAuthorization.js +172 -0
- package/dist/security/authorization/securityAuthorization.js.map +1 -0
- package/dist/security/comprehensive-targeting.d.ts +85 -0
- package/dist/security/comprehensive-targeting.d.ts.map +1 -0
- package/dist/security/comprehensive-targeting.js +438 -0
- package/dist/security/comprehensive-targeting.js.map +1 -0
- package/dist/security/global-security-integration.d.ts +91 -0
- package/dist/security/global-security-integration.d.ts.map +1 -0
- package/dist/security/global-security-integration.js +218 -0
- package/dist/security/global-security-integration.js.map +1 -0
- package/dist/security/index.d.ts +38 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +47 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/persistence-analyzer.d.ts +56 -0
- package/dist/security/persistence-analyzer.d.ts.map +1 -0
- package/dist/security/persistence-analyzer.js +187 -0
- package/dist/security/persistence-analyzer.js.map +1 -0
- package/dist/security/persistence-cli.d.ts +36 -0
- package/dist/security/persistence-cli.d.ts.map +1 -0
- package/dist/security/persistence-cli.js +160 -0
- package/dist/security/persistence-cli.js.map +1 -0
- package/dist/security/persistence-research.d.ts +92 -0
- package/dist/security/persistence-research.d.ts.map +1 -0
- package/dist/security/persistence-research.js +364 -0
- package/dist/security/persistence-research.js.map +1 -0
- package/dist/security/research/persistenceResearch.d.ts +97 -0
- package/dist/security/research/persistenceResearch.d.ts.map +1 -0
- package/dist/security/research/persistenceResearch.js +282 -0
- package/dist/security/research/persistenceResearch.js.map +1 -0
- package/dist/security/security-integration.d.ts +74 -0
- package/dist/security/security-integration.d.ts.map +1 -0
- package/dist/security/security-integration.js +137 -0
- package/dist/security/security-integration.js.map +1 -0
- package/dist/security/security-testing-framework.d.ts +112 -0
- package/dist/security/security-testing-framework.d.ts.map +1 -0
- package/dist/security/security-testing-framework.js +364 -0
- package/dist/security/security-testing-framework.js.map +1 -0
- package/dist/security/simulation/attackSimulation.d.ts +93 -0
- package/dist/security/simulation/attackSimulation.d.ts.map +1 -0
- package/dist/security/simulation/attackSimulation.js +341 -0
- package/dist/security/simulation/attackSimulation.js.map +1 -0
- package/dist/security/strategic-operations.d.ts +100 -0
- package/dist/security/strategic-operations.d.ts.map +1 -0
- package/dist/security/strategic-operations.js +276 -0
- package/dist/security/strategic-operations.js.map +1 -0
- package/dist/security/tool-security-wrapper.d.ts +58 -0
- package/dist/security/tool-security-wrapper.d.ts.map +1 -0
- package/dist/security/tool-security-wrapper.js +156 -0
- package/dist/security/tool-security-wrapper.js.map +1 -0
- package/dist/shell/autoExecutor.d.ts +70 -0
- package/dist/shell/autoExecutor.d.ts.map +1 -0
- package/dist/shell/autoExecutor.js +288 -0
- package/dist/shell/autoExecutor.js.map +1 -0
- package/dist/shell/claudeCodeStreamHandler.d.ts +145 -0
- package/dist/shell/claudeCodeStreamHandler.d.ts.map +1 -0
- package/dist/shell/claudeCodeStreamHandler.js +312 -0
- package/dist/shell/claudeCodeStreamHandler.js.map +1 -0
- package/dist/shell/composableMessage.d.ts +183 -0
- package/dist/shell/composableMessage.d.ts.map +1 -0
- package/dist/shell/composableMessage.js +420 -0
- package/dist/shell/composableMessage.js.map +1 -0
- package/dist/shell/fileChangeTracker.d.ts +39 -0
- package/dist/shell/fileChangeTracker.d.ts.map +1 -0
- package/dist/shell/fileChangeTracker.js +64 -0
- package/dist/shell/fileChangeTracker.js.map +1 -0
- package/dist/shell/inputQueueManager.d.ts +144 -0
- package/dist/shell/inputQueueManager.d.ts.map +1 -0
- package/dist/shell/inputQueueManager.js +290 -0
- package/dist/shell/inputQueueManager.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +321 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -0
- package/dist/shell/interactiveShell.js +3339 -0
- package/dist/shell/interactiveShell.js.map +1 -0
- package/dist/shell/liveStatus.d.ts +29 -0
- package/dist/shell/liveStatus.d.ts.map +1 -0
- package/dist/shell/liveStatus.js +77 -0
- package/dist/shell/liveStatus.js.map +1 -0
- package/dist/shell/shellApp.d.ts +19 -0
- package/dist/shell/shellApp.d.ts.map +1 -0
- package/dist/shell/shellApp.js +364 -0
- package/dist/shell/shellApp.js.map +1 -0
- package/dist/shell/streamingOutputManager.d.ts +114 -0
- package/dist/shell/streamingOutputManager.d.ts.map +1 -0
- package/dist/shell/streamingOutputManager.js +213 -0
- package/dist/shell/streamingOutputManager.js.map +1 -0
- package/dist/shell/systemPrompt.d.ts +3 -0
- package/dist/shell/systemPrompt.d.ts.map +1 -0
- package/dist/shell/systemPrompt.js +78 -0
- package/dist/shell/systemPrompt.js.map +1 -0
- package/dist/shell/taskCompletionDetector.d.ts +106 -0
- package/dist/shell/taskCompletionDetector.d.ts.map +1 -0
- package/dist/shell/taskCompletionDetector.js +402 -0
- package/dist/shell/taskCompletionDetector.js.map +1 -0
- package/dist/shell/terminalInput.d.ts +222 -0
- package/dist/shell/terminalInput.d.ts.map +1 -0
- package/dist/shell/terminalInput.js +1089 -0
- package/dist/shell/terminalInput.js.map +1 -0
- package/dist/shell/terminalInputAdapter.d.ts +121 -0
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -0
- package/dist/shell/terminalInputAdapter.js +223 -0
- package/dist/shell/terminalInputAdapter.js.map +1 -0
- package/dist/shell/updateManager.d.ts +2 -0
- package/dist/shell/updateManager.d.ts.map +1 -0
- package/dist/shell/updateManager.js +111 -0
- package/dist/shell/updateManager.js.map +1 -0
- package/dist/skills/skillRepository.d.ts +103 -0
- package/dist/skills/skillRepository.d.ts.map +1 -0
- package/dist/skills/skillRepository.js +237 -0
- package/dist/skills/skillRepository.js.map +1 -0
- package/dist/skills/types.d.ts +37 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/subagents/taskRunner.d.ts +23 -0
- package/dist/subagents/taskRunner.d.ts.map +1 -0
- package/dist/subagents/taskRunner.js +271 -0
- package/dist/subagents/taskRunner.js.map +1 -0
- package/dist/tools/advancedTestGenerationTools.d.ts +21 -0
- package/dist/tools/advancedTestGenerationTools.d.ts.map +1 -0
- package/dist/tools/advancedTestGenerationTools.js +301 -0
- package/dist/tools/advancedTestGenerationTools.js.map +1 -0
- package/dist/tools/backgroundBashTools.d.ts +21 -0
- package/dist/tools/backgroundBashTools.d.ts.map +1 -0
- package/dist/tools/backgroundBashTools.js +215 -0
- package/dist/tools/backgroundBashTools.js.map +1 -0
- package/dist/tools/bashTools.d.ts +8 -0
- package/dist/tools/bashTools.d.ts.map +1 -0
- package/dist/tools/bashTools.js +227 -0
- package/dist/tools/bashTools.js.map +1 -0
- package/dist/tools/browserAutomationTools.d.ts +23 -0
- package/dist/tools/browserAutomationTools.d.ts.map +1 -0
- package/dist/tools/browserAutomationTools.js +916 -0
- package/dist/tools/browserAutomationTools.js.map +1 -0
- package/dist/tools/cloudTools.d.ts +49 -0
- package/dist/tools/cloudTools.d.ts.map +1 -0
- package/dist/tools/cloudTools.js +1258 -0
- package/dist/tools/cloudTools.js.map +1 -0
- package/dist/tools/code-quality-dashboard.d.ts +57 -0
- package/dist/tools/code-quality-dashboard.d.ts.map +1 -0
- package/dist/tools/code-quality-dashboard.js +218 -0
- package/dist/tools/code-quality-dashboard.js.map +1 -0
- package/dist/tools/codeAnalysisTools.d.ts +74 -0
- package/dist/tools/codeAnalysisTools.d.ts.map +1 -0
- package/dist/tools/codeAnalysisTools.js +664 -0
- package/dist/tools/codeAnalysisTools.js.map +1 -0
- package/dist/tools/codeGenerationTools.d.ts +3 -0
- package/dist/tools/codeGenerationTools.d.ts.map +1 -0
- package/dist/tools/codeGenerationTools.js +439 -0
- package/dist/tools/codeGenerationTools.js.map +1 -0
- package/dist/tools/codeQualityTools.d.ts +3 -0
- package/dist/tools/codeQualityTools.d.ts.map +1 -0
- package/dist/tools/codeQualityTools.js +296 -0
- package/dist/tools/codeQualityTools.js.map +1 -0
- package/dist/tools/dependencyTools.d.ts +3 -0
- package/dist/tools/dependencyTools.d.ts.map +1 -0
- package/dist/tools/dependencyTools.js +283 -0
- package/dist/tools/dependencyTools.js.map +1 -0
- package/dist/tools/devTools.d.ts +10 -0
- package/dist/tools/devTools.d.ts.map +1 -0
- package/dist/tools/devTools.js +2305 -0
- package/dist/tools/devTools.js.map +1 -0
- package/dist/tools/diffUtils.d.ts +36 -0
- package/dist/tools/diffUtils.d.ts.map +1 -0
- package/dist/tools/diffUtils.js +528 -0
- package/dist/tools/diffUtils.js.map +1 -0
- package/dist/tools/editTools.d.ts +29 -0
- package/dist/tools/editTools.d.ts.map +1 -0
- package/dist/tools/editTools.js +419 -0
- package/dist/tools/editTools.js.map +1 -0
- package/dist/tools/emailTools.d.ts +21 -0
- package/dist/tools/emailTools.d.ts.map +1 -0
- package/dist/tools/emailTools.js +449 -0
- package/dist/tools/emailTools.js.map +1 -0
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts +27 -0
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts.map +1 -0
- package/dist/tools/enhancedCodeIntelligenceTools.js +418 -0
- package/dist/tools/enhancedCodeIntelligenceTools.js.map +1 -0
- package/dist/tools/enhancedDevWorkflowTools.d.ts +15 -0
- package/dist/tools/enhancedDevWorkflowTools.d.ts.map +1 -0
- package/dist/tools/enhancedDevWorkflowTools.js +303 -0
- package/dist/tools/enhancedDevWorkflowTools.js.map +1 -0
- package/dist/tools/fileTools.d.ts +3 -0
- package/dist/tools/fileTools.d.ts.map +1 -0
- package/dist/tools/fileTools.js +252 -0
- package/dist/tools/fileTools.js.map +1 -0
- package/dist/tools/frontendTestingTools.d.ts +35 -0
- package/dist/tools/frontendTestingTools.d.ts.map +1 -0
- package/dist/tools/frontendTestingTools.js +1254 -0
- package/dist/tools/frontendTestingTools.js.map +1 -0
- package/dist/tools/globTools.d.ts +15 -0
- package/dist/tools/globTools.d.ts.map +1 -0
- package/dist/tools/globTools.js +174 -0
- package/dist/tools/globTools.js.map +1 -0
- package/dist/tools/grepTools.d.ts +19 -0
- package/dist/tools/grepTools.d.ts.map +1 -0
- package/dist/tools/grepTools.js +339 -0
- package/dist/tools/grepTools.js.map +1 -0
- package/dist/tools/interactionTools.d.ts +13 -0
- package/dist/tools/interactionTools.d.ts.map +1 -0
- package/dist/tools/interactionTools.js +171 -0
- package/dist/tools/interactionTools.js.map +1 -0
- package/dist/tools/learnTools.d.ts +152 -0
- package/dist/tools/learnTools.d.ts.map +1 -0
- package/dist/tools/learnTools.js +1819 -0
- package/dist/tools/learnTools.js.map +1 -0
- package/dist/tools/notebookEditTools.d.ts +15 -0
- package/dist/tools/notebookEditTools.d.ts.map +1 -0
- package/dist/tools/notebookEditTools.js +197 -0
- package/dist/tools/notebookEditTools.js.map +1 -0
- package/dist/tools/planningTools.d.ts +12 -0
- package/dist/tools/planningTools.d.ts.map +1 -0
- package/dist/tools/planningTools.js +95 -0
- package/dist/tools/planningTools.js.map +1 -0
- package/dist/tools/refactoringTools.d.ts +3 -0
- package/dist/tools/refactoringTools.d.ts.map +1 -0
- package/dist/tools/refactoringTools.js +294 -0
- package/dist/tools/refactoringTools.js.map +1 -0
- package/dist/tools/repoChecksTools.d.ts +3 -0
- package/dist/tools/repoChecksTools.d.ts.map +1 -0
- package/dist/tools/repoChecksTools.js +161 -0
- package/dist/tools/repoChecksTools.js.map +1 -0
- package/dist/tools/searchTools.d.ts +3 -0
- package/dist/tools/searchTools.d.ts.map +1 -0
- package/dist/tools/searchTools.js +207 -0
- package/dist/tools/searchTools.js.map +1 -0
- package/dist/tools/skillTools.d.ts +8 -0
- package/dist/tools/skillTools.d.ts.map +1 -0
- package/dist/tools/skillTools.js +178 -0
- package/dist/tools/skillTools.js.map +1 -0
- package/dist/tools/softwareEngineeringTools.d.ts +7 -0
- package/dist/tools/softwareEngineeringTools.d.ts.map +1 -0
- package/dist/tools/softwareEngineeringTools.js +338 -0
- package/dist/tools/softwareEngineeringTools.js.map +1 -0
- package/dist/tools/taskManagementTools.d.ts +10 -0
- package/dist/tools/taskManagementTools.d.ts.map +1 -0
- package/dist/tools/taskManagementTools.js +157 -0
- package/dist/tools/taskManagementTools.js.map +1 -0
- package/dist/tools/testingTools.d.ts +3 -0
- package/dist/tools/testingTools.d.ts.map +1 -0
- package/dist/tools/testingTools.js +233 -0
- package/dist/tools/testingTools.js.map +1 -0
- package/dist/tools/validationTools.d.ts +7 -0
- package/dist/tools/validationTools.d.ts.map +1 -0
- package/dist/tools/validationTools.js +278 -0
- package/dist/tools/validationTools.js.map +1 -0
- package/dist/tools/webTools.d.ts +3 -0
- package/dist/tools/webTools.d.ts.map +1 -0
- package/dist/tools/webTools.js +495 -0
- package/dist/tools/webTools.js.map +1 -0
- package/dist/ui/FixedInputArea.d.ts +108 -0
- package/dist/ui/FixedInputArea.d.ts.map +1 -0
- package/dist/ui/FixedInputArea.js +312 -0
- package/dist/ui/FixedInputArea.js.map +1 -0
- package/dist/ui/ShellUIAdapter.d.ts +141 -0
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -0
- package/dist/ui/ShellUIAdapter.js +680 -0
- package/dist/ui/ShellUIAdapter.js.map +1 -0
- package/dist/ui/UnifiedUIController.d.ts +70 -0
- package/dist/ui/UnifiedUIController.d.ts.map +1 -0
- package/dist/ui/UnifiedUIController.js +190 -0
- package/dist/ui/UnifiedUIController.js.map +1 -0
- package/dist/ui/advancedTheme.d.ts +246 -0
- package/dist/ui/advancedTheme.d.ts.map +1 -0
- package/dist/ui/advancedTheme.js +478 -0
- package/dist/ui/advancedTheme.js.map +1 -0
- package/dist/ui/animation/AnimationScheduler.d.ts +192 -0
- package/dist/ui/animation/AnimationScheduler.d.ts.map +1 -0
- package/dist/ui/animation/AnimationScheduler.js +432 -0
- package/dist/ui/animation/AnimationScheduler.js.map +1 -0
- package/dist/ui/codeHighlighter.d.ts +6 -0
- package/dist/ui/codeHighlighter.d.ts.map +1 -0
- package/dist/ui/codeHighlighter.js +855 -0
- package/dist/ui/codeHighlighter.js.map +1 -0
- package/dist/ui/collapsibleContent.d.ts +57 -0
- package/dist/ui/collapsibleContent.d.ts.map +1 -0
- package/dist/ui/collapsibleContent.js +106 -0
- package/dist/ui/collapsibleContent.js.map +1 -0
- package/dist/ui/designSystem.d.ts +26 -0
- package/dist/ui/designSystem.d.ts.map +1 -0
- package/dist/ui/designSystem.js +122 -0
- package/dist/ui/designSystem.js.map +1 -0
- package/dist/ui/diffViewer.d.ts +42 -0
- package/dist/ui/diffViewer.d.ts.map +1 -0
- package/dist/ui/diffViewer.js +343 -0
- package/dist/ui/diffViewer.js.map +1 -0
- package/dist/ui/display.d.ts +251 -0
- package/dist/ui/display.d.ts.map +1 -0
- package/dist/ui/display.js +1170 -0
- package/dist/ui/display.js.map +1 -0
- package/dist/ui/errorFormatter.d.ts +54 -0
- package/dist/ui/errorFormatter.d.ts.map +1 -0
- package/dist/ui/errorFormatter.js +251 -0
- package/dist/ui/errorFormatter.js.map +1 -0
- package/dist/ui/gitDisplay.d.ts +45 -0
- package/dist/ui/gitDisplay.d.ts.map +1 -0
- package/dist/ui/gitDisplay.js +215 -0
- package/dist/ui/gitDisplay.js.map +1 -0
- package/dist/ui/gitFormatter.d.ts +29 -0
- package/dist/ui/gitFormatter.d.ts.map +1 -0
- package/dist/ui/gitFormatter.js +203 -0
- package/dist/ui/gitFormatter.js.map +1 -0
- package/dist/ui/interrupts/InterruptManager.d.ts +142 -0
- package/dist/ui/interrupts/InterruptManager.d.ts.map +1 -0
- package/dist/ui/interrupts/InterruptManager.js +439 -0
- package/dist/ui/interrupts/InterruptManager.js.map +1 -0
- package/dist/ui/keyboardShortcuts.d.ts +49 -0
- package/dist/ui/keyboardShortcuts.d.ts.map +1 -0
- package/dist/ui/keyboardShortcuts.js +128 -0
- package/dist/ui/keyboardShortcuts.js.map +1 -0
- package/dist/ui/layout.d.ts +17 -0
- package/dist/ui/layout.d.ts.map +1 -0
- package/dist/ui/layout.js +140 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/logFormatter.d.ts +70 -0
- package/dist/ui/logFormatter.d.ts.map +1 -0
- package/dist/ui/logFormatter.js +323 -0
- package/dist/ui/logFormatter.js.map +1 -0
- package/dist/ui/orchestration/StatusOrchestrator.d.ts +156 -0
- package/dist/ui/orchestration/StatusOrchestrator.d.ts.map +1 -0
- package/dist/ui/orchestration/StatusOrchestrator.js +406 -0
- package/dist/ui/orchestration/StatusOrchestrator.js.map +1 -0
- package/dist/ui/outputMode.d.ts +22 -0
- package/dist/ui/outputMode.d.ts.map +1 -0
- package/dist/ui/outputMode.js +40 -0
- package/dist/ui/outputMode.js.map +1 -0
- package/dist/ui/outputSummarizer.d.ts +52 -0
- package/dist/ui/outputSummarizer.d.ts.map +1 -0
- package/dist/ui/outputSummarizer.js +242 -0
- package/dist/ui/outputSummarizer.js.map +1 -0
- package/dist/ui/progressBar.d.ts +51 -0
- package/dist/ui/progressBar.d.ts.map +1 -0
- package/dist/ui/progressBar.js +153 -0
- package/dist/ui/progressBar.js.map +1 -0
- package/dist/ui/progressIndicator.d.ts +69 -0
- package/dist/ui/progressIndicator.d.ts.map +1 -0
- package/dist/ui/progressIndicator.js +145 -0
- package/dist/ui/progressIndicator.js.map +1 -0
- package/dist/ui/richText.d.ts +6 -0
- package/dist/ui/richText.d.ts.map +1 -0
- package/dist/ui/richText.js +391 -0
- package/dist/ui/richText.js.map +1 -0
- package/dist/ui/shortcutsHelp.d.ts +23 -0
- package/dist/ui/shortcutsHelp.d.ts.map +1 -0
- package/dist/ui/shortcutsHelp.js +89 -0
- package/dist/ui/shortcutsHelp.js.map +1 -0
- package/dist/ui/streamingIndicators.d.ts +42 -0
- package/dist/ui/streamingIndicators.d.ts.map +1 -0
- package/dist/ui/streamingIndicators.js +155 -0
- package/dist/ui/streamingIndicators.js.map +1 -0
- package/dist/ui/tableFormatter.d.ts +31 -0
- package/dist/ui/tableFormatter.d.ts.map +1 -0
- package/dist/ui/tableFormatter.js +186 -0
- package/dist/ui/tableFormatter.js.map +1 -0
- package/dist/ui/telemetry/UITelemetry.d.ts +181 -0
- package/dist/ui/telemetry/UITelemetry.d.ts.map +1 -0
- package/dist/ui/telemetry/UITelemetry.js +446 -0
- package/dist/ui/telemetry/UITelemetry.js.map +1 -0
- package/dist/ui/textHighlighter.d.ts +83 -0
- package/dist/ui/textHighlighter.d.ts.map +1 -0
- package/dist/ui/textHighlighter.js +267 -0
- package/dist/ui/textHighlighter.js.map +1 -0
- package/dist/ui/theme.d.ts +103 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +128 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/thinkingTracker.d.ts +51 -0
- package/dist/ui/thinkingTracker.d.ts.map +1 -0
- package/dist/ui/thinkingTracker.js +115 -0
- package/dist/ui/thinkingTracker.js.map +1 -0
- package/dist/ui/toolDisplay.d.ts +151 -0
- package/dist/ui/toolDisplay.d.ts.map +1 -0
- package/dist/ui/toolDisplay.js +1355 -0
- package/dist/ui/toolDisplay.js.map +1 -0
- package/dist/ui/toolDisplayAdapter.d.ts +66 -0
- package/dist/ui/toolDisplayAdapter.d.ts.map +1 -0
- package/dist/ui/toolDisplayAdapter.js +356 -0
- package/dist/ui/toolDisplayAdapter.js.map +1 -0
- package/dist/ui/treeVisualizer.d.ts +56 -0
- package/dist/ui/treeVisualizer.d.ts.map +1 -0
- package/dist/ui/treeVisualizer.js +247 -0
- package/dist/ui/treeVisualizer.js.map +1 -0
- package/dist/utils/asyncUtils.d.ts +95 -0
- package/dist/utils/asyncUtils.d.ts.map +1 -0
- package/dist/utils/asyncUtils.js +286 -0
- package/dist/utils/asyncUtils.js.map +1 -0
- package/dist/utils/errorUtils.d.ts +16 -0
- package/dist/utils/errorUtils.d.ts.map +1 -0
- package/dist/utils/errorUtils.js +66 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/planFormatter.d.ts +34 -0
- package/dist/utils/planFormatter.d.ts.map +1 -0
- package/dist/utils/planFormatter.js +140 -0
- package/dist/utils/planFormatter.js.map +1 -0
- package/dist/workspace.d.ts +8 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +107 -0
- package/dist/workspace.js.map +1 -0
- package/dist/workspace.validator.d.ts +49 -0
- package/dist/workspace.validator.d.ts.map +1 -0
- package/dist/workspace.validator.js +214 -0
- package/dist/workspace.validator.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,3339 @@
|
|
|
1
|
+
import { stdin as input, stdout as output, exit } from 'node:process';
|
|
2
|
+
import { exec } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { display } from '../ui/display.js';
|
|
5
|
+
import { formatUserPrompt, theme } from '../ui/theme.js';
|
|
6
|
+
import { getContextWindowTokens } from '../core/contextWindow.js';
|
|
7
|
+
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
8
|
+
import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, } from '../core/preferences.js';
|
|
9
|
+
import { buildEnabledToolSet, evaluateToolPermissions, getToolToggleOptions, } from '../capabilities/toolRegistry.js';
|
|
10
|
+
import { detectApiKeyError } from '../core/errors/apiKeyErrors.js';
|
|
11
|
+
import { buildWorkspaceContext } from '../workspace.js';
|
|
12
|
+
import { buildInteractiveSystemPrompt } from './systemPrompt.js';
|
|
13
|
+
import { getTaskCompletionDetector, resetTaskCompletionDetector, } from './taskCompletionDetector.js';
|
|
14
|
+
import { discoverAllModels, quickCheckProviders, getCachedDiscoveredModels, sortModelsByPriority } from '../core/modelDiscovery.js';
|
|
15
|
+
import { getModels, getSlashCommands, getProviders } from '../core/agentSchemaLoader.js';
|
|
16
|
+
import { clearAutosaveSnapshot, deleteSession, listSessions, loadAutosaveSnapshot, loadSessionById, saveAutosaveSnapshot, saveSessionSnapshot, } from '../core/sessionStore.js';
|
|
17
|
+
import { buildCustomCommandPrompt, loadCustomSlashCommands, } from '../core/customCommands.js';
|
|
18
|
+
import { SkillRepository } from '../skills/skillRepository.js';
|
|
19
|
+
import { createSkillTools } from '../tools/skillTools.js';
|
|
20
|
+
import { FileChangeTracker } from './fileChangeTracker.js';
|
|
21
|
+
import { formatShortcutsHelp } from '../ui/shortcutsHelp.js';
|
|
22
|
+
import { MetricsTracker } from '../alpha-zero/index.js';
|
|
23
|
+
import { listAvailablePlugins } from '../plugins/index.js';
|
|
24
|
+
import { TerminalInputAdapter } from './terminalInputAdapter.js';
|
|
25
|
+
const execAsync = promisify(exec);
|
|
26
|
+
const DROPDOWN_COLORS = [
|
|
27
|
+
theme.primary,
|
|
28
|
+
theme.info,
|
|
29
|
+
theme.accent,
|
|
30
|
+
theme.secondary,
|
|
31
|
+
theme.success,
|
|
32
|
+
theme.warning,
|
|
33
|
+
];
|
|
34
|
+
// Load MODEL_PRESETS from centralized schema
|
|
35
|
+
const MODEL_PRESETS = getModels().map((model) => ({
|
|
36
|
+
id: model.id,
|
|
37
|
+
label: model.label,
|
|
38
|
+
provider: model.provider,
|
|
39
|
+
description: model.description ?? '',
|
|
40
|
+
reasoningEffort: model.reasoningEffort,
|
|
41
|
+
temperature: model.temperature,
|
|
42
|
+
maxTokens: model.maxTokens,
|
|
43
|
+
}));
|
|
44
|
+
// Load BASE_SLASH_COMMANDS from centralized schema
|
|
45
|
+
const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
|
|
46
|
+
command: cmd.command,
|
|
47
|
+
description: cmd.description,
|
|
48
|
+
}));
|
|
49
|
+
// Load PROVIDER_LABELS from centralized schema
|
|
50
|
+
const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
|
|
51
|
+
// Allow enough time for paste detection to kick in before flushing buffered lines
|
|
52
|
+
const CONTEXT_USAGE_THRESHOLD = 0.9;
|
|
53
|
+
const CONTEXT_RECENT_MESSAGE_COUNT = 12;
|
|
54
|
+
const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
|
|
55
|
+
const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
|
|
56
|
+
const CONTEXT_CLEANUP_SYSTEM_PROMPT = `You condense earlier IDE collaboration logs so the agent can keep working.
|
|
57
|
+
- Merge any prior summary with the new conversation chunk.
|
|
58
|
+
- Capture key decisions, TODOs, file edits, tool observations, and open questions.
|
|
59
|
+
- Clearly distinguish resolved work from outstanding follow-ups.
|
|
60
|
+
- Keep the response under roughly 200 words, prefer short bullet lists.
|
|
61
|
+
- Never call tools or run shell commands; respond with plain Markdown text only.`;
|
|
62
|
+
export class InteractiveShell {
|
|
63
|
+
agent = null;
|
|
64
|
+
profile;
|
|
65
|
+
profileLabel;
|
|
66
|
+
workingDir;
|
|
67
|
+
runtimeSession;
|
|
68
|
+
baseSystemPrompt;
|
|
69
|
+
workspaceOptions;
|
|
70
|
+
sessionState;
|
|
71
|
+
isProcessing = false;
|
|
72
|
+
shuttingDown = false;
|
|
73
|
+
pendingInteraction = null;
|
|
74
|
+
pendingSecretRetry = null;
|
|
75
|
+
terminalInput;
|
|
76
|
+
currentInput = '';
|
|
77
|
+
pendingCleanup = null;
|
|
78
|
+
cleanupInProgress = false;
|
|
79
|
+
slashPreviewVisible = false;
|
|
80
|
+
skillRepository;
|
|
81
|
+
skillToolHandlers = new Map();
|
|
82
|
+
thinkingMode = 'balanced';
|
|
83
|
+
agentMenu;
|
|
84
|
+
slashCommands;
|
|
85
|
+
bannerSessionState = null;
|
|
86
|
+
statusTracker;
|
|
87
|
+
uiAdapter;
|
|
88
|
+
_fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
|
|
89
|
+
alphaZeroMetrics; // Alpha Zero 2 performance tracking
|
|
90
|
+
statusSubscription = null;
|
|
91
|
+
followUpQueue = [];
|
|
92
|
+
isDrainingQueue = false;
|
|
93
|
+
activeContextWindowTokens = null;
|
|
94
|
+
sessionPreferences;
|
|
95
|
+
autosaveEnabled;
|
|
96
|
+
autoContinueEnabled;
|
|
97
|
+
editGuardMode = 'display-edits';
|
|
98
|
+
pendingPermissionInput = null;
|
|
99
|
+
pendingHistoryLoad = null;
|
|
100
|
+
cachedHistory = [];
|
|
101
|
+
activeSessionId = null;
|
|
102
|
+
activeSessionTitle = null;
|
|
103
|
+
sessionResumeNotice = null;
|
|
104
|
+
customCommands;
|
|
105
|
+
customCommandMap;
|
|
106
|
+
sessionRestoreConfig;
|
|
107
|
+
_enabledPlugins;
|
|
108
|
+
// Cached provider status for unified status bar display after streaming
|
|
109
|
+
cachedProviderStatus = [];
|
|
110
|
+
// Auto-test tracking
|
|
111
|
+
autoTestInFlight = false;
|
|
112
|
+
lastAutoTestRun = null;
|
|
113
|
+
// Streaming UX tracking
|
|
114
|
+
streamingHeartbeat = null;
|
|
115
|
+
streamingHeartbeatStart = null;
|
|
116
|
+
streamingHeartbeatFrame = 0;
|
|
117
|
+
promptRefreshTimer = null;
|
|
118
|
+
constructor(config) {
|
|
119
|
+
this.profile = config.profile;
|
|
120
|
+
this.profileLabel = config.profileLabel;
|
|
121
|
+
this.workingDir = config.workingDir;
|
|
122
|
+
this.runtimeSession = config.session;
|
|
123
|
+
this.baseSystemPrompt = config.baseSystemPrompt;
|
|
124
|
+
this.workspaceOptions = { ...config.workspaceOptions };
|
|
125
|
+
this.sessionPreferences = loadSessionPreferences();
|
|
126
|
+
this.thinkingMode = this.sessionPreferences.thinkingMode;
|
|
127
|
+
this.autosaveEnabled = this.sessionPreferences.autosave;
|
|
128
|
+
this.autoContinueEnabled = this.sessionPreferences.autoContinue;
|
|
129
|
+
this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
|
|
130
|
+
this._enabledPlugins = config.enabledPlugins ?? [];
|
|
131
|
+
this.initializeSessionHistory();
|
|
132
|
+
this.sessionState = {
|
|
133
|
+
provider: config.initialModel.provider,
|
|
134
|
+
model: config.initialModel.model,
|
|
135
|
+
temperature: config.initialModel.temperature,
|
|
136
|
+
maxTokens: config.initialModel.maxTokens,
|
|
137
|
+
reasoningEffort: config.initialModel.reasoningEffort,
|
|
138
|
+
};
|
|
139
|
+
this.applyPresetReasoningDefaults();
|
|
140
|
+
// The welcome banner only includes model + provider on launch, so mark that as the initial state.
|
|
141
|
+
this.bannerSessionState = {
|
|
142
|
+
model: this.sessionState.model,
|
|
143
|
+
provider: this.sessionState.provider,
|
|
144
|
+
};
|
|
145
|
+
this.agentMenu = config.agentSelection ?? null;
|
|
146
|
+
this.slashCommands = [...BASE_SLASH_COMMANDS];
|
|
147
|
+
if (this.agentMenu) {
|
|
148
|
+
this.slashCommands.push({
|
|
149
|
+
command: '/agents',
|
|
150
|
+
description: 'Select the default agent profile (applies on next launch)',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
this.customCommands = loadCustomSlashCommands();
|
|
154
|
+
this.customCommandMap = new Map(this.customCommands.map((command) => [command.command, command]));
|
|
155
|
+
for (const custom of this.customCommands) {
|
|
156
|
+
this.slashCommands.push({
|
|
157
|
+
command: custom.command,
|
|
158
|
+
description: `${custom.description} (custom)`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// Add /plugins command
|
|
162
|
+
this.slashCommands.push({
|
|
163
|
+
command: '/plugins',
|
|
164
|
+
description: 'Show available and loaded plugins',
|
|
165
|
+
});
|
|
166
|
+
this.statusTracker = config.statusTracker;
|
|
167
|
+
this.uiAdapter = config.uiAdapter;
|
|
168
|
+
// Set up file change tracking callback
|
|
169
|
+
this.uiAdapter.setFileChangeCallback((path, type, additions, removals) => {
|
|
170
|
+
this._fileChangeTracker.recordChange(path, type, additions, removals);
|
|
171
|
+
});
|
|
172
|
+
// Set up tool status callback to update status during tool execution
|
|
173
|
+
this.uiAdapter.setToolStatusCallback((status) => {
|
|
174
|
+
this.updateStatusMessage(status ?? null);
|
|
175
|
+
});
|
|
176
|
+
this.skillRepository = new SkillRepository({
|
|
177
|
+
workingDir: this.workingDir,
|
|
178
|
+
env: process.env,
|
|
179
|
+
});
|
|
180
|
+
for (const definition of createSkillTools({ repository: this.skillRepository })) {
|
|
181
|
+
this.skillToolHandlers.set(definition.name, definition.handler);
|
|
182
|
+
}
|
|
183
|
+
// Initialize unified terminal input handler
|
|
184
|
+
this.terminalInput = new TerminalInputAdapter(input, output, {
|
|
185
|
+
onSubmit: (text) => this.processInput(text),
|
|
186
|
+
onQueue: (text) => this.handleQueuedInput(text),
|
|
187
|
+
onInterrupt: () => this.handleInterrupt(),
|
|
188
|
+
onChange: (text) => this.handleInputChange(text),
|
|
189
|
+
onEditModeChange: (mode) => this.handleEditModeChange(mode),
|
|
190
|
+
});
|
|
191
|
+
// Register output interceptor for cursor positioning during streaming
|
|
192
|
+
this.terminalInput.registerOutputInterceptor(display);
|
|
193
|
+
// Initialize Alpha Zero 2 metrics tracking
|
|
194
|
+
this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
195
|
+
this.setupStatusTracking();
|
|
196
|
+
this.refreshContextGauge();
|
|
197
|
+
this.terminalInput.start();
|
|
198
|
+
this.rebuildAgent();
|
|
199
|
+
this.setupHandlers();
|
|
200
|
+
this.refreshBannerSessionInfo();
|
|
201
|
+
}
|
|
202
|
+
initializeSessionHistory() {
|
|
203
|
+
this.cachedHistory = [];
|
|
204
|
+
this.pendingHistoryLoad = null;
|
|
205
|
+
this.activeSessionId = null;
|
|
206
|
+
this.activeSessionTitle = null;
|
|
207
|
+
this.sessionResumeNotice = null;
|
|
208
|
+
// Handle explicit session restore requests via CLI flags
|
|
209
|
+
if (this.sessionRestoreConfig.mode === 'session-id' && this.sessionRestoreConfig.sessionId) {
|
|
210
|
+
const stored = loadSessionById(this.sessionRestoreConfig.sessionId);
|
|
211
|
+
if (stored) {
|
|
212
|
+
this.cachedHistory = stored.messages;
|
|
213
|
+
this.pendingHistoryLoad = stored.messages;
|
|
214
|
+
this.activeSessionId = stored.id;
|
|
215
|
+
this.activeSessionTitle = stored.title;
|
|
216
|
+
this.sessionResumeNotice = `Resumed session "${stored.title}".`;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
display.showWarning(`Session "${this.sessionRestoreConfig.sessionId}" not found. Starting fresh session.`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (this.sessionRestoreConfig.mode === 'autosave') {
|
|
223
|
+
const autosave = loadAutosaveSnapshot(this.profile);
|
|
224
|
+
if (autosave) {
|
|
225
|
+
this.cachedHistory = autosave.messages;
|
|
226
|
+
this.pendingHistoryLoad = autosave.messages;
|
|
227
|
+
this.activeSessionId = null;
|
|
228
|
+
this.activeSessionTitle = autosave.title;
|
|
229
|
+
this.sessionResumeNotice = 'Restored last autosaved session.';
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
display.showWarning('No autosaved session found. Starting fresh session.');
|
|
233
|
+
}
|
|
234
|
+
// Default: Start fresh (mode === 'none')
|
|
235
|
+
}
|
|
236
|
+
showSessionResumeNotice() {
|
|
237
|
+
if (!this.sessionResumeNotice) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
display.showInfo(this.sessionResumeNotice);
|
|
241
|
+
this.sessionResumeNotice = null;
|
|
242
|
+
}
|
|
243
|
+
async start(initialPrompt) {
|
|
244
|
+
if (initialPrompt) {
|
|
245
|
+
display.newLine();
|
|
246
|
+
console.log(`${formatUserPrompt(this.profileLabel || this.profile)}${initialPrompt}`);
|
|
247
|
+
await this.processInputBlock(initialPrompt);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
// Ensure the terminal input is visible
|
|
251
|
+
this.terminalInput.render();
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* TerminalInputAdapter submit handler
|
|
255
|
+
*/
|
|
256
|
+
processInput(text) {
|
|
257
|
+
const approved = this.resolveEditPermission(text);
|
|
258
|
+
if (!approved) {
|
|
259
|
+
this.handleInputChange('');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
this.handleInputChange('');
|
|
263
|
+
void this.processInputBlock(approved).catch((err) => {
|
|
264
|
+
display.showError(err instanceof Error ? err.message : String(err), err);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* TerminalInputAdapter queue handler (streaming mode)
|
|
269
|
+
*/
|
|
270
|
+
handleQueuedInput(text) {
|
|
271
|
+
// Keep adapter queue trimmed so hints stay accurate
|
|
272
|
+
this.terminalInput.dequeue();
|
|
273
|
+
this.followUpQueue.push({ type: 'request', text });
|
|
274
|
+
display.showInfo(`Queued: "${text}"`);
|
|
275
|
+
this.refreshQueueIndicators();
|
|
276
|
+
this.scheduleQueueProcessing();
|
|
277
|
+
this.handleInputChange('');
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* TerminalInputAdapter change handler
|
|
281
|
+
*/
|
|
282
|
+
handleInputChange(text) {
|
|
283
|
+
this.currentInput = text;
|
|
284
|
+
this.handleSlashCommandPreviewChange();
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Edit guard mode change handler (Shift+Tab from terminal input)
|
|
288
|
+
*/
|
|
289
|
+
handleEditModeChange(mode) {
|
|
290
|
+
this.editGuardMode = mode;
|
|
291
|
+
this.pendingPermissionInput = null;
|
|
292
|
+
if (mode === 'ask-permission') {
|
|
293
|
+
display.showSystemMessage('🛡️ Ask-to-edit mode enabled. Confirm each request before sending.');
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
display.showSystemMessage('✏️ Display edits mode enabled.');
|
|
297
|
+
}
|
|
298
|
+
this.terminalInput.render();
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Gate submissions when edit permission mode is active.
|
|
302
|
+
* Returns the text to send when approved, or null when waiting for confirmation.
|
|
303
|
+
*/
|
|
304
|
+
resolveEditPermission(text) {
|
|
305
|
+
if (this.editGuardMode !== 'ask-permission') {
|
|
306
|
+
this.pendingPermissionInput = null;
|
|
307
|
+
return text;
|
|
308
|
+
}
|
|
309
|
+
const trimmed = text.trim();
|
|
310
|
+
const lower = trimmed.toLowerCase();
|
|
311
|
+
if (this.pendingPermissionInput === null) {
|
|
312
|
+
this.pendingPermissionInput = text;
|
|
313
|
+
this.showPermissionPrompt(text, false);
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
if (!trimmed || lower === 'y' || lower === 'yes') {
|
|
317
|
+
const toSend = this.pendingPermissionInput;
|
|
318
|
+
this.pendingPermissionInput = null;
|
|
319
|
+
return toSend;
|
|
320
|
+
}
|
|
321
|
+
if (['n', 'no', 'cancel', '/cancel'].includes(lower)) {
|
|
322
|
+
this.pendingPermissionInput = null;
|
|
323
|
+
display.showInfo('Request cancelled.');
|
|
324
|
+
this.terminalInput.render();
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
// Treat any other input as a replacement request that also needs confirmation
|
|
328
|
+
this.pendingPermissionInput = text;
|
|
329
|
+
this.showPermissionPrompt(text, true);
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
showPermissionPrompt(text, updated) {
|
|
333
|
+
const singleLine = text.replace(/\s+/g, ' ').trim();
|
|
334
|
+
const preview = singleLine.length > 120 ? `${singleLine.slice(0, 117)}...` : singleLine;
|
|
335
|
+
const prefix = updated ? 'Updated request captured.' : 'Edit permission required.';
|
|
336
|
+
display.showSystemMessage([
|
|
337
|
+
`${prefix} Press Enter again (or type "yes") to allow edits, or type "cancel" to abort.`,
|
|
338
|
+
preview ? `Pending: "${preview}"` : '',
|
|
339
|
+
]
|
|
340
|
+
.filter(Boolean)
|
|
341
|
+
.join('\n'));
|
|
342
|
+
this.terminalInput.render();
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* TerminalInputAdapter interrupt handler (Ctrl+C with empty buffer)
|
|
346
|
+
*/
|
|
347
|
+
handleInterrupt() {
|
|
348
|
+
if (this.isProcessing && this.agent) {
|
|
349
|
+
this.agent.requestCancellation();
|
|
350
|
+
display.showWarning('Cancelling current operation... (Ctrl+C again to force quit)');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this.shutdown();
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Gracefully tear down the shell and exit
|
|
357
|
+
*/
|
|
358
|
+
shutdown() {
|
|
359
|
+
if (this.shuttingDown) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
this.shuttingDown = true;
|
|
363
|
+
// Stop any active spinner to prevent process hang
|
|
364
|
+
display.stopThinking(false);
|
|
365
|
+
this.stopStreamingHeartbeat();
|
|
366
|
+
this.clearPromptRefreshTimer();
|
|
367
|
+
this.teardownStatusTracking();
|
|
368
|
+
// Clear any pending cleanup to prevent hanging
|
|
369
|
+
this.pendingCleanup = null;
|
|
370
|
+
// Dispose terminal input handler
|
|
371
|
+
this.terminalInput.dispose();
|
|
372
|
+
// Dispose unified UI adapter
|
|
373
|
+
this.uiAdapter.dispose();
|
|
374
|
+
display.newLine();
|
|
375
|
+
const highlightedEmail = theme.info('support@ero.solar');
|
|
376
|
+
const infoMessage = [
|
|
377
|
+
'Thank you to Anthropic for allowing me to use Claude Code to build erosolar-cli.',
|
|
378
|
+
'https://www.anthropic.com/news/disrupting-AI-espionage',
|
|
379
|
+
'',
|
|
380
|
+
`Email ${highlightedEmail} with any bugs or feedback`,
|
|
381
|
+
'GitHub: https://github.com/ErosolarAI/erosolar-by-bo',
|
|
382
|
+
'npm: https://www.npmjs.com/package/erosolar-cli',
|
|
383
|
+
].join('\n');
|
|
384
|
+
display.showInfo(infoMessage);
|
|
385
|
+
exit(0);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Update status bar message
|
|
389
|
+
*/
|
|
390
|
+
updateStatusMessage(_message) {
|
|
391
|
+
this.terminalInput.render();
|
|
392
|
+
}
|
|
393
|
+
async handleToolSettingsInput(input) {
|
|
394
|
+
const pending = this.pendingInteraction;
|
|
395
|
+
if (!pending || pending.type !== 'tool-settings') {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const trimmed = input.trim();
|
|
399
|
+
if (!trimmed) {
|
|
400
|
+
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
401
|
+
this.terminalInput.render();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const normalized = trimmed.toLowerCase();
|
|
405
|
+
if (normalized === 'cancel') {
|
|
406
|
+
this.pendingInteraction = null;
|
|
407
|
+
display.showInfo('Tool selection cancelled.');
|
|
408
|
+
this.terminalInput.render();
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (normalized === 'defaults') {
|
|
412
|
+
pending.selection = buildEnabledToolSet(null);
|
|
413
|
+
this.renderToolMenu(pending);
|
|
414
|
+
this.terminalInput.render();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (normalized === 'save') {
|
|
418
|
+
await this.persistToolSelection(pending);
|
|
419
|
+
this.pendingInteraction = null;
|
|
420
|
+
this.terminalInput.render();
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const choice = Number.parseInt(trimmed, 10);
|
|
424
|
+
if (Number.isFinite(choice)) {
|
|
425
|
+
const option = pending.options[choice - 1];
|
|
426
|
+
if (!option) {
|
|
427
|
+
display.showWarning('That option is not available.');
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
if (pending.selection.has(option.id)) {
|
|
431
|
+
pending.selection.delete(option.id);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
pending.selection.add(option.id);
|
|
435
|
+
}
|
|
436
|
+
this.renderToolMenu(pending);
|
|
437
|
+
}
|
|
438
|
+
this.terminalInput.render();
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
442
|
+
this.terminalInput.render();
|
|
443
|
+
}
|
|
444
|
+
async persistToolSelection(interaction) {
|
|
445
|
+
if (setsEqual(interaction.selection, interaction.initialSelection)) {
|
|
446
|
+
display.showInfo('No changes to save.');
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const defaults = buildEnabledToolSet(null);
|
|
450
|
+
if (setsEqual(interaction.selection, defaults)) {
|
|
451
|
+
clearToolSettings();
|
|
452
|
+
display.showInfo('Tool settings cleared. Defaults will be used on the next launch.');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const ordered = interaction.options
|
|
456
|
+
.map((option) => option.id)
|
|
457
|
+
.filter((id) => interaction.selection.has(id));
|
|
458
|
+
saveToolSettings({ enabledTools: ordered });
|
|
459
|
+
display.showInfo('Tool settings saved. Restart the CLI to apply them.');
|
|
460
|
+
}
|
|
461
|
+
async handleAgentSelectionInput(input) {
|
|
462
|
+
const pending = this.pendingInteraction;
|
|
463
|
+
if (!pending || pending.type !== 'agent-selection') {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (!this.agentMenu) {
|
|
467
|
+
this.pendingInteraction = null;
|
|
468
|
+
display.showWarning('Agent selection is unavailable in this CLI.');
|
|
469
|
+
this.terminalInput.render();
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const trimmed = input.trim();
|
|
473
|
+
if (!trimmed) {
|
|
474
|
+
display.showWarning('Enter a number or type "cancel".');
|
|
475
|
+
this.terminalInput.render();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (trimmed.toLowerCase() === 'cancel') {
|
|
479
|
+
this.pendingInteraction = null;
|
|
480
|
+
display.showInfo('Agent selection cancelled.');
|
|
481
|
+
this.terminalInput.render();
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const choice = Number.parseInt(trimmed, 10);
|
|
485
|
+
if (!Number.isFinite(choice)) {
|
|
486
|
+
display.showWarning('Please enter a valid number.');
|
|
487
|
+
this.terminalInput.render();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const option = pending.options[choice - 1];
|
|
491
|
+
if (!option) {
|
|
492
|
+
display.showWarning('That option is not available.');
|
|
493
|
+
this.terminalInput.render();
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
await this.persistAgentSelection(option.name);
|
|
497
|
+
this.pendingInteraction = null;
|
|
498
|
+
this.terminalInput.render();
|
|
499
|
+
}
|
|
500
|
+
async persistAgentSelection(profileName) {
|
|
501
|
+
if (!this.agentMenu) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const currentDefault = this.agentMenu.persistedProfile ?? this.agentMenu.defaultProfile;
|
|
505
|
+
if (profileName === currentDefault) {
|
|
506
|
+
display.showInfo(`${this.agentMenuLabel(profileName)} is already configured for the next launch.`);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (profileName === this.agentMenu.defaultProfile) {
|
|
510
|
+
clearActiveProfilePreference();
|
|
511
|
+
this.agentMenu.persistedProfile = null;
|
|
512
|
+
display.showInfo(`${this.agentMenuLabel(profileName)} restored as the default agent. Restart the CLI to switch.`);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
saveActiveProfilePreference(profileName);
|
|
516
|
+
this.agentMenu.persistedProfile = profileName;
|
|
517
|
+
display.showInfo(`${this.agentMenuLabel(profileName)} will load the next time you start the CLI. Restart to switch now.`);
|
|
518
|
+
}
|
|
519
|
+
setupHandlers() {
|
|
520
|
+
// Handle terminal resize
|
|
521
|
+
output.on('resize', () => {
|
|
522
|
+
this.terminalInput.handleResize();
|
|
523
|
+
});
|
|
524
|
+
// Show initial input UI
|
|
525
|
+
this.terminalInput.render();
|
|
526
|
+
}
|
|
527
|
+
setupStatusTracking() {
|
|
528
|
+
this.statusSubscription = this.statusTracker.subscribe((_state) => {
|
|
529
|
+
// Status tracking callback - currently no-op
|
|
530
|
+
});
|
|
531
|
+
this.setIdleStatus();
|
|
532
|
+
}
|
|
533
|
+
teardownStatusTracking() {
|
|
534
|
+
if (this.statusSubscription) {
|
|
535
|
+
this.statusSubscription();
|
|
536
|
+
this.statusSubscription = null;
|
|
537
|
+
}
|
|
538
|
+
this.statusTracker.reset();
|
|
539
|
+
}
|
|
540
|
+
setIdleStatus(detail) {
|
|
541
|
+
this.statusTracker.setBase('Ready for prompts', {
|
|
542
|
+
detail: this.describeStatusDetail(detail),
|
|
543
|
+
tone: 'success',
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
setProcessingStatus(detail) {
|
|
547
|
+
this.statusTracker.setBase('Working on your request', {
|
|
548
|
+
detail: this.describeStatusDetail(detail),
|
|
549
|
+
tone: 'info',
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
describeStatusDetail(detail) {
|
|
553
|
+
const parts = [detail?.trim() || this.describeModelDetail()];
|
|
554
|
+
const queued = this.followUpQueue.length;
|
|
555
|
+
if (queued > 0) {
|
|
556
|
+
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
|
|
557
|
+
}
|
|
558
|
+
return parts.join(' • ');
|
|
559
|
+
}
|
|
560
|
+
describeModelDetail() {
|
|
561
|
+
const provider = this.providerLabel(this.sessionState.provider);
|
|
562
|
+
return `${provider} · ${this.sessionState.model}`;
|
|
563
|
+
}
|
|
564
|
+
refreshContextGauge() {
|
|
565
|
+
const tokens = getContextWindowTokens(this.sessionState.model);
|
|
566
|
+
this.activeContextWindowTokens =
|
|
567
|
+
typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
568
|
+
}
|
|
569
|
+
updateContextUsage(percentage) {
|
|
570
|
+
this.uiAdapter.updateContextUsage(percentage);
|
|
571
|
+
this.terminalInput.setContextUsage(percentage);
|
|
572
|
+
}
|
|
573
|
+
handleSlashCommandPreviewChange() {
|
|
574
|
+
if (this.pendingInteraction) {
|
|
575
|
+
this.slashPreviewVisible = false;
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const shouldShow = this.shouldShowSlashCommandPreview();
|
|
579
|
+
if (shouldShow && !this.slashPreviewVisible) {
|
|
580
|
+
this.slashPreviewVisible = true;
|
|
581
|
+
this.showSlashCommandPreview();
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (!shouldShow && this.slashPreviewVisible) {
|
|
585
|
+
this.slashPreviewVisible = false;
|
|
586
|
+
this.uiAdapter.hideSlashCommandPreview();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
shouldShowSlashCommandPreview() {
|
|
590
|
+
const line = this.currentInput ?? '';
|
|
591
|
+
if (!line.trim()) {
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
const trimmed = line.trimStart();
|
|
595
|
+
return trimmed.startsWith('/');
|
|
596
|
+
}
|
|
597
|
+
showSlashCommandPreview() {
|
|
598
|
+
// Filter commands based on current input
|
|
599
|
+
const line = this.currentInput ?? '';
|
|
600
|
+
const trimmed = line.trimStart();
|
|
601
|
+
// Filter commands that match the current input
|
|
602
|
+
const filtered = this.slashCommands.filter(cmd => cmd.command.startsWith(trimmed) || trimmed === '/');
|
|
603
|
+
// Show in the unified UI with dynamic overlay
|
|
604
|
+
this.uiAdapter.showSlashCommandPreview(filtered);
|
|
605
|
+
// Don't reprompt - this causes flickering
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Ensure the terminal input is ready for interactive input.
|
|
609
|
+
*/
|
|
610
|
+
ensureReadlineReady() {
|
|
611
|
+
this.terminalInput.render();
|
|
612
|
+
}
|
|
613
|
+
requestPromptRefresh(force = false) {
|
|
614
|
+
if (force) {
|
|
615
|
+
this.terminalInput.forceRender();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (this.promptRefreshTimer) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
this.promptRefreshTimer = setTimeout(() => {
|
|
622
|
+
this.promptRefreshTimer = null;
|
|
623
|
+
this.terminalInput.render();
|
|
624
|
+
}, 48);
|
|
625
|
+
}
|
|
626
|
+
clearPromptRefreshTimer() {
|
|
627
|
+
if (this.promptRefreshTimer) {
|
|
628
|
+
clearTimeout(this.promptRefreshTimer);
|
|
629
|
+
this.promptRefreshTimer = null;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
startStreamingHeartbeat(label = 'Streaming response') {
|
|
633
|
+
this.stopStreamingHeartbeat();
|
|
634
|
+
this.streamingHeartbeatStart = Date.now();
|
|
635
|
+
this.streamingHeartbeatFrame = 0;
|
|
636
|
+
const frames = ['●', '◐', '◉', '◐'];
|
|
637
|
+
const tick = () => {
|
|
638
|
+
const frame = frames[this.streamingHeartbeatFrame % frames.length];
|
|
639
|
+
this.streamingHeartbeatFrame++;
|
|
640
|
+
const elapsed = this.streamingHeartbeatStart
|
|
641
|
+
? Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000)
|
|
642
|
+
: 0;
|
|
643
|
+
const suffix = elapsed > 0 ? ` • ${elapsed}s` : '';
|
|
644
|
+
display.updateStreamingStatus(`${theme.info(frame)} ${label}${suffix}`);
|
|
645
|
+
this.requestPromptRefresh();
|
|
646
|
+
};
|
|
647
|
+
tick();
|
|
648
|
+
this.streamingHeartbeat = setInterval(tick, 2000);
|
|
649
|
+
}
|
|
650
|
+
stopStreamingHeartbeat() {
|
|
651
|
+
if (this.streamingHeartbeat) {
|
|
652
|
+
clearInterval(this.streamingHeartbeat);
|
|
653
|
+
this.streamingHeartbeat = null;
|
|
654
|
+
}
|
|
655
|
+
this.streamingHeartbeatStart = null;
|
|
656
|
+
display.clearStreamingStatus();
|
|
657
|
+
this.requestPromptRefresh();
|
|
658
|
+
}
|
|
659
|
+
refreshQueueIndicators() {
|
|
660
|
+
if (this.isProcessing) {
|
|
661
|
+
this.setProcessingStatus();
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
this.setIdleStatus();
|
|
665
|
+
}
|
|
666
|
+
this.terminalInput.render();
|
|
667
|
+
}
|
|
668
|
+
enqueueFollowUpAction(action) {
|
|
669
|
+
this.followUpQueue.push(action);
|
|
670
|
+
const normalized = action.text.replace(/\s+/g, ' ').trim();
|
|
671
|
+
const previewLimit = 80;
|
|
672
|
+
const preview = normalized.length > previewLimit ? `${normalized.slice(0, previewLimit - 3)}...` : normalized;
|
|
673
|
+
const position = this.followUpQueue.length === 1 ? 'to run next' : `#${this.followUpQueue.length} in queue`;
|
|
674
|
+
const label = action.type === 'continuous' ? 'continuous command' : 'follow-up';
|
|
675
|
+
// Show immediate acknowledgment with checkmark
|
|
676
|
+
if (preview) {
|
|
677
|
+
display.showInfo(`✓ ${theme.info(label)} ${position}: ${theme.ui.muted(preview)}`);
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
display.showInfo(`✓ ${theme.info(label)} queued ${position}.`);
|
|
681
|
+
}
|
|
682
|
+
this.refreshQueueIndicators();
|
|
683
|
+
this.scheduleQueueProcessing();
|
|
684
|
+
// Re-show the prompt so user can continue typing more follow-ups
|
|
685
|
+
this.terminalInput.render();
|
|
686
|
+
}
|
|
687
|
+
scheduleQueueProcessing() {
|
|
688
|
+
if (!this.followUpQueue.length) {
|
|
689
|
+
this.refreshQueueIndicators();
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
queueMicrotask(() => {
|
|
693
|
+
void this.processQueuedActions();
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Process queued follow-up actions.
|
|
698
|
+
*/
|
|
699
|
+
async processQueuedActions() {
|
|
700
|
+
if (this.isDrainingQueue || this.isProcessing || !this.followUpQueue.length) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
this.isDrainingQueue = true;
|
|
704
|
+
try {
|
|
705
|
+
while (!this.isProcessing && this.followUpQueue.length) {
|
|
706
|
+
const next = this.followUpQueue.shift();
|
|
707
|
+
const remaining = this.followUpQueue.length;
|
|
708
|
+
const label = next.type === 'continuous' ? 'continuous command' : 'follow-up';
|
|
709
|
+
const suffix = remaining ? ` (${remaining} left after this)` : '';
|
|
710
|
+
display.showSystemMessage(`▶ Running queued ${label}${suffix}.`);
|
|
711
|
+
this.refreshQueueIndicators();
|
|
712
|
+
if (next.type === 'continuous') {
|
|
713
|
+
await this.processContinuousRequest(next.text);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
await this.processRequest(next.text);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
finally {
|
|
721
|
+
this.isDrainingQueue = false;
|
|
722
|
+
this.refreshQueueIndicators();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async processInputBlock(line, _wasRapidMultiLine = false) {
|
|
726
|
+
this.slashPreviewVisible = false;
|
|
727
|
+
this.uiAdapter.hideSlashCommandPreview();
|
|
728
|
+
const trimmed = line.trim();
|
|
729
|
+
if (await this.handlePendingInteraction(trimmed)) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (!trimmed) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const lower = trimmed.toLowerCase();
|
|
736
|
+
if (lower === 'exit' || lower === 'quit') {
|
|
737
|
+
this.shutdown();
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
if (lower === 'clear') {
|
|
741
|
+
display.clear();
|
|
742
|
+
this.terminalInput.render();
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (lower === 'help') {
|
|
746
|
+
this.showHelp();
|
|
747
|
+
this.terminalInput.render();
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (trimmed.startsWith('/')) {
|
|
751
|
+
await this.processSlashCommand(trimmed);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
// Check for continuous/infinite loop commands
|
|
755
|
+
if (this.isContinuousCommand(trimmed)) {
|
|
756
|
+
await this.processContinuousRequest(trimmed);
|
|
757
|
+
this.terminalInput.render();
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// Direct execution for all inputs, including multi-line pastes
|
|
761
|
+
await this.processRequest(trimmed);
|
|
762
|
+
this.terminalInput.render();
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Check if the command is a continuous/infinite loop command
|
|
766
|
+
* These commands run until the task is complete or user interrupts
|
|
767
|
+
*/
|
|
768
|
+
isContinuousCommand(input) {
|
|
769
|
+
const lower = input.toLowerCase().trim();
|
|
770
|
+
const patterns = [
|
|
771
|
+
/^(keep going|continue|finish|until done|run until done|complete|finish it|keep working)/i,
|
|
772
|
+
/\b(until done|until complete|until finished|to completion|to the end)\b/i,
|
|
773
|
+
/^(do it|just do it|make it work|fix it all|finish everything)\b/i,
|
|
774
|
+
];
|
|
775
|
+
return patterns.some(pattern => pattern.test(lower));
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Check if the request is a self-improvement task
|
|
779
|
+
* These requests should use git to track changes
|
|
780
|
+
*/
|
|
781
|
+
isSelfImprovementRequest(input) {
|
|
782
|
+
const lower = input.toLowerCase();
|
|
783
|
+
const patterns = [
|
|
784
|
+
/\b(improve|enhance|upgrade|refactor|optimize)\b.*\b(codebase|code|project|app|application)\b/i,
|
|
785
|
+
/\b(self[- ]?improv|self[- ]?modif|self[- ]?updat)/i,
|
|
786
|
+
/\b(make.*better|add.*feature|fix.*bug|implement)/i,
|
|
787
|
+
/\b(ability to code|coding capabilit)/i,
|
|
788
|
+
];
|
|
789
|
+
return patterns.some(pattern => pattern.test(lower));
|
|
790
|
+
}
|
|
791
|
+
async handlePendingInteraction(input) {
|
|
792
|
+
if (!this.pendingInteraction) {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
switch (this.pendingInteraction.type) {
|
|
796
|
+
case 'model-provider':
|
|
797
|
+
await this.handleModelProviderSelection(input);
|
|
798
|
+
return true;
|
|
799
|
+
case 'model':
|
|
800
|
+
await this.handleModelSelection(input);
|
|
801
|
+
return true;
|
|
802
|
+
case 'secret-select':
|
|
803
|
+
await this.handleSecretSelection(input);
|
|
804
|
+
return true;
|
|
805
|
+
case 'secret-input':
|
|
806
|
+
await this.handleSecretInput(input);
|
|
807
|
+
return true;
|
|
808
|
+
case 'tool-settings':
|
|
809
|
+
await this.handleToolSettingsInput(input);
|
|
810
|
+
return true;
|
|
811
|
+
case 'agent-selection':
|
|
812
|
+
await this.handleAgentSelectionInput(input);
|
|
813
|
+
return true;
|
|
814
|
+
default:
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
async processSlashCommand(input) {
|
|
819
|
+
const [command] = input.split(/\s+/);
|
|
820
|
+
if (!command) {
|
|
821
|
+
display.showWarning('Enter a slash command.');
|
|
822
|
+
this.terminalInput.render();
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
switch (command) {
|
|
826
|
+
case '/model':
|
|
827
|
+
this.showModelMenu();
|
|
828
|
+
break;
|
|
829
|
+
case '/secrets':
|
|
830
|
+
this.showSecretsMenu();
|
|
831
|
+
break;
|
|
832
|
+
case '/tools':
|
|
833
|
+
this.showToolsMenu();
|
|
834
|
+
break;
|
|
835
|
+
case '/doctor':
|
|
836
|
+
this.runDoctor();
|
|
837
|
+
break;
|
|
838
|
+
case '/checks':
|
|
839
|
+
await this.runRepoChecksCommand();
|
|
840
|
+
break;
|
|
841
|
+
case '/context':
|
|
842
|
+
await this.refreshWorkspaceContextCommand(input);
|
|
843
|
+
break;
|
|
844
|
+
case '/agents':
|
|
845
|
+
this.showAgentsMenu();
|
|
846
|
+
break;
|
|
847
|
+
case '/sessions':
|
|
848
|
+
await this.handleSessionCommand(input);
|
|
849
|
+
break;
|
|
850
|
+
case '/skills':
|
|
851
|
+
await this.handleSkillsCommand(input);
|
|
852
|
+
break;
|
|
853
|
+
case '/thinking':
|
|
854
|
+
this.handleThinkingCommand(input);
|
|
855
|
+
break;
|
|
856
|
+
case '/autocontinue':
|
|
857
|
+
this.handleAutoContinueCommand(input);
|
|
858
|
+
break;
|
|
859
|
+
case '/shortcuts':
|
|
860
|
+
case '/keys':
|
|
861
|
+
this.handleShortcutsCommand();
|
|
862
|
+
break;
|
|
863
|
+
case '/changes':
|
|
864
|
+
case '/summary':
|
|
865
|
+
this.showFileChangeSummary();
|
|
866
|
+
break;
|
|
867
|
+
case '/metrics':
|
|
868
|
+
case '/stats':
|
|
869
|
+
case '/perf':
|
|
870
|
+
this.showAlphaZeroMetrics();
|
|
871
|
+
break;
|
|
872
|
+
case '/suggestions':
|
|
873
|
+
case '/improve':
|
|
874
|
+
this.showImprovementSuggestions();
|
|
875
|
+
break;
|
|
876
|
+
case '/plugins':
|
|
877
|
+
this.showPluginStatus();
|
|
878
|
+
break;
|
|
879
|
+
case '/provider':
|
|
880
|
+
await this.handleProviderCommand(input);
|
|
881
|
+
break;
|
|
882
|
+
case '/providers':
|
|
883
|
+
this.showConfiguredProviders();
|
|
884
|
+
break;
|
|
885
|
+
case '/local':
|
|
886
|
+
await this.handleLocalCommand(input);
|
|
887
|
+
break;
|
|
888
|
+
case '/discover':
|
|
889
|
+
await this.discoverModelsCommand();
|
|
890
|
+
break;
|
|
891
|
+
default:
|
|
892
|
+
if (!(await this.tryCustomSlashCommand(command, input))) {
|
|
893
|
+
display.showWarning(`Unknown command "${command}".`);
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
this.terminalInput.render();
|
|
898
|
+
}
|
|
899
|
+
async tryCustomSlashCommand(command, fullInput) {
|
|
900
|
+
const custom = this.customCommandMap.get(command);
|
|
901
|
+
if (!custom) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
const args = fullInput.slice(command.length).trim();
|
|
905
|
+
if (custom.requireInput && !args) {
|
|
906
|
+
display.showWarning(`${command} requires additional input.`);
|
|
907
|
+
return true;
|
|
908
|
+
}
|
|
909
|
+
const prompt = buildCustomCommandPrompt(custom, args, {
|
|
910
|
+
workspace: this.workingDir,
|
|
911
|
+
profile: this.profile,
|
|
912
|
+
provider: this.sessionState.provider,
|
|
913
|
+
model: this.sessionState.model,
|
|
914
|
+
}).trim();
|
|
915
|
+
if (!prompt) {
|
|
916
|
+
display.showWarning(`Custom command ${command} did not produce any text. Check ${custom.source} for errors.`);
|
|
917
|
+
return true;
|
|
918
|
+
}
|
|
919
|
+
display.showInfo(`Running ${command} from ${custom.source}...`);
|
|
920
|
+
await this.processRequest(prompt);
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
showHelp() {
|
|
924
|
+
const info = [
|
|
925
|
+
this.buildSlashCommandList('Available Commands:'),
|
|
926
|
+
'',
|
|
927
|
+
'Type your request in natural language and press Enter.',
|
|
928
|
+
];
|
|
929
|
+
display.showSystemMessage(info.join('\n'));
|
|
930
|
+
}
|
|
931
|
+
runDoctor() {
|
|
932
|
+
const lines = [];
|
|
933
|
+
lines.push(theme.bold('Environment diagnostics'));
|
|
934
|
+
lines.push('');
|
|
935
|
+
lines.push(`${theme.secondary('Workspace')}: ${this.workingDir}`);
|
|
936
|
+
lines.push('');
|
|
937
|
+
lines.push(theme.bold('Provider credentials'));
|
|
938
|
+
const providerDefinition = getSecretDefinitionForProvider(this.sessionState.provider);
|
|
939
|
+
if (providerDefinition) {
|
|
940
|
+
const currentValue = getSecretValue(providerDefinition.id);
|
|
941
|
+
if (currentValue) {
|
|
942
|
+
lines.push(`${theme.success('✓')} ${providerDefinition.label} configured (${providerDefinition.envVar}).`);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
lines.push(`${theme.warning('⚠')} Missing ${providerDefinition.label} (${providerDefinition.envVar}). Run /secrets to configure it.`);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
lines.push(`${theme.secondary('•')} ${this.providerLabel(this.sessionState.provider)} does not require an API key.`);
|
|
950
|
+
}
|
|
951
|
+
lines.push('');
|
|
952
|
+
lines.push(theme.bold('Tool suites'));
|
|
953
|
+
const toolSettings = loadToolSettings();
|
|
954
|
+
const selection = buildEnabledToolSet(toolSettings);
|
|
955
|
+
const permissions = evaluateToolPermissions(selection);
|
|
956
|
+
const options = getToolToggleOptions();
|
|
957
|
+
const enabledLabels = options
|
|
958
|
+
.filter((option) => selection.has(option.id))
|
|
959
|
+
.map((option) => option.label);
|
|
960
|
+
lines.push(`Enabled: ${enabledLabels.length ? enabledLabels.join(', ') : 'none'}`);
|
|
961
|
+
if (!permissions.warnings.length) {
|
|
962
|
+
lines.push(theme.success('All enabled suites loaded successfully.'));
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
lines.push(theme.warning('Issues detected:'));
|
|
966
|
+
for (const warning of permissions.warnings) {
|
|
967
|
+
const detail = this.describeToolWarning(warning);
|
|
968
|
+
lines.push(` - ${detail}`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
display.showSystemMessage(lines.join('\n'));
|
|
972
|
+
}
|
|
973
|
+
async runRepoChecksCommand() {
|
|
974
|
+
if (this.isProcessing) {
|
|
975
|
+
display.showWarning('Wait for the active response to finish before running checks.');
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const call = {
|
|
979
|
+
id: 'manual-run-repo-checks',
|
|
980
|
+
name: 'run_repo_checks',
|
|
981
|
+
arguments: {},
|
|
982
|
+
};
|
|
983
|
+
display.showInfo('Running repo checks (npm test/build/lint when available)...');
|
|
984
|
+
const output = await this.runtimeSession.toolRuntime.execute(call);
|
|
985
|
+
display.showSystemMessage(output);
|
|
986
|
+
}
|
|
987
|
+
async refreshWorkspaceContextCommand(input) {
|
|
988
|
+
if (this.isProcessing) {
|
|
989
|
+
display.showWarning('Wait for the active response to finish before refreshing the snapshot.');
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const { overrides, error } = this.parseContextOverrideTokens(input);
|
|
993
|
+
if (error) {
|
|
994
|
+
display.showWarning(`${error} ${this.describeContextOverrideUsage()}`);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (overrides) {
|
|
998
|
+
this.workspaceOptions = { ...this.workspaceOptions, ...overrides };
|
|
999
|
+
}
|
|
1000
|
+
display.showInfo('Refreshing workspace snapshot...');
|
|
1001
|
+
const context = buildWorkspaceContext(this.workingDir, this.workspaceOptions);
|
|
1002
|
+
const profileConfig = this.runtimeSession.refreshWorkspaceContext(context);
|
|
1003
|
+
const tools = this.runtimeSession.toolRuntime.listProviderTools();
|
|
1004
|
+
this.baseSystemPrompt = buildInteractiveSystemPrompt(profileConfig.systemPrompt, profileConfig.label, tools);
|
|
1005
|
+
if (this.rebuildAgent()) {
|
|
1006
|
+
display.showInfo(`Workspace snapshot refreshed (${this.describeWorkspaceOptions()}).`);
|
|
1007
|
+
this.resetChatBoxAfterModelSwap();
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
display.showWarning('Workspace snapshot refreshed, but the agent failed to rebuild. Run /doctor for details.');
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
parseContextOverrideTokens(input) {
|
|
1014
|
+
const overrides = {};
|
|
1015
|
+
let hasOverride = false;
|
|
1016
|
+
const tokens = input
|
|
1017
|
+
.trim()
|
|
1018
|
+
.split(/\s+/)
|
|
1019
|
+
.slice(1);
|
|
1020
|
+
for (const token of tokens) {
|
|
1021
|
+
if (!token) {
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
const [rawKey, rawValue] = token.split('=');
|
|
1025
|
+
if (!rawKey || !rawValue) {
|
|
1026
|
+
return { overrides: null, error: `Invalid option "${token}".` };
|
|
1027
|
+
}
|
|
1028
|
+
const key = rawKey.toLowerCase();
|
|
1029
|
+
const value = Number.parseInt(rawValue, 10);
|
|
1030
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
1031
|
+
return { overrides: null, error: `Value for "${key}" must be a positive integer.` };
|
|
1032
|
+
}
|
|
1033
|
+
switch (key) {
|
|
1034
|
+
case 'depth':
|
|
1035
|
+
overrides.treeDepth = value;
|
|
1036
|
+
hasOverride = true;
|
|
1037
|
+
break;
|
|
1038
|
+
case 'entries':
|
|
1039
|
+
overrides.maxEntries = value;
|
|
1040
|
+
hasOverride = true;
|
|
1041
|
+
break;
|
|
1042
|
+
case 'excerpt':
|
|
1043
|
+
case 'doc':
|
|
1044
|
+
case 'docs':
|
|
1045
|
+
overrides.docExcerptLimit = value;
|
|
1046
|
+
hasOverride = true;
|
|
1047
|
+
break;
|
|
1048
|
+
default:
|
|
1049
|
+
return { overrides: null, error: `Unknown option "${key}".` };
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return { overrides: hasOverride ? overrides : null };
|
|
1053
|
+
}
|
|
1054
|
+
async handleSessionCommand(input) {
|
|
1055
|
+
const tokens = input
|
|
1056
|
+
.trim()
|
|
1057
|
+
.split(/\s+/)
|
|
1058
|
+
.slice(1);
|
|
1059
|
+
const action = (tokens.shift() ?? 'list').toLowerCase();
|
|
1060
|
+
switch (action) {
|
|
1061
|
+
case '':
|
|
1062
|
+
case 'list':
|
|
1063
|
+
this.showSessionList();
|
|
1064
|
+
return;
|
|
1065
|
+
case 'save':
|
|
1066
|
+
await this.saveSessionCommand(tokens.join(' ').trim());
|
|
1067
|
+
return;
|
|
1068
|
+
case 'load':
|
|
1069
|
+
await this.loadSessionCommand(tokens.join(' ').trim());
|
|
1070
|
+
return;
|
|
1071
|
+
case 'delete':
|
|
1072
|
+
case 'remove':
|
|
1073
|
+
this.deleteSessionCommand(tokens.join(' ').trim());
|
|
1074
|
+
return;
|
|
1075
|
+
case 'new':
|
|
1076
|
+
this.newSessionCommand(tokens.join(' ').trim());
|
|
1077
|
+
return;
|
|
1078
|
+
case 'autosave':
|
|
1079
|
+
this.toggleAutosaveCommand(tokens[0]);
|
|
1080
|
+
return;
|
|
1081
|
+
case 'clear':
|
|
1082
|
+
this.clearAutosaveCommand();
|
|
1083
|
+
return;
|
|
1084
|
+
default:
|
|
1085
|
+
display.showWarning('Usage: /sessions [list|save <title>|load <id>|delete <id>|new <title>|autosave on|off|clear]');
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
async handleSkillsCommand(input) {
|
|
1090
|
+
const raw = input.slice('/skills'.length).trim();
|
|
1091
|
+
const tokens = raw ? raw.split(/\s+/).filter(Boolean) : [];
|
|
1092
|
+
let refresh = false;
|
|
1093
|
+
const filtered = [];
|
|
1094
|
+
for (const token of tokens) {
|
|
1095
|
+
if (token === '--refresh' || token === '-r') {
|
|
1096
|
+
refresh = true;
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
filtered.push(token);
|
|
1100
|
+
}
|
|
1101
|
+
let mode = filtered.shift()?.toLowerCase() ?? 'list';
|
|
1102
|
+
if (mode === 'refresh') {
|
|
1103
|
+
refresh = true;
|
|
1104
|
+
mode = 'list';
|
|
1105
|
+
}
|
|
1106
|
+
try {
|
|
1107
|
+
switch (mode) {
|
|
1108
|
+
case '':
|
|
1109
|
+
case 'list': {
|
|
1110
|
+
const query = filtered.join(' ');
|
|
1111
|
+
const output = await this.invokeSkillTool('ListSkills', {
|
|
1112
|
+
query: query || undefined,
|
|
1113
|
+
refresh_cache: refresh,
|
|
1114
|
+
});
|
|
1115
|
+
display.showSystemMessage(output);
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
case 'show':
|
|
1119
|
+
case 'view': {
|
|
1120
|
+
const identifier = filtered.shift();
|
|
1121
|
+
if (!identifier) {
|
|
1122
|
+
display.showWarning('Usage: /skills show <skill-id> [sections=metadata,body]');
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
let sectionsArg;
|
|
1126
|
+
for (let i = 0; i < filtered.length; i += 1) {
|
|
1127
|
+
const token = filtered[i];
|
|
1128
|
+
if (!token) {
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
if (token.startsWith('sections=')) {
|
|
1132
|
+
sectionsArg = token.slice('sections='.length);
|
|
1133
|
+
filtered.splice(i, 1);
|
|
1134
|
+
break;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
const sections = sectionsArg
|
|
1138
|
+
? sectionsArg
|
|
1139
|
+
.split(',')
|
|
1140
|
+
.map((section) => section.trim())
|
|
1141
|
+
.filter(Boolean)
|
|
1142
|
+
: undefined;
|
|
1143
|
+
const output = await this.invokeSkillTool('Skill', {
|
|
1144
|
+
skill: identifier,
|
|
1145
|
+
sections,
|
|
1146
|
+
refresh_cache: refresh,
|
|
1147
|
+
});
|
|
1148
|
+
display.showSystemMessage(output);
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
default:
|
|
1152
|
+
display.showWarning('Usage: /skills [list|refresh|show <id> [sections=a,b]]');
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
catch (error) {
|
|
1157
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1158
|
+
display.showError(`Skill command failed: ${message}`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
async invokeSkillTool(name, args) {
|
|
1162
|
+
const handler = this.skillToolHandlers.get(name);
|
|
1163
|
+
if (!handler) {
|
|
1164
|
+
throw new Error(`Skill tool "${name}" is not registered.`);
|
|
1165
|
+
}
|
|
1166
|
+
const result = await handler(args);
|
|
1167
|
+
return typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
1168
|
+
}
|
|
1169
|
+
handleThinkingCommand(input) {
|
|
1170
|
+
const value = input.slice('/thinking'.length).trim().toLowerCase();
|
|
1171
|
+
if (!value) {
|
|
1172
|
+
display.showInfo(`Thinking mode is currently ${theme.info(this.thinkingMode)}. Usage: /thinking [concise|balanced|extended]`);
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
if (value !== 'concise' && value !== 'balanced' && value !== 'extended') {
|
|
1176
|
+
display.showWarning('Usage: /thinking [concise|balanced|extended]');
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
if (this.isProcessing) {
|
|
1180
|
+
display.showWarning('Wait until the current request finishes before changing thinking mode.');
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
this.thinkingMode = value;
|
|
1184
|
+
saveSessionPreferences({ thinkingMode: this.thinkingMode });
|
|
1185
|
+
if (this.rebuildAgent()) {
|
|
1186
|
+
this.resetChatBoxAfterModelSwap();
|
|
1187
|
+
}
|
|
1188
|
+
const descriptions = {
|
|
1189
|
+
concise: 'Hides internal reasoning and responds directly.',
|
|
1190
|
+
balanced: 'Shows short thoughts only when helpful.',
|
|
1191
|
+
extended: 'Always emits a <thinking> block before the final response.',
|
|
1192
|
+
};
|
|
1193
|
+
display.showInfo(`Thinking mode set to ${theme.info(value)} – ${descriptions[this.thinkingMode]}`);
|
|
1194
|
+
}
|
|
1195
|
+
handleShortcutsCommand() {
|
|
1196
|
+
// Display keyboard shortcuts help (Claude Code style)
|
|
1197
|
+
display.showSystemMessage(formatShortcutsHelp());
|
|
1198
|
+
}
|
|
1199
|
+
showFileChangeSummary() {
|
|
1200
|
+
const summary = this._fileChangeTracker.getSummary();
|
|
1201
|
+
const changes = this._fileChangeTracker.getAllChanges();
|
|
1202
|
+
if (changes.length === 0) {
|
|
1203
|
+
display.showInfo('No files modified in this session.');
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const lines = [];
|
|
1207
|
+
lines.push(theme.bold('Session File Changes'));
|
|
1208
|
+
lines.push('');
|
|
1209
|
+
lines.push(`${theme.info('•')} ${summary.files} file${summary.files === 1 ? '' : 's'} modified`);
|
|
1210
|
+
lines.push(`${theme.info('•')} ${theme.success('+' + summary.additions)} ${theme.error('-' + summary.removals)} lines`);
|
|
1211
|
+
lines.push('');
|
|
1212
|
+
// Group changes by file
|
|
1213
|
+
const fileMap = new Map();
|
|
1214
|
+
for (const change of changes) {
|
|
1215
|
+
const existing = fileMap.get(change.path) || { edits: 0, writes: 0, additions: 0, removals: 0 };
|
|
1216
|
+
if (change.type === 'edit') {
|
|
1217
|
+
existing.edits++;
|
|
1218
|
+
}
|
|
1219
|
+
else if (change.type === 'write') {
|
|
1220
|
+
existing.writes++;
|
|
1221
|
+
}
|
|
1222
|
+
existing.additions += change.additions;
|
|
1223
|
+
existing.removals += change.removals;
|
|
1224
|
+
fileMap.set(change.path, existing);
|
|
1225
|
+
}
|
|
1226
|
+
// Display each file
|
|
1227
|
+
for (const [path, stats] of fileMap) {
|
|
1228
|
+
const operations = [];
|
|
1229
|
+
if (stats.edits > 0)
|
|
1230
|
+
operations.push(`${stats.edits} edit${stats.edits === 1 ? '' : 's'}`);
|
|
1231
|
+
if (stats.writes > 0)
|
|
1232
|
+
operations.push(`${stats.writes} write${stats.writes === 1 ? '' : 's'}`);
|
|
1233
|
+
const opsText = operations.join(', ');
|
|
1234
|
+
const diffText = `${theme.success('+' + stats.additions)} ${theme.error('-' + stats.removals)}`;
|
|
1235
|
+
lines.push(` ${theme.dim(path)}`);
|
|
1236
|
+
lines.push(` ${opsText} • ${diffText}`);
|
|
1237
|
+
}
|
|
1238
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1239
|
+
}
|
|
1240
|
+
showAlphaZeroMetrics() {
|
|
1241
|
+
const summary = this.alphaZeroMetrics.getPerformanceSummary();
|
|
1242
|
+
display.showSystemMessage(summary);
|
|
1243
|
+
}
|
|
1244
|
+
showImprovementSuggestions() {
|
|
1245
|
+
const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
|
|
1246
|
+
if (suggestions.length === 0) {
|
|
1247
|
+
display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const lines = [
|
|
1251
|
+
theme.bold('Improvement Suggestions (Alpha Zero 2):'),
|
|
1252
|
+
'',
|
|
1253
|
+
];
|
|
1254
|
+
for (let i = 0; i < suggestions.length; i++) {
|
|
1255
|
+
const suggestion = suggestions[i];
|
|
1256
|
+
const severityColor = suggestion.severity === 'high'
|
|
1257
|
+
? theme.error
|
|
1258
|
+
: suggestion.severity === 'medium'
|
|
1259
|
+
? theme.warning
|
|
1260
|
+
: theme.info;
|
|
1261
|
+
lines.push(`${i + 1}. [${severityColor(suggestion.severity.toUpperCase())}] ${suggestion.message}`);
|
|
1262
|
+
if (suggestion.suggestedAction) {
|
|
1263
|
+
lines.push(` ${theme.dim('Action:')} ${suggestion.suggestedAction}`);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1267
|
+
}
|
|
1268
|
+
showPluginStatus() {
|
|
1269
|
+
const available = listAvailablePlugins();
|
|
1270
|
+
const lines = [];
|
|
1271
|
+
lines.push(theme.bold('Plugin Status'));
|
|
1272
|
+
lines.push('');
|
|
1273
|
+
if (available.length === 0) {
|
|
1274
|
+
lines.push(theme.secondary('No plugins registered.'));
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
lines.push(theme.secondary('Available Plugins:'));
|
|
1278
|
+
lines.push('');
|
|
1279
|
+
for (const pluginId of available) {
|
|
1280
|
+
const isEnabled = this._enabledPlugins.includes(pluginId);
|
|
1281
|
+
const status = isEnabled
|
|
1282
|
+
? theme.success('[ENABLED]')
|
|
1283
|
+
: theme.dim('[available]');
|
|
1284
|
+
const displayName = pluginId.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1285
|
+
lines.push(` ${status} ${theme.bold(displayName)}`);
|
|
1286
|
+
lines.push(` ${theme.dim(`ID: ${pluginId}`)}`);
|
|
1287
|
+
lines.push('');
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
lines.push(theme.secondary('CLI Flags:'));
|
|
1291
|
+
lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
|
|
1292
|
+
lines.push(' --coding Enable enhanced coding tools');
|
|
1293
|
+
lines.push(' --security Enable security research tools');
|
|
1294
|
+
lines.push(' --all-plugins Enable all optional plugins');
|
|
1295
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1296
|
+
}
|
|
1297
|
+
showSessionList() {
|
|
1298
|
+
const sessions = listSessions(this.profile);
|
|
1299
|
+
const lines = [];
|
|
1300
|
+
lines.push(theme.bold('Saved sessions'));
|
|
1301
|
+
lines.push('Use "/sessions save <title>" to persist history or "/sessions load <id>" to resume.');
|
|
1302
|
+
lines.push('');
|
|
1303
|
+
if (!sessions.length) {
|
|
1304
|
+
lines.push(theme.secondary('No saved sessions yet.'));
|
|
1305
|
+
}
|
|
1306
|
+
else {
|
|
1307
|
+
sessions.forEach((session, index) => {
|
|
1308
|
+
const prefix = `${index + 1}.`;
|
|
1309
|
+
const label = session.title || '(untitled)';
|
|
1310
|
+
const relative = this.describeRelativeTime(session.updatedAt);
|
|
1311
|
+
const active = this.activeSessionId && session.id === this.activeSessionId
|
|
1312
|
+
? ` ${theme.success('[active]')}`
|
|
1313
|
+
: '';
|
|
1314
|
+
const messageCount = `${session.messageCount} msg`;
|
|
1315
|
+
const shortId = this.formatSessionId(session.id);
|
|
1316
|
+
lines.push(`${prefix.padEnd(3)} ${label} ${theme.secondary(`(${messageCount}, ${relative}, ${shortId})`)}${active}`);
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
lines.push('');
|
|
1320
|
+
lines.push(`Autosave: ${this.autosaveEnabled ? theme.success('on') : theme.warning('off')} (toggle via "/sessions autosave on|off")`);
|
|
1321
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1322
|
+
}
|
|
1323
|
+
async saveSessionCommand(title) {
|
|
1324
|
+
const agent = this.agent;
|
|
1325
|
+
if (!agent) {
|
|
1326
|
+
display.showWarning('Start a conversation before saving a session.');
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const history = agent.getHistory();
|
|
1330
|
+
if (!history || history.length <= 1) {
|
|
1331
|
+
display.showWarning('You need at least one user message before saving a session.');
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
const summary = saveSessionSnapshot({
|
|
1335
|
+
id: this.activeSessionId ?? undefined,
|
|
1336
|
+
title: title || this.activeSessionTitle || null,
|
|
1337
|
+
profile: this.profile,
|
|
1338
|
+
provider: this.sessionState.provider,
|
|
1339
|
+
model: this.sessionState.model,
|
|
1340
|
+
workspaceRoot: this.workingDir,
|
|
1341
|
+
messages: history,
|
|
1342
|
+
});
|
|
1343
|
+
this.cachedHistory = history;
|
|
1344
|
+
this.updateActiveSession(summary, true);
|
|
1345
|
+
this.sessionResumeNotice = null;
|
|
1346
|
+
this.autosaveIfEnabled();
|
|
1347
|
+
display.showInfo(`Session saved as "${summary.title}" (id ${this.formatSessionId(summary.id)}).`);
|
|
1348
|
+
}
|
|
1349
|
+
async loadSessionCommand(selector) {
|
|
1350
|
+
const summary = this.resolveSessionBySelector(selector);
|
|
1351
|
+
if (!summary) {
|
|
1352
|
+
display.showWarning('No session matches that selection.');
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const stored = loadSessionById(summary.id);
|
|
1356
|
+
if (!stored) {
|
|
1357
|
+
display.showWarning('Failed to load that session. It may have been corrupted or deleted.');
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
this.cachedHistory = stored.messages;
|
|
1361
|
+
this.updateActiveSession(summary, true);
|
|
1362
|
+
this.sessionResumeNotice = `Loaded session "${summary.title}".`;
|
|
1363
|
+
if (this.agent) {
|
|
1364
|
+
this.agent.loadHistory(stored.messages);
|
|
1365
|
+
this.sessionResumeNotice = null;
|
|
1366
|
+
display.showInfo(`Loaded session "${summary.title}".`);
|
|
1367
|
+
this.refreshContextGauge();
|
|
1368
|
+
this.captureHistorySnapshot();
|
|
1369
|
+
this.pendingHistoryLoad = null;
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
this.pendingHistoryLoad = stored.messages;
|
|
1373
|
+
display.showInfo(`Session "${summary.title}" queued to load once the agent is ready.`);
|
|
1374
|
+
}
|
|
1375
|
+
this.autosaveIfEnabled();
|
|
1376
|
+
}
|
|
1377
|
+
deleteSessionCommand(selector) {
|
|
1378
|
+
const summary = this.resolveSessionBySelector(selector);
|
|
1379
|
+
if (!summary) {
|
|
1380
|
+
display.showWarning('No session matches that selection.');
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
if (!deleteSession(summary.id)) {
|
|
1384
|
+
display.showWarning('Unable to delete that session.');
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
display.showInfo(`Deleted session "${summary.title}".`);
|
|
1388
|
+
if (this.activeSessionId === summary.id) {
|
|
1389
|
+
this.activeSessionId = null;
|
|
1390
|
+
this.activeSessionTitle = null;
|
|
1391
|
+
saveSessionPreferences({ lastSessionId: null });
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
newSessionCommand(title) {
|
|
1395
|
+
if (this.agent) {
|
|
1396
|
+
this.agent.clearHistory();
|
|
1397
|
+
this.cachedHistory = this.agent.getHistory();
|
|
1398
|
+
this.pendingHistoryLoad = null;
|
|
1399
|
+
}
|
|
1400
|
+
if (!this.agent) {
|
|
1401
|
+
this.cachedHistory = [];
|
|
1402
|
+
this.pendingHistoryLoad = [];
|
|
1403
|
+
}
|
|
1404
|
+
this.activeSessionId = null;
|
|
1405
|
+
this.activeSessionTitle = title || null;
|
|
1406
|
+
this.sessionResumeNotice = null;
|
|
1407
|
+
saveSessionPreferences({ lastSessionId: null });
|
|
1408
|
+
clearAutosaveSnapshot(this.profile);
|
|
1409
|
+
display.showInfo('Started a new empty session.');
|
|
1410
|
+
this.refreshContextGauge();
|
|
1411
|
+
}
|
|
1412
|
+
toggleAutosaveCommand(value) {
|
|
1413
|
+
if (!value) {
|
|
1414
|
+
display.showWarning('Usage: /sessions autosave on|off');
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
const normalized = value.toLowerCase();
|
|
1418
|
+
if (normalized !== 'on' && normalized !== 'off') {
|
|
1419
|
+
display.showWarning('Usage: /sessions autosave on|off');
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
this.autosaveEnabled = normalized === 'on';
|
|
1423
|
+
saveSessionPreferences({ autosave: this.autosaveEnabled });
|
|
1424
|
+
display.showInfo(`Autosave ${this.autosaveEnabled ? 'enabled' : 'disabled'}.`);
|
|
1425
|
+
if (!this.autosaveEnabled) {
|
|
1426
|
+
clearAutosaveSnapshot(this.profile);
|
|
1427
|
+
}
|
|
1428
|
+
else {
|
|
1429
|
+
this.autosaveIfEnabled();
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
clearAutosaveCommand() {
|
|
1433
|
+
clearAutosaveSnapshot(this.profile);
|
|
1434
|
+
display.showInfo('Cleared autosave history.');
|
|
1435
|
+
}
|
|
1436
|
+
handleAutoContinueCommand(input) {
|
|
1437
|
+
const tokens = input.split(/\s+/).slice(1);
|
|
1438
|
+
const value = tokens[0]?.toLowerCase();
|
|
1439
|
+
if (!value) {
|
|
1440
|
+
// Show current status
|
|
1441
|
+
display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
|
|
1442
|
+
`Use /autocontinue on|off to toggle.`);
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
if (value !== 'on' && value !== 'off') {
|
|
1446
|
+
display.showWarning('Usage: /autocontinue on|off');
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
this.autoContinueEnabled = value === 'on';
|
|
1450
|
+
saveSessionPreferences({ autoContinue: this.autoContinueEnabled });
|
|
1451
|
+
// Update the current agent if it exists
|
|
1452
|
+
if (this.agent) {
|
|
1453
|
+
this.agent.setAutoContinue(this.autoContinueEnabled);
|
|
1454
|
+
}
|
|
1455
|
+
display.showInfo(`Auto-continue ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
|
|
1456
|
+
(this.autoContinueEnabled
|
|
1457
|
+
? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
|
|
1458
|
+
: 'The model will not be auto-prompted to continue.'));
|
|
1459
|
+
}
|
|
1460
|
+
updateActiveSession(summary, remember = false) {
|
|
1461
|
+
this.activeSessionId = summary?.id ?? null;
|
|
1462
|
+
this.activeSessionTitle = summary?.title ?? null;
|
|
1463
|
+
if (remember) {
|
|
1464
|
+
saveSessionPreferences({ lastSessionId: summary?.id ?? null });
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
resolveSessionBySelector(selector) {
|
|
1468
|
+
const sessions = listSessions(this.profile);
|
|
1469
|
+
if (!sessions.length) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
if (!selector) {
|
|
1473
|
+
return sessions[0] ?? null;
|
|
1474
|
+
}
|
|
1475
|
+
const trimmed = selector.trim();
|
|
1476
|
+
if (!trimmed) {
|
|
1477
|
+
return sessions[0] ?? null;
|
|
1478
|
+
}
|
|
1479
|
+
const index = Number.parseInt(trimmed, 10);
|
|
1480
|
+
if (Number.isFinite(index)) {
|
|
1481
|
+
const entry = sessions[index - 1];
|
|
1482
|
+
return entry ?? null;
|
|
1483
|
+
}
|
|
1484
|
+
const match = sessions.find((session) => session.id.startsWith(trimmed));
|
|
1485
|
+
return match ?? null;
|
|
1486
|
+
}
|
|
1487
|
+
formatSessionId(id) {
|
|
1488
|
+
return id.length > 8 ? `${id.slice(0, 8)}…` : id;
|
|
1489
|
+
}
|
|
1490
|
+
describeRelativeTime(timestamp) {
|
|
1491
|
+
const updated = Date.parse(timestamp);
|
|
1492
|
+
if (!updated) {
|
|
1493
|
+
return 'unknown';
|
|
1494
|
+
}
|
|
1495
|
+
const deltaMs = Date.now() - updated;
|
|
1496
|
+
const minutes = Math.round(deltaMs / 60000);
|
|
1497
|
+
if (minutes < 1) {
|
|
1498
|
+
return 'just now';
|
|
1499
|
+
}
|
|
1500
|
+
if (minutes < 60) {
|
|
1501
|
+
return `${minutes}m ago`;
|
|
1502
|
+
}
|
|
1503
|
+
const hours = Math.round(minutes / 60);
|
|
1504
|
+
if (hours < 24) {
|
|
1505
|
+
return `${hours}h ago`;
|
|
1506
|
+
}
|
|
1507
|
+
const days = Math.round(hours / 24);
|
|
1508
|
+
return `${days}d ago`;
|
|
1509
|
+
}
|
|
1510
|
+
captureHistorySnapshot() {
|
|
1511
|
+
if (!this.agent) {
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
this.cachedHistory = this.agent.getHistory();
|
|
1515
|
+
}
|
|
1516
|
+
autosaveIfEnabled() {
|
|
1517
|
+
if (!this.autosaveEnabled) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
if (!this.cachedHistory || this.cachedHistory.length <= 1) {
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
saveAutosaveSnapshot(this.profile, {
|
|
1524
|
+
provider: this.sessionState.provider,
|
|
1525
|
+
model: this.sessionState.model,
|
|
1526
|
+
workspaceRoot: this.workingDir,
|
|
1527
|
+
title: this.activeSessionTitle,
|
|
1528
|
+
messages: this.cachedHistory,
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
describeWorkspaceOptions() {
|
|
1532
|
+
const depth = this.workspaceOptions.treeDepth ?? 'default';
|
|
1533
|
+
const entries = this.workspaceOptions.maxEntries ?? 'default';
|
|
1534
|
+
const excerpt = this.workspaceOptions.docExcerptLimit ?? 'default';
|
|
1535
|
+
return `depth=${depth}, entries=${entries}, excerpt=${excerpt}`;
|
|
1536
|
+
}
|
|
1537
|
+
describeContextOverrideUsage() {
|
|
1538
|
+
return 'Usage: /context [depth=<n>] [entries=<n>] [excerpt=<n>]';
|
|
1539
|
+
}
|
|
1540
|
+
describeToolWarning(warning) {
|
|
1541
|
+
if (warning.reason === 'missing-secret' && warning.secretId) {
|
|
1542
|
+
return `${warning.label}: missing ${warning.secretId}. Use /secrets to configure it.`;
|
|
1543
|
+
}
|
|
1544
|
+
return `${warning.label}: ${warning.reason}.`;
|
|
1545
|
+
}
|
|
1546
|
+
buildSlashCommandList(header) {
|
|
1547
|
+
const lines = [theme.gradient.primary(header), ''];
|
|
1548
|
+
for (const command of this.slashCommands) {
|
|
1549
|
+
lines.push(`${theme.primary(command.command)} - ${command.description}`);
|
|
1550
|
+
}
|
|
1551
|
+
return lines.join('\n');
|
|
1552
|
+
}
|
|
1553
|
+
async showModelMenu() {
|
|
1554
|
+
display.showSystemMessage(theme.ui.muted('Fetching latest models from providers...'));
|
|
1555
|
+
// Fetch live models from all configured providers
|
|
1556
|
+
const providerStatuses = await quickCheckProviders();
|
|
1557
|
+
const providerOptions = this.buildProviderOptionsWithDiscovery(providerStatuses);
|
|
1558
|
+
if (!providerOptions.length) {
|
|
1559
|
+
display.showWarning('No providers are available.');
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
const lines = [
|
|
1563
|
+
theme.bold('Select a provider:'),
|
|
1564
|
+
...providerOptions.map((option, index) => {
|
|
1565
|
+
const isCurrent = option.provider === this.sessionState.provider;
|
|
1566
|
+
const countLabel = `${option.modelCount} model${option.modelCount === 1 ? '' : 's'}`;
|
|
1567
|
+
const latestLabel = option.latestModel ? theme.success(` (latest: ${option.latestModel})`) : '';
|
|
1568
|
+
const label = this.colorizeDropdownLine(`${index + 1}. ${option.label} — ${countLabel}${latestLabel}`, index);
|
|
1569
|
+
const suffix = isCurrent ? ` ${theme.primary('• current')}` : '';
|
|
1570
|
+
return `${label}${suffix}`;
|
|
1571
|
+
}),
|
|
1572
|
+
'Type the number of the provider to continue, or type "cancel".',
|
|
1573
|
+
];
|
|
1574
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1575
|
+
this.pendingInteraction = { type: 'model-provider', options: providerOptions };
|
|
1576
|
+
}
|
|
1577
|
+
buildProviderOptions() {
|
|
1578
|
+
const counts = new Map();
|
|
1579
|
+
for (const preset of MODEL_PRESETS) {
|
|
1580
|
+
counts.set(preset.provider, (counts.get(preset.provider) ?? 0) + 1);
|
|
1581
|
+
}
|
|
1582
|
+
const orderedProviders = [];
|
|
1583
|
+
const seen = new Set();
|
|
1584
|
+
for (const preset of MODEL_PRESETS) {
|
|
1585
|
+
if (seen.has(preset.provider)) {
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
seen.add(preset.provider);
|
|
1589
|
+
orderedProviders.push(preset.provider);
|
|
1590
|
+
}
|
|
1591
|
+
return orderedProviders.map((provider) => ({
|
|
1592
|
+
provider,
|
|
1593
|
+
label: this.providerLabel(provider),
|
|
1594
|
+
modelCount: counts.get(provider) ?? 0,
|
|
1595
|
+
}));
|
|
1596
|
+
}
|
|
1597
|
+
buildProviderOptionsWithDiscovery(providerStatuses) {
|
|
1598
|
+
// Merge static presets with discovered models
|
|
1599
|
+
const providerData = new Map();
|
|
1600
|
+
// Initialize with static presets
|
|
1601
|
+
for (const preset of MODEL_PRESETS) {
|
|
1602
|
+
const existing = providerData.get(preset.provider);
|
|
1603
|
+
if (existing) {
|
|
1604
|
+
existing.count++;
|
|
1605
|
+
}
|
|
1606
|
+
else {
|
|
1607
|
+
providerData.set(preset.provider, {
|
|
1608
|
+
count: 1,
|
|
1609
|
+
latestModel: '',
|
|
1610
|
+
discoveredModels: [],
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
// Merge in discovered models from API
|
|
1615
|
+
for (const status of providerStatuses) {
|
|
1616
|
+
if (!status.available)
|
|
1617
|
+
continue;
|
|
1618
|
+
const existing = providerData.get(status.provider);
|
|
1619
|
+
if (existing) {
|
|
1620
|
+
existing.latestModel = status.latestModel;
|
|
1621
|
+
}
|
|
1622
|
+
else {
|
|
1623
|
+
providerData.set(status.provider, {
|
|
1624
|
+
count: 1,
|
|
1625
|
+
latestModel: status.latestModel,
|
|
1626
|
+
discoveredModels: [],
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
// Also check cached discovered models for additional models
|
|
1631
|
+
const cachedModels = getCachedDiscoveredModels();
|
|
1632
|
+
for (const model of cachedModels) {
|
|
1633
|
+
const existing = providerData.get(model.provider);
|
|
1634
|
+
if (existing && !existing.discoveredModels.includes(model.id)) {
|
|
1635
|
+
existing.discoveredModels.push(model.id);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
// Build ordered list (same order as static presets)
|
|
1639
|
+
const orderedProviders = [];
|
|
1640
|
+
const seen = new Set();
|
|
1641
|
+
for (const preset of MODEL_PRESETS) {
|
|
1642
|
+
if (!seen.has(preset.provider)) {
|
|
1643
|
+
seen.add(preset.provider);
|
|
1644
|
+
orderedProviders.push(preset.provider);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
// Add any providers that only have discovered models
|
|
1648
|
+
for (const status of providerStatuses) {
|
|
1649
|
+
if (status.available && !seen.has(status.provider)) {
|
|
1650
|
+
seen.add(status.provider);
|
|
1651
|
+
orderedProviders.push(status.provider);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return orderedProviders.map((provider) => {
|
|
1655
|
+
const data = providerData.get(provider);
|
|
1656
|
+
return {
|
|
1657
|
+
provider,
|
|
1658
|
+
label: this.providerLabel(provider),
|
|
1659
|
+
modelCount: data?.count ?? 0,
|
|
1660
|
+
latestModel: data?.latestModel,
|
|
1661
|
+
discoveredModels: data?.discoveredModels ?? [],
|
|
1662
|
+
};
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
showProviderModels(option) {
|
|
1666
|
+
// Start with static presets
|
|
1667
|
+
const staticModels = MODEL_PRESETS.filter((preset) => preset.provider === option.provider);
|
|
1668
|
+
// Build combined list with latest model at top if discovered
|
|
1669
|
+
const allModels = [];
|
|
1670
|
+
const seenIds = new Set();
|
|
1671
|
+
// If we have a latestModel from discovery, add it first if not in static list
|
|
1672
|
+
if (option.latestModel && !staticModels.some(m => m.id === option.latestModel)) {
|
|
1673
|
+
allModels.push({
|
|
1674
|
+
id: option.latestModel,
|
|
1675
|
+
label: option.latestModel,
|
|
1676
|
+
provider: option.provider,
|
|
1677
|
+
description: `Latest ${this.providerLabel(option.provider)} model (auto-discovered)`,
|
|
1678
|
+
});
|
|
1679
|
+
seenIds.add(option.latestModel);
|
|
1680
|
+
}
|
|
1681
|
+
// Add static models
|
|
1682
|
+
for (const model of staticModels) {
|
|
1683
|
+
if (!seenIds.has(model.id)) {
|
|
1684
|
+
allModels.push(model);
|
|
1685
|
+
seenIds.add(model.id);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
// Add any additional discovered models not in static list
|
|
1689
|
+
if (option.discoveredModels) {
|
|
1690
|
+
const sortedDiscovered = sortModelsByPriority(option.provider, option.discoveredModels);
|
|
1691
|
+
for (const modelId of sortedDiscovered) {
|
|
1692
|
+
if (!seenIds.has(modelId)) {
|
|
1693
|
+
allModels.push({
|
|
1694
|
+
id: modelId,
|
|
1695
|
+
label: modelId,
|
|
1696
|
+
provider: option.provider,
|
|
1697
|
+
description: `${this.providerLabel(option.provider)} model (auto-discovered)`,
|
|
1698
|
+
});
|
|
1699
|
+
seenIds.add(modelId);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
if (!allModels.length) {
|
|
1704
|
+
display.showWarning(`No models available for ${option.label}.`);
|
|
1705
|
+
this.pendingInteraction = null;
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
const lines = [
|
|
1709
|
+
theme.bold(`Select a model from ${option.label}:`),
|
|
1710
|
+
...allModels.map((preset, index) => {
|
|
1711
|
+
const isCurrent = preset.id === this.sessionState.model;
|
|
1712
|
+
const isLatest = preset.id === option.latestModel;
|
|
1713
|
+
const latestBadge = isLatest ? theme.success(' ★ LATEST') : '';
|
|
1714
|
+
const label = this.colorizeDropdownLine(`${index + 1}. ${preset.label}${latestBadge}`, index);
|
|
1715
|
+
const suffix = isCurrent ? ` ${theme.primary('• current')}` : '';
|
|
1716
|
+
const description = this.colorizeDropdownLine(` ${preset.description}`, index);
|
|
1717
|
+
return `${label}${suffix}\n${description}`;
|
|
1718
|
+
}),
|
|
1719
|
+
'Type the number of the model to select it, type "back" to change provider, or type "cancel".',
|
|
1720
|
+
];
|
|
1721
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1722
|
+
this.pendingInteraction = { type: 'model', provider: option.provider, options: allModels };
|
|
1723
|
+
}
|
|
1724
|
+
showSecretsMenu() {
|
|
1725
|
+
const definitions = listSecretDefinitions();
|
|
1726
|
+
const lines = [
|
|
1727
|
+
theme.bold('Manage Secrets:'),
|
|
1728
|
+
...definitions.map((definition, index) => {
|
|
1729
|
+
const value = getSecretValue(definition.id);
|
|
1730
|
+
const status = value ? maskSecret(value) : theme.warning('not set');
|
|
1731
|
+
const providers = definition.providers.map((id) => this.providerLabel(id)).join(', ');
|
|
1732
|
+
const label = this.colorizeDropdownLine(`${index + 1}. ${definition.label} (${providers})`, index);
|
|
1733
|
+
return `${label} — ${status}`;
|
|
1734
|
+
}),
|
|
1735
|
+
'Enter the number to update a key, or type "cancel".',
|
|
1736
|
+
];
|
|
1737
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1738
|
+
this.pendingInteraction = { type: 'secret-select', options: definitions };
|
|
1739
|
+
}
|
|
1740
|
+
showToolsMenu() {
|
|
1741
|
+
const options = getToolToggleOptions();
|
|
1742
|
+
if (!options.length) {
|
|
1743
|
+
display.showWarning('No configurable tools are available.');
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
const selection = buildEnabledToolSet(loadToolSettings());
|
|
1747
|
+
const interaction = {
|
|
1748
|
+
type: 'tool-settings',
|
|
1749
|
+
options,
|
|
1750
|
+
selection,
|
|
1751
|
+
initialSelection: new Set(selection),
|
|
1752
|
+
};
|
|
1753
|
+
this.pendingInteraction = interaction;
|
|
1754
|
+
this.renderToolMenu(interaction);
|
|
1755
|
+
}
|
|
1756
|
+
renderToolMenu(interaction) {
|
|
1757
|
+
const lines = [
|
|
1758
|
+
theme.bold('Select which tools are enabled (changes apply on next launch):'),
|
|
1759
|
+
...interaction.options.map((option, index) => this.formatToolOptionLine(option, index, interaction.selection)),
|
|
1760
|
+
'',
|
|
1761
|
+
'Enter the number to toggle, "save" to persist, "defaults" to restore recommended tools, or "cancel".',
|
|
1762
|
+
];
|
|
1763
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1764
|
+
}
|
|
1765
|
+
formatToolOptionLine(option, index, selection) {
|
|
1766
|
+
const enabled = selection.has(option.id);
|
|
1767
|
+
const checkbox = enabled ? theme.primary('[x]') : theme.ui.muted('[ ]');
|
|
1768
|
+
const details = [option.description];
|
|
1769
|
+
if (option.requiresSecret) {
|
|
1770
|
+
const hasSecret = Boolean(getSecretValue(option.requiresSecret));
|
|
1771
|
+
const status = hasSecret ? theme.success('API key set') : theme.warning('API key missing');
|
|
1772
|
+
details.push(status);
|
|
1773
|
+
}
|
|
1774
|
+
const numberLabel = this.colorizeDropdownLine(`${index + 1}.`, index);
|
|
1775
|
+
const optionLabel = this.colorizeDropdownLine(option.label, index);
|
|
1776
|
+
const detailLine = this.colorizeDropdownLine(` ${details.join(' • ')}`, index);
|
|
1777
|
+
return `${numberLabel} ${checkbox} ${optionLabel}\n${detailLine}`;
|
|
1778
|
+
}
|
|
1779
|
+
showAgentsMenu() {
|
|
1780
|
+
if (!this.agentMenu) {
|
|
1781
|
+
display.showWarning('Agent selection is not available in this CLI.');
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
const lines = [
|
|
1785
|
+
theme.bold('Select the default agent profile (changes apply on next launch):'),
|
|
1786
|
+
...this.agentMenu.options.map((option, index) => this.formatAgentOptionLine(option, index)),
|
|
1787
|
+
'',
|
|
1788
|
+
'Enter the number to save it, or type "cancel".',
|
|
1789
|
+
];
|
|
1790
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1791
|
+
this.pendingInteraction = { type: 'agent-selection', options: this.agentMenu.options };
|
|
1792
|
+
}
|
|
1793
|
+
formatAgentOptionLine(option, index) {
|
|
1794
|
+
const numberLabel = this.colorizeDropdownLine(`${index + 1}. ${option.label}`, index);
|
|
1795
|
+
if (!this.agentMenu) {
|
|
1796
|
+
return numberLabel;
|
|
1797
|
+
}
|
|
1798
|
+
const badges = [];
|
|
1799
|
+
const nextProfile = this.agentMenu.persistedProfile ?? this.agentMenu.defaultProfile;
|
|
1800
|
+
if (option.name === nextProfile) {
|
|
1801
|
+
badges.push(theme.primary('next launch'));
|
|
1802
|
+
}
|
|
1803
|
+
if (option.name === this.profile) {
|
|
1804
|
+
badges.push(theme.success('current session'));
|
|
1805
|
+
}
|
|
1806
|
+
const badgeSuffix = badges.length ? ` ${badges.join(' • ')}` : '';
|
|
1807
|
+
const rows = [
|
|
1808
|
+
`${numberLabel}${badgeSuffix}`,
|
|
1809
|
+
` ${this.providerLabel(option.defaultProvider)} • ${option.defaultModel}`,
|
|
1810
|
+
];
|
|
1811
|
+
if (option.description?.trim()) {
|
|
1812
|
+
rows.push(` ${option.description.trim()}`);
|
|
1813
|
+
}
|
|
1814
|
+
return rows.join('\n');
|
|
1815
|
+
}
|
|
1816
|
+
async handleModelProviderSelection(input) {
|
|
1817
|
+
const pending = this.pendingInteraction;
|
|
1818
|
+
if (!pending || pending.type !== 'model-provider') {
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
const trimmed = input.trim();
|
|
1822
|
+
if (!trimmed) {
|
|
1823
|
+
display.showWarning('Enter a number or type cancel.');
|
|
1824
|
+
this.terminalInput.render();
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (trimmed.toLowerCase() === 'cancel') {
|
|
1828
|
+
this.pendingInteraction = null;
|
|
1829
|
+
display.showInfo('Model selection cancelled.');
|
|
1830
|
+
this.terminalInput.render();
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
const choice = Number.parseInt(trimmed, 10);
|
|
1834
|
+
if (!Number.isFinite(choice)) {
|
|
1835
|
+
display.showWarning('Please enter a valid number.');
|
|
1836
|
+
this.terminalInput.render();
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
const option = pending.options[choice - 1];
|
|
1840
|
+
if (!option) {
|
|
1841
|
+
display.showWarning('That option is not available.');
|
|
1842
|
+
this.terminalInput.render();
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
this.showProviderModels(option);
|
|
1846
|
+
this.terminalInput.render();
|
|
1847
|
+
}
|
|
1848
|
+
async handleModelSelection(input) {
|
|
1849
|
+
const pending = this.pendingInteraction;
|
|
1850
|
+
if (!pending || pending.type !== 'model') {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
const trimmed = input.trim();
|
|
1854
|
+
if (!trimmed) {
|
|
1855
|
+
display.showWarning('Enter a number, type "back", or type "cancel".');
|
|
1856
|
+
this.terminalInput.render();
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
if (trimmed.toLowerCase() === 'back') {
|
|
1860
|
+
this.showModelMenu();
|
|
1861
|
+
this.terminalInput.render();
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
if (trimmed.toLowerCase() === 'cancel') {
|
|
1865
|
+
this.pendingInteraction = null;
|
|
1866
|
+
display.showInfo('Model selection cancelled.');
|
|
1867
|
+
this.terminalInput.render();
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
const choice = Number.parseInt(trimmed, 10);
|
|
1871
|
+
if (!Number.isFinite(choice)) {
|
|
1872
|
+
display.showWarning('Please enter a valid number.');
|
|
1873
|
+
this.terminalInput.render();
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
const preset = pending.options[choice - 1];
|
|
1877
|
+
if (!preset) {
|
|
1878
|
+
display.showWarning('That option is not available.');
|
|
1879
|
+
this.terminalInput.render();
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
this.pendingInteraction = null;
|
|
1883
|
+
await this.applyModelPreset(preset);
|
|
1884
|
+
this.terminalInput.render();
|
|
1885
|
+
}
|
|
1886
|
+
async applyModelPreset(preset) {
|
|
1887
|
+
try {
|
|
1888
|
+
ensureSecretForProvider(preset.provider);
|
|
1889
|
+
}
|
|
1890
|
+
catch (error) {
|
|
1891
|
+
this.handleAgentSetupError(error, () => this.applyModelPreset(preset), preset.provider);
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
this.sessionState = {
|
|
1895
|
+
provider: preset.provider,
|
|
1896
|
+
model: preset.id,
|
|
1897
|
+
temperature: preset.temperature,
|
|
1898
|
+
maxTokens: preset.maxTokens,
|
|
1899
|
+
reasoningEffort: preset.reasoningEffort,
|
|
1900
|
+
};
|
|
1901
|
+
this.applyPresetReasoningDefaults();
|
|
1902
|
+
if (this.rebuildAgent()) {
|
|
1903
|
+
display.showInfo(`Switched to ${preset.label}.`);
|
|
1904
|
+
this.refreshBannerSessionInfo();
|
|
1905
|
+
this.persistSessionPreference();
|
|
1906
|
+
this.resetChatBoxAfterModelSwap();
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
async handleSecretSelection(input) {
|
|
1910
|
+
const pending = this.pendingInteraction;
|
|
1911
|
+
if (!pending || pending.type !== 'secret-select') {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
const trimmed = input.trim();
|
|
1915
|
+
if (!trimmed) {
|
|
1916
|
+
display.showWarning('Enter a number or type cancel.');
|
|
1917
|
+
this.terminalInput.render();
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
if (trimmed.toLowerCase() === 'cancel') {
|
|
1921
|
+
this.pendingInteraction = null;
|
|
1922
|
+
display.showInfo('Secret management cancelled.');
|
|
1923
|
+
this.terminalInput.render();
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
const choice = Number.parseInt(trimmed, 10);
|
|
1927
|
+
if (!Number.isFinite(choice)) {
|
|
1928
|
+
display.showWarning('Please enter a valid number.');
|
|
1929
|
+
this.terminalInput.render();
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
const secret = pending.options[choice - 1];
|
|
1933
|
+
if (!secret) {
|
|
1934
|
+
display.showWarning('That option is not available.');
|
|
1935
|
+
this.terminalInput.render();
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
display.showSystemMessage(`Enter a new value for ${secret.label} or type "cancel".`);
|
|
1939
|
+
this.pendingInteraction = { type: 'secret-input', secret };
|
|
1940
|
+
this.terminalInput.render();
|
|
1941
|
+
}
|
|
1942
|
+
async handleSecretInput(input) {
|
|
1943
|
+
const pending = this.pendingInteraction;
|
|
1944
|
+
if (!pending || pending.type !== 'secret-input') {
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
const trimmed = input.trim();
|
|
1948
|
+
if (!trimmed) {
|
|
1949
|
+
display.showWarning('Enter a value or type cancel.');
|
|
1950
|
+
this.terminalInput.render();
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (trimmed.toLowerCase() === 'cancel') {
|
|
1954
|
+
this.pendingInteraction = null;
|
|
1955
|
+
this.pendingSecretRetry = null;
|
|
1956
|
+
display.showInfo('Secret unchanged.');
|
|
1957
|
+
this.terminalInput.render();
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
try {
|
|
1961
|
+
setSecretValue(pending.secret.id, trimmed);
|
|
1962
|
+
display.showInfo(`${pending.secret.label} updated.`);
|
|
1963
|
+
this.pendingInteraction = null;
|
|
1964
|
+
const deferred = this.pendingSecretRetry;
|
|
1965
|
+
this.pendingSecretRetry = null;
|
|
1966
|
+
if (pending.secret.providers.includes(this.sessionState.provider)) {
|
|
1967
|
+
if (this.rebuildAgent()) {
|
|
1968
|
+
this.resetChatBoxAfterModelSwap();
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (deferred) {
|
|
1972
|
+
await deferred();
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
catch (error) {
|
|
1976
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1977
|
+
display.showError(message);
|
|
1978
|
+
this.pendingInteraction = null;
|
|
1979
|
+
this.pendingSecretRetry = null;
|
|
1980
|
+
}
|
|
1981
|
+
this.terminalInput.render();
|
|
1982
|
+
}
|
|
1983
|
+
async processRequest(request) {
|
|
1984
|
+
if (this.isProcessing) {
|
|
1985
|
+
this.enqueueFollowUpAction({ type: 'request', text: request });
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (!this.agent && !this.rebuildAgent()) {
|
|
1989
|
+
display.showWarning('Configure an API key via /secrets before sending requests.');
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
const agent = this.agent;
|
|
1993
|
+
if (!agent) {
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
this.isProcessing = true;
|
|
1997
|
+
this.terminalInput.setStreaming(true);
|
|
1998
|
+
const requestStartTime = Date.now(); // Alpha Zero 2 timing
|
|
1999
|
+
this.uiAdapter.startProcessing('Working on your request');
|
|
2000
|
+
this.setProcessingStatus();
|
|
2001
|
+
let responseText = '';
|
|
2002
|
+
try {
|
|
2003
|
+
// Add visual separator between user prompt and AI response
|
|
2004
|
+
display.newLine();
|
|
2005
|
+
// Claude Code style: Show unified streaming header before response
|
|
2006
|
+
// This provides visual consistency with the startup Ready bar
|
|
2007
|
+
display.showStreamingHeader();
|
|
2008
|
+
this.startStreamingHeartbeat('Streaming response');
|
|
2009
|
+
display.showThinking('Responding...');
|
|
2010
|
+
// Stream responses so users immediately see progress like Claude Code
|
|
2011
|
+
responseText = await agent.send(request, true);
|
|
2012
|
+
await this.awaitPendingCleanup();
|
|
2013
|
+
this.captureHistorySnapshot();
|
|
2014
|
+
this.autosaveIfEnabled();
|
|
2015
|
+
// Track metrics with Alpha Zero 2
|
|
2016
|
+
const elapsedMs = Date.now() - requestStartTime;
|
|
2017
|
+
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
2018
|
+
if (!responseText?.trim()) {
|
|
2019
|
+
display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
catch (error) {
|
|
2023
|
+
const handled = this.handleProviderError(error, () => this.processRequest(request));
|
|
2024
|
+
if (!handled) {
|
|
2025
|
+
// Pass full error object for enhanced formatting with stack trace
|
|
2026
|
+
display.showError(error instanceof Error ? error.message : String(error), error);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
finally {
|
|
2030
|
+
display.stopThinking(false);
|
|
2031
|
+
this.stopStreamingHeartbeat();
|
|
2032
|
+
this.isProcessing = false;
|
|
2033
|
+
this.terminalInput.setStreaming(false);
|
|
2034
|
+
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2035
|
+
this.setIdleStatus();
|
|
2036
|
+
display.newLine();
|
|
2037
|
+
this.updateStatusMessage(null);
|
|
2038
|
+
// Claude Code style: Show unified status bar before prompt
|
|
2039
|
+
// This creates consistent UI between startup and post-streaming
|
|
2040
|
+
this.showUnifiedStatusBar();
|
|
2041
|
+
// CRITICAL: Ensure readline prompt is active for user input
|
|
2042
|
+
// Claude Code style: New prompt naturally appears at bottom
|
|
2043
|
+
this.ensureReadlineReady();
|
|
2044
|
+
this.terminalInput.render();
|
|
2045
|
+
this.scheduleQueueProcessing();
|
|
2046
|
+
this.refreshQueueIndicators();
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
/**
|
|
2050
|
+
* Process a continuous/infinite loop request.
|
|
2051
|
+
* Runs the agent in a loop until:
|
|
2052
|
+
* 1. The agent indicates completion (verified by AI confirmation)
|
|
2053
|
+
* 2. User interrupts (Ctrl+C)
|
|
2054
|
+
* 3. Maximum iterations reached (safety limit)
|
|
2055
|
+
*
|
|
2056
|
+
* Uses intelligent task completion detection with AI verification
|
|
2057
|
+
* to ensure tasks are truly complete before stopping.
|
|
2058
|
+
*
|
|
2059
|
+
* Context is automatically managed - overflow errors trigger auto-recovery.
|
|
2060
|
+
*/
|
|
2061
|
+
async processContinuousRequest(initialRequest) {
|
|
2062
|
+
const MAX_ITERATIONS = 100; // Safety limit to prevent truly infinite loops
|
|
2063
|
+
if (this.isProcessing) {
|
|
2064
|
+
this.enqueueFollowUpAction({ type: 'continuous', text: initialRequest });
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
if (!this.agent && !this.rebuildAgent()) {
|
|
2068
|
+
display.showWarning('Configure an API key via /secrets before sending requests.');
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const agent = this.agent;
|
|
2072
|
+
if (!agent) {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
this.isProcessing = true;
|
|
2076
|
+
this.terminalInput.setStreaming(true);
|
|
2077
|
+
const overallStartTime = Date.now();
|
|
2078
|
+
// Initialize the task completion detector
|
|
2079
|
+
const completionDetector = getTaskCompletionDetector();
|
|
2080
|
+
completionDetector.reset();
|
|
2081
|
+
display.showSystemMessage(`🔄 Starting continuous execution mode. Press Ctrl+C to stop.`);
|
|
2082
|
+
display.showSystemMessage(`📊 Using intelligent task completion detection with AI verification.`);
|
|
2083
|
+
this.uiAdapter.startProcessing('Continuous execution mode');
|
|
2084
|
+
this.setProcessingStatus();
|
|
2085
|
+
// Claude Code style: Show unified streaming header before response
|
|
2086
|
+
display.showStreamingHeader();
|
|
2087
|
+
this.startStreamingHeartbeat('Continuous streaming');
|
|
2088
|
+
let iteration = 0;
|
|
2089
|
+
let lastResponse = '';
|
|
2090
|
+
let consecutiveNoProgress = 0;
|
|
2091
|
+
const MAX_NO_PROGRESS = 5; // Increased to allow more attempts before giving up
|
|
2092
|
+
let pendingVerification = false;
|
|
2093
|
+
let verificationAttempts = 0;
|
|
2094
|
+
const MAX_VERIFICATION_ATTEMPTS = 2;
|
|
2095
|
+
try {
|
|
2096
|
+
// Enhance initial prompt with git context for self-improvement tasks
|
|
2097
|
+
let currentPrompt = initialRequest;
|
|
2098
|
+
if (this.isSelfImprovementRequest(initialRequest)) {
|
|
2099
|
+
currentPrompt = `${initialRequest}
|
|
2100
|
+
|
|
2101
|
+
IMPORTANT: You have full git access. After making improvements:
|
|
2102
|
+
1. Use bash to run: git status (see changes)
|
|
2103
|
+
2. Use bash to run: git add -A (stage changes)
|
|
2104
|
+
3. Use bash to run: git commit -m "descriptive message" (commit)
|
|
2105
|
+
4. Use bash to run: git push (when milestone reached)
|
|
2106
|
+
|
|
2107
|
+
Commit frequently with descriptive messages. Push when ready.
|
|
2108
|
+
When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
2109
|
+
}
|
|
2110
|
+
while (iteration < MAX_ITERATIONS) {
|
|
2111
|
+
iteration++;
|
|
2112
|
+
display.showSystemMessage(`\n📍 Iteration ${iteration}/${MAX_ITERATIONS}`);
|
|
2113
|
+
this.updateStatusMessage(`Working on iteration ${iteration}...`);
|
|
2114
|
+
try {
|
|
2115
|
+
// Send the request and capture the response (streaming disabled)
|
|
2116
|
+
display.showThinking('Responding...');
|
|
2117
|
+
const response = await agent.send(currentPrompt, true);
|
|
2118
|
+
await this.awaitPendingCleanup();
|
|
2119
|
+
this.captureHistorySnapshot();
|
|
2120
|
+
this.autosaveIfEnabled();
|
|
2121
|
+
// Track metrics
|
|
2122
|
+
const elapsedMs = Date.now() - overallStartTime;
|
|
2123
|
+
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
2124
|
+
if (!response?.trim()) {
|
|
2125
|
+
display.showWarning('Model returned an empty response. Retrying this iteration...');
|
|
2126
|
+
consecutiveNoProgress++;
|
|
2127
|
+
currentPrompt = `${initialRequest}
|
|
2128
|
+
|
|
2129
|
+
The previous reply was empty. Resume the task now: take the next action, call the necessary tools, and report progress.`;
|
|
2130
|
+
continue;
|
|
2131
|
+
}
|
|
2132
|
+
// Extract tools used from the response (look for tool call patterns)
|
|
2133
|
+
const toolsUsed = this.extractToolsFromResponse(response);
|
|
2134
|
+
completionDetector.recordToolCall.bind(completionDetector);
|
|
2135
|
+
toolsUsed.forEach(tool => completionDetector.recordToolCall(tool, true, true));
|
|
2136
|
+
// Use intelligent completion detection
|
|
2137
|
+
const completionAnalysis = completionDetector.analyzeCompletion(response, toolsUsed);
|
|
2138
|
+
display.showSystemMessage(`📈 Completion confidence: ${(completionAnalysis.confidence * 100).toFixed(0)}%`);
|
|
2139
|
+
// Check for explicit TASK_FULLY_COMPLETE marker (highest priority)
|
|
2140
|
+
// BUT: Don't terminate if the response also indicates work is incomplete
|
|
2141
|
+
if (response.includes('TASK_FULLY_COMPLETE')) {
|
|
2142
|
+
const hasContradiction = this.responseIndicatesIncompleteWork(response);
|
|
2143
|
+
if (hasContradiction) {
|
|
2144
|
+
display.showSystemMessage(`\n⚠️ TASK_FULLY_COMPLETE detected but response indicates incomplete work. Continuing...`);
|
|
2145
|
+
// Override the completion signal - the AI is contradicting itself
|
|
2146
|
+
currentPrompt = `You marked the task as TASK_FULLY_COMPLETE but also indicated that work is still pending or not integrated. Please clarify:
|
|
2147
|
+
|
|
2148
|
+
1. Is ALL the originally requested work actually complete and functional?
|
|
2149
|
+
2. If there are parts that are "ready but not integrated" or "implemented but not connected", those are NOT complete.
|
|
2150
|
+
3. Only say TASK_FULLY_COMPLETE when the user's original request is 100% fulfilled.
|
|
2151
|
+
|
|
2152
|
+
What remains to be done? Continue with the next step.`;
|
|
2153
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
display.showSystemMessage(`\n✅ Task explicitly marked complete after ${iteration} iteration(s).`);
|
|
2157
|
+
break;
|
|
2158
|
+
}
|
|
2159
|
+
// High confidence completion without verification needed
|
|
2160
|
+
if (completionAnalysis.isComplete && completionAnalysis.confidence >= 0.85) {
|
|
2161
|
+
display.showSystemMessage(`\n✅ Task completed with high confidence after ${iteration} iteration(s).`);
|
|
2162
|
+
display.showSystemMessage(` Reason: ${completionAnalysis.reason}`);
|
|
2163
|
+
break;
|
|
2164
|
+
}
|
|
2165
|
+
// Medium confidence - run verification round
|
|
2166
|
+
if (completionAnalysis.shouldVerify && completionAnalysis.verificationPrompt && !pendingVerification) {
|
|
2167
|
+
if (verificationAttempts < MAX_VERIFICATION_ATTEMPTS) {
|
|
2168
|
+
display.showSystemMessage(`\n🔍 Running verification round (confidence: ${(completionAnalysis.confidence * 100).toFixed(0)}%)...`);
|
|
2169
|
+
pendingVerification = true;
|
|
2170
|
+
verificationAttempts++;
|
|
2171
|
+
currentPrompt = completionAnalysis.verificationPrompt;
|
|
2172
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
// If we were in verification mode, check the result
|
|
2177
|
+
if (pendingVerification) {
|
|
2178
|
+
pendingVerification = false;
|
|
2179
|
+
if (completionDetector.isVerificationConfirmed(response)) {
|
|
2180
|
+
display.showSystemMessage(`\n✅ Task completion verified by AI after ${iteration} iteration(s).`);
|
|
2181
|
+
break;
|
|
2182
|
+
}
|
|
2183
|
+
else {
|
|
2184
|
+
display.showSystemMessage(`🔄 Verification indicates more work needed. Continuing...`);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
// Check for no progress (same response multiple times)
|
|
2188
|
+
const responseChanged = response !== lastResponse;
|
|
2189
|
+
if (!responseChanged) {
|
|
2190
|
+
consecutiveNoProgress++;
|
|
2191
|
+
if (consecutiveNoProgress >= MAX_NO_PROGRESS) {
|
|
2192
|
+
// Before giving up, ask one final verification
|
|
2193
|
+
if (verificationAttempts < MAX_VERIFICATION_ATTEMPTS) {
|
|
2194
|
+
display.showSystemMessage(`\n⚠️ No progress for ${MAX_NO_PROGRESS} iterations. Running final verification...`);
|
|
2195
|
+
currentPrompt = `I notice you may be stuck or finished. Please confirm:
|
|
2196
|
+
|
|
2197
|
+
1. Is the original task FULLY complete?
|
|
2198
|
+
2. If yes, respond with exactly: "TASK_FULLY_COMPLETE"
|
|
2199
|
+
3. If no, what specific action should be taken next?
|
|
2200
|
+
|
|
2201
|
+
Be explicit about the current state.`;
|
|
2202
|
+
verificationAttempts++;
|
|
2203
|
+
consecutiveNoProgress = 0;
|
|
2204
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
display.showSystemMessage(`\n⚠️ No progress detected for ${MAX_NO_PROGRESS} iterations and verification exhausted. Stopping.`);
|
|
2208
|
+
break;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
else {
|
|
2212
|
+
consecutiveNoProgress = 0;
|
|
2213
|
+
}
|
|
2214
|
+
lastResponse = response;
|
|
2215
|
+
// Prepare next iteration prompt - explicitly encourage progress reporting
|
|
2216
|
+
currentPrompt = `Continue with the next step. Remember:
|
|
2217
|
+
- Use bash to run git commands (git status, git add, git commit, git push)
|
|
2218
|
+
- Commit your changes with descriptive messages after completing improvements
|
|
2219
|
+
- Push changes when a logical milestone is reached
|
|
2220
|
+
- If all tasks are complete, respond with exactly: "TASK_FULLY_COMPLETE"
|
|
2221
|
+
- If there are errors or blockers, explain what's preventing progress
|
|
2222
|
+
|
|
2223
|
+
What's the next action?`;
|
|
2224
|
+
// Small delay between iterations to prevent rate limiting
|
|
2225
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
2226
|
+
}
|
|
2227
|
+
catch (error) {
|
|
2228
|
+
display.stopThinking(false);
|
|
2229
|
+
// Handle context overflow specially - the agent should auto-recover
|
|
2230
|
+
// but if it propagates here, we continue the loop
|
|
2231
|
+
if (this.isContextOverflowError(error)) {
|
|
2232
|
+
display.showSystemMessage(`⚡ Context overflow handled. Continuing with reduced context...`);
|
|
2233
|
+
// The agent.ts should have already handled recovery
|
|
2234
|
+
// Continue to next iteration
|
|
2235
|
+
continue;
|
|
2236
|
+
}
|
|
2237
|
+
// For other errors, check if handled by provider error handler
|
|
2238
|
+
const handled = this.handleProviderError(error, () => this.processContinuousRequest(initialRequest));
|
|
2239
|
+
if (!handled) {
|
|
2240
|
+
display.showError(error instanceof Error ? error.message : String(error), error);
|
|
2241
|
+
break;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
if (iteration >= MAX_ITERATIONS) {
|
|
2246
|
+
display.showWarning(`\n⚠️ Reached maximum iterations (${MAX_ITERATIONS}). Stopping to prevent infinite loop.`);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
finally {
|
|
2250
|
+
const totalElapsed = Date.now() - overallStartTime;
|
|
2251
|
+
const minutes = Math.floor(totalElapsed / 60000);
|
|
2252
|
+
const seconds = Math.floor((totalElapsed % 60000) / 1000);
|
|
2253
|
+
display.showSystemMessage(`\n🏁 Continuous execution completed: ${iteration} iterations, ${minutes}m ${seconds}s total`);
|
|
2254
|
+
// Reset completion detector for next task
|
|
2255
|
+
resetTaskCompletionDetector();
|
|
2256
|
+
this.isProcessing = false;
|
|
2257
|
+
this.terminalInput.setStreaming(false);
|
|
2258
|
+
this.updateStatusMessage(null);
|
|
2259
|
+
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2260
|
+
this.setIdleStatus();
|
|
2261
|
+
this.stopStreamingHeartbeat();
|
|
2262
|
+
display.newLine();
|
|
2263
|
+
// Claude Code style: Show unified status bar before prompt
|
|
2264
|
+
// This creates consistent UI between startup and post-streaming
|
|
2265
|
+
this.showUnifiedStatusBar();
|
|
2266
|
+
// CRITICAL: Ensure readline prompt is active for user input
|
|
2267
|
+
// Claude Code style: New prompt naturally appears at bottom
|
|
2268
|
+
this.ensureReadlineReady();
|
|
2269
|
+
this.scheduleQueueProcessing();
|
|
2270
|
+
this.refreshQueueIndicators();
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Check if a response contains indicators that work is actually incomplete,
|
|
2275
|
+
* even if it also contains TASK_FULLY_COMPLETE marker.
|
|
2276
|
+
* This catches contradictory responses where the AI says "done" but also "not integrated yet".
|
|
2277
|
+
*/
|
|
2278
|
+
responseIndicatesIncompleteWork(response) {
|
|
2279
|
+
// Patterns that indicate work isn't actually complete
|
|
2280
|
+
// Organized by category for maintainability
|
|
2281
|
+
const incompletePatterns = [
|
|
2282
|
+
// === INTEGRATION/DEPLOYMENT STATE ===
|
|
2283
|
+
// "hasn't been integrated/implemented/connected yet"
|
|
2284
|
+
/hasn'?t\s+been\s+(integrated|implemented|connected|deployed|added|completed|tested|verified)\s*(yet|still)?/i,
|
|
2285
|
+
// "not yet integrated/implemented" or "not integrated"
|
|
2286
|
+
/not\s+(yet\s+)?(integrated|implemented|connected|deployed|functional|working|complete|tested|verified)/i,
|
|
2287
|
+
// "ready for integration" = NOT integrated
|
|
2288
|
+
/ready\s+(for|to\s+be)\s+(integration|integrated|connected|deployed|testing|review)/i,
|
|
2289
|
+
// "needs to be integrated"
|
|
2290
|
+
/needs?\s+to\s+be\s+(integrated|connected|deployed|added|hooked|wired|tested|reviewed|merged)/i,
|
|
2291
|
+
// Passive voice: "was not performed/completed"
|
|
2292
|
+
/was\s+not\s+(performed|completed|implemented|deployed|integrated|tested)/i,
|
|
2293
|
+
// "the [X] service hasn't been"
|
|
2294
|
+
/the\s+\w+\s+(service|module|component|feature)\s+hasn'?t\s+been/i,
|
|
2295
|
+
// === PARTIAL/INCOMPLETE STATE ===
|
|
2296
|
+
// "still stores/uses/has" (current bad state persists)
|
|
2297
|
+
/still\s+(stores?|uses?|has|contains?|needs?|requires?|missing|lacks?|broken)/i,
|
|
2298
|
+
// Partial completion: "partially", "mostly", "almost"
|
|
2299
|
+
/\b(partially|mostly|almost|nearly|not\s+fully)\s+(complete|done|finished|implemented|working)/i,
|
|
2300
|
+
// Explicit partial: "part of", "some of", "half of"
|
|
2301
|
+
/\b(only\s+)?(part|some|half|portion)\s+of\s+(the\s+)?(task|work|feature|implementation)/i,
|
|
2302
|
+
// === QUALIFIER WORDS (uncertain completion) ===
|
|
2303
|
+
// "should be complete", "appears complete", "theoretically"
|
|
2304
|
+
/\b(should|might|may|could|appears?\s+to)\s+be\s+(complete|done|working|functional)/i,
|
|
2305
|
+
/\btheoretically\s+(complete|done|working|functional)/i,
|
|
2306
|
+
// "assuming", "if everything works"
|
|
2307
|
+
/\b(assuming|provided|if)\s+(everything|it|this|that)\s+(works?|is\s+correct)/i,
|
|
2308
|
+
// === SELF-CONTRADICTION PHRASES ===
|
|
2309
|
+
// "done but...", "complete except...", "finished however..."
|
|
2310
|
+
/\b(done|complete|finished)\s+(but|except|however|although|though)/i,
|
|
2311
|
+
// "however" followed by incomplete indicator
|
|
2312
|
+
/however[,\s].{0,50}?(hasn'?t|not\s+yet|still\s+needs?|pending|remains?|missing|broken|failing)/i,
|
|
2313
|
+
// "but" followed by negative state
|
|
2314
|
+
/\bbut\s+.{0,30}?(not|hasn'?t|won'?t|can'?t|doesn'?t|isn'?t|wasn'?t)/i,
|
|
2315
|
+
// === FUTURE TENSE / DEFERRED WORK ===
|
|
2316
|
+
// "will need to", "will require"
|
|
2317
|
+
/will\s+(need\s+to|require|have\s+to)\s+(integrate|connect|deploy|complete|implement|test|fix)/i,
|
|
2318
|
+
// Deferred: "left as", "deferred", "postponed", "out of scope"
|
|
2319
|
+
/\b(left\s+as|deferred|postponed|out\s+of\s+scope|for\s+later|in\s+a\s+future)/i,
|
|
2320
|
+
// Time-dependent: "after restart", "takes effect after", "once you"
|
|
2321
|
+
/\b(after\s+(restart|reboot|redeploy)|takes?\s+effect\s+after|once\s+you)/i,
|
|
2322
|
+
// === REMAINING WORK INDICATORS ===
|
|
2323
|
+
// "remaining tasks", "outstanding items"
|
|
2324
|
+
/\b(remaining|outstanding|pending|leftover)\s+(tasks?|items?|work|issues?|steps?)/i,
|
|
2325
|
+
// "X more to do", "still have to"
|
|
2326
|
+
/\b(more\s+to\s+do|still\s+have\s+to|yet\s+to\s+be\s+done)/i,
|
|
2327
|
+
// Explicit blockers
|
|
2328
|
+
/\b(blocker|blocked\s+by|waiting\s+(for|on)|depends?\s+on)/i,
|
|
2329
|
+
// === ERROR/FAILURE STATE ===
|
|
2330
|
+
// "failing tests", "build errors"
|
|
2331
|
+
/\b(failing|broken|erroring)\s+(tests?|builds?|checks?|validations?)/i,
|
|
2332
|
+
// "tests? (are )?(still )?failing"
|
|
2333
|
+
/\btests?\s+(are\s+)?(still\s+)?failing/i,
|
|
2334
|
+
// "errors? to (address|fix)"
|
|
2335
|
+
/\b(errors?|warnings?|issues?)\s+to\s+(address|fix|resolve)/i,
|
|
2336
|
+
// "doesn't work", "isn't working", "not working"
|
|
2337
|
+
/\b(doesn'?t|isn'?t|not)\s+(work|working|functional|functioning)/i,
|
|
2338
|
+
// === MANUAL STEPS REQUIRED ===
|
|
2339
|
+
// "you'll need to", "manually run", "requires user"
|
|
2340
|
+
/\b(you('ll|\s+will)\s+need\s+to|manually\s+(run|configure|set|update)|requires?\s+user)/i,
|
|
2341
|
+
// "run this command", "execute the following"
|
|
2342
|
+
/\b(run\s+this|execute\s+the\s+following|apply\s+the\s+migration)/i,
|
|
2343
|
+
// === TODO/FIXME IN PROSE ===
|
|
2344
|
+
// TODO or FIXME mentioned as remaining work (not in code blocks)
|
|
2345
|
+
/\b(todo|fixme|hack|xxx):\s/i,
|
|
2346
|
+
// "need to add", "should implement"
|
|
2347
|
+
/\b(need\s+to|should|must)\s+(add|implement|create|write|build|fix)\b/i,
|
|
2348
|
+
// === SCOPE LIMITATIONS ===
|
|
2349
|
+
// "didn't have time", "ran out of time"
|
|
2350
|
+
/\b(didn'?t|did\s+not)\s+have\s+(time|chance|opportunity)/i,
|
|
2351
|
+
// "beyond scope", "outside scope"
|
|
2352
|
+
/\b(beyond|outside)\s+(the\s+)?scope/i,
|
|
2353
|
+
// "for now" (temporary state)
|
|
2354
|
+
/\b(for\s+now|at\s+this\s+point|currently)\s*.{0,20}?(not|without|lacks?|missing)/i,
|
|
2355
|
+
];
|
|
2356
|
+
for (const pattern of incompletePatterns) {
|
|
2357
|
+
if (pattern.test(response)) {
|
|
2358
|
+
return true;
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
return false;
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Extract tool names from a response by looking for tool call patterns
|
|
2365
|
+
*/
|
|
2366
|
+
extractToolsFromResponse(response) {
|
|
2367
|
+
const tools = [];
|
|
2368
|
+
// Look for common tool call patterns in the response
|
|
2369
|
+
const toolPatterns = [
|
|
2370
|
+
/(?:running|executing|called?|using)\s+(?:the\s+)?(\w+(?:_\w+)*)\s+tool/gi,
|
|
2371
|
+
/tool[:\s]+(\w+(?:_\w+)*)/gi,
|
|
2372
|
+
/⎿\s*(\w+)/g, // Tool result prefix pattern
|
|
2373
|
+
/(?:read_file|edit_file|Edit|bash|grep|glob|search)/gi,
|
|
2374
|
+
];
|
|
2375
|
+
for (const pattern of toolPatterns) {
|
|
2376
|
+
let match;
|
|
2377
|
+
while ((match = pattern.exec(response)) !== null) {
|
|
2378
|
+
const toolName = match[1] || match[0];
|
|
2379
|
+
if (toolName && !tools.includes(toolName.toLowerCase())) {
|
|
2380
|
+
tools.push(toolName.toLowerCase());
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
return tools;
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Check if an error is a context overflow error
|
|
2388
|
+
*/
|
|
2389
|
+
isContextOverflowError(error) {
|
|
2390
|
+
if (!(error instanceof Error))
|
|
2391
|
+
return false;
|
|
2392
|
+
const message = error.message.toLowerCase();
|
|
2393
|
+
return (message.includes('context length') ||
|
|
2394
|
+
(message.includes('token') && (message.includes('limit') || message.includes('exceed') || message.includes('maximum'))) ||
|
|
2395
|
+
message.includes('too long') ||
|
|
2396
|
+
message.includes('too many tokens') ||
|
|
2397
|
+
message.includes('max_tokens') ||
|
|
2398
|
+
message.includes('context window'));
|
|
2399
|
+
}
|
|
2400
|
+
async awaitPendingCleanup() {
|
|
2401
|
+
if (!this.pendingCleanup) {
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
let timeoutId = null;
|
|
2405
|
+
try {
|
|
2406
|
+
// Add timeout to prevent indefinite hangs (10 second max wait)
|
|
2407
|
+
const CLEANUP_TIMEOUT_MS = 10000;
|
|
2408
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2409
|
+
timeoutId = setTimeout(() => reject(new Error('Cleanup timed out')), CLEANUP_TIMEOUT_MS);
|
|
2410
|
+
});
|
|
2411
|
+
await Promise.race([this.pendingCleanup, timeoutPromise]);
|
|
2412
|
+
}
|
|
2413
|
+
catch (error) {
|
|
2414
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2415
|
+
display.showWarning(`Context cleanup failed: ${message}`);
|
|
2416
|
+
}
|
|
2417
|
+
finally {
|
|
2418
|
+
// Clear timeout to prevent leaking timers
|
|
2419
|
+
if (timeoutId) {
|
|
2420
|
+
clearTimeout(timeoutId);
|
|
2421
|
+
}
|
|
2422
|
+
this.pendingCleanup = null;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
getLatestFileChangeTimestamp() {
|
|
2426
|
+
const changes = this._fileChangeTracker.getAllChanges();
|
|
2427
|
+
if (!changes.length) {
|
|
2428
|
+
return null;
|
|
2429
|
+
}
|
|
2430
|
+
let latest = 0;
|
|
2431
|
+
for (const change of changes) {
|
|
2432
|
+
latest = Math.max(latest, change.timestamp);
|
|
2433
|
+
}
|
|
2434
|
+
return latest || null;
|
|
2435
|
+
}
|
|
2436
|
+
isTestToolCall(entry) {
|
|
2437
|
+
const name = entry.toolName.toLowerCase();
|
|
2438
|
+
if (name === 'run_tests' || name === 'run_repo_checks' || name === 'run_build') {
|
|
2439
|
+
return true;
|
|
2440
|
+
}
|
|
2441
|
+
if (name === 'bash' || name === 'execute_bash') {
|
|
2442
|
+
const command = String(entry.args['command'] ?? '').toLowerCase();
|
|
2443
|
+
return command.includes('npm test') || command.includes('yarn test') || command.includes('pnpm test');
|
|
2444
|
+
}
|
|
2445
|
+
return false;
|
|
2446
|
+
}
|
|
2447
|
+
getLatestTestTimestamp() {
|
|
2448
|
+
const history = this.runtimeSession.toolRuntime.getToolHistory?.() ?? [];
|
|
2449
|
+
let latest = this.lastAutoTestRun;
|
|
2450
|
+
for (const entry of history) {
|
|
2451
|
+
if (this.isTestToolCall(entry)) {
|
|
2452
|
+
latest = latest ? Math.max(latest, entry.timestamp) : entry.timestamp;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return latest;
|
|
2456
|
+
}
|
|
2457
|
+
formatCommandError(error) {
|
|
2458
|
+
const parts = [error?.stdout, error?.stderr, error?.message].filter((part) => typeof part === 'string' && part.trim());
|
|
2459
|
+
return parts.join('\n').trim();
|
|
2460
|
+
}
|
|
2461
|
+
async enforceAutoTests(trigger) {
|
|
2462
|
+
if (this.autoTestInFlight) {
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
const latestChange = this.getLatestFileChangeTimestamp();
|
|
2466
|
+
if (!latestChange) {
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
const latestTest = this.getLatestTestTimestamp();
|
|
2470
|
+
if (latestTest && latestChange <= latestTest) {
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
this.autoTestInFlight = true;
|
|
2474
|
+
const command = 'npm test -- --runInBand';
|
|
2475
|
+
display.showSystemMessage(`🧪 Auto-testing recent changes (${trigger}) with "${command}"...`);
|
|
2476
|
+
this.updateStatusMessage('Running tests automatically...');
|
|
2477
|
+
try {
|
|
2478
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
2479
|
+
cwd: this.workingDir,
|
|
2480
|
+
timeout: 10 * 60 * 1000,
|
|
2481
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
2482
|
+
});
|
|
2483
|
+
this.lastAutoTestRun = Date.now();
|
|
2484
|
+
const outputText = [stdout, stderr].filter(Boolean).join('\n').trim();
|
|
2485
|
+
display.showSystemMessage('✅ Auto-tests finished.');
|
|
2486
|
+
if (outputText) {
|
|
2487
|
+
process.stdout.write(`${outputText}\n`);
|
|
2488
|
+
}
|
|
2489
|
+
this.statusTracker.clearOverride('tests');
|
|
2490
|
+
}
|
|
2491
|
+
catch (error) {
|
|
2492
|
+
this.lastAutoTestRun = Date.now();
|
|
2493
|
+
const message = this.formatCommandError(error);
|
|
2494
|
+
display.showWarning('⚠️ Auto-tests failed. Review output below.');
|
|
2495
|
+
if (message) {
|
|
2496
|
+
process.stdout.write(`${message}\n`);
|
|
2497
|
+
}
|
|
2498
|
+
this.statusTracker.pushOverride('tests', 'Tests failing', {
|
|
2499
|
+
detail: 'Auto-run npm test failed',
|
|
2500
|
+
tone: 'danger',
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
finally {
|
|
2504
|
+
this.updateStatusMessage(null);
|
|
2505
|
+
this.autoTestInFlight = false;
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
rebuildAgent() {
|
|
2509
|
+
const previousHistory = this.agent ? this.agent.getHistory() : this.cachedHistory;
|
|
2510
|
+
try {
|
|
2511
|
+
ensureSecretForProvider(this.sessionState.provider);
|
|
2512
|
+
this.runtimeSession.updateToolContext(this.sessionState);
|
|
2513
|
+
const selection = {
|
|
2514
|
+
provider: this.sessionState.provider,
|
|
2515
|
+
model: this.sessionState.model,
|
|
2516
|
+
temperature: this.sessionState.temperature,
|
|
2517
|
+
maxTokens: this.sessionState.maxTokens,
|
|
2518
|
+
systemPrompt: this.buildSystemPrompt(),
|
|
2519
|
+
reasoningEffort: this.sessionState.reasoningEffort,
|
|
2520
|
+
autoContinue: this.autoContinueEnabled,
|
|
2521
|
+
};
|
|
2522
|
+
this.agent = this.runtimeSession.createAgent(selection, {
|
|
2523
|
+
onStreamChunk: (chunk) => {
|
|
2524
|
+
// Claude Code style: Stream output through display module
|
|
2525
|
+
// The output interceptor automatically refreshes the fixed input area
|
|
2526
|
+
// after each chunk, keeping cursor at the chat box
|
|
2527
|
+
if (display.isSpinnerActive()) {
|
|
2528
|
+
display.stopThinking(false);
|
|
2529
|
+
display.stream('\n');
|
|
2530
|
+
}
|
|
2531
|
+
display.stream(chunk);
|
|
2532
|
+
this.requestPromptRefresh();
|
|
2533
|
+
},
|
|
2534
|
+
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
2535
|
+
onAssistantMessage: (content, metadata) => {
|
|
2536
|
+
const enriched = this.buildDisplayMetadata(metadata);
|
|
2537
|
+
// Update spinner based on message type
|
|
2538
|
+
if (metadata.isFinal) {
|
|
2539
|
+
// Skip display if content was already streamed to avoid double-display
|
|
2540
|
+
if (!metadata.wasStreamed) {
|
|
2541
|
+
const parsed = this.splitThinkingResponse(content);
|
|
2542
|
+
if (parsed?.thinking) {
|
|
2543
|
+
const summary = this.extractThoughtSummary(parsed.thinking);
|
|
2544
|
+
if (summary) {
|
|
2545
|
+
display.updateThinking(`💭 ${summary}`);
|
|
2546
|
+
}
|
|
2547
|
+
display.showAssistantMessage(parsed.thinking, { ...enriched, isFinal: false });
|
|
2548
|
+
}
|
|
2549
|
+
const finalContent = parsed?.response?.trim() || content;
|
|
2550
|
+
if (finalContent) {
|
|
2551
|
+
display.showAssistantMessage(finalContent, enriched);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
// Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
|
|
2555
|
+
display.stopThinking();
|
|
2556
|
+
// Calculate context usage
|
|
2557
|
+
let contextInfo;
|
|
2558
|
+
if (enriched.contextWindowTokens && metadata.usage) {
|
|
2559
|
+
const total = this.totalTokens(metadata.usage);
|
|
2560
|
+
if (total && total > 0) {
|
|
2561
|
+
const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
|
|
2562
|
+
contextInfo = { percentage, tokens: total };
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
|
|
2566
|
+
void this.enforceAutoTests('final-response');
|
|
2567
|
+
}
|
|
2568
|
+
else {
|
|
2569
|
+
// Non-final message = narrative text before tool calls (Claude Code style)
|
|
2570
|
+
// Stop spinner and show the narrative text directly
|
|
2571
|
+
display.stopThinking();
|
|
2572
|
+
// Skip display if content was already streamed to avoid double-display
|
|
2573
|
+
if (!metadata.wasStreamed) {
|
|
2574
|
+
display.showNarrative(content.trim());
|
|
2575
|
+
}
|
|
2576
|
+
// The isProcessing flag already shows "⏳ Processing..." - no need for duplicate status
|
|
2577
|
+
this.requestPromptRefresh();
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
const cleanup = this.handleContextTelemetry(metadata, enriched);
|
|
2581
|
+
if (cleanup) {
|
|
2582
|
+
this.pendingCleanup = cleanup;
|
|
2583
|
+
}
|
|
2584
|
+
this.requestPromptRefresh();
|
|
2585
|
+
},
|
|
2586
|
+
onContextSquishing: (message) => {
|
|
2587
|
+
// Show notification in UI when auto context squishing occurs
|
|
2588
|
+
display.showSystemMessage(`🔄 ${message}`);
|
|
2589
|
+
this.statusTracker.pushOverride('context-squish', 'Auto-squishing context', {
|
|
2590
|
+
detail: 'Reducing conversation history to fit within token limits',
|
|
2591
|
+
tone: 'warning',
|
|
2592
|
+
});
|
|
2593
|
+
},
|
|
2594
|
+
onContextRecovery: (attempt, maxAttempts, message) => {
|
|
2595
|
+
// Show recovery progress in UI
|
|
2596
|
+
display.showSystemMessage(`⚡ Context Recovery (${attempt}/${maxAttempts}): ${message}`);
|
|
2597
|
+
},
|
|
2598
|
+
onContextPruned: (removedCount, stats) => {
|
|
2599
|
+
// Clear squish overlay if active
|
|
2600
|
+
this.statusTracker.clearOverride('context-squish');
|
|
2601
|
+
// Show notification that context was pruned
|
|
2602
|
+
const method = stats['method'];
|
|
2603
|
+
const percentage = stats['percentage'];
|
|
2604
|
+
if (method === 'emergency-recovery') {
|
|
2605
|
+
display.showSystemMessage(`✅ Context recovery complete. Removed ${removedCount} messages. Context now at ${percentage ?? 'unknown'}%`);
|
|
2606
|
+
}
|
|
2607
|
+
// Update context usage in UI
|
|
2608
|
+
if (typeof percentage === 'number') {
|
|
2609
|
+
this.updateContextUsage(percentage);
|
|
2610
|
+
}
|
|
2611
|
+
// Ensure prompt remains visible at bottom after context messages
|
|
2612
|
+
this.terminalInput.render();
|
|
2613
|
+
},
|
|
2614
|
+
onContinueAfterRecovery: () => {
|
|
2615
|
+
// Update UI to show we're continuing after context recovery
|
|
2616
|
+
display.showSystemMessage(`🔄 Continuing after context recovery...`);
|
|
2617
|
+
this.updateStatusMessage('Retrying with reduced context...');
|
|
2618
|
+
this.terminalInput.render();
|
|
2619
|
+
},
|
|
2620
|
+
onAutoContinue: (attempt, maxAttempts, _message) => {
|
|
2621
|
+
// Show auto-continue progress in UI
|
|
2622
|
+
display.showSystemMessage(`🔄 Auto-continue (${attempt}/${maxAttempts}): Model expressed intent, prompting to act...`);
|
|
2623
|
+
this.updateStatusMessage('Auto-continuing...');
|
|
2624
|
+
this.terminalInput.render();
|
|
2625
|
+
},
|
|
2626
|
+
onCancelled: () => {
|
|
2627
|
+
// Update UI to show operation was cancelled
|
|
2628
|
+
display.showWarning('Operation cancelled.');
|
|
2629
|
+
this.updateStatusMessage(null);
|
|
2630
|
+
this.stopStreamingHeartbeat();
|
|
2631
|
+
this.terminalInput.setStreaming(false);
|
|
2632
|
+
this.terminalInput.render();
|
|
2633
|
+
},
|
|
2634
|
+
onVerificationNeeded: () => {
|
|
2635
|
+
void this.enforceAutoTests('verification');
|
|
2636
|
+
},
|
|
2637
|
+
});
|
|
2638
|
+
const historyToLoad = (this.pendingHistoryLoad && this.pendingHistoryLoad.length
|
|
2639
|
+
? this.pendingHistoryLoad
|
|
2640
|
+
: previousHistory && previousHistory.length
|
|
2641
|
+
? previousHistory
|
|
2642
|
+
: null) ?? null;
|
|
2643
|
+
if (historyToLoad && historyToLoad.length) {
|
|
2644
|
+
this.agent.loadHistory(historyToLoad);
|
|
2645
|
+
this.cachedHistory = historyToLoad;
|
|
2646
|
+
}
|
|
2647
|
+
else {
|
|
2648
|
+
this.cachedHistory = [];
|
|
2649
|
+
}
|
|
2650
|
+
this.pendingHistoryLoad = null;
|
|
2651
|
+
this.showSessionResumeNotice();
|
|
2652
|
+
return true;
|
|
2653
|
+
}
|
|
2654
|
+
catch (error) {
|
|
2655
|
+
this.agent = null;
|
|
2656
|
+
this.handleAgentSetupError(error, () => this.rebuildAgent(), this.sessionState.provider);
|
|
2657
|
+
return false;
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Reset the unified input box to a fresh state after model/provider swap.
|
|
2662
|
+
* Ensures the input area is visible and ready for input, just like on startup.
|
|
2663
|
+
*/
|
|
2664
|
+
resetChatBoxAfterModelSwap() {
|
|
2665
|
+
this.updateStatusMessage(null);
|
|
2666
|
+
this.terminalInput.setStreaming(false);
|
|
2667
|
+
this.terminalInput.render();
|
|
2668
|
+
this.ensureReadlineReady();
|
|
2669
|
+
}
|
|
2670
|
+
buildSystemPrompt() {
|
|
2671
|
+
const providerLabel = this.providerLabel(this.sessionState.provider);
|
|
2672
|
+
const lines = [
|
|
2673
|
+
this.baseSystemPrompt.trim(),
|
|
2674
|
+
'',
|
|
2675
|
+
'ACTIVE RUNTIME METADATA:',
|
|
2676
|
+
`- CLI profile: ${this.profileLabel} (${this.profile})`,
|
|
2677
|
+
`- Provider: ${providerLabel} (${this.sessionState.provider})`,
|
|
2678
|
+
`- Model: ${this.sessionState.model}`,
|
|
2679
|
+
];
|
|
2680
|
+
if (typeof this.sessionState.temperature === 'number') {
|
|
2681
|
+
lines.push(`- Temperature: ${this.sessionState.temperature}`);
|
|
2682
|
+
}
|
|
2683
|
+
if (typeof this.sessionState.maxTokens === 'number') {
|
|
2684
|
+
lines.push(`- Max tokens: ${this.sessionState.maxTokens}`);
|
|
2685
|
+
}
|
|
2686
|
+
lines.push('', 'Use these values when describing your identity or answering model/provider questions. If anything feels stale, call the `profile_details` tool before responding.');
|
|
2687
|
+
const thinkingDirective = this.buildThinkingDirective();
|
|
2688
|
+
if (thinkingDirective) {
|
|
2689
|
+
lines.push('', thinkingDirective);
|
|
2690
|
+
}
|
|
2691
|
+
return lines.join('\n').trim();
|
|
2692
|
+
}
|
|
2693
|
+
buildThinkingDirective() {
|
|
2694
|
+
switch (this.thinkingMode) {
|
|
2695
|
+
case 'concise':
|
|
2696
|
+
return 'Concise thinking mode is enabled: respond directly with the final answer and skip <thinking> blocks unless the user explicitly asks for your reasoning.';
|
|
2697
|
+
case 'extended':
|
|
2698
|
+
return [
|
|
2699
|
+
'Extended thinking mode is enabled. Format every reply as:',
|
|
2700
|
+
'<thinking>',
|
|
2701
|
+
'Detailed multi-step reasoning (reference tool runs/files when relevant, keep secrets redacted, no code blocks unless citing filenames).',
|
|
2702
|
+
'</thinking>',
|
|
2703
|
+
'<response>',
|
|
2704
|
+
'Final answer with actionable next steps and any code/commands requested.',
|
|
2705
|
+
'</response>',
|
|
2706
|
+
].join('\n');
|
|
2707
|
+
case 'balanced':
|
|
2708
|
+
default:
|
|
2709
|
+
return 'Balanced thinking mode: include a short <thinking>...</thinking> block before <response> when the reasoning is non-trivial; skip it for simple answers.';
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
buildDisplayMetadata(metadata) {
|
|
2713
|
+
return {
|
|
2714
|
+
...metadata,
|
|
2715
|
+
contextWindowTokens: this.activeContextWindowTokens,
|
|
2716
|
+
};
|
|
2717
|
+
}
|
|
2718
|
+
handleContextTelemetry(metadata, displayMetadata) {
|
|
2719
|
+
if (!metadata.isFinal) {
|
|
2720
|
+
return null;
|
|
2721
|
+
}
|
|
2722
|
+
const windowTokens = displayMetadata.contextWindowTokens;
|
|
2723
|
+
if (!windowTokens || windowTokens <= 0) {
|
|
2724
|
+
return null;
|
|
2725
|
+
}
|
|
2726
|
+
const total = this.totalTokens(metadata.usage);
|
|
2727
|
+
if (total === null) {
|
|
2728
|
+
return null;
|
|
2729
|
+
}
|
|
2730
|
+
const usageRatio = total / windowTokens;
|
|
2731
|
+
// Always update context usage in the UI
|
|
2732
|
+
const percentUsed = Math.round(usageRatio * 100);
|
|
2733
|
+
this.updateContextUsage(percentUsed);
|
|
2734
|
+
if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
|
|
2735
|
+
return null;
|
|
2736
|
+
}
|
|
2737
|
+
if (!this.agent || this.cleanupInProgress) {
|
|
2738
|
+
return null;
|
|
2739
|
+
}
|
|
2740
|
+
return this.runContextCleanup(windowTokens, total);
|
|
2741
|
+
}
|
|
2742
|
+
totalTokens(usage) {
|
|
2743
|
+
if (!usage) {
|
|
2744
|
+
return null;
|
|
2745
|
+
}
|
|
2746
|
+
if (typeof usage.totalTokens === 'number' && Number.isFinite(usage.totalTokens)) {
|
|
2747
|
+
return usage.totalTokens;
|
|
2748
|
+
}
|
|
2749
|
+
const input = typeof usage.inputTokens === 'number' ? usage.inputTokens : 0;
|
|
2750
|
+
const output = typeof usage.outputTokens === 'number' ? usage.outputTokens : 0;
|
|
2751
|
+
const sum = input + output;
|
|
2752
|
+
return sum > 0 ? sum : null;
|
|
2753
|
+
}
|
|
2754
|
+
async runContextCleanup(windowTokens, totalTokens) {
|
|
2755
|
+
if (!this.agent) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
this.cleanupInProgress = true;
|
|
2759
|
+
const cleanupStatusId = 'context-cleanup';
|
|
2760
|
+
let cleanupOverlayActive = false;
|
|
2761
|
+
try {
|
|
2762
|
+
const history = this.agent.getHistory();
|
|
2763
|
+
const { system, conversation } = this.partitionHistory(history);
|
|
2764
|
+
if (!conversation.length) {
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
const preserveCount = Math.min(conversation.length, CONTEXT_RECENT_MESSAGE_COUNT);
|
|
2768
|
+
const preserved = conversation.slice(conversation.length - preserveCount);
|
|
2769
|
+
const toSummarize = conversation.slice(0, conversation.length - preserveCount);
|
|
2770
|
+
if (!toSummarize.length) {
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
cleanupOverlayActive = true;
|
|
2774
|
+
this.statusTracker.pushOverride(cleanupStatusId, 'Running context cleanup', {
|
|
2775
|
+
detail: `Summarizing ${toSummarize.length} earlier messages`,
|
|
2776
|
+
tone: 'warning',
|
|
2777
|
+
});
|
|
2778
|
+
const percentUsed = Math.round((totalTokens / windowTokens) * 100);
|
|
2779
|
+
// Update context usage in unified UI
|
|
2780
|
+
this.updateContextUsage(percentUsed);
|
|
2781
|
+
display.showSystemMessage([
|
|
2782
|
+
`Context usage: ${totalTokens.toLocaleString('en-US')} of ${windowTokens.toLocaleString('en-US')} tokens`,
|
|
2783
|
+
`(${percentUsed}% full). Running automatic cleanup...`,
|
|
2784
|
+
].join(' '));
|
|
2785
|
+
const summary = await this.buildContextSummary(toSummarize);
|
|
2786
|
+
if (!summary) {
|
|
2787
|
+
throw new Error('Summary could not be generated.');
|
|
2788
|
+
}
|
|
2789
|
+
const trimmed = this.buildTrimmedHistory(system, summary, preserved);
|
|
2790
|
+
this.agent.loadHistory(trimmed);
|
|
2791
|
+
display.showSystemMessage(`Context cleanup complete. Summarized ${toSummarize.length} earlier messages and preserved the latest ${preserved.length}.`);
|
|
2792
|
+
}
|
|
2793
|
+
finally {
|
|
2794
|
+
if (cleanupOverlayActive) {
|
|
2795
|
+
this.statusTracker.clearOverride(cleanupStatusId);
|
|
2796
|
+
}
|
|
2797
|
+
this.cleanupInProgress = false;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
partitionHistory(history) {
|
|
2801
|
+
const system = [];
|
|
2802
|
+
const conversation = [];
|
|
2803
|
+
for (const message of history) {
|
|
2804
|
+
if (message.role === 'system') {
|
|
2805
|
+
if (system.length === 0) {
|
|
2806
|
+
system.push(message);
|
|
2807
|
+
}
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
conversation.push(message);
|
|
2811
|
+
}
|
|
2812
|
+
return { system, conversation };
|
|
2813
|
+
}
|
|
2814
|
+
async buildContextSummary(messages) {
|
|
2815
|
+
const chunks = this.buildSummaryChunks(messages);
|
|
2816
|
+
if (!chunks.length) {
|
|
2817
|
+
return null;
|
|
2818
|
+
}
|
|
2819
|
+
const summarizer = this.runtimeSession.createAgent({
|
|
2820
|
+
provider: this.sessionState.provider,
|
|
2821
|
+
model: this.sessionState.model,
|
|
2822
|
+
temperature: 0,
|
|
2823
|
+
maxTokens: Math.min(this.sessionState.maxTokens ?? CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS, CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS),
|
|
2824
|
+
systemPrompt: CONTEXT_CLEANUP_SYSTEM_PROMPT,
|
|
2825
|
+
}, {});
|
|
2826
|
+
let runningSummary = '';
|
|
2827
|
+
for (const chunk of chunks) {
|
|
2828
|
+
const prompt = this.buildSummaryPrompt(chunk, runningSummary);
|
|
2829
|
+
runningSummary = (await summarizer.send(prompt)).trim();
|
|
2830
|
+
summarizer.clearHistory();
|
|
2831
|
+
}
|
|
2832
|
+
return runningSummary || null;
|
|
2833
|
+
}
|
|
2834
|
+
buildSummaryChunks(messages) {
|
|
2835
|
+
const serialized = messages.map((message) => this.serializeMessage(message)).filter((text) => text.length > 0);
|
|
2836
|
+
if (!serialized.length) {
|
|
2837
|
+
return [];
|
|
2838
|
+
}
|
|
2839
|
+
const chunks = [];
|
|
2840
|
+
let buffer = '';
|
|
2841
|
+
for (const entry of serialized) {
|
|
2842
|
+
const segment = buffer ? `\n\n${entry}` : entry;
|
|
2843
|
+
if (buffer && buffer.length + segment.length > CONTEXT_CLEANUP_CHARS_PER_CHUNK) {
|
|
2844
|
+
chunks.push(buffer.trim());
|
|
2845
|
+
buffer = entry;
|
|
2846
|
+
continue;
|
|
2847
|
+
}
|
|
2848
|
+
buffer += buffer ? `\n\n${entry}` : entry;
|
|
2849
|
+
}
|
|
2850
|
+
if (buffer.trim()) {
|
|
2851
|
+
chunks.push(buffer.trim());
|
|
2852
|
+
}
|
|
2853
|
+
return chunks;
|
|
2854
|
+
}
|
|
2855
|
+
serializeMessage(message) {
|
|
2856
|
+
const role = this.describeRole(message);
|
|
2857
|
+
const parts = [`${role}:`];
|
|
2858
|
+
const content = message.content?.trim() ?? '';
|
|
2859
|
+
if (content) {
|
|
2860
|
+
parts.push(content);
|
|
2861
|
+
}
|
|
2862
|
+
if (message.role === 'assistant' && message.toolCalls && message.toolCalls.length > 0) {
|
|
2863
|
+
parts.push('Tool calls:', ...message.toolCalls.map((call) => {
|
|
2864
|
+
const args = JSON.stringify(call.arguments ?? {});
|
|
2865
|
+
return `- ${call.name} ${args}`;
|
|
2866
|
+
}));
|
|
2867
|
+
}
|
|
2868
|
+
return parts.join('\n').trim();
|
|
2869
|
+
}
|
|
2870
|
+
describeRole(message) {
|
|
2871
|
+
switch (message.role) {
|
|
2872
|
+
case 'assistant':
|
|
2873
|
+
return 'Assistant';
|
|
2874
|
+
case 'user':
|
|
2875
|
+
return 'User';
|
|
2876
|
+
case 'tool':
|
|
2877
|
+
return `Tool(${message.name ?? message.toolCallId ?? 'result'})`;
|
|
2878
|
+
case 'system':
|
|
2879
|
+
default:
|
|
2880
|
+
return 'System';
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
buildSummaryPrompt(chunk, existingSummary) {
|
|
2884
|
+
const sections = [];
|
|
2885
|
+
if (existingSummary) {
|
|
2886
|
+
sections.push(`Existing summary:\n${existingSummary}`);
|
|
2887
|
+
}
|
|
2888
|
+
sections.push(`Conversation chunk:\n${chunk}`);
|
|
2889
|
+
sections.push([
|
|
2890
|
+
'Instructions:',
|
|
2891
|
+
'- Merge the chunk into the running summary.',
|
|
2892
|
+
'- Preserve critical TODOs, bugs, test gaps, and file references.',
|
|
2893
|
+
'- Call out what is resolved vs. still pending.',
|
|
2894
|
+
'- Keep the output concise (<= 200 words) using short headings or bullets.',
|
|
2895
|
+
].join('\n'));
|
|
2896
|
+
return sections.join('\n\n');
|
|
2897
|
+
}
|
|
2898
|
+
buildTrimmedHistory(systemMessages, summary, preserved) {
|
|
2899
|
+
const history = [];
|
|
2900
|
+
if (systemMessages.length > 0) {
|
|
2901
|
+
history.push(systemMessages[0]);
|
|
2902
|
+
}
|
|
2903
|
+
else {
|
|
2904
|
+
history.push({ role: 'system', content: this.buildSystemPrompt() });
|
|
2905
|
+
}
|
|
2906
|
+
history.push({
|
|
2907
|
+
role: 'system',
|
|
2908
|
+
content: [
|
|
2909
|
+
'Condensed context summary (auto cleanup):',
|
|
2910
|
+
summary.trim(),
|
|
2911
|
+
`Last updated: ${new Date().toISOString()}`,
|
|
2912
|
+
].join('\n\n'),
|
|
2913
|
+
});
|
|
2914
|
+
history.push(...preserved);
|
|
2915
|
+
return history;
|
|
2916
|
+
}
|
|
2917
|
+
handleAgentSetupError(error, retryAction, providerOverride) {
|
|
2918
|
+
this.pendingInteraction = null;
|
|
2919
|
+
const provider = providerOverride ?? this.sessionState.provider;
|
|
2920
|
+
const apiKeyIssue = detectApiKeyError(error, provider);
|
|
2921
|
+
if (apiKeyIssue) {
|
|
2922
|
+
this.handleApiKeyIssue(apiKeyIssue, retryAction);
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
this.pendingSecretRetry = null;
|
|
2926
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2927
|
+
display.showError(message);
|
|
2928
|
+
}
|
|
2929
|
+
handleStreamingFallback(info) {
|
|
2930
|
+
const detailText = info.message.trim();
|
|
2931
|
+
const detail = detailText ? ` Error: ${detailText}` : '';
|
|
2932
|
+
display.showWarning(`Streaming failed, retrying without streaming.${detail}`);
|
|
2933
|
+
this.startStreamingHeartbeat('Fallback in progress');
|
|
2934
|
+
this.requestPromptRefresh(true);
|
|
2935
|
+
}
|
|
2936
|
+
handleProviderError(error, retryAction) {
|
|
2937
|
+
const apiKeyIssue = detectApiKeyError(error, this.sessionState.provider);
|
|
2938
|
+
if (!apiKeyIssue) {
|
|
2939
|
+
return false;
|
|
2940
|
+
}
|
|
2941
|
+
this.handleApiKeyIssue(apiKeyIssue, retryAction);
|
|
2942
|
+
return true;
|
|
2943
|
+
}
|
|
2944
|
+
handleApiKeyIssue(info, retryAction) {
|
|
2945
|
+
const secret = info.secret ?? null;
|
|
2946
|
+
const providerLabel = info.provider ? this.providerLabel(info.provider) : 'the selected provider';
|
|
2947
|
+
if (!secret) {
|
|
2948
|
+
this.pendingSecretRetry = null;
|
|
2949
|
+
const guidance = 'Run "/secrets" to configure the required API key or export it (e.g., EXPORT KEY=value) before launching the CLI.';
|
|
2950
|
+
const baseMessage = info.type === 'missing'
|
|
2951
|
+
? `An API key is required before using ${providerLabel}.`
|
|
2952
|
+
: `API authentication failed for ${providerLabel}.`;
|
|
2953
|
+
display.showWarning(`${baseMessage} ${guidance}`.trim());
|
|
2954
|
+
return;
|
|
2955
|
+
}
|
|
2956
|
+
const isMissing = info.type === 'missing';
|
|
2957
|
+
if (!isMissing && info.message && info.message.trim()) {
|
|
2958
|
+
display.showWarning(info.message.trim());
|
|
2959
|
+
}
|
|
2960
|
+
const prefix = isMissing
|
|
2961
|
+
? `${secret.label} is required before you can use ${providerLabel}.`
|
|
2962
|
+
: `${secret.label} appears to be invalid for ${providerLabel}.`;
|
|
2963
|
+
display.showWarning(prefix);
|
|
2964
|
+
this.pendingSecretRetry = retryAction ?? null;
|
|
2965
|
+
this.pendingInteraction = { type: 'secret-input', secret };
|
|
2966
|
+
this.showSecretGuidance(secret, isMissing);
|
|
2967
|
+
}
|
|
2968
|
+
showSecretGuidance(secret, promptForInput) {
|
|
2969
|
+
const lines = [];
|
|
2970
|
+
if (promptForInput) {
|
|
2971
|
+
lines.push(`Enter a new value for ${secret.label} or type "cancel".`);
|
|
2972
|
+
}
|
|
2973
|
+
else {
|
|
2974
|
+
lines.push(`Update the stored value for ${secret.label} or type "cancel".`);
|
|
2975
|
+
}
|
|
2976
|
+
lines.push(`Tip: run "/secrets" anytime to manage credentials or export ${secret.envVar}=<value> before launching the CLI.`);
|
|
2977
|
+
display.showSystemMessage(lines.join('\n'));
|
|
2978
|
+
}
|
|
2979
|
+
colorizeDropdownLine(text, index) {
|
|
2980
|
+
if (!DROPDOWN_COLORS.length) {
|
|
2981
|
+
return text;
|
|
2982
|
+
}
|
|
2983
|
+
const color = DROPDOWN_COLORS[index % DROPDOWN_COLORS.length];
|
|
2984
|
+
return color(text);
|
|
2985
|
+
}
|
|
2986
|
+
findModelPreset(modelId) {
|
|
2987
|
+
return MODEL_PRESETS.find((preset) => preset.id === modelId);
|
|
2988
|
+
}
|
|
2989
|
+
applyPresetReasoningDefaults() {
|
|
2990
|
+
if (this.sessionState.reasoningEffort) {
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
const preset = this.findModelPreset(this.sessionState.model);
|
|
2994
|
+
if (preset?.reasoningEffort) {
|
|
2995
|
+
this.sessionState.reasoningEffort = preset.reasoningEffort;
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
refreshBannerSessionInfo() {
|
|
2999
|
+
const nextState = {
|
|
3000
|
+
model: this.sessionState.model,
|
|
3001
|
+
provider: this.sessionState.provider,
|
|
3002
|
+
};
|
|
3003
|
+
const previous = this.bannerSessionState;
|
|
3004
|
+
if (previous && previous.model === nextState.model && previous.provider === nextState.provider) {
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
this.refreshContextGauge();
|
|
3008
|
+
display.updateSessionInfo(nextState.model, nextState.provider);
|
|
3009
|
+
if (!this.isProcessing) {
|
|
3010
|
+
this.setIdleStatus();
|
|
3011
|
+
}
|
|
3012
|
+
this.bannerSessionState = nextState;
|
|
3013
|
+
}
|
|
3014
|
+
providerLabel(id) {
|
|
3015
|
+
return PROVIDER_LABELS[id] ?? id;
|
|
3016
|
+
}
|
|
3017
|
+
agentMenuLabel(name) {
|
|
3018
|
+
if (!this.agentMenu) {
|
|
3019
|
+
return name;
|
|
3020
|
+
}
|
|
3021
|
+
const entry = this.agentMenu.options.find((option) => option.name === name);
|
|
3022
|
+
return entry?.label ?? name;
|
|
3023
|
+
}
|
|
3024
|
+
extractThoughtSummary(thought) {
|
|
3025
|
+
// Extract first non-empty line
|
|
3026
|
+
const lines = thought?.split('\n').filter(line => line.trim()) ?? [];
|
|
3027
|
+
if (!lines.length) {
|
|
3028
|
+
return null;
|
|
3029
|
+
}
|
|
3030
|
+
// Remove common thought prefixes
|
|
3031
|
+
const cleaned = lines[0]
|
|
3032
|
+
.trim()
|
|
3033
|
+
.replace(/^(Thinking|Analyzing|Considering|Looking at|Let me)[:.\s]+/i, '')
|
|
3034
|
+
.replace(/^I (should|need to|will|am)[:.\s]+/i, '')
|
|
3035
|
+
.trim();
|
|
3036
|
+
if (!cleaned) {
|
|
3037
|
+
return null;
|
|
3038
|
+
}
|
|
3039
|
+
// Truncate to reasonable length
|
|
3040
|
+
const maxLength = 50;
|
|
3041
|
+
return cleaned.length > maxLength
|
|
3042
|
+
? cleaned.slice(0, maxLength - 3) + '...'
|
|
3043
|
+
: cleaned;
|
|
3044
|
+
}
|
|
3045
|
+
splitThinkingResponse(content) {
|
|
3046
|
+
if (!content?.includes('<thinking') && !content?.includes('<response')) {
|
|
3047
|
+
return null;
|
|
3048
|
+
}
|
|
3049
|
+
const thinkingMatch = /<thinking>([\s\S]*?)<\/thinking>/i.exec(content);
|
|
3050
|
+
const responseMatch = /<response>([\s\S]*?)<\/response>/i.exec(content);
|
|
3051
|
+
if (!thinkingMatch && !responseMatch) {
|
|
3052
|
+
return null;
|
|
3053
|
+
}
|
|
3054
|
+
const thinkingBody = thinkingMatch?.[1]?.trim() ?? null;
|
|
3055
|
+
let responseBody = responseMatch?.[1]?.trim();
|
|
3056
|
+
if (!responseBody) {
|
|
3057
|
+
responseBody = content
|
|
3058
|
+
.replace(thinkingMatch?.[0] ?? '', '')
|
|
3059
|
+
.replace(/<\/?response>/gi, '')
|
|
3060
|
+
.trim();
|
|
3061
|
+
}
|
|
3062
|
+
return {
|
|
3063
|
+
thinking: thinkingBody && thinkingBody.length ? thinkingBody : null,
|
|
3064
|
+
response: responseBody ?? '',
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
persistSessionPreference() {
|
|
3068
|
+
saveModelPreference(this.profile, {
|
|
3069
|
+
provider: this.sessionState.provider,
|
|
3070
|
+
model: this.sessionState.model,
|
|
3071
|
+
temperature: this.sessionState.temperature,
|
|
3072
|
+
maxTokens: this.sessionState.maxTokens,
|
|
3073
|
+
reasoningEffort: this.sessionState.reasoningEffort,
|
|
3074
|
+
});
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* Handle the /provider command to switch AI providers.
|
|
3078
|
+
*/
|
|
3079
|
+
async handleProviderCommand(input) {
|
|
3080
|
+
const tokens = input.trim().split(/\s+/).slice(1);
|
|
3081
|
+
const targetProvider = tokens[0]?.toLowerCase();
|
|
3082
|
+
if (!targetProvider) {
|
|
3083
|
+
this.showConfiguredProviders();
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
// Find matching provider
|
|
3087
|
+
const providerOptions = this.buildProviderOptions();
|
|
3088
|
+
const match = providerOptions.find((opt) => opt.provider.toLowerCase() === targetProvider || opt.label.toLowerCase() === targetProvider);
|
|
3089
|
+
if (!match) {
|
|
3090
|
+
display.showWarning(`Unknown provider "${targetProvider}".`);
|
|
3091
|
+
const available = providerOptions.map((opt) => opt.provider).join(', ');
|
|
3092
|
+
display.showInfo(`Available providers: ${available}`);
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
if (match.provider === this.sessionState.provider) {
|
|
3096
|
+
display.showInfo(`Already using ${match.label}.`);
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
// Get default model for the provider
|
|
3100
|
+
const models = MODEL_PRESETS.filter((preset) => preset.provider === match.provider);
|
|
3101
|
+
if (!models.length) {
|
|
3102
|
+
display.showWarning(`No models available for ${match.label}.`);
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
const defaultModel = models[0];
|
|
3106
|
+
const oldProvider = this.sessionState.provider;
|
|
3107
|
+
const oldModel = this.sessionState.model;
|
|
3108
|
+
// Update session state
|
|
3109
|
+
this.sessionState = {
|
|
3110
|
+
provider: match.provider,
|
|
3111
|
+
model: defaultModel.id,
|
|
3112
|
+
temperature: defaultModel.temperature,
|
|
3113
|
+
maxTokens: defaultModel.maxTokens,
|
|
3114
|
+
reasoningEffort: defaultModel.reasoningEffort,
|
|
3115
|
+
};
|
|
3116
|
+
// Rebuild agent with new provider
|
|
3117
|
+
if (this.rebuildAgent()) {
|
|
3118
|
+
this.persistSessionPreference();
|
|
3119
|
+
this.refreshBannerSessionInfo();
|
|
3120
|
+
display.showInfo(`Switched from ${this.providerLabel(oldProvider)}/${oldModel} to ${match.label}/${defaultModel.id}`);
|
|
3121
|
+
this.resetChatBoxAfterModelSwap();
|
|
3122
|
+
}
|
|
3123
|
+
else {
|
|
3124
|
+
// Revert on failure
|
|
3125
|
+
this.sessionState.provider = oldProvider;
|
|
3126
|
+
this.sessionState.model = oldModel;
|
|
3127
|
+
display.showError(`Failed to switch to ${match.label}. Reverted to ${this.providerLabel(oldProvider)}.`);
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
/**
|
|
3131
|
+
* Discover models from provider APIs.
|
|
3132
|
+
*/
|
|
3133
|
+
async discoverModelsCommand() {
|
|
3134
|
+
display.showInfo('Discovering models from provider APIs...');
|
|
3135
|
+
try {
|
|
3136
|
+
const result = await discoverAllModels();
|
|
3137
|
+
const lines = [
|
|
3138
|
+
theme.bold('Model Discovery Results:'),
|
|
3139
|
+
'',
|
|
3140
|
+
];
|
|
3141
|
+
for (const providerResult of result.results) {
|
|
3142
|
+
if (providerResult.success) {
|
|
3143
|
+
const count = providerResult.models.length;
|
|
3144
|
+
lines.push(` ${theme.success('✓')} ${providerResult.provider}: ${count} model${count === 1 ? '' : 's'} found`);
|
|
3145
|
+
// Show top 3 models
|
|
3146
|
+
const topModels = providerResult.models.slice(0, 3).map(m => m.id);
|
|
3147
|
+
if (topModels.length > 0) {
|
|
3148
|
+
lines.push(` ${theme.secondary(topModels.join(', '))}${providerResult.models.length > 3 ? '...' : ''}`);
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
else {
|
|
3152
|
+
const errorMsg = providerResult.error || 'Unknown error';
|
|
3153
|
+
lines.push(` ${theme.warning('⚠')} ${providerResult.provider}: ${errorMsg}`);
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
lines.push('');
|
|
3157
|
+
lines.push(`Total: ${result.totalModelsDiscovered} models discovered`);
|
|
3158
|
+
if (result.errors.length > 0) {
|
|
3159
|
+
lines.push('');
|
|
3160
|
+
lines.push(theme.secondary('Some providers had errors. Check API keys with /secrets.'));
|
|
3161
|
+
}
|
|
3162
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3163
|
+
}
|
|
3164
|
+
catch (error) {
|
|
3165
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3166
|
+
display.showError(`Discovery failed: ${message}`);
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
/**
|
|
3170
|
+
* Show all configured providers and their status.
|
|
3171
|
+
*/
|
|
3172
|
+
showConfiguredProviders() {
|
|
3173
|
+
const providerOptions = this.buildProviderOptions();
|
|
3174
|
+
if (!providerOptions.length) {
|
|
3175
|
+
display.showWarning('No providers are configured.');
|
|
3176
|
+
display.showInfo('Set an API key: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.');
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
const lines = [
|
|
3180
|
+
theme.bold('Configured Providers:'),
|
|
3181
|
+
'',
|
|
3182
|
+
...providerOptions.map((option) => {
|
|
3183
|
+
const isCurrent = option.provider === this.sessionState.provider;
|
|
3184
|
+
const marker = isCurrent ? theme.primary(' ← active') : '';
|
|
3185
|
+
const countLabel = `${option.modelCount} model${option.modelCount === 1 ? '' : 's'}`;
|
|
3186
|
+
return ` ${theme.success('✓')} ${option.label} (${option.provider}) — ${countLabel}${marker}`;
|
|
3187
|
+
}),
|
|
3188
|
+
'',
|
|
3189
|
+
'Switch with: /provider <name>',
|
|
3190
|
+
'Example: /provider xai',
|
|
3191
|
+
];
|
|
3192
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Handle the /local command for local/air-gapped LLM management.
|
|
3196
|
+
*/
|
|
3197
|
+
async handleLocalCommand(input) {
|
|
3198
|
+
const tokens = input.trim().split(/\s+/).slice(1);
|
|
3199
|
+
const subcommand = (tokens[0] ?? '').toLowerCase();
|
|
3200
|
+
switch (subcommand) {
|
|
3201
|
+
case '':
|
|
3202
|
+
case 'scan':
|
|
3203
|
+
case 'status':
|
|
3204
|
+
await this.scanLocalProviders();
|
|
3205
|
+
break;
|
|
3206
|
+
case 'use':
|
|
3207
|
+
const provider = tokens[1]?.toLowerCase();
|
|
3208
|
+
if (!provider) {
|
|
3209
|
+
display.showWarning('Usage: /local use <provider>');
|
|
3210
|
+
display.showInfo('Example: /local use ollama');
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
await this.handleProviderCommand(`/provider ${provider}`);
|
|
3214
|
+
break;
|
|
3215
|
+
default:
|
|
3216
|
+
this.showLocalHelp();
|
|
3217
|
+
break;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
/**
|
|
3221
|
+
* Scan for running local LLM servers.
|
|
3222
|
+
*/
|
|
3223
|
+
async scanLocalProviders() {
|
|
3224
|
+
const localProviders = [
|
|
3225
|
+
{ id: 'ollama', label: 'Ollama', url: 'http://localhost:11434', envVar: 'OLLAMA_BASE_URL' },
|
|
3226
|
+
{ id: 'lmstudio', label: 'LM Studio', url: 'http://localhost:1234', envVar: 'LMSTUDIO_BASE_URL' },
|
|
3227
|
+
{ id: 'vllm', label: 'vLLM', url: 'http://localhost:8000', envVar: 'VLLM_BASE_URL' },
|
|
3228
|
+
{ id: 'llamacpp', label: 'llama.cpp', url: 'http://localhost:8080', envVar: 'LLAMACPP_BASE_URL' },
|
|
3229
|
+
];
|
|
3230
|
+
display.showInfo('Scanning for local LLM servers...');
|
|
3231
|
+
const results = [];
|
|
3232
|
+
for (const provider of localProviders) {
|
|
3233
|
+
const baseUrl = process.env[provider.envVar] || provider.url;
|
|
3234
|
+
try {
|
|
3235
|
+
const controller = new AbortController();
|
|
3236
|
+
const timeout = setTimeout(() => controller.abort(), 2000);
|
|
3237
|
+
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
3238
|
+
signal: controller.signal,
|
|
3239
|
+
}).catch(() => fetch(`${baseUrl}/v1/models`, { signal: controller.signal }));
|
|
3240
|
+
clearTimeout(timeout);
|
|
3241
|
+
if (response.ok) {
|
|
3242
|
+
const data = await response.json();
|
|
3243
|
+
const models = data.models?.map((m) => m.name) ?? [];
|
|
3244
|
+
results.push({ provider, running: true, models });
|
|
3245
|
+
}
|
|
3246
|
+
else {
|
|
3247
|
+
results.push({ provider, running: false });
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
catch {
|
|
3251
|
+
results.push({ provider, running: false });
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
const running = results.filter((r) => r.running);
|
|
3255
|
+
const stopped = results.filter((r) => !r.running);
|
|
3256
|
+
const lines = [theme.bold('Local LLM Servers:'), ''];
|
|
3257
|
+
if (running.length) {
|
|
3258
|
+
lines.push(theme.success('Running:'));
|
|
3259
|
+
for (const r of running) {
|
|
3260
|
+
const modelCount = r.models?.length ?? 0;
|
|
3261
|
+
const modelInfo = modelCount ? ` (${modelCount} model${modelCount === 1 ? '' : 's'})` : '';
|
|
3262
|
+
lines.push(` ${theme.success('●')} ${r.provider.label}${modelInfo}`);
|
|
3263
|
+
if (r.models?.length) {
|
|
3264
|
+
for (const model of r.models.slice(0, 5)) {
|
|
3265
|
+
lines.push(` • ${model}`);
|
|
3266
|
+
}
|
|
3267
|
+
if (r.models.length > 5) {
|
|
3268
|
+
lines.push(` • ... and ${r.models.length - 5} more`);
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
lines.push('');
|
|
3273
|
+
}
|
|
3274
|
+
if (stopped.length) {
|
|
3275
|
+
lines.push(theme.secondary('Not detected:'));
|
|
3276
|
+
for (const r of stopped) {
|
|
3277
|
+
lines.push(` ${theme.ui.muted('○')} ${r.provider.label}`);
|
|
3278
|
+
}
|
|
3279
|
+
lines.push('');
|
|
3280
|
+
}
|
|
3281
|
+
if (running.length) {
|
|
3282
|
+
lines.push(`Switch with: /local use ${running[0].provider.id}`);
|
|
3283
|
+
}
|
|
3284
|
+
else {
|
|
3285
|
+
lines.push('No local servers running.');
|
|
3286
|
+
lines.push('Install Ollama: https://ollama.ai');
|
|
3287
|
+
}
|
|
3288
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3289
|
+
}
|
|
3290
|
+
/**
|
|
3291
|
+
* Show help for /local commands.
|
|
3292
|
+
*/
|
|
3293
|
+
showLocalHelp() {
|
|
3294
|
+
const lines = [
|
|
3295
|
+
theme.bold('/local Commands:'),
|
|
3296
|
+
'',
|
|
3297
|
+
' /local Scan for running local LLM servers',
|
|
3298
|
+
' /local status Same as /local (scan for servers)',
|
|
3299
|
+
' /local use <name> Switch to a local provider',
|
|
3300
|
+
'',
|
|
3301
|
+
'Supported Local Providers:',
|
|
3302
|
+
' ollama - Easy-to-use local LLM runner (recommended)',
|
|
3303
|
+
' lmstudio - GUI-based local model serving',
|
|
3304
|
+
' vllm - High-throughput production serving',
|
|
3305
|
+
' llamacpp - Lightweight llama.cpp server',
|
|
3306
|
+
'',
|
|
3307
|
+
'Example:',
|
|
3308
|
+
' /local # Scan for running servers',
|
|
3309
|
+
' /local use ollama # Switch to Ollama',
|
|
3310
|
+
];
|
|
3311
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3312
|
+
}
|
|
3313
|
+
/**
|
|
3314
|
+
* Set the cached provider status for unified status bar display.
|
|
3315
|
+
* Called once at startup after checking providers.
|
|
3316
|
+
*/
|
|
3317
|
+
setProviderStatus(providers) {
|
|
3318
|
+
this.cachedProviderStatus = providers;
|
|
3319
|
+
}
|
|
3320
|
+
/**
|
|
3321
|
+
* Show the unified status bar (Claude Code style).
|
|
3322
|
+
* Displays provider indicators and ready hints before the prompt.
|
|
3323
|
+
*/
|
|
3324
|
+
showUnifiedStatusBar() {
|
|
3325
|
+
display.showUnifiedStatusBar(this.cachedProviderStatus);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
function setsEqual(first, second) {
|
|
3329
|
+
if (first.size !== second.size) {
|
|
3330
|
+
return false;
|
|
3331
|
+
}
|
|
3332
|
+
for (const entry of first) {
|
|
3333
|
+
if (!second.has(entry)) {
|
|
3334
|
+
return false;
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
return true;
|
|
3338
|
+
}
|
|
3339
|
+
//# sourceMappingURL=interactiveShell.js.map
|