@muggleai/works 5.19.0-staging.129 → 5.19.0-staging.131

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 (33) hide show
  1. package/dist/{chunk-JNYP5PWT.js → chunk-ODEPI25T.js} +3 -3
  2. package/dist/{chunk-ESPHO3WB.js → chunk-U6ZACW6K.js} +159 -58
  3. package/dist/cli.js +2 -2
  4. package/dist/index.js +2 -2
  5. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  6. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  7. package/dist/plugin/config/preference-defaults.json +26 -25
  8. package/dist/plugin/skills/do/resolve-conflicts.md +68 -59
  9. package/dist/plugin/skills/muggle-pr-followup/blocked-tick.md +40 -38
  10. package/dist/plugin/skills/muggle-pr-followup/contract.md +8 -2
  11. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +6 -1
  12. package/dist/plugin/skills/muggle-preferences/SKILL.md +33 -33
  13. package/dist/plugin/skills/muggle-preferences/ops/configure.md +51 -50
  14. package/dist/plugin/skills/muggle-preferences/ops/list.md +11 -10
  15. package/dist/plugin/skills/muggle-preferences/ops/onboard.md +54 -54
  16. package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +69 -63
  17. package/dist/plugin/skills/muggle-preferences/preference-gates/maxCatchUpRebases.md +28 -0
  18. package/dist/release-manifest.json +3 -3
  19. package/dist/{src-ZF6QSZJV.js → src-C2IZ3MAZ.js} +1 -1
  20. package/package.json +1 -1
  21. package/plugin/.claude-plugin/plugin.json +1 -1
  22. package/plugin/.cursor-plugin/plugin.json +1 -1
  23. package/plugin/config/preference-defaults.json +26 -25
  24. package/plugin/skills/do/resolve-conflicts.md +68 -59
  25. package/plugin/skills/muggle-pr-followup/blocked-tick.md +40 -38
  26. package/plugin/skills/muggle-pr-followup/contract.md +8 -2
  27. package/plugin/skills/muggle-pr-followup/state-schemas.md +6 -1
  28. package/plugin/skills/muggle-preferences/SKILL.md +33 -33
  29. package/plugin/skills/muggle-preferences/ops/configure.md +51 -50
  30. package/plugin/skills/muggle-preferences/ops/list.md +11 -10
  31. package/plugin/skills/muggle-preferences/ops/onboard.md +54 -54
  32. package/plugin/skills/muggle-preferences/preference-gates/README.md +69 -63
  33. package/plugin/skills/muggle-preferences/preference-gates/maxCatchUpRebases.md +28 -0
@@ -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, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require, getDisclosureCopy, buildOnboardingPlan, applyOnboardingAnswers, needsOnboarding, OnboardingBlanketChoice, PreferenceKey } from './chunk-ESPHO3WB.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-U6ZACW6K.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';
@@ -754,7 +754,7 @@ async function resolveGsScreenshotUrls(report, opts) {
754
754
  if (gsUrls.length === 0) {
755
755
  return report;
756
756
  }
757
- const mcps = await import('./src-ZF6QSZJV.js');
757
+ const mcps = await import('./src-C2IZ3MAZ.js');
758
758
  const credentials = await mcps.getCallerCredentialsAsync();
759
759
  if (!credentials.bearerToken && !credentials.apiKey) {
760
760
  stderrWrite(
@@ -807,7 +807,7 @@ var withSentinel = (s) => s ? `${REPORT_SECTION_SENTINEL}
807
807
  ${s}` : s;
808
808
  async function resolveDashboardBaseUrl(stderrWrite) {
809
809
  try {
810
- const mcps = await import('./src-ZF6QSZJV.js');
810
+ const mcps = await import('./src-C2IZ3MAZ.js');
811
811
  return mcps.resolveActiveProfile().dashboardBaseUrl;
812
812
  } catch (err) {
813
813
  stderrWrite(
@@ -2230,6 +2230,7 @@ var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
2230
2230
  PreferenceKey2["AutoRouteBuildToMuggleDo"] = "autoRouteBuildToMuggleDo";
2231
2231
  PreferenceKey2["AutoWatchPR"] = "autoWatchPR";
2232
2232
  PreferenceKey2["WatcherLifetime"] = "watcherLifetime";
2233
+ PreferenceKey2["MaxCatchUpRebases"] = "maxCatchUpRebases";
2233
2234
  PreferenceKey2["ReusePreparePlan"] = "reusePreparePlan";
2234
2235
  return PreferenceKey2;
2235
2236
  })(PreferenceKey || {});
@@ -2241,6 +2242,9 @@ var PreferenceValue = /* @__PURE__ */ ((PreferenceValue2) => {
2241
2242
  PreferenceValue2["Remote"] = "remote";
2242
2243
  PreferenceValue2["OneDay"] = "1d";
2243
2244
  PreferenceValue2["SevenDays"] = "7d";
2245
+ PreferenceValue2["TenRebases"] = "10";
2246
+ PreferenceValue2["TwentyRebases"] = "20";
2247
+ PreferenceValue2["FiftyRebases"] = "50";
2244
2248
  return PreferenceValue2;
2245
2249
  })(PreferenceValue || {});
2246
2250
 
@@ -2271,7 +2275,8 @@ var DEFAULT_PREFERENCES = {
2271
2275
  ["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: "always" /* Always */,
2272
2276
  ["autoWatchPR" /* AutoWatchPR */]: "always" /* Always */,
2273
2277
  ["reusePreparePlan" /* ReusePreparePlan */]: "always" /* Always */,
2274
- ["watcherLifetime" /* WatcherLifetime */]: "7d" /* SevenDays */
2278
+ ["watcherLifetime" /* WatcherLifetime */]: "7d" /* SevenDays */,
2279
+ ["maxCatchUpRebases" /* MaxCatchUpRebases */]: "20" /* TwentyRebases */
2275
2280
  };
2276
2281
  var ALWAYS_ASK_NEVER = [
2277
2282
  "always" /* Always */,
@@ -2292,6 +2297,12 @@ var WATCHER_LIFETIMES = [
2292
2297
  "7d" /* SevenDays */,
2293
2298
  "never" /* Never */
2294
2299
  ];
2300
+ var CATCH_UP_REBASE_BUDGETS = [
2301
+ "10" /* TenRebases */,
2302
+ "20" /* TwentyRebases */,
2303
+ "50" /* FiftyRebases */,
2304
+ "never" /* Never */
2305
+ ];
2295
2306
  var PREFERENCE_ALLOWED_VALUES = {
2296
2307
  ["autoLogin" /* AutoLogin */]: ALWAYS_ASK_NEVER,
2297
2308
  ["autoSelectProject" /* AutoSelectProject */]: ALWAYS_ASK_NEVER,
@@ -2315,7 +2326,8 @@ var PREFERENCE_ALLOWED_VALUES = {
2315
2326
  ["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: ALWAYS_ASK_NEVER,
2316
2327
  ["autoWatchPR" /* AutoWatchPR */]: ALWAYS_ASK_NEVER,
2317
2328
  ["reusePreparePlan" /* ReusePreparePlan */]: ALWAYS_ASK_NEVER,
2318
- ["watcherLifetime" /* WatcherLifetime */]: WATCHER_LIFETIMES
2329
+ ["watcherLifetime" /* WatcherLifetime */]: WATCHER_LIFETIMES,
2330
+ ["maxCatchUpRebases" /* MaxCatchUpRebases */]: CATCH_UP_REBASE_BUDGETS
2319
2331
  };
2320
2332
  var PREFERENCES_SCHEMA = {
2321
2333
  ["autoLogin" /* AutoLogin */]: {
@@ -2386,6 +2398,9 @@ var PREFERENCES_SCHEMA = {
2386
2398
  },
2387
2399
  ["watcherLifetime" /* WatcherLifetime */]: {
2388
2400
  description: "How long a muggle-pr-followup watch loop polls before retiring itself \u2014 1d, 7d, or never (unbounded, which leaves no time-based reaper for an orphaned loop)"
2401
+ },
2402
+ ["maxCatchUpRebases" /* MaxCatchUpRebases */]: {
2403
+ description: "How many catch-up rebases muggle-pr-followup runs on one PR before it stops and reports the branch back to its owner \u2014 10, 20, 50, or never (unbounded, which lets an active base rebase a PR for as long as it stays open)"
2389
2404
  }
2390
2405
  };
2391
2406
 
@@ -3892,23 +3907,10 @@ __export(e2e_exports, {
3892
3907
  executeQaTool: () => executeQaTool,
3893
3908
  getQaToolByName: () => getQaToolByName
3894
3909
  });
3895
-
3896
- var ENV_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
3897
- var ENV_VITE_CONNECTION_STRING = "VITE_APPLICATIONINSIGHTS_CONNECTION_STRING";
3898
- var ENV_TELEMETRY_DISABLED = "MUGGLE_TELEMETRY_DISABLED";
3899
-
3900
- var DATA_DIR_NAME2 = ".muggle-ai";
3901
3910
  var INSTALL_ID_FILENAME = "install-id.json";
3902
- var PREFS_FILENAME = "preferences.json";
3903
- var OAUTH_SESSION_FILENAME = "oauth-session.json";
3904
- var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
3905
- function getDataDir3() {
3906
- return path11.join(os4.homedir(), DATA_DIR_NAME2);
3907
- }
3908
-
3909
3911
  var cachedInstallId;
3910
3912
  function installIdFilePath() {
3911
- return join(getDataDir3(), INSTALL_ID_FILENAME);
3913
+ return join(getDataDir(), INSTALL_ID_FILENAME);
3912
3914
  }
3913
3915
  function generateAndPersist(filePath) {
3914
3916
  const installId = randomUUID();
@@ -3921,8 +3923,7 @@ function isValid(value) {
3921
3923
  return typeof value === "object" && value !== null && typeof value.installId === "string" && value.installId.length > 0;
3922
3924
  }
3923
3925
  function getInstallId() {
3924
- if (cachedInstallId !== void 0)
3925
- return cachedInstallId;
3926
+ if (cachedInstallId !== void 0) return cachedInstallId;
3926
3927
  const filePath = installIdFilePath();
3927
3928
  if (!existsSync(filePath)) {
3928
3929
  cachedInstallId = generateAndPersist(filePath);
@@ -3943,6 +3944,113 @@ function getInstallId() {
3943
3944
  }
3944
3945
  }
3945
3946
 
3947
+ // packages/mcps/src/shared/register.ts
3948
+ var CONFLICT_STATUS = 409;
3949
+ var THROTTLED_STATUS = 429;
3950
+ async function registerAccount(email, userProvidedPassword) {
3951
+ const logger6 = getLogger();
3952
+ const config = getConfig();
3953
+ const registerUrl = `${config.e2e.promptServiceBaseUrl}/v1/public/auth/register`;
3954
+ try {
3955
+ const response = await axios.post(
3956
+ registerUrl,
3957
+ {
3958
+ email,
3959
+ password: userProvidedPassword,
3960
+ installId: getInstallId()
3961
+ },
3962
+ { headers: { "Content-Type": "application/json" } }
3963
+ );
3964
+ const created = response.data;
3965
+ saveApiKey({ apiKey: created.apiKey, apiKeyId: created.userId });
3966
+ logger6.info("[Register] Account created and credential stored", {
3967
+ userId: created.userId,
3968
+ plan: created.plan
3969
+ });
3970
+ return {
3971
+ outcome: "created" /* Created */,
3972
+ userId: created.userId,
3973
+ email: created.email,
3974
+ plan: created.plan,
3975
+ emailVerified: created.emailVerified,
3976
+ tokensGranted: created.tokensGranted,
3977
+ tokensOnVerification: created.tokensOnVerification,
3978
+ credentialStored: true,
3979
+ message: `Account created on the ${created.plan} plan and the API key stored \u2014 remote tools will use it automatically. ${created.tokensGranted.toLocaleString()} tokens are available now. Verifying ${created.email} upgrades the account to the Starter package \u2014 free and permanent \u2014 and raises that to ${created.tokensOnVerification.toLocaleString()}.`
3980
+ };
3981
+ } catch (error) {
3982
+ const status = axios.isAxiosError(error) ? error.response?.status : void 0;
3983
+ if (status === CONFLICT_STATUS) {
3984
+ return {
3985
+ outcome: "already-registered" /* AlreadyRegistered */,
3986
+ message: "An account already exists for this email. Use muggle-remote-auth-login to sign in instead."
3987
+ };
3988
+ }
3989
+ if (status === THROTTLED_STATUS) {
3990
+ const retryAfterSeconds = axios.isAxiosError(error) ? error.response?.data?.retryAfterSeconds : void 0;
3991
+ return {
3992
+ outcome: "throttled" /* Throttled */,
3993
+ retryAfterSeconds,
3994
+ message: retryAfterSeconds ? `Too many registrations from this machine. Try again in ${retryAfterSeconds} seconds.` : "Too many registrations from this machine. Try again later."
3995
+ };
3996
+ }
3997
+ logger6.error("[Register] Registration failed", {
3998
+ error: error instanceof Error ? error.message : String(error)
3999
+ });
4000
+ throw error;
4001
+ }
4002
+ }
4003
+
4004
+ var ENV_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
4005
+ var ENV_VITE_CONNECTION_STRING = "VITE_APPLICATIONINSIGHTS_CONNECTION_STRING";
4006
+ var ENV_TELEMETRY_DISABLED = "MUGGLE_TELEMETRY_DISABLED";
4007
+
4008
+ var DATA_DIR_NAME2 = ".muggle-ai";
4009
+ var INSTALL_ID_FILENAME2 = "install-id.json";
4010
+ var PREFS_FILENAME = "preferences.json";
4011
+ var OAUTH_SESSION_FILENAME = "oauth-session.json";
4012
+ var RELEASE_MANIFEST_FILENAME = "release-manifest.json";
4013
+ function getDataDir3() {
4014
+ return path11.join(os4.homedir(), DATA_DIR_NAME2);
4015
+ }
4016
+
4017
+ var cachedInstallId2;
4018
+ function installIdFilePath2() {
4019
+ return join(getDataDir3(), INSTALL_ID_FILENAME2);
4020
+ }
4021
+ function generateAndPersist2(filePath) {
4022
+ const installId = randomUUID();
4023
+ const contents = { installId };
4024
+ mkdirSync(dirname(filePath), { recursive: true });
4025
+ writeFileSync(filePath, JSON.stringify(contents, null, 2) + "\n", "utf8");
4026
+ return installId;
4027
+ }
4028
+ function isValid2(value) {
4029
+ return typeof value === "object" && value !== null && typeof value.installId === "string" && value.installId.length > 0;
4030
+ }
4031
+ function getInstallId2() {
4032
+ if (cachedInstallId2 !== void 0)
4033
+ return cachedInstallId2;
4034
+ const filePath = installIdFilePath2();
4035
+ if (!existsSync(filePath)) {
4036
+ cachedInstallId2 = generateAndPersist2(filePath);
4037
+ return cachedInstallId2;
4038
+ }
4039
+ try {
4040
+ const raw = readFileSync(filePath, "utf8");
4041
+ const parsed = JSON.parse(raw);
4042
+ if (isValid2(parsed)) {
4043
+ cachedInstallId2 = parsed.installId;
4044
+ return cachedInstallId2;
4045
+ }
4046
+ cachedInstallId2 = generateAndPersist2(filePath);
4047
+ return cachedInstallId2;
4048
+ } catch {
4049
+ cachedInstallId2 = generateAndPersist2(filePath);
4050
+ return cachedInstallId2;
4051
+ }
4052
+ }
4053
+
3946
4054
  var DEV_MANIFEST2 = {
3947
4055
  release: "dev",
3948
4056
  buildId: "dev",
@@ -3959,7 +4067,7 @@ var MANIFEST_PATH2 = (() => {
3959
4067
  }
3960
4068
  })();
3961
4069
  var cachedManifest2;
3962
- function isValid2(value) {
4070
+ function isValid3(value) {
3963
4071
  if (typeof value !== "object" || value === null)
3964
4072
  return false;
3965
4073
  const m = value;
@@ -3972,7 +4080,7 @@ function readReleaseManifest2() {
3972
4080
  try {
3973
4081
  const raw = readFileSync(path17, "utf8");
3974
4082
  const parsed = JSON.parse(raw);
3975
- cachedManifest2 = isValid2(parsed) ? parsed : DEV_MANIFEST2;
4083
+ cachedManifest2 = isValid3(parsed) ? parsed : DEV_MANIFEST2;
3976
4084
  return cachedManifest2;
3977
4085
  } catch (err) {
3978
4086
  const code = err.code;
@@ -4017,7 +4125,7 @@ function buildCommonProperties(serviceName, surface) {
4017
4125
  buildId: manifest.buildId,
4018
4126
  commitSha: manifest.commitSha,
4019
4127
  buildTime: manifest.buildTime,
4020
- installId: getInstallId(),
4128
+ installId: getInstallId2(),
4021
4129
  nodeVersion: process.version,
4022
4130
  platform: process.platform
4023
4131
  };
@@ -4658,6 +4766,10 @@ var AuthLoginInputSchema = z.object({
4658
4766
  timeoutMs: z.number().int().positive().min(1e3).max(9e5).optional().describe("Maximum time to wait for login completion in milliseconds. Default: 120000"),
4659
4767
  forceNewSession: z.boolean().optional().describe("Force a fresh login by clearing any existing Auth0 browser session before redirecting to the device activation page. Use this to switch accounts. Default: false")
4660
4768
  });
4769
+ var AuthRegisterInputSchema = z.object({
4770
+ email: z.string().email().describe("Email address to register the new Muggle AI account under"),
4771
+ password: z.string().min(8).describe("Password for the new account, at least 8 characters. Sent once and not stored locally.")
4772
+ });
4661
4773
  var AuthPollInputSchema = z.object({
4662
4774
  deviceCode: z.string().optional().describe("Device code from the login response. Optional if a login was recently started.")
4663
4775
  });
@@ -4705,42 +4817,6 @@ function detectMcpHost(env = process.env) {
4705
4817
  }
4706
4818
  return "unknown";
4707
4819
  }
4708
- var INSTALL_ID_FILENAME2 = "install-id.json";
4709
- var cachedInstallId2;
4710
- function installIdFilePath2() {
4711
- return join(getDataDir(), INSTALL_ID_FILENAME2);
4712
- }
4713
- function generateAndPersist2(filePath) {
4714
- const installId = randomUUID();
4715
- const contents = { installId };
4716
- mkdirSync(dirname(filePath), { recursive: true });
4717
- writeFileSync(filePath, JSON.stringify(contents, null, 2) + "\n", "utf8");
4718
- return installId;
4719
- }
4720
- function isValid3(value) {
4721
- return typeof value === "object" && value !== null && typeof value.installId === "string" && value.installId.length > 0;
4722
- }
4723
- function getInstallId2() {
4724
- if (cachedInstallId2 !== void 0) return cachedInstallId2;
4725
- const filePath = installIdFilePath2();
4726
- if (!existsSync(filePath)) {
4727
- cachedInstallId2 = generateAndPersist2(filePath);
4728
- return cachedInstallId2;
4729
- }
4730
- try {
4731
- const raw = readFileSync(filePath, "utf8");
4732
- const parsed = JSON.parse(raw);
4733
- if (isValid3(parsed)) {
4734
- cachedInstallId2 = parsed.installId;
4735
- return cachedInstallId2;
4736
- }
4737
- cachedInstallId2 = generateAndPersist2(filePath);
4738
- return cachedInstallId2;
4739
- } catch {
4740
- cachedInstallId2 = generateAndPersist2(filePath);
4741
- return cachedInstallId2;
4742
- }
4743
- }
4744
4820
 
4745
4821
  // packages/mcps/src/mcp/e2e/upstream-client.ts
4746
4822
  var MUTATING_METHODS = ["POST", "PUT", "PATCH", "DELETE"];
@@ -4791,7 +4867,7 @@ var PromptServiceClient = class {
4791
4867
  */
4792
4868
  buildHeaders(credentials, correlationId) {
4793
4869
  const manifest = readReleaseManifest();
4794
- const installId = getInstallId2();
4870
+ const installId = getInstallId();
4795
4871
  const host = detectMcpHost();
4796
4872
  const headers = {
4797
4873
  "X-Correlation-Id": correlationId,
@@ -6511,6 +6587,19 @@ var userFeedbackTools = [
6511
6587
  }
6512
6588
  ];
6513
6589
  var authTools = [
6590
+ {
6591
+ name: "muggle-remote-auth-register",
6592
+ description: "Create a new Muggle AI account from an email and password and start using E2E features on the free plan immediately \u2014 no browser, no human step. Verifying the address on that account upgrades it to the Starter package for free and permanently, raising the monthly token allowance tenfold; the account keeps working unverified, with less. Use this when there is no account yet; use muggle-remote-auth-login when one already exists. The API key it returns is stored automatically, so remote tools work straight afterwards.",
6593
+ inputSchema: AuthRegisterInputSchema,
6594
+ requiresAuth: false,
6595
+ mapToUpstream: () => {
6596
+ throw new Error("LOCAL_HANDLER_ONLY");
6597
+ },
6598
+ localHandler: async (input) => {
6599
+ const authRegisterInput = input;
6600
+ return registerAccount(authRegisterInput.email, authRegisterInput.password);
6601
+ }
6602
+ },
6514
6603
  {
6515
6604
  name: "muggle-remote-auth-status",
6516
6605
  description: "Check current authentication status. Shows if you're logged in and when your session expires.",
@@ -7796,6 +7885,7 @@ __export(e2e_exports2, {
7796
7885
  ApiKeyRevokeInputSchema: () => ApiKeyRevokeInputSchema,
7797
7886
  AuthLoginInputSchema: () => AuthLoginInputSchema,
7798
7887
  AuthPollInputSchema: () => AuthPollInputSchema,
7888
+ AuthRegisterInputSchema: () => AuthRegisterInputSchema,
7799
7889
  BulkPreviewJobCancelInputSchema: () => BulkPreviewJobCancelInputSchema,
7800
7890
  BulkPreviewJobGetInputSchema: () => BulkPreviewJobGetInputSchema,
7801
7891
  BulkPreviewJobKindSchema: () => BulkPreviewJobKindSchema,
@@ -8121,6 +8211,17 @@ var ONBOARDING_CHOICE_GROUPS = [
8121
8211
  { value: "7d" /* SevenDays */, label: "Retire after 7 days" },
8122
8212
  { value: "never" /* Never */, label: "Never retire \u2014 no time-based reaper for an orphaned loop" }
8123
8213
  ]
8214
+ },
8215
+ {
8216
+ header: "Rebase budget",
8217
+ key: "maxCatchUpRebases" /* MaxCatchUpRebases */,
8218
+ prompt: "How many times should a PR be rebased onto a moving base before you are asked to step in?",
8219
+ optionLabels: [
8220
+ { value: "10" /* TenRebases */, label: "Stop after 10" },
8221
+ { value: "20" /* TwentyRebases */, label: "Stop after 20" },
8222
+ { value: "50" /* FiftyRebases */, label: "Stop after 50" },
8223
+ { value: "never" /* Never */, label: "Never stop \u2014 an active base can rebase a PR for as long as it stays open" }
8224
+ ]
8124
8225
  }
8125
8226
  ];
8126
8227
  var ONBOARDING_BLANKET_OPTIONS = [
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from './chunk-JNYP5PWT.js';
3
- import './chunk-ESPHO3WB.js';
2
+ import { runCli } from './chunk-ODEPI25T.js';
3
+ import './chunk-U6ZACW6K.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-JNYP5PWT.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-ESPHO3WB.js';
1
+ export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-ODEPI25T.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-U6ZACW6K.js';
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "muggle",
3
3
  "description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
4
- "version": "5.19.0-staging.129",
4
+ "version": "5.19.0-staging.131",
5
5
  "author": {
6
6
  "name": "Muggle AI",
7
7
  "email": "support@muggle-ai.com"
@@ -2,7 +2,7 @@
2
2
  "name": "muggle",
3
3
  "displayName": "Muggle AI",
4
4
  "description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
5
- "version": "5.19.0-staging.129",
5
+ "version": "5.19.0-staging.131",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -1,25 +1,26 @@
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
- }
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
+ "maxCatchUpRebases": "20"
26
+ }
@@ -1,59 +1,68 @@
1
- # Rebase (watcher-dispatched)
2
-
3
- Rebase a PR's branch onto its base — whether it's merely **behind** (out of date, no conflict) or actually **conflicting** — behind a verify-or-rollback gate, then force-push, so a PR doesn't sit stale or un-mergeable forever. A dumb-pipe dispatch like fix-ci: the watcher detects the branch is behind or conflicting and hands off; the executor owns the rebase (and any conflict resolution), never the decision to dispatch.
4
-
5
- ## Turn preamble
6
-
7
- ```
8
- **/muggle-do rebase** — rebasing <owner>/<repo>#<n> onto <base> to bring the branch up to date.
9
- ```
10
-
11
- ## Input
12
-
13
- `$ARGUMENTS` carries a `github.com/.../pull/<n>` URL, `slug=<slug>`, and a `rebase` directive (no review ids, no failing check names). Parse all three.
14
-
15
- ## Inputs from disk
16
-
17
- From `~/.muggle-ai/muggle-do/sessions/<slug>/`: `prs.json` (PR + branch + `head_sha`), `last_seen.json` (`conflict_resolve_attempts`, `conflict_escalated_keys`, `pushed_shas`), `state.md` (worktree path, validation strategy, base branch).
18
-
19
- ## Procedure
20
-
21
- ### Step 1 — Re-attach
22
-
23
- Materialize the PR branch in its worktree per [`../_shared/pr-branch-worktree.md`](../_shared/pr-branch-worktree.md) (or use `state.md`'s `worktreePath`). Capture `rebase_sha = prs.json[0].head_sha` and the base branch (`baseRefName` from [`../_shared/vcs/github/pr-metadata.md`](../_shared/vcs/github/pr-metadata.md)). Capture the base tip too — `.base_commit.sha` from that recipe's `compare` call — and form `rebase_key = "<rebase_sha>..<base_tip_sha>"`. Both budget fields below are keyed on that pair, matching the watcher's Step 5; writing a bare SHA instead leaves an entry the watcher ignores, and the rebase re-dispatches forever.
24
-
25
- ### Step 2 — Rebase onto base (resolve conflicts if any)
26
-
27
- Run the rebase from [`../_shared/sync-branch-with-base.md`](../_shared/sync-branch-with-base.md) against the base branch, taking its `always` path unconditionally — this programmatic mode never asks, so skip the `autoRebase` prompt (the watcher already decided a rebase is due).
28
-
29
- - **Clean replay** — a behind-only branch (and any rebase that hits no conflicts) replays without intervention. Proceed to Step 3.
30
- - **Conflicts** — handle per [`autoResolveConflicts`](../muggle-preferences/preference-gates/autoResolveConflicts.md):
31
- - `never` → abort and escalate per Step 5 (`kind: "rebase-conflict"`). The watcher keeps polling; the user resolves on GitHub.
32
- - `always` → resolve via [`../_shared/resolve-rebase-conflicts.md`](../_shared/resolve-rebase-conflicts.md); Steps 3 and 5 below are this mode's instance of the [`../_shared/verify-or-rollback-gate.md`](../_shared/verify-or-rollback-gate.md).
33
-
34
- ### Step 3 — Verify the resolution
35
-
36
- Build (typecheck + lint on the changed surface) + unit suite must pass. Run E2E per [`e2e-acceptance.md`](e2e-acceptance.md) when app logic changed and the session carries validation context. A rebase that does not verify is rolled back → escalate per Step 5. **Never push an unverified rebase.**
37
-
38
- ### Step 4 — Force-push + respawn
39
-
40
- Force-push per [`../_shared/vcs/common/push-to-branch.md`](../_shared/vcs/common/push-to-branch.md) (tool-agnostic instruction; handles the signing gate for rebased commits and directs to provider-specific force-push paths). Use `git push --force-with-lease` for the force operation. Append the new SHA to `last_seen.pushed_shas`; increment `last_seen.conflict_resolve_attempts[rebase_key]` — both whole-file rewrites (Read → change field → Write) per [`../_shared/session-state-writes.md`](../_shared/session-state-writes.md), never the Edit tool. Respawn the watcher per [`respawn-watcher.md`](respawn-watcher.md). Its next tick re-checks the branch against its base on the new head — the rebase is its own verify loop, bounded by the per-SHA attempt budget.
41
-
42
- ### Step 5 — Escalate (can't resolve / budget spent)
43
-
44
- When `autoResolveConflicts=never`, the resolution failed verification, or `conflict_resolve_attempts[rebase_key]` has reached 2:
45
-
46
- 1. Add `rebase_key` to `last_seen.conflict_escalated_keys` so the watcher does not re-dispatch this head against this base. If the base later moves, the key changes and the branch re-arms on its own — a conflict the user resolved upstream stops being this watcher's dead end.
47
- 2. Emit one terminal escalation naming the PR and the conflicting files (or the failing verification, for a behind-only rebase that didn't verify).
48
- 3. Respawn the watcher per [`respawn-watcher.md`](respawn-watcher.md) — it keeps polling for the user's manual resolution or any new reviews.
49
-
50
- ### Step 6 — Telemetry
51
-
52
- Emit one `muggle-do:cycle` event ([`../_shared/telemetry-events/muggle-do-cycle.md`](../_shared/telemetry-events/muggle-do-cycle.md)) with `outcome: "rebased"` (a verified rebase pushed — behind-only or conflicts resolved) or `"rebase-escalated"`.
53
-
54
- ## Guardrails
55
-
56
- - Max 2 rebase attempts per SHA; then escalate rather than churn.
57
- - Never push an unverified rebase — verify-or-rollback always.
58
- - Never push unsigned commits — every push or force-push goes through the signing gate in [`../_shared/vcs/common/push-to-branch.md`](../_shared/vcs/common/push-to-branch.md).
59
- - Resolve `autoResolveConflicts` from the configured preference (per the gate contract — don't assume a default): `always` resolves conflicts behind the verify-or-rollback gate, `never` escalates to the user. A clean behind-only rebase needs neither.
1
+ # Rebase (watcher-dispatched)
2
+
3
+ Rebase a PR's branch onto its base — whether it's merely **behind** (out of date, no conflict) or actually **conflicting** — behind a verify-or-rollback gate, then force-push, so a PR doesn't sit stale or un-mergeable forever. A dumb-pipe dispatch like fix-ci: the watcher detects the branch is behind or conflicting and hands off; the executor owns the rebase (and any conflict resolution), never the decision to dispatch.
4
+
5
+ ## Turn preamble
6
+
7
+ ```
8
+ **/muggle-do rebase** — rebasing <owner>/<repo>#<n> onto <base> to bring the branch up to date.
9
+ ```
10
+
11
+ ## Input
12
+
13
+ `$ARGUMENTS` carries a `github.com/.../pull/<n>` URL, `slug=<slug>`, and a `rebase` directive (no review ids, no failing check names). Parse all three.
14
+
15
+ ## Inputs from disk
16
+
17
+ From `~/.muggle-ai/muggle-do/sessions/<slug>/`: `prs.json` (PR + branch + `head_sha`), `last_seen.json` (`conflict_resolve_attempts`, `conflict_escalated_keys`, `catch_up_rebases`, `pushed_shas`), `state.md` (worktree path, validation strategy, base branch).
18
+
19
+ ## Procedure
20
+
21
+ ### Step 1 — Re-attach
22
+
23
+ Materialize the PR branch in its worktree per [`../_shared/pr-branch-worktree.md`](../_shared/pr-branch-worktree.md) (or use `state.md`'s `worktreePath`). Capture `rebase_sha = prs.json[0].head_sha` and the base branch (`baseRefName` from [`../_shared/vcs/github/pr-metadata.md`](../_shared/vcs/github/pr-metadata.md)). Capture the base tip too — `.base_commit.sha` from that recipe's `compare` call — and form `rebase_key = "<rebase_sha>..<base_tip_sha>"`. Both budget fields below are keyed on that pair, matching the watcher's Step 5; writing a bare SHA instead leaves an entry the watcher ignores, and the rebase re-dispatches forever.
24
+
25
+ ### Step 2 — Rebase onto base (resolve conflicts if any)
26
+
27
+ Run the rebase from [`../_shared/sync-branch-with-base.md`](../_shared/sync-branch-with-base.md) against the base branch, taking its `always` path unconditionally — this programmatic mode never asks, so skip the `autoRebase` prompt (the watcher already decided a rebase is due).
28
+
29
+ - **Clean replay** — a behind-only branch (and any rebase that hits no conflicts) replays without intervention. Proceed to Step 3.
30
+ - **Conflicts** — handle per [`autoResolveConflicts`](../muggle-preferences/preference-gates/autoResolveConflicts.md):
31
+ - `never` → abort and escalate per Step 5 (`kind: "rebase-conflict"`). The watcher keeps polling; the user resolves on GitHub.
32
+ - `always` → resolve via [`../_shared/resolve-rebase-conflicts.md`](../_shared/resolve-rebase-conflicts.md); Steps 3 and 5 below are this mode's instance of the [`../_shared/verify-or-rollback-gate.md`](../_shared/verify-or-rollback-gate.md).
33
+
34
+ ### Step 3 — Verify the resolution
35
+
36
+ Build (typecheck + lint on the changed surface) + unit suite must pass. Run E2E per [`e2e-acceptance.md`](e2e-acceptance.md) when app logic changed and the session carries validation context. A rebase that does not verify is rolled back → escalate per Step 5. **Never push an unverified rebase.**
37
+
38
+ ### Step 4 — Force-push + respawn
39
+
40
+ Force-push per [`../_shared/vcs/common/push-to-branch.md`](../_shared/vcs/common/push-to-branch.md) (tool-agnostic instruction; handles the signing gate for rebased commits and directs to provider-specific force-push paths). Use `git push --force-with-lease` for the force operation. Append the new SHA to `last_seen.pushed_shas`; increment `last_seen.conflict_resolve_attempts[rebase_key]` **and** `last_seen.catch_up_rebases` — all whole-file rewrites (Read → change field → Write) per [`../_shared/session-state-writes.md`](../_shared/session-state-writes.md), never the Edit tool. The second counter is unkeyed on purpose: `rebase_key` carries the base tip, so it mints a fresh budget every time the base moves and cannot bound a PR on an active base. Increment it on every push here, including one that later escalates, or a branch that fails the same way twenty times reads as having spent nothing. Respawn the watcher per [`respawn-watcher.md`](respawn-watcher.md). Its next tick re-checks the branch against its base on the new head — the rebase is its own verify loop, bounded by the per-SHA attempt budget.
41
+
42
+ ### Step 5 — Escalate (can't resolve / budget spent)
43
+
44
+ When `autoResolveConflicts=never`, the resolution failed verification, or `conflict_resolve_attempts[rebase_key]` has reached 2:
45
+
46
+ 1. Add `rebase_key` to `last_seen.conflict_escalated_keys` so the watcher does not re-dispatch this head against this base. If the base later moves, the key changes and the branch re-arms on its own — a conflict the user resolved upstream stops being this watcher's dead end.
47
+ 2. Emit one terminal escalation naming the PR and the conflicting files (or the failing verification, for a behind-only rebase that didn't verify).
48
+ 3. Respawn the watcher per [`respawn-watcher.md`](respawn-watcher.md) — it keeps polling for the user's manual resolution or any new reviews.
49
+
50
+ ### Step 5a — Escalate (per-PR catch-up budget spent)
51
+
52
+ When `catch_up_rebases` has reached [`maxCatchUpRebases`](../muggle-preferences/preference-gates/maxCatchUpRebases.md) (20 unless the user changed it), the PR is out of catch-up budget for good — a different escalation from Step 5, which retires one `rebase_key` and re-arms the moment the base moves.
53
+
54
+ 1. Set `last_seen.rebase_budget_exhausted` to `true`. The watcher stops dispatching rebases for this PR outright, so no base advance re-arms it.
55
+ 2. Emit one terminal escalation, and post it on the PR, naming the count, the cap, and `maxCatchUpRebases` as the way to raise it. Say what the owner has to decide — rebase onto a different base, split the branch, or close it — because the harness has stopped trying and silence here reads as a healthy watcher.
56
+ 3. Respawn the watcher per [`respawn-watcher.md`](respawn-watcher.md); it keeps polling reviews and CI, and blocks with reason `rebase_budget_exhausted`.
57
+
58
+ ### Step 6 — Telemetry
59
+
60
+ Emit one `muggle-do:cycle` event ([`../_shared/telemetry-events/muggle-do-cycle.md`](../_shared/telemetry-events/muggle-do-cycle.md)) with `outcome: "rebased"` (a verified rebase pushed — behind-only or conflicts resolved), `"rebase-escalated"`, or `"rebase-budget-exhausted"` (Step 5a).
61
+
62
+ ## Guardrails
63
+
64
+ - Max 2 rebase attempts per `rebase_key`, and `maxCatchUpRebases` (20 by default) across the PR's whole life; then escalate rather than churn. The per-key cap alone bounds nothing on an active base, since a base advance mints a new key.
65
+ - Never let an exhausted budget pass as silence — Step 5a reports on the PR. A watcher that stops without saying so is indistinguishable from one that has nothing to do.
66
+ - Never push an unverified rebase — verify-or-rollback always.
67
+ - Never push unsigned commits — every push or force-push goes through the signing gate in [`../_shared/vcs/common/push-to-branch.md`](../_shared/vcs/common/push-to-branch.md).
68
+ - Resolve `autoResolveConflicts` from the configured preference (per the gate contract — don't assume a default): `always` resolves conflicts behind the verify-or-rollback gate, `never` escalates to the user. A clean behind-only rebase needs neither.