veryfront 0.1.208 → 0.1.210

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.
@@ -0,0 +1,101 @@
1
+ /**
2
+ * MCP tool: vf_run_tests
3
+ *
4
+ * Runs the project test suite via subprocess and returns structured results.
5
+ * Reuses parseTestOutput from the CLI test command.
6
+ */
7
+ import * as dntShim from "../../../_dnt.shims.js";
8
+
9
+
10
+ import { z } from "zod";
11
+ import type { MCPTool } from "../../../src/mcp/index.js";
12
+ import { parseTestOutput, type TestResult } from "../../commands/test/command.js";
13
+
14
+ const runTestsInput = z.object({
15
+ filter: z.string().optional().describe(
16
+ "Filter tests by name pattern. Example: 'router' to run only tests matching 'router'.",
17
+ ),
18
+ parallel: z.boolean().optional().default(false).describe(
19
+ "Run tests in parallel. Defaults to false.",
20
+ ),
21
+ timeout: z.number().optional().default(300000).describe(
22
+ "Maximum time to wait for test completion in milliseconds. Defaults to 300000 (5 minutes).",
23
+ ),
24
+ });
25
+
26
+ type RunTestsInput = z.infer<typeof runTestsInput>;
27
+
28
+ /** Build the deno test command args from input options. */
29
+ export function buildTestArgs(input: { filter?: string; parallel?: boolean }): string[] {
30
+ return [
31
+ "test",
32
+ "--no-check",
33
+ "--allow-all",
34
+ "--unstable-worker-options",
35
+ "--unstable-net",
36
+ ...(input.parallel ? ["--parallel"] : []),
37
+ ...(input.filter ? [`--filter=${input.filter}`] : []),
38
+ ];
39
+ }
40
+
41
+ /** Env vars required for deterministic test runs. */
42
+ export const TEST_ENV: Record<string, string> = {
43
+ VF_DISABLE_LRU_INTERVAL: "1",
44
+ SSR_TRANSFORM_PER_PROJECT_LIMIT: "0",
45
+ REVALIDATION_PER_PROJECT_LIMIT: "0",
46
+ NODE_ENV: "production",
47
+ LOG_FORMAT: "text",
48
+ };
49
+
50
+ /** Spawn deno test and return structured results. Exported for standalone reuse. */
51
+ export async function executeTests(
52
+ input: { filter?: string; parallel?: boolean; timeout?: number },
53
+ ): Promise<TestResult> {
54
+ const cmd = new dntShim.Deno.Command("deno", {
55
+ args: buildTestArgs(input),
56
+ stdout: "piped",
57
+ stderr: "piped",
58
+ env: TEST_ENV,
59
+ });
60
+
61
+ const child = cmd.spawn();
62
+ const timeoutMs = input.timeout ?? 300000;
63
+
64
+ const result = await Promise.race([
65
+ child.output(),
66
+ new Promise<never>((_, reject) => {
67
+ const timer = dntShim.setTimeout(() => {
68
+ try {
69
+ child.kill();
70
+ } catch {
71
+ // Process may have already exited
72
+ }
73
+ reject(new Error(`Test execution timed out after ${timeoutMs}ms`));
74
+ }, timeoutMs);
75
+ // Don't prevent process exit while waiting
76
+ dntShim.Deno.unrefTimer(timer);
77
+ }),
78
+ ]);
79
+
80
+ const stdout = new TextDecoder().decode(result.stdout);
81
+ const stderr = new TextDecoder().decode(result.stderr);
82
+ return parseTestOutput(stdout + "\n" + stderr, result.code);
83
+ }
84
+
85
+ export const vfRunTests: MCPTool<RunTestsInput, TestResult> = {
86
+ name: "vf_run_tests",
87
+ title: "Run Tests",
88
+ annotations: {
89
+ readOnlyHint: false,
90
+ destructiveHint: false,
91
+ idempotentHint: true,
92
+ openWorldHint: false,
93
+ },
94
+ description:
95
+ "Use this when you need to run the project's test suite and get structured pass/fail results. " +
96
+ "Returns a summary with total, passed, failed, skipped counts and failure details including " +
97
+ "file path, test name, error message, and line number. " +
98
+ "Do not use for lint checks — use vf_run_lint instead.",
99
+ inputSchema: runTestsInput,
100
+ execute: (input) => executeTests(input),
101
+ };
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.208",
3
+ "version": "0.1.210",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -37,6 +37,29 @@ export function mergeToolInputDelta(currentArguments: string, nextDelta: string)
37
37
  }
38
38
  }
39
39
 
40
+ if (nextDelta.length === 0) {
41
+ return currentArguments;
42
+ }
43
+
44
+ if (currentArguments.length === 0) {
45
+ return nextDelta;
46
+ }
47
+
48
+ if (nextDelta === currentArguments || currentArguments.includes(nextDelta)) {
49
+ return currentArguments;
50
+ }
51
+
52
+ if (nextDelta.startsWith(currentArguments)) {
53
+ return nextDelta;
54
+ }
55
+
56
+ const maxOverlap = Math.min(currentArguments.length, nextDelta.length);
57
+ for (let overlap = maxOverlap; overlap > 0; overlap--) {
58
+ if (currentArguments.endsWith(nextDelta.slice(0, overlap))) {
59
+ return currentArguments + nextDelta.slice(overlap);
60
+ }
61
+ }
62
+
40
63
  return currentArguments + nextDelta;
41
64
  }
42
65