erosolar-cli 1.5.2 → 1.5.4
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/config/security-deployment.json +54 -0
- package/dist/bin/adapters/node/index.js +33 -0
- package/dist/bin/adapters/types.js +1 -0
- package/dist/bin/alpha-zero/agentWrapper.js +165 -0
- package/dist/bin/alpha-zero/codeEvaluator.js +272 -0
- package/dist/bin/alpha-zero/competitiveRunner.js +219 -0
- package/dist/bin/alpha-zero/index.js +98 -0
- package/dist/bin/alpha-zero/introspection.js +298 -0
- package/dist/bin/alpha-zero/metricsTracker.js +207 -0
- package/dist/bin/alpha-zero/security/core.js +269 -0
- package/dist/bin/alpha-zero/security/google.js +308 -0
- package/dist/bin/alpha-zero/security/googleLoader.js +40 -0
- package/dist/bin/alpha-zero/security/index.js +31 -0
- package/dist/bin/alpha-zero/security/simulation.js +274 -0
- package/dist/bin/alpha-zero/selfModification.js +231 -0
- package/dist/bin/alpha-zero/types.js +30 -0
- package/dist/bin/bin/erosolar-optimized.js +205 -0
- package/dist/bin/capabilities/agentSpawningCapability.js +116 -0
- package/dist/bin/capabilities/bashCapability.js +22 -0
- package/dist/bin/capabilities/cloudCapability.js +36 -0
- package/dist/bin/capabilities/codeAnalysisCapability.js +22 -0
- package/dist/bin/capabilities/codeQualityCapability.js +23 -0
- package/dist/bin/capabilities/dependencySecurityCapability.js +22 -0
- package/dist/bin/capabilities/devCapability.js +22 -0
- package/dist/bin/capabilities/editCapability.js +28 -0
- package/dist/bin/capabilities/emailCapability.js +20 -0
- package/dist/bin/capabilities/enhancedGitCapability.js +221 -0
- package/dist/bin/capabilities/filesystemCapability.js +22 -0
- package/dist/bin/capabilities/globCapability.js +28 -0
- package/dist/bin/capabilities/interactionCapability.js +20 -0
- package/dist/bin/capabilities/learnCapability.js +22 -0
- package/dist/bin/capabilities/mcpCapability.js +20 -0
- package/dist/bin/capabilities/notebookCapability.js +28 -0
- package/dist/bin/capabilities/planningCapability.js +27 -0
- package/dist/bin/capabilities/refactoringCapability.js +23 -0
- package/dist/bin/capabilities/repoChecksCapability.js +22 -0
- package/dist/bin/capabilities/searchCapability.js +22 -0
- package/dist/bin/capabilities/skillCapability.js +76 -0
- package/dist/bin/capabilities/taskManagementCapability.js +20 -0
- package/dist/bin/capabilities/testingCapability.js +23 -0
- package/dist/bin/capabilities/toolManifest.js +159 -0
- package/dist/bin/capabilities/toolRegistry.js +114 -0
- package/dist/bin/capabilities/webCapability.js +20 -0
- package/dist/bin/config.js +139 -0
- package/dist/bin/contracts/v1/agent.js +7 -0
- package/dist/bin/contracts/v1/agentProfileManifest.js +8 -0
- package/dist/bin/contracts/v1/agentRules.js +9 -0
- package/dist/bin/contracts/v1/toolAccess.js +8 -0
- package/dist/bin/core/agent.js +362 -0
- package/dist/bin/core/agentProfileManifest.js +187 -0
- package/dist/bin/core/agentProfiles.js +34 -0
- package/dist/bin/core/agentRulebook.js +135 -0
- package/dist/bin/core/agentSchemaLoader.js +233 -0
- package/dist/bin/core/contextManager.js +412 -0
- package/dist/bin/core/contextWindow.js +122 -0
- package/dist/bin/core/customCommands.js +80 -0
- package/dist/bin/core/errors/apiKeyErrors.js +114 -0
- package/dist/bin/core/errors/errorTypes.js +340 -0
- package/dist/bin/core/errors/safetyValidator.js +304 -0
- package/dist/bin/core/errors.js +32 -0
- package/dist/bin/core/modelDiscovery.js +755 -0
- package/dist/bin/core/preferences.js +224 -0
- package/dist/bin/core/schemaValidator.js +92 -0
- package/dist/bin/core/secretStore.js +199 -0
- package/dist/bin/core/sessionStore.js +187 -0
- package/dist/bin/core/toolRuntime.js +290 -0
- package/dist/bin/core/types.js +1 -0
- package/dist/bin/erosolar-optimized.d.ts +12 -0
- package/dist/bin/erosolar-optimized.d.ts.map +1 -0
- package/dist/bin/erosolar-optimized.js +239 -0
- package/dist/bin/erosolar-optimized.js.map +1 -0
- package/dist/bin/erosolar.js +14 -0
- package/dist/bin/erosolar.js.map +1 -1
- package/dist/bin/headless/headlessApp.js +172 -0
- package/dist/bin/mcp/config.js +202 -0
- package/dist/bin/mcp/stdioClient.js +172 -0
- package/dist/bin/mcp/toolBridge.js +104 -0
- package/dist/bin/mcp/types.js +1 -0
- package/dist/bin/plugins/index.js +113 -0
- package/dist/bin/plugins/providers/anthropic/index.js +25 -0
- package/dist/bin/plugins/providers/deepseek/index.js +24 -0
- package/dist/bin/plugins/providers/google/index.js +26 -0
- package/dist/bin/plugins/providers/index.js +19 -0
- package/dist/bin/plugins/providers/ollama/index.js +59 -0
- package/dist/bin/plugins/providers/openai/index.js +26 -0
- package/dist/bin/plugins/providers/xai/index.js +24 -0
- package/dist/bin/plugins/tools/agentSpawning/agentSpawningPlugin.js +8 -0
- package/dist/bin/plugins/tools/bash/localBashPlugin.js +13 -0
- package/dist/bin/plugins/tools/checks/localRepoChecksPlugin.js +13 -0
- package/dist/bin/plugins/tools/cloud/cloudPlugin.js +13 -0
- package/dist/bin/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +13 -0
- package/dist/bin/plugins/tools/codeQuality/codeQualityPlugin.js +13 -0
- package/dist/bin/plugins/tools/dependency/dependencyPlugin.js +11 -0
- package/dist/bin/plugins/tools/development/devPlugin.js +13 -0
- package/dist/bin/plugins/tools/edit/editPlugin.js +14 -0
- package/dist/bin/plugins/tools/email/emailPlugin.js +11 -0
- package/dist/bin/plugins/tools/enhancedGit/enhancedGitPlugin.js +8 -0
- package/dist/bin/plugins/tools/filesystem/localFilesystemPlugin.js +13 -0
- package/dist/bin/plugins/tools/glob/globPlugin.js +14 -0
- package/dist/bin/plugins/tools/index.js +2 -0
- package/dist/bin/plugins/tools/interaction/interactionPlugin.js +11 -0
- package/dist/bin/plugins/tools/learn/learnPlugin.js +13 -0
- package/dist/bin/plugins/tools/mcp/mcpPlugin.js +8 -0
- package/dist/bin/plugins/tools/nodeDefaults.js +56 -0
- package/dist/bin/plugins/tools/notebook/notebookPlugin.js +14 -0
- package/dist/bin/plugins/tools/planning/planningPlugin.js +14 -0
- package/dist/bin/plugins/tools/refactoring/refactoringPlugin.js +11 -0
- package/dist/bin/plugins/tools/registry.js +57 -0
- package/dist/bin/plugins/tools/search/localSearchPlugin.js +13 -0
- package/dist/bin/plugins/tools/skills/skillPlugin.js +8 -0
- package/dist/bin/plugins/tools/taskManagement/taskManagementPlugin.js +11 -0
- package/dist/bin/plugins/tools/testing/testingPlugin.js +11 -0
- package/dist/bin/plugins/tools/web/webPlugin.js +11 -0
- package/dist/bin/providers/anthropicProvider.js +329 -0
- package/dist/bin/providers/googleProvider.js +203 -0
- package/dist/bin/providers/openaiChatCompletionsProvider.js +208 -0
- package/dist/bin/providers/openaiResponsesProvider.js +249 -0
- package/dist/bin/providers/providerFactory.js +24 -0
- package/dist/bin/runtime/agentController.js +321 -0
- package/dist/bin/runtime/agentHost.js +153 -0
- package/dist/bin/runtime/agentSession.js +195 -0
- package/dist/bin/runtime/node.js +10 -0
- package/dist/bin/runtime/universal.js +28 -0
- package/dist/bin/shell/bracketedPasteManager.js +350 -0
- package/dist/bin/shell/fileChangeTracker.js +65 -0
- package/dist/bin/shell/interactiveShell.js +2908 -0
- package/dist/bin/shell/liveStatus.js +78 -0
- package/dist/bin/shell/shellApp.js +290 -0
- package/dist/bin/shell/systemPrompt.js +60 -0
- package/dist/bin/shell/updateManager.js +108 -0
- package/dist/bin/skills/skillRepository.js +236 -0
- package/dist/bin/skills/types.js +1 -0
- package/dist/bin/subagents/taskRunner.js +269 -0
- package/dist/bin/tools/backgroundBashTools.js +211 -0
- package/dist/bin/tools/bashTools.js +159 -0
- package/dist/bin/tools/cloudTools.js +864 -0
- package/dist/bin/tools/codeAnalysisTools.js +641 -0
- package/dist/bin/tools/codeQualityTools.js +294 -0
- package/dist/bin/tools/dependencyTools.js +282 -0
- package/dist/bin/tools/devTools.js +238 -0
- package/dist/bin/tools/diffUtils.js +137 -0
- package/dist/bin/tools/editTools.js +134 -0
- package/dist/bin/tools/emailTools.js +448 -0
- package/dist/bin/tools/fileTools.js +282 -0
- package/dist/bin/tools/globTools.js +173 -0
- package/dist/bin/tools/grepTools.js +332 -0
- package/dist/bin/tools/interactionTools.js +170 -0
- package/dist/bin/tools/learnTools.js +1818 -0
- package/dist/bin/tools/notebookEditTools.js +196 -0
- package/dist/bin/tools/planningTools.js +46 -0
- package/dist/bin/tools/refactoringTools.js +293 -0
- package/dist/bin/tools/repoChecksTools.js +160 -0
- package/dist/bin/tools/searchTools.js +206 -0
- package/dist/bin/tools/skillTools.js +177 -0
- package/dist/bin/tools/taskManagementTools.js +156 -0
- package/dist/bin/tools/testingTools.js +232 -0
- package/dist/bin/tools/webTools.js +480 -0
- package/dist/bin/ui/ShellUIAdapter.js +459 -0
- package/dist/bin/ui/UnifiedUIController.js +183 -0
- package/dist/bin/ui/animation/AnimationScheduler.js +430 -0
- package/dist/bin/ui/codeHighlighter.js +854 -0
- package/dist/bin/ui/designSystem.js +121 -0
- package/dist/bin/ui/display.js +1222 -0
- package/dist/bin/ui/interrupts/InterruptManager.js +437 -0
- package/dist/bin/ui/layout.js +139 -0
- package/dist/bin/ui/orchestration/StatusOrchestrator.js +403 -0
- package/dist/bin/ui/outputMode.js +38 -0
- package/dist/bin/ui/persistentPrompt.js +183 -0
- package/dist/bin/ui/richText.js +338 -0
- package/dist/bin/ui/shortcutsHelp.js +87 -0
- package/dist/bin/ui/telemetry/UITelemetry.js +443 -0
- package/dist/bin/ui/textHighlighter.js +210 -0
- package/dist/bin/ui/theme.js +116 -0
- package/dist/bin/ui/toolDisplay.js +423 -0
- package/dist/bin/ui/toolDisplayAdapter.js +357 -0
- package/dist/bin/workspace.js +106 -0
- package/dist/bin/workspace.validator.js +213 -0
- package/dist/capabilities/cloudCapability.d.ts +13 -0
- package/dist/capabilities/cloudCapability.d.ts.map +1 -0
- package/dist/capabilities/cloudCapability.js +38 -0
- package/dist/capabilities/cloudCapability.js.map +1 -0
- package/dist/capabilities/index.d.ts +1 -0
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +1 -0
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/offensiveSecurityCapability.d.ts +26 -0
- package/dist/capabilities/offensiveSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/offensiveSecurityCapability.js +58 -0
- package/dist/capabilities/offensiveSecurityCapability.js.map +1 -0
- package/dist/capabilities/realSecurityCapability.d.ts +26 -0
- package/dist/capabilities/realSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/realSecurityCapability.js +53 -0
- package/dist/capabilities/realSecurityCapability.js.map +1 -0
- package/dist/capabilities/securityCapability.d.ts +32 -0
- package/dist/capabilities/securityCapability.d.ts.map +1 -0
- package/dist/capabilities/securityCapability.js +57 -0
- package/dist/capabilities/securityCapability.js.map +1 -0
- package/dist/capabilities/ultimateSecurityCapability.d.ts +42 -0
- package/dist/capabilities/ultimateSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/ultimateSecurityCapability.js +96 -0
- package/dist/capabilities/ultimateSecurityCapability.js.map +1 -0
- package/dist/core/LazyLoader.d.ts +129 -0
- package/dist/core/LazyLoader.d.ts.map +1 -0
- package/dist/core/LazyLoader.js +240 -0
- package/dist/core/LazyLoader.js.map +1 -0
- package/dist/core/intelligenceTools.d.ts +19 -0
- package/dist/core/intelligenceTools.d.ts.map +1 -0
- package/dist/core/intelligenceTools.js +453 -0
- package/dist/core/intelligenceTools.js.map +1 -0
- package/dist/core/operationalTools.d.ts +19 -0
- package/dist/core/operationalTools.d.ts.map +1 -0
- package/dist/core/operationalTools.js +467 -0
- package/dist/core/operationalTools.js.map +1 -0
- package/dist/offensive/core/offensive-engine.d.ts +171 -0
- package/dist/offensive/core/offensive-engine.d.ts.map +1 -0
- package/dist/offensive/core/offensive-engine.js +345 -0
- package/dist/offensive/core/offensive-engine.js.map +1 -0
- package/dist/offensive/core/offensive-integration.d.ts +129 -0
- package/dist/offensive/core/offensive-integration.d.ts.map +1 -0
- package/dist/offensive/core/offensive-integration.js +364 -0
- package/dist/offensive/core/offensive-integration.js.map +1 -0
- package/dist/offensive/core/offensive-tools.d.ts +55 -0
- package/dist/offensive/core/offensive-tools.d.ts.map +1 -0
- package/dist/offensive/core/offensive-tools.js +438 -0
- package/dist/offensive/core/offensive-tools.js.map +1 -0
- package/dist/offensive/offensive-cli.d.ts +48 -0
- package/dist/offensive/offensive-cli.d.ts.map +1 -0
- package/dist/offensive/offensive-cli.js +233 -0
- package/dist/offensive/offensive-cli.js.map +1 -0
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts +3 -0
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/cloud/cloudPlugin.js +14 -0
- package/dist/plugins/tools/cloud/cloudPlugin.js.map +1 -0
- package/dist/plugins/tools/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/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/apt-simulation-cli.d.ts +57 -0
- package/dist/security/apt-simulation-cli.d.ts.map +1 -0
- package/dist/security/apt-simulation-cli.js +278 -0
- package/dist/security/apt-simulation-cli.js.map +1 -0
- package/dist/security/apt-simulation-engine-complete.d.ts +97 -0
- package/dist/security/apt-simulation-engine-complete.d.ts.map +1 -0
- package/dist/security/apt-simulation-engine-complete.js +441 -0
- package/dist/security/apt-simulation-engine-complete.js.map +1 -0
- package/dist/security/apt-simulation-engine.d.ts +97 -0
- package/dist/security/apt-simulation-engine.d.ts.map +1 -0
- package/dist/security/apt-simulation-engine.js +441 -0
- package/dist/security/apt-simulation-engine.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/authorization.d.ts +45 -0
- package/dist/security/authorization.d.ts.map +1 -0
- package/dist/security/authorization.js +128 -0
- package/dist/security/authorization.js.map +1 -0
- package/dist/security/comprehensive-security-research.d.ts +84 -0
- package/dist/security/comprehensive-security-research.d.ts.map +1 -0
- package/dist/security/comprehensive-security-research.js +211 -0
- package/dist/security/comprehensive-security-research.js.map +1 -0
- package/dist/security/offensive/exploitationEngine.d.ts +54 -0
- package/dist/security/offensive/exploitationEngine.d.ts.map +1 -0
- package/dist/security/offensive/exploitationEngine.js +263 -0
- package/dist/security/offensive/exploitationEngine.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 +100 -0
- package/dist/security/persistence-research.d.ts.map +1 -0
- package/dist/security/persistence-research.js +372 -0
- package/dist/security/persistence-research.js.map +1 -0
- package/dist/security/real/networkExploitation.d.ts +92 -0
- package/dist/security/real/networkExploitation.d.ts.map +1 -0
- package/dist/security/real/networkExploitation.js +316 -0
- package/dist/security/real/networkExploitation.js.map +1 -0
- package/dist/security/real/persistenceImplementation.d.ts +62 -0
- package/dist/security/real/persistenceImplementation.d.ts.map +1 -0
- package/dist/security/real/persistenceImplementation.js +323 -0
- package/dist/security/real/persistenceImplementation.js.map +1 -0
- package/dist/security/real/vulnerabilityScanner.d.ts +73 -0
- package/dist/security/real/vulnerabilityScanner.d.ts.map +1 -0
- package/dist/security/real/vulnerabilityScanner.js +341 -0
- package/dist/security/real/vulnerabilityScanner.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-testing-framework.d.ts +120 -0
- package/dist/security/security-testing-framework.d.ts.map +1 -0
- package/dist/security/security-testing-framework.js +372 -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/shell/bracketedPasteManager.d.ts +76 -0
- package/dist/shell/bracketedPasteManager.d.ts.map +1 -1
- package/dist/shell/bracketedPasteManager.js +267 -9
- package/dist/shell/bracketedPasteManager.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +34 -1
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +304 -24
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/taskCompletionDetector.d.ts +101 -0
- package/dist/shell/taskCompletionDetector.d.ts.map +1 -0
- package/dist/shell/taskCompletionDetector.js +343 -0
- package/dist/shell/taskCompletionDetector.js.map +1 -0
- package/dist/tools/cloudTools.d.ts +57 -0
- package/dist/tools/cloudTools.d.ts.map +1 -0
- package/dist/tools/cloudTools.js +865 -0
- package/dist/tools/cloudTools.js.map +1 -0
- package/dist/tools/enhancedSecurityTools.d.ts +19 -0
- package/dist/tools/enhancedSecurityTools.d.ts.map +1 -0
- package/dist/tools/enhancedSecurityTools.js +215 -0
- package/dist/tools/enhancedSecurityTools.js.map +1 -0
- package/dist/tools/offensiveSecurityTools.d.ts +16 -0
- package/dist/tools/offensiveSecurityTools.d.ts.map +1 -0
- package/dist/tools/offensiveSecurityTools.js +285 -0
- package/dist/tools/offensiveSecurityTools.js.map +1 -0
- package/dist/tools/realSecurityTools.d.ts +18 -0
- package/dist/tools/realSecurityTools.d.ts.map +1 -0
- package/dist/tools/realSecurityTools.js +468 -0
- package/dist/tools/realSecurityTools.js.map +1 -0
- package/dist/tools/securityTools.d.ts +20 -0
- package/dist/tools/securityTools.d.ts.map +1 -0
- package/dist/tools/securityTools.js +449 -0
- package/dist/tools/securityTools.js.map +1 -0
- package/package.json +27 -12
- package/scripts/deploy-security-capabilities.js +178 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Display Adapter - Integrates Claude Code style display with ShellUIAdapter
|
|
3
|
+
*
|
|
4
|
+
* Provides high-level interface for displaying tool executions with
|
|
5
|
+
* Claude Code's clean formatting.
|
|
6
|
+
*/
|
|
7
|
+
import { formatToolCall, formatToolResult, formatDiff, formatDiffSummary, formatThinking, formatDuration, } from './toolDisplay.js';
|
|
8
|
+
import { theme } from './theme.js';
|
|
9
|
+
export class ToolDisplayAdapter {
|
|
10
|
+
constructor(display) {
|
|
11
|
+
this.activeTools = new Map();
|
|
12
|
+
this.display = display;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Show tool call starting
|
|
16
|
+
*/
|
|
17
|
+
showToolStart(call) {
|
|
18
|
+
this.activeTools.set(call.id, {
|
|
19
|
+
call,
|
|
20
|
+
startTime: Date.now(),
|
|
21
|
+
});
|
|
22
|
+
const display = {
|
|
23
|
+
name: call.name,
|
|
24
|
+
args: call.arguments ?? {},
|
|
25
|
+
timestamp: Date.now(),
|
|
26
|
+
};
|
|
27
|
+
const formatted = formatToolCall(display, { includePrefix: false });
|
|
28
|
+
// Claude Code style: show tool call with ⏺ prefix (handled by showAction)
|
|
29
|
+
this.display.showAction(formatted);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Show tool result
|
|
33
|
+
*/
|
|
34
|
+
showToolResult(callId, output, status = 'success') {
|
|
35
|
+
const active = this.activeTools.get(callId);
|
|
36
|
+
const duration = active ? Date.now() - active.startTime : undefined;
|
|
37
|
+
// Analyze output to create summary
|
|
38
|
+
const summary = this.createResultSummary(active?.call.name ?? 'tool', output, status);
|
|
39
|
+
const lines = output.split('\n');
|
|
40
|
+
const nonEmptyLines = lines.filter(l => l.trim());
|
|
41
|
+
const result = {
|
|
42
|
+
summary,
|
|
43
|
+
fullOutput: output,
|
|
44
|
+
linesShown: Math.min(nonEmptyLines.length, 3),
|
|
45
|
+
totalLines: nonEmptyLines.length,
|
|
46
|
+
status,
|
|
47
|
+
duration,
|
|
48
|
+
};
|
|
49
|
+
const formatted = formatToolResult(result, { includePrefix: false });
|
|
50
|
+
// Claude Code style: show result with ⎿ prefix (using showSubAction)
|
|
51
|
+
// Add duration if available
|
|
52
|
+
if (duration !== undefined && duration > 100) {
|
|
53
|
+
const durationStr = formatDuration(duration);
|
|
54
|
+
this.display.showSubAction(`${formatted} ${theme.ui.muted(`(${durationStr})`)}`, status === 'success' ? 'success' : 'error');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this.display.showSubAction(formatted, status === 'success' ? 'success' : 'error');
|
|
58
|
+
}
|
|
59
|
+
// Show preview of output if it's substantial
|
|
60
|
+
if (nonEmptyLines.length > 0 && this.shouldShowPreview(active?.call.name)) {
|
|
61
|
+
const preview = this.formatOutputPreview(output, active?.call.name, 4);
|
|
62
|
+
if (preview) {
|
|
63
|
+
// Show preview as continuation (more indented)
|
|
64
|
+
this.display.showSystemMessage(preview);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
this.activeTools.delete(callId);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Determine if we should show output preview for this tool
|
|
71
|
+
*/
|
|
72
|
+
shouldShowPreview(toolName) {
|
|
73
|
+
if (!toolName)
|
|
74
|
+
return false;
|
|
75
|
+
// Tools that should show previews
|
|
76
|
+
const showPreviewFor = new Set([
|
|
77
|
+
'Bash', 'bash', 'execute_bash',
|
|
78
|
+
'Grep', 'grep_search',
|
|
79
|
+
'Glob', 'list_files',
|
|
80
|
+
]);
|
|
81
|
+
return showPreviewFor.has(toolName);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Format output preview with proper indentation
|
|
85
|
+
* Handles JSON, structured data, and plain text intelligently
|
|
86
|
+
*/
|
|
87
|
+
formatOutputPreview(output, _toolName, maxLines) {
|
|
88
|
+
const lines = output.split('\n').filter(l => l.trim());
|
|
89
|
+
if (lines.length === 0)
|
|
90
|
+
return null;
|
|
91
|
+
// Try to detect and format JSON
|
|
92
|
+
const jsonFormatted = this.tryFormatJSON(output);
|
|
93
|
+
if (jsonFormatted) {
|
|
94
|
+
return jsonFormatted;
|
|
95
|
+
}
|
|
96
|
+
// Show fewer lines for long content
|
|
97
|
+
const previewLines = lines.slice(0, Math.min(maxLines, lines.length));
|
|
98
|
+
const remaining = lines.length - previewLines.length;
|
|
99
|
+
// Format with indentation (continuing from ⎿ symbol)
|
|
100
|
+
const formatted = previewLines.map(line => {
|
|
101
|
+
// Truncate very long lines
|
|
102
|
+
if (line.length > 100) {
|
|
103
|
+
return ` ${line.slice(0, 97)}...`;
|
|
104
|
+
}
|
|
105
|
+
return ` ${line}`;
|
|
106
|
+
});
|
|
107
|
+
// Add ellipsis if there are more lines
|
|
108
|
+
if (remaining > 0) {
|
|
109
|
+
formatted.push(` ${theme.ui.muted(`… +${remaining} line${remaining === 1 ? '' : 's'} ${theme.ui.muted('(ctrl+o to expand)')}`)}`.trim());
|
|
110
|
+
}
|
|
111
|
+
return formatted.join('\n');
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Try to parse and format output as JSON
|
|
115
|
+
*/
|
|
116
|
+
tryFormatJSON(output) {
|
|
117
|
+
const trimmed = output.trim();
|
|
118
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const parsed = JSON.parse(trimmed);
|
|
123
|
+
const formatted = JSON.stringify(parsed, null, 2);
|
|
124
|
+
// Add basic syntax highlighting
|
|
125
|
+
const highlighted = formatted
|
|
126
|
+
.split('\n')
|
|
127
|
+
.slice(0, 10) // Limit to 10 lines for preview
|
|
128
|
+
.map(line => {
|
|
129
|
+
// Color keys
|
|
130
|
+
line = line.replace(/"([^"]+)":/g, (_, key) => `${theme.info(`"${key}"`)}: `);
|
|
131
|
+
// Color string values
|
|
132
|
+
line = line.replace(/: "([^"]*)"/g, (_, value) => `: ${theme.success(`"${value}"`)}`);
|
|
133
|
+
// Color numbers
|
|
134
|
+
line = line.replace(/: (\d+\.?\d*)/g, (_, num) => `: ${theme.warning(num)}`);
|
|
135
|
+
// Color booleans/null
|
|
136
|
+
line = line.replace(/: (true|false|null)/g, (_, bool) => `: ${theme.secondary(bool)}`);
|
|
137
|
+
return ` ${line}`;
|
|
138
|
+
})
|
|
139
|
+
.join('\n');
|
|
140
|
+
const totalLines = formatted.split('\n').length;
|
|
141
|
+
if (totalLines > 10) {
|
|
142
|
+
return `${highlighted}\n ${theme.ui.muted(`… +${totalLines - 10} lines (ctrl+o to expand)`)}`;
|
|
143
|
+
}
|
|
144
|
+
return highlighted;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Show tool error
|
|
152
|
+
*/
|
|
153
|
+
showToolError(callId, error) {
|
|
154
|
+
this.showToolResult(callId, error, 'error');
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Show diff output (for Edit/Write tools)
|
|
158
|
+
*/
|
|
159
|
+
showDiff(file, additions, removals, diff) {
|
|
160
|
+
// Show summary first (Claude Code style)
|
|
161
|
+
const summary = formatDiffSummary(file, additions, removals);
|
|
162
|
+
this.display.showSubAction(summary);
|
|
163
|
+
// Show formatted diff
|
|
164
|
+
const formatted = formatDiff(diff);
|
|
165
|
+
this.display.showSystemMessage(formatted);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Show thinking indicator
|
|
169
|
+
*/
|
|
170
|
+
showThinking(durationMs) {
|
|
171
|
+
const formatted = formatThinking(durationMs, false);
|
|
172
|
+
this.display.showAction(formatted);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a concise summary from tool output
|
|
176
|
+
* Parses output intelligently to extract meaningful information
|
|
177
|
+
*/
|
|
178
|
+
createResultSummary(toolName, output, status) {
|
|
179
|
+
if (status === 'error') {
|
|
180
|
+
return 'Error';
|
|
181
|
+
}
|
|
182
|
+
if (!toolName) {
|
|
183
|
+
return 'Completed';
|
|
184
|
+
}
|
|
185
|
+
const lines = output.split('\n');
|
|
186
|
+
const nonEmptyLines = lines.filter(l => l.trim());
|
|
187
|
+
// Tool-specific summaries
|
|
188
|
+
switch (toolName) {
|
|
189
|
+
case 'Read':
|
|
190
|
+
case 'read_file': {
|
|
191
|
+
const lineCount = nonEmptyLines.length;
|
|
192
|
+
return `Read ${lineCount} line${lineCount === 1 ? '' : 's'}`;
|
|
193
|
+
}
|
|
194
|
+
case 'Write':
|
|
195
|
+
case 'write_file':
|
|
196
|
+
return 'Wrote file';
|
|
197
|
+
case 'Edit':
|
|
198
|
+
case 'edit_file': {
|
|
199
|
+
// Try to extract addition/removal counts from output
|
|
200
|
+
const addMatch = output.match(/(\d+) addition/);
|
|
201
|
+
const remMatch = output.match(/(\d+) removal/);
|
|
202
|
+
if (addMatch || remMatch) {
|
|
203
|
+
const parts = ['Updated'];
|
|
204
|
+
if (addMatch)
|
|
205
|
+
parts.push(`${addMatch[1]} addition${addMatch[1] === '1' ? '' : 's'}`);
|
|
206
|
+
if (remMatch) {
|
|
207
|
+
if (addMatch)
|
|
208
|
+
parts.push('and');
|
|
209
|
+
parts.push(`${remMatch[1]} removal${remMatch[1] === '1' ? '' : 's'}`);
|
|
210
|
+
}
|
|
211
|
+
return parts.join(' ');
|
|
212
|
+
}
|
|
213
|
+
return 'Updated file';
|
|
214
|
+
}
|
|
215
|
+
case 'Glob':
|
|
216
|
+
case 'list_files': {
|
|
217
|
+
const fileCount = nonEmptyLines.length;
|
|
218
|
+
if (fileCount === 0) {
|
|
219
|
+
return 'No files found';
|
|
220
|
+
}
|
|
221
|
+
return `Found ${fileCount} file${fileCount === 1 ? '' : 's'}`;
|
|
222
|
+
}
|
|
223
|
+
case 'Grep':
|
|
224
|
+
case 'grep_search': {
|
|
225
|
+
// Check output mode from result
|
|
226
|
+
if (output.includes(':')) {
|
|
227
|
+
// Content mode - count lines
|
|
228
|
+
const matchCount = nonEmptyLines.length;
|
|
229
|
+
return `Found ${matchCount} line${matchCount === 1 ? '' : 's'}`;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Files mode - count files
|
|
233
|
+
const fileCount = nonEmptyLines.length;
|
|
234
|
+
return `Found ${fileCount} file${fileCount === 1 ? '' : 's'}`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
case 'Bash':
|
|
238
|
+
case 'bash':
|
|
239
|
+
case 'execute_bash': {
|
|
240
|
+
// Try to parse command output for meaningful summary
|
|
241
|
+
if (nonEmptyLines.length === 0) {
|
|
242
|
+
return 'Completed';
|
|
243
|
+
}
|
|
244
|
+
// Check for common command patterns
|
|
245
|
+
const firstLine = nonEmptyLines[0];
|
|
246
|
+
if (!firstLine) {
|
|
247
|
+
return 'Completed';
|
|
248
|
+
}
|
|
249
|
+
// Git commands
|
|
250
|
+
if (firstLine.includes('On branch')) {
|
|
251
|
+
return 'Git status';
|
|
252
|
+
}
|
|
253
|
+
if (firstLine.includes('commit') || firstLine.includes('Author:')) {
|
|
254
|
+
return 'Git log';
|
|
255
|
+
}
|
|
256
|
+
// Build/test commands
|
|
257
|
+
if (output.includes('error TS') || output.includes('error:')) {
|
|
258
|
+
const errorCount = (output.match(/error/gi) || []).length;
|
|
259
|
+
return `${errorCount} error${errorCount === 1 ? '' : 's'}`;
|
|
260
|
+
}
|
|
261
|
+
if (output.includes('passing') || output.includes('✓')) {
|
|
262
|
+
return 'Tests passed';
|
|
263
|
+
}
|
|
264
|
+
// Default to first line or "Completed"
|
|
265
|
+
if (firstLine.length <= 40) {
|
|
266
|
+
return firstLine;
|
|
267
|
+
}
|
|
268
|
+
return 'Completed';
|
|
269
|
+
}
|
|
270
|
+
case 'WebFetch':
|
|
271
|
+
case 'web_fetch':
|
|
272
|
+
return 'Content fetched';
|
|
273
|
+
case 'WebSearch':
|
|
274
|
+
case 'web_search': {
|
|
275
|
+
// Count search results
|
|
276
|
+
const resultMatch = output.match(/(\d+) results?/i);
|
|
277
|
+
if (resultMatch) {
|
|
278
|
+
return `Found ${resultMatch[1]} results`;
|
|
279
|
+
}
|
|
280
|
+
return 'Results retrieved';
|
|
281
|
+
}
|
|
282
|
+
case 'Task':
|
|
283
|
+
case 'SubAgent': {
|
|
284
|
+
// For task/subagent, try to extract completion message
|
|
285
|
+
const lastLine = nonEmptyLines[nonEmptyLines.length - 1];
|
|
286
|
+
if (lastLine && lastLine.length <= 50) {
|
|
287
|
+
return lastLine;
|
|
288
|
+
}
|
|
289
|
+
return 'Task completed';
|
|
290
|
+
}
|
|
291
|
+
default:
|
|
292
|
+
// Generic fallback - try to use first meaningful line
|
|
293
|
+
if (nonEmptyLines.length > 0) {
|
|
294
|
+
const firstLine = nonEmptyLines[0];
|
|
295
|
+
if (firstLine && firstLine.length <= 40) {
|
|
296
|
+
return firstLine;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return 'Completed';
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Parse diff output into structured format
|
|
304
|
+
*/
|
|
305
|
+
static parseDiffOutput(diffText) {
|
|
306
|
+
const lines = [];
|
|
307
|
+
let additions = 0;
|
|
308
|
+
let removals = 0;
|
|
309
|
+
const diffLines = diffText.split('\n');
|
|
310
|
+
let currentLineNum = 0;
|
|
311
|
+
for (const line of diffLines) {
|
|
312
|
+
// Check for line number prefix (e.g., " 42→" or " 42 ")
|
|
313
|
+
const lineNumMatch = line.match(/^\s*(\d+)[→\s]/);
|
|
314
|
+
if (lineNumMatch && lineNumMatch[1]) {
|
|
315
|
+
currentLineNum = parseInt(lineNumMatch[1], 10);
|
|
316
|
+
}
|
|
317
|
+
// Detect diff type
|
|
318
|
+
if (line.trim().startsWith('+') && !line.startsWith('+++')) {
|
|
319
|
+
additions++;
|
|
320
|
+
lines.push({
|
|
321
|
+
lineNumber: currentLineNum,
|
|
322
|
+
type: 'add',
|
|
323
|
+
content: line.replace(/^\s*\d+[→\s]\s*\+\s*/, ''),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
else if (line.trim().startsWith('-') && !line.startsWith('---')) {
|
|
327
|
+
removals++;
|
|
328
|
+
lines.push({
|
|
329
|
+
lineNumber: currentLineNum,
|
|
330
|
+
type: 'remove',
|
|
331
|
+
content: line.replace(/^\s*\d+[→\s]\s*-\s*/, ''),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else if (line.trim().startsWith('@@')) {
|
|
335
|
+
lines.push({
|
|
336
|
+
type: 'info',
|
|
337
|
+
content: line,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
else if (lineNumMatch) {
|
|
341
|
+
lines.push({
|
|
342
|
+
lineNumber: currentLineNum,
|
|
343
|
+
type: 'context',
|
|
344
|
+
content: line.replace(/^\s*\d+[→\s]\s*/, ''),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return { additions, removals, lines };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Enhanced display for tool executions
|
|
353
|
+
* Wraps Display with Claude Code style formatting
|
|
354
|
+
*/
|
|
355
|
+
export function createToolDisplayAdapter(display) {
|
|
356
|
+
return new ToolDisplayAdapter(display);
|
|
357
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { safeWorkspaceContext, validateWorkspaceOptions } from './workspace.validator.js';
|
|
4
|
+
const PRIORITY_DOCS = ['README.md']; // Removed package.json to save context
|
|
5
|
+
const IGNORED_DIRS = new Set([
|
|
6
|
+
'.git', 'node_modules', 'dist', '.erosolar', 'build', 'coverage', '.next', 'out',
|
|
7
|
+
'__pycache__', '.pytest_cache', '.mypy_cache', 'venv', '.venv', 'env',
|
|
8
|
+
'target', 'bin', 'obj', '.idea', '.vscode', '.DS_Store'
|
|
9
|
+
]);
|
|
10
|
+
const DEFAULT_TREE_DEPTH = 1; // Reduced from 2 to 1 for critical context savings
|
|
11
|
+
const DEFAULT_MAX_ENTRIES = 30; // Further reduced from 50 to 30 - emergency reduction
|
|
12
|
+
const DEFAULT_DOC_LIMIT = 200; // Further reduced from 300 to 200 - emergency reduction
|
|
13
|
+
export function resolveWorkspaceCaptureOptions(env = process.env) {
|
|
14
|
+
return {
|
|
15
|
+
treeDepth: parsePositiveInt(env['EROSOLAR_CONTEXT_TREE_DEPTH']),
|
|
16
|
+
maxEntries: parsePositiveInt(env['EROSOLAR_CONTEXT_MAX_ENTRIES']),
|
|
17
|
+
docExcerptLimit: parsePositiveInt(env['EROSOLAR_CONTEXT_DOC_LIMIT']),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function buildWorkspaceContext(root, options = {}) {
|
|
21
|
+
// CRITICAL: Validate options BEFORE building context
|
|
22
|
+
const optionsValidation = validateWorkspaceOptions(options);
|
|
23
|
+
if (!optionsValidation.valid) {
|
|
24
|
+
console.error('[Workspace Context] Invalid options:', optionsValidation.errors);
|
|
25
|
+
throw new Error(`Invalid workspace options: ${optionsValidation.errors.join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
// Log warnings if any
|
|
28
|
+
if (optionsValidation.warnings.length > 0) {
|
|
29
|
+
console.warn('[Workspace Context] Warnings:', optionsValidation.warnings);
|
|
30
|
+
}
|
|
31
|
+
const treeDepth = options.treeDepth ?? DEFAULT_TREE_DEPTH;
|
|
32
|
+
const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
33
|
+
const docLimit = options.docExcerptLimit ?? DEFAULT_DOC_LIMIT;
|
|
34
|
+
try {
|
|
35
|
+
const treeLines = formatFileTree(root, treeDepth, maxEntries);
|
|
36
|
+
const docSnippets = capturePriorityDocs(root, docLimit);
|
|
37
|
+
// REMOVED: Rulebook duplication - rulebooks are already in system prompt
|
|
38
|
+
const sections = [`cwd: ${root}`, 'files:', ...treeLines];
|
|
39
|
+
if (docSnippets.length) {
|
|
40
|
+
sections.push(docSnippets.join('\n\n'));
|
|
41
|
+
}
|
|
42
|
+
// REMOVED: Rulebook duplication
|
|
43
|
+
// if (rulebooks.length) {
|
|
44
|
+
// sections.push(rulebooks.join('\n\n'));
|
|
45
|
+
// }
|
|
46
|
+
const rawContent = sections.filter((section) => section.trim().length > 0).join('\n');
|
|
47
|
+
// CRITICAL: Validate and enforce limits on final output
|
|
48
|
+
const safe = safeWorkspaceContext(rawContent, {
|
|
49
|
+
truncate: true, // Auto-truncate if too large
|
|
50
|
+
throwOnError: false // Don't throw, just truncate
|
|
51
|
+
});
|
|
52
|
+
// Log stats for monitoring
|
|
53
|
+
if (process.env['DEBUG_CONTEXT']) {
|
|
54
|
+
console.log('[Workspace Context] Stats:', safe.stats);
|
|
55
|
+
}
|
|
56
|
+
return safe.content;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
60
|
+
return `Workspace context unavailable (${message}).`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function capturePriorityDocs(root, docLimit) {
|
|
64
|
+
return PRIORITY_DOCS.filter((name) => existsSync(join(root, name))).map((name) => {
|
|
65
|
+
try {
|
|
66
|
+
const content = readFileSync(join(root, name), 'utf8');
|
|
67
|
+
// Safety: Hard limit to prevent context explosion
|
|
68
|
+
const safeLimit = Math.min(docLimit, 300);
|
|
69
|
+
const snippet = content.length > safeLimit ? `${content.slice(0, safeLimit)}\n...` : content;
|
|
70
|
+
return `--- ${name} ---\n${snippet.trim()}`;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return `--- ${name} ---\n[Could not read file]`;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function formatFileTree(root, maxDepth, maxEntries) {
|
|
78
|
+
const lines = [];
|
|
79
|
+
const walk = (dir, depth, prefix) => {
|
|
80
|
+
if (depth > maxDepth || lines.length >= maxEntries) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const entries = readdirSync(dir, { withFileTypes: true })
|
|
84
|
+
.filter((entry) => !IGNORED_DIRS.has(entry.name))
|
|
85
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (lines.length >= maxEntries) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
const isDir = entry.isDirectory();
|
|
91
|
+
lines.push(`${prefix}${entry.name}${isDir ? '/' : ''}`);
|
|
92
|
+
if (isDir && depth < maxDepth) {
|
|
93
|
+
walk(join(dir, entry.name), depth + 1, `${prefix} `);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
walk(root, 0, '');
|
|
98
|
+
return lines;
|
|
99
|
+
}
|
|
100
|
+
function parsePositiveInt(raw) {
|
|
101
|
+
if (!raw) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const value = Number.parseInt(raw, 10);
|
|
105
|
+
return Number.isFinite(value) && value > 0 ? value : undefined;
|
|
106
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace Context Validator - Enforces strict safety limits
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: Prevents context explosion by validating all workspace context
|
|
5
|
+
* before it's sent to the LLM. Multiple safety layers ensure we never
|
|
6
|
+
* exceed token limits.
|
|
7
|
+
*/
|
|
8
|
+
import { ContextOverflowError, ResourceLimitError } from './core/errors/errorTypes.js';
|
|
9
|
+
// ABSOLUTE MAXIMUM LIMITS - Never exceed these under any circumstances
|
|
10
|
+
const ABSOLUTE_MAX_CHARS = 5000; // ~1,250 tokens (4 chars per token)
|
|
11
|
+
const ABSOLUTE_MAX_LINES = 100; // Maximum lines in any context
|
|
12
|
+
const ABSOLUTE_MAX_FILE_ENTRIES = 50; // Maximum files in tree
|
|
13
|
+
const ABSOLUTE_MAX_DOC_CHARS = 300; // Maximum chars per priority doc
|
|
14
|
+
const WARNING_THRESHOLD = 0.7; // Warn at 70% of max
|
|
15
|
+
/**
|
|
16
|
+
* Estimate token count (rough: 1 token ≈ 4 characters)
|
|
17
|
+
*/
|
|
18
|
+
function estimateTokens(text) {
|
|
19
|
+
return Math.ceil(text.length / 4);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate workspace context options BEFORE building context
|
|
23
|
+
*/
|
|
24
|
+
export function validateWorkspaceOptions(options) {
|
|
25
|
+
const errors = [];
|
|
26
|
+
const warnings = [];
|
|
27
|
+
// Validate tree depth
|
|
28
|
+
if (options.treeDepth !== undefined) {
|
|
29
|
+
if (options.treeDepth < 0) {
|
|
30
|
+
errors.push('treeDepth cannot be negative');
|
|
31
|
+
}
|
|
32
|
+
if (options.treeDepth > 2) {
|
|
33
|
+
errors.push(`treeDepth ${options.treeDepth} exceeds maximum of 2`);
|
|
34
|
+
}
|
|
35
|
+
if (options.treeDepth > 1) {
|
|
36
|
+
warnings.push('treeDepth > 1 can significantly increase context size');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Validate max entries
|
|
40
|
+
if (options.maxEntries !== undefined) {
|
|
41
|
+
if (options.maxEntries < 0) {
|
|
42
|
+
errors.push('maxEntries cannot be negative');
|
|
43
|
+
}
|
|
44
|
+
if (options.maxEntries > ABSOLUTE_MAX_FILE_ENTRIES) {
|
|
45
|
+
errors.push(`maxEntries ${options.maxEntries} exceeds maximum of ${ABSOLUTE_MAX_FILE_ENTRIES}`);
|
|
46
|
+
}
|
|
47
|
+
if (options.maxEntries > 40) {
|
|
48
|
+
warnings.push('maxEntries > 40 may use significant context');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Validate doc excerpt limit
|
|
52
|
+
if (options.docExcerptLimit !== undefined) {
|
|
53
|
+
if (options.docExcerptLimit < 0) {
|
|
54
|
+
errors.push('docExcerptLimit cannot be negative');
|
|
55
|
+
}
|
|
56
|
+
if (options.docExcerptLimit > ABSOLUTE_MAX_DOC_CHARS) {
|
|
57
|
+
errors.push(`docExcerptLimit ${options.docExcerptLimit} exceeds maximum of ${ABSOLUTE_MAX_DOC_CHARS}`);
|
|
58
|
+
}
|
|
59
|
+
if (options.docExcerptLimit > 250) {
|
|
60
|
+
warnings.push('docExcerptLimit > 250 may use significant context');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
valid: errors.length === 0,
|
|
65
|
+
errors,
|
|
66
|
+
warnings,
|
|
67
|
+
stats: {
|
|
68
|
+
totalChars: 0,
|
|
69
|
+
totalLines: 0,
|
|
70
|
+
estimatedTokens: 0,
|
|
71
|
+
fileEntries: options.maxEntries ?? 0,
|
|
72
|
+
docChars: options.docExcerptLimit ?? 0,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate workspace context AFTER building - CRITICAL SAFETY CHECK
|
|
78
|
+
* This is the final line of defense against context explosion
|
|
79
|
+
*/
|
|
80
|
+
export function validateWorkspaceContext(content) {
|
|
81
|
+
const errors = [];
|
|
82
|
+
const warnings = [];
|
|
83
|
+
// Count basic metrics
|
|
84
|
+
const totalChars = content.length;
|
|
85
|
+
const lines = content.split('\n');
|
|
86
|
+
const totalLines = lines.length;
|
|
87
|
+
const estimatedTokens = estimateTokens(content);
|
|
88
|
+
// Count file entries (lines that look like file paths)
|
|
89
|
+
const fileEntries = lines.filter(line => line.trim() && !line.startsWith('---') && !line.startsWith('cwd:')).length;
|
|
90
|
+
// Count chars in priority docs section
|
|
91
|
+
const docMatch = content.match(/--- .* ---[\s\S]*?(?=\n\n|$)/g);
|
|
92
|
+
const docChars = docMatch ? docMatch.join('').length : 0;
|
|
93
|
+
const stats = {
|
|
94
|
+
totalChars,
|
|
95
|
+
totalLines,
|
|
96
|
+
estimatedTokens,
|
|
97
|
+
fileEntries,
|
|
98
|
+
docChars,
|
|
99
|
+
};
|
|
100
|
+
// CRITICAL: Check absolute maximum character limit
|
|
101
|
+
if (totalChars > ABSOLUTE_MAX_CHARS) {
|
|
102
|
+
const error = new ContextOverflowError(totalChars, ABSOLUTE_MAX_CHARS, 'chars', true);
|
|
103
|
+
errors.push(`Context exceeds ABSOLUTE maximum: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
// CRITICAL: Check absolute maximum line limit
|
|
106
|
+
if (totalLines > ABSOLUTE_MAX_LINES) {
|
|
107
|
+
const error = new ContextOverflowError(totalLines, ABSOLUTE_MAX_LINES, 'lines', true);
|
|
108
|
+
errors.push(`Context exceeds ABSOLUTE maximum: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
// CRITICAL: Check absolute maximum file entries
|
|
111
|
+
if (fileEntries > ABSOLUTE_MAX_FILE_ENTRIES) {
|
|
112
|
+
const error = new ResourceLimitError('file entries', fileEntries, ABSOLUTE_MAX_FILE_ENTRIES, false);
|
|
113
|
+
errors.push(`Context exceeds ABSOLUTE maximum: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
// WARNING: Approaching limits
|
|
116
|
+
if (totalChars > ABSOLUTE_MAX_CHARS * WARNING_THRESHOLD) {
|
|
117
|
+
warnings.push(`Context size ${totalChars} chars is ${Math.round(totalChars / ABSOLUTE_MAX_CHARS * 100)}% of maximum. ` +
|
|
118
|
+
`Consider reducing treeDepth, maxEntries, or docExcerptLimit.`);
|
|
119
|
+
}
|
|
120
|
+
if (estimatedTokens > 1000) {
|
|
121
|
+
warnings.push(`Estimated ${estimatedTokens} tokens in workspace context. This is high and may impact performance.`);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
valid: errors.length === 0,
|
|
125
|
+
errors,
|
|
126
|
+
warnings,
|
|
127
|
+
stats,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Safe truncation - if content exceeds limits, truncate intelligently
|
|
132
|
+
*/
|
|
133
|
+
export function truncateWorkspaceContext(content) {
|
|
134
|
+
const validation = validateWorkspaceContext(content);
|
|
135
|
+
// If valid, return as-is
|
|
136
|
+
if (validation.valid) {
|
|
137
|
+
return {
|
|
138
|
+
content,
|
|
139
|
+
stats: validation.stats,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// CRITICAL: Content exceeds limits, must truncate
|
|
143
|
+
const lines = content.split('\n');
|
|
144
|
+
const truncatedLines = [];
|
|
145
|
+
let charCount = 0;
|
|
146
|
+
// Keep up to absolute maximums
|
|
147
|
+
for (const line of lines) {
|
|
148
|
+
if (truncatedLines.length >= ABSOLUTE_MAX_LINES) {
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
if (charCount + line.length > ABSOLUTE_MAX_CHARS) {
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
truncatedLines.push(line);
|
|
155
|
+
charCount += line.length + 1; // +1 for newline
|
|
156
|
+
}
|
|
157
|
+
// Add truncation notice
|
|
158
|
+
if (truncatedLines.length < lines.length) {
|
|
159
|
+
truncatedLines.push('');
|
|
160
|
+
truncatedLines.push('[Workspace context truncated to prevent context overflow]');
|
|
161
|
+
truncatedLines.push(`[Showing ${truncatedLines.length} of ${lines.length} lines]`);
|
|
162
|
+
}
|
|
163
|
+
const truncatedContent = truncatedLines.join('\n');
|
|
164
|
+
const stats = validateWorkspaceContext(truncatedContent).stats;
|
|
165
|
+
return {
|
|
166
|
+
content: truncatedContent,
|
|
167
|
+
stats,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Validate and enforce limits in a single call - RECOMMENDED USAGE
|
|
172
|
+
*/
|
|
173
|
+
export function safeWorkspaceContext(content, options) {
|
|
174
|
+
const { truncate = true, throwOnError = false } = options ?? {};
|
|
175
|
+
if (!content) {
|
|
176
|
+
return {
|
|
177
|
+
content: '',
|
|
178
|
+
stats: {
|
|
179
|
+
totalChars: 0,
|
|
180
|
+
totalLines: 0,
|
|
181
|
+
estimatedTokens: 0,
|
|
182
|
+
fileEntries: 0,
|
|
183
|
+
docChars: 0,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const validation = validateWorkspaceContext(content);
|
|
188
|
+
// Log warnings to console
|
|
189
|
+
if (validation.warnings.length > 0) {
|
|
190
|
+
console.warn('[Workspace Context Validator] Warnings:');
|
|
191
|
+
for (const warning of validation.warnings) {
|
|
192
|
+
console.warn(` - ${warning}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Handle errors
|
|
196
|
+
if (!validation.valid) {
|
|
197
|
+
console.error('[Workspace Context Validator] CRITICAL ERRORS:');
|
|
198
|
+
for (const error of validation.errors) {
|
|
199
|
+
console.error(` - ${error}`);
|
|
200
|
+
}
|
|
201
|
+
if (throwOnError) {
|
|
202
|
+
throw new Error(`Workspace context validation failed:\n${validation.errors.join('\n')}`);
|
|
203
|
+
}
|
|
204
|
+
if (truncate) {
|
|
205
|
+
console.warn('[Workspace Context Validator] Auto-truncating to safe limits...');
|
|
206
|
+
return truncateWorkspaceContext(content);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
content,
|
|
211
|
+
stats: validation.stats,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CapabilityContribution, CapabilityContext, CapabilityModule } from '../runtime/agentHost.js';
|
|
2
|
+
export interface CloudCapabilityOptions {
|
|
3
|
+
workingDir?: string;
|
|
4
|
+
id?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class CloudCapabilityModule implements CapabilityModule {
|
|
8
|
+
readonly id = "capability.cloud";
|
|
9
|
+
private readonly options;
|
|
10
|
+
constructor(options?: CloudCapabilityOptions);
|
|
11
|
+
create(context: CapabilityContext): Promise<CapabilityContribution>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=cloudCapability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudCapability.d.ts","sourceRoot":"","sources":["../../src/capabilities/cloudCapability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3G,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,qBAAsB,YAAW,gBAAgB;IAC5D,QAAQ,CAAC,EAAE,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAErC,OAAO,GAAE,sBAA2B;IAI1C,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,sBAAsB,CAAC;CA8B1E"}
|