@muggleai/works 5.16.0-staging.111 → 5.17.0-staging.113

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 (35) hide show
  1. package/README.md +3 -0
  2. package/dist/{chunk-FK7XVMVA.js → chunk-6ILUPFM5.js} +188 -4
  3. package/dist/{chunk-VQZLKLAY.js → chunk-EKSYEVM2.js} +279 -2
  4. package/dist/cli.js +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/plugin/config/onboarding-limits.json +3 -0
  7. package/dist/plugin/config/preference-defaults.json +25 -0
  8. package/dist/plugin/scripts/ensure-electron-app.sh +36 -21
  9. package/dist/plugin/skills/muggle/SKILL.md +1 -1
  10. package/dist/plugin/skills/muggle-preferences/SKILL.md +3 -2
  11. package/dist/plugin/skills/muggle-preferences/ops/configure.md +4 -3
  12. package/dist/plugin/skills/muggle-preferences/ops/list.md +2 -1
  13. package/dist/plugin/skills/muggle-preferences/ops/onboard.md +54 -0
  14. package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +7 -5
  15. package/dist/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +1 -1
  16. package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
  17. package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +1 -1
  18. package/dist/release-manifest.json +3 -3
  19. package/dist/src-52J7RTUV.js +1 -0
  20. package/package.json +2 -1
  21. package/plugin/config/onboarding-limits.json +3 -0
  22. package/plugin/config/preference-defaults.json +25 -0
  23. package/plugin/scripts/ensure-electron-app.sh +36 -21
  24. package/plugin/skills/muggle/SKILL.md +1 -1
  25. package/plugin/skills/muggle-preferences/SKILL.md +3 -2
  26. package/plugin/skills/muggle-preferences/ops/configure.md +4 -3
  27. package/plugin/skills/muggle-preferences/ops/list.md +2 -1
  28. package/plugin/skills/muggle-preferences/ops/onboard.md +54 -0
  29. package/plugin/skills/muggle-preferences/preference-gates/README.md +7 -5
  30. package/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +1 -1
  31. package/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
  32. package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +1 -1
  33. package/scripts/onboarding-backfill.mjs +49 -0
  34. package/scripts/postinstall.mjs +12 -0
  35. package/dist/src-EHF3T2T2.js +0 -1
package/README.md CHANGED
@@ -387,6 +387,8 @@ muggle serve --e2e # Cloud E2E tools only (muggle-remote-*)
387
387
  muggle serve --local # Local E2E tools only (muggle-local-*)
388
388
 
389
389
  # Setup and Diagnostics
390
+ muggle init # First-run walkthrough: explains Muggle Test, saves preferences
391
+ muggle init --json # Emit the walkthrough for another front-end to render
390
392
  muggle setup # Download/update browser test runner
391
393
  muggle setup --force # Force re-download
392
394
  muggle doctor # Diagnose installation issues
@@ -514,6 +516,7 @@ muggle-ai-works/
514
516
  │ │ ├── muggle-repair/ # /muggle:muggle-repair
515
517
  │ │ └── muggle-upgrade/ # /muggle:muggle-upgrade
516
518
  │ ├── hooks/ # Session hooks (hooks.json)
519
+ │ ├── config/ # Data the hooks read (preference defaults, onboarding limits)
517
520
  │ ├── scripts/ # Hook scripts (ensure-electron-app.sh)
518
521
  │ ├── .mcp.json # MCP server config
519
522
  │ └── README.md # Plugin install and usage docs
@@ -1,4 +1,4 @@
1
- import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getActiveRuntimeTarget, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, reconcileProjectPreferences, getDataDir, PREFERENCES_FILE_NAME, isFirstRun, writePreferences, DEFAULT_PREFERENCES, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, getElectronAppSignedFromVersion, getReleaseSignerIdentityUri, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, assertDeviceCodeClientProvisioned, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-VQZLKLAY.js';
1
+ import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getActiveRuntimeTarget, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, reconcileProjectPreferences, getDataDir, PREFERENCES_FILE_NAME, isFirstRun, writePreferences, DEFAULT_PREFERENCES, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, getElectronAppSignedFromVersion, getReleaseSignerIdentityUri, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, assertDeviceCodeClientProvisioned, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require, getDisclosureCopy, buildOnboardingPlan, applyOnboardingAnswers, needsOnboarding, OnboardingBlanketChoice, PreferenceKey } from './chunk-EKSYEVM2.js';
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
4
  import { v4 } from 'uuid';
@@ -12,6 +12,7 @@ import { fileURLToPath } from 'url';
12
12
  import { Command } from 'commander';
13
13
  import axios from 'axios';
14
14
  import { platform, homedir, arch } from 'os';
15
+ import { createInterface } from 'readline/promises';
15
16
  import { execFile } from 'child_process';
16
17
  import { pipeline } from 'stream/promises';
17
18
  import { readFile } from 'fs/promises';
@@ -753,7 +754,7 @@ async function resolveGsScreenshotUrls(report, opts) {
753
754
  if (gsUrls.length === 0) {
754
755
  return report;
755
756
  }
756
- const mcps = await import('./src-EHF3T2T2.js');
757
+ const mcps = await import('./src-52J7RTUV.js');
757
758
  const credentials = await mcps.getCallerCredentialsAsync();
758
759
  if (!credentials.bearerToken && !credentials.apiKey) {
759
760
  stderrWrite(
@@ -806,7 +807,7 @@ var withSentinel = (s) => s ? `${REPORT_SECTION_SENTINEL}
806
807
  ${s}` : s;
807
808
  async function resolveDashboardBaseUrl(stderrWrite) {
808
809
  try {
809
- const mcps = await import('./src-EHF3T2T2.js');
810
+ const mcps = await import('./src-52J7RTUV.js');
810
811
  return mcps.resolveActiveProfile().dashboardBaseUrl;
811
812
  } catch (err) {
812
813
  stderrWrite(
@@ -1536,6 +1537,7 @@ function getHelpGuidance() {
1536
1537
  ` ${cmd("muggle serve --local")} Start with local E2E tools only`,
1537
1538
  "",
1538
1539
  ` ${colorize("Setup & Diagnostics:", COLORS.bold)}`,
1540
+ ` ${cmd("muggle init")} Explain Muggle Test and save your preferences`,
1539
1541
  ` ${cmd("muggle setup")} Download/update Electron app`,
1540
1542
  ` ${cmd("muggle setup --force")} Force re-download`,
1541
1543
  ` ${cmd("muggle doctor")} Diagnose installation issues`,
@@ -1617,6 +1619,173 @@ function getHelpGuidance() {
1617
1619
  function helpCommand() {
1618
1620
  console.log(getHelpGuidance());
1619
1621
  }
1622
+ var ACCEPT_HINT = "press Enter to accept";
1623
+ function printPrimer() {
1624
+ const plan = buildOnboardingPlan();
1625
+ console.log("");
1626
+ console.log(plan.primerHeadline);
1627
+ console.log("");
1628
+ for (const bullet of plan.primerBullets) {
1629
+ console.log(` - ${bullet}`);
1630
+ }
1631
+ console.log("");
1632
+ }
1633
+ async function askOptionNumber(rl, optionCount, defaultIndex) {
1634
+ for (; ; ) {
1635
+ const answer = (await rl.question(`Choose 1-${optionCount} (${ACCEPT_HINT}): `)).trim();
1636
+ if (answer.length === 0) {
1637
+ return defaultIndex;
1638
+ }
1639
+ const picked = Number.parseInt(answer, 10);
1640
+ if (Number.isInteger(picked) && picked >= 1 && picked <= optionCount) {
1641
+ return picked - 1;
1642
+ }
1643
+ console.log(`Enter a number between 1 and ${optionCount}.`);
1644
+ }
1645
+ }
1646
+ async function askBlanketChoice(rl) {
1647
+ const options = buildOnboardingPlan().blanketOptions;
1648
+ options.forEach((option, index) => {
1649
+ console.log(` ${index + 1}. ${option.label}`);
1650
+ console.log(` ${option.description}`);
1651
+ });
1652
+ console.log("");
1653
+ const picked = await askOptionNumber(rl, options.length, 0);
1654
+ return options[picked].choice;
1655
+ }
1656
+ async function askToggleGroup(rl, group, selected) {
1657
+ console.log("");
1658
+ console.log(`- ${group.header} -`);
1659
+ console.log(group.prompt);
1660
+ group.entries.forEach((entry, index) => {
1661
+ if (entry.isSelectedByDefault) {
1662
+ selected.add(entry.key);
1663
+ }
1664
+ const mark = entry.isSelectedByDefault ? "x" : " ";
1665
+ console.log(` [${mark}] ${index + 1}. ${entry.key} \u2014 ${entry.description}`);
1666
+ });
1667
+ const answer = (await rl.question(`Numbers to flip, comma-separated (${ACCEPT_HINT}): `)).trim();
1668
+ if (answer.length === 0) {
1669
+ return;
1670
+ }
1671
+ for (const token of answer.split(",")) {
1672
+ const picked = Number.parseInt(token.trim(), 10);
1673
+ if (!Number.isInteger(picked) || picked < 1 || picked > group.entries.length) {
1674
+ continue;
1675
+ }
1676
+ const { key } = group.entries[picked - 1];
1677
+ if (selected.has(key)) {
1678
+ selected.delete(key);
1679
+ } else {
1680
+ selected.add(key);
1681
+ }
1682
+ }
1683
+ }
1684
+ async function askChoiceGroup(rl, group, choices) {
1685
+ console.log("");
1686
+ console.log(`- ${group.header} -`);
1687
+ console.log(group.prompt);
1688
+ const defaultIndex = Math.max(
1689
+ group.options.findIndex((option) => option.isDefault),
1690
+ 0
1691
+ );
1692
+ group.options.forEach((option, index) => {
1693
+ const mark = option.isDefault ? "*" : " ";
1694
+ console.log(` ${mark} ${index + 1}. ${option.label}`);
1695
+ });
1696
+ const picked = await askOptionNumber(rl, group.options.length, defaultIndex);
1697
+ choices[group.key] = group.options[picked].value;
1698
+ }
1699
+ async function runTerminalWalkthrough() {
1700
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1701
+ try {
1702
+ printPrimer();
1703
+ const blanket = await askBlanketChoice(rl);
1704
+ if (blanket !== "customize" /* Customize */) {
1705
+ return { blanket };
1706
+ }
1707
+ const selected = /* @__PURE__ */ new Set();
1708
+ const choices = {};
1709
+ for (const group of buildOnboardingPlan().groups) {
1710
+ if (group.kind === "toggle" /* Toggle */) {
1711
+ await askToggleGroup(rl, group, selected);
1712
+ } else {
1713
+ await askChoiceGroup(rl, group, choices);
1714
+ }
1715
+ }
1716
+ return {
1717
+ blanket,
1718
+ selectedToggleKeys: [...selected],
1719
+ choices
1720
+ };
1721
+ } finally {
1722
+ rl.close();
1723
+ }
1724
+ }
1725
+
1726
+ // src/cli/init/init-command.ts
1727
+ function isBlanketChoice(value) {
1728
+ return Object.values(OnboardingBlanketChoice).includes(value);
1729
+ }
1730
+ function parseAnswersFile(filePath) {
1731
+ const parsed = JSON.parse(readFileSync(filePath, "utf-8"));
1732
+ if (!isBlanketChoice(parsed.blanket)) {
1733
+ throw new Error(
1734
+ `Answers file must set "blanket" to one of: ${Object.values(OnboardingBlanketChoice).join(", ")}`
1735
+ );
1736
+ }
1737
+ const validKeys = Object.values(PreferenceKey);
1738
+ for (const key of parsed.selectedToggleKeys ?? []) {
1739
+ if (!validKeys.includes(key)) {
1740
+ throw new Error(`Unknown preference key in selectedToggleKeys: ${key}`);
1741
+ }
1742
+ }
1743
+ return {
1744
+ blanket: parsed.blanket,
1745
+ selectedToggleKeys: parsed.selectedToggleKeys,
1746
+ choices: parsed.choices
1747
+ };
1748
+ }
1749
+ function reportOutcome(result) {
1750
+ if (result.skip && !result.skip.isRetired) {
1751
+ console.log("Skipped. Muggle will offer this again next session.");
1752
+ return;
1753
+ }
1754
+ if (result.skip) {
1755
+ console.log("Skipped. Muggle will not ask again \u2014 run `muggle init` whenever you want it.");
1756
+ return;
1757
+ }
1758
+ const summary = Object.entries(result.preferences).map(([key, value]) => `${key}=${value}`).join(" ");
1759
+ console.log("");
1760
+ console.log("Preferences saved.");
1761
+ console.log(summary);
1762
+ }
1763
+ async function initCommand(options) {
1764
+ if (options.json) {
1765
+ console.log(JSON.stringify(buildOnboardingPlan(), null, 2));
1766
+ return;
1767
+ }
1768
+ if (options.apply) {
1769
+ try {
1770
+ reportOutcome(applyOnboardingAnswers(parseAnswersFile(options.apply)));
1771
+ } catch (error) {
1772
+ console.error(error instanceof Error ? error.message : String(error));
1773
+ process.exitCode = 1;
1774
+ }
1775
+ return;
1776
+ }
1777
+ if (!process.stdin.isTTY) {
1778
+ console.error(
1779
+ "`muggle init` needs an interactive terminal. Use `--json` to render the walkthrough elsewhere and `--apply <file>` to save the answers."
1780
+ );
1781
+ process.exitCode = 1;
1782
+ return;
1783
+ }
1784
+ if (!needsOnboarding()) {
1785
+ console.log("Muggle is already set up. Re-running the walkthrough \u2014 your current values are pre-selected.");
1786
+ }
1787
+ reportOutcome(applyOnboardingAnswers(await runTerminalWalkthrough()));
1788
+ }
1620
1789
 
1621
1790
  // src/cli/login.ts
1622
1791
  var logger4 = getLogger();
@@ -1687,12 +1856,26 @@ async function statusCommand() {
1687
1856
  }
1688
1857
  }
1689
1858
 
1859
+ // src/cli/disclosure/disclosure-constants.ts
1860
+ var DISCLOSURE_OPT_OUT_MARKER = "To opt out,";
1861
+ var DISCLOSURE_OPT_OUT_COPY = 'To opt out, set MUGGLE_TELEMETRY_DISABLED=1 in your environment, or set "telemetryEnabled": false at the top level of ~/.muggle-ai/preferences.json.';
1862
+
1863
+ // src/cli/disclosure/disclosure-copy.ts
1864
+ function resolveDisclosureCopy() {
1865
+ const upstream = getDisclosureCopy();
1866
+ const markerIndex = upstream.indexOf(DISCLOSURE_OPT_OUT_MARKER);
1867
+ if (markerIndex < 0) {
1868
+ return `${upstream} ${DISCLOSURE_OPT_OUT_COPY}`;
1869
+ }
1870
+ return `${upstream.slice(0, markerIndex)}${DISCLOSURE_OPT_OUT_COPY}`;
1871
+ }
1872
+
1690
1873
  // src/cli/serve.ts
1691
1874
  var APPLICATIONINSIGHTS_CONNECTION_STRING = "InstrumentationKey=0e28df42-b98e-4089-b3b5-6decefb99447;IngestionEndpoint=https://westus3-1.in.applicationinsights.azure.com/;LiveEndpoint=https://westus3.livediagnostics.monitor.azure.com/;ApplicationId=b64a932f-85ec-40cd-a74b-e181a3660f6c";
1692
1875
  function showDisclosureIfNeeded() {
1693
1876
  try {
1694
1877
  if (hasShownDisclosure()) return;
1695
- process.stderr.write(getDisclosureCopy() + "\n");
1878
+ process.stderr.write(resolveDisclosureCopy() + "\n");
1696
1879
  markDisclosureShown();
1697
1880
  } catch {
1698
1881
  }
@@ -2448,6 +2631,7 @@ function createProgram() {
2448
2631
  const program = new Command();
2449
2632
  program.name("muggle").description("Unified MCP server for Muggle AI \u2014 cloud E2E and local E2E testing").version(packageVersion);
2450
2633
  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);
2634
+ program.command("init").description("Set up Muggle Test \u2014 explains how it works and saves your preferences").option("--json", "Emit the walkthrough as JSON instead of prompting").option("--apply <file>", "Apply answers from a JSON file").action(initCommand);
2451
2635
  program.command("setup").description("Download/update the Electron app for local testing").option("--force", "Force re-download even if already installed").action(setupCommand);
2452
2636
  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);
2453
2637
  program.command("versions").description("List installed electron-app versions").action(versionsCommand);
@@ -31,6 +31,16 @@ var src_exports = {};
31
31
  __export(src_exports, {
32
32
  DEFAULT_PREFERENCES: () => DEFAULT_PREFERENCES,
33
33
  ElectronAppReleaseStream: () => ElectronAppReleaseStream,
34
+ ONBOARDING_BLANKET_OPTIONS: () => ONBOARDING_BLANKET_OPTIONS,
35
+ ONBOARDING_CHOICE_GROUPS: () => ONBOARDING_CHOICE_GROUPS,
36
+ ONBOARDING_MAX_OFFERS: () => ONBOARDING_MAX_OFFERS,
37
+ ONBOARDING_PRIMER_BULLETS: () => ONBOARDING_PRIMER_BULLETS,
38
+ ONBOARDING_PRIMER_HEADLINE: () => ONBOARDING_PRIMER_HEADLINE,
39
+ ONBOARDING_TOGGLE_GROUPS: () => ONBOARDING_TOGGLE_GROUPS,
40
+ ONBOARDING_TOGGLE_PROMPT: () => ONBOARDING_TOGGLE_PROMPT,
41
+ ONBOARDING_UNSELECTED_TOGGLE_VALUE: () => ONBOARDING_UNSELECTED_TOGGLE_VALUE,
42
+ OnboardingBlanketChoice: () => OnboardingBlanketChoice,
43
+ OnboardingGroupKind: () => OnboardingGroupKind,
34
44
  PREFERENCES_FILE_NAME: () => PREFERENCES_FILE_NAME,
35
45
  PREFERENCES_PROJECT_DIR_NAME: () => PREFERENCES_PROJECT_DIR_NAME,
36
46
  PREFERENCES_SCHEMA: () => PREFERENCES_SCHEMA,
@@ -42,11 +52,14 @@ __export(src_exports, {
42
52
  RuntimeTarget: () => RuntimeTarget,
43
53
  WATCHER_LIFETIME_SECONDS: () => WATCHER_LIFETIME_SECONDS,
44
54
  WATCHER_LIFETIME_UNBOUNDED_SECONDS: () => WATCHER_LIFETIME_UNBOUNDED_SECONDS,
55
+ applyOnboardingAnswers: () => applyOnboardingAnswers,
45
56
  assertDeviceCodeClientProvisioned: () => assertDeviceCodeClientProvisioned,
46
57
  buildElectronAppChecksumsUrl: () => buildElectronAppChecksumsUrl,
47
58
  buildElectronAppReleaseAssetUrl: () => buildElectronAppReleaseAssetUrl,
48
59
  buildElectronAppReleaseTag: () => buildElectronAppReleaseTag,
60
+ buildOnboardingPlan: () => buildOnboardingPlan,
49
61
  calculateFileChecksum: () => calculateFileChecksum,
62
+ completeOnboarding: () => completeOnboarding,
50
63
  createApiKeyWithToken: () => createApiKeyWithToken,
51
64
  createChildLogger: () => createChildLogger,
52
65
  deleteApiKeyData: () => deleteApiKeyData,
@@ -74,6 +87,7 @@ __export(src_exports, {
74
87
  getElectronAppVersionSource: () => getElectronAppVersionSource,
75
88
  getLocalQaTools: () => getLocalQaTools,
76
89
  getLogger: () => getLogger,
90
+ getOnboardingToggleKeys: () => getOnboardingToggleKeys,
77
91
  getPlatformKey: () => getPlatformKey,
78
92
  getQaTools: () => getQaTools,
79
93
  getReleaseSignerIdentityUri: () => getReleaseSignerIdentityUri,
@@ -85,22 +99,29 @@ __export(src_exports, {
85
99
  loadApiKeyData: () => loadApiKeyData,
86
100
  loadCredentials: () => loadCredentials,
87
101
  localQa: () => local_exports2,
102
+ markOnboardingCompleted: () => markOnboardingCompleted,
88
103
  mcp: () => mcp_exports,
104
+ needsOnboarding: () => needsOnboarding,
89
105
  openBrowserUrl: () => openBrowserUrl,
90
106
  performLogin: () => performLogin,
91
107
  performLogout: () => performLogout,
92
108
  pollDeviceCode: () => pollDeviceCode,
93
109
  qa: () => e2e_exports2,
110
+ readPreferencesMetadata: () => readPreferencesMetadata,
94
111
  reconcileProjectPreferences: () => reconcileProjectPreferences,
112
+ recordOnboardingSkip: () => recordOnboardingSkip,
95
113
  resetConfig: () => resetConfig,
96
114
  resetLogger: () => resetLogger,
97
115
  resetPreference: () => resetPreference,
98
116
  resolveActiveProfile: () => resolveActiveProfile,
99
117
  resolveActiveReleaseStream: () => resolveActiveReleaseStream,
100
118
  resolveActiveReleaseTagPrefix: () => resolveActiveReleaseTagPrefix,
119
+ resolveBlanketPreferences: () => resolveBlanketPreferences,
101
120
  resolveElectronAppPathOrNull: () => resolveElectronAppPathOrNull,
121
+ resolveOnboardingAnswers: () => resolveOnboardingAnswers,
102
122
  resolvePreferences: () => resolvePreferences,
103
123
  resolveRuntimeTarget: () => resolveRuntimeTarget,
124
+ resolveTogglePreferences: () => resolveTogglePreferences,
104
125
  saveApiKey: () => saveApiKey,
105
126
  saveApiKeyData: () => saveApiKeyData,
106
127
  saveCredentials: () => saveCredentials,
@@ -108,7 +129,8 @@ __export(src_exports, {
108
129
  toolRequiresAuth: () => toolRequiresAuth,
109
130
  validatePreference: () => validatePreference,
110
131
  verifyFileChecksum: () => verifyFileChecksum,
111
- writePreferences: () => writePreferences2
132
+ writePreferences: () => writePreferences2,
133
+ writePreferencesWithMetadata: () => writePreferencesWithMetadata
112
134
  });
113
135
 
114
136
  // packages/mcps/src/shared/runtime-target-types.ts
@@ -6940,6 +6962,27 @@ function writePreferences2(prefs, dataDirOverride2) {
6940
6962
  const existing = readPreferencesFile(filePath);
6941
6963
  writePreferencesFile(filePath, { ...existing, ...prefs });
6942
6964
  }
6965
+ function readPreferencesMetadata(dataDirOverride2) {
6966
+ const metadata = {
6967
+ ...readRawPreferencesFile(getGlobalPreferencesFilePath(dataDirOverride2))
6968
+ };
6969
+ delete metadata.preferences;
6970
+ return metadata;
6971
+ }
6972
+ function writePreferencesWithMetadata(prefs, metadata, dataDirOverride2) {
6973
+ const dir = dataDirOverride2 ?? getDataDir();
6974
+ fs6.mkdirSync(dir, { recursive: true });
6975
+ const filePath = path11.join(dir, PREFERENCES_FILE_NAME);
6976
+ const existing = readRawPreferencesFile(filePath);
6977
+ const file = {
6978
+ ...existing,
6979
+ ...metadata,
6980
+ version: PREFERENCES_VERSION,
6981
+ preferences: { ...existing.preferences ?? {}, ...prefs }
6982
+ };
6983
+ fs6.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}
6984
+ `, "utf-8");
6985
+ }
6943
6986
  function resetPreference(key, dataDirOverride2) {
6944
6987
  const filePath = getGlobalPreferencesFilePath(dataDirOverride2);
6945
6988
  if (!fs6.existsSync(filePath)) {
@@ -7923,4 +7966,238 @@ var WATCHER_LIFETIME_SECONDS = {
7923
7966
  ["never" /* Never */]: WATCHER_LIFETIME_UNBOUNDED_SECONDS
7924
7967
  };
7925
7968
 
7926
- export { DEFAULT_PREFERENCES, ElectronAppReleaseStream, EventName, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, RuntimeTarget, ServiceName, Surface, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, __export, __require, assertDeviceCodeClientProvisioned, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, getActiveElectronAppReleaseStream, getActiveRuntimeTarget, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDisclosureCopy, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppReleaseTagPrefix, getElectronAppSignedFromVersion, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getReleaseSignerIdentityUri, getValidApiKeyData, getValidCredentials, hasApiKey, hasShownDisclosure, initTelemetry, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, markDisclosureShown, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, reconcileProjectPreferences, resetConfig, resetLogger, resetPreference, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveElectronAppPathOrNull, resolvePreferences, resolveRuntimeTarget, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences };
7969
+ // packages/mcps/src/shared/onboarding/onboarding-types.ts
7970
+ var OnboardingGroupKind = /* @__PURE__ */ ((OnboardingGroupKind2) => {
7971
+ OnboardingGroupKind2["Toggle"] = "toggle";
7972
+ OnboardingGroupKind2["Choice"] = "choice";
7973
+ return OnboardingGroupKind2;
7974
+ })(OnboardingGroupKind || {});
7975
+ var OnboardingBlanketChoice = /* @__PURE__ */ ((OnboardingBlanketChoice2) => {
7976
+ OnboardingBlanketChoice2["AcceptDefaults"] = "accept-defaults";
7977
+ OnboardingBlanketChoice2["AskEverything"] = "ask-everything";
7978
+ OnboardingBlanketChoice2["Customize"] = "customize";
7979
+ OnboardingBlanketChoice2["Skip"] = "skip";
7980
+ return OnboardingBlanketChoice2;
7981
+ })(OnboardingBlanketChoice || {});
7982
+
7983
+ // packages/mcps/src/shared/onboarding/onboarding-constants.ts
7984
+ var ONBOARDING_PRIMER_HEADLINE = "Muggle Test drives a real browser against your app.";
7985
+ var ONBOARDING_PRIMER_BULLETS = [
7986
+ "Tests are plain English",
7987
+ "Scripts replay as regressions",
7988
+ "Run locally or in the cloud",
7989
+ "Real logins, real inboxes",
7990
+ "Screenshots land on your PR"
7991
+ ];
7992
+ var ONBOARDING_MAX_OFFERS = 3;
7993
+ var ONBOARDING_UNSELECTED_TOGGLE_VALUE = "ask" /* Ask */;
7994
+ var ONBOARDING_TOGGLE_PROMPT = 'Which of these should Muggle do on its own? Anything you leave off is set to "ask".';
7995
+ var ONBOARDING_TOGGLE_GROUPS = [
7996
+ {
7997
+ header: "Auth & session",
7998
+ keys: [
7999
+ "autoLogin" /* AutoLogin */,
8000
+ "autoSelectProject" /* AutoSelectProject */,
8001
+ "checkForUpdates" /* CheckForUpdates */,
8002
+ "verboseOutput" /* VerboseOutput */
8003
+ ]
8004
+ },
8005
+ {
8006
+ header: "Test setup",
8007
+ keys: [
8008
+ "autoSelectLocalHost" /* AutoSelectLocalHost */,
8009
+ "autoDetectChanges" /* AutoDetectChanges */,
8010
+ "autoReuseValidationContext" /* AutoReuseValidationContext */,
8011
+ "reusePreparePlan" /* ReusePreparePlan */
8012
+ ]
8013
+ },
8014
+ {
8015
+ header: "Test run",
8016
+ keys: ["showElectronBrowser" /* ShowElectronBrowser */, "openTestResultsAfterRun" /* OpenTestResultsAfterRun */]
8017
+ },
8018
+ {
8019
+ header: "Suggestions",
8020
+ keys: ["suggestRelatedUseCases" /* SuggestRelatedUseCases */, "suggestRelatedTestCases" /* SuggestRelatedTestCases */]
8021
+ },
8022
+ {
8023
+ header: "PR",
8024
+ keys: [
8025
+ "postPRVisualWalkthrough" /* PostPRVisualWalkthrough */,
8026
+ "autoCreatePR" /* AutoCreatePR */,
8027
+ "autoWatchPR" /* AutoWatchPR */,
8028
+ "autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */
8029
+ ]
8030
+ },
8031
+ {
8032
+ header: "Branch hygiene",
8033
+ keys: [
8034
+ "autoUseWorktree" /* AutoUseWorktree */,
8035
+ "autoRebase" /* AutoRebase */,
8036
+ "autoCleanup" /* AutoCleanup */,
8037
+ "autoResolveConflicts" /* AutoResolveConflicts */
8038
+ ]
8039
+ }
8040
+ ];
8041
+ var ONBOARDING_CHOICE_GROUPS = [
8042
+ {
8043
+ header: "E2E acceptance",
8044
+ key: "autoE2ETest" /* AutoE2ETest */,
8045
+ prompt: "Run E2E acceptance at the end of every dev cycle?",
8046
+ optionLabels: [
8047
+ { value: "always" /* Always */, label: "Always run it at the end" },
8048
+ { value: "ask" /* Ask */, label: "Ask each cycle" }
8049
+ ]
8050
+ },
8051
+ {
8052
+ header: "Default mode",
8053
+ key: "defaultExecutionMode" /* DefaultExecutionMode */,
8054
+ prompt: "Where should tests run by default?",
8055
+ optionLabels: [
8056
+ { value: "local" /* Local */, label: "Local \u2014 run on my computer" },
8057
+ { value: "remote" /* Remote */, label: "Remote \u2014 run in the Muggle Test cloud" },
8058
+ { value: "ask" /* Ask */, label: "Ask each time" }
8059
+ ]
8060
+ },
8061
+ {
8062
+ header: "PR watcher",
8063
+ key: "watcherLifetime" /* WatcherLifetime */,
8064
+ prompt: "How long should a PR watcher keep polling for new reviews?",
8065
+ optionLabels: [
8066
+ { value: "1d" /* OneDay */, label: "Retire after 1 day" },
8067
+ { value: "7d" /* SevenDays */, label: "Retire after 7 days" },
8068
+ { value: "never" /* Never */, label: "Never retire \u2014 no time-based reaper for an orphaned loop" }
8069
+ ]
8070
+ }
8071
+ ];
8072
+ var ONBOARDING_BLANKET_OPTIONS = [
8073
+ {
8074
+ choice: "accept-defaults" /* AcceptDefaults */,
8075
+ label: "Accept recommended defaults",
8076
+ description: "Automate the safe parts, run tests locally, show the browser. Done in one keystroke."
8077
+ },
8078
+ {
8079
+ choice: "ask-everything" /* AskEverything */,
8080
+ label: "Ask me before everything",
8081
+ description: "Nothing proceeds unattended. Features stay available; Muggle just checks with you first."
8082
+ },
8083
+ {
8084
+ choice: "customize" /* Customize */,
8085
+ label: "Walk me through the questions",
8086
+ description: "Go group by group, with the recommended answer pre-selected."
8087
+ },
8088
+ {
8089
+ choice: "skip" /* Skip */,
8090
+ label: "Skip for now",
8091
+ description: "Use defaults without saving a choice. Offered again next session."
8092
+ }
8093
+ ];
8094
+
8095
+ // packages/mcps/src/shared/onboarding/onboarding-service.ts
8096
+ function needsOnboarding(dataDirOverride2) {
8097
+ const completedAt = readPreferencesMetadata(dataDirOverride2).onboardingCompletedAt;
8098
+ return typeof completedAt !== "string" || completedAt.length === 0;
8099
+ }
8100
+ function getOnboardingToggleKeys() {
8101
+ return ONBOARDING_TOGGLE_GROUPS.flatMap((group) => group.keys);
8102
+ }
8103
+ function buildOnboardingPlan() {
8104
+ const toggleGroups = ONBOARDING_TOGGLE_GROUPS.map((group) => ({
8105
+ kind: "toggle" /* Toggle */,
8106
+ header: group.header,
8107
+ prompt: ONBOARDING_TOGGLE_PROMPT,
8108
+ entries: group.keys.map((key) => ({
8109
+ key,
8110
+ description: PREFERENCES_SCHEMA[key].description,
8111
+ isSelectedByDefault: DEFAULT_PREFERENCES[key] === "always" /* Always */
8112
+ }))
8113
+ }));
8114
+ const choiceGroups = ONBOARDING_CHOICE_GROUPS.map((group) => ({
8115
+ kind: "choice" /* Choice */,
8116
+ header: group.header,
8117
+ prompt: group.prompt,
8118
+ key: group.key,
8119
+ description: PREFERENCES_SCHEMA[group.key].description,
8120
+ options: group.optionLabels.map((option) => ({
8121
+ label: option.label,
8122
+ value: option.value,
8123
+ isDefault: DEFAULT_PREFERENCES[group.key] === option.value
8124
+ }))
8125
+ }));
8126
+ return {
8127
+ primerHeadline: ONBOARDING_PRIMER_HEADLINE,
8128
+ primerBullets: [...ONBOARDING_PRIMER_BULLETS],
8129
+ blanketOptions: [...ONBOARDING_BLANKET_OPTIONS],
8130
+ groups: [...toggleGroups, ...choiceGroups]
8131
+ };
8132
+ }
8133
+ function resolveBlanketPreferences(choice) {
8134
+ if (choice === "ask-everything" /* AskEverything */) {
8135
+ const prefs = {};
8136
+ for (const key of Object.values(PreferenceKey)) {
8137
+ prefs[key] = PREFERENCE_ALLOWED_VALUES[key].includes("ask" /* Ask */) ? "ask" /* Ask */ : DEFAULT_PREFERENCES[key];
8138
+ }
8139
+ return prefs;
8140
+ }
8141
+ return { ...DEFAULT_PREFERENCES };
8142
+ }
8143
+ function resolveUnselectedValue(key) {
8144
+ return DEFAULT_PREFERENCES[key] === "never" /* Never */ ? "never" /* Never */ : ONBOARDING_UNSELECTED_TOGGLE_VALUE;
8145
+ }
8146
+ function resolveTogglePreferences(selectedKeys) {
8147
+ const selected = new Set(selectedKeys);
8148
+ const prefs = {};
8149
+ for (const key of getOnboardingToggleKeys()) {
8150
+ prefs[key] = selected.has(key) ? "always" /* Always */ : resolveUnselectedValue(key);
8151
+ }
8152
+ return prefs;
8153
+ }
8154
+ function completeOnboarding(prefs, dataDirOverride2, now = /* @__PURE__ */ new Date()) {
8155
+ writePreferencesWithMetadata(
8156
+ prefs,
8157
+ { onboardingCompletedAt: now.toISOString() },
8158
+ dataDirOverride2
8159
+ );
8160
+ }
8161
+ function recordOnboardingSkip(dataDirOverride2, now = /* @__PURE__ */ new Date()) {
8162
+ const offerCount = (readPreferencesMetadata(dataDirOverride2).onboardingOfferCount ?? 0) + 1;
8163
+ const isRetired = offerCount >= ONBOARDING_MAX_OFFERS;
8164
+ writePreferencesWithMetadata(
8165
+ {},
8166
+ {
8167
+ onboardingOfferCount: offerCount,
8168
+ ...isRetired ? { onboardingCompletedAt: now.toISOString() } : {}
8169
+ },
8170
+ dataDirOverride2
8171
+ );
8172
+ return { offerCount, isRetired };
8173
+ }
8174
+ function markOnboardingCompleted(dataDirOverride2, now = /* @__PURE__ */ new Date()) {
8175
+ writePreferencesWithMetadata({}, { onboardingCompletedAt: now.toISOString() }, dataDirOverride2);
8176
+ }
8177
+ function resolveOnboardingAnswers(answers) {
8178
+ if (answers.blanket === "skip" /* Skip */) {
8179
+ return {};
8180
+ }
8181
+ if (answers.blanket !== "customize" /* Customize */) {
8182
+ return resolveBlanketPreferences(answers.blanket);
8183
+ }
8184
+ const prefs = resolveTogglePreferences(answers.selectedToggleKeys ?? []);
8185
+ for (const [key, value] of Object.entries(answers.choices ?? {})) {
8186
+ if (!validatePreference(key, value)) {
8187
+ throw new Error(`Invalid onboarding choice: ${key}=${value}`);
8188
+ }
8189
+ prefs[key] = value;
8190
+ }
8191
+ return prefs;
8192
+ }
8193
+ function applyOnboardingAnswers(answers, dataDirOverride2, now = /* @__PURE__ */ new Date()) {
8194
+ if (answers.blanket === "skip" /* Skip */) {
8195
+ const skip = recordOnboardingSkip(dataDirOverride2, now);
8196
+ return { isCompleted: skip.isRetired, preferences: {}, skip };
8197
+ }
8198
+ const prefs = resolveOnboardingAnswers(answers);
8199
+ completeOnboarding(prefs, dataDirOverride2, now);
8200
+ return { isCompleted: true, preferences: prefs };
8201
+ }
8202
+
8203
+ export { DEFAULT_PREFERENCES, ElectronAppReleaseStream, EventName, ONBOARDING_BLANKET_OPTIONS, ONBOARDING_CHOICE_GROUPS, ONBOARDING_MAX_OFFERS, ONBOARDING_PRIMER_BULLETS, ONBOARDING_PRIMER_HEADLINE, ONBOARDING_TOGGLE_GROUPS, ONBOARDING_TOGGLE_PROMPT, ONBOARDING_UNSELECTED_TOGGLE_VALUE, OnboardingBlanketChoice, OnboardingGroupKind, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, ProjectPreferencesReconcileOutcome, RuntimeTarget, ServiceName, Surface, WATCHER_LIFETIME_SECONDS, WATCHER_LIFETIME_UNBOUNDED_SECONDS, __export, __require, applyOnboardingAnswers, assertDeviceCodeClientProvisioned, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, buildOnboardingPlan, calculateFileChecksum, completeOnboarding, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports2 as e2e_exports, formatPreferencesOneLiner, getActiveElectronAppReleaseStream, getActiveRuntimeTarget, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir2 as getDataDir, getDisclosureCopy, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppReleaseTagPrefix, getElectronAppSignedFromVersion, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getOnboardingToggleKeys, getPlatformKey, getQaTools, getReleaseSignerIdentityUri, getValidApiKeyData, getValidCredentials, hasApiKey, hasShownDisclosure, initTelemetry, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, markDisclosureShown, markOnboardingCompleted, mcp_exports, needsOnboarding, openBrowserUrl, performLogin, performLogout, pollDeviceCode, readPreferencesMetadata, reconcileProjectPreferences, recordOnboardingSkip, resetConfig, resetLogger, resetPreference, resolveActiveProfile, resolveActiveReleaseStream, resolveActiveReleaseTagPrefix, resolveBlanketPreferences, resolveElectronAppPathOrNull, resolveOnboardingAnswers, resolvePreferences, resolveRuntimeTarget, resolveTogglePreferences, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences, writePreferencesWithMetadata };
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from './chunk-FK7XVMVA.js';
3
- import './chunk-VQZLKLAY.js';
2
+ import { runCli } from './chunk-6ILUPFM5.js';
3
+ import './chunk-EKSYEVM2.js';
4
4
 
5
5
  // src/cli/main.ts
6
6
  runCli().catch((error) => {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-FK7XVMVA.js';
2
- export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-VQZLKLAY.js';
1
+ export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-6ILUPFM5.js';
2
+ export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-EKSYEVM2.js';
@@ -0,0 +1,3 @@
1
+ {
2
+ "maxOffers": 3
3
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "autoLogin": "always",
3
+ "autoSelectProject": "always",
4
+ "autoSelectLocalHost": "always",
5
+ "showElectronBrowser": "always",
6
+ "openTestResultsAfterRun": "always",
7
+ "defaultExecutionMode": "local",
8
+ "suggestRelatedUseCases": "always",
9
+ "suggestRelatedTestCases": "always",
10
+ "autoDetectChanges": "always",
11
+ "postPRVisualWalkthrough": "always",
12
+ "autoCreatePR": "always",
13
+ "checkForUpdates": "always",
14
+ "verboseOutput": "never",
15
+ "autoUseWorktree": "always",
16
+ "autoRebase": "always",
17
+ "autoCleanup": "always",
18
+ "autoE2ETest": "always",
19
+ "autoResolveConflicts": "always",
20
+ "autoReuseValidationContext": "always",
21
+ "autoRouteBuildToMuggleDo": "always",
22
+ "autoWatchPR": "always",
23
+ "reusePreparePlan": "always",
24
+ "watcherLifetime": "7d"
25
+ }