@muggleai/works 4.5.0 → 4.6.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.
@@ -1,23 +1,17 @@
1
- import * as fs3 from 'fs';
2
- import { readFileSync, existsSync, mkdirSync, writeFileSync, rmSync, readdirSync, createWriteStream, statSync } from 'fs';
3
- import * as os3 from 'os';
4
- import { platform, arch, homedir } from 'os';
1
+ import * as crypto from 'crypto';
2
+ import { randomUUID } from 'crypto';
3
+ import * as fs5 from 'fs';
4
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
5
5
  import * as path2 from 'path';
6
- import { join, dirname, resolve } from 'path';
7
- import { fileURLToPath } from 'url';
6
+ import { join, dirname } from 'path';
7
+ import * as os3 from 'os';
8
+ import { platform } from 'os';
8
9
  import winston from 'winston';
10
+ import { fileURLToPath } from 'url';
11
+ import { spawn, exec } from 'child_process';
9
12
  import axios, { AxiosError } from 'axios';
10
- import { spawn, exec, execFile } from 'child_process';
11
- import * as crypto from 'crypto';
12
- import { randomUUID } from 'crypto';
13
- import * as fs5 from 'fs/promises';
14
- import { z, ZodError } from 'zod';
15
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
16
- import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
17
- import { v4 } from 'uuid';
18
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
19
- import { Command } from 'commander';
20
- import { pipeline } from 'stream/promises';
13
+ import * as fs7 from 'fs/promises';
14
+ import { z } from 'zod';
21
15
 
22
16
  var __defProp = Object.defineProperty;
23
17
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -30,6 +24,60 @@ var __export = (target, all) => {
30
24
  for (var name in all)
31
25
  __defProp(target, name, { get: all[name], enumerable: true });
32
26
  };
27
+
28
+ // packages/mcps/src/index.ts
29
+ var src_exports = {};
30
+ __export(src_exports, {
31
+ buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
32
+ buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
33
+ buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
34
+ calculateFileChecksum: () => calculateFileChecksum,
35
+ createApiKeyWithToken: () => createApiKeyWithToken,
36
+ createChildLogger: () => createChildLogger,
37
+ deleteApiKeyData: () => deleteApiKeyData,
38
+ deleteCredentials: () => deleteCredentials,
39
+ e2e: () => e2e_exports2,
40
+ getApiKey: () => getApiKey,
41
+ getApiKeyFilePath: () => getApiKeyFilePath,
42
+ getAuthService: () => getAuthService,
43
+ getBundledElectronAppVersion: () => getBundledElectronAppVersion,
44
+ getCallerCredentials: () => getCallerCredentials,
45
+ getCallerCredentialsAsync: () => getCallerCredentialsAsync,
46
+ getChecksumForPlatform: () => getChecksumForPlatform,
47
+ getConfig: () => getConfig,
48
+ getCredentialsFilePath: () => getCredentialsFilePath,
49
+ getDataDir: () => getDataDir2,
50
+ getDownloadBaseUrl: () => getDownloadBaseUrl,
51
+ getElectronAppChecksums: () => getElectronAppChecksums,
52
+ getElectronAppDir: () => getElectronAppDir,
53
+ getElectronAppVersion: () => getElectronAppVersion,
54
+ getElectronAppVersionSource: () => getElectronAppVersionSource,
55
+ getLocalQaTools: () => getLocalQaTools,
56
+ getLogger: () => getLogger,
57
+ getPlatformKey: () => getPlatformKey,
58
+ getQaTools: () => getQaTools,
59
+ getValidApiKeyData: () => getValidApiKeyData,
60
+ getValidCredentials: () => getValidCredentials,
61
+ hasApiKey: () => hasApiKey,
62
+ isElectronAppInstalled: () => isElectronAppInstalled,
63
+ loadApiKeyData: () => loadApiKeyData,
64
+ loadCredentials: () => loadCredentials,
65
+ localQa: () => local_exports2,
66
+ mcp: () => mcp_exports,
67
+ openBrowserUrl: () => openBrowserUrl,
68
+ performLogin: () => performLogin,
69
+ performLogout: () => performLogout,
70
+ pollDeviceCode: () => pollDeviceCode,
71
+ qa: () => e2e_exports2,
72
+ resetConfig: () => resetConfig,
73
+ resetLogger: () => resetLogger,
74
+ saveApiKey: () => saveApiKey,
75
+ saveApiKeyData: () => saveApiKeyData,
76
+ saveCredentials: () => saveCredentials,
77
+ startDeviceCodeFlow: () => startDeviceCodeFlow,
78
+ toolRequiresAuth: () => toolRequiresAuth,
79
+ verifyFileChecksum: () => verifyFileChecksum
80
+ });
33
81
  var DATA_DIR_NAME = ".muggle-ai";
34
82
  function getDataDir() {
35
83
  return path2.join(os3.homedir(), DATA_DIR_NAME);
@@ -116,7 +164,7 @@ function getMuggleConfig() {
116
164
  const packageJsonPath = path2.join(packageRoot, "package.json");
117
165
  let packageJson;
118
166
  try {
119
- const content = fs3.readFileSync(packageJsonPath, "utf-8");
167
+ const content = fs5.readFileSync(packageJsonPath, "utf-8");
120
168
  packageJson = JSON.parse(content);
121
169
  } catch (error) {
122
170
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -191,7 +239,7 @@ function getDownloadedElectronAppPath() {
191
239
  default:
192
240
  return null;
193
241
  }
194
- if (fs3.existsSync(binaryPath)) {
242
+ if (fs5.existsSync(binaryPath)) {
195
243
  return binaryPath;
196
244
  }
197
245
  return null;
@@ -213,14 +261,14 @@ function getSystemElectronAppPath() {
213
261
  default:
214
262
  return null;
215
263
  }
216
- if (fs3.existsSync(binaryPath)) {
264
+ if (fs5.existsSync(binaryPath)) {
217
265
  return binaryPath;
218
266
  }
219
267
  return null;
220
268
  }
221
269
  function resolveElectronAppPathOrNull() {
222
270
  const customPath = process.env.ELECTRON_APP_PATH;
223
- if (customPath && fs3.existsSync(customPath)) {
271
+ if (customPath && fs5.existsSync(customPath)) {
224
272
  return customPath;
225
273
  }
226
274
  const downloadedPath = getDownloadedElectronAppPath();
@@ -235,12 +283,12 @@ function resolveElectronAppPathOrNull() {
235
283
  }
236
284
  function resolveWebServicePath() {
237
285
  const customPath = process.env.WEB_SERVICE_PATH;
238
- if (customPath && fs3.existsSync(customPath)) {
286
+ if (customPath && fs5.existsSync(customPath)) {
239
287
  return customPath;
240
288
  }
241
289
  const packageRoot = getPackageRoot();
242
290
  const siblingPath = path2.resolve(packageRoot, "..", "web-service", "dist", "src", "index.js");
243
- if (fs3.existsSync(siblingPath)) {
291
+ if (fs5.existsSync(siblingPath)) {
244
292
  return siblingPath;
245
293
  }
246
294
  return null;
@@ -369,9 +417,9 @@ function getElectronAppVersion() {
369
417
  return envVersion;
370
418
  }
371
419
  const overridePath = path2.join(getDataDir2(), VERSION_OVERRIDE_FILE);
372
- if (fs3.existsSync(overridePath)) {
420
+ if (fs5.existsSync(overridePath)) {
373
421
  try {
374
- const content = JSON.parse(fs3.readFileSync(overridePath, "utf-8"));
422
+ const content = JSON.parse(fs5.readFileSync(overridePath, "utf-8"));
375
423
  if (content.version && typeof content.version === "string") {
376
424
  return content.version;
377
425
  }
@@ -386,9 +434,9 @@ function getElectronAppVersionSource() {
386
434
  return "env";
387
435
  }
388
436
  const overridePath = path2.join(getDataDir2(), VERSION_OVERRIDE_FILE);
389
- if (fs3.existsSync(overridePath)) {
437
+ if (fs5.existsSync(overridePath)) {
390
438
  try {
391
- const content = JSON.parse(fs3.readFileSync(overridePath, "utf-8"));
439
+ const content = JSON.parse(fs5.readFileSync(overridePath, "utf-8"));
392
440
  if (content.version && typeof content.version === "string") {
393
441
  return "override";
394
442
  }
@@ -422,6 +470,8 @@ function getElectronAppDir(version) {
422
470
  const resolvedVersion = version ?? getElectronAppVersion();
423
471
  return path2.join(getDataDir2(), ELECTRON_APP_DIR, resolvedVersion);
424
472
  }
473
+
474
+ // packages/mcps/src/shared/logger.ts
425
475
  var loggerInstance = null;
426
476
  function createLogger() {
427
477
  const config = getConfig();
@@ -451,109 +501,101 @@ function getLogger() {
451
501
  return loggerInstance;
452
502
  }
453
503
  function createChildLogger(correlationId) {
454
- const logger14 = getLogger();
455
- return logger14.child({ correlationId });
504
+ const logger6 = getLogger();
505
+ return logger6.child({ correlationId });
456
506
  }
457
507
  function resetLogger() {
458
508
  loggerInstance = null;
459
509
  }
460
510
 
461
- // packages/mcps/src/mcp/e2e/index.ts
462
- var e2e_exports2 = {};
463
- __export(e2e_exports2, {
464
- ActionScriptGetInputSchema: () => ActionScriptGetInputSchema,
465
- ApiKeyCreateInputSchema: () => ApiKeyCreateInputSchema,
466
- ApiKeyGetInputSchema: () => ApiKeyGetInputSchema,
467
- ApiKeyListInputSchema: () => ApiKeyListInputSchema,
468
- ApiKeyRecordIdSchema: () => ApiKeyRecordIdSchema,
469
- ApiKeyRevokeInputSchema: () => ApiKeyRevokeInputSchema,
470
- AuthLoginInputSchema: () => AuthLoginInputSchema,
471
- AuthPollInputSchema: () => AuthPollInputSchema,
472
- BulkPreviewJobCancelInputSchema: () => BulkPreviewJobCancelInputSchema,
473
- BulkPreviewJobGetInputSchema: () => BulkPreviewJobGetInputSchema,
474
- BulkPreviewJobKindSchema: () => BulkPreviewJobKindSchema,
475
- BulkPreviewJobListInputSchema: () => BulkPreviewJobListInputSchema,
476
- BulkPreviewJobStatusSchema: () => BulkPreviewJobStatusSchema,
477
- BulkPreviewPromptSchema: () => BulkPreviewPromptSchema,
478
- BulkPreviewSubmitTestCaseInputSchema: () => BulkPreviewSubmitTestCaseInputSchema,
479
- BulkPreviewSubmitUseCaseInputSchema: () => BulkPreviewSubmitUseCaseInputSchema,
480
- EmptyInputSchema: () => EmptyInputSchema,
481
- GatewayError: () => GatewayError,
482
- IdSchema: () => IdSchema,
483
- LocalExecutionContextInputSchema: () => LocalExecutionContextInputSchema,
484
- LocalRunUploadInputSchema: () => LocalRunUploadInputSchema,
485
- McpErrorCode: () => McpErrorCode,
486
- MuggleEntityIdSchema: () => MuggleEntityIdSchema,
487
- PaginationInputSchema: () => PaginationInputSchema,
488
- PrdFileDeleteInputSchema: () => PrdFileDeleteInputSchema,
489
- PrdFileListInputSchema: () => PrdFileListInputSchema,
490
- PrdFileProcessLatestRunInputSchema: () => PrdFileProcessLatestRunInputSchema,
491
- PrdFileProcessStartInputSchema: () => PrdFileProcessStartInputSchema,
492
- PrdFileUploadInputSchema: () => PrdFileUploadInputSchema,
493
- ProjectCreateInputSchema: () => ProjectCreateInputSchema,
494
- ProjectDeleteInputSchema: () => ProjectDeleteInputSchema,
495
- ProjectGetInputSchema: () => ProjectGetInputSchema,
496
- ProjectListInputSchema: () => ProjectListInputSchema,
497
- ProjectTestResultsSummaryInputSchema: () => ProjectTestResultsSummaryInputSchema,
498
- ProjectTestRunsSummaryInputSchema: () => ProjectTestRunsSummaryInputSchema,
499
- ProjectTestScriptsSummaryInputSchema: () => ProjectTestScriptsSummaryInputSchema,
500
- ProjectUpdateInputSchema: () => ProjectUpdateInputSchema,
501
- PromptServiceClient: () => PromptServiceClient,
502
- RecommendCicdSetupInputSchema: () => RecommendCicdSetupInputSchema,
503
- RecommendScheduleInputSchema: () => RecommendScheduleInputSchema,
504
- ReportCostQueryInputSchema: () => ReportCostQueryInputSchema,
505
- ReportFinalGenerateInputSchema: () => ReportFinalGenerateInputSchema,
506
- ReportPreferencesUpsertInputSchema: () => ReportPreferencesUpsertInputSchema,
507
- ReportStatsSummaryInputSchema: () => ReportStatsSummaryInputSchema,
508
- RunBatchIdSchema: () => RunBatchIdSchema,
509
- SecretCreateInputSchema: () => SecretCreateInputSchema,
510
- SecretDeleteInputSchema: () => SecretDeleteInputSchema,
511
- SecretGetInputSchema: () => SecretGetInputSchema,
512
- SecretListInputSchema: () => SecretListInputSchema,
513
- SecretUpdateInputSchema: () => SecretUpdateInputSchema,
514
- StripePaymentMethodIdSchema: () => StripePaymentMethodIdSchema,
515
- TestCaseCreateInputSchema: () => TestCaseCreateInputSchema,
516
- TestCaseGenerateFromPromptInputSchema: () => TestCaseGenerateFromPromptInputSchema,
517
- TestCaseGetInputSchema: () => TestCaseGetInputSchema,
518
- TestCaseListByUseCaseInputSchema: () => TestCaseListByUseCaseInputSchema,
519
- TestCaseListInputSchema: () => TestCaseListInputSchema,
520
- TestScriptGetInputSchema: () => TestScriptGetInputSchema,
521
- TestScriptListInputSchema: () => TestScriptListInputSchema,
522
- TokenPackageIdSchema: () => TokenPackageIdSchema,
523
- TokenUsageFilterTypeSchema: () => TokenUsageFilterTypeSchema,
524
- UseCaseCandidatesApproveInputSchema: () => UseCaseCandidatesApproveInputSchema,
525
- UseCaseCreateFromPromptsInputSchema: () => UseCaseCreateFromPromptsInputSchema,
526
- UseCaseCreateInputSchema: () => UseCaseCreateInputSchema,
527
- UseCaseDiscoveryMemoryGetInputSchema: () => UseCaseDiscoveryMemoryGetInputSchema,
528
- UseCaseGetInputSchema: () => UseCaseGetInputSchema,
529
- UseCaseListInputSchema: () => UseCaseListInputSchema,
530
- UseCasePromptPreviewInputSchema: () => UseCasePromptPreviewInputSchema,
531
- UseCaseUpdateFromPromptInputSchema: () => UseCaseUpdateFromPromptInputSchema,
532
- WalletAutoTopUpSetPaymentMethodInputSchema: () => WalletAutoTopUpSetPaymentMethodInputSchema,
533
- WalletAutoTopUpUpdateInputSchema: () => WalletAutoTopUpUpdateInputSchema,
534
- WalletPaymentMethodCreateSetupSessionInputSchema: () => WalletPaymentMethodCreateSetupSessionInputSchema,
535
- WalletPaymentMethodListInputSchema: () => WalletPaymentMethodListInputSchema,
536
- WalletTopUpInputSchema: () => WalletTopUpInputSchema,
537
- WorkflowCancelRunInputSchema: () => WorkflowCancelRunInputSchema,
538
- WorkflowCancelRuntimeInputSchema: () => WorkflowCancelRuntimeInputSchema,
539
- WorkflowGetLatestRunInputSchema: () => WorkflowGetLatestRunInputSchema,
540
- WorkflowGetLatestScriptGenByTestCaseInputSchema: () => WorkflowGetLatestScriptGenByTestCaseInputSchema,
541
- WorkflowGetReplayBulkBatchSummaryInputSchema: () => WorkflowGetReplayBulkBatchSummaryInputSchema,
542
- WorkflowListRuntimesInputSchema: () => WorkflowListRuntimesInputSchema,
543
- WorkflowMemoryParamsSchema: () => WorkflowMemoryParamsSchema,
544
- WorkflowParamsSchema: () => WorkflowParamsSchema,
545
- WorkflowStartTestCaseDetectionInputSchema: () => WorkflowStartTestCaseDetectionInputSchema,
546
- WorkflowStartTestScriptGenerationInputSchema: () => WorkflowStartTestScriptGenerationInputSchema,
547
- WorkflowStartTestScriptReplayBulkInputSchema: () => WorkflowStartTestScriptReplayBulkInputSchema,
548
- WorkflowStartTestScriptReplayInputSchema: () => WorkflowStartTestScriptReplayInputSchema,
549
- WorkflowStartWebsiteScanInputSchema: () => WorkflowStartWebsiteScanInputSchema,
550
- allQaToolDefinitions: () => allQaToolDefinitions,
551
- executeQaTool: () => executeQaTool,
552
- getPromptServiceClient: () => getPromptServiceClient,
553
- getQaToolByName: () => getQaToolByName,
554
- getQaTools: () => getQaTools
555
- });
511
+ // packages/mcps/src/shared/checksum.ts
556
512
  var logger = getLogger();
513
+ function getPlatformKey() {
514
+ const os4 = platform();
515
+ const arch2 = process.arch;
516
+ switch (os4) {
517
+ case "darwin":
518
+ return arch2 === "arm64" ? "darwin-arm64" : "darwin-x64";
519
+ case "win32":
520
+ return "win32-x64";
521
+ case "linux":
522
+ return "linux-x64";
523
+ default:
524
+ throw new Error(`Unsupported platform: ${os4}`);
525
+ }
526
+ }
527
+ async function calculateFileChecksum(filePath) {
528
+ return new Promise((resolve3, reject) => {
529
+ const hash = crypto.createHash("sha256");
530
+ const stream = fs5.createReadStream(filePath);
531
+ stream.on("data", (data) => {
532
+ hash.update(data);
533
+ });
534
+ stream.on("end", () => {
535
+ resolve3(hash.digest("hex"));
536
+ });
537
+ stream.on("error", (error) => {
538
+ reject(error);
539
+ });
540
+ });
541
+ }
542
+ async function verifyFileChecksum(filePath, expectedChecksum) {
543
+ if (!expectedChecksum || expectedChecksum.trim() === "") {
544
+ logger.warn("Checksum verification skipped - no checksum provided", {
545
+ file: path2.basename(filePath)
546
+ });
547
+ return {
548
+ valid: true,
549
+ expected: "",
550
+ actual: "",
551
+ error: "Checksum verification skipped - no checksum configured"
552
+ };
553
+ }
554
+ try {
555
+ const actualChecksum = await calculateFileChecksum(filePath);
556
+ const normalizedExpected = expectedChecksum.toLowerCase().trim();
557
+ const normalizedActual = actualChecksum.toLowerCase();
558
+ const valid = normalizedExpected === normalizedActual;
559
+ if (!valid) {
560
+ logger.error("Checksum verification failed", {
561
+ file: path2.basename(filePath),
562
+ expected: normalizedExpected,
563
+ actual: normalizedActual
564
+ });
565
+ } else {
566
+ logger.info("Checksum verified successfully", {
567
+ file: path2.basename(filePath),
568
+ checksum: normalizedActual
569
+ });
570
+ }
571
+ return {
572
+ valid,
573
+ expected: normalizedExpected,
574
+ actual: normalizedActual,
575
+ error: valid ? void 0 : "Checksum mismatch - file may be corrupted or tampered with"
576
+ };
577
+ } catch (error) {
578
+ const errorMessage = error instanceof Error ? error.message : String(error);
579
+ logger.error("Checksum calculation failed", {
580
+ file: path2.basename(filePath),
581
+ error: errorMessage
582
+ });
583
+ return {
584
+ valid: false,
585
+ expected: expectedChecksum,
586
+ actual: "",
587
+ error: `Failed to calculate checksum: ${errorMessage}`
588
+ };
589
+ }
590
+ }
591
+ function getChecksumForPlatform(checksums) {
592
+ if (!checksums) {
593
+ return "";
594
+ }
595
+ const platformKey = getPlatformKey();
596
+ return checksums[platformKey] || "";
597
+ }
598
+ var logger2 = getLogger();
557
599
  function getOpenCommand(url) {
558
600
  const platformName = platform();
559
601
  switch (platformName) {
@@ -568,59 +610,160 @@ function getOpenCommand(url) {
568
610
  }
569
611
  }
570
612
  async function openBrowserUrl(options) {
571
- return new Promise((resolve4) => {
613
+ return new Promise((resolve3) => {
572
614
  try {
573
615
  const command = getOpenCommand(options.url);
574
- logger.debug("[Browser] Opening URL", { url: options.url, command });
616
+ logger2.debug("[Browser] Opening URL", { url: options.url, command });
575
617
  exec(command, (error) => {
576
618
  if (error) {
577
- logger.warn("[Browser] Failed to open URL", {
619
+ logger2.warn("[Browser] Failed to open URL", {
578
620
  url: options.url,
579
621
  error: error.message
580
622
  });
581
- resolve4({
623
+ resolve3({
582
624
  opened: false,
583
625
  error: error.message
584
626
  });
585
627
  } else {
586
- logger.info("[Browser] URL opened successfully", { url: options.url });
587
- resolve4({ opened: true });
628
+ logger2.info("[Browser] URL opened successfully", { url: options.url });
629
+ resolve3({ opened: true });
588
630
  }
589
631
  });
590
632
  } catch (error) {
591
633
  const errorMessage = error instanceof Error ? error.message : String(error);
592
- logger.warn("[Browser] Failed to open URL", {
634
+ logger2.warn("[Browser] Failed to open URL", {
593
635
  url: options.url,
594
636
  error: errorMessage
595
637
  });
596
- resolve4({
638
+ resolve3({
597
639
  opened: false,
598
640
  error: errorMessage
599
641
  });
600
642
  }
601
643
  });
602
644
  }
603
-
604
- // packages/mcps/src/mcp/local/types/enums.ts
605
- var DeviceCodePollStatus = /* @__PURE__ */ ((DeviceCodePollStatus2) => {
606
- DeviceCodePollStatus2["Pending"] = "pending";
607
- DeviceCodePollStatus2["Complete"] = "complete";
608
- DeviceCodePollStatus2["Expired"] = "expired";
609
- DeviceCodePollStatus2["Error"] = "error";
610
- return DeviceCodePollStatus2;
611
- })(DeviceCodePollStatus || {});
612
- var SessionStatus = /* @__PURE__ */ ((SessionStatus2) => {
613
- SessionStatus2["Running"] = "running";
614
- SessionStatus2["Completed"] = "completed";
615
- SessionStatus2["Failed"] = "failed";
616
- return SessionStatus2;
617
- })(SessionStatus || {});
618
- var LocalRunStatus = /* @__PURE__ */ ((LocalRunStatus2) => {
619
- LocalRunStatus2["PENDING"] = "pending";
620
- LocalRunStatus2["RUNNING"] = "running";
621
- LocalRunStatus2["PASSED"] = "passed";
622
- LocalRunStatus2["FAILED"] = "failed";
623
- LocalRunStatus2["CANCELLED"] = "cancelled";
645
+ var API_KEY_FILE2 = "api-key.json";
646
+ function getApiKeyFilePath() {
647
+ return path2.join(getDataDir(), API_KEY_FILE2);
648
+ }
649
+ function ensureDataDir() {
650
+ const dataDir = getDataDir();
651
+ if (!fs5.existsSync(dataDir)) {
652
+ fs5.mkdirSync(dataDir, { recursive: true });
653
+ }
654
+ }
655
+ function loadApiKeyData() {
656
+ const logger6 = getLogger();
657
+ const apiKeyPath = getApiKeyFilePath();
658
+ try {
659
+ if (!fs5.existsSync(apiKeyPath)) {
660
+ logger6.debug("No API key file found", { path: apiKeyPath });
661
+ return null;
662
+ }
663
+ const content = fs5.readFileSync(apiKeyPath, "utf-8");
664
+ const data = JSON.parse(content);
665
+ return data;
666
+ } catch (error) {
667
+ logger6.warn("Failed to load API key data", {
668
+ error: error instanceof Error ? error.message : String(error)
669
+ });
670
+ return null;
671
+ }
672
+ }
673
+ function saveApiKeyData(data) {
674
+ const logger6 = getLogger();
675
+ const apiKeyPath = getApiKeyFilePath();
676
+ try {
677
+ ensureDataDir();
678
+ const content = JSON.stringify(data, null, 2);
679
+ fs5.writeFileSync(apiKeyPath, content, { mode: 384 });
680
+ logger6.info("API key saved", { path: apiKeyPath });
681
+ } catch (error) {
682
+ logger6.error("Failed to save API key", {
683
+ error: error instanceof Error ? error.message : String(error)
684
+ });
685
+ throw error;
686
+ }
687
+ }
688
+ function deleteApiKeyData() {
689
+ const logger6 = getLogger();
690
+ const apiKeyPath = getApiKeyFilePath();
691
+ try {
692
+ if (fs5.existsSync(apiKeyPath)) {
693
+ fs5.unlinkSync(apiKeyPath);
694
+ logger6.info("API key deleted", { path: apiKeyPath });
695
+ }
696
+ } catch (error) {
697
+ logger6.warn("Failed to delete API key", {
698
+ error: error instanceof Error ? error.message : String(error)
699
+ });
700
+ }
701
+ }
702
+ function getValidApiKeyData() {
703
+ const data = loadApiKeyData();
704
+ if (!data) {
705
+ return null;
706
+ }
707
+ if (data.apiKey) {
708
+ return data;
709
+ }
710
+ return null;
711
+ }
712
+ function hasApiKey() {
713
+ const data = loadApiKeyData();
714
+ return !!data?.apiKey;
715
+ }
716
+ function getApiKey() {
717
+ const data = loadApiKeyData();
718
+ return data?.apiKey ?? null;
719
+ }
720
+ function saveApiKey(params) {
721
+ const logger6 = getLogger();
722
+ const apiKeyPath = getApiKeyFilePath();
723
+ try {
724
+ ensureDataDir();
725
+ const data = {
726
+ accessToken: "",
727
+ expiresAt: "",
728
+ apiKey: params.apiKey,
729
+ apiKeyId: params.apiKeyId
730
+ };
731
+ const content = JSON.stringify(data, null, 2);
732
+ fs5.writeFileSync(apiKeyPath, content, { mode: 384 });
733
+ logger6.info("API key saved", { path: apiKeyPath });
734
+ } catch (error) {
735
+ logger6.error("Failed to save API key", {
736
+ error: error instanceof Error ? error.message : String(error)
737
+ });
738
+ throw error;
739
+ }
740
+ }
741
+ var loadCredentials = loadApiKeyData;
742
+ var saveCredentials = saveApiKeyData;
743
+ var deleteCredentials = deleteApiKeyData;
744
+ var getValidCredentials = getValidApiKeyData;
745
+ var getCredentialsFilePath = getApiKeyFilePath;
746
+
747
+ // packages/mcps/src/mcp/local/types/enums.ts
748
+ var DeviceCodePollStatus = /* @__PURE__ */ ((DeviceCodePollStatus2) => {
749
+ DeviceCodePollStatus2["Pending"] = "pending";
750
+ DeviceCodePollStatus2["Complete"] = "complete";
751
+ DeviceCodePollStatus2["Expired"] = "expired";
752
+ DeviceCodePollStatus2["Error"] = "error";
753
+ return DeviceCodePollStatus2;
754
+ })(DeviceCodePollStatus || {});
755
+ var SessionStatus = /* @__PURE__ */ ((SessionStatus2) => {
756
+ SessionStatus2["Running"] = "running";
757
+ SessionStatus2["Completed"] = "completed";
758
+ SessionStatus2["Failed"] = "failed";
759
+ return SessionStatus2;
760
+ })(SessionStatus || {});
761
+ var LocalRunStatus = /* @__PURE__ */ ((LocalRunStatus2) => {
762
+ LocalRunStatus2["PENDING"] = "pending";
763
+ LocalRunStatus2["RUNNING"] = "running";
764
+ LocalRunStatus2["PASSED"] = "passed";
765
+ LocalRunStatus2["FAILED"] = "failed";
766
+ LocalRunStatus2["CANCELLED"] = "cancelled";
624
767
  return LocalRunStatus2;
625
768
  })(LocalRunStatus || {});
626
769
  var LocalRunType = /* @__PURE__ */ ((LocalRunType2) => {
@@ -699,16 +842,16 @@ var AuthService = class {
699
842
  * Get current authentication status.
700
843
  */
701
844
  getAuthStatus() {
702
- const logger14 = getLogger();
845
+ const logger6 = getLogger();
703
846
  const storedAuth = this.loadStoredAuth();
704
847
  if (!storedAuth) {
705
- logger14.debug("No stored auth found");
848
+ logger6.debug("No stored auth found");
706
849
  return { authenticated: false };
707
850
  }
708
851
  const now = /* @__PURE__ */ new Date();
709
852
  const expiresAt = new Date(storedAuth.expiresAt);
710
853
  const isExpired = now >= expiresAt;
711
- logger14.debug("Auth status checked", {
854
+ logger6.debug("Auth status checked", {
712
855
  email: storedAuth.email,
713
856
  isExpired,
714
857
  expiresAt: storedAuth.expiresAt
@@ -723,12 +866,13 @@ var AuthService = class {
723
866
  }
724
867
  /**
725
868
  * Start the device code flow.
869
+ * @param options.forceNewSession - Clear existing Auth0 browser session before login to allow account switching.
726
870
  */
727
- async startDeviceCodeFlow() {
728
- const logger14 = getLogger();
871
+ async startDeviceCodeFlow(options) {
872
+ const logger6 = getLogger();
729
873
  const config = getConfig();
730
874
  const { domain, clientId, audience, scopes } = config.localQa.auth0;
731
- logger14.info("Starting device code flow");
875
+ logger6.info("Starting device code flow");
732
876
  const url = `https://${domain}/oauth/device/code`;
733
877
  const body = new URLSearchParams({
734
878
  client_id: clientId,
@@ -744,14 +888,14 @@ var AuthService = class {
744
888
  });
745
889
  if (!response.ok) {
746
890
  const errorText = await response.text();
747
- logger14.error("Device code request failed", {
891
+ logger6.error("Device code request failed", {
748
892
  status: response.status,
749
893
  error: errorText
750
894
  });
751
895
  throw new Error(`Failed to start device code flow: ${response.status} ${errorText}`);
752
896
  }
753
897
  const data = await response.json();
754
- logger14.info("Device code flow started", {
898
+ logger6.info("Device code flow started", {
755
899
  userCode: data.user_code,
756
900
  verificationUri: data.verification_uri,
757
901
  expiresIn: data.expires_in
@@ -761,15 +905,25 @@ var AuthService = class {
761
905
  userCode: data.user_code,
762
906
  expiresAt: new Date(Date.now() + data.expires_in * 1e3).toISOString()
763
907
  });
908
+ let browserUrl = data.verification_uri_complete;
909
+ if (options?.forceNewSession) {
910
+ const logoutUrl = new URL(`https://${domain}/v2/logout`);
911
+ logoutUrl.searchParams.set("client_id", clientId);
912
+ logoutUrl.searchParams.set("returnTo", data.verification_uri_complete);
913
+ browserUrl = logoutUrl.toString();
914
+ logger6.info("Force new session: opening logout-redirect URL", {
915
+ logoutUrl: browserUrl
916
+ });
917
+ }
764
918
  const browserOpenResult = await openBrowserUrl({
765
- url: data.verification_uri_complete
919
+ url: browserUrl
766
920
  });
767
921
  if (browserOpenResult.opened) {
768
- logger14.info("Browser opened for device code login");
922
+ logger6.info("Browser opened for device code login");
769
923
  } else {
770
- logger14.warn("Failed to open browser for device code login", {
924
+ logger6.warn("Failed to open browser for device code login", {
771
925
  error: browserOpenResult.error,
772
- verificationUriComplete: data.verification_uri_complete
926
+ url: browserUrl
773
927
  });
774
928
  }
775
929
  return {
@@ -787,39 +941,39 @@ var AuthService = class {
787
941
  * Store a pending device code for later retrieval.
788
942
  */
789
943
  storePendingDeviceCode(params) {
790
- const logger14 = getLogger();
944
+ const logger6 = getLogger();
791
945
  const dir = path2.dirname(this.pendingDeviceCodePath);
792
- if (!fs3.existsSync(dir)) {
793
- fs3.mkdirSync(dir, { recursive: true });
946
+ if (!fs5.existsSync(dir)) {
947
+ fs5.mkdirSync(dir, { recursive: true });
794
948
  }
795
- fs3.writeFileSync(this.pendingDeviceCodePath, JSON.stringify(params, null, 2), {
949
+ fs5.writeFileSync(this.pendingDeviceCodePath, JSON.stringify(params, null, 2), {
796
950
  encoding: "utf-8",
797
951
  mode: 384
798
952
  });
799
- logger14.debug("Pending device code stored", { userCode: params.userCode });
953
+ logger6.debug("Pending device code stored", { userCode: params.userCode });
800
954
  }
801
955
  /**
802
956
  * Get the pending device code if one exists and is not expired.
803
957
  */
804
958
  getPendingDeviceCode() {
805
- const logger14 = getLogger();
806
- if (!fs3.existsSync(this.pendingDeviceCodePath)) {
807
- logger14.debug("No pending device code found");
959
+ const logger6 = getLogger();
960
+ if (!fs5.existsSync(this.pendingDeviceCodePath)) {
961
+ logger6.debug("No pending device code found");
808
962
  return null;
809
963
  }
810
964
  try {
811
- const content = fs3.readFileSync(this.pendingDeviceCodePath, "utf-8");
965
+ const content = fs5.readFileSync(this.pendingDeviceCodePath, "utf-8");
812
966
  const data = JSON.parse(content);
813
967
  const now = /* @__PURE__ */ new Date();
814
968
  const expiresAt = new Date(data.expiresAt);
815
969
  if (now >= expiresAt) {
816
- logger14.debug("Pending device code expired");
970
+ logger6.debug("Pending device code expired");
817
971
  this.clearPendingDeviceCode();
818
972
  return null;
819
973
  }
820
974
  return data.deviceCode;
821
975
  } catch (error) {
822
- logger14.warn("Failed to read pending device code", {
976
+ logger6.warn("Failed to read pending device code", {
823
977
  error: error instanceof Error ? error.message : String(error)
824
978
  });
825
979
  return null;
@@ -829,13 +983,13 @@ var AuthService = class {
829
983
  * Clear the pending device code file.
830
984
  */
831
985
  clearPendingDeviceCode() {
832
- const logger14 = getLogger();
833
- if (fs3.existsSync(this.pendingDeviceCodePath)) {
986
+ const logger6 = getLogger();
987
+ if (fs5.existsSync(this.pendingDeviceCodePath)) {
834
988
  try {
835
- fs3.unlinkSync(this.pendingDeviceCodePath);
836
- logger14.debug("Pending device code cleared");
989
+ fs5.unlinkSync(this.pendingDeviceCodePath);
990
+ logger6.debug("Pending device code cleared");
837
991
  } catch (error) {
838
- logger14.warn("Failed to clear pending device code", {
992
+ logger6.warn("Failed to clear pending device code", {
839
993
  error: error instanceof Error ? error.message : String(error)
840
994
  });
841
995
  }
@@ -845,10 +999,10 @@ var AuthService = class {
845
999
  * Poll for device code authorization completion.
846
1000
  */
847
1001
  async pollDeviceCode(deviceCode) {
848
- const logger14 = getLogger();
1002
+ const logger6 = getLogger();
849
1003
  const config = getConfig();
850
1004
  const { domain, clientId } = config.localQa.auth0;
851
- logger14.debug("Polling for device code authorization");
1005
+ logger6.debug("Polling for device code authorization");
852
1006
  const url = `https://${domain}/oauth/token`;
853
1007
  const body = new URLSearchParams({
854
1008
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
@@ -878,7 +1032,7 @@ var AuthService = class {
878
1032
  userId: userInfo.sub
879
1033
  });
880
1034
  this.clearPendingDeviceCode();
881
- logger14.info("Device code authorization complete", { email: userInfo.email });
1035
+ logger6.info("Device code authorization complete", { email: userInfo.email });
882
1036
  return {
883
1037
  status: "complete" /* Complete */,
884
1038
  message: "Authentication successful!",
@@ -887,35 +1041,35 @@ var AuthService = class {
887
1041
  }
888
1042
  const errorData = await response.json();
889
1043
  if (errorData.error === "authorization_pending") {
890
- logger14.debug("Authorization pending");
1044
+ logger6.debug("Authorization pending");
891
1045
  return {
892
1046
  status: "pending" /* Pending */,
893
1047
  message: "Waiting for user to complete authorization..."
894
1048
  };
895
1049
  }
896
1050
  if (errorData.error === "slow_down") {
897
- logger14.debug("Polling too fast");
1051
+ logger6.debug("Polling too fast");
898
1052
  return {
899
1053
  status: "pending" /* Pending */,
900
1054
  message: "Polling too fast, slowing down..."
901
1055
  };
902
1056
  }
903
1057
  if (errorData.error === "expired_token") {
904
- logger14.warn("Device code expired");
1058
+ logger6.warn("Device code expired");
905
1059
  return {
906
1060
  status: "expired" /* Expired */,
907
1061
  message: "The authorization code has expired. Please start again."
908
1062
  };
909
1063
  }
910
1064
  if (errorData.error === "access_denied") {
911
- logger14.warn("Access denied");
1065
+ logger6.warn("Access denied");
912
1066
  return {
913
1067
  status: "error" /* Error */,
914
1068
  message: "Access was denied by the user.",
915
1069
  error: errorData.error_description ?? errorData.error
916
1070
  };
917
1071
  }
918
- logger14.error("Unexpected error during polling", { error: errorData });
1072
+ logger6.error("Unexpected error during polling", { error: errorData });
919
1073
  return {
920
1074
  status: "error" /* Error */,
921
1075
  message: errorData.error_description ?? errorData.error,
@@ -923,7 +1077,7 @@ var AuthService = class {
923
1077
  };
924
1078
  } catch (error) {
925
1079
  const errorMessage = error instanceof Error ? error.message : String(error);
926
- logger14.error("Poll request failed", { error: errorMessage });
1080
+ logger6.error("Poll request failed", { error: errorMessage });
927
1081
  return {
928
1082
  status: "error" /* Error */,
929
1083
  message: `Poll request failed: ${errorMessage}`,
@@ -935,11 +1089,11 @@ var AuthService = class {
935
1089
  * Poll for device code authorization until completion or timeout.
936
1090
  */
937
1091
  async waitForDeviceCodeAuthorization(params) {
938
- const logger14 = getLogger();
1092
+ const logger6 = getLogger();
939
1093
  const timeoutMs = params.timeoutMs ?? DEFAULT_LOGIN_WAIT_TIMEOUT_MS;
940
1094
  const pollIntervalMs = Math.max(params.intervalSeconds, 1) * 1e3;
941
1095
  const startedAt = Date.now();
942
- logger14.info("Waiting for device code authorization", {
1096
+ logger6.info("Waiting for device code authorization", {
943
1097
  timeoutMs,
944
1098
  pollIntervalMs
945
1099
  });
@@ -963,7 +1117,7 @@ var AuthService = class {
963
1117
  * Get user info from Auth0.
964
1118
  */
965
1119
  async getUserInfo(accessToken) {
966
- const logger14 = getLogger();
1120
+ const logger6 = getLogger();
967
1121
  const config = getConfig();
968
1122
  const { domain } = config.localQa.auth0;
969
1123
  const url = `https://${domain}/userinfo`;
@@ -975,13 +1129,13 @@ var AuthService = class {
975
1129
  }
976
1130
  });
977
1131
  if (!response.ok) {
978
- logger14.warn("Failed to get user info", { status: response.status });
1132
+ logger6.warn("Failed to get user info", { status: response.status });
979
1133
  return {};
980
1134
  }
981
1135
  const data = await response.json();
982
1136
  return data;
983
1137
  } catch (error) {
984
- logger14.warn("User info request failed", {
1138
+ logger6.warn("User info request failed", {
985
1139
  error: error instanceof Error ? error.message : String(error)
986
1140
  });
987
1141
  return {};
@@ -992,7 +1146,7 @@ var AuthService = class {
992
1146
  */
993
1147
  async storeAuth(params) {
994
1148
  const { tokenResponse, email, userId } = params;
995
- const logger14 = getLogger();
1149
+ const logger6 = getLogger();
996
1150
  const expiresAt = new Date(Date.now() + tokenResponse.expiresIn * 1e3).toISOString();
997
1151
  const storedAuth = {
998
1152
  accessToken: tokenResponse.accessToken,
@@ -1002,28 +1156,28 @@ var AuthService = class {
1002
1156
  userId
1003
1157
  };
1004
1158
  const dir = path2.dirname(this.oauthSessionFilePath);
1005
- if (!fs3.existsSync(dir)) {
1006
- fs3.mkdirSync(dir, { recursive: true });
1159
+ if (!fs5.existsSync(dir)) {
1160
+ fs5.mkdirSync(dir, { recursive: true });
1007
1161
  }
1008
- fs3.writeFileSync(this.oauthSessionFilePath, JSON.stringify(storedAuth, null, 2), {
1162
+ fs5.writeFileSync(this.oauthSessionFilePath, JSON.stringify(storedAuth, null, 2), {
1009
1163
  encoding: "utf-8",
1010
1164
  mode: 384
1011
1165
  });
1012
- logger14.info("Auth stored successfully", { email, expiresAt });
1166
+ logger6.info("Auth stored successfully", { email, expiresAt });
1013
1167
  }
1014
1168
  /**
1015
1169
  * Load stored authentication.
1016
1170
  */
1017
1171
  loadStoredAuth() {
1018
- const logger14 = getLogger();
1019
- if (!fs3.existsSync(this.oauthSessionFilePath)) {
1172
+ const logger6 = getLogger();
1173
+ if (!fs5.existsSync(this.oauthSessionFilePath)) {
1020
1174
  return null;
1021
1175
  }
1022
1176
  try {
1023
- const content = fs3.readFileSync(this.oauthSessionFilePath, "utf-8");
1177
+ const content = fs5.readFileSync(this.oauthSessionFilePath, "utf-8");
1024
1178
  return JSON.parse(content);
1025
1179
  } catch (error) {
1026
- logger14.error("Failed to load stored auth", {
1180
+ logger6.error("Failed to load stored auth", {
1027
1181
  error: error instanceof Error ? error.message : String(error)
1028
1182
  });
1029
1183
  return null;
@@ -1064,15 +1218,15 @@ var AuthService = class {
1064
1218
  * @returns New access token or null if refresh failed.
1065
1219
  */
1066
1220
  async refreshAccessToken() {
1067
- const logger14 = getLogger();
1221
+ const logger6 = getLogger();
1068
1222
  const storedAuth = this.loadStoredAuth();
1069
1223
  if (!storedAuth?.refreshToken) {
1070
- logger14.debug("No refresh token available");
1224
+ logger6.debug("No refresh token available");
1071
1225
  return null;
1072
1226
  }
1073
1227
  const config = getConfig();
1074
1228
  const { domain, clientId } = config.localQa.auth0;
1075
- logger14.info("Refreshing access token");
1229
+ logger6.info("Refreshing access token");
1076
1230
  const url = `https://${domain}/oauth/token`;
1077
1231
  const body = new URLSearchParams({
1078
1232
  grant_type: "refresh_token",
@@ -1089,7 +1243,7 @@ var AuthService = class {
1089
1243
  });
1090
1244
  if (!response.ok) {
1091
1245
  const errorText = await response.text();
1092
- logger14.error("Token refresh failed", {
1246
+ logger6.error("Token refresh failed", {
1093
1247
  status: response.status,
1094
1248
  error: errorText
1095
1249
  });
@@ -1105,17 +1259,17 @@ var AuthService = class {
1105
1259
  userId: storedAuth.userId
1106
1260
  };
1107
1261
  const dir = path2.dirname(this.oauthSessionFilePath);
1108
- if (!fs3.existsSync(dir)) {
1109
- fs3.mkdirSync(dir, { recursive: true });
1262
+ if (!fs5.existsSync(dir)) {
1263
+ fs5.mkdirSync(dir, { recursive: true });
1110
1264
  }
1111
- fs3.writeFileSync(this.oauthSessionFilePath, JSON.stringify(updatedAuth, null, 2), {
1265
+ fs5.writeFileSync(this.oauthSessionFilePath, JSON.stringify(updatedAuth, null, 2), {
1112
1266
  encoding: "utf-8",
1113
1267
  mode: 384
1114
1268
  });
1115
- logger14.info("Access token refreshed", { expiresAt: newExpiresAt });
1269
+ logger6.info("Access token refreshed", { expiresAt: newExpiresAt });
1116
1270
  return tokenData.access_token;
1117
1271
  } catch (error) {
1118
- logger14.error("Token refresh request failed", {
1272
+ logger6.error("Token refresh request failed", {
1119
1273
  error: error instanceof Error ? error.message : String(error)
1120
1274
  });
1121
1275
  return null;
@@ -1127,10 +1281,10 @@ var AuthService = class {
1127
1281
  * @returns Valid access token or null if not authenticated or refresh failed.
1128
1282
  */
1129
1283
  async getValidAccessToken() {
1130
- const logger14 = getLogger();
1284
+ const logger6 = getLogger();
1131
1285
  const storedAuth = this.loadStoredAuth();
1132
1286
  if (!storedAuth) {
1133
- logger14.debug("No stored auth, cannot get valid token");
1287
+ logger6.debug("No stored auth, cannot get valid token");
1134
1288
  return null;
1135
1289
  }
1136
1290
  const now = /* @__PURE__ */ new Date();
@@ -1140,36 +1294,36 @@ var AuthService = class {
1140
1294
  return storedAuth.accessToken;
1141
1295
  }
1142
1296
  if (!isStrictlyExpired) {
1143
- logger14.debug("Access token in buffer zone, attempting proactive refresh");
1297
+ logger6.debug("Access token in buffer zone, attempting proactive refresh");
1144
1298
  } else {
1145
- logger14.info("Access token expired, attempting refresh");
1299
+ logger6.info("Access token expired, attempting refresh");
1146
1300
  }
1147
1301
  const refreshedToken = await this.refreshAccessToken();
1148
1302
  if (refreshedToken) {
1149
1303
  return refreshedToken;
1150
1304
  }
1151
1305
  if (!isStrictlyExpired) {
1152
- logger14.warn("Token refresh failed, but token not yet expired - using existing token");
1306
+ logger6.warn("Token refresh failed, but token not yet expired - using existing token");
1153
1307
  return storedAuth.accessToken;
1154
1308
  }
1155
- logger14.warn("Token refresh failed and token is expired, user needs to re-authenticate");
1309
+ logger6.warn("Token refresh failed and token is expired, user needs to re-authenticate");
1156
1310
  return null;
1157
1311
  }
1158
1312
  /**
1159
1313
  * Clear stored authentication (logout).
1160
1314
  */
1161
1315
  logout() {
1162
- const logger14 = getLogger();
1163
- if (!fs3.existsSync(this.oauthSessionFilePath)) {
1164
- logger14.debug("No auth to clear");
1316
+ const logger6 = getLogger();
1317
+ if (!fs5.existsSync(this.oauthSessionFilePath)) {
1318
+ logger6.debug("No auth to clear");
1165
1319
  return false;
1166
1320
  }
1167
1321
  try {
1168
- fs3.unlinkSync(this.oauthSessionFilePath);
1169
- logger14.info("Auth cleared successfully");
1322
+ fs5.unlinkSync(this.oauthSessionFilePath);
1323
+ logger6.info("Auth cleared successfully");
1170
1324
  return true;
1171
1325
  } catch (error) {
1172
- logger14.error("Failed to clear auth", {
1326
+ logger6.error("Failed to clear auth", {
1173
1327
  error: error instanceof Error ? error.message : String(error)
1174
1328
  });
1175
1329
  return false;
@@ -1185,9 +1339,9 @@ function resetAuthService() {
1185
1339
  serviceInstance = null;
1186
1340
  }
1187
1341
  function sleep(params) {
1188
- return new Promise((resolve4) => {
1342
+ return new Promise((resolve3) => {
1189
1343
  setTimeout(() => {
1190
- resolve4();
1344
+ resolve3();
1191
1345
  }, params.durationMs);
1192
1346
  });
1193
1347
  }
@@ -1209,14 +1363,14 @@ var StorageService = class {
1209
1363
  * Ensure the base directories exist.
1210
1364
  */
1211
1365
  ensureDirectories() {
1212
- const logger14 = getLogger();
1213
- if (!fs3.existsSync(this.dataDir)) {
1214
- fs3.mkdirSync(this.dataDir, { recursive: true });
1215
- logger14.info("Created data directory", { path: this.dataDir });
1366
+ const logger6 = getLogger();
1367
+ if (!fs5.existsSync(this.dataDir)) {
1368
+ fs5.mkdirSync(this.dataDir, { recursive: true });
1369
+ logger6.info("Created data directory", { path: this.dataDir });
1216
1370
  }
1217
- if (!fs3.existsSync(this.sessionsDir)) {
1218
- fs3.mkdirSync(this.sessionsDir, { recursive: true });
1219
- logger14.info("Created sessions directory", { path: this.sessionsDir });
1371
+ if (!fs5.existsSync(this.sessionsDir)) {
1372
+ fs5.mkdirSync(this.sessionsDir, { recursive: true });
1373
+ logger6.info("Created sessions directory", { path: this.sessionsDir });
1220
1374
  }
1221
1375
  }
1222
1376
  /**
@@ -1225,14 +1379,14 @@ var StorageService = class {
1225
1379
  * @returns Path to the session directory.
1226
1380
  */
1227
1381
  createSessionDirectory(sessionId) {
1228
- const logger14 = getLogger();
1382
+ const logger6 = getLogger();
1229
1383
  this.ensureDirectories();
1230
1384
  const sessionDir = path2.join(this.sessionsDir, sessionId);
1231
- if (!fs3.existsSync(sessionDir)) {
1232
- fs3.mkdirSync(sessionDir, { recursive: true });
1233
- fs3.mkdirSync(path2.join(sessionDir, "screenshots"), { recursive: true });
1234
- fs3.mkdirSync(path2.join(sessionDir, "logs"), { recursive: true });
1235
- logger14.info("Created session directory", { sessionId, path: sessionDir });
1385
+ if (!fs5.existsSync(sessionDir)) {
1386
+ fs5.mkdirSync(sessionDir, { recursive: true });
1387
+ fs5.mkdirSync(path2.join(sessionDir, "screenshots"), { recursive: true });
1388
+ fs5.mkdirSync(path2.join(sessionDir, "logs"), { recursive: true });
1389
+ logger6.info("Created session directory", { sessionId, path: sessionDir });
1236
1390
  }
1237
1391
  return sessionDir;
1238
1392
  }
@@ -1241,11 +1395,11 @@ var StorageService = class {
1241
1395
  * @param metadata - Session metadata to save.
1242
1396
  */
1243
1397
  saveSessionMetadata(metadata) {
1244
- const logger14 = getLogger();
1398
+ const logger6 = getLogger();
1245
1399
  const sessionDir = this.createSessionDirectory(metadata.sessionId);
1246
1400
  const metadataPath = path2.join(sessionDir, "metadata.json");
1247
- fs3.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
1248
- logger14.debug("Saved session metadata", { sessionId: metadata.sessionId });
1401
+ fs5.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
1402
+ logger6.debug("Saved session metadata", { sessionId: metadata.sessionId });
1249
1403
  }
1250
1404
  /**
1251
1405
  * Load session metadata.
@@ -1253,16 +1407,16 @@ var StorageService = class {
1253
1407
  * @returns Session metadata, or null if not found.
1254
1408
  */
1255
1409
  loadSessionMetadata(sessionId) {
1256
- const logger14 = getLogger();
1410
+ const logger6 = getLogger();
1257
1411
  const metadataPath = path2.join(this.sessionsDir, sessionId, "metadata.json");
1258
- if (!fs3.existsSync(metadataPath)) {
1412
+ if (!fs5.existsSync(metadataPath)) {
1259
1413
  return null;
1260
1414
  }
1261
1415
  try {
1262
- const content = fs3.readFileSync(metadataPath, "utf-8");
1416
+ const content = fs5.readFileSync(metadataPath, "utf-8");
1263
1417
  return JSON.parse(content);
1264
1418
  } catch (error) {
1265
- logger14.error("Failed to load session metadata", {
1419
+ logger6.error("Failed to load session metadata", {
1266
1420
  sessionId,
1267
1421
  error: error instanceof Error ? error.message : String(error)
1268
1422
  });
@@ -1274,12 +1428,12 @@ var StorageService = class {
1274
1428
  * @returns Array of session IDs.
1275
1429
  */
1276
1430
  listSessions() {
1277
- if (!fs3.existsSync(this.sessionsDir)) {
1431
+ if (!fs5.existsSync(this.sessionsDir)) {
1278
1432
  return [];
1279
1433
  }
1280
- return fs3.readdirSync(this.sessionsDir).filter((entry) => {
1434
+ return fs5.readdirSync(this.sessionsDir).filter((entry) => {
1281
1435
  const entryPath = path2.join(this.sessionsDir, entry);
1282
- return fs3.statSync(entryPath).isDirectory();
1436
+ return fs5.statSync(entryPath).isDirectory();
1283
1437
  });
1284
1438
  }
1285
1439
  /**
@@ -1288,11 +1442,11 @@ var StorageService = class {
1288
1442
  */
1289
1443
  getCurrentSessionId() {
1290
1444
  const currentPath = path2.join(this.sessionsDir, "current");
1291
- if (!fs3.existsSync(currentPath)) {
1445
+ if (!fs5.existsSync(currentPath)) {
1292
1446
  return null;
1293
1447
  }
1294
1448
  try {
1295
- const target = fs3.readlinkSync(currentPath);
1449
+ const target = fs5.readlinkSync(currentPath);
1296
1450
  return path2.basename(target);
1297
1451
  } catch {
1298
1452
  return null;
@@ -1303,14 +1457,14 @@ var StorageService = class {
1303
1457
  * @param sessionId - Session ID to set as current.
1304
1458
  */
1305
1459
  setCurrentSession(sessionId) {
1306
- const logger14 = getLogger();
1460
+ const logger6 = getLogger();
1307
1461
  const currentPath = path2.join(this.sessionsDir, "current");
1308
1462
  const targetPath = path2.join(this.sessionsDir, sessionId);
1309
- if (fs3.existsSync(currentPath)) {
1310
- fs3.unlinkSync(currentPath);
1463
+ if (fs5.existsSync(currentPath)) {
1464
+ fs5.unlinkSync(currentPath);
1311
1465
  }
1312
- fs3.symlinkSync(targetPath, currentPath);
1313
- logger14.info("Set current session", { sessionId });
1466
+ fs5.symlinkSync(targetPath, currentPath);
1467
+ logger6.info("Set current session", { sessionId });
1314
1468
  }
1315
1469
  /**
1316
1470
  * Save a screenshot to the session directory.
@@ -1318,11 +1472,11 @@ var StorageService = class {
1318
1472
  */
1319
1473
  saveScreenshot(params) {
1320
1474
  const { sessionId, filename, data } = params;
1321
- const logger14 = getLogger();
1475
+ const logger6 = getLogger();
1322
1476
  const sessionDir = this.createSessionDirectory(sessionId);
1323
1477
  const screenshotPath = path2.join(sessionDir, "screenshots", filename);
1324
- fs3.writeFileSync(screenshotPath, data);
1325
- logger14.debug("Saved screenshot", { sessionId, filename });
1478
+ fs5.writeFileSync(screenshotPath, data);
1479
+ logger6.debug("Saved screenshot", { sessionId, filename });
1326
1480
  return screenshotPath;
1327
1481
  }
1328
1482
  /**
@@ -1331,11 +1485,11 @@ var StorageService = class {
1331
1485
  */
1332
1486
  appendToResults(params) {
1333
1487
  const { sessionId, content } = params;
1334
- const logger14 = getLogger();
1488
+ const logger6 = getLogger();
1335
1489
  const sessionDir = this.createSessionDirectory(sessionId);
1336
1490
  const resultsPath = path2.join(sessionDir, "results.md");
1337
- fs3.appendFileSync(resultsPath, content + "\n", "utf-8");
1338
- logger14.debug("Appended to results", { sessionId });
1491
+ fs5.appendFileSync(resultsPath, content + "\n", "utf-8");
1492
+ logger6.debug("Appended to results", { sessionId });
1339
1493
  }
1340
1494
  /**
1341
1495
  * Get the results markdown content.
@@ -1344,10 +1498,10 @@ var StorageService = class {
1344
1498
  */
1345
1499
  getResults(sessionId) {
1346
1500
  const resultsPath = path2.join(this.sessionsDir, sessionId, "results.md");
1347
- if (!fs3.existsSync(resultsPath)) {
1501
+ if (!fs5.existsSync(resultsPath)) {
1348
1502
  return null;
1349
1503
  }
1350
- return fs3.readFileSync(resultsPath, "utf-8");
1504
+ return fs5.readFileSync(resultsPath, "utf-8");
1351
1505
  }
1352
1506
  /**
1353
1507
  * Get the data directory path.
@@ -1370,7 +1524,7 @@ var StorageService = class {
1370
1524
  */
1371
1525
  createSession(params) {
1372
1526
  const { sessionId, targetUrl, testInstructions } = params;
1373
- const logger14 = getLogger();
1527
+ const logger6 = getLogger();
1374
1528
  const sessionDir = this.createSessionDirectory(sessionId);
1375
1529
  const metadata = {
1376
1530
  sessionId,
@@ -1382,7 +1536,7 @@ var StorageService = class {
1382
1536
  };
1383
1537
  this.saveSessionMetadata(metadata);
1384
1538
  this.setCurrentSession(sessionId);
1385
- logger14.info("Created session", { sessionId, targetUrl });
1539
+ logger6.info("Created session", { sessionId, targetUrl });
1386
1540
  return sessionDir;
1387
1541
  }
1388
1542
  /**
@@ -1391,10 +1545,10 @@ var StorageService = class {
1391
1545
  */
1392
1546
  updateSessionStatus(params) {
1393
1547
  const { sessionId, status } = params;
1394
- const logger14 = getLogger();
1548
+ const logger6 = getLogger();
1395
1549
  const metadata = this.loadSessionMetadata(sessionId);
1396
1550
  if (!metadata) {
1397
- logger14.warn("Session not found for status update", { sessionId });
1551
+ logger6.warn("Session not found for status update", { sessionId });
1398
1552
  return;
1399
1553
  }
1400
1554
  metadata.status = status;
@@ -1402,7 +1556,7 @@ var StorageService = class {
1402
1556
  metadata.endTime = (/* @__PURE__ */ new Date()).toISOString();
1403
1557
  }
1404
1558
  this.saveSessionMetadata(metadata);
1405
- logger14.debug("Updated session status", { sessionId, status });
1559
+ logger6.debug("Updated session status", { sessionId, status });
1406
1560
  }
1407
1561
  /**
1408
1562
  * Initialize the results.md file with a header.
@@ -1410,10 +1564,10 @@ var StorageService = class {
1410
1564
  */
1411
1565
  initializeResults(params) {
1412
1566
  const { sessionId, targetUrl, testInstructions } = params;
1413
- const logger14 = getLogger();
1567
+ const logger6 = getLogger();
1414
1568
  const sessionDir = this.createSessionDirectory(sessionId);
1415
1569
  const resultsPath = path2.join(sessionDir, "results.md");
1416
- const header2 = [
1570
+ const header = [
1417
1571
  `# Test Results: ${sessionId}`,
1418
1572
  "",
1419
1573
  `**Target URL:** ${targetUrl}`,
@@ -1425,8 +1579,8 @@ var StorageService = class {
1425
1579
  "## Test Steps",
1426
1580
  ""
1427
1581
  ].join("\n");
1428
- fs3.writeFileSync(resultsPath, header2, "utf-8");
1429
- logger14.debug("Initialized results.md", { sessionId });
1582
+ fs5.writeFileSync(resultsPath, header, "utf-8");
1583
+ logger6.debug("Initialized results.md", { sessionId });
1430
1584
  }
1431
1585
  /**
1432
1586
  * Append a test step to the results.md file.
@@ -1434,7 +1588,7 @@ var StorageService = class {
1434
1588
  */
1435
1589
  appendStepToResults(params) {
1436
1590
  const { sessionId, step } = params;
1437
- const logger14 = getLogger();
1591
+ const logger6 = getLogger();
1438
1592
  const sessionDir = this.createSessionDirectory(sessionId);
1439
1593
  const resultsPath = path2.join(sessionDir, "results.md");
1440
1594
  const statusIcon = step.success ? "\u2713" : "\u2717";
@@ -1446,8 +1600,8 @@ var StorageService = class {
1446
1600
  step.screenshotPath ? `- **Screenshot:** [step-${String(step.stepNumber).padStart(3, "0")}.png](screenshots/step-${String(step.stepNumber).padStart(3, "0")}.png)` : "",
1447
1601
  ""
1448
1602
  ].filter(Boolean).join("\n");
1449
- fs3.appendFileSync(resultsPath, stepContent + "\n", "utf-8");
1450
- logger14.debug("Appended step to results", { sessionId, stepNumber: step.stepNumber });
1603
+ fs5.appendFileSync(resultsPath, stepContent + "\n", "utf-8");
1604
+ logger6.debug("Appended step to results", { sessionId, stepNumber: step.stepNumber });
1451
1605
  const metadata = this.loadSessionMetadata(sessionId);
1452
1606
  if (metadata) {
1453
1607
  metadata.stepsCount = (metadata.stepsCount ?? 0) + 1;
@@ -1460,11 +1614,11 @@ var StorageService = class {
1460
1614
  */
1461
1615
  finalizeResults(params) {
1462
1616
  const { sessionId, status, summary } = params;
1463
- const logger14 = getLogger();
1617
+ const logger6 = getLogger();
1464
1618
  const sessionDir = path2.join(this.sessionsDir, sessionId);
1465
1619
  const resultsPath = path2.join(sessionDir, "results.md");
1466
- if (!fs3.existsSync(resultsPath)) {
1467
- logger14.warn("Results file not found for finalization", { sessionId });
1620
+ if (!fs5.existsSync(resultsPath)) {
1621
+ logger6.warn("Results file not found for finalization", { sessionId });
1468
1622
  return;
1469
1623
  }
1470
1624
  const metadata = this.loadSessionMetadata(sessionId);
@@ -1486,8 +1640,8 @@ var StorageService = class {
1486
1640
  "",
1487
1641
  summary ? summary : ""
1488
1642
  ].join("\n");
1489
- fs3.appendFileSync(resultsPath, footer, "utf-8");
1490
- logger14.debug("Finalized results.md", { sessionId, status });
1643
+ fs5.appendFileSync(resultsPath, footer, "utf-8");
1644
+ logger6.debug("Finalized results.md", { sessionId, status });
1491
1645
  if (metadata) {
1492
1646
  metadata.durationMs = durationMs;
1493
1647
  metadata.endTime = endTime.toISOString();
@@ -1529,7 +1683,7 @@ var StorageService = class {
1529
1683
  */
1530
1684
  cleanupOldSessions(params) {
1531
1685
  const maxAgeDays = params?.maxAgeDays ?? DEFAULT_SESSION_MAX_AGE_DAYS;
1532
- const logger14 = getLogger();
1686
+ const logger6 = getLogger();
1533
1687
  const cutoffDate = /* @__PURE__ */ new Date();
1534
1688
  cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
1535
1689
  const sessionIds = this.listSessions();
@@ -1546,14 +1700,14 @@ var StorageService = class {
1546
1700
  if (sessionDate < cutoffDate) {
1547
1701
  const sessionDir = path2.join(this.sessionsDir, sessionId);
1548
1702
  try {
1549
- fs3.rmSync(sessionDir, { recursive: true, force: true });
1703
+ fs5.rmSync(sessionDir, { recursive: true, force: true });
1550
1704
  deletedCount++;
1551
- logger14.info("Deleted old session", {
1705
+ logger6.info("Deleted old session", {
1552
1706
  sessionId,
1553
1707
  age: Math.floor((Date.now() - sessionDate.getTime()) / (1e3 * 60 * 60 * 24))
1554
1708
  });
1555
1709
  } catch (error) {
1556
- logger14.error("Failed to delete session", {
1710
+ logger6.error("Failed to delete session", {
1557
1711
  sessionId,
1558
1712
  error: error instanceof Error ? error.message : String(error)
1559
1713
  });
@@ -1561,7 +1715,7 @@ var StorageService = class {
1561
1715
  }
1562
1716
  }
1563
1717
  if (deletedCount > 0) {
1564
- logger14.info("Session cleanup completed", {
1718
+ logger6.info("Session cleanup completed", {
1565
1719
  deletedCount,
1566
1720
  maxAgeDays
1567
1721
  });
@@ -1582,25 +1736,25 @@ var StorageService = class {
1582
1736
  * @returns Whether deletion succeeded.
1583
1737
  */
1584
1738
  deleteSession(sessionId) {
1585
- const logger14 = getLogger();
1739
+ const logger6 = getLogger();
1586
1740
  const sessionDir = path2.join(this.sessionsDir, sessionId);
1587
- if (!fs3.existsSync(sessionDir)) {
1588
- logger14.warn("Session not found for deletion", { sessionId });
1741
+ if (!fs5.existsSync(sessionDir)) {
1742
+ logger6.warn("Session not found for deletion", { sessionId });
1589
1743
  return false;
1590
1744
  }
1591
1745
  try {
1592
1746
  const currentId = this.getCurrentSessionId();
1593
1747
  if (currentId === sessionId) {
1594
1748
  const currentPath = path2.join(this.sessionsDir, "current");
1595
- if (fs3.existsSync(currentPath)) {
1596
- fs3.unlinkSync(currentPath);
1749
+ if (fs5.existsSync(currentPath)) {
1750
+ fs5.unlinkSync(currentPath);
1597
1751
  }
1598
1752
  }
1599
- fs3.rmSync(sessionDir, { recursive: true, force: true });
1600
- logger14.info("Deleted session", { sessionId });
1753
+ fs5.rmSync(sessionDir, { recursive: true, force: true });
1754
+ logger6.info("Deleted session", { sessionId });
1601
1755
  return true;
1602
1756
  } catch (error) {
1603
- logger14.error("Failed to delete session", {
1757
+ logger6.error("Failed to delete session", {
1604
1758
  sessionId,
1605
1759
  error: error instanceof Error ? error.message : String(error)
1606
1760
  });
@@ -1616,7 +1770,7 @@ function getStorageService() {
1616
1770
  function resetStorageService() {
1617
1771
  serviceInstance2 = null;
1618
1772
  }
1619
- var logger2 = getLogger();
1773
+ var logger3 = getLogger();
1620
1774
  var RunResultStorageService = class {
1621
1775
  /** Base directory for run results. */
1622
1776
  runResultsDir;
@@ -1633,11 +1787,11 @@ var RunResultStorageService = class {
1633
1787
  * Ensure storage directories exist.
1634
1788
  */
1635
1789
  ensureDirectories() {
1636
- if (!fs3.existsSync(this.runResultsDir)) {
1637
- fs3.mkdirSync(this.runResultsDir, { recursive: true });
1790
+ if (!fs5.existsSync(this.runResultsDir)) {
1791
+ fs5.mkdirSync(this.runResultsDir, { recursive: true });
1638
1792
  }
1639
- if (!fs3.existsSync(this.testScriptsDir)) {
1640
- fs3.mkdirSync(this.testScriptsDir, { recursive: true });
1793
+ if (!fs5.existsSync(this.testScriptsDir)) {
1794
+ fs5.mkdirSync(this.testScriptsDir, { recursive: true });
1641
1795
  }
1642
1796
  }
1643
1797
  // ========================================
@@ -1648,14 +1802,14 @@ var RunResultStorageService = class {
1648
1802
  */
1649
1803
  listRunResults() {
1650
1804
  try {
1651
- const files = fs3.readdirSync(this.runResultsDir).filter((f) => f.endsWith(".json"));
1805
+ const files = fs5.readdirSync(this.runResultsDir).filter((f) => f.endsWith(".json"));
1652
1806
  const results = [];
1653
1807
  for (const file of files) {
1654
1808
  try {
1655
- const content = fs3.readFileSync(path2.join(this.runResultsDir, file), "utf-8");
1809
+ const content = fs5.readFileSync(path2.join(this.runResultsDir, file), "utf-8");
1656
1810
  results.push(JSON.parse(content));
1657
1811
  } catch {
1658
- logger2.warn("Failed to read run result file", { file });
1812
+ logger3.warn("Failed to read run result file", { file });
1659
1813
  }
1660
1814
  }
1661
1815
  return results.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
@@ -1668,11 +1822,11 @@ var RunResultStorageService = class {
1668
1822
  */
1669
1823
  getRunResult(runId) {
1670
1824
  const filePath = path2.join(this.runResultsDir, `${runId}.json`);
1671
- if (!fs3.existsSync(filePath)) {
1825
+ if (!fs5.existsSync(filePath)) {
1672
1826
  return void 0;
1673
1827
  }
1674
1828
  try {
1675
- const content = fs3.readFileSync(filePath, "utf-8");
1829
+ const content = fs5.readFileSync(filePath, "utf-8");
1676
1830
  return JSON.parse(content);
1677
1831
  } catch {
1678
1832
  return void 0;
@@ -1683,7 +1837,7 @@ var RunResultStorageService = class {
1683
1837
  */
1684
1838
  saveRunResult(result) {
1685
1839
  const filePath = path2.join(this.runResultsDir, `${result.id}.json`);
1686
- fs3.writeFileSync(filePath, JSON.stringify(result, null, 2));
1840
+ fs5.writeFileSync(filePath, JSON.stringify(result, null, 2));
1687
1841
  }
1688
1842
  /**
1689
1843
  * Create a new run result.
@@ -1731,14 +1885,14 @@ var RunResultStorageService = class {
1731
1885
  */
1732
1886
  listTestScripts() {
1733
1887
  try {
1734
- const files = fs3.readdirSync(this.testScriptsDir).filter((f) => f.endsWith(".json"));
1888
+ const files = fs5.readdirSync(this.testScriptsDir).filter((f) => f.endsWith(".json"));
1735
1889
  const scripts = [];
1736
1890
  for (const file of files) {
1737
1891
  try {
1738
- const content = fs3.readFileSync(path2.join(this.testScriptsDir, file), "utf-8");
1892
+ const content = fs5.readFileSync(path2.join(this.testScriptsDir, file), "utf-8");
1739
1893
  scripts.push(JSON.parse(content));
1740
1894
  } catch {
1741
- logger2.warn("Failed to read test script file", { file });
1895
+ logger3.warn("Failed to read test script file", { file });
1742
1896
  }
1743
1897
  }
1744
1898
  return scripts.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
@@ -1751,11 +1905,11 @@ var RunResultStorageService = class {
1751
1905
  */
1752
1906
  getTestScript(testScriptId) {
1753
1907
  const filePath = path2.join(this.testScriptsDir, `${testScriptId}.json`);
1754
- if (!fs3.existsSync(filePath)) {
1908
+ if (!fs5.existsSync(filePath)) {
1755
1909
  return void 0;
1756
1910
  }
1757
1911
  try {
1758
- const content = fs3.readFileSync(filePath, "utf-8");
1912
+ const content = fs5.readFileSync(filePath, "utf-8");
1759
1913
  return JSON.parse(content);
1760
1914
  } catch {
1761
1915
  return void 0;
@@ -1766,7 +1920,7 @@ var RunResultStorageService = class {
1766
1920
  */
1767
1921
  saveTestScript(script) {
1768
1922
  const filePath = path2.join(this.testScriptsDir, `${script.id}.json`);
1769
- fs3.writeFileSync(filePath, JSON.stringify(script, null, 2));
1923
+ fs5.writeFileSync(filePath, JSON.stringify(script, null, 2));
1770
1924
  }
1771
1925
  /**
1772
1926
  * Create a new test script.
@@ -1814,7 +1968,7 @@ function getRunResultStorageService() {
1814
1968
  function resetRunResultStorageService() {
1815
1969
  instance = null;
1816
1970
  }
1817
- var logger3 = getLogger();
1971
+ var logger4 = getLogger();
1818
1972
  var activeProcesses = /* @__PURE__ */ new Map();
1819
1973
  function getAuthenticatedUserId() {
1820
1974
  const authService = getAuthService();
@@ -1837,7 +1991,7 @@ async function findPackageJsonAsync() {
1837
1991
  ];
1838
1992
  for (const candidatePath of candidatePaths) {
1839
1993
  try {
1840
- const packageJsonRaw = await fs5.readFile(candidatePath, "utf-8");
1994
+ const packageJsonRaw = await fs7.readFile(candidatePath, "utf-8");
1841
1995
  const packageJson = JSON.parse(packageJsonRaw);
1842
1996
  if (packageJson.name === "@muggleai/works" && packageJson.version && packageJson.muggleConfig?.electronAppVersion) {
1843
1997
  return {
@@ -1884,19 +2038,19 @@ function buildStudioAuthContent() {
1884
2038
  async function ensureTempDir() {
1885
2039
  const config = getConfig();
1886
2040
  const tempDir = path2.join(config.localQa.dataDir, "temp");
1887
- await fs5.mkdir(tempDir, { recursive: true });
2041
+ await fs7.mkdir(tempDir, { recursive: true });
1888
2042
  return tempDir;
1889
2043
  }
1890
2044
  async function writeTempFile(params) {
1891
2045
  const tempDir = await ensureTempDir();
1892
2046
  const filePath = path2.join(tempDir, params.filename);
1893
- await fs5.writeFile(filePath, JSON.stringify(params.data, null, 2));
2047
+ await fs7.writeFile(filePath, JSON.stringify(params.data, null, 2));
1894
2048
  return filePath;
1895
2049
  }
1896
2050
  async function cleanupTempFiles(params) {
1897
2051
  for (const filePath of params.filePaths) {
1898
2052
  try {
1899
- await fs5.unlink(filePath);
2053
+ await fs7.unlink(filePath);
1900
2054
  } catch {
1901
2055
  }
1902
2056
  }
@@ -1906,10 +2060,10 @@ async function moveResultsToArtifacts(params) {
1906
2060
  const sessionsDir = storageService.getSessionsDir();
1907
2061
  const artifactsDir = path2.join(sessionsDir, params.runId);
1908
2062
  const actionScriptPath = path2.join(artifactsDir, "action-script.json");
1909
- await fs5.mkdir(artifactsDir, { recursive: true });
1910
- await fs5.copyFile(params.generatedScriptPath, actionScriptPath);
2063
+ await fs7.mkdir(artifactsDir, { recursive: true });
2064
+ await fs7.copyFile(params.generatedScriptPath, actionScriptPath);
1911
2065
  try {
1912
- await fs5.unlink(params.generatedScriptPath);
2066
+ await fs7.unlink(params.generatedScriptPath);
1913
2067
  } catch {
1914
2068
  }
1915
2069
  return artifactsDir;
@@ -1918,14 +2072,14 @@ async function writeExecutionLogs(params) {
1918
2072
  const storageService = getStorageService();
1919
2073
  const sessionsDir = storageService.getSessionsDir();
1920
2074
  const artifactsDir = path2.join(sessionsDir, params.runId);
1921
- await fs5.mkdir(artifactsDir, { recursive: true });
2075
+ await fs7.mkdir(artifactsDir, { recursive: true });
1922
2076
  const stdoutPath = path2.join(artifactsDir, "stdout.log");
1923
2077
  const stderrPath = path2.join(artifactsDir, "stderr.log");
1924
2078
  await Promise.all([
1925
- fs5.writeFile(stdoutPath, params.stdout, "utf-8"),
1926
- fs5.writeFile(stderrPath, params.stderr, "utf-8")
2079
+ fs7.writeFile(stdoutPath, params.stdout, "utf-8"),
2080
+ fs7.writeFile(stderrPath, params.stderr, "utf-8")
1927
2081
  ]);
1928
- logger3.info("Wrote execution logs to artifacts directory", {
2082
+ logger4.info("Wrote execution logs to artifacts directory", {
1929
2083
  runId: params.runId,
1930
2084
  artifactsDir
1931
2085
  });
@@ -2057,7 +2211,7 @@ async function executeElectronAppAsync(params) {
2057
2211
  if (params.showUi) {
2058
2212
  spawnArgs.push("--show-ui");
2059
2213
  }
2060
- logger3.info("Spawning electron-app for local execution", {
2214
+ logger4.info("Spawning electron-app for local execution", {
2061
2215
  runId: params.runId,
2062
2216
  mode,
2063
2217
  electronAppPath,
@@ -2079,7 +2233,7 @@ async function executeElectronAppAsync(params) {
2079
2233
  capturedStderr: ""
2080
2234
  };
2081
2235
  activeProcesses.set(params.runId, processInfo);
2082
- return await new Promise((resolve4, reject) => {
2236
+ return await new Promise((resolve3, reject) => {
2083
2237
  let settled = false;
2084
2238
  const finalize = (result) => {
2085
2239
  if (settled) {
@@ -2091,7 +2245,7 @@ async function executeElectronAppAsync(params) {
2091
2245
  }
2092
2246
  activeProcesses.delete(params.runId);
2093
2247
  if (result.ok) {
2094
- resolve4(result.payload);
2248
+ resolve3(result.payload);
2095
2249
  } else {
2096
2250
  reject(result.payload);
2097
2251
  }
@@ -2245,7 +2399,7 @@ ${executionResult.stderr}`;
2245
2399
  path2.dirname(inputFilePath),
2246
2400
  `gen_${path2.basename(inputFilePath)}`
2247
2401
  );
2248
- const generatedScriptRaw = await fs5.readFile(generatedScriptPath, "utf-8");
2402
+ const generatedScriptRaw = await fs7.readFile(generatedScriptPath, "utf-8");
2249
2403
  const generatedScript = JSON.parse(generatedScriptRaw);
2250
2404
  const generatedSteps = generatedScript.steps;
2251
2405
  if (!Array.isArray(generatedSteps)) {
@@ -2452,114 +2606,13 @@ function listActiveExecutions() {
2452
2606
  status: process2.status
2453
2607
  }));
2454
2608
  }
2455
- var API_KEY_FILE2 = "api-key.json";
2456
- function getApiKeyFilePath() {
2457
- return path2.join(getDataDir(), API_KEY_FILE2);
2458
- }
2459
- function ensureDataDir() {
2460
- const dataDir = getDataDir();
2461
- if (!fs3.existsSync(dataDir)) {
2462
- fs3.mkdirSync(dataDir, { recursive: true });
2463
- }
2464
- }
2465
- function loadApiKeyData() {
2466
- const logger14 = getLogger();
2467
- const apiKeyPath = getApiKeyFilePath();
2468
- try {
2469
- if (!fs3.existsSync(apiKeyPath)) {
2470
- logger14.debug("No API key file found", { path: apiKeyPath });
2471
- return null;
2472
- }
2473
- const content = fs3.readFileSync(apiKeyPath, "utf-8");
2474
- const data = JSON.parse(content);
2475
- return data;
2476
- } catch (error) {
2477
- logger14.warn("Failed to load API key data", {
2478
- error: error instanceof Error ? error.message : String(error)
2479
- });
2480
- return null;
2481
- }
2482
- }
2483
- function saveApiKeyData(data) {
2484
- const logger14 = getLogger();
2485
- const apiKeyPath = getApiKeyFilePath();
2486
- try {
2487
- ensureDataDir();
2488
- const content = JSON.stringify(data, null, 2);
2489
- fs3.writeFileSync(apiKeyPath, content, { mode: 384 });
2490
- logger14.info("API key saved", { path: apiKeyPath });
2491
- } catch (error) {
2492
- logger14.error("Failed to save API key", {
2493
- error: error instanceof Error ? error.message : String(error)
2494
- });
2495
- throw error;
2496
- }
2497
- }
2498
- function deleteApiKeyData() {
2499
- const logger14 = getLogger();
2500
- const apiKeyPath = getApiKeyFilePath();
2501
- try {
2502
- if (fs3.existsSync(apiKeyPath)) {
2503
- fs3.unlinkSync(apiKeyPath);
2504
- logger14.info("API key deleted", { path: apiKeyPath });
2505
- }
2506
- } catch (error) {
2507
- logger14.warn("Failed to delete API key", {
2508
- error: error instanceof Error ? error.message : String(error)
2509
- });
2510
- }
2511
- }
2512
- function getValidApiKeyData() {
2513
- const data = loadApiKeyData();
2514
- if (!data) {
2515
- return null;
2516
- }
2517
- if (data.apiKey) {
2518
- return data;
2519
- }
2520
- return null;
2521
- }
2522
- function hasApiKey() {
2523
- const data = loadApiKeyData();
2524
- return !!data?.apiKey;
2525
- }
2526
- function getApiKey() {
2527
- const data = loadApiKeyData();
2528
- return data?.apiKey ?? null;
2529
- }
2530
- function saveApiKey(params) {
2531
- const logger14 = getLogger();
2532
- const apiKeyPath = getApiKeyFilePath();
2533
- try {
2534
- ensureDataDir();
2535
- const data = {
2536
- accessToken: "",
2537
- expiresAt: "",
2538
- apiKey: params.apiKey,
2539
- apiKeyId: params.apiKeyId
2540
- };
2541
- const content = JSON.stringify(data, null, 2);
2542
- fs3.writeFileSync(apiKeyPath, content, { mode: 384 });
2543
- logger14.info("API key saved", { path: apiKeyPath });
2544
- } catch (error) {
2545
- logger14.error("Failed to save API key", {
2546
- error: error instanceof Error ? error.message : String(error)
2547
- });
2548
- throw error;
2549
- }
2550
- }
2551
- var loadCredentials = loadApiKeyData;
2552
- var saveCredentials = saveApiKeyData;
2553
- var deleteCredentials = deleteApiKeyData;
2554
- var getValidCredentials = getValidApiKeyData;
2555
- var getCredentialsFilePath = getApiKeyFilePath;
2556
2609
 
2557
2610
  // packages/mcps/src/shared/auth.ts
2558
- var logger4 = getLogger();
2559
- async function startDeviceCodeFlow(config) {
2611
+ var logger5 = getLogger();
2612
+ async function startDeviceCodeFlow(config, options) {
2560
2613
  const deviceCodeUrl = `https://${config.domain}/oauth/device/code`;
2561
2614
  try {
2562
- logger4.info("[Auth] Starting device code flow", {
2615
+ logger5.info("[Auth] Starting device code flow", {
2563
2616
  domain: config.domain,
2564
2617
  clientId: config.clientId
2565
2618
  });
@@ -2577,17 +2630,25 @@ async function startDeviceCodeFlow(config) {
2577
2630
  }
2578
2631
  );
2579
2632
  const data = response.data;
2580
- logger4.info("[Auth] Device code flow started successfully", {
2633
+ logger5.info("[Auth] Device code flow started successfully", {
2581
2634
  userCode: data.user_code,
2582
2635
  expiresIn: data.expires_in
2583
2636
  });
2637
+ let browserUrl = data.verification_uri_complete;
2638
+ if (options?.forceNewSession) {
2639
+ const logoutUrl = new URL(`https://${config.domain}/v2/logout`);
2640
+ logoutUrl.searchParams.set("client_id", config.clientId);
2641
+ logoutUrl.searchParams.set("returnTo", data.verification_uri_complete);
2642
+ browserUrl = logoutUrl.toString();
2643
+ logger5.info("[Auth] Force new session: opening logout-redirect URL");
2644
+ }
2584
2645
  const browserOpenResult = await openBrowserUrl({
2585
- url: data.verification_uri_complete
2646
+ url: browserUrl
2586
2647
  });
2587
2648
  if (browserOpenResult.opened) {
2588
- logger4.info("[Auth] Browser opened for device code login");
2649
+ logger5.info("[Auth] Browser opened for device code login");
2589
2650
  } else {
2590
- logger4.warn("[Auth] Failed to open browser", {
2651
+ logger5.warn("[Auth] Failed to open browser", {
2591
2652
  error: browserOpenResult.error,
2592
2653
  verificationUriComplete: data.verification_uri_complete
2593
2654
  });
@@ -2604,7 +2665,7 @@ async function startDeviceCodeFlow(config) {
2604
2665
  };
2605
2666
  } catch (error) {
2606
2667
  if (error instanceof AxiosError) {
2607
- logger4.error("[Auth] Failed to start device code flow", {
2668
+ logger5.error("[Auth] Failed to start device code flow", {
2608
2669
  status: error.response?.status,
2609
2670
  data: error.response?.data
2610
2671
  });
@@ -2632,7 +2693,7 @@ async function pollDeviceCode(config, deviceCode) {
2632
2693
  }
2633
2694
  }
2634
2695
  );
2635
- logger4.info("[Auth] Authorization successful");
2696
+ logger5.info("[Auth] Authorization successful");
2636
2697
  return {
2637
2698
  status: "authorized",
2638
2699
  accessToken: response.data.access_token,
@@ -2671,7 +2732,7 @@ async function pollDeviceCode(config, deviceCode) {
2671
2732
  errorDescription: data.error_description || "User denied access"
2672
2733
  };
2673
2734
  }
2674
- logger4.error("[Auth] Unexpected error during poll", {
2735
+ logger5.error("[Auth] Unexpected error during poll", {
2675
2736
  status: error.response.status,
2676
2737
  error: errorCode,
2677
2738
  description: data.error_description
@@ -2688,7 +2749,7 @@ async function createApiKeyWithToken(accessToken, keyName, expiry = "90d") {
2688
2749
  const config = getConfig();
2689
2750
  const apiKeyUrl = `${config.e2e.promptServiceBaseUrl}/v1/protected/api-keys`;
2690
2751
  try {
2691
- logger4.info("[Auth] Creating API key", {
2752
+ logger5.info("[Auth] Creating API key", {
2692
2753
  keyName,
2693
2754
  expiry
2694
2755
  });
@@ -2705,13 +2766,13 @@ async function createApiKeyWithToken(accessToken, keyName, expiry = "90d") {
2705
2766
  }
2706
2767
  }
2707
2768
  );
2708
- logger4.info("[Auth] API key created successfully", {
2769
+ logger5.info("[Auth] API key created successfully", {
2709
2770
  keyId: response.data.id
2710
2771
  });
2711
2772
  return response.data;
2712
2773
  } catch (error) {
2713
2774
  if (error instanceof AxiosError) {
2714
- logger4.error("[Auth] Failed to create API key", {
2775
+ logger5.error("[Auth] Failed to create API key", {
2715
2776
  status: error.response?.status,
2716
2777
  data: error.response?.data
2717
2778
  });
@@ -2751,7 +2812,7 @@ async function performLogin(keyName, keyExpiry = "90d", timeoutMs = 12e4) {
2751
2812
  userId: storedAuth?.userId
2752
2813
  };
2753
2814
  if (keyName && storedAuth?.accessToken) {
2754
- logger4.info("[Auth] Creating API key as explicitly requested", {
2815
+ logger5.info("[Auth] Creating API key as explicitly requested", {
2755
2816
  keyName
2756
2817
  });
2757
2818
  const apiKeyResult = await createApiKeyWithToken(
@@ -2799,7 +2860,7 @@ function performLogout() {
2799
2860
  const authService = getAuthService();
2800
2861
  authService.logout();
2801
2862
  deleteApiKeyData();
2802
- logger4.info("[Auth] Logged out successfully");
2863
+ logger5.info("[Auth] Logged out successfully");
2803
2864
  }
2804
2865
  function getCallerCredentials() {
2805
2866
  const apiKeyData = getValidApiKeyData();
@@ -2879,6 +2940,34 @@ function toolRequiresAuth(toolName) {
2879
2940
  ];
2880
2941
  return !noAuthTools.includes(toolName);
2881
2942
  }
2943
+
2944
+ // packages/mcps/src/mcp/index.ts
2945
+ var mcp_exports = {};
2946
+ __export(mcp_exports, {
2947
+ agents: () => agents_exports,
2948
+ e2e: () => e2e_exports2,
2949
+ localQa: () => local_exports2,
2950
+ plugins: () => plugins_exports,
2951
+ qa: () => e2e_exports2,
2952
+ skills: () => skills_exports,
2953
+ tools: () => tools_exports
2954
+ });
2955
+
2956
+ // packages/mcps/src/mcp/tools/index.ts
2957
+ var tools_exports = {};
2958
+ __export(tools_exports, {
2959
+ e2e: () => e2e_exports,
2960
+ localQa: () => local_exports,
2961
+ qa: () => e2e_exports
2962
+ });
2963
+
2964
+ // packages/mcps/src/mcp/tools/e2e/index.ts
2965
+ var e2e_exports = {};
2966
+ __export(e2e_exports, {
2967
+ allQaToolDefinitions: () => allQaToolDefinitions,
2968
+ executeQaTool: () => executeQaTool,
2969
+ getQaToolByName: () => getQaToolByName
2970
+ });
2882
2971
  var MuggleEntityIdSchema = z.string().uuid();
2883
2972
  var LocalExecutionContextInputSchema = z.object({
2884
2973
  originalUrl: z.string().url().describe("Original local URL used during local execution (typically localhost)"),
@@ -3251,7 +3340,8 @@ var ApiKeyRevokeInputSchema = z.object({
3251
3340
  });
3252
3341
  var AuthLoginInputSchema = z.object({
3253
3342
  waitForCompletion: z.boolean().optional().describe("Whether to wait for browser login completion before returning. Default: true"),
3254
- timeoutMs: z.number().int().positive().min(1e3).max(9e5).optional().describe("Maximum time to wait for login completion in milliseconds. Default: 120000")
3343
+ timeoutMs: z.number().int().positive().min(1e3).max(9e5).optional().describe("Maximum time to wait for login completion in milliseconds. Default: 120000"),
3344
+ forceNewSession: z.boolean().optional().describe("Force a fresh login by clearing any existing Auth0 browser session before redirecting to the device activation page. Use this to switch accounts. Default: false")
3255
3345
  });
3256
3346
  var AuthPollInputSchema = z.object({
3257
3347
  deviceCode: z.string().optional().describe("Device code from the login response. Optional if a login was recently started.")
@@ -3363,17 +3453,17 @@ var PromptServiceClient = class {
3363
3453
  * @param path - Path to validate.
3364
3454
  * @throws GatewayError if path is not allowed.
3365
3455
  */
3366
- validatePath(path15) {
3367
- const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path15.startsWith(prefix));
3456
+ validatePath(path10) {
3457
+ const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path10.startsWith(prefix));
3368
3458
  if (!isAllowed) {
3369
- const logger14 = getLogger();
3370
- logger14.error("Path not in allowlist", {
3371
- path: path15,
3459
+ const logger6 = getLogger();
3460
+ logger6.error("Path not in allowlist", {
3461
+ path: path10,
3372
3462
  allowedPrefixes: ALLOWED_UPSTREAM_PREFIXES
3373
3463
  });
3374
3464
  throw new GatewayError({
3375
3465
  code: "FORBIDDEN" /* FORBIDDEN */,
3376
- message: `Path '${path15}' is not allowed`
3466
+ message: `Path '${path10}' is not allowed`
3377
3467
  });
3378
3468
  }
3379
3469
  }
@@ -3482,7 +3572,7 @@ var PromptServiceClient = class {
3482
3572
  * @throws GatewayError on validation or upstream errors.
3483
3573
  */
3484
3574
  async execute(call, credentials, correlationId) {
3485
- const logger14 = getLogger();
3575
+ const logger6 = getLogger();
3486
3576
  if (!credentials.bearerToken && !credentials.apiKey) {
3487
3577
  throw new GatewayError({
3488
3578
  code: "UNAUTHORIZED" /* UNAUTHORIZED */,
@@ -3494,7 +3584,7 @@ var PromptServiceClient = class {
3494
3584
  const headers = this.buildHeaders(credentials, correlationId);
3495
3585
  const timeout = call.timeoutMs || this.requestTimeoutMs;
3496
3586
  const startTime = Date.now();
3497
- logger14.info("Upstream request", {
3587
+ logger6.info("Upstream request", {
3498
3588
  correlationId,
3499
3589
  method: call.method,
3500
3590
  path: call.path,
@@ -3521,7 +3611,7 @@ var PromptServiceClient = class {
3521
3611
  }
3522
3612
  const response = await this.httpClient.request(requestConfig);
3523
3613
  const latency = Date.now() - startTime;
3524
- logger14.info("Upstream response", {
3614
+ logger6.info("Upstream response", {
3525
3615
  correlationId,
3526
3616
  statusCode: response.status,
3527
3617
  latencyMs: latency
@@ -3552,7 +3642,7 @@ var PromptServiceClient = class {
3552
3642
  throw error;
3553
3643
  }
3554
3644
  if (error instanceof AxiosError) {
3555
- logger14.error("Upstream request failed", {
3645
+ logger6.error("Upstream request failed", {
3556
3646
  correlationId,
3557
3647
  error: error.message,
3558
3648
  code: error.code,
@@ -3571,7 +3661,7 @@ var PromptServiceClient = class {
3571
3661
  details: { upstreamPath: call.path }
3572
3662
  });
3573
3663
  }
3574
- logger14.error("Unknown upstream error", {
3664
+ logger6.error("Unknown upstream error", {
3575
3665
  correlationId,
3576
3666
  error: String(error),
3577
3667
  latencyMs: latency
@@ -4880,7 +4970,9 @@ var authTools = [
4880
4970
  localHandler: async (input) => {
4881
4971
  const data = input;
4882
4972
  const authService = getAuthService();
4883
- const deviceCodeResponse = await authService.startDeviceCodeFlow();
4973
+ const deviceCodeResponse = await authService.startDeviceCodeFlow({
4974
+ forceNewSession: data.forceNewSession
4975
+ });
4884
4976
  const waitForCompletion = data.waitForCompletion ?? true;
4885
4977
  if (!waitForCompletion) {
4886
4978
  return {
@@ -4985,7 +5077,7 @@ function defaultResponseMapper(response) {
4985
5077
  return response.data;
4986
5078
  }
4987
5079
  async function executeQaTool(toolName, input, correlationId) {
4988
- const logger14 = createChildLogger(correlationId);
5080
+ const logger6 = createChildLogger(correlationId);
4989
5081
  const tool = getQaToolByName(toolName);
4990
5082
  if (!tool) {
4991
5083
  return {
@@ -5026,7 +5118,7 @@ async function executeQaTool(toolName, input, correlationId) {
5026
5118
  }
5027
5119
  } catch (error) {
5028
5120
  if (error instanceof GatewayError) {
5029
- logger14.warn("Tool call failed with gateway error", {
5121
+ logger6.warn("Tool call failed with gateway error", {
5030
5122
  tool: toolName,
5031
5123
  code: error.code,
5032
5124
  message: error.message
@@ -5037,7 +5129,7 @@ async function executeQaTool(toolName, input, correlationId) {
5037
5129
  };
5038
5130
  }
5039
5131
  const errorMessage = error instanceof Error ? error.message : String(error);
5040
- logger14.error("Tool call failed", { tool: toolName, error: errorMessage });
5132
+ logger6.error("Tool call failed", { tool: toolName, error: errorMessage });
5041
5133
  return {
5042
5134
  content: JSON.stringify({ error: "INTERNAL_ERROR", message: errorMessage }),
5043
5135
  isError: true
@@ -5045,82 +5137,12 @@ async function executeQaTool(toolName, input, correlationId) {
5045
5137
  }
5046
5138
  }
5047
5139
 
5048
- // packages/mcps/src/mcp/tools/e2e/index.ts
5049
- var e2e_exports = {};
5050
- __export(e2e_exports, {
5051
- allQaToolDefinitions: () => allQaToolDefinitions,
5052
- executeQaTool: () => executeQaTool,
5053
- getQaToolByName: () => getQaToolByName
5054
- });
5055
-
5056
- // packages/mcps/src/mcp/e2e/index.ts
5057
- function getQaTools() {
5058
- return allQaToolDefinitions.map((tool) => ({
5059
- name: tool.name,
5060
- description: tool.description,
5061
- inputSchema: tool.inputSchema,
5062
- requiresAuth: tool.requiresAuth !== false,
5063
- execute: async (params) => {
5064
- return executeQaTool(tool.name, params.input, params.correlationId);
5065
- }
5066
- }));
5067
- }
5068
-
5069
- // packages/mcps/src/mcp/local/index.ts
5070
- var local_exports2 = {};
5071
- __export(local_exports2, {
5072
- AuthLoginInputSchema: () => AuthLoginInputSchema2,
5073
- AuthPollInputSchema: () => AuthPollInputSchema2,
5074
- AuthService: () => AuthService,
5075
- CancelExecutionInputSchema: () => CancelExecutionInputSchema,
5076
- CleanupSessionsInputSchema: () => CleanupSessionsInputSchema,
5077
- CloudMappingEntityType: () => CloudMappingEntityType,
5078
- DeviceCodePollStatus: () => DeviceCodePollStatus,
5079
- EmptyInputSchema: () => EmptyInputSchema2,
5080
- ExecuteReplayInputSchema: () => ExecuteReplayInputSchema,
5081
- ExecuteTestGenerationInputSchema: () => ExecuteTestGenerationInputSchema,
5082
- ExecutionStatus: () => ExecutionStatus,
5083
- HealthStatus: () => HealthStatus,
5084
- ListSessionsInputSchema: () => ListSessionsInputSchema,
5085
- LocalRunStatus: () => LocalRunStatus,
5086
- LocalRunType: () => LocalRunType,
5087
- LocalTestScriptStatus: () => LocalTestScriptStatus,
5088
- LocalWorkflowFileEntityType: () => LocalWorkflowFileEntityType,
5089
- LocalWorkflowRunStatus: () => LocalWorkflowRunStatus,
5090
- MuggleEntityIdSchema: () => MuggleEntityIdSchema,
5091
- PublishTestScriptInputSchema: () => PublishTestScriptInputSchema,
5092
- RunResultGetInputSchema: () => RunResultGetInputSchema,
5093
- RunResultListInputSchema: () => RunResultListInputSchema,
5094
- RunResultStorageService: () => RunResultStorageService,
5095
- SessionStatus: () => SessionStatus,
5096
- StorageService: () => StorageService,
5097
- TestCaseDetailsSchema: () => TestCaseDetailsSchema,
5098
- TestResultStatus: () => TestResultStatus,
5099
- TestScriptDetailsSchema: () => TestScriptDetailsSchema,
5100
- TestScriptGetInputSchema: () => TestScriptGetInputSchema2,
5101
- TestScriptListInputSchema: () => TestScriptListInputSchema2,
5102
- allLocalQaTools: () => allLocalQaTools,
5103
- cancelExecution: () => cancelExecution,
5104
- executeReplay: () => executeReplay,
5105
- executeTestGeneration: () => executeTestGeneration,
5106
- executeTool: () => executeTool,
5107
- getAuthService: () => getAuthService,
5108
- getLocalQaTools: () => getLocalQaTools,
5109
- getRunResultStorageService: () => getRunResultStorageService,
5110
- getStorageService: () => getStorageService,
5111
- getTool: () => getTool,
5112
- listActiveExecutions: () => listActiveExecutions,
5113
- resetAuthService: () => resetAuthService,
5114
- resetRunResultStorageService: () => resetRunResultStorageService,
5115
- resetStorageService: () => resetStorageService
5116
- });
5117
-
5118
- // packages/mcps/src/mcp/tools/local/index.ts
5119
- var local_exports = {};
5120
- __export(local_exports, {
5121
- allLocalQaTools: () => allLocalQaTools,
5122
- executeTool: () => executeTool,
5123
- getTool: () => getTool
5140
+ // packages/mcps/src/mcp/tools/local/index.ts
5141
+ var local_exports = {};
5142
+ __export(local_exports, {
5143
+ allLocalQaTools: () => allLocalQaTools,
5144
+ executeTool: () => executeTool,
5145
+ getTool: () => getTool
5124
5146
  });
5125
5147
  var AuthLoginInputSchema2 = z.object({
5126
5148
  waitForCompletion: z.boolean().optional().describe("Whether to wait for browser login completion before returning. Default: true"),
@@ -5173,12 +5195,10 @@ var ExecuteTestGenerationInputSchema = z.object({
5173
5195
  testCase: TestCaseDetailsSchema.describe("Test case details obtained from muggle-remote-test-case-get"),
5174
5196
  /** Local URL to test against. */
5175
5197
  localUrl: z.string().url().describe("Local URL to test against (e.g., http://localhost:3000)"),
5176
- /** Explicit approval to launch electron-app. */
5177
- approveElectronAppLaunch: z.boolean().describe("Set to true after the user explicitly approves launching electron-app"),
5178
5198
  /** Optional timeout. */
5179
5199
  timeoutMs: z.number().int().positive().optional().describe("Timeout in milliseconds (default: 300000 = 5 min)"),
5180
- /** Show the electron-app UI during execution. Ask the user before approving; true = visible window, false or omit = headless. */
5181
- 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.")
5200
+ /** Show the electron-app UI during execution. Default: visible window. Pass false to run headless. */
5201
+ showUi: z.boolean().optional().describe("Show the electron-app UI during generation. Defaults to visible; pass false to run headless.")
5182
5202
  });
5183
5203
  var ExecuteReplayInputSchema = z.object({
5184
5204
  /** Test script metadata from muggle-remote-test-script-get. */
@@ -5187,12 +5207,10 @@ var ExecuteReplayInputSchema = z.object({
5187
5207
  actionScript: z.array(z.unknown()).describe("Action script steps from muggle-remote-action-script-get"),
5188
5208
  /** Local URL to test against. */
5189
5209
  localUrl: z.string().url().describe("Local URL to test against (e.g., http://localhost:3000)"),
5190
- /** Explicit approval to launch electron-app. */
5191
- approveElectronAppLaunch: z.boolean().describe("Set to true after the user explicitly approves launching electron-app"),
5192
5210
  /** Optional timeout. */
5193
5211
  timeoutMs: z.number().int().positive().optional().describe("Timeout in milliseconds (default: 180000 = 3 min)"),
5194
- /** Show the electron-app UI during execution. Ask the user before approving; true = visible window, false or omit = headless. */
5195
- 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.")
5212
+ /** Show the electron-app UI during execution. Default: visible window. Pass false to run headless. */
5213
+ showUi: z.boolean().optional().describe("Show the electron-app UI during replay. Defaults to visible; pass false to run headless.")
5196
5214
  });
5197
5215
  var CancelExecutionInputSchema = z.object({
5198
5216
  runId: MuggleEntityIdSchema.describe("Run ID (UUID) to cancel")
@@ -5223,12 +5241,12 @@ var CleanupSessionsInputSchema = z.object({
5223
5241
 
5224
5242
  // packages/mcps/src/mcp/tools/local/tool-registry.ts
5225
5243
  function createChildLogger2(correlationId) {
5226
- const logger14 = getLogger();
5244
+ const logger6 = getLogger();
5227
5245
  return {
5228
- info: (msg, meta) => logger14.info(msg, { ...meta, correlationId }),
5229
- error: (msg, meta) => logger14.error(msg, { ...meta, correlationId }),
5230
- warn: (msg, meta) => logger14.warn(msg, { ...meta, correlationId }),
5231
- debug: (msg, meta) => logger14.debug(msg, { ...meta, correlationId })
5246
+ info: (msg, meta) => logger6.info(msg, { ...meta, correlationId }),
5247
+ error: (msg, meta) => logger6.error(msg, { ...meta, correlationId }),
5248
+ warn: (msg, meta) => logger6.warn(msg, { ...meta, correlationId }),
5249
+ debug: (msg, meta) => logger6.debug(msg, { ...meta, correlationId })
5232
5250
  };
5233
5251
  }
5234
5252
  var checkStatusTool = {
@@ -5236,8 +5254,8 @@ var checkStatusTool = {
5236
5254
  description: "Check the status of Muggle Test Local. This verifies the connection to web-service and shows current session information.",
5237
5255
  inputSchema: EmptyInputSchema2,
5238
5256
  execute: async (ctx) => {
5239
- const logger14 = createChildLogger2(ctx.correlationId);
5240
- logger14.info("Executing muggle-local-check-status");
5257
+ const logger6 = createChildLogger2(ctx.correlationId);
5258
+ logger6.info("Executing muggle-local-check-status");
5241
5259
  const authService = getAuthService();
5242
5260
  const storageService = getStorageService();
5243
5261
  const authStatus = authService.getAuthStatus();
@@ -5260,8 +5278,8 @@ var listSessionsTool = {
5260
5278
  description: "List all stored testing sessions. Shows session IDs, status, and metadata for each session.",
5261
5279
  inputSchema: ListSessionsInputSchema,
5262
5280
  execute: async (ctx) => {
5263
- const logger14 = createChildLogger2(ctx.correlationId);
5264
- logger14.info("Executing muggle-local-list-sessions");
5281
+ const logger6 = createChildLogger2(ctx.correlationId);
5282
+ logger6.info("Executing muggle-local-list-sessions");
5265
5283
  const input = ListSessionsInputSchema.parse(ctx.input);
5266
5284
  const storageService = getStorageService();
5267
5285
  const sessions = storageService.listSessionsWithMetadata();
@@ -5288,8 +5306,8 @@ var runResultListTool = {
5288
5306
  description: "List run results (test generation and replay history), optionally filtered by cloud test case ID.",
5289
5307
  inputSchema: RunResultListInputSchema,
5290
5308
  execute: async (ctx) => {
5291
- const logger14 = createChildLogger2(ctx.correlationId);
5292
- logger14.info("Executing muggle-local-run-result-list");
5309
+ const logger6 = createChildLogger2(ctx.correlationId);
5310
+ logger6.info("Executing muggle-local-run-result-list");
5293
5311
  const input = RunResultListInputSchema.parse(ctx.input);
5294
5312
  const storage = getRunResultStorageService();
5295
5313
  let results = storage.listRunResults();
@@ -5313,8 +5331,8 @@ var runResultGetTool = {
5313
5331
  description: "Get detailed information about a run result including screenshots and action script output.",
5314
5332
  inputSchema: RunResultGetInputSchema,
5315
5333
  execute: async (ctx) => {
5316
- const logger14 = createChildLogger2(ctx.correlationId);
5317
- logger14.info("Executing muggle-local-run-result-get");
5334
+ const logger6 = createChildLogger2(ctx.correlationId);
5335
+ logger6.info("Executing muggle-local-run-result-get");
5318
5336
  const input = RunResultGetInputSchema.parse(ctx.input);
5319
5337
  const storage = getRunResultStorageService();
5320
5338
  const result = storage.getRunResult(input.runId);
@@ -5336,7 +5354,7 @@ var runResultGetTool = {
5336
5354
  const testScript = storage.getTestScript(result.testScriptId);
5337
5355
  testScriptSteps = testScript?.actionScript?.length;
5338
5356
  }
5339
- if (result.artifactsDir && fs3.existsSync(result.artifactsDir)) {
5357
+ if (result.artifactsDir && fs5.existsSync(result.artifactsDir)) {
5340
5358
  contentParts.push(
5341
5359
  "",
5342
5360
  "### Artifacts (view action script + screenshots)",
@@ -5350,20 +5368,20 @@ var runResultGetTool = {
5350
5368
  const stdoutLogPath = path2.join(result.artifactsDir, "stdout.log");
5351
5369
  const stderrLogPath = path2.join(result.artifactsDir, "stderr.log");
5352
5370
  const artifactItems = [];
5353
- if (fs3.existsSync(actionScriptPath)) {
5371
+ if (fs5.existsSync(actionScriptPath)) {
5354
5372
  artifactItems.push("- `action-script.json` \u2014 generated test steps");
5355
5373
  }
5356
- if (fs3.existsSync(resultsMdPath)) {
5374
+ if (fs5.existsSync(resultsMdPath)) {
5357
5375
  artifactItems.push("- `results.md` \u2014 step-by-step report with screenshot links");
5358
5376
  }
5359
- if (fs3.existsSync(screenshotsDir)) {
5360
- const screenshots = fs3.readdirSync(screenshotsDir).filter((f) => /\.(png|jpg|jpeg|webp)$/i.test(f));
5377
+ if (fs5.existsSync(screenshotsDir)) {
5378
+ const screenshots = fs5.readdirSync(screenshotsDir).filter((f) => /\.(png|jpg|jpeg|webp)$/i.test(f));
5361
5379
  artifactItems.push(`- \`screenshots/\` \u2014 ${screenshots.length} image(s)`);
5362
5380
  }
5363
- if (fs3.existsSync(stdoutLogPath)) {
5381
+ if (fs5.existsSync(stdoutLogPath)) {
5364
5382
  artifactItems.push("- `stdout.log` \u2014 electron-app stdout output");
5365
5383
  }
5366
- if (fs3.existsSync(stderrLogPath)) {
5384
+ if (fs5.existsSync(stderrLogPath)) {
5367
5385
  artifactItems.push("- `stderr.log` \u2014 electron-app stderr output");
5368
5386
  }
5369
5387
  if (artifactItems.length > 0) {
@@ -5388,8 +5406,8 @@ var testScriptListTool = {
5388
5406
  description: "List locally generated test scripts, optionally filtered by cloud test case ID.",
5389
5407
  inputSchema: TestScriptListInputSchema2,
5390
5408
  execute: async (ctx) => {
5391
- const logger14 = createChildLogger2(ctx.correlationId);
5392
- logger14.info("Executing muggle-local-test-script-list");
5409
+ const logger6 = createChildLogger2(ctx.correlationId);
5410
+ logger6.info("Executing muggle-local-test-script-list");
5393
5411
  const input = TestScriptListInputSchema2.parse(ctx.input);
5394
5412
  const storage = getRunResultStorageService();
5395
5413
  let scripts = storage.listTestScripts();
@@ -5409,8 +5427,8 @@ var testScriptGetTool = {
5409
5427
  description: "Get details of a locally generated test script including action script steps.",
5410
5428
  inputSchema: TestScriptGetInputSchema2,
5411
5429
  execute: async (ctx) => {
5412
- const logger14 = createChildLogger2(ctx.correlationId);
5413
- logger14.info("Executing muggle-local-test-script-get");
5430
+ const logger6 = createChildLogger2(ctx.correlationId);
5431
+ logger6.info("Executing muggle-local-test-script-get");
5414
5432
  const input = TestScriptGetInputSchema2.parse(ctx.input);
5415
5433
  const storage = getRunResultStorageService();
5416
5434
  const testScript = storage.getTestScript(input.testScriptId);
@@ -5432,38 +5450,13 @@ var testScriptGetTool = {
5432
5450
  };
5433
5451
  var executeTestGenerationTool = {
5434
5452
  name: "muggle-local-execute-test-generation",
5435
- 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).",
5453
+ 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 defaults to a visible window; pass showUi: false to run headless.",
5436
5454
  inputSchema: ExecuteTestGenerationInputSchema,
5437
5455
  execute: async (ctx) => {
5438
- const logger14 = createChildLogger2(ctx.correlationId);
5439
- logger14.info("Executing muggle-local-execute-test-generation");
5456
+ const logger6 = createChildLogger2(ctx.correlationId);
5457
+ logger6.info("Executing muggle-local-execute-test-generation");
5440
5458
  const input = ExecuteTestGenerationInputSchema.parse(ctx.input);
5441
- if (!input.approveElectronAppLaunch) {
5442
- const showUiExplicit = input.showUi !== void 0;
5443
- const uiMode = input.showUi === true ? "visible GUI (showUi: true)" : "headless (showUi: false or omitted)";
5444
- return {
5445
- content: [
5446
- "## Electron App Launch Required",
5447
- "",
5448
- "This tool will launch the electron-app to generate a test script.",
5449
- "Please set `approveElectronAppLaunch: true` to proceed.",
5450
- "",
5451
- "**Visible GUI:** Ask the user whether they want to watch the Electron window during generation.",
5452
- "- If **yes** \u2192 when approving, pass `showUi: true`.",
5453
- "- If **no** \u2192 when approving, pass `showUi: false` (or omit `showUi`; generation runs headless).",
5454
- "",
5455
- showUiExplicit ? `**Current choice:** ${uiMode}` : "**Current choice:** not set \u2014 default on approval is headless unless you pass `showUi: true`.",
5456
- "",
5457
- `**Test Case:** ${input.testCase.title}`,
5458
- `**Local URL:** ${input.localUrl}`,
5459
- "",
5460
- "**Note:** The electron-app will navigate your test URL and record steps."
5461
- ].join("\n"),
5462
- isError: false,
5463
- data: { requiresApproval: true }
5464
- };
5465
- }
5466
- const showUi = input.showUi === true;
5459
+ const showUi = input.showUi !== false;
5467
5460
  try {
5468
5461
  const result = await executeTestGeneration({
5469
5462
  testCase: input.testCase,
@@ -5488,46 +5481,20 @@ var executeTestGenerationTool = {
5488
5481
  };
5489
5482
  } catch (error) {
5490
5483
  const errorMessage = error instanceof Error ? error.message : String(error);
5491
- logger14.error("Test generation failed", { error: errorMessage });
5484
+ logger6.error("Test generation failed", { error: errorMessage });
5492
5485
  return { content: `Test generation failed: ${errorMessage}`, isError: true };
5493
5486
  }
5494
5487
  }
5495
5488
  };
5496
5489
  var executeReplayTool = {
5497
5490
  name: "muggle-local-execute-replay",
5498
- 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).",
5491
+ 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 defaults to a visible window; pass showUi: false to run headless.",
5499
5492
  inputSchema: ExecuteReplayInputSchema,
5500
5493
  execute: async (ctx) => {
5501
- const logger14 = createChildLogger2(ctx.correlationId);
5502
- logger14.info("Executing muggle-local-execute-replay");
5494
+ const logger6 = createChildLogger2(ctx.correlationId);
5495
+ logger6.info("Executing muggle-local-execute-replay");
5503
5496
  const input = ExecuteReplayInputSchema.parse(ctx.input);
5504
- if (!input.approveElectronAppLaunch) {
5505
- const showUiExplicit = input.showUi !== void 0;
5506
- const uiMode = input.showUi === true ? "visible GUI (showUi: true)" : "headless (showUi: false or omitted)";
5507
- return {
5508
- content: [
5509
- "## Electron App Launch Required",
5510
- "",
5511
- "This tool will launch the electron-app to replay a test script.",
5512
- "Please set `approveElectronAppLaunch: true` to proceed.",
5513
- "",
5514
- "**Visible GUI:** Ask the user whether they want to watch the Electron window during replay.",
5515
- "- If **yes** \u2192 when approving, pass `showUi: true`.",
5516
- "- If **no** \u2192 when approving, pass `showUi: false` (or omit `showUi`; replay runs headless).",
5517
- "",
5518
- showUiExplicit ? `**Current choice:** ${uiMode}` : "**Current choice:** not set \u2014 default on approval is headless unless you pass `showUi: true`.",
5519
- "",
5520
- `**Test Script:** ${input.testScript.name}`,
5521
- `**Local URL:** ${input.localUrl}`,
5522
- `**Steps:** ${input.actionScript.length}`,
5523
- "",
5524
- "**Note:** The electron-app will execute the test steps against your local URL."
5525
- ].join("\n"),
5526
- isError: false,
5527
- data: { requiresApproval: true }
5528
- };
5529
- }
5530
- const showUi = input.showUi === true;
5497
+ const showUi = input.showUi !== false;
5531
5498
  try {
5532
5499
  const result = await executeReplay({
5533
5500
  testScript: input.testScript,
@@ -5553,7 +5520,7 @@ var executeReplayTool = {
5553
5520
  };
5554
5521
  } catch (error) {
5555
5522
  const errorMessage = error instanceof Error ? error.message : String(error);
5556
- logger14.error("Test replay failed", { error: errorMessage });
5523
+ logger6.error("Test replay failed", { error: errorMessage });
5557
5524
  return { content: `Test replay failed: ${errorMessage}`, isError: true };
5558
5525
  }
5559
5526
  }
@@ -5563,8 +5530,8 @@ var cancelExecutionTool = {
5563
5530
  description: "Cancel an active test generation or replay execution.",
5564
5531
  inputSchema: CancelExecutionInputSchema,
5565
5532
  execute: async (ctx) => {
5566
- const logger14 = createChildLogger2(ctx.correlationId);
5567
- logger14.info("Executing muggle-local-cancel-execution");
5533
+ const logger6 = createChildLogger2(ctx.correlationId);
5534
+ logger6.info("Executing muggle-local-cancel-execution");
5568
5535
  const input = CancelExecutionInputSchema.parse(ctx.input);
5569
5536
  const cancelled = cancelExecution({ runId: input.runId });
5570
5537
  if (cancelled) {
@@ -5578,8 +5545,8 @@ var publishTestScriptTool = {
5578
5545
  description: "Publish a locally generated test script to the cloud. Uses the run ID from muggle_execute_test_generation to find the script and uploads it to the specified cloud test case. Returns a viewUrl that can be opened in the user's browser to view the published test script on the dashboard.",
5579
5546
  inputSchema: PublishTestScriptInputSchema,
5580
5547
  execute: async (ctx) => {
5581
- const logger14 = createChildLogger2(ctx.correlationId);
5582
- logger14.info("Executing muggle-local-publish-test-script");
5548
+ const logger6 = createChildLogger2(ctx.correlationId);
5549
+ logger6.info("Executing muggle-local-publish-test-script");
5583
5550
  const input = PublishTestScriptInputSchema.parse(ctx.input);
5584
5551
  const storage = getRunResultStorageService();
5585
5552
  const runResult = storage.getRunResult(input.runId);
@@ -5698,7 +5665,7 @@ var publishTestScriptTool = {
5698
5665
  };
5699
5666
  } catch (error) {
5700
5667
  const errorMessage = error instanceof Error ? error.message : String(error);
5701
- logger14.error("Failed to publish local test script to cloud", {
5668
+ logger6.error("Failed to publish local test script to cloud", {
5702
5669
  runId: input.runId,
5703
5670
  cloudTestCaseId: input.cloudTestCaseId,
5704
5671
  error: errorMessage
@@ -5744,7 +5711,161 @@ async function executeTool(name, input, correlationId) {
5744
5711
  return tool.execute({ input, correlationId });
5745
5712
  }
5746
5713
 
5714
+ // packages/mcps/src/mcp/e2e/index.ts
5715
+ var e2e_exports2 = {};
5716
+ __export(e2e_exports2, {
5717
+ ActionScriptGetInputSchema: () => ActionScriptGetInputSchema,
5718
+ ApiKeyCreateInputSchema: () => ApiKeyCreateInputSchema,
5719
+ ApiKeyGetInputSchema: () => ApiKeyGetInputSchema,
5720
+ ApiKeyListInputSchema: () => ApiKeyListInputSchema,
5721
+ ApiKeyRecordIdSchema: () => ApiKeyRecordIdSchema,
5722
+ ApiKeyRevokeInputSchema: () => ApiKeyRevokeInputSchema,
5723
+ AuthLoginInputSchema: () => AuthLoginInputSchema,
5724
+ AuthPollInputSchema: () => AuthPollInputSchema,
5725
+ BulkPreviewJobCancelInputSchema: () => BulkPreviewJobCancelInputSchema,
5726
+ BulkPreviewJobGetInputSchema: () => BulkPreviewJobGetInputSchema,
5727
+ BulkPreviewJobKindSchema: () => BulkPreviewJobKindSchema,
5728
+ BulkPreviewJobListInputSchema: () => BulkPreviewJobListInputSchema,
5729
+ BulkPreviewJobStatusSchema: () => BulkPreviewJobStatusSchema,
5730
+ BulkPreviewPromptSchema: () => BulkPreviewPromptSchema,
5731
+ BulkPreviewSubmitTestCaseInputSchema: () => BulkPreviewSubmitTestCaseInputSchema,
5732
+ BulkPreviewSubmitUseCaseInputSchema: () => BulkPreviewSubmitUseCaseInputSchema,
5733
+ EmptyInputSchema: () => EmptyInputSchema,
5734
+ GatewayError: () => GatewayError,
5735
+ IdSchema: () => IdSchema,
5736
+ LocalExecutionContextInputSchema: () => LocalExecutionContextInputSchema,
5737
+ LocalRunUploadInputSchema: () => LocalRunUploadInputSchema,
5738
+ McpErrorCode: () => McpErrorCode,
5739
+ MuggleEntityIdSchema: () => MuggleEntityIdSchema,
5740
+ PaginationInputSchema: () => PaginationInputSchema,
5741
+ PrdFileDeleteInputSchema: () => PrdFileDeleteInputSchema,
5742
+ PrdFileListInputSchema: () => PrdFileListInputSchema,
5743
+ PrdFileProcessLatestRunInputSchema: () => PrdFileProcessLatestRunInputSchema,
5744
+ PrdFileProcessStartInputSchema: () => PrdFileProcessStartInputSchema,
5745
+ PrdFileUploadInputSchema: () => PrdFileUploadInputSchema,
5746
+ ProjectCreateInputSchema: () => ProjectCreateInputSchema,
5747
+ ProjectDeleteInputSchema: () => ProjectDeleteInputSchema,
5748
+ ProjectGetInputSchema: () => ProjectGetInputSchema,
5749
+ ProjectListInputSchema: () => ProjectListInputSchema,
5750
+ ProjectTestResultsSummaryInputSchema: () => ProjectTestResultsSummaryInputSchema,
5751
+ ProjectTestRunsSummaryInputSchema: () => ProjectTestRunsSummaryInputSchema,
5752
+ ProjectTestScriptsSummaryInputSchema: () => ProjectTestScriptsSummaryInputSchema,
5753
+ ProjectUpdateInputSchema: () => ProjectUpdateInputSchema,
5754
+ PromptServiceClient: () => PromptServiceClient,
5755
+ RecommendCicdSetupInputSchema: () => RecommendCicdSetupInputSchema,
5756
+ RecommendScheduleInputSchema: () => RecommendScheduleInputSchema,
5757
+ ReportCostQueryInputSchema: () => ReportCostQueryInputSchema,
5758
+ ReportFinalGenerateInputSchema: () => ReportFinalGenerateInputSchema,
5759
+ ReportPreferencesUpsertInputSchema: () => ReportPreferencesUpsertInputSchema,
5760
+ ReportStatsSummaryInputSchema: () => ReportStatsSummaryInputSchema,
5761
+ RunBatchIdSchema: () => RunBatchIdSchema,
5762
+ SecretCreateInputSchema: () => SecretCreateInputSchema,
5763
+ SecretDeleteInputSchema: () => SecretDeleteInputSchema,
5764
+ SecretGetInputSchema: () => SecretGetInputSchema,
5765
+ SecretListInputSchema: () => SecretListInputSchema,
5766
+ SecretUpdateInputSchema: () => SecretUpdateInputSchema,
5767
+ StripePaymentMethodIdSchema: () => StripePaymentMethodIdSchema,
5768
+ TestCaseCreateInputSchema: () => TestCaseCreateInputSchema,
5769
+ TestCaseGenerateFromPromptInputSchema: () => TestCaseGenerateFromPromptInputSchema,
5770
+ TestCaseGetInputSchema: () => TestCaseGetInputSchema,
5771
+ TestCaseListByUseCaseInputSchema: () => TestCaseListByUseCaseInputSchema,
5772
+ TestCaseListInputSchema: () => TestCaseListInputSchema,
5773
+ TestScriptGetInputSchema: () => TestScriptGetInputSchema,
5774
+ TestScriptListInputSchema: () => TestScriptListInputSchema,
5775
+ TokenPackageIdSchema: () => TokenPackageIdSchema,
5776
+ TokenUsageFilterTypeSchema: () => TokenUsageFilterTypeSchema,
5777
+ UseCaseCandidatesApproveInputSchema: () => UseCaseCandidatesApproveInputSchema,
5778
+ UseCaseCreateFromPromptsInputSchema: () => UseCaseCreateFromPromptsInputSchema,
5779
+ UseCaseCreateInputSchema: () => UseCaseCreateInputSchema,
5780
+ UseCaseDiscoveryMemoryGetInputSchema: () => UseCaseDiscoveryMemoryGetInputSchema,
5781
+ UseCaseGetInputSchema: () => UseCaseGetInputSchema,
5782
+ UseCaseListInputSchema: () => UseCaseListInputSchema,
5783
+ UseCasePromptPreviewInputSchema: () => UseCasePromptPreviewInputSchema,
5784
+ UseCaseUpdateFromPromptInputSchema: () => UseCaseUpdateFromPromptInputSchema,
5785
+ WalletAutoTopUpSetPaymentMethodInputSchema: () => WalletAutoTopUpSetPaymentMethodInputSchema,
5786
+ WalletAutoTopUpUpdateInputSchema: () => WalletAutoTopUpUpdateInputSchema,
5787
+ WalletPaymentMethodCreateSetupSessionInputSchema: () => WalletPaymentMethodCreateSetupSessionInputSchema,
5788
+ WalletPaymentMethodListInputSchema: () => WalletPaymentMethodListInputSchema,
5789
+ WalletTopUpInputSchema: () => WalletTopUpInputSchema,
5790
+ WorkflowCancelRunInputSchema: () => WorkflowCancelRunInputSchema,
5791
+ WorkflowCancelRuntimeInputSchema: () => WorkflowCancelRuntimeInputSchema,
5792
+ WorkflowGetLatestRunInputSchema: () => WorkflowGetLatestRunInputSchema,
5793
+ WorkflowGetLatestScriptGenByTestCaseInputSchema: () => WorkflowGetLatestScriptGenByTestCaseInputSchema,
5794
+ WorkflowGetReplayBulkBatchSummaryInputSchema: () => WorkflowGetReplayBulkBatchSummaryInputSchema,
5795
+ WorkflowListRuntimesInputSchema: () => WorkflowListRuntimesInputSchema,
5796
+ WorkflowMemoryParamsSchema: () => WorkflowMemoryParamsSchema,
5797
+ WorkflowParamsSchema: () => WorkflowParamsSchema,
5798
+ WorkflowStartTestCaseDetectionInputSchema: () => WorkflowStartTestCaseDetectionInputSchema,
5799
+ WorkflowStartTestScriptGenerationInputSchema: () => WorkflowStartTestScriptGenerationInputSchema,
5800
+ WorkflowStartTestScriptReplayBulkInputSchema: () => WorkflowStartTestScriptReplayBulkInputSchema,
5801
+ WorkflowStartTestScriptReplayInputSchema: () => WorkflowStartTestScriptReplayInputSchema,
5802
+ WorkflowStartWebsiteScanInputSchema: () => WorkflowStartWebsiteScanInputSchema,
5803
+ allQaToolDefinitions: () => allQaToolDefinitions,
5804
+ executeQaTool: () => executeQaTool,
5805
+ getPromptServiceClient: () => getPromptServiceClient,
5806
+ getQaToolByName: () => getQaToolByName,
5807
+ getQaTools: () => getQaTools
5808
+ });
5809
+ function getQaTools() {
5810
+ return allQaToolDefinitions.map((tool) => ({
5811
+ name: tool.name,
5812
+ description: tool.description,
5813
+ inputSchema: tool.inputSchema,
5814
+ requiresAuth: tool.requiresAuth !== false,
5815
+ execute: async (params) => {
5816
+ return executeQaTool(tool.name, params.input, params.correlationId);
5817
+ }
5818
+ }));
5819
+ }
5820
+
5747
5821
  // packages/mcps/src/mcp/local/index.ts
5822
+ var local_exports2 = {};
5823
+ __export(local_exports2, {
5824
+ AuthLoginInputSchema: () => AuthLoginInputSchema2,
5825
+ AuthPollInputSchema: () => AuthPollInputSchema2,
5826
+ AuthService: () => AuthService,
5827
+ CancelExecutionInputSchema: () => CancelExecutionInputSchema,
5828
+ CleanupSessionsInputSchema: () => CleanupSessionsInputSchema,
5829
+ CloudMappingEntityType: () => CloudMappingEntityType,
5830
+ DeviceCodePollStatus: () => DeviceCodePollStatus,
5831
+ EmptyInputSchema: () => EmptyInputSchema2,
5832
+ ExecuteReplayInputSchema: () => ExecuteReplayInputSchema,
5833
+ ExecuteTestGenerationInputSchema: () => ExecuteTestGenerationInputSchema,
5834
+ ExecutionStatus: () => ExecutionStatus,
5835
+ HealthStatus: () => HealthStatus,
5836
+ ListSessionsInputSchema: () => ListSessionsInputSchema,
5837
+ LocalRunStatus: () => LocalRunStatus,
5838
+ LocalRunType: () => LocalRunType,
5839
+ LocalTestScriptStatus: () => LocalTestScriptStatus,
5840
+ LocalWorkflowFileEntityType: () => LocalWorkflowFileEntityType,
5841
+ LocalWorkflowRunStatus: () => LocalWorkflowRunStatus,
5842
+ MuggleEntityIdSchema: () => MuggleEntityIdSchema,
5843
+ PublishTestScriptInputSchema: () => PublishTestScriptInputSchema,
5844
+ RunResultGetInputSchema: () => RunResultGetInputSchema,
5845
+ RunResultListInputSchema: () => RunResultListInputSchema,
5846
+ RunResultStorageService: () => RunResultStorageService,
5847
+ SessionStatus: () => SessionStatus,
5848
+ StorageService: () => StorageService,
5849
+ TestCaseDetailsSchema: () => TestCaseDetailsSchema,
5850
+ TestResultStatus: () => TestResultStatus,
5851
+ TestScriptDetailsSchema: () => TestScriptDetailsSchema,
5852
+ TestScriptGetInputSchema: () => TestScriptGetInputSchema2,
5853
+ TestScriptListInputSchema: () => TestScriptListInputSchema2,
5854
+ allLocalQaTools: () => allLocalQaTools,
5855
+ cancelExecution: () => cancelExecution,
5856
+ executeReplay: () => executeReplay,
5857
+ executeTestGeneration: () => executeTestGeneration,
5858
+ executeTool: () => executeTool,
5859
+ getAuthService: () => getAuthService,
5860
+ getLocalQaTools: () => getLocalQaTools,
5861
+ getRunResultStorageService: () => getRunResultStorageService,
5862
+ getStorageService: () => getStorageService,
5863
+ getTool: () => getTool,
5864
+ listActiveExecutions: () => listActiveExecutions,
5865
+ resetAuthService: () => resetAuthService,
5866
+ resetRunResultStorageService: () => resetRunResultStorageService,
5867
+ resetStorageService: () => resetStorageService
5868
+ });
5748
5869
  function getLocalQaTools() {
5749
5870
  return allLocalQaTools.map((tool) => ({
5750
5871
  name: tool.name,
@@ -5778,26 +5899,6 @@ function isLocalOnlyTool(toolName) {
5778
5899
  return localOnlyTools.includes(toolName);
5779
5900
  }
5780
5901
 
5781
- // packages/mcps/src/mcp/index.ts
5782
- var mcp_exports = {};
5783
- __export(mcp_exports, {
5784
- agents: () => agents_exports,
5785
- e2e: () => e2e_exports2,
5786
- localQa: () => local_exports2,
5787
- plugins: () => plugins_exports,
5788
- qa: () => e2e_exports2,
5789
- skills: () => skills_exports,
5790
- tools: () => tools_exports
5791
- });
5792
-
5793
- // packages/mcps/src/mcp/tools/index.ts
5794
- var tools_exports = {};
5795
- __export(tools_exports, {
5796
- e2e: () => e2e_exports,
5797
- localQa: () => local_exports,
5798
- qa: () => e2e_exports
5799
- });
5800
-
5801
5902
  // packages/mcps/src/mcp/skills/index.ts
5802
5903
  var skills_exports = {};
5803
5904
 
@@ -5807,2164 +5908,4 @@ var plugins_exports = {};
5807
5908
  // packages/mcps/src/mcp/agents/index.ts
5808
5909
  var agents_exports = {};
5809
5910
 
5810
- // packages/mcps/src/index.ts
5811
- var src_exports = {};
5812
- __export(src_exports, {
5813
- buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
5814
- buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
5815
- buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
5816
- calculateFileChecksum: () => calculateFileChecksum,
5817
- createApiKeyWithToken: () => createApiKeyWithToken,
5818
- createChildLogger: () => createChildLogger,
5819
- deleteApiKeyData: () => deleteApiKeyData,
5820
- deleteCredentials: () => deleteCredentials,
5821
- e2e: () => e2e_exports2,
5822
- getApiKey: () => getApiKey,
5823
- getApiKeyFilePath: () => getApiKeyFilePath,
5824
- getAuthService: () => getAuthService,
5825
- getBundledElectronAppVersion: () => getBundledElectronAppVersion,
5826
- getCallerCredentials: () => getCallerCredentials,
5827
- getCallerCredentialsAsync: () => getCallerCredentialsAsync,
5828
- getChecksumForPlatform: () => getChecksumForPlatform,
5829
- getConfig: () => getConfig,
5830
- getCredentialsFilePath: () => getCredentialsFilePath,
5831
- getDataDir: () => getDataDir2,
5832
- getDownloadBaseUrl: () => getDownloadBaseUrl,
5833
- getElectronAppChecksums: () => getElectronAppChecksums,
5834
- getElectronAppDir: () => getElectronAppDir,
5835
- getElectronAppVersion: () => getElectronAppVersion,
5836
- getElectronAppVersionSource: () => getElectronAppVersionSource,
5837
- getLocalQaTools: () => getLocalQaTools,
5838
- getLogger: () => getLogger,
5839
- getPlatformKey: () => getPlatformKey,
5840
- getQaTools: () => getQaTools,
5841
- getValidApiKeyData: () => getValidApiKeyData,
5842
- getValidCredentials: () => getValidCredentials,
5843
- hasApiKey: () => hasApiKey,
5844
- isElectronAppInstalled: () => isElectronAppInstalled,
5845
- loadApiKeyData: () => loadApiKeyData,
5846
- loadCredentials: () => loadCredentials,
5847
- localQa: () => local_exports2,
5848
- mcp: () => mcp_exports,
5849
- openBrowserUrl: () => openBrowserUrl,
5850
- performLogin: () => performLogin,
5851
- performLogout: () => performLogout,
5852
- pollDeviceCode: () => pollDeviceCode,
5853
- qa: () => e2e_exports2,
5854
- resetConfig: () => resetConfig,
5855
- resetLogger: () => resetLogger,
5856
- saveApiKey: () => saveApiKey,
5857
- saveApiKeyData: () => saveApiKeyData,
5858
- saveCredentials: () => saveCredentials,
5859
- startDeviceCodeFlow: () => startDeviceCodeFlow,
5860
- toolRequiresAuth: () => toolRequiresAuth,
5861
- verifyFileChecksum: () => verifyFileChecksum
5862
- });
5863
- var logger5 = getLogger();
5864
- function getPlatformKey() {
5865
- const os4 = platform();
5866
- const arch3 = process.arch;
5867
- switch (os4) {
5868
- case "darwin":
5869
- return arch3 === "arm64" ? "darwin-arm64" : "darwin-x64";
5870
- case "win32":
5871
- return "win32-x64";
5872
- case "linux":
5873
- return "linux-x64";
5874
- default:
5875
- throw new Error(`Unsupported platform: ${os4}`);
5876
- }
5877
- }
5878
- async function calculateFileChecksum(filePath) {
5879
- return new Promise((resolve4, reject) => {
5880
- const hash = crypto.createHash("sha256");
5881
- const stream = fs3.createReadStream(filePath);
5882
- stream.on("data", (data) => {
5883
- hash.update(data);
5884
- });
5885
- stream.on("end", () => {
5886
- resolve4(hash.digest("hex"));
5887
- });
5888
- stream.on("error", (error) => {
5889
- reject(error);
5890
- });
5891
- });
5892
- }
5893
- async function verifyFileChecksum(filePath, expectedChecksum) {
5894
- if (!expectedChecksum || expectedChecksum.trim() === "") {
5895
- logger5.warn("Checksum verification skipped - no checksum provided", {
5896
- file: path2.basename(filePath)
5897
- });
5898
- return {
5899
- valid: true,
5900
- expected: "",
5901
- actual: "",
5902
- error: "Checksum verification skipped - no checksum configured"
5903
- };
5904
- }
5905
- try {
5906
- const actualChecksum = await calculateFileChecksum(filePath);
5907
- const normalizedExpected = expectedChecksum.toLowerCase().trim();
5908
- const normalizedActual = actualChecksum.toLowerCase();
5909
- const valid = normalizedExpected === normalizedActual;
5910
- if (!valid) {
5911
- logger5.error("Checksum verification failed", {
5912
- file: path2.basename(filePath),
5913
- expected: normalizedExpected,
5914
- actual: normalizedActual
5915
- });
5916
- } else {
5917
- logger5.info("Checksum verified successfully", {
5918
- file: path2.basename(filePath),
5919
- checksum: normalizedActual
5920
- });
5921
- }
5922
- return {
5923
- valid,
5924
- expected: normalizedExpected,
5925
- actual: normalizedActual,
5926
- error: valid ? void 0 : "Checksum mismatch - file may be corrupted or tampered with"
5927
- };
5928
- } catch (error) {
5929
- const errorMessage = error instanceof Error ? error.message : String(error);
5930
- logger5.error("Checksum calculation failed", {
5931
- file: path2.basename(filePath),
5932
- error: errorMessage
5933
- });
5934
- return {
5935
- valid: false,
5936
- expected: expectedChecksum,
5937
- actual: "",
5938
- error: `Failed to calculate checksum: ${errorMessage}`
5939
- };
5940
- }
5941
- }
5942
- function getChecksumForPlatform(checksums) {
5943
- if (!checksums) {
5944
- return "";
5945
- }
5946
- const platformKey = getPlatformKey();
5947
- return checksums[platformKey] || "";
5948
- }
5949
- var registeredTools = [];
5950
- function registerTools(tools) {
5951
- registeredTools = [...registeredTools, ...tools];
5952
- }
5953
- function getAllTools() {
5954
- return registeredTools;
5955
- }
5956
- function clearTools() {
5957
- registeredTools = [];
5958
- }
5959
- function zodToJsonSchema(schema) {
5960
- try {
5961
- if (schema && typeof schema === "object" && "safeParse" in schema) {
5962
- return z.toJSONSchema(schema);
5963
- }
5964
- } catch {
5965
- }
5966
- try {
5967
- const zodSchema = schema;
5968
- if (zodSchema._def) {
5969
- return convertZodDef(zodSchema);
5970
- }
5971
- } catch {
5972
- }
5973
- return {
5974
- type: "object",
5975
- properties: {},
5976
- additionalProperties: true
5977
- };
5978
- }
5979
- function convertZodDef(schema) {
5980
- const zodSchema = schema;
5981
- if (!zodSchema._def) {
5982
- return { type: "object" };
5983
- }
5984
- const def = zodSchema._def;
5985
- const typeName = def.typeName ?? def.type;
5986
- switch (typeName) {
5987
- case "ZodObject":
5988
- case "object": {
5989
- const shapeFromDef = typeof def.shape === "function" ? def.shape() : def.shape;
5990
- const shape = shapeFromDef || zodSchema.shape || {};
5991
- const properties = {};
5992
- const required = [];
5993
- for (const [key, value] of Object.entries(shape)) {
5994
- properties[key] = convertZodDef(value);
5995
- const valueDef = value._def;
5996
- if (valueDef?.typeName !== "ZodOptional") {
5997
- required.push(key);
5998
- }
5999
- }
6000
- const result = {
6001
- type: "object",
6002
- properties
6003
- };
6004
- if (required.length > 0) {
6005
- result.required = required;
6006
- }
6007
- return result;
6008
- }
6009
- case "ZodString":
6010
- case "string": {
6011
- const result = { type: "string" };
6012
- if (def.description) result.description = def.description;
6013
- if (def.checks) {
6014
- for (const check of def.checks) {
6015
- if (check.kind === "min") result.minLength = check.value;
6016
- if (check.kind === "max") result.maxLength = check.value;
6017
- if (check.kind === "url") result.format = "uri";
6018
- if (check.kind === "email") result.format = "email";
6019
- }
6020
- }
6021
- return result;
6022
- }
6023
- case "ZodNumber":
6024
- case "number": {
6025
- const result = { type: "number" };
6026
- if (def.description) result.description = def.description;
6027
- if (def.checks) {
6028
- for (const check of def.checks) {
6029
- if (check.kind === "int") result.type = "integer";
6030
- if (check.kind === "min") result.minimum = check.value;
6031
- if (check.kind === "max") result.maximum = check.value;
6032
- }
6033
- }
6034
- return result;
6035
- }
6036
- case "ZodBoolean":
6037
- case "boolean": {
6038
- const result = { type: "boolean" };
6039
- if (def.description) result.description = def.description;
6040
- return result;
6041
- }
6042
- case "ZodArray":
6043
- case "array": {
6044
- const result = {
6045
- type: "array",
6046
- items: def.innerType ? convertZodDef(def.innerType) : def.element ? convertZodDef(def.element) : {}
6047
- };
6048
- if (def.description) result.description = def.description;
6049
- return result;
6050
- }
6051
- case "ZodEnum":
6052
- case "enum": {
6053
- const enumValues = Array.isArray(def.values) ? def.values : def.values ? Object.values(def.values) : [];
6054
- const result = {
6055
- type: "string",
6056
- enum: enumValues
6057
- };
6058
- if (def.description) result.description = def.description;
6059
- return result;
6060
- }
6061
- case "ZodOptional":
6062
- case "optional": {
6063
- const inner = def.innerType ? convertZodDef(def.innerType) : {};
6064
- if (def.description) inner.description = def.description;
6065
- return inner;
6066
- }
6067
- case "ZodUnion": {
6068
- const options = def.options || [];
6069
- return {
6070
- oneOf: options.map((opt) => convertZodDef(opt))
6071
- };
6072
- }
6073
- default:
6074
- return { type: "object" };
6075
- }
6076
- }
6077
- async function handleJitAuth(toolName, correlationId) {
6078
- const childLogger = createChildLogger(correlationId);
6079
- if (!toolRequiresAuth(toolName)) {
6080
- return { credentials: {}, authTriggered: false };
6081
- }
6082
- const credentials = getCallerCredentials();
6083
- if (credentials.apiKey || credentials.bearerToken) {
6084
- return { credentials, authTriggered: false };
6085
- }
6086
- childLogger.info("No credentials found, triggering JIT auth", { tool: toolName });
6087
- return { credentials: {}, authTriggered: false };
6088
- }
6089
- function createUnifiedMcpServer(options) {
6090
- const logger14 = getLogger();
6091
- const config = getConfig();
6092
- const server = new Server(
6093
- {
6094
- name: config.serverName,
6095
- version: config.serverVersion
6096
- },
6097
- {
6098
- capabilities: {
6099
- tools: {},
6100
- resources: {}
6101
- },
6102
- 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."
6103
- }
6104
- );
6105
- server.setRequestHandler(ListToolsRequestSchema, () => {
6106
- const tools = getAllTools();
6107
- logger14.debug("Listing tools", { count: tools.length });
6108
- const toolDefinitions = tools.map((tool) => {
6109
- const jsonSchema = zodToJsonSchema(tool.inputSchema);
6110
- return {
6111
- name: tool.name,
6112
- description: tool.description,
6113
- inputSchema: jsonSchema
6114
- };
6115
- });
6116
- return { tools: toolDefinitions };
6117
- });
6118
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
6119
- const correlationId = v4();
6120
- const childLogger = createChildLogger(correlationId);
6121
- const toolName = request.params.name;
6122
- const toolInput = request.params.arguments || {};
6123
- childLogger.info("Tool call received", {
6124
- tool: toolName,
6125
- hasArguments: Object.keys(toolInput).length > 0
6126
- });
6127
- try {
6128
- const tool = getAllTools().find((t) => t.name === toolName);
6129
- if (!tool) {
6130
- return {
6131
- content: [
6132
- {
6133
- type: "text",
6134
- text: JSON.stringify({
6135
- error: "NOT_FOUND",
6136
- message: `Unknown tool: ${toolName}`
6137
- })
6138
- }
6139
- ],
6140
- isError: true
6141
- };
6142
- }
6143
- const { authTriggered } = await handleJitAuth(toolName, correlationId);
6144
- if (authTriggered) {
6145
- return {
6146
- content: [
6147
- {
6148
- type: "text",
6149
- text: JSON.stringify({
6150
- message: "Authentication required. Please complete login in your browser."
6151
- })
6152
- }
6153
- ]
6154
- };
6155
- }
6156
- const startTime = Date.now();
6157
- const result = await tool.execute({
6158
- input: toolInput,
6159
- correlationId
6160
- });
6161
- const latency = Date.now() - startTime;
6162
- childLogger.info("Tool call completed", {
6163
- tool: toolName,
6164
- latencyMs: latency,
6165
- isError: result.isError
6166
- });
6167
- return {
6168
- content: [
6169
- {
6170
- type: "text",
6171
- text: result.content
6172
- }
6173
- ],
6174
- isError: result.isError
6175
- };
6176
- } catch (error) {
6177
- if (error instanceof ZodError) {
6178
- childLogger.warn("Tool call failed with validation error", {
6179
- tool: toolName,
6180
- errors: error.issues
6181
- });
6182
- const issueMessages = error.issues.slice(0, 3).map((issue) => {
6183
- const path15 = issue.path.join(".");
6184
- return path15 ? `'${path15}': ${issue.message}` : issue.message;
6185
- });
6186
- return {
6187
- content: [
6188
- {
6189
- type: "text",
6190
- text: JSON.stringify({
6191
- error: "INVALID_ARGUMENT",
6192
- message: `Invalid input: ${issueMessages.join("; ")}`
6193
- })
6194
- }
6195
- ],
6196
- isError: true
6197
- };
6198
- }
6199
- childLogger.error("Tool call failed with error", {
6200
- tool: toolName,
6201
- error: String(error)
6202
- });
6203
- return {
6204
- content: [
6205
- {
6206
- type: "text",
6207
- text: JSON.stringify({
6208
- error: "INTERNAL_ERROR",
6209
- message: error instanceof Error ? error.message : "An unexpected error occurred"
6210
- })
6211
- }
6212
- ],
6213
- isError: true
6214
- };
6215
- }
6216
- });
6217
- server.setRequestHandler(ListResourcesRequestSchema, () => {
6218
- logger14.debug("Listing resources");
6219
- return { resources: [] };
6220
- });
6221
- server.setRequestHandler(ReadResourceRequestSchema, (request) => {
6222
- const uri = request.params.uri;
6223
- logger14.debug("Reading resource", { uri });
6224
- return {
6225
- contents: [
6226
- {
6227
- uri,
6228
- mimeType: "text/plain",
6229
- text: `Resource not found: ${uri}`
6230
- }
6231
- ]
6232
- };
6233
- });
6234
- logger14.info("Unified MCP server configured", {
6235
- tools: getAllTools().length,
6236
- enableQaTools: options.enableQaTools,
6237
- enableLocalTools: options.enableLocalTools
6238
- });
6239
- return server;
6240
- }
6241
-
6242
- // src/server/index.ts
6243
- var server_exports = {};
6244
- __export(server_exports, {
6245
- clearTools: () => clearTools,
6246
- createUnifiedMcpServer: () => createUnifiedMcpServer,
6247
- getAllTools: () => getAllTools,
6248
- registerTools: () => registerTools,
6249
- startStdioServer: () => startStdioServer
6250
- });
6251
- var logger6 = getLogger();
6252
- async function startStdioServer(server) {
6253
- logger6.info("Starting stdio server transport");
6254
- const transport = new StdioServerTransport();
6255
- await server.connect(transport);
6256
- logger6.info("Stdio server connected");
6257
- const shutdown = (signal) => {
6258
- logger6.info(`Received ${signal}, shutting down...`);
6259
- process.exit(0);
6260
- };
6261
- process.on("SIGTERM", () => shutdown("SIGTERM"));
6262
- process.on("SIGINT", () => shutdown("SIGINT"));
6263
- }
6264
-
6265
- // src/cli/pr-section/selectors.ts
6266
- var ONE_LINER_BUDGET = 160;
6267
- function selectHero(report) {
6268
- const firstFailed = report.tests.find(
6269
- (t) => t.status === "failed"
6270
- );
6271
- if (firstFailed) {
6272
- const step = firstFailed.steps.find((s) => s.stepIndex === firstFailed.failureStepIndex);
6273
- if (step) {
6274
- return {
6275
- screenshotUrl: step.screenshotUrl,
6276
- testName: firstFailed.name,
6277
- kind: "failure"
6278
- };
6279
- }
6280
- }
6281
- const firstPassedWithSteps = report.tests.find(
6282
- (t) => t.status === "passed" && t.steps.length > 0
6283
- );
6284
- if (firstPassedWithSteps) {
6285
- const lastStep = firstPassedWithSteps.steps[firstPassedWithSteps.steps.length - 1];
6286
- return {
6287
- screenshotUrl: lastStep.screenshotUrl,
6288
- testName: firstPassedWithSteps.name,
6289
- kind: "final"
6290
- };
6291
- }
6292
- return null;
6293
- }
6294
- function buildOneLiner(report) {
6295
- const total = report.tests.length;
6296
- if (total === 0) {
6297
- return "No acceptance tests were executed.";
6298
- }
6299
- const failed = report.tests.filter((t) => t.status === "failed");
6300
- if (failed.length === 0) {
6301
- return `All ${total} acceptance tests passed.`;
6302
- }
6303
- const first = failed[0];
6304
- const prefix = `${failed.length} of ${total} failed \u2014 "${first.name}" broke at step ${first.failureStepIndex}: `;
6305
- const available = ONE_LINER_BUDGET - prefix.length - 1;
6306
- const error = first.error.length > available ? first.error.slice(0, Math.max(0, available - 1)) + "\u2026" : first.error;
6307
- return `${prefix}${error}.`;
6308
- }
6309
-
6310
- // src/cli/pr-section/render.ts
6311
- var DASHBOARD_URL_BASE = "https://www.muggle-ai.com/muggleTestV0/dashboard/projects";
6312
- var ROW_THUMB_WIDTH = 120;
6313
- var DETAIL_THUMB_WIDTH = 200;
6314
- var HERO_WIDTH = 480;
6315
- function thumbnail(url, width) {
6316
- return `<a href="${url}"><img src="${url}" width="${width}"></a>`;
6317
- }
6318
- function counts(report) {
6319
- const passed = report.tests.filter((t) => t.status === "passed").length;
6320
- const failed = report.tests.filter((t) => t.status === "failed").length;
6321
- return { passed, failed, text: `**${passed} passed / ${failed} failed**` };
6322
- }
6323
- function renderSummary(report) {
6324
- const { text: countsLine } = counts(report);
6325
- const oneLiner = buildOneLiner(report);
6326
- const hero = selectHero(report);
6327
- const dashboard = `${DASHBOARD_URL_BASE}/${report.projectId}/scripts`;
6328
- const lines = [
6329
- countsLine,
6330
- "",
6331
- oneLiner,
6332
- ""
6333
- ];
6334
- if (hero) {
6335
- lines.push(
6336
- `<a href="${hero.screenshotUrl}"><img src="${hero.screenshotUrl}" width="${HERO_WIDTH}" alt="${hero.testName}"></a>`,
6337
- ""
6338
- );
6339
- }
6340
- lines.push(`[View project dashboard on muggle-ai.com](${dashboard})`);
6341
- return lines.join("\n");
6342
- }
6343
- function renderRow(test) {
6344
- const link = `[${test.name}](${test.viewUrl})`;
6345
- if (test.status === "passed") {
6346
- const lastStep = test.steps[test.steps.length - 1];
6347
- const thumb2 = lastStep ? thumbnail(lastStep.screenshotUrl, ROW_THUMB_WIDTH) : "\u2014";
6348
- return `| ${link} | \u2705 PASSED | ${thumb2} |`;
6349
- }
6350
- const failStep = test.steps.find((s) => s.stepIndex === test.failureStepIndex);
6351
- const thumb = failStep ? thumbnail(failStep.screenshotUrl, ROW_THUMB_WIDTH) : "\u2014";
6352
- return `| ${link} | \u274C FAILED \u2014 ${test.error} | ${thumb} |`;
6353
- }
6354
- function renderFailureDetails(test) {
6355
- const stepCount = test.steps.length;
6356
- const header2 = `<details>
6357
- <summary>\u{1F4F8} <strong>${test.name}</strong> \u2014 ${stepCount} steps (failed at step ${test.failureStepIndex})</summary>
6358
-
6359
- | # | Action | Screenshot |
6360
- |---|--------|------------|`;
6361
- const rows = test.steps.map((step) => renderFailureStepRow(step, test)).join("\n");
6362
- return `${header2}
6363
- ${rows}
6364
-
6365
- </details>`;
6366
- }
6367
- function renderFailureStepRow(step, test) {
6368
- const isFailure = step.stepIndex === test.failureStepIndex;
6369
- const marker = isFailure ? `${step.stepIndex} \u26A0\uFE0F` : String(step.stepIndex);
6370
- const action = isFailure ? `${step.action} \u2014 **${test.error}**` : step.action;
6371
- return `| ${marker} | ${action} | ${thumbnail(step.screenshotUrl, DETAIL_THUMB_WIDTH)} |`;
6372
- }
6373
- function renderRowsTable(report) {
6374
- if (report.tests.length === 0) {
6375
- return "_No tests were executed._";
6376
- }
6377
- const header2 = "| Test Case | Status | Evidence |\n|-----------|--------|----------|";
6378
- const rows = report.tests.map(renderRow).join("\n");
6379
- return `${header2}
6380
- ${rows}`;
6381
- }
6382
- function renderBody(report, opts) {
6383
- const sections = [
6384
- "## E2E Acceptance Results",
6385
- "",
6386
- renderSummary(report),
6387
- "",
6388
- renderRowsTable(report)
6389
- ];
6390
- const failures = report.tests.filter((t) => t.status === "failed");
6391
- if (failures.length > 0) {
6392
- if (opts.inlineFailureDetails) {
6393
- sections.push("", ...failures.map(renderFailureDetails));
6394
- } else {
6395
- sections.push(
6396
- "",
6397
- "_Full step-by-step evidence in the comment below \u2014 the PR description was too large to inline it._"
6398
- );
6399
- }
6400
- }
6401
- return sections.join("\n");
6402
- }
6403
- function renderComment(report) {
6404
- const failures = report.tests.filter((t) => t.status === "failed");
6405
- if (failures.length === 0) {
6406
- return "";
6407
- }
6408
- const sections = [
6409
- "## E2E acceptance evidence (overflow)",
6410
- "",
6411
- "_This comment was posted because the full step-by-step evidence did not fit in the PR description._",
6412
- "",
6413
- ...failures.map(renderFailureDetails)
6414
- ];
6415
- return sections.join("\n");
6416
- }
6417
-
6418
- // src/cli/pr-section/overflow.ts
6419
- function splitWithOverflow(report, opts) {
6420
- const inlineBody = renderBody(report, { inlineFailureDetails: true });
6421
- const inlineBytes = Buffer.byteLength(inlineBody, "utf-8");
6422
- if (inlineBytes <= opts.maxBodyBytes) {
6423
- return { body: inlineBody, comment: null };
6424
- }
6425
- const spilledBody = renderBody(report, { inlineFailureDetails: false });
6426
- const comment = renderComment(report);
6427
- return {
6428
- body: spilledBody,
6429
- comment: comment.length > 0 ? comment : null
6430
- };
6431
- }
6432
- var StepSchema = z.object({
6433
- stepIndex: z.number().int().nonnegative(),
6434
- action: z.string().min(1),
6435
- screenshotUrl: z.string().url()
6436
- });
6437
- var PassedTestSchema = z.object({
6438
- name: z.string().min(1),
6439
- testCaseId: z.string().min(1),
6440
- testScriptId: z.string().min(1).optional(),
6441
- runId: z.string().min(1),
6442
- viewUrl: z.string().url(),
6443
- status: z.literal("passed"),
6444
- steps: z.array(StepSchema)
6445
- });
6446
- var FailedTestSchema = z.object({
6447
- name: z.string().min(1),
6448
- testCaseId: z.string().min(1),
6449
- testScriptId: z.string().min(1).optional(),
6450
- runId: z.string().min(1),
6451
- viewUrl: z.string().url(),
6452
- status: z.literal("failed"),
6453
- steps: z.array(StepSchema),
6454
- failureStepIndex: z.number().int().nonnegative(),
6455
- error: z.string().min(1),
6456
- artifactsDir: z.string().min(1).optional()
6457
- });
6458
- var TestResultSchema = z.discriminatedUnion("status", [
6459
- PassedTestSchema,
6460
- FailedTestSchema
6461
- ]);
6462
- var E2eReportSchema = z.object({
6463
- projectId: z.string().min(1),
6464
- tests: z.array(TestResultSchema)
6465
- });
6466
-
6467
- // src/cli/pr-section/index.ts
6468
- function buildPrSection(report, opts) {
6469
- return splitWithOverflow(report, opts);
6470
- }
6471
-
6472
- // src/cli/build-pr-section.ts
6473
- var DEFAULT_MAX_BODY_BYTES = 6e4;
6474
- async function readAll(stream) {
6475
- const chunks = [];
6476
- for await (const chunk of stream) {
6477
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
6478
- }
6479
- return Buffer.concat(chunks).toString("utf-8");
6480
- }
6481
- function errMsg(e) {
6482
- return e instanceof Error ? e.message : String(e);
6483
- }
6484
- async function runBuildPrSection(opts) {
6485
- let raw;
6486
- try {
6487
- raw = await readAll(opts.stdin);
6488
- } catch (err) {
6489
- opts.stderrWrite(`build-pr-section: failed to read stdin: ${errMsg(err)}
6490
- `);
6491
- return 1;
6492
- }
6493
- let json;
6494
- try {
6495
- json = JSON.parse(raw);
6496
- } catch (err) {
6497
- opts.stderrWrite(`build-pr-section: failed to parse stdin as JSON: ${errMsg(err)}
6498
- `);
6499
- return 1;
6500
- }
6501
- let report;
6502
- try {
6503
- report = E2eReportSchema.parse(json);
6504
- } catch (err) {
6505
- if (err instanceof ZodError) {
6506
- opts.stderrWrite(
6507
- `build-pr-section: report validation failed:
6508
- ${err.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}
6509
- `
6510
- );
6511
- } else {
6512
- opts.stderrWrite(`build-pr-section: report validation failed: ${errMsg(err)}
6513
- `);
6514
- }
6515
- return 1;
6516
- }
6517
- const result = buildPrSection(report, { maxBodyBytes: opts.maxBodyBytes });
6518
- opts.stdoutWrite(JSON.stringify({ body: result.body, comment: result.comment }));
6519
- return 0;
6520
- }
6521
- async function buildPrSectionCommand(options) {
6522
- const maxBodyBytes = options.maxBodyBytes ? Number(options.maxBodyBytes) : DEFAULT_MAX_BODY_BYTES;
6523
- if (!Number.isFinite(maxBodyBytes) || maxBodyBytes <= 0) {
6524
- process.stderr.write(`build-pr-section: --max-body-bytes must be a positive number
6525
- `);
6526
- process.exitCode = 1;
6527
- return;
6528
- }
6529
- const code = await runBuildPrSection({
6530
- stdin: process.stdin,
6531
- stdoutWrite: (s) => process.stdout.write(s),
6532
- stderrWrite: (s) => process.stderr.write(s),
6533
- maxBodyBytes
6534
- });
6535
- if (code !== 0) {
6536
- process.exitCode = code;
6537
- }
6538
- }
6539
- var logger7 = getLogger();
6540
- var ELECTRON_APP_DIR2 = "electron-app";
6541
- var CURSOR_SKILLS_DIR = ".cursor";
6542
- var CURSOR_SKILLS_SUBDIR = "skills";
6543
- var MUGGLE_SKILL_PREFIX = "muggle";
6544
- var INSTALL_MANIFEST_FILE = "install-manifest.json";
6545
- function getElectronAppBaseDir() {
6546
- return path2.join(getDataDir2(), ELECTRON_APP_DIR2);
6547
- }
6548
- function getCursorSkillsDir() {
6549
- return path2.join(homedir(), CURSOR_SKILLS_DIR, CURSOR_SKILLS_SUBDIR);
6550
- }
6551
- function getInstallManifestPath() {
6552
- return path2.join(getDataDir2(), INSTALL_MANIFEST_FILE);
6553
- }
6554
- function readInstallManifest() {
6555
- const manifestPath = getInstallManifestPath();
6556
- if (!existsSync(manifestPath)) {
6557
- return null;
6558
- }
6559
- try {
6560
- const content = readFileSync(manifestPath, "utf-8");
6561
- const manifest = JSON.parse(content);
6562
- if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) {
6563
- return null;
6564
- }
6565
- return manifest;
6566
- } catch {
6567
- return null;
6568
- }
6569
- }
6570
- function listObsoleteSkills() {
6571
- const skillsDir = getCursorSkillsDir();
6572
- const manifest = readInstallManifest();
6573
- const obsoleteSkills = [];
6574
- if (!existsSync(skillsDir)) {
6575
- return obsoleteSkills;
6576
- }
6577
- const manifestSkills = new Set(manifest?.skills ?? []);
6578
- try {
6579
- const entries = readdirSync(skillsDir, { withFileTypes: true });
6580
- for (const entry of entries) {
6581
- if (!entry.isDirectory()) {
6582
- continue;
6583
- }
6584
- if (!entry.name.startsWith(MUGGLE_SKILL_PREFIX)) {
6585
- continue;
6586
- }
6587
- if (manifestSkills.has(entry.name)) {
6588
- continue;
6589
- }
6590
- const skillPath = path2.join(skillsDir, entry.name);
6591
- const sizeBytes = getDirectorySize(skillPath);
6592
- obsoleteSkills.push({
6593
- name: entry.name,
6594
- path: skillPath,
6595
- sizeBytes
6596
- });
6597
- }
6598
- } catch (error) {
6599
- const errorMessage = error instanceof Error ? error.message : String(error);
6600
- logger7.warn("Failed to list obsolete skills", { error: errorMessage });
6601
- }
6602
- return obsoleteSkills;
6603
- }
6604
- function cleanupObsoleteSkills(options = {}) {
6605
- const { dryRun = false } = options;
6606
- const obsoleteSkills = listObsoleteSkills();
6607
- const removed = [];
6608
- let freedBytes = 0;
6609
- for (const skill of obsoleteSkills) {
6610
- if (!dryRun) {
6611
- try {
6612
- rmSync(skill.path, { recursive: true, force: true });
6613
- logger7.info("Removed obsolete skill", {
6614
- skill: skill.name,
6615
- freedBytes: skill.sizeBytes
6616
- });
6617
- } catch (error) {
6618
- const errorMessage = error instanceof Error ? error.message : String(error);
6619
- logger7.error("Failed to remove skill", {
6620
- skill: skill.name,
6621
- error: errorMessage
6622
- });
6623
- continue;
6624
- }
6625
- }
6626
- removed.push(skill);
6627
- freedBytes += skill.sizeBytes;
6628
- }
6629
- return { removed, freedBytes };
6630
- }
6631
- function getDirectorySize(dirPath) {
6632
- let totalSize = 0;
6633
- try {
6634
- const entries = readdirSync(dirPath, { withFileTypes: true });
6635
- for (const entry of entries) {
6636
- const fullPath = path2.join(dirPath, entry.name);
6637
- if (entry.isDirectory()) {
6638
- totalSize += getDirectorySize(fullPath);
6639
- } else if (entry.isFile()) {
6640
- try {
6641
- const stats = statSync(fullPath);
6642
- totalSize += stats.size;
6643
- } catch {
6644
- }
6645
- }
6646
- }
6647
- } catch {
6648
- }
6649
- return totalSize;
6650
- }
6651
- function formatBytes(bytes) {
6652
- if (bytes === 0) {
6653
- return "0 B";
6654
- }
6655
- const units = ["B", "KB", "MB", "GB"];
6656
- const k = 1024;
6657
- const i = Math.floor(Math.log(bytes) / Math.log(k));
6658
- const size = bytes / Math.pow(k, i);
6659
- return `${size.toFixed(1)} ${units[i]}`;
6660
- }
6661
- function compareVersions(a, b) {
6662
- const partsA = a.split(".").map(Number);
6663
- const partsB = b.split(".").map(Number);
6664
- for (let i = 0; i < 3; i++) {
6665
- const partA = partsA[i] || 0;
6666
- const partB = partsB[i] || 0;
6667
- if (partA !== partB) {
6668
- return partA - partB;
6669
- }
6670
- }
6671
- return 0;
6672
- }
6673
- function listInstalledVersions() {
6674
- const baseDir = getElectronAppBaseDir();
6675
- const currentVersion = getElectronAppVersion();
6676
- const versions = [];
6677
- if (!existsSync(baseDir)) {
6678
- return versions;
6679
- }
6680
- try {
6681
- const entries = readdirSync(baseDir, { withFileTypes: true });
6682
- for (const entry of entries) {
6683
- if (!entry.isDirectory()) {
6684
- continue;
6685
- }
6686
- if (!/^\d+\.\d+\.\d+$/.test(entry.name)) {
6687
- continue;
6688
- }
6689
- const versionPath = path2.join(baseDir, entry.name);
6690
- const sizeBytes = getDirectorySize(versionPath);
6691
- versions.push({
6692
- version: entry.name,
6693
- path: versionPath,
6694
- sizeBytes,
6695
- isCurrent: entry.name === currentVersion
6696
- });
6697
- }
6698
- } catch (error) {
6699
- const errorMessage = error instanceof Error ? error.message : String(error);
6700
- logger7.warn("Failed to list installed versions", { error: errorMessage });
6701
- }
6702
- versions.sort((a, b) => compareVersions(b.version, a.version));
6703
- return versions;
6704
- }
6705
- function cleanupOldVersions(options = {}) {
6706
- const { all = false, dryRun = false } = options;
6707
- const versions = listInstalledVersions();
6708
- const removed = [];
6709
- let freedBytes = 0;
6710
- const versionsToKeep = all ? 1 : 2;
6711
- let keptCount = 0;
6712
- for (const version of versions) {
6713
- if (version.isCurrent) {
6714
- keptCount++;
6715
- continue;
6716
- }
6717
- if (keptCount < versionsToKeep) {
6718
- keptCount++;
6719
- continue;
6720
- }
6721
- if (!dryRun) {
6722
- try {
6723
- rmSync(version.path, { recursive: true, force: true });
6724
- logger7.info("Removed old version", {
6725
- version: version.version,
6726
- freedBytes: version.sizeBytes
6727
- });
6728
- } catch (error) {
6729
- const errorMessage = error instanceof Error ? error.message : String(error);
6730
- logger7.error("Failed to remove version", {
6731
- version: version.version,
6732
- error: errorMessage
6733
- });
6734
- continue;
6735
- }
6736
- }
6737
- removed.push(version);
6738
- freedBytes += version.sizeBytes;
6739
- }
6740
- return { removed, freedBytes };
6741
- }
6742
- async function versionsCommand() {
6743
- console.log("\nInstalled Electron App Versions");
6744
- console.log("================================\n");
6745
- const versions = listInstalledVersions();
6746
- if (versions.length === 0) {
6747
- console.log("No versions installed.");
6748
- console.log("Run 'muggle setup' to download the Electron app.\n");
6749
- return;
6750
- }
6751
- let totalSize = 0;
6752
- for (const version of versions) {
6753
- const marker = version.isCurrent ? " (current)" : "";
6754
- const size = formatBytes(version.sizeBytes);
6755
- console.log(` v${version.version}${marker} - ${size}`);
6756
- totalSize += version.sizeBytes;
6757
- }
6758
- console.log("");
6759
- console.log(`Total: ${versions.length} version(s), ${formatBytes(totalSize)}`);
6760
- console.log("");
6761
- }
6762
- async function cleanupCommand(options) {
6763
- let totalFreedBytes = 0;
6764
- let totalRemovedCount = 0;
6765
- console.log("\nElectron App Cleanup");
6766
- console.log("====================\n");
6767
- const versions = listInstalledVersions();
6768
- if (versions.length === 0) {
6769
- console.log("No versions installed. Nothing to clean up.\n");
6770
- } else if (versions.length === 1) {
6771
- console.log("Only the current version is installed. Nothing to clean up.\n");
6772
- } else {
6773
- const currentVersion = versions.find((v) => v.isCurrent);
6774
- const oldVersions = versions.filter((v) => !v.isCurrent);
6775
- console.log(`Current version: v${currentVersion?.version ?? "unknown"}`);
6776
- console.log(`Old versions: ${oldVersions.length}`);
6777
- console.log("");
6778
- if (options.dryRun) {
6779
- console.log("Dry run - showing what would be deleted:\n");
6780
- }
6781
- const result = cleanupOldVersions(options);
6782
- if (result.removed.length === 0) {
6783
- if (options.all) {
6784
- console.log("No old versions to remove.\n");
6785
- } else {
6786
- console.log("Keeping one previous version for rollback.");
6787
- console.log("Use --all to remove all old versions.\n");
6788
- }
6789
- } else {
6790
- console.log(options.dryRun ? "Would remove:" : "Removed:");
6791
- for (const version of result.removed) {
6792
- console.log(` v${version.version} (${formatBytes(version.sizeBytes)})`);
6793
- }
6794
- totalFreedBytes += result.freedBytes;
6795
- totalRemovedCount += result.removed.length;
6796
- console.log("");
6797
- }
6798
- }
6799
- if (options.skills) {
6800
- console.log("Skills Cleanup");
6801
- console.log("==============\n");
6802
- const obsoleteSkills = listObsoleteSkills();
6803
- if (obsoleteSkills.length === 0) {
6804
- console.log("No obsolete skills found. Nothing to clean up.\n");
6805
- } else {
6806
- console.log(`Found ${obsoleteSkills.length} obsolete skill(s):
6807
- `);
6808
- if (options.dryRun) {
6809
- console.log("Dry run - showing what would be deleted:\n");
6810
- }
6811
- const skillResult = cleanupObsoleteSkills({ dryRun: options.dryRun });
6812
- console.log(options.dryRun ? "Would remove:" : "Removed:");
6813
- for (const skill of skillResult.removed) {
6814
- console.log(` ${skill.name} (${formatBytes(skill.sizeBytes)})`);
6815
- }
6816
- totalFreedBytes += skillResult.freedBytes;
6817
- totalRemovedCount += skillResult.removed.length;
6818
- console.log("");
6819
- }
6820
- }
6821
- if (totalRemovedCount > 0) {
6822
- console.log(
6823
- `${options.dryRun ? "Would free" : "Freed"}: ${formatBytes(totalFreedBytes)} total`
6824
- );
6825
- console.log("");
6826
- if (options.dryRun) {
6827
- console.log("Run without --dry-run to actually delete.\n");
6828
- }
6829
- }
6830
- logger7.info("Cleanup completed", {
6831
- removed: totalRemovedCount,
6832
- freedBytes: totalFreedBytes,
6833
- dryRun: options.dryRun,
6834
- includeSkills: options.skills
6835
- });
6836
- }
6837
- var logger8 = getLogger();
6838
- function getCursorMcpConfigPath() {
6839
- return join(homedir(), ".cursor", "mcp.json");
6840
- }
6841
- function getExpectedExecutablePath(versionDir) {
6842
- const os4 = platform();
6843
- switch (os4) {
6844
- case "darwin":
6845
- return path2.join(versionDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
6846
- case "win32":
6847
- return path2.join(versionDir, "MuggleAI.exe");
6848
- case "linux":
6849
- return path2.join(versionDir, "MuggleAI");
6850
- default:
6851
- throw new Error(`Unsupported platform: ${os4}`);
6852
- }
6853
- }
6854
- function verifyElectronAppInstallation() {
6855
- const version = getElectronAppVersion();
6856
- const versionDir = getElectronAppDir(version);
6857
- const executablePath = getExpectedExecutablePath(versionDir);
6858
- const metadataPath = path2.join(versionDir, ".install-metadata.json");
6859
- const result = {
6860
- valid: false,
6861
- versionDir,
6862
- executablePath,
6863
- executableExists: false,
6864
- executableIsFile: false,
6865
- metadataExists: false,
6866
- hasPartialArchive: false
6867
- };
6868
- if (!fs3.existsSync(versionDir)) {
6869
- result.errorDetail = "Version directory does not exist";
6870
- return result;
6871
- }
6872
- const archivePatterns = ["MuggleAI-darwin", "MuggleAI-win32", "MuggleAI-linux"];
6873
- try {
6874
- const files = fs3.readdirSync(versionDir);
6875
- for (const file of files) {
6876
- if (archivePatterns.some((pattern) => file.startsWith(pattern)) && (file.endsWith(".zip") || file.endsWith(".tar.gz"))) {
6877
- result.hasPartialArchive = true;
6878
- break;
6879
- }
6880
- }
6881
- } catch {
6882
- }
6883
- result.executableExists = fs3.existsSync(executablePath);
6884
- if (!result.executableExists) {
6885
- if (result.hasPartialArchive) {
6886
- result.errorDetail = "Download incomplete: archive found but not extracted";
6887
- } else {
6888
- result.errorDetail = "Executable not found at expected path";
6889
- }
6890
- return result;
6891
- }
6892
- try {
6893
- const stats = fs3.statSync(executablePath);
6894
- result.executableIsFile = stats.isFile();
6895
- if (!result.executableIsFile) {
6896
- result.errorDetail = "Executable path exists but is not a file";
6897
- return result;
6898
- }
6899
- } catch {
6900
- result.errorDetail = "Cannot stat executable (broken symlink?)";
6901
- return result;
6902
- }
6903
- result.metadataExists = fs3.existsSync(metadataPath);
6904
- result.valid = true;
6905
- return result;
6906
- }
6907
- function validateCursorMcpConfig() {
6908
- const cursorMcpConfigPath = getCursorMcpConfigPath();
6909
- if (!existsSync(cursorMcpConfigPath)) {
6910
- return {
6911
- passed: false,
6912
- description: `Missing at ${cursorMcpConfigPath}`
6913
- };
6914
- }
6915
- try {
6916
- const rawCursorConfig = JSON.parse(
6917
- readFileSync(cursorMcpConfigPath, "utf-8")
6918
- );
6919
- if (!rawCursorConfig.mcpServers) {
6920
- return {
6921
- passed: false,
6922
- description: "Missing mcpServers key"
6923
- };
6924
- }
6925
- const muggleServerConfig = rawCursorConfig.mcpServers.muggle;
6926
- if (!muggleServerConfig) {
6927
- return {
6928
- passed: false,
6929
- description: "Missing mcpServers.muggle entry"
6930
- };
6931
- }
6932
- if (!Array.isArray(muggleServerConfig.args)) {
6933
- return {
6934
- passed: false,
6935
- description: "mcpServers.muggle.args is not an array"
6936
- };
6937
- }
6938
- const hasServeArgument = muggleServerConfig.args.includes("serve");
6939
- if (!hasServeArgument) {
6940
- return {
6941
- passed: false,
6942
- description: "mcpServers.muggle args does not include 'serve'"
6943
- };
6944
- }
6945
- if (muggleServerConfig.command === "node") {
6946
- const firstArgument = muggleServerConfig.args.at(0);
6947
- if (!firstArgument) {
6948
- return {
6949
- passed: false,
6950
- description: "mcpServers.muggle command is node but args[0] is missing"
6951
- };
6952
- }
6953
- if (!existsSync(firstArgument)) {
6954
- return {
6955
- passed: false,
6956
- description: `mcpServers.muggle args[0] does not exist: ${firstArgument}`
6957
- };
6958
- }
6959
- }
6960
- return {
6961
- passed: true,
6962
- description: `Configured at ${cursorMcpConfigPath}`
6963
- };
6964
- } catch (error) {
6965
- const errorMessage = error instanceof Error ? error.message : String(error);
6966
- return {
6967
- passed: false,
6968
- description: `Invalid JSON or schema: ${errorMessage}`
6969
- };
6970
- }
6971
- }
6972
- function runDiagnostics() {
6973
- const results = [];
6974
- const config = getConfig();
6975
- const dataDir = getDataDir2();
6976
- results.push({
6977
- name: "Data Directory",
6978
- passed: existsSync(dataDir),
6979
- description: existsSync(dataDir) ? `Found at ${dataDir}` : `Not found at ${dataDir}`,
6980
- suggestion: "Run 'muggle login' to create the data directory"
6981
- });
6982
- const electronVersion = getElectronAppVersion();
6983
- const bundledVersion = getBundledElectronAppVersion();
6984
- const versionSource = getElectronAppVersionSource();
6985
- const installVerification = verifyElectronAppInstallation();
6986
- let electronDescription;
6987
- let electronSuggestion;
6988
- if (installVerification.valid) {
6989
- electronDescription = `Installed (v${electronVersion})`;
6990
- switch (versionSource) {
6991
- case "env":
6992
- electronDescription += ` [from ELECTRON_APP_VERSION env]`;
6993
- break;
6994
- case "override":
6995
- electronDescription += ` [overridden from bundled v${bundledVersion}]`;
6996
- break;
6997
- }
6998
- if (!installVerification.metadataExists) {
6999
- electronDescription += " [missing metadata]";
7000
- }
7001
- } else {
7002
- electronDescription = `Not installed (expected v${electronVersion})`;
7003
- if (installVerification.errorDetail) {
7004
- electronDescription += `
7005
- \u2514\u2500 ${installVerification.errorDetail}`;
7006
- electronDescription += `
7007
- \u2514\u2500 Checked: ${installVerification.versionDir}`;
7008
- }
7009
- if (installVerification.hasPartialArchive) {
7010
- electronSuggestion = "Run 'muggle setup --force' to re-download and extract";
7011
- } else {
7012
- electronSuggestion = "Run 'muggle setup' to download the Electron app";
7013
- }
7014
- }
7015
- results.push({
7016
- name: "Electron App",
7017
- passed: installVerification.valid,
7018
- description: electronDescription,
7019
- suggestion: electronSuggestion
7020
- });
7021
- if (installVerification.valid) {
7022
- results.push({
7023
- name: "Electron App Updates",
7024
- passed: true,
7025
- description: "Run 'muggle upgrade --check' to check for updates"
7026
- });
7027
- }
7028
- const authService = getAuthService();
7029
- const authStatus = authService.getAuthStatus();
7030
- results.push({
7031
- name: "Authentication",
7032
- passed: authStatus.authenticated,
7033
- description: authStatus.authenticated ? `Authenticated as ${authStatus.email ?? "unknown"}` : "Not authenticated",
7034
- suggestion: "Run 'muggle login' to authenticate"
7035
- });
7036
- const hasStoredApiKey = hasApiKey();
7037
- results.push({
7038
- name: "API Key",
7039
- passed: hasStoredApiKey,
7040
- description: hasStoredApiKey ? "API key stored" : "No API key stored (optional)",
7041
- suggestion: "Run 'muggle login --key-name <name>' to generate an API key"
7042
- });
7043
- const credentialsPath = getCredentialsFilePath();
7044
- results.push({
7045
- name: "Credentials File",
7046
- passed: existsSync(credentialsPath),
7047
- description: existsSync(credentialsPath) ? `Found at ${credentialsPath}` : `Not found at ${credentialsPath}`,
7048
- suggestion: "Run 'muggle login' to create credentials"
7049
- });
7050
- results.push({
7051
- name: "Prompt Service URL",
7052
- passed: !!config.e2e.promptServiceBaseUrl,
7053
- description: config.e2e.promptServiceBaseUrl
7054
- });
7055
- results.push({
7056
- name: "Web Service URL",
7057
- passed: !!config.localQa.webServiceUrl,
7058
- description: config.localQa.webServiceUrl
7059
- });
7060
- const cursorMcpConfigValidationResult = validateCursorMcpConfig();
7061
- results.push({
7062
- name: "Cursor MCP Config",
7063
- passed: cursorMcpConfigValidationResult.passed,
7064
- description: cursorMcpConfigValidationResult.description,
7065
- suggestion: "Re-run npm install -g @muggleai/works to refresh ~/.cursor/mcp.json"
7066
- });
7067
- return results;
7068
- }
7069
- function formatCheckResult(result) {
7070
- const icon = result.passed ? "\u2713" : "\u2717";
7071
- const color = result.passed ? "\x1B[32m" : "\x1B[31m";
7072
- const reset = "\x1B[0m";
7073
- let output = `${color}${icon}${reset} ${result.name}: ${result.description}`;
7074
- if (!result.passed && result.suggestion) {
7075
- output += `
7076
- \u2514\u2500 ${result.suggestion}`;
7077
- }
7078
- return output;
7079
- }
7080
- async function doctorCommand() {
7081
- console.log("\nMuggle Works Doctor");
7082
- console.log("=================\n");
7083
- const results = runDiagnostics();
7084
- for (const result of results) {
7085
- console.log(formatCheckResult(result));
7086
- }
7087
- console.log("");
7088
- const failedCount = results.filter((r) => !r.passed).length;
7089
- if (failedCount === 0) {
7090
- console.log("All checks passed! Your installation is ready.");
7091
- } else {
7092
- console.log(`${failedCount} issue(s) found. See suggestions above.`);
7093
- }
7094
- logger8.info("Doctor command completed", {
7095
- totalChecks: results.length,
7096
- passed: results.length - failedCount,
7097
- failed: failedCount
7098
- });
7099
- }
7100
-
7101
- // src/cli/help.ts
7102
- var COLORS = {
7103
- reset: "\x1B[0m",
7104
- bold: "\x1B[1m",
7105
- dim: "\x1B[2m",
7106
- cyan: "\x1B[36m",
7107
- green: "\x1B[32m",
7108
- yellow: "\x1B[33m",
7109
- blue: "\x1B[34m"};
7110
- function colorize(text, color) {
7111
- if (process.env.NO_COLOR) {
7112
- return text;
7113
- }
7114
- return `${color}${text}${COLORS.reset}`;
7115
- }
7116
- function header(title) {
7117
- return colorize(`
7118
- ${title}`, COLORS.bold + COLORS.cyan);
7119
- }
7120
- function cmd(cmd2) {
7121
- return colorize(cmd2, COLORS.green);
7122
- }
7123
- function path12(path15) {
7124
- return colorize(path15, COLORS.yellow);
7125
- }
7126
- function getHelpGuidance() {
7127
- const lines = [
7128
- "",
7129
- colorize("=".repeat(70), COLORS.cyan),
7130
- colorize(" Muggle AI Works - Comprehensive How-To Guide", COLORS.bold + COLORS.green),
7131
- colorize("=".repeat(70), COLORS.cyan),
7132
- "",
7133
- header("What is Muggle AI Works?"),
7134
- "",
7135
- " Muggle AI Works is a Model Context Protocol server that provides AI",
7136
- " assistants with tools to perform automated end-to-end (E2E) acceptance testing of web applications.",
7137
- "",
7138
- " It supports both:",
7139
- ` ${colorize("\u2022", COLORS.green)} Cloud E2E - Test remote production/staging sites with a public URL`,
7140
- ` ${colorize("\u2022", COLORS.green)} Local E2E - Test localhost development servers`,
7141
- "",
7142
- header("Setup Instructions"),
7143
- "",
7144
- ` ${colorize("Step 1:", COLORS.bold)} Configure your MCP client`,
7145
- "",
7146
- ` For ${colorize("Cursor", COLORS.bold)}, edit ${path12("~/.cursor/mcp.json")}:`,
7147
- "",
7148
- ` ${colorize("{", COLORS.dim)}`,
7149
- ` ${colorize('"mcpServers"', COLORS.yellow)}: {`,
7150
- ` ${colorize('"muggle"', COLORS.yellow)}: {`,
7151
- ` ${colorize('"command"', COLORS.yellow)}: ${colorize('"muggle"', COLORS.green)},`,
7152
- ` ${colorize('"args"', COLORS.yellow)}: [${colorize('"serve"', COLORS.green)}]`,
7153
- ` }`,
7154
- ` }`,
7155
- ` ${colorize("}", COLORS.dim)}`,
7156
- "",
7157
- ` ${colorize("Step 2:", COLORS.bold)} Restart your MCP client`,
7158
- "",
7159
- ` ${colorize("Step 3:", COLORS.bold)} Start testing! Ask your AI assistant:`,
7160
- ` ${colorize('"Test the login flow on my app at http://localhost:3000"', COLORS.dim)}`,
7161
- "",
7162
- header("CLI Commands"),
7163
- "",
7164
- ` ${colorize("Server Commands:", COLORS.bold)}`,
7165
- ` ${cmd("muggle serve")} Start MCP server with all tools`,
7166
- ` ${cmd("muggle serve --e2e")} Start with cloud E2E tools only`,
7167
- ` ${cmd("muggle serve --local")} Start with local E2E tools only`,
7168
- "",
7169
- ` ${colorize("Setup & Diagnostics:", COLORS.bold)}`,
7170
- ` ${cmd("muggle setup")} Download/update Electron app`,
7171
- ` ${cmd("muggle setup --force")} Force re-download`,
7172
- ` ${cmd("muggle doctor")} Diagnose installation issues`,
7173
- ` ${cmd("muggle upgrade")} Check for updates`,
7174
- ` ${cmd("muggle upgrade --check")} Check updates without installing`,
7175
- "",
7176
- ` ${colorize("Authentication:", COLORS.bold)}`,
7177
- ` ${cmd("muggle login")} Login to Muggle AI`,
7178
- ` ${cmd("muggle logout")} Clear stored credentials`,
7179
- ` ${cmd("muggle status")} Show authentication status`,
7180
- "",
7181
- ` ${colorize("Maintenance:", COLORS.bold)}`,
7182
- ` ${cmd("muggle versions")} List installed Electron app versions`,
7183
- ` ${cmd("muggle cleanup")} Remove old Electron app versions`,
7184
- ` ${cmd("muggle cleanup --all")} Remove all old versions`,
7185
- ` ${cmd("muggle cleanup --skills")} Also remove obsolete skills`,
7186
- "",
7187
- ` ${colorize("Help:", COLORS.bold)}`,
7188
- ` ${cmd("muggle help")} Show this guide`,
7189
- ` ${cmd("muggle --help")} Show command synopsis`,
7190
- ` ${cmd("muggle --version")} Show version`,
7191
- "",
7192
- header("Authentication Flow"),
7193
- "",
7194
- " Authentication happens automatically when you first use a tool that",
7195
- " requires it:",
7196
- "",
7197
- ` 1. ${colorize("A browser window opens", COLORS.bold)} with a verification code`,
7198
- ` 2. ${colorize("Log in", COLORS.bold)} with your Muggle AI account`,
7199
- ` 3. ${colorize("The tool call continues", COLORS.bold)} with your credentials`,
7200
- "",
7201
- ` API keys are stored in ${path12("~/.muggle-ai/api-key.json")}`,
7202
- "",
7203
- header("Available MCP Tools"),
7204
- "",
7205
- ` ${colorize("Cloud E2E tools:", COLORS.bold)} (prefix: muggle-remote-)`,
7206
- " muggle-remote-project-create, muggle-remote-project-list, muggle-remote-use-case-create-from-prompts,",
7207
- " muggle-remote-test-case-generate-from-prompt, muggle-remote-workflow-start-*, etc.",
7208
- "",
7209
- ` ${colorize("Local E2E tools:", COLORS.bold)} (prefix: muggle-local-)`,
7210
- " muggle-local-execute-test-generation, muggle-local-execute-replay,",
7211
- " muggle-local-publish-test-script, muggle-local-run-result-get,",
7212
- " muggle-local-check-status, etc.",
7213
- "",
7214
- header("Data Directory"),
7215
- "",
7216
- ` All data is stored in ${path12("~/.muggle-ai/")}:`,
7217
- "",
7218
- ` ${path12("api-key.json")} Long-lived API key (auto-generated)`,
7219
- ` ${path12("projects/")} Local test projects`,
7220
- ` ${path12("sessions/")} Test execution sessions`,
7221
- ` ${path12("electron-app/")} Downloaded Electron app binaries`,
7222
- "",
7223
- header("Troubleshooting"),
7224
- "",
7225
- ` ${colorize("Installation issues:", COLORS.bold)}`,
7226
- ` Run ${cmd("muggle doctor")} to diagnose problems`,
7227
- "",
7228
- ` ${colorize("Electron app not found:", COLORS.bold)}`,
7229
- ` Run ${cmd("muggle setup --force")} to re-download`,
7230
- "",
7231
- ` ${colorize("Authentication issues:", COLORS.bold)}`,
7232
- ` Run ${cmd("muggle logout")} then ${cmd("muggle login")}`,
7233
- "",
7234
- ` ${colorize("MCP not working in client:", COLORS.bold)}`,
7235
- " 1. Verify mcp.json configuration",
7236
- " 2. Restart your MCP client",
7237
- ` 3. Check ${cmd("muggle doctor")} output`,
7238
- "",
7239
- header("Documentation & Support"),
7240
- "",
7241
- ` Docs: ${colorize("https://www.muggle-ai.com/muggleTestV0/docs/mcp/mcp-overview", COLORS.blue)}`,
7242
- ` GitHub: ${colorize("https://github.com/multiplex-ai/muggle-ai-works", COLORS.blue)}`,
7243
- "",
7244
- colorize("=".repeat(70), COLORS.cyan),
7245
- ""
7246
- ];
7247
- return lines.join("\n");
7248
- }
7249
- function helpCommand() {
7250
- console.log(getHelpGuidance());
7251
- }
7252
-
7253
- // src/cli/login.ts
7254
- var logger9 = getLogger();
7255
- async function loginCommand(options) {
7256
- console.log("\nMuggle AI Login");
7257
- console.log("===============\n");
7258
- const expiry = options.keyExpiry || "90d";
7259
- console.log("Starting device code authentication...");
7260
- console.log("A browser window will open for you to complete login.\n");
7261
- const result = await performLogin(options.keyName, expiry);
7262
- if (result.success) {
7263
- console.log("\u2713 Login successful!");
7264
- if (result.credentials?.email) {
7265
- console.log(` Logged in as: ${result.credentials.email}`);
7266
- }
7267
- if (result.credentials?.apiKey) {
7268
- console.log(" API key created and stored for future use.");
7269
- }
7270
- console.log("\nYou can now use Muggle AI Works tools.");
7271
- } else {
7272
- console.error("\u2717 Login failed");
7273
- if (result.error) {
7274
- console.error(` Error: ${result.error}`);
7275
- }
7276
- if (result.deviceCodeResponse) {
7277
- console.log("\nIf browser didn't open, visit:");
7278
- console.log(` ${result.deviceCodeResponse.verificationUriComplete}`);
7279
- console.log(` Code: ${result.deviceCodeResponse.userCode}`);
7280
- }
7281
- process.exit(1);
7282
- }
7283
- }
7284
- async function logoutCommand() {
7285
- console.log("\nLogging out...");
7286
- performLogout();
7287
- console.log("\u2713 Credentials cleared successfully.");
7288
- logger9.info("Logout completed");
7289
- }
7290
- async function statusCommand() {
7291
- console.log("\nAuthentication Status");
7292
- console.log("=====================\n");
7293
- const authService = getAuthService();
7294
- const status = authService.getAuthStatus();
7295
- const hasStoredApiKey = hasApiKey();
7296
- if (status.authenticated) {
7297
- console.log("\u2713 Authenticated");
7298
- if (status.email) {
7299
- console.log(` Email: ${status.email}`);
7300
- }
7301
- if (status.userId) {
7302
- console.log(` User ID: ${status.userId}`);
7303
- }
7304
- if (status.expiresAt) {
7305
- const expiresDate = new Date(status.expiresAt);
7306
- console.log(` Token expires: ${expiresDate.toLocaleString()}`);
7307
- if (status.isExpired) {
7308
- console.log(" (Token expired - will refresh automatically on next API call)");
7309
- }
7310
- }
7311
- console.log(` API Key: ${hasStoredApiKey ? "Yes" : "No"}`);
7312
- } else {
7313
- console.log("\u2717 Not authenticated");
7314
- console.log("\nRun 'muggle login' to authenticate.");
7315
- }
7316
- }
7317
-
7318
- // src/cli/serve.ts
7319
- var logger10 = getLogger();
7320
- async function serveCommand(options) {
7321
- const config = getConfig();
7322
- const enableQa = options.local ? false : true;
7323
- const enableLocal = options.e2e ? false : true;
7324
- logger10.info("Starting Muggle MCP Server", {
7325
- version: config.serverVersion,
7326
- enableQa,
7327
- enableLocal,
7328
- transport: "stdio"
7329
- });
7330
- try {
7331
- if (enableQa) {
7332
- const qaTools = getQaTools();
7333
- registerTools(qaTools);
7334
- logger10.info("Registered cloud E2E acceptance tools", { count: qaTools.length });
7335
- }
7336
- if (enableLocal) {
7337
- const localTools = getLocalQaTools();
7338
- registerTools(localTools);
7339
- logger10.info("Registered local E2E acceptance tools", { count: localTools.length });
7340
- }
7341
- const mcpServer = createUnifiedMcpServer({
7342
- enableQaTools: enableQa,
7343
- enableLocalTools: enableLocal
7344
- });
7345
- await startStdioServer(mcpServer);
7346
- logger10.info("MCP server started successfully");
7347
- } catch (error) {
7348
- logger10.error("Failed to start MCP server", {
7349
- error: error instanceof Error ? error.message : String(error),
7350
- stack: error instanceof Error ? error.stack : void 0
7351
- });
7352
- process.exit(1);
7353
- }
7354
- }
7355
- var logger11 = getLogger();
7356
- var MAX_RETRY_ATTEMPTS = 3;
7357
- var RETRY_BASE_DELAY_MS = 2e3;
7358
- var INSTALL_METADATA_FILE_NAME = ".install-metadata.json";
7359
- function getBinaryName() {
7360
- const os4 = platform();
7361
- const architecture = arch();
7362
- switch (os4) {
7363
- case "darwin": {
7364
- const darwinArch = architecture === "arm64" ? "arm64" : "x64";
7365
- return `MuggleAI-darwin-${darwinArch}.zip`;
7366
- }
7367
- case "win32":
7368
- return "MuggleAI-win32-x64.zip";
7369
- case "linux":
7370
- return "MuggleAI-linux-x64.zip";
7371
- default:
7372
- throw new Error(`Unsupported platform: ${os4}`);
7373
- }
7374
- }
7375
- function getExpectedExecutablePath2(versionDir) {
7376
- const os4 = platform();
7377
- switch (os4) {
7378
- case "darwin":
7379
- return path2.join(versionDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
7380
- case "win32":
7381
- return path2.join(versionDir, "MuggleAI.exe");
7382
- case "linux":
7383
- return path2.join(versionDir, "MuggleAI");
7384
- default:
7385
- throw new Error(`Unsupported platform: ${os4}`);
7386
- }
7387
- }
7388
- async function extractZip(zipPath, destDir) {
7389
- return new Promise((resolve4, reject) => {
7390
- if (platform() === "win32") {
7391
- execFile(
7392
- "powershell",
7393
- ["-command", `Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force`],
7394
- (error) => {
7395
- if (error) {
7396
- reject(error);
7397
- } else {
7398
- resolve4();
7399
- }
7400
- }
7401
- );
7402
- } else {
7403
- execFile("unzip", ["-o", zipPath, "-d", destDir], (error) => {
7404
- if (error) {
7405
- reject(error);
7406
- } else {
7407
- resolve4();
7408
- }
7409
- });
7410
- }
7411
- });
7412
- }
7413
- async function extractTarGz(tarPath, destDir) {
7414
- return new Promise((resolve4, reject) => {
7415
- execFile("tar", ["-xzf", tarPath, "-C", destDir], (error) => {
7416
- if (error) {
7417
- reject(error);
7418
- } else {
7419
- resolve4();
7420
- }
7421
- });
7422
- });
7423
- }
7424
- function sleep2(ms) {
7425
- return new Promise((resolve4) => setTimeout(resolve4, ms));
7426
- }
7427
- async function downloadWithRetry(downloadUrl, destPath) {
7428
- let lastError = null;
7429
- for (let attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
7430
- try {
7431
- if (attempt > 1) {
7432
- const delayMs = RETRY_BASE_DELAY_MS * Math.pow(2, attempt - 2);
7433
- console.log(`Retry attempt ${attempt}/${MAX_RETRY_ATTEMPTS} after ${delayMs}ms delay...`);
7434
- await sleep2(delayMs);
7435
- }
7436
- const response = await fetch(downloadUrl);
7437
- if (!response.ok) {
7438
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
7439
- }
7440
- if (!response.body) {
7441
- throw new Error("No response body received");
7442
- }
7443
- const fileStream = createWriteStream(destPath);
7444
- await pipeline(response.body, fileStream);
7445
- return true;
7446
- } catch (error) {
7447
- lastError = error instanceof Error ? error : new Error(String(error));
7448
- console.error(`Download attempt ${attempt} failed: ${lastError.message}`);
7449
- if (existsSync(destPath)) {
7450
- rmSync(destPath, { force: true });
7451
- }
7452
- }
7453
- }
7454
- if (lastError) {
7455
- throw new Error(`Download failed after ${MAX_RETRY_ATTEMPTS} attempts: ${lastError.message}`);
7456
- }
7457
- return false;
7458
- }
7459
- function writeInstallMetadata(params) {
7460
- const metadata = {
7461
- version: params.version,
7462
- binaryName: params.binaryName,
7463
- platformKey: params.platformKey,
7464
- executableChecksum: params.executableChecksum,
7465
- expectedArchiveChecksum: params.expectedArchiveChecksum,
7466
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
7467
- };
7468
- writeFileSync(params.metadataPath, `${JSON.stringify(metadata, null, 2)}
7469
- `, "utf-8");
7470
- }
7471
- function cleanupFailedInstall(versionDir) {
7472
- if (existsSync(versionDir)) {
7473
- try {
7474
- rmSync(versionDir, { recursive: true, force: true });
7475
- } catch {
7476
- }
7477
- }
7478
- }
7479
- async function setupCommand(options) {
7480
- const version = getElectronAppVersion();
7481
- const versionDir = getElectronAppDir(version);
7482
- const platformKey = getPlatformKey();
7483
- if (!options.force && isElectronAppInstalled()) {
7484
- console.log(`Electron app v${version} is already installed at ${versionDir}`);
7485
- console.log("Use --force to re-download.");
7486
- return;
7487
- }
7488
- const binaryName = getBinaryName();
7489
- const downloadUrl = buildElectronAppReleaseAssetUrl({
7490
- version,
7491
- assetFileName: binaryName
7492
- });
7493
- console.log(`Downloading Muggle Test Electron app v${version}...`);
7494
- console.log(`URL: ${downloadUrl}`);
7495
- try {
7496
- if (existsSync(versionDir)) {
7497
- rmSync(versionDir, { recursive: true, force: true });
7498
- }
7499
- mkdirSync(versionDir, { recursive: true });
7500
- const tempFile = path2.join(versionDir, binaryName);
7501
- await downloadWithRetry(downloadUrl, tempFile);
7502
- console.log("Download complete, verifying checksum...");
7503
- const checksums = getElectronAppChecksums();
7504
- const expectedChecksum = getChecksumForPlatform(checksums);
7505
- const checksumResult = await verifyFileChecksum(tempFile, expectedChecksum);
7506
- if (!checksumResult.valid && expectedChecksum) {
7507
- cleanupFailedInstall(versionDir);
7508
- throw new Error(
7509
- `Checksum verification failed!
7510
- Expected: ${checksumResult.expected}
7511
- Actual: ${checksumResult.actual}
7512
- The downloaded file may be corrupted or tampered with.`
7513
- );
7514
- }
7515
- if (expectedChecksum) {
7516
- console.log("Checksum verified successfully.");
7517
- } else {
7518
- console.log("Warning: No checksum configured, skipping verification.");
7519
- }
7520
- console.log("Extracting...");
7521
- if (binaryName.endsWith(".zip")) {
7522
- await extractZip(tempFile, versionDir);
7523
- } else if (binaryName.endsWith(".tar.gz")) {
7524
- await extractTarGz(tempFile, versionDir);
7525
- }
7526
- const executablePath = getExpectedExecutablePath2(versionDir);
7527
- if (!existsSync(executablePath)) {
7528
- cleanupFailedInstall(versionDir);
7529
- throw new Error(
7530
- `Extraction failed: executable not found at expected path.
7531
- Expected: ${executablePath}
7532
- The archive may be corrupted or in an unexpected format.`
7533
- );
7534
- }
7535
- const executableChecksum = await calculateFileChecksum(executablePath);
7536
- const metadataPath = path2.join(versionDir, INSTALL_METADATA_FILE_NAME);
7537
- writeInstallMetadata({
7538
- metadataPath,
7539
- version,
7540
- binaryName,
7541
- platformKey,
7542
- executableChecksum,
7543
- expectedArchiveChecksum: expectedChecksum
7544
- });
7545
- rmSync(tempFile, { force: true });
7546
- console.log(`Electron app installed to ${versionDir}`);
7547
- logger11.info("Setup complete", { version, path: versionDir });
7548
- } catch (error) {
7549
- const errorMessage = error instanceof Error ? error.message : String(error);
7550
- console.error(`Failed to download Electron app: ${errorMessage}`);
7551
- logger11.error("Setup failed", { error: errorMessage });
7552
- process.exit(1);
7553
- }
7554
- }
7555
- var logger12 = getLogger();
7556
- var GITHUB_RELEASES_API = "https://api.github.com/repos/multiplex-ai/muggle-ai-works/releases";
7557
- var INSTALL_METADATA_FILE_NAME2 = ".install-metadata.json";
7558
- var VERSION_OVERRIDE_FILE2 = "electron-app-version-override.json";
7559
- function getBinaryName2() {
7560
- const os4 = platform();
7561
- const arch3 = process.arch;
7562
- switch (os4) {
7563
- case "darwin":
7564
- return arch3 === "arm64" ? "MuggleAI-darwin-arm64.zip" : "MuggleAI-darwin-x64.zip";
7565
- case "win32":
7566
- return "MuggleAI-win32-x64.zip";
7567
- case "linux":
7568
- return "MuggleAI-linux-x64.zip";
7569
- default:
7570
- throw new Error(`Unsupported platform: ${os4}`);
7571
- }
7572
- }
7573
- function extractVersionFromTag(tag) {
7574
- const match = tag.match(/^(?:electron-app-)?v(\d+\.\d+\.\d+)$/);
7575
- return match ? match[1] : null;
7576
- }
7577
- function getVersionOverridePath() {
7578
- return path2.join(getDataDir2(), VERSION_OVERRIDE_FILE2);
7579
- }
7580
- function getEffectiveElectronAppVersion() {
7581
- const overridePath = getVersionOverridePath();
7582
- if (existsSync(overridePath)) {
7583
- try {
7584
- const content = JSON.parse(__require("fs").readFileSync(overridePath, "utf-8"));
7585
- if (content.version) {
7586
- return content.version;
7587
- }
7588
- } catch {
7589
- }
7590
- }
7591
- return getElectronAppVersion();
7592
- }
7593
- function saveVersionOverride(version) {
7594
- const overridePath = getVersionOverridePath();
7595
- const dataDir = getDataDir2();
7596
- if (!existsSync(dataDir)) {
7597
- mkdirSync(dataDir, { recursive: true });
7598
- }
7599
- writeFileSync(overridePath, JSON.stringify({
7600
- version,
7601
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
7602
- }, null, 2), "utf-8");
7603
- }
7604
- async function checkForUpdates() {
7605
- const currentVersion = getEffectiveElectronAppVersion();
7606
- try {
7607
- const response = await fetch(GITHUB_RELEASES_API, {
7608
- headers: {
7609
- "Accept": "application/vnd.github.v3+json",
7610
- "User-Agent": "muggle"
7611
- }
7612
- });
7613
- if (!response.ok) {
7614
- throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
7615
- }
7616
- const releases = await response.json();
7617
- for (const release2 of releases) {
7618
- if (release2.prerelease || release2.draft) {
7619
- continue;
7620
- }
7621
- const version = extractVersionFromTag(release2.tag_name);
7622
- if (version) {
7623
- const updateAvailable = compareVersions2(version, currentVersion) > 0;
7624
- const binaryName = getBinaryName2();
7625
- return {
7626
- currentVersion,
7627
- latestVersion: version,
7628
- updateAvailable,
7629
- downloadUrl: buildElectronAppReleaseAssetUrl({
7630
- version,
7631
- assetFileName: binaryName
7632
- })
7633
- };
7634
- }
7635
- }
7636
- return {
7637
- currentVersion,
7638
- latestVersion: currentVersion,
7639
- updateAvailable: false
7640
- };
7641
- } catch (error) {
7642
- const errorMessage = error instanceof Error ? error.message : String(error);
7643
- logger12.warn("Failed to check for updates", { error: errorMessage });
7644
- throw new Error(`Failed to check for updates: ${errorMessage}`, { cause: error });
7645
- }
7646
- }
7647
- function compareVersions2(a, b) {
7648
- const partsA = a.split(".").map(Number);
7649
- const partsB = b.split(".").map(Number);
7650
- for (let i = 0; i < 3; i++) {
7651
- const partA = partsA[i] || 0;
7652
- const partB = partsB[i] || 0;
7653
- if (partA > partB) {
7654
- return 1;
7655
- }
7656
- if (partA < partB) {
7657
- return -1;
7658
- }
7659
- }
7660
- return 0;
7661
- }
7662
- function getExpectedExecutablePath3(versionDir) {
7663
- const os4 = platform();
7664
- switch (os4) {
7665
- case "darwin":
7666
- return path2.join(versionDir, "MuggleAI.app", "Contents", "MacOS", "MuggleAI");
7667
- case "win32":
7668
- return path2.join(versionDir, "MuggleAI.exe");
7669
- case "linux":
7670
- return path2.join(versionDir, "MuggleAI");
7671
- default:
7672
- throw new Error(`Unsupported platform: ${os4}`);
7673
- }
7674
- }
7675
- function writeInstallMetadata2(params) {
7676
- const metadata = {
7677
- version: params.version,
7678
- binaryName: params.binaryName,
7679
- platformKey: params.platformKey,
7680
- executableChecksum: params.executableChecksum,
7681
- expectedArchiveChecksum: params.expectedArchiveChecksum,
7682
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
7683
- };
7684
- writeFileSync(params.metadataPath, `${JSON.stringify(metadata, null, 2)}
7685
- `, "utf-8");
7686
- }
7687
- async function extractZip2(zipPath, destDir) {
7688
- return new Promise((resolve4, reject) => {
7689
- if (platform() === "win32") {
7690
- execFile(
7691
- "powershell",
7692
- ["-command", `Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force`],
7693
- (error) => {
7694
- if (error) {
7695
- reject(error);
7696
- } else {
7697
- resolve4();
7698
- }
7699
- }
7700
- );
7701
- } else {
7702
- execFile("unzip", ["-o", zipPath, "-d", destDir], (error) => {
7703
- if (error) {
7704
- reject(error);
7705
- } else {
7706
- resolve4();
7707
- }
7708
- });
7709
- }
7710
- });
7711
- }
7712
- async function extractTarGz2(tarPath, destDir) {
7713
- return new Promise((resolve4, reject) => {
7714
- execFile("tar", ["-xzf", tarPath, "-C", destDir], (error) => {
7715
- if (error) {
7716
- reject(error);
7717
- } else {
7718
- resolve4();
7719
- }
7720
- });
7721
- });
7722
- }
7723
- async function fetchChecksumFromRelease(version) {
7724
- const checksumUrl = buildElectronAppChecksumsUrl(version);
7725
- try {
7726
- const response = await fetch(checksumUrl);
7727
- if (!response.ok) {
7728
- logger12.warn("Checksums file not found in release", { version });
7729
- return "";
7730
- }
7731
- const text = await response.text();
7732
- const binaryName = getBinaryName2();
7733
- const platformKey = getPlatformKey();
7734
- const lines = text.split("\n");
7735
- for (const line of lines) {
7736
- const trimmed = line.trim();
7737
- if (!trimmed) {
7738
- continue;
7739
- }
7740
- const match = trimmed.match(/^([a-fA-F0-9]{64})\s+(.+)$/);
7741
- if (match) {
7742
- const checksum = match[1];
7743
- const filename = match[2];
7744
- if (filename === binaryName || filename.includes(platformKey)) {
7745
- logger12.info("Found checksum in release", {
7746
- version,
7747
- platform: platformKey,
7748
- checksum: checksum.substring(0, 16) + "..."
7749
- });
7750
- return checksum;
7751
- }
7752
- }
7753
- }
7754
- logger12.warn("Platform checksum not found in checksums.txt", {
7755
- version,
7756
- platform: platformKey
7757
- });
7758
- return "";
7759
- } catch (error) {
7760
- const errorMessage = error instanceof Error ? error.message : String(error);
7761
- logger12.warn("Failed to fetch checksums from release", {
7762
- version,
7763
- error: errorMessage
7764
- });
7765
- return "";
7766
- }
7767
- }
7768
- async function downloadAndInstall(version, downloadUrl, checksum) {
7769
- const versionDir = getElectronAppDir(version);
7770
- const binaryName = getBinaryName2();
7771
- const platformKey = getPlatformKey();
7772
- console.log(`Downloading Muggle Test Electron app v${version}...`);
7773
- console.log(`URL: ${downloadUrl}`);
7774
- if (existsSync(versionDir)) {
7775
- rmSync(versionDir, { recursive: true, force: true });
7776
- }
7777
- mkdirSync(versionDir, { recursive: true });
7778
- const response = await fetch(downloadUrl);
7779
- if (!response.ok) {
7780
- throw new Error(`Download failed: ${response.status} ${response.statusText}`);
7781
- }
7782
- const tempFile = path2.join(versionDir, binaryName);
7783
- const fileStream = createWriteStream(tempFile);
7784
- if (!response.body) {
7785
- throw new Error("No response body");
7786
- }
7787
- await pipeline(response.body, fileStream);
7788
- console.log("Download complete, verifying checksum...");
7789
- let expectedChecksum = checksum;
7790
- if (!expectedChecksum) {
7791
- expectedChecksum = await fetchChecksumFromRelease(version);
7792
- }
7793
- const checksumResult = await verifyFileChecksum(tempFile, expectedChecksum || "");
7794
- if (!checksumResult.valid && expectedChecksum) {
7795
- rmSync(versionDir, { recursive: true, force: true });
7796
- throw new Error(
7797
- `Checksum verification failed!
7798
- Expected: ${checksumResult.expected}
7799
- Actual: ${checksumResult.actual}
7800
- The downloaded file may be corrupted or tampered with.`
7801
- );
7802
- }
7803
- if (expectedChecksum) {
7804
- console.log("Checksum verified successfully.");
7805
- } else {
7806
- console.log("Warning: No checksum available, skipping verification.");
7807
- }
7808
- console.log("Extracting...");
7809
- if (binaryName.endsWith(".zip")) {
7810
- await extractZip2(tempFile, versionDir);
7811
- } else if (binaryName.endsWith(".tar.gz")) {
7812
- await extractTarGz2(tempFile, versionDir);
7813
- }
7814
- const executablePath = getExpectedExecutablePath3(versionDir);
7815
- if (!existsSync(executablePath)) {
7816
- rmSync(versionDir, { recursive: true, force: true });
7817
- throw new Error(
7818
- `Extraction failed: executable not found at expected path.
7819
- Expected: ${executablePath}
7820
- The archive may be corrupted or in an unexpected format.`
7821
- );
7822
- }
7823
- const executableChecksum = await calculateFileChecksum(executablePath);
7824
- const metadataPath = path2.join(versionDir, INSTALL_METADATA_FILE_NAME2);
7825
- writeInstallMetadata2({
7826
- metadataPath,
7827
- version,
7828
- binaryName,
7829
- platformKey,
7830
- executableChecksum,
7831
- expectedArchiveChecksum: expectedChecksum || ""
7832
- });
7833
- rmSync(tempFile, { force: true });
7834
- saveVersionOverride(version);
7835
- console.log(`Electron app v${version} installed to ${versionDir}`);
7836
- logger12.info("Upgrade complete", { version, path: versionDir });
7837
- }
7838
- async function upgradeCommand(options) {
7839
- try {
7840
- if (options.version) {
7841
- const binaryName = getBinaryName2();
7842
- const downloadUrl = buildElectronAppReleaseAssetUrl({
7843
- version: options.version,
7844
- assetFileName: binaryName
7845
- });
7846
- await downloadAndInstall(options.version, downloadUrl);
7847
- const cleanupResult2 = cleanupOldVersions({ all: false });
7848
- if (cleanupResult2.removed.length > 0) {
7849
- console.log(
7850
- `
7851
- Cleaned up ${cleanupResult2.removed.length} old version(s), freed ${formatBytes(cleanupResult2.freedBytes)}`
7852
- );
7853
- }
7854
- return;
7855
- }
7856
- console.log("Checking for updates...");
7857
- const result = await checkForUpdates();
7858
- console.log(`Current version: ${result.currentVersion}`);
7859
- console.log(`Latest version: ${result.latestVersion}`);
7860
- if (options.check) {
7861
- if (result.updateAvailable) {
7862
- console.log("\nUpdate available! Run 'muggle upgrade' to install.");
7863
- } else {
7864
- console.log("\nYou are on the latest version.");
7865
- }
7866
- return;
7867
- }
7868
- if (!result.updateAvailable && !options.force) {
7869
- console.log("\nYou are already on the latest version.");
7870
- console.log("Use --force to re-download the current version.");
7871
- return;
7872
- }
7873
- if (!result.downloadUrl) {
7874
- throw new Error("No download URL available");
7875
- }
7876
- await downloadAndInstall(result.latestVersion, result.downloadUrl);
7877
- const cleanupResult = cleanupOldVersions({ all: false });
7878
- if (cleanupResult.removed.length > 0) {
7879
- console.log(
7880
- `
7881
- Cleaned up ${cleanupResult.removed.length} old version(s), freed ${formatBytes(cleanupResult.freedBytes)}`
7882
- );
7883
- }
7884
- } catch (error) {
7885
- const errorMessage = error instanceof Error ? error.message : String(error);
7886
- console.error(`Upgrade failed: ${errorMessage}`);
7887
- logger12.error("Upgrade failed", { error: errorMessage });
7888
- process.exit(1);
7889
- }
7890
- }
7891
-
7892
- // packages/commands/src/cli/run-cli.ts
7893
- var __dirname$1 = dirname(fileURLToPath(import.meta.url));
7894
- function getPackageRoot2() {
7895
- if (__dirname$1.endsWith("dist")) {
7896
- return resolve(__dirname$1, "..");
7897
- }
7898
- return resolve(__dirname$1, "..", "..", "..", "..");
7899
- }
7900
- var packageVersion = JSON.parse(
7901
- readFileSync(resolve(getPackageRoot2(), "package.json"), "utf-8")
7902
- ).version;
7903
- var logger13 = getLogger();
7904
- function createProgram() {
7905
- const program = new Command();
7906
- program.name("muggle").description("Unified MCP server for Muggle AI \u2014 cloud E2E and local E2E testing").version(packageVersion);
7907
- 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);
7908
- program.command("setup").description("Download/update the Electron app for local testing").option("--force", "Force re-download even if already installed").action(setupCommand);
7909
- 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);
7910
- program.command("versions").description("List installed electron-app versions").action(versionsCommand);
7911
- program.command("cleanup").description("Remove old electron-app versions and obsolete skills").option("--all", "Remove all old versions (default: keep one previous)").option("--dry-run", "Show what would be deleted without deleting").option("--skills", "Also clean up obsolete skills from ~/.cursor/skills").action(cleanupCommand);
7912
- program.command("doctor").description("Diagnose installation and configuration issues").action(doctorCommand);
7913
- 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);
7914
- program.command("logout").description("Clear stored credentials").action(logoutCommand);
7915
- program.command("status").description("Show authentication status").action(statusCommand);
7916
- 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);
7917
- program.action(() => {
7918
- helpCommand();
7919
- });
7920
- program.on("command:*", () => {
7921
- helpCommand();
7922
- process.exit(1);
7923
- });
7924
- return program;
7925
- }
7926
- function handleHelpCommand() {
7927
- const args = process.argv.slice(2);
7928
- if (args.length === 1 && args[0] === "help") {
7929
- helpCommand();
7930
- return true;
7931
- }
7932
- return false;
7933
- }
7934
- async function runCli() {
7935
- try {
7936
- if (handleHelpCommand()) {
7937
- return;
7938
- }
7939
- const program = createProgram();
7940
- await program.parseAsync(process.argv);
7941
- } catch (error) {
7942
- logger13.error("CLI error", {
7943
- error: error instanceof Error ? error.message : String(error)
7944
- });
7945
- process.exit(1);
7946
- }
7947
- }
7948
-
7949
- // packages/commands/src/index.ts
7950
- var src_exports2 = {};
7951
- __export(src_exports2, {
7952
- cleanupCommand: () => cleanupCommand,
7953
- doctorCommand: () => doctorCommand,
7954
- helpCommand: () => helpCommand,
7955
- loginCommand: () => loginCommand,
7956
- logoutCommand: () => logoutCommand,
7957
- registerCoreCommands: () => registerCoreCommands,
7958
- runCli: () => runCli,
7959
- serveCommand: () => serveCommand,
7960
- setupCommand: () => setupCommand,
7961
- statusCommand: () => statusCommand,
7962
- upgradeCommand: () => upgradeCommand,
7963
- versionsCommand: () => versionsCommand
7964
- });
7965
-
7966
- // packages/commands/src/registry/register-core-commands.ts
7967
- function registerCoreCommands(commandRegistrationContext) {
7968
- }
7969
-
7970
- 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 };
5911
+ export { __export, __require, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, loadApiKeyData, loadCredentials, local_exports2 as local_exports, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, resetConfig, resetLogger, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, verifyFileChecksum };