@muggleai/works 4.2.2 → 4.4.0
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 +45 -37
- package/dist/{chunk-BZJXQZ5Q.js → chunk-PMI2DI3V.js} +524 -173
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +4 -4
- package/dist/plugin/.cursor-plugin/plugin.json +3 -3
- package/dist/plugin/README.md +7 -5
- package/dist/plugin/scripts/ensure-electron-app.sh +3 -3
- package/dist/plugin/skills/do/e2e-acceptance.md +161 -0
- package/dist/plugin/skills/do/open-prs.md +86 -16
- package/dist/plugin/skills/muggle/SKILL.md +15 -13
- package/dist/plugin/skills/muggle-do/SKILL.md +6 -6
- package/dist/plugin/skills/muggle-test/SKILL.md +380 -0
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +44 -27
- package/dist/plugin/skills/muggle-test-import/SKILL.md +272 -0
- package/dist/plugin/skills/muggle-upgrade/SKILL.md +1 -1
- package/dist/plugin/skills/optimize-descriptions/SKILL.md +8 -8
- package/package.json +15 -12
- package/plugin/.claude-plugin/plugin.json +4 -4
- package/plugin/.cursor-plugin/plugin.json +3 -3
- package/plugin/README.md +7 -5
- package/plugin/scripts/ensure-electron-app.sh +3 -3
- package/plugin/skills/do/e2e-acceptance.md +161 -0
- package/plugin/skills/do/open-prs.md +86 -16
- package/plugin/skills/muggle/SKILL.md +15 -13
- package/plugin/skills/muggle-do/SKILL.md +6 -6
- package/plugin/skills/muggle-test/SKILL.md +380 -0
- package/plugin/skills/muggle-test-feature-local/SKILL.md +44 -27
- package/plugin/skills/muggle-test-import/SKILL.md +272 -0
- package/plugin/skills/muggle-upgrade/SKILL.md +1 -1
- package/plugin/skills/optimize-descriptions/SKILL.md +8 -8
- package/dist/plugin/skills/do/qa.md +0 -89
- package/plugin/skills/do/qa.md +0 -89
|
@@ -8,9 +8,10 @@ import { fileURLToPath } from 'url';
|
|
|
8
8
|
import winston from 'winston';
|
|
9
9
|
import axios, { AxiosError } from 'axios';
|
|
10
10
|
import { spawn, exec, execFile } from 'child_process';
|
|
11
|
+
import * as crypto from 'crypto';
|
|
12
|
+
import { randomUUID } from 'crypto';
|
|
11
13
|
import * as fs5 from 'fs/promises';
|
|
12
14
|
import { z, ZodError } from 'zod';
|
|
13
|
-
import * as crypto from 'crypto';
|
|
14
15
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
15
16
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
16
17
|
import { v4 } from 'uuid';
|
|
@@ -39,6 +40,7 @@ var DEFAULT_PROMPT_SERVICE_PRODUCTION_URL = "https://promptservice.muggle-ai.com
|
|
|
39
40
|
var DEFAULT_PROMPT_SERVICE_DEV_URL = "http://localhost:5050";
|
|
40
41
|
var DEFAULT_WEB_SERVICE_URL = "http://localhost:3001";
|
|
41
42
|
var ELECTRON_APP_DIR = "electron-app";
|
|
43
|
+
var ELECTRON_APP_RELEASE_TAG_PREFIX = "electron-app-v";
|
|
42
44
|
var API_KEY_FILE = "api-key.json";
|
|
43
45
|
var DEFAULT_AUTH0_PRODUCTION_DOMAIN = "login.muggle-ai.com";
|
|
44
46
|
var DEFAULT_AUTH0_PRODUCTION_CLIENT_ID = "UgG5UjoyLksxMciWWKqVpwfWrJ4rFvtT";
|
|
@@ -262,7 +264,7 @@ function buildAuth0Config() {
|
|
|
262
264
|
scope: process.env.AUTH0_SCOPE ?? DEFAULT_AUTH0_SCOPE
|
|
263
265
|
};
|
|
264
266
|
}
|
|
265
|
-
function
|
|
267
|
+
function buildE2eConfig() {
|
|
266
268
|
const defaultPromptServiceUrl = getDefaultPromptServiceUrl();
|
|
267
269
|
return {
|
|
268
270
|
promptServiceBaseUrl: process.env.PROMPT_SERVICE_BASE_URL ?? defaultPromptServiceUrl,
|
|
@@ -306,7 +308,7 @@ function getConfig() {
|
|
|
306
308
|
serverVersion: "1.0.0",
|
|
307
309
|
logLevel: process.env.LOG_LEVEL ?? "info",
|
|
308
310
|
auth0: buildAuth0Config(),
|
|
309
|
-
|
|
311
|
+
e2e: buildE2eConfig(),
|
|
310
312
|
localQa: buildLocalQaConfig()
|
|
311
313
|
};
|
|
312
314
|
return configInstance;
|
|
@@ -357,6 +359,15 @@ function getBundledElectronAppVersion() {
|
|
|
357
359
|
function getDownloadBaseUrl() {
|
|
358
360
|
return getMuggleConfig().downloadBaseUrl;
|
|
359
361
|
}
|
|
362
|
+
function buildElectronAppReleaseTag(version) {
|
|
363
|
+
return `${ELECTRON_APP_RELEASE_TAG_PREFIX}${version}`;
|
|
364
|
+
}
|
|
365
|
+
function buildElectronAppReleaseAssetUrl(params) {
|
|
366
|
+
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(params.version)}/${params.assetFileName}`;
|
|
367
|
+
}
|
|
368
|
+
function buildElectronAppChecksumsUrl(version) {
|
|
369
|
+
return `${getDownloadBaseUrl()}/${buildElectronAppReleaseTag(version)}/checksums.txt`;
|
|
370
|
+
}
|
|
360
371
|
function getElectronAppChecksums() {
|
|
361
372
|
return getMuggleConfig().checksums;
|
|
362
373
|
}
|
|
@@ -403,13 +414,14 @@ function resetLogger() {
|
|
|
403
414
|
loggerInstance = null;
|
|
404
415
|
}
|
|
405
416
|
|
|
406
|
-
// packages/mcps/src/mcp/
|
|
407
|
-
var
|
|
408
|
-
__export(
|
|
417
|
+
// packages/mcps/src/mcp/e2e/index.ts
|
|
418
|
+
var e2e_exports2 = {};
|
|
419
|
+
__export(e2e_exports2, {
|
|
409
420
|
ActionScriptGetInputSchema: () => ActionScriptGetInputSchema,
|
|
410
421
|
ApiKeyCreateInputSchema: () => ApiKeyCreateInputSchema,
|
|
411
422
|
ApiKeyGetInputSchema: () => ApiKeyGetInputSchema,
|
|
412
423
|
ApiKeyListInputSchema: () => ApiKeyListInputSchema,
|
|
424
|
+
ApiKeyRecordIdSchema: () => ApiKeyRecordIdSchema,
|
|
413
425
|
ApiKeyRevokeInputSchema: () => ApiKeyRevokeInputSchema,
|
|
414
426
|
AuthLoginInputSchema: () => AuthLoginInputSchema,
|
|
415
427
|
AuthPollInputSchema: () => AuthPollInputSchema,
|
|
@@ -419,6 +431,7 @@ __export(qa_exports2, {
|
|
|
419
431
|
LocalExecutionContextInputSchema: () => LocalExecutionContextInputSchema,
|
|
420
432
|
LocalRunUploadInputSchema: () => LocalRunUploadInputSchema,
|
|
421
433
|
McpErrorCode: () => McpErrorCode,
|
|
434
|
+
MuggleEntityIdSchema: () => MuggleEntityIdSchema,
|
|
422
435
|
PaginationInputSchema: () => PaginationInputSchema,
|
|
423
436
|
PrdFileDeleteInputSchema: () => PrdFileDeleteInputSchema,
|
|
424
437
|
PrdFileListInputSchema: () => PrdFileListInputSchema,
|
|
@@ -440,11 +453,13 @@ __export(qa_exports2, {
|
|
|
440
453
|
ReportFinalGenerateInputSchema: () => ReportFinalGenerateInputSchema,
|
|
441
454
|
ReportPreferencesUpsertInputSchema: () => ReportPreferencesUpsertInputSchema,
|
|
442
455
|
ReportStatsSummaryInputSchema: () => ReportStatsSummaryInputSchema,
|
|
456
|
+
RunBatchIdSchema: () => RunBatchIdSchema,
|
|
443
457
|
SecretCreateInputSchema: () => SecretCreateInputSchema,
|
|
444
458
|
SecretDeleteInputSchema: () => SecretDeleteInputSchema,
|
|
445
459
|
SecretGetInputSchema: () => SecretGetInputSchema,
|
|
446
460
|
SecretListInputSchema: () => SecretListInputSchema,
|
|
447
461
|
SecretUpdateInputSchema: () => SecretUpdateInputSchema,
|
|
462
|
+
StripePaymentMethodIdSchema: () => StripePaymentMethodIdSchema,
|
|
448
463
|
TestCaseCreateInputSchema: () => TestCaseCreateInputSchema,
|
|
449
464
|
TestCaseGenerateFromPromptInputSchema: () => TestCaseGenerateFromPromptInputSchema,
|
|
450
465
|
TestCaseGetInputSchema: () => TestCaseGetInputSchema,
|
|
@@ -453,6 +468,8 @@ __export(qa_exports2, {
|
|
|
453
468
|
TestScriptGetInputSchema: () => TestScriptGetInputSchema,
|
|
454
469
|
TestScriptListInputSchema: () => TestScriptListInputSchema,
|
|
455
470
|
TestScriptListPaginatedInputSchema: () => TestScriptListPaginatedInputSchema,
|
|
471
|
+
TokenPackageIdSchema: () => TokenPackageIdSchema,
|
|
472
|
+
TokenUsageFilterTypeSchema: () => TokenUsageFilterTypeSchema,
|
|
456
473
|
UseCaseCandidatesApproveInputSchema: () => UseCaseCandidatesApproveInputSchema,
|
|
457
474
|
UseCaseCreateFromPromptsInputSchema: () => UseCaseCreateFromPromptsInputSchema,
|
|
458
475
|
UseCaseDiscoveryMemoryGetInputSchema: () => UseCaseDiscoveryMemoryGetInputSchema,
|
|
@@ -1621,7 +1638,7 @@ var RunResultStorageService = class {
|
|
|
1621
1638
|
*/
|
|
1622
1639
|
createRunResult(params) {
|
|
1623
1640
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1624
|
-
const id =
|
|
1641
|
+
const id = randomUUID();
|
|
1625
1642
|
const result = {
|
|
1626
1643
|
id,
|
|
1627
1644
|
runType: params.runType,
|
|
@@ -1704,7 +1721,7 @@ var RunResultStorageService = class {
|
|
|
1704
1721
|
*/
|
|
1705
1722
|
createTestScript(params) {
|
|
1706
1723
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1707
|
-
const id =
|
|
1724
|
+
const id = randomUUID();
|
|
1708
1725
|
const script = {
|
|
1709
1726
|
id,
|
|
1710
1727
|
name: params.name,
|
|
@@ -1751,7 +1768,7 @@ function getAuthenticatedUserId() {
|
|
|
1751
1768
|
const authService = getAuthService();
|
|
1752
1769
|
const authStatus = authService.getAuthStatus();
|
|
1753
1770
|
if (!authStatus.authenticated) {
|
|
1754
|
-
throw new Error("Not authenticated. Please run
|
|
1771
|
+
throw new Error("Not authenticated. Please run muggle-remote-auth-login first.");
|
|
1755
1772
|
}
|
|
1756
1773
|
if (!authStatus.userId) {
|
|
1757
1774
|
throw new Error("User ID not found in auth. Please re-authenticate.");
|
|
@@ -1801,7 +1818,7 @@ function buildStudioAuthContent() {
|
|
|
1801
1818
|
const authStatus = authService.getAuthStatus();
|
|
1802
1819
|
const storedAuth = authService.loadStoredAuth();
|
|
1803
1820
|
if (!authStatus.authenticated || !storedAuth) {
|
|
1804
|
-
throw new Error("Not authenticated. Please run
|
|
1821
|
+
throw new Error("Not authenticated. Please run muggle-remote-auth-login first.");
|
|
1805
1822
|
}
|
|
1806
1823
|
if (!storedAuth.email || !storedAuth.userId) {
|
|
1807
1824
|
throw new Error("Auth data incomplete. Please re-authenticate.");
|
|
@@ -1928,6 +1945,7 @@ function buildGenerationActionScript(params) {
|
|
|
1928
1945
|
url: params.localUrl,
|
|
1929
1946
|
description: params.testCase.title,
|
|
1930
1947
|
precondition: params.testCase.precondition ?? "",
|
|
1948
|
+
instructions: params.testCase.instructions ?? "",
|
|
1931
1949
|
expectedResult: params.testCase.expectedResult,
|
|
1932
1950
|
steps: [],
|
|
1933
1951
|
ownerId: params.ownerUserId,
|
|
@@ -2616,7 +2634,7 @@ async function pollDeviceCode(config, deviceCode) {
|
|
|
2616
2634
|
}
|
|
2617
2635
|
async function createApiKeyWithToken(accessToken, keyName, expiry = "90d") {
|
|
2618
2636
|
const config = getConfig();
|
|
2619
|
-
const apiKeyUrl = `${config.
|
|
2637
|
+
const apiKeyUrl = `${config.e2e.promptServiceBaseUrl}/v1/protected/api-keys`;
|
|
2620
2638
|
try {
|
|
2621
2639
|
logger4.info("[Auth] Creating API key", {
|
|
2622
2640
|
keyName,
|
|
@@ -2809,6 +2827,7 @@ function toolRequiresAuth(toolName) {
|
|
|
2809
2827
|
];
|
|
2810
2828
|
return !noAuthTools.includes(toolName);
|
|
2811
2829
|
}
|
|
2830
|
+
var MuggleEntityIdSchema = z.string().uuid();
|
|
2812
2831
|
var LocalExecutionContextInputSchema = z.object({
|
|
2813
2832
|
originalUrl: z.string().url().describe("Original local URL used during local execution (typically localhost)"),
|
|
2814
2833
|
productionUrl: z.string().url().describe("Cloud production URL for the test case"),
|
|
@@ -2818,12 +2837,12 @@ var LocalExecutionContextInputSchema = z.object({
|
|
|
2818
2837
|
electronAppVersion: z.string().optional().describe("Electron app version used for local run"),
|
|
2819
2838
|
mcpServerVersion: z.string().optional().describe("MCP server version used for local run"),
|
|
2820
2839
|
localExecutionCompletedAt: z.number().int().positive().describe("Epoch milliseconds when local run completed"),
|
|
2821
|
-
uploadedAt: z.number().int().positive().
|
|
2840
|
+
uploadedAt: z.number().int().positive().describe("Epoch milliseconds when uploaded to cloud")
|
|
2822
2841
|
});
|
|
2823
2842
|
var LocalRunUploadInputSchema = z.object({
|
|
2824
|
-
projectId:
|
|
2825
|
-
useCaseId:
|
|
2826
|
-
testCaseId:
|
|
2843
|
+
projectId: MuggleEntityIdSchema.describe("Project ID (UUID) for the local run"),
|
|
2844
|
+
useCaseId: MuggleEntityIdSchema.describe("Use case ID (UUID) for the local run"),
|
|
2845
|
+
testCaseId: MuggleEntityIdSchema.describe("Test case ID (UUID) for the local run"),
|
|
2827
2846
|
runType: z.enum(["generation", "replay"]).describe("Type of local run to upload"),
|
|
2828
2847
|
productionUrl: z.string().url().describe("Cloud production URL associated with the run"),
|
|
2829
2848
|
localExecutionContext: LocalExecutionContextInputSchema.describe("Local execution metadata"),
|
|
@@ -2833,12 +2852,16 @@ var LocalRunUploadInputSchema = z.object({
|
|
|
2833
2852
|
errorMessage: z.string().optional().describe("Error message when status is failed")
|
|
2834
2853
|
});
|
|
2835
2854
|
|
|
2836
|
-
// packages/mcps/src/mcp/
|
|
2855
|
+
// packages/mcps/src/mcp/e2e/contracts/index.ts
|
|
2837
2856
|
var PaginationInputSchema = z.object({
|
|
2838
2857
|
page: z.number().int().positive().optional().describe("Page number (1-based)"),
|
|
2839
2858
|
pageSize: z.number().int().positive().max(100).optional().describe("Number of items per page")
|
|
2840
2859
|
});
|
|
2841
|
-
var IdSchema =
|
|
2860
|
+
var IdSchema = MuggleEntityIdSchema;
|
|
2861
|
+
var RunBatchIdSchema = MuggleEntityIdSchema.describe("Bulk replay run batch ID (UUID)");
|
|
2862
|
+
var TokenPackageIdSchema = z.string().min(1).describe("Token package ID from wallet catalog");
|
|
2863
|
+
var StripePaymentMethodIdSchema = z.string().regex(/^pm_[a-zA-Z0-9]+$/).describe("Stripe payment method ID (pm_\u2026)");
|
|
2864
|
+
var ApiKeyRecordIdSchema = z.string().length(24).regex(/^[0-9a-f]+$/i).describe("API key record ID (24-character hex)");
|
|
2842
2865
|
var WorkflowMemoryParamsSchema = z.object({
|
|
2843
2866
|
enableSharedTestMemory: z.boolean().optional().describe("Override to enable/disable SharedTestMemory for this workflow run"),
|
|
2844
2867
|
enableEverMemOS: z.boolean().optional().describe("Override to enable/disable EverMemOS for this workflow run")
|
|
@@ -2846,39 +2869,46 @@ var WorkflowMemoryParamsSchema = z.object({
|
|
|
2846
2869
|
var WorkflowParamsSchema = z.object({
|
|
2847
2870
|
memory: WorkflowMemoryParamsSchema.optional().describe("Per-run memory override settings")
|
|
2848
2871
|
}).passthrough().optional().describe("Optional workflow parameters for workflow-level overrides");
|
|
2872
|
+
var TokenUsageFilterTypeSchema = z.enum([
|
|
2873
|
+
"project",
|
|
2874
|
+
"useCase",
|
|
2875
|
+
"testCase",
|
|
2876
|
+
"testScript",
|
|
2877
|
+
"actionScript"
|
|
2878
|
+
]).describe("Token cost aggregation dimension");
|
|
2849
2879
|
var ProjectCreateInputSchema = z.object({
|
|
2850
2880
|
projectName: z.string().min(1).max(255).describe("Name of the project"),
|
|
2851
2881
|
description: z.string().min(1).describe("Project description"),
|
|
2852
2882
|
url: z.string().url().describe("Target website URL to test")
|
|
2853
2883
|
});
|
|
2854
2884
|
var ProjectGetInputSchema = z.object({
|
|
2855
|
-
projectId: IdSchema.describe("Project ID to retrieve")
|
|
2885
|
+
projectId: IdSchema.describe("Project ID (UUID) to retrieve")
|
|
2856
2886
|
});
|
|
2857
2887
|
var ProjectDeleteInputSchema = z.object({
|
|
2858
|
-
projectId: IdSchema.describe("Project ID to delete")
|
|
2888
|
+
projectId: IdSchema.describe("Project ID (UUID) to delete")
|
|
2859
2889
|
});
|
|
2860
2890
|
var ProjectUpdateInputSchema = z.object({
|
|
2861
|
-
projectId: IdSchema.describe("Project ID to update"),
|
|
2891
|
+
projectId: IdSchema.describe("Project ID (UUID) to update"),
|
|
2862
2892
|
projectName: z.string().min(1).max(255).optional().describe("New project name"),
|
|
2863
2893
|
description: z.string().optional().describe("Updated description"),
|
|
2864
2894
|
url: z.string().url().optional().describe("Updated target URL")
|
|
2865
2895
|
});
|
|
2866
2896
|
var ProjectListInputSchema = PaginationInputSchema.extend({});
|
|
2867
2897
|
var PrdFileUploadInputSchema = z.object({
|
|
2868
|
-
projectId: IdSchema.describe("Project ID to associate the PRD file with"),
|
|
2898
|
+
projectId: IdSchema.describe("Project ID (UUID) to associate the PRD file with"),
|
|
2869
2899
|
fileName: z.string().min(1).describe("Name of the file"),
|
|
2870
2900
|
contentBase64: z.string().min(1).describe("Base64-encoded file content"),
|
|
2871
2901
|
contentType: z.string().optional().describe("MIME type of the file")
|
|
2872
2902
|
});
|
|
2873
2903
|
var PrdFileListInputSchema = z.object({
|
|
2874
|
-
projectId: IdSchema.describe("Project ID to list PRD files for")
|
|
2904
|
+
projectId: IdSchema.describe("Project ID (UUID) to list PRD files for")
|
|
2875
2905
|
});
|
|
2876
2906
|
var PrdFileDeleteInputSchema = z.object({
|
|
2877
|
-
projectId: IdSchema.describe("Project ID"),
|
|
2878
|
-
prdFileId: IdSchema.describe("PRD file ID to delete")
|
|
2907
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
2908
|
+
prdFileId: IdSchema.describe("PRD file ID (UUID) to delete")
|
|
2879
2909
|
});
|
|
2880
2910
|
var PrdFileProcessStartInputSchema = z.object({
|
|
2881
|
-
projectId: IdSchema.describe("Project ID to process PRD files for"),
|
|
2911
|
+
projectId: IdSchema.describe("Project ID (UUID) to process PRD files for"),
|
|
2882
2912
|
name: z.string().min(1).describe("Workflow name"),
|
|
2883
2913
|
description: z.string().min(1).describe("Description of the PRD processing workflow"),
|
|
2884
2914
|
prdFilePath: z.string().min(1).describe("Storage path of the uploaded PRD file (from upload response)"),
|
|
@@ -2888,75 +2918,75 @@ var PrdFileProcessStartInputSchema = z.object({
|
|
|
2888
2918
|
fileSize: z.number().int().min(0).describe("Size of the PRD file in bytes (from upload response)")
|
|
2889
2919
|
});
|
|
2890
2920
|
var PrdFileProcessLatestRunInputSchema = z.object({
|
|
2891
|
-
workflowRuntimeId: IdSchema.describe("PRD processing workflow runtime ID")
|
|
2921
|
+
workflowRuntimeId: IdSchema.describe("PRD processing workflow runtime ID (UUID)")
|
|
2892
2922
|
});
|
|
2893
2923
|
var SecretListInputSchema = z.object({
|
|
2894
|
-
projectId: IdSchema.describe("Project ID to list secrets for")
|
|
2924
|
+
projectId: IdSchema.describe("Project ID (UUID) to list secrets for")
|
|
2895
2925
|
});
|
|
2896
2926
|
var SecretCreateInputSchema = z.object({
|
|
2897
|
-
projectId: IdSchema.describe("Project ID to create the secret for"),
|
|
2927
|
+
projectId: IdSchema.describe("Project ID (UUID) to create the secret for"),
|
|
2898
2928
|
name: z.string().min(1).describe("Secret name/key"),
|
|
2899
2929
|
value: z.string().min(1).describe("Secret value"),
|
|
2900
2930
|
description: z.string().min(1).describe("Human-readable description for selection guidance"),
|
|
2901
2931
|
source: z.enum(["user", "agent"]).optional().describe("Source of the secret: 'user' for user-provided credentials, 'agent' for agent-generated credentials")
|
|
2902
2932
|
});
|
|
2903
2933
|
var SecretGetInputSchema = z.object({
|
|
2904
|
-
secretId: IdSchema.describe("Secret ID to retrieve")
|
|
2934
|
+
secretId: IdSchema.describe("Secret ID (UUID) to retrieve")
|
|
2905
2935
|
});
|
|
2906
2936
|
var SecretUpdateInputSchema = z.object({
|
|
2907
|
-
secretId: IdSchema.describe("Secret ID to update"),
|
|
2937
|
+
secretId: IdSchema.describe("Secret ID (UUID) to update"),
|
|
2908
2938
|
name: z.string().min(1).optional().describe("Updated secret name"),
|
|
2909
2939
|
value: z.string().min(1).optional().describe("Updated secret value"),
|
|
2910
2940
|
description: z.string().optional().describe("Updated description")
|
|
2911
2941
|
});
|
|
2912
2942
|
var SecretDeleteInputSchema = z.object({
|
|
2913
|
-
secretId: IdSchema.describe("Secret ID to delete")
|
|
2943
|
+
secretId: IdSchema.describe("Secret ID (UUID) to delete")
|
|
2914
2944
|
});
|
|
2915
2945
|
var UseCaseDiscoveryMemoryGetInputSchema = z.object({
|
|
2916
|
-
projectId: IdSchema.describe("Project ID to get use case discovery memory for")
|
|
2946
|
+
projectId: IdSchema.describe("Project ID (UUID) to get use case discovery memory for")
|
|
2917
2947
|
});
|
|
2918
2948
|
var UseCaseCandidatesApproveInputSchema = z.object({
|
|
2919
|
-
projectId: IdSchema.describe("Project ID"),
|
|
2949
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
2920
2950
|
approvedCandidateIds: z.array(IdSchema).min(1).describe("IDs of candidates to approve/graduate")
|
|
2921
2951
|
});
|
|
2922
2952
|
var UseCaseListInputSchema = z.object({
|
|
2923
|
-
projectId: IdSchema.describe("Project ID to list use cases for")
|
|
2953
|
+
projectId: IdSchema.describe("Project ID (UUID) to list use cases for")
|
|
2924
2954
|
}).merge(PaginationInputSchema);
|
|
2925
2955
|
var UseCaseGetInputSchema = z.object({
|
|
2926
|
-
useCaseId: IdSchema.describe("Use case ID to retrieve")
|
|
2956
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to retrieve")
|
|
2927
2957
|
});
|
|
2928
2958
|
var UseCasePromptPreviewInputSchema = z.object({
|
|
2929
|
-
projectId: IdSchema.describe("Project ID to generate use case for"),
|
|
2959
|
+
projectId: IdSchema.describe("Project ID (UUID) to generate use case for"),
|
|
2930
2960
|
instruction: z.string().min(1).describe("Natural language instruction describing the use case (e.g., 'As a logged-in user, I can add items to cart')")
|
|
2931
2961
|
});
|
|
2932
2962
|
var UseCaseCreateFromPromptsInputSchema = z.object({
|
|
2933
|
-
projectId: IdSchema.describe("Project ID to create use cases for"),
|
|
2963
|
+
projectId: IdSchema.describe("Project ID (UUID) to create use cases for"),
|
|
2934
2964
|
prompts: z.array(z.object({
|
|
2935
2965
|
instruction: z.string().min(1).describe("Natural language instruction describing the use case")
|
|
2936
2966
|
})).min(1).describe("Array of prompts to generate use cases from")
|
|
2937
2967
|
});
|
|
2938
2968
|
var UseCaseUpdateFromPromptInputSchema = z.object({
|
|
2939
|
-
projectId: IdSchema.describe("Project ID"),
|
|
2940
|
-
useCaseId: IdSchema.describe("Use case ID to update"),
|
|
2969
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
2970
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to update"),
|
|
2941
2971
|
instruction: z.string().min(1).describe("Natural language instruction to regenerate the use case from")
|
|
2942
2972
|
});
|
|
2943
2973
|
var TestCaseListInputSchema = z.object({
|
|
2944
|
-
projectId: IdSchema.describe("Project ID to list test cases for")
|
|
2974
|
+
projectId: IdSchema.describe("Project ID (UUID) to list test cases for")
|
|
2945
2975
|
}).merge(PaginationInputSchema);
|
|
2946
2976
|
var TestCaseGetInputSchema = z.object({
|
|
2947
|
-
testCaseId: IdSchema.describe("Test case ID to retrieve")
|
|
2977
|
+
testCaseId: IdSchema.describe("Test case ID (UUID) to retrieve")
|
|
2948
2978
|
});
|
|
2949
2979
|
var TestCaseListByUseCaseInputSchema = z.object({
|
|
2950
|
-
useCaseId: IdSchema.describe("Use case ID to list test cases for")
|
|
2980
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to list test cases for")
|
|
2951
2981
|
});
|
|
2952
2982
|
var TestCaseGenerateFromPromptInputSchema = z.object({
|
|
2953
|
-
projectId: IdSchema.describe("Project ID"),
|
|
2954
|
-
useCaseId: IdSchema.describe("Use case ID to generate test cases for"),
|
|
2983
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
2984
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to generate test cases for"),
|
|
2955
2985
|
instruction: z.string().min(1).describe("Natural language instruction describing the test cases to generate")
|
|
2956
2986
|
});
|
|
2957
2987
|
var TestCaseCreateInputSchema = z.object({
|
|
2958
|
-
projectId: IdSchema.describe("Project ID"),
|
|
2959
|
-
useCaseId: IdSchema.describe("Use case ID to associate the test case with"),
|
|
2988
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
2989
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to associate the test case with"),
|
|
2960
2990
|
title: z.string().min(1).describe("Test case title"),
|
|
2961
2991
|
description: z.string().min(1).describe("Detailed description of what the test case validates"),
|
|
2962
2992
|
goal: z.string().min(1).describe("Concise, measurable goal of the test"),
|
|
@@ -2970,43 +3000,43 @@ var TestCaseCreateInputSchema = z.object({
|
|
|
2970
3000
|
automated: z.boolean().optional().describe("Whether this test case is automated (default: true)")
|
|
2971
3001
|
});
|
|
2972
3002
|
var TestScriptListInputSchema = z.object({
|
|
2973
|
-
projectId: IdSchema.describe("Project ID to list test scripts for"),
|
|
2974
|
-
testCaseId: IdSchema.optional().describe("Optional test case ID to filter scripts by")
|
|
3003
|
+
projectId: IdSchema.describe("Project ID (UUID) to list test scripts for"),
|
|
3004
|
+
testCaseId: IdSchema.optional().describe("Optional test case ID (UUID) to filter scripts by")
|
|
2975
3005
|
}).merge(PaginationInputSchema);
|
|
2976
3006
|
var TestScriptGetInputSchema = z.object({
|
|
2977
|
-
testScriptId: IdSchema.describe("Test script ID to retrieve")
|
|
3007
|
+
testScriptId: IdSchema.describe("Test script ID (UUID) to retrieve")
|
|
2978
3008
|
});
|
|
2979
3009
|
var TestScriptListPaginatedInputSchema = z.object({
|
|
2980
|
-
projectId: IdSchema.describe("Project ID to list test scripts for")
|
|
3010
|
+
projectId: IdSchema.describe("Project ID (UUID) to list test scripts for")
|
|
2981
3011
|
}).merge(PaginationInputSchema);
|
|
2982
3012
|
var ActionScriptGetInputSchema = z.object({
|
|
2983
|
-
actionScriptId: IdSchema.describe("Action script ID to retrieve")
|
|
3013
|
+
actionScriptId: IdSchema.describe("Action script ID (UUID) to retrieve")
|
|
2984
3014
|
});
|
|
2985
3015
|
var WorkflowStartWebsiteScanInputSchema = z.object({
|
|
2986
|
-
projectId: IdSchema.describe("Project ID to scan"),
|
|
3016
|
+
projectId: IdSchema.describe("Project ID (UUID) to scan"),
|
|
2987
3017
|
url: z.string().url().describe("Website URL to scan"),
|
|
2988
3018
|
description: z.string().min(1).describe("Description of what to scan/discover"),
|
|
2989
3019
|
archiveUnapproved: z.boolean().optional().describe("Whether to archive unapproved candidates before scanning"),
|
|
2990
3020
|
workflowParams: WorkflowParamsSchema
|
|
2991
3021
|
});
|
|
2992
3022
|
var WorkflowListRuntimesInputSchema = z.object({
|
|
2993
|
-
projectId: IdSchema.optional().describe("Filter by project ID")
|
|
3023
|
+
projectId: IdSchema.optional().describe("Filter by project ID (UUID)")
|
|
2994
3024
|
});
|
|
2995
3025
|
var WorkflowGetLatestRunInputSchema = z.object({
|
|
2996
|
-
workflowRuntimeId: IdSchema.describe("Workflow runtime ID")
|
|
3026
|
+
workflowRuntimeId: IdSchema.describe("Workflow runtime ID (UUID)")
|
|
2997
3027
|
});
|
|
2998
3028
|
var WorkflowStartTestCaseDetectionInputSchema = z.object({
|
|
2999
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3000
|
-
useCaseId: IdSchema.describe("Use case ID to detect test cases for"),
|
|
3029
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3030
|
+
useCaseId: IdSchema.describe("Use case ID (UUID) to detect test cases for"),
|
|
3001
3031
|
name: z.string().min(1).describe("Workflow name"),
|
|
3002
3032
|
description: z.string().min(1).describe("Workflow description"),
|
|
3003
3033
|
url: z.string().url().describe("Target website URL"),
|
|
3004
3034
|
workflowParams: WorkflowParamsSchema
|
|
3005
3035
|
});
|
|
3006
3036
|
var WorkflowStartTestScriptGenerationInputSchema = z.object({
|
|
3007
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3008
|
-
useCaseId: IdSchema.describe("Use case ID"),
|
|
3009
|
-
testCaseId: IdSchema.describe("Test case ID"),
|
|
3037
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3038
|
+
useCaseId: IdSchema.describe("Use case ID (UUID)"),
|
|
3039
|
+
testCaseId: IdSchema.describe("Test case ID (UUID)"),
|
|
3010
3040
|
name: z.string().min(1).describe("Workflow name"),
|
|
3011
3041
|
url: z.string().url().describe("Target website URL"),
|
|
3012
3042
|
goal: z.string().min(1).describe("Test goal"),
|
|
@@ -3016,57 +3046,57 @@ var WorkflowStartTestScriptGenerationInputSchema = z.object({
|
|
|
3016
3046
|
workflowParams: WorkflowParamsSchema
|
|
3017
3047
|
});
|
|
3018
3048
|
var WorkflowGetLatestScriptGenByTestCaseInputSchema = z.object({
|
|
3019
|
-
testCaseId: IdSchema.describe("Test case ID")
|
|
3049
|
+
testCaseId: IdSchema.describe("Test case ID (UUID)")
|
|
3020
3050
|
});
|
|
3021
3051
|
var WorkflowStartTestScriptReplayInputSchema = z.object({
|
|
3022
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3023
|
-
useCaseId: IdSchema.describe("Use case ID"),
|
|
3024
|
-
testCaseId: IdSchema.describe("Test case ID"),
|
|
3025
|
-
testScriptId: IdSchema.describe("Test script ID to replay"),
|
|
3052
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3053
|
+
useCaseId: IdSchema.describe("Use case ID (UUID)"),
|
|
3054
|
+
testCaseId: IdSchema.describe("Test case ID (UUID)"),
|
|
3055
|
+
testScriptId: IdSchema.describe("Test script ID (UUID) to replay"),
|
|
3026
3056
|
name: z.string().min(1).describe("Workflow name"),
|
|
3027
3057
|
workflowParams: WorkflowParamsSchema
|
|
3028
3058
|
});
|
|
3029
3059
|
var WorkflowStartTestScriptReplayBulkInputSchema = z.object({
|
|
3030
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3060
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3031
3061
|
name: z.string().min(1).describe("Workflow name"),
|
|
3032
3062
|
intervalSec: z.number().int().describe("Interval in seconds (-1 for one-time / on-demand)"),
|
|
3033
|
-
useCaseId: IdSchema.optional().describe("Optional: only replay test cases under this use case"),
|
|
3063
|
+
useCaseId: IdSchema.optional().describe("Optional: only replay test cases under this use case (UUID)"),
|
|
3034
3064
|
namePrefix: z.string().optional().describe("Optional: prefix for generated workflow names"),
|
|
3035
3065
|
limit: z.number().int().optional().describe("Optional: limit number of test cases to replay"),
|
|
3036
|
-
testCaseIds: z.array(IdSchema).optional().describe("Optional: targeted test
|
|
3066
|
+
testCaseIds: z.array(IdSchema).optional().describe("Optional: targeted test case UUIDs to replay"),
|
|
3037
3067
|
repeatPerTestCase: z.number().int().optional().describe("Optional: repeat count per test case"),
|
|
3038
3068
|
workflowParams: WorkflowParamsSchema
|
|
3039
3069
|
});
|
|
3040
3070
|
var WorkflowGetReplayBulkBatchSummaryInputSchema = z.object({
|
|
3041
|
-
runBatchId:
|
|
3071
|
+
runBatchId: RunBatchIdSchema.describe("Run batch ID (UUID) from bulk replay workflow")
|
|
3042
3072
|
});
|
|
3043
3073
|
var WorkflowCancelRunInputSchema = z.object({
|
|
3044
|
-
workflowRunId: IdSchema.describe("Workflow run ID to cancel")
|
|
3074
|
+
workflowRunId: IdSchema.describe("Workflow run ID (UUID) to cancel")
|
|
3045
3075
|
});
|
|
3046
3076
|
var WorkflowCancelRuntimeInputSchema = z.object({
|
|
3047
|
-
workflowRuntimeId: IdSchema.describe("Workflow runtime ID to cancel")
|
|
3077
|
+
workflowRuntimeId: IdSchema.describe("Workflow runtime ID (UUID) to cancel")
|
|
3048
3078
|
});
|
|
3049
3079
|
var ProjectTestResultsSummaryInputSchema = z.object({
|
|
3050
|
-
projectId: IdSchema.describe("Project ID to get test results summary for")
|
|
3080
|
+
projectId: IdSchema.describe("Project ID (UUID) to get test results summary for")
|
|
3051
3081
|
});
|
|
3052
3082
|
var ProjectTestScriptsSummaryInputSchema = z.object({
|
|
3053
|
-
projectId: IdSchema.describe("Project ID to get test scripts summary for")
|
|
3083
|
+
projectId: IdSchema.describe("Project ID (UUID) to get test scripts summary for")
|
|
3054
3084
|
});
|
|
3055
3085
|
var ProjectTestRunsSummaryInputSchema = z.object({
|
|
3056
|
-
projectId: IdSchema.describe("Project ID to get test runs summary for")
|
|
3086
|
+
projectId: IdSchema.describe("Project ID (UUID) to get test runs summary for")
|
|
3057
3087
|
});
|
|
3058
3088
|
var ReportStatsSummaryInputSchema = z.object({
|
|
3059
|
-
projectId: IdSchema.describe("Project ID to get report stats for")
|
|
3089
|
+
projectId: IdSchema.describe("Project ID (UUID) to get report stats for")
|
|
3060
3090
|
});
|
|
3061
3091
|
var ReportCostQueryInputSchema = z.object({
|
|
3062
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3092
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3063
3093
|
startDateKey: z.string().optional().describe("Start date key (YYYYMMDD)"),
|
|
3064
3094
|
endDateKey: z.string().optional().describe("End date key (YYYYMMDD)"),
|
|
3065
|
-
filterType:
|
|
3066
|
-
filterIds: z.array(
|
|
3095
|
+
filterType: TokenUsageFilterTypeSchema.optional().describe("Aggregation dimension for cost breakdown"),
|
|
3096
|
+
filterIds: z.array(IdSchema).optional().describe("Entity UUIDs matching filterType (project / use case / test case / test script / action script)")
|
|
3067
3097
|
});
|
|
3068
3098
|
var ReportPreferencesUpsertInputSchema = z.object({
|
|
3069
|
-
projectId: IdSchema.describe("Project ID"),
|
|
3099
|
+
projectId: IdSchema.describe("Project ID (UUID)"),
|
|
3070
3100
|
channels: z.array(z.unknown()).describe("Delivery channels to enable"),
|
|
3071
3101
|
emails: z.array(z.unknown()).optional().describe("Email addresses for delivery"),
|
|
3072
3102
|
phones: z.array(z.unknown()).optional().describe("Phone numbers for SMS delivery"),
|
|
@@ -3074,11 +3104,11 @@ var ReportPreferencesUpsertInputSchema = z.object({
|
|
|
3074
3104
|
defaultExportFormat: z.string().optional().describe("Default export format (pdf, html, etc.)")
|
|
3075
3105
|
});
|
|
3076
3106
|
var ReportFinalGenerateInputSchema = z.object({
|
|
3077
|
-
projectId: IdSchema.describe("Project ID to generate report for"),
|
|
3107
|
+
projectId: IdSchema.describe("Project ID (UUID) to generate report for"),
|
|
3078
3108
|
exportFormat: z.enum(["pdf", "html", "markdown"]).describe("Export format for the report")
|
|
3079
3109
|
});
|
|
3080
3110
|
var WalletTopUpInputSchema = z.object({
|
|
3081
|
-
packageId:
|
|
3111
|
+
packageId: TokenPackageIdSchema.describe("Token package ID to purchase"),
|
|
3082
3112
|
checkoutSuccessCallback: z.string().url().describe("URL to redirect to when checkout succeeds"),
|
|
3083
3113
|
checkoutCancelCallback: z.string().url().describe("URL to redirect to when checkout is canceled")
|
|
3084
3114
|
});
|
|
@@ -3087,21 +3117,21 @@ var WalletPaymentMethodCreateSetupSessionInputSchema = z.object({
|
|
|
3087
3117
|
checkoutCancelCallback: z.string().url().describe("URL to redirect to when payment method setup is canceled")
|
|
3088
3118
|
});
|
|
3089
3119
|
var WalletAutoTopUpSetPaymentMethodInputSchema = z.object({
|
|
3090
|
-
paymentMethodId:
|
|
3120
|
+
paymentMethodId: StripePaymentMethodIdSchema.describe("Saved Stripe payment method ID")
|
|
3091
3121
|
});
|
|
3092
3122
|
var WalletPaymentMethodListInputSchema = z.object({});
|
|
3093
3123
|
var WalletAutoTopUpUpdateInputSchema = z.object({
|
|
3094
3124
|
enabled: z.boolean().describe("Whether auto top-up is enabled"),
|
|
3095
3125
|
topUpTriggerTokenThreshold: z.number().int().min(0).describe("Token balance threshold to trigger auto top-up"),
|
|
3096
|
-
packageId:
|
|
3126
|
+
packageId: TokenPackageIdSchema.describe("Token package ID to purchase when auto top-up triggers")
|
|
3097
3127
|
});
|
|
3098
3128
|
var RecommendScheduleInputSchema = z.object({
|
|
3099
|
-
projectId: IdSchema.optional().describe("Project ID for context"),
|
|
3129
|
+
projectId: IdSchema.optional().describe("Project ID (UUID) for context"),
|
|
3100
3130
|
testFrequency: z.enum(["daily", "weekly", "onDemand"]).optional().describe("Desired test frequency"),
|
|
3101
3131
|
timezone: z.string().optional().describe("Timezone for scheduling")
|
|
3102
3132
|
});
|
|
3103
3133
|
var RecommendCicdSetupInputSchema = z.object({
|
|
3104
|
-
projectId: IdSchema.optional().describe("Project ID for context"),
|
|
3134
|
+
projectId: IdSchema.optional().describe("Project ID (UUID) for context"),
|
|
3105
3135
|
repositoryProvider: z.enum(["github", "azureDevOps", "gitlab", "other"]).optional().describe("Git repository provider"),
|
|
3106
3136
|
cadence: z.enum(["onPullRequest", "nightly", "onDemand"]).optional().describe("CI/CD trigger cadence")
|
|
3107
3137
|
});
|
|
@@ -3111,10 +3141,10 @@ var ApiKeyCreateInputSchema = z.object({
|
|
|
3111
3141
|
});
|
|
3112
3142
|
var ApiKeyListInputSchema = z.object({});
|
|
3113
3143
|
var ApiKeyGetInputSchema = z.object({
|
|
3114
|
-
apiKeyId:
|
|
3144
|
+
apiKeyId: ApiKeyRecordIdSchema.describe("ID of the API key record to retrieve")
|
|
3115
3145
|
});
|
|
3116
3146
|
var ApiKeyRevokeInputSchema = z.object({
|
|
3117
|
-
apiKeyId:
|
|
3147
|
+
apiKeyId: ApiKeyRecordIdSchema.describe("ID of the API key record to revoke")
|
|
3118
3148
|
});
|
|
3119
3149
|
var AuthLoginInputSchema = z.object({
|
|
3120
3150
|
waitForCompletion: z.boolean().optional().describe("Whether to wait for browser login completion before returning. Default: true"),
|
|
@@ -3125,7 +3155,7 @@ var AuthPollInputSchema = z.object({
|
|
|
3125
3155
|
});
|
|
3126
3156
|
var EmptyInputSchema = z.object({});
|
|
3127
3157
|
|
|
3128
|
-
// packages/mcps/src/mcp/
|
|
3158
|
+
// packages/mcps/src/mcp/e2e/types.ts
|
|
3129
3159
|
var McpErrorCode = /* @__PURE__ */ ((McpErrorCode2) => {
|
|
3130
3160
|
McpErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
3131
3161
|
McpErrorCode2["FORBIDDEN"] = "FORBIDDEN";
|
|
@@ -3162,8 +3192,8 @@ var PromptServiceClient = class {
|
|
|
3162
3192
|
requestTimeoutMs;
|
|
3163
3193
|
constructor() {
|
|
3164
3194
|
const config = getConfig();
|
|
3165
|
-
this.baseUrl = config.
|
|
3166
|
-
this.requestTimeoutMs = config.
|
|
3195
|
+
this.baseUrl = config.e2e.promptServiceBaseUrl;
|
|
3196
|
+
this.requestTimeoutMs = config.e2e.requestTimeoutMs;
|
|
3167
3197
|
this.httpClient = axios.create({
|
|
3168
3198
|
baseURL: this.baseUrl,
|
|
3169
3199
|
timeout: this.requestTimeoutMs,
|
|
@@ -3394,13 +3424,13 @@ function getPromptServiceClient() {
|
|
|
3394
3424
|
return clientInstance;
|
|
3395
3425
|
}
|
|
3396
3426
|
|
|
3397
|
-
// packages/mcps/src/mcp/tools/
|
|
3427
|
+
// packages/mcps/src/mcp/tools/e2e/tool-registry.ts
|
|
3398
3428
|
var MUGGLE_TEST_PREFIX = "/v1/protected/muggle-test";
|
|
3399
|
-
var getWorkflowTimeoutMs = () => getConfig().
|
|
3429
|
+
var getWorkflowTimeoutMs = () => getConfig().e2e.workflowTimeoutMs;
|
|
3400
3430
|
var projectTools = [
|
|
3401
3431
|
{
|
|
3402
3432
|
name: "muggle-remote-project-create",
|
|
3403
|
-
description: "Create
|
|
3433
|
+
description: "Create an E2E acceptance testing project to organize browser tests for a web app. A project groups test scenarios (use cases), specific test steps (test cases), and replayable browser scripts (test scripts) for one application. Create a project first before generating or running any E2E tests.",
|
|
3404
3434
|
inputSchema: ProjectCreateInputSchema,
|
|
3405
3435
|
mapToUpstream: (input) => {
|
|
3406
3436
|
const data = input;
|
|
@@ -3601,7 +3631,7 @@ var testCaseTools = [
|
|
|
3601
3631
|
},
|
|
3602
3632
|
{
|
|
3603
3633
|
name: "muggle-remote-test-case-generate-from-prompt",
|
|
3604
|
-
description: "Generate
|
|
3634
|
+
description: "Generate E2E acceptance test cases from a plain-English description of what to test \u2014 e.g., 'test the signup flow with invalid email' or 'verify the checkout handles empty cart'. Returns preview test cases that can be used to generate executable browser test scripts.",
|
|
3605
3635
|
inputSchema: TestCaseGenerateFromPromptInputSchema,
|
|
3606
3636
|
mapToUpstream: (input) => {
|
|
3607
3637
|
const data = input;
|
|
@@ -3697,7 +3727,7 @@ var actionScriptTools = [
|
|
|
3697
3727
|
var workflowTools = [
|
|
3698
3728
|
{
|
|
3699
3729
|
name: "muggle-remote-workflow-start-website-scan",
|
|
3700
|
-
description: "Scan a website to automatically discover testable user flows and UI interactions. Crawls the site and identifies use cases like signup, login, search, checkout, form submissions, and navigation patterns. Use this when setting up
|
|
3730
|
+
description: "Scan a website to automatically discover testable user flows and UI interactions. Crawls the site and identifies use cases like signup, login, search, checkout, form submissions, and navigation patterns. Use this when setting up E2E acceptance testing for a site without predefined test cases.",
|
|
3701
3731
|
inputSchema: WorkflowStartWebsiteScanInputSchema,
|
|
3702
3732
|
mapToUpstream: (input) => {
|
|
3703
3733
|
const data = input;
|
|
@@ -4520,7 +4550,7 @@ var apiKeyTools = [
|
|
|
4520
4550
|
},
|
|
4521
4551
|
{
|
|
4522
4552
|
name: "muggle-remote-auth-api-key-revoke",
|
|
4523
|
-
description: "Revoke an API key. The key will immediately stop working. Use
|
|
4553
|
+
description: "Revoke an API key. The key will immediately stop working. Use muggle-remote-auth-api-key-list to find the key ID first.",
|
|
4524
4554
|
inputSchema: ApiKeyRevokeInputSchema,
|
|
4525
4555
|
mapToUpstream: (input) => {
|
|
4526
4556
|
const data = input;
|
|
@@ -4739,15 +4769,15 @@ async function executeQaTool(toolName, input, correlationId) {
|
|
|
4739
4769
|
}
|
|
4740
4770
|
}
|
|
4741
4771
|
|
|
4742
|
-
// packages/mcps/src/mcp/tools/
|
|
4743
|
-
var
|
|
4744
|
-
__export(
|
|
4772
|
+
// packages/mcps/src/mcp/tools/e2e/index.ts
|
|
4773
|
+
var e2e_exports = {};
|
|
4774
|
+
__export(e2e_exports, {
|
|
4745
4775
|
allQaToolDefinitions: () => allQaToolDefinitions,
|
|
4746
4776
|
executeQaTool: () => executeQaTool,
|
|
4747
4777
|
getQaToolByName: () => getQaToolByName
|
|
4748
4778
|
});
|
|
4749
4779
|
|
|
4750
|
-
// packages/mcps/src/mcp/
|
|
4780
|
+
// packages/mcps/src/mcp/e2e/index.ts
|
|
4751
4781
|
function getQaTools() {
|
|
4752
4782
|
return allQaToolDefinitions.map((tool) => ({
|
|
4753
4783
|
name: tool.name,
|
|
@@ -4781,6 +4811,7 @@ __export(local_exports2, {
|
|
|
4781
4811
|
LocalTestScriptStatus: () => LocalTestScriptStatus,
|
|
4782
4812
|
LocalWorkflowFileEntityType: () => LocalWorkflowFileEntityType,
|
|
4783
4813
|
LocalWorkflowRunStatus: () => LocalWorkflowRunStatus,
|
|
4814
|
+
MuggleEntityIdSchema: () => MuggleEntityIdSchema,
|
|
4784
4815
|
PublishTestScriptInputSchema: () => PublishTestScriptInputSchema,
|
|
4785
4816
|
RunResultGetInputSchema: () => RunResultGetInputSchema,
|
|
4786
4817
|
RunResultListInputSchema: () => RunResultListInputSchema,
|
|
@@ -4825,7 +4856,7 @@ var AuthPollInputSchema2 = z.object({
|
|
|
4825
4856
|
var EmptyInputSchema2 = z.object({});
|
|
4826
4857
|
var TestCaseDetailsSchema = z.object({
|
|
4827
4858
|
/** Cloud test case ID. */
|
|
4828
|
-
id:
|
|
4859
|
+
id: MuggleEntityIdSchema.describe("Cloud test case ID (UUID)"),
|
|
4829
4860
|
/** Test case title. */
|
|
4830
4861
|
title: z.string().min(1).describe("Test case title"),
|
|
4831
4862
|
/** Test goal. */
|
|
@@ -4839,37 +4870,39 @@ var TestCaseDetailsSchema = z.object({
|
|
|
4839
4870
|
/** Original cloud URL (for reference, replaced by localUrl). */
|
|
4840
4871
|
url: z.string().url().optional().describe("Original cloud URL (replaced by localUrl during execution)"),
|
|
4841
4872
|
/** Cloud project ID (required for electron workflow context). */
|
|
4842
|
-
projectId:
|
|
4873
|
+
projectId: MuggleEntityIdSchema.describe("Cloud project ID (UUID)"),
|
|
4843
4874
|
/** Cloud use case ID (required for electron workflow context). */
|
|
4844
|
-
useCaseId:
|
|
4875
|
+
useCaseId: MuggleEntityIdSchema.describe("Cloud use case ID (UUID)")
|
|
4845
4876
|
});
|
|
4846
4877
|
var TestScriptDetailsSchema = z.object({
|
|
4847
4878
|
/** Cloud test script ID. */
|
|
4848
|
-
id:
|
|
4879
|
+
id: MuggleEntityIdSchema.describe("Cloud test script ID (UUID)"),
|
|
4849
4880
|
/** Script name. */
|
|
4850
4881
|
name: z.string().min(1).describe("Test script name"),
|
|
4851
4882
|
/** Cloud test case ID this script belongs to. */
|
|
4852
|
-
testCaseId:
|
|
4883
|
+
testCaseId: MuggleEntityIdSchema.describe("Cloud test case ID (UUID) this script was generated from"),
|
|
4853
4884
|
/** Action script ID reference (use muggle-remote-action-script-get to fetch content). */
|
|
4854
|
-
actionScriptId:
|
|
4885
|
+
actionScriptId: MuggleEntityIdSchema.describe(
|
|
4886
|
+
"Action script ID (UUID) \u2014 use muggle-remote-action-script-get to fetch the full script"
|
|
4887
|
+
),
|
|
4855
4888
|
/** Original cloud URL (for reference, replaced by localUrl). */
|
|
4856
4889
|
url: z.string().url().optional().describe("Original cloud URL (replaced by localUrl during execution)"),
|
|
4857
4890
|
/** Cloud project ID (required for electron workflow context). */
|
|
4858
|
-
projectId:
|
|
4891
|
+
projectId: MuggleEntityIdSchema.describe("Cloud project ID (UUID)"),
|
|
4859
4892
|
/** Cloud use case ID (required for electron workflow context). */
|
|
4860
|
-
useCaseId:
|
|
4893
|
+
useCaseId: MuggleEntityIdSchema.describe("Cloud use case ID (UUID)")
|
|
4861
4894
|
});
|
|
4862
4895
|
var ExecuteTestGenerationInputSchema = z.object({
|
|
4863
|
-
/** Test case details from
|
|
4864
|
-
testCase: TestCaseDetailsSchema.describe("Test case details obtained from
|
|
4896
|
+
/** Test case details from muggle-remote-test-case-get. */
|
|
4897
|
+
testCase: TestCaseDetailsSchema.describe("Test case details obtained from muggle-remote-test-case-get"),
|
|
4865
4898
|
/** Local URL to test against. */
|
|
4866
4899
|
localUrl: z.string().url().describe("Local URL to test against (e.g., http://localhost:3000)"),
|
|
4867
4900
|
/** Explicit approval to launch electron-app. */
|
|
4868
4901
|
approveElectronAppLaunch: z.boolean().describe("Set to true after the user explicitly approves launching electron-app"),
|
|
4869
4902
|
/** Optional timeout. */
|
|
4870
4903
|
timeoutMs: z.number().int().positive().optional().describe("Timeout in milliseconds (default: 300000 = 5 min)"),
|
|
4871
|
-
/** Show the electron-app UI during execution. */
|
|
4872
|
-
showUi: z.boolean().optional().describe("Show the electron-app UI during
|
|
4904
|
+
/** Show the electron-app UI during execution. Ask the user before approving; true = visible window, false or omit = headless. */
|
|
4905
|
+
showUi: z.boolean().optional().describe("Show the electron-app UI during generation. Ask the user: true to watch the window, false or omit for headless.")
|
|
4873
4906
|
});
|
|
4874
4907
|
var ExecuteReplayInputSchema = z.object({
|
|
4875
4908
|
/** Test script metadata from muggle-remote-test-script-get. */
|
|
@@ -4882,28 +4915,28 @@ var ExecuteReplayInputSchema = z.object({
|
|
|
4882
4915
|
approveElectronAppLaunch: z.boolean().describe("Set to true after the user explicitly approves launching electron-app"),
|
|
4883
4916
|
/** Optional timeout. */
|
|
4884
4917
|
timeoutMs: z.number().int().positive().optional().describe("Timeout in milliseconds (default: 180000 = 3 min)"),
|
|
4885
|
-
/** Show the electron-app UI during execution. */
|
|
4886
|
-
showUi: z.boolean().optional().describe("Show the electron-app UI during
|
|
4918
|
+
/** Show the electron-app UI during execution. Ask the user before approving; true = visible window, false or omit = headless. */
|
|
4919
|
+
showUi: z.boolean().optional().describe("Show the electron-app UI during replay. Ask the user: true to watch the window, false or omit for headless.")
|
|
4887
4920
|
});
|
|
4888
4921
|
var CancelExecutionInputSchema = z.object({
|
|
4889
|
-
runId:
|
|
4922
|
+
runId: MuggleEntityIdSchema.describe("Run ID (UUID) to cancel")
|
|
4890
4923
|
});
|
|
4891
4924
|
var RunResultListInputSchema = z.object({
|
|
4892
|
-
cloudTestCaseId:
|
|
4925
|
+
cloudTestCaseId: MuggleEntityIdSchema.optional().describe("Optional cloud test case ID (UUID) to filter by"),
|
|
4893
4926
|
limit: z.number().int().positive().optional().describe("Maximum results to return (default: 20)")
|
|
4894
4927
|
});
|
|
4895
4928
|
var RunResultGetInputSchema = z.object({
|
|
4896
|
-
runId:
|
|
4929
|
+
runId: MuggleEntityIdSchema.describe("Run result ID (UUID) to retrieve")
|
|
4897
4930
|
});
|
|
4898
4931
|
var TestScriptListInputSchema2 = z.object({
|
|
4899
|
-
cloudTestCaseId:
|
|
4932
|
+
cloudTestCaseId: MuggleEntityIdSchema.optional().describe("Optional cloud test case ID (UUID) to filter by")
|
|
4900
4933
|
});
|
|
4901
4934
|
var TestScriptGetInputSchema2 = z.object({
|
|
4902
|
-
testScriptId:
|
|
4935
|
+
testScriptId: MuggleEntityIdSchema.describe("Local stored test script ID (UUID) to retrieve")
|
|
4903
4936
|
});
|
|
4904
4937
|
var PublishTestScriptInputSchema = z.object({
|
|
4905
|
-
runId:
|
|
4906
|
-
cloudTestCaseId:
|
|
4938
|
+
runId: MuggleEntityIdSchema.describe("Local run result ID (UUID) from muggle_execute_test_generation"),
|
|
4939
|
+
cloudTestCaseId: MuggleEntityIdSchema.describe("Cloud test case ID (UUID) to publish the script under")
|
|
4907
4940
|
});
|
|
4908
4941
|
var ListSessionsInputSchema = z.object({
|
|
4909
4942
|
limit: z.number().int().positive().optional().describe("Maximum number of sessions to return. Defaults to 10.")
|
|
@@ -5123,14 +5156,15 @@ var testScriptGetTool = {
|
|
|
5123
5156
|
};
|
|
5124
5157
|
var executeTestGenerationTool = {
|
|
5125
5158
|
name: "muggle-local-execute-test-generation",
|
|
5126
|
-
description: "Generate
|
|
5159
|
+
description: "Generate an end-to-end (E2E) acceptance test script by launching a real browser against your web app. The browser navigates your app, executes the test case steps (like signing up, filling forms, clicking through flows), and produces a replayable test script with screenshots. Use this to create new browser tests for any user flow. Requires a test case (from muggle-remote-test-case-get) and a localhost URL. Launches an Electron browser \u2014 requires explicit approval via approveElectronAppLaunch. Before approving, ask the user whether they want a visible GUI; pass showUi: true to watch the window or showUi: false for headless (default when omitted).",
|
|
5127
5160
|
inputSchema: ExecuteTestGenerationInputSchema,
|
|
5128
5161
|
execute: async (ctx) => {
|
|
5129
5162
|
const logger14 = createChildLogger2(ctx.correlationId);
|
|
5130
5163
|
logger14.info("Executing muggle-local-execute-test-generation");
|
|
5131
5164
|
const input = ExecuteTestGenerationInputSchema.parse(ctx.input);
|
|
5132
5165
|
if (!input.approveElectronAppLaunch) {
|
|
5133
|
-
const
|
|
5166
|
+
const showUiExplicit = input.showUi !== void 0;
|
|
5167
|
+
const uiMode = input.showUi === true ? "visible GUI (showUi: true)" : "headless (showUi: false or omitted)";
|
|
5134
5168
|
return {
|
|
5135
5169
|
content: [
|
|
5136
5170
|
"## Electron App Launch Required",
|
|
@@ -5138,22 +5172,28 @@ var executeTestGenerationTool = {
|
|
|
5138
5172
|
"This tool will launch the electron-app to generate a test script.",
|
|
5139
5173
|
"Please set `approveElectronAppLaunch: true` to proceed.",
|
|
5140
5174
|
"",
|
|
5175
|
+
"**Visible GUI:** Ask the user whether they want to watch the Electron window during generation.",
|
|
5176
|
+
"- If **yes** \u2192 when approving, pass `showUi: true`.",
|
|
5177
|
+
"- If **no** \u2192 when approving, pass `showUi: false` (or omit `showUi`; generation runs headless).",
|
|
5178
|
+
"",
|
|
5179
|
+
showUiExplicit ? `**Current choice:** ${uiMode}` : "**Current choice:** not set \u2014 default on approval is headless unless you pass `showUi: true`.",
|
|
5180
|
+
"",
|
|
5141
5181
|
`**Test Case:** ${input.testCase.title}`,
|
|
5142
5182
|
`**Local URL:** ${input.localUrl}`,
|
|
5143
|
-
`**UI Mode:** ${uiMode}`,
|
|
5144
5183
|
"",
|
|
5145
|
-
"**Note:** The electron-app will
|
|
5184
|
+
"**Note:** The electron-app will navigate your test URL and record steps."
|
|
5146
5185
|
].join("\n"),
|
|
5147
5186
|
isError: false,
|
|
5148
5187
|
data: { requiresApproval: true }
|
|
5149
5188
|
};
|
|
5150
5189
|
}
|
|
5190
|
+
const showUi = input.showUi === true;
|
|
5151
5191
|
try {
|
|
5152
5192
|
const result = await executeTestGeneration({
|
|
5153
5193
|
testCase: input.testCase,
|
|
5154
5194
|
localUrl: input.localUrl,
|
|
5155
5195
|
timeoutMs: input.timeoutMs,
|
|
5156
|
-
showUi
|
|
5196
|
+
showUi
|
|
5157
5197
|
});
|
|
5158
5198
|
const content = [
|
|
5159
5199
|
"## Test Generation " + (result.status === "passed" ? "Successful" : "Failed"),
|
|
@@ -5162,6 +5202,7 @@ var executeTestGenerationTool = {
|
|
|
5162
5202
|
`**Test Script ID:** ${result.testScriptId}`,
|
|
5163
5203
|
`**Status:** ${result.status}`,
|
|
5164
5204
|
`**Duration:** ${result.executionTimeMs}ms`,
|
|
5205
|
+
`**UI:** ${showUi ? "visible GUI" : "headless"}`,
|
|
5165
5206
|
result.errorMessage ? `**Error:** ${result.errorMessage}` : ""
|
|
5166
5207
|
].filter(Boolean).join("\n");
|
|
5167
5208
|
return {
|
|
@@ -5178,14 +5219,15 @@ var executeTestGenerationTool = {
|
|
|
5178
5219
|
};
|
|
5179
5220
|
var executeReplayTool = {
|
|
5180
5221
|
name: "muggle-local-execute-replay",
|
|
5181
|
-
description: "Replay an existing
|
|
5222
|
+
description: "Replay an existing E2E acceptance test script in a real browser to verify your app still works correctly \u2014 use this for regression testing after code changes. The browser executes each saved step and captures screenshots so you can see what happened. Requires: (1) test script metadata from muggle-remote-test-script-get, (2) actionScript content from muggle-remote-action-script-get using the testScript.actionScriptId, and (3) a localhost URL. Launches an Electron browser \u2014 requires explicit approval via approveElectronAppLaunch. Before approving, ask the user whether they want a visible GUI; pass showUi: true to watch the window or showUi: false for headless (default when omitted).",
|
|
5182
5223
|
inputSchema: ExecuteReplayInputSchema,
|
|
5183
5224
|
execute: async (ctx) => {
|
|
5184
5225
|
const logger14 = createChildLogger2(ctx.correlationId);
|
|
5185
5226
|
logger14.info("Executing muggle-local-execute-replay");
|
|
5186
5227
|
const input = ExecuteReplayInputSchema.parse(ctx.input);
|
|
5187
5228
|
if (!input.approveElectronAppLaunch) {
|
|
5188
|
-
const
|
|
5229
|
+
const showUiExplicit = input.showUi !== void 0;
|
|
5230
|
+
const uiMode = input.showUi === true ? "visible GUI (showUi: true)" : "headless (showUi: false or omitted)";
|
|
5189
5231
|
return {
|
|
5190
5232
|
content: [
|
|
5191
5233
|
"## Electron App Launch Required",
|
|
@@ -5193,24 +5235,30 @@ var executeReplayTool = {
|
|
|
5193
5235
|
"This tool will launch the electron-app to replay a test script.",
|
|
5194
5236
|
"Please set `approveElectronAppLaunch: true` to proceed.",
|
|
5195
5237
|
"",
|
|
5238
|
+
"**Visible GUI:** Ask the user whether they want to watch the Electron window during replay.",
|
|
5239
|
+
"- If **yes** \u2192 when approving, pass `showUi: true`.",
|
|
5240
|
+
"- If **no** \u2192 when approving, pass `showUi: false` (or omit `showUi`; replay runs headless).",
|
|
5241
|
+
"",
|
|
5242
|
+
showUiExplicit ? `**Current choice:** ${uiMode}` : "**Current choice:** not set \u2014 default on approval is headless unless you pass `showUi: true`.",
|
|
5243
|
+
"",
|
|
5196
5244
|
`**Test Script:** ${input.testScript.name}`,
|
|
5197
5245
|
`**Local URL:** ${input.localUrl}`,
|
|
5198
5246
|
`**Steps:** ${input.actionScript.length}`,
|
|
5199
|
-
`**UI Mode:** ${uiMode}`,
|
|
5200
5247
|
"",
|
|
5201
|
-
"**Note:** The electron-app will
|
|
5248
|
+
"**Note:** The electron-app will execute the test steps against your local URL."
|
|
5202
5249
|
].join("\n"),
|
|
5203
5250
|
isError: false,
|
|
5204
5251
|
data: { requiresApproval: true }
|
|
5205
5252
|
};
|
|
5206
5253
|
}
|
|
5254
|
+
const showUi = input.showUi === true;
|
|
5207
5255
|
try {
|
|
5208
5256
|
const result = await executeReplay({
|
|
5209
5257
|
testScript: input.testScript,
|
|
5210
5258
|
actionScript: input.actionScript,
|
|
5211
5259
|
localUrl: input.localUrl,
|
|
5212
5260
|
timeoutMs: input.timeoutMs,
|
|
5213
|
-
showUi
|
|
5261
|
+
showUi
|
|
5214
5262
|
});
|
|
5215
5263
|
const content = [
|
|
5216
5264
|
"## Test Replay " + (result.status === "passed" ? "Successful" : "Failed"),
|
|
@@ -5219,6 +5267,7 @@ var executeReplayTool = {
|
|
|
5219
5267
|
`**Test Script ID:** ${result.testScriptId}`,
|
|
5220
5268
|
`**Status:** ${result.status}`,
|
|
5221
5269
|
`**Duration:** ${result.executionTimeMs}ms`,
|
|
5270
|
+
`**UI:** ${showUi ? "visible GUI" : "headless"}`,
|
|
5222
5271
|
result.errorMessage ? `**Error:** ${result.errorMessage}` : ""
|
|
5223
5272
|
].filter(Boolean).join("\n");
|
|
5224
5273
|
return {
|
|
@@ -5457,9 +5506,10 @@ function isLocalOnlyTool(toolName) {
|
|
|
5457
5506
|
var mcp_exports = {};
|
|
5458
5507
|
__export(mcp_exports, {
|
|
5459
5508
|
agents: () => agents_exports,
|
|
5509
|
+
e2e: () => e2e_exports2,
|
|
5460
5510
|
localQa: () => local_exports2,
|
|
5461
5511
|
plugins: () => plugins_exports,
|
|
5462
|
-
qa: () =>
|
|
5512
|
+
qa: () => e2e_exports2,
|
|
5463
5513
|
skills: () => skills_exports,
|
|
5464
5514
|
tools: () => tools_exports
|
|
5465
5515
|
});
|
|
@@ -5467,8 +5517,9 @@ __export(mcp_exports, {
|
|
|
5467
5517
|
// packages/mcps/src/mcp/tools/index.ts
|
|
5468
5518
|
var tools_exports = {};
|
|
5469
5519
|
__export(tools_exports, {
|
|
5520
|
+
e2e: () => e2e_exports,
|
|
5470
5521
|
localQa: () => local_exports,
|
|
5471
|
-
qa: () =>
|
|
5522
|
+
qa: () => e2e_exports
|
|
5472
5523
|
});
|
|
5473
5524
|
|
|
5474
5525
|
// packages/mcps/src/mcp/skills/index.ts
|
|
@@ -5483,11 +5534,15 @@ var agents_exports = {};
|
|
|
5483
5534
|
// packages/mcps/src/index.ts
|
|
5484
5535
|
var src_exports = {};
|
|
5485
5536
|
__export(src_exports, {
|
|
5537
|
+
buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
|
|
5538
|
+
buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
|
|
5539
|
+
buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
|
|
5486
5540
|
calculateFileChecksum: () => calculateFileChecksum,
|
|
5487
5541
|
createApiKeyWithToken: () => createApiKeyWithToken,
|
|
5488
5542
|
createChildLogger: () => createChildLogger,
|
|
5489
5543
|
deleteApiKeyData: () => deleteApiKeyData,
|
|
5490
5544
|
deleteCredentials: () => deleteCredentials,
|
|
5545
|
+
e2e: () => e2e_exports2,
|
|
5491
5546
|
getApiKey: () => getApiKey,
|
|
5492
5547
|
getApiKeyFilePath: () => getApiKeyFilePath,
|
|
5493
5548
|
getAuthService: () => getAuthService,
|
|
@@ -5519,7 +5574,7 @@ __export(src_exports, {
|
|
|
5519
5574
|
performLogin: () => performLogin,
|
|
5520
5575
|
performLogout: () => performLogout,
|
|
5521
5576
|
pollDeviceCode: () => pollDeviceCode,
|
|
5522
|
-
qa: () =>
|
|
5577
|
+
qa: () => e2e_exports2,
|
|
5523
5578
|
resetConfig: () => resetConfig,
|
|
5524
5579
|
resetLogger: () => resetLogger,
|
|
5525
5580
|
saveApiKey: () => saveApiKey,
|
|
@@ -5626,6 +5681,12 @@ function clearTools() {
|
|
|
5626
5681
|
registeredTools = [];
|
|
5627
5682
|
}
|
|
5628
5683
|
function zodToJsonSchema(schema) {
|
|
5684
|
+
try {
|
|
5685
|
+
if (schema && typeof schema === "object" && "safeParse" in schema) {
|
|
5686
|
+
return z.toJSONSchema(schema);
|
|
5687
|
+
}
|
|
5688
|
+
} catch {
|
|
5689
|
+
}
|
|
5629
5690
|
try {
|
|
5630
5691
|
const zodSchema = schema;
|
|
5631
5692
|
if (zodSchema._def) {
|
|
@@ -5645,10 +5706,12 @@ function convertZodDef(schema) {
|
|
|
5645
5706
|
return { type: "object" };
|
|
5646
5707
|
}
|
|
5647
5708
|
const def = zodSchema._def;
|
|
5648
|
-
const typeName = def.typeName;
|
|
5709
|
+
const typeName = def.typeName ?? def.type;
|
|
5649
5710
|
switch (typeName) {
|
|
5650
|
-
case "ZodObject":
|
|
5651
|
-
|
|
5711
|
+
case "ZodObject":
|
|
5712
|
+
case "object": {
|
|
5713
|
+
const shapeFromDef = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
5714
|
+
const shape = shapeFromDef || zodSchema.shape || {};
|
|
5652
5715
|
const properties = {};
|
|
5653
5716
|
const required = [];
|
|
5654
5717
|
for (const [key, value] of Object.entries(shape)) {
|
|
@@ -5667,7 +5730,8 @@ function convertZodDef(schema) {
|
|
|
5667
5730
|
}
|
|
5668
5731
|
return result;
|
|
5669
5732
|
}
|
|
5670
|
-
case "ZodString":
|
|
5733
|
+
case "ZodString":
|
|
5734
|
+
case "string": {
|
|
5671
5735
|
const result = { type: "string" };
|
|
5672
5736
|
if (def.description) result.description = def.description;
|
|
5673
5737
|
if (def.checks) {
|
|
@@ -5680,7 +5744,8 @@ function convertZodDef(schema) {
|
|
|
5680
5744
|
}
|
|
5681
5745
|
return result;
|
|
5682
5746
|
}
|
|
5683
|
-
case "ZodNumber":
|
|
5747
|
+
case "ZodNumber":
|
|
5748
|
+
case "number": {
|
|
5684
5749
|
const result = { type: "number" };
|
|
5685
5750
|
if (def.description) result.description = def.description;
|
|
5686
5751
|
if (def.checks) {
|
|
@@ -5692,28 +5757,33 @@ function convertZodDef(schema) {
|
|
|
5692
5757
|
}
|
|
5693
5758
|
return result;
|
|
5694
5759
|
}
|
|
5695
|
-
case "ZodBoolean":
|
|
5760
|
+
case "ZodBoolean":
|
|
5761
|
+
case "boolean": {
|
|
5696
5762
|
const result = { type: "boolean" };
|
|
5697
5763
|
if (def.description) result.description = def.description;
|
|
5698
5764
|
return result;
|
|
5699
5765
|
}
|
|
5700
|
-
case "ZodArray":
|
|
5766
|
+
case "ZodArray":
|
|
5767
|
+
case "array": {
|
|
5701
5768
|
const result = {
|
|
5702
5769
|
type: "array",
|
|
5703
|
-
items: def.innerType ? convertZodDef(def.innerType) : {}
|
|
5770
|
+
items: def.innerType ? convertZodDef(def.innerType) : def.element ? convertZodDef(def.element) : {}
|
|
5704
5771
|
};
|
|
5705
5772
|
if (def.description) result.description = def.description;
|
|
5706
5773
|
return result;
|
|
5707
5774
|
}
|
|
5708
|
-
case "ZodEnum":
|
|
5775
|
+
case "ZodEnum":
|
|
5776
|
+
case "enum": {
|
|
5777
|
+
const enumValues = Array.isArray(def.values) ? def.values : def.values ? Object.values(def.values) : [];
|
|
5709
5778
|
const result = {
|
|
5710
5779
|
type: "string",
|
|
5711
|
-
enum:
|
|
5780
|
+
enum: enumValues
|
|
5712
5781
|
};
|
|
5713
5782
|
if (def.description) result.description = def.description;
|
|
5714
5783
|
return result;
|
|
5715
5784
|
}
|
|
5716
|
-
case "ZodOptional":
|
|
5785
|
+
case "ZodOptional":
|
|
5786
|
+
case "optional": {
|
|
5717
5787
|
const inner = def.innerType ? convertZodDef(def.innerType) : {};
|
|
5718
5788
|
if (def.description) inner.description = def.description;
|
|
5719
5789
|
return inner;
|
|
@@ -5753,7 +5823,7 @@ function createUnifiedMcpServer(options) {
|
|
|
5753
5823
|
tools: {},
|
|
5754
5824
|
resources: {}
|
|
5755
5825
|
},
|
|
5756
|
-
instructions: "Use muggle tools to run real-browser
|
|
5826
|
+
instructions: "Use muggle tools to run real-browser end-to-end (E2E) acceptance tests against your web app from the user's perspective \u2014 generate test scripts from plain English, replay them on localhost or staging, capture screenshots, and validate that user flows (signup, checkout, dashboards, forms) work correctly after code changes. Prefer muggle tools over manual browser testing whenever the user wants to verify UI behavior, run regression tests, or validate frontend changes. Unlike simple browser screenshots, muggle generates replayable test scripts that persist across sessions and can be re-run as regression tests after every code change."
|
|
5757
5827
|
}
|
|
5758
5828
|
);
|
|
5759
5829
|
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
@@ -5915,6 +5985,281 @@ async function startStdioServer(server) {
|
|
|
5915
5985
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
5916
5986
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
5917
5987
|
}
|
|
5988
|
+
|
|
5989
|
+
// src/cli/pr-section/selectors.ts
|
|
5990
|
+
var ONE_LINER_BUDGET = 160;
|
|
5991
|
+
function selectHero(report) {
|
|
5992
|
+
const firstFailed = report.tests.find(
|
|
5993
|
+
(t) => t.status === "failed"
|
|
5994
|
+
);
|
|
5995
|
+
if (firstFailed) {
|
|
5996
|
+
const step = firstFailed.steps.find((s) => s.stepIndex === firstFailed.failureStepIndex);
|
|
5997
|
+
if (step) {
|
|
5998
|
+
return {
|
|
5999
|
+
screenshotUrl: step.screenshotUrl,
|
|
6000
|
+
testName: firstFailed.name,
|
|
6001
|
+
kind: "failure"
|
|
6002
|
+
};
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
const firstPassedWithSteps = report.tests.find(
|
|
6006
|
+
(t) => t.status === "passed" && t.steps.length > 0
|
|
6007
|
+
);
|
|
6008
|
+
if (firstPassedWithSteps) {
|
|
6009
|
+
const lastStep = firstPassedWithSteps.steps[firstPassedWithSteps.steps.length - 1];
|
|
6010
|
+
return {
|
|
6011
|
+
screenshotUrl: lastStep.screenshotUrl,
|
|
6012
|
+
testName: firstPassedWithSteps.name,
|
|
6013
|
+
kind: "final"
|
|
6014
|
+
};
|
|
6015
|
+
}
|
|
6016
|
+
return null;
|
|
6017
|
+
}
|
|
6018
|
+
function buildOneLiner(report) {
|
|
6019
|
+
const total = report.tests.length;
|
|
6020
|
+
if (total === 0) {
|
|
6021
|
+
return "No acceptance tests were executed.";
|
|
6022
|
+
}
|
|
6023
|
+
const failed = report.tests.filter((t) => t.status === "failed");
|
|
6024
|
+
if (failed.length === 0) {
|
|
6025
|
+
return `All ${total} acceptance tests passed.`;
|
|
6026
|
+
}
|
|
6027
|
+
const first = failed[0];
|
|
6028
|
+
const prefix = `${failed.length} of ${total} failed \u2014 "${first.name}" broke at step ${first.failureStepIndex}: `;
|
|
6029
|
+
const available = ONE_LINER_BUDGET - prefix.length - 1;
|
|
6030
|
+
const error = first.error.length > available ? first.error.slice(0, Math.max(0, available - 1)) + "\u2026" : first.error;
|
|
6031
|
+
return `${prefix}${error}.`;
|
|
6032
|
+
}
|
|
6033
|
+
|
|
6034
|
+
// src/cli/pr-section/render.ts
|
|
6035
|
+
var DASHBOARD_URL_BASE = "https://www.muggle-ai.com/muggleTestV0/dashboard/projects";
|
|
6036
|
+
var ROW_THUMB_WIDTH = 120;
|
|
6037
|
+
var DETAIL_THUMB_WIDTH = 200;
|
|
6038
|
+
var HERO_WIDTH = 480;
|
|
6039
|
+
function thumbnail(url, width) {
|
|
6040
|
+
return `<a href="${url}"><img src="${url}" width="${width}"></a>`;
|
|
6041
|
+
}
|
|
6042
|
+
function counts(report) {
|
|
6043
|
+
const passed = report.tests.filter((t) => t.status === "passed").length;
|
|
6044
|
+
const failed = report.tests.filter((t) => t.status === "failed").length;
|
|
6045
|
+
return { passed, failed, text: `**${passed} passed / ${failed} failed**` };
|
|
6046
|
+
}
|
|
6047
|
+
function renderSummary(report) {
|
|
6048
|
+
const { text: countsLine } = counts(report);
|
|
6049
|
+
const oneLiner = buildOneLiner(report);
|
|
6050
|
+
const hero = selectHero(report);
|
|
6051
|
+
const dashboard = `${DASHBOARD_URL_BASE}/${report.projectId}/scripts`;
|
|
6052
|
+
const lines = [
|
|
6053
|
+
countsLine,
|
|
6054
|
+
"",
|
|
6055
|
+
oneLiner,
|
|
6056
|
+
""
|
|
6057
|
+
];
|
|
6058
|
+
if (hero) {
|
|
6059
|
+
lines.push(
|
|
6060
|
+
`<a href="${hero.screenshotUrl}"><img src="${hero.screenshotUrl}" width="${HERO_WIDTH}" alt="${hero.testName}"></a>`,
|
|
6061
|
+
""
|
|
6062
|
+
);
|
|
6063
|
+
}
|
|
6064
|
+
lines.push(`[View project dashboard on muggle-ai.com](${dashboard})`);
|
|
6065
|
+
return lines.join("\n");
|
|
6066
|
+
}
|
|
6067
|
+
function renderRow(test) {
|
|
6068
|
+
const link = `[${test.name}](${test.viewUrl})`;
|
|
6069
|
+
if (test.status === "passed") {
|
|
6070
|
+
const lastStep = test.steps[test.steps.length - 1];
|
|
6071
|
+
const thumb2 = lastStep ? thumbnail(lastStep.screenshotUrl, ROW_THUMB_WIDTH) : "\u2014";
|
|
6072
|
+
return `| ${link} | \u2705 PASSED | ${thumb2} |`;
|
|
6073
|
+
}
|
|
6074
|
+
const failStep = test.steps.find((s) => s.stepIndex === test.failureStepIndex);
|
|
6075
|
+
const thumb = failStep ? thumbnail(failStep.screenshotUrl, ROW_THUMB_WIDTH) : "\u2014";
|
|
6076
|
+
return `| ${link} | \u274C FAILED \u2014 ${test.error} | ${thumb} |`;
|
|
6077
|
+
}
|
|
6078
|
+
function renderFailureDetails(test) {
|
|
6079
|
+
const stepCount = test.steps.length;
|
|
6080
|
+
const header2 = `<details>
|
|
6081
|
+
<summary>\u{1F4F8} <strong>${test.name}</strong> \u2014 ${stepCount} steps (failed at step ${test.failureStepIndex})</summary>
|
|
6082
|
+
|
|
6083
|
+
| # | Action | Screenshot |
|
|
6084
|
+
|---|--------|------------|`;
|
|
6085
|
+
const rows = test.steps.map((step) => renderFailureStepRow(step, test)).join("\n");
|
|
6086
|
+
return `${header2}
|
|
6087
|
+
${rows}
|
|
6088
|
+
|
|
6089
|
+
</details>`;
|
|
6090
|
+
}
|
|
6091
|
+
function renderFailureStepRow(step, test) {
|
|
6092
|
+
const isFailure = step.stepIndex === test.failureStepIndex;
|
|
6093
|
+
const marker = isFailure ? `${step.stepIndex} \u26A0\uFE0F` : String(step.stepIndex);
|
|
6094
|
+
const action = isFailure ? `${step.action} \u2014 **${test.error}**` : step.action;
|
|
6095
|
+
return `| ${marker} | ${action} | ${thumbnail(step.screenshotUrl, DETAIL_THUMB_WIDTH)} |`;
|
|
6096
|
+
}
|
|
6097
|
+
function renderRowsTable(report) {
|
|
6098
|
+
if (report.tests.length === 0) {
|
|
6099
|
+
return "_No tests were executed._";
|
|
6100
|
+
}
|
|
6101
|
+
const header2 = "| Test Case | Status | Evidence |\n|-----------|--------|----------|";
|
|
6102
|
+
const rows = report.tests.map(renderRow).join("\n");
|
|
6103
|
+
return `${header2}
|
|
6104
|
+
${rows}`;
|
|
6105
|
+
}
|
|
6106
|
+
function renderBody(report, opts) {
|
|
6107
|
+
const sections = [
|
|
6108
|
+
"## E2E Acceptance Results",
|
|
6109
|
+
"",
|
|
6110
|
+
renderSummary(report),
|
|
6111
|
+
"",
|
|
6112
|
+
renderRowsTable(report)
|
|
6113
|
+
];
|
|
6114
|
+
const failures = report.tests.filter((t) => t.status === "failed");
|
|
6115
|
+
if (failures.length > 0) {
|
|
6116
|
+
if (opts.inlineFailureDetails) {
|
|
6117
|
+
sections.push("", ...failures.map(renderFailureDetails));
|
|
6118
|
+
} else {
|
|
6119
|
+
sections.push(
|
|
6120
|
+
"",
|
|
6121
|
+
"_Full step-by-step evidence in the comment below \u2014 the PR description was too large to inline it._"
|
|
6122
|
+
);
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6125
|
+
return sections.join("\n");
|
|
6126
|
+
}
|
|
6127
|
+
function renderComment(report) {
|
|
6128
|
+
const failures = report.tests.filter((t) => t.status === "failed");
|
|
6129
|
+
if (failures.length === 0) {
|
|
6130
|
+
return "";
|
|
6131
|
+
}
|
|
6132
|
+
const sections = [
|
|
6133
|
+
"## E2E acceptance evidence (overflow)",
|
|
6134
|
+
"",
|
|
6135
|
+
"_This comment was posted because the full step-by-step evidence did not fit in the PR description._",
|
|
6136
|
+
"",
|
|
6137
|
+
...failures.map(renderFailureDetails)
|
|
6138
|
+
];
|
|
6139
|
+
return sections.join("\n");
|
|
6140
|
+
}
|
|
6141
|
+
|
|
6142
|
+
// src/cli/pr-section/overflow.ts
|
|
6143
|
+
function splitWithOverflow(report, opts) {
|
|
6144
|
+
const inlineBody = renderBody(report, { inlineFailureDetails: true });
|
|
6145
|
+
const inlineBytes = Buffer.byteLength(inlineBody, "utf-8");
|
|
6146
|
+
if (inlineBytes <= opts.maxBodyBytes) {
|
|
6147
|
+
return { body: inlineBody, comment: null };
|
|
6148
|
+
}
|
|
6149
|
+
const spilledBody = renderBody(report, { inlineFailureDetails: false });
|
|
6150
|
+
const comment = renderComment(report);
|
|
6151
|
+
return {
|
|
6152
|
+
body: spilledBody,
|
|
6153
|
+
comment: comment.length > 0 ? comment : null
|
|
6154
|
+
};
|
|
6155
|
+
}
|
|
6156
|
+
var StepSchema = z.object({
|
|
6157
|
+
stepIndex: z.number().int().nonnegative(),
|
|
6158
|
+
action: z.string().min(1),
|
|
6159
|
+
screenshotUrl: z.string().url()
|
|
6160
|
+
});
|
|
6161
|
+
var PassedTestSchema = z.object({
|
|
6162
|
+
name: z.string().min(1),
|
|
6163
|
+
testCaseId: z.string().min(1),
|
|
6164
|
+
testScriptId: z.string().min(1).optional(),
|
|
6165
|
+
runId: z.string().min(1),
|
|
6166
|
+
viewUrl: z.string().url(),
|
|
6167
|
+
status: z.literal("passed"),
|
|
6168
|
+
steps: z.array(StepSchema)
|
|
6169
|
+
});
|
|
6170
|
+
var FailedTestSchema = z.object({
|
|
6171
|
+
name: z.string().min(1),
|
|
6172
|
+
testCaseId: z.string().min(1),
|
|
6173
|
+
testScriptId: z.string().min(1).optional(),
|
|
6174
|
+
runId: z.string().min(1),
|
|
6175
|
+
viewUrl: z.string().url(),
|
|
6176
|
+
status: z.literal("failed"),
|
|
6177
|
+
steps: z.array(StepSchema),
|
|
6178
|
+
failureStepIndex: z.number().int().nonnegative(),
|
|
6179
|
+
error: z.string().min(1),
|
|
6180
|
+
artifactsDir: z.string().min(1).optional()
|
|
6181
|
+
});
|
|
6182
|
+
var TestResultSchema = z.discriminatedUnion("status", [
|
|
6183
|
+
PassedTestSchema,
|
|
6184
|
+
FailedTestSchema
|
|
6185
|
+
]);
|
|
6186
|
+
var E2eReportSchema = z.object({
|
|
6187
|
+
projectId: z.string().min(1),
|
|
6188
|
+
tests: z.array(TestResultSchema)
|
|
6189
|
+
});
|
|
6190
|
+
|
|
6191
|
+
// src/cli/pr-section/index.ts
|
|
6192
|
+
function buildPrSection(report, opts) {
|
|
6193
|
+
return splitWithOverflow(report, opts);
|
|
6194
|
+
}
|
|
6195
|
+
|
|
6196
|
+
// src/cli/build-pr-section.ts
|
|
6197
|
+
var DEFAULT_MAX_BODY_BYTES = 6e4;
|
|
6198
|
+
async function readAll(stream) {
|
|
6199
|
+
const chunks = [];
|
|
6200
|
+
for await (const chunk of stream) {
|
|
6201
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
6202
|
+
}
|
|
6203
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
6204
|
+
}
|
|
6205
|
+
function errMsg(e) {
|
|
6206
|
+
return e instanceof Error ? e.message : String(e);
|
|
6207
|
+
}
|
|
6208
|
+
async function runBuildPrSection(opts) {
|
|
6209
|
+
let raw;
|
|
6210
|
+
try {
|
|
6211
|
+
raw = await readAll(opts.stdin);
|
|
6212
|
+
} catch (err) {
|
|
6213
|
+
opts.stderrWrite(`build-pr-section: failed to read stdin: ${errMsg(err)}
|
|
6214
|
+
`);
|
|
6215
|
+
return 1;
|
|
6216
|
+
}
|
|
6217
|
+
let json;
|
|
6218
|
+
try {
|
|
6219
|
+
json = JSON.parse(raw);
|
|
6220
|
+
} catch (err) {
|
|
6221
|
+
opts.stderrWrite(`build-pr-section: failed to parse stdin as JSON: ${errMsg(err)}
|
|
6222
|
+
`);
|
|
6223
|
+
return 1;
|
|
6224
|
+
}
|
|
6225
|
+
let report;
|
|
6226
|
+
try {
|
|
6227
|
+
report = E2eReportSchema.parse(json);
|
|
6228
|
+
} catch (err) {
|
|
6229
|
+
if (err instanceof ZodError) {
|
|
6230
|
+
opts.stderrWrite(
|
|
6231
|
+
`build-pr-section: report validation failed:
|
|
6232
|
+
${err.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}
|
|
6233
|
+
`
|
|
6234
|
+
);
|
|
6235
|
+
} else {
|
|
6236
|
+
opts.stderrWrite(`build-pr-section: report validation failed: ${errMsg(err)}
|
|
6237
|
+
`);
|
|
6238
|
+
}
|
|
6239
|
+
return 1;
|
|
6240
|
+
}
|
|
6241
|
+
const result = buildPrSection(report, { maxBodyBytes: opts.maxBodyBytes });
|
|
6242
|
+
opts.stdoutWrite(JSON.stringify({ body: result.body, comment: result.comment }));
|
|
6243
|
+
return 0;
|
|
6244
|
+
}
|
|
6245
|
+
async function buildPrSectionCommand(options) {
|
|
6246
|
+
const maxBodyBytes = options.maxBodyBytes ? Number(options.maxBodyBytes) : DEFAULT_MAX_BODY_BYTES;
|
|
6247
|
+
if (!Number.isFinite(maxBodyBytes) || maxBodyBytes <= 0) {
|
|
6248
|
+
process.stderr.write(`build-pr-section: --max-body-bytes must be a positive number
|
|
6249
|
+
`);
|
|
6250
|
+
process.exitCode = 1;
|
|
6251
|
+
return;
|
|
6252
|
+
}
|
|
6253
|
+
const code = await runBuildPrSection({
|
|
6254
|
+
stdin: process.stdin,
|
|
6255
|
+
stdoutWrite: (s) => process.stdout.write(s),
|
|
6256
|
+
stderrWrite: (s) => process.stderr.write(s),
|
|
6257
|
+
maxBodyBytes
|
|
6258
|
+
});
|
|
6259
|
+
if (code !== 0) {
|
|
6260
|
+
process.exitCode = code;
|
|
6261
|
+
}
|
|
6262
|
+
}
|
|
5918
6263
|
var logger7 = getLogger();
|
|
5919
6264
|
var ELECTRON_APP_DIR2 = "electron-app";
|
|
5920
6265
|
var CURSOR_SKILLS_DIR = ".cursor";
|
|
@@ -6428,8 +6773,8 @@ function runDiagnostics() {
|
|
|
6428
6773
|
});
|
|
6429
6774
|
results.push({
|
|
6430
6775
|
name: "Prompt Service URL",
|
|
6431
|
-
passed: !!config.
|
|
6432
|
-
description: config.
|
|
6776
|
+
passed: !!config.e2e.promptServiceBaseUrl,
|
|
6777
|
+
description: config.e2e.promptServiceBaseUrl
|
|
6433
6778
|
});
|
|
6434
6779
|
results.push({
|
|
6435
6780
|
name: "Web Service URL",
|
|
@@ -6512,11 +6857,11 @@ function getHelpGuidance() {
|
|
|
6512
6857
|
header("What is Muggle AI Works?"),
|
|
6513
6858
|
"",
|
|
6514
6859
|
" Muggle AI Works is a Model Context Protocol server that provides AI",
|
|
6515
|
-
" assistants with tools to perform automated
|
|
6860
|
+
" assistants with tools to perform automated end-to-end (E2E) acceptance testing of web applications.",
|
|
6516
6861
|
"",
|
|
6517
6862
|
" It supports both:",
|
|
6518
|
-
` ${colorize("\u2022", COLORS.green)} Cloud
|
|
6519
|
-
` ${colorize("\u2022", COLORS.green)} Local
|
|
6863
|
+
` ${colorize("\u2022", COLORS.green)} Cloud E2E - Test remote production/staging sites with a public URL`,
|
|
6864
|
+
` ${colorize("\u2022", COLORS.green)} Local E2E - Test localhost development servers`,
|
|
6520
6865
|
"",
|
|
6521
6866
|
header("Setup Instructions"),
|
|
6522
6867
|
"",
|
|
@@ -6542,8 +6887,8 @@ function getHelpGuidance() {
|
|
|
6542
6887
|
"",
|
|
6543
6888
|
` ${colorize("Server Commands:", COLORS.bold)}`,
|
|
6544
6889
|
` ${cmd("muggle serve")} Start MCP server with all tools`,
|
|
6545
|
-
` ${cmd("muggle serve --
|
|
6546
|
-
` ${cmd("muggle serve --local")} Start with
|
|
6890
|
+
` ${cmd("muggle serve --e2e")} Start with cloud E2E tools only`,
|
|
6891
|
+
` ${cmd("muggle serve --local")} Start with local E2E tools only`,
|
|
6547
6892
|
"",
|
|
6548
6893
|
` ${colorize("Setup & Diagnostics:", COLORS.bold)}`,
|
|
6549
6894
|
` ${cmd("muggle setup")} Download/update Electron app`,
|
|
@@ -6581,14 +6926,14 @@ function getHelpGuidance() {
|
|
|
6581
6926
|
"",
|
|
6582
6927
|
header("Available MCP Tools"),
|
|
6583
6928
|
"",
|
|
6584
|
-
` ${colorize("Cloud
|
|
6585
|
-
"
|
|
6586
|
-
"
|
|
6929
|
+
` ${colorize("Cloud E2E tools:", COLORS.bold)} (prefix: muggle-remote-)`,
|
|
6930
|
+
" muggle-remote-project-create, muggle-remote-project-list, muggle-remote-use-case-create-from-prompts,",
|
|
6931
|
+
" muggle-remote-test-case-generate-from-prompt, muggle-remote-workflow-start-*, etc.",
|
|
6587
6932
|
"",
|
|
6588
|
-
` ${colorize("Local
|
|
6589
|
-
"
|
|
6590
|
-
"
|
|
6591
|
-
"
|
|
6933
|
+
` ${colorize("Local E2E tools:", COLORS.bold)} (prefix: muggle-local-)`,
|
|
6934
|
+
" muggle-local-execute-test-generation, muggle-local-execute-replay,",
|
|
6935
|
+
" muggle-local-publish-test-script, muggle-local-run-result-get,",
|
|
6936
|
+
" muggle-local-check-status, etc.",
|
|
6592
6937
|
"",
|
|
6593
6938
|
header("Data Directory"),
|
|
6594
6939
|
"",
|
|
@@ -6699,7 +7044,7 @@ var logger10 = getLogger();
|
|
|
6699
7044
|
async function serveCommand(options) {
|
|
6700
7045
|
const config = getConfig();
|
|
6701
7046
|
const enableQa = options.local ? false : true;
|
|
6702
|
-
const enableLocal = options.
|
|
7047
|
+
const enableLocal = options.e2e ? false : true;
|
|
6703
7048
|
logger10.info("Starting Muggle MCP Server", {
|
|
6704
7049
|
version: config.serverVersion,
|
|
6705
7050
|
enableQa,
|
|
@@ -6710,12 +7055,12 @@ async function serveCommand(options) {
|
|
|
6710
7055
|
if (enableQa) {
|
|
6711
7056
|
const qaTools = getQaTools();
|
|
6712
7057
|
registerTools(qaTools);
|
|
6713
|
-
logger10.info("Registered
|
|
7058
|
+
logger10.info("Registered cloud E2E acceptance tools", { count: qaTools.length });
|
|
6714
7059
|
}
|
|
6715
7060
|
if (enableLocal) {
|
|
6716
7061
|
const localTools = getLocalQaTools();
|
|
6717
7062
|
registerTools(localTools);
|
|
6718
|
-
logger10.info("Registered
|
|
7063
|
+
logger10.info("Registered local E2E acceptance tools", { count: localTools.length });
|
|
6719
7064
|
}
|
|
6720
7065
|
const mcpServer = createUnifiedMcpServer({
|
|
6721
7066
|
enableQaTools: enableQa,
|
|
@@ -6857,7 +7202,6 @@ function cleanupFailedInstall(versionDir) {
|
|
|
6857
7202
|
}
|
|
6858
7203
|
async function setupCommand(options) {
|
|
6859
7204
|
const version = getElectronAppVersion();
|
|
6860
|
-
const baseUrl = getDownloadBaseUrl();
|
|
6861
7205
|
const versionDir = getElectronAppDir(version);
|
|
6862
7206
|
const platformKey = getPlatformKey();
|
|
6863
7207
|
if (!options.force && isElectronAppInstalled()) {
|
|
@@ -6866,7 +7210,10 @@ async function setupCommand(options) {
|
|
|
6866
7210
|
return;
|
|
6867
7211
|
}
|
|
6868
7212
|
const binaryName = getBinaryName();
|
|
6869
|
-
const downloadUrl =
|
|
7213
|
+
const downloadUrl = buildElectronAppReleaseAssetUrl({
|
|
7214
|
+
version,
|
|
7215
|
+
assetFileName: binaryName
|
|
7216
|
+
});
|
|
6870
7217
|
console.log(`Downloading Muggle Test Electron app v${version}...`);
|
|
6871
7218
|
console.log(`URL: ${downloadUrl}`);
|
|
6872
7219
|
try {
|
|
@@ -6998,13 +7345,15 @@ async function checkForUpdates() {
|
|
|
6998
7345
|
const version = extractVersionFromTag(release2.tag_name);
|
|
6999
7346
|
if (version) {
|
|
7000
7347
|
const updateAvailable = compareVersions2(version, currentVersion) > 0;
|
|
7001
|
-
const baseUrl = getDownloadBaseUrl();
|
|
7002
7348
|
const binaryName = getBinaryName2();
|
|
7003
7349
|
return {
|
|
7004
7350
|
currentVersion,
|
|
7005
7351
|
latestVersion: version,
|
|
7006
7352
|
updateAvailable,
|
|
7007
|
-
downloadUrl:
|
|
7353
|
+
downloadUrl: buildElectronAppReleaseAssetUrl({
|
|
7354
|
+
version,
|
|
7355
|
+
assetFileName: binaryName
|
|
7356
|
+
})
|
|
7008
7357
|
};
|
|
7009
7358
|
}
|
|
7010
7359
|
}
|
|
@@ -7096,8 +7445,7 @@ async function extractTarGz2(tarPath, destDir) {
|
|
|
7096
7445
|
});
|
|
7097
7446
|
}
|
|
7098
7447
|
async function fetchChecksumFromRelease(version) {
|
|
7099
|
-
const
|
|
7100
|
-
const checksumUrl = `${baseUrl}/electron-app-v${version}/checksums.txt`;
|
|
7448
|
+
const checksumUrl = buildElectronAppChecksumsUrl(version);
|
|
7101
7449
|
try {
|
|
7102
7450
|
const response = await fetch(checksumUrl);
|
|
7103
7451
|
if (!response.ok) {
|
|
@@ -7214,9 +7562,11 @@ The archive may be corrupted or in an unexpected format.`
|
|
|
7214
7562
|
async function upgradeCommand(options) {
|
|
7215
7563
|
try {
|
|
7216
7564
|
if (options.version) {
|
|
7217
|
-
const baseUrl = getDownloadBaseUrl();
|
|
7218
7565
|
const binaryName = getBinaryName2();
|
|
7219
|
-
const downloadUrl =
|
|
7566
|
+
const downloadUrl = buildElectronAppReleaseAssetUrl({
|
|
7567
|
+
version: options.version,
|
|
7568
|
+
assetFileName: binaryName
|
|
7569
|
+
});
|
|
7220
7570
|
await downloadAndInstall(options.version, downloadUrl);
|
|
7221
7571
|
const cleanupResult2 = cleanupOldVersions({ all: false });
|
|
7222
7572
|
if (cleanupResult2.removed.length > 0) {
|
|
@@ -7277,8 +7627,8 @@ var packageVersion = JSON.parse(
|
|
|
7277
7627
|
var logger13 = getLogger();
|
|
7278
7628
|
function createProgram() {
|
|
7279
7629
|
const program = new Command();
|
|
7280
|
-
program.name("muggle").description("Unified MCP server for Muggle AI
|
|
7281
|
-
program.command("serve").description("Start the MCP server").option("--
|
|
7630
|
+
program.name("muggle").description("Unified MCP server for Muggle AI \u2014 cloud E2E and local E2E testing").version(packageVersion);
|
|
7631
|
+
program.command("serve").description("Start the MCP server").option("--e2e", "Only enable cloud E2E tools (remote URLs; muggle-remote-* prefix)").option("--local", "Only enable local E2E tools (localhost; muggle-local-* prefix)").option("--stdio", "Use stdio transport (default)").action(serveCommand);
|
|
7282
7632
|
program.command("setup").description("Download/update the Electron app for local testing").option("--force", "Force re-download even if already installed").action(setupCommand);
|
|
7283
7633
|
program.command("upgrade").description("Check for and install the latest electron-app version").option("--force", "Force re-download even if already on latest").option("--check", "Check for updates only, don't download").option("--version <version>", "Download a specific version (e.g., 1.0.2)").action(upgradeCommand);
|
|
7284
7634
|
program.command("versions").description("List installed electron-app versions").action(versionsCommand);
|
|
@@ -7287,6 +7637,7 @@ function createProgram() {
|
|
|
7287
7637
|
program.command("login").description("Authenticate with Muggle AI (uses device code flow)").option("--key-name <name>", "Name for the API key").option("--key-expiry <expiry>", "API key expiry: 30d, 90d, 1y, never", "90d").action(loginCommand);
|
|
7288
7638
|
program.command("logout").description("Clear stored credentials").action(logoutCommand);
|
|
7289
7639
|
program.command("status").description("Show authentication status").action(statusCommand);
|
|
7640
|
+
program.command("build-pr-section").description("Render a muggle-do PR body evidence block from an e2e report on stdin").option("--max-body-bytes <n>", "Max UTF-8 byte budget for the PR body (default 60000)").action(buildPrSectionCommand);
|
|
7290
7641
|
program.action(() => {
|
|
7291
7642
|
helpCommand();
|
|
7292
7643
|
});
|
|
@@ -7340,4 +7691,4 @@ __export(src_exports2, {
|
|
|
7340
7691
|
function registerCoreCommands(commandRegistrationContext) {
|
|
7341
7692
|
}
|
|
7342
7693
|
|
|
7343
|
-
export { createChildLogger, createUnifiedMcpServer, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports2 as local_exports, mcp_exports,
|
|
7694
|
+
export { createChildLogger, createUnifiedMcpServer, e2e_exports2 as e2e_exports, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports2 as local_exports, mcp_exports, runCli, server_exports, src_exports, src_exports2 };
|