erosolar-cli 1.7.355 → 1.7.356
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -24
- package/dist/alpha-zero/agentWrapper.d.ts +84 -0
- package/dist/alpha-zero/agentWrapper.d.ts.map +1 -0
- package/dist/alpha-zero/agentWrapper.js +171 -0
- package/dist/alpha-zero/agentWrapper.js.map +1 -0
- package/dist/alpha-zero/codeEvaluator.d.ts +25 -0
- package/dist/alpha-zero/codeEvaluator.d.ts.map +1 -0
- package/dist/alpha-zero/codeEvaluator.js +273 -0
- package/dist/alpha-zero/codeEvaluator.js.map +1 -0
- package/dist/alpha-zero/competitiveRunner.d.ts +66 -0
- package/dist/alpha-zero/competitiveRunner.d.ts.map +1 -0
- package/dist/alpha-zero/competitiveRunner.js +224 -0
- package/dist/alpha-zero/competitiveRunner.js.map +1 -0
- package/dist/alpha-zero/index.d.ts +67 -0
- package/dist/alpha-zero/index.d.ts.map +1 -0
- package/dist/alpha-zero/index.js +99 -0
- package/dist/alpha-zero/index.js.map +1 -0
- package/dist/alpha-zero/introspection.d.ts +128 -0
- package/dist/alpha-zero/introspection.d.ts.map +1 -0
- package/dist/alpha-zero/introspection.js +300 -0
- package/dist/alpha-zero/introspection.js.map +1 -0
- package/dist/alpha-zero/metricsTracker.d.ts +71 -0
- package/dist/alpha-zero/metricsTracker.d.ts.map +1 -0
- package/dist/{core → alpha-zero}/metricsTracker.js +5 -2
- package/dist/alpha-zero/metricsTracker.js.map +1 -0
- package/dist/alpha-zero/security/core.d.ts +125 -0
- package/dist/alpha-zero/security/core.d.ts.map +1 -0
- package/dist/alpha-zero/security/core.js +271 -0
- package/dist/alpha-zero/security/core.js.map +1 -0
- package/dist/alpha-zero/security/google.d.ts +125 -0
- package/dist/alpha-zero/security/google.d.ts.map +1 -0
- package/dist/alpha-zero/security/google.js +311 -0
- package/dist/alpha-zero/security/google.js.map +1 -0
- package/dist/alpha-zero/security/googleLoader.d.ts +17 -0
- package/dist/alpha-zero/security/googleLoader.d.ts.map +1 -0
- package/dist/alpha-zero/security/googleLoader.js +41 -0
- package/dist/alpha-zero/security/googleLoader.js.map +1 -0
- package/dist/alpha-zero/security/index.d.ts +29 -0
- package/dist/alpha-zero/security/index.d.ts.map +1 -0
- package/dist/alpha-zero/security/index.js +32 -0
- package/dist/alpha-zero/security/index.js.map +1 -0
- package/dist/alpha-zero/security/simulation.d.ts +124 -0
- package/dist/alpha-zero/security/simulation.d.ts.map +1 -0
- package/dist/alpha-zero/security/simulation.js +277 -0
- package/dist/alpha-zero/security/simulation.js.map +1 -0
- package/dist/alpha-zero/selfModification.d.ts +109 -0
- package/dist/alpha-zero/selfModification.d.ts.map +1 -0
- package/dist/alpha-zero/selfModification.js +233 -0
- package/dist/alpha-zero/selfModification.js.map +1 -0
- package/dist/alpha-zero/types.d.ts +170 -0
- package/dist/alpha-zero/types.d.ts.map +1 -0
- package/dist/alpha-zero/types.js +31 -0
- package/dist/alpha-zero/types.js.map +1 -0
- package/dist/bin/erosolar.js +21 -5
- package/dist/bin/erosolar.js.map +1 -1
- package/dist/capabilities/agentSpawningCapability.d.ts.map +1 -1
- package/dist/capabilities/agentSpawningCapability.js +31 -56
- package/dist/capabilities/agentSpawningCapability.js.map +1 -1
- package/dist/capabilities/securityTestingCapability.d.ts +13 -0
- package/dist/capabilities/securityTestingCapability.d.ts.map +1 -0
- package/dist/capabilities/securityTestingCapability.js +25 -0
- package/dist/capabilities/securityTestingCapability.js.map +1 -0
- package/dist/contracts/agent-schemas.json +15 -0
- package/dist/contracts/tools.schema.json +9 -0
- package/dist/core/agent.d.ts +2 -2
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js.map +1 -1
- package/dist/core/aiFlowOptimizer.d.ts +26 -0
- package/dist/core/aiFlowOptimizer.d.ts.map +1 -0
- package/dist/core/aiFlowOptimizer.js +31 -0
- package/dist/core/aiFlowOptimizer.js.map +1 -0
- package/dist/core/aiOptimizationEngine.d.ts +158 -0
- package/dist/core/aiOptimizationEngine.d.ts.map +1 -0
- package/dist/core/aiOptimizationEngine.js +428 -0
- package/dist/core/aiOptimizationEngine.js.map +1 -0
- package/dist/core/aiOptimizationIntegration.d.ts +93 -0
- package/dist/core/aiOptimizationIntegration.d.ts.map +1 -0
- package/dist/core/aiOptimizationIntegration.js +250 -0
- package/dist/core/aiOptimizationIntegration.js.map +1 -0
- package/dist/core/customCommands.d.ts +0 -1
- package/dist/core/customCommands.d.ts.map +1 -1
- package/dist/core/customCommands.js +0 -3
- package/dist/core/customCommands.js.map +1 -1
- package/dist/core/enhancedErrorRecovery.d.ts +100 -0
- package/dist/core/enhancedErrorRecovery.d.ts.map +1 -0
- package/dist/core/enhancedErrorRecovery.js +345 -0
- package/dist/core/enhancedErrorRecovery.js.map +1 -0
- package/dist/core/hooksSystem.d.ts +65 -0
- package/dist/core/hooksSystem.d.ts.map +1 -0
- package/dist/core/hooksSystem.js +273 -0
- package/dist/core/hooksSystem.js.map +1 -0
- package/dist/core/memorySystem.d.ts +48 -0
- package/dist/core/memorySystem.d.ts.map +1 -0
- package/dist/core/memorySystem.js +271 -0
- package/dist/core/memorySystem.js.map +1 -0
- package/dist/core/sessionStore.d.ts +0 -2
- package/dist/core/sessionStore.d.ts.map +1 -1
- package/dist/core/sessionStore.js +0 -1
- package/dist/core/sessionStore.js.map +1 -1
- package/dist/core/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +14 -0
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts +1 -22
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +5 -0
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/toolValidation.d.ts.map +1 -1
- package/dist/core/toolValidation.js +3 -14
- package/dist/core/toolValidation.js.map +1 -1
- package/dist/core/unified/errors.d.ts +189 -0
- package/dist/core/unified/errors.d.ts.map +1 -0
- package/dist/core/unified/errors.js +497 -0
- package/dist/core/unified/errors.js.map +1 -0
- package/dist/core/unified/index.d.ts +19 -0
- package/dist/core/unified/index.d.ts.map +1 -0
- package/dist/core/unified/index.js +68 -0
- package/dist/core/unified/index.js.map +1 -0
- package/dist/core/unified/schema.d.ts +101 -0
- package/dist/core/unified/schema.d.ts.map +1 -0
- package/dist/core/unified/schema.js +350 -0
- package/dist/core/unified/schema.js.map +1 -0
- package/dist/core/unified/toolRuntime.d.ts +179 -0
- package/dist/core/unified/toolRuntime.d.ts.map +1 -0
- package/dist/core/unified/toolRuntime.js +517 -0
- package/dist/core/unified/toolRuntime.js.map +1 -0
- package/dist/core/unified/tools.d.ts +127 -0
- package/dist/core/unified/tools.d.ts.map +1 -0
- package/dist/core/unified/tools.js +1333 -0
- package/dist/core/unified/tools.js.map +1 -0
- package/dist/core/unified/types.d.ts +352 -0
- package/dist/core/unified/types.d.ts.map +1 -0
- package/dist/core/unified/types.js +12 -0
- package/dist/core/unified/types.js.map +1 -0
- package/dist/core/unified/version.d.ts +209 -0
- package/dist/core/unified/version.d.ts.map +1 -0
- package/dist/core/unified/version.js +454 -0
- package/dist/core/unified/version.js.map +1 -0
- package/dist/core/validationRunner.d.ts +3 -1
- package/dist/core/validationRunner.d.ts.map +1 -1
- package/dist/core/validationRunner.js.map +1 -1
- package/dist/headless/headlessApp.d.ts.map +1 -1
- package/dist/headless/headlessApp.js +0 -21
- package/dist/headless/headlessApp.js.map +1 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +18 -9
- package/dist/mcp/sseClient.js.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.d.ts +6 -0
- package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.js +10 -4
- package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +2 -0
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/plugins/tools/security/securityPlugin.d.ts +3 -0
- package/dist/plugins/tools/security/securityPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/security/securityPlugin.js +12 -0
- package/dist/plugins/tools/security/securityPlugin.js.map +1 -0
- package/dist/runtime/agentSession.d.ts +2 -2
- package/dist/runtime/agentSession.d.ts.map +1 -1
- package/dist/runtime/agentSession.js +2 -2
- package/dist/runtime/agentSession.js.map +1 -1
- package/dist/security/active-stack-security.d.ts +112 -0
- package/dist/security/active-stack-security.d.ts.map +1 -0
- package/dist/security/active-stack-security.js +296 -0
- package/dist/security/active-stack-security.js.map +1 -0
- package/dist/security/advanced-persistence-research.d.ts +92 -0
- package/dist/security/advanced-persistence-research.d.ts.map +1 -0
- package/dist/security/advanced-persistence-research.js +195 -0
- package/dist/security/advanced-persistence-research.js.map +1 -0
- package/dist/security/advanced-targeting.d.ts +119 -0
- package/dist/security/advanced-targeting.d.ts.map +1 -0
- package/dist/security/advanced-targeting.js +233 -0
- package/dist/security/advanced-targeting.js.map +1 -0
- package/dist/security/assessment/vulnerabilityAssessment.d.ts +104 -0
- package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +1 -0
- package/dist/security/assessment/vulnerabilityAssessment.js +315 -0
- package/dist/security/assessment/vulnerabilityAssessment.js.map +1 -0
- package/dist/security/authorization/securityAuthorization.d.ts +88 -0
- package/dist/security/authorization/securityAuthorization.d.ts.map +1 -0
- package/dist/security/authorization/securityAuthorization.js +172 -0
- package/dist/security/authorization/securityAuthorization.js.map +1 -0
- package/dist/security/comprehensive-targeting.d.ts +85 -0
- package/dist/security/comprehensive-targeting.d.ts.map +1 -0
- package/dist/security/comprehensive-targeting.js +438 -0
- package/dist/security/comprehensive-targeting.js.map +1 -0
- package/dist/security/global-security-integration.d.ts +91 -0
- package/dist/security/global-security-integration.d.ts.map +1 -0
- package/dist/security/global-security-integration.js +218 -0
- package/dist/security/global-security-integration.js.map +1 -0
- package/dist/security/index.d.ts +38 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +47 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/persistence-analyzer.d.ts +56 -0
- package/dist/security/persistence-analyzer.d.ts.map +1 -0
- package/dist/security/persistence-analyzer.js +187 -0
- package/dist/security/persistence-analyzer.js.map +1 -0
- package/dist/security/persistence-cli.d.ts +36 -0
- package/dist/security/persistence-cli.d.ts.map +1 -0
- package/dist/security/persistence-cli.js +160 -0
- package/dist/security/persistence-cli.js.map +1 -0
- package/dist/security/persistence-research.d.ts +92 -0
- package/dist/security/persistence-research.d.ts.map +1 -0
- package/dist/security/persistence-research.js +364 -0
- package/dist/security/persistence-research.js.map +1 -0
- package/dist/security/research/persistenceResearch.d.ts +97 -0
- package/dist/security/research/persistenceResearch.d.ts.map +1 -0
- package/dist/security/research/persistenceResearch.js +282 -0
- package/dist/security/research/persistenceResearch.js.map +1 -0
- package/dist/security/security-integration.d.ts +74 -0
- package/dist/security/security-integration.d.ts.map +1 -0
- package/dist/security/security-integration.js +137 -0
- package/dist/security/security-integration.js.map +1 -0
- package/dist/security/security-testing-framework.d.ts +112 -0
- package/dist/security/security-testing-framework.d.ts.map +1 -0
- package/dist/security/security-testing-framework.js +364 -0
- package/dist/security/security-testing-framework.js.map +1 -0
- package/dist/security/simulation/attackSimulation.d.ts +93 -0
- package/dist/security/simulation/attackSimulation.d.ts.map +1 -0
- package/dist/security/simulation/attackSimulation.js +341 -0
- package/dist/security/simulation/attackSimulation.js.map +1 -0
- package/dist/security/strategic-operations.d.ts +100 -0
- package/dist/security/strategic-operations.d.ts.map +1 -0
- package/dist/security/strategic-operations.js +276 -0
- package/dist/security/strategic-operations.js.map +1 -0
- package/dist/security/tool-security-wrapper.d.ts +58 -0
- package/dist/security/tool-security-wrapper.d.ts.map +1 -0
- package/dist/security/tool-security-wrapper.js +156 -0
- package/dist/security/tool-security-wrapper.js.map +1 -0
- package/dist/shell/claudeCodeStreamHandler.d.ts +145 -0
- package/dist/shell/claudeCodeStreamHandler.d.ts.map +1 -0
- package/dist/shell/claudeCodeStreamHandler.js +322 -0
- package/dist/shell/claudeCodeStreamHandler.js.map +1 -0
- package/dist/shell/inputQueueManager.d.ts +144 -0
- package/dist/shell/inputQueueManager.d.ts.map +1 -0
- package/dist/shell/inputQueueManager.js +290 -0
- package/dist/shell/inputQueueManager.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +7 -43
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +166 -418
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/metricsTracker.d.ts +60 -0
- package/dist/shell/metricsTracker.d.ts.map +1 -0
- package/dist/shell/metricsTracker.js +119 -0
- package/dist/shell/metricsTracker.js.map +1 -0
- package/dist/shell/shellApp.d.ts +0 -2
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +9 -82
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/streamingOutputManager.d.ts +115 -0
- package/dist/shell/streamingOutputManager.d.ts.map +1 -0
- package/dist/shell/streamingOutputManager.js +225 -0
- package/dist/shell/streamingOutputManager.js.map +1 -0
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +4 -1
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +124 -258
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +608 -1010
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +24 -106
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +30 -140
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/subagents/taskRunner.d.ts +1 -7
- package/dist/subagents/taskRunner.d.ts.map +1 -1
- package/dist/subagents/taskRunner.js +47 -180
- package/dist/subagents/taskRunner.js.map +1 -1
- package/dist/tools/learnTools.js +4 -127
- package/dist/tools/learnTools.js.map +1 -1
- package/dist/tools/securityTools.d.ts +22 -0
- package/dist/tools/securityTools.d.ts.map +1 -0
- package/dist/tools/securityTools.js +448 -0
- package/dist/tools/securityTools.js.map +1 -0
- package/dist/ui/ShellUIAdapter.d.ts +1 -7
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +18 -42
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/display.d.ts +45 -24
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +274 -148
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/persistentPrompt.d.ts +50 -0
- package/dist/ui/persistentPrompt.d.ts.map +1 -0
- package/dist/ui/persistentPrompt.js +92 -0
- package/dist/ui/persistentPrompt.js.map +1 -0
- package/dist/ui/terminalUISchema.d.ts +195 -0
- package/dist/ui/terminalUISchema.d.ts.map +1 -0
- package/dist/ui/terminalUISchema.js +113 -0
- package/dist/ui/terminalUISchema.js.map +1 -0
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js +8 -6
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts +158 -0
- package/dist/ui/toolDisplay.d.ts.map +1 -1
- package/dist/ui/toolDisplay.js +348 -0
- package/dist/ui/toolDisplay.js.map +1 -1
- package/dist/ui/unified/layout.d.ts +0 -20
- package/dist/ui/unified/layout.d.ts.map +1 -1
- package/dist/ui/unified/layout.js +216 -105
- package/dist/ui/unified/layout.js.map +1 -1
- package/package.json +4 -4
- package/scripts/deploy-security-capabilities.js +178 -0
- 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/metricsTracker.d.ts +0 -122
- package/dist/core/metricsTracker.d.ts.map +0 -1
- package/dist/core/metricsTracker.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/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/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/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
|
@@ -2,7 +2,7 @@ import { stdin as input, stdout as output, exit } from 'node:process';
|
|
|
2
2
|
import { exec } from 'node:child_process';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import { display } from '../ui/display.js';
|
|
5
|
-
import { theme } from '../ui/theme.js';
|
|
5
|
+
import { theme, formatUserPrompt } from '../ui/theme.js';
|
|
6
6
|
import { getContextWindowTokens } from '../core/contextWindow.js';
|
|
7
7
|
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
8
8
|
import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, } from '../core/preferences.js';
|
|
@@ -19,11 +19,11 @@ import { SkillRepository } from '../skills/skillRepository.js';
|
|
|
19
19
|
import { createSkillTools } from '../tools/skillTools.js';
|
|
20
20
|
import { FileChangeTracker } from './fileChangeTracker.js';
|
|
21
21
|
import { formatShortcutsHelp } from '../ui/shortcutsHelp.js';
|
|
22
|
-
import { MetricsTracker } from '
|
|
22
|
+
import { MetricsTracker } from './metricsTracker.js';
|
|
23
23
|
import { listAvailablePlugins } from '../plugins/index.js';
|
|
24
|
+
import { loadMemory, listMemoryPaths, getDefaultProjectMemoryPath, getUserMemoryEditPath, } from '../core/memorySystem.js';
|
|
24
25
|
import { TerminalInputAdapter } from './terminalInputAdapter.js';
|
|
25
|
-
import {
|
|
26
|
-
import { isUpdateInProgress, maybeOfferCliUpdate } from './updateManager.js';
|
|
26
|
+
import { isUpdateInProgress } from './updateManager.js';
|
|
27
27
|
import { writeLock } from '../ui/writeLock.js';
|
|
28
28
|
import { enterStreamingMode, exitStreamingMode } from '../ui/globalWriteLock.js';
|
|
29
29
|
const execAsync = promisify(exec);
|
|
@@ -35,7 +35,6 @@ const DROPDOWN_COLORS = [
|
|
|
35
35
|
theme.success,
|
|
36
36
|
theme.warning,
|
|
37
37
|
];
|
|
38
|
-
const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
|
|
39
38
|
// Load MODEL_PRESETS from centralized schema
|
|
40
39
|
const MODEL_PRESETS = getModels().map((model) => ({
|
|
41
40
|
id: model.id,
|
|
@@ -50,13 +49,11 @@ const MODEL_PRESETS = getModels().map((model) => ({
|
|
|
50
49
|
const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
|
|
51
50
|
command: cmd.command,
|
|
52
51
|
description: cmd.description,
|
|
53
|
-
category: cmd.category,
|
|
54
52
|
}));
|
|
55
53
|
// Load PROVIDER_LABELS from centralized schema
|
|
56
54
|
const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
|
|
57
55
|
// Allow enough time for paste detection to kick in before flushing buffered lines
|
|
58
56
|
const CONTEXT_USAGE_THRESHOLD = 0.9;
|
|
59
|
-
const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
|
|
60
57
|
const CONTEXT_RECENT_MESSAGE_COUNT = 12;
|
|
61
58
|
const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
|
|
62
59
|
const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
|
|
@@ -97,12 +94,11 @@ export class InteractiveShell {
|
|
|
97
94
|
uiAdapter;
|
|
98
95
|
uiUpdates;
|
|
99
96
|
_fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
|
|
100
|
-
|
|
97
|
+
sessionMetrics; // Session performance tracking
|
|
101
98
|
statusSubscription = null;
|
|
102
99
|
followUpQueue = [];
|
|
103
100
|
isDrainingQueue = false;
|
|
104
101
|
activeContextWindowTokens = null;
|
|
105
|
-
latestTokenUsage = { used: null, limit: null };
|
|
106
102
|
sessionPreferences;
|
|
107
103
|
autosaveEnabled;
|
|
108
104
|
autoContinueEnabled;
|
|
@@ -133,9 +129,6 @@ export class InteractiveShell {
|
|
|
133
129
|
statusLineState = null;
|
|
134
130
|
statusMessageOverride = null;
|
|
135
131
|
promptRefreshTimer = null;
|
|
136
|
-
launchPaletteShown = false;
|
|
137
|
-
version;
|
|
138
|
-
alternateScreenEnabled;
|
|
139
132
|
constructor(config) {
|
|
140
133
|
this.profile = config.profile;
|
|
141
134
|
this.profileLabel = config.profileLabel;
|
|
@@ -149,9 +142,6 @@ export class InteractiveShell {
|
|
|
149
142
|
this.autoContinueEnabled = this.sessionPreferences.autoContinue;
|
|
150
143
|
this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
|
|
151
144
|
this._enabledPlugins = config.enabledPlugins ?? [];
|
|
152
|
-
this.version = config.version ?? '0.0.0';
|
|
153
|
-
// Alternate screen disabled - use terminal-native mode for proper scrollback and text selection
|
|
154
|
-
this.alternateScreenEnabled = false;
|
|
155
145
|
this.initializeSessionHistory();
|
|
156
146
|
this.sessionState = {
|
|
157
147
|
provider: config.initialModel.provider,
|
|
@@ -172,7 +162,6 @@ export class InteractiveShell {
|
|
|
172
162
|
this.slashCommands.push({
|
|
173
163
|
command: '/agents',
|
|
174
164
|
description: 'Select the default agent profile (applies on next launch)',
|
|
175
|
-
category: 'configuration',
|
|
176
165
|
});
|
|
177
166
|
}
|
|
178
167
|
this.customCommands = loadCustomSlashCommands();
|
|
@@ -181,21 +170,18 @@ export class InteractiveShell {
|
|
|
181
170
|
this.slashCommands.push({
|
|
182
171
|
command: custom.command,
|
|
183
172
|
description: `${custom.description} (custom)`,
|
|
184
|
-
category: custom.category ?? 'other',
|
|
185
173
|
});
|
|
186
174
|
}
|
|
187
175
|
if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
|
|
188
176
|
this.slashCommands.push({
|
|
189
177
|
command: '/exit',
|
|
190
178
|
description: 'Quit the CLI immediately',
|
|
191
|
-
category: 'other',
|
|
192
179
|
});
|
|
193
180
|
}
|
|
194
181
|
// Add /plugins command
|
|
195
182
|
this.slashCommands.push({
|
|
196
183
|
command: '/plugins',
|
|
197
184
|
description: 'Show available and loaded plugins',
|
|
198
|
-
category: 'configuration',
|
|
199
185
|
});
|
|
200
186
|
this.statusTracker = config.statusTracker;
|
|
201
187
|
this.ui = config.ui;
|
|
@@ -227,28 +213,20 @@ export class InteractiveShell {
|
|
|
227
213
|
onEditModeChange: (mode) => this.handleEditModeChange(mode),
|
|
228
214
|
onToggleVerify: () => this.toggleVerificationMode(),
|
|
229
215
|
onToggleAutoContinue: () => this.toggleAutoContinueMode(),
|
|
230
|
-
onToggleThinking: () => this.cycleThinkingMode(),
|
|
231
|
-
onClearContext: () => this.handleClearContext(),
|
|
232
216
|
});
|
|
217
|
+
// Register output interceptor for cursor positioning during streaming
|
|
218
|
+
this.terminalInput.registerOutputInterceptor(display);
|
|
219
|
+
// Set banner content to be written during unified UI initialization
|
|
220
|
+
this.terminalInput.setBannerContent(display.getBannerContent());
|
|
221
|
+
// Initialize unified UI - clears screen, sets up scroll region, writes banner,
|
|
222
|
+
// and renders input area at bottom
|
|
223
|
+
this.terminalInput.initializeUnifiedUI();
|
|
233
224
|
// Initialize Alpha Zero 2 metrics tracking
|
|
234
|
-
this.
|
|
225
|
+
this.sessionMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
235
226
|
this.setupStatusTracking();
|
|
236
227
|
this.refreshContextGauge();
|
|
237
|
-
// Start terminal input (sets up handlers)
|
|
238
228
|
this.terminalInput.start();
|
|
239
|
-
// Enter alternate screen buffer when enabled, otherwise clear the main screen for layout
|
|
240
|
-
if (this.alternateScreenEnabled) {
|
|
241
|
-
this.terminalInput.enterAlternateScreen();
|
|
242
|
-
}
|
|
243
|
-
else if (output.isTTY) {
|
|
244
|
-
this.terminalInput.clearScreen();
|
|
245
|
-
}
|
|
246
|
-
// Stream banner first - this sets up scroll region dynamically
|
|
247
|
-
const banner = this.buildBanner();
|
|
248
|
-
this.terminalInput.streamContent(banner + '\n\n');
|
|
249
|
-
// Render chat box after banner is streamed
|
|
250
229
|
this.refreshControlBar();
|
|
251
|
-
this.terminalInput.forceRender();
|
|
252
230
|
this.rebuildAgent();
|
|
253
231
|
this.setupHandlers();
|
|
254
232
|
this.refreshBannerSessionInfo();
|
|
@@ -268,10 +246,6 @@ export class InteractiveShell {
|
|
|
268
246
|
this.activeSessionId = stored.id;
|
|
269
247
|
this.activeSessionTitle = stored.title;
|
|
270
248
|
this.sessionResumeNotice = `Resumed session "${stored.title}".`;
|
|
271
|
-
// Restore scrollback buffer if available
|
|
272
|
-
if (stored.scrollbackBuffer && Array.isArray(stored.scrollbackBuffer)) {
|
|
273
|
-
this.terminalInput.loadScrollbackBuffer(stored.scrollbackBuffer);
|
|
274
|
-
}
|
|
275
249
|
return;
|
|
276
250
|
}
|
|
277
251
|
display.showWarning(`Session "${this.sessionRestoreConfig.sessionId}" not found. Starting fresh session.`);
|
|
@@ -285,10 +259,6 @@ export class InteractiveShell {
|
|
|
285
259
|
this.activeSessionId = null;
|
|
286
260
|
this.activeSessionTitle = autosave.title;
|
|
287
261
|
this.sessionResumeNotice = 'Restored last autosaved session.';
|
|
288
|
-
// Restore scrollback buffer if available
|
|
289
|
-
if (autosave.scrollbackBuffer && Array.isArray(autosave.scrollbackBuffer)) {
|
|
290
|
-
this.terminalInput.loadScrollbackBuffer(autosave.scrollbackBuffer);
|
|
291
|
-
}
|
|
292
262
|
return;
|
|
293
263
|
}
|
|
294
264
|
display.showWarning('No autosaved session found. Starting fresh session.');
|
|
@@ -303,24 +273,14 @@ export class InteractiveShell {
|
|
|
303
273
|
this.sessionResumeNotice = null;
|
|
304
274
|
}
|
|
305
275
|
async start(initialPrompt) {
|
|
306
|
-
// Check for updates in background (non-blocking)
|
|
307
|
-
if (this.version) {
|
|
308
|
-
void maybeOfferCliUpdate(this.version);
|
|
309
|
-
}
|
|
310
276
|
if (initialPrompt) {
|
|
311
277
|
this.logUserPrompt(initialPrompt);
|
|
312
278
|
await this.processInputBlock(initialPrompt);
|
|
313
279
|
return;
|
|
314
280
|
}
|
|
315
|
-
this.showLaunchCommandPalette();
|
|
316
281
|
// Ensure the terminal input is visible
|
|
317
282
|
this.terminalInput.render();
|
|
318
283
|
}
|
|
319
|
-
showLaunchCommandPalette() {
|
|
320
|
-
// Disabled: Quick commands palette takes up too much space
|
|
321
|
-
// Users can type /help to see available commands
|
|
322
|
-
this.launchPaletteShown = true;
|
|
323
|
-
}
|
|
324
284
|
/**
|
|
325
285
|
* TerminalInputAdapter submit handler
|
|
326
286
|
*/
|
|
@@ -334,8 +294,9 @@ export class InteractiveShell {
|
|
|
334
294
|
this.handleInputChange('');
|
|
335
295
|
return;
|
|
336
296
|
}
|
|
337
|
-
//
|
|
338
|
-
//
|
|
297
|
+
// Enter streaming mode BEFORE logging prompt - this positions cursor correctly
|
|
298
|
+
// so content appears right after the banner, not at bottom with blank space above
|
|
299
|
+
this.terminalInput.setStreaming(true);
|
|
339
300
|
this.logUserPrompt(approved);
|
|
340
301
|
void this.processInputBlock(approved).catch((err) => {
|
|
341
302
|
display.showError(err instanceof Error ? err.message : String(err), err);
|
|
@@ -425,59 +386,6 @@ export class InteractiveShell {
|
|
|
425
386
|
: 'The model will not be auto-prompted to continue.') +
|
|
426
387
|
' Toggle with alt+c.');
|
|
427
388
|
}
|
|
428
|
-
/**
|
|
429
|
-
* Cycle through thinking modes (Alt+T keyboard shortcut).
|
|
430
|
-
*/
|
|
431
|
-
cycleThinkingMode() {
|
|
432
|
-
const modes = ['concise', 'balanced', 'extended'];
|
|
433
|
-
const currentIndex = modes.indexOf(this.thinkingMode);
|
|
434
|
-
const nextIndex = (currentIndex + 1) % modes.length;
|
|
435
|
-
const nextMode = modes[nextIndex];
|
|
436
|
-
this.thinkingMode = nextMode;
|
|
437
|
-
saveSessionPreferences({ thinkingMode: this.thinkingMode });
|
|
438
|
-
this.refreshControlBar();
|
|
439
|
-
const descriptions = {
|
|
440
|
-
concise: 'Minimal reasoning, faster responses',
|
|
441
|
-
balanced: 'Default reasoning depth',
|
|
442
|
-
extended: 'Deep reasoning, thorough analysis',
|
|
443
|
-
};
|
|
444
|
-
display.showInfo(`Thinking mode: ${theme.info(nextMode)} - ${descriptions[nextMode]}. (Alt+T to cycle)`);
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Handle context clear/compact request (Alt+X keyboard shortcut).
|
|
448
|
-
*/
|
|
449
|
-
handleClearContext() {
|
|
450
|
-
if (this.isProcessing) {
|
|
451
|
-
display.showWarning('Cannot clear context while processing. Wait for completion or press Ctrl+C.');
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
// Trigger context compaction
|
|
455
|
-
display.showInfo('Compacting context... This will summarize the conversation and free up space.');
|
|
456
|
-
void this.performContextCompaction();
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Perform context compaction by summarizing conversation history.
|
|
460
|
-
*/
|
|
461
|
-
async performContextCompaction() {
|
|
462
|
-
try {
|
|
463
|
-
// For now, just clear the history and show a message
|
|
464
|
-
// A full implementation would summarize the conversation
|
|
465
|
-
const oldLength = this.cachedHistory.length;
|
|
466
|
-
if (oldLength === 0) {
|
|
467
|
-
display.showInfo('Context is already empty.');
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
// Keep the last few messages for continuity
|
|
471
|
-
const keepCount = Math.min(4, oldLength);
|
|
472
|
-
this.cachedHistory = this.cachedHistory.slice(-keepCount);
|
|
473
|
-
display.showSuccess(`Context compacted: ${oldLength} messages reduced to ${keepCount}. ` +
|
|
474
|
-
`Context usage reset. Continue your conversation.`);
|
|
475
|
-
this.refreshControlBar();
|
|
476
|
-
}
|
|
477
|
-
catch (error) {
|
|
478
|
-
display.showError('Failed to compact context', error);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
389
|
/**
|
|
482
390
|
* Gate submissions when edit permission mode is active.
|
|
483
391
|
* Returns the text to send when approved, or null when waiting for confirmation.
|
|
@@ -577,10 +485,6 @@ export class InteractiveShell {
|
|
|
577
485
|
return;
|
|
578
486
|
}
|
|
579
487
|
this.shuttingDown = true;
|
|
580
|
-
const shouldRestoreScrollback = this.alternateScreenEnabled && this.terminalInput.isAlternateScreenActive();
|
|
581
|
-
const scrollbackSnapshot = shouldRestoreScrollback
|
|
582
|
-
? this.terminalInput.getScrollbackSnapshot()
|
|
583
|
-
: null;
|
|
584
488
|
// Stop any active spinner to prevent process hang
|
|
585
489
|
display.stopThinking(false);
|
|
586
490
|
this.stopStreamingHeartbeat();
|
|
@@ -589,34 +493,18 @@ export class InteractiveShell {
|
|
|
589
493
|
this.teardownStatusTracking();
|
|
590
494
|
// Clear any pending cleanup to prevent hanging
|
|
591
495
|
this.pendingCleanup = null;
|
|
592
|
-
// Reset terminal state before disposing adapters
|
|
593
|
-
this.terminalInput.exitStreamingScrollRegion();
|
|
594
|
-
if (this.alternateScreenEnabled) {
|
|
595
|
-
this.terminalInput.exitAlternateScreen();
|
|
596
|
-
}
|
|
597
496
|
// Dispose terminal input handler
|
|
598
497
|
this.terminalInput.dispose();
|
|
599
498
|
// Dispose unified UI adapter
|
|
600
499
|
this.uiAdapter.dispose();
|
|
601
|
-
if (scrollbackSnapshot && scrollbackSnapshot.length > 0) {
|
|
602
|
-
this.restoreScrollbackSnapshot(scrollbackSnapshot);
|
|
603
|
-
}
|
|
604
500
|
display.newLine();
|
|
605
|
-
|
|
606
|
-
console.log(theme.
|
|
607
|
-
console.log(theme.ui.muted('
|
|
501
|
+
const version = display.getVersion() || 'unknown';
|
|
502
|
+
console.log(theme.gradient.warm('━'.repeat(50)));
|
|
503
|
+
console.log(` ${theme.gradient.cool('✨ Goodbye!')} ${theme.ui.muted('·')} ${theme.info(`erosolar-cli v${version}`)}`);
|
|
504
|
+
console.log(` ${theme.ui.muted('Support:')} ${theme.info('support@ero.solar')}`);
|
|
505
|
+
console.log(theme.gradient.warm('━'.repeat(50)));
|
|
608
506
|
exit(0);
|
|
609
507
|
}
|
|
610
|
-
restoreScrollbackSnapshot(lines) {
|
|
611
|
-
if (!lines.length) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
const transcript = lines.join('\n');
|
|
615
|
-
const separator = theme.ui.muted('─'.repeat(44));
|
|
616
|
-
const header = theme.ui.muted('Restored scrollback from this session:');
|
|
617
|
-
// Write directly to stdout after exiting alternate screen to preserve the transcript
|
|
618
|
-
process.stdout.write(`\n${separator}\n${header}\n${transcript}\n${separator}\n`);
|
|
619
|
-
}
|
|
620
508
|
/**
|
|
621
509
|
* Update status bar message
|
|
622
510
|
*/
|
|
@@ -784,14 +672,13 @@ export class InteractiveShell {
|
|
|
784
672
|
});
|
|
785
673
|
}
|
|
786
674
|
setProcessingStatus(detail) {
|
|
787
|
-
this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
|
|
788
675
|
this.statusTracker.setBase('Working on your request', {
|
|
789
676
|
detail: this.describeStatusDetail(detail),
|
|
790
677
|
tone: 'info',
|
|
791
678
|
});
|
|
792
679
|
}
|
|
793
680
|
describeStatusDetail(detail) {
|
|
794
|
-
const parts = detail?.trim()
|
|
681
|
+
const parts = [detail?.trim() || this.describeModelDetail()];
|
|
795
682
|
const queued = this.followUpQueue.length;
|
|
796
683
|
if (queued > 0) {
|
|
797
684
|
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
|
|
@@ -804,18 +691,12 @@ export class InteractiveShell {
|
|
|
804
691
|
}
|
|
805
692
|
refreshContextGauge() {
|
|
806
693
|
const tokens = getContextWindowTokens(this.sessionState.model);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
if (normalizedTokens !== null) {
|
|
810
|
-
this.latestTokenUsage = {
|
|
811
|
-
used: this.latestTokenUsage.used,
|
|
812
|
-
limit: normalizedTokens,
|
|
813
|
-
};
|
|
814
|
-
}
|
|
694
|
+
this.activeContextWindowTokens =
|
|
695
|
+
typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
815
696
|
}
|
|
816
697
|
updateContextUsage(percentage) {
|
|
817
698
|
this.uiAdapter.updateContextUsage(percentage);
|
|
818
|
-
this.terminalInput.setContextUsage(percentage
|
|
699
|
+
this.terminalInput.setContextUsage(percentage);
|
|
819
700
|
}
|
|
820
701
|
refreshControlBar() {
|
|
821
702
|
this.terminalInput.setModeToggles({
|
|
@@ -823,9 +704,9 @@ export class InteractiveShell {
|
|
|
823
704
|
autoContinueEnabled: this.autoContinueEnabled,
|
|
824
705
|
verificationHotkey: 'alt+v',
|
|
825
706
|
autoContinueHotkey: 'alt+c',
|
|
826
|
-
thinkingModeLabel: this.thinkingMode,
|
|
827
|
-
thinkingHotkey: '/thinking',
|
|
828
707
|
});
|
|
708
|
+
// Update persistent model info display
|
|
709
|
+
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
829
710
|
this.refreshStatusLine();
|
|
830
711
|
this.terminalInput.render();
|
|
831
712
|
}
|
|
@@ -856,25 +737,6 @@ export class InteractiveShell {
|
|
|
856
737
|
// Set main status (tool execution, etc.) - shown when not overridden
|
|
857
738
|
const statusText = this.formatStatusLine(this.statusLineState);
|
|
858
739
|
this.terminalInput.setStatusMessage(statusText);
|
|
859
|
-
// Surface meta header (elapsed + context usage) above the divider
|
|
860
|
-
const elapsedSeconds = this.statusLineState
|
|
861
|
-
? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
|
|
862
|
-
: null;
|
|
863
|
-
const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
|
|
864
|
-
const tokensUsed = this.latestTokenUsage.used;
|
|
865
|
-
const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
|
|
866
|
-
this.terminalInput.setMetaStatus({
|
|
867
|
-
elapsedSeconds,
|
|
868
|
-
tokensUsed,
|
|
869
|
-
tokenLimit,
|
|
870
|
-
thinkingMs,
|
|
871
|
-
thinkingHasContent: display.isSpinnerActive(),
|
|
872
|
-
});
|
|
873
|
-
// Keep model/provider visible in the controls bar
|
|
874
|
-
this.terminalInput.setModelContext({
|
|
875
|
-
model: this.sessionState.model,
|
|
876
|
-
provider: this.providerLabel(this.sessionState.provider),
|
|
877
|
-
});
|
|
878
740
|
if (forceRender) {
|
|
879
741
|
this.terminalInput.render();
|
|
880
742
|
}
|
|
@@ -934,14 +796,15 @@ export class InteractiveShell {
|
|
|
934
796
|
this.terminalInput.render();
|
|
935
797
|
}
|
|
936
798
|
/**
|
|
937
|
-
* Log user prompt
|
|
799
|
+
* Log the user's prompt as a visible message in the conversation.
|
|
800
|
+
* This creates a persistent log entry that remains visible during and after streaming.
|
|
938
801
|
*/
|
|
939
802
|
logUserPrompt(text) {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
this.terminalInput.
|
|
803
|
+
// Display the user's prompt with the standard prefix
|
|
804
|
+
const prefix = formatUserPrompt();
|
|
805
|
+
display.stream(`\n${prefix}${text}\n\n`);
|
|
806
|
+
// Update content end row so chat box renders below the user prompt
|
|
807
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
945
808
|
}
|
|
946
809
|
requestPromptRefresh(force = false) {
|
|
947
810
|
if (force) {
|
|
@@ -966,40 +829,16 @@ export class InteractiveShell {
|
|
|
966
829
|
this.stopStreamingHeartbeat();
|
|
967
830
|
// Enter global streaming mode - blocks all non-streaming UI output
|
|
968
831
|
enterStreamingMode();
|
|
969
|
-
// Set up scroll region for streaming content
|
|
970
|
-
this.terminalInput.enterStreamingScrollRegion();
|
|
971
832
|
this.uiUpdates.setMode('streaming');
|
|
972
833
|
this.streamingHeartbeatStart = Date.now();
|
|
973
834
|
this.streamingHeartbeatFrame = 0;
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
this.refreshStatusLine(true);
|
|
978
|
-
// Periodically refresh the pinned input/status region while streaming so
|
|
979
|
-
// elapsed time remains visible without interrupting the scroll region.
|
|
980
|
-
this.uiUpdates.startHeartbeat('streaming', {
|
|
981
|
-
intervalMs: 1000,
|
|
982
|
-
lane: 'heartbeat',
|
|
983
|
-
mode: ['streaming', 'processing'],
|
|
984
|
-
coalesceKey: 'streaming:heartbeat',
|
|
985
|
-
run: () => {
|
|
986
|
-
const elapsedSeconds = this.streamingHeartbeatStart
|
|
987
|
-
? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
|
|
988
|
-
: 0;
|
|
989
|
-
this.streamingHeartbeatFrame =
|
|
990
|
-
(this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
|
|
991
|
-
const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
992
|
-
this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
|
|
993
|
-
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
994
|
-
this.refreshStatusLine(true);
|
|
995
|
-
},
|
|
996
|
-
});
|
|
835
|
+
// Note: We don't start a heartbeat during streaming anymore
|
|
836
|
+
// because the UI shouldn't be rendering during streaming.
|
|
837
|
+
// The streaming status is shown in the streaming header instead.
|
|
997
838
|
}
|
|
998
839
|
stopStreamingHeartbeat() {
|
|
999
840
|
// Exit global streaming mode - allows UI to render again
|
|
1000
841
|
exitStreamingMode();
|
|
1001
|
-
// Exit scroll region mode
|
|
1002
|
-
this.terminalInput.exitStreamingScrollRegion();
|
|
1003
842
|
this.uiUpdates.stopHeartbeat('streaming');
|
|
1004
843
|
this.streamingHeartbeatStart = null;
|
|
1005
844
|
this.streamingHeartbeatFrame = 0;
|
|
@@ -1011,28 +850,10 @@ export class InteractiveShell {
|
|
|
1011
850
|
// Force refresh to update the input area now that streaming has ended
|
|
1012
851
|
this.refreshStatusLine(true);
|
|
1013
852
|
}
|
|
1014
|
-
buildStreamingStatus(label
|
|
853
|
+
buildStreamingStatus(label) {
|
|
1015
854
|
const detail = this.describeModelDetail();
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1018
|
-
: null;
|
|
1019
|
-
const prefix = theme.info('⏺');
|
|
1020
|
-
const parts = [label];
|
|
1021
|
-
if (detail) {
|
|
1022
|
-
parts.push(theme.ui.muted('·'), detail);
|
|
1023
|
-
}
|
|
1024
|
-
if (elapsedLabel) {
|
|
1025
|
-
parts.push(theme.ui.muted('·'), elapsedLabel);
|
|
1026
|
-
}
|
|
1027
|
-
return `${prefix} ${parts.join(' ')}`.trim();
|
|
1028
|
-
}
|
|
1029
|
-
formatElapsedShort(seconds) {
|
|
1030
|
-
if (seconds < 60) {
|
|
1031
|
-
return `${seconds}s`;
|
|
1032
|
-
}
|
|
1033
|
-
const minutes = Math.floor(seconds / 60);
|
|
1034
|
-
const remaining = seconds % 60;
|
|
1035
|
-
return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
|
|
855
|
+
const prefix = theme.info('●');
|
|
856
|
+
return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
|
|
1036
857
|
}
|
|
1037
858
|
refreshQueueIndicators() {
|
|
1038
859
|
if (this.isProcessing) {
|
|
@@ -1280,6 +1101,17 @@ export class InteractiveShell {
|
|
|
1280
1101
|
case '/discover':
|
|
1281
1102
|
await this.discoverModelsCommand();
|
|
1282
1103
|
break;
|
|
1104
|
+
case '/memory':
|
|
1105
|
+
this.handleMemoryCommand(input);
|
|
1106
|
+
break;
|
|
1107
|
+
case '/clear':
|
|
1108
|
+
display.clear();
|
|
1109
|
+
this.cachedHistory = [];
|
|
1110
|
+
display.showInfo('Conversation cleared.');
|
|
1111
|
+
break;
|
|
1112
|
+
case '/help':
|
|
1113
|
+
this.showHelp();
|
|
1114
|
+
break;
|
|
1283
1115
|
default:
|
|
1284
1116
|
if (!(await this.tryCustomSlashCommand(command, input))) {
|
|
1285
1117
|
display.showWarning(`Unknown command "${command}".`);
|
|
@@ -1588,6 +1420,99 @@ export class InteractiveShell {
|
|
|
1588
1420
|
// Display keyboard shortcuts help (Claude Code style)
|
|
1589
1421
|
display.showSystemMessage(formatShortcutsHelp());
|
|
1590
1422
|
}
|
|
1423
|
+
handleMemoryCommand(input) {
|
|
1424
|
+
const tokens = input.trim().split(/\s+/).slice(1);
|
|
1425
|
+
const action = (tokens.shift() ?? 'show').toLowerCase();
|
|
1426
|
+
switch (action) {
|
|
1427
|
+
case '':
|
|
1428
|
+
case 'show':
|
|
1429
|
+
case 'list': {
|
|
1430
|
+
this.showMemoryStatus();
|
|
1431
|
+
break;
|
|
1432
|
+
}
|
|
1433
|
+
case 'paths': {
|
|
1434
|
+
this.showMemoryPaths();
|
|
1435
|
+
break;
|
|
1436
|
+
}
|
|
1437
|
+
case 'edit': {
|
|
1438
|
+
const level = (tokens[0] ?? 'project').toLowerCase();
|
|
1439
|
+
this.openMemoryForEdit(level);
|
|
1440
|
+
break;
|
|
1441
|
+
}
|
|
1442
|
+
default:
|
|
1443
|
+
display.showWarning('Usage: /memory [show|paths|edit <user|project>]');
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
showMemoryStatus() {
|
|
1448
|
+
const memory = loadMemory(this.workingDir);
|
|
1449
|
+
const lines = [];
|
|
1450
|
+
lines.push(theme.bold('Persistent Memory'));
|
|
1451
|
+
lines.push('');
|
|
1452
|
+
if (memory.sources.length === 0) {
|
|
1453
|
+
lines.push(theme.secondary('No memory files found.'));
|
|
1454
|
+
lines.push('');
|
|
1455
|
+
lines.push(`Create ${theme.info('EROSOLAR.md')} in your project to add persistent context.`);
|
|
1456
|
+
lines.push(`Use ${theme.info('/memory edit project')} to create one.`);
|
|
1457
|
+
}
|
|
1458
|
+
else {
|
|
1459
|
+
for (const source of memory.sources) {
|
|
1460
|
+
const levelLabel = source.level === 'enterprise' ? 'Enterprise' :
|
|
1461
|
+
source.level === 'user' ? 'User' : 'Project';
|
|
1462
|
+
const preview = source.content.slice(0, 200).replace(/\n/g, ' ').trim();
|
|
1463
|
+
const truncated = source.content.length > 200 ? '...' : '';
|
|
1464
|
+
lines.push(`${theme.success('●')} ${theme.bold(levelLabel)}: ${source.path}`);
|
|
1465
|
+
lines.push(` ${theme.dim(preview + truncated)}`);
|
|
1466
|
+
lines.push('');
|
|
1467
|
+
}
|
|
1468
|
+
if (memory.importedPaths.length > memory.sources.length) {
|
|
1469
|
+
lines.push(theme.secondary(`Imported ${memory.importedPaths.length - memory.sources.length} additional files via @imports.`));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1473
|
+
}
|
|
1474
|
+
showMemoryPaths() {
|
|
1475
|
+
const paths = listMemoryPaths(this.workingDir);
|
|
1476
|
+
const lines = [];
|
|
1477
|
+
lines.push(theme.bold('Memory File Locations'));
|
|
1478
|
+
lines.push('');
|
|
1479
|
+
for (const { level, path, exists } of paths) {
|
|
1480
|
+
const icon = exists ? theme.success('✓') : theme.dim('○');
|
|
1481
|
+
const levelLabel = level.charAt(0).toUpperCase() + level.slice(1);
|
|
1482
|
+
lines.push(`${icon} ${levelLabel}: ${path}`);
|
|
1483
|
+
}
|
|
1484
|
+
lines.push('');
|
|
1485
|
+
lines.push(theme.secondary('Create any of these files to add persistent memory.'));
|
|
1486
|
+
lines.push(theme.secondary('Use @path/to/file.md syntax to import other files.'));
|
|
1487
|
+
display.showSystemMessage(lines.join('\n'));
|
|
1488
|
+
}
|
|
1489
|
+
openMemoryForEdit(level) {
|
|
1490
|
+
let targetPath;
|
|
1491
|
+
if (level === 'user') {
|
|
1492
|
+
targetPath = getUserMemoryEditPath();
|
|
1493
|
+
}
|
|
1494
|
+
else if (level === 'project') {
|
|
1495
|
+
targetPath = getDefaultProjectMemoryPath(this.workingDir);
|
|
1496
|
+
}
|
|
1497
|
+
else {
|
|
1498
|
+
display.showWarning('Specify "user" or "project" to edit. Enterprise memory is read-only.');
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
display.showInfo(`Memory file: ${targetPath}`);
|
|
1502
|
+
display.showInfo('Create or edit this file to add persistent context for the AI.');
|
|
1503
|
+
display.showInfo('');
|
|
1504
|
+
display.showInfo('Example EROSOLAR.md content:');
|
|
1505
|
+
display.showInfo('');
|
|
1506
|
+
display.showInfo(theme.dim(`# Project Guidelines
|
|
1507
|
+
|
|
1508
|
+
When working in this codebase:
|
|
1509
|
+
- Follow TypeScript strict mode conventions
|
|
1510
|
+
- Use functional patterns where appropriate
|
|
1511
|
+
- Run tests before committing
|
|
1512
|
+
|
|
1513
|
+
@./docs/coding-standards.md
|
|
1514
|
+
`));
|
|
1515
|
+
}
|
|
1591
1516
|
showFileChangeSummary() {
|
|
1592
1517
|
const summary = this._fileChangeTracker.getSummary();
|
|
1593
1518
|
const changes = this._fileChangeTracker.getAllChanges();
|
|
@@ -1630,11 +1555,11 @@ export class InteractiveShell {
|
|
|
1630
1555
|
display.showSystemMessage(lines.join('\n'));
|
|
1631
1556
|
}
|
|
1632
1557
|
showAlphaZeroMetrics() {
|
|
1633
|
-
const summary = this.
|
|
1558
|
+
const summary = this.sessionMetrics.getPerformanceSummary();
|
|
1634
1559
|
display.showSystemMessage(summary);
|
|
1635
1560
|
}
|
|
1636
1561
|
showImprovementSuggestions() {
|
|
1637
|
-
const suggestions = this.
|
|
1562
|
+
const suggestions = this.sessionMetrics.getImprovementSuggestions();
|
|
1638
1563
|
if (suggestions.length === 0) {
|
|
1639
1564
|
display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
|
|
1640
1565
|
return;
|
|
@@ -1680,9 +1605,7 @@ export class InteractiveShell {
|
|
|
1680
1605
|
}
|
|
1681
1606
|
}
|
|
1682
1607
|
lines.push(theme.secondary('CLI Flags:'));
|
|
1683
|
-
lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
|
|
1684
1608
|
lines.push(' --coding Enable enhanced coding tools');
|
|
1685
|
-
lines.push(' --security Enable security research tools');
|
|
1686
1609
|
lines.push(' --all-plugins Enable all optional plugins');
|
|
1687
1610
|
display.showSystemMessage(lines.join('\n'));
|
|
1688
1611
|
}
|
|
@@ -1731,7 +1654,6 @@ export class InteractiveShell {
|
|
|
1731
1654
|
model: this.sessionState.model,
|
|
1732
1655
|
workspaceRoot: this.workingDir,
|
|
1733
1656
|
messages: history,
|
|
1734
|
-
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1735
1657
|
});
|
|
1736
1658
|
this.cachedHistory = history;
|
|
1737
1659
|
this.updateActiveSession(summary, true);
|
|
@@ -1910,7 +1832,6 @@ export class InteractiveShell {
|
|
|
1910
1832
|
workspaceRoot: this.workingDir,
|
|
1911
1833
|
title: this.activeSessionTitle,
|
|
1912
1834
|
messages: this.cachedHistory,
|
|
1913
|
-
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1914
1835
|
});
|
|
1915
1836
|
}
|
|
1916
1837
|
describeWorkspaceOptions() {
|
|
@@ -1928,75 +1849,6 @@ export class InteractiveShell {
|
|
|
1928
1849
|
}
|
|
1929
1850
|
return `${warning.label}: ${warning.reason}.`;
|
|
1930
1851
|
}
|
|
1931
|
-
buildLaunchCommandPalette() {
|
|
1932
|
-
const entries = [];
|
|
1933
|
-
const secretsSummary = this.summarizeSecretsForPalette();
|
|
1934
|
-
const toolSummary = this.getToolSelectionSummary();
|
|
1935
|
-
const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
|
|
1936
|
-
for (const command of this.slashCommands) {
|
|
1937
|
-
const entry = {
|
|
1938
|
-
command: command.command,
|
|
1939
|
-
description: command.description,
|
|
1940
|
-
category: command.category ?? 'other',
|
|
1941
|
-
};
|
|
1942
|
-
switch (command.command) {
|
|
1943
|
-
case '/secrets':
|
|
1944
|
-
if (secretsSummary.text) {
|
|
1945
|
-
entry.description = `${command.description} (${secretsSummary.text})`;
|
|
1946
|
-
entry.tone = secretsSummary.tone;
|
|
1947
|
-
}
|
|
1948
|
-
break;
|
|
1949
|
-
case '/tools':
|
|
1950
|
-
if (toolSummary) {
|
|
1951
|
-
entry.description = `${command.description} (${toolSummary})`;
|
|
1952
|
-
}
|
|
1953
|
-
break;
|
|
1954
|
-
case '/sessions':
|
|
1955
|
-
entry.description = `${command.description} (autosave ${autosaveLabel})`;
|
|
1956
|
-
break;
|
|
1957
|
-
case '/model':
|
|
1958
|
-
entry.description = `${command.description} (current: ${this.sessionState.model})`;
|
|
1959
|
-
break;
|
|
1960
|
-
case '/provider':
|
|
1961
|
-
entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
|
|
1962
|
-
break;
|
|
1963
|
-
default:
|
|
1964
|
-
break;
|
|
1965
|
-
}
|
|
1966
|
-
entries.push(entry);
|
|
1967
|
-
}
|
|
1968
|
-
return entries;
|
|
1969
|
-
}
|
|
1970
|
-
summarizeSecretsForPalette() {
|
|
1971
|
-
const definitions = listSecretDefinitions();
|
|
1972
|
-
if (!definitions.length) {
|
|
1973
|
-
return { text: null };
|
|
1974
|
-
}
|
|
1975
|
-
const missing = definitions.filter((definition) => !getSecretValue(definition.id));
|
|
1976
|
-
if (missing.length === 0) {
|
|
1977
|
-
return { text: 'all configured', tone: 'success' };
|
|
1978
|
-
}
|
|
1979
|
-
const labels = missing.map((definition) => definition.label ?? definition.id);
|
|
1980
|
-
return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
|
|
1981
|
-
}
|
|
1982
|
-
getToolSelectionSummary() {
|
|
1983
|
-
const toolSettings = loadToolSettings();
|
|
1984
|
-
const selection = buildEnabledToolSet(toolSettings);
|
|
1985
|
-
const options = getToolToggleOptions();
|
|
1986
|
-
if (!options.length) {
|
|
1987
|
-
return null;
|
|
1988
|
-
}
|
|
1989
|
-
const enabledCount = options.filter((option) => selection.has(option.id)).length;
|
|
1990
|
-
return `${enabledCount}/${options.length} enabled`;
|
|
1991
|
-
}
|
|
1992
|
-
formatList(values, maxItems = 3) {
|
|
1993
|
-
if (!values.length) {
|
|
1994
|
-
return '';
|
|
1995
|
-
}
|
|
1996
|
-
const shown = values.slice(0, maxItems);
|
|
1997
|
-
const suffix = values.length > maxItems ? ', …' : '';
|
|
1998
|
-
return `${shown.join(', ')}${suffix}`;
|
|
1999
|
-
}
|
|
2000
1852
|
buildSlashCommandList(header) {
|
|
2001
1853
|
const lines = [theme.gradient.primary(header), ''];
|
|
2002
1854
|
for (const command of this.slashCommands) {
|
|
@@ -2465,7 +2317,7 @@ export class InteractiveShell {
|
|
|
2465
2317
|
this.autosaveIfEnabled();
|
|
2466
2318
|
// Track metrics with Alpha Zero 2
|
|
2467
2319
|
const elapsedMs = Date.now() - requestStartTime;
|
|
2468
|
-
this.
|
|
2320
|
+
this.sessionMetrics.recordMessage(elapsedMs);
|
|
2469
2321
|
if (!responseText?.trim()) {
|
|
2470
2322
|
display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
|
|
2471
2323
|
}
|
|
@@ -2483,10 +2335,14 @@ export class InteractiveShell {
|
|
|
2483
2335
|
this.stopStreamingHeartbeat();
|
|
2484
2336
|
this.isProcessing = false;
|
|
2485
2337
|
this.terminalInput.setStreaming(false);
|
|
2338
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2486
2339
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2487
2340
|
this.setIdleStatus();
|
|
2488
2341
|
display.newLine();
|
|
2489
2342
|
this.updateStatusMessage(null);
|
|
2343
|
+
// Claude Code style: Show unified status bar before prompt
|
|
2344
|
+
// This creates consistent UI between startup and post-streaming
|
|
2345
|
+
this.showUnifiedStatusBar();
|
|
2490
2346
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
2491
2347
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
2492
2348
|
// Claude Code style: New prompt naturally appears at bottom
|
|
@@ -2563,14 +2419,13 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
2563
2419
|
try {
|
|
2564
2420
|
// Send the request and capture the response (streaming disabled)
|
|
2565
2421
|
display.showThinking('Responding...');
|
|
2566
|
-
this.refreshStatusLine(true);
|
|
2567
2422
|
const response = await agent.send(currentPrompt, true);
|
|
2568
2423
|
await this.awaitPendingCleanup();
|
|
2569
2424
|
this.captureHistorySnapshot();
|
|
2570
2425
|
this.autosaveIfEnabled();
|
|
2571
2426
|
// Track metrics
|
|
2572
2427
|
const elapsedMs = Date.now() - overallStartTime;
|
|
2573
|
-
this.
|
|
2428
|
+
this.sessionMetrics.recordMessage(elapsedMs);
|
|
2574
2429
|
if (!response?.trim()) {
|
|
2575
2430
|
display.showWarning('Model returned an empty response. Retrying this iteration...');
|
|
2576
2431
|
consecutiveNoProgress++;
|
|
@@ -2707,6 +2562,7 @@ What's the next action?`;
|
|
|
2707
2562
|
this.stopStreamingHeartbeat();
|
|
2708
2563
|
this.isProcessing = false;
|
|
2709
2564
|
this.terminalInput.setStreaming(false);
|
|
2565
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2710
2566
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2711
2567
|
this.setIdleStatus();
|
|
2712
2568
|
this.updateStatusMessage(null);
|
|
@@ -3063,10 +2919,8 @@ What's the next action?`;
|
|
|
3063
2919
|
try {
|
|
3064
2920
|
// Send the error to the agent for fixing
|
|
3065
2921
|
display.showThinking('Analyzing build errors');
|
|
3066
|
-
this.refreshStatusLine(true);
|
|
3067
2922
|
const response = await this.agent.send(prompt, true);
|
|
3068
2923
|
display.stopThinking();
|
|
3069
|
-
this.refreshStatusLine(true);
|
|
3070
2924
|
if (response) {
|
|
3071
2925
|
display.showAssistantMessage(response, { isFinal: true });
|
|
3072
2926
|
}
|
|
@@ -3093,8 +2947,8 @@ What's the next action?`;
|
|
|
3093
2947
|
};
|
|
3094
2948
|
this.agent = this.runtimeSession.createAgent(selection, {
|
|
3095
2949
|
onStreamChunk: (chunk) => {
|
|
3096
|
-
// Stream output
|
|
3097
|
-
|
|
2950
|
+
// Stream output directly - no spinner during streaming to avoid race conditions
|
|
2951
|
+
display.stream(chunk);
|
|
3098
2952
|
},
|
|
3099
2953
|
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
3100
2954
|
onAssistantMessage: (content, metadata) => {
|
|
@@ -3116,16 +2970,18 @@ What's the next action?`;
|
|
|
3116
2970
|
display.showAssistantMessage(finalContent, enriched);
|
|
3117
2971
|
}
|
|
3118
2972
|
}
|
|
3119
|
-
//
|
|
2973
|
+
// Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
|
|
3120
2974
|
display.stopThinking();
|
|
3121
|
-
//
|
|
2975
|
+
// Calculate context usage
|
|
2976
|
+
let contextInfo;
|
|
3122
2977
|
if (enriched.contextWindowTokens && metadata.usage) {
|
|
3123
2978
|
const total = this.totalTokens(metadata.usage);
|
|
3124
2979
|
if (total && total > 0) {
|
|
3125
2980
|
const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
|
|
3126
|
-
|
|
2981
|
+
contextInfo = { percentage, tokens: total };
|
|
3127
2982
|
}
|
|
3128
2983
|
}
|
|
2984
|
+
display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
|
|
3129
2985
|
// Auto-verify changes: build first (catches type errors), then tests
|
|
3130
2986
|
void this.enforceAutoBuild('final-response');
|
|
3131
2987
|
void this.enforceAutoTests('final-response');
|
|
@@ -3195,6 +3051,7 @@ What's the next action?`;
|
|
|
3195
3051
|
this.stopStreamingHeartbeat();
|
|
3196
3052
|
this.updateStatusMessage(null);
|
|
3197
3053
|
this.terminalInput.setStreaming(false);
|
|
3054
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3198
3055
|
this.terminalInput.render();
|
|
3199
3056
|
},
|
|
3200
3057
|
onVerificationNeeded: () => {
|
|
@@ -3231,6 +3088,7 @@ What's the next action?`;
|
|
|
3231
3088
|
resetChatBoxAfterModelSwap() {
|
|
3232
3089
|
this.updateStatusMessage(null);
|
|
3233
3090
|
this.terminalInput.setStreaming(false);
|
|
3091
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3234
3092
|
this.terminalInput.render();
|
|
3235
3093
|
this.ensureReadlineReady();
|
|
3236
3094
|
}
|
|
@@ -3295,14 +3153,9 @@ What's the next action?`;
|
|
|
3295
3153
|
return null;
|
|
3296
3154
|
}
|
|
3297
3155
|
const usageRatio = total / windowTokens;
|
|
3298
|
-
this.latestTokenUsage = {
|
|
3299
|
-
used: total,
|
|
3300
|
-
limit: windowTokens,
|
|
3301
|
-
};
|
|
3302
3156
|
// Always update context usage in the UI
|
|
3303
3157
|
const percentUsed = Math.round(usageRatio * 100);
|
|
3304
3158
|
this.updateContextUsage(percentUsed);
|
|
3305
|
-
this.refreshStatusLine(true);
|
|
3306
3159
|
if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
|
|
3307
3160
|
return null;
|
|
3308
3161
|
}
|
|
@@ -3569,113 +3422,6 @@ What's the next action?`;
|
|
|
3569
3422
|
this.sessionState.reasoningEffort = preset.reasoningEffort;
|
|
3570
3423
|
}
|
|
3571
3424
|
}
|
|
3572
|
-
/**
|
|
3573
|
-
* Build the session banner with comprehensive feature status.
|
|
3574
|
-
*/
|
|
3575
|
-
buildBanner() {
|
|
3576
|
-
const terminalWidth = output.columns ?? 100;
|
|
3577
|
-
const width = Math.min(terminalWidth - 4, 110);
|
|
3578
|
-
// Collect tool categories for display
|
|
3579
|
-
const toolCategories = this.collectToolCategories();
|
|
3580
|
-
return renderSessionFrame({
|
|
3581
|
-
profileLabel: this.profileLabel,
|
|
3582
|
-
profileName: this.profile,
|
|
3583
|
-
model: this.sessionState.model,
|
|
3584
|
-
provider: this.sessionState.provider,
|
|
3585
|
-
workspace: this.workingDir,
|
|
3586
|
-
version: this.version,
|
|
3587
|
-
width,
|
|
3588
|
-
features: {
|
|
3589
|
-
verification: this.verificationEnabled,
|
|
3590
|
-
autoContinue: this.autoContinueEnabled,
|
|
3591
|
-
thinkingMode: this.thinkingMode,
|
|
3592
|
-
plugins: this._enabledPlugins,
|
|
3593
|
-
tools: toolCategories,
|
|
3594
|
-
sessionId: this.activeSessionId ?? undefined,
|
|
3595
|
-
},
|
|
3596
|
-
});
|
|
3597
|
-
}
|
|
3598
|
-
/**
|
|
3599
|
-
* Collect tool categories for banner display.
|
|
3600
|
-
*/
|
|
3601
|
-
collectToolCategories() {
|
|
3602
|
-
const categories = [];
|
|
3603
|
-
try {
|
|
3604
|
-
const providerTools = this.runtimeSession.toolRuntime.listProviderTools();
|
|
3605
|
-
if (providerTools.length > 0) {
|
|
3606
|
-
// Group by category (first word of tool name or namespace)
|
|
3607
|
-
const groups = new Map();
|
|
3608
|
-
for (const tool of providerTools) {
|
|
3609
|
-
const category = this.extractToolCategory(tool.name);
|
|
3610
|
-
groups.set(category, (groups.get(category) || 0) + 1);
|
|
3611
|
-
}
|
|
3612
|
-
// Convert to array sorted by count
|
|
3613
|
-
const sorted = Array.from(groups.entries())
|
|
3614
|
-
.sort((a, b) => b[1] - a[1])
|
|
3615
|
-
.slice(0, 5); // Top 5 categories
|
|
3616
|
-
for (const [name, count] of sorted) {
|
|
3617
|
-
categories.push({ name, count, icon: this.getToolCategoryIcon(name) });
|
|
3618
|
-
}
|
|
3619
|
-
}
|
|
3620
|
-
}
|
|
3621
|
-
catch {
|
|
3622
|
-
// Ignore errors in tool collection
|
|
3623
|
-
}
|
|
3624
|
-
return categories;
|
|
3625
|
-
}
|
|
3626
|
-
/**
|
|
3627
|
-
* Extract category from tool name.
|
|
3628
|
-
*/
|
|
3629
|
-
extractToolCategory(toolName) {
|
|
3630
|
-
// Common tool prefixes
|
|
3631
|
-
const prefixMap = {
|
|
3632
|
-
git: 'Git',
|
|
3633
|
-
npm: 'NPM',
|
|
3634
|
-
bash: 'Shell',
|
|
3635
|
-
file: 'Files',
|
|
3636
|
-
read: 'Files',
|
|
3637
|
-
write: 'Files',
|
|
3638
|
-
edit: 'Files',
|
|
3639
|
-
search: 'Search',
|
|
3640
|
-
glob: 'Search',
|
|
3641
|
-
grep: 'Search',
|
|
3642
|
-
web: 'Web',
|
|
3643
|
-
fetch: 'Web',
|
|
3644
|
-
test: 'Testing',
|
|
3645
|
-
build: 'Build',
|
|
3646
|
-
deploy: 'Deploy',
|
|
3647
|
-
cloud: 'Cloud',
|
|
3648
|
-
browser: 'Browser',
|
|
3649
|
-
};
|
|
3650
|
-
const lower = toolName.toLowerCase();
|
|
3651
|
-
for (const [prefix, category] of Object.entries(prefixMap)) {
|
|
3652
|
-
if (lower.startsWith(prefix)) {
|
|
3653
|
-
return category;
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
// Default to first word capitalized
|
|
3657
|
-
const firstWord = toolName.split(/[_\-\s]/)[0] || 'Other';
|
|
3658
|
-
return firstWord.charAt(0).toUpperCase() + firstWord.slice(1).toLowerCase();
|
|
3659
|
-
}
|
|
3660
|
-
/**
|
|
3661
|
-
* Get icon for tool category.
|
|
3662
|
-
*/
|
|
3663
|
-
getToolCategoryIcon(category) {
|
|
3664
|
-
const icons = {
|
|
3665
|
-
Git: '⎇',
|
|
3666
|
-
NPM: '📦',
|
|
3667
|
-
Shell: '⌘',
|
|
3668
|
-
Files: '📁',
|
|
3669
|
-
Search: '🔍',
|
|
3670
|
-
Web: '🌐',
|
|
3671
|
-
Testing: '🧪',
|
|
3672
|
-
Build: '🔧',
|
|
3673
|
-
Deploy: '🚀',
|
|
3674
|
-
Cloud: '☁',
|
|
3675
|
-
Browser: '🌐',
|
|
3676
|
-
};
|
|
3677
|
-
return icons[category] || '⚙';
|
|
3678
|
-
}
|
|
3679
3425
|
refreshBannerSessionInfo() {
|
|
3680
3426
|
const nextState = {
|
|
3681
3427
|
model: this.sessionState.model,
|
|
@@ -3686,11 +3432,13 @@ What's the next action?`;
|
|
|
3686
3432
|
return;
|
|
3687
3433
|
}
|
|
3688
3434
|
this.refreshContextGauge();
|
|
3689
|
-
|
|
3690
|
-
//
|
|
3435
|
+
display.updateSessionInfo(nextState.model, nextState.provider);
|
|
3436
|
+
// Update the persistent model info display in terminal input
|
|
3437
|
+
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
3691
3438
|
if (!this.isProcessing) {
|
|
3692
3439
|
this.setIdleStatus();
|
|
3693
3440
|
}
|
|
3441
|
+
// Pinned header rows are disabled; scroll region handles all output.
|
|
3694
3442
|
this.bannerSessionState = nextState;
|
|
3695
3443
|
}
|
|
3696
3444
|
providerLabel(id) {
|