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,238 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
const execAsync = promisify(exec);
|
|
6
|
+
export function createDevTools(workingDir) {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: 'run_tests',
|
|
10
|
+
description: 'Execute test suite using npm test or other test runners',
|
|
11
|
+
parameters: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
testPattern: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Optional test pattern or file to run specific tests',
|
|
17
|
+
},
|
|
18
|
+
timeout: {
|
|
19
|
+
type: 'number',
|
|
20
|
+
description: 'Timeout in milliseconds (default: 60000)',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
},
|
|
25
|
+
handler: async (args) => {
|
|
26
|
+
const testPatternArg = args['testPattern'];
|
|
27
|
+
const testPattern = typeof testPatternArg === 'string' && testPatternArg.trim() ? testPatternArg.trim() : undefined;
|
|
28
|
+
const timeoutArg = args['timeout'];
|
|
29
|
+
const timeout = typeof timeoutArg === 'number' && Number.isFinite(timeoutArg) && timeoutArg > 0 ? timeoutArg : 60000;
|
|
30
|
+
try {
|
|
31
|
+
// Check if package.json exists
|
|
32
|
+
const packageJsonPath = join(workingDir, 'package.json');
|
|
33
|
+
if (!existsSync(packageJsonPath)) {
|
|
34
|
+
return 'Error: package.json not found. Cannot run tests.';
|
|
35
|
+
}
|
|
36
|
+
// Build test command
|
|
37
|
+
let command = 'npm test';
|
|
38
|
+
if (testPattern) {
|
|
39
|
+
// Try to detect test runner and build appropriate command
|
|
40
|
+
const packageInfo = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
41
|
+
const scripts = packageInfo.scripts || {};
|
|
42
|
+
const testScript = scripts['test'] ?? '';
|
|
43
|
+
if (testScript.includes('jest')) {
|
|
44
|
+
command = `npx jest ${testPattern}`;
|
|
45
|
+
}
|
|
46
|
+
else if (testScript.includes('vitest')) {
|
|
47
|
+
command = `npx vitest run ${testPattern}`;
|
|
48
|
+
}
|
|
49
|
+
else if (testScript.includes('mocha')) {
|
|
50
|
+
command = `npx mocha ${testPattern}`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Fallback to npm test with pattern
|
|
54
|
+
command = `npm test -- ${testPattern}`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
58
|
+
cwd: workingDir,
|
|
59
|
+
timeout,
|
|
60
|
+
maxBuffer: 1024 * 1024 * 10, // 10MB
|
|
61
|
+
});
|
|
62
|
+
let result = `Test command: ${command}\n\n`;
|
|
63
|
+
if (stdout)
|
|
64
|
+
result += `stdout:\n${stdout}\n`;
|
|
65
|
+
if (stderr)
|
|
66
|
+
result += `stderr:\n${stderr}\n`;
|
|
67
|
+
return result || 'Tests completed (no output)';
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.killed) {
|
|
71
|
+
return `Error: Test command timed out after ${timeout}ms`;
|
|
72
|
+
}
|
|
73
|
+
return `Error running tests: ${error.message}\nstderr: ${error.stderr || 'none'}`;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'install_dependencies',
|
|
79
|
+
description: 'Install project dependencies using npm, yarn, or pnpm',
|
|
80
|
+
parameters: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
packageManager: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
enum: ['npm', 'yarn', 'pnpm'],
|
|
86
|
+
description: 'Package manager to use (default: npm)',
|
|
87
|
+
},
|
|
88
|
+
production: {
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
description: 'Install only production dependencies',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
additionalProperties: false,
|
|
94
|
+
},
|
|
95
|
+
handler: async (args) => {
|
|
96
|
+
const packageManager = typeof args['packageManager'] === 'string' ? args['packageManager'] : 'npm';
|
|
97
|
+
const production = args['production'] === true;
|
|
98
|
+
try {
|
|
99
|
+
let command;
|
|
100
|
+
if (packageManager === 'npm') {
|
|
101
|
+
command = production ? 'npm ci --production' : 'npm ci';
|
|
102
|
+
}
|
|
103
|
+
else if (packageManager === 'yarn') {
|
|
104
|
+
command = production ? 'yarn install --production' : 'yarn install';
|
|
105
|
+
}
|
|
106
|
+
else if (packageManager === 'pnpm') {
|
|
107
|
+
command = production ? 'pnpm install --prod' : 'pnpm install';
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return `Error: Unsupported package manager: ${packageManager}`;
|
|
111
|
+
}
|
|
112
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
113
|
+
cwd: workingDir,
|
|
114
|
+
timeout: 300000, // 5 minutes
|
|
115
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
116
|
+
});
|
|
117
|
+
let result = `Dependency installation command: ${command}\n\n`;
|
|
118
|
+
if (stdout)
|
|
119
|
+
result += `stdout:\n${stdout}\n`;
|
|
120
|
+
if (stderr)
|
|
121
|
+
result += `stderr:\n${stderr}\n`;
|
|
122
|
+
return result || 'Dependencies installed successfully (no output)';
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (error.killed) {
|
|
126
|
+
return 'Error: Dependency installation timed out';
|
|
127
|
+
}
|
|
128
|
+
return `Error installing dependencies: ${error.message}\nstderr: ${error.stderr || 'none'}`;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'check_package_info',
|
|
134
|
+
description: 'Get information about project dependencies and scripts from package.json',
|
|
135
|
+
parameters: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
detail: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
enum: ['basic', 'dependencies', 'scripts', 'full'],
|
|
141
|
+
description: 'Level of detail to include',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
additionalProperties: false,
|
|
145
|
+
},
|
|
146
|
+
handler: async (args) => {
|
|
147
|
+
const detailArg = args['detail'];
|
|
148
|
+
const detail = typeof detailArg === 'string' && detailArg.trim() ? detailArg : 'basic';
|
|
149
|
+
try {
|
|
150
|
+
const packageJsonPath = join(workingDir, 'package.json');
|
|
151
|
+
if (!existsSync(packageJsonPath)) {
|
|
152
|
+
return 'Error: package.json not found';
|
|
153
|
+
}
|
|
154
|
+
const packageInfo = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
155
|
+
const output = [];
|
|
156
|
+
output.push(`# Package Info: ${packageInfo.name || 'Unnamed'} v${packageInfo.version || 'Unknown'}`);
|
|
157
|
+
output.push('');
|
|
158
|
+
if (detail === 'basic' || detail === 'full') {
|
|
159
|
+
output.push('## Basic Info');
|
|
160
|
+
output.push(`- Name: ${packageInfo.name || 'Not specified'}`);
|
|
161
|
+
output.push(`- Version: ${packageInfo.version || 'Not specified'}`);
|
|
162
|
+
output.push('');
|
|
163
|
+
}
|
|
164
|
+
if ((detail === 'scripts' || detail === 'full') && packageInfo.scripts) {
|
|
165
|
+
output.push('## Scripts');
|
|
166
|
+
Object.entries(packageInfo.scripts).forEach(([name, script]) => {
|
|
167
|
+
output.push(`- ${name}: ${script}`);
|
|
168
|
+
});
|
|
169
|
+
output.push('');
|
|
170
|
+
}
|
|
171
|
+
if ((detail === 'dependencies' || detail === 'full') && packageInfo.dependencies) {
|
|
172
|
+
output.push('## Dependencies');
|
|
173
|
+
Object.entries(packageInfo.dependencies).forEach(([name, version]) => {
|
|
174
|
+
output.push(`- ${name}: ${version}`);
|
|
175
|
+
});
|
|
176
|
+
output.push('');
|
|
177
|
+
}
|
|
178
|
+
if ((detail === 'dependencies' || detail === 'full') && packageInfo.devDependencies) {
|
|
179
|
+
output.push('## Dev Dependencies');
|
|
180
|
+
Object.entries(packageInfo.devDependencies).forEach(([name, version]) => {
|
|
181
|
+
output.push(`- ${name}: ${version}`);
|
|
182
|
+
});
|
|
183
|
+
output.push('');
|
|
184
|
+
}
|
|
185
|
+
return output.join('\n');
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
return `Error reading package.json: ${error instanceof Error ? error.message : String(error)}`;
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: 'run_build',
|
|
194
|
+
description: 'Execute build process using npm run build or other build commands',
|
|
195
|
+
parameters: {
|
|
196
|
+
type: 'object',
|
|
197
|
+
properties: {
|
|
198
|
+
buildCommand: {
|
|
199
|
+
type: 'string',
|
|
200
|
+
description: 'Custom build command (defaults to npm run build)',
|
|
201
|
+
},
|
|
202
|
+
timeout: {
|
|
203
|
+
type: 'number',
|
|
204
|
+
description: 'Timeout in milliseconds (default: 300000)',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
additionalProperties: false,
|
|
208
|
+
},
|
|
209
|
+
handler: async (args) => {
|
|
210
|
+
const buildCommandArg = args['buildCommand'];
|
|
211
|
+
const buildCommand = typeof buildCommandArg === 'string' && buildCommandArg.trim()
|
|
212
|
+
? buildCommandArg
|
|
213
|
+
: 'npm run build';
|
|
214
|
+
const timeoutArg = args['timeout'];
|
|
215
|
+
const timeout = typeof timeoutArg === 'number' && Number.isFinite(timeoutArg) && timeoutArg > 0 ? timeoutArg : 300000; // 5 minutes
|
|
216
|
+
try {
|
|
217
|
+
const { stdout, stderr } = await execAsync(buildCommand, {
|
|
218
|
+
cwd: workingDir,
|
|
219
|
+
timeout,
|
|
220
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
221
|
+
});
|
|
222
|
+
let result = `Build command: ${buildCommand}\n\n`;
|
|
223
|
+
if (stdout)
|
|
224
|
+
result += `stdout:\n${stdout}\n`;
|
|
225
|
+
if (stderr)
|
|
226
|
+
result += `stderr:\n${stderr}\n`;
|
|
227
|
+
return result || 'Build completed (no output)';
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (error.killed) {
|
|
231
|
+
return `Error: Build command timed out after ${timeout}ms`;
|
|
232
|
+
}
|
|
233
|
+
return `Error running build: ${error.message}\nstderr: ${error.stderr || 'none'}`;
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
];
|
|
238
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
export function buildDiffSegments(previous, next) {
|
|
6
|
+
const before = normalizeNewlines(previous);
|
|
7
|
+
const after = normalizeNewlines(next);
|
|
8
|
+
if (before === after) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const gitSegments = tryBuildWithGit(before, after);
|
|
12
|
+
if (gitSegments) {
|
|
13
|
+
return gitSegments;
|
|
14
|
+
}
|
|
15
|
+
return buildNaiveDiff(before, after);
|
|
16
|
+
}
|
|
17
|
+
export function formatDiffLines(diff) {
|
|
18
|
+
if (!diff.length) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
const width = Math.max(1, ...diff.map((entry) => Math.max(1, entry.lineNumber).toString().length));
|
|
22
|
+
return diff.map((entry) => {
|
|
23
|
+
const prefix = entry.type === 'added' ? '+' : '-';
|
|
24
|
+
const lineNumber = Math.max(1, entry.lineNumber);
|
|
25
|
+
const body = entry.content.length > 0 ? entry.content : '[empty line]';
|
|
26
|
+
const paddedNumber = lineNumber.toString().padStart(width, ' ');
|
|
27
|
+
return `${prefix} L${paddedNumber} | ${body}`;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function tryBuildWithGit(before, after) {
|
|
31
|
+
let tempDir = null;
|
|
32
|
+
try {
|
|
33
|
+
tempDir = mkdtempSync(join(tmpdir(), 'erosolar-diff-'));
|
|
34
|
+
const originalPath = join(tempDir, 'before.txt');
|
|
35
|
+
const updatedPath = join(tempDir, 'after.txt');
|
|
36
|
+
writeFileSync(originalPath, before, 'utf8');
|
|
37
|
+
writeFileSync(updatedPath, after, 'utf8');
|
|
38
|
+
const result = spawnSync('git', ['--no-pager', 'diff', '--no-index', '--unified=0', '--color=never', '--', originalPath, updatedPath], { encoding: 'utf8' });
|
|
39
|
+
if (result.error) {
|
|
40
|
+
const code = result.error.code;
|
|
41
|
+
if (code === 'ENOENT') {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (typeof result.status === 'number' && result.status > 1) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return parseUnifiedDiff(result.stdout);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
if (tempDir) {
|
|
56
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function parseUnifiedDiff(output) {
|
|
61
|
+
if (!output.trim()) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const lines = output.split('\n');
|
|
65
|
+
const segments = [];
|
|
66
|
+
let oldLine = 0;
|
|
67
|
+
let newLine = 0;
|
|
68
|
+
for (const rawLine of lines) {
|
|
69
|
+
const line = rawLine.replace(/\r$/, '');
|
|
70
|
+
if (!line) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (line.startsWith('@@')) {
|
|
74
|
+
const match = /@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
75
|
+
if (match?.[1] && match?.[2]) {
|
|
76
|
+
oldLine = parseInt(match[1], 10);
|
|
77
|
+
newLine = parseInt(match[2], 10);
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (line.startsWith('+++') || line.startsWith('---') || line.startsWith('diff ') || line.startsWith('index ')) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (line.startsWith('Binary ')) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (line.startsWith('\\')) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (line.startsWith('+')) {
|
|
91
|
+
segments.push({ type: 'added', lineNumber: newLine, content: line.slice(1) });
|
|
92
|
+
newLine += 1;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (line.startsWith('-')) {
|
|
96
|
+
segments.push({ type: 'removed', lineNumber: oldLine, content: line.slice(1) });
|
|
97
|
+
oldLine += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (line.startsWith(' ')) {
|
|
101
|
+
oldLine += 1;
|
|
102
|
+
newLine += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return segments;
|
|
107
|
+
}
|
|
108
|
+
function buildNaiveDiff(before, after) {
|
|
109
|
+
const a = splitLines(before);
|
|
110
|
+
const b = splitLines(after);
|
|
111
|
+
const max = Math.max(a.length, b.length);
|
|
112
|
+
const segments = [];
|
|
113
|
+
for (let index = 0; index < max; index += 1) {
|
|
114
|
+
const left = a[index];
|
|
115
|
+
const right = b[index];
|
|
116
|
+
if (left === right) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (typeof left === 'string') {
|
|
120
|
+
segments.push({ type: 'removed', lineNumber: index + 1, content: left });
|
|
121
|
+
}
|
|
122
|
+
if (typeof right === 'string') {
|
|
123
|
+
segments.push({ type: 'added', lineNumber: index + 1, content: right });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return segments;
|
|
127
|
+
}
|
|
128
|
+
function normalizeNewlines(value) {
|
|
129
|
+
return value.replace(/\r\n/g, '\n');
|
|
130
|
+
}
|
|
131
|
+
function splitLines(value) {
|
|
132
|
+
if (!value) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
const normalized = normalizeNewlines(value);
|
|
136
|
+
return normalized.split('\n');
|
|
137
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { buildError } from '../core/errors.js';
|
|
4
|
+
import { buildDiffSegments, formatDiffLines } from './diffUtils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates the Edit tool for surgical file modifications using exact string replacement.
|
|
7
|
+
*
|
|
8
|
+
* This tool performs string-based edits without requiring full file rewrites,
|
|
9
|
+
* making it ideal for targeted changes while preserving exact formatting and indentation.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Exact string matching (preserves indentation)
|
|
13
|
+
* - Replace all occurrences or enforce uniqueness
|
|
14
|
+
* - Unified diff preview
|
|
15
|
+
* - Validation before writing
|
|
16
|
+
*
|
|
17
|
+
* @param workingDir - The working directory for resolving relative paths
|
|
18
|
+
* @returns Array containing the Edit tool definition
|
|
19
|
+
*/
|
|
20
|
+
export function createEditTools(workingDir) {
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
name: 'Edit',
|
|
24
|
+
description: 'Performs exact string replacements in files. Use for surgical edits when you know the exact text to replace. The edit will FAIL if old_string is not unique unless replace_all is true.',
|
|
25
|
+
parameters: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
file_path: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'The absolute path to the file to modify',
|
|
31
|
+
},
|
|
32
|
+
old_string: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'The exact text to replace (must match precisely including indentation and whitespace)',
|
|
35
|
+
},
|
|
36
|
+
new_string: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'The text to replace it with (must be different from old_string)',
|
|
39
|
+
},
|
|
40
|
+
replace_all: {
|
|
41
|
+
type: 'boolean',
|
|
42
|
+
description: 'Replace all occurrences of old_string (default false). When false, the edit fails if old_string appears multiple times.',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ['file_path', 'old_string', 'new_string'],
|
|
46
|
+
additionalProperties: false,
|
|
47
|
+
},
|
|
48
|
+
handler: async (args) => {
|
|
49
|
+
const pathArg = args['file_path'];
|
|
50
|
+
const oldString = args['old_string'];
|
|
51
|
+
const newString = args['new_string'];
|
|
52
|
+
const replaceAll = args['replace_all'] === true;
|
|
53
|
+
// Validate inputs
|
|
54
|
+
if (typeof pathArg !== 'string' || !pathArg.trim()) {
|
|
55
|
+
return 'Error: file_path must be a non-empty string.';
|
|
56
|
+
}
|
|
57
|
+
if (typeof oldString !== 'string') {
|
|
58
|
+
return 'Error: old_string must be a string.';
|
|
59
|
+
}
|
|
60
|
+
if (typeof newString !== 'string') {
|
|
61
|
+
return 'Error: new_string must be a string.';
|
|
62
|
+
}
|
|
63
|
+
if (oldString === newString) {
|
|
64
|
+
return 'Error: old_string and new_string must be different.';
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const filePath = resolveFilePath(workingDir, pathArg);
|
|
68
|
+
// Check file exists
|
|
69
|
+
if (!existsSync(filePath)) {
|
|
70
|
+
return `Error: File not found: ${filePath}`;
|
|
71
|
+
}
|
|
72
|
+
// Read current content
|
|
73
|
+
const currentContent = readFileSync(filePath, 'utf-8');
|
|
74
|
+
// Check if old_string exists in file
|
|
75
|
+
if (!currentContent.includes(oldString)) {
|
|
76
|
+
return `Error: old_string not found in file. The exact text must match including all whitespace and indentation.\n\nFile: ${filePath}\nSearching for: ${JSON.stringify(oldString.substring(0, 100))}...`;
|
|
77
|
+
}
|
|
78
|
+
// Count occurrences
|
|
79
|
+
const occurrences = countOccurrences(currentContent, oldString);
|
|
80
|
+
if (!replaceAll && occurrences > 1) {
|
|
81
|
+
return `Error: old_string appears ${occurrences} times in the file. Either:\n1. Provide a larger unique string that includes more context\n2. Set replace_all: true to replace all ${occurrences} occurrences\n\nFile: ${filePath}`;
|
|
82
|
+
}
|
|
83
|
+
// Perform replacement
|
|
84
|
+
const newContent = replaceAll
|
|
85
|
+
? currentContent.split(oldString).join(newString)
|
|
86
|
+
: currentContent.replace(oldString, newString);
|
|
87
|
+
// Generate diff
|
|
88
|
+
const diffSegments = buildDiffSegments(currentContent, newContent);
|
|
89
|
+
// Write file
|
|
90
|
+
writeFileSync(filePath, newContent, 'utf-8');
|
|
91
|
+
// Build summary
|
|
92
|
+
const relativePath = relative(workingDir, filePath);
|
|
93
|
+
const displayPath = relativePath && !relativePath.startsWith('..') ? relativePath : filePath;
|
|
94
|
+
const addedLines = diffSegments.filter(s => s.type === 'added').length;
|
|
95
|
+
const removedLines = diffSegments.filter(s => s.type === 'removed').length;
|
|
96
|
+
const occurrencesText = replaceAll ? ` (${occurrences} occurrence${occurrences > 1 ? 's' : ''})` : '';
|
|
97
|
+
const diffLines = formatDiffLines(diffSegments);
|
|
98
|
+
const diffBlock = diffLines.length > 0
|
|
99
|
+
? ['```diff', ...diffLines, '```'].join('\n')
|
|
100
|
+
: '(No visual diff - whitespace or formatting changes only)';
|
|
101
|
+
return [
|
|
102
|
+
`✓ Edited ${displayPath}${occurrencesText}`,
|
|
103
|
+
`Lines changed: +${addedLines} / -${removedLines}`,
|
|
104
|
+
'',
|
|
105
|
+
'Diff preview:',
|
|
106
|
+
diffBlock,
|
|
107
|
+
].join('\n');
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return buildError('editing file', error, {
|
|
111
|
+
file_path: pathArg,
|
|
112
|
+
old_string_length: typeof oldString === 'string' ? oldString.length : 0,
|
|
113
|
+
new_string_length: typeof newString === 'string' ? newString.length : 0,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
function resolveFilePath(workingDir, path) {
|
|
121
|
+
const normalized = path.trim();
|
|
122
|
+
return normalized.startsWith('/') ? normalized : join(workingDir, normalized);
|
|
123
|
+
}
|
|
124
|
+
function countOccurrences(text, search) {
|
|
125
|
+
if (!search)
|
|
126
|
+
return 0;
|
|
127
|
+
let count = 0;
|
|
128
|
+
let position = 0;
|
|
129
|
+
while ((position = text.indexOf(search, position)) !== -1) {
|
|
130
|
+
count++;
|
|
131
|
+
position += search.length;
|
|
132
|
+
}
|
|
133
|
+
return count;
|
|
134
|
+
}
|