erosolar-cli 1.7.412 → 1.7.414
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/shell/interactiveShell.d.ts +14 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +276 -89
- package/dist/shell/interactiveShell.js.map +1 -1
- package/package.json +1 -1
- package/dist/StringUtils.d.ts +0 -8
- package/dist/StringUtils.d.ts.map +0 -1
- package/dist/StringUtils.js +0 -11
- package/dist/StringUtils.js.map +0 -1
- package/dist/adapters/browser/index.d.ts +0 -12
- package/dist/adapters/browser/index.d.ts.map +0 -1
- package/dist/adapters/browser/index.js +0 -11
- package/dist/adapters/browser/index.js.map +0 -1
- package/dist/adapters/node/index.d.ts +0 -17
- package/dist/adapters/node/index.d.ts.map +0 -1
- package/dist/adapters/node/index.js +0 -35
- package/dist/adapters/node/index.js.map +0 -1
- package/dist/adapters/remote/index.d.ts +0 -13
- package/dist/adapters/remote/index.d.ts.map +0 -1
- package/dist/adapters/remote/index.js +0 -20
- package/dist/adapters/remote/index.js.map +0 -1
- package/dist/adapters/types.d.ts +0 -14
- package/dist/adapters/types.d.ts.map +0 -1
- package/dist/adapters/types.js +0 -2
- package/dist/adapters/types.js.map +0 -1
- package/dist/bin/erosolar.d.ts +0 -9
- package/dist/bin/erosolar.d.ts.map +0 -1
- package/dist/bin/erosolar.js +0 -93
- package/dist/bin/erosolar.js.map +0 -1
- package/dist/bin/selfTest.d.ts +0 -14
- package/dist/bin/selfTest.d.ts.map +0 -1
- package/dist/bin/selfTest.js +0 -304
- package/dist/bin/selfTest.js.map +0 -1
- package/dist/browser/BrowserSessionManager.d.ts +0 -307
- package/dist/browser/BrowserSessionManager.d.ts.map +0 -1
- package/dist/browser/BrowserSessionManager.js +0 -713
- package/dist/browser/BrowserSessionManager.js.map +0 -1
- package/dist/capabilities/advancedTestGenerationCapability.d.ts +0 -17
- package/dist/capabilities/advancedTestGenerationCapability.d.ts.map +0 -1
- package/dist/capabilities/advancedTestGenerationCapability.js +0 -28
- package/dist/capabilities/advancedTestGenerationCapability.js.map +0 -1
- package/dist/capabilities/agentSpawningCapability.d.ts +0 -6
- package/dist/capabilities/agentSpawningCapability.d.ts.map +0 -1
- package/dist/capabilities/agentSpawningCapability.js +0 -168
- package/dist/capabilities/agentSpawningCapability.js.map +0 -1
- package/dist/capabilities/askUserCapability.d.ts +0 -21
- package/dist/capabilities/askUserCapability.d.ts.map +0 -1
- package/dist/capabilities/askUserCapability.js +0 -155
- package/dist/capabilities/askUserCapability.js.map +0 -1
- package/dist/capabilities/bashCapability.d.ts +0 -13
- package/dist/capabilities/bashCapability.d.ts.map +0 -1
- package/dist/capabilities/bashCapability.js +0 -24
- package/dist/capabilities/bashCapability.js.map +0 -1
- package/dist/capabilities/browserAutomationCapability.d.ts +0 -37
- package/dist/capabilities/browserAutomationCapability.d.ts.map +0 -1
- package/dist/capabilities/browserAutomationCapability.js +0 -49
- package/dist/capabilities/browserAutomationCapability.js.map +0 -1
- package/dist/capabilities/buildCapability.d.ts +0 -24
- package/dist/capabilities/buildCapability.d.ts.map +0 -1
- package/dist/capabilities/buildCapability.js +0 -25
- package/dist/capabilities/buildCapability.js.map +0 -1
- package/dist/capabilities/cloudCapability.d.ts +0 -13
- package/dist/capabilities/cloudCapability.d.ts.map +0 -1
- package/dist/capabilities/cloudCapability.js +0 -38
- package/dist/capabilities/cloudCapability.js.map +0 -1
- package/dist/capabilities/codeAnalysisCapability.d.ts +0 -13
- package/dist/capabilities/codeAnalysisCapability.d.ts.map +0 -1
- package/dist/capabilities/codeAnalysisCapability.js +0 -24
- package/dist/capabilities/codeAnalysisCapability.js.map +0 -1
- package/dist/capabilities/codeGenerationCapability.d.ts +0 -13
- package/dist/capabilities/codeGenerationCapability.d.ts.map +0 -1
- package/dist/capabilities/codeGenerationCapability.js +0 -25
- package/dist/capabilities/codeGenerationCapability.js.map +0 -1
- package/dist/capabilities/codeQualityCapability.d.ts +0 -13
- package/dist/capabilities/codeQualityCapability.d.ts.map +0 -1
- package/dist/capabilities/codeQualityCapability.js +0 -25
- package/dist/capabilities/codeQualityCapability.js.map +0 -1
- package/dist/capabilities/dependencySecurityCapability.d.ts +0 -13
- package/dist/capabilities/dependencySecurityCapability.d.ts.map +0 -1
- package/dist/capabilities/dependencySecurityCapability.js +0 -24
- package/dist/capabilities/dependencySecurityCapability.js.map +0 -1
- package/dist/capabilities/devCapability.d.ts +0 -13
- package/dist/capabilities/devCapability.d.ts.map +0 -1
- package/dist/capabilities/devCapability.js +0 -24
- package/dist/capabilities/devCapability.js.map +0 -1
- package/dist/capabilities/editCapability.d.ts +0 -17
- package/dist/capabilities/editCapability.d.ts.map +0 -1
- package/dist/capabilities/editCapability.js +0 -27
- package/dist/capabilities/editCapability.js.map +0 -1
- package/dist/capabilities/emailCapability.d.ts +0 -12
- package/dist/capabilities/emailCapability.d.ts.map +0 -1
- package/dist/capabilities/emailCapability.js +0 -22
- package/dist/capabilities/emailCapability.js.map +0 -1
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts +0 -17
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js +0 -28
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js.map +0 -1
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts +0 -17
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedDevWorkflowCapability.js +0 -28
- package/dist/capabilities/enhancedDevWorkflowCapability.js.map +0 -1
- package/dist/capabilities/enhancedGitCapability.d.ts +0 -7
- package/dist/capabilities/enhancedGitCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedGitCapability.js +0 -220
- package/dist/capabilities/enhancedGitCapability.js.map +0 -1
- package/dist/capabilities/filesystemCapability.d.ts +0 -13
- package/dist/capabilities/filesystemCapability.d.ts.map +0 -1
- package/dist/capabilities/filesystemCapability.js +0 -24
- package/dist/capabilities/filesystemCapability.js.map +0 -1
- package/dist/capabilities/frontendTestingCapability.d.ts +0 -13
- package/dist/capabilities/frontendTestingCapability.d.ts.map +0 -1
- package/dist/capabilities/frontendTestingCapability.js +0 -28
- package/dist/capabilities/frontendTestingCapability.js.map +0 -1
- package/dist/capabilities/globCapability.d.ts +0 -17
- package/dist/capabilities/globCapability.d.ts.map +0 -1
- package/dist/capabilities/globCapability.js +0 -27
- package/dist/capabilities/globCapability.js.map +0 -1
- package/dist/capabilities/index.d.ts +0 -26
- package/dist/capabilities/index.d.ts.map +0 -1
- package/dist/capabilities/index.js +0 -26
- package/dist/capabilities/index.js.map +0 -1
- package/dist/capabilities/interactionCapability.d.ts +0 -12
- package/dist/capabilities/interactionCapability.d.ts.map +0 -1
- package/dist/capabilities/interactionCapability.js +0 -22
- package/dist/capabilities/interactionCapability.js.map +0 -1
- package/dist/capabilities/learnCapability.d.ts +0 -22
- package/dist/capabilities/learnCapability.d.ts.map +0 -1
- package/dist/capabilities/learnCapability.js +0 -37
- package/dist/capabilities/learnCapability.js.map +0 -1
- package/dist/capabilities/mcpCapability.d.ts +0 -6
- package/dist/capabilities/mcpCapability.d.ts.map +0 -1
- package/dist/capabilities/mcpCapability.js +0 -19
- package/dist/capabilities/mcpCapability.js.map +0 -1
- package/dist/capabilities/notebookCapability.d.ts +0 -17
- package/dist/capabilities/notebookCapability.d.ts.map +0 -1
- package/dist/capabilities/notebookCapability.js +0 -27
- package/dist/capabilities/notebookCapability.js.map +0 -1
- package/dist/capabilities/performanceMonitoringCapability.d.ts +0 -108
- package/dist/capabilities/performanceMonitoringCapability.d.ts.map +0 -1
- package/dist/capabilities/performanceMonitoringCapability.js +0 -176
- package/dist/capabilities/performanceMonitoringCapability.js.map +0 -1
- package/dist/capabilities/planningCapability.d.ts +0 -16
- package/dist/capabilities/planningCapability.d.ts.map +0 -1
- package/dist/capabilities/planningCapability.js +0 -26
- package/dist/capabilities/planningCapability.js.map +0 -1
- package/dist/capabilities/refactoringCapability.d.ts +0 -13
- package/dist/capabilities/refactoringCapability.d.ts.map +0 -1
- package/dist/capabilities/refactoringCapability.js +0 -25
- package/dist/capabilities/refactoringCapability.js.map +0 -1
- package/dist/capabilities/repoChecksCapability.d.ts +0 -10
- package/dist/capabilities/repoChecksCapability.d.ts.map +0 -1
- package/dist/capabilities/repoChecksCapability.js +0 -24
- package/dist/capabilities/repoChecksCapability.js.map +0 -1
- package/dist/capabilities/searchCapability.d.ts +0 -13
- package/dist/capabilities/searchCapability.d.ts.map +0 -1
- package/dist/capabilities/searchCapability.js +0 -24
- package/dist/capabilities/searchCapability.js.map +0 -1
- package/dist/capabilities/skillCapability.d.ts +0 -3
- package/dist/capabilities/skillCapability.d.ts.map +0 -1
- package/dist/capabilities/skillCapability.js +0 -77
- package/dist/capabilities/skillCapability.js.map +0 -1
- package/dist/capabilities/taskManagementCapability.d.ts +0 -12
- package/dist/capabilities/taskManagementCapability.d.ts.map +0 -1
- package/dist/capabilities/taskManagementCapability.js +0 -22
- package/dist/capabilities/taskManagementCapability.js.map +0 -1
- package/dist/capabilities/testingCapability.d.ts +0 -13
- package/dist/capabilities/testingCapability.d.ts.map +0 -1
- package/dist/capabilities/testingCapability.js +0 -25
- package/dist/capabilities/testingCapability.js.map +0 -1
- package/dist/capabilities/todoCapability.d.ts +0 -19
- package/dist/capabilities/todoCapability.d.ts.map +0 -1
- package/dist/capabilities/todoCapability.js +0 -169
- package/dist/capabilities/todoCapability.js.map +0 -1
- package/dist/capabilities/toolManifest.d.ts +0 -3
- package/dist/capabilities/toolManifest.d.ts.map +0 -1
- package/dist/capabilities/toolManifest.js +0 -160
- package/dist/capabilities/toolManifest.js.map +0 -1
- package/dist/capabilities/toolRegistry.d.ts +0 -24
- package/dist/capabilities/toolRegistry.d.ts.map +0 -1
- package/dist/capabilities/toolRegistry.js +0 -150
- package/dist/capabilities/toolRegistry.js.map +0 -1
- package/dist/capabilities/validationCapability.d.ts +0 -13
- package/dist/capabilities/validationCapability.d.ts.map +0 -1
- package/dist/capabilities/validationCapability.js +0 -24
- package/dist/capabilities/validationCapability.js.map +0 -1
- package/dist/capabilities/webCapability.d.ts +0 -12
- package/dist/capabilities/webCapability.d.ts.map +0 -1
- package/dist/capabilities/webCapability.js +0 -22
- package/dist/capabilities/webCapability.js.map +0 -1
- package/dist/config.d.ts +0 -25
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -140
- package/dist/config.js.map +0 -1
- package/dist/contracts/v1/agent.d.ts +0 -147
- package/dist/contracts/v1/agent.d.ts.map +0 -1
- package/dist/contracts/v1/agent.js +0 -8
- package/dist/contracts/v1/agent.js.map +0 -1
- package/dist/contracts/v1/agentProfileManifest.d.ts +0 -60
- package/dist/contracts/v1/agentProfileManifest.d.ts.map +0 -1
- package/dist/contracts/v1/agentProfileManifest.js +0 -9
- package/dist/contracts/v1/agentProfileManifest.js.map +0 -1
- package/dist/contracts/v1/agentRules.d.ts +0 -60
- package/dist/contracts/v1/agentRules.d.ts.map +0 -1
- package/dist/contracts/v1/agentRules.js +0 -10
- package/dist/contracts/v1/agentRules.js.map +0 -1
- package/dist/contracts/v1/provider.d.ts +0 -149
- package/dist/contracts/v1/provider.d.ts.map +0 -1
- package/dist/contracts/v1/provider.js +0 -7
- package/dist/contracts/v1/provider.js.map +0 -1
- package/dist/contracts/v1/tool.d.ts +0 -136
- package/dist/contracts/v1/tool.d.ts.map +0 -1
- package/dist/contracts/v1/tool.js +0 -7
- package/dist/contracts/v1/tool.js.map +0 -1
- package/dist/contracts/v1/toolAccess.d.ts +0 -43
- package/dist/contracts/v1/toolAccess.d.ts.map +0 -1
- package/dist/contracts/v1/toolAccess.js +0 -9
- package/dist/contracts/v1/toolAccess.js.map +0 -1
- package/dist/core/LazyLoader.d.ts +0 -129
- package/dist/core/LazyLoader.d.ts.map +0 -1
- package/dist/core/LazyLoader.js +0 -240
- package/dist/core/LazyLoader.js.map +0 -1
- package/dist/core/agent.d.ts +0 -153
- package/dist/core/agent.d.ts.map +0 -1
- package/dist/core/agent.js +0 -881
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agentProfileManifest.d.ts +0 -3
- package/dist/core/agentProfileManifest.d.ts.map +0 -1
- package/dist/core/agentProfileManifest.js +0 -188
- package/dist/core/agentProfileManifest.js.map +0 -1
- package/dist/core/agentProfiles.d.ts +0 -22
- package/dist/core/agentProfiles.d.ts.map +0 -1
- package/dist/core/agentProfiles.js +0 -35
- package/dist/core/agentProfiles.js.map +0 -1
- package/dist/core/agentRulebook.d.ts +0 -11
- package/dist/core/agentRulebook.d.ts.map +0 -1
- package/dist/core/agentRulebook.js +0 -136
- package/dist/core/agentRulebook.js.map +0 -1
- package/dist/core/agentSchemaLoader.d.ts +0 -131
- package/dist/core/agentSchemaLoader.d.ts.map +0 -1
- package/dist/core/agentSchemaLoader.js +0 -234
- package/dist/core/agentSchemaLoader.js.map +0 -1
- package/dist/core/aiErrorFixer.d.ts +0 -70
- package/dist/core/aiErrorFixer.d.ts.map +0 -1
- package/dist/core/aiErrorFixer.js +0 -402
- package/dist/core/aiErrorFixer.js.map +0 -1
- package/dist/core/alphaZeroEngine.d.ts +0 -269
- package/dist/core/alphaZeroEngine.d.ts.map +0 -1
- package/dist/core/alphaZeroEngine.js +0 -523
- package/dist/core/alphaZeroEngine.js.map +0 -1
- package/dist/core/alphaZeroModular.d.ts +0 -186
- package/dist/core/alphaZeroModular.d.ts.map +0 -1
- package/dist/core/alphaZeroModular.js +0 -755
- package/dist/core/alphaZeroModular.js.map +0 -1
- package/dist/core/alphaZeroOrchestrator.d.ts +0 -140
- package/dist/core/alphaZeroOrchestrator.d.ts.map +0 -1
- package/dist/core/alphaZeroOrchestrator.js +0 -418
- package/dist/core/alphaZeroOrchestrator.js.map +0 -1
- package/dist/core/checkpoint.d.ts +0 -76
- package/dist/core/checkpoint.d.ts.map +0 -1
- package/dist/core/checkpoint.js +0 -278
- package/dist/core/checkpoint.js.map +0 -1
- package/dist/core/claudeCodeFeatures.d.ts +0 -64
- package/dist/core/claudeCodeFeatures.d.ts.map +0 -1
- package/dist/core/claudeCodeFeatures.js +0 -163
- package/dist/core/claudeCodeFeatures.js.map +0 -1
- package/dist/core/cliTestHarness.d.ts +0 -200
- package/dist/core/cliTestHarness.d.ts.map +0 -1
- package/dist/core/cliTestHarness.js +0 -549
- package/dist/core/cliTestHarness.js.map +0 -1
- package/dist/core/contextManager.d.ts +0 -263
- package/dist/core/contextManager.d.ts.map +0 -1
- package/dist/core/contextManager.js +0 -1073
- package/dist/core/contextManager.js.map +0 -1
- package/dist/core/contextWindow.d.ts +0 -42
- package/dist/core/contextWindow.d.ts.map +0 -1
- package/dist/core/contextWindow.js +0 -123
- package/dist/core/contextWindow.js.map +0 -1
- package/dist/core/costTracker.d.ts +0 -87
- package/dist/core/costTracker.d.ts.map +0 -1
- package/dist/core/costTracker.js +0 -285
- package/dist/core/costTracker.js.map +0 -1
- package/dist/core/customCommands.d.ts +0 -19
- package/dist/core/customCommands.d.ts.map +0 -1
- package/dist/core/customCommands.js +0 -84
- package/dist/core/customCommands.js.map +0 -1
- package/dist/core/errors/apiKeyErrors.d.ts +0 -11
- package/dist/core/errors/apiKeyErrors.d.ts.map +0 -1
- package/dist/core/errors/apiKeyErrors.js +0 -159
- package/dist/core/errors/apiKeyErrors.js.map +0 -1
- package/dist/core/errors/errorTypes.d.ts +0 -111
- package/dist/core/errors/errorTypes.d.ts.map +0 -1
- package/dist/core/errors/errorTypes.js +0 -348
- package/dist/core/errors/errorTypes.js.map +0 -1
- package/dist/core/errors/errorUtils.d.ts +0 -87
- package/dist/core/errors/errorUtils.d.ts.map +0 -1
- package/dist/core/errors/errorUtils.js +0 -158
- package/dist/core/errors/errorUtils.js.map +0 -1
- package/dist/core/errors/safetyValidator.d.ts +0 -71
- package/dist/core/errors/safetyValidator.d.ts.map +0 -1
- package/dist/core/errors/safetyValidator.js +0 -302
- package/dist/core/errors/safetyValidator.js.map +0 -1
- package/dist/core/errors.d.ts +0 -4
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -33
- package/dist/core/errors.js.map +0 -1
- package/dist/core/failureRecovery.d.ts +0 -122
- package/dist/core/failureRecovery.d.ts.map +0 -1
- package/dist/core/failureRecovery.js +0 -477
- package/dist/core/failureRecovery.js.map +0 -1
- package/dist/core/hooks.d.ts +0 -113
- package/dist/core/hooks.d.ts.map +0 -1
- package/dist/core/hooks.js +0 -267
- package/dist/core/hooks.js.map +0 -1
- package/dist/core/intelligentTestFlows.d.ts +0 -126
- package/dist/core/intelligentTestFlows.d.ts.map +0 -1
- package/dist/core/intelligentTestFlows.js +0 -678
- package/dist/core/intelligentTestFlows.js.map +0 -1
- package/dist/core/isolatedVerifier.d.ts +0 -40
- package/dist/core/isolatedVerifier.d.ts.map +0 -1
- package/dist/core/isolatedVerifier.js +0 -129
- package/dist/core/isolatedVerifier.js.map +0 -1
- package/dist/core/learningPersistence.d.ts +0 -145
- package/dist/core/learningPersistence.d.ts.map +0 -1
- package/dist/core/learningPersistence.js +0 -477
- package/dist/core/learningPersistence.js.map +0 -1
- package/dist/core/memorySystem.d.ts +0 -67
- package/dist/core/memorySystem.d.ts.map +0 -1
- package/dist/core/memorySystem.js +0 -334
- package/dist/core/memorySystem.js.map +0 -1
- package/dist/core/metricsTracker.d.ts +0 -157
- package/dist/core/metricsTracker.d.ts.map +0 -1
- package/dist/core/metricsTracker.js +0 -273
- package/dist/core/metricsTracker.js.map +0 -1
- package/dist/core/modelDiscovery.d.ts +0 -101
- package/dist/core/modelDiscovery.d.ts.map +0 -1
- package/dist/core/modelDiscovery.js +0 -780
- package/dist/core/modelDiscovery.js.map +0 -1
- package/dist/core/multilinePasteHandler.d.ts +0 -35
- package/dist/core/multilinePasteHandler.d.ts.map +0 -1
- package/dist/core/multilinePasteHandler.js +0 -80
- package/dist/core/multilinePasteHandler.js.map +0 -1
- package/dist/core/offsecAlphaZero.d.ts +0 -56
- package/dist/core/offsecAlphaZero.d.ts.map +0 -1
- package/dist/core/offsecAlphaZero.js +0 -395
- package/dist/core/offsecAlphaZero.js.map +0 -1
- package/dist/core/outputStyles.d.ts +0 -48
- package/dist/core/outputStyles.d.ts.map +0 -1
- package/dist/core/outputStyles.js +0 -270
- package/dist/core/outputStyles.js.map +0 -1
- package/dist/core/performanceMonitor.d.ts +0 -124
- package/dist/core/performanceMonitor.d.ts.map +0 -1
- package/dist/core/performanceMonitor.js +0 -192
- package/dist/core/performanceMonitor.js.map +0 -1
- package/dist/core/preferences.d.ts +0 -67
- package/dist/core/preferences.d.ts.map +0 -1
- package/dist/core/preferences.js +0 -314
- package/dist/core/preferences.js.map +0 -1
- package/dist/core/responseVerifier.d.ts +0 -98
- package/dist/core/responseVerifier.d.ts.map +0 -1
- package/dist/core/responseVerifier.js +0 -509
- package/dist/core/responseVerifier.js.map +0 -1
- package/dist/core/resultVerification.d.ts +0 -141
- package/dist/core/resultVerification.d.ts.map +0 -1
- package/dist/core/resultVerification.js +0 -482
- package/dist/core/resultVerification.js.map +0 -1
- package/dist/core/schemaValidator.d.ts +0 -44
- package/dist/core/schemaValidator.d.ts.map +0 -1
- package/dist/core/schemaValidator.js +0 -155
- package/dist/core/schemaValidator.js.map +0 -1
- package/dist/core/secretStore.d.ts +0 -48
- package/dist/core/secretStore.d.ts.map +0 -1
- package/dist/core/secretStore.js +0 -367
- package/dist/core/secretStore.js.map +0 -1
- package/dist/core/securityAssessment.d.ts +0 -91
- package/dist/core/securityAssessment.d.ts.map +0 -1
- package/dist/core/securityAssessment.js +0 -580
- package/dist/core/securityAssessment.js.map +0 -1
- package/dist/core/selfEvolution.d.ts +0 -155
- package/dist/core/selfEvolution.d.ts.map +0 -1
- package/dist/core/selfEvolution.js +0 -1000
- package/dist/core/selfEvolution.js.map +0 -1
- package/dist/core/selfImprovement.d.ts +0 -141
- package/dist/core/selfImprovement.d.ts.map +0 -1
- package/dist/core/selfImprovement.js +0 -700
- package/dist/core/selfImprovement.js.map +0 -1
- package/dist/core/sessionStore.d.ts +0 -35
- package/dist/core/sessionStore.d.ts.map +0 -1
- package/dist/core/sessionStore.js +0 -189
- package/dist/core/sessionStore.js.map +0 -1
- package/dist/core/testUtils.d.ts +0 -121
- package/dist/core/testUtils.d.ts.map +0 -1
- package/dist/core/testUtils.js +0 -235
- package/dist/core/testUtils.js.map +0 -1
- package/dist/core/toolPreconditions.d.ts +0 -42
- package/dist/core/toolPreconditions.d.ts.map +0 -1
- package/dist/core/toolPreconditions.js +0 -357
- package/dist/core/toolPreconditions.js.map +0 -1
- package/dist/core/toolRuntime.d.ts +0 -158
- package/dist/core/toolRuntime.d.ts.map +0 -1
- package/dist/core/toolRuntime.js +0 -415
- package/dist/core/toolRuntime.js.map +0 -1
- package/dist/core/toolValidation.d.ts +0 -117
- package/dist/core/toolValidation.d.ts.map +0 -1
- package/dist/core/toolValidation.js +0 -282
- package/dist/core/toolValidation.js.map +0 -1
- package/dist/core/types/utilityTypes.d.ts +0 -192
- package/dist/core/types/utilityTypes.d.ts.map +0 -1
- package/dist/core/types/utilityTypes.js +0 -272
- package/dist/core/types/utilityTypes.js.map +0 -1
- package/dist/core/types.d.ts +0 -306
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -76
- package/dist/core/types.js.map +0 -1
- package/dist/core/updateManager.d.ts +0 -62
- package/dist/core/updateManager.d.ts.map +0 -1
- package/dist/core/updateManager.js +0 -266
- package/dist/core/updateManager.js.map +0 -1
- package/dist/core/validationRunner.d.ts +0 -106
- package/dist/core/validationRunner.d.ts.map +0 -1
- package/dist/core/validationRunner.js +0 -888
- package/dist/core/validationRunner.js.map +0 -1
- package/dist/core/verification.d.ts +0 -137
- package/dist/core/verification.d.ts.map +0 -1
- package/dist/core/verification.js +0 -323
- package/dist/core/verification.js.map +0 -1
- package/dist/headless/headlessApp.d.ts +0 -5
- package/dist/headless/headlessApp.d.ts.map +0 -1
- package/dist/headless/headlessApp.js +0 -210
- package/dist/headless/headlessApp.js.map +0 -1
- package/dist/intelligence/codeIntelligence.d.ts +0 -118
- package/dist/intelligence/codeIntelligence.d.ts.map +0 -1
- package/dist/intelligence/codeIntelligence.js +0 -552
- package/dist/intelligence/codeIntelligence.js.map +0 -1
- package/dist/intelligence/docGenerator.d.ts +0 -86
- package/dist/intelligence/docGenerator.d.ts.map +0 -1
- package/dist/intelligence/docGenerator.js +0 -564
- package/dist/intelligence/docGenerator.js.map +0 -1
- package/dist/intelligence/index.d.ts +0 -51
- package/dist/intelligence/index.d.ts.map +0 -1
- package/dist/intelligence/index.js +0 -253
- package/dist/intelligence/index.js.map +0 -1
- package/dist/intelligence/refactoring.d.ts +0 -50
- package/dist/intelligence/refactoring.d.ts.map +0 -1
- package/dist/intelligence/refactoring.js +0 -354
- package/dist/intelligence/refactoring.js.map +0 -1
- package/dist/intelligence/testGenerator.d.ts +0 -74
- package/dist/intelligence/testGenerator.d.ts.map +0 -1
- package/dist/intelligence/testGenerator.js +0 -483
- package/dist/intelligence/testGenerator.js.map +0 -1
- package/dist/mcp/config.d.ts +0 -8
- package/dist/mcp/config.d.ts.map +0 -1
- package/dist/mcp/config.js +0 -252
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/sseClient.d.ts +0 -34
- package/dist/mcp/sseClient.d.ts.map +0 -1
- package/dist/mcp/sseClient.js +0 -327
- package/dist/mcp/sseClient.js.map +0 -1
- package/dist/mcp/stdioClient.d.ts +0 -24
- package/dist/mcp/stdioClient.d.ts.map +0 -1
- package/dist/mcp/stdioClient.js +0 -179
- package/dist/mcp/stdioClient.js.map +0 -1
- package/dist/mcp/toolBridge.d.ts +0 -12
- package/dist/mcp/toolBridge.d.ts.map +0 -1
- package/dist/mcp/toolBridge.js +0 -117
- package/dist/mcp/toolBridge.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -60
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js +0 -2
- package/dist/mcp/types.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -49
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -114
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/providers/anthropic/index.d.ts +0 -11
- package/dist/plugins/providers/anthropic/index.d.ts.map +0 -1
- package/dist/plugins/providers/anthropic/index.js +0 -38
- package/dist/plugins/providers/anthropic/index.js.map +0 -1
- package/dist/plugins/providers/deepseek/index.d.ts +0 -11
- package/dist/plugins/providers/deepseek/index.d.ts.map +0 -1
- package/dist/plugins/providers/deepseek/index.js +0 -52
- package/dist/plugins/providers/deepseek/index.js.map +0 -1
- package/dist/plugins/providers/google/index.d.ts +0 -11
- package/dist/plugins/providers/google/index.d.ts.map +0 -1
- package/dist/plugins/providers/google/index.js +0 -40
- package/dist/plugins/providers/google/index.js.map +0 -1
- package/dist/plugins/providers/index.d.ts +0 -2
- package/dist/plugins/providers/index.d.ts.map +0 -1
- package/dist/plugins/providers/index.js +0 -20
- package/dist/plugins/providers/index.js.map +0 -1
- package/dist/plugins/providers/ollama/index.d.ts +0 -21
- package/dist/plugins/providers/ollama/index.d.ts.map +0 -1
- package/dist/plugins/providers/ollama/index.js +0 -69
- package/dist/plugins/providers/ollama/index.js.map +0 -1
- package/dist/plugins/providers/openai/index.d.ts +0 -12
- package/dist/plugins/providers/openai/index.d.ts.map +0 -1
- package/dist/plugins/providers/openai/index.js +0 -39
- package/dist/plugins/providers/openai/index.js.map +0 -1
- package/dist/plugins/providers/xai/index.d.ts +0 -11
- package/dist/plugins/providers/xai/index.d.ts.map +0 -1
- package/dist/plugins/providers/xai/index.js +0 -39
- package/dist/plugins/providers/xai/index.js.map +0 -1
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +0 -3
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +0 -9
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +0 -1
- package/dist/plugins/tools/bash/localBashPlugin.d.ts +0 -3
- package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/bash/localBashPlugin.js +0 -14
- package/dist/plugins/tools/bash/localBashPlugin.js.map +0 -1
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts +0 -14
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/browser/browserAutomationPlugin.js +0 -26
- package/dist/plugins/tools/browser/browserAutomationPlugin.js.map +0 -1
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts +0 -3
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js +0 -14
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js.map +0 -1
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts +0 -3
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/cloud/cloudPlugin.js +0 -14
- package/dist/plugins/tools/cloud/cloudPlugin.js.map +0 -1
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts +0 -3
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +0 -14
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js.map +0 -1
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts +0 -3
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js +0 -14
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js.map +0 -1
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts +0 -3
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/dependency/dependencyPlugin.js +0 -12
- package/dist/plugins/tools/dependency/dependencyPlugin.js.map +0 -1
- package/dist/plugins/tools/development/devPlugin.d.ts +0 -3
- package/dist/plugins/tools/development/devPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/development/devPlugin.js +0 -14
- package/dist/plugins/tools/development/devPlugin.js.map +0 -1
- package/dist/plugins/tools/edit/editPlugin.d.ts +0 -9
- package/dist/plugins/tools/edit/editPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/edit/editPlugin.js +0 -15
- package/dist/plugins/tools/edit/editPlugin.js.map +0 -1
- package/dist/plugins/tools/email/emailPlugin.d.ts +0 -3
- package/dist/plugins/tools/email/emailPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/email/emailPlugin.js +0 -12
- package/dist/plugins/tools/email/emailPlugin.js.map +0 -1
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +0 -3
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +0 -9
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +0 -1
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +0 -3
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +0 -14
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +0 -1
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts +0 -3
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js +0 -14
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js.map +0 -1
- package/dist/plugins/tools/glob/globPlugin.d.ts +0 -9
- package/dist/plugins/tools/glob/globPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/glob/globPlugin.js +0 -15
- package/dist/plugins/tools/glob/globPlugin.js.map +0 -1
- package/dist/plugins/tools/index.d.ts +0 -3
- package/dist/plugins/tools/index.d.ts.map +0 -1
- package/dist/plugins/tools/index.js +0 -3
- package/dist/plugins/tools/index.js.map +0 -1
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts +0 -3
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/interaction/interactionPlugin.js +0 -12
- package/dist/plugins/tools/interaction/interactionPlugin.js.map +0 -1
- package/dist/plugins/tools/learn/learnPlugin.d.ts +0 -3
- package/dist/plugins/tools/learn/learnPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/learn/learnPlugin.js +0 -14
- package/dist/plugins/tools/learn/learnPlugin.js.map +0 -1
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts +0 -3
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/mcp/mcpPlugin.js +0 -9
- package/dist/plugins/tools/mcp/mcpPlugin.js.map +0 -1
- package/dist/plugins/tools/nodeDefaults.d.ts +0 -2
- package/dist/plugins/tools/nodeDefaults.d.ts.map +0 -1
- package/dist/plugins/tools/nodeDefaults.js +0 -65
- package/dist/plugins/tools/nodeDefaults.js.map +0 -1
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts +0 -9
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/notebook/notebookPlugin.js +0 -15
- package/dist/plugins/tools/notebook/notebookPlugin.js.map +0 -1
- package/dist/plugins/tools/planning/planningPlugin.d.ts +0 -9
- package/dist/plugins/tools/planning/planningPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/planning/planningPlugin.js +0 -15
- package/dist/plugins/tools/planning/planningPlugin.js.map +0 -1
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts +0 -3
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/refactoring/refactoringPlugin.js +0 -12
- package/dist/plugins/tools/refactoring/refactoringPlugin.js.map +0 -1
- package/dist/plugins/tools/registry.d.ts +0 -22
- package/dist/plugins/tools/registry.d.ts.map +0 -1
- package/dist/plugins/tools/registry.js +0 -58
- package/dist/plugins/tools/registry.js.map +0 -1
- package/dist/plugins/tools/search/localSearchPlugin.d.ts +0 -3
- package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/search/localSearchPlugin.js +0 -14
- package/dist/plugins/tools/search/localSearchPlugin.js.map +0 -1
- package/dist/plugins/tools/skills/skillPlugin.d.ts +0 -3
- package/dist/plugins/tools/skills/skillPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/skills/skillPlugin.js +0 -9
- package/dist/plugins/tools/skills/skillPlugin.js.map +0 -1
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts +0 -3
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js +0 -12
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js.map +0 -1
- package/dist/plugins/tools/testing/testingPlugin.d.ts +0 -3
- package/dist/plugins/tools/testing/testingPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/testing/testingPlugin.js +0 -12
- package/dist/plugins/tools/testing/testingPlugin.js.map +0 -1
- package/dist/plugins/tools/validation/validationPlugin.d.ts +0 -3
- package/dist/plugins/tools/validation/validationPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/validation/validationPlugin.js +0 -14
- package/dist/plugins/tools/validation/validationPlugin.js.map +0 -1
- package/dist/plugins/tools/web/webPlugin.d.ts +0 -3
- package/dist/plugins/tools/web/webPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/web/webPlugin.js +0 -12
- package/dist/plugins/tools/web/webPlugin.js.map +0 -1
- package/dist/providers/anthropicProvider.d.ts +0 -41
- package/dist/providers/anthropicProvider.d.ts.map +0 -1
- package/dist/providers/anthropicProvider.js +0 -446
- package/dist/providers/anthropicProvider.js.map +0 -1
- package/dist/providers/googleProvider.d.ts +0 -36
- package/dist/providers/googleProvider.d.ts.map +0 -1
- package/dist/providers/googleProvider.js +0 -312
- package/dist/providers/googleProvider.js.map +0 -1
- package/dist/providers/openaiChatCompletionsProvider.d.ts +0 -43
- package/dist/providers/openaiChatCompletionsProvider.d.ts.map +0 -1
- package/dist/providers/openaiChatCompletionsProvider.js +0 -475
- package/dist/providers/openaiChatCompletionsProvider.js.map +0 -1
- package/dist/providers/openaiResponsesProvider.d.ts +0 -38
- package/dist/providers/openaiResponsesProvider.d.ts.map +0 -1
- package/dist/providers/openaiResponsesProvider.js +0 -364
- package/dist/providers/openaiResponsesProvider.js.map +0 -1
- package/dist/providers/providerFactory.d.ts +0 -18
- package/dist/providers/providerFactory.d.ts.map +0 -1
- package/dist/providers/providerFactory.js +0 -25
- package/dist/providers/providerFactory.js.map +0 -1
- package/dist/providers/resilientProvider.d.ts +0 -94
- package/dist/providers/resilientProvider.d.ts.map +0 -1
- package/dist/providers/resilientProvider.js +0 -370
- package/dist/providers/resilientProvider.js.map +0 -1
- package/dist/runtime/agentController.d.ts +0 -65
- package/dist/runtime/agentController.d.ts.map +0 -1
- package/dist/runtime/agentController.js +0 -353
- package/dist/runtime/agentController.js.map +0 -1
- package/dist/runtime/agentHost.d.ts +0 -61
- package/dist/runtime/agentHost.d.ts.map +0 -1
- package/dist/runtime/agentHost.js +0 -156
- package/dist/runtime/agentHost.js.map +0 -1
- package/dist/runtime/agentSession.d.ts +0 -40
- package/dist/runtime/agentSession.d.ts.map +0 -1
- package/dist/runtime/agentSession.js +0 -206
- package/dist/runtime/agentSession.js.map +0 -1
- package/dist/runtime/browser.d.ts +0 -7
- package/dist/runtime/browser.d.ts.map +0 -1
- package/dist/runtime/browser.js +0 -10
- package/dist/runtime/browser.js.map +0 -1
- package/dist/runtime/cloud.d.ts +0 -7
- package/dist/runtime/cloud.d.ts.map +0 -1
- package/dist/runtime/cloud.js +0 -10
- package/dist/runtime/cloud.js.map +0 -1
- package/dist/runtime/node.d.ts +0 -8
- package/dist/runtime/node.d.ts.map +0 -1
- package/dist/runtime/node.js +0 -11
- package/dist/runtime/node.js.map +0 -1
- package/dist/runtime/universal.d.ts +0 -21
- package/dist/runtime/universal.d.ts.map +0 -1
- package/dist/runtime/universal.js +0 -29
- package/dist/runtime/universal.js.map +0 -1
- package/dist/shell/autoExecutor.d.ts +0 -70
- package/dist/shell/autoExecutor.d.ts.map +0 -1
- package/dist/shell/autoExecutor.js +0 -288
- package/dist/shell/autoExecutor.js.map +0 -1
- package/dist/shell/composableMessage.d.ts +0 -183
- package/dist/shell/composableMessage.d.ts.map +0 -1
- package/dist/shell/composableMessage.js +0 -420
- package/dist/shell/composableMessage.js.map +0 -1
- package/dist/shell/fileChangeTracker.d.ts +0 -39
- package/dist/shell/fileChangeTracker.d.ts.map +0 -1
- package/dist/shell/fileChangeTracker.js +0 -64
- package/dist/shell/fileChangeTracker.js.map +0 -1
- package/dist/shell/keyboardShortcuts.d.ts +0 -53
- package/dist/shell/keyboardShortcuts.d.ts.map +0 -1
- package/dist/shell/keyboardShortcuts.js +0 -166
- package/dist/shell/keyboardShortcuts.js.map +0 -1
- package/dist/shell/liveStatus.d.ts +0 -30
- package/dist/shell/liveStatus.d.ts.map +0 -1
- package/dist/shell/liveStatus.js +0 -102
- package/dist/shell/liveStatus.js.map +0 -1
- package/dist/shell/shellApp.d.ts +0 -19
- package/dist/shell/shellApp.d.ts.map +0 -1
- package/dist/shell/shellApp.js +0 -408
- package/dist/shell/shellApp.js.map +0 -1
- package/dist/shell/systemPrompt.d.ts +0 -3
- package/dist/shell/systemPrompt.d.ts.map +0 -1
- package/dist/shell/systemPrompt.js +0 -81
- package/dist/shell/systemPrompt.js.map +0 -1
- package/dist/shell/taskCompletionDetector.d.ts +0 -106
- package/dist/shell/taskCompletionDetector.d.ts.map +0 -1
- package/dist/shell/taskCompletionDetector.js +0 -402
- package/dist/shell/taskCompletionDetector.js.map +0 -1
- package/dist/shell/terminalInput.d.ts +0 -617
- package/dist/shell/terminalInput.d.ts.map +0 -1
- package/dist/shell/terminalInput.js +0 -2633
- package/dist/shell/terminalInput.js.map +0 -1
- package/dist/shell/terminalInputAdapter.d.ts +0 -263
- package/dist/shell/terminalInputAdapter.d.ts.map +0 -1
- package/dist/shell/terminalInputAdapter.js +0 -406
- package/dist/shell/terminalInputAdapter.js.map +0 -1
- package/dist/shell/updateManager.d.ts +0 -3
- package/dist/shell/updateManager.d.ts.map +0 -1
- package/dist/shell/updateManager.js +0 -120
- package/dist/shell/updateManager.js.map +0 -1
- package/dist/shell/vimMode.d.ts +0 -66
- package/dist/shell/vimMode.d.ts.map +0 -1
- package/dist/shell/vimMode.js +0 -434
- package/dist/shell/vimMode.js.map +0 -1
- package/dist/skills/skillRepository.d.ts +0 -103
- package/dist/skills/skillRepository.d.ts.map +0 -1
- package/dist/skills/skillRepository.js +0 -237
- package/dist/skills/skillRepository.js.map +0 -1
- package/dist/skills/types.d.ts +0 -37
- package/dist/skills/types.d.ts.map +0 -1
- package/dist/skills/types.js +0 -2
- package/dist/skills/types.js.map +0 -1
- package/dist/subagents/agentConfig.d.ts +0 -27
- package/dist/subagents/agentConfig.d.ts.map +0 -1
- package/dist/subagents/agentConfig.js +0 -89
- package/dist/subagents/agentConfig.js.map +0 -1
- package/dist/subagents/agentRegistry.d.ts +0 -33
- package/dist/subagents/agentRegistry.d.ts.map +0 -1
- package/dist/subagents/agentRegistry.js +0 -162
- package/dist/subagents/agentRegistry.js.map +0 -1
- package/dist/subagents/parallelAgentManager.d.ts +0 -99
- package/dist/subagents/parallelAgentManager.d.ts.map +0 -1
- package/dist/subagents/parallelAgentManager.js +0 -248
- package/dist/subagents/parallelAgentManager.js.map +0 -1
- package/dist/subagents/taskRunner.d.ts +0 -34
- package/dist/subagents/taskRunner.d.ts.map +0 -1
- package/dist/subagents/taskRunner.js +0 -459
- package/dist/subagents/taskRunner.js.map +0 -1
- package/dist/tools/advancedTestGenerationTools.d.ts +0 -21
- package/dist/tools/advancedTestGenerationTools.d.ts.map +0 -1
- package/dist/tools/advancedTestGenerationTools.js +0 -301
- package/dist/tools/advancedTestGenerationTools.js.map +0 -1
- package/dist/tools/backgroundBashTools.d.ts +0 -21
- package/dist/tools/backgroundBashTools.d.ts.map +0 -1
- package/dist/tools/backgroundBashTools.js +0 -215
- package/dist/tools/backgroundBashTools.js.map +0 -1
- package/dist/tools/bashTools.d.ts +0 -8
- package/dist/tools/bashTools.d.ts.map +0 -1
- package/dist/tools/bashTools.js +0 -251
- package/dist/tools/bashTools.js.map +0 -1
- package/dist/tools/browserAutomationTools.d.ts +0 -23
- package/dist/tools/browserAutomationTools.d.ts.map +0 -1
- package/dist/tools/browserAutomationTools.js +0 -916
- package/dist/tools/browserAutomationTools.js.map +0 -1
- package/dist/tools/buildTools.d.ts +0 -9
- package/dist/tools/buildTools.d.ts.map +0 -1
- package/dist/tools/buildTools.js +0 -344
- package/dist/tools/buildTools.js.map +0 -1
- package/dist/tools/cloudTools.d.ts +0 -49
- package/dist/tools/cloudTools.d.ts.map +0 -1
- package/dist/tools/cloudTools.js +0 -1258
- package/dist/tools/cloudTools.js.map +0 -1
- package/dist/tools/code-quality-dashboard.d.ts +0 -57
- package/dist/tools/code-quality-dashboard.d.ts.map +0 -1
- package/dist/tools/code-quality-dashboard.js +0 -218
- package/dist/tools/code-quality-dashboard.js.map +0 -1
- package/dist/tools/codeAnalysisTools.d.ts +0 -74
- package/dist/tools/codeAnalysisTools.d.ts.map +0 -1
- package/dist/tools/codeAnalysisTools.js +0 -664
- package/dist/tools/codeAnalysisTools.js.map +0 -1
- package/dist/tools/codeGenerationTools.d.ts +0 -3
- package/dist/tools/codeGenerationTools.d.ts.map +0 -1
- package/dist/tools/codeGenerationTools.js +0 -439
- package/dist/tools/codeGenerationTools.js.map +0 -1
- package/dist/tools/codeQualityTools.d.ts +0 -3
- package/dist/tools/codeQualityTools.d.ts.map +0 -1
- package/dist/tools/codeQualityTools.js +0 -296
- package/dist/tools/codeQualityTools.js.map +0 -1
- package/dist/tools/dependencyTools.d.ts +0 -3
- package/dist/tools/dependencyTools.d.ts.map +0 -1
- package/dist/tools/dependencyTools.js +0 -283
- package/dist/tools/dependencyTools.js.map +0 -1
- package/dist/tools/devTools.d.ts +0 -10
- package/dist/tools/devTools.d.ts.map +0 -1
- package/dist/tools/devTools.js +0 -2125
- package/dist/tools/devTools.js.map +0 -1
- package/dist/tools/diffUtils.d.ts +0 -36
- package/dist/tools/diffUtils.d.ts.map +0 -1
- package/dist/tools/diffUtils.js +0 -528
- package/dist/tools/diffUtils.js.map +0 -1
- package/dist/tools/editTools.d.ts +0 -29
- package/dist/tools/editTools.d.ts.map +0 -1
- package/dist/tools/editTools.js +0 -419
- package/dist/tools/editTools.js.map +0 -1
- package/dist/tools/emailTools.d.ts +0 -21
- package/dist/tools/emailTools.d.ts.map +0 -1
- package/dist/tools/emailTools.js +0 -449
- package/dist/tools/emailTools.js.map +0 -1
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts +0 -27
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts.map +0 -1
- package/dist/tools/enhancedCodeIntelligenceTools.js +0 -418
- package/dist/tools/enhancedCodeIntelligenceTools.js.map +0 -1
- package/dist/tools/enhancedDevWorkflowTools.d.ts +0 -15
- package/dist/tools/enhancedDevWorkflowTools.d.ts.map +0 -1
- package/dist/tools/enhancedDevWorkflowTools.js +0 -303
- package/dist/tools/enhancedDevWorkflowTools.js.map +0 -1
- package/dist/tools/fileTools.d.ts +0 -3
- package/dist/tools/fileTools.d.ts.map +0 -1
- package/dist/tools/fileTools.js +0 -334
- package/dist/tools/fileTools.js.map +0 -1
- package/dist/tools/frontendTestingTools.d.ts +0 -35
- package/dist/tools/frontendTestingTools.d.ts.map +0 -1
- package/dist/tools/frontendTestingTools.js +0 -1254
- package/dist/tools/frontendTestingTools.js.map +0 -1
- package/dist/tools/globTools.d.ts +0 -15
- package/dist/tools/globTools.d.ts.map +0 -1
- package/dist/tools/globTools.js +0 -174
- package/dist/tools/globTools.js.map +0 -1
- package/dist/tools/grepTools.d.ts +0 -19
- package/dist/tools/grepTools.d.ts.map +0 -1
- package/dist/tools/grepTools.js +0 -358
- package/dist/tools/grepTools.js.map +0 -1
- package/dist/tools/interactionTools.d.ts +0 -13
- package/dist/tools/interactionTools.d.ts.map +0 -1
- package/dist/tools/interactionTools.js +0 -171
- package/dist/tools/interactionTools.js.map +0 -1
- package/dist/tools/learnTools.d.ts +0 -152
- package/dist/tools/learnTools.d.ts.map +0 -1
- package/dist/tools/learnTools.js +0 -1942
- package/dist/tools/learnTools.js.map +0 -1
- package/dist/tools/localExplore.d.ts +0 -225
- package/dist/tools/localExplore.d.ts.map +0 -1
- package/dist/tools/localExplore.js +0 -1291
- package/dist/tools/localExplore.js.map +0 -1
- package/dist/tools/notebookEditTools.d.ts +0 -15
- package/dist/tools/notebookEditTools.d.ts.map +0 -1
- package/dist/tools/notebookEditTools.js +0 -197
- package/dist/tools/notebookEditTools.js.map +0 -1
- package/dist/tools/planningTools.d.ts +0 -21
- package/dist/tools/planningTools.d.ts.map +0 -1
- package/dist/tools/planningTools.js +0 -185
- package/dist/tools/planningTools.js.map +0 -1
- package/dist/tools/refactoringTools.d.ts +0 -3
- package/dist/tools/refactoringTools.d.ts.map +0 -1
- package/dist/tools/refactoringTools.js +0 -294
- package/dist/tools/refactoringTools.js.map +0 -1
- package/dist/tools/repoChecksTools.d.ts +0 -3
- package/dist/tools/repoChecksTools.d.ts.map +0 -1
- package/dist/tools/repoChecksTools.js +0 -161
- package/dist/tools/repoChecksTools.js.map +0 -1
- package/dist/tools/searchTools.d.ts +0 -3
- package/dist/tools/searchTools.d.ts.map +0 -1
- package/dist/tools/searchTools.js +0 -207
- package/dist/tools/searchTools.js.map +0 -1
- package/dist/tools/skillTools.d.ts +0 -8
- package/dist/tools/skillTools.d.ts.map +0 -1
- package/dist/tools/skillTools.js +0 -178
- package/dist/tools/skillTools.js.map +0 -1
- package/dist/tools/softwareEngineeringTools.d.ts +0 -7
- package/dist/tools/softwareEngineeringTools.d.ts.map +0 -1
- package/dist/tools/softwareEngineeringTools.js +0 -338
- package/dist/tools/softwareEngineeringTools.js.map +0 -1
- package/dist/tools/taskManagementTools.d.ts +0 -10
- package/dist/tools/taskManagementTools.d.ts.map +0 -1
- package/dist/tools/taskManagementTools.js +0 -157
- package/dist/tools/taskManagementTools.js.map +0 -1
- package/dist/tools/testingTools.d.ts +0 -3
- package/dist/tools/testingTools.d.ts.map +0 -1
- package/dist/tools/testingTools.js +0 -233
- package/dist/tools/testingTools.js.map +0 -1
- package/dist/tools/validationTools.d.ts +0 -7
- package/dist/tools/validationTools.d.ts.map +0 -1
- package/dist/tools/validationTools.js +0 -344
- package/dist/tools/validationTools.js.map +0 -1
- package/dist/tools/webTools.d.ts +0 -3
- package/dist/tools/webTools.d.ts.map +0 -1
- package/dist/tools/webTools.js +0 -502
- package/dist/tools/webTools.js.map +0 -1
- package/dist/ui/ShellUIAdapter.d.ts +0 -194
- package/dist/ui/ShellUIAdapter.d.ts.map +0 -1
- package/dist/ui/ShellUIAdapter.js +0 -1069
- package/dist/ui/ShellUIAdapter.js.map +0 -1
- package/dist/ui/UnifiedUIController.d.ts +0 -70
- package/dist/ui/UnifiedUIController.d.ts.map +0 -1
- package/dist/ui/UnifiedUIController.js +0 -190
- package/dist/ui/UnifiedUIController.js.map +0 -1
- package/dist/ui/animation/AnimationScheduler.d.ts +0 -192
- package/dist/ui/animation/AnimationScheduler.d.ts.map +0 -1
- package/dist/ui/animation/AnimationScheduler.js +0 -432
- package/dist/ui/animation/AnimationScheduler.js.map +0 -1
- package/dist/ui/codeHighlighter.d.ts +0 -6
- package/dist/ui/codeHighlighter.d.ts.map +0 -1
- package/dist/ui/codeHighlighter.js +0 -855
- package/dist/ui/codeHighlighter.js.map +0 -1
- package/dist/ui/compactRenderer.d.ts +0 -139
- package/dist/ui/compactRenderer.d.ts.map +0 -1
- package/dist/ui/compactRenderer.js +0 -398
- package/dist/ui/compactRenderer.js.map +0 -1
- package/dist/ui/designSystem.d.ts +0 -26
- package/dist/ui/designSystem.d.ts.map +0 -1
- package/dist/ui/designSystem.js +0 -122
- package/dist/ui/designSystem.js.map +0 -1
- package/dist/ui/display.d.ts +0 -324
- package/dist/ui/display.d.ts.map +0 -1
- package/dist/ui/display.js +0 -1328
- package/dist/ui/display.js.map +0 -1
- package/dist/ui/errorFormatter.d.ts +0 -54
- package/dist/ui/errorFormatter.d.ts.map +0 -1
- package/dist/ui/errorFormatter.js +0 -251
- package/dist/ui/errorFormatter.js.map +0 -1
- package/dist/ui/globalWriteLock.d.ts +0 -38
- package/dist/ui/globalWriteLock.d.ts.map +0 -1
- package/dist/ui/globalWriteLock.js +0 -54
- package/dist/ui/globalWriteLock.js.map +0 -1
- package/dist/ui/inPlaceUpdater.d.ts +0 -181
- package/dist/ui/inPlaceUpdater.d.ts.map +0 -1
- package/dist/ui/inPlaceUpdater.js +0 -515
- package/dist/ui/inPlaceUpdater.js.map +0 -1
- package/dist/ui/interrupts/InterruptManager.d.ts +0 -142
- package/dist/ui/interrupts/InterruptManager.d.ts.map +0 -1
- package/dist/ui/interrupts/InterruptManager.js +0 -439
- package/dist/ui/interrupts/InterruptManager.js.map +0 -1
- package/dist/ui/layout.d.ts +0 -17
- package/dist/ui/layout.d.ts.map +0 -1
- package/dist/ui/layout.js +0 -140
- package/dist/ui/layout.js.map +0 -1
- package/dist/ui/orchestration/StatusOrchestrator.d.ts +0 -156
- package/dist/ui/orchestration/StatusOrchestrator.d.ts.map +0 -1
- package/dist/ui/orchestration/StatusOrchestrator.js +0 -406
- package/dist/ui/orchestration/StatusOrchestrator.js.map +0 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.d.ts +0 -77
- package/dist/ui/orchestration/UIUpdateCoordinator.d.ts.map +0 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.js +0 -265
- package/dist/ui/orchestration/UIUpdateCoordinator.js.map +0 -1
- package/dist/ui/outputMode.d.ts +0 -22
- package/dist/ui/outputMode.d.ts.map +0 -1
- package/dist/ui/outputMode.js +0 -40
- package/dist/ui/outputMode.js.map +0 -1
- package/dist/ui/richText.d.ts +0 -6
- package/dist/ui/richText.d.ts.map +0 -1
- package/dist/ui/richText.js +0 -391
- package/dist/ui/richText.js.map +0 -1
- package/dist/ui/shortcutsHelp.d.ts +0 -39
- package/dist/ui/shortcutsHelp.d.ts.map +0 -1
- package/dist/ui/shortcutsHelp.js +0 -152
- package/dist/ui/shortcutsHelp.js.map +0 -1
- package/dist/ui/streamingFormatter.d.ts +0 -17
- package/dist/ui/streamingFormatter.d.ts.map +0 -1
- package/dist/ui/streamingFormatter.js +0 -71
- package/dist/ui/streamingFormatter.js.map +0 -1
- package/dist/ui/telemetry/UITelemetry.d.ts +0 -181
- package/dist/ui/telemetry/UITelemetry.d.ts.map +0 -1
- package/dist/ui/telemetry/UITelemetry.js +0 -446
- package/dist/ui/telemetry/UITelemetry.js.map +0 -1
- package/dist/ui/textHighlighter.d.ts +0 -83
- package/dist/ui/textHighlighter.d.ts.map +0 -1
- package/dist/ui/textHighlighter.js +0 -267
- package/dist/ui/textHighlighter.js.map +0 -1
- package/dist/ui/theme.d.ts +0 -208
- package/dist/ui/theme.d.ts.map +0 -1
- package/dist/ui/theme.js +0 -249
- package/dist/ui/theme.js.map +0 -1
- package/dist/ui/toolDisplay.d.ts +0 -195
- package/dist/ui/toolDisplay.d.ts.map +0 -1
- package/dist/ui/toolDisplay.js +0 -1527
- package/dist/ui/toolDisplay.js.map +0 -1
- package/dist/ui/unified/index.d.ts +0 -50
- package/dist/ui/unified/index.d.ts.map +0 -1
- package/dist/ui/unified/index.js +0 -77
- package/dist/ui/unified/index.js.map +0 -1
- package/dist/ui/unified/layout.d.ts +0 -12
- package/dist/ui/unified/layout.d.ts.map +0 -1
- package/dist/ui/unified/layout.js +0 -96
- package/dist/ui/unified/layout.js.map +0 -1
- package/dist/ui/writeLock.d.ts +0 -65
- package/dist/ui/writeLock.d.ts.map +0 -1
- package/dist/ui/writeLock.js +0 -114
- package/dist/ui/writeLock.js.map +0 -1
- package/dist/utils/asyncUtils.d.ts +0 -95
- package/dist/utils/asyncUtils.d.ts.map +0 -1
- package/dist/utils/asyncUtils.js +0 -286
- package/dist/utils/asyncUtils.js.map +0 -1
- package/dist/utils/errorUtils.d.ts +0 -16
- package/dist/utils/errorUtils.d.ts.map +0 -1
- package/dist/utils/errorUtils.js +0 -66
- package/dist/utils/errorUtils.js.map +0 -1
- package/dist/utils/frontmatter.d.ts +0 -10
- package/dist/utils/frontmatter.d.ts.map +0 -1
- package/dist/utils/frontmatter.js +0 -78
- package/dist/utils/frontmatter.js.map +0 -1
- package/dist/utils/planFormatter.d.ts +0 -34
- package/dist/utils/planFormatter.d.ts.map +0 -1
- package/dist/utils/planFormatter.js +0 -140
- package/dist/utils/planFormatter.js.map +0 -1
- package/dist/workspace.d.ts +0 -8
- package/dist/workspace.d.ts.map +0 -1
- package/dist/workspace.js +0 -107
- package/dist/workspace.js.map +0 -1
- package/dist/workspace.validator.d.ts +0 -49
- package/dist/workspace.validator.d.ts.map +0 -1
- package/dist/workspace.validator.js +0 -214
- package/dist/workspace.validator.js.map +0 -1
|
@@ -1,2633 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TerminalInput - Clean, unified terminal input handling
|
|
3
|
-
*
|
|
4
|
-
* Design principles:
|
|
5
|
-
* - Single source of truth for input state
|
|
6
|
-
* - Hybrid floating/scroll approach:
|
|
7
|
-
* - Initially: chat box floats below content
|
|
8
|
-
* - When terminal fills: scroll region activates, chat box pins to bottom
|
|
9
|
-
* - Native bracketed paste support (no heuristics)
|
|
10
|
-
* - Clean cursor model with render-time wrapping
|
|
11
|
-
* - State machine for different input modes
|
|
12
|
-
* - No readline dependency for display
|
|
13
|
-
* - Text selection enabled: mouse tracking disabled by default to preserve
|
|
14
|
-
* native terminal text selection and copy/paste functionality
|
|
15
|
-
* - Scrollback navigation via keyboard: PageUp/PageDown, Ctrl+Home/End
|
|
16
|
-
*/
|
|
17
|
-
import { EventEmitter } from 'node:events';
|
|
18
|
-
import { isMultilinePaste } from '../core/multilinePasteHandler.js';
|
|
19
|
-
import { writeLock } from '../ui/writeLock.js';
|
|
20
|
-
import { renderDivider, renderStatusLine, renderStatusLines } from '../ui/unified/layout.js';
|
|
21
|
-
import { isStreamingMode } from '../ui/globalWriteLock.js';
|
|
22
|
-
import { formatThinking } from '../ui/toolDisplay.js';
|
|
23
|
-
import { theme } from '../ui/theme.js';
|
|
24
|
-
import { formatEditModeIndicator } from '../ui/shortcutsHelp.js';
|
|
25
|
-
// ANSI escape codes
|
|
26
|
-
const ESC = {
|
|
27
|
-
// Cursor control
|
|
28
|
-
SAVE: '\x1b7',
|
|
29
|
-
RESTORE: '\x1b8',
|
|
30
|
-
HIDE: '\x1b[?25l',
|
|
31
|
-
SHOW: '\x1b[?25h',
|
|
32
|
-
TO: (row, col) => `\x1b[${row};${col}H`,
|
|
33
|
-
TO_COL: (col) => `\x1b[${col}G`,
|
|
34
|
-
// Line control
|
|
35
|
-
CLEAR_LINE: '\x1b[2K',
|
|
36
|
-
CLEAR_TO_END: '\x1b[0J',
|
|
37
|
-
// Screen control
|
|
38
|
-
HOME: '\x1b[H',
|
|
39
|
-
CLEAR_SCREEN: '\x1b[2J',
|
|
40
|
-
// Alternate screen buffer (like vim/tmux)
|
|
41
|
-
ENTER_ALT_SCREEN: '\x1b[?1049h',
|
|
42
|
-
EXIT_ALT_SCREEN: '\x1b[?1049l',
|
|
43
|
-
// Scroll region
|
|
44
|
-
SET_SCROLL: (top, bottom) => `\x1b[${top};${bottom}r`,
|
|
45
|
-
RESET_SCROLL: '\x1b[r',
|
|
46
|
-
// Style
|
|
47
|
-
RESET: '\x1b[0m',
|
|
48
|
-
DIM: '\x1b[2m',
|
|
49
|
-
REVERSE: '\x1b[7m',
|
|
50
|
-
BOLD: '\x1b[1m',
|
|
51
|
-
BG_DARK: '\x1b[48;5;236m', // Dark gray background
|
|
52
|
-
// Bracketed paste mode
|
|
53
|
-
PASTE_ENABLE: '\x1b[?2004h',
|
|
54
|
-
PASTE_DISABLE: '\x1b[?2004l',
|
|
55
|
-
PASTE_START: '\x1b[200~',
|
|
56
|
-
PASTE_END: '\x1b[201~',
|
|
57
|
-
// Mouse tracking - Button events only (allows Shift+drag for text selection)
|
|
58
|
-
// Mode 1000: Track button presses/releases (wheel events included)
|
|
59
|
-
// Mode 1006: SGR extended format for better coordinate handling
|
|
60
|
-
// Note: NOT using mode 1003 (all motion) to preserve terminal text selection
|
|
61
|
-
MOUSE_ENABLE: '\x1b[?1000h\x1b[?1006h', // Enable button tracking + SGR mode
|
|
62
|
-
MOUSE_DISABLE: '\x1b[?1006l\x1b[?1000l', // Disable mouse tracking
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Unified terminal input handler
|
|
66
|
-
*/
|
|
67
|
-
export class TerminalInput extends EventEmitter {
|
|
68
|
-
out;
|
|
69
|
-
config;
|
|
70
|
-
// Core state
|
|
71
|
-
buffer = '';
|
|
72
|
-
cursor = 0;
|
|
73
|
-
mode = 'idle';
|
|
74
|
-
// Paste accumulation
|
|
75
|
-
pasteBuffer = '';
|
|
76
|
-
isPasting = false;
|
|
77
|
-
pastePlaceholders = [];
|
|
78
|
-
pasteCounter = 0;
|
|
79
|
-
// History
|
|
80
|
-
history = [];
|
|
81
|
-
historyIndex = -1;
|
|
82
|
-
tempInput = '';
|
|
83
|
-
maxHistory = 100;
|
|
84
|
-
// Queue for streaming mode
|
|
85
|
-
queue = [];
|
|
86
|
-
queueIdCounter = 0;
|
|
87
|
-
// Display state
|
|
88
|
-
statusMessage = null;
|
|
89
|
-
overrideStatusMessage = null; // Secondary status (warnings, etc.)
|
|
90
|
-
streamingLabel = null; // Streaming progress indicator
|
|
91
|
-
metaElapsedSeconds = null; // Optional elapsed time for header line
|
|
92
|
-
metaTokensUsed = null; // Optional token usage
|
|
93
|
-
metaTokenLimit = null; // Optional token window
|
|
94
|
-
metaThinkingMs = null; // Optional thinking duration
|
|
95
|
-
metaThinkingHasContent = false; // Whether collapsed thinking content exists
|
|
96
|
-
lastRenderContent = '';
|
|
97
|
-
lastRenderCursor = -1;
|
|
98
|
-
renderDirty = false;
|
|
99
|
-
isRendering = false;
|
|
100
|
-
// Lifecycle
|
|
101
|
-
disposed = false;
|
|
102
|
-
enabled = true;
|
|
103
|
-
contextUsage = null;
|
|
104
|
-
contextAutoCompactThreshold = 90;
|
|
105
|
-
// Track current content row (starts at top, moves down)
|
|
106
|
-
contentRow = 1;
|
|
107
|
-
// Track if scroll region is currently active
|
|
108
|
-
scrollRegionActive = false;
|
|
109
|
-
thinkingModeLabel = null;
|
|
110
|
-
// Scrollback buffer
|
|
111
|
-
scrollbackBuffer = [];
|
|
112
|
-
maxScrollbackLines = 10000;
|
|
113
|
-
scrollbackOffset = 0; // 0 = at bottom (live), > 0 = scrolled up
|
|
114
|
-
isInScrollbackMode = false;
|
|
115
|
-
scrollIndicatorFrame = 0; // For animated scroll indicator
|
|
116
|
-
// Alternate screen state
|
|
117
|
-
alternateScreenActive = false;
|
|
118
|
-
editMode = 'display-edits';
|
|
119
|
-
verificationEnabled = false;
|
|
120
|
-
autoContinueEnabled = false;
|
|
121
|
-
verificationHotkey = 'ctrl+shift+v';
|
|
122
|
-
autoContinueHotkey = 'ctrl+shift+c';
|
|
123
|
-
thinkingHotkey = 'tab';
|
|
124
|
-
modelLabel = null;
|
|
125
|
-
providerLabel = null;
|
|
126
|
-
// Streaming render throttle
|
|
127
|
-
lastStreamingRender = 0;
|
|
128
|
-
streamingRenderInterval = 250; // ms between renders during streaming
|
|
129
|
-
streamingRenderTimer = null;
|
|
130
|
-
// Command autocomplete state
|
|
131
|
-
commandSuggestions = [];
|
|
132
|
-
showingSuggestions = false;
|
|
133
|
-
selectedSuggestionIndex = 0;
|
|
134
|
-
maxVisibleSuggestions = 10;
|
|
135
|
-
suggestionRenderState = null;
|
|
136
|
-
lastSuggestionStartRow = null;
|
|
137
|
-
lastChatBoxStartRow = null;
|
|
138
|
-
lastChatBoxHeight = 0;
|
|
139
|
-
displayInterceptorDispose = null;
|
|
140
|
-
constructor(writeStream = process.stdout, config = {}) {
|
|
141
|
-
super();
|
|
142
|
-
this.out = writeStream;
|
|
143
|
-
this.config = {
|
|
144
|
-
maxLines: config.maxLines ?? 1000,
|
|
145
|
-
maxLength: config.maxLength ?? 10000,
|
|
146
|
-
maxQueueSize: config.maxQueueSize ?? 100,
|
|
147
|
-
promptChar: config.promptChar ?? '> ',
|
|
148
|
-
continuationChar: config.continuationChar ?? '│ ',
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
// ===========================================================================
|
|
152
|
-
// PUBLIC API
|
|
153
|
-
// ===========================================================================
|
|
154
|
-
/**
|
|
155
|
-
* Enable bracketed paste mode in terminal
|
|
156
|
-
*/
|
|
157
|
-
enableBracketedPaste() {
|
|
158
|
-
if (this.isTTY()) {
|
|
159
|
-
this.write(ESC.PASTE_ENABLE);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Disable bracketed paste mode
|
|
164
|
-
*/
|
|
165
|
-
disableBracketedPaste() {
|
|
166
|
-
if (this.isTTY()) {
|
|
167
|
-
this.write(ESC.PASTE_DISABLE);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Enable mouse tracking in terminal
|
|
172
|
-
*/
|
|
173
|
-
enableMouseTracking() {
|
|
174
|
-
if (this.isTTY()) {
|
|
175
|
-
this.write(ESC.MOUSE_ENABLE);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Disable mouse tracking
|
|
180
|
-
*/
|
|
181
|
-
disableMouseTracking() {
|
|
182
|
-
if (this.isTTY()) {
|
|
183
|
-
this.write(ESC.MOUSE_DISABLE);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Process raw terminal data (handles bracketed paste sequences and mouse events)
|
|
188
|
-
* Returns true if the data was consumed (paste sequence)
|
|
189
|
-
*/
|
|
190
|
-
processRawData(data) {
|
|
191
|
-
// Handle ALL mouse events in the data (SGR mode: \x1b[<button;x;yM or m)
|
|
192
|
-
// Process repeatedly until no more mouse events
|
|
193
|
-
const mousePattern = /\x1b\[<(\d+);(\d+);(\d+)([Mm])/g;
|
|
194
|
-
let remaining = data;
|
|
195
|
-
let hadMouseEvents = false;
|
|
196
|
-
// Remove all mouse escape sequences from the data
|
|
197
|
-
let match;
|
|
198
|
-
while ((match = mousePattern.exec(data)) !== null) {
|
|
199
|
-
const button = parseInt(match[1], 10);
|
|
200
|
-
const x = parseInt(match[2], 10);
|
|
201
|
-
const y = parseInt(match[3], 10);
|
|
202
|
-
this.handleMouseEvent(button, x, y, match[4]);
|
|
203
|
-
hadMouseEvents = true;
|
|
204
|
-
}
|
|
205
|
-
if (hadMouseEvents) {
|
|
206
|
-
// Strip all mouse sequences from the data
|
|
207
|
-
remaining = data.replace(/\x1b\[<\d+;\d+;\d+[Mm]/g, '');
|
|
208
|
-
if (!remaining) {
|
|
209
|
-
return { consumed: true, passthrough: '' };
|
|
210
|
-
}
|
|
211
|
-
// If there's remaining content, continue processing it
|
|
212
|
-
}
|
|
213
|
-
// Check for paste start
|
|
214
|
-
if (remaining.includes(ESC.PASTE_START)) {
|
|
215
|
-
this.isPasting = true;
|
|
216
|
-
this.pasteBuffer = '';
|
|
217
|
-
// Extract content after paste start
|
|
218
|
-
const startIdx = remaining.indexOf(ESC.PASTE_START) + ESC.PASTE_START.length;
|
|
219
|
-
const afterStart = remaining.slice(startIdx);
|
|
220
|
-
// Check if paste end is also in this chunk
|
|
221
|
-
if (afterStart.includes(ESC.PASTE_END)) {
|
|
222
|
-
const endIdx = afterStart.indexOf(ESC.PASTE_END);
|
|
223
|
-
this.pasteBuffer = afterStart.slice(0, endIdx);
|
|
224
|
-
this.finishPaste();
|
|
225
|
-
return { consumed: true, passthrough: afterStart.slice(endIdx + ESC.PASTE_END.length) };
|
|
226
|
-
}
|
|
227
|
-
this.pasteBuffer = afterStart;
|
|
228
|
-
return { consumed: true, passthrough: '' };
|
|
229
|
-
}
|
|
230
|
-
// Accumulating paste
|
|
231
|
-
if (this.isPasting) {
|
|
232
|
-
if (remaining.includes(ESC.PASTE_END)) {
|
|
233
|
-
const endIdx = remaining.indexOf(ESC.PASTE_END);
|
|
234
|
-
this.pasteBuffer += remaining.slice(0, endIdx);
|
|
235
|
-
this.finishPaste();
|
|
236
|
-
return { consumed: true, passthrough: remaining.slice(endIdx + ESC.PASTE_END.length) };
|
|
237
|
-
}
|
|
238
|
-
this.pasteBuffer += remaining;
|
|
239
|
-
return { consumed: true, passthrough: '' };
|
|
240
|
-
}
|
|
241
|
-
// If we processed mouse events but have remaining text, return it as passthrough
|
|
242
|
-
if (hadMouseEvents && remaining) {
|
|
243
|
-
return { consumed: true, passthrough: remaining };
|
|
244
|
-
}
|
|
245
|
-
return { consumed: false, passthrough: remaining };
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Handle mouse events (button, x, y coordinates, action)
|
|
249
|
-
*/
|
|
250
|
-
handleMouseEvent(button, x, y, action) {
|
|
251
|
-
// Mouse wheel events: button 64 = scroll up, button 65 = scroll down
|
|
252
|
-
if (button === 64) {
|
|
253
|
-
// Scroll up (3 lines per wheel tick)
|
|
254
|
-
this.scrollUp(3);
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
if (button === 65) {
|
|
258
|
-
// Scroll down (3 lines per wheel tick)
|
|
259
|
-
this.scrollDown(3);
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
// Left-click selection inside the command suggestions menu
|
|
263
|
-
if (button === 0 && action === 'M') {
|
|
264
|
-
if (this.handleSuggestionClick(y)) {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
// No other left-click handling needed; fall through to consume silently
|
|
268
|
-
}
|
|
269
|
-
// Left button (0), middle button (1), right button (2)
|
|
270
|
-
// These are captured by SGR mouse tracking but we don't need to handle them
|
|
271
|
-
// Just consume silently - the escape sequence has already been processed
|
|
272
|
-
// The 'M' action is press, 'm' is release
|
|
273
|
-
if (button <= 2) {
|
|
274
|
-
// Silently consume click events to prevent artifacts
|
|
275
|
-
// Left clicks (button=0) in the input area could focus the input
|
|
276
|
-
// but terminal apps typically handle this natively
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// Button with motion flag (button + 32) - drag events
|
|
280
|
-
if (button >= 32 && button <= 34) {
|
|
281
|
-
// Drag events - consume silently
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
// Any other unrecognized button - log for debugging in dev mode
|
|
285
|
-
// but don't output anything to prevent artifacts
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Handle a keypress event
|
|
289
|
-
*/
|
|
290
|
-
handleKeypress(str, key) {
|
|
291
|
-
if (this.disposed || !this.enabled)
|
|
292
|
-
return;
|
|
293
|
-
const normalizedName = key?.name ?? this.getArrowKeyName(key?.sequence ?? str);
|
|
294
|
-
const effectiveKey = normalizedName ? { ...key, name: normalizedName } : key;
|
|
295
|
-
const safeStr = this.isArrowEscapeFragment(str) ? undefined : str;
|
|
296
|
-
let handled = false;
|
|
297
|
-
// Handle control keys
|
|
298
|
-
if (effectiveKey?.ctrl) {
|
|
299
|
-
handled = this.handleCtrlKey(effectiveKey);
|
|
300
|
-
if (handled) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// Handle meta/alt keys
|
|
305
|
-
if (effectiveKey?.meta) {
|
|
306
|
-
this.handleMetaKey(effectiveKey);
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
// Handle special keys
|
|
310
|
-
if (effectiveKey?.name) {
|
|
311
|
-
const handled = this.handleSpecialKey(safeStr, effectiveKey);
|
|
312
|
-
if (handled)
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
// Ignore orphaned escape fragments that sometimes leak through (e.g., "[D" from arrow keys)
|
|
316
|
-
if (safeStr && this.isOrphanedEscapeSequence(safeStr, effectiveKey)) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
// Insert printable characters
|
|
320
|
-
if (safeStr && !effectiveKey?.ctrl && !effectiveKey?.meta) {
|
|
321
|
-
this.insertText(safeStr);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Set the input mode
|
|
326
|
-
*
|
|
327
|
-
* Content flows naturally - no scroll region pinning.
|
|
328
|
-
*/
|
|
329
|
-
setMode(mode) {
|
|
330
|
-
const prevMode = this.mode;
|
|
331
|
-
this.mode = mode;
|
|
332
|
-
if (mode === 'streaming' && prevMode !== 'streaming') {
|
|
333
|
-
this.resetStreamingRenderThrottle();
|
|
334
|
-
this.renderDirty = true;
|
|
335
|
-
this.render();
|
|
336
|
-
}
|
|
337
|
-
else if (mode !== 'streaming' && prevMode === 'streaming') {
|
|
338
|
-
// Streaming ended - render the input area
|
|
339
|
-
this.resetStreamingRenderThrottle();
|
|
340
|
-
this.forceRender();
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Legacy method - no longer used (content flows naturally).
|
|
345
|
-
* @deprecated Use setContentRow instead
|
|
346
|
-
*/
|
|
347
|
-
setPinnedHeaderLines(_count) {
|
|
348
|
-
// No-op: scroll region pinning removed
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Get current mode
|
|
352
|
-
*/
|
|
353
|
-
getMode() {
|
|
354
|
-
return this.mode;
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Get the current buffer content (may contain placeholders for pasted text)
|
|
358
|
-
*/
|
|
359
|
-
getBuffer() {
|
|
360
|
-
return this.buffer;
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Get the actual text with paste placeholders expanded
|
|
364
|
-
*/
|
|
365
|
-
getText() {
|
|
366
|
-
return this.assembleText();
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Set buffer content
|
|
370
|
-
*/
|
|
371
|
-
setBuffer(text, cursorPos) {
|
|
372
|
-
this.pastePlaceholders = [];
|
|
373
|
-
const clean = this.sanitize(text).slice(0, this.config.maxLength);
|
|
374
|
-
this.buffer = clean;
|
|
375
|
-
this.cursor = cursorPos ?? this.buffer.length;
|
|
376
|
-
this.clampCursor();
|
|
377
|
-
this.scheduleRender();
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Clear the buffer
|
|
381
|
-
*/
|
|
382
|
-
clear() {
|
|
383
|
-
this.buffer = '';
|
|
384
|
-
this.cursor = 0;
|
|
385
|
-
this.historyIndex = -1;
|
|
386
|
-
this.tempInput = '';
|
|
387
|
-
this.pastePlaceholders = [];
|
|
388
|
-
this.showingSuggestions = false;
|
|
389
|
-
this.selectedSuggestionIndex = 0;
|
|
390
|
-
this.scheduleRender();
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Get queued inputs
|
|
394
|
-
*/
|
|
395
|
-
getQueue() {
|
|
396
|
-
return [...this.queue];
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Dequeue next input
|
|
400
|
-
*/
|
|
401
|
-
dequeue() {
|
|
402
|
-
const item = this.queue.shift();
|
|
403
|
-
this.scheduleRender();
|
|
404
|
-
return item;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* Clear the queue
|
|
408
|
-
*/
|
|
409
|
-
clearQueue() {
|
|
410
|
-
this.queue = [];
|
|
411
|
-
this.scheduleRender();
|
|
412
|
-
}
|
|
413
|
-
// ===========================================================================
|
|
414
|
-
// COMMAND AUTOCOMPLETE
|
|
415
|
-
// ===========================================================================
|
|
416
|
-
/**
|
|
417
|
-
* Set available commands for autocomplete.
|
|
418
|
-
* Call this once during initialization with all slash commands.
|
|
419
|
-
*/
|
|
420
|
-
setAvailableCommands(commands) {
|
|
421
|
-
this.commandSuggestions = commands;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Check if command suggestions are currently being shown
|
|
425
|
-
*/
|
|
426
|
-
isShowingSuggestions() {
|
|
427
|
-
return this.showingSuggestions;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Get filtered commands based on current input
|
|
431
|
-
*/
|
|
432
|
-
getFilteredCommands() {
|
|
433
|
-
const input = this.buffer.trim().toLowerCase();
|
|
434
|
-
// Only show suggestions if buffer starts with "/"
|
|
435
|
-
if (!input.startsWith('/')) {
|
|
436
|
-
return [];
|
|
437
|
-
}
|
|
438
|
-
// If just "/", show all commands
|
|
439
|
-
if (input === '/') {
|
|
440
|
-
return this.commandSuggestions;
|
|
441
|
-
}
|
|
442
|
-
// Filter commands that match the typed prefix
|
|
443
|
-
return this.commandSuggestions.filter(cmd => cmd.command.toLowerCase().startsWith(input));
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* Update suggestion visibility based on current buffer
|
|
447
|
-
*/
|
|
448
|
-
updateSuggestionVisibility() {
|
|
449
|
-
const filtered = this.getFilteredCommands();
|
|
450
|
-
const shouldShow = filtered.length > 0 && this.buffer.startsWith('/');
|
|
451
|
-
if (shouldShow !== this.showingSuggestions) {
|
|
452
|
-
this.showingSuggestions = shouldShow;
|
|
453
|
-
this.selectedSuggestionIndex = 0;
|
|
454
|
-
this.scheduleRender();
|
|
455
|
-
}
|
|
456
|
-
else if (shouldShow) {
|
|
457
|
-
// Clamp selection index
|
|
458
|
-
this.selectedSuggestionIndex = Math.min(this.selectedSuggestionIndex, Math.max(0, filtered.length - 1));
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Handle selecting a suggestion (Enter key or click)
|
|
463
|
-
*/
|
|
464
|
-
selectSuggestion(options = {}) {
|
|
465
|
-
const { submit = false } = options;
|
|
466
|
-
if (!this.showingSuggestions)
|
|
467
|
-
return false;
|
|
468
|
-
const filtered = this.getFilteredCommands();
|
|
469
|
-
if (filtered.length === 0)
|
|
470
|
-
return false;
|
|
471
|
-
const selected = filtered[this.selectedSuggestionIndex];
|
|
472
|
-
if (!selected)
|
|
473
|
-
return false;
|
|
474
|
-
// Replace buffer with selected command
|
|
475
|
-
const nextBuffer = submit ? selected.command : `${selected.command} `;
|
|
476
|
-
this.buffer = nextBuffer;
|
|
477
|
-
this.cursor = this.buffer.length;
|
|
478
|
-
this.showingSuggestions = false;
|
|
479
|
-
this.scheduleRender();
|
|
480
|
-
if (submit) {
|
|
481
|
-
this.submit();
|
|
482
|
-
}
|
|
483
|
-
return true;
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* Move selection up in suggestions list
|
|
487
|
-
*/
|
|
488
|
-
moveSuggestionUp() {
|
|
489
|
-
if (!this.showingSuggestions)
|
|
490
|
-
return false;
|
|
491
|
-
const filtered = this.getFilteredCommands();
|
|
492
|
-
if (filtered.length === 0)
|
|
493
|
-
return false;
|
|
494
|
-
this.selectedSuggestionIndex = Math.max(0, this.selectedSuggestionIndex - 1);
|
|
495
|
-
this.scheduleRender();
|
|
496
|
-
return true;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Move selection down in suggestions list
|
|
500
|
-
*/
|
|
501
|
-
moveSuggestionDown() {
|
|
502
|
-
if (!this.showingSuggestions)
|
|
503
|
-
return false;
|
|
504
|
-
const filtered = this.getFilteredCommands();
|
|
505
|
-
if (filtered.length === 0)
|
|
506
|
-
return false;
|
|
507
|
-
this.selectedSuggestionIndex = Math.min(filtered.length - 1, this.selectedSuggestionIndex + 1);
|
|
508
|
-
this.scheduleRender();
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* Handle mouse selection inside the suggestions list.
|
|
513
|
-
* Returns true if the click selected a command.
|
|
514
|
-
*/
|
|
515
|
-
handleSuggestionClick(clickRow) {
|
|
516
|
-
if (!this.showingSuggestions || !this.suggestionRenderState)
|
|
517
|
-
return false;
|
|
518
|
-
if (this.lastSuggestionStartRow === null)
|
|
519
|
-
return false;
|
|
520
|
-
// First line is the header; suggestions start on the next row
|
|
521
|
-
const relativeRow = clickRow - this.lastSuggestionStartRow - 1;
|
|
522
|
-
if (relativeRow < 0)
|
|
523
|
-
return false;
|
|
524
|
-
const { startIdx, visibleCount } = this.suggestionRenderState;
|
|
525
|
-
if (relativeRow >= visibleCount)
|
|
526
|
-
return false;
|
|
527
|
-
this.selectedSuggestionIndex = startIdx + relativeRow;
|
|
528
|
-
this.selectSuggestion();
|
|
529
|
-
return true;
|
|
530
|
-
}
|
|
531
|
-
/**
|
|
532
|
-
* Cancel suggestion display (Escape)
|
|
533
|
-
*/
|
|
534
|
-
cancelSuggestions() {
|
|
535
|
-
if (!this.showingSuggestions)
|
|
536
|
-
return false;
|
|
537
|
-
this.showingSuggestions = false;
|
|
538
|
-
this.scheduleRender();
|
|
539
|
-
return true;
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Build command suggestion display lines
|
|
543
|
-
*/
|
|
544
|
-
buildSuggestionLines(width) {
|
|
545
|
-
this.suggestionRenderState = null;
|
|
546
|
-
if (!this.showingSuggestions)
|
|
547
|
-
return [];
|
|
548
|
-
const filtered = this.getFilteredCommands();
|
|
549
|
-
if (filtered.length === 0)
|
|
550
|
-
return [];
|
|
551
|
-
const lines = [];
|
|
552
|
-
const maxDisplay = Math.min(filtered.length, this.maxVisibleSuggestions);
|
|
553
|
-
// Calculate scroll window for long lists
|
|
554
|
-
let startIdx = 0;
|
|
555
|
-
if (filtered.length > maxDisplay) {
|
|
556
|
-
// Keep selected item in view with some context
|
|
557
|
-
const padding = Math.floor(maxDisplay / 3);
|
|
558
|
-
startIdx = Math.max(0, this.selectedSuggestionIndex - padding);
|
|
559
|
-
startIdx = Math.min(startIdx, filtered.length - maxDisplay);
|
|
560
|
-
}
|
|
561
|
-
this.suggestionRenderState = {
|
|
562
|
-
startIdx,
|
|
563
|
-
visibleCount: Math.min(maxDisplay, Math.max(0, filtered.length - startIdx))
|
|
564
|
-
};
|
|
565
|
-
// Header with navigation hint - keep it short
|
|
566
|
-
lines.push(theme.ui.muted(`Commands (↑↓ Enter to run · Tab to fill)`));
|
|
567
|
-
// Render visible suggestions
|
|
568
|
-
for (let i = 0; i < maxDisplay; i++) {
|
|
569
|
-
const idx = startIdx + i;
|
|
570
|
-
if (idx >= filtered.length)
|
|
571
|
-
break;
|
|
572
|
-
const cmd = filtered[idx];
|
|
573
|
-
const isSelected = idx === this.selectedSuggestionIndex;
|
|
574
|
-
// Format: [indicator] /command description
|
|
575
|
-
const indicator = isSelected ? theme.accent('▸') : ' ';
|
|
576
|
-
// Command name - use available space wisely
|
|
577
|
-
const cmdWidth = Math.min(20, Math.max(12, Math.floor(width * 0.3)));
|
|
578
|
-
const cmdText = isSelected
|
|
579
|
-
? theme.accent(cmd.command.padEnd(cmdWidth))
|
|
580
|
-
: theme.primary(cmd.command.padEnd(cmdWidth));
|
|
581
|
-
// Description - use remaining space
|
|
582
|
-
const descMaxLen = Math.max(20, width - cmdWidth - 4);
|
|
583
|
-
const desc = cmd.description.length > descMaxLen
|
|
584
|
-
? cmd.description.slice(0, descMaxLen - 1) + '…'
|
|
585
|
-
: cmd.description;
|
|
586
|
-
const descText = isSelected
|
|
587
|
-
? theme.info(desc)
|
|
588
|
-
: theme.ui.muted(desc);
|
|
589
|
-
lines.push(`${indicator}${cmdText} ${descText}`);
|
|
590
|
-
}
|
|
591
|
-
// Show scroll indicator if needed
|
|
592
|
-
if (filtered.length > maxDisplay) {
|
|
593
|
-
const position = startIdx + 1;
|
|
594
|
-
const endPos = Math.min(startIdx + maxDisplay, filtered.length);
|
|
595
|
-
lines.push(theme.ui.muted(` [${position}-${endPos} of ${filtered.length}]`));
|
|
596
|
-
}
|
|
597
|
-
return lines;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Update the inline status message shown before the prompt (e.g., streaming heartbeat).
|
|
601
|
-
*/
|
|
602
|
-
setStatusMessage(message) {
|
|
603
|
-
const normalized = message ? message.replace(/\s+/g, ' ').trim() : null;
|
|
604
|
-
const maxLen = 48;
|
|
605
|
-
const next = normalized && normalized.length > maxLen
|
|
606
|
-
? `${normalized.slice(0, maxLen - 3)}...`
|
|
607
|
-
: normalized;
|
|
608
|
-
if (this.statusMessage === next) {
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
this.statusMessage = next;
|
|
612
|
-
// Schedule render - throttling during streaming is handled in render()
|
|
613
|
-
this.scheduleRender();
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Set an override status message (warnings, errors) that shows alongside the main status.
|
|
617
|
-
* Both streaming label and override can be displayed simultaneously.
|
|
618
|
-
*/
|
|
619
|
-
setOverrideStatus(message) {
|
|
620
|
-
const normalized = message ? message.replace(/\s+/g, ' ').trim() : null;
|
|
621
|
-
const maxLen = 32;
|
|
622
|
-
const next = normalized && normalized.length > maxLen
|
|
623
|
-
? `${normalized.slice(0, maxLen - 3)}...`
|
|
624
|
-
: normalized;
|
|
625
|
-
if (this.overrideStatusMessage === next) {
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
this.overrideStatusMessage = next;
|
|
629
|
-
this.scheduleRender();
|
|
630
|
-
}
|
|
631
|
-
/**
|
|
632
|
-
* Set the streaming label (e.g., "Streaming response...").
|
|
633
|
-
* Can be shown alongside override status messages.
|
|
634
|
-
*/
|
|
635
|
-
setStreamingLabel(label) {
|
|
636
|
-
const normalized = label ? label.replace(/\s+/g, ' ').trim() : null;
|
|
637
|
-
const maxLen = 24;
|
|
638
|
-
const next = normalized && normalized.length > maxLen
|
|
639
|
-
? `${normalized.slice(0, maxLen - 3)}...`
|
|
640
|
-
: normalized;
|
|
641
|
-
if (this.streamingLabel === next) {
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
this.streamingLabel = next;
|
|
645
|
-
this.scheduleRender();
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Surface meta status just above the divider (e.g., elapsed time or token usage).
|
|
649
|
-
*/
|
|
650
|
-
setMetaStatus(meta) {
|
|
651
|
-
const nextElapsed = typeof meta.elapsedSeconds === 'number' && Number.isFinite(meta.elapsedSeconds) && meta.elapsedSeconds >= 0
|
|
652
|
-
? Math.floor(meta.elapsedSeconds)
|
|
653
|
-
: null;
|
|
654
|
-
const nextTokens = typeof meta.tokensUsed === 'number' && Number.isFinite(meta.tokensUsed) && meta.tokensUsed >= 0
|
|
655
|
-
? Math.floor(meta.tokensUsed)
|
|
656
|
-
: null;
|
|
657
|
-
const nextLimit = typeof meta.tokenLimit === 'number' && Number.isFinite(meta.tokenLimit) && meta.tokenLimit > 0
|
|
658
|
-
? Math.floor(meta.tokenLimit)
|
|
659
|
-
: null;
|
|
660
|
-
const nextThinking = typeof meta.thinkingMs === 'number' && Number.isFinite(meta.thinkingMs) && meta.thinkingMs >= 0
|
|
661
|
-
? Math.floor(meta.thinkingMs)
|
|
662
|
-
: null;
|
|
663
|
-
const nextThinkingHasContent = !!meta.thinkingHasContent;
|
|
664
|
-
if (this.metaElapsedSeconds === nextElapsed &&
|
|
665
|
-
this.metaTokensUsed === nextTokens &&
|
|
666
|
-
this.metaTokenLimit === nextLimit &&
|
|
667
|
-
this.metaThinkingMs === nextThinking &&
|
|
668
|
-
this.metaThinkingHasContent === nextThinkingHasContent) {
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
this.metaElapsedSeconds = nextElapsed;
|
|
672
|
-
this.metaTokensUsed = nextTokens;
|
|
673
|
-
this.metaTokenLimit = nextLimit;
|
|
674
|
-
this.metaThinkingMs = nextThinking;
|
|
675
|
-
this.metaThinkingHasContent = nextThinkingHasContent;
|
|
676
|
-
this.scheduleRender();
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Keep mode toggles (verification/auto-continue) visible in the control bar.
|
|
680
|
-
* Hotkey labels remain stable so the bar looks the same before/during streaming.
|
|
681
|
-
*/
|
|
682
|
-
setModeToggles(options) {
|
|
683
|
-
const nextVerification = !!options.verificationEnabled;
|
|
684
|
-
const nextAutoContinue = !!options.autoContinueEnabled;
|
|
685
|
-
const nextVerifyHotkey = options.verificationHotkey ?? this.verificationHotkey;
|
|
686
|
-
const nextAutoHotkey = options.autoContinueHotkey ?? this.autoContinueHotkey;
|
|
687
|
-
const nextThinkingHotkey = options.thinkingHotkey ?? this.thinkingHotkey;
|
|
688
|
-
const nextThinkingLabel = options.thinkingModeLabel === undefined ? this.thinkingModeLabel : (options.thinkingModeLabel || null);
|
|
689
|
-
if (this.verificationEnabled === nextVerification &&
|
|
690
|
-
this.autoContinueEnabled === nextAutoContinue &&
|
|
691
|
-
this.verificationHotkey === nextVerifyHotkey &&
|
|
692
|
-
this.autoContinueHotkey === nextAutoHotkey &&
|
|
693
|
-
this.thinkingHotkey === nextThinkingHotkey &&
|
|
694
|
-
this.thinkingModeLabel === nextThinkingLabel) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
this.verificationEnabled = nextVerification;
|
|
698
|
-
this.autoContinueEnabled = nextAutoContinue;
|
|
699
|
-
this.verificationHotkey = nextVerifyHotkey;
|
|
700
|
-
this.autoContinueHotkey = nextAutoHotkey;
|
|
701
|
-
this.thinkingHotkey = nextThinkingHotkey;
|
|
702
|
-
this.thinkingModeLabel = nextThinkingLabel;
|
|
703
|
-
this.scheduleRender();
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Clear all status messages at once (convenience method).
|
|
707
|
-
*/
|
|
708
|
-
clearAllStatus() {
|
|
709
|
-
this.statusMessage = null;
|
|
710
|
-
this.overrideStatusMessage = null;
|
|
711
|
-
this.streamingLabel = null;
|
|
712
|
-
this.scheduleRender();
|
|
713
|
-
}
|
|
714
|
-
/**
|
|
715
|
-
* Surface model/provider context in the controls bar.
|
|
716
|
-
*/
|
|
717
|
-
setModelContext(options) {
|
|
718
|
-
const nextModel = options.model?.trim() || null;
|
|
719
|
-
const nextProvider = options.provider?.trim() || null;
|
|
720
|
-
if (this.modelLabel === nextModel && this.providerLabel === nextProvider) {
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
this.modelLabel = nextModel;
|
|
724
|
-
this.providerLabel = nextProvider;
|
|
725
|
-
this.scheduleRender();
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Render the floating input area at contentRow.
|
|
729
|
-
*
|
|
730
|
-
* The chat box "floats" - it renders right below the last streamed content.
|
|
731
|
-
* As content is added, contentRow advances, and the chat box moves down.
|
|
732
|
-
* No scroll regions - pure floating behavior.
|
|
733
|
-
*/
|
|
734
|
-
render() {
|
|
735
|
-
if (!this.canRender())
|
|
736
|
-
return;
|
|
737
|
-
if (this.isRendering)
|
|
738
|
-
return;
|
|
739
|
-
const streamingActive = this.mode === 'streaming' || isStreamingMode();
|
|
740
|
-
const bufferChanged = this.buffer !== this.lastRenderContent || this.cursor !== this.lastRenderCursor;
|
|
741
|
-
// During streaming, throttle re-renders unless the buffer actually changed
|
|
742
|
-
// (e.g., typing slash commands while streaming should update immediately).
|
|
743
|
-
const shouldThrottle = streamingActive &&
|
|
744
|
-
this.lastStreamingRender > 0 &&
|
|
745
|
-
!this.renderDirty &&
|
|
746
|
-
!bufferChanged &&
|
|
747
|
-
!this.showingSuggestions;
|
|
748
|
-
if (shouldThrottle) {
|
|
749
|
-
const elapsed = Date.now() - this.lastStreamingRender;
|
|
750
|
-
const waitMs = Math.max(0, this.streamingRenderInterval - elapsed);
|
|
751
|
-
if (waitMs > 0) {
|
|
752
|
-
this.renderDirty = true;
|
|
753
|
-
this.scheduleStreamingRender(waitMs);
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
const shouldSkip = !this.renderDirty && !bufferChanged;
|
|
758
|
-
this.renderDirty = false;
|
|
759
|
-
if (shouldSkip) {
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
762
|
-
if (writeLock.isLocked()) {
|
|
763
|
-
writeLock.safeWrite(() => this.render());
|
|
764
|
-
return;
|
|
765
|
-
}
|
|
766
|
-
this.renderPinnedChatBox();
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Unified scroll region renderer.
|
|
770
|
-
* Chat box is ALWAYS pinned at the bottom of the terminal.
|
|
771
|
-
* Content scrolls in the region above the chat box.
|
|
772
|
-
*/
|
|
773
|
-
renderPinnedChatBox() {
|
|
774
|
-
const { rows, cols } = this.getSize();
|
|
775
|
-
const maxWidth = Math.max(8, cols - 4);
|
|
776
|
-
const streamingActive = this.mode === 'streaming' || isStreamingMode();
|
|
777
|
-
const prevChatBoxStart = this.lastChatBoxStartRow;
|
|
778
|
-
const prevChatBoxHeight = this.lastChatBoxHeight;
|
|
779
|
-
// Wrap buffer into display lines
|
|
780
|
-
const { lines, cursorLine, cursorCol } = this.wrapBuffer(maxWidth);
|
|
781
|
-
const maxVisible = Math.max(1, Math.min(this.config.maxLines, rows - 3));
|
|
782
|
-
const displayLines = Math.min(lines.length, maxVisible);
|
|
783
|
-
const metaLines = this.buildMetaLines(cols - 2);
|
|
784
|
-
// Calculate display window (keep cursor visible)
|
|
785
|
-
let startLine = 0;
|
|
786
|
-
if (lines.length > displayLines) {
|
|
787
|
-
startLine = Math.max(0, cursorLine - displayLines + 1);
|
|
788
|
-
startLine = Math.min(startLine, lines.length - displayLines);
|
|
789
|
-
}
|
|
790
|
-
const visibleLines = lines.slice(startLine, startLine + displayLines);
|
|
791
|
-
const adjustedCursorLine = cursorLine - startLine;
|
|
792
|
-
// Chat box height
|
|
793
|
-
const chatBoxHeight = this.getChatBoxHeight();
|
|
794
|
-
// ALWAYS pin chat box at absolute bottom
|
|
795
|
-
const chatBoxStartRow = Math.max(1, rows - chatBoxHeight + 1);
|
|
796
|
-
const scrollEnd = chatBoxStartRow - 1;
|
|
797
|
-
this.lastChatBoxStartRow = chatBoxStartRow;
|
|
798
|
-
this.lastChatBoxHeight = chatBoxHeight;
|
|
799
|
-
this.lastSuggestionStartRow = null;
|
|
800
|
-
writeLock.lock('terminalInput.renderPinned');
|
|
801
|
-
this.isRendering = true;
|
|
802
|
-
try {
|
|
803
|
-
// Ensure content stays above the expanded chat/menu area when idle
|
|
804
|
-
if (!streamingActive && !this.scrollRegionActive) {
|
|
805
|
-
this.ensureContentAboveChatBox(chatBoxStartRow, rows);
|
|
806
|
-
}
|
|
807
|
-
this.write(ESC.SAVE);
|
|
808
|
-
this.write(ESC.HIDE);
|
|
809
|
-
// Temporarily reset scroll region to write chat box cleanly
|
|
810
|
-
if (this.scrollRegionActive) {
|
|
811
|
-
this.write(ESC.RESET_SCROLL);
|
|
812
|
-
}
|
|
813
|
-
// Clear the current and previous chat box footprint to avoid ghost text when the height shrinks
|
|
814
|
-
const prevHeight = prevChatBoxStart !== null ? Math.max(1, prevChatBoxHeight) : chatBoxHeight;
|
|
815
|
-
const prevStart = prevChatBoxStart ?? chatBoxStartRow;
|
|
816
|
-
const prevEnd = prevStart + prevHeight - 1;
|
|
817
|
-
const newEnd = chatBoxStartRow + chatBoxHeight - 1;
|
|
818
|
-
const clearStart = Math.max(1, Math.min(prevStart, chatBoxStartRow));
|
|
819
|
-
const clearEnd = Math.min(rows, Math.max(prevEnd, newEnd));
|
|
820
|
-
for (let row = clearStart; row <= clearEnd; row++) {
|
|
821
|
-
this.write(ESC.TO(row, 1));
|
|
822
|
-
this.write(ESC.CLEAR_LINE);
|
|
823
|
-
}
|
|
824
|
-
let currentRow = chatBoxStartRow;
|
|
825
|
-
// Render scroll/status indicator on the left (Claude Code style)
|
|
826
|
-
const scrollIndicator = this.buildScrollIndicator();
|
|
827
|
-
// Meta/status header with scroll indicator
|
|
828
|
-
for (const metaLine of metaLines) {
|
|
829
|
-
this.write(ESC.TO(currentRow, 1));
|
|
830
|
-
this.write(metaLine);
|
|
831
|
-
currentRow += 1;
|
|
832
|
-
}
|
|
833
|
-
// Separator line with scroll status
|
|
834
|
-
this.write(ESC.TO(currentRow, 1));
|
|
835
|
-
const dividerLabel = scrollIndicator || undefined;
|
|
836
|
-
this.write(renderDivider(cols - 2, dividerLabel));
|
|
837
|
-
currentRow += 1;
|
|
838
|
-
// Render input lines
|
|
839
|
-
let finalRow = currentRow;
|
|
840
|
-
let finalCol = 3;
|
|
841
|
-
for (let i = 0; i < visibleLines.length; i++) {
|
|
842
|
-
const rowNum = currentRow + i;
|
|
843
|
-
this.write(ESC.TO(rowNum, 1));
|
|
844
|
-
const line = visibleLines[i] ?? '';
|
|
845
|
-
const isFirstLine = (startLine + i) === 0;
|
|
846
|
-
const isCursorLine = i === adjustedCursorLine;
|
|
847
|
-
const col = isCursorLine ? Math.max(0, Math.min(cursorCol, line.length)) : 0;
|
|
848
|
-
this.write(ESC.BG_DARK);
|
|
849
|
-
this.write(ESC.DIM);
|
|
850
|
-
this.write(isFirstLine ? this.config.promptChar : this.config.continuationChar);
|
|
851
|
-
this.write(ESC.RESET);
|
|
852
|
-
this.write(ESC.BG_DARK);
|
|
853
|
-
if (isCursorLine) {
|
|
854
|
-
const before = line.slice(0, col);
|
|
855
|
-
const at = line.charAt(col) || ' ';
|
|
856
|
-
const after = col < line.length ? line.slice(col + 1) : '';
|
|
857
|
-
this.write(before);
|
|
858
|
-
this.write(ESC.REVERSE + ESC.BOLD);
|
|
859
|
-
this.write(at);
|
|
860
|
-
this.write(ESC.RESET + ESC.BG_DARK);
|
|
861
|
-
this.write(after);
|
|
862
|
-
finalRow = rowNum;
|
|
863
|
-
finalCol = this.config.promptChar.length + col + 1;
|
|
864
|
-
}
|
|
865
|
-
else {
|
|
866
|
-
this.write(line);
|
|
867
|
-
}
|
|
868
|
-
// Pad to edge
|
|
869
|
-
const lineLen = this.config.promptChar.length +
|
|
870
|
-
line.length +
|
|
871
|
-
(isCursorLine && col >= line.length ? 1 : 0);
|
|
872
|
-
const padding = Math.max(0, cols - lineLen - 1);
|
|
873
|
-
if (padding > 0)
|
|
874
|
-
this.write(' '.repeat(padding));
|
|
875
|
-
this.write(ESC.RESET);
|
|
876
|
-
}
|
|
877
|
-
// Command suggestions (shown above controls when "/" is typed)
|
|
878
|
-
const suggestionLines = this.buildSuggestionLines(cols - 2);
|
|
879
|
-
let suggestionRow = currentRow + visibleLines.length;
|
|
880
|
-
if (suggestionLines.length > 0) {
|
|
881
|
-
this.lastSuggestionStartRow = suggestionRow;
|
|
882
|
-
}
|
|
883
|
-
for (const suggestionLine of suggestionLines) {
|
|
884
|
-
this.write(ESC.TO(suggestionRow, 1));
|
|
885
|
-
this.write(' '); // Indent to match input
|
|
886
|
-
this.write(suggestionLine);
|
|
887
|
-
suggestionRow += 1;
|
|
888
|
-
}
|
|
889
|
-
// Mode controls lines with all keyboard shortcuts
|
|
890
|
-
// Can be multiple lines during streaming (status + toggles)
|
|
891
|
-
const controlLines = this.buildModeControls(cols);
|
|
892
|
-
let controlRow = suggestionRow;
|
|
893
|
-
for (const controlLine of controlLines) {
|
|
894
|
-
this.write(ESC.TO(controlRow, 1));
|
|
895
|
-
this.write(controlLine);
|
|
896
|
-
controlRow += 1;
|
|
897
|
-
}
|
|
898
|
-
// Restore scroll region and cursor
|
|
899
|
-
if (this.scrollRegionActive) {
|
|
900
|
-
// Restore scroll region
|
|
901
|
-
this.write(ESC.SET_SCROLL(1, scrollEnd));
|
|
902
|
-
// Restore cursor to where it was before rendering (preserves column position)
|
|
903
|
-
this.write(ESC.RESTORE);
|
|
904
|
-
}
|
|
905
|
-
else {
|
|
906
|
-
// Not streaming - position cursor in input box
|
|
907
|
-
this.write(ESC.RESTORE);
|
|
908
|
-
this.write(ESC.TO(finalRow, Math.min(finalCol, cols)));
|
|
909
|
-
}
|
|
910
|
-
this.write(ESC.SHOW);
|
|
911
|
-
// Update state
|
|
912
|
-
this.lastRenderContent = this.buffer;
|
|
913
|
-
this.lastRenderCursor = this.cursor;
|
|
914
|
-
this.lastStreamingRender = streamingActive ? Date.now() : 0;
|
|
915
|
-
if (this.streamingRenderTimer) {
|
|
916
|
-
clearTimeout(this.streamingRenderTimer);
|
|
917
|
-
this.streamingRenderTimer = null;
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
finally {
|
|
921
|
-
writeLock.unlock();
|
|
922
|
-
this.isRendering = false;
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Keep assistant/user content above the chat box when it expands (e.g., slash menu).
|
|
927
|
-
* Scrolls just enough to free space without moving the cursor.
|
|
928
|
-
*/
|
|
929
|
-
ensureContentAboveChatBox(chatBoxStartRow, rows) {
|
|
930
|
-
const contentMaxRow = Math.max(1, chatBoxStartRow - 1);
|
|
931
|
-
if (this.contentRow < contentMaxRow)
|
|
932
|
-
return;
|
|
933
|
-
const overflow = (this.contentRow - contentMaxRow) + 1;
|
|
934
|
-
const scrollLines = Math.min(overflow, rows);
|
|
935
|
-
this.write(ESC.SAVE);
|
|
936
|
-
this.write(ESC.TO(rows, 1));
|
|
937
|
-
this.write('\n'.repeat(scrollLines));
|
|
938
|
-
this.write(ESC.RESTORE);
|
|
939
|
-
this.contentRow = contentMaxRow;
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* Track output written directly by the display (system/assistant messages) so
|
|
943
|
-
* it is captured in scrollback and accounted for when re-rendering the chat box.
|
|
944
|
-
*/
|
|
945
|
-
trackExternalOutput(content) {
|
|
946
|
-
if (!content)
|
|
947
|
-
return;
|
|
948
|
-
// Normalize and capture in scrollback for history
|
|
949
|
-
const normalized = content.replace(/\r/g, '\n');
|
|
950
|
-
this.addToScrollback(normalized);
|
|
951
|
-
// Advance content row based on rendered height (accounts for wrapping)
|
|
952
|
-
const rowsUsed = this.countRenderedRows(normalized);
|
|
953
|
-
if (rowsUsed > 0) {
|
|
954
|
-
this.contentRow += rowsUsed;
|
|
955
|
-
if (!this.scrollRegionActive) {
|
|
956
|
-
this.scheduleRender();
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Estimate how many terminal rows the provided content will consume.
|
|
962
|
-
* Considers ANSI-stripped visible length and terminal width so wrapped lines
|
|
963
|
-
* correctly advance the tracked cursor position.
|
|
964
|
-
*/
|
|
965
|
-
countRenderedRows(content) {
|
|
966
|
-
if (!content)
|
|
967
|
-
return 0;
|
|
968
|
-
const width = Math.max(1, this.getSize().cols);
|
|
969
|
-
const normalized = content.replace(/\r\n/g, '\n');
|
|
970
|
-
const lines = normalized.split('\n');
|
|
971
|
-
let rows = 0;
|
|
972
|
-
for (let i = 0; i < lines.length; i++) {
|
|
973
|
-
const line = this.normalizeCarriageReturnLine(lines[i] ?? '');
|
|
974
|
-
const visibleLen = this.visibleLength(line);
|
|
975
|
-
if (visibleLen > 0) {
|
|
976
|
-
const wraps = Math.ceil(visibleLen / width);
|
|
977
|
-
if (wraps > 1) {
|
|
978
|
-
rows += wraps - 1;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
// Each newline moves the cursor to the start of the next row
|
|
982
|
-
if (i < lines.length - 1) {
|
|
983
|
-
rows += 1;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
return rows;
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Treat carriage returns as line rewrites rather than newlines for row estimates.
|
|
990
|
-
* If a CR is followed by text, only the text after the last CR is visible.
|
|
991
|
-
* If the line ends with a CR, the existing text stays visible.
|
|
992
|
-
*/
|
|
993
|
-
normalizeCarriageReturnLine(line) {
|
|
994
|
-
if (!line.includes('\r')) {
|
|
995
|
-
return line;
|
|
996
|
-
}
|
|
997
|
-
const lastCr = line.lastIndexOf('\r');
|
|
998
|
-
const after = line.slice(lastCr + 1);
|
|
999
|
-
if (after.length > 0) {
|
|
1000
|
-
return after;
|
|
1001
|
-
}
|
|
1002
|
-
return line.slice(0, lastCr);
|
|
1003
|
-
}
|
|
1004
|
-
/**
|
|
1005
|
-
* Build compact meta line above the divider.
|
|
1006
|
-
* Shows model/provider and key metrics in a single line.
|
|
1007
|
-
*/
|
|
1008
|
-
buildMetaLines(width) {
|
|
1009
|
-
const leftParts = [];
|
|
1010
|
-
const rightParts = [];
|
|
1011
|
-
// Model/provider info (left side)
|
|
1012
|
-
if (this.modelLabel) {
|
|
1013
|
-
const modelText = this.providerLabel
|
|
1014
|
-
? `${this.modelLabel} @ ${this.providerLabel}`
|
|
1015
|
-
: this.modelLabel;
|
|
1016
|
-
leftParts.push({ text: modelText, tone: 'info' });
|
|
1017
|
-
}
|
|
1018
|
-
// Elapsed time (right side)
|
|
1019
|
-
if (this.metaElapsedSeconds !== null) {
|
|
1020
|
-
rightParts.push({ text: `⏱ ${this.formatElapsedLabel(this.metaElapsedSeconds)}`, tone: 'muted' });
|
|
1021
|
-
}
|
|
1022
|
-
// Token usage (right side)
|
|
1023
|
-
if (this.metaTokensUsed !== null) {
|
|
1024
|
-
const formattedUsed = this.formatTokenCount(this.metaTokensUsed);
|
|
1025
|
-
const formattedLimit = this.metaTokenLimit ? `/${this.formatTokenCount(this.metaTokenLimit)}` : '';
|
|
1026
|
-
rightParts.push({ text: `⊛ ${formattedUsed}${formattedLimit}`, tone: 'muted' });
|
|
1027
|
-
}
|
|
1028
|
-
// Context remaining warning
|
|
1029
|
-
const tokensRemaining = this.computeTokensRemaining();
|
|
1030
|
-
if (tokensRemaining !== null) {
|
|
1031
|
-
const contextPct = this.contextUsage !== null ? `${100 - this.contextUsage}%` : '';
|
|
1032
|
-
rightParts.push({ text: `↓${tokensRemaining} ${contextPct}`, tone: this.contextUsage && this.contextUsage > 80 ? 'warn' : 'muted' });
|
|
1033
|
-
}
|
|
1034
|
-
// Thinking indicator
|
|
1035
|
-
if (this.metaThinkingMs !== null) {
|
|
1036
|
-
leftParts.push({ text: formatThinking(this.metaThinkingMs, this.metaThinkingHasContent), tone: 'info' });
|
|
1037
|
-
}
|
|
1038
|
-
if (!leftParts.length && !rightParts.length) {
|
|
1039
|
-
return [];
|
|
1040
|
-
}
|
|
1041
|
-
// Render left and right aligned
|
|
1042
|
-
if (!rightParts.length || width < 50) {
|
|
1043
|
-
return [renderStatusLine([...leftParts, ...rightParts], width)];
|
|
1044
|
-
}
|
|
1045
|
-
const leftWidth = Math.max(12, Math.floor(width * 0.5));
|
|
1046
|
-
const rightWidth = Math.max(14, width - leftWidth - 1);
|
|
1047
|
-
const leftText = renderStatusLine(leftParts, leftWidth);
|
|
1048
|
-
const rightText = renderStatusLine(rightParts, rightWidth);
|
|
1049
|
-
const spacing = Math.max(1, width - this.visibleLength(leftText) - this.visibleLength(rightText));
|
|
1050
|
-
return [`${leftText}${' '.repeat(spacing)}${rightText}`];
|
|
1051
|
-
}
|
|
1052
|
-
/**
|
|
1053
|
-
* Build mode controls lines with all keyboard shortcuts.
|
|
1054
|
-
* Shows status, all toggles, and contextual information.
|
|
1055
|
-
* Enhanced with comprehensive feature status display.
|
|
1056
|
-
*
|
|
1057
|
-
* Returns multiple lines to ensure all context is visible during streaming:
|
|
1058
|
-
* - Line 1 (during streaming): Status/spinner + interrupt shortcut
|
|
1059
|
-
* - Line 2: Mode toggles (edit, verify, auto-continue, thinking)
|
|
1060
|
-
*
|
|
1061
|
-
* Format: [Key] Label:status · [Key] Label:status · context% · model
|
|
1062
|
-
*/
|
|
1063
|
-
buildModeControls(cols) {
|
|
1064
|
-
const width = Math.max(8, cols - 2);
|
|
1065
|
-
const streamingActive = this.mode === 'streaming' || this.scrollRegionActive;
|
|
1066
|
-
// === LINE 1: STATUS LINE (streaming status + interrupt) ===
|
|
1067
|
-
const statusParts = [];
|
|
1068
|
-
// Streaming indicator with animated spinner
|
|
1069
|
-
if (this.streamingLabel) {
|
|
1070
|
-
statusParts.push({ text: `◐ ${this.streamingLabel}`, tone: 'info' });
|
|
1071
|
-
}
|
|
1072
|
-
// Override status (warnings, errors)
|
|
1073
|
-
if (this.overrideStatusMessage) {
|
|
1074
|
-
statusParts.push({ text: `⚠ ${this.overrideStatusMessage}`, tone: 'warn' });
|
|
1075
|
-
}
|
|
1076
|
-
// Main status message
|
|
1077
|
-
if (this.statusMessage) {
|
|
1078
|
-
statusParts.push({ text: this.statusMessage, tone: this.streamingLabel ? 'muted' : 'info' });
|
|
1079
|
-
}
|
|
1080
|
-
// Interrupt shortcut (during streaming)
|
|
1081
|
-
// Queued commands
|
|
1082
|
-
if (this.queue.length > 0) {
|
|
1083
|
-
const queueIcon = streamingActive ? '⏳' : '▸';
|
|
1084
|
-
statusParts.push({ text: `${queueIcon}${this.queue.length} queued`, tone: 'info' });
|
|
1085
|
-
}
|
|
1086
|
-
// === LINE 2: MODE TOGGLES (always visible, same as before streaming) ===
|
|
1087
|
-
const toggleParts = [];
|
|
1088
|
-
// Claude Code style mode indicator: "⏵⏵ accept edits on (shift+tab to cycle)"
|
|
1089
|
-
const editModeLabel = this.editMode === 'display-edits' ? 'auto' :
|
|
1090
|
-
this.editMode === 'ask-permission' ? 'ask' : 'plan';
|
|
1091
|
-
toggleParts.push({ text: formatEditModeIndicator(editModeLabel), tone: editModeLabel === 'plan' ? 'info' : undefined });
|
|
1092
|
-
// Context usage (show percentage remaining)
|
|
1093
|
-
if (this.contextUsage !== null) {
|
|
1094
|
-
const remaining = 100 - this.contextUsage;
|
|
1095
|
-
const contextTone = this.contextUsage > 80 ? 'warn' : this.contextUsage > 60 ? 'info' : 'muted';
|
|
1096
|
-
toggleParts.push({ text: `ctx:${remaining}%`, tone: contextTone });
|
|
1097
|
-
}
|
|
1098
|
-
const verifyHotkey = this.formatHotkey(this.verificationHotkey);
|
|
1099
|
-
const verifyStatus = this.verificationEnabled ? 'Verify on' : 'Verify off';
|
|
1100
|
-
toggleParts.push({
|
|
1101
|
-
text: `${verifyHotkey} ${verifyStatus}`,
|
|
1102
|
-
tone: this.verificationEnabled ? 'success' : 'muted'
|
|
1103
|
-
});
|
|
1104
|
-
const autoHotkey = this.formatHotkey(this.autoContinueHotkey);
|
|
1105
|
-
const autoStatus = this.autoContinueEnabled ? 'Auto-continue on' : 'Auto-continue off';
|
|
1106
|
-
toggleParts.push({
|
|
1107
|
-
text: `${autoHotkey} ${autoStatus}`,
|
|
1108
|
-
tone: this.autoContinueEnabled ? 'info' : 'muted'
|
|
1109
|
-
});
|
|
1110
|
-
// Thinking mode toggle
|
|
1111
|
-
if (this.thinkingModeLabel) {
|
|
1112
|
-
const shortThinking = this.thinkingModeLabel.length > 10
|
|
1113
|
-
? this.thinkingModeLabel.slice(0, 8) + '..'
|
|
1114
|
-
: this.thinkingModeLabel;
|
|
1115
|
-
const thinkingHotkey = this.formatHotkey(this.thinkingHotkey);
|
|
1116
|
-
toggleParts.push({ text: `${thinkingHotkey} Thinking ${shortThinking}`, tone: 'info' });
|
|
1117
|
-
}
|
|
1118
|
-
// Navigation shortcuts - always show these
|
|
1119
|
-
toggleParts.push({ text: 'PgUp/Dn:scroll', tone: 'muted' });
|
|
1120
|
-
toggleParts.push({ text: '/help', tone: 'muted' });
|
|
1121
|
-
// Multi-line indicator
|
|
1122
|
-
if (this.buffer.includes('\n')) {
|
|
1123
|
-
const lineCount = this.buffer.split('\n').length;
|
|
1124
|
-
toggleParts.push({ text: `${lineCount}L`, tone: 'muted' });
|
|
1125
|
-
}
|
|
1126
|
-
// Paste indicator
|
|
1127
|
-
if (this.pastePlaceholders.length > 0) {
|
|
1128
|
-
const latest = this.pastePlaceholders[this.pastePlaceholders.length - 1];
|
|
1129
|
-
toggleParts.push({
|
|
1130
|
-
text: `📋${latest.lineCount}L`,
|
|
1131
|
-
tone: 'info',
|
|
1132
|
-
});
|
|
1133
|
-
}
|
|
1134
|
-
// Build the output lines - use wrapping to never truncate
|
|
1135
|
-
const lines = [];
|
|
1136
|
-
// During streaming: show status line first, then toggles (wrapped as needed)
|
|
1137
|
-
// Not streaming: show combined or just toggles (wrapped as needed)
|
|
1138
|
-
if (streamingActive && statusParts.length > 0) {
|
|
1139
|
-
// Status line (usually fits on one line)
|
|
1140
|
-
lines.push(renderStatusLine(statusParts, width));
|
|
1141
|
-
// Toggle parts - wrap to multiple lines if needed
|
|
1142
|
-
lines.push(...renderStatusLines(toggleParts, width));
|
|
1143
|
-
}
|
|
1144
|
-
else if (statusParts.length > 0) {
|
|
1145
|
-
// Not streaming but have status - use wrapping for all parts
|
|
1146
|
-
const combined = [...statusParts, ...toggleParts];
|
|
1147
|
-
lines.push(...renderStatusLines(combined, width));
|
|
1148
|
-
}
|
|
1149
|
-
else {
|
|
1150
|
-
// No streaming, no status - just show toggles (wrapped as needed)
|
|
1151
|
-
lines.push(...renderStatusLines(toggleParts, width));
|
|
1152
|
-
}
|
|
1153
|
-
// Ensure at least one line is returned
|
|
1154
|
-
if (lines.length === 0) {
|
|
1155
|
-
lines.push('');
|
|
1156
|
-
}
|
|
1157
|
-
return lines;
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Render a mini context usage bar (5 chars)
|
|
1161
|
-
*/
|
|
1162
|
-
renderMiniContextBar(percentRemaining) {
|
|
1163
|
-
const bars = 5;
|
|
1164
|
-
const filled = Math.round((percentRemaining / 100) * bars);
|
|
1165
|
-
const empty = bars - filled;
|
|
1166
|
-
return '█'.repeat(filled) + '░'.repeat(empty);
|
|
1167
|
-
}
|
|
1168
|
-
formatHotkey(hotkey) {
|
|
1169
|
-
const normalized = hotkey.trim().toLowerCase();
|
|
1170
|
-
if (!normalized)
|
|
1171
|
-
return hotkey;
|
|
1172
|
-
const parts = normalized.split('+').filter(Boolean);
|
|
1173
|
-
const map = {
|
|
1174
|
-
shift: 'Shift',
|
|
1175
|
-
sh: 'Shift',
|
|
1176
|
-
alt: 'Alt',
|
|
1177
|
-
option: 'Alt',
|
|
1178
|
-
opt: 'Alt',
|
|
1179
|
-
ctrl: 'Ctrl',
|
|
1180
|
-
control: 'Ctrl',
|
|
1181
|
-
cmd: 'Cmd',
|
|
1182
|
-
meta: 'Cmd',
|
|
1183
|
-
};
|
|
1184
|
-
const formatted = parts
|
|
1185
|
-
.map((part) => {
|
|
1186
|
-
const symbol = map[part];
|
|
1187
|
-
if (symbol)
|
|
1188
|
-
return symbol;
|
|
1189
|
-
if (part.startsWith('/'))
|
|
1190
|
-
return part;
|
|
1191
|
-
if (part.length === 1)
|
|
1192
|
-
return part.toUpperCase();
|
|
1193
|
-
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
1194
|
-
})
|
|
1195
|
-
.join('+');
|
|
1196
|
-
return formatted || hotkey;
|
|
1197
|
-
}
|
|
1198
|
-
computeContextRemaining() {
|
|
1199
|
-
if (this.contextUsage === null) {
|
|
1200
|
-
return null;
|
|
1201
|
-
}
|
|
1202
|
-
return Math.max(0, this.contextAutoCompactThreshold - this.contextUsage);
|
|
1203
|
-
}
|
|
1204
|
-
computeTokensRemaining() {
|
|
1205
|
-
if (this.metaTokensUsed === null || this.metaTokenLimit === null) {
|
|
1206
|
-
return null;
|
|
1207
|
-
}
|
|
1208
|
-
const remaining = Math.max(0, this.metaTokenLimit - this.metaTokensUsed);
|
|
1209
|
-
return this.formatTokenCount(remaining);
|
|
1210
|
-
}
|
|
1211
|
-
formatElapsedLabel(seconds) {
|
|
1212
|
-
if (seconds < 60) {
|
|
1213
|
-
return `${seconds}s`;
|
|
1214
|
-
}
|
|
1215
|
-
const mins = Math.floor(seconds / 60);
|
|
1216
|
-
const secs = seconds % 60;
|
|
1217
|
-
return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;
|
|
1218
|
-
}
|
|
1219
|
-
formatTokenCount(value) {
|
|
1220
|
-
if (!Number.isFinite(value)) {
|
|
1221
|
-
return `${value}`;
|
|
1222
|
-
}
|
|
1223
|
-
if (value >= 1_000_000) {
|
|
1224
|
-
return `${(value / 1_000_000).toFixed(1)}M`;
|
|
1225
|
-
}
|
|
1226
|
-
if (value >= 1_000) {
|
|
1227
|
-
return `${(value / 1_000).toFixed(1)}k`;
|
|
1228
|
-
}
|
|
1229
|
-
return `${Math.round(value)}`;
|
|
1230
|
-
}
|
|
1231
|
-
visibleLength(value) {
|
|
1232
|
-
const ansiPattern = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
1233
|
-
return value.replace(ansiPattern, '').length;
|
|
1234
|
-
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Debug-only snapshot used by tests to assert rendered strings without
|
|
1237
|
-
* needing a TTY. Not used by production code.
|
|
1238
|
-
*/
|
|
1239
|
-
getDebugUiSnapshot(width) {
|
|
1240
|
-
const cols = Math.max(8, width ?? this.getSize().cols);
|
|
1241
|
-
return {
|
|
1242
|
-
meta: this.buildMetaLines(cols - 2),
|
|
1243
|
-
controls: this.buildModeControls(cols),
|
|
1244
|
-
};
|
|
1245
|
-
}
|
|
1246
|
-
/**
|
|
1247
|
-
* Force a re-render
|
|
1248
|
-
*/
|
|
1249
|
-
forceRender() {
|
|
1250
|
-
this.lastRenderContent = '';
|
|
1251
|
-
this.lastRenderCursor = -1;
|
|
1252
|
-
this.renderDirty = true;
|
|
1253
|
-
this.render();
|
|
1254
|
-
}
|
|
1255
|
-
/**
|
|
1256
|
-
* Enable/disable input
|
|
1257
|
-
*/
|
|
1258
|
-
setEnabled(enabled) {
|
|
1259
|
-
this.enabled = enabled;
|
|
1260
|
-
}
|
|
1261
|
-
/**
|
|
1262
|
-
* Handle terminal resize
|
|
1263
|
-
*/
|
|
1264
|
-
handleResize() {
|
|
1265
|
-
this.lastRenderContent = '';
|
|
1266
|
-
this.lastRenderCursor = -1;
|
|
1267
|
-
this.resetStreamingRenderThrottle();
|
|
1268
|
-
// If in scrollback mode, re-render the scrollback view with new dimensions
|
|
1269
|
-
if (this.isInScrollbackMode) {
|
|
1270
|
-
this.renderScrollbackView();
|
|
1271
|
-
}
|
|
1272
|
-
else {
|
|
1273
|
-
this.scheduleRender();
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
* Enter streaming mode with scroll region.
|
|
1278
|
-
* Sets up terminal scroll region to exclude chat box.
|
|
1279
|
-
*/
|
|
1280
|
-
enterStreamingScrollRegion() {
|
|
1281
|
-
const { rows } = this.getSize();
|
|
1282
|
-
const chatBoxHeight = this.getChatBoxHeight();
|
|
1283
|
-
const scrollEnd = Math.max(1, rows - chatBoxHeight);
|
|
1284
|
-
writeLock.lock('enterStreamingScrollRegion');
|
|
1285
|
-
try {
|
|
1286
|
-
// Set scroll region for content area (above chat box)
|
|
1287
|
-
this.write(ESC.SET_SCROLL(1, scrollEnd));
|
|
1288
|
-
// Position cursor at current content row
|
|
1289
|
-
this.write(ESC.TO(Math.min(this.contentRow, scrollEnd), 1));
|
|
1290
|
-
this.scrollRegionActive = true;
|
|
1291
|
-
this.setStatusMessage('esc to interrupt');
|
|
1292
|
-
}
|
|
1293
|
-
finally {
|
|
1294
|
-
writeLock.unlock();
|
|
1295
|
-
}
|
|
1296
|
-
// Render pinned chat box at bottom
|
|
1297
|
-
this.forceRender();
|
|
1298
|
-
}
|
|
1299
|
-
/**
|
|
1300
|
-
* Exit streaming mode and restore normal operation.
|
|
1301
|
-
* Clears the old pinned chat box area to prevent duplication.
|
|
1302
|
-
*/
|
|
1303
|
-
exitStreamingScrollRegion() {
|
|
1304
|
-
const { rows } = this.getSize();
|
|
1305
|
-
const chatBoxHeight = this.getChatBoxHeight();
|
|
1306
|
-
writeLock.lock('exitStreamingScrollRegion');
|
|
1307
|
-
try {
|
|
1308
|
-
// Reset scroll region to full terminal
|
|
1309
|
-
this.write(ESC.RESET_SCROLL);
|
|
1310
|
-
// Clear the old pinned chat box area to prevent duplication
|
|
1311
|
-
// The old chat box was rendered at fixed bottom positions
|
|
1312
|
-
const oldChatBoxStart = Math.max(1, rows - chatBoxHeight + 1);
|
|
1313
|
-
for (let i = 0; i < chatBoxHeight; i++) {
|
|
1314
|
-
const row = oldChatBoxStart + i;
|
|
1315
|
-
if (row <= rows) {
|
|
1316
|
-
this.write(ESC.TO(row, 1));
|
|
1317
|
-
this.write(ESC.CLEAR_LINE);
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
// Move cursor back up to where content should continue
|
|
1321
|
-
this.write(ESC.TO(oldChatBoxStart, 1));
|
|
1322
|
-
this.scrollRegionActive = false;
|
|
1323
|
-
this.setStatusMessage('Ready for prompts');
|
|
1324
|
-
}
|
|
1325
|
-
finally {
|
|
1326
|
-
writeLock.unlock();
|
|
1327
|
-
}
|
|
1328
|
-
// Final render - will render new chat box at correct position
|
|
1329
|
-
this.forceRender();
|
|
1330
|
-
}
|
|
1331
|
-
/**
|
|
1332
|
-
* Render chat box at bottom - now uses unified renderer.
|
|
1333
|
-
* @deprecated Use renderPinnedChatBox() directly via render()/forceRender()
|
|
1334
|
-
*/
|
|
1335
|
-
renderChatBoxAtBottom() {
|
|
1336
|
-
this.renderPinnedChatBox();
|
|
1337
|
-
}
|
|
1338
|
-
/**
|
|
1339
|
-
* Stream content within the scroll region.
|
|
1340
|
-
* Content is written directly and scrolls naturally.
|
|
1341
|
-
*/
|
|
1342
|
-
streamContent(content) {
|
|
1343
|
-
if (!content)
|
|
1344
|
-
return;
|
|
1345
|
-
// Capture content in scrollback buffer
|
|
1346
|
-
this.addToScrollback(content);
|
|
1347
|
-
writeLock.lock('streamContent');
|
|
1348
|
-
try {
|
|
1349
|
-
// Write content - scroll region handles scrolling
|
|
1350
|
-
this.write(content);
|
|
1351
|
-
// Track rendered rows (handles wrapping)
|
|
1352
|
-
const rowsUsed = this.countRenderedRows(content);
|
|
1353
|
-
this.contentRow += rowsUsed;
|
|
1354
|
-
}
|
|
1355
|
-
finally {
|
|
1356
|
-
writeLock.unlock();
|
|
1357
|
-
}
|
|
1358
|
-
// Throttle chat box updates only when a re-render is needed.
|
|
1359
|
-
// In streaming mode the chat box stays pinned, so skip redundant redraws.
|
|
1360
|
-
const needsRender = !this.scrollRegionActive || this.renderDirty;
|
|
1361
|
-
if (needsRender) {
|
|
1362
|
-
if (!this.scrollRegionActive) {
|
|
1363
|
-
// Content moved; force a render so the chat box follows.
|
|
1364
|
-
this.renderDirty = true;
|
|
1365
|
-
}
|
|
1366
|
-
this.scheduleStreamingRender(200);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
/**
|
|
1370
|
-
* Enable scroll region (no-op in floating mode).
|
|
1371
|
-
*/
|
|
1372
|
-
enableScrollRegion() {
|
|
1373
|
-
// No-op: using pure floating approach
|
|
1374
|
-
}
|
|
1375
|
-
/**
|
|
1376
|
-
* Disable scroll region (no-op in floating mode).
|
|
1377
|
-
*/
|
|
1378
|
-
disableScrollRegion() {
|
|
1379
|
-
// No-op: using pure floating approach
|
|
1380
|
-
}
|
|
1381
|
-
/**
|
|
1382
|
-
* Calculate chat box height dynamically.
|
|
1383
|
-
* Accounts for:
|
|
1384
|
-
* - Meta lines (model, elapsed, tokens)
|
|
1385
|
-
* - Divider
|
|
1386
|
-
* - Input line(s) - expands for multi-line/wrapped input
|
|
1387
|
-
* - Command suggestions (when showing)
|
|
1388
|
-
* - Control lines (wraps as needed to fit all toggles)
|
|
1389
|
-
* - Buffer
|
|
1390
|
-
*/
|
|
1391
|
-
getChatBoxHeight() {
|
|
1392
|
-
const { rows, cols } = this.getSize();
|
|
1393
|
-
// Calculate actual input lines needed (wrapped buffer)
|
|
1394
|
-
const maxWidth = Math.max(1, cols - 4); // Account for prompt and padding
|
|
1395
|
-
const { lines: wrappedLines } = this.wrapBuffer(maxWidth);
|
|
1396
|
-
// Allow the chat box to grow with the prompt while respecting any explicit limit
|
|
1397
|
-
const inputLines = Math.max(1, Math.min(wrappedLines.length, this.config.maxLines));
|
|
1398
|
-
// Calculate actual control lines (they wrap as needed)
|
|
1399
|
-
const controlLines = this.buildModeControls(cols);
|
|
1400
|
-
const controlLineCount = Math.max(1, controlLines.length);
|
|
1401
|
-
// Meta line only if we have model/elapsed info
|
|
1402
|
-
const hasMetaInfo = this.modelLabel || this.metaElapsedSeconds !== null || this.metaTokensUsed !== null;
|
|
1403
|
-
const metaLines = hasMetaInfo ? 1 : 0;
|
|
1404
|
-
// Command suggestion lines (when showing)
|
|
1405
|
-
let suggestionLines = 0;
|
|
1406
|
-
if (this.showingSuggestions) {
|
|
1407
|
-
const filtered = this.getFilteredCommands();
|
|
1408
|
-
suggestionLines = Math.min(filtered.length, this.maxVisibleSuggestions) + 1; // +1 for header
|
|
1409
|
-
}
|
|
1410
|
-
// Total: meta + divider + input lines + suggestions + controls + buffer
|
|
1411
|
-
// Leave a small buffer so streamed content still has space above the chat box
|
|
1412
|
-
const totalHeight = metaLines + 1 + inputLines + suggestionLines + controlLineCount + 1;
|
|
1413
|
-
const minContentRows = 2;
|
|
1414
|
-
const maxHeight = Math.max(4, rows - minContentRows);
|
|
1415
|
-
return Math.min(totalHeight, maxHeight);
|
|
1416
|
-
}
|
|
1417
|
-
/**
|
|
1418
|
-
* @deprecated Use streamContent() instead
|
|
1419
|
-
* Register with display's output interceptor - kept for backwards compatibility
|
|
1420
|
-
*/
|
|
1421
|
-
registerOutputInterceptor(_display) {
|
|
1422
|
-
const display = _display;
|
|
1423
|
-
if (!display?.registerOutputInterceptor)
|
|
1424
|
-
return;
|
|
1425
|
-
// Remove prior hook if present
|
|
1426
|
-
if (this.displayInterceptorDispose) {
|
|
1427
|
-
this.displayInterceptorDispose();
|
|
1428
|
-
this.displayInterceptorDispose = null;
|
|
1429
|
-
}
|
|
1430
|
-
this.displayInterceptorDispose = display.registerOutputInterceptor({
|
|
1431
|
-
afterWrite: (content) => {
|
|
1432
|
-
if (!content)
|
|
1433
|
-
return;
|
|
1434
|
-
this.trackExternalOutput(content);
|
|
1435
|
-
},
|
|
1436
|
-
});
|
|
1437
|
-
}
|
|
1438
|
-
/**
|
|
1439
|
-
* Write content above the floating chat box.
|
|
1440
|
-
* Works both during streaming and when idle.
|
|
1441
|
-
*/
|
|
1442
|
-
writeToScrollRegion(content) {
|
|
1443
|
-
if (!content)
|
|
1444
|
-
return;
|
|
1445
|
-
// Capture content in scrollback buffer
|
|
1446
|
-
this.addToScrollback(content);
|
|
1447
|
-
writeLock.lock('writeToScrollRegion');
|
|
1448
|
-
try {
|
|
1449
|
-
// Position cursor at content row and write
|
|
1450
|
-
this.write(ESC.TO(this.contentRow, 1));
|
|
1451
|
-
this.write(content);
|
|
1452
|
-
// Track rendered rows (handles wrapping)
|
|
1453
|
-
const rowsUsed = this.countRenderedRows(content);
|
|
1454
|
-
this.contentRow += rowsUsed;
|
|
1455
|
-
}
|
|
1456
|
-
finally {
|
|
1457
|
-
writeLock.unlock();
|
|
1458
|
-
}
|
|
1459
|
-
// Re-render chat box below new content (only when not streaming)
|
|
1460
|
-
if (!this.scrollRegionActive) {
|
|
1461
|
-
this.forceRender();
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
/**
|
|
1465
|
-
* Enter alternate screen buffer.
|
|
1466
|
-
* DISABLED: Using terminal-native mode for proper scrollback and text selection.
|
|
1467
|
-
*/
|
|
1468
|
-
enterAlternateScreen() {
|
|
1469
|
-
// Disabled - using terminal-native mode
|
|
1470
|
-
this.contentRow = 1;
|
|
1471
|
-
}
|
|
1472
|
-
/**
|
|
1473
|
-
* Exit alternate screen buffer.
|
|
1474
|
-
* DISABLED: Using terminal-native mode.
|
|
1475
|
-
*/
|
|
1476
|
-
exitAlternateScreen() {
|
|
1477
|
-
// Disabled - using terminal-native mode
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* Check if alternate screen buffer is currently active.
|
|
1481
|
-
* Always returns false - using terminal-native mode.
|
|
1482
|
-
*/
|
|
1483
|
-
isAlternateScreenActive() {
|
|
1484
|
-
return false;
|
|
1485
|
-
}
|
|
1486
|
-
/**
|
|
1487
|
-
* Get a snapshot of the scrollback buffer (for display on exit).
|
|
1488
|
-
*/
|
|
1489
|
-
getScrollbackSnapshot() {
|
|
1490
|
-
return [...this.scrollbackBuffer];
|
|
1491
|
-
}
|
|
1492
|
-
/**
|
|
1493
|
-
* Clear the visible terminal area and reset content position.
|
|
1494
|
-
* In terminal-native mode, this just adds newlines to scroll past content
|
|
1495
|
-
* rather than clearing history (preserving scrollback).
|
|
1496
|
-
*/
|
|
1497
|
-
clearScreen() {
|
|
1498
|
-
writeLock.lock('clearScreen');
|
|
1499
|
-
try {
|
|
1500
|
-
// In native mode, scroll past existing content rather than clearing
|
|
1501
|
-
const { rows } = this.getSize();
|
|
1502
|
-
this.write('\n'.repeat(rows));
|
|
1503
|
-
this.write(ESC.HOME);
|
|
1504
|
-
this.contentRow = 1;
|
|
1505
|
-
}
|
|
1506
|
-
finally {
|
|
1507
|
-
writeLock.unlock();
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
/**
|
|
1511
|
-
* Reset content position to row 1.
|
|
1512
|
-
* Does NOT clear the terminal - content starts from current position.
|
|
1513
|
-
*/
|
|
1514
|
-
resetContentPosition() {
|
|
1515
|
-
this.contentRow = 1;
|
|
1516
|
-
}
|
|
1517
|
-
/**
|
|
1518
|
-
* Set the content row explicitly (used after banner is written).
|
|
1519
|
-
* This tells the input where content should start flowing from.
|
|
1520
|
-
*/
|
|
1521
|
-
setContentRow(row) {
|
|
1522
|
-
this.contentRow = Math.max(1, row);
|
|
1523
|
-
}
|
|
1524
|
-
/**
|
|
1525
|
-
* Get the current content row position.
|
|
1526
|
-
*/
|
|
1527
|
-
getContentRow() {
|
|
1528
|
-
return this.contentRow;
|
|
1529
|
-
}
|
|
1530
|
-
/**
|
|
1531
|
-
* Dispose and clean up
|
|
1532
|
-
*/
|
|
1533
|
-
dispose() {
|
|
1534
|
-
if (this.disposed)
|
|
1535
|
-
return;
|
|
1536
|
-
this.disposed = true;
|
|
1537
|
-
this.enabled = false;
|
|
1538
|
-
if (this.displayInterceptorDispose) {
|
|
1539
|
-
this.displayInterceptorDispose();
|
|
1540
|
-
this.displayInterceptorDispose = null;
|
|
1541
|
-
}
|
|
1542
|
-
this.disableScrollRegion();
|
|
1543
|
-
this.resetStreamingRenderThrottle();
|
|
1544
|
-
this.disableBracketedPaste();
|
|
1545
|
-
this.buffer = '';
|
|
1546
|
-
this.queue = [];
|
|
1547
|
-
this.removeAllListeners();
|
|
1548
|
-
}
|
|
1549
|
-
// ===========================================================================
|
|
1550
|
-
// INPUT HANDLING
|
|
1551
|
-
// ===========================================================================
|
|
1552
|
-
handleCtrlKey(key) {
|
|
1553
|
-
switch (key.name) {
|
|
1554
|
-
case 'c':
|
|
1555
|
-
if (this.buffer.length > 0) {
|
|
1556
|
-
this.clear();
|
|
1557
|
-
}
|
|
1558
|
-
else {
|
|
1559
|
-
this.emit('interrupt');
|
|
1560
|
-
}
|
|
1561
|
-
return true;
|
|
1562
|
-
case 'a': // Home
|
|
1563
|
-
this.moveCursorToLineStart();
|
|
1564
|
-
return true;
|
|
1565
|
-
case 'e': // End
|
|
1566
|
-
if (key.shift) {
|
|
1567
|
-
this.toggleEditMode();
|
|
1568
|
-
this.emit('toggleEditMode');
|
|
1569
|
-
return true;
|
|
1570
|
-
}
|
|
1571
|
-
this.moveCursorToLineEnd();
|
|
1572
|
-
return true;
|
|
1573
|
-
case 'u': // Delete to start
|
|
1574
|
-
this.deleteToStart();
|
|
1575
|
-
return true;
|
|
1576
|
-
case 'k': // Delete to end
|
|
1577
|
-
this.deleteToEnd();
|
|
1578
|
-
return true;
|
|
1579
|
-
case 'w': // Delete word
|
|
1580
|
-
this.deleteWord();
|
|
1581
|
-
return true;
|
|
1582
|
-
case 'left': // Word left
|
|
1583
|
-
this.moveCursorWordLeft();
|
|
1584
|
-
return true;
|
|
1585
|
-
case 'right': // Word right
|
|
1586
|
-
this.moveCursorWordRight();
|
|
1587
|
-
return true;
|
|
1588
|
-
case 'return': // Ctrl+Enter => newline instead of submit
|
|
1589
|
-
this.insertNewline();
|
|
1590
|
-
return true;
|
|
1591
|
-
case 'v':
|
|
1592
|
-
if (key.shift) {
|
|
1593
|
-
this.emit('toggleVerify');
|
|
1594
|
-
return true;
|
|
1595
|
-
}
|
|
1596
|
-
break;
|
|
1597
|
-
case 'c':
|
|
1598
|
-
if (key.shift) {
|
|
1599
|
-
this.emit('toggleAutoContinue');
|
|
1600
|
-
return true;
|
|
1601
|
-
}
|
|
1602
|
-
break;
|
|
1603
|
-
case 't':
|
|
1604
|
-
if (key.shift) {
|
|
1605
|
-
this.emit('toggleThinking');
|
|
1606
|
-
return true;
|
|
1607
|
-
}
|
|
1608
|
-
break;
|
|
1609
|
-
case 'x':
|
|
1610
|
-
if (key.shift) {
|
|
1611
|
-
this.emit('clearContext');
|
|
1612
|
-
return true;
|
|
1613
|
-
}
|
|
1614
|
-
break;
|
|
1615
|
-
case 's':
|
|
1616
|
-
if (key.shift) {
|
|
1617
|
-
this.toggleScrollbackMode();
|
|
1618
|
-
return true;
|
|
1619
|
-
}
|
|
1620
|
-
break;
|
|
1621
|
-
}
|
|
1622
|
-
return false;
|
|
1623
|
-
}
|
|
1624
|
-
/**
|
|
1625
|
-
* Handle Alt/Meta key combinations for mode toggles and navigation.
|
|
1626
|
-
* Ctrl-based shortcuts are primary; Alt/Meta remains as a compatibility fallback.
|
|
1627
|
-
*/
|
|
1628
|
-
handleMetaKey(key) {
|
|
1629
|
-
switch (key.name) {
|
|
1630
|
-
// === CURSOR MOVEMENT ===
|
|
1631
|
-
case 'left':
|
|
1632
|
-
case 'b':
|
|
1633
|
-
this.moveCursorWordLeft();
|
|
1634
|
-
break;
|
|
1635
|
-
case 'right':
|
|
1636
|
-
case 'f':
|
|
1637
|
-
this.moveCursorWordRight();
|
|
1638
|
-
break;
|
|
1639
|
-
case 'backspace':
|
|
1640
|
-
this.deleteWord();
|
|
1641
|
-
break;
|
|
1642
|
-
case 'return':
|
|
1643
|
-
this.insertNewline();
|
|
1644
|
-
break;
|
|
1645
|
-
// === MODE TOGGLES ===
|
|
1646
|
-
case 'v':
|
|
1647
|
-
// Alt+V: Toggle verification mode (auto-tests after edits)
|
|
1648
|
-
this.emit('toggleVerify');
|
|
1649
|
-
break;
|
|
1650
|
-
case 'c':
|
|
1651
|
-
// Alt+C: Toggle auto-continue mode
|
|
1652
|
-
this.emit('toggleAutoContinue');
|
|
1653
|
-
break;
|
|
1654
|
-
case 't':
|
|
1655
|
-
// Alt+T: Toggle/cycle thinking mode
|
|
1656
|
-
this.emit('toggleThinking');
|
|
1657
|
-
break;
|
|
1658
|
-
case 'e':
|
|
1659
|
-
// Alt+E: Toggle edit permission mode (ask/auto)
|
|
1660
|
-
this.toggleEditMode();
|
|
1661
|
-
this.emit('toggleEditMode');
|
|
1662
|
-
break;
|
|
1663
|
-
case 'x':
|
|
1664
|
-
// Alt+X: Clear/compact context
|
|
1665
|
-
this.emit('clearContext');
|
|
1666
|
-
break;
|
|
1667
|
-
// === SCROLLBACK NAVIGATION ===
|
|
1668
|
-
case 's':
|
|
1669
|
-
// Alt+S: Toggle scrollback mode
|
|
1670
|
-
this.toggleScrollbackMode();
|
|
1671
|
-
break;
|
|
1672
|
-
case 'up':
|
|
1673
|
-
// Alt+Up: Quick scroll up into history
|
|
1674
|
-
if (!this.isInScrollbackMode) {
|
|
1675
|
-
this.scrollUp(10);
|
|
1676
|
-
}
|
|
1677
|
-
else {
|
|
1678
|
-
this.scrollUp(1);
|
|
1679
|
-
}
|
|
1680
|
-
break;
|
|
1681
|
-
case 'down':
|
|
1682
|
-
// Alt+Down: Quick scroll down
|
|
1683
|
-
if (this.isInScrollbackMode) {
|
|
1684
|
-
this.scrollDown(1);
|
|
1685
|
-
}
|
|
1686
|
-
break;
|
|
1687
|
-
case 'pageup':
|
|
1688
|
-
// Alt+PageUp: Page up in scrollback
|
|
1689
|
-
this.scrollUp(this.getPageSize());
|
|
1690
|
-
break;
|
|
1691
|
-
case 'pagedown':
|
|
1692
|
-
// Alt+PageDown: Page down in scrollback
|
|
1693
|
-
this.scrollDown(this.getPageSize());
|
|
1694
|
-
break;
|
|
1695
|
-
case 'home':
|
|
1696
|
-
// Alt+Home: Jump to top of scrollback
|
|
1697
|
-
this.scrollToTop();
|
|
1698
|
-
break;
|
|
1699
|
-
case 'end':
|
|
1700
|
-
// Alt+End: Jump to bottom (live)
|
|
1701
|
-
this.scrollToBottom();
|
|
1702
|
-
break;
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
/**
|
|
1706
|
-
* Get page size for scrollback navigation.
|
|
1707
|
-
*/
|
|
1708
|
-
getPageSize() {
|
|
1709
|
-
const { rows } = this.getSize();
|
|
1710
|
-
const chatBoxHeight = this.getChatBoxHeight();
|
|
1711
|
-
return Math.max(5, rows - chatBoxHeight - 2);
|
|
1712
|
-
}
|
|
1713
|
-
/**
|
|
1714
|
-
* Build scroll indicator for the divider line.
|
|
1715
|
-
* Scrollback navigation is disabled in alternate screen mode.
|
|
1716
|
-
* This returns null - no scroll indicator is shown.
|
|
1717
|
-
*/
|
|
1718
|
-
buildScrollIndicator() {
|
|
1719
|
-
// Scrollback navigation disabled - no indicator needed
|
|
1720
|
-
return null;
|
|
1721
|
-
}
|
|
1722
|
-
handleSpecialKey(_str, key) {
|
|
1723
|
-
switch (key.name) {
|
|
1724
|
-
case 'return':
|
|
1725
|
-
if (key.shift || key.meta || key.ctrl) {
|
|
1726
|
-
this.insertNewline();
|
|
1727
|
-
}
|
|
1728
|
-
else if (this.showingSuggestions) {
|
|
1729
|
-
// Select highlighted suggestion and submit immediately
|
|
1730
|
-
this.selectSuggestion({ submit: true });
|
|
1731
|
-
}
|
|
1732
|
-
else {
|
|
1733
|
-
this.submit();
|
|
1734
|
-
}
|
|
1735
|
-
return true;
|
|
1736
|
-
case 'escape':
|
|
1737
|
-
// Cancel suggestions first, or emit interrupt
|
|
1738
|
-
if (this.cancelSuggestions()) {
|
|
1739
|
-
return true;
|
|
1740
|
-
}
|
|
1741
|
-
this.emit('interrupt');
|
|
1742
|
-
return true;
|
|
1743
|
-
case 'backspace':
|
|
1744
|
-
this.deleteBackward();
|
|
1745
|
-
return true;
|
|
1746
|
-
case 'delete':
|
|
1747
|
-
this.deleteForward();
|
|
1748
|
-
return true;
|
|
1749
|
-
case 'left':
|
|
1750
|
-
// Cancel suggestions on cursor movement
|
|
1751
|
-
if (this.showingSuggestions) {
|
|
1752
|
-
this.cancelSuggestions();
|
|
1753
|
-
}
|
|
1754
|
-
this.moveCursorLeft();
|
|
1755
|
-
return true;
|
|
1756
|
-
case 'right':
|
|
1757
|
-
// Cancel suggestions on cursor movement
|
|
1758
|
-
if (this.showingSuggestions) {
|
|
1759
|
-
this.cancelSuggestions();
|
|
1760
|
-
}
|
|
1761
|
-
this.moveCursorRight();
|
|
1762
|
-
return true;
|
|
1763
|
-
case 'up':
|
|
1764
|
-
// When showing suggestions, navigate up
|
|
1765
|
-
if (this.showingSuggestions) {
|
|
1766
|
-
this.moveSuggestionUp();
|
|
1767
|
-
return true;
|
|
1768
|
-
}
|
|
1769
|
-
// Ctrl+Shift+Up or Shift+Up: Quick scroll up in scrollback
|
|
1770
|
-
if ((key.ctrl && key.shift) || key.shift) {
|
|
1771
|
-
this.scrollUp(5);
|
|
1772
|
-
}
|
|
1773
|
-
else {
|
|
1774
|
-
this.handleUp();
|
|
1775
|
-
}
|
|
1776
|
-
return true;
|
|
1777
|
-
case 'down':
|
|
1778
|
-
// When showing suggestions, navigate down
|
|
1779
|
-
if (this.showingSuggestions) {
|
|
1780
|
-
this.moveSuggestionDown();
|
|
1781
|
-
return true;
|
|
1782
|
-
}
|
|
1783
|
-
// Ctrl+Shift+Down or Shift+Down: Quick scroll down in scrollback
|
|
1784
|
-
if ((key.ctrl && key.shift) || key.shift) {
|
|
1785
|
-
this.scrollDown(5);
|
|
1786
|
-
}
|
|
1787
|
-
else {
|
|
1788
|
-
this.handleDown();
|
|
1789
|
-
}
|
|
1790
|
-
return true;
|
|
1791
|
-
case 'home':
|
|
1792
|
-
// Ctrl+Home or in scrollback mode: scroll to top
|
|
1793
|
-
if (key.ctrl || this.isInScrollbackMode) {
|
|
1794
|
-
this.scrollToTop();
|
|
1795
|
-
}
|
|
1796
|
-
else {
|
|
1797
|
-
this.moveCursorToLineStart();
|
|
1798
|
-
}
|
|
1799
|
-
return true;
|
|
1800
|
-
case 'end':
|
|
1801
|
-
// Ctrl+End or in scrollback mode: scroll to bottom (live mode)
|
|
1802
|
-
if (key.ctrl || this.isInScrollbackMode) {
|
|
1803
|
-
this.scrollToBottom();
|
|
1804
|
-
}
|
|
1805
|
-
else {
|
|
1806
|
-
this.moveCursorToLineEnd();
|
|
1807
|
-
}
|
|
1808
|
-
return true;
|
|
1809
|
-
case 'pageup':
|
|
1810
|
-
// Scrollback disabled in alternate screen mode
|
|
1811
|
-
// Users should use terminal's native scrollback if available
|
|
1812
|
-
return true;
|
|
1813
|
-
case 'pagedown':
|
|
1814
|
-
// Scrollback disabled in alternate screen mode
|
|
1815
|
-
return true;
|
|
1816
|
-
case 'tab':
|
|
1817
|
-
// Tab can select suggestion too without submitting
|
|
1818
|
-
if (this.showingSuggestions && !key.shift) {
|
|
1819
|
-
this.selectSuggestion();
|
|
1820
|
-
return true;
|
|
1821
|
-
}
|
|
1822
|
-
if (key.shift) {
|
|
1823
|
-
this.toggleEditMode();
|
|
1824
|
-
return true;
|
|
1825
|
-
}
|
|
1826
|
-
this.emit('toggleThinking');
|
|
1827
|
-
return true;
|
|
1828
|
-
}
|
|
1829
|
-
return false;
|
|
1830
|
-
}
|
|
1831
|
-
insertText(text) {
|
|
1832
|
-
const clean = this.sanitize(text);
|
|
1833
|
-
if (!clean)
|
|
1834
|
-
return;
|
|
1835
|
-
const available = this.config.maxLength - this.getComposedLength();
|
|
1836
|
-
if (available <= 0)
|
|
1837
|
-
return;
|
|
1838
|
-
const chunk = clean.slice(0, available);
|
|
1839
|
-
const placeholder = this.findPlaceholderAt(this.cursor);
|
|
1840
|
-
const insertPos = placeholder && this.cursor > placeholder.start ? placeholder.end : this.cursor;
|
|
1841
|
-
this.insertPlainText(chunk, insertPos);
|
|
1842
|
-
this.cursor = insertPos + chunk.length;
|
|
1843
|
-
this.emit('change', this.buffer);
|
|
1844
|
-
// Update command autocomplete visibility
|
|
1845
|
-
this.updateSuggestionVisibility();
|
|
1846
|
-
this.scheduleRender();
|
|
1847
|
-
}
|
|
1848
|
-
insertNewline() {
|
|
1849
|
-
if (this.getComposedLength() >= this.config.maxLength)
|
|
1850
|
-
return;
|
|
1851
|
-
const placeholder = this.findPlaceholderAt(this.cursor);
|
|
1852
|
-
const insertPos = placeholder && this.cursor > placeholder.start ? placeholder.end : this.cursor;
|
|
1853
|
-
this.insertPlainText('\n', insertPos);
|
|
1854
|
-
this.cursor = insertPos + 1;
|
|
1855
|
-
this.emit('change', this.buffer);
|
|
1856
|
-
this.scheduleRender();
|
|
1857
|
-
}
|
|
1858
|
-
deleteBackward() {
|
|
1859
|
-
if (this.cursor === 0)
|
|
1860
|
-
return;
|
|
1861
|
-
const placeholder = this.findPlaceholderAt(this.cursor - 1);
|
|
1862
|
-
if (placeholder) {
|
|
1863
|
-
this.deletePlaceholder(placeholder);
|
|
1864
|
-
}
|
|
1865
|
-
else {
|
|
1866
|
-
this.removeRange(this.cursor - 1, this.cursor);
|
|
1867
|
-
this.cursor = Math.max(0, this.cursor - 1);
|
|
1868
|
-
}
|
|
1869
|
-
this.emit('change', this.buffer);
|
|
1870
|
-
this.updateSuggestionVisibility();
|
|
1871
|
-
this.scheduleRender();
|
|
1872
|
-
}
|
|
1873
|
-
deleteForward() {
|
|
1874
|
-
if (this.cursor >= this.buffer.length)
|
|
1875
|
-
return;
|
|
1876
|
-
const placeholder = this.findPlaceholderAt(this.cursor);
|
|
1877
|
-
if (placeholder) {
|
|
1878
|
-
this.deletePlaceholder(placeholder);
|
|
1879
|
-
}
|
|
1880
|
-
else {
|
|
1881
|
-
this.removeRange(this.cursor, this.cursor + 1);
|
|
1882
|
-
}
|
|
1883
|
-
this.emit('change', this.buffer);
|
|
1884
|
-
this.updateSuggestionVisibility();
|
|
1885
|
-
this.scheduleRender();
|
|
1886
|
-
}
|
|
1887
|
-
deleteToStart() {
|
|
1888
|
-
if (this.cursor === 0)
|
|
1889
|
-
return;
|
|
1890
|
-
this.removeRange(0, this.cursor);
|
|
1891
|
-
this.cursor = 0;
|
|
1892
|
-
this.emit('change', this.buffer);
|
|
1893
|
-
this.updateSuggestionVisibility();
|
|
1894
|
-
this.scheduleRender();
|
|
1895
|
-
}
|
|
1896
|
-
deleteToEnd() {
|
|
1897
|
-
if (this.cursor >= this.buffer.length)
|
|
1898
|
-
return;
|
|
1899
|
-
this.removeRange(this.cursor, this.buffer.length);
|
|
1900
|
-
this.emit('change', this.buffer);
|
|
1901
|
-
this.updateSuggestionVisibility();
|
|
1902
|
-
this.scheduleRender();
|
|
1903
|
-
}
|
|
1904
|
-
deleteWord() {
|
|
1905
|
-
if (this.cursor === 0)
|
|
1906
|
-
return;
|
|
1907
|
-
const placeholder = this.findPlaceholderAt(this.cursor - 1);
|
|
1908
|
-
if (placeholder) {
|
|
1909
|
-
this.deletePlaceholder(placeholder);
|
|
1910
|
-
this.emit('change', this.buffer);
|
|
1911
|
-
this.scheduleRender();
|
|
1912
|
-
return;
|
|
1913
|
-
}
|
|
1914
|
-
let pos = this.cursor;
|
|
1915
|
-
// Skip whitespace
|
|
1916
|
-
while (pos > 0 && this.isWhitespace(this.buffer[pos - 1]))
|
|
1917
|
-
pos--;
|
|
1918
|
-
// Skip word
|
|
1919
|
-
while (pos > 0 && !this.isWhitespace(this.buffer[pos - 1]))
|
|
1920
|
-
pos--;
|
|
1921
|
-
this.buffer = this.buffer.slice(0, pos) + this.buffer.slice(this.cursor);
|
|
1922
|
-
this.cursor = pos;
|
|
1923
|
-
this.emit('change', this.buffer);
|
|
1924
|
-
this.scheduleRender();
|
|
1925
|
-
}
|
|
1926
|
-
moveCursorLeft() {
|
|
1927
|
-
if (this.cursor > 0) {
|
|
1928
|
-
this.cursor--;
|
|
1929
|
-
this.scheduleRender();
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
moveCursorRight() {
|
|
1933
|
-
if (this.cursor < this.buffer.length) {
|
|
1934
|
-
this.cursor++;
|
|
1935
|
-
this.scheduleRender();
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
moveCursorWordLeft() {
|
|
1939
|
-
let pos = this.cursor;
|
|
1940
|
-
while (pos > 0 && this.isWhitespace(this.buffer[pos - 1]))
|
|
1941
|
-
pos--;
|
|
1942
|
-
while (pos > 0 && !this.isWhitespace(this.buffer[pos - 1]))
|
|
1943
|
-
pos--;
|
|
1944
|
-
this.cursor = pos;
|
|
1945
|
-
this.scheduleRender();
|
|
1946
|
-
}
|
|
1947
|
-
moveCursorWordRight() {
|
|
1948
|
-
let pos = this.cursor;
|
|
1949
|
-
while (pos < this.buffer.length && !this.isWhitespace(this.buffer[pos]))
|
|
1950
|
-
pos++;
|
|
1951
|
-
while (pos < this.buffer.length && this.isWhitespace(this.buffer[pos]))
|
|
1952
|
-
pos++;
|
|
1953
|
-
this.cursor = pos;
|
|
1954
|
-
this.scheduleRender();
|
|
1955
|
-
}
|
|
1956
|
-
moveCursorToLineStart() {
|
|
1957
|
-
// Find start of current line
|
|
1958
|
-
let pos = this.cursor;
|
|
1959
|
-
while (pos > 0 && this.buffer[pos - 1] !== '\n')
|
|
1960
|
-
pos--;
|
|
1961
|
-
this.cursor = pos;
|
|
1962
|
-
this.scheduleRender();
|
|
1963
|
-
}
|
|
1964
|
-
moveCursorToLineEnd() {
|
|
1965
|
-
// Find end of current line
|
|
1966
|
-
let pos = this.cursor;
|
|
1967
|
-
while (pos < this.buffer.length && this.buffer[pos] !== '\n')
|
|
1968
|
-
pos++;
|
|
1969
|
-
this.cursor = pos;
|
|
1970
|
-
this.scheduleRender();
|
|
1971
|
-
}
|
|
1972
|
-
handleUp() {
|
|
1973
|
-
// Check if we can move up within buffer (multi-line)
|
|
1974
|
-
const { cursorLine } = this.getCursorPosition();
|
|
1975
|
-
if (cursorLine > 0) {
|
|
1976
|
-
this.moveCursorUp();
|
|
1977
|
-
return;
|
|
1978
|
-
}
|
|
1979
|
-
// Otherwise navigate history
|
|
1980
|
-
if (this.history.length === 0)
|
|
1981
|
-
return;
|
|
1982
|
-
if (this.historyIndex === -1) {
|
|
1983
|
-
this.tempInput = this.buffer;
|
|
1984
|
-
}
|
|
1985
|
-
if (this.historyIndex < this.history.length - 1) {
|
|
1986
|
-
this.historyIndex++;
|
|
1987
|
-
this.buffer = this.history[this.history.length - 1 - this.historyIndex] ?? '';
|
|
1988
|
-
this.cursor = this.buffer.length;
|
|
1989
|
-
this.scheduleRender();
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
handleDown() {
|
|
1993
|
-
// Check if we can move down within buffer
|
|
1994
|
-
const { cursorLine, totalLines } = this.getCursorPosition();
|
|
1995
|
-
if (cursorLine < totalLines - 1) {
|
|
1996
|
-
this.moveCursorDown();
|
|
1997
|
-
return;
|
|
1998
|
-
}
|
|
1999
|
-
// Otherwise navigate history
|
|
2000
|
-
if (this.historyIndex > 0) {
|
|
2001
|
-
this.historyIndex--;
|
|
2002
|
-
this.buffer = this.history[this.history.length - 1 - this.historyIndex] ?? '';
|
|
2003
|
-
this.cursor = this.buffer.length;
|
|
2004
|
-
this.scheduleRender();
|
|
2005
|
-
}
|
|
2006
|
-
else if (this.historyIndex === 0) {
|
|
2007
|
-
this.historyIndex = -1;
|
|
2008
|
-
this.buffer = this.tempInput;
|
|
2009
|
-
this.cursor = this.buffer.length;
|
|
2010
|
-
this.scheduleRender();
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
moveCursorUp() {
|
|
2014
|
-
const lines = this.buffer.split('\n');
|
|
2015
|
-
let lineStart = 0;
|
|
2016
|
-
let lineIdx = 0;
|
|
2017
|
-
// Find current line
|
|
2018
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2019
|
-
const lineEnd = lineStart + (lines[i]?.length ?? 0);
|
|
2020
|
-
if (this.cursor <= lineEnd) {
|
|
2021
|
-
lineIdx = i;
|
|
2022
|
-
break;
|
|
2023
|
-
}
|
|
2024
|
-
lineStart = lineEnd + 1; // +1 for newline
|
|
2025
|
-
}
|
|
2026
|
-
if (lineIdx === 0)
|
|
2027
|
-
return;
|
|
2028
|
-
// Calculate column in current line
|
|
2029
|
-
const colInLine = this.cursor - lineStart;
|
|
2030
|
-
// Move to previous line
|
|
2031
|
-
const prevLineStart = lineStart - 1 - (lines[lineIdx - 1]?.length ?? 0);
|
|
2032
|
-
const prevLineLen = lines[lineIdx - 1]?.length ?? 0;
|
|
2033
|
-
this.cursor = prevLineStart + Math.min(colInLine, prevLineLen);
|
|
2034
|
-
this.scheduleRender();
|
|
2035
|
-
}
|
|
2036
|
-
moveCursorDown() {
|
|
2037
|
-
const lines = this.buffer.split('\n');
|
|
2038
|
-
let lineStart = 0;
|
|
2039
|
-
let lineIdx = 0;
|
|
2040
|
-
// Find current line
|
|
2041
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2042
|
-
const lineEnd = lineStart + (lines[i]?.length ?? 0);
|
|
2043
|
-
if (this.cursor <= lineEnd) {
|
|
2044
|
-
lineIdx = i;
|
|
2045
|
-
break;
|
|
2046
|
-
}
|
|
2047
|
-
lineStart = lineEnd + 1;
|
|
2048
|
-
}
|
|
2049
|
-
if (lineIdx >= lines.length - 1)
|
|
2050
|
-
return;
|
|
2051
|
-
const colInLine = this.cursor - lineStart;
|
|
2052
|
-
const nextLineStart = lineStart + (lines[lineIdx]?.length ?? 0) + 1;
|
|
2053
|
-
const nextLineLen = lines[lineIdx + 1]?.length ?? 0;
|
|
2054
|
-
this.cursor = nextLineStart + Math.min(colInLine, nextLineLen);
|
|
2055
|
-
this.scheduleRender();
|
|
2056
|
-
}
|
|
2057
|
-
getCursorPosition() {
|
|
2058
|
-
const lines = this.buffer.split('\n');
|
|
2059
|
-
let pos = 0;
|
|
2060
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2061
|
-
const lineLen = lines[i]?.length ?? 0;
|
|
2062
|
-
if (this.cursor <= pos + lineLen) {
|
|
2063
|
-
return {
|
|
2064
|
-
cursorLine: i,
|
|
2065
|
-
cursorCol: this.cursor - pos,
|
|
2066
|
-
totalLines: lines.length,
|
|
2067
|
-
};
|
|
2068
|
-
}
|
|
2069
|
-
pos += lineLen + 1;
|
|
2070
|
-
}
|
|
2071
|
-
return {
|
|
2072
|
-
cursorLine: lines.length - 1,
|
|
2073
|
-
cursorCol: lines[lines.length - 1]?.length ?? 0,
|
|
2074
|
-
totalLines: lines.length,
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
submit() {
|
|
2078
|
-
const text = this.assembleText();
|
|
2079
|
-
if (!text.trim())
|
|
2080
|
-
return;
|
|
2081
|
-
const submission = text;
|
|
2082
|
-
// Add to history
|
|
2083
|
-
if (this.history[this.history.length - 1] !== submission) {
|
|
2084
|
-
this.history.push(submission);
|
|
2085
|
-
if (this.history.length > this.maxHistory) {
|
|
2086
|
-
this.history.shift();
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2089
|
-
this.historyIndex = -1;
|
|
2090
|
-
this.tempInput = '';
|
|
2091
|
-
// Queue or submit based on mode
|
|
2092
|
-
if (this.mode === 'streaming') {
|
|
2093
|
-
if (this.queue.length >= this.config.maxQueueSize) {
|
|
2094
|
-
return; // Queue full
|
|
2095
|
-
}
|
|
2096
|
-
this.queue.push({
|
|
2097
|
-
id: ++this.queueIdCounter,
|
|
2098
|
-
text: submission,
|
|
2099
|
-
timestamp: Date.now(),
|
|
2100
|
-
});
|
|
2101
|
-
this.emit('queue', submission);
|
|
2102
|
-
this.clear(); // Clear immediately for queued input
|
|
2103
|
-
}
|
|
2104
|
-
else {
|
|
2105
|
-
// In idle mode, clear the input first, then emit submit.
|
|
2106
|
-
// The prompt will be logged as a visible message by the caller.
|
|
2107
|
-
this.clear();
|
|
2108
|
-
this.emit('submit', submission);
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
finishPaste() {
|
|
2112
|
-
const content = this.pasteBuffer;
|
|
2113
|
-
this.pasteBuffer = '';
|
|
2114
|
-
this.isPasting = false;
|
|
2115
|
-
if (!content)
|
|
2116
|
-
return;
|
|
2117
|
-
const clean = this.sanitize(content);
|
|
2118
|
-
if (!clean)
|
|
2119
|
-
return;
|
|
2120
|
-
const available = this.config.maxLength - this.getComposedLength();
|
|
2121
|
-
if (available <= 0)
|
|
2122
|
-
return;
|
|
2123
|
-
const chunk = clean.slice(0, available);
|
|
2124
|
-
const isMultiline = isMultilinePaste(chunk);
|
|
2125
|
-
const isShortMultiline = isMultiline && this.shouldInlineMultiline(chunk);
|
|
2126
|
-
if (isMultiline && !isShortMultiline) {
|
|
2127
|
-
this.insertPastePlaceholder(chunk);
|
|
2128
|
-
}
|
|
2129
|
-
else {
|
|
2130
|
-
const placeholder = this.findPlaceholderAt(this.cursor);
|
|
2131
|
-
const insertPos = placeholder && this.cursor > placeholder.start ? placeholder.end : this.cursor;
|
|
2132
|
-
this.insertPlainText(chunk, insertPos);
|
|
2133
|
-
this.cursor = insertPos + chunk.length;
|
|
2134
|
-
}
|
|
2135
|
-
this.emit('change', this.buffer);
|
|
2136
|
-
this.scheduleRender();
|
|
2137
|
-
}
|
|
2138
|
-
// ===========================================================================
|
|
2139
|
-
// BUFFER WRAPPING
|
|
2140
|
-
// ===========================================================================
|
|
2141
|
-
wrapBuffer(maxWidth) {
|
|
2142
|
-
const width = Math.max(1, maxWidth);
|
|
2143
|
-
const lines = [];
|
|
2144
|
-
let cursorLine = 0;
|
|
2145
|
-
let cursorCol = 0;
|
|
2146
|
-
let charIndex = 0;
|
|
2147
|
-
if (this.buffer.length === 0) {
|
|
2148
|
-
return { lines: [''], cursorLine: 0, cursorCol: 0 };
|
|
2149
|
-
}
|
|
2150
|
-
const rawLines = this.buffer.split('\n');
|
|
2151
|
-
for (let i = 0; i < rawLines.length; i++) {
|
|
2152
|
-
const raw = rawLines[i] ?? '';
|
|
2153
|
-
if (raw.length === 0) {
|
|
2154
|
-
// Empty line from newline
|
|
2155
|
-
if (this.cursor === charIndex) {
|
|
2156
|
-
cursorLine = lines.length;
|
|
2157
|
-
cursorCol = 0;
|
|
2158
|
-
}
|
|
2159
|
-
lines.push('');
|
|
2160
|
-
}
|
|
2161
|
-
else {
|
|
2162
|
-
// Wrap long lines
|
|
2163
|
-
for (let start = 0; start < raw.length; start += width) {
|
|
2164
|
-
const segment = raw.slice(start, start + width);
|
|
2165
|
-
const segmentStart = charIndex + start;
|
|
2166
|
-
const segmentEnd = segmentStart + segment.length;
|
|
2167
|
-
if (this.cursor >= segmentStart && this.cursor <= segmentEnd) {
|
|
2168
|
-
cursorLine = lines.length;
|
|
2169
|
-
cursorCol = this.cursor - segmentStart;
|
|
2170
|
-
}
|
|
2171
|
-
lines.push(segment);
|
|
2172
|
-
}
|
|
2173
|
-
}
|
|
2174
|
-
charIndex += raw.length;
|
|
2175
|
-
// Account for newline between raw lines
|
|
2176
|
-
if (i < rawLines.length - 1) {
|
|
2177
|
-
if (this.cursor === charIndex) {
|
|
2178
|
-
cursorLine = lines.length;
|
|
2179
|
-
cursorCol = 0;
|
|
2180
|
-
}
|
|
2181
|
-
charIndex++;
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
// Safety: clamp values
|
|
2185
|
-
cursorLine = Math.max(0, Math.min(cursorLine, lines.length - 1));
|
|
2186
|
-
cursorCol = Math.max(0, Math.min(cursorCol, lines[cursorLine]?.length ?? 0));
|
|
2187
|
-
return { lines, cursorLine, cursorCol };
|
|
2188
|
-
}
|
|
2189
|
-
// ===========================================================================
|
|
2190
|
-
// SCROLLBACK BUFFER
|
|
2191
|
-
// ===========================================================================
|
|
2192
|
-
/**
|
|
2193
|
-
* Add content to the scrollback buffer for history retention
|
|
2194
|
-
*/
|
|
2195
|
-
addToScrollback(content) {
|
|
2196
|
-
if (!content)
|
|
2197
|
-
return;
|
|
2198
|
-
// Split content into lines and add to buffer
|
|
2199
|
-
const lines = content.split('\n');
|
|
2200
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2201
|
-
const line = lines[i];
|
|
2202
|
-
if (line !== undefined) {
|
|
2203
|
-
// Only add non-empty lines or preserve newlines between content
|
|
2204
|
-
if (i < lines.length - 1 || line.length > 0) {
|
|
2205
|
-
this.scrollbackBuffer.push(line);
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
// Trim buffer if it exceeds max size
|
|
2210
|
-
while (this.scrollbackBuffer.length > this.maxScrollbackLines) {
|
|
2211
|
-
this.scrollbackBuffer.shift();
|
|
2212
|
-
}
|
|
2213
|
-
// If we're in live mode (not scrolled up), keep offset at 0
|
|
2214
|
-
if (this.scrollbackOffset === 0) {
|
|
2215
|
-
this.isInScrollbackMode = false;
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
/**
|
|
2219
|
-
* Scroll up by a number of lines (PageUp)
|
|
2220
|
-
* Note: Scrollback is disabled in alternate screen mode to avoid display corruption.
|
|
2221
|
-
* Users should use their terminal's native scrollback or copy/paste features.
|
|
2222
|
-
*/
|
|
2223
|
-
scrollUp(_lines = 10) {
|
|
2224
|
-
// Scrollback disabled - alternate screen buffer doesn't support it well
|
|
2225
|
-
// The scrollback buffer is still maintained for potential future use
|
|
2226
|
-
// Users can select and copy text normally since mouse tracking is off
|
|
2227
|
-
}
|
|
2228
|
-
/**
|
|
2229
|
-
* Scroll down by a number of lines (PageDown)
|
|
2230
|
-
* Note: Scrollback disabled - see scrollUp comment
|
|
2231
|
-
*/
|
|
2232
|
-
scrollDown(_lines = 10) {
|
|
2233
|
-
// Scrollback disabled
|
|
2234
|
-
}
|
|
2235
|
-
/**
|
|
2236
|
-
* Jump to the top of scrollback buffer
|
|
2237
|
-
* DISABLED: Scrollback navigation causes display corruption in alternate screen mode.
|
|
2238
|
-
* The scrollback buffer is maintained but cannot be rendered properly.
|
|
2239
|
-
*/
|
|
2240
|
-
scrollToTop() {
|
|
2241
|
-
// Disabled - causes display corruption in alternate screen buffer
|
|
2242
|
-
}
|
|
2243
|
-
/**
|
|
2244
|
-
* Jump to the bottom (live mode)
|
|
2245
|
-
* DISABLED: Scrollback navigation causes display corruption.
|
|
2246
|
-
*/
|
|
2247
|
-
scrollToBottom() {
|
|
2248
|
-
// Reset scrollback state in case it was somehow enabled
|
|
2249
|
-
this.scrollbackOffset = 0;
|
|
2250
|
-
this.isInScrollbackMode = false;
|
|
2251
|
-
}
|
|
2252
|
-
/**
|
|
2253
|
-
* Toggle scrollback mode on/off (Ctrl+Shift+S hotkey; Alt+S legacy)
|
|
2254
|
-
* DISABLED: Scrollback navigation causes display corruption in alternate screen mode.
|
|
2255
|
-
*/
|
|
2256
|
-
toggleScrollbackMode() {
|
|
2257
|
-
// Disabled - alternate screen buffer doesn't support manual scrollback rendering
|
|
2258
|
-
}
|
|
2259
|
-
/**
|
|
2260
|
-
* Render the scrollback buffer view.
|
|
2261
|
-
* DISABLED: This causes display corruption in alternate screen mode.
|
|
2262
|
-
* The alternate screen buffer has its own rendering model that conflicts with
|
|
2263
|
-
* manual scroll region manipulation.
|
|
2264
|
-
*/
|
|
2265
|
-
renderScrollbackView() {
|
|
2266
|
-
// Disabled - causes display corruption
|
|
2267
|
-
}
|
|
2268
|
-
/**
|
|
2269
|
-
* Build scrollback header with navigation hints
|
|
2270
|
-
*/
|
|
2271
|
-
buildScrollbackHeader(cols, totalLines, startIdx, endIdx) {
|
|
2272
|
-
const percentage = Math.round((endIdx / totalLines) * 100);
|
|
2273
|
-
// Animated scroll indicator
|
|
2274
|
-
const scrollFrames = ['◆', '◇', '◆', '◈'];
|
|
2275
|
-
this.scrollIndicatorFrame = (this.scrollIndicatorFrame + 1) % scrollFrames.length;
|
|
2276
|
-
const indicator = scrollFrames[this.scrollIndicatorFrame];
|
|
2277
|
-
// Build header parts
|
|
2278
|
-
const leftPart = theme.info(`${indicator} SCROLLBACK`) +
|
|
2279
|
-
theme.ui.muted(` [${startIdx + 1}-${endIdx} of ${totalLines}]`);
|
|
2280
|
-
const progressBar = this.buildProgressBar(percentage, 15);
|
|
2281
|
-
const rightPart = progressBar +
|
|
2282
|
-
theme.ui.muted(` ${percentage}%`) +
|
|
2283
|
-
theme.ui.muted(' │ ') +
|
|
2284
|
-
theme.primary('PgUp') + theme.ui.muted('/') + theme.primary('PgDn') +
|
|
2285
|
-
theme.ui.muted(' scroll · ') +
|
|
2286
|
-
theme.primary('End') + theme.ui.muted(' exit');
|
|
2287
|
-
const leftLen = this.visibleLength(leftPart);
|
|
2288
|
-
const rightLen = this.visibleLength(rightPart);
|
|
2289
|
-
const padding = Math.max(1, cols - leftLen - rightLen - 2);
|
|
2290
|
-
return `${leftPart}${' '.repeat(padding)}${rightPart}`;
|
|
2291
|
-
}
|
|
2292
|
-
/**
|
|
2293
|
-
* Render visual scroll track on the right side
|
|
2294
|
-
*/
|
|
2295
|
-
renderScrollTrack(cols, contentHeight, totalLines, startIdx, endIdx) {
|
|
2296
|
-
if (totalLines <= contentHeight || cols < 40)
|
|
2297
|
-
return;
|
|
2298
|
-
const trackHeight = contentHeight - 1; // Exclude header
|
|
2299
|
-
const viewportRatio = (endIdx - startIdx) / totalLines;
|
|
2300
|
-
const positionRatio = startIdx / Math.max(1, totalLines - (endIdx - startIdx));
|
|
2301
|
-
// Calculate thumb size and position
|
|
2302
|
-
const thumbSize = Math.max(1, Math.round(viewportRatio * trackHeight));
|
|
2303
|
-
const thumbStart = Math.round(positionRatio * (trackHeight - thumbSize));
|
|
2304
|
-
// Render track on right edge
|
|
2305
|
-
for (let i = 0; i < trackHeight; i++) {
|
|
2306
|
-
const row = 2 + i; // Start after header
|
|
2307
|
-
this.write(ESC.TO(row, cols));
|
|
2308
|
-
if (i >= thumbStart && i < thumbStart + thumbSize) {
|
|
2309
|
-
// Thumb (viewport indicator)
|
|
2310
|
-
this.write(theme.accent('█'));
|
|
2311
|
-
}
|
|
2312
|
-
else {
|
|
2313
|
-
// Track background
|
|
2314
|
-
this.write(theme.ui.muted('░'));
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
/**
|
|
2319
|
-
* Build a visual progress bar
|
|
2320
|
-
*/
|
|
2321
|
-
buildProgressBar(percentage, width = 10) {
|
|
2322
|
-
const filled = Math.round((percentage / 100) * width);
|
|
2323
|
-
const empty = width - filled;
|
|
2324
|
-
const bar = theme.accent('█'.repeat(filled)) +
|
|
2325
|
-
theme.ui.muted('░'.repeat(empty));
|
|
2326
|
-
return `${theme.ui.muted('[')}${bar}${theme.ui.muted(']')}`;
|
|
2327
|
-
}
|
|
2328
|
-
/**
|
|
2329
|
-
* Get scrollback buffer content (for persistence)
|
|
2330
|
-
*/
|
|
2331
|
-
getScrollbackBuffer() {
|
|
2332
|
-
return [...this.scrollbackBuffer];
|
|
2333
|
-
}
|
|
2334
|
-
/**
|
|
2335
|
-
* Load scrollback buffer (for restoration)
|
|
2336
|
-
*/
|
|
2337
|
-
loadScrollbackBuffer(lines) {
|
|
2338
|
-
this.scrollbackBuffer = [...lines];
|
|
2339
|
-
// Trim if necessary
|
|
2340
|
-
while (this.scrollbackBuffer.length > this.maxScrollbackLines) {
|
|
2341
|
-
this.scrollbackBuffer.shift();
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
/**
|
|
2345
|
-
* Clear scrollback buffer
|
|
2346
|
-
*/
|
|
2347
|
-
clearScrollbackBuffer() {
|
|
2348
|
-
this.scrollbackBuffer = [];
|
|
2349
|
-
this.scrollbackOffset = 0;
|
|
2350
|
-
this.isInScrollbackMode = false;
|
|
2351
|
-
}
|
|
2352
|
-
// ===========================================================================
|
|
2353
|
-
// UTILITIES
|
|
2354
|
-
// ===========================================================================
|
|
2355
|
-
getComposedLength() {
|
|
2356
|
-
if (this.pastePlaceholders.length === 0) {
|
|
2357
|
-
return this.buffer.length;
|
|
2358
|
-
}
|
|
2359
|
-
const sorted = [...this.pastePlaceholders].sort((a, b) => a.start - b.start);
|
|
2360
|
-
let composed = 0;
|
|
2361
|
-
let cursor = 0;
|
|
2362
|
-
for (const placeholder of sorted) {
|
|
2363
|
-
composed += Math.max(0, placeholder.start - cursor);
|
|
2364
|
-
composed += placeholder.content.length;
|
|
2365
|
-
cursor = placeholder.end;
|
|
2366
|
-
}
|
|
2367
|
-
composed += Math.max(0, this.buffer.length - cursor);
|
|
2368
|
-
return composed;
|
|
2369
|
-
}
|
|
2370
|
-
assembleText() {
|
|
2371
|
-
if (this.pastePlaceholders.length === 0) {
|
|
2372
|
-
return this.buffer;
|
|
2373
|
-
}
|
|
2374
|
-
const sorted = [...this.pastePlaceholders].sort((a, b) => a.start - b.start);
|
|
2375
|
-
let result = '';
|
|
2376
|
-
let cursor = 0;
|
|
2377
|
-
for (const placeholder of sorted) {
|
|
2378
|
-
result += this.buffer.slice(cursor, placeholder.start);
|
|
2379
|
-
result += placeholder.content;
|
|
2380
|
-
cursor = placeholder.end;
|
|
2381
|
-
}
|
|
2382
|
-
result += this.buffer.slice(cursor);
|
|
2383
|
-
return result;
|
|
2384
|
-
}
|
|
2385
|
-
shiftPlaceholders(start, delta, excludeId) {
|
|
2386
|
-
if (delta === 0)
|
|
2387
|
-
return;
|
|
2388
|
-
for (const placeholder of this.pastePlaceholders) {
|
|
2389
|
-
if (excludeId && placeholder.id === excludeId)
|
|
2390
|
-
continue;
|
|
2391
|
-
if (placeholder.start >= start) {
|
|
2392
|
-
placeholder.start += delta;
|
|
2393
|
-
placeholder.end += delta;
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
2397
|
-
removeRange(start, end) {
|
|
2398
|
-
// Expand deletion to cover any placeholder that overlaps the range
|
|
2399
|
-
let adjustedStart = start;
|
|
2400
|
-
let adjustedEnd = end;
|
|
2401
|
-
for (const ph of this.pastePlaceholders) {
|
|
2402
|
-
if (ph.start < adjustedEnd && ph.end > adjustedStart) {
|
|
2403
|
-
adjustedStart = Math.min(adjustedStart, ph.start);
|
|
2404
|
-
adjustedEnd = Math.max(adjustedEnd, ph.end);
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
const length = Math.max(0, adjustedEnd - adjustedStart);
|
|
2408
|
-
if (length === 0)
|
|
2409
|
-
return;
|
|
2410
|
-
this.buffer = this.buffer.slice(0, adjustedStart) + this.buffer.slice(adjustedEnd);
|
|
2411
|
-
// Remove any placeholders that were within the deleted range
|
|
2412
|
-
this.pastePlaceholders = this.pastePlaceholders.filter((ph) => {
|
|
2413
|
-
return ph.end <= adjustedStart || ph.start >= adjustedEnd;
|
|
2414
|
-
});
|
|
2415
|
-
// Shift remaining placeholders that were after the deleted range
|
|
2416
|
-
this.shiftPlaceholders(adjustedEnd, -length);
|
|
2417
|
-
this.clampCursor();
|
|
2418
|
-
}
|
|
2419
|
-
insertPlainText(text, position) {
|
|
2420
|
-
if (!text)
|
|
2421
|
-
return;
|
|
2422
|
-
this.shiftPlaceholders(position, text.length);
|
|
2423
|
-
this.buffer = this.buffer.slice(0, position) + text + this.buffer.slice(position);
|
|
2424
|
-
}
|
|
2425
|
-
shouldInlineMultiline(content) {
|
|
2426
|
-
const lines = content.split('\n').length;
|
|
2427
|
-
const maxInlineLines = 4;
|
|
2428
|
-
const maxInlineChars = 240;
|
|
2429
|
-
return lines <= maxInlineLines && content.length <= maxInlineChars;
|
|
2430
|
-
}
|
|
2431
|
-
findPlaceholderAt(position) {
|
|
2432
|
-
return this.pastePlaceholders.find((ph) => position >= ph.start && position < ph.end) ?? null;
|
|
2433
|
-
}
|
|
2434
|
-
buildPlaceholder(lineCount) {
|
|
2435
|
-
const id = ++this.pasteCounter;
|
|
2436
|
-
const plural = lineCount === 1 ? '' : 's';
|
|
2437
|
-
const placeholder = `[Pasted text #${id} +${lineCount} line${plural}]`;
|
|
2438
|
-
return { id, placeholder };
|
|
2439
|
-
}
|
|
2440
|
-
insertPastePlaceholder(content) {
|
|
2441
|
-
const available = this.config.maxLength - this.getComposedLength();
|
|
2442
|
-
if (available <= 0)
|
|
2443
|
-
return;
|
|
2444
|
-
const cleanContent = content.slice(0, available);
|
|
2445
|
-
const lineCount = cleanContent.split('\n').length;
|
|
2446
|
-
const { id, placeholder } = this.buildPlaceholder(lineCount);
|
|
2447
|
-
const insertPos = this.cursor;
|
|
2448
|
-
this.shiftPlaceholders(insertPos, placeholder.length);
|
|
2449
|
-
this.pastePlaceholders.push({
|
|
2450
|
-
id,
|
|
2451
|
-
content: cleanContent,
|
|
2452
|
-
lineCount,
|
|
2453
|
-
placeholder,
|
|
2454
|
-
start: insertPos,
|
|
2455
|
-
end: insertPos + placeholder.length,
|
|
2456
|
-
});
|
|
2457
|
-
this.buffer = this.buffer.slice(0, insertPos) + placeholder + this.buffer.slice(insertPos);
|
|
2458
|
-
this.cursor = insertPos + placeholder.length;
|
|
2459
|
-
}
|
|
2460
|
-
deletePlaceholder(placeholder) {
|
|
2461
|
-
const length = placeholder.end - placeholder.start;
|
|
2462
|
-
this.buffer = this.buffer.slice(0, placeholder.start) + this.buffer.slice(placeholder.end);
|
|
2463
|
-
this.pastePlaceholders = this.pastePlaceholders.filter((ph) => ph.id !== placeholder.id);
|
|
2464
|
-
this.shiftPlaceholders(placeholder.end, -length, placeholder.id);
|
|
2465
|
-
this.cursor = placeholder.start;
|
|
2466
|
-
}
|
|
2467
|
-
updateContextUsage(value, autoCompactThreshold) {
|
|
2468
|
-
if (typeof autoCompactThreshold === 'number' && Number.isFinite(autoCompactThreshold)) {
|
|
2469
|
-
const boundedThreshold = Math.max(1, Math.min(100, Math.round(autoCompactThreshold)));
|
|
2470
|
-
this.contextAutoCompactThreshold = boundedThreshold;
|
|
2471
|
-
}
|
|
2472
|
-
if (value === null || !Number.isFinite(value)) {
|
|
2473
|
-
this.contextUsage = null;
|
|
2474
|
-
}
|
|
2475
|
-
else {
|
|
2476
|
-
const bounded = Math.max(0, Math.min(100, Math.round(value)));
|
|
2477
|
-
this.contextUsage = bounded;
|
|
2478
|
-
}
|
|
2479
|
-
this.scheduleRender();
|
|
2480
|
-
}
|
|
2481
|
-
getEditMode() {
|
|
2482
|
-
return this.editMode;
|
|
2483
|
-
}
|
|
2484
|
-
applyEditMode(mode) {
|
|
2485
|
-
this.setEditMode(mode);
|
|
2486
|
-
}
|
|
2487
|
-
setEditMode(mode) {
|
|
2488
|
-
if (this.editMode === mode)
|
|
2489
|
-
return;
|
|
2490
|
-
this.editMode = mode;
|
|
2491
|
-
this.emit('mode-change', this.editMode);
|
|
2492
|
-
this.scheduleRender();
|
|
2493
|
-
}
|
|
2494
|
-
toggleEditMode() {
|
|
2495
|
-
// Cycle through: display-edits → ask-permission → plan → display-edits
|
|
2496
|
-
const cycle = ['display-edits', 'ask-permission', 'plan'];
|
|
2497
|
-
const currentIndex = cycle.indexOf(this.editMode);
|
|
2498
|
-
const nextIndex = (currentIndex + 1) % cycle.length;
|
|
2499
|
-
this.setEditMode(cycle[nextIndex]);
|
|
2500
|
-
}
|
|
2501
|
-
scheduleStreamingRender(delayMs) {
|
|
2502
|
-
if (this.streamingRenderTimer)
|
|
2503
|
-
return;
|
|
2504
|
-
const wait = Math.max(16, delayMs);
|
|
2505
|
-
this.streamingRenderTimer = setTimeout(() => {
|
|
2506
|
-
this.streamingRenderTimer = null;
|
|
2507
|
-
// During streaming, only update chat box (not full render)
|
|
2508
|
-
if (this.scrollRegionActive) {
|
|
2509
|
-
this.renderStreamingFrame();
|
|
2510
|
-
}
|
|
2511
|
-
else {
|
|
2512
|
-
this.render();
|
|
2513
|
-
}
|
|
2514
|
-
}, wait);
|
|
2515
|
-
}
|
|
2516
|
-
/**
|
|
2517
|
-
* Render the pinned chat box during streaming only when we actually have
|
|
2518
|
-
* pending UI changes. Prevents meta/header lines from being echoed into the
|
|
2519
|
-
* streamed log when nothing changed.
|
|
2520
|
-
*/
|
|
2521
|
-
renderStreamingFrame() {
|
|
2522
|
-
if (!this.canRender())
|
|
2523
|
-
return;
|
|
2524
|
-
if (this.isRendering)
|
|
2525
|
-
return;
|
|
2526
|
-
const shouldSkip = !this.renderDirty &&
|
|
2527
|
-
this.buffer === this.lastRenderContent &&
|
|
2528
|
-
this.cursor === this.lastRenderCursor;
|
|
2529
|
-
// Clear the dirty flag even when skipping to avoid runaway retries.
|
|
2530
|
-
this.renderDirty = false;
|
|
2531
|
-
if (shouldSkip) {
|
|
2532
|
-
return;
|
|
2533
|
-
}
|
|
2534
|
-
if (writeLock.isLocked()) {
|
|
2535
|
-
writeLock.safeWrite(() => this.renderStreamingFrame());
|
|
2536
|
-
return;
|
|
2537
|
-
}
|
|
2538
|
-
this.renderPinnedChatBox();
|
|
2539
|
-
}
|
|
2540
|
-
resetStreamingRenderThrottle() {
|
|
2541
|
-
if (this.streamingRenderTimer) {
|
|
2542
|
-
clearTimeout(this.streamingRenderTimer);
|
|
2543
|
-
this.streamingRenderTimer = null;
|
|
2544
|
-
}
|
|
2545
|
-
this.lastStreamingRender = 0;
|
|
2546
|
-
}
|
|
2547
|
-
scheduleRender() {
|
|
2548
|
-
if (!this.canRender())
|
|
2549
|
-
return;
|
|
2550
|
-
this.renderDirty = true;
|
|
2551
|
-
queueMicrotask(() => this.render());
|
|
2552
|
-
}
|
|
2553
|
-
canRender() {
|
|
2554
|
-
return !this.disposed && this.enabled && this.isTTY();
|
|
2555
|
-
}
|
|
2556
|
-
isTTY() {
|
|
2557
|
-
return !!this.out.isTTY && this.out.writable !== false;
|
|
2558
|
-
}
|
|
2559
|
-
getSize() {
|
|
2560
|
-
return {
|
|
2561
|
-
rows: this.out.rows ?? 24,
|
|
2562
|
-
cols: this.out.columns ?? 80,
|
|
2563
|
-
};
|
|
2564
|
-
}
|
|
2565
|
-
write(data) {
|
|
2566
|
-
try {
|
|
2567
|
-
if (this.out.writable) {
|
|
2568
|
-
this.out.write(data);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
catch {
|
|
2572
|
-
// Ignore write errors
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
sanitize(text) {
|
|
2576
|
-
if (!text)
|
|
2577
|
-
return '';
|
|
2578
|
-
// Remove ANSI codes and control chars (except newlines)
|
|
2579
|
-
return text
|
|
2580
|
-
.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, '') // OSC sequences
|
|
2581
|
-
.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '') // CSI sequences
|
|
2582
|
-
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '') // Control chars except \n and \r
|
|
2583
|
-
.replace(/\r\n?/g, '\n'); // Normalize line endings
|
|
2584
|
-
}
|
|
2585
|
-
getArrowKeyName(sequence) {
|
|
2586
|
-
if (!sequence)
|
|
2587
|
-
return null;
|
|
2588
|
-
const match = sequence.match(/\x1b(?:\[[0-9;]*|O)([ABCD])$/) ||
|
|
2589
|
-
sequence.match(/^\[?[0-9;]*([ABCD])$/);
|
|
2590
|
-
if (!match)
|
|
2591
|
-
return null;
|
|
2592
|
-
switch (match[1]) {
|
|
2593
|
-
case 'A':
|
|
2594
|
-
return 'up';
|
|
2595
|
-
case 'B':
|
|
2596
|
-
return 'down';
|
|
2597
|
-
case 'C':
|
|
2598
|
-
return 'right';
|
|
2599
|
-
case 'D':
|
|
2600
|
-
return 'left';
|
|
2601
|
-
default:
|
|
2602
|
-
return null;
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
isArrowEscapeFragment(text) {
|
|
2606
|
-
if (!text)
|
|
2607
|
-
return false;
|
|
2608
|
-
if (text.length > 8)
|
|
2609
|
-
return false;
|
|
2610
|
-
return (/^\x1b?(?:\[[0-9;]*|O)[ABCD]$/.test(text) ||
|
|
2611
|
-
(/^\[?[0-9;]*[ABCD]$/.test(text) && text.length <= 6));
|
|
2612
|
-
}
|
|
2613
|
-
isOrphanedEscapeSequence(text, key) {
|
|
2614
|
-
if (!text || key?.name)
|
|
2615
|
-
return false;
|
|
2616
|
-
// If sanitizing leaves printable content, treat it as user input.
|
|
2617
|
-
const sanitized = this.sanitize(text);
|
|
2618
|
-
if (sanitized.length > 0) {
|
|
2619
|
-
return false;
|
|
2620
|
-
}
|
|
2621
|
-
if (text.includes('\x1b'))
|
|
2622
|
-
return true;
|
|
2623
|
-
// Common stray fragments when terminals partially echo arrow sequences (e.g., "[D")
|
|
2624
|
-
return text.length <= 5 && (/^[\[O][0-9;]*[A-Za-z]$/.test(text));
|
|
2625
|
-
}
|
|
2626
|
-
isWhitespace(char) {
|
|
2627
|
-
return char === ' ' || char === '\t' || char === '\n';
|
|
2628
|
-
}
|
|
2629
|
-
clampCursor() {
|
|
2630
|
-
this.cursor = Math.max(0, Math.min(this.cursor, this.buffer.length));
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
//# sourceMappingURL=terminalInput.js.map
|