@muggleai/works 4.9.2 → 4.10.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.
Files changed (190) hide show
  1. package/README.md +3 -3
  2. package/dist/{chunk-6N7OIBAS.js → chunk-Q7WNEMN4.js} +109 -43
  3. package/dist/{chunk-4KQZLF56.js → chunk-ZKRHFTIC.js} +996 -91
  4. package/dist/cli.js +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  7. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  8. package/dist/plugin/README.md +4 -2
  9. package/dist/plugin/agents/acceptance-tester.md +24 -10
  10. package/dist/plugin/commands/m.md +7 -0
  11. package/dist/plugin/commands/mdo.md +7 -0
  12. package/dist/plugin/commands/mfeedback.md +7 -0
  13. package/dist/plugin/commands/mimport.md +7 -0
  14. package/dist/plugin/commands/mpr.md +7 -0
  15. package/dist/plugin/commands/mprefs.md +7 -0
  16. package/dist/plugin/commands/mregen.md +7 -0
  17. package/dist/plugin/commands/mrelease.md +7 -0
  18. package/dist/plugin/commands/mrepair.md +7 -0
  19. package/dist/plugin/commands/mstatus.md +7 -0
  20. package/dist/plugin/commands/mtest.md +7 -0
  21. package/dist/plugin/commands/mtestlocal.md +7 -0
  22. package/dist/plugin/commands/mtestprep.md +7 -0
  23. package/dist/plugin/commands/mupgrade.md +7 -0
  24. package/dist/plugin/scripts/ensure-electron-app.sh +56 -6
  25. package/dist/plugin/skills/_aliases.json +18 -0
  26. package/dist/plugin/skills/_shared/dev-server-readiness.md +231 -0
  27. package/dist/plugin/skills/_shared/failure-mode-handling.md +244 -0
  28. package/dist/plugin/skills/_shared/post-merge-cleanup.md +10 -0
  29. package/dist/plugin/skills/_shared/rebase-before-e2e.md +15 -0
  30. package/dist/plugin/skills/_shared/telemetry-emit.md +15 -0
  31. package/dist/plugin/skills/_shared/use-worktrees.md +53 -0
  32. package/dist/plugin/skills/do/e2e-acceptance.md +63 -18
  33. package/dist/plugin/skills/do/impact-analysis.md +45 -5
  34. package/dist/plugin/skills/do/open-prs.md +13 -4
  35. package/dist/plugin/skills/do/pr-followup.md +225 -0
  36. package/dist/plugin/skills/do/pre-flight.md +18 -11
  37. package/dist/plugin/skills/m/SKILL.md +8 -0
  38. package/dist/plugin/skills/mdo/SKILL.md +8 -0
  39. package/dist/plugin/skills/mfeedback/SKILL.md +8 -0
  40. package/dist/plugin/skills/mimport/SKILL.md +8 -0
  41. package/dist/plugin/skills/mpr/SKILL.md +8 -0
  42. package/dist/plugin/skills/mprefs/SKILL.md +8 -0
  43. package/dist/plugin/skills/mregen/SKILL.md +8 -0
  44. package/dist/plugin/skills/mrelease/SKILL.md +8 -0
  45. package/dist/plugin/skills/mrepair/SKILL.md +8 -0
  46. package/dist/plugin/skills/mstatus/SKILL.md +8 -0
  47. package/dist/plugin/skills/mtest/SKILL.md +8 -0
  48. package/dist/plugin/skills/mtestlocal/SKILL.md +8 -0
  49. package/dist/plugin/skills/mtestprep/SKILL.md +8 -0
  50. package/dist/plugin/skills/muggle/SKILL.md +11 -17
  51. package/dist/plugin/skills/muggle-do/SKILL.md +22 -4
  52. package/dist/plugin/skills/muggle-do-pr-followup/SKILL.md +37 -0
  53. package/dist/plugin/skills/muggle-do-task/SKILL.md +134 -0
  54. package/dist/plugin/skills/muggle-feedback/SKILL.md +38 -0
  55. package/dist/plugin/skills/muggle-feedback/ops/delete.md +49 -0
  56. package/dist/plugin/skills/muggle-feedback/ops/list.md +65 -0
  57. package/dist/plugin/skills/muggle-feedback/ops/submit.md +117 -0
  58. package/dist/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +73 -55
  59. package/dist/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +86 -0
  60. package/dist/plugin/skills/muggle-preferences/SKILL.md +17 -68
  61. package/dist/plugin/skills/muggle-preferences/ops/change-one.md +10 -0
  62. package/dist/plugin/skills/muggle-preferences/ops/configure.md +49 -0
  63. package/dist/plugin/skills/muggle-preferences/ops/list.md +9 -0
  64. package/dist/plugin/skills/muggle-preferences/ops/reset.md +6 -0
  65. package/dist/plugin/skills/muggle-preferences/ops/set.md +10 -0
  66. package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +58 -0
  67. package/dist/plugin/skills/muggle-preferences/preference-gates/autoCleanup.md +11 -0
  68. package/dist/plugin/skills/muggle-preferences/preference-gates/autoCreatePR.md +13 -0
  69. package/dist/plugin/skills/muggle-preferences/preference-gates/autoDetectChanges.md +11 -0
  70. package/dist/plugin/skills/muggle-preferences/preference-gates/autoE2ETest.md +11 -0
  71. package/dist/plugin/skills/muggle-preferences/preference-gates/autoLogin.md +11 -0
  72. package/dist/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +11 -0
  73. package/dist/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +11 -0
  74. package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +19 -0
  75. package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +16 -0
  76. package/dist/plugin/skills/muggle-preferences/preference-gates/autoUseWorktree.md +11 -0
  77. package/dist/plugin/skills/muggle-preferences/preference-gates/checkForUpdates.md +11 -0
  78. package/dist/plugin/skills/muggle-preferences/preference-gates/defaultExecutionMode.md +15 -0
  79. package/dist/plugin/skills/muggle-preferences/preference-gates/openTestResultsAfterRun.md +11 -0
  80. package/dist/plugin/skills/muggle-preferences/preference-gates/postPRVisualWalkthrough.md +13 -0
  81. package/dist/plugin/skills/muggle-preferences/preference-gates/showElectronBrowser.md +11 -0
  82. package/dist/plugin/skills/muggle-preferences/preference-gates/suggestRelatedTestCases.md +11 -0
  83. package/dist/plugin/skills/muggle-preferences/preference-gates/suggestRelatedUseCases.md +11 -0
  84. package/dist/plugin/skills/muggle-preferences/preference-gates/verboseOutput.md +8 -0
  85. package/dist/plugin/skills/muggle-repair/SKILL.md +4 -2
  86. package/dist/plugin/skills/muggle-status/SKILL.md +14 -16
  87. package/dist/plugin/skills/muggle-test/SKILL.md +148 -123
  88. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +92 -86
  89. package/dist/plugin/skills/muggle-test-import/SKILL.md +74 -35
  90. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +79 -18
  91. package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +49 -35
  92. package/dist/plugin/skills/muggle-test-regenerate-missing/evals/evals.json +9 -9
  93. package/dist/plugin/skills/muggle-upgrade/SKILL.md +4 -2
  94. package/dist/plugin/skills/muggle-works-npm-release/SKILL.md +6 -4
  95. package/dist/plugin/skills/mupgrade/SKILL.md +8 -0
  96. package/dist/release-manifest.json +4 -4
  97. package/dist/src-2G7ENRGI.js +1 -0
  98. package/package.json +10 -8
  99. package/plugin/.claude-plugin/plugin.json +1 -1
  100. package/plugin/.cursor-plugin/plugin.json +1 -1
  101. package/plugin/README.md +4 -2
  102. package/plugin/agents/acceptance-tester.md +24 -10
  103. package/plugin/commands/m.md +7 -0
  104. package/plugin/commands/mdo.md +7 -0
  105. package/plugin/commands/mfeedback.md +7 -0
  106. package/plugin/commands/mimport.md +7 -0
  107. package/plugin/commands/mpr.md +7 -0
  108. package/plugin/commands/mprefs.md +7 -0
  109. package/plugin/commands/mregen.md +7 -0
  110. package/plugin/commands/mrelease.md +7 -0
  111. package/plugin/commands/mrepair.md +7 -0
  112. package/plugin/commands/mstatus.md +7 -0
  113. package/plugin/commands/mtest.md +7 -0
  114. package/plugin/commands/mtestlocal.md +7 -0
  115. package/plugin/commands/mtestprep.md +7 -0
  116. package/plugin/commands/mupgrade.md +7 -0
  117. package/plugin/scripts/ensure-electron-app.sh +56 -6
  118. package/plugin/skills/_aliases.json +18 -0
  119. package/plugin/skills/_shared/dev-server-readiness.md +231 -0
  120. package/plugin/skills/_shared/failure-mode-handling.md +244 -0
  121. package/plugin/skills/_shared/post-merge-cleanup.md +10 -0
  122. package/plugin/skills/_shared/rebase-before-e2e.md +15 -0
  123. package/plugin/skills/_shared/telemetry-emit.md +15 -0
  124. package/plugin/skills/_shared/use-worktrees.md +53 -0
  125. package/plugin/skills/do/e2e-acceptance.md +63 -18
  126. package/plugin/skills/do/impact-analysis.md +45 -5
  127. package/plugin/skills/do/open-prs.md +13 -4
  128. package/plugin/skills/do/pr-followup.md +225 -0
  129. package/plugin/skills/do/pre-flight.md +18 -11
  130. package/plugin/skills/m/SKILL.md +8 -0
  131. package/plugin/skills/mdo/SKILL.md +8 -0
  132. package/plugin/skills/mfeedback/SKILL.md +8 -0
  133. package/plugin/skills/mimport/SKILL.md +8 -0
  134. package/plugin/skills/mpr/SKILL.md +8 -0
  135. package/plugin/skills/mprefs/SKILL.md +8 -0
  136. package/plugin/skills/mregen/SKILL.md +8 -0
  137. package/plugin/skills/mrelease/SKILL.md +8 -0
  138. package/plugin/skills/mrepair/SKILL.md +8 -0
  139. package/plugin/skills/mstatus/SKILL.md +8 -0
  140. package/plugin/skills/mtest/SKILL.md +8 -0
  141. package/plugin/skills/mtestlocal/SKILL.md +8 -0
  142. package/plugin/skills/mtestprep/SKILL.md +8 -0
  143. package/plugin/skills/muggle/SKILL.md +11 -17
  144. package/plugin/skills/muggle-do/SKILL.md +22 -4
  145. package/plugin/skills/muggle-do-pr-followup/SKILL.md +37 -0
  146. package/plugin/skills/muggle-do-task/SKILL.md +134 -0
  147. package/plugin/skills/muggle-feedback/SKILL.md +38 -0
  148. package/plugin/skills/muggle-feedback/ops/delete.md +49 -0
  149. package/plugin/skills/muggle-feedback/ops/list.md +65 -0
  150. package/plugin/skills/muggle-feedback/ops/submit.md +117 -0
  151. package/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +73 -55
  152. package/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +86 -0
  153. package/plugin/skills/muggle-preferences/SKILL.md +17 -68
  154. package/plugin/skills/muggle-preferences/ops/change-one.md +10 -0
  155. package/plugin/skills/muggle-preferences/ops/configure.md +49 -0
  156. package/plugin/skills/muggle-preferences/ops/list.md +9 -0
  157. package/plugin/skills/muggle-preferences/ops/reset.md +6 -0
  158. package/plugin/skills/muggle-preferences/ops/set.md +10 -0
  159. package/plugin/skills/muggle-preferences/preference-gates/README.md +58 -0
  160. package/plugin/skills/muggle-preferences/preference-gates/autoCleanup.md +11 -0
  161. package/plugin/skills/muggle-preferences/preference-gates/autoCreatePR.md +13 -0
  162. package/plugin/skills/muggle-preferences/preference-gates/autoDetectChanges.md +11 -0
  163. package/plugin/skills/muggle-preferences/preference-gates/autoE2ETest.md +11 -0
  164. package/plugin/skills/muggle-preferences/preference-gates/autoLogin.md +11 -0
  165. package/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +11 -0
  166. package/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +11 -0
  167. package/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +19 -0
  168. package/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +16 -0
  169. package/plugin/skills/muggle-preferences/preference-gates/autoUseWorktree.md +11 -0
  170. package/plugin/skills/muggle-preferences/preference-gates/checkForUpdates.md +11 -0
  171. package/plugin/skills/muggle-preferences/preference-gates/defaultExecutionMode.md +15 -0
  172. package/plugin/skills/muggle-preferences/preference-gates/openTestResultsAfterRun.md +11 -0
  173. package/plugin/skills/muggle-preferences/preference-gates/postPRVisualWalkthrough.md +13 -0
  174. package/plugin/skills/muggle-preferences/preference-gates/showElectronBrowser.md +11 -0
  175. package/plugin/skills/muggle-preferences/preference-gates/suggestRelatedTestCases.md +11 -0
  176. package/plugin/skills/muggle-preferences/preference-gates/suggestRelatedUseCases.md +11 -0
  177. package/plugin/skills/muggle-preferences/preference-gates/verboseOutput.md +8 -0
  178. package/plugin/skills/muggle-repair/SKILL.md +4 -2
  179. package/plugin/skills/muggle-status/SKILL.md +14 -16
  180. package/plugin/skills/muggle-test/SKILL.md +148 -123
  181. package/plugin/skills/muggle-test-feature-local/SKILL.md +92 -86
  182. package/plugin/skills/muggle-test-import/SKILL.md +74 -35
  183. package/plugin/skills/muggle-test-prepare/SKILL.md +79 -18
  184. package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +49 -35
  185. package/plugin/skills/muggle-test-regenerate-missing/evals/evals.json +9 -9
  186. package/plugin/skills/muggle-upgrade/SKILL.md +4 -2
  187. package/plugin/skills/muggle-works-npm-release/SKILL.md +6 -4
  188. package/plugin/skills/mupgrade/SKILL.md +8 -0
  189. package/scripts/postinstall.mjs +11 -1
  190. package/dist/src-7GB7WIFT.js +0 -1
@@ -11,6 +11,7 @@ import { fileURLToPath } from 'url';
11
11
  import { spawn, exec } from 'child_process';
12
12
  import axios, { AxiosError } from 'axios';
13
13
  import * as fs7 from 'fs/promises';
14
+ import AppInsights from 'applicationinsights';
14
15
  import { z } from 'zod';
15
16
 
16
17
  var __defProp = Object.defineProperty;
@@ -33,6 +34,7 @@ __export(src_exports, {
33
34
  PREFERENCES_PROJECT_DIR_NAME: () => PREFERENCES_PROJECT_DIR_NAME,
34
35
  PREFERENCES_SCHEMA: () => PREFERENCES_SCHEMA,
35
36
  PREFERENCES_VERSION: () => PREFERENCES_VERSION,
37
+ PREFERENCE_ALLOWED_VALUES: () => PREFERENCE_ALLOWED_VALUES,
36
38
  PreferenceKey: () => PreferenceKey,
37
39
  PreferenceValue: () => PreferenceValue,
38
40
  buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
@@ -83,6 +85,7 @@ __export(src_exports, {
83
85
  resetConfig: () => resetConfig,
84
86
  resetLogger: () => resetLogger,
85
87
  resetPreference: () => resetPreference,
88
+ resolveElectronAppPathOrNull: () => resolveElectronAppPathOrNull,
86
89
  resolvePreferences: () => resolvePreferences,
87
90
  saveApiKey: () => saveApiKey,
88
91
  saveApiKeyData: () => saveApiKeyData,
@@ -394,7 +397,6 @@ function buildLocalQaConfig() {
394
397
  tempDir: path2.join(dataDir, "temp"),
395
398
  apiKeyFilePath: path2.join(dataDir, API_KEY_FILE),
396
399
  oauthSessionFilePath: path2.join(dataDir, "oauth-session.json"),
397
- electronAppPath: resolveElectronAppPathOrNull(),
398
400
  webServicePath: resolveWebServicePath(),
399
401
  webServicePidFile: path2.join(dataDir, "web-service.pid"),
400
402
  auth0: {
@@ -526,9 +528,9 @@ function resetLogger() {
526
528
  // packages/mcps/src/shared/checksum.ts
527
529
  var logger = getLogger();
528
530
  function getPlatformKey() {
529
- const os4 = platform();
531
+ const os5 = platform();
530
532
  const arch2 = process.arch;
531
- switch (os4) {
533
+ switch (os5) {
532
534
  case "darwin":
533
535
  return arch2 === "arm64" ? "darwin-arm64" : "darwin-x64";
534
536
  case "win32":
@@ -536,7 +538,7 @@ function getPlatformKey() {
536
538
  case "linux":
537
539
  return "linux-x64";
538
540
  default:
539
- throw new Error(`Unsupported platform: ${os4}`);
541
+ throw new Error(`Unsupported platform: ${os5}`);
540
542
  }
541
543
  }
542
544
  async function calculateFileChecksum(filePath) {
@@ -1998,7 +2000,7 @@ function getAuthenticatedUserId() {
1998
2000
  }
1999
2001
  async function findPackageJsonAsync() {
2000
2002
  const currentFileUrl = import.meta.url;
2001
- const currentDir = path2.dirname(new URL(currentFileUrl).pathname);
2003
+ const currentDir = path2.dirname(fileURLToPath(currentFileUrl));
2002
2004
  const candidatePaths = [
2003
2005
  path2.resolve(currentDir, "../../../package.json"),
2004
2006
  path2.resolve(currentDir, "../package.json"),
@@ -2100,29 +2102,28 @@ async function writeExecutionLogs(params) {
2100
2102
  });
2101
2103
  }
2102
2104
  function getElectronAppPathOrThrow() {
2103
- const config = getConfig();
2104
- const electronAppPath = config.localQa.electronAppPath;
2105
- if (!electronAppPath || electronAppPath.trim() === "") {
2106
- const version = getElectronAppVersion();
2107
- const versionDir = getElectronAppDir(version);
2108
- const envPath = process.env.ELECTRON_APP_PATH;
2109
- const errorLines = [
2110
- "Electron app binary not found.",
2111
- "",
2112
- ` Expected version: ${version}`,
2113
- ` Checked directory: ${versionDir}`
2114
- ];
2115
- if (envPath) {
2116
- errorLines.push(` ELECTRON_APP_PATH: ${envPath} (not found or invalid)`);
2117
- } else {
2118
- errorLines.push(" ELECTRON_APP_PATH: (not set)");
2119
- }
2120
- errorLines.push("");
2121
- errorLines.push("To fix this, run: muggle setup");
2122
- errorLines.push("Or set ELECTRON_APP_PATH to the path of the MuggleAI executable.");
2123
- throw new Error(errorLines.join("\n"));
2105
+ const electronAppPath = resolveElectronAppPathOrNull();
2106
+ if (electronAppPath && electronAppPath.trim() !== "") {
2107
+ return electronAppPath;
2124
2108
  }
2125
- return electronAppPath;
2109
+ const version = getElectronAppVersion();
2110
+ const versionDir = getElectronAppDir(version);
2111
+ const envPath = process.env.ELECTRON_APP_PATH;
2112
+ const errorLines = [
2113
+ "Electron app binary not found.",
2114
+ "",
2115
+ ` Expected version: ${version}`,
2116
+ ` Checked directory: ${versionDir}`
2117
+ ];
2118
+ if (envPath) {
2119
+ errorLines.push(` ELECTRON_APP_PATH: ${envPath} (not found or invalid)`);
2120
+ } else {
2121
+ errorLines.push(" ELECTRON_APP_PATH: (not set)");
2122
+ }
2123
+ errorLines.push("");
2124
+ errorLines.push("To fix this, run: muggle setup");
2125
+ errorLines.push("Or set ELECTRON_APP_PATH to the path of the MuggleAI executable.");
2126
+ throw new Error(errorLines.join("\n"));
2126
2127
  }
2127
2128
  function getRequiredStringField(params) {
2128
2129
  const value = params.source[params.fieldName];
@@ -2222,7 +2223,7 @@ function buildReplayActionScript(params) {
2222
2223
  async function executeElectronAppAsync(params) {
2223
2224
  const mode = params.runType === "generation" ? "explore" : "engine";
2224
2225
  const electronAppPath = getElectronAppPathOrThrow();
2225
- const spawnArgs = [mode, params.scriptFilePath, "", params.authFilePath];
2226
+ const spawnArgs = [mode, params.scriptFilePath, params.mutationsFilePath ?? "", params.authFilePath];
2226
2227
  if (params.showUi) {
2227
2228
  spawnArgs.push("--show-ui");
2228
2229
  }
@@ -2370,11 +2371,16 @@ async function executeTestGeneration(params) {
2370
2371
  filename: `${runId}_auth.json`,
2371
2372
  data: authContent
2372
2373
  });
2374
+ const mutationsFilePath = params.mutations && params.mutations.length > 0 ? await writeTempFile({
2375
+ filename: `${runId}_mutations.json`,
2376
+ data: params.mutations
2377
+ }) : void 0;
2373
2378
  try {
2374
2379
  const executionResult = await executeElectronAppAsync({
2375
2380
  runId,
2376
2381
  runType: "generation",
2377
2382
  scriptFilePath: inputFilePath,
2383
+ mutationsFilePath,
2378
2384
  authFilePath,
2379
2385
  timeoutMs,
2380
2386
  showUi: params.showUi,
@@ -2517,11 +2523,16 @@ async function executeReplay(params) {
2517
2523
  filename: `${runId}_auth.json`,
2518
2524
  data: authContent
2519
2525
  });
2526
+ const mutationsFilePath = params.mutations && params.mutations.length > 0 ? await writeTempFile({
2527
+ filename: `${runId}_mutations.json`,
2528
+ data: params.mutations
2529
+ }) : void 0;
2520
2530
  try {
2521
2531
  const executionResult = await executeElectronAppAsync({
2522
2532
  runId,
2523
2533
  runType: "replay",
2524
2534
  scriptFilePath: inputFilePath,
2535
+ mutationsFilePath,
2525
2536
  authFilePath,
2526
2537
  timeoutMs,
2527
2538
  showUi: params.showUi,
@@ -2990,6 +3001,268 @@ __export(e2e_exports, {
2990
3001
  executeQaTool: () => executeQaTool,
2991
3002
  getQaToolByName: () => getQaToolByName
2992
3003
  });
3004
+
3005
+ var ENV_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
3006
+ var ENV_VITE_CONNECTION_STRING = "VITE_APPLICATIONINSIGHTS_CONNECTION_STRING";
3007
+ var ENV_TELEMETRY_DISABLED = "MUGGLE_TELEMETRY_DISABLED";
3008
+
3009
+ var DATA_DIR_NAME2 = ".muggle-ai";
3010
+ var INSTALL_ID_FILENAME = "install-id.json";
3011
+ var PREFS_FILENAME = "preferences.json";
3012
+ var OAUTH_SESSION_FILENAME = "oauth-session.json";
3013
+ var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
3014
+ function getDataDir3() {
3015
+ return path2.join(os3.homedir(), DATA_DIR_NAME2);
3016
+ }
3017
+
3018
+ var cachedInstallId;
3019
+ function installIdFilePath() {
3020
+ return join(getDataDir3(), INSTALL_ID_FILENAME);
3021
+ }
3022
+ function generateAndPersist(filePath) {
3023
+ const installId = randomUUID();
3024
+ const contents = { installId };
3025
+ mkdirSync(dirname(filePath), { recursive: true });
3026
+ writeFileSync(filePath, JSON.stringify(contents, null, 2) + "\n", "utf8");
3027
+ return installId;
3028
+ }
3029
+ function isValid(value) {
3030
+ return typeof value === "object" && value !== null && typeof value.installId === "string" && value.installId.length > 0;
3031
+ }
3032
+ function getInstallId() {
3033
+ if (cachedInstallId !== void 0)
3034
+ return cachedInstallId;
3035
+ const filePath = installIdFilePath();
3036
+ if (!existsSync(filePath)) {
3037
+ cachedInstallId = generateAndPersist(filePath);
3038
+ return cachedInstallId;
3039
+ }
3040
+ try {
3041
+ const raw = readFileSync(filePath, "utf8");
3042
+ const parsed = JSON.parse(raw);
3043
+ if (isValid(parsed)) {
3044
+ cachedInstallId = parsed.installId;
3045
+ return cachedInstallId;
3046
+ }
3047
+ cachedInstallId = generateAndPersist(filePath);
3048
+ return cachedInstallId;
3049
+ } catch {
3050
+ cachedInstallId = generateAndPersist(filePath);
3051
+ return cachedInstallId;
3052
+ }
3053
+ }
3054
+
3055
+ var DEV_MANIFEST2 = {
3056
+ release: "dev",
3057
+ buildId: "dev",
3058
+ commitSha: "dev",
3059
+ buildTime: "1970-01-01T00:00:00Z",
3060
+ serviceName: "muggle-ai-telemetry"
3061
+ };
3062
+
3063
+ var MANIFEST_PATH2 = (() => {
3064
+ try {
3065
+ return join(dirname(fileURLToPath(import.meta.url)), RELEASE_MANIFEST_FILENAME);
3066
+ } catch {
3067
+ return RELEASE_MANIFEST_FILENAME;
3068
+ }
3069
+ })();
3070
+ var cachedManifest2;
3071
+ function isValid2(value) {
3072
+ if (typeof value !== "object" || value === null)
3073
+ return false;
3074
+ const m = value;
3075
+ return typeof m.release === "string" && typeof m.buildId === "string" && typeof m.commitSha === "string" && typeof m.buildTime === "string" && typeof m.serviceName === "string";
3076
+ }
3077
+ function readReleaseManifest2() {
3078
+ if (cachedManifest2 !== void 0)
3079
+ return cachedManifest2;
3080
+ const path15 = MANIFEST_PATH2;
3081
+ try {
3082
+ const raw = readFileSync(path15, "utf8");
3083
+ const parsed = JSON.parse(raw);
3084
+ cachedManifest2 = isValid2(parsed) ? parsed : DEV_MANIFEST2;
3085
+ return cachedManifest2;
3086
+ } catch (err) {
3087
+ const code = err.code;
3088
+ if (code !== "ENOENT") {
3089
+ console.warn("release-manifest: unexpected read error, using DEV fallback", {
3090
+ error: err.message
3091
+ });
3092
+ }
3093
+ cachedManifest2 = DEV_MANIFEST2;
3094
+ return cachedManifest2;
3095
+ }
3096
+ }
3097
+ function readUserId() {
3098
+ const filePath = join(getDataDir3(), OAUTH_SESSION_FILENAME);
3099
+ if (!existsSync(filePath))
3100
+ return void 0;
3101
+ try {
3102
+ const raw = readFileSync(filePath, "utf8");
3103
+ const parsed = JSON.parse(raw);
3104
+ if (typeof parsed.userId === "string" && parsed.userId.length > 0) {
3105
+ return parsed.userId;
3106
+ }
3107
+ return void 0;
3108
+ } catch {
3109
+ return void 0;
3110
+ }
3111
+ }
3112
+
3113
+ var state = null;
3114
+ function resolveConnectionString(explicit) {
3115
+ if (explicit && explicit.length > 0)
3116
+ return explicit;
3117
+ return process.env[ENV_CONNECTION_STRING] ?? process.env[ENV_VITE_CONNECTION_STRING] ?? void 0;
3118
+ }
3119
+ function buildCommonProperties(serviceName, surface) {
3120
+ const manifest = readReleaseManifest2();
3121
+ const props = {
3122
+ source: "client",
3123
+ serviceName,
3124
+ surface,
3125
+ release: manifest.release,
3126
+ buildId: manifest.buildId,
3127
+ commitSha: manifest.commitSha,
3128
+ buildTime: manifest.buildTime,
3129
+ installId: getInstallId(),
3130
+ nodeVersion: process.version,
3131
+ platform: process.platform
3132
+ };
3133
+ const userId = readUserId();
3134
+ if (userId !== void 0)
3135
+ props.userId = userId;
3136
+ return props;
3137
+ }
3138
+ function initTelemetry(options) {
3139
+ if (state !== null && state.initialized)
3140
+ return;
3141
+ const connectionString = resolveConnectionString(options.connectionString);
3142
+ if (!connectionString) {
3143
+ state = {
3144
+ client: null,
3145
+ serviceName: options.serviceName,
3146
+ surface: options.surface,
3147
+ initialized: true
3148
+ };
3149
+ return;
3150
+ }
3151
+ try {
3152
+ AppInsights.setup(connectionString).setUseDiskRetryCaching(true).setDistributedTracingMode(AppInsights.DistributedTracingModes.AI_AND_W3C).setAutoCollectRequests(false).setAutoCollectPerformance(false, false).setAutoCollectExceptions(true).setAutoCollectDependencies(false).setAutoCollectConsole(false).setSendLiveMetrics(false);
3153
+ const client = AppInsights.defaultClient;
3154
+ const manifest = readReleaseManifest2();
3155
+ client.context.tags[client.context.keys.cloudRole] = options.serviceName;
3156
+ client.context.tags[client.context.keys.applicationVersion] = manifest.release;
3157
+ client.commonProperties = {
3158
+ ...client.commonProperties,
3159
+ ...buildCommonProperties(options.serviceName, options.surface)
3160
+ };
3161
+ AppInsights.start();
3162
+ state = {
3163
+ client,
3164
+ serviceName: options.serviceName,
3165
+ surface: options.surface,
3166
+ initialized: true
3167
+ };
3168
+ } catch (err) {
3169
+ console.warn("[muggle-telemetry] init failed; events will be dropped", {
3170
+ error: err.message
3171
+ });
3172
+ state = {
3173
+ client: null,
3174
+ serviceName: options.serviceName,
3175
+ surface: options.surface,
3176
+ initialized: true
3177
+ };
3178
+ }
3179
+ }
3180
+ function getClient() {
3181
+ return state?.client ?? null;
3182
+ }
3183
+ function prefsFilePath() {
3184
+ return join(getDataDir3(), PREFS_FILENAME);
3185
+ }
3186
+ function readPreferences() {
3187
+ const filePath = prefsFilePath();
3188
+ if (!existsSync(filePath))
3189
+ return {};
3190
+ try {
3191
+ const raw = readFileSync(filePath, "utf8");
3192
+ const parsed = JSON.parse(raw);
3193
+ if (typeof parsed === "object" && parsed !== null) {
3194
+ return parsed;
3195
+ }
3196
+ return {};
3197
+ } catch {
3198
+ return {};
3199
+ }
3200
+ }
3201
+
3202
+ function isTelemetryEnabled() {
3203
+ if (process.env[ENV_TELEMETRY_DISABLED] === "1")
3204
+ return false;
3205
+ const prefs = readPreferences();
3206
+ if (prefs.telemetryEnabled === false)
3207
+ return false;
3208
+ return true;
3209
+ }
3210
+
3211
+ function track(event) {
3212
+ if (!isTelemetryEnabled())
3213
+ return;
3214
+ const client = getClient();
3215
+ if (!client)
3216
+ return;
3217
+ try {
3218
+ client.trackEvent({
3219
+ name: event.name,
3220
+ properties: event.props
3221
+ });
3222
+ } catch {
3223
+ }
3224
+ }
3225
+
3226
+ var Trigger;
3227
+ (function(Trigger2) {
3228
+ Trigger2["UserSlash"] = "user-slash";
3229
+ Trigger2["ClaudeProactive"] = "claude-proactive";
3230
+ Trigger2["NestedSkill"] = "nested-skill";
3231
+ })(Trigger || (Trigger = {}));
3232
+ var Outcome;
3233
+ (function(Outcome2) {
3234
+ Outcome2["Success"] = "success";
3235
+ Outcome2["Error"] = "error";
3236
+ Outcome2["Cancelled"] = "cancelled";
3237
+ })(Outcome || (Outcome = {}));
3238
+ var ToolSurface;
3239
+ (function(ToolSurface2) {
3240
+ ToolSurface2["Local"] = "local";
3241
+ ToolSurface2["Remote"] = "remote";
3242
+ })(ToolSurface || (ToolSurface = {}));
3243
+ var Surface;
3244
+ (function(Surface2) {
3245
+ Surface2["McpLocal"] = "mcp-local";
3246
+ Surface2["McpRemote"] = "mcp-remote";
3247
+ Surface2["Skill"] = "skill";
3248
+ Surface2["Electron"] = "electron";
3249
+ })(Surface || (Surface = {}));
3250
+ var ServiceName;
3251
+ (function(ServiceName2) {
3252
+ ServiceName2["MuggleMcp"] = "muggle-mcp";
3253
+ ServiceName2["MuggleElectron"] = "muggle-electron";
3254
+ ServiceName2["MuggleSkill"] = "muggle-skill";
3255
+ })(ServiceName || (ServiceName = {}));
3256
+ var EventName;
3257
+ (function(EventName2) {
3258
+ EventName2["SkillInvoked"] = "skill.invoked";
3259
+ EventName2["SkillCompleted"] = "skill.completed";
3260
+ EventName2["McpToolInvoked"] = "mcp.tool.invoked";
3261
+ EventName2["McpToolCompleted"] = "mcp.tool.completed";
3262
+ EventName2["SystemStartup"] = "system.startup";
3263
+ EventName2["SystemOptOutChanged"] = "system.opt_out_changed";
3264
+ EventName2["SystemDisclosureShown"] = "system.disclosure_shown";
3265
+ })(EventName || (EventName = {}));
2993
3266
  var MuggleEntityIdSchema = z.string().uuid();
2994
3267
  var LocalExecutionContextInputSchema = z.object({
2995
3268
  originalUrl: z.string().url().describe("Original local URL used during local execution (typically localhost)"),
@@ -3133,6 +3406,21 @@ var UseCaseUpdateFromPromptInputSchema = z.object({
3133
3406
  useCaseId: IdSchema.describe("Use case ID (UUID) to update"),
3134
3407
  instruction: z.string().min(1).describe("Natural language instruction to regenerate the use case from")
3135
3408
  });
3409
+ var UseCaseUpdateInputSchema = z.object({
3410
+ useCaseId: IdSchema.describe("Use case ID (UUID) to update"),
3411
+ title: z.string().min(1).optional().describe("Updated use case title"),
3412
+ description: z.string().min(1).optional().describe("Updated description"),
3413
+ userStory: z.string().min(1).optional().describe("Updated one-line user story"),
3414
+ url: z.string().url().optional().describe("Updated target URL"),
3415
+ useCaseBreakdown: z.array(z.object({
3416
+ requirement: z.string().min(1).describe("One requirement of the use case"),
3417
+ acceptanceCriteria: z.string().min(1).describe("Concrete, measurable acceptance criteria for the requirement")
3418
+ })).optional().describe("Updated main/alternative/error flows as requirement + acceptance criteria pairs"),
3419
+ status: z.enum(["DRAFT", "IN_REVIEW", "APPROVED", "IMPLEMENTED", "ARCHIVED"]).optional().describe("Updated status"),
3420
+ priority: z.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]).optional().describe("Updated priority"),
3421
+ source: z.enum(["PRD_FILE", "SITEMAP", "CRAWLER", "PROMPT", "MANUAL"]).optional().describe("Updated source"),
3422
+ category: z.string().optional().describe("Updated category")
3423
+ });
3136
3424
  var UseCaseCreateInputSchema = z.object({
3137
3425
  projectId: IdSchema.describe("Project ID (UUID) the use case belongs to"),
3138
3426
  title: z.string().min(1).describe("Use case title"),
@@ -3216,6 +3504,20 @@ var TestCaseCreateInputSchema = z.object({
3216
3504
  category: z.string().optional().describe("Test case category"),
3217
3505
  automated: z.boolean().optional().describe("Whether this test case is automated (default: true)")
3218
3506
  });
3507
+ var TestCaseUpdateInputSchema = z.object({
3508
+ testCaseId: IdSchema.describe("Test case ID (UUID) to update"),
3509
+ title: z.string().min(1).optional().describe("Updated test case title"),
3510
+ description: z.string().min(1).optional().describe("Updated description"),
3511
+ goal: z.string().min(1).optional().describe("Updated goal"),
3512
+ precondition: z.string().optional().describe("Updated precondition"),
3513
+ expectedResult: z.string().min(1).optional().describe("Updated expected result"),
3514
+ url: z.string().url().optional().describe("Updated target URL"),
3515
+ status: z.enum(["DRAFT", "ACTIVE", "DEPRECATED", "ARCHIVED"]).optional().describe("Updated status"),
3516
+ priority: z.enum(["HIGH", "MEDIUM", "LOW"]).optional().describe("Updated priority"),
3517
+ tags: z.array(z.string()).optional().describe("Updated tags"),
3518
+ category: z.string().optional().describe("Updated category"),
3519
+ automated: z.boolean().optional().describe("Whether this test case is automated")
3520
+ });
3219
3521
  var TestScriptListInputSchema = z.object({
3220
3522
  projectId: IdSchema.describe("Project ID (UUID) to list test scripts for"),
3221
3523
  testCaseId: IdSchema.optional().describe("Optional test case ID (UUID) to filter scripts by")
@@ -3366,6 +3668,34 @@ var ApiKeyGetInputSchema = z.object({
3366
3668
  var ApiKeyRevokeInputSchema = z.object({
3367
3669
  apiKeyId: ApiKeyRecordIdSchema.describe("ID of the API key record to revoke")
3368
3670
  });
3671
+ var UserFeedbackTargetTypeSchema = z.enum(["actionScript", "step"]);
3672
+ var UserFeedbackTargetSchema = z.object({
3673
+ targetType: UserFeedbackTargetTypeSchema.describe("Target entity kind: 'actionScript' for whole-script feedback, 'step' for a specific step"),
3674
+ targetId: z.string().min(1).describe("Target identifier. For 'actionScript' use the actionScriptId; for 'step' use `${actionScriptId}:${stepIndex}` (0-based stepIndex)")
3675
+ });
3676
+ var UserFeedbackCreateInputSchema = z.object({
3677
+ projectId: IdSchema.describe("Project ID (UUID) the feedback belongs to"),
3678
+ target: UserFeedbackTargetSchema.describe("What entity this feedback is about (action script or a specific step)"),
3679
+ feedbackText: z.string().min(1).describe("Free-form paragraph describing what went wrong and what the expected behavior should be")
3680
+ });
3681
+ var UserFeedbackListInputSchema = z.object({
3682
+ projectId: IdSchema.describe("Project ID (UUID) to list feedback for. Always required \u2014 defines the auth boundary."),
3683
+ actionScriptId: IdSchema.optional().describe("Narrow to feedback whose target resolves to this action script. Mutually exclusive with the other narrowing filters."),
3684
+ testScriptId: IdSchema.optional().describe("Narrow to feedback on the action script of this test script. Mutually exclusive with the other narrowing filters."),
3685
+ testCaseId: IdSchema.optional().describe("Narrow to feedback on any action script ever generated for this test case. Mutually exclusive with the other narrowing filters."),
3686
+ useCaseId: IdSchema.optional().describe("Narrow to feedback on any action script ever generated under this use case. Mutually exclusive with the other narrowing filters."),
3687
+ limit: z.number().int().positive().max(1e3).optional().describe("Max entries to return (default 100)"),
3688
+ offset: z.number().int().min(0).optional().describe("Offset for pagination (default 0)")
3689
+ }).refine(
3690
+ (data) => {
3691
+ const set = [data.actionScriptId, data.testScriptId, data.testCaseId, data.useCaseId].filter(Boolean);
3692
+ return set.length <= 1;
3693
+ },
3694
+ { message: "At most one of actionScriptId / testScriptId / testCaseId / useCaseId may be set" }
3695
+ );
3696
+ var UserFeedbackDeleteInputSchema = z.object({
3697
+ feedbackId: IdSchema.describe("User feedback ID (UUID) to soft-delete")
3698
+ });
3369
3699
  var AuthLoginInputSchema = z.object({
3370
3700
  waitForCompletion: z.boolean().optional().describe("Whether to wait for browser login completion before returning. Default: true"),
3371
3701
  timeoutMs: z.number().int().positive().min(1e3).max(9e5).optional().describe("Maximum time to wait for login completion in milliseconds. Default: 120000"),
@@ -3418,40 +3748,40 @@ function detectMcpHost(env = process.env) {
3418
3748
  }
3419
3749
  return "unknown";
3420
3750
  }
3421
- var INSTALL_ID_FILENAME = "install-id.json";
3422
- var cachedInstallId;
3423
- function installIdFilePath() {
3424
- return join(getDataDir(), INSTALL_ID_FILENAME);
3751
+ var INSTALL_ID_FILENAME2 = "install-id.json";
3752
+ var cachedInstallId2;
3753
+ function installIdFilePath2() {
3754
+ return join(getDataDir(), INSTALL_ID_FILENAME2);
3425
3755
  }
3426
- function generateAndPersist(filePath) {
3756
+ function generateAndPersist2(filePath) {
3427
3757
  const installId = randomUUID();
3428
3758
  const contents = { installId };
3429
3759
  mkdirSync(dirname(filePath), { recursive: true });
3430
3760
  writeFileSync(filePath, JSON.stringify(contents, null, 2) + "\n", "utf8");
3431
3761
  return installId;
3432
3762
  }
3433
- function isValid(value) {
3763
+ function isValid3(value) {
3434
3764
  return typeof value === "object" && value !== null && typeof value.installId === "string" && value.installId.length > 0;
3435
3765
  }
3436
- function getInstallId() {
3437
- if (cachedInstallId !== void 0) return cachedInstallId;
3438
- const filePath = installIdFilePath();
3766
+ function getInstallId2() {
3767
+ if (cachedInstallId2 !== void 0) return cachedInstallId2;
3768
+ const filePath = installIdFilePath2();
3439
3769
  if (!existsSync(filePath)) {
3440
- cachedInstallId = generateAndPersist(filePath);
3441
- return cachedInstallId;
3770
+ cachedInstallId2 = generateAndPersist2(filePath);
3771
+ return cachedInstallId2;
3442
3772
  }
3443
3773
  try {
3444
3774
  const raw = readFileSync(filePath, "utf8");
3445
3775
  const parsed = JSON.parse(raw);
3446
- if (isValid(parsed)) {
3447
- cachedInstallId = parsed.installId;
3448
- return cachedInstallId;
3776
+ if (isValid3(parsed)) {
3777
+ cachedInstallId2 = parsed.installId;
3778
+ return cachedInstallId2;
3449
3779
  }
3450
- cachedInstallId = generateAndPersist(filePath);
3451
- return cachedInstallId;
3780
+ cachedInstallId2 = generateAndPersist2(filePath);
3781
+ return cachedInstallId2;
3452
3782
  } catch {
3453
- cachedInstallId = generateAndPersist(filePath);
3454
- return cachedInstallId;
3783
+ cachedInstallId2 = generateAndPersist2(filePath);
3784
+ return cachedInstallId2;
3455
3785
  }
3456
3786
  }
3457
3787
 
@@ -3481,17 +3811,17 @@ var PromptServiceClient = class {
3481
3811
  * @param path - Path to validate.
3482
3812
  * @throws GatewayError if path is not allowed.
3483
3813
  */
3484
- validatePath(path11) {
3485
- const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path11.startsWith(prefix));
3814
+ validatePath(path15) {
3815
+ const isAllowed = ALLOWED_UPSTREAM_PREFIXES.some((prefix) => path15.startsWith(prefix));
3486
3816
  if (!isAllowed) {
3487
3817
  const logger6 = getLogger();
3488
3818
  logger6.error("Path not in allowlist", {
3489
- path: path11,
3819
+ path: path15,
3490
3820
  allowedPrefixes: ALLOWED_UPSTREAM_PREFIXES
3491
3821
  });
3492
3822
  throw new GatewayError({
3493
3823
  code: "FORBIDDEN" /* FORBIDDEN */,
3494
- message: `Path '${path11}' is not allowed`
3824
+ message: `Path '${path15}' is not allowed`
3495
3825
  });
3496
3826
  }
3497
3827
  }
@@ -3503,7 +3833,7 @@ var PromptServiceClient = class {
3503
3833
  */
3504
3834
  buildHeaders(credentials, correlationId) {
3505
3835
  const manifest = readReleaseManifest();
3506
- const installId = getInstallId();
3836
+ const installId = getInstallId2();
3507
3837
  const host = detectMcpHost();
3508
3838
  const headers = {
3509
3839
  "X-Correlation-Id": correlationId,
@@ -3889,6 +4219,29 @@ var useCaseTools = [
3889
4219
  };
3890
4220
  }
3891
4221
  },
4222
+ {
4223
+ name: "muggle-remote-use-case-update",
4224
+ description: "Directly update an existing use case's fields without invoking the LLM. Pass only the fields you want to change \u2014 others are left untouched. Use this for cheap, deterministic edits (rename, flip status DRAFT\u2192APPROVED, change priority, edit acceptance criteria). For LLM regeneration from a new instruction, use muggle-remote-use-case-update-from-prompt instead. Note: changing title, description, or url triggers background regeneration of dependent test cases on the server.",
4225
+ inputSchema: UseCaseUpdateInputSchema,
4226
+ mapToUpstream: (input) => {
4227
+ const data = input;
4228
+ const body = { id: data.useCaseId };
4229
+ if (data.title !== void 0) body.title = data.title;
4230
+ if (data.description !== void 0) body.description = data.description;
4231
+ if (data.userStory !== void 0) body.userStory = data.userStory;
4232
+ if (data.url !== void 0) body.url = data.url;
4233
+ if (data.useCaseBreakdown !== void 0) body.useCaseBreakdown = data.useCaseBreakdown;
4234
+ if (data.status !== void 0) body.status = data.status;
4235
+ if (data.priority !== void 0) body.priority = data.priority;
4236
+ if (data.source !== void 0) body.source = data.source;
4237
+ if (data.category !== void 0) body.category = data.category;
4238
+ return {
4239
+ method: "PUT",
4240
+ path: `${MUGGLE_TEST_PREFIX}/use-cases/${data.useCaseId}`,
4241
+ body
4242
+ };
4243
+ }
4244
+ },
3892
4245
  {
3893
4246
  name: "muggle-remote-use-case-create",
3894
4247
  description: "Create a single use case from a fully-specified payload. Use this to persist use cases returned by muggle-remote-use-case-bulk-preview-submit \u2014 no LLM is invoked.",
@@ -4011,6 +4364,31 @@ var testCaseTools = [
4011
4364
  };
4012
4365
  }
4013
4366
  },
4367
+ {
4368
+ name: "muggle-remote-test-case-update",
4369
+ description: "Directly update an existing test case's fields. Pass only the fields you want to change \u2014 others are left untouched. Use this for cheap, deterministic edits (rename, change status/priority, fix expected result, add tags). Does not touch the associated test script \u2014 script regeneration is a separate workflow (muggle-remote-workflow-start-test-script-generation).",
4370
+ inputSchema: TestCaseUpdateInputSchema,
4371
+ mapToUpstream: (input) => {
4372
+ const data = input;
4373
+ const body = { id: data.testCaseId };
4374
+ if (data.title !== void 0) body.title = data.title;
4375
+ if (data.description !== void 0) body.description = data.description;
4376
+ if (data.goal !== void 0) body.goal = data.goal;
4377
+ if (data.precondition !== void 0) body.precondition = data.precondition;
4378
+ if (data.expectedResult !== void 0) body.expectedResult = data.expectedResult;
4379
+ if (data.url !== void 0) body.url = data.url;
4380
+ if (data.status !== void 0) body.status = data.status;
4381
+ if (data.priority !== void 0) body.priority = data.priority;
4382
+ if (data.tags !== void 0) body.tags = data.tags;
4383
+ if (data.category !== void 0) body.category = data.category;
4384
+ if (data.automated !== void 0) body.automated = data.automated;
4385
+ return {
4386
+ method: "PUT",
4387
+ path: `${MUGGLE_TEST_PREFIX}/test-cases/${data.testCaseId}`,
4388
+ body
4389
+ };
4390
+ }
4391
+ },
4014
4392
  {
4015
4393
  name: "muggle-remote-test-case-bulk-preview-submit",
4016
4394
  description: "Submit an async bulk-preview job that uses the OpenAI Batch API to generate test cases for a single use case from many prompts at ~50% of normal LLM cost. Returns a job ID immediately; poll with muggle-remote-bulk-preview-job-get until the job reaches a terminal status, then persist each successful result via muggle-remote-test-case-create. Note: one input prompt may fan out to 1\u20135 test cases.",
@@ -4979,6 +5357,58 @@ var apiKeyTools = [
4979
5357
  }
4980
5358
  }
4981
5359
  ];
5360
+ var userFeedbackTools = [
5361
+ {
5362
+ name: "muggle-remote-user-feedback-create",
5363
+ description: "Submit user feedback on a generated action script \u2014 either the whole script (targetType='actionScript', targetId=actionScriptId) or a specific step (targetType='step', targetId=`${actionScriptId}:${stepIndex}` with 0-based stepIndex). Persists the feedback and triggers an async feedback-analysis workflow that may regenerate the script. The response includes the saved feedback and, when the analysis workflow was started, a feedbackAnalysisWorkflowRuntimeId for polling.",
5364
+ inputSchema: UserFeedbackCreateInputSchema,
5365
+ mapToUpstream: (input) => {
5366
+ const data = input;
5367
+ return {
5368
+ method: "POST",
5369
+ path: `${MUGGLE_TEST_PREFIX}/user-feedback`,
5370
+ body: {
5371
+ projectId: data.projectId,
5372
+ target: data.target,
5373
+ feedbackText: data.feedbackText
5374
+ }
5375
+ };
5376
+ }
5377
+ },
5378
+ {
5379
+ name: "muggle-remote-user-feedback-list",
5380
+ description: "List active user feedback entries for a project. Optionally narrow by exactly one of actionScriptId / testScriptId / testCaseId / useCaseId \u2014 the typical query is 'show me feedback on this test case (or test script, or use case).' Supports limit/offset pagination. Response: { feedback: IUserFeedback[], total: number, hasMore: boolean }.",
5381
+ inputSchema: UserFeedbackListInputSchema,
5382
+ mapToUpstream: (input) => {
5383
+ const data = input;
5384
+ return {
5385
+ method: "GET",
5386
+ path: `${MUGGLE_TEST_PREFIX}/user-feedback`,
5387
+ queryParams: {
5388
+ projectId: data.projectId,
5389
+ actionScriptId: data.actionScriptId,
5390
+ testScriptId: data.testScriptId,
5391
+ testCaseId: data.testCaseId,
5392
+ useCaseId: data.useCaseId,
5393
+ limit: data.limit,
5394
+ offset: data.offset
5395
+ }
5396
+ };
5397
+ }
5398
+ },
5399
+ {
5400
+ name: "muggle-remote-user-feedback-delete",
5401
+ description: "Soft-delete a user feedback entry by ID. Returns 204 on success.",
5402
+ inputSchema: UserFeedbackDeleteInputSchema,
5403
+ mapToUpstream: (input) => {
5404
+ const data = input;
5405
+ return {
5406
+ method: "DELETE",
5407
+ path: `${MUGGLE_TEST_PREFIX}/user-feedback/${data.feedbackId}`
5408
+ };
5409
+ }
5410
+ }
5411
+ ];
4982
5412
  var authTools = [
4983
5413
  {
4984
5414
  name: "muggle-remote-auth-status",
@@ -5115,6 +5545,7 @@ var allQaToolDefinitions = [
5115
5545
  ...walletTools,
5116
5546
  ...recommendationTools,
5117
5547
  ...apiKeyTools,
5548
+ ...userFeedbackTools,
5118
5549
  ...authTools
5119
5550
  ];
5120
5551
  function getQaToolByName(name) {
@@ -5132,6 +5563,13 @@ async function executeQaTool(toolName, input, correlationId) {
5132
5563
  isError: true
5133
5564
  };
5134
5565
  }
5566
+ const startTime = Date.now();
5567
+ safeTrack({
5568
+ name: EventName.McpToolInvoked,
5569
+ props: { toolName, toolSurface: ToolSurface.Remote, correlationId }
5570
+ });
5571
+ let outcome = Outcome.Success;
5572
+ let errorCode;
5135
5573
  try {
5136
5574
  const validatedInput = tool.inputSchema.parse(input);
5137
5575
  if (tool.localHandler) {
@@ -5164,7 +5602,9 @@ async function executeQaTool(toolName, input, correlationId) {
5164
5602
  throw error;
5165
5603
  }
5166
5604
  } catch (error) {
5605
+ outcome = Outcome.Error;
5167
5606
  if (error instanceof GatewayError) {
5607
+ errorCode = error.code;
5168
5608
  logger6.warn("Tool call failed with gateway error", {
5169
5609
  tool: toolName,
5170
5610
  code: error.code,
@@ -5175,12 +5615,31 @@ async function executeQaTool(toolName, input, correlationId) {
5175
5615
  isError: true
5176
5616
  };
5177
5617
  }
5618
+ errorCode = error instanceof Error ? error.name : "UnknownError";
5178
5619
  const errorMessage = error instanceof Error ? error.message : String(error);
5179
5620
  logger6.error("Tool call failed", { tool: toolName, error: errorMessage });
5180
5621
  return {
5181
5622
  content: JSON.stringify({ error: "INTERNAL_ERROR", message: errorMessage }),
5182
5623
  isError: true
5183
5624
  };
5625
+ } finally {
5626
+ safeTrack({
5627
+ name: EventName.McpToolCompleted,
5628
+ props: {
5629
+ toolName,
5630
+ toolSurface: ToolSurface.Remote,
5631
+ correlationId,
5632
+ durationMs: Date.now() - startTime,
5633
+ outcome,
5634
+ ...errorCode !== void 0 ? { errorCode } : {}
5635
+ }
5636
+ });
5637
+ }
5638
+ }
5639
+ function safeTrack(event) {
5640
+ try {
5641
+ track(event);
5642
+ } catch {
5184
5643
  }
5185
5644
  }
5186
5645
 
@@ -5239,7 +5698,9 @@ var ExecuteTestGenerationInputSchema = z.object({
5239
5698
  /** Show the electron-app UI during execution. Default: visible window. Pass false to run headless. */
5240
5699
  showUi: z.boolean().optional().describe("Show the electron-app UI during generation. Defaults to visible; pass false to run headless."),
5241
5700
  /** Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state, such as registration, login, or cookie consent flows. */
5242
- freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false.")
5701
+ freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false."),
5702
+ /** Mutation parameters providing variable context for this generation run — a string[] where each element is a plain-English instruction or a local file path for uploads (e.g. "Attach the image at C:\\Users\\user\\photo.jpg"). Matches the electron-app's string[] mutation file format. */
5703
+ mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`)
5243
5704
  });
5244
5705
  var ExecuteReplayInputSchema = z.object({
5245
5706
  /** Test script metadata from muggle-remote-test-script-get. */
@@ -5253,7 +5714,9 @@ var ExecuteReplayInputSchema = z.object({
5253
5714
  /** Show the electron-app UI during execution. Default: visible window. Pass false to run headless. */
5254
5715
  showUi: z.boolean().optional().describe("Show the electron-app UI during replay. Defaults to visible; pass false to run headless."),
5255
5716
  /** Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state, such as registration, login, or cookie consent flows. */
5256
- freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false.")
5717
+ freshSession: z.boolean().optional().describe("Clear all session storage (cookies, localStorage, etc.) before execution. Use for test cases that require a clean browser state \u2014 e.g. registration, login, or cookie consent flows. Default: false."),
5718
+ /** Mutation parameters passed to the LLM step predictor — a string[] where each element is an instruction describing what varies this run. Supports plain-English instructions (e.g. "The post content should be 'Hello world'") and local file paths for uploads (e.g. "Attach the image at C:\\Users\\user\\photo.jpg"). Matches the electron-app's string[] mutation file format. When provided, the electron app uses LLM-driven step prediction instead of deterministic replay. */
5719
+ mutations: z.array(z.string()).optional().describe(`Mutation parameters: string[] where each element is a plain-English instruction or a local file path (e.g. ["The post content should be 'Hello'", "Attach the image at C:\\\\Users\\\\user\\\\photo.jpg"]).`)
5257
5720
  });
5258
5721
  var CancelExecutionInputSchema = z.object({
5259
5722
  runId: MuggleEntityIdSchema.describe("Run ID (UUID) to cancel")
@@ -5287,6 +5750,7 @@ var EmptyInputSchema2 = z.object({});
5287
5750
  var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
5288
5751
  PreferenceKey2["AutoLogin"] = "autoLogin";
5289
5752
  PreferenceKey2["AutoSelectProject"] = "autoSelectProject";
5753
+ PreferenceKey2["AutoSelectLocalHost"] = "autoSelectLocalHost";
5290
5754
  PreferenceKey2["ShowElectronBrowser"] = "showElectronBrowser";
5291
5755
  PreferenceKey2["OpenTestResultsAfterRun"] = "openTestResultsAfterRun";
5292
5756
  PreferenceKey2["DefaultExecutionMode"] = "defaultExecutionMode";
@@ -5295,27 +5759,24 @@ var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
5295
5759
  PreferenceKey2["SuggestRelatedTestCases"] = "suggestRelatedTestCases";
5296
5760
  PreferenceKey2["AutoDetectChanges"] = "autoDetectChanges";
5297
5761
  PreferenceKey2["PostPRVisualWalkthrough"] = "postPRVisualWalkthrough";
5762
+ PreferenceKey2["AutoCreatePR"] = "autoCreatePR";
5298
5763
  PreferenceKey2["CheckForUpdates"] = "checkForUpdates";
5299
5764
  PreferenceKey2["VerboseOutput"] = "verboseOutput";
5765
+ PreferenceKey2["AutoUseWorktree"] = "autoUseWorktree";
5766
+ PreferenceKey2["AutoRebase"] = "autoRebase";
5767
+ PreferenceKey2["AutoCleanup"] = "autoCleanup";
5768
+ PreferenceKey2["AutoE2ETest"] = "autoE2ETest";
5300
5769
  return PreferenceKey2;
5301
5770
  })(PreferenceKey || {});
5302
5771
  var PreferenceValue = /* @__PURE__ */ ((PreferenceValue2) => {
5303
5772
  PreferenceValue2["Always"] = "always";
5304
5773
  PreferenceValue2["Ask"] = "ask";
5305
5774
  PreferenceValue2["Never"] = "never";
5775
+ PreferenceValue2["Local"] = "local";
5776
+ PreferenceValue2["Remote"] = "remote";
5306
5777
  return PreferenceValue2;
5307
5778
  })(PreferenceValue || {});
5308
5779
 
5309
- // packages/mcps/src/mcp/local/contracts/preferences-schemas.ts
5310
- var preferenceKeyValues = Object.values(PreferenceKey);
5311
- var preferenceValueValues = Object.values(PreferenceValue);
5312
- var PreferencesSetInputSchema = z.object({
5313
- key: z.enum(preferenceKeyValues).describe("The preference key to set."),
5314
- value: z.enum(preferenceValueValues).describe("The value: always, ask, or never."),
5315
- scope: z.enum(["global", "project"]).default("global").describe("Write to global (~/.muggle-ai/) or project (.muggle-ai/) preferences."),
5316
- cwd: z.string().optional().describe("Project root directory. Required when scope is 'project'.")
5317
- });
5318
-
5319
5780
  // packages/mcps/src/shared/preferences-constants.ts
5320
5781
  var PREFERENCES_FILE_NAME = "preferences.json";
5321
5782
  var PREFERENCES_PROJECT_DIR_NAME = ".muggle-ai";
@@ -5323,6 +5784,7 @@ var PREFERENCES_VERSION = 1;
5323
5784
  var DEFAULT_PREFERENCES = {
5324
5785
  ["autoLogin" /* AutoLogin */]: "ask" /* Ask */,
5325
5786
  ["autoSelectProject" /* AutoSelectProject */]: "ask" /* Ask */,
5787
+ ["autoSelectLocalHost" /* AutoSelectLocalHost */]: "ask" /* Ask */,
5326
5788
  ["showElectronBrowser" /* ShowElectronBrowser */]: "ask" /* Ask */,
5327
5789
  ["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: "ask" /* Ask */,
5328
5790
  ["defaultExecutionMode" /* DefaultExecutionMode */]: "ask" /* Ask */,
@@ -5331,27 +5793,69 @@ var DEFAULT_PREFERENCES = {
5331
5793
  ["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: "ask" /* Ask */,
5332
5794
  ["autoDetectChanges" /* AutoDetectChanges */]: "ask" /* Ask */,
5333
5795
  ["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: "ask" /* Ask */,
5796
+ ["autoCreatePR" /* AutoCreatePR */]: "ask" /* Ask */,
5334
5797
  ["checkForUpdates" /* CheckForUpdates */]: "ask" /* Ask */,
5335
- ["verboseOutput" /* VerboseOutput */]: "ask" /* Ask */
5798
+ ["verboseOutput" /* VerboseOutput */]: "ask" /* Ask */,
5799
+ ["autoUseWorktree" /* AutoUseWorktree */]: "ask" /* Ask */,
5800
+ ["autoRebase" /* AutoRebase */]: "ask" /* Ask */,
5801
+ ["autoCleanup" /* AutoCleanup */]: "ask" /* Ask */,
5802
+ ["autoE2ETest" /* AutoE2ETest */]: "always" /* Always */
5803
+ };
5804
+ var ALWAYS_ASK_NEVER = [
5805
+ "always" /* Always */,
5806
+ "ask" /* Ask */,
5807
+ "never" /* Never */
5808
+ ];
5809
+ var ALWAYS_ASK = [
5810
+ "always" /* Always */,
5811
+ "ask" /* Ask */
5812
+ ];
5813
+ var LOCAL_REMOTE_ASK = [
5814
+ "local" /* Local */,
5815
+ "remote" /* Remote */,
5816
+ "ask" /* Ask */
5817
+ ];
5818
+ var PREFERENCE_ALLOWED_VALUES = {
5819
+ ["autoLogin" /* AutoLogin */]: ALWAYS_ASK_NEVER,
5820
+ ["autoSelectProject" /* AutoSelectProject */]: ALWAYS_ASK_NEVER,
5821
+ ["autoSelectLocalHost" /* AutoSelectLocalHost */]: ALWAYS_ASK_NEVER,
5822
+ ["showElectronBrowser" /* ShowElectronBrowser */]: ALWAYS_ASK_NEVER,
5823
+ ["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: ALWAYS_ASK_NEVER,
5824
+ ["defaultExecutionMode" /* DefaultExecutionMode */]: LOCAL_REMOTE_ASK,
5825
+ ["autoPublishLocalResults" /* AutoPublishLocalResults */]: ALWAYS_ASK_NEVER,
5826
+ ["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: ALWAYS_ASK_NEVER,
5827
+ ["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: ALWAYS_ASK_NEVER,
5828
+ ["autoDetectChanges" /* AutoDetectChanges */]: ALWAYS_ASK_NEVER,
5829
+ ["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: ALWAYS_ASK_NEVER,
5830
+ ["autoCreatePR" /* AutoCreatePR */]: ALWAYS_ASK_NEVER,
5831
+ ["checkForUpdates" /* CheckForUpdates */]: ALWAYS_ASK_NEVER,
5832
+ ["verboseOutput" /* VerboseOutput */]: ALWAYS_ASK_NEVER,
5833
+ ["autoUseWorktree" /* AutoUseWorktree */]: ALWAYS_ASK_NEVER,
5834
+ ["autoRebase" /* AutoRebase */]: ALWAYS_ASK_NEVER,
5835
+ ["autoCleanup" /* AutoCleanup */]: ALWAYS_ASK_NEVER,
5836
+ ["autoE2ETest" /* AutoE2ETest */]: ALWAYS_ASK
5336
5837
  };
5337
5838
  var PREFERENCES_SCHEMA = {
5338
5839
  ["autoLogin" /* AutoLogin */]: {
5339
5840
  description: "When a tool requires auth and saved credentials exist, reuse them without prompting"
5340
5841
  },
5341
5842
  ["autoSelectProject" /* AutoSelectProject */]: {
5342
- description: "When a skill needs a Muggle project and one was used previously in this repo, reuse it without prompting"
5843
+ description: "When a skill needs a Muggle Test project and one was used previously in this repo, reuse it without prompting"
5844
+ },
5845
+ ["autoSelectLocalHost" /* AutoSelectLocalHost */]: {
5846
+ description: "When running local tests, reuse the dev server URL from the previous run in this repo without prompting"
5343
5847
  },
5344
5848
  ["showElectronBrowser" /* ShowElectronBrowser */]: {
5345
5849
  description: "When running local E2E tests, show the Electron browser window"
5346
5850
  },
5347
5851
  ["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: {
5348
- description: "After a local E2E test run completes, open the per-run results page on Muggle dashboard"
5852
+ description: "After a local E2E test run completes, open the per-run results page on Muggle Test dashboard"
5349
5853
  },
5350
5854
  ["defaultExecutionMode" /* DefaultExecutionMode */]: {
5351
5855
  description: "When a skill supports both local and remote test execution, which to default to"
5352
5856
  },
5353
5857
  ["autoPublishLocalResults" /* AutoPublishLocalResults */]: {
5354
- description: "After a local E2E test run completes, upload results to Muggle cloud for team visibility"
5858
+ description: "After a local E2E test run completes, upload results to Muggle Test cloud for team visibility"
5355
5859
  },
5356
5860
  ["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: {
5357
5861
  description: "After creating or running a use case, suggest related use cases to add"
@@ -5365,17 +5869,121 @@ var PREFERENCES_SCHEMA = {
5365
5869
  ["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: {
5366
5870
  description: "After test results are available, post visual walkthrough comment with screenshots to the PR"
5367
5871
  },
5872
+ ["autoCreatePR" /* AutoCreatePR */]: {
5873
+ description: "At the end of the muggle-do dev cycle (or when a test needs an open PR to post results to), push the branch and open a PR without prompting"
5874
+ },
5368
5875
  ["checkForUpdates" /* CheckForUpdates */]: {
5369
- description: "At session start, check if a newer Muggle version is available and notify"
5876
+ description: "At session start, check if a newer Muggle Test version is available and notify"
5370
5877
  },
5371
5878
  ["verboseOutput" /* VerboseOutput */]: {
5372
5879
  description: "Show detailed progress logs during skill and tool execution"
5880
+ },
5881
+ ["autoUseWorktree" /* AutoUseWorktree */]: {
5882
+ description: "When starting non-trivial development work, create a git worktree to isolate the change from the current checkout"
5883
+ },
5884
+ ["autoRebase" /* AutoRebase */]: {
5885
+ description: "Before running dev servers or E2E tests on a branch behind origin, rebase onto the default branch first"
5886
+ },
5887
+ ["autoCleanup" /* AutoCleanup */]: {
5888
+ description: "After a PR is merged, automatically run the cleanup sequence: remove worktree, delete branches, clear local artifacts, prune [gone] branches"
5889
+ },
5890
+ ["autoE2ETest" /* AutoE2ETest */]: {
5891
+ description: "Run Stage 6 (E2E acceptance) at the end of every /muggle-do cycle (default always \u2014 running E2E is the point of muggle-do; never is not an option)"
5373
5892
  }
5374
5893
  };
5375
5894
 
5376
- // packages/mcps/src/shared/preferences.ts
5377
- function isFirstRun(dataDirOverride) {
5378
- const filePath = path2.join(dataDirOverride ?? getDataDir(), PREFERENCES_FILE_NAME);
5895
+ // packages/mcps/src/mcp/local/contracts/preferences-schemas.ts
5896
+ var preferenceKeyValues = Object.values(PreferenceKey);
5897
+ var preferenceValueValues = Object.values(PreferenceValue);
5898
+ var PreferencesSetInputSchema = z.object({
5899
+ key: z.enum(preferenceKeyValues).describe("The preference key to set."),
5900
+ value: z.enum(preferenceValueValues).describe("The value. Most keys accept always/ask/never; defaultExecutionMode accepts local/remote/ask."),
5901
+ scope: z.enum(["global", "project"]).default("global").describe("Write to global (~/.muggle-ai/) or project (.muggle-ai/) preferences."),
5902
+ cwd: z.string().optional().describe("Project root directory. Required when scope is 'project'.")
5903
+ }).superRefine((data, ctx) => {
5904
+ const allowed = PREFERENCE_ALLOWED_VALUES[data.key];
5905
+ if (!allowed.includes(data.value)) {
5906
+ ctx.addIssue({
5907
+ code: "custom",
5908
+ message: `Value "${data.value}" is not allowed for preference "${data.key}". Allowed: ${allowed.join(", ")}`,
5909
+ path: ["value"]
5910
+ });
5911
+ }
5912
+ });
5913
+ var LastProjectGetInputSchema = z.object({
5914
+ cwd: z.string().describe("Project root directory whose last-used project to return.")
5915
+ });
5916
+ var LastProjectSetInputSchema = z.object({
5917
+ cwd: z.string().describe("Project root directory to save the cached project to."),
5918
+ projectId: z.string().min(1).describe("Muggle Test project ID."),
5919
+ projectUrl: z.string().min(1).describe("Muggle Test project URL."),
5920
+ projectName: z.string().min(1).describe("Muggle Test project name.")
5921
+ });
5922
+ var LastProjectClearInputSchema = z.object({
5923
+ cwd: z.string().describe("Project root directory whose last-used project cache to remove.")
5924
+ });
5925
+ var LastHostGetInputSchema = z.object({
5926
+ cwd: z.string().describe("Project root directory whose last-used host to return.")
5927
+ });
5928
+ var LastHostSetInputSchema = z.object({
5929
+ cwd: z.string().describe("Project root directory to save the cached host to."),
5930
+ host: z.string().min(1).describe("Local dev server URL (e.g. http://localhost:3000).")
5931
+ });
5932
+ var LastHostClearInputSchema = z.object({
5933
+ cwd: z.string().describe("Project root directory whose last-used host cache to remove.")
5934
+ });
5935
+ var SkillTelemetryEmitInputSchema = z.object({
5936
+ skillName: z.string().min(1).describe("Name of the skill being invoked, e.g. 'muggle-test'."),
5937
+ trigger: z.nativeEnum(Trigger).default(Trigger.UserSlash).describe("Why this skill ran. Defaults to 'user-slash' (user typed /skill-name).")
5938
+ });
5939
+ var FailureEventType = /* @__PURE__ */ ((FailureEventType2) => {
5940
+ FailureEventType2["PreExecutionClassification"] = "pre-execution-classification";
5941
+ FailureEventType2["ReplayFailureClassified"] = "replay-failure-classified";
5942
+ FailureEventType2["ReplayFailureResolved"] = "replay-failure-resolved";
5943
+ FailureEventType2["RegenFailureClassified"] = "regen-failure-classified";
5944
+ FailureEventType2["RegenFailureResolved"] = "regen-failure-resolved";
5945
+ return FailureEventType2;
5946
+ })(FailureEventType || {});
5947
+ var EventTelemetryEmitInputSchema = z.object({
5948
+ eventType: z.nativeEnum(FailureEventType).describe(
5949
+ "Which decision point this event records. Five values cover the AI's pre-execution replay-vs-regen choice and the four post-failure classify\u2192resolve pairs."
5950
+ ),
5951
+ skillName: z.string().min(1).describe("Skill that emitted this event (e.g. 'muggle-test', 'muggle-test-feature-local')."),
5952
+ aiClassification: z.string().optional().describe(
5953
+ "What the AI classified the situation as. pre-execution: 'replay' or 'regen'. replay-failure: 'infra' | 'stale-script' | 'product-defect'. regen-failure: 'transient' | 'infra' | 'agent-course' | 'product-uxux'."
5954
+ ),
5955
+ aiSuggestion: z.string().optional().describe(
5956
+ "What the AI suggested the user do. Examples: 'regenerate', 'report-bug', 'muggle-feedback', 'retry', 'wait-and-share'."
5957
+ ),
5958
+ userAction: z.string().optional().describe(
5959
+ "What the user actually picked (only set on *-resolved events). Compare against aiSuggestion to measure classification accuracy."
5960
+ ),
5961
+ runId: z.string().optional().describe("Anchor: local run ID for the affected execution."),
5962
+ testCaseId: z.string().optional().describe("Anchor: cloud test case ID."),
5963
+ projectId: z.string().optional().describe("Anchor: cloud project ID."),
5964
+ signals: z.array(z.string()).optional().describe(
5965
+ "Signals that drove the classification, e.g. ['element-not-found', 'selector-timeout', 'electron-exit-26', 'goal-not-achievable']. Used to refine the rules later."
5966
+ ),
5967
+ metadata: z.record(z.string(), z.unknown()).optional().describe("Free-form additional context (e.g. error excerpt, last step name).")
5968
+ });
5969
+ var TELEMETRY_DIR_NAME = "telemetry";
5970
+ var FAILURE_EVENTS_FILE_NAME = "failure-events.jsonl";
5971
+ function appendFailureEvent(record) {
5972
+ try {
5973
+ const dir = path2.join(getDataDir(), TELEMETRY_DIR_NAME);
5974
+ fs5.mkdirSync(dir, { recursive: true });
5975
+ const filePath = path2.join(dir, FAILURE_EVENTS_FILE_NAME);
5976
+ const full = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...record };
5977
+ fs5.appendFileSync(filePath, `${JSON.stringify(full)}
5978
+ `, "utf-8");
5979
+ } catch (error) {
5980
+ getLogger().warn("Failed to append failure event", {
5981
+ error: error instanceof Error ? error.message : String(error)
5982
+ });
5983
+ }
5984
+ }
5985
+ function isFirstRun(dataDirOverride2) {
5986
+ const filePath = path2.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
5379
5987
  return !fs5.existsSync(filePath);
5380
5988
  }
5381
5989
  function readPreferencesFile(filePath) {
@@ -5393,8 +6001,8 @@ function readPreferencesFile(filePath) {
5393
6001
  return {};
5394
6002
  }
5395
6003
  }
5396
- function readGlobalPreferences(dataDirOverride) {
5397
- const filePath = path2.join(dataDirOverride ?? getDataDir(), PREFERENCES_FILE_NAME);
6004
+ function readGlobalPreferences(dataDirOverride2) {
6005
+ const filePath = path2.join(dataDirOverride2 ?? getDataDir(), PREFERENCES_FILE_NAME);
5398
6006
  const partial = readPreferencesFile(filePath);
5399
6007
  return { ...DEFAULT_PREFERENCES, ...partial };
5400
6008
  }
@@ -5402,16 +6010,16 @@ function readProjectPreferences(cwd) {
5402
6010
  const filePath = path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_FILE_NAME);
5403
6011
  return readPreferencesFile(filePath);
5404
6012
  }
5405
- function resolvePreferences(dataDirOverride, cwd) {
5406
- const global = readGlobalPreferences(dataDirOverride);
6013
+ function resolvePreferences(dataDirOverride2, cwd) {
6014
+ const global = readGlobalPreferences(dataDirOverride2);
5407
6015
  if (!cwd) {
5408
6016
  return global;
5409
6017
  }
5410
6018
  const project = readProjectPreferences(cwd);
5411
6019
  return { ...global, ...project };
5412
6020
  }
5413
- function writePreferences(prefs, scope, dataDirOverride, cwd) {
5414
- const dir = scope === "project" && cwd ? path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride ?? getDataDir();
6021
+ function writePreferences(prefs, scope, dataDirOverride2, cwd) {
6022
+ const dir = scope === "project" && cwd ? path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride2 ?? getDataDir();
5415
6023
  fs5.mkdirSync(dir, { recursive: true });
5416
6024
  const filePath = path2.join(dir, PREFERENCES_FILE_NAME);
5417
6025
  const existing = readPreferencesFile(filePath);
@@ -5423,8 +6031,8 @@ function writePreferences(prefs, scope, dataDirOverride, cwd) {
5423
6031
  fs5.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
5424
6032
  `, "utf-8");
5425
6033
  }
5426
- function resetPreference(key, scope, dataDirOverride, cwd) {
5427
- const dir = scope === "project" && cwd ? path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride ?? getDataDir();
6034
+ function resetPreference(key, scope, dataDirOverride2, cwd) {
6035
+ const dir = scope === "project" && cwd ? path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride2 ?? getDataDir();
5428
6036
  const filePath = path2.join(dir, PREFERENCES_FILE_NAME);
5429
6037
  if (!fs5.existsSync(filePath)) {
5430
6038
  return;
@@ -5443,12 +6051,87 @@ function resetPreference(key, scope, dataDirOverride, cwd) {
5443
6051
  }
5444
6052
  function validatePreference(key, value) {
5445
6053
  const validKeys = Object.values(PreferenceKey);
5446
- const validValues = Object.values(PreferenceValue);
5447
- return validKeys.includes(key) && validValues.includes(value);
6054
+ if (!validKeys.includes(key)) {
6055
+ return false;
6056
+ }
6057
+ const allowed = PREFERENCE_ALLOWED_VALUES[key];
6058
+ return allowed.includes(value);
5448
6059
  }
5449
6060
  function formatPreferencesOneLiner(prefs) {
5450
6061
  return Object.entries(prefs).map(([key, value]) => `${key}=${value}`).join(" ");
5451
6062
  }
6063
+ var LAST_PROJECT_FILE_NAME = "last-project.json";
6064
+ var LAST_PROJECT_DIR_NAME = ".muggle-ai";
6065
+ var LAST_PROJECT_VERSION = 1;
6066
+ function readLastProject(cwd) {
6067
+ const filePath = path2.join(cwd, LAST_PROJECT_DIR_NAME, LAST_PROJECT_FILE_NAME);
6068
+ try {
6069
+ if (!fs5.existsSync(filePath)) {
6070
+ return null;
6071
+ }
6072
+ const raw = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
6073
+ return raw.lastProject ?? null;
6074
+ } catch (error) {
6075
+ getLogger().warn("Failed to read last-project file", {
6076
+ path: filePath,
6077
+ error: error instanceof Error ? error.message : String(error)
6078
+ });
6079
+ return null;
6080
+ }
6081
+ }
6082
+ function writeLastProject(cwd, lastProject) {
6083
+ const dir = path2.join(cwd, LAST_PROJECT_DIR_NAME);
6084
+ fs5.mkdirSync(dir, { recursive: true });
6085
+ const filePath = path2.join(dir, LAST_PROJECT_FILE_NAME);
6086
+ const file = {
6087
+ version: LAST_PROJECT_VERSION,
6088
+ lastProject: { ...lastProject, savedAt: (/* @__PURE__ */ new Date()).toISOString() }
6089
+ };
6090
+ fs5.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
6091
+ `, "utf-8");
6092
+ }
6093
+ function clearLastProject(cwd) {
6094
+ const filePath = path2.join(cwd, LAST_PROJECT_DIR_NAME, LAST_PROJECT_FILE_NAME);
6095
+ if (fs5.existsSync(filePath)) {
6096
+ fs5.unlinkSync(filePath);
6097
+ }
6098
+ }
6099
+ var LAST_HOST_FILE_NAME = "last-host.json";
6100
+ var LAST_HOST_DIR_NAME = ".muggle-ai";
6101
+ var LAST_HOST_VERSION = 1;
6102
+ function readLastHost(cwd) {
6103
+ const filePath = path2.join(cwd, LAST_HOST_DIR_NAME, LAST_HOST_FILE_NAME);
6104
+ try {
6105
+ if (!fs5.existsSync(filePath)) {
6106
+ return null;
6107
+ }
6108
+ const raw = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
6109
+ return raw.lastHost ?? null;
6110
+ } catch (error) {
6111
+ getLogger().warn("Failed to read last-host file", {
6112
+ path: filePath,
6113
+ error: error instanceof Error ? error.message : String(error)
6114
+ });
6115
+ return null;
6116
+ }
6117
+ }
6118
+ function writeLastHost(cwd, host) {
6119
+ const dir = path2.join(cwd, LAST_HOST_DIR_NAME);
6120
+ fs5.mkdirSync(dir, { recursive: true });
6121
+ const filePath = path2.join(dir, LAST_HOST_FILE_NAME);
6122
+ const file = {
6123
+ version: LAST_HOST_VERSION,
6124
+ lastHost: { host, savedAt: (/* @__PURE__ */ new Date()).toISOString() }
6125
+ };
6126
+ fs5.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
6127
+ `, "utf-8");
6128
+ }
6129
+ function clearLastHost(cwd) {
6130
+ const filePath = path2.join(cwd, LAST_HOST_DIR_NAME, LAST_HOST_FILE_NAME);
6131
+ if (fs5.existsSync(filePath)) {
6132
+ fs5.unlinkSync(filePath);
6133
+ }
6134
+ }
5452
6135
 
5453
6136
  // packages/mcps/src/mcp/tools/local/tool-registry.ts
5454
6137
  function createChildLogger2(correlationId) {
@@ -5672,6 +6355,7 @@ var executeTestGenerationTool = {
5672
6355
  const result = await executeTestGeneration({
5673
6356
  testCase: input.testCase,
5674
6357
  localUrl: input.localUrl,
6358
+ mutations: input.mutations,
5675
6359
  timeoutMs: input.timeoutMs,
5676
6360
  showUi,
5677
6361
  freshSession: input.freshSession
@@ -5712,6 +6396,7 @@ var executeReplayTool = {
5712
6396
  testScript: input.testScript,
5713
6397
  actionScript: input.actionScript,
5714
6398
  localUrl: input.localUrl,
6399
+ mutations: input.mutations,
5715
6400
  timeoutMs: input.timeoutMs,
5716
6401
  showUi,
5717
6402
  freshSession: input.freshSession
@@ -5905,19 +6590,172 @@ var preferencesSetTool = {
5905
6590
  void 0,
5906
6591
  input.cwd
5907
6592
  );
5908
- const resolved = resolvePreferences(void 0, input.cwd);
5909
- const oneLiner = formatPreferencesOneLiner(resolved);
6593
+ return {
6594
+ content: `**${input.key}** set to **${input.value}** (${input.scope}).`,
6595
+ isError: false
6596
+ };
6597
+ }
6598
+ };
6599
+ var lastProjectGetTool = {
6600
+ name: "muggle-local-last-project-get",
6601
+ description: "Get the cached last-used Muggle Test project for a repo (read from <cwd>/.muggle-ai/last-project.json). Returns the project ID, URL, name, and saved-at timestamp, or null if no cache exists. Skills consult this when 'autoSelectProject = always' to silently reuse the project the user picked previously, instead of presenting the project picker every time.",
6602
+ inputSchema: LastProjectGetInputSchema,
6603
+ execute: async (ctx) => {
6604
+ const logger6 = createChildLogger2(ctx.correlationId);
6605
+ logger6.info("Executing muggle-local-last-project-get");
6606
+ const input = LastProjectGetInputSchema.parse(ctx.input);
6607
+ const cached = readLastProject(input.cwd);
6608
+ if (!cached) {
6609
+ const content2 = [
6610
+ "No cached last-used project for this repo.",
6611
+ "",
6612
+ `Looked at: \`${input.cwd}/.muggle-ai/${LAST_PROJECT_FILE_NAME}\``,
6613
+ "",
6614
+ "The cache is populated when a user picks an existing project AND chooses 'Yes, save it' on the memory picker (the autoSelectProject preference)."
6615
+ ].join("\n");
6616
+ return { content: content2, isError: false };
6617
+ }
5910
6618
  const content = [
5911
- `**${input.key}** set to **${input.value}** (${input.scope}).`,
6619
+ "**Cached last-used project:**",
5912
6620
  "",
5913
- `Preferences file: ~/.muggle-ai/${PREFERENCES_FILE_NAME}`,
6621
+ `- ID: \`${cached.projectId}\``,
6622
+ `- URL: ${cached.projectUrl}`,
6623
+ `- Name: ${cached.projectName}`,
6624
+ `- Saved at: ${cached.savedAt}`
6625
+ ].join("\n");
6626
+ return { content, isError: false };
6627
+ }
6628
+ };
6629
+ var lastProjectSetTool = {
6630
+ name: "muggle-local-last-project-set",
6631
+ description: "Save the user's selected Muggle Test project as the cached last-used project for this repo. Writes to <cwd>/.muggle-ai/last-project.json. Subsequent skill invocations honor 'autoSelectProject = always' by silently reusing this entry \u2014 no project picker shown. Always pair this call with 'muggle-local-preferences-set autoSelectProject=always' when the user chose 'Yes, save it'.",
6632
+ inputSchema: LastProjectSetInputSchema,
6633
+ execute: async (ctx) => {
6634
+ const logger6 = createChildLogger2(ctx.correlationId);
6635
+ logger6.info("Executing muggle-local-last-project-set");
6636
+ const input = LastProjectSetInputSchema.parse(ctx.input);
6637
+ writeLastProject(input.cwd, {
6638
+ projectId: input.projectId,
6639
+ projectUrl: input.projectUrl,
6640
+ projectName: input.projectName
6641
+ });
6642
+ const content = [
6643
+ `Cached **${input.projectName}** as the last-used project for this repo.`,
5914
6644
  "",
5915
- "Current resolved preferences:",
5916
- `\`${oneLiner}\``
6645
+ `Written to: \`${input.cwd}/.muggle-ai/${LAST_PROJECT_FILE_NAME}\``,
6646
+ "",
6647
+ "Skills will silently reuse this project on future runs when `autoSelectProject = always`."
5917
6648
  ].join("\n");
5918
6649
  return { content, isError: false };
5919
6650
  }
5920
6651
  };
6652
+ var lastProjectClearTool = {
6653
+ name: "muggle-local-last-project-clear",
6654
+ description: "Remove the cached last-used project for this repo. After this, `autoSelectProject = always` will fall through to ask until the user picks a new project. No-op if no cache exists.",
6655
+ inputSchema: LastProjectClearInputSchema,
6656
+ execute: async (ctx) => {
6657
+ const logger6 = createChildLogger2(ctx.correlationId);
6658
+ logger6.info("Executing muggle-local-last-project-clear");
6659
+ const input = LastProjectClearInputSchema.parse(ctx.input);
6660
+ clearLastProject(input.cwd);
6661
+ const content = [
6662
+ "Cleared the cached last-used project for this repo.",
6663
+ "",
6664
+ `Path: \`${input.cwd}/.muggle-ai/${LAST_PROJECT_FILE_NAME}\``
6665
+ ].join("\n");
6666
+ return { content, isError: false };
6667
+ }
6668
+ };
6669
+ var lastHostGetTool = {
6670
+ name: "muggle-local-last-host-get",
6671
+ description: "Get the cached last-used local dev server URL for a repo (read from <cwd>/.muggle-ai/last-host.json). Returns the URL and saved-at timestamp, or null if no cache exists. Skills consult this when 'autoSelectLocalHost = always' to silently reuse the URL the user used previously.",
6672
+ inputSchema: LastHostGetInputSchema,
6673
+ execute: async (ctx) => {
6674
+ const logger6 = createChildLogger2(ctx.correlationId);
6675
+ logger6.info("Executing muggle-local-last-host-get");
6676
+ const input = LastHostGetInputSchema.parse(ctx.input);
6677
+ const cached = readLastHost(input.cwd);
6678
+ if (!cached) {
6679
+ const content2 = [
6680
+ "No cached last-used host for this repo.",
6681
+ "",
6682
+ `Looked at: \`${input.cwd}/.muggle-ai/${LAST_HOST_FILE_NAME}\``
6683
+ ].join("\n");
6684
+ return { content: content2, isError: false };
6685
+ }
6686
+ const content = [
6687
+ "**Cached last-used host:**",
6688
+ "",
6689
+ `- URL: ${cached.host}`,
6690
+ `- Saved at: ${cached.savedAt}`
6691
+ ].join("\n");
6692
+ return { content, isError: false };
6693
+ }
6694
+ };
6695
+ var lastHostSetTool = {
6696
+ name: "muggle-local-last-host-set",
6697
+ description: "Save the user's chosen local dev server URL as the cached last-used host for this repo. Writes to <cwd>/.muggle-ai/last-host.json. Call this on every host pick (independent of 'Remember this URL?' Picker 2) so future runs can offer 'Use {lastHost}' regardless of whether the user opted to set autoSelectLocalHost=always.",
6698
+ inputSchema: LastHostSetInputSchema,
6699
+ execute: async (ctx) => {
6700
+ const logger6 = createChildLogger2(ctx.correlationId);
6701
+ logger6.info("Executing muggle-local-last-host-set");
6702
+ const input = LastHostSetInputSchema.parse(ctx.input);
6703
+ writeLastHost(input.cwd, input.host);
6704
+ return {
6705
+ content: `Cached **${input.host}** as the last-used host for this repo.`,
6706
+ isError: false
6707
+ };
6708
+ }
6709
+ };
6710
+ var lastHostClearTool = {
6711
+ name: "muggle-local-last-host-clear",
6712
+ description: "Remove the cached last-used host for this repo. After this, `autoSelectLocalHost = always` will fall through to ask until the user picks a new URL. No-op if no cache exists.",
6713
+ inputSchema: LastHostClearInputSchema,
6714
+ execute: async (ctx) => {
6715
+ const logger6 = createChildLogger2(ctx.correlationId);
6716
+ logger6.info("Executing muggle-local-last-host-clear");
6717
+ const input = LastHostClearInputSchema.parse(ctx.input);
6718
+ clearLastHost(input.cwd);
6719
+ return {
6720
+ content: `Cleared the cached last-used host for this repo.`,
6721
+ isError: false
6722
+ };
6723
+ }
6724
+ };
6725
+ var telemetrySkillEmitTool = {
6726
+ name: "muggle-local-telemetry-skill-emit",
6727
+ description: "Emit a client telemetry event recording that a Muggle Test skill was invoked. Each muggle-* skill calls this in its first step so we can measure skill usage. Never fails the skill on telemetry errors.",
6728
+ inputSchema: SkillTelemetryEmitInputSchema,
6729
+ execute: async (ctx) => {
6730
+ const input = SkillTelemetryEmitInputSchema.parse(ctx.input);
6731
+ safeTrack2({
6732
+ name: EventName.SkillInvoked,
6733
+ props: { skillName: input.skillName, trigger: input.trigger }
6734
+ });
6735
+ return { content: "ok", isError: false, data: { recorded: true } };
6736
+ }
6737
+ };
6738
+ var telemetryEventEmitTool = {
6739
+ name: "muggle-local-telemetry-event-emit",
6740
+ description: "Emit a structured failure-mode telemetry event recording how a Muggle Test skill classified a situation and what action the user took. Used at five decision points: 'pre-execution-classification' (replay vs regen), 'replay-failure-classified', 'replay-failure-resolved', 'regen-failure-classified', 'regen-failure-resolved'. Records to ~/.muggle-ai/telemetry/failure-events.jsonl. Never fails the skill on telemetry errors.",
6741
+ inputSchema: EventTelemetryEmitInputSchema,
6742
+ execute: async (ctx) => {
6743
+ const input = EventTelemetryEmitInputSchema.parse(ctx.input);
6744
+ appendFailureEvent({
6745
+ eventType: input.eventType,
6746
+ skillName: input.skillName,
6747
+ aiClassification: input.aiClassification,
6748
+ aiSuggestion: input.aiSuggestion,
6749
+ userAction: input.userAction,
6750
+ runId: input.runId,
6751
+ testCaseId: input.testCaseId,
6752
+ projectId: input.projectId,
6753
+ signals: input.signals,
6754
+ metadata: input.metadata
6755
+ });
6756
+ return { content: "ok", isError: false, data: { recorded: true } };
6757
+ }
6758
+ };
5921
6759
  var allLocalQaTools = [
5922
6760
  // Status tools
5923
6761
  checkStatusTool,
@@ -5935,7 +6773,18 @@ var allLocalQaTools = [
5935
6773
  // Publishing tools
5936
6774
  publishTestScriptTool,
5937
6775
  // Preferences tools
5938
- preferencesSetTool
6776
+ preferencesSetTool,
6777
+ // Last-project cache tools (per-repo "last used Muggle Test project")
6778
+ lastProjectGetTool,
6779
+ lastProjectSetTool,
6780
+ lastProjectClearTool,
6781
+ // Last-host cache tools (per-repo "last used local dev server URL")
6782
+ lastHostGetTool,
6783
+ lastHostSetTool,
6784
+ lastHostClearTool,
6785
+ // Client telemetry: skills emit invocation events through this tool
6786
+ telemetrySkillEmitTool,
6787
+ telemetryEventEmitTool
5939
6788
  ];
5940
6789
  var toolMap = new Map(
5941
6790
  allLocalQaTools.map((tool) => [tool.name, tool])
@@ -5951,7 +6800,44 @@ async function executeTool(name, input, correlationId) {
5951
6800
  isError: true
5952
6801
  };
5953
6802
  }
5954
- return tool.execute({ input, correlationId });
6803
+ const startTime = Date.now();
6804
+ safeTrack2({
6805
+ name: EventName.McpToolInvoked,
6806
+ props: { toolName: name, toolSurface: ToolSurface.Local, correlationId }
6807
+ });
6808
+ try {
6809
+ const result = await tool.execute({ input, correlationId });
6810
+ safeTrack2({
6811
+ name: EventName.McpToolCompleted,
6812
+ props: {
6813
+ toolName: name,
6814
+ toolSurface: ToolSurface.Local,
6815
+ correlationId,
6816
+ durationMs: Date.now() - startTime,
6817
+ outcome: result.isError ? Outcome.Error : Outcome.Success
6818
+ }
6819
+ });
6820
+ return result;
6821
+ } catch (err) {
6822
+ safeTrack2({
6823
+ name: EventName.McpToolCompleted,
6824
+ props: {
6825
+ toolName: name,
6826
+ toolSurface: ToolSurface.Local,
6827
+ correlationId,
6828
+ durationMs: Date.now() - startTime,
6829
+ outcome: Outcome.Error,
6830
+ errorCode: err instanceof Error ? err.name : "UnknownError"
6831
+ }
6832
+ });
6833
+ throw err;
6834
+ }
6835
+ }
6836
+ function safeTrack2(event) {
6837
+ try {
6838
+ track(event);
6839
+ } catch {
6840
+ }
5955
6841
  }
5956
6842
 
5957
6843
  // packages/mcps/src/mcp/e2e/index.ts
@@ -6013,6 +6899,7 @@ __export(e2e_exports2, {
6013
6899
  TestCaseGetInputSchema: () => TestCaseGetInputSchema,
6014
6900
  TestCaseListByUseCaseInputSchema: () => TestCaseListByUseCaseInputSchema,
6015
6901
  TestCaseListInputSchema: () => TestCaseListInputSchema,
6902
+ TestCaseUpdateInputSchema: () => TestCaseUpdateInputSchema,
6016
6903
  TestScriptGetInputSchema: () => TestScriptGetInputSchema,
6017
6904
  TestScriptListInputSchema: () => TestScriptListInputSchema,
6018
6905
  TokenPackageIdSchema: () => TokenPackageIdSchema,
@@ -6025,6 +6912,12 @@ __export(e2e_exports2, {
6025
6912
  UseCaseListInputSchema: () => UseCaseListInputSchema,
6026
6913
  UseCasePromptPreviewInputSchema: () => UseCasePromptPreviewInputSchema,
6027
6914
  UseCaseUpdateFromPromptInputSchema: () => UseCaseUpdateFromPromptInputSchema,
6915
+ UseCaseUpdateInputSchema: () => UseCaseUpdateInputSchema,
6916
+ UserFeedbackCreateInputSchema: () => UserFeedbackCreateInputSchema,
6917
+ UserFeedbackDeleteInputSchema: () => UserFeedbackDeleteInputSchema,
6918
+ UserFeedbackListInputSchema: () => UserFeedbackListInputSchema,
6919
+ UserFeedbackTargetSchema: () => UserFeedbackTargetSchema,
6920
+ UserFeedbackTargetTypeSchema: () => UserFeedbackTargetTypeSchema,
6028
6921
  WalletAutoTopUpSetPaymentMethodInputSchema: () => WalletAutoTopUpSetPaymentMethodInputSchema,
6029
6922
  WalletAutoTopUpUpdateInputSchema: () => WalletAutoTopUpUpdateInputSchema,
6030
6923
  WalletPaymentMethodCreateSetupSessionInputSchema: () => WalletPaymentMethodCreateSetupSessionInputSchema,
@@ -6071,10 +6964,18 @@ __export(local_exports2, {
6071
6964
  CloudMappingEntityType: () => CloudMappingEntityType,
6072
6965
  DeviceCodePollStatus: () => DeviceCodePollStatus,
6073
6966
  EmptyInputSchema: () => EmptyInputSchema2,
6967
+ EventTelemetryEmitInputSchema: () => EventTelemetryEmitInputSchema,
6074
6968
  ExecuteReplayInputSchema: () => ExecuteReplayInputSchema,
6075
6969
  ExecuteTestGenerationInputSchema: () => ExecuteTestGenerationInputSchema,
6076
6970
  ExecutionStatus: () => ExecutionStatus,
6971
+ FailureEventType: () => FailureEventType,
6077
6972
  HealthStatus: () => HealthStatus,
6973
+ LastHostClearInputSchema: () => LastHostClearInputSchema,
6974
+ LastHostGetInputSchema: () => LastHostGetInputSchema,
6975
+ LastHostSetInputSchema: () => LastHostSetInputSchema,
6976
+ LastProjectClearInputSchema: () => LastProjectClearInputSchema,
6977
+ LastProjectGetInputSchema: () => LastProjectGetInputSchema,
6978
+ LastProjectSetInputSchema: () => LastProjectSetInputSchema,
6078
6979
  ListSessionsInputSchema: () => ListSessionsInputSchema,
6079
6980
  LocalRunStatus: () => LocalRunStatus,
6080
6981
  LocalRunType: () => LocalRunType,
@@ -6088,6 +6989,7 @@ __export(local_exports2, {
6088
6989
  RunResultListInputSchema: () => RunResultListInputSchema,
6089
6990
  RunResultStorageService: () => RunResultStorageService,
6090
6991
  SessionStatus: () => SessionStatus,
6992
+ SkillTelemetryEmitInputSchema: () => SkillTelemetryEmitInputSchema,
6091
6993
  StorageService: () => StorageService,
6092
6994
  TestCaseDetailsSchema: () => TestCaseDetailsSchema,
6093
6995
  TestResultStatus: () => TestResultStatus,
@@ -6137,7 +7039,10 @@ function isLocalOnlyTool(toolName) {
6137
7039
  "muggle_run_result_list",
6138
7040
  "muggle_run_result_get",
6139
7041
  "muggle_test_script_list",
6140
- "muggle_test_script_get"
7042
+ "muggle_test_script_get",
7043
+ // Client telemetry — purely local, no backend call
7044
+ "muggle-local-telemetry-skill-emit",
7045
+ "muggle-local-telemetry-event-emit"
6141
7046
  ];
6142
7047
  return localOnlyTools.includes(toolName);
6143
7048
  }
@@ -6151,4 +7056,4 @@ var plugins_exports = {};
6151
7056
  // packages/mcps/src/mcp/agents/index.ts
6152
7057
  var agents_exports = {};
6153
7058
 
6154
- export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PreferenceKey, PreferenceValue, __export, __require, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, 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, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences };
7059
+ export { DEFAULT_PREFERENCES, EventName, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ServiceName, Surface, __export, __require, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, initTelemetry, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences };