@mxf-dev/core 1.0.1 → 2.0.1
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 +18 -0
- package/dist/adapters/FrameworkAdapter.js +1 -1
- package/dist/adapters/FrameworkAdapter.js.map +1 -1
- package/dist/config/ConfigManager.d.ts +9 -8
- package/dist/config/ConfigManager.d.ts.map +1 -1
- package/dist/config/ConfigManager.js +47 -17
- package/dist/config/ConfigManager.js.map +1 -1
- package/dist/config/memory-strata.config.d.ts +25 -0
- package/dist/config/memory-strata.config.d.ts.map +1 -0
- package/dist/config/memory-strata.config.js +107 -0
- package/dist/config/memory-strata.config.js.map +1 -0
- package/dist/constants/ToolNames.d.ts +1 -29
- package/dist/constants/ToolNames.d.ts.map +1 -1
- package/dist/constants/ToolNames.js +4 -17
- package/dist/constants/ToolNames.js.map +1 -1
- package/dist/database/DatabaseAdapterFactory.d.ts +14 -2
- package/dist/database/DatabaseAdapterFactory.d.ts.map +1 -1
- package/dist/database/DatabaseAdapterFactory.js +21 -6
- package/dist/database/DatabaseAdapterFactory.js.map +1 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts +7 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts.map +1 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.js +12 -2
- package/dist/database/adapters/mongodb/MongoBaseRepository.js.map +1 -1
- package/dist/events/ClientEventBus.d.ts +16 -77
- package/dist/events/ClientEventBus.d.ts.map +1 -1
- package/dist/events/ClientEventBus.js +38 -311
- package/dist/events/ClientEventBus.js.map +1 -1
- package/dist/events/EventBus.d.ts +1 -1
- package/dist/events/EventBus.d.ts.map +1 -1
- package/dist/events/EventBus.js +5 -4
- package/dist/events/EventBus.js.map +1 -1
- package/dist/events/EventBusBase.d.ts +139 -34
- package/dist/events/EventBusBase.d.ts.map +1 -1
- package/dist/events/EventBusBase.js +366 -88
- package/dist/events/EventBusBase.js.map +1 -1
- package/dist/events/EventNames.d.ts +10 -1
- package/dist/events/EventNames.d.ts.map +1 -1
- package/dist/events/EventNames.js +3 -0
- package/dist/events/EventNames.js.map +1 -1
- package/dist/events/PublicEvents.d.ts +6 -2
- package/dist/events/PublicEvents.d.ts.map +1 -1
- package/dist/events/PublicEvents.js +7 -4
- package/dist/events/PublicEvents.js.map +1 -1
- package/dist/events/ServerEventBus.d.ts +23 -112
- package/dist/events/ServerEventBus.d.ts.map +1 -1
- package/dist/events/ServerEventBus.js +58 -323
- package/dist/events/ServerEventBus.js.map +1 -1
- package/dist/events/event-definitions/LlmBudgetEvents.d.ts +68 -0
- package/dist/events/event-definitions/LlmBudgetEvents.d.ts.map +1 -0
- package/dist/events/event-definitions/LlmBudgetEvents.js +35 -0
- package/dist/events/event-definitions/LlmBudgetEvents.js.map +1 -0
- package/dist/interfaces/IMemoryPersistence.d.ts +41 -0
- package/dist/interfaces/IMemoryPersistence.d.ts.map +1 -0
- package/dist/interfaces/IMemoryPersistence.js +15 -0
- package/dist/interfaces/IMemoryPersistence.js.map +1 -0
- package/dist/middleware/MxpMiddleware.d.ts +8 -1
- package/dist/middleware/MxpMiddleware.d.ts.map +1 -1
- package/dist/middleware/MxpMiddleware.js +42 -20
- package/dist/middleware/MxpMiddleware.js.map +1 -1
- package/dist/models/channelKey.d.ts +1 -0
- package/dist/models/channelKey.d.ts.map +1 -1
- package/dist/models/channelKey.js +5 -0
- package/dist/models/channelKey.js.map +1 -1
- package/dist/models/memoryUtility.d.ts +39 -0
- package/dist/models/memoryUtility.d.ts.map +1 -0
- package/dist/models/memoryUtility.js +39 -0
- package/dist/models/memoryUtility.js.map +1 -0
- package/dist/models/user.d.ts.map +1 -1
- package/dist/models/user.js +23 -1
- package/dist/models/user.js.map +1 -1
- package/dist/mxp/BinaryProtocolLayer.d.ts +24 -8
- package/dist/mxp/BinaryProtocolLayer.d.ts.map +1 -1
- package/dist/mxp/BinaryProtocolLayer.js +90 -103
- package/dist/mxp/BinaryProtocolLayer.js.map +1 -1
- package/dist/mxp/ContextCompressionEngine.d.ts +57 -10
- package/dist/mxp/ContextCompressionEngine.d.ts.map +1 -1
- package/dist/mxp/ContextCompressionEngine.js +170 -128
- package/dist/mxp/ContextCompressionEngine.js.map +1 -1
- package/dist/mxp/MxpTokenOptimizer.d.ts +7 -3
- package/dist/mxp/MxpTokenOptimizer.d.ts.map +1 -1
- package/dist/mxp/MxpTokenOptimizer.js +8 -5
- package/dist/mxp/MxpTokenOptimizer.js.map +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.d.ts +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.d.ts.map +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.js +47 -57
- package/dist/prompts/MxfAgentSystemPrompt.js.map +1 -1
- package/dist/protocols/mcp/ToolError.d.ts +123 -0
- package/dist/protocols/mcp/ToolError.d.ts.map +1 -0
- package/dist/protocols/mcp/ToolError.js +108 -0
- package/dist/protocols/mcp/ToolError.js.map +1 -0
- package/dist/protocols/mcp/defineTool.d.ts +133 -0
- package/dist/protocols/mcp/defineTool.d.ts.map +1 -0
- package/dist/protocols/mcp/defineTool.js +236 -0
- package/dist/protocols/mcp/defineTool.js.map +1 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.d.ts +38 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.d.ts.map +1 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.js +227 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.js.map +1 -0
- package/dist/protocols/mcp/security/McpSecurityGuard.d.ts +9 -1
- package/dist/protocols/mcp/security/McpSecurityGuard.d.ts.map +1 -1
- package/dist/protocols/mcp/security/McpSecurityGuard.js +10 -2
- package/dist/protocols/mcp/security/McpSecurityGuard.js.map +1 -1
- package/dist/protocols/mcp/security/McpToolPolicy.d.ts +81 -0
- package/dist/protocols/mcp/security/McpToolPolicy.d.ts.map +1 -0
- package/dist/protocols/mcp/security/McpToolPolicy.js +202 -0
- package/dist/protocols/mcp/security/McpToolPolicy.js.map +1 -0
- package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts +51 -18
- package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts.map +1 -1
- package/dist/protocols/mcp/services/ExternalMcpServerManager.js +256 -283
- package/dist/protocols/mcp/services/ExternalMcpServerManager.js.map +1 -1
- package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts +39 -6
- package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts.map +1 -1
- package/dist/protocols/mcp/services/ExternalServerConfigs.js +76 -18
- package/dist/protocols/mcp/services/ExternalServerConfigs.js.map +1 -1
- package/dist/protocols/mcp/tools/AnalyticsTools.js +1 -1
- package/dist/protocols/mcp/tools/AnalyticsTools.js.map +1 -1
- package/dist/protocols/mcp/tools/CodeAnalysisTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/CodeAnalysisTools.js +15 -0
- package/dist/protocols/mcp/tools/CodeAnalysisTools.js.map +1 -1
- package/dist/protocols/mcp/tools/EffectivenessTools.js +3 -3
- package/dist/protocols/mcp/tools/EffectivenessTools.js.map +1 -1
- package/dist/protocols/mcp/tools/GitTools.d.ts +9 -369
- package/dist/protocols/mcp/tools/GitTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/GitTools.js +222 -517
- package/dist/protocols/mcp/tools/GitTools.js.map +1 -1
- package/dist/protocols/mcp/tools/InfrastructureTools.d.ts +56 -24
- package/dist/protocols/mcp/tools/InfrastructureTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/InfrastructureTools.js +117 -26
- package/dist/protocols/mcp/tools/InfrastructureTools.js.map +1 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.d.ts +0 -3
- package/dist/protocols/mcp/tools/MemorySearchTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.js +58 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.js.map +1 -1
- package/dist/protocols/mcp/tools/OrparTools.d.ts +8 -0
- package/dist/protocols/mcp/tools/OrparTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/OrparTools.js +66 -0
- package/dist/protocols/mcp/tools/OrparTools.js.map +1 -1
- package/dist/protocols/mcp/tools/SafetyTools.d.ts +7 -525
- package/dist/protocols/mcp/tools/SafetyTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/SafetyTools.js +349 -514
- package/dist/protocols/mcp/tools/SafetyTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TaskPlanningTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TaskPlanningTools.js +56 -26
- package/dist/protocols/mcp/tools/TaskPlanningTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TestTools.d.ts +15 -376
- package/dist/protocols/mcp/tools/TestTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TestTools.js +241 -363
- package/dist/protocols/mcp/tools/TestTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TypeScriptTools.d.ts +6 -276
- package/dist/protocols/mcp/tools/TypeScriptTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TypeScriptTools.js +223 -337
- package/dist/protocols/mcp/tools/TypeScriptTools.js.map +1 -1
- package/dist/protocols/mcp/tools/WebTools.d.ts +15 -728
- package/dist/protocols/mcp/tools/WebTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/WebTools.js +151 -257
- package/dist/protocols/mcp/tools/WebTools.js.map +1 -1
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts +5 -3
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js +31 -6
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js.map +1 -1
- package/dist/schemas/EventPayloadSchema.d.ts +21 -0
- package/dist/schemas/EventPayloadSchema.d.ts.map +1 -1
- package/dist/schemas/EventPayloadSchema.js +14 -0
- package/dist/schemas/EventPayloadSchema.js.map +1 -1
- package/dist/services/BackgroundTaskManager.d.ts.map +1 -1
- package/dist/services/BackgroundTaskManager.js +12 -4
- package/dist/services/BackgroundTaskManager.js.map +1 -1
- package/dist/services/BrowserManager.d.ts +1 -1
- package/dist/services/BrowserManager.d.ts.map +1 -1
- package/dist/services/BrowserManager.js +26 -3
- package/dist/services/BrowserManager.js.map +1 -1
- package/dist/services/MemoryCompressor.d.ts +11 -2
- package/dist/services/MemoryCompressor.d.ts.map +1 -1
- package/dist/services/MemoryCompressor.js +8 -26
- package/dist/services/MemoryCompressor.js.map +1 -1
- package/dist/services/MemoryService.d.ts +16 -3
- package/dist/services/MemoryService.d.ts.map +1 -1
- package/dist/services/MemoryService.js +79 -55
- package/dist/services/MemoryService.js.map +1 -1
- package/dist/services/MxfMLService.d.ts +5 -0
- package/dist/services/MxfMLService.d.ts.map +1 -1
- package/dist/services/MxfMLService.js +32 -6
- package/dist/services/MxfMLService.js.map +1 -1
- package/dist/services/PredictiveAnalyticsService.d.ts +45 -9
- package/dist/services/PredictiveAnalyticsService.d.ts.map +1 -1
- package/dist/services/PredictiveAnalyticsService.js +82 -44
- package/dist/services/PredictiveAnalyticsService.js.map +1 -1
- package/dist/services/QValueManager.d.ts +7 -0
- package/dist/services/QValueManager.d.ts.map +1 -1
- package/dist/services/QValueManager.js +9 -0
- package/dist/services/QValueManager.js.map +1 -1
- package/dist/services/RewardSignalProcessor.d.ts +38 -1
- package/dist/services/RewardSignalProcessor.d.ts.map +1 -1
- package/dist/services/RewardSignalProcessor.js +109 -7
- package/dist/services/RewardSignalProcessor.js.map +1 -1
- package/dist/services/SharedStateService.d.ts +16 -2
- package/dist/services/SharedStateService.d.ts.map +1 -1
- package/dist/services/SharedStateService.js +44 -3
- package/dist/services/SharedStateService.js.map +1 -1
- package/dist/services/TaskEffectivenessService.d.ts +34 -18
- package/dist/services/TaskEffectivenessService.d.ts.map +1 -1
- package/dist/services/TaskEffectivenessService.js +91 -155
- package/dist/services/TaskEffectivenessService.js.map +1 -1
- package/dist/services/WebSearchService.d.ts.map +1 -1
- package/dist/services/WebSearchService.js.map +1 -1
- package/dist/services/dag/TaskDagService.d.ts.map +1 -1
- package/dist/services/dag/TaskDagService.js +2 -0
- package/dist/services/dag/TaskDagService.js.map +1 -1
- package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts +7 -0
- package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts.map +1 -1
- package/dist/services/orpar-memory/OrparMemoryCoordinator.js +71 -10
- package/dist/services/orpar-memory/OrparMemoryCoordinator.js.map +1 -1
- package/dist/types/MemoryUtilityTypes.d.ts +2 -0
- package/dist/types/MemoryUtilityTypes.d.ts.map +1 -1
- package/dist/types/MemoryUtilityTypes.js.map +1 -1
- package/dist/utils/Logger.d.ts +43 -3
- package/dist/utils/Logger.d.ts.map +1 -1
- package/dist/utils/Logger.js +78 -36
- package/dist/utils/Logger.js.map +1 -1
- package/dist/utils/MxpEncryption.d.ts +19 -6
- package/dist/utils/MxpEncryption.d.ts.map +1 -1
- package/dist/utils/MxpEncryption.js +48 -16
- package/dist/utils/MxpEncryption.js.map +1 -1
- package/package.json +19 -4
- package/src/adapters/FrameworkAdapter.ts +1 -1
- package/src/config/ConfigManager.ts +52 -19
- package/src/config/memory-strata.config.ts +136 -0
- package/src/constants/ToolNames.ts +4 -18
- package/src/database/DatabaseAdapterFactory.ts +23 -6
- package/src/database/adapters/mongodb/MongoBaseRepository.ts +16 -2
- package/src/events/ClientEventBus.ts +68 -403
- package/src/events/EventBus.ts +7 -8
- package/src/events/EventBusBase.ts +479 -116
- package/src/events/EventNames.ts +6 -0
- package/src/events/PublicEvents.ts +7 -4
- package/src/events/ServerEventBus.ts +78 -473
- package/src/events/event-definitions/LlmBudgetEvents.ts +74 -0
- package/src/interfaces/IMemoryPersistence.ts +51 -0
- package/src/middleware/MxpMiddleware.ts +51 -24
- package/src/models/channelKey.ts +18 -4
- package/src/models/memoryUtility.ts +64 -0
- package/src/models/user.ts +36 -4
- package/src/mxp/BinaryProtocolLayer.ts +108 -124
- package/src/mxp/ContextCompressionEngine.ts +219 -161
- package/src/mxp/MxpTokenOptimizer.ts +10 -10
- package/src/prompts/MxfAgentSystemPrompt.ts +45 -55
- package/src/protocols/mcp/ToolError.ts +201 -0
- package/src/protocols/mcp/defineTool.ts +379 -0
- package/src/protocols/mcp/security/HttpTargetGuard.ts +267 -0
- package/src/protocols/mcp/security/McpSecurityGuard.ts +10 -3
- package/src/protocols/mcp/security/McpToolPolicy.ts +221 -0
- package/src/protocols/mcp/services/ExternalMcpServerManager.ts +340 -322
- package/src/protocols/mcp/services/ExternalServerConfigs.ts +82 -19
- package/src/protocols/mcp/tools/AnalyticsTools.ts +1 -1
- package/src/protocols/mcp/tools/CodeAnalysisTools.ts +15 -0
- package/src/protocols/mcp/tools/EffectivenessTools.ts +3 -3
- package/src/protocols/mcp/tools/GitTools.ts +290 -569
- package/src/protocols/mcp/tools/InfrastructureTools.ts +189 -43
- package/src/protocols/mcp/tools/MemorySearchTools.ts +77 -1
- package/src/protocols/mcp/tools/OrparTools.ts +87 -0
- package/src/protocols/mcp/tools/SafetyTools.ts +501 -579
- package/src/protocols/mcp/tools/TaskPlanningTools.ts +81 -39
- package/src/protocols/mcp/tools/TestTools.ts +339 -419
- package/src/protocols/mcp/tools/TypeScriptTools.ts +316 -376
- package/src/protocols/mcp/tools/WebTools.ts +209 -307
- package/src/protocols/mcp/tools/shell/ShellExecuteHandler.ts +53 -14
- package/src/schemas/EventPayloadSchema.ts +37 -0
- package/src/services/BackgroundTaskManager.ts +12 -4
- package/src/services/BrowserManager.ts +41 -1
- package/src/services/MemoryCompressor.ts +20 -32
- package/src/services/MemoryService.ts +96 -58
- package/src/services/MxfMLService.ts +41 -7
- package/src/services/PredictiveAnalyticsService.ts +101 -51
- package/src/services/QValueManager.ts +10 -0
- package/src/services/RewardSignalProcessor.ts +138 -9
- package/src/services/SharedStateService.ts +56 -8
- package/src/services/TaskEffectivenessService.ts +114 -187
- package/src/services/WebSearchService.ts +2 -1
- package/src/services/dag/TaskDagService.ts +2 -0
- package/src/services/orpar-memory/OrparMemoryCoordinator.ts +86 -10
- package/src/types/MemoryUtilityTypes.ts +2 -0
- package/src/utils/Logger.ts +116 -40
- package/src/utils/MxpEncryption.ts +69 -34
- package/dist/mxp/MxpEventForwardingEnhancer.d.ts +0 -134
- package/dist/mxp/MxpEventForwardingEnhancer.d.ts.map +0 -1
- package/dist/mxp/MxpEventForwardingEnhancer.js +0 -361
- package/dist/mxp/MxpEventForwardingEnhancer.js.map +0 -1
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts +0 -56
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts.map +0 -1
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.js +0 -57
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.js.map +0 -1
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts +0 -270
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts.map +0 -1
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.js +0 -256
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.js.map +0 -1
- package/dist/protocols/mcp/tools/LspTools.d.ts +0 -495
- package/dist/protocols/mcp/tools/LspTools.d.ts.map +0 -1
- package/dist/protocols/mcp/tools/LspTools.js +0 -469
- package/dist/protocols/mcp/tools/LspTools.js.map +0 -1
- package/src/mxp/MxpEventForwardingEnhancer.ts +0 -471
- package/src/protocols/mcp/services/ToolSchemaEnhancements.ts +0 -92
- package/src/protocols/mcp/tools/ControlLoopLifecycle.ts +0 -302
- package/src/protocols/mcp/tools/LspTools.ts +0 -476
|
@@ -18,469 +18,409 @@
|
|
|
18
18
|
* @documentation https://mxf-dev.github.io/mxf/
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
/**
|
|
22
|
+
* TypeScriptTools.ts
|
|
23
|
+
*
|
|
24
|
+
* TypeScript checking, building, formatting, linting and test running. Each tool
|
|
25
|
+
* shells out to the real binary (tsc, prettier, eslint, jest) through
|
|
26
|
+
* executeShellCommand, which validates the command and strips the child's
|
|
27
|
+
* environment.
|
|
28
|
+
*
|
|
29
|
+
* On exit codes: tsc, eslint and jest all exit non-zero to mean "I found
|
|
30
|
+
* problems". That is a successful tool call with a negative finding, not a tool
|
|
31
|
+
* failure — so those tools return `passed: false` with the diagnostics, and
|
|
32
|
+
* `isError` stays false. `isError` is reserved for the tool genuinely not
|
|
33
|
+
* working: the binary is missing, the working directory does not exist, output
|
|
34
|
+
* cannot be parsed.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { TOOL_CATEGORIES } from '../../../constants/ToolNames.js';
|
|
38
|
+
import { defineTool, ToolRunContext } from '../defineTool.js';
|
|
39
|
+
import { ToolError } from '../ToolError.js';
|
|
40
|
+
import { executeShellCommand, ShellCommandResult } from './InfrastructureTools.js';
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
/** Exit code the shell reports when a command could not be found or spawned. */
|
|
43
|
+
const COMMAND_NOT_FOUND = 127;
|
|
44
|
+
|
|
45
|
+
const workingDirectoryProperty = {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Working directory path (defaults to the server working directory)'
|
|
48
|
+
};
|
|
26
49
|
|
|
27
50
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* Full implementation would integrate with shell_execute tool
|
|
51
|
+
* Run one of the node toolchain binaries via npx.
|
|
52
|
+
*
|
|
53
|
+
* Throws only when the binary could not be run at all. A non-zero exit that the
|
|
54
|
+
* binary uses to report findings is handed back to the caller to interpret.
|
|
33
55
|
*/
|
|
56
|
+
async function runNpx(
|
|
57
|
+
args: string[],
|
|
58
|
+
workingDirectory: string | undefined,
|
|
59
|
+
context: ToolRunContext
|
|
60
|
+
): Promise<ShellCommandResult> {
|
|
61
|
+
const result = await executeShellCommand('npx', args, {
|
|
62
|
+
context: {
|
|
63
|
+
agentId: context.agentId,
|
|
64
|
+
channelId: context.channelId,
|
|
65
|
+
requestId: context.requestId
|
|
66
|
+
},
|
|
67
|
+
workingDirectory: workingDirectory || process.cwd(),
|
|
68
|
+
captureOutput: true
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (result.exitCode === COMMAND_NOT_FOUND) {
|
|
72
|
+
throw ToolError.preconditionFailed(
|
|
73
|
+
`Could not run "npx ${args[0]}" — the command was not found. ` +
|
|
74
|
+
`${result.stderr?.trim() ?? ''}`.trim(),
|
|
75
|
+
{ command: args[0] }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
34
78
|
|
|
35
|
-
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Pull `file(line,col): error TSxxxx: message` diagnostics out of tsc output. */
|
|
83
|
+
function parseTscDiagnostics(output: string): Array<{
|
|
84
|
+
type: 'error' | 'warning';
|
|
85
|
+
file: string;
|
|
86
|
+
line: number;
|
|
87
|
+
column: number;
|
|
88
|
+
code: string;
|
|
89
|
+
message: string;
|
|
90
|
+
}> {
|
|
91
|
+
const diagnostics: Array<{
|
|
92
|
+
type: 'error' | 'warning';
|
|
93
|
+
file: string;
|
|
94
|
+
line: number;
|
|
95
|
+
column: number;
|
|
96
|
+
code: string;
|
|
97
|
+
message: string;
|
|
98
|
+
}> = [];
|
|
99
|
+
|
|
100
|
+
// tsc --pretty false emits: path/file.ts(12,5): error TS2304: Cannot find name 'x'.
|
|
101
|
+
const pattern = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.*)$/;
|
|
102
|
+
|
|
103
|
+
for (const line of output.split('\n')) {
|
|
104
|
+
const match = line.match(pattern);
|
|
105
|
+
if (!match) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
diagnostics.push({
|
|
109
|
+
type: match[4] as 'error' | 'warning',
|
|
110
|
+
file: match[1],
|
|
111
|
+
line: parseInt(match[2], 10),
|
|
112
|
+
column: parseInt(match[3], 10),
|
|
113
|
+
code: match[5],
|
|
114
|
+
message: match[6].trim()
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return diagnostics;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const typescriptCheckTool = defineTool<
|
|
122
|
+
{ workingDirectory?: string; files?: string[] },
|
|
123
|
+
{
|
|
124
|
+
passed: boolean;
|
|
125
|
+
totalErrors: number;
|
|
126
|
+
totalWarnings: number;
|
|
127
|
+
diagnostics: ReturnType<typeof parseTscDiagnostics>;
|
|
128
|
+
}
|
|
129
|
+
>({
|
|
36
130
|
name: 'typescript_check',
|
|
37
|
-
|
|
131
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
132
|
+
description:
|
|
133
|
+
'Type-check TypeScript with `tsc --noEmit` and return the diagnostics. ' +
|
|
134
|
+
'passed is false when there are type errors.',
|
|
38
135
|
inputSchema: {
|
|
39
136
|
type: 'object',
|
|
40
137
|
properties: {
|
|
41
|
-
workingDirectory:
|
|
42
|
-
type: 'string',
|
|
43
|
-
description: 'Working directory path (defaults to current directory)'
|
|
44
|
-
},
|
|
138
|
+
workingDirectory: workingDirectoryProperty,
|
|
45
139
|
files: {
|
|
46
140
|
type: 'array',
|
|
47
141
|
items: { type: 'string' },
|
|
48
|
-
description: 'Specific files to check
|
|
142
|
+
description: 'Specific files to check. Checks the whole project when omitted.'
|
|
49
143
|
}
|
|
50
144
|
}
|
|
51
145
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
files
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (args.files && args.files.length > 0) {
|
|
60
|
-
tscArgs.push(...args.files);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const result = await executeShellCommand('npx', ['tsc', ...tscArgs], {
|
|
64
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
65
|
-
captureOutput: true
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// TypeScript compiler exits with code 1 if there are errors, but this is expected
|
|
69
|
-
const diagnostics = [];
|
|
70
|
-
let totalErrors = 0;
|
|
71
|
-
let totalWarnings = 0;
|
|
72
|
-
let filesChecked = 0;
|
|
73
|
-
|
|
74
|
-
if (result.stdout) {
|
|
75
|
-
// Parse TypeScript compiler output
|
|
76
|
-
const lines = result.stdout.split('\n');
|
|
77
|
-
for (const line of lines) {
|
|
78
|
-
if (line.includes('error TS')) {
|
|
79
|
-
totalErrors++;
|
|
80
|
-
diagnostics.push({
|
|
81
|
-
type: 'error',
|
|
82
|
-
message: line.trim(),
|
|
83
|
-
file: line.split('(')[0] || '',
|
|
84
|
-
line: 0,
|
|
85
|
-
column: 0
|
|
86
|
-
});
|
|
87
|
-
} else if (line.includes('warning TS')) {
|
|
88
|
-
totalWarnings++;
|
|
89
|
-
diagnostics.push({
|
|
90
|
-
type: 'warning',
|
|
91
|
-
message: line.trim(),
|
|
92
|
-
file: line.split('(')[0] || '',
|
|
93
|
-
line: 0,
|
|
94
|
-
column: 0
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
146
|
+
run: async (input, context) => {
|
|
147
|
+
const tscArgs = ['tsc', '--noEmit', '--pretty', 'false'];
|
|
148
|
+
if (input.files && input.files.length > 0) {
|
|
149
|
+
tscArgs.push(...input.files);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const result = await runNpx(tscArgs, input.workingDirectory, context);
|
|
99
153
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
logger.error('TypeScript check failed', { error });
|
|
114
|
-
const content: McpToolResultContent = {
|
|
115
|
-
type: 'application/json',
|
|
116
|
-
data: {
|
|
117
|
-
success: false,
|
|
118
|
-
diagnostics: [],
|
|
119
|
-
totalErrors: 0,
|
|
120
|
-
totalWarnings: 0,
|
|
121
|
-
filesChecked: 0,
|
|
122
|
-
error: error instanceof Error ? error.message : String(error)
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
return { content };
|
|
154
|
+
// tsc writes diagnostics to stdout and exits 1 when it finds any. That is
|
|
155
|
+
// the tool working, not the tool failing.
|
|
156
|
+
const diagnostics = parseTscDiagnostics(result.stdout ?? '');
|
|
157
|
+
const totalErrors = diagnostics.filter(d => d.type === 'error').length;
|
|
158
|
+
const totalWarnings = diagnostics.filter(d => d.type === 'warning').length;
|
|
159
|
+
|
|
160
|
+
// A non-zero exit with nothing parseable means tsc fell over for some other
|
|
161
|
+
// reason (bad tsconfig, unreadable directory). That is a real failure.
|
|
162
|
+
if (result.exitCode !== 0 && diagnostics.length === 0) {
|
|
163
|
+
throw ToolError.executionFailed(
|
|
164
|
+
`tsc exited ${result.exitCode} without producing diagnostics: ` +
|
|
165
|
+
`${(result.stderr || result.stdout)?.trim() || 'no output'}`
|
|
166
|
+
);
|
|
126
167
|
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
passed: totalErrors === 0,
|
|
171
|
+
totalErrors,
|
|
172
|
+
totalWarnings,
|
|
173
|
+
diagnostics
|
|
174
|
+
};
|
|
127
175
|
}
|
|
128
|
-
};
|
|
176
|
+
});
|
|
129
177
|
|
|
130
|
-
export const typescriptBuildTool =
|
|
178
|
+
export const typescriptBuildTool = defineTool<
|
|
179
|
+
{ workingDirectory?: string; clean?: boolean },
|
|
180
|
+
{ passed: boolean; buildTimeMs: number; errors: string[]; output: string }
|
|
181
|
+
>({
|
|
131
182
|
name: 'typescript_build',
|
|
132
|
-
|
|
183
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
184
|
+
description: 'Build the TypeScript project with `tsc --build` and emit JavaScript.',
|
|
133
185
|
inputSchema: {
|
|
134
186
|
type: 'object',
|
|
135
187
|
properties: {
|
|
136
|
-
workingDirectory:
|
|
137
|
-
type: 'string',
|
|
138
|
-
description: 'Working directory path (defaults to current directory)'
|
|
139
|
-
},
|
|
188
|
+
workingDirectory: workingDirectoryProperty,
|
|
140
189
|
clean: {
|
|
141
190
|
type: 'boolean',
|
|
142
191
|
default: false,
|
|
143
|
-
description: '
|
|
192
|
+
description: 'Run `tsc --build --clean` first'
|
|
144
193
|
}
|
|
145
194
|
}
|
|
146
195
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
clean?: boolean;
|
|
150
|
-
}, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
const startTime = Date.now();
|
|
154
|
-
|
|
155
|
-
// Clean output directory if requested
|
|
156
|
-
if (args.clean) {
|
|
157
|
-
const cleanResult = await executeShellCommand('npx', ['tsc', '--build', '--clean'], {
|
|
158
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
159
|
-
captureOutput: true
|
|
160
|
-
});
|
|
161
|
-
if (cleanResult.exitCode !== 0) {
|
|
162
|
-
logger.warn('Clean command failed', { error: cleanResult.stderr });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const result = await executeShellCommand('npx', ['tsc', '--build'], {
|
|
167
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
168
|
-
captureOutput: true
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const buildTime = Date.now() - startTime;
|
|
172
|
-
|
|
173
|
-
const errors = [];
|
|
174
|
-
const warnings = [];
|
|
175
|
-
|
|
176
|
-
if (result.stdout) {
|
|
177
|
-
const lines = result.stdout.split('\n');
|
|
178
|
-
for (const line of lines) {
|
|
179
|
-
if (line.includes('error TS')) {
|
|
180
|
-
errors.push(line.trim());
|
|
181
|
-
} else if (line.includes('warning TS')) {
|
|
182
|
-
warnings.push(line.trim());
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
196
|
+
run: async (input, context) => {
|
|
197
|
+
const startedAt = Date.now();
|
|
186
198
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const content: McpToolResultContent = {
|
|
202
|
-
type: 'application/json',
|
|
203
|
-
data: {
|
|
204
|
-
success: false,
|
|
205
|
-
output: '',
|
|
206
|
-
errors: [],
|
|
207
|
-
warnings: [],
|
|
208
|
-
buildTime: 0,
|
|
209
|
-
error: error instanceof Error ? error.message : String(error)
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
return { content };
|
|
199
|
+
if (input.clean) {
|
|
200
|
+
const cleanResult = await runNpx(
|
|
201
|
+
['tsc', '--build', '--clean'],
|
|
202
|
+
input.workingDirectory,
|
|
203
|
+
context
|
|
204
|
+
);
|
|
205
|
+
// A failed clean leaves stale output behind, which makes the build's
|
|
206
|
+
// result meaningless. Say so rather than building on top of it.
|
|
207
|
+
if (cleanResult.exitCode !== 0) {
|
|
208
|
+
throw ToolError.executionFailed(
|
|
209
|
+
`tsc --build --clean failed (exit ${cleanResult.exitCode}): ` +
|
|
210
|
+
`${(cleanResult.stderr || cleanResult.stdout)?.trim() || 'no output'}`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
213
|
}
|
|
214
|
+
|
|
215
|
+
const result = await runNpx(['tsc', '--build'], input.workingDirectory, context);
|
|
216
|
+
|
|
217
|
+
const errors = (result.stdout ?? '')
|
|
218
|
+
.split('\n')
|
|
219
|
+
.filter(line => line.includes('error TS'))
|
|
220
|
+
.map(line => line.trim());
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
passed: result.exitCode === 0,
|
|
224
|
+
buildTimeMs: Date.now() - startedAt,
|
|
225
|
+
errors,
|
|
226
|
+
output: result.stdout ?? ''
|
|
227
|
+
};
|
|
214
228
|
}
|
|
215
|
-
};
|
|
229
|
+
});
|
|
216
230
|
|
|
217
|
-
export const typescriptFormatTool =
|
|
231
|
+
export const typescriptFormatTool = defineTool<
|
|
232
|
+
{ files?: string[]; check?: boolean; workingDirectory?: string },
|
|
233
|
+
{ mode: 'check' | 'write'; formatted: boolean; files: string[]; output: string }
|
|
234
|
+
>({
|
|
218
235
|
name: 'typescript_format',
|
|
219
|
-
|
|
236
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
237
|
+
description:
|
|
238
|
+
'Format TypeScript/JavaScript files with prettier. ' +
|
|
239
|
+
'With check: true it reports whether files are formatted without changing them.',
|
|
220
240
|
inputSchema: {
|
|
221
241
|
type: 'object',
|
|
222
242
|
properties: {
|
|
223
243
|
files: {
|
|
224
244
|
type: 'array',
|
|
225
245
|
items: { type: 'string' },
|
|
226
|
-
description: 'Files to format (
|
|
246
|
+
description: 'Files to format (glob patterns allowed). Defaults to all TS/JS sources.'
|
|
227
247
|
},
|
|
228
248
|
check: {
|
|
229
249
|
type: 'boolean',
|
|
230
250
|
default: false,
|
|
231
|
-
description: '
|
|
251
|
+
description: 'Report formatting problems instead of rewriting files'
|
|
232
252
|
},
|
|
233
|
-
workingDirectory:
|
|
234
|
-
type: 'string',
|
|
235
|
-
description: 'Working directory path (defaults to current directory)'
|
|
236
|
-
}
|
|
253
|
+
workingDirectory: workingDirectoryProperty
|
|
237
254
|
}
|
|
238
255
|
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
check
|
|
242
|
-
workingDirectory?: string;
|
|
243
|
-
}, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
const prettierArgs = args.check ? ['--check'] : ['--write'];
|
|
247
|
-
if (args.files && args.files.length > 0) {
|
|
248
|
-
prettierArgs.push(...args.files);
|
|
249
|
-
} else {
|
|
250
|
-
prettierArgs.push('**/*.{ts,tsx,js,jsx}');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const result = await executeShellCommand('npx', ['prettier', ...prettierArgs], {
|
|
254
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
255
|
-
captureOutput: true
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
const formattedFiles = [];
|
|
259
|
-
const unchanged = [];
|
|
260
|
-
|
|
261
|
-
if (result.stdout) {
|
|
262
|
-
const lines = result.stdout.split('\n');
|
|
263
|
-
for (const line of lines) {
|
|
264
|
-
if (line.includes('unchanged')) {
|
|
265
|
-
unchanged.push(line.trim());
|
|
266
|
-
} else if (line.trim() && !line.startsWith('Checking')) {
|
|
267
|
-
formattedFiles.push(line.trim());
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
256
|
+
run: async (input, context) => {
|
|
257
|
+
const mode: 'check' | 'write' = input.check ? 'check' : 'write';
|
|
258
|
+
const prettierArgs = ['prettier', input.check ? '--check' : '--write'];
|
|
271
259
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
formattedFiles,
|
|
277
|
-
unchanged,
|
|
278
|
-
error: result.exitCode !== 0 ? result.stderr : null
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
return { content };
|
|
282
|
-
} catch (error) {
|
|
283
|
-
logger.error('TypeScript format failed', { error });
|
|
284
|
-
const content: McpToolResultContent = {
|
|
285
|
-
type: 'application/json',
|
|
286
|
-
data: {
|
|
287
|
-
success: false,
|
|
288
|
-
formattedFiles: [],
|
|
289
|
-
unchanged: [],
|
|
290
|
-
error: error instanceof Error ? error.message : String(error)
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
return { content };
|
|
260
|
+
if (input.files && input.files.length > 0) {
|
|
261
|
+
prettierArgs.push(...input.files);
|
|
262
|
+
} else {
|
|
263
|
+
prettierArgs.push('**/*.{ts,tsx,js,jsx}');
|
|
294
264
|
}
|
|
265
|
+
|
|
266
|
+
const result = await runNpx(prettierArgs, input.workingDirectory, context);
|
|
267
|
+
|
|
268
|
+
// In check mode prettier exits 1 when files need formatting — a finding,
|
|
269
|
+
// not a failure. In write mode a non-zero exit means it could not write.
|
|
270
|
+
if (mode === 'write' && result.exitCode !== 0) {
|
|
271
|
+
throw ToolError.executionFailed(
|
|
272
|
+
`prettier --write failed (exit ${result.exitCode}): ` +
|
|
273
|
+
`${(result.stderr || result.stdout)?.trim() || 'no output'}`
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const files = (result.stdout ?? '')
|
|
278
|
+
.split('\n')
|
|
279
|
+
.map(line => line.trim())
|
|
280
|
+
.filter(line => line.length > 0 && !line.startsWith('Checking'));
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
mode,
|
|
284
|
+
formatted: result.exitCode === 0,
|
|
285
|
+
files,
|
|
286
|
+
output: result.stdout ?? ''
|
|
287
|
+
};
|
|
295
288
|
}
|
|
296
|
-
};
|
|
289
|
+
});
|
|
297
290
|
|
|
298
|
-
export const typescriptLintTool =
|
|
291
|
+
export const typescriptLintTool = defineTool<
|
|
292
|
+
{ files?: string[]; fix?: boolean; workingDirectory?: string },
|
|
293
|
+
{ passed: boolean; errorCount: number; warningCount: number; results: unknown[] }
|
|
294
|
+
>({
|
|
299
295
|
name: 'typescript_lint',
|
|
300
|
-
|
|
296
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
297
|
+
description:
|
|
298
|
+
'Lint TypeScript/JavaScript with ESLint and return the findings. ' +
|
|
299
|
+
'passed is false when there are lint errors.',
|
|
301
300
|
inputSchema: {
|
|
302
301
|
type: 'object',
|
|
303
302
|
properties: {
|
|
304
303
|
files: {
|
|
305
304
|
type: 'array',
|
|
306
305
|
items: { type: 'string' },
|
|
307
|
-
description: 'Files to lint (
|
|
306
|
+
description: 'Files to lint (glob patterns allowed). Defaults to all TS/JS sources.'
|
|
308
307
|
},
|
|
309
308
|
fix: {
|
|
310
309
|
type: 'boolean',
|
|
311
310
|
default: false,
|
|
312
|
-
description: 'Automatically fix problems'
|
|
311
|
+
description: 'Automatically fix the problems ESLint can fix'
|
|
313
312
|
},
|
|
314
|
-
workingDirectory:
|
|
315
|
-
type: 'string',
|
|
316
|
-
description: 'Working directory path (defaults to current directory)'
|
|
317
|
-
}
|
|
313
|
+
workingDirectory: workingDirectoryProperty
|
|
318
314
|
}
|
|
319
315
|
},
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
fix
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
eslintArgs.push(...args.files);
|
|
334
|
-
} else {
|
|
335
|
-
eslintArgs.push('**/*.{ts,tsx,js,jsx}');
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const result = await executeShellCommand('npx', ['eslint', ...eslintArgs], {
|
|
339
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
340
|
-
captureOutput: true
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
let results = [];
|
|
344
|
-
try {
|
|
345
|
-
if (result.stdout) {
|
|
346
|
-
results = JSON.parse(result.stdout);
|
|
347
|
-
}
|
|
348
|
-
} catch (parseError) {
|
|
349
|
-
logger.warn('Could not parse ESLint output as JSON', { output: result.stdout });
|
|
350
|
-
results = [{
|
|
351
|
-
filePath: 'unknown',
|
|
352
|
-
messages: [{
|
|
353
|
-
message: result.stdout,
|
|
354
|
-
severity: 1,
|
|
355
|
-
line: 0,
|
|
356
|
-
column: 0
|
|
357
|
-
}]
|
|
358
|
-
}];
|
|
359
|
-
}
|
|
316
|
+
run: async (input, context) => {
|
|
317
|
+
const eslintArgs = ['eslint', '--format', 'json'];
|
|
318
|
+
if (input.fix) {
|
|
319
|
+
eslintArgs.push('--fix');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (input.files && input.files.length > 0) {
|
|
323
|
+
eslintArgs.push(...input.files);
|
|
324
|
+
} else {
|
|
325
|
+
eslintArgs.push('**/*.{ts,tsx,js,jsx}');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const result = await runNpx(eslintArgs, input.workingDirectory, context);
|
|
360
329
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
} catch (error) {
|
|
371
|
-
logger.error('TypeScript lint failed', { error });
|
|
372
|
-
const content: McpToolResultContent = {
|
|
373
|
-
type: 'application/json',
|
|
374
|
-
data: {
|
|
375
|
-
success: false,
|
|
376
|
-
results: [],
|
|
377
|
-
error: error instanceof Error ? error.message : String(error)
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
return { content };
|
|
330
|
+
// ESLint exits 1 when it finds errors, but always prints its JSON report.
|
|
331
|
+
// No parseable report means ESLint itself fell over — that is a failure,
|
|
332
|
+
// and it must not be reported as "no lint problems".
|
|
333
|
+
const raw = (result.stdout ?? '').trim();
|
|
334
|
+
if (raw.length === 0) {
|
|
335
|
+
throw ToolError.executionFailed(
|
|
336
|
+
`eslint produced no report (exit ${result.exitCode}): ` +
|
|
337
|
+
`${result.stderr?.trim() || 'no error output'}`
|
|
338
|
+
);
|
|
381
339
|
}
|
|
340
|
+
|
|
341
|
+
let results: Array<{ errorCount?: number; warningCount?: number }>;
|
|
342
|
+
try {
|
|
343
|
+
results = JSON.parse(raw);
|
|
344
|
+
} catch (parseError) {
|
|
345
|
+
throw ToolError.executionFailed(
|
|
346
|
+
`Could not parse the ESLint JSON report: ` +
|
|
347
|
+
`${parseError instanceof Error ? parseError.message : String(parseError)}`,
|
|
348
|
+
{ details: { outputPreview: raw.slice(0, 200) } }
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const errorCount = results.reduce((sum, file) => sum + (file.errorCount ?? 0), 0);
|
|
353
|
+
const warningCount = results.reduce((sum, file) => sum + (file.warningCount ?? 0), 0);
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
passed: errorCount === 0,
|
|
357
|
+
errorCount,
|
|
358
|
+
warningCount,
|
|
359
|
+
results
|
|
360
|
+
};
|
|
382
361
|
}
|
|
383
|
-
};
|
|
362
|
+
});
|
|
384
363
|
|
|
385
|
-
export const typescriptTestTool =
|
|
364
|
+
export const typescriptTestTool = defineTool<
|
|
365
|
+
{ testFiles?: string[]; coverage?: boolean; workingDirectory?: string },
|
|
366
|
+
{ passed: boolean; testsRun: number; testsPassed: number; testsFailed: number; output: string }
|
|
367
|
+
>({
|
|
386
368
|
name: 'typescript_test',
|
|
387
|
-
|
|
369
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
370
|
+
description:
|
|
371
|
+
'Run Jest tests and return the counts. passed is false when any test fails.',
|
|
388
372
|
inputSchema: {
|
|
389
373
|
type: 'object',
|
|
390
374
|
properties: {
|
|
391
375
|
testFiles: {
|
|
392
376
|
type: 'array',
|
|
393
377
|
items: { type: 'string' },
|
|
394
|
-
description: 'Specific test files to run'
|
|
378
|
+
description: 'Specific test files to run. Runs the whole suite when omitted.'
|
|
395
379
|
},
|
|
396
380
|
coverage: {
|
|
397
381
|
type: 'boolean',
|
|
398
382
|
default: false,
|
|
399
|
-
description: 'Generate
|
|
383
|
+
description: 'Generate a coverage report'
|
|
400
384
|
},
|
|
401
|
-
workingDirectory:
|
|
402
|
-
type: 'string',
|
|
403
|
-
description: 'Working directory path (defaults to current directory)'
|
|
404
|
-
}
|
|
385
|
+
workingDirectory: workingDirectoryProperty
|
|
405
386
|
}
|
|
406
387
|
},
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
coverage?: boolean;
|
|
410
|
-
workingDirectory?: string;
|
|
411
|
-
}, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
|
|
412
|
-
|
|
413
|
-
try {
|
|
414
|
-
const jestArgs = ['--no-watchman', '--passWithNoTests'];
|
|
415
|
-
|
|
416
|
-
if (args.coverage) {
|
|
417
|
-
jestArgs.push('--coverage');
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (args.testFiles && args.testFiles.length > 0) {
|
|
421
|
-
jestArgs.push(...args.testFiles);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const result = await executeShellCommand('npx', ['jest', ...jestArgs], {
|
|
425
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
426
|
-
captureOutput: true
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
// Parse Jest output for test results
|
|
430
|
-
let testsRun = 0;
|
|
431
|
-
let testsPassed = 0;
|
|
432
|
-
let testsFailed = 0;
|
|
433
|
-
|
|
434
|
-
if (result.stdout) {
|
|
435
|
-
const runMatch = result.stdout.match(/Tests:\s+(\d+)\s+total/);
|
|
436
|
-
const passMatch = result.stdout.match(/Tests:\s+\d+\s+failed,\s+(\d+)\s+passed/);
|
|
437
|
-
const failMatch = result.stdout.match(/Tests:\s+(\d+)\s+failed/);
|
|
438
|
-
|
|
439
|
-
if (runMatch) testsRun = parseInt(runMatch[1]);
|
|
440
|
-
if (passMatch) testsPassed = parseInt(passMatch[1]);
|
|
441
|
-
if (failMatch) testsFailed = parseInt(failMatch[1]);
|
|
442
|
-
|
|
443
|
-
// Alternative parsing for different Jest output formats
|
|
444
|
-
if (testsRun === 0) {
|
|
445
|
-
const totalMatch = result.stdout.match(/(\d+)\s+tests?\s+passed/);
|
|
446
|
-
if (totalMatch) {
|
|
447
|
-
testsRun = parseInt(totalMatch[1]);
|
|
448
|
-
testsPassed = testsRun;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
388
|
+
run: async (input, context) => {
|
|
389
|
+
const jestArgs = ['jest', '--no-watchman', '--passWithNoTests'];
|
|
452
390
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
testsRun,
|
|
459
|
-
testsPassed,
|
|
460
|
-
testsFailed,
|
|
461
|
-
error: result.exitCode !== 0 ? result.stderr : null
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
return { content };
|
|
465
|
-
} catch (error) {
|
|
466
|
-
logger.error('TypeScript test failed', { error });
|
|
467
|
-
const content: McpToolResultContent = {
|
|
468
|
-
type: 'application/json',
|
|
469
|
-
data: {
|
|
470
|
-
success: false,
|
|
471
|
-
output: '',
|
|
472
|
-
testsRun: 0,
|
|
473
|
-
testsPassed: 0,
|
|
474
|
-
testsFailed: 0,
|
|
475
|
-
error: error instanceof Error ? error.message : String(error)
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
return { content };
|
|
391
|
+
if (input.coverage) {
|
|
392
|
+
jestArgs.push('--coverage');
|
|
393
|
+
}
|
|
394
|
+
if (input.testFiles && input.testFiles.length > 0) {
|
|
395
|
+
jestArgs.push(...input.testFiles);
|
|
479
396
|
}
|
|
397
|
+
|
|
398
|
+
const result = await runNpx(jestArgs, input.workingDirectory, context);
|
|
399
|
+
|
|
400
|
+
// Jest writes its summary to stderr, not stdout.
|
|
401
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
402
|
+
|
|
403
|
+
// Summary line: "Tests: 1 failed, 2 skipped, 17 passed, 20 total"
|
|
404
|
+
const summary = output.match(/^Tests:\s+(.+)$/m)?.[1] ?? '';
|
|
405
|
+
const readCount = (label: string): number => {
|
|
406
|
+
const match = summary.match(new RegExp(`(\\d+)\\s+${label}`));
|
|
407
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const testsRun = readCount('total');
|
|
411
|
+
const testsPassed = readCount('passed');
|
|
412
|
+
const testsFailed = readCount('failed');
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
passed: result.exitCode === 0,
|
|
416
|
+
testsRun,
|
|
417
|
+
testsPassed,
|
|
418
|
+
testsFailed,
|
|
419
|
+
output
|
|
420
|
+
};
|
|
480
421
|
}
|
|
481
|
-
};
|
|
422
|
+
});
|
|
482
423
|
|
|
483
|
-
// Export all TypeScript tools
|
|
484
424
|
export const typescriptTools = [
|
|
485
425
|
typescriptCheckTool,
|
|
486
426
|
typescriptBuildTool,
|