@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
|
@@ -17,18 +17,109 @@
|
|
|
17
17
|
* @repository https://github.com/BradA1878/model-exchange-framework
|
|
18
18
|
* @documentation https://mxf-dev.github.io/mxf/
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* TestTools.ts
|
|
22
|
+
*
|
|
23
|
+
* Run a project's test suite with Jest, Mocha or Vitest, or let test_runner pick
|
|
24
|
+
* the one the project actually uses.
|
|
25
|
+
*
|
|
26
|
+
* On exit codes: a test runner exits non-zero when tests fail. That is the tool
|
|
27
|
+
* working — it ran the suite and the suite failed. So a failing suite comes back
|
|
28
|
+
* with `passed: false` and `isError: false`, and `isError` is reserved for the
|
|
29
|
+
* runner not being usable at all.
|
|
30
|
+
*
|
|
31
|
+
* Watch mode is deliberately not offered. These tools are request/response: a
|
|
32
|
+
* watching runner never exits, so the call would hang until it timed out.
|
|
33
|
+
*/
|
|
34
|
+
import * as fs from 'fs/promises';
|
|
35
|
+
import * as path from 'path';
|
|
36
|
+
import { TOOL_CATEGORIES } from '../../../constants/ToolNames.js';
|
|
37
|
+
import { defineTool } from '../defineTool.js';
|
|
38
|
+
import { ToolError } from '../ToolError.js';
|
|
21
39
|
import { executeShellCommand } from './InfrastructureTools.js';
|
|
22
|
-
|
|
40
|
+
/** Exit code the shell reports when a command could not be found or spawned. */
|
|
41
|
+
const COMMAND_NOT_FOUND = 127;
|
|
42
|
+
const workingDirectoryProperty = {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Working directory path (defaults to the server working directory)'
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Run a test runner via npx and normalize its output.
|
|
48
|
+
*
|
|
49
|
+
* Throws only when the runner could not be executed. A failing suite is a
|
|
50
|
+
* result, and comes back with passed: false.
|
|
51
|
+
*/
|
|
52
|
+
async function runTestRunner(runner, runnerArgs, workingDirectory, context) {
|
|
53
|
+
const startedAt = Date.now();
|
|
54
|
+
const result = await executeShellCommand('npx', [runner, ...runnerArgs], {
|
|
55
|
+
context: {
|
|
56
|
+
agentId: context.agentId,
|
|
57
|
+
channelId: context.channelId,
|
|
58
|
+
requestId: context.requestId
|
|
59
|
+
},
|
|
60
|
+
workingDirectory: workingDirectory || process.cwd(),
|
|
61
|
+
captureOutput: true
|
|
62
|
+
});
|
|
63
|
+
if (result.exitCode === COMMAND_NOT_FOUND) {
|
|
64
|
+
throw ToolError.preconditionFailed(`Could not run ${runner} — the command was not found. ` +
|
|
65
|
+
`Install it in the project before running this tool.`, { runner });
|
|
66
|
+
}
|
|
67
|
+
// Jest and Vitest write their summary to stderr; Mocha writes to stdout.
|
|
68
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
69
|
+
const counts = parseTestCounts(runner, output);
|
|
70
|
+
return {
|
|
71
|
+
runner,
|
|
72
|
+
passed: result.exitCode === 0,
|
|
73
|
+
...counts,
|
|
74
|
+
executionTimeMs: Date.now() - startedAt,
|
|
75
|
+
output
|
|
76
|
+
};
|
|
77
|
+
}
|
|
23
78
|
/**
|
|
24
|
-
*
|
|
79
|
+
* Pull pass/fail counts out of a runner's summary.
|
|
25
80
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
81
|
+
* Each runner prints a different summary, so each gets its own pattern rather
|
|
82
|
+
* than one regex that half-matches all three.
|
|
28
83
|
*/
|
|
29
|
-
|
|
84
|
+
function parseTestCounts(runner, output) {
|
|
85
|
+
if (runner === 'jest') {
|
|
86
|
+
// "Tests: 1 failed, 2 skipped, 17 passed, 20 total"
|
|
87
|
+
const summary = output.match(/^Tests:\s+(.+)$/m)?.[1] ?? '';
|
|
88
|
+
const read = (label) => {
|
|
89
|
+
const match = summary.match(new RegExp(`(\\d+)\\s+${label}`));
|
|
90
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
testsRun: read('total'),
|
|
94
|
+
testsPassed: read('passed'),
|
|
95
|
+
testsFailed: read('failed')
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (runner === 'vitest') {
|
|
99
|
+
// "Tests 1 failed | 17 passed (18)"
|
|
100
|
+
const summary = output.match(/^\s*Tests\s+(.+)$/m)?.[1] ?? '';
|
|
101
|
+
const passed = parseInt(summary.match(/(\d+)\s+passed/)?.[1] ?? '0', 10);
|
|
102
|
+
const failed = parseInt(summary.match(/(\d+)\s+failed/)?.[1] ?? '0', 10);
|
|
103
|
+
const total = parseInt(summary.match(/\((\d+)\)/)?.[1] ?? '0', 10);
|
|
104
|
+
return {
|
|
105
|
+
testsRun: total || passed + failed,
|
|
106
|
+
testsPassed: passed,
|
|
107
|
+
testsFailed: failed
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Mocha: " 17 passing (1s)" / " 1 failing"
|
|
111
|
+
const passed = parseInt(output.match(/(\d+)\s+passing/)?.[1] ?? '0', 10);
|
|
112
|
+
const failed = parseInt(output.match(/(\d+)\s+failing/)?.[1] ?? '0', 10);
|
|
113
|
+
return {
|
|
114
|
+
testsRun: passed + failed,
|
|
115
|
+
testsPassed: passed,
|
|
116
|
+
testsFailed: failed
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export const jestTestTool = defineTool({
|
|
30
120
|
name: 'test_jest',
|
|
31
|
-
|
|
121
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
122
|
+
description: 'Run Jest tests. passed is false when any test fails.',
|
|
32
123
|
inputSchema: {
|
|
33
124
|
type: 'object',
|
|
34
125
|
properties: {
|
|
@@ -39,142 +130,50 @@ export const jestTestTool = {
|
|
|
39
130
|
},
|
|
40
131
|
testNamePattern: {
|
|
41
132
|
type: 'string',
|
|
42
|
-
description: 'Run tests
|
|
133
|
+
description: 'Run only tests whose name matches this pattern'
|
|
43
134
|
},
|
|
44
135
|
coverage: {
|
|
45
136
|
type: 'boolean',
|
|
46
137
|
default: false,
|
|
47
|
-
description: 'Generate
|
|
48
|
-
},
|
|
49
|
-
watchMode: {
|
|
50
|
-
type: 'boolean',
|
|
51
|
-
default: false,
|
|
52
|
-
description: 'Run tests in watch mode'
|
|
138
|
+
description: 'Generate a coverage report'
|
|
53
139
|
},
|
|
54
140
|
verbose: {
|
|
55
141
|
type: 'boolean',
|
|
56
142
|
default: false,
|
|
57
|
-
description: '
|
|
143
|
+
description: 'Report each test individually'
|
|
58
144
|
},
|
|
59
145
|
maxWorkers: {
|
|
60
146
|
type: 'number',
|
|
147
|
+
minimum: 1,
|
|
61
148
|
description: 'Maximum number of worker processes'
|
|
62
149
|
},
|
|
63
|
-
workingDirectory:
|
|
64
|
-
type: 'string',
|
|
65
|
-
description: 'Working directory path (defaults to current directory)'
|
|
66
|
-
}
|
|
150
|
+
workingDirectory: workingDirectoryProperty
|
|
67
151
|
}
|
|
68
152
|
},
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
jestArgs.push('--coverage');
|
|
74
|
-
}
|
|
75
|
-
if (args.verbose) {
|
|
76
|
-
jestArgs.push('--verbose');
|
|
77
|
-
}
|
|
78
|
-
if (args.maxWorkers) {
|
|
79
|
-
jestArgs.push('--maxWorkers', args.maxWorkers.toString());
|
|
80
|
-
}
|
|
81
|
-
if (args.testNamePattern) {
|
|
82
|
-
jestArgs.push('--testNamePattern', args.testNamePattern);
|
|
83
|
-
}
|
|
84
|
-
if (args.watchMode) {
|
|
85
|
-
jestArgs.push('--watch');
|
|
86
|
-
}
|
|
87
|
-
if (args.testFiles && args.testFiles.length > 0) {
|
|
88
|
-
jestArgs.push(...args.testFiles);
|
|
89
|
-
}
|
|
90
|
-
const result = await executeShellCommand('npx', ['jest', ...jestArgs], {
|
|
91
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
92
|
-
captureOutput: true
|
|
93
|
-
});
|
|
94
|
-
// Parse Jest output for test results
|
|
95
|
-
let testsRun = 0;
|
|
96
|
-
let testsPassed = 0;
|
|
97
|
-
let testsFailed = 0;
|
|
98
|
-
let testSuites = 0;
|
|
99
|
-
let testSuitesPassed = 0;
|
|
100
|
-
let testSuitesFailed = 0;
|
|
101
|
-
if (result.stdout) {
|
|
102
|
-
// Parse test results
|
|
103
|
-
const runMatch = result.stdout.match(/Tests:\s+(\d+)\s+total/);
|
|
104
|
-
const passMatch = result.stdout.match(/Tests:\s+\d+\s+failed,\s+(\d+)\s+passed/);
|
|
105
|
-
const failMatch = result.stdout.match(/Tests:\s+(\d+)\s+failed/);
|
|
106
|
-
// Parse test suites
|
|
107
|
-
const suitesMatch = result.stdout.match(/Test Suites:\s+(\d+)\s+total/);
|
|
108
|
-
const suitesPassMatch = result.stdout.match(/Test Suites:\s+\d+\s+failed,\s+(\d+)\s+passed/);
|
|
109
|
-
const suitesFailMatch = result.stdout.match(/Test Suites:\s+(\d+)\s+failed/);
|
|
110
|
-
if (runMatch)
|
|
111
|
-
testsRun = parseInt(runMatch[1]);
|
|
112
|
-
if (passMatch)
|
|
113
|
-
testsPassed = parseInt(passMatch[1]);
|
|
114
|
-
if (failMatch)
|
|
115
|
-
testsFailed = parseInt(failMatch[1]);
|
|
116
|
-
if (suitesMatch)
|
|
117
|
-
testSuites = parseInt(suitesMatch[1]);
|
|
118
|
-
if (suitesPassMatch)
|
|
119
|
-
testSuitesPassed = parseInt(suitesPassMatch[1]);
|
|
120
|
-
if (suitesFailMatch)
|
|
121
|
-
testSuitesFailed = parseInt(suitesFailMatch[1]);
|
|
122
|
-
// Alternative parsing for different Jest output formats
|
|
123
|
-
if (testsRun === 0) {
|
|
124
|
-
const totalMatch = result.stdout.match(/(\d+)\s+tests?\s+passed/);
|
|
125
|
-
if (totalMatch) {
|
|
126
|
-
testsRun = parseInt(totalMatch[1]);
|
|
127
|
-
testsPassed = testsRun;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const content = {
|
|
132
|
-
type: 'application/json',
|
|
133
|
-
data: {
|
|
134
|
-
success: result.exitCode === 0,
|
|
135
|
-
runner: 'jest',
|
|
136
|
-
output: result.stdout || '',
|
|
137
|
-
errorOutput: result.stderr || '',
|
|
138
|
-
testsRun,
|
|
139
|
-
testsPassed,
|
|
140
|
-
testsFailed,
|
|
141
|
-
testSuites,
|
|
142
|
-
testSuitesPassed,
|
|
143
|
-
testSuitesFailed,
|
|
144
|
-
executionTime: result.executionTime,
|
|
145
|
-
coverage: args.coverage ? 'Coverage report generated' : null,
|
|
146
|
-
error: result.exitCode !== 0 ? result.stderr : null
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
return { content };
|
|
153
|
+
run: async (input, context) => {
|
|
154
|
+
const args = ['--no-watchman', '--passWithNoTests'];
|
|
155
|
+
if (input.coverage) {
|
|
156
|
+
args.push('--coverage');
|
|
150
157
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
errorOutput: '',
|
|
160
|
-
testsRun: 0,
|
|
161
|
-
testsPassed: 0,
|
|
162
|
-
testsFailed: 0,
|
|
163
|
-
testSuites: 0,
|
|
164
|
-
testSuitesPassed: 0,
|
|
165
|
-
testSuitesFailed: 0,
|
|
166
|
-
executionTime: 0,
|
|
167
|
-
coverage: null,
|
|
168
|
-
error: error instanceof Error ? error.message : String(error)
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
return { content };
|
|
158
|
+
if (input.verbose) {
|
|
159
|
+
args.push('--verbose');
|
|
160
|
+
}
|
|
161
|
+
if (input.maxWorkers) {
|
|
162
|
+
args.push('--maxWorkers', String(input.maxWorkers));
|
|
163
|
+
}
|
|
164
|
+
if (input.testNamePattern) {
|
|
165
|
+
args.push('--testNamePattern', input.testNamePattern);
|
|
172
166
|
}
|
|
167
|
+
if (input.testFiles && input.testFiles.length > 0) {
|
|
168
|
+
args.push(...input.testFiles);
|
|
169
|
+
}
|
|
170
|
+
return runTestRunner('jest', args, input.workingDirectory, context);
|
|
173
171
|
}
|
|
174
|
-
};
|
|
175
|
-
export const mochaTestTool = {
|
|
172
|
+
});
|
|
173
|
+
export const mochaTestTool = defineTool({
|
|
176
174
|
name: 'test_mocha',
|
|
177
|
-
|
|
175
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
176
|
+
description: 'Run Mocha tests. passed is false when any test fails.',
|
|
178
177
|
inputSchema: {
|
|
179
178
|
type: 'object',
|
|
180
179
|
properties: {
|
|
@@ -185,104 +184,51 @@ export const mochaTestTool = {
|
|
|
185
184
|
},
|
|
186
185
|
grep: {
|
|
187
186
|
type: 'string',
|
|
188
|
-
description: 'Run tests matching this pattern'
|
|
187
|
+
description: 'Run only tests matching this pattern'
|
|
189
188
|
},
|
|
190
189
|
reporter: {
|
|
191
190
|
type: 'string',
|
|
192
|
-
enum: ['spec', '
|
|
191
|
+
enum: ['spec', 'dot', 'nyan', 'tap', 'json', 'min'],
|
|
193
192
|
default: 'spec',
|
|
194
|
-
description: '
|
|
193
|
+
description: 'Reporter format'
|
|
195
194
|
},
|
|
196
195
|
timeout: {
|
|
197
196
|
type: 'number',
|
|
198
|
-
|
|
199
|
-
description: '
|
|
197
|
+
minimum: 1,
|
|
198
|
+
description: 'Per-test timeout in milliseconds'
|
|
200
199
|
},
|
|
201
200
|
recursive: {
|
|
202
201
|
type: 'boolean',
|
|
203
202
|
default: false,
|
|
204
203
|
description: 'Look for tests in subdirectories'
|
|
205
204
|
},
|
|
206
|
-
workingDirectory:
|
|
207
|
-
type: 'string',
|
|
208
|
-
description: 'Working directory path (defaults to current directory)'
|
|
209
|
-
}
|
|
205
|
+
workingDirectory: workingDirectoryProperty
|
|
210
206
|
}
|
|
211
207
|
},
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
mochaArgs.push('--timeout', args.timeout.toString());
|
|
217
|
-
}
|
|
218
|
-
if (args.grep) {
|
|
219
|
-
mochaArgs.push('--grep', args.grep);
|
|
220
|
-
}
|
|
221
|
-
if (args.recursive) {
|
|
222
|
-
mochaArgs.push('--recursive');
|
|
223
|
-
}
|
|
224
|
-
if (args.testFiles && args.testFiles.length > 0) {
|
|
225
|
-
mochaArgs.push(...args.testFiles);
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
mochaArgs.push('test/**/*.js');
|
|
229
|
-
}
|
|
230
|
-
const result = await executeShellCommand('npx', ['mocha', ...mochaArgs], {
|
|
231
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
232
|
-
captureOutput: true
|
|
233
|
-
});
|
|
234
|
-
// Parse Mocha output for test results
|
|
235
|
-
let testsRun = 0;
|
|
236
|
-
let testsPassed = 0;
|
|
237
|
-
let testsFailed = 0;
|
|
238
|
-
if (result.stdout) {
|
|
239
|
-
const passMatch = result.stdout.match(/(\d+)\s+passing/);
|
|
240
|
-
const failMatch = result.stdout.match(/(\d+)\s+failing/);
|
|
241
|
-
if (passMatch)
|
|
242
|
-
testsPassed = parseInt(passMatch[1]);
|
|
243
|
-
if (failMatch)
|
|
244
|
-
testsFailed = parseInt(failMatch[1]);
|
|
245
|
-
testsRun = testsPassed + testsFailed;
|
|
246
|
-
}
|
|
247
|
-
const content = {
|
|
248
|
-
type: 'application/json',
|
|
249
|
-
data: {
|
|
250
|
-
success: result.exitCode === 0,
|
|
251
|
-
runner: 'mocha',
|
|
252
|
-
output: result.stdout || '',
|
|
253
|
-
errorOutput: result.stderr || '',
|
|
254
|
-
testsRun,
|
|
255
|
-
testsPassed,
|
|
256
|
-
testsFailed,
|
|
257
|
-
executionTime: result.executionTime,
|
|
258
|
-
error: result.exitCode !== 0 ? result.stderr : null
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
return { content };
|
|
208
|
+
run: async (input, context) => {
|
|
209
|
+
const args = [];
|
|
210
|
+
if (input.reporter) {
|
|
211
|
+
args.push('--reporter', input.reporter);
|
|
262
212
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
errorOutput: '',
|
|
272
|
-
testsRun: 0,
|
|
273
|
-
testsPassed: 0,
|
|
274
|
-
testsFailed: 0,
|
|
275
|
-
executionTime: 0,
|
|
276
|
-
error: error instanceof Error ? error.message : String(error)
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
return { content };
|
|
213
|
+
if (input.grep) {
|
|
214
|
+
args.push('--grep', input.grep);
|
|
215
|
+
}
|
|
216
|
+
if (input.timeout) {
|
|
217
|
+
args.push('--timeout', String(input.timeout));
|
|
218
|
+
}
|
|
219
|
+
if (input.recursive) {
|
|
220
|
+
args.push('--recursive');
|
|
280
221
|
}
|
|
222
|
+
if (input.testFiles && input.testFiles.length > 0) {
|
|
223
|
+
args.push(...input.testFiles);
|
|
224
|
+
}
|
|
225
|
+
return runTestRunner('mocha', args, input.workingDirectory, context);
|
|
281
226
|
}
|
|
282
|
-
};
|
|
283
|
-
export const vitestTestTool = {
|
|
227
|
+
});
|
|
228
|
+
export const vitestTestTool = defineTool({
|
|
284
229
|
name: 'test_vitest',
|
|
285
|
-
|
|
230
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
231
|
+
description: 'Run Vitest tests once (not in watch mode). passed is false when any test fails.',
|
|
286
232
|
inputSchema: {
|
|
287
233
|
type: 'object',
|
|
288
234
|
properties: {
|
|
@@ -294,99 +240,77 @@ export const vitestTestTool = {
|
|
|
294
240
|
coverage: {
|
|
295
241
|
type: 'boolean',
|
|
296
242
|
default: false,
|
|
297
|
-
description: 'Generate
|
|
298
|
-
},
|
|
299
|
-
watchMode: {
|
|
300
|
-
type: 'boolean',
|
|
301
|
-
default: false,
|
|
302
|
-
description: 'Run tests in watch mode'
|
|
243
|
+
description: 'Generate a coverage report'
|
|
303
244
|
},
|
|
304
245
|
reporter: {
|
|
305
246
|
type: 'string',
|
|
306
|
-
enum: ['default', 'verbose', 'dot', 'json', '
|
|
247
|
+
enum: ['default', 'verbose', 'dot', 'json', 'tap'],
|
|
307
248
|
default: 'default',
|
|
308
|
-
description: '
|
|
249
|
+
description: 'Reporter format'
|
|
309
250
|
},
|
|
310
|
-
workingDirectory:
|
|
311
|
-
type: 'string',
|
|
312
|
-
description: 'Working directory path (defaults to current directory)'
|
|
313
|
-
}
|
|
251
|
+
workingDirectory: workingDirectoryProperty
|
|
314
252
|
}
|
|
315
253
|
},
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (args.watchMode) {
|
|
323
|
-
vitestArgs.pop(); // Remove --run
|
|
324
|
-
vitestArgs.push('--watch');
|
|
325
|
-
}
|
|
326
|
-
if (args.reporter) {
|
|
327
|
-
vitestArgs.push('--reporter', args.reporter);
|
|
328
|
-
}
|
|
329
|
-
if (args.testFiles && args.testFiles.length > 0) {
|
|
330
|
-
vitestArgs.push(...args.testFiles);
|
|
331
|
-
}
|
|
332
|
-
const result = await executeShellCommand('npx', ['vitest', ...vitestArgs], {
|
|
333
|
-
workingDirectory: args.workingDirectory || process.cwd(),
|
|
334
|
-
captureOutput: true
|
|
335
|
-
});
|
|
336
|
-
// Parse Vitest output for test results
|
|
337
|
-
let testsRun = 0;
|
|
338
|
-
let testsPassed = 0;
|
|
339
|
-
let testsFailed = 0;
|
|
340
|
-
if (result.stdout) {
|
|
341
|
-
const testsMatch = result.stdout.match(/Test Files\s+(\d+)\s+passed/);
|
|
342
|
-
const failMatch = result.stdout.match(/Test Files\s+(\d+)\s+failed/);
|
|
343
|
-
if (testsMatch)
|
|
344
|
-
testsPassed = parseInt(testsMatch[1]);
|
|
345
|
-
if (failMatch)
|
|
346
|
-
testsFailed = parseInt(failMatch[1]);
|
|
347
|
-
testsRun = testsPassed + testsFailed;
|
|
348
|
-
}
|
|
349
|
-
const content = {
|
|
350
|
-
type: 'application/json',
|
|
351
|
-
data: {
|
|
352
|
-
success: result.exitCode === 0,
|
|
353
|
-
runner: 'vitest',
|
|
354
|
-
output: result.stdout || '',
|
|
355
|
-
errorOutput: result.stderr || '',
|
|
356
|
-
testsRun,
|
|
357
|
-
testsPassed,
|
|
358
|
-
testsFailed,
|
|
359
|
-
executionTime: result.executionTime,
|
|
360
|
-
coverage: args.coverage ? 'Coverage report generated' : null,
|
|
361
|
-
error: result.exitCode !== 0 ? result.stderr : null
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
return { content };
|
|
254
|
+
run: async (input, context) => {
|
|
255
|
+
// `run` is Vitest's non-watching mode. Without it Vitest watches by
|
|
256
|
+
// default and the process would never exit.
|
|
257
|
+
const args = ['run'];
|
|
258
|
+
if (input.coverage) {
|
|
259
|
+
args.push('--coverage');
|
|
365
260
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
success: false,
|
|
372
|
-
runner: 'vitest',
|
|
373
|
-
output: '',
|
|
374
|
-
errorOutput: '',
|
|
375
|
-
testsRun: 0,
|
|
376
|
-
testsPassed: 0,
|
|
377
|
-
testsFailed: 0,
|
|
378
|
-
executionTime: 0,
|
|
379
|
-
coverage: null,
|
|
380
|
-
error: error instanceof Error ? error.message : String(error)
|
|
381
|
-
}
|
|
382
|
-
};
|
|
383
|
-
return { content };
|
|
261
|
+
if (input.reporter) {
|
|
262
|
+
args.push('--reporter', input.reporter);
|
|
263
|
+
}
|
|
264
|
+
if (input.testFiles && input.testFiles.length > 0) {
|
|
265
|
+
args.push(...input.testFiles);
|
|
384
266
|
}
|
|
267
|
+
return runTestRunner('vitest', args, input.workingDirectory, context);
|
|
385
268
|
}
|
|
386
|
-
};
|
|
387
|
-
|
|
269
|
+
});
|
|
270
|
+
/**
|
|
271
|
+
* Read the project's package.json and work out which runner it uses.
|
|
272
|
+
*
|
|
273
|
+
* Throws when there is no package.json or no known runner in it — guessing
|
|
274
|
+
* "jest" for a project that does not use jest produces a confusing failure two
|
|
275
|
+
* steps later.
|
|
276
|
+
*/
|
|
277
|
+
async function detectFramework(workingDirectory) {
|
|
278
|
+
const packageJsonPath = path.join(workingDirectory, 'package.json');
|
|
279
|
+
let raw;
|
|
280
|
+
try {
|
|
281
|
+
raw = await fs.readFile(packageJsonPath, 'utf-8');
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
throw ToolError.notFound(`No package.json in ${workingDirectory}, so the test framework cannot be detected. ` +
|
|
285
|
+
`Pass framework explicitly, or run this from the project root.`);
|
|
286
|
+
}
|
|
287
|
+
let packageJson;
|
|
288
|
+
try {
|
|
289
|
+
packageJson = JSON.parse(raw);
|
|
290
|
+
}
|
|
291
|
+
catch (parseError) {
|
|
292
|
+
throw ToolError.executionFailed(`package.json in ${workingDirectory} is not valid JSON: ` +
|
|
293
|
+
`${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
294
|
+
}
|
|
295
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
296
|
+
if (deps.vitest) {
|
|
297
|
+
return 'vitest';
|
|
298
|
+
}
|
|
299
|
+
if (deps.jest) {
|
|
300
|
+
return 'jest';
|
|
301
|
+
}
|
|
302
|
+
if (deps.mocha) {
|
|
303
|
+
return 'mocha';
|
|
304
|
+
}
|
|
305
|
+
throw ToolError.notFound(`No supported test framework found in ${packageJsonPath}. ` +
|
|
306
|
+
`Expected one of jest, mocha or vitest in dependencies or devDependencies. ` +
|
|
307
|
+
`Pass framework explicitly to override.`);
|
|
308
|
+
}
|
|
309
|
+
export const testRunnerTool = defineTool({
|
|
388
310
|
name: 'test_runner',
|
|
389
|
-
|
|
311
|
+
category: TOOL_CATEGORIES.INFRASTRUCTURE,
|
|
312
|
+
description: 'Run the project\'s tests, detecting whether it uses Jest, Mocha or Vitest from ' +
|
|
313
|
+
'package.json. passed is false when any test fails.',
|
|
390
314
|
inputSchema: {
|
|
391
315
|
type: 'object',
|
|
392
316
|
properties: {
|
|
@@ -394,7 +318,7 @@ export const testRunnerTool = {
|
|
|
394
318
|
type: 'string',
|
|
395
319
|
enum: ['auto', 'jest', 'mocha', 'vitest'],
|
|
396
320
|
default: 'auto',
|
|
397
|
-
description: 'Test framework
|
|
321
|
+
description: 'Test framework. "auto" reads it from package.json.'
|
|
398
322
|
},
|
|
399
323
|
testFiles: {
|
|
400
324
|
type: 'array',
|
|
@@ -404,91 +328,45 @@ export const testRunnerTool = {
|
|
|
404
328
|
coverage: {
|
|
405
329
|
type: 'boolean',
|
|
406
330
|
default: false,
|
|
407
|
-
description: 'Generate
|
|
331
|
+
description: 'Generate a coverage report'
|
|
408
332
|
},
|
|
409
|
-
|
|
410
|
-
type: 'boolean',
|
|
411
|
-
default: false,
|
|
412
|
-
description: 'Run tests in watch mode'
|
|
413
|
-
},
|
|
414
|
-
workingDirectory: {
|
|
415
|
-
type: 'string',
|
|
416
|
-
description: 'Working directory path (defaults to current directory)'
|
|
417
|
-
}
|
|
333
|
+
workingDirectory: workingDirectoryProperty
|
|
418
334
|
}
|
|
419
335
|
},
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
// Check dependencies and devDependencies
|
|
434
|
-
const allDeps = {
|
|
435
|
-
...packageJson.dependencies,
|
|
436
|
-
...packageJson.devDependencies
|
|
437
|
-
};
|
|
438
|
-
if (allDeps.vitest) {
|
|
439
|
-
framework = 'vitest';
|
|
440
|
-
}
|
|
441
|
-
else if (allDeps.jest) {
|
|
442
|
-
framework = 'jest';
|
|
443
|
-
}
|
|
444
|
-
else if (allDeps.mocha) {
|
|
445
|
-
framework = 'mocha';
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
framework = 'jest'; // Default fallback
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
catch (parseError) {
|
|
452
|
-
framework = 'jest'; // Default fallback
|
|
453
|
-
}
|
|
336
|
+
run: async (input, context) => {
|
|
337
|
+
const workingDirectory = input.workingDirectory || process.cwd();
|
|
338
|
+
const requested = input.framework ?? 'auto';
|
|
339
|
+
const detected = requested === 'auto';
|
|
340
|
+
const framework = detected
|
|
341
|
+
? await detectFramework(workingDirectory)
|
|
342
|
+
: requested;
|
|
343
|
+
const args = [];
|
|
344
|
+
switch (framework) {
|
|
345
|
+
case 'jest':
|
|
346
|
+
args.push('--no-watchman', '--passWithNoTests');
|
|
347
|
+
if (input.coverage) {
|
|
348
|
+
args.push('--coverage');
|
|
454
349
|
}
|
|
455
|
-
|
|
456
|
-
|
|
350
|
+
break;
|
|
351
|
+
case 'vitest':
|
|
352
|
+
args.push('run');
|
|
353
|
+
if (input.coverage) {
|
|
354
|
+
args.push('--coverage');
|
|
457
355
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return await jestTestTool.handler(args, context);
|
|
463
|
-
case 'mocha':
|
|
464
|
-
return await mochaTestTool.handler(args, context);
|
|
465
|
-
case 'vitest':
|
|
466
|
-
return await vitestTestTool.handler(args, context);
|
|
467
|
-
default:
|
|
468
|
-
throw new Error(`Unknown test framework: ${framework}`);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
catch (error) {
|
|
472
|
-
logger.error('Universal test runner failed', { error });
|
|
473
|
-
const content = {
|
|
474
|
-
type: 'application/json',
|
|
475
|
-
data: {
|
|
476
|
-
success: false,
|
|
477
|
-
runner: 'unknown',
|
|
478
|
-
output: '',
|
|
479
|
-
errorOutput: '',
|
|
480
|
-
testsRun: 0,
|
|
481
|
-
testsPassed: 0,
|
|
482
|
-
testsFailed: 0,
|
|
483
|
-
executionTime: 0,
|
|
484
|
-
error: error instanceof Error ? error.message : String(error)
|
|
356
|
+
break;
|
|
357
|
+
case 'mocha':
|
|
358
|
+
if (input.coverage) {
|
|
359
|
+
throw ToolError.notImplemented('Mocha does not produce coverage on its own — run it under nyc or c8 instead.');
|
|
485
360
|
}
|
|
486
|
-
|
|
487
|
-
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
if (input.testFiles && input.testFiles.length > 0) {
|
|
364
|
+
args.push(...input.testFiles);
|
|
488
365
|
}
|
|
366
|
+
const result = await runTestRunner(framework, args, workingDirectory, context);
|
|
367
|
+
return { ...result, detected };
|
|
489
368
|
}
|
|
490
|
-
};
|
|
491
|
-
// Export all test tools
|
|
369
|
+
});
|
|
492
370
|
export const testTools = [
|
|
493
371
|
jestTestTool,
|
|
494
372
|
mochaTestTool,
|