erosolar-cli 1.7.354 → 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 -417
- 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 +125 -250
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +612 -1071
- 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 -139
- 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 +49 -200
- package/dist/subagents/taskRunner.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,8 +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
|
-
this.alternateScreenEnabled = config.alternateScreen ?? false;
|
|
154
145
|
this.initializeSessionHistory();
|
|
155
146
|
this.sessionState = {
|
|
156
147
|
provider: config.initialModel.provider,
|
|
@@ -171,7 +162,6 @@ export class InteractiveShell {
|
|
|
171
162
|
this.slashCommands.push({
|
|
172
163
|
command: '/agents',
|
|
173
164
|
description: 'Select the default agent profile (applies on next launch)',
|
|
174
|
-
category: 'configuration',
|
|
175
165
|
});
|
|
176
166
|
}
|
|
177
167
|
this.customCommands = loadCustomSlashCommands();
|
|
@@ -180,21 +170,18 @@ export class InteractiveShell {
|
|
|
180
170
|
this.slashCommands.push({
|
|
181
171
|
command: custom.command,
|
|
182
172
|
description: `${custom.description} (custom)`,
|
|
183
|
-
category: custom.category ?? 'other',
|
|
184
173
|
});
|
|
185
174
|
}
|
|
186
175
|
if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
|
|
187
176
|
this.slashCommands.push({
|
|
188
177
|
command: '/exit',
|
|
189
178
|
description: 'Quit the CLI immediately',
|
|
190
|
-
category: 'other',
|
|
191
179
|
});
|
|
192
180
|
}
|
|
193
181
|
// Add /plugins command
|
|
194
182
|
this.slashCommands.push({
|
|
195
183
|
command: '/plugins',
|
|
196
184
|
description: 'Show available and loaded plugins',
|
|
197
|
-
category: 'configuration',
|
|
198
185
|
});
|
|
199
186
|
this.statusTracker = config.statusTracker;
|
|
200
187
|
this.ui = config.ui;
|
|
@@ -226,28 +213,20 @@ export class InteractiveShell {
|
|
|
226
213
|
onEditModeChange: (mode) => this.handleEditModeChange(mode),
|
|
227
214
|
onToggleVerify: () => this.toggleVerificationMode(),
|
|
228
215
|
onToggleAutoContinue: () => this.toggleAutoContinueMode(),
|
|
229
|
-
onToggleThinking: () => this.cycleThinkingMode(),
|
|
230
|
-
onClearContext: () => this.handleClearContext(),
|
|
231
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();
|
|
232
224
|
// Initialize Alpha Zero 2 metrics tracking
|
|
233
|
-
this.
|
|
225
|
+
this.sessionMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
234
226
|
this.setupStatusTracking();
|
|
235
227
|
this.refreshContextGauge();
|
|
236
|
-
// Start terminal input (sets up handlers)
|
|
237
228
|
this.terminalInput.start();
|
|
238
|
-
// Enter alternate screen buffer when enabled, otherwise clear the main screen for layout
|
|
239
|
-
if (this.alternateScreenEnabled) {
|
|
240
|
-
this.terminalInput.enterAlternateScreen();
|
|
241
|
-
}
|
|
242
|
-
else if (output.isTTY) {
|
|
243
|
-
this.terminalInput.clearScreen();
|
|
244
|
-
}
|
|
245
|
-
// Stream banner first - this sets up scroll region dynamically
|
|
246
|
-
const banner = this.buildBanner();
|
|
247
|
-
this.terminalInput.streamContent(banner + '\n\n');
|
|
248
|
-
// Render chat box after banner is streamed
|
|
249
229
|
this.refreshControlBar();
|
|
250
|
-
this.terminalInput.forceRender();
|
|
251
230
|
this.rebuildAgent();
|
|
252
231
|
this.setupHandlers();
|
|
253
232
|
this.refreshBannerSessionInfo();
|
|
@@ -267,10 +246,6 @@ export class InteractiveShell {
|
|
|
267
246
|
this.activeSessionId = stored.id;
|
|
268
247
|
this.activeSessionTitle = stored.title;
|
|
269
248
|
this.sessionResumeNotice = `Resumed session "${stored.title}".`;
|
|
270
|
-
// Restore scrollback buffer if available
|
|
271
|
-
if (stored.scrollbackBuffer && Array.isArray(stored.scrollbackBuffer)) {
|
|
272
|
-
this.terminalInput.loadScrollbackBuffer(stored.scrollbackBuffer);
|
|
273
|
-
}
|
|
274
249
|
return;
|
|
275
250
|
}
|
|
276
251
|
display.showWarning(`Session "${this.sessionRestoreConfig.sessionId}" not found. Starting fresh session.`);
|
|
@@ -284,10 +259,6 @@ export class InteractiveShell {
|
|
|
284
259
|
this.activeSessionId = null;
|
|
285
260
|
this.activeSessionTitle = autosave.title;
|
|
286
261
|
this.sessionResumeNotice = 'Restored last autosaved session.';
|
|
287
|
-
// Restore scrollback buffer if available
|
|
288
|
-
if (autosave.scrollbackBuffer && Array.isArray(autosave.scrollbackBuffer)) {
|
|
289
|
-
this.terminalInput.loadScrollbackBuffer(autosave.scrollbackBuffer);
|
|
290
|
-
}
|
|
291
262
|
return;
|
|
292
263
|
}
|
|
293
264
|
display.showWarning('No autosaved session found. Starting fresh session.');
|
|
@@ -302,24 +273,14 @@ export class InteractiveShell {
|
|
|
302
273
|
this.sessionResumeNotice = null;
|
|
303
274
|
}
|
|
304
275
|
async start(initialPrompt) {
|
|
305
|
-
// Check for updates in background (non-blocking)
|
|
306
|
-
if (this.version) {
|
|
307
|
-
void maybeOfferCliUpdate(this.version);
|
|
308
|
-
}
|
|
309
276
|
if (initialPrompt) {
|
|
310
277
|
this.logUserPrompt(initialPrompt);
|
|
311
278
|
await this.processInputBlock(initialPrompt);
|
|
312
279
|
return;
|
|
313
280
|
}
|
|
314
|
-
this.showLaunchCommandPalette();
|
|
315
281
|
// Ensure the terminal input is visible
|
|
316
282
|
this.terminalInput.render();
|
|
317
283
|
}
|
|
318
|
-
showLaunchCommandPalette() {
|
|
319
|
-
// Disabled: Quick commands palette takes up too much space
|
|
320
|
-
// Users can type /help to see available commands
|
|
321
|
-
this.launchPaletteShown = true;
|
|
322
|
-
}
|
|
323
284
|
/**
|
|
324
285
|
* TerminalInputAdapter submit handler
|
|
325
286
|
*/
|
|
@@ -333,8 +294,9 @@ export class InteractiveShell {
|
|
|
333
294
|
this.handleInputChange('');
|
|
334
295
|
return;
|
|
335
296
|
}
|
|
336
|
-
//
|
|
337
|
-
//
|
|
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);
|
|
338
300
|
this.logUserPrompt(approved);
|
|
339
301
|
void this.processInputBlock(approved).catch((err) => {
|
|
340
302
|
display.showError(err instanceof Error ? err.message : String(err), err);
|
|
@@ -424,59 +386,6 @@ export class InteractiveShell {
|
|
|
424
386
|
: 'The model will not be auto-prompted to continue.') +
|
|
425
387
|
' Toggle with alt+c.');
|
|
426
388
|
}
|
|
427
|
-
/**
|
|
428
|
-
* Cycle through thinking modes (Alt+T keyboard shortcut).
|
|
429
|
-
*/
|
|
430
|
-
cycleThinkingMode() {
|
|
431
|
-
const modes = ['concise', 'balanced', 'extended'];
|
|
432
|
-
const currentIndex = modes.indexOf(this.thinkingMode);
|
|
433
|
-
const nextIndex = (currentIndex + 1) % modes.length;
|
|
434
|
-
const nextMode = modes[nextIndex];
|
|
435
|
-
this.thinkingMode = nextMode;
|
|
436
|
-
saveSessionPreferences({ thinkingMode: this.thinkingMode });
|
|
437
|
-
this.refreshControlBar();
|
|
438
|
-
const descriptions = {
|
|
439
|
-
concise: 'Minimal reasoning, faster responses',
|
|
440
|
-
balanced: 'Default reasoning depth',
|
|
441
|
-
extended: 'Deep reasoning, thorough analysis',
|
|
442
|
-
};
|
|
443
|
-
display.showInfo(`Thinking mode: ${theme.info(nextMode)} - ${descriptions[nextMode]}. (Alt+T to cycle)`);
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* Handle context clear/compact request (Alt+X keyboard shortcut).
|
|
447
|
-
*/
|
|
448
|
-
handleClearContext() {
|
|
449
|
-
if (this.isProcessing) {
|
|
450
|
-
display.showWarning('Cannot clear context while processing. Wait for completion or press Ctrl+C.');
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
// Trigger context compaction
|
|
454
|
-
display.showInfo('Compacting context... This will summarize the conversation and free up space.');
|
|
455
|
-
void this.performContextCompaction();
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* Perform context compaction by summarizing conversation history.
|
|
459
|
-
*/
|
|
460
|
-
async performContextCompaction() {
|
|
461
|
-
try {
|
|
462
|
-
// For now, just clear the history and show a message
|
|
463
|
-
// A full implementation would summarize the conversation
|
|
464
|
-
const oldLength = this.cachedHistory.length;
|
|
465
|
-
if (oldLength === 0) {
|
|
466
|
-
display.showInfo('Context is already empty.');
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
// Keep the last few messages for continuity
|
|
470
|
-
const keepCount = Math.min(4, oldLength);
|
|
471
|
-
this.cachedHistory = this.cachedHistory.slice(-keepCount);
|
|
472
|
-
display.showSuccess(`Context compacted: ${oldLength} messages reduced to ${keepCount}. ` +
|
|
473
|
-
`Context usage reset. Continue your conversation.`);
|
|
474
|
-
this.refreshControlBar();
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
display.showError('Failed to compact context', error);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
389
|
/**
|
|
481
390
|
* Gate submissions when edit permission mode is active.
|
|
482
391
|
* Returns the text to send when approved, or null when waiting for confirmation.
|
|
@@ -576,10 +485,6 @@ export class InteractiveShell {
|
|
|
576
485
|
return;
|
|
577
486
|
}
|
|
578
487
|
this.shuttingDown = true;
|
|
579
|
-
const shouldRestoreScrollback = this.alternateScreenEnabled && this.terminalInput.isAlternateScreenActive();
|
|
580
|
-
const scrollbackSnapshot = shouldRestoreScrollback
|
|
581
|
-
? this.terminalInput.getScrollbackSnapshot()
|
|
582
|
-
: null;
|
|
583
488
|
// Stop any active spinner to prevent process hang
|
|
584
489
|
display.stopThinking(false);
|
|
585
490
|
this.stopStreamingHeartbeat();
|
|
@@ -588,34 +493,18 @@ export class InteractiveShell {
|
|
|
588
493
|
this.teardownStatusTracking();
|
|
589
494
|
// Clear any pending cleanup to prevent hanging
|
|
590
495
|
this.pendingCleanup = null;
|
|
591
|
-
// Reset terminal state before disposing adapters
|
|
592
|
-
this.terminalInput.exitStreamingScrollRegion();
|
|
593
|
-
if (this.alternateScreenEnabled) {
|
|
594
|
-
this.terminalInput.exitAlternateScreen();
|
|
595
|
-
}
|
|
596
496
|
// Dispose terminal input handler
|
|
597
497
|
this.terminalInput.dispose();
|
|
598
498
|
// Dispose unified UI adapter
|
|
599
499
|
this.uiAdapter.dispose();
|
|
600
|
-
if (scrollbackSnapshot && scrollbackSnapshot.length > 0) {
|
|
601
|
-
this.restoreScrollbackSnapshot(scrollbackSnapshot);
|
|
602
|
-
}
|
|
603
500
|
display.newLine();
|
|
604
|
-
|
|
605
|
-
console.log(theme.
|
|
606
|
-
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)));
|
|
607
506
|
exit(0);
|
|
608
507
|
}
|
|
609
|
-
restoreScrollbackSnapshot(lines) {
|
|
610
|
-
if (!lines.length) {
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
const transcript = lines.join('\n');
|
|
614
|
-
const separator = theme.ui.muted('─'.repeat(44));
|
|
615
|
-
const header = theme.ui.muted('Restored scrollback from this session:');
|
|
616
|
-
// Write directly to stdout after exiting alternate screen to preserve the transcript
|
|
617
|
-
process.stdout.write(`\n${separator}\n${header}\n${transcript}\n${separator}\n`);
|
|
618
|
-
}
|
|
619
508
|
/**
|
|
620
509
|
* Update status bar message
|
|
621
510
|
*/
|
|
@@ -783,14 +672,13 @@ export class InteractiveShell {
|
|
|
783
672
|
});
|
|
784
673
|
}
|
|
785
674
|
setProcessingStatus(detail) {
|
|
786
|
-
this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
|
|
787
675
|
this.statusTracker.setBase('Working on your request', {
|
|
788
676
|
detail: this.describeStatusDetail(detail),
|
|
789
677
|
tone: 'info',
|
|
790
678
|
});
|
|
791
679
|
}
|
|
792
680
|
describeStatusDetail(detail) {
|
|
793
|
-
const parts = detail?.trim()
|
|
681
|
+
const parts = [detail?.trim() || this.describeModelDetail()];
|
|
794
682
|
const queued = this.followUpQueue.length;
|
|
795
683
|
if (queued > 0) {
|
|
796
684
|
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
|
|
@@ -803,18 +691,12 @@ export class InteractiveShell {
|
|
|
803
691
|
}
|
|
804
692
|
refreshContextGauge() {
|
|
805
693
|
const tokens = getContextWindowTokens(this.sessionState.model);
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (normalizedTokens !== null) {
|
|
809
|
-
this.latestTokenUsage = {
|
|
810
|
-
used: this.latestTokenUsage.used,
|
|
811
|
-
limit: normalizedTokens,
|
|
812
|
-
};
|
|
813
|
-
}
|
|
694
|
+
this.activeContextWindowTokens =
|
|
695
|
+
typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
814
696
|
}
|
|
815
697
|
updateContextUsage(percentage) {
|
|
816
698
|
this.uiAdapter.updateContextUsage(percentage);
|
|
817
|
-
this.terminalInput.setContextUsage(percentage
|
|
699
|
+
this.terminalInput.setContextUsage(percentage);
|
|
818
700
|
}
|
|
819
701
|
refreshControlBar() {
|
|
820
702
|
this.terminalInput.setModeToggles({
|
|
@@ -822,9 +704,9 @@ export class InteractiveShell {
|
|
|
822
704
|
autoContinueEnabled: this.autoContinueEnabled,
|
|
823
705
|
verificationHotkey: 'alt+v',
|
|
824
706
|
autoContinueHotkey: 'alt+c',
|
|
825
|
-
thinkingModeLabel: this.thinkingMode,
|
|
826
|
-
thinkingHotkey: '/thinking',
|
|
827
707
|
});
|
|
708
|
+
// Update persistent model info display
|
|
709
|
+
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
828
710
|
this.refreshStatusLine();
|
|
829
711
|
this.terminalInput.render();
|
|
830
712
|
}
|
|
@@ -855,25 +737,6 @@ export class InteractiveShell {
|
|
|
855
737
|
// Set main status (tool execution, etc.) - shown when not overridden
|
|
856
738
|
const statusText = this.formatStatusLine(this.statusLineState);
|
|
857
739
|
this.terminalInput.setStatusMessage(statusText);
|
|
858
|
-
// Surface meta header (elapsed + context usage) above the divider
|
|
859
|
-
const elapsedSeconds = this.statusLineState
|
|
860
|
-
? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
|
|
861
|
-
: null;
|
|
862
|
-
const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
|
|
863
|
-
const tokensUsed = this.latestTokenUsage.used;
|
|
864
|
-
const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
|
|
865
|
-
this.terminalInput.setMetaStatus({
|
|
866
|
-
elapsedSeconds,
|
|
867
|
-
tokensUsed,
|
|
868
|
-
tokenLimit,
|
|
869
|
-
thinkingMs,
|
|
870
|
-
thinkingHasContent: display.isSpinnerActive(),
|
|
871
|
-
});
|
|
872
|
-
// Keep model/provider visible in the controls bar
|
|
873
|
-
this.terminalInput.setModelContext({
|
|
874
|
-
model: this.sessionState.model,
|
|
875
|
-
provider: this.providerLabel(this.sessionState.provider),
|
|
876
|
-
});
|
|
877
740
|
if (forceRender) {
|
|
878
741
|
this.terminalInput.render();
|
|
879
742
|
}
|
|
@@ -933,14 +796,15 @@ export class InteractiveShell {
|
|
|
933
796
|
this.terminalInput.render();
|
|
934
797
|
}
|
|
935
798
|
/**
|
|
936
|
-
* 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.
|
|
937
801
|
*/
|
|
938
802
|
logUserPrompt(text) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
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());
|
|
944
808
|
}
|
|
945
809
|
requestPromptRefresh(force = false) {
|
|
946
810
|
if (force) {
|
|
@@ -965,40 +829,16 @@ export class InteractiveShell {
|
|
|
965
829
|
this.stopStreamingHeartbeat();
|
|
966
830
|
// Enter global streaming mode - blocks all non-streaming UI output
|
|
967
831
|
enterStreamingMode();
|
|
968
|
-
// Set up scroll region for streaming content
|
|
969
|
-
this.terminalInput.enterStreamingScrollRegion();
|
|
970
832
|
this.uiUpdates.setMode('streaming');
|
|
971
833
|
this.streamingHeartbeatStart = Date.now();
|
|
972
834
|
this.streamingHeartbeatFrame = 0;
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
this.refreshStatusLine(true);
|
|
977
|
-
// Periodically refresh the pinned input/status region while streaming so
|
|
978
|
-
// elapsed time remains visible without interrupting the scroll region.
|
|
979
|
-
this.uiUpdates.startHeartbeat('streaming', {
|
|
980
|
-
intervalMs: 1000,
|
|
981
|
-
lane: 'heartbeat',
|
|
982
|
-
mode: ['streaming', 'processing'],
|
|
983
|
-
coalesceKey: 'streaming:heartbeat',
|
|
984
|
-
run: () => {
|
|
985
|
-
const elapsedSeconds = this.streamingHeartbeatStart
|
|
986
|
-
? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
|
|
987
|
-
: 0;
|
|
988
|
-
this.streamingHeartbeatFrame =
|
|
989
|
-
(this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
|
|
990
|
-
const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
991
|
-
this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
|
|
992
|
-
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
993
|
-
this.refreshStatusLine(true);
|
|
994
|
-
},
|
|
995
|
-
});
|
|
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.
|
|
996
838
|
}
|
|
997
839
|
stopStreamingHeartbeat() {
|
|
998
840
|
// Exit global streaming mode - allows UI to render again
|
|
999
841
|
exitStreamingMode();
|
|
1000
|
-
// Exit scroll region mode
|
|
1001
|
-
this.terminalInput.exitStreamingScrollRegion();
|
|
1002
842
|
this.uiUpdates.stopHeartbeat('streaming');
|
|
1003
843
|
this.streamingHeartbeatStart = null;
|
|
1004
844
|
this.streamingHeartbeatFrame = 0;
|
|
@@ -1010,28 +850,10 @@ export class InteractiveShell {
|
|
|
1010
850
|
// Force refresh to update the input area now that streaming has ended
|
|
1011
851
|
this.refreshStatusLine(true);
|
|
1012
852
|
}
|
|
1013
|
-
buildStreamingStatus(label
|
|
853
|
+
buildStreamingStatus(label) {
|
|
1014
854
|
const detail = this.describeModelDetail();
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
: null;
|
|
1018
|
-
const prefix = theme.info('⏺');
|
|
1019
|
-
const parts = [label];
|
|
1020
|
-
if (detail) {
|
|
1021
|
-
parts.push(theme.ui.muted('·'), detail);
|
|
1022
|
-
}
|
|
1023
|
-
if (elapsedLabel) {
|
|
1024
|
-
parts.push(theme.ui.muted('·'), elapsedLabel);
|
|
1025
|
-
}
|
|
1026
|
-
return `${prefix} ${parts.join(' ')}`.trim();
|
|
1027
|
-
}
|
|
1028
|
-
formatElapsedShort(seconds) {
|
|
1029
|
-
if (seconds < 60) {
|
|
1030
|
-
return `${seconds}s`;
|
|
1031
|
-
}
|
|
1032
|
-
const minutes = Math.floor(seconds / 60);
|
|
1033
|
-
const remaining = seconds % 60;
|
|
1034
|
-
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}`;
|
|
1035
857
|
}
|
|
1036
858
|
refreshQueueIndicators() {
|
|
1037
859
|
if (this.isProcessing) {
|
|
@@ -1279,6 +1101,17 @@ export class InteractiveShell {
|
|
|
1279
1101
|
case '/discover':
|
|
1280
1102
|
await this.discoverModelsCommand();
|
|
1281
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;
|
|
1282
1115
|
default:
|
|
1283
1116
|
if (!(await this.tryCustomSlashCommand(command, input))) {
|
|
1284
1117
|
display.showWarning(`Unknown command "${command}".`);
|
|
@@ -1587,6 +1420,99 @@ export class InteractiveShell {
|
|
|
1587
1420
|
// Display keyboard shortcuts help (Claude Code style)
|
|
1588
1421
|
display.showSystemMessage(formatShortcutsHelp());
|
|
1589
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
|
+
}
|
|
1590
1516
|
showFileChangeSummary() {
|
|
1591
1517
|
const summary = this._fileChangeTracker.getSummary();
|
|
1592
1518
|
const changes = this._fileChangeTracker.getAllChanges();
|
|
@@ -1629,11 +1555,11 @@ export class InteractiveShell {
|
|
|
1629
1555
|
display.showSystemMessage(lines.join('\n'));
|
|
1630
1556
|
}
|
|
1631
1557
|
showAlphaZeroMetrics() {
|
|
1632
|
-
const summary = this.
|
|
1558
|
+
const summary = this.sessionMetrics.getPerformanceSummary();
|
|
1633
1559
|
display.showSystemMessage(summary);
|
|
1634
1560
|
}
|
|
1635
1561
|
showImprovementSuggestions() {
|
|
1636
|
-
const suggestions = this.
|
|
1562
|
+
const suggestions = this.sessionMetrics.getImprovementSuggestions();
|
|
1637
1563
|
if (suggestions.length === 0) {
|
|
1638
1564
|
display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
|
|
1639
1565
|
return;
|
|
@@ -1679,9 +1605,7 @@ export class InteractiveShell {
|
|
|
1679
1605
|
}
|
|
1680
1606
|
}
|
|
1681
1607
|
lines.push(theme.secondary('CLI Flags:'));
|
|
1682
|
-
lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
|
|
1683
1608
|
lines.push(' --coding Enable enhanced coding tools');
|
|
1684
|
-
lines.push(' --security Enable security research tools');
|
|
1685
1609
|
lines.push(' --all-plugins Enable all optional plugins');
|
|
1686
1610
|
display.showSystemMessage(lines.join('\n'));
|
|
1687
1611
|
}
|
|
@@ -1730,7 +1654,6 @@ export class InteractiveShell {
|
|
|
1730
1654
|
model: this.sessionState.model,
|
|
1731
1655
|
workspaceRoot: this.workingDir,
|
|
1732
1656
|
messages: history,
|
|
1733
|
-
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1734
1657
|
});
|
|
1735
1658
|
this.cachedHistory = history;
|
|
1736
1659
|
this.updateActiveSession(summary, true);
|
|
@@ -1909,7 +1832,6 @@ export class InteractiveShell {
|
|
|
1909
1832
|
workspaceRoot: this.workingDir,
|
|
1910
1833
|
title: this.activeSessionTitle,
|
|
1911
1834
|
messages: this.cachedHistory,
|
|
1912
|
-
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1913
1835
|
});
|
|
1914
1836
|
}
|
|
1915
1837
|
describeWorkspaceOptions() {
|
|
@@ -1927,75 +1849,6 @@ export class InteractiveShell {
|
|
|
1927
1849
|
}
|
|
1928
1850
|
return `${warning.label}: ${warning.reason}.`;
|
|
1929
1851
|
}
|
|
1930
|
-
buildLaunchCommandPalette() {
|
|
1931
|
-
const entries = [];
|
|
1932
|
-
const secretsSummary = this.summarizeSecretsForPalette();
|
|
1933
|
-
const toolSummary = this.getToolSelectionSummary();
|
|
1934
|
-
const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
|
|
1935
|
-
for (const command of this.slashCommands) {
|
|
1936
|
-
const entry = {
|
|
1937
|
-
command: command.command,
|
|
1938
|
-
description: command.description,
|
|
1939
|
-
category: command.category ?? 'other',
|
|
1940
|
-
};
|
|
1941
|
-
switch (command.command) {
|
|
1942
|
-
case '/secrets':
|
|
1943
|
-
if (secretsSummary.text) {
|
|
1944
|
-
entry.description = `${command.description} (${secretsSummary.text})`;
|
|
1945
|
-
entry.tone = secretsSummary.tone;
|
|
1946
|
-
}
|
|
1947
|
-
break;
|
|
1948
|
-
case '/tools':
|
|
1949
|
-
if (toolSummary) {
|
|
1950
|
-
entry.description = `${command.description} (${toolSummary})`;
|
|
1951
|
-
}
|
|
1952
|
-
break;
|
|
1953
|
-
case '/sessions':
|
|
1954
|
-
entry.description = `${command.description} (autosave ${autosaveLabel})`;
|
|
1955
|
-
break;
|
|
1956
|
-
case '/model':
|
|
1957
|
-
entry.description = `${command.description} (current: ${this.sessionState.model})`;
|
|
1958
|
-
break;
|
|
1959
|
-
case '/provider':
|
|
1960
|
-
entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
|
|
1961
|
-
break;
|
|
1962
|
-
default:
|
|
1963
|
-
break;
|
|
1964
|
-
}
|
|
1965
|
-
entries.push(entry);
|
|
1966
|
-
}
|
|
1967
|
-
return entries;
|
|
1968
|
-
}
|
|
1969
|
-
summarizeSecretsForPalette() {
|
|
1970
|
-
const definitions = listSecretDefinitions();
|
|
1971
|
-
if (!definitions.length) {
|
|
1972
|
-
return { text: null };
|
|
1973
|
-
}
|
|
1974
|
-
const missing = definitions.filter((definition) => !getSecretValue(definition.id));
|
|
1975
|
-
if (missing.length === 0) {
|
|
1976
|
-
return { text: 'all configured', tone: 'success' };
|
|
1977
|
-
}
|
|
1978
|
-
const labels = missing.map((definition) => definition.label ?? definition.id);
|
|
1979
|
-
return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
|
|
1980
|
-
}
|
|
1981
|
-
getToolSelectionSummary() {
|
|
1982
|
-
const toolSettings = loadToolSettings();
|
|
1983
|
-
const selection = buildEnabledToolSet(toolSettings);
|
|
1984
|
-
const options = getToolToggleOptions();
|
|
1985
|
-
if (!options.length) {
|
|
1986
|
-
return null;
|
|
1987
|
-
}
|
|
1988
|
-
const enabledCount = options.filter((option) => selection.has(option.id)).length;
|
|
1989
|
-
return `${enabledCount}/${options.length} enabled`;
|
|
1990
|
-
}
|
|
1991
|
-
formatList(values, maxItems = 3) {
|
|
1992
|
-
if (!values.length) {
|
|
1993
|
-
return '';
|
|
1994
|
-
}
|
|
1995
|
-
const shown = values.slice(0, maxItems);
|
|
1996
|
-
const suffix = values.length > maxItems ? ', …' : '';
|
|
1997
|
-
return `${shown.join(', ')}${suffix}`;
|
|
1998
|
-
}
|
|
1999
1852
|
buildSlashCommandList(header) {
|
|
2000
1853
|
const lines = [theme.gradient.primary(header), ''];
|
|
2001
1854
|
for (const command of this.slashCommands) {
|
|
@@ -2464,7 +2317,7 @@ export class InteractiveShell {
|
|
|
2464
2317
|
this.autosaveIfEnabled();
|
|
2465
2318
|
// Track metrics with Alpha Zero 2
|
|
2466
2319
|
const elapsedMs = Date.now() - requestStartTime;
|
|
2467
|
-
this.
|
|
2320
|
+
this.sessionMetrics.recordMessage(elapsedMs);
|
|
2468
2321
|
if (!responseText?.trim()) {
|
|
2469
2322
|
display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
|
|
2470
2323
|
}
|
|
@@ -2482,10 +2335,14 @@ export class InteractiveShell {
|
|
|
2482
2335
|
this.stopStreamingHeartbeat();
|
|
2483
2336
|
this.isProcessing = false;
|
|
2484
2337
|
this.terminalInput.setStreaming(false);
|
|
2338
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2485
2339
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2486
2340
|
this.setIdleStatus();
|
|
2487
2341
|
display.newLine();
|
|
2488
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();
|
|
2489
2346
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
2490
2347
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
2491
2348
|
// Claude Code style: New prompt naturally appears at bottom
|
|
@@ -2562,14 +2419,13 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
2562
2419
|
try {
|
|
2563
2420
|
// Send the request and capture the response (streaming disabled)
|
|
2564
2421
|
display.showThinking('Responding...');
|
|
2565
|
-
this.refreshStatusLine(true);
|
|
2566
2422
|
const response = await agent.send(currentPrompt, true);
|
|
2567
2423
|
await this.awaitPendingCleanup();
|
|
2568
2424
|
this.captureHistorySnapshot();
|
|
2569
2425
|
this.autosaveIfEnabled();
|
|
2570
2426
|
// Track metrics
|
|
2571
2427
|
const elapsedMs = Date.now() - overallStartTime;
|
|
2572
|
-
this.
|
|
2428
|
+
this.sessionMetrics.recordMessage(elapsedMs);
|
|
2573
2429
|
if (!response?.trim()) {
|
|
2574
2430
|
display.showWarning('Model returned an empty response. Retrying this iteration...');
|
|
2575
2431
|
consecutiveNoProgress++;
|
|
@@ -2706,6 +2562,7 @@ What's the next action?`;
|
|
|
2706
2562
|
this.stopStreamingHeartbeat();
|
|
2707
2563
|
this.isProcessing = false;
|
|
2708
2564
|
this.terminalInput.setStreaming(false);
|
|
2565
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2709
2566
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2710
2567
|
this.setIdleStatus();
|
|
2711
2568
|
this.updateStatusMessage(null);
|
|
@@ -3062,10 +2919,8 @@ What's the next action?`;
|
|
|
3062
2919
|
try {
|
|
3063
2920
|
// Send the error to the agent for fixing
|
|
3064
2921
|
display.showThinking('Analyzing build errors');
|
|
3065
|
-
this.refreshStatusLine(true);
|
|
3066
2922
|
const response = await this.agent.send(prompt, true);
|
|
3067
2923
|
display.stopThinking();
|
|
3068
|
-
this.refreshStatusLine(true);
|
|
3069
2924
|
if (response) {
|
|
3070
2925
|
display.showAssistantMessage(response, { isFinal: true });
|
|
3071
2926
|
}
|
|
@@ -3092,8 +2947,8 @@ What's the next action?`;
|
|
|
3092
2947
|
};
|
|
3093
2948
|
this.agent = this.runtimeSession.createAgent(selection, {
|
|
3094
2949
|
onStreamChunk: (chunk) => {
|
|
3095
|
-
// Stream output
|
|
3096
|
-
|
|
2950
|
+
// Stream output directly - no spinner during streaming to avoid race conditions
|
|
2951
|
+
display.stream(chunk);
|
|
3097
2952
|
},
|
|
3098
2953
|
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
3099
2954
|
onAssistantMessage: (content, metadata) => {
|
|
@@ -3115,16 +2970,18 @@ What's the next action?`;
|
|
|
3115
2970
|
display.showAssistantMessage(finalContent, enriched);
|
|
3116
2971
|
}
|
|
3117
2972
|
}
|
|
3118
|
-
//
|
|
2973
|
+
// Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
|
|
3119
2974
|
display.stopThinking();
|
|
3120
|
-
//
|
|
2975
|
+
// Calculate context usage
|
|
2976
|
+
let contextInfo;
|
|
3121
2977
|
if (enriched.contextWindowTokens && metadata.usage) {
|
|
3122
2978
|
const total = this.totalTokens(metadata.usage);
|
|
3123
2979
|
if (total && total > 0) {
|
|
3124
2980
|
const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
|
|
3125
|
-
|
|
2981
|
+
contextInfo = { percentage, tokens: total };
|
|
3126
2982
|
}
|
|
3127
2983
|
}
|
|
2984
|
+
display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
|
|
3128
2985
|
// Auto-verify changes: build first (catches type errors), then tests
|
|
3129
2986
|
void this.enforceAutoBuild('final-response');
|
|
3130
2987
|
void this.enforceAutoTests('final-response');
|
|
@@ -3194,6 +3051,7 @@ What's the next action?`;
|
|
|
3194
3051
|
this.stopStreamingHeartbeat();
|
|
3195
3052
|
this.updateStatusMessage(null);
|
|
3196
3053
|
this.terminalInput.setStreaming(false);
|
|
3054
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3197
3055
|
this.terminalInput.render();
|
|
3198
3056
|
},
|
|
3199
3057
|
onVerificationNeeded: () => {
|
|
@@ -3230,6 +3088,7 @@ What's the next action?`;
|
|
|
3230
3088
|
resetChatBoxAfterModelSwap() {
|
|
3231
3089
|
this.updateStatusMessage(null);
|
|
3232
3090
|
this.terminalInput.setStreaming(false);
|
|
3091
|
+
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3233
3092
|
this.terminalInput.render();
|
|
3234
3093
|
this.ensureReadlineReady();
|
|
3235
3094
|
}
|
|
@@ -3294,14 +3153,9 @@ What's the next action?`;
|
|
|
3294
3153
|
return null;
|
|
3295
3154
|
}
|
|
3296
3155
|
const usageRatio = total / windowTokens;
|
|
3297
|
-
this.latestTokenUsage = {
|
|
3298
|
-
used: total,
|
|
3299
|
-
limit: windowTokens,
|
|
3300
|
-
};
|
|
3301
3156
|
// Always update context usage in the UI
|
|
3302
3157
|
const percentUsed = Math.round(usageRatio * 100);
|
|
3303
3158
|
this.updateContextUsage(percentUsed);
|
|
3304
|
-
this.refreshStatusLine(true);
|
|
3305
3159
|
if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
|
|
3306
3160
|
return null;
|
|
3307
3161
|
}
|
|
@@ -3568,113 +3422,6 @@ What's the next action?`;
|
|
|
3568
3422
|
this.sessionState.reasoningEffort = preset.reasoningEffort;
|
|
3569
3423
|
}
|
|
3570
3424
|
}
|
|
3571
|
-
/**
|
|
3572
|
-
* Build the session banner with comprehensive feature status.
|
|
3573
|
-
*/
|
|
3574
|
-
buildBanner() {
|
|
3575
|
-
const terminalWidth = output.columns ?? 100;
|
|
3576
|
-
const width = Math.min(terminalWidth - 4, 110);
|
|
3577
|
-
// Collect tool categories for display
|
|
3578
|
-
const toolCategories = this.collectToolCategories();
|
|
3579
|
-
return renderSessionFrame({
|
|
3580
|
-
profileLabel: this.profileLabel,
|
|
3581
|
-
profileName: this.profile,
|
|
3582
|
-
model: this.sessionState.model,
|
|
3583
|
-
provider: this.sessionState.provider,
|
|
3584
|
-
workspace: this.workingDir,
|
|
3585
|
-
version: this.version,
|
|
3586
|
-
width,
|
|
3587
|
-
features: {
|
|
3588
|
-
verification: this.verificationEnabled,
|
|
3589
|
-
autoContinue: this.autoContinueEnabled,
|
|
3590
|
-
thinkingMode: this.thinkingMode,
|
|
3591
|
-
plugins: this._enabledPlugins,
|
|
3592
|
-
tools: toolCategories,
|
|
3593
|
-
sessionId: this.activeSessionId ?? undefined,
|
|
3594
|
-
},
|
|
3595
|
-
});
|
|
3596
|
-
}
|
|
3597
|
-
/**
|
|
3598
|
-
* Collect tool categories for banner display.
|
|
3599
|
-
*/
|
|
3600
|
-
collectToolCategories() {
|
|
3601
|
-
const categories = [];
|
|
3602
|
-
try {
|
|
3603
|
-
const providerTools = this.runtimeSession.toolRuntime.listProviderTools();
|
|
3604
|
-
if (providerTools.length > 0) {
|
|
3605
|
-
// Group by category (first word of tool name or namespace)
|
|
3606
|
-
const groups = new Map();
|
|
3607
|
-
for (const tool of providerTools) {
|
|
3608
|
-
const category = this.extractToolCategory(tool.name);
|
|
3609
|
-
groups.set(category, (groups.get(category) || 0) + 1);
|
|
3610
|
-
}
|
|
3611
|
-
// Convert to array sorted by count
|
|
3612
|
-
const sorted = Array.from(groups.entries())
|
|
3613
|
-
.sort((a, b) => b[1] - a[1])
|
|
3614
|
-
.slice(0, 5); // Top 5 categories
|
|
3615
|
-
for (const [name, count] of sorted) {
|
|
3616
|
-
categories.push({ name, count, icon: this.getToolCategoryIcon(name) });
|
|
3617
|
-
}
|
|
3618
|
-
}
|
|
3619
|
-
}
|
|
3620
|
-
catch {
|
|
3621
|
-
// Ignore errors in tool collection
|
|
3622
|
-
}
|
|
3623
|
-
return categories;
|
|
3624
|
-
}
|
|
3625
|
-
/**
|
|
3626
|
-
* Extract category from tool name.
|
|
3627
|
-
*/
|
|
3628
|
-
extractToolCategory(toolName) {
|
|
3629
|
-
// Common tool prefixes
|
|
3630
|
-
const prefixMap = {
|
|
3631
|
-
git: 'Git',
|
|
3632
|
-
npm: 'NPM',
|
|
3633
|
-
bash: 'Shell',
|
|
3634
|
-
file: 'Files',
|
|
3635
|
-
read: 'Files',
|
|
3636
|
-
write: 'Files',
|
|
3637
|
-
edit: 'Files',
|
|
3638
|
-
search: 'Search',
|
|
3639
|
-
glob: 'Search',
|
|
3640
|
-
grep: 'Search',
|
|
3641
|
-
web: 'Web',
|
|
3642
|
-
fetch: 'Web',
|
|
3643
|
-
test: 'Testing',
|
|
3644
|
-
build: 'Build',
|
|
3645
|
-
deploy: 'Deploy',
|
|
3646
|
-
cloud: 'Cloud',
|
|
3647
|
-
browser: 'Browser',
|
|
3648
|
-
};
|
|
3649
|
-
const lower = toolName.toLowerCase();
|
|
3650
|
-
for (const [prefix, category] of Object.entries(prefixMap)) {
|
|
3651
|
-
if (lower.startsWith(prefix)) {
|
|
3652
|
-
return category;
|
|
3653
|
-
}
|
|
3654
|
-
}
|
|
3655
|
-
// Default to first word capitalized
|
|
3656
|
-
const firstWord = toolName.split(/[_\-\s]/)[0] || 'Other';
|
|
3657
|
-
return firstWord.charAt(0).toUpperCase() + firstWord.slice(1).toLowerCase();
|
|
3658
|
-
}
|
|
3659
|
-
/**
|
|
3660
|
-
* Get icon for tool category.
|
|
3661
|
-
*/
|
|
3662
|
-
getToolCategoryIcon(category) {
|
|
3663
|
-
const icons = {
|
|
3664
|
-
Git: '⎇',
|
|
3665
|
-
NPM: '📦',
|
|
3666
|
-
Shell: '⌘',
|
|
3667
|
-
Files: '📁',
|
|
3668
|
-
Search: '🔍',
|
|
3669
|
-
Web: '🌐',
|
|
3670
|
-
Testing: '🧪',
|
|
3671
|
-
Build: '🔧',
|
|
3672
|
-
Deploy: '🚀',
|
|
3673
|
-
Cloud: '☁',
|
|
3674
|
-
Browser: '🌐',
|
|
3675
|
-
};
|
|
3676
|
-
return icons[category] || '⚙';
|
|
3677
|
-
}
|
|
3678
3425
|
refreshBannerSessionInfo() {
|
|
3679
3426
|
const nextState = {
|
|
3680
3427
|
model: this.sessionState.model,
|
|
@@ -3685,11 +3432,13 @@ What's the next action?`;
|
|
|
3685
3432
|
return;
|
|
3686
3433
|
}
|
|
3687
3434
|
this.refreshContextGauge();
|
|
3688
|
-
|
|
3689
|
-
//
|
|
3435
|
+
display.updateSessionInfo(nextState.model, nextState.provider);
|
|
3436
|
+
// Update the persistent model info display in terminal input
|
|
3437
|
+
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
3690
3438
|
if (!this.isProcessing) {
|
|
3691
3439
|
this.setIdleStatus();
|
|
3692
3440
|
}
|
|
3441
|
+
// Pinned header rows are disabled; scroll region handles all output.
|
|
3693
3442
|
this.bannerSessionState = nextState;
|
|
3694
3443
|
}
|
|
3695
3444
|
providerLabel(id) {
|