@muggleai/works 4.11.0 → 4.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-Q7WNEMN4.js → chunk-7WRAMBOS.js} +17 -3
- package/dist/{chunk-ZKRHFTIC.js → chunk-AYWLYB3F.js} +32 -4
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/skills/_shared/pr-followup-helpers.md +5 -4
- package/dist/plugin/skills/muggle-pr-followup/contract.md +6 -7
- package/dist/release-manifest.json +4 -4
- package/dist/{src-2G7ENRGI.js → src-NJUUHKPW.js} +1 -1
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/skills/_shared/pr-followup-helpers.md +5 -4
- package/plugin/skills/muggle-pr-followup/contract.md +6 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-
|
|
1
|
+
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-AYWLYB3F.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';
|
|
@@ -731,7 +731,7 @@ async function resolveGsScreenshotUrls(report, opts) {
|
|
|
731
731
|
if (gsUrls.length === 0) {
|
|
732
732
|
return report;
|
|
733
733
|
}
|
|
734
|
-
const mcps = await import('./src-
|
|
734
|
+
const mcps = await import('./src-NJUUHKPW.js');
|
|
735
735
|
const credentials = await mcps.getCallerCredentialsAsync();
|
|
736
736
|
if (!credentials.bearerToken && !credentials.apiKey) {
|
|
737
737
|
stderrWrite(
|
|
@@ -1638,6 +1638,15 @@ async function statusCommand() {
|
|
|
1638
1638
|
}
|
|
1639
1639
|
|
|
1640
1640
|
// src/cli/serve.ts
|
|
1641
|
+
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";
|
|
1642
|
+
function showDisclosureIfNeeded() {
|
|
1643
|
+
try {
|
|
1644
|
+
if (hasShownDisclosure()) return;
|
|
1645
|
+
process.stderr.write(getDisclosureCopy() + "\n");
|
|
1646
|
+
markDisclosureShown();
|
|
1647
|
+
} catch {
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1641
1650
|
var logger5 = getLogger();
|
|
1642
1651
|
async function serveCommand(options) {
|
|
1643
1652
|
const config = getConfig();
|
|
@@ -1650,7 +1659,12 @@ async function serveCommand(options) {
|
|
|
1650
1659
|
transport: "stdio"
|
|
1651
1660
|
});
|
|
1652
1661
|
try {
|
|
1653
|
-
|
|
1662
|
+
showDisclosureIfNeeded();
|
|
1663
|
+
initTelemetry({
|
|
1664
|
+
serviceName: ServiceName.MuggleMcp,
|
|
1665
|
+
surface: Surface.McpLocal,
|
|
1666
|
+
connectionString: APPLICATIONINSIGHTS_CONNECTION_STRING
|
|
1667
|
+
});
|
|
1654
1668
|
track({ name: EventName.SystemStartup, props: { serviceName: ServiceName.MuggleMcp } });
|
|
1655
1669
|
} catch (err) {
|
|
1656
1670
|
logger5.warn("Telemetry init skipped", {
|
|
@@ -94,7 +94,7 @@ __export(src_exports, {
|
|
|
94
94
|
toolRequiresAuth: () => toolRequiresAuth,
|
|
95
95
|
validatePreference: () => validatePreference,
|
|
96
96
|
verifyFileChecksum: () => verifyFileChecksum,
|
|
97
|
-
writePreferences: () =>
|
|
97
|
+
writePreferences: () => writePreferences2
|
|
98
98
|
});
|
|
99
99
|
var DATA_DIR_NAME = ".muggle-ai";
|
|
100
100
|
function getDataDir() {
|
|
@@ -3198,6 +3198,19 @@ function readPreferences() {
|
|
|
3198
3198
|
return {};
|
|
3199
3199
|
}
|
|
3200
3200
|
}
|
|
3201
|
+
function writePreferences(prefs) {
|
|
3202
|
+
const filePath = prefsFilePath();
|
|
3203
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
3204
|
+
writeFileSync(filePath, JSON.stringify(prefs, null, 2) + "\n", "utf8");
|
|
3205
|
+
}
|
|
3206
|
+
function updatePreference(key, value) {
|
|
3207
|
+
const prefs = readPreferences();
|
|
3208
|
+
prefs[key] = value;
|
|
3209
|
+
writePreferences(prefs);
|
|
3210
|
+
}
|
|
3211
|
+
function preferencesFileExists() {
|
|
3212
|
+
return existsSync(prefsFilePath());
|
|
3213
|
+
}
|
|
3201
3214
|
|
|
3202
3215
|
function isTelemetryEnabled() {
|
|
3203
3216
|
if (process.env[ENV_TELEMETRY_DISABLED] === "1")
|
|
@@ -3223,6 +3236,21 @@ function track(event) {
|
|
|
3223
3236
|
}
|
|
3224
3237
|
}
|
|
3225
3238
|
|
|
3239
|
+
var DISCLOSURE_COPY = `Muggle Test collects anonymous usage telemetry \u2014 which features you use, how long they take, and whether they succeed \u2014 to help us improve the product. We attach an opaque install ID, your account ID (when signed in), and your IP. We do not collect file contents, OS username, hostname, or file paths. To opt out, set telemetryEnabled to false in ~/.muggle-ai/preferences.json or run \`muggle preferences set telemetryEnabled false\`.`;
|
|
3240
|
+
|
|
3241
|
+
function getDisclosureCopy() {
|
|
3242
|
+
return DISCLOSURE_COPY;
|
|
3243
|
+
}
|
|
3244
|
+
function hasShownDisclosure() {
|
|
3245
|
+
if (!preferencesFileExists())
|
|
3246
|
+
return false;
|
|
3247
|
+
const prefs = readPreferences();
|
|
3248
|
+
return typeof prefs.disclosureShownAt === "string" && prefs.disclosureShownAt.length > 0;
|
|
3249
|
+
}
|
|
3250
|
+
function markDisclosureShown(now = /* @__PURE__ */ new Date()) {
|
|
3251
|
+
updatePreference("disclosureShownAt", now.toISOString());
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3226
3254
|
var Trigger;
|
|
3227
3255
|
(function(Trigger2) {
|
|
3228
3256
|
Trigger2["UserSlash"] = "user-slash";
|
|
@@ -6018,7 +6046,7 @@ function resolvePreferences(dataDirOverride2, cwd) {
|
|
|
6018
6046
|
const project = readProjectPreferences(cwd);
|
|
6019
6047
|
return { ...global, ...project };
|
|
6020
6048
|
}
|
|
6021
|
-
function
|
|
6049
|
+
function writePreferences2(prefs, scope, dataDirOverride2, cwd) {
|
|
6022
6050
|
const dir = scope === "project" && cwd ? path2.join(cwd, PREFERENCES_PROJECT_DIR_NAME) : dataDirOverride2 ?? getDataDir();
|
|
6023
6051
|
fs5.mkdirSync(dir, { recursive: true });
|
|
6024
6052
|
const filePath = path2.join(dir, PREFERENCES_FILE_NAME);
|
|
@@ -6584,7 +6612,7 @@ var preferencesSetTool = {
|
|
|
6584
6612
|
const logger6 = createChildLogger2(ctx.correlationId);
|
|
6585
6613
|
logger6.info("Executing muggle-local-preferences-set");
|
|
6586
6614
|
const input = PreferencesSetInputSchema.parse(ctx.input);
|
|
6587
|
-
|
|
6615
|
+
writePreferences2(
|
|
6588
6616
|
{ [input.key]: input.value },
|
|
6589
6617
|
input.scope,
|
|
6590
6618
|
void 0,
|
|
@@ -7056,4 +7084,4 @@ var plugins_exports = {};
|
|
|
7056
7084
|
// packages/mcps/src/mcp/agents/index.ts
|
|
7057
7085
|
var agents_exports = {};
|
|
7058
7086
|
|
|
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 };
|
|
7087
|
+
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, getDisclosureCopy, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, hasShownDisclosure, initTelemetry, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports2 as local_exports, markDisclosureShown, mcp_exports, openBrowserUrl, performLogin, performLogout, pollDeviceCode, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, src_exports, startDeviceCodeFlow, toolRequiresAuth, track, validatePreference, verifyFileChecksum, writePreferences2 as writePreferences };
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-
|
|
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-
|
|
1
|
+
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-7WRAMBOS.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-AYWLYB3F.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": "4.11.
|
|
4
|
+
"version": "4.11.1",
|
|
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": "4.11.
|
|
5
|
+
"version": "4.11.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -101,18 +101,19 @@ fix(ci): lint — remove unused import
|
|
|
101
101
|
|
|
102
102
|
## Classify
|
|
103
103
|
|
|
104
|
-
Classify the **review as a unit
|
|
104
|
+
Classify the **review as a unit** — but reply per line comment (threaded), not per review.
|
|
105
105
|
|
|
106
106
|
| Class | Signal | Action |
|
|
107
107
|
| :---- | :----- | :----- |
|
|
108
|
-
| **actionable** | Review names at least one concrete change or asks an answerable question. Soft phrasing counts when there's a concrete referent. | Treat as amended requirements; run
|
|
108
|
+
| **actionable** | Review names at least one concrete change or asks an answerable question. Soft phrasing counts when there's a concrete referent. | Treat as amended requirements; run **one** implementation cycle for the whole review; reply **threaded per line comment** referencing the new SHA (top-level only when the review is body-only). |
|
|
109
109
|
| **ambiguous** | No actionable signal — pure vibes, contradictory, or depends on knowledge the loop can't access. | Escalate once with two interpretations; pause the PR. |
|
|
110
110
|
|
|
111
111
|
Default to **actionable**. CI catches wrong attempts; reviewers correct on the next round. Escalation is a round-trip with an absent user — reserve it.
|
|
112
112
|
|
|
113
|
-
Reply
|
|
113
|
+
Reply shape (all replies for one review reference the same SHA):
|
|
114
114
|
|
|
115
|
-
- **
|
|
115
|
+
- **threaded** (default): `Done in <sha> — <attribution>. (Review #<review_id>, cycle <status>.)`
|
|
116
|
+
- **top-level** (fallback, body-only reviews): `Re: review #<review_id> — addressed in <sha>, cycle <status>.`
|
|
116
117
|
- **ambiguous**: no bot reply.
|
|
117
118
|
|
|
118
119
|
### Worked examples — Actionable reviews
|
|
@@ -86,10 +86,7 @@ When the review is actionable:
|
|
|
86
86
|
2. **Amend `requirements.md`** in the session dir with a new `## Amendment — review <review_id> by <login> (<timestamp>)` section pasting the review body and each comment (with `<file>:<line>` context).
|
|
87
87
|
3. **Invoke the implementation cycle** declared in the caller's `cycle.json`. Iterate the `steps[]` in order. Each step is either a markdown file to follow, a skill to invoke, or a shell command (per the `cycle.json` schema in SKILL.md). When a step fails, the cycle returns `failed: <step-name>`; the loop escalates per Step 8 with the failure as the reason.
|
|
88
88
|
4. **Push** via `cycle.json`'s `pushHandler`. Set `last_seen.last_pushed_sha` to the new HEAD.
|
|
89
|
-
5. **Reply**
|
|
90
|
-
```
|
|
91
|
-
Addressed review <review_id> in <sha> — cycle ran clean (or: with <N> failures, see walkthrough).
|
|
92
|
-
```
|
|
89
|
+
5. **Reply** per [helpers § Reply routing](../_shared/pr-followup-helpers.md#reply-routing) and [§ Classify](../_shared/pr-followup-helpers.md#classify) (reply shape). For each line comment in the review, derive `<attribution>` from `git diff <last_pushed_sha>..HEAD -- <comment.path>` near `comment.line` ±5 (fall back to `addressed indirectly — see walkthrough` if empty). `<status>` = `ran clean` or `had <N> failures, see walkthrough`. If the review is body-only (no line comments), post the top-level fallback shape; if both body and line comments, threaded replies cover it — no top-level.
|
|
93
90
|
6. **Resume polling**: clear `cycling: true`, increment `cycles_completed`, advance `last_seen.reviewId` past this review.
|
|
94
91
|
7. Emit per-cycle telemetry.
|
|
95
92
|
|
|
@@ -133,9 +130,10 @@ Emit one tick event per `muggle-local-telemetry-skill-emit`. Exit the turn.
|
|
|
133
130
|
|
|
134
131
|
## Reply routing
|
|
135
132
|
|
|
136
|
-
- **
|
|
137
|
-
- **
|
|
138
|
-
- **Never post the same
|
|
133
|
+
- **Threaded reply per line comment** (default): `POST /repos/{owner}/{repo}/pulls/{n}/comments/{comment_id}/replies`. Use for every line comment in the review so each thread can be resolved in GitHub's UI.
|
|
134
|
+
- **Top-level summary on a body-only review** (fallback): `gh pr comment <number> --body "..."` referencing the review id and the new SHA. Used only when the review has body content and zero line comments — GitHub has no "reply to a review body" endpoint.
|
|
135
|
+
- **Never post the same reply twice** — `last_seen.reviewId` is the only re-entry guard.
|
|
136
|
+
- **Never post a top-level summary alongside threaded replies** — duplication pollutes the Conversation tab.
|
|
139
137
|
|
|
140
138
|
## Telemetry
|
|
141
139
|
|
|
@@ -187,5 +185,6 @@ This stage produces no console output beyond:
|
|
|
187
185
|
- [ ] `followup.log` has at minimum a heartbeat or per-review line for this tick.
|
|
188
186
|
- [ ] Telemetry events emitted (per-cycle when applicable + per-tick).
|
|
189
187
|
- [ ] If pushed, `last_pushed_sha` is set and `cycles_completed` incremented.
|
|
188
|
+
- [ ] If actionable, one threaded reply posted per line comment (or one top-level reply for body-only reviews) — never both, never zero.
|
|
190
189
|
- [ ] If escalated, `escalated_review_ids` contains the review id.
|
|
191
190
|
- [ ] If terminal, the loop is NOT continued.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release": "4.11.
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-05-
|
|
2
|
+
"release": "4.11.1",
|
|
3
|
+
"buildId": "run-35-1",
|
|
4
|
+
"commitSha": "91afe33fb96f46115bd399141f165832253b4809",
|
|
5
|
+
"buildTime": "2026-05-19T23:10:43Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-
|
|
1
|
+
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-AYWLYB3F.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muggleai/works",
|
|
3
3
|
"mcpName": "io.github.multiplex-ai/muggle",
|
|
4
|
-
"version": "4.11.
|
|
4
|
+
"version": "4.11.2",
|
|
5
5
|
"description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"test:watch": "vitest"
|
|
42
42
|
},
|
|
43
43
|
"muggleConfig": {
|
|
44
|
-
"electronAppVersion": "1.0.
|
|
44
|
+
"electronAppVersion": "1.0.87",
|
|
45
45
|
"downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
|
|
46
46
|
"runtimeTargetDefault": "production",
|
|
47
47
|
"checksums": {
|
|
48
|
-
"darwin-arm64": "
|
|
49
|
-
"darwin-x64": "
|
|
50
|
-
"win32-x64": "
|
|
51
|
-
"linux-x64": "
|
|
48
|
+
"darwin-arm64": "df04c98269e22ae427bb863956215b3f20cbf2ff0b51c037647d6e734a7b7502",
|
|
49
|
+
"darwin-x64": "e9f5b8a61f4a9f47743aaabb27d6e4c462dca5aa922ba66ae04f0a0133b8a7eb",
|
|
50
|
+
"win32-x64": "75e552672757d280259637bdcbe0aae0eecc2417ed9a6e5bd49f42d3466f66cf",
|
|
51
|
+
"linux-x64": "2c8b64cf549f9a6682db959b17c5f04578d632d5bcdba1ac9efbb45d6a097802"
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
@@ -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": "4.11.
|
|
4
|
+
"version": "4.11.1",
|
|
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": "4.11.
|
|
5
|
+
"version": "4.11.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -101,18 +101,19 @@ fix(ci): lint — remove unused import
|
|
|
101
101
|
|
|
102
102
|
## Classify
|
|
103
103
|
|
|
104
|
-
Classify the **review as a unit
|
|
104
|
+
Classify the **review as a unit** — but reply per line comment (threaded), not per review.
|
|
105
105
|
|
|
106
106
|
| Class | Signal | Action |
|
|
107
107
|
| :---- | :----- | :----- |
|
|
108
|
-
| **actionable** | Review names at least one concrete change or asks an answerable question. Soft phrasing counts when there's a concrete referent. | Treat as amended requirements; run
|
|
108
|
+
| **actionable** | Review names at least one concrete change or asks an answerable question. Soft phrasing counts when there's a concrete referent. | Treat as amended requirements; run **one** implementation cycle for the whole review; reply **threaded per line comment** referencing the new SHA (top-level only when the review is body-only). |
|
|
109
109
|
| **ambiguous** | No actionable signal — pure vibes, contradictory, or depends on knowledge the loop can't access. | Escalate once with two interpretations; pause the PR. |
|
|
110
110
|
|
|
111
111
|
Default to **actionable**. CI catches wrong attempts; reviewers correct on the next round. Escalation is a round-trip with an absent user — reserve it.
|
|
112
112
|
|
|
113
|
-
Reply
|
|
113
|
+
Reply shape (all replies for one review reference the same SHA):
|
|
114
114
|
|
|
115
|
-
- **
|
|
115
|
+
- **threaded** (default): `Done in <sha> — <attribution>. (Review #<review_id>, cycle <status>.)`
|
|
116
|
+
- **top-level** (fallback, body-only reviews): `Re: review #<review_id> — addressed in <sha>, cycle <status>.`
|
|
116
117
|
- **ambiguous**: no bot reply.
|
|
117
118
|
|
|
118
119
|
### Worked examples — Actionable reviews
|
|
@@ -86,10 +86,7 @@ When the review is actionable:
|
|
|
86
86
|
2. **Amend `requirements.md`** in the session dir with a new `## Amendment — review <review_id> by <login> (<timestamp>)` section pasting the review body and each comment (with `<file>:<line>` context).
|
|
87
87
|
3. **Invoke the implementation cycle** declared in the caller's `cycle.json`. Iterate the `steps[]` in order. Each step is either a markdown file to follow, a skill to invoke, or a shell command (per the `cycle.json` schema in SKILL.md). When a step fails, the cycle returns `failed: <step-name>`; the loop escalates per Step 8 with the failure as the reason.
|
|
88
88
|
4. **Push** via `cycle.json`'s `pushHandler`. Set `last_seen.last_pushed_sha` to the new HEAD.
|
|
89
|
-
5. **Reply**
|
|
90
|
-
```
|
|
91
|
-
Addressed review <review_id> in <sha> — cycle ran clean (or: with <N> failures, see walkthrough).
|
|
92
|
-
```
|
|
89
|
+
5. **Reply** per [helpers § Reply routing](../_shared/pr-followup-helpers.md#reply-routing) and [§ Classify](../_shared/pr-followup-helpers.md#classify) (reply shape). For each line comment in the review, derive `<attribution>` from `git diff <last_pushed_sha>..HEAD -- <comment.path>` near `comment.line` ±5 (fall back to `addressed indirectly — see walkthrough` if empty). `<status>` = `ran clean` or `had <N> failures, see walkthrough`. If the review is body-only (no line comments), post the top-level fallback shape; if both body and line comments, threaded replies cover it — no top-level.
|
|
93
90
|
6. **Resume polling**: clear `cycling: true`, increment `cycles_completed`, advance `last_seen.reviewId` past this review.
|
|
94
91
|
7. Emit per-cycle telemetry.
|
|
95
92
|
|
|
@@ -133,9 +130,10 @@ Emit one tick event per `muggle-local-telemetry-skill-emit`. Exit the turn.
|
|
|
133
130
|
|
|
134
131
|
## Reply routing
|
|
135
132
|
|
|
136
|
-
- **
|
|
137
|
-
- **
|
|
138
|
-
- **Never post the same
|
|
133
|
+
- **Threaded reply per line comment** (default): `POST /repos/{owner}/{repo}/pulls/{n}/comments/{comment_id}/replies`. Use for every line comment in the review so each thread can be resolved in GitHub's UI.
|
|
134
|
+
- **Top-level summary on a body-only review** (fallback): `gh pr comment <number> --body "..."` referencing the review id and the new SHA. Used only when the review has body content and zero line comments — GitHub has no "reply to a review body" endpoint.
|
|
135
|
+
- **Never post the same reply twice** — `last_seen.reviewId` is the only re-entry guard.
|
|
136
|
+
- **Never post a top-level summary alongside threaded replies** — duplication pollutes the Conversation tab.
|
|
139
137
|
|
|
140
138
|
## Telemetry
|
|
141
139
|
|
|
@@ -187,5 +185,6 @@ This stage produces no console output beyond:
|
|
|
187
185
|
- [ ] `followup.log` has at minimum a heartbeat or per-review line for this tick.
|
|
188
186
|
- [ ] Telemetry events emitted (per-cycle when applicable + per-tick).
|
|
189
187
|
- [ ] If pushed, `last_pushed_sha` is set and `cycles_completed` incremented.
|
|
188
|
+
- [ ] If actionable, one threaded reply posted per line comment (or one top-level reply for body-only reviews) — never both, never zero.
|
|
190
189
|
- [ ] If escalated, `escalated_review_ids` contains the review id.
|
|
191
190
|
- [ ] If terminal, the loop is NOT continued.
|