erosolar-cli 1.7.356 → 1.7.357
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 +24 -148
- package/dist/bin/erosolar.js +5 -21
- package/dist/bin/erosolar.js.map +1 -1
- package/dist/capabilities/agentSpawningCapability.d.ts.map +1 -1
- package/dist/capabilities/agentSpawningCapability.js +56 -31
- package/dist/capabilities/agentSpawningCapability.js.map +1 -1
- package/dist/contracts/agent-schemas.json +0 -15
- package/dist/contracts/tools.schema.json +0 -9
- 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/customCommands.d.ts +1 -0
- package/dist/core/customCommands.d.ts.map +1 -1
- package/dist/core/customCommands.js +3 -0
- package/dist/core/customCommands.js.map +1 -1
- package/dist/core/hooks.d.ts +113 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +267 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/metricsTracker.d.ts +122 -0
- package/dist/core/metricsTracker.d.ts.map +1 -0
- package/dist/{alpha-zero → core}/metricsTracker.js +2 -5
- package/dist/core/metricsTracker.js.map +1 -0
- package/dist/core/securityAssessment.d.ts +91 -0
- package/dist/core/securityAssessment.d.ts.map +1 -0
- package/dist/core/securityAssessment.js +580 -0
- package/dist/core/securityAssessment.js.map +1 -0
- package/dist/core/sessionStore.d.ts +2 -0
- package/dist/core/sessionStore.d.ts.map +1 -1
- package/dist/core/sessionStore.js +1 -0
- package/dist/core/sessionStore.js.map +1 -1
- package/dist/core/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +0 -14
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts +22 -1
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +0 -5
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/toolValidation.d.ts.map +1 -1
- package/dist/core/toolValidation.js +14 -3
- package/dist/core/toolValidation.js.map +1 -1
- package/dist/core/validationRunner.d.ts +1 -3
- package/dist/core/validationRunner.d.ts.map +1 -1
- package/dist/core/validationRunner.js.map +1 -1
- package/dist/core/verification.d.ts +137 -0
- package/dist/core/verification.d.ts.map +1 -0
- package/dist/core/verification.js +323 -0
- package/dist/core/verification.js.map +1 -0
- package/dist/headless/headlessApp.d.ts.map +1 -1
- package/dist/headless/headlessApp.js +21 -0
- package/dist/headless/headlessApp.js.map +1 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +9 -18
- package/dist/mcp/sseClient.js.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.d.ts +0 -6
- package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.js +4 -10
- 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 +0 -2
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- 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/shell/interactiveShell.d.ts +41 -7
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +399 -166
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.d.ts +2 -0
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +82 -9
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +1 -4
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +250 -125
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +1071 -612
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +106 -24
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +137 -30
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/subagents/agentConfig.d.ts +27 -0
- package/dist/subagents/agentConfig.d.ts.map +1 -0
- package/dist/subagents/agentConfig.js +89 -0
- package/dist/subagents/agentConfig.js.map +1 -0
- package/dist/subagents/agentRegistry.d.ts +33 -0
- package/dist/subagents/agentRegistry.d.ts.map +1 -0
- package/dist/subagents/agentRegistry.js +162 -0
- package/dist/subagents/agentRegistry.js.map +1 -0
- package/dist/subagents/taskRunner.d.ts +7 -1
- package/dist/subagents/taskRunner.d.ts.map +1 -1
- package/dist/subagents/taskRunner.js +200 -49
- package/dist/subagents/taskRunner.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +7 -1
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +42 -18
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/display.d.ts +24 -45
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +148 -274
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js +6 -8
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts +0 -158
- package/dist/ui/toolDisplay.d.ts.map +1 -1
- package/dist/ui/toolDisplay.js +0 -348
- package/dist/ui/toolDisplay.js.map +1 -1
- package/dist/ui/unified/layout.d.ts +20 -0
- package/dist/ui/unified/layout.d.ts.map +1 -1
- package/dist/ui/unified/layout.js +105 -216
- package/dist/ui/unified/layout.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +10 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +78 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/package.json +4 -4
- package/dist/alpha-zero/agentWrapper.d.ts +0 -84
- package/dist/alpha-zero/agentWrapper.d.ts.map +0 -1
- package/dist/alpha-zero/agentWrapper.js +0 -171
- package/dist/alpha-zero/agentWrapper.js.map +0 -1
- package/dist/alpha-zero/codeEvaluator.d.ts +0 -25
- package/dist/alpha-zero/codeEvaluator.d.ts.map +0 -1
- package/dist/alpha-zero/codeEvaluator.js +0 -273
- package/dist/alpha-zero/codeEvaluator.js.map +0 -1
- package/dist/alpha-zero/competitiveRunner.d.ts +0 -66
- package/dist/alpha-zero/competitiveRunner.d.ts.map +0 -1
- package/dist/alpha-zero/competitiveRunner.js +0 -224
- package/dist/alpha-zero/competitiveRunner.js.map +0 -1
- package/dist/alpha-zero/index.d.ts +0 -67
- package/dist/alpha-zero/index.d.ts.map +0 -1
- package/dist/alpha-zero/index.js +0 -99
- package/dist/alpha-zero/index.js.map +0 -1
- package/dist/alpha-zero/introspection.d.ts +0 -128
- package/dist/alpha-zero/introspection.d.ts.map +0 -1
- package/dist/alpha-zero/introspection.js +0 -300
- package/dist/alpha-zero/introspection.js.map +0 -1
- package/dist/alpha-zero/metricsTracker.d.ts +0 -71
- package/dist/alpha-zero/metricsTracker.d.ts.map +0 -1
- package/dist/alpha-zero/metricsTracker.js.map +0 -1
- package/dist/alpha-zero/security/core.d.ts +0 -125
- package/dist/alpha-zero/security/core.d.ts.map +0 -1
- package/dist/alpha-zero/security/core.js +0 -271
- package/dist/alpha-zero/security/core.js.map +0 -1
- package/dist/alpha-zero/security/google.d.ts +0 -125
- package/dist/alpha-zero/security/google.d.ts.map +0 -1
- package/dist/alpha-zero/security/google.js +0 -311
- package/dist/alpha-zero/security/google.js.map +0 -1
- package/dist/alpha-zero/security/googleLoader.d.ts +0 -17
- package/dist/alpha-zero/security/googleLoader.d.ts.map +0 -1
- package/dist/alpha-zero/security/googleLoader.js +0 -41
- package/dist/alpha-zero/security/googleLoader.js.map +0 -1
- package/dist/alpha-zero/security/index.d.ts +0 -29
- package/dist/alpha-zero/security/index.d.ts.map +0 -1
- package/dist/alpha-zero/security/index.js +0 -32
- package/dist/alpha-zero/security/index.js.map +0 -1
- package/dist/alpha-zero/security/simulation.d.ts +0 -124
- package/dist/alpha-zero/security/simulation.d.ts.map +0 -1
- package/dist/alpha-zero/security/simulation.js +0 -277
- package/dist/alpha-zero/security/simulation.js.map +0 -1
- package/dist/alpha-zero/selfModification.d.ts +0 -109
- package/dist/alpha-zero/selfModification.d.ts.map +0 -1
- package/dist/alpha-zero/selfModification.js +0 -233
- package/dist/alpha-zero/selfModification.js.map +0 -1
- package/dist/alpha-zero/types.d.ts +0 -170
- package/dist/alpha-zero/types.d.ts.map +0 -1
- package/dist/alpha-zero/types.js +0 -31
- package/dist/alpha-zero/types.js.map +0 -1
- package/dist/capabilities/securityTestingCapability.d.ts +0 -13
- package/dist/capabilities/securityTestingCapability.d.ts.map +0 -1
- package/dist/capabilities/securityTestingCapability.js +0 -25
- package/dist/capabilities/securityTestingCapability.js.map +0 -1
- package/dist/core/aiFlowOptimizer.d.ts +0 -26
- package/dist/core/aiFlowOptimizer.d.ts.map +0 -1
- package/dist/core/aiFlowOptimizer.js +0 -31
- package/dist/core/aiFlowOptimizer.js.map +0 -1
- package/dist/core/aiOptimizationEngine.d.ts +0 -158
- package/dist/core/aiOptimizationEngine.d.ts.map +0 -1
- package/dist/core/aiOptimizationEngine.js +0 -428
- package/dist/core/aiOptimizationEngine.js.map +0 -1
- package/dist/core/aiOptimizationIntegration.d.ts +0 -93
- package/dist/core/aiOptimizationIntegration.d.ts.map +0 -1
- package/dist/core/aiOptimizationIntegration.js +0 -250
- package/dist/core/aiOptimizationIntegration.js.map +0 -1
- package/dist/core/enhancedErrorRecovery.d.ts +0 -100
- package/dist/core/enhancedErrorRecovery.d.ts.map +0 -1
- package/dist/core/enhancedErrorRecovery.js +0 -345
- package/dist/core/enhancedErrorRecovery.js.map +0 -1
- package/dist/core/hooksSystem.d.ts +0 -65
- package/dist/core/hooksSystem.d.ts.map +0 -1
- package/dist/core/hooksSystem.js +0 -273
- package/dist/core/hooksSystem.js.map +0 -1
- package/dist/core/memorySystem.d.ts +0 -48
- package/dist/core/memorySystem.d.ts.map +0 -1
- package/dist/core/memorySystem.js +0 -271
- package/dist/core/memorySystem.js.map +0 -1
- package/dist/core/unified/errors.d.ts +0 -189
- package/dist/core/unified/errors.d.ts.map +0 -1
- package/dist/core/unified/errors.js +0 -497
- package/dist/core/unified/errors.js.map +0 -1
- package/dist/core/unified/index.d.ts +0 -19
- package/dist/core/unified/index.d.ts.map +0 -1
- package/dist/core/unified/index.js +0 -68
- package/dist/core/unified/index.js.map +0 -1
- package/dist/core/unified/schema.d.ts +0 -101
- package/dist/core/unified/schema.d.ts.map +0 -1
- package/dist/core/unified/schema.js +0 -350
- package/dist/core/unified/schema.js.map +0 -1
- package/dist/core/unified/toolRuntime.d.ts +0 -179
- package/dist/core/unified/toolRuntime.d.ts.map +0 -1
- package/dist/core/unified/toolRuntime.js +0 -517
- package/dist/core/unified/toolRuntime.js.map +0 -1
- package/dist/core/unified/tools.d.ts +0 -127
- package/dist/core/unified/tools.d.ts.map +0 -1
- package/dist/core/unified/tools.js +0 -1333
- package/dist/core/unified/tools.js.map +0 -1
- package/dist/core/unified/types.d.ts +0 -352
- package/dist/core/unified/types.d.ts.map +0 -1
- package/dist/core/unified/types.js +0 -12
- package/dist/core/unified/types.js.map +0 -1
- package/dist/core/unified/version.d.ts +0 -209
- package/dist/core/unified/version.d.ts.map +0 -1
- package/dist/core/unified/version.js +0 -454
- package/dist/core/unified/version.js.map +0 -1
- package/dist/plugins/tools/security/securityPlugin.d.ts +0 -3
- package/dist/plugins/tools/security/securityPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/security/securityPlugin.js +0 -12
- package/dist/plugins/tools/security/securityPlugin.js.map +0 -1
- package/dist/security/active-stack-security.d.ts +0 -112
- package/dist/security/active-stack-security.d.ts.map +0 -1
- package/dist/security/active-stack-security.js +0 -296
- package/dist/security/active-stack-security.js.map +0 -1
- package/dist/security/advanced-persistence-research.d.ts +0 -92
- package/dist/security/advanced-persistence-research.d.ts.map +0 -1
- package/dist/security/advanced-persistence-research.js +0 -195
- package/dist/security/advanced-persistence-research.js.map +0 -1
- package/dist/security/advanced-targeting.d.ts +0 -119
- package/dist/security/advanced-targeting.d.ts.map +0 -1
- package/dist/security/advanced-targeting.js +0 -233
- package/dist/security/advanced-targeting.js.map +0 -1
- package/dist/security/assessment/vulnerabilityAssessment.d.ts +0 -104
- package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +0 -1
- package/dist/security/assessment/vulnerabilityAssessment.js +0 -315
- package/dist/security/assessment/vulnerabilityAssessment.js.map +0 -1
- package/dist/security/authorization/securityAuthorization.d.ts +0 -88
- package/dist/security/authorization/securityAuthorization.d.ts.map +0 -1
- package/dist/security/authorization/securityAuthorization.js +0 -172
- package/dist/security/authorization/securityAuthorization.js.map +0 -1
- package/dist/security/comprehensive-targeting.d.ts +0 -85
- package/dist/security/comprehensive-targeting.d.ts.map +0 -1
- package/dist/security/comprehensive-targeting.js +0 -438
- package/dist/security/comprehensive-targeting.js.map +0 -1
- package/dist/security/global-security-integration.d.ts +0 -91
- package/dist/security/global-security-integration.d.ts.map +0 -1
- package/dist/security/global-security-integration.js +0 -218
- package/dist/security/global-security-integration.js.map +0 -1
- package/dist/security/index.d.ts +0 -38
- package/dist/security/index.d.ts.map +0 -1
- package/dist/security/index.js +0 -47
- package/dist/security/index.js.map +0 -1
- package/dist/security/persistence-analyzer.d.ts +0 -56
- package/dist/security/persistence-analyzer.d.ts.map +0 -1
- package/dist/security/persistence-analyzer.js +0 -187
- package/dist/security/persistence-analyzer.js.map +0 -1
- package/dist/security/persistence-cli.d.ts +0 -36
- package/dist/security/persistence-cli.d.ts.map +0 -1
- package/dist/security/persistence-cli.js +0 -160
- package/dist/security/persistence-cli.js.map +0 -1
- package/dist/security/persistence-research.d.ts +0 -92
- package/dist/security/persistence-research.d.ts.map +0 -1
- package/dist/security/persistence-research.js +0 -364
- package/dist/security/persistence-research.js.map +0 -1
- package/dist/security/research/persistenceResearch.d.ts +0 -97
- package/dist/security/research/persistenceResearch.d.ts.map +0 -1
- package/dist/security/research/persistenceResearch.js +0 -282
- package/dist/security/research/persistenceResearch.js.map +0 -1
- package/dist/security/security-integration.d.ts +0 -74
- package/dist/security/security-integration.d.ts.map +0 -1
- package/dist/security/security-integration.js +0 -137
- package/dist/security/security-integration.js.map +0 -1
- package/dist/security/security-testing-framework.d.ts +0 -112
- package/dist/security/security-testing-framework.d.ts.map +0 -1
- package/dist/security/security-testing-framework.js +0 -364
- package/dist/security/security-testing-framework.js.map +0 -1
- package/dist/security/simulation/attackSimulation.d.ts +0 -93
- package/dist/security/simulation/attackSimulation.d.ts.map +0 -1
- package/dist/security/simulation/attackSimulation.js +0 -341
- package/dist/security/simulation/attackSimulation.js.map +0 -1
- package/dist/security/strategic-operations.d.ts +0 -100
- package/dist/security/strategic-operations.d.ts.map +0 -1
- package/dist/security/strategic-operations.js +0 -276
- package/dist/security/strategic-operations.js.map +0 -1
- package/dist/security/tool-security-wrapper.d.ts +0 -58
- package/dist/security/tool-security-wrapper.d.ts.map +0 -1
- package/dist/security/tool-security-wrapper.js +0 -156
- package/dist/security/tool-security-wrapper.js.map +0 -1
- package/dist/shell/claudeCodeStreamHandler.d.ts +0 -145
- package/dist/shell/claudeCodeStreamHandler.d.ts.map +0 -1
- package/dist/shell/claudeCodeStreamHandler.js +0 -322
- package/dist/shell/claudeCodeStreamHandler.js.map +0 -1
- package/dist/shell/inputQueueManager.d.ts +0 -144
- package/dist/shell/inputQueueManager.d.ts.map +0 -1
- package/dist/shell/inputQueueManager.js +0 -290
- package/dist/shell/inputQueueManager.js.map +0 -1
- package/dist/shell/metricsTracker.d.ts +0 -60
- package/dist/shell/metricsTracker.d.ts.map +0 -1
- package/dist/shell/metricsTracker.js +0 -119
- package/dist/shell/metricsTracker.js.map +0 -1
- package/dist/shell/streamingOutputManager.d.ts +0 -115
- package/dist/shell/streamingOutputManager.d.ts.map +0 -1
- package/dist/shell/streamingOutputManager.js +0 -225
- package/dist/shell/streamingOutputManager.js.map +0 -1
- package/dist/tools/securityTools.d.ts +0 -22
- package/dist/tools/securityTools.d.ts.map +0 -1
- package/dist/tools/securityTools.js +0 -448
- package/dist/tools/securityTools.js.map +0 -1
- package/dist/ui/persistentPrompt.d.ts +0 -50
- package/dist/ui/persistentPrompt.d.ts.map +0 -1
- package/dist/ui/persistentPrompt.js +0 -92
- package/dist/ui/persistentPrompt.js.map +0 -1
- package/dist/ui/terminalUISchema.d.ts +0 -195
- package/dist/ui/terminalUISchema.d.ts.map +0 -1
- package/dist/ui/terminalUISchema.js +0 -113
- package/dist/ui/terminalUISchema.js.map +0 -1
- package/scripts/deploy-security-capabilities.js +0 -178
|
@@ -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
|
|
5
|
+
import { theme } 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 '../core/metricsTracker.js';
|
|
23
23
|
import { listAvailablePlugins } from '../plugins/index.js';
|
|
24
|
-
import { loadMemory, listMemoryPaths, getDefaultProjectMemoryPath, getUserMemoryEditPath, } from '../core/memorySystem.js';
|
|
25
24
|
import { TerminalInputAdapter } from './terminalInputAdapter.js';
|
|
26
|
-
import {
|
|
25
|
+
import { renderSessionFrame } from '../ui/unified/layout.js';
|
|
26
|
+
import { isUpdateInProgress, maybeOfferCliUpdate } 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,6 +35,7 @@ const DROPDOWN_COLORS = [
|
|
|
35
35
|
theme.success,
|
|
36
36
|
theme.warning,
|
|
37
37
|
];
|
|
38
|
+
const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
|
|
38
39
|
// Load MODEL_PRESETS from centralized schema
|
|
39
40
|
const MODEL_PRESETS = getModels().map((model) => ({
|
|
40
41
|
id: model.id,
|
|
@@ -49,11 +50,13 @@ const MODEL_PRESETS = getModels().map((model) => ({
|
|
|
49
50
|
const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
|
|
50
51
|
command: cmd.command,
|
|
51
52
|
description: cmd.description,
|
|
53
|
+
category: cmd.category,
|
|
52
54
|
}));
|
|
53
55
|
// Load PROVIDER_LABELS from centralized schema
|
|
54
56
|
const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
|
|
55
57
|
// Allow enough time for paste detection to kick in before flushing buffered lines
|
|
56
58
|
const CONTEXT_USAGE_THRESHOLD = 0.9;
|
|
59
|
+
const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
|
|
57
60
|
const CONTEXT_RECENT_MESSAGE_COUNT = 12;
|
|
58
61
|
const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
|
|
59
62
|
const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
|
|
@@ -94,11 +97,12 @@ export class InteractiveShell {
|
|
|
94
97
|
uiAdapter;
|
|
95
98
|
uiUpdates;
|
|
96
99
|
_fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
|
|
97
|
-
|
|
100
|
+
alphaZeroMetrics; // Alpha Zero 2 performance tracking
|
|
98
101
|
statusSubscription = null;
|
|
99
102
|
followUpQueue = [];
|
|
100
103
|
isDrainingQueue = false;
|
|
101
104
|
activeContextWindowTokens = null;
|
|
105
|
+
latestTokenUsage = { used: null, limit: null };
|
|
102
106
|
sessionPreferences;
|
|
103
107
|
autosaveEnabled;
|
|
104
108
|
autoContinueEnabled;
|
|
@@ -129,6 +133,9 @@ export class InteractiveShell {
|
|
|
129
133
|
statusLineState = null;
|
|
130
134
|
statusMessageOverride = null;
|
|
131
135
|
promptRefreshTimer = null;
|
|
136
|
+
launchPaletteShown = false;
|
|
137
|
+
version;
|
|
138
|
+
// Alternate screen disabled - use main terminal for better scrollback
|
|
132
139
|
constructor(config) {
|
|
133
140
|
this.profile = config.profile;
|
|
134
141
|
this.profileLabel = config.profileLabel;
|
|
@@ -142,6 +149,7 @@ export class InteractiveShell {
|
|
|
142
149
|
this.autoContinueEnabled = this.sessionPreferences.autoContinue;
|
|
143
150
|
this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
|
|
144
151
|
this._enabledPlugins = config.enabledPlugins ?? [];
|
|
152
|
+
this.version = config.version ?? '0.0.0';
|
|
145
153
|
this.initializeSessionHistory();
|
|
146
154
|
this.sessionState = {
|
|
147
155
|
provider: config.initialModel.provider,
|
|
@@ -162,6 +170,7 @@ export class InteractiveShell {
|
|
|
162
170
|
this.slashCommands.push({
|
|
163
171
|
command: '/agents',
|
|
164
172
|
description: 'Select the default agent profile (applies on next launch)',
|
|
173
|
+
category: 'configuration',
|
|
165
174
|
});
|
|
166
175
|
}
|
|
167
176
|
this.customCommands = loadCustomSlashCommands();
|
|
@@ -170,18 +179,21 @@ export class InteractiveShell {
|
|
|
170
179
|
this.slashCommands.push({
|
|
171
180
|
command: custom.command,
|
|
172
181
|
description: `${custom.description} (custom)`,
|
|
182
|
+
category: custom.category ?? 'other',
|
|
173
183
|
});
|
|
174
184
|
}
|
|
175
185
|
if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
|
|
176
186
|
this.slashCommands.push({
|
|
177
187
|
command: '/exit',
|
|
178
188
|
description: 'Quit the CLI immediately',
|
|
189
|
+
category: 'other',
|
|
179
190
|
});
|
|
180
191
|
}
|
|
181
192
|
// Add /plugins command
|
|
182
193
|
this.slashCommands.push({
|
|
183
194
|
command: '/plugins',
|
|
184
195
|
description: 'Show available and loaded plugins',
|
|
196
|
+
category: 'configuration',
|
|
185
197
|
});
|
|
186
198
|
this.statusTracker = config.statusTracker;
|
|
187
199
|
this.ui = config.ui;
|
|
@@ -213,20 +225,31 @@ export class InteractiveShell {
|
|
|
213
225
|
onEditModeChange: (mode) => this.handleEditModeChange(mode),
|
|
214
226
|
onToggleVerify: () => this.toggleVerificationMode(),
|
|
215
227
|
onToggleAutoContinue: () => this.toggleAutoContinueMode(),
|
|
228
|
+
onToggleThinking: () => this.cycleThinkingMode(),
|
|
229
|
+
onClearContext: () => this.handleClearContext(),
|
|
216
230
|
});
|
|
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();
|
|
224
231
|
// Initialize Alpha Zero 2 metrics tracking
|
|
225
|
-
this.
|
|
232
|
+
this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
226
233
|
this.setupStatusTracking();
|
|
227
234
|
this.refreshContextGauge();
|
|
235
|
+
// Start terminal input (sets up handlers)
|
|
228
236
|
this.terminalInput.start();
|
|
237
|
+
// Clear screen for clean layout (no alternate screen - use main terminal)
|
|
238
|
+
if (output.isTTY) {
|
|
239
|
+
this.terminalInput.clearScreen();
|
|
240
|
+
}
|
|
241
|
+
// Stream banner first - this sets up scroll region dynamically
|
|
242
|
+
const banner = this.buildBanner();
|
|
243
|
+
// Add extra spacing to ensure chat box doesn't overlap banner
|
|
244
|
+
const termRows = output.rows ?? 24;
|
|
245
|
+
const chatBoxHeight = 5;
|
|
246
|
+
const bannerLines = (banner.match(/\n/g) || []).length + 1;
|
|
247
|
+
const minSpacing = Math.max(2, termRows - bannerLines - chatBoxHeight - 1);
|
|
248
|
+
const spacing = '\n'.repeat(Math.min(minSpacing, 3));
|
|
249
|
+
this.terminalInput.streamContent(banner + spacing);
|
|
250
|
+
// Render chat box after banner is streamed
|
|
229
251
|
this.refreshControlBar();
|
|
252
|
+
this.terminalInput.forceRender();
|
|
230
253
|
this.rebuildAgent();
|
|
231
254
|
this.setupHandlers();
|
|
232
255
|
this.refreshBannerSessionInfo();
|
|
@@ -246,6 +269,10 @@ export class InteractiveShell {
|
|
|
246
269
|
this.activeSessionId = stored.id;
|
|
247
270
|
this.activeSessionTitle = stored.title;
|
|
248
271
|
this.sessionResumeNotice = `Resumed session "${stored.title}".`;
|
|
272
|
+
// Restore scrollback buffer if available
|
|
273
|
+
if (stored.scrollbackBuffer && Array.isArray(stored.scrollbackBuffer)) {
|
|
274
|
+
this.terminalInput.loadScrollbackBuffer(stored.scrollbackBuffer);
|
|
275
|
+
}
|
|
249
276
|
return;
|
|
250
277
|
}
|
|
251
278
|
display.showWarning(`Session "${this.sessionRestoreConfig.sessionId}" not found. Starting fresh session.`);
|
|
@@ -259,6 +286,10 @@ export class InteractiveShell {
|
|
|
259
286
|
this.activeSessionId = null;
|
|
260
287
|
this.activeSessionTitle = autosave.title;
|
|
261
288
|
this.sessionResumeNotice = 'Restored last autosaved session.';
|
|
289
|
+
// Restore scrollback buffer if available
|
|
290
|
+
if (autosave.scrollbackBuffer && Array.isArray(autosave.scrollbackBuffer)) {
|
|
291
|
+
this.terminalInput.loadScrollbackBuffer(autosave.scrollbackBuffer);
|
|
292
|
+
}
|
|
262
293
|
return;
|
|
263
294
|
}
|
|
264
295
|
display.showWarning('No autosaved session found. Starting fresh session.');
|
|
@@ -273,14 +304,24 @@ export class InteractiveShell {
|
|
|
273
304
|
this.sessionResumeNotice = null;
|
|
274
305
|
}
|
|
275
306
|
async start(initialPrompt) {
|
|
307
|
+
// Check for updates in background (non-blocking)
|
|
308
|
+
if (this.version) {
|
|
309
|
+
void maybeOfferCliUpdate(this.version);
|
|
310
|
+
}
|
|
276
311
|
if (initialPrompt) {
|
|
277
312
|
this.logUserPrompt(initialPrompt);
|
|
278
313
|
await this.processInputBlock(initialPrompt);
|
|
279
314
|
return;
|
|
280
315
|
}
|
|
316
|
+
this.showLaunchCommandPalette();
|
|
281
317
|
// Ensure the terminal input is visible
|
|
282
318
|
this.terminalInput.render();
|
|
283
319
|
}
|
|
320
|
+
showLaunchCommandPalette() {
|
|
321
|
+
// Disabled: Quick commands palette takes up too much space
|
|
322
|
+
// Users can type /help to see available commands
|
|
323
|
+
this.launchPaletteShown = true;
|
|
324
|
+
}
|
|
284
325
|
/**
|
|
285
326
|
* TerminalInputAdapter submit handler
|
|
286
327
|
*/
|
|
@@ -294,9 +335,8 @@ export class InteractiveShell {
|
|
|
294
335
|
this.handleInputChange('');
|
|
295
336
|
return;
|
|
296
337
|
}
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
this.terminalInput.setStreaming(true);
|
|
338
|
+
// DON'T clear the input here - keep it visible while streaming.
|
|
339
|
+
// The input will be cleared after streaming completes in the finally block.
|
|
300
340
|
this.logUserPrompt(approved);
|
|
301
341
|
void this.processInputBlock(approved).catch((err) => {
|
|
302
342
|
display.showError(err instanceof Error ? err.message : String(err), err);
|
|
@@ -386,6 +426,59 @@ export class InteractiveShell {
|
|
|
386
426
|
: 'The model will not be auto-prompted to continue.') +
|
|
387
427
|
' Toggle with alt+c.');
|
|
388
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Cycle through thinking modes (Alt+T keyboard shortcut).
|
|
431
|
+
*/
|
|
432
|
+
cycleThinkingMode() {
|
|
433
|
+
const modes = ['concise', 'balanced', 'extended'];
|
|
434
|
+
const currentIndex = modes.indexOf(this.thinkingMode);
|
|
435
|
+
const nextIndex = (currentIndex + 1) % modes.length;
|
|
436
|
+
const nextMode = modes[nextIndex];
|
|
437
|
+
this.thinkingMode = nextMode;
|
|
438
|
+
saveSessionPreferences({ thinkingMode: this.thinkingMode });
|
|
439
|
+
this.refreshControlBar();
|
|
440
|
+
const descriptions = {
|
|
441
|
+
concise: 'Minimal reasoning, faster responses',
|
|
442
|
+
balanced: 'Default reasoning depth',
|
|
443
|
+
extended: 'Deep reasoning, thorough analysis',
|
|
444
|
+
};
|
|
445
|
+
display.showInfo(`Thinking mode: ${theme.info(nextMode)} - ${descriptions[nextMode]}. (Alt+T to cycle)`);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Handle context clear/compact request (Alt+X keyboard shortcut).
|
|
449
|
+
*/
|
|
450
|
+
handleClearContext() {
|
|
451
|
+
if (this.isProcessing) {
|
|
452
|
+
display.showWarning('Cannot clear context while processing. Wait for completion or press Ctrl+C.');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
// Trigger context compaction
|
|
456
|
+
display.showInfo('Compacting context... This will summarize the conversation and free up space.');
|
|
457
|
+
void this.performContextCompaction();
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Perform context compaction by summarizing conversation history.
|
|
461
|
+
*/
|
|
462
|
+
async performContextCompaction() {
|
|
463
|
+
try {
|
|
464
|
+
// For now, just clear the history and show a message
|
|
465
|
+
// A full implementation would summarize the conversation
|
|
466
|
+
const oldLength = this.cachedHistory.length;
|
|
467
|
+
if (oldLength === 0) {
|
|
468
|
+
display.showInfo('Context is already empty.');
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
// Keep the last few messages for continuity
|
|
472
|
+
const keepCount = Math.min(4, oldLength);
|
|
473
|
+
this.cachedHistory = this.cachedHistory.slice(-keepCount);
|
|
474
|
+
display.showSuccess(`Context compacted: ${oldLength} messages reduced to ${keepCount}. ` +
|
|
475
|
+
`Context usage reset. Continue your conversation.`);
|
|
476
|
+
this.refreshControlBar();
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
display.showError('Failed to compact context', error);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
389
482
|
/**
|
|
390
483
|
* Gate submissions when edit permission mode is active.
|
|
391
484
|
* Returns the text to send when approved, or null when waiting for confirmation.
|
|
@@ -493,16 +586,16 @@ export class InteractiveShell {
|
|
|
493
586
|
this.teardownStatusTracking();
|
|
494
587
|
// Clear any pending cleanup to prevent hanging
|
|
495
588
|
this.pendingCleanup = null;
|
|
589
|
+
// Reset terminal state before disposing adapters
|
|
590
|
+
this.terminalInput.exitStreamingScrollRegion();
|
|
496
591
|
// Dispose terminal input handler
|
|
497
592
|
this.terminalInput.dispose();
|
|
498
593
|
// Dispose unified UI adapter
|
|
499
594
|
this.uiAdapter.dispose();
|
|
500
595
|
display.newLine();
|
|
501
|
-
|
|
502
|
-
console.log(theme.
|
|
503
|
-
console.log(
|
|
504
|
-
console.log(` ${theme.ui.muted('Support:')} ${theme.info('support@ero.solar')}`);
|
|
505
|
-
console.log(theme.gradient.warm('━'.repeat(50)));
|
|
596
|
+
console.log(theme.ui.muted('━'.repeat(44)));
|
|
597
|
+
console.log(theme.ui.muted(' Goodbye! · support@ero.solar'));
|
|
598
|
+
console.log(theme.ui.muted('━'.repeat(44)));
|
|
506
599
|
exit(0);
|
|
507
600
|
}
|
|
508
601
|
/**
|
|
@@ -672,13 +765,14 @@ export class InteractiveShell {
|
|
|
672
765
|
});
|
|
673
766
|
}
|
|
674
767
|
setProcessingStatus(detail) {
|
|
768
|
+
this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
|
|
675
769
|
this.statusTracker.setBase('Working on your request', {
|
|
676
770
|
detail: this.describeStatusDetail(detail),
|
|
677
771
|
tone: 'info',
|
|
678
772
|
});
|
|
679
773
|
}
|
|
680
774
|
describeStatusDetail(detail) {
|
|
681
|
-
const parts =
|
|
775
|
+
const parts = detail?.trim() ? [detail.trim()] : [];
|
|
682
776
|
const queued = this.followUpQueue.length;
|
|
683
777
|
if (queued > 0) {
|
|
684
778
|
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
|
|
@@ -691,12 +785,18 @@ export class InteractiveShell {
|
|
|
691
785
|
}
|
|
692
786
|
refreshContextGauge() {
|
|
693
787
|
const tokens = getContextWindowTokens(this.sessionState.model);
|
|
694
|
-
|
|
695
|
-
|
|
788
|
+
const normalizedTokens = typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
789
|
+
this.activeContextWindowTokens = normalizedTokens;
|
|
790
|
+
if (normalizedTokens !== null) {
|
|
791
|
+
this.latestTokenUsage = {
|
|
792
|
+
used: this.latestTokenUsage.used,
|
|
793
|
+
limit: normalizedTokens,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
696
796
|
}
|
|
697
797
|
updateContextUsage(percentage) {
|
|
698
798
|
this.uiAdapter.updateContextUsage(percentage);
|
|
699
|
-
this.terminalInput.setContextUsage(percentage);
|
|
799
|
+
this.terminalInput.setContextUsage(percentage, CONTEXT_AUTOCOMPACT_PERCENT);
|
|
700
800
|
}
|
|
701
801
|
refreshControlBar() {
|
|
702
802
|
this.terminalInput.setModeToggles({
|
|
@@ -704,9 +804,9 @@ export class InteractiveShell {
|
|
|
704
804
|
autoContinueEnabled: this.autoContinueEnabled,
|
|
705
805
|
verificationHotkey: 'alt+v',
|
|
706
806
|
autoContinueHotkey: 'alt+c',
|
|
807
|
+
thinkingModeLabel: this.thinkingMode,
|
|
808
|
+
thinkingHotkey: '/thinking',
|
|
707
809
|
});
|
|
708
|
-
// Update persistent model info display
|
|
709
|
-
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
710
810
|
this.refreshStatusLine();
|
|
711
811
|
this.terminalInput.render();
|
|
712
812
|
}
|
|
@@ -737,6 +837,25 @@ export class InteractiveShell {
|
|
|
737
837
|
// Set main status (tool execution, etc.) - shown when not overridden
|
|
738
838
|
const statusText = this.formatStatusLine(this.statusLineState);
|
|
739
839
|
this.terminalInput.setStatusMessage(statusText);
|
|
840
|
+
// Surface meta header (elapsed + context usage) above the divider
|
|
841
|
+
const elapsedSeconds = this.statusLineState
|
|
842
|
+
? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
|
|
843
|
+
: null;
|
|
844
|
+
const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
|
|
845
|
+
const tokensUsed = this.latestTokenUsage.used;
|
|
846
|
+
const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
|
|
847
|
+
this.terminalInput.setMetaStatus({
|
|
848
|
+
elapsedSeconds,
|
|
849
|
+
tokensUsed,
|
|
850
|
+
tokenLimit,
|
|
851
|
+
thinkingMs,
|
|
852
|
+
thinkingHasContent: display.isSpinnerActive(),
|
|
853
|
+
});
|
|
854
|
+
// Keep model/provider visible in the controls bar
|
|
855
|
+
this.terminalInput.setModelContext({
|
|
856
|
+
model: this.sessionState.model,
|
|
857
|
+
provider: this.providerLabel(this.sessionState.provider),
|
|
858
|
+
});
|
|
740
859
|
if (forceRender) {
|
|
741
860
|
this.terminalInput.render();
|
|
742
861
|
}
|
|
@@ -796,15 +915,14 @@ export class InteractiveShell {
|
|
|
796
915
|
this.terminalInput.render();
|
|
797
916
|
}
|
|
798
917
|
/**
|
|
799
|
-
* Log
|
|
800
|
-
* This creates a persistent log entry that remains visible during and after streaming.
|
|
918
|
+
* Log user prompt to the scroll region so it's part of the conversation flow.
|
|
801
919
|
*/
|
|
802
920
|
logUserPrompt(text) {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
this.terminalInput.
|
|
921
|
+
if (!text.trim())
|
|
922
|
+
return;
|
|
923
|
+
// Format with user prompt prefix and write to scroll region
|
|
924
|
+
const formatted = `${theme.user('>')} ${text}\n`;
|
|
925
|
+
this.terminalInput.writeToScrollRegion(formatted);
|
|
808
926
|
}
|
|
809
927
|
requestPromptRefresh(force = false) {
|
|
810
928
|
if (force) {
|
|
@@ -829,16 +947,40 @@ export class InteractiveShell {
|
|
|
829
947
|
this.stopStreamingHeartbeat();
|
|
830
948
|
// Enter global streaming mode - blocks all non-streaming UI output
|
|
831
949
|
enterStreamingMode();
|
|
950
|
+
// Set up scroll region for streaming content
|
|
951
|
+
this.terminalInput.enterStreamingScrollRegion();
|
|
832
952
|
this.uiUpdates.setMode('streaming');
|
|
833
953
|
this.streamingHeartbeatStart = Date.now();
|
|
834
954
|
this.streamingHeartbeatFrame = 0;
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
955
|
+
const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
956
|
+
this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
|
|
957
|
+
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
958
|
+
this.refreshStatusLine(true);
|
|
959
|
+
// Periodically refresh the pinned input/status region while streaming so
|
|
960
|
+
// elapsed time remains visible without interrupting the scroll region.
|
|
961
|
+
this.uiUpdates.startHeartbeat('streaming', {
|
|
962
|
+
intervalMs: 1000,
|
|
963
|
+
lane: 'heartbeat',
|
|
964
|
+
mode: ['streaming', 'processing'],
|
|
965
|
+
coalesceKey: 'streaming:heartbeat',
|
|
966
|
+
run: () => {
|
|
967
|
+
const elapsedSeconds = this.streamingHeartbeatStart
|
|
968
|
+
? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
|
|
969
|
+
: 0;
|
|
970
|
+
this.streamingHeartbeatFrame =
|
|
971
|
+
(this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
|
|
972
|
+
const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
973
|
+
this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
|
|
974
|
+
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
975
|
+
this.refreshStatusLine(true);
|
|
976
|
+
},
|
|
977
|
+
});
|
|
838
978
|
}
|
|
839
979
|
stopStreamingHeartbeat() {
|
|
840
980
|
// Exit global streaming mode - allows UI to render again
|
|
841
981
|
exitStreamingMode();
|
|
982
|
+
// Exit scroll region mode
|
|
983
|
+
this.terminalInput.exitStreamingScrollRegion();
|
|
842
984
|
this.uiUpdates.stopHeartbeat('streaming');
|
|
843
985
|
this.streamingHeartbeatStart = null;
|
|
844
986
|
this.streamingHeartbeatFrame = 0;
|
|
@@ -850,10 +992,28 @@ export class InteractiveShell {
|
|
|
850
992
|
// Force refresh to update the input area now that streaming has ended
|
|
851
993
|
this.refreshStatusLine(true);
|
|
852
994
|
}
|
|
853
|
-
buildStreamingStatus(label) {
|
|
995
|
+
buildStreamingStatus(label, elapsedSeconds) {
|
|
854
996
|
const detail = this.describeModelDetail();
|
|
855
|
-
const
|
|
856
|
-
|
|
997
|
+
const elapsedLabel = typeof elapsedSeconds === 'number' && elapsedSeconds >= 0
|
|
998
|
+
? theme.ui.muted(this.formatElapsedShort(elapsedSeconds))
|
|
999
|
+
: null;
|
|
1000
|
+
const prefix = theme.info('⏺');
|
|
1001
|
+
const parts = [label];
|
|
1002
|
+
if (detail) {
|
|
1003
|
+
parts.push(theme.ui.muted('·'), detail);
|
|
1004
|
+
}
|
|
1005
|
+
if (elapsedLabel) {
|
|
1006
|
+
parts.push(theme.ui.muted('·'), elapsedLabel);
|
|
1007
|
+
}
|
|
1008
|
+
return `${prefix} ${parts.join(' ')}`.trim();
|
|
1009
|
+
}
|
|
1010
|
+
formatElapsedShort(seconds) {
|
|
1011
|
+
if (seconds < 60) {
|
|
1012
|
+
return `${seconds}s`;
|
|
1013
|
+
}
|
|
1014
|
+
const minutes = Math.floor(seconds / 60);
|
|
1015
|
+
const remaining = seconds % 60;
|
|
1016
|
+
return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
|
|
857
1017
|
}
|
|
858
1018
|
refreshQueueIndicators() {
|
|
859
1019
|
if (this.isProcessing) {
|
|
@@ -1101,17 +1261,6 @@ export class InteractiveShell {
|
|
|
1101
1261
|
case '/discover':
|
|
1102
1262
|
await this.discoverModelsCommand();
|
|
1103
1263
|
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;
|
|
1115
1264
|
default:
|
|
1116
1265
|
if (!(await this.tryCustomSlashCommand(command, input))) {
|
|
1117
1266
|
display.showWarning(`Unknown command "${command}".`);
|
|
@@ -1420,99 +1569,6 @@ export class InteractiveShell {
|
|
|
1420
1569
|
// Display keyboard shortcuts help (Claude Code style)
|
|
1421
1570
|
display.showSystemMessage(formatShortcutsHelp());
|
|
1422
1571
|
}
|
|
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
|
-
}
|
|
1516
1572
|
showFileChangeSummary() {
|
|
1517
1573
|
const summary = this._fileChangeTracker.getSummary();
|
|
1518
1574
|
const changes = this._fileChangeTracker.getAllChanges();
|
|
@@ -1555,11 +1611,11 @@ When working in this codebase:
|
|
|
1555
1611
|
display.showSystemMessage(lines.join('\n'));
|
|
1556
1612
|
}
|
|
1557
1613
|
showAlphaZeroMetrics() {
|
|
1558
|
-
const summary = this.
|
|
1614
|
+
const summary = this.alphaZeroMetrics.getPerformanceSummary();
|
|
1559
1615
|
display.showSystemMessage(summary);
|
|
1560
1616
|
}
|
|
1561
1617
|
showImprovementSuggestions() {
|
|
1562
|
-
const suggestions = this.
|
|
1618
|
+
const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
|
|
1563
1619
|
if (suggestions.length === 0) {
|
|
1564
1620
|
display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
|
|
1565
1621
|
return;
|
|
@@ -1605,7 +1661,9 @@ When working in this codebase:
|
|
|
1605
1661
|
}
|
|
1606
1662
|
}
|
|
1607
1663
|
lines.push(theme.secondary('CLI Flags:'));
|
|
1664
|
+
lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
|
|
1608
1665
|
lines.push(' --coding Enable enhanced coding tools');
|
|
1666
|
+
lines.push(' --security Enable security research tools');
|
|
1609
1667
|
lines.push(' --all-plugins Enable all optional plugins');
|
|
1610
1668
|
display.showSystemMessage(lines.join('\n'));
|
|
1611
1669
|
}
|
|
@@ -1654,6 +1712,7 @@ When working in this codebase:
|
|
|
1654
1712
|
model: this.sessionState.model,
|
|
1655
1713
|
workspaceRoot: this.workingDir,
|
|
1656
1714
|
messages: history,
|
|
1715
|
+
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1657
1716
|
});
|
|
1658
1717
|
this.cachedHistory = history;
|
|
1659
1718
|
this.updateActiveSession(summary, true);
|
|
@@ -1832,6 +1891,7 @@ When working in this codebase:
|
|
|
1832
1891
|
workspaceRoot: this.workingDir,
|
|
1833
1892
|
title: this.activeSessionTitle,
|
|
1834
1893
|
messages: this.cachedHistory,
|
|
1894
|
+
scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
|
|
1835
1895
|
});
|
|
1836
1896
|
}
|
|
1837
1897
|
describeWorkspaceOptions() {
|
|
@@ -1849,6 +1909,75 @@ When working in this codebase:
|
|
|
1849
1909
|
}
|
|
1850
1910
|
return `${warning.label}: ${warning.reason}.`;
|
|
1851
1911
|
}
|
|
1912
|
+
buildLaunchCommandPalette() {
|
|
1913
|
+
const entries = [];
|
|
1914
|
+
const secretsSummary = this.summarizeSecretsForPalette();
|
|
1915
|
+
const toolSummary = this.getToolSelectionSummary();
|
|
1916
|
+
const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
|
|
1917
|
+
for (const command of this.slashCommands) {
|
|
1918
|
+
const entry = {
|
|
1919
|
+
command: command.command,
|
|
1920
|
+
description: command.description,
|
|
1921
|
+
category: command.category ?? 'other',
|
|
1922
|
+
};
|
|
1923
|
+
switch (command.command) {
|
|
1924
|
+
case '/secrets':
|
|
1925
|
+
if (secretsSummary.text) {
|
|
1926
|
+
entry.description = `${command.description} (${secretsSummary.text})`;
|
|
1927
|
+
entry.tone = secretsSummary.tone;
|
|
1928
|
+
}
|
|
1929
|
+
break;
|
|
1930
|
+
case '/tools':
|
|
1931
|
+
if (toolSummary) {
|
|
1932
|
+
entry.description = `${command.description} (${toolSummary})`;
|
|
1933
|
+
}
|
|
1934
|
+
break;
|
|
1935
|
+
case '/sessions':
|
|
1936
|
+
entry.description = `${command.description} (autosave ${autosaveLabel})`;
|
|
1937
|
+
break;
|
|
1938
|
+
case '/model':
|
|
1939
|
+
entry.description = `${command.description} (current: ${this.sessionState.model})`;
|
|
1940
|
+
break;
|
|
1941
|
+
case '/provider':
|
|
1942
|
+
entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
|
|
1943
|
+
break;
|
|
1944
|
+
default:
|
|
1945
|
+
break;
|
|
1946
|
+
}
|
|
1947
|
+
entries.push(entry);
|
|
1948
|
+
}
|
|
1949
|
+
return entries;
|
|
1950
|
+
}
|
|
1951
|
+
summarizeSecretsForPalette() {
|
|
1952
|
+
const definitions = listSecretDefinitions();
|
|
1953
|
+
if (!definitions.length) {
|
|
1954
|
+
return { text: null };
|
|
1955
|
+
}
|
|
1956
|
+
const missing = definitions.filter((definition) => !getSecretValue(definition.id));
|
|
1957
|
+
if (missing.length === 0) {
|
|
1958
|
+
return { text: 'all configured', tone: 'success' };
|
|
1959
|
+
}
|
|
1960
|
+
const labels = missing.map((definition) => definition.label ?? definition.id);
|
|
1961
|
+
return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
|
|
1962
|
+
}
|
|
1963
|
+
getToolSelectionSummary() {
|
|
1964
|
+
const toolSettings = loadToolSettings();
|
|
1965
|
+
const selection = buildEnabledToolSet(toolSettings);
|
|
1966
|
+
const options = getToolToggleOptions();
|
|
1967
|
+
if (!options.length) {
|
|
1968
|
+
return null;
|
|
1969
|
+
}
|
|
1970
|
+
const enabledCount = options.filter((option) => selection.has(option.id)).length;
|
|
1971
|
+
return `${enabledCount}/${options.length} enabled`;
|
|
1972
|
+
}
|
|
1973
|
+
formatList(values, maxItems = 3) {
|
|
1974
|
+
if (!values.length) {
|
|
1975
|
+
return '';
|
|
1976
|
+
}
|
|
1977
|
+
const shown = values.slice(0, maxItems);
|
|
1978
|
+
const suffix = values.length > maxItems ? ', …' : '';
|
|
1979
|
+
return `${shown.join(', ')}${suffix}`;
|
|
1980
|
+
}
|
|
1852
1981
|
buildSlashCommandList(header) {
|
|
1853
1982
|
const lines = [theme.gradient.primary(header), ''];
|
|
1854
1983
|
for (const command of this.slashCommands) {
|
|
@@ -2317,7 +2446,7 @@ When working in this codebase:
|
|
|
2317
2446
|
this.autosaveIfEnabled();
|
|
2318
2447
|
// Track metrics with Alpha Zero 2
|
|
2319
2448
|
const elapsedMs = Date.now() - requestStartTime;
|
|
2320
|
-
this.
|
|
2449
|
+
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
2321
2450
|
if (!responseText?.trim()) {
|
|
2322
2451
|
display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
|
|
2323
2452
|
}
|
|
@@ -2335,14 +2464,10 @@ When working in this codebase:
|
|
|
2335
2464
|
this.stopStreamingHeartbeat();
|
|
2336
2465
|
this.isProcessing = false;
|
|
2337
2466
|
this.terminalInput.setStreaming(false);
|
|
2338
|
-
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2339
2467
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2340
2468
|
this.setIdleStatus();
|
|
2341
2469
|
display.newLine();
|
|
2342
2470
|
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();
|
|
2346
2471
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
2347
2472
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
2348
2473
|
// Claude Code style: New prompt naturally appears at bottom
|
|
@@ -2419,13 +2544,14 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
2419
2544
|
try {
|
|
2420
2545
|
// Send the request and capture the response (streaming disabled)
|
|
2421
2546
|
display.showThinking('Responding...');
|
|
2547
|
+
this.refreshStatusLine(true);
|
|
2422
2548
|
const response = await agent.send(currentPrompt, true);
|
|
2423
2549
|
await this.awaitPendingCleanup();
|
|
2424
2550
|
this.captureHistorySnapshot();
|
|
2425
2551
|
this.autosaveIfEnabled();
|
|
2426
2552
|
// Track metrics
|
|
2427
2553
|
const elapsedMs = Date.now() - overallStartTime;
|
|
2428
|
-
this.
|
|
2554
|
+
this.alphaZeroMetrics.recordMessage(elapsedMs);
|
|
2429
2555
|
if (!response?.trim()) {
|
|
2430
2556
|
display.showWarning('Model returned an empty response. Retrying this iteration...');
|
|
2431
2557
|
consecutiveNoProgress++;
|
|
@@ -2562,7 +2688,6 @@ What's the next action?`;
|
|
|
2562
2688
|
this.stopStreamingHeartbeat();
|
|
2563
2689
|
this.isProcessing = false;
|
|
2564
2690
|
this.terminalInput.setStreaming(false);
|
|
2565
|
-
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
2566
2691
|
this.uiAdapter.endProcessing('Ready for prompts');
|
|
2567
2692
|
this.setIdleStatus();
|
|
2568
2693
|
this.updateStatusMessage(null);
|
|
@@ -2919,8 +3044,10 @@ What's the next action?`;
|
|
|
2919
3044
|
try {
|
|
2920
3045
|
// Send the error to the agent for fixing
|
|
2921
3046
|
display.showThinking('Analyzing build errors');
|
|
3047
|
+
this.refreshStatusLine(true);
|
|
2922
3048
|
const response = await this.agent.send(prompt, true);
|
|
2923
3049
|
display.stopThinking();
|
|
3050
|
+
this.refreshStatusLine(true);
|
|
2924
3051
|
if (response) {
|
|
2925
3052
|
display.showAssistantMessage(response, { isFinal: true });
|
|
2926
3053
|
}
|
|
@@ -2947,8 +3074,8 @@ What's the next action?`;
|
|
|
2947
3074
|
};
|
|
2948
3075
|
this.agent = this.runtimeSession.createAgent(selection, {
|
|
2949
3076
|
onStreamChunk: (chunk) => {
|
|
2950
|
-
// Stream output
|
|
2951
|
-
|
|
3077
|
+
// Stream output using clean streamContent() - chat box floats below
|
|
3078
|
+
this.terminalInput.streamContent(chunk);
|
|
2952
3079
|
},
|
|
2953
3080
|
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
2954
3081
|
onAssistantMessage: (content, metadata) => {
|
|
@@ -2970,18 +3097,16 @@ What's the next action?`;
|
|
|
2970
3097
|
display.showAssistantMessage(finalContent, enriched);
|
|
2971
3098
|
}
|
|
2972
3099
|
}
|
|
2973
|
-
//
|
|
3100
|
+
// Status shown in mode controls bar - no separate status line needed
|
|
2974
3101
|
display.stopThinking();
|
|
2975
|
-
//
|
|
2976
|
-
let contextInfo;
|
|
3102
|
+
// Update context usage for mode controls display
|
|
2977
3103
|
if (enriched.contextWindowTokens && metadata.usage) {
|
|
2978
3104
|
const total = this.totalTokens(metadata.usage);
|
|
2979
3105
|
if (total && total > 0) {
|
|
2980
3106
|
const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
|
|
2981
|
-
|
|
3107
|
+
this.updateContextUsage(percentage);
|
|
2982
3108
|
}
|
|
2983
3109
|
}
|
|
2984
|
-
display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
|
|
2985
3110
|
// Auto-verify changes: build first (catches type errors), then tests
|
|
2986
3111
|
void this.enforceAutoBuild('final-response');
|
|
2987
3112
|
void this.enforceAutoTests('final-response');
|
|
@@ -3051,7 +3176,6 @@ What's the next action?`;
|
|
|
3051
3176
|
this.stopStreamingHeartbeat();
|
|
3052
3177
|
this.updateStatusMessage(null);
|
|
3053
3178
|
this.terminalInput.setStreaming(false);
|
|
3054
|
-
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3055
3179
|
this.terminalInput.render();
|
|
3056
3180
|
},
|
|
3057
3181
|
onVerificationNeeded: () => {
|
|
@@ -3088,7 +3212,6 @@ What's the next action?`;
|
|
|
3088
3212
|
resetChatBoxAfterModelSwap() {
|
|
3089
3213
|
this.updateStatusMessage(null);
|
|
3090
3214
|
this.terminalInput.setStreaming(false);
|
|
3091
|
-
this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
|
|
3092
3215
|
this.terminalInput.render();
|
|
3093
3216
|
this.ensureReadlineReady();
|
|
3094
3217
|
}
|
|
@@ -3153,9 +3276,14 @@ What's the next action?`;
|
|
|
3153
3276
|
return null;
|
|
3154
3277
|
}
|
|
3155
3278
|
const usageRatio = total / windowTokens;
|
|
3279
|
+
this.latestTokenUsage = {
|
|
3280
|
+
used: total,
|
|
3281
|
+
limit: windowTokens,
|
|
3282
|
+
};
|
|
3156
3283
|
// Always update context usage in the UI
|
|
3157
3284
|
const percentUsed = Math.round(usageRatio * 100);
|
|
3158
3285
|
this.updateContextUsage(percentUsed);
|
|
3286
|
+
this.refreshStatusLine(true);
|
|
3159
3287
|
if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
|
|
3160
3288
|
return null;
|
|
3161
3289
|
}
|
|
@@ -3422,6 +3550,113 @@ What's the next action?`;
|
|
|
3422
3550
|
this.sessionState.reasoningEffort = preset.reasoningEffort;
|
|
3423
3551
|
}
|
|
3424
3552
|
}
|
|
3553
|
+
/**
|
|
3554
|
+
* Build the session banner with comprehensive feature status.
|
|
3555
|
+
*/
|
|
3556
|
+
buildBanner() {
|
|
3557
|
+
const terminalWidth = output.columns ?? 100;
|
|
3558
|
+
const width = Math.min(terminalWidth - 4, 110);
|
|
3559
|
+
// Collect tool categories for display
|
|
3560
|
+
const toolCategories = this.collectToolCategories();
|
|
3561
|
+
return renderSessionFrame({
|
|
3562
|
+
profileLabel: this.profileLabel,
|
|
3563
|
+
profileName: this.profile,
|
|
3564
|
+
model: this.sessionState.model,
|
|
3565
|
+
provider: this.sessionState.provider,
|
|
3566
|
+
workspace: this.workingDir,
|
|
3567
|
+
version: this.version,
|
|
3568
|
+
width,
|
|
3569
|
+
features: {
|
|
3570
|
+
verification: this.verificationEnabled,
|
|
3571
|
+
autoContinue: this.autoContinueEnabled,
|
|
3572
|
+
thinkingMode: this.thinkingMode,
|
|
3573
|
+
plugins: this._enabledPlugins,
|
|
3574
|
+
tools: toolCategories,
|
|
3575
|
+
sessionId: this.activeSessionId ?? undefined,
|
|
3576
|
+
},
|
|
3577
|
+
});
|
|
3578
|
+
}
|
|
3579
|
+
/**
|
|
3580
|
+
* Collect tool categories for banner display.
|
|
3581
|
+
*/
|
|
3582
|
+
collectToolCategories() {
|
|
3583
|
+
const categories = [];
|
|
3584
|
+
try {
|
|
3585
|
+
const providerTools = this.runtimeSession.toolRuntime.listProviderTools();
|
|
3586
|
+
if (providerTools.length > 0) {
|
|
3587
|
+
// Group by category (first word of tool name or namespace)
|
|
3588
|
+
const groups = new Map();
|
|
3589
|
+
for (const tool of providerTools) {
|
|
3590
|
+
const category = this.extractToolCategory(tool.name);
|
|
3591
|
+
groups.set(category, (groups.get(category) || 0) + 1);
|
|
3592
|
+
}
|
|
3593
|
+
// Convert to array sorted by count
|
|
3594
|
+
const sorted = Array.from(groups.entries())
|
|
3595
|
+
.sort((a, b) => b[1] - a[1])
|
|
3596
|
+
.slice(0, 5); // Top 5 categories
|
|
3597
|
+
for (const [name, count] of sorted) {
|
|
3598
|
+
categories.push({ name, count, icon: this.getToolCategoryIcon(name) });
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
catch {
|
|
3603
|
+
// Ignore errors in tool collection
|
|
3604
|
+
}
|
|
3605
|
+
return categories;
|
|
3606
|
+
}
|
|
3607
|
+
/**
|
|
3608
|
+
* Extract category from tool name.
|
|
3609
|
+
*/
|
|
3610
|
+
extractToolCategory(toolName) {
|
|
3611
|
+
// Common tool prefixes
|
|
3612
|
+
const prefixMap = {
|
|
3613
|
+
git: 'Git',
|
|
3614
|
+
npm: 'NPM',
|
|
3615
|
+
bash: 'Shell',
|
|
3616
|
+
file: 'Files',
|
|
3617
|
+
read: 'Files',
|
|
3618
|
+
write: 'Files',
|
|
3619
|
+
edit: 'Files',
|
|
3620
|
+
search: 'Search',
|
|
3621
|
+
glob: 'Search',
|
|
3622
|
+
grep: 'Search',
|
|
3623
|
+
web: 'Web',
|
|
3624
|
+
fetch: 'Web',
|
|
3625
|
+
test: 'Testing',
|
|
3626
|
+
build: 'Build',
|
|
3627
|
+
deploy: 'Deploy',
|
|
3628
|
+
cloud: 'Cloud',
|
|
3629
|
+
browser: 'Browser',
|
|
3630
|
+
};
|
|
3631
|
+
const lower = toolName.toLowerCase();
|
|
3632
|
+
for (const [prefix, category] of Object.entries(prefixMap)) {
|
|
3633
|
+
if (lower.startsWith(prefix)) {
|
|
3634
|
+
return category;
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
// Default to first word capitalized
|
|
3638
|
+
const firstWord = toolName.split(/[_\-\s]/)[0] || 'Other';
|
|
3639
|
+
return firstWord.charAt(0).toUpperCase() + firstWord.slice(1).toLowerCase();
|
|
3640
|
+
}
|
|
3641
|
+
/**
|
|
3642
|
+
* Get icon for tool category.
|
|
3643
|
+
*/
|
|
3644
|
+
getToolCategoryIcon(category) {
|
|
3645
|
+
const icons = {
|
|
3646
|
+
Git: '⎇',
|
|
3647
|
+
NPM: '📦',
|
|
3648
|
+
Shell: '⌘',
|
|
3649
|
+
Files: '📁',
|
|
3650
|
+
Search: '🔍',
|
|
3651
|
+
Web: '🌐',
|
|
3652
|
+
Testing: '🧪',
|
|
3653
|
+
Build: '🔧',
|
|
3654
|
+
Deploy: '🚀',
|
|
3655
|
+
Cloud: '☁',
|
|
3656
|
+
Browser: '🌐',
|
|
3657
|
+
};
|
|
3658
|
+
return icons[category] || '⚙';
|
|
3659
|
+
}
|
|
3425
3660
|
refreshBannerSessionInfo() {
|
|
3426
3661
|
const nextState = {
|
|
3427
3662
|
model: this.sessionState.model,
|
|
@@ -3432,13 +3667,11 @@ What's the next action?`;
|
|
|
3432
3667
|
return;
|
|
3433
3668
|
}
|
|
3434
3669
|
this.refreshContextGauge();
|
|
3435
|
-
display
|
|
3436
|
-
//
|
|
3437
|
-
this.terminalInput.setModelInfo(this.describeModelDetail());
|
|
3670
|
+
// Banner is no longer stored in display - it was streamed as content
|
|
3671
|
+
// Model/provider changes are visible in the control bar
|
|
3438
3672
|
if (!this.isProcessing) {
|
|
3439
3673
|
this.setIdleStatus();
|
|
3440
3674
|
}
|
|
3441
|
-
// Pinned header rows are disabled; scroll region handles all output.
|
|
3442
3675
|
this.bannerSessionState = nextState;
|
|
3443
3676
|
}
|
|
3444
3677
|
providerLabel(id) {
|