@muggleai/works 4.12.3 → 4.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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.12.3",
4
+ "version": "4.12.4",
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.12.3",
5
+ "version": "4.12.4",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -13,3 +13,4 @@ Filter client-side:
13
13
  - `id` not in `last_seen.escalated_review_ids`
14
14
  - `user.login` in the resolved allow-list
15
15
  - `state` in `{CHANGES_REQUESTED, COMMENTED}`, OR `APPROVED` with a non-empty body or at least one line comment
16
+ - **Not a reply-wrapper.** `POST /pulls/<n>/comments/<id>/replies` creates an implicit review whose comments all have `in_reply_to_id` set. Fetch each candidate review's comments via `gh api repos/<owner>/<repo>/pulls/<n>/reviews/<id>/comments` and drop the review if every comment has a non-null `in_reply_to_id` (no new top-level critique). Without this clause, the loop's own threaded replies — submitted under the PR author's identity in single-account workflows — pass the allow-list and re-dispatch `/muggle-do` on a no-op cycle.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The address-reviews flow only acts on reviews submitted by users in the **allow-list** = (requested reviewers ∪ CODEOWNERS ∪ {PR author}) − bots. Re-resolve every invocation — never cache across cycles.
4
4
 
5
- The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews. The agent itself never appears in the submitted-reviews list (it pushes commits and posts inline replies; it does not submit GitHub reviews), so there's no self-loop risk from including the author.
5
+ The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews. Self-loop is prevented at the watcher's filter layer rather than here: `POST /pulls/<n>/comments/<id>/replies` does create an implicit review under the loop user's identity, and the watcher drops it via the reply-wrapper clause in [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md). Including the PR author in this allow-list is therefore safe.
6
6
 
7
7
  ## Step 1: requested reviewers
8
8
 
@@ -8,7 +8,7 @@ Pick the first applicable path. Stop at the first that yields an `actionScriptId
8
8
 
9
9
  ### 1a. Dashboard URL in user's prompt
10
10
 
11
- A Muggle dashboard URL looks like `https://app.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://app.muggle-ai.com/...` URL.
11
+ A Muggle dashboard URL looks like `https://www.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://www.muggle-ai.com/...` URL.
12
12
 
13
13
  - Extract any UUID-shaped path segments. If `/projects/<uuid>` is present, capture as `projectId`. If `/test-scripts/<uuid>` is present, capture as `testScriptId`.
14
14
  - If a `testScriptId` was captured: call `muggle-remote-test-script-get` to get the script and read `actionScriptId` off it. Done — proceed to step 2.
@@ -37,7 +37,8 @@ If `state` is `MERGED` or `CLOSED`:
37
37
  2. Write `result.md` per [`state-schemas.md`](state-schemas.md#resultmd).
38
38
  3. Append a terminal line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
39
39
  4. Emit a `tick` event with `terminal: true` per [`../_shared/telemetry-events/pr-followup-tick.md`](../_shared/telemetry-events/pr-followup-tick.md).
40
- 5. Exit. **Do not schedule another tick.** The `/loop` framework stops invoking this skill once it sees no follow-up dispatch.
40
+ 5. **Cancel the cron schedule that fires this watcher.** `/loop 1m ...` from bootstrap was registered via `CronCreate`; a fixed-interval cron keeps firing regardless of whether the skill re-dispatches. Call `CronList`, find any job whose command ends with `/muggle:muggle-pr-followup <slug> <pr-number>` (exact two-arg match), and `CronDelete` it. No-op if none matches — the tick may have been invoked manually rather than via `/loop`.
41
+ 6. Exit. The watcher has now unscheduled itself; no future ticks will fire for this PR.
41
42
 
42
43
  ### Step 3 — Fetch new submitted reviews
43
44
 
@@ -66,7 +67,7 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
66
67
  ```
67
68
  3. Append a dispatching line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
68
69
  4. Emit a `tick` event with `reviews_seen: <count>`, `dispatched_review_ids: [<id>, ...]`.
69
- 5. Exit. **Do not schedule another tick.** `/muggle-do` will respawn the watcher at the end of its cycle.
70
+ 5. Exit. The cron schedule from bootstrap keeps firing the watcher every minute, so the next tick still arrives even though this turn dispatched `/muggle-do`. The watcher only self-unschedules in Step 2 (terminal).
70
71
 
71
72
  ## Output
72
73
 
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "4.12.3",
3
- "buildId": "run-41-1",
4
- "commitSha": "9f6c0d27cf0e83976386db90321cf9cc35ac5328",
5
- "buildTime": "2026-05-22T06:22:26Z",
2
+ "release": "4.12.4",
3
+ "buildId": "run-42-1",
4
+ "commitSha": "184a2b0b2eec344362e3ebb2a909684c4790f5d5",
5
+ "buildTime": "2026-05-22T23:47:18Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
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.12.3",
4
+ "version": "4.12.4",
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",
@@ -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.12.3",
4
+ "version": "4.12.4",
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.12.3",
5
+ "version": "4.12.4",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -13,3 +13,4 @@ Filter client-side:
13
13
  - `id` not in `last_seen.escalated_review_ids`
14
14
  - `user.login` in the resolved allow-list
15
15
  - `state` in `{CHANGES_REQUESTED, COMMENTED}`, OR `APPROVED` with a non-empty body or at least one line comment
16
+ - **Not a reply-wrapper.** `POST /pulls/<n>/comments/<id>/replies` creates an implicit review whose comments all have `in_reply_to_id` set. Fetch each candidate review's comments via `gh api repos/<owner>/<repo>/pulls/<n>/reviews/<id>/comments` and drop the review if every comment has a non-null `in_reply_to_id` (no new top-level critique). Without this clause, the loop's own threaded replies — submitted under the PR author's identity in single-account workflows — pass the allow-list and re-dispatch `/muggle-do` on a no-op cycle.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The address-reviews flow only acts on reviews submitted by users in the **allow-list** = (requested reviewers ∪ CODEOWNERS ∪ {PR author}) − bots. Re-resolve every invocation — never cache across cycles.
4
4
 
5
- The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews. The agent itself never appears in the submitted-reviews list (it pushes commits and posts inline replies; it does not submit GitHub reviews), so there's no self-loop risk from including the author.
5
+ The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews. Self-loop is prevented at the watcher's filter layer rather than here: `POST /pulls/<n>/comments/<id>/replies` does create an implicit review under the loop user's identity, and the watcher drops it via the reply-wrapper clause in [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md). Including the PR author in this allow-list is therefore safe.
6
6
 
7
7
  ## Step 1: requested reviewers
8
8
 
@@ -8,7 +8,7 @@ Pick the first applicable path. Stop at the first that yields an `actionScriptId
8
8
 
9
9
  ### 1a. Dashboard URL in user's prompt
10
10
 
11
- A Muggle dashboard URL looks like `https://app.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://app.muggle-ai.com/...` URL.
11
+ A Muggle dashboard URL looks like `https://www.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://www.muggle-ai.com/...` URL.
12
12
 
13
13
  - Extract any UUID-shaped path segments. If `/projects/<uuid>` is present, capture as `projectId`. If `/test-scripts/<uuid>` is present, capture as `testScriptId`.
14
14
  - If a `testScriptId` was captured: call `muggle-remote-test-script-get` to get the script and read `actionScriptId` off it. Done — proceed to step 2.
@@ -37,7 +37,8 @@ If `state` is `MERGED` or `CLOSED`:
37
37
  2. Write `result.md` per [`state-schemas.md`](state-schemas.md#resultmd).
38
38
  3. Append a terminal line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
39
39
  4. Emit a `tick` event with `terminal: true` per [`../_shared/telemetry-events/pr-followup-tick.md`](../_shared/telemetry-events/pr-followup-tick.md).
40
- 5. Exit. **Do not schedule another tick.** The `/loop` framework stops invoking this skill once it sees no follow-up dispatch.
40
+ 5. **Cancel the cron schedule that fires this watcher.** `/loop 1m ...` from bootstrap was registered via `CronCreate`; a fixed-interval cron keeps firing regardless of whether the skill re-dispatches. Call `CronList`, find any job whose command ends with `/muggle:muggle-pr-followup <slug> <pr-number>` (exact two-arg match), and `CronDelete` it. No-op if none matches — the tick may have been invoked manually rather than via `/loop`.
41
+ 6. Exit. The watcher has now unscheduled itself; no future ticks will fire for this PR.
41
42
 
42
43
  ### Step 3 — Fetch new submitted reviews
43
44
 
@@ -66,7 +67,7 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
66
67
  ```
67
68
  3. Append a dispatching line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
68
69
  4. Emit a `tick` event with `reviews_seen: <count>`, `dispatched_review_ids: [<id>, ...]`.
69
- 5. Exit. **Do not schedule another tick.** `/muggle-do` will respawn the watcher at the end of its cycle.
70
+ 5. Exit. The cron schedule from bootstrap keeps firing the watcher every minute, so the next tick still arrives even though this turn dispatched `/muggle-do`. The watcher only self-unschedules in Step 2 (terminal).
70
71
 
71
72
  ## Output
72
73