@muggleai/works 5.0.0 → 5.0.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.
Files changed (63) hide show
  1. package/dist/{chunk-YKR2TQ24.js → chunk-KDRSEHK5.js} +2 -1
  2. package/dist/{chunk-5G7WI7IY.js → chunk-XO5BQZM3.js} +2 -2
  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/scripts/guardrails.mjs +2 -1
  8. package/dist/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +14 -6
  9. package/dist/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +6 -2
  10. package/dist/plugin/skills/_shared/github-cli-recipes.md +2 -2
  11. package/dist/plugin/skills/_shared/pr-followup-helpers/classify.md +2 -2
  12. package/dist/plugin/skills/_shared/pr-followup-helpers/echo-skip.md +6 -12
  13. package/dist/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +1 -1
  14. package/dist/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -4
  15. package/dist/plugin/skills/do/address-reviews.md +7 -7
  16. package/dist/plugin/skills/do/open-prs/forward.md +1 -1
  17. package/dist/plugin/skills/muggle-feedback/SKILL.md +1 -1
  18. package/dist/plugin/skills/muggle-pr-followup/SKILL.md +2 -2
  19. package/dist/plugin/skills/muggle-pr-followup/auto-track.md +1 -1
  20. package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +8 -6
  21. package/dist/plugin/skills/muggle-pr-followup/contract.md +17 -14
  22. package/dist/plugin/skills/muggle-pr-followup/output-templates/bootstrap.md +1 -1
  23. package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +1 -1
  24. package/dist/plugin/skills/muggle-pr-followup/output-templates/watcher-log.md +2 -2
  25. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +7 -7
  26. package/dist/plugin/skills/muggle-status/SKILL.md +1 -1
  27. package/dist/plugin/skills/muggle-test/SKILL.md +20 -56
  28. package/dist/plugin/skills/muggle-test/reference.md +35 -0
  29. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +7 -5
  30. package/dist/plugin/skills/muggle-test-import/SKILL.md +1 -10
  31. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +1 -1
  32. package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
  33. package/dist/release-manifest.json +4 -4
  34. package/dist/{src-ECRJW2LY.js → src-2O5UH4FA.js} +1 -1
  35. package/package.json +6 -6
  36. package/plugin/.claude-plugin/plugin.json +1 -1
  37. package/plugin/.cursor-plugin/plugin.json +1 -1
  38. package/plugin/scripts/guardrails.mjs +2 -1
  39. package/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +14 -6
  40. package/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +6 -2
  41. package/plugin/skills/_shared/github-cli-recipes.md +2 -2
  42. package/plugin/skills/_shared/pr-followup-helpers/classify.md +2 -2
  43. package/plugin/skills/_shared/pr-followup-helpers/echo-skip.md +6 -12
  44. package/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +1 -1
  45. package/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -4
  46. package/plugin/skills/do/address-reviews.md +7 -7
  47. package/plugin/skills/do/open-prs/forward.md +1 -1
  48. package/plugin/skills/muggle-feedback/SKILL.md +1 -1
  49. package/plugin/skills/muggle-pr-followup/SKILL.md +2 -2
  50. package/plugin/skills/muggle-pr-followup/auto-track.md +1 -1
  51. package/plugin/skills/muggle-pr-followup/bootstrap.md +8 -6
  52. package/plugin/skills/muggle-pr-followup/contract.md +17 -14
  53. package/plugin/skills/muggle-pr-followup/output-templates/bootstrap.md +1 -1
  54. package/plugin/skills/muggle-pr-followup/output-templates/help.md +1 -1
  55. package/plugin/skills/muggle-pr-followup/output-templates/watcher-log.md +2 -2
  56. package/plugin/skills/muggle-pr-followup/state-schemas.md +7 -7
  57. package/plugin/skills/muggle-status/SKILL.md +1 -1
  58. package/plugin/skills/muggle-test/SKILL.md +20 -56
  59. package/plugin/skills/muggle-test/reference.md +35 -0
  60. package/plugin/skills/muggle-test-feature-local/SKILL.md +7 -5
  61. package/plugin/skills/muggle-test-import/SKILL.md +1 -10
  62. package/plugin/skills/muggle-test-prepare/SKILL.md +1 -1
  63. package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-test
3
- description: "Run change-driven E2E acceptance testing using Muggle AI — detect the user's recent code changes (local diff or a PR), map them to affected user flows, then run real-browser acceptance tests on localhost or a deployed preview/staging URL, publish results to the dashboard, and post a screenshot summary to the PR. Use this whenever the user wants to test, validate, check, or regression-test their own changes or work — 'test my changes', 'validate my changes', 'regression test my work', 'make sure I didn't break anything', 'did my recent commits/changes break anything or any user flows?', 'test before I push' — and especially as the acceptance-test gate before opening a pull request or merging (e.g. 'validate my changes before I open the PR' means run the acceptance suite, not just a completion checklist). The defining signal is change-driven validation of in-progress work tied to a commit, push, PR, or merge. For testing one specific named feature/flow use muggle-test-feature-local; this is not importing existing tests, configuring preferences, or replaying a single named script."
3
+ description: "Change-driven E2E acceptance testing with Muggle AI: detect the user's recent code changes (local diff or a PR), map them to affected user flows, run real-browser tests on localhost or a preview/staging URL, publish results, and post a screenshot summary to the PR. Use whenever the user wants to test, validate, or regression-test their own in-progress changes or work — \"make sure I didn't break anything\", \"did my recent commits break any user flows?\", \"test before I push\" — especially as the acceptance gate before opening or merging a PR. The defining signal is change-driven validation tied to a commit, push, PR, or merge. For one specific named feature/flow use muggle-test-feature-local; not for importing existing tests, configuring preferences, or replaying a single named script."
4
4
  ---
5
5
 
6
6
  # Muggle Test — Change-Driven E2E Acceptance Router
@@ -113,13 +113,15 @@ If no changes detected (clean tree), tell the user and ask what they want to tes
113
113
 
114
114
  ## Step 3: Authenticate
115
115
 
116
- 1. Call `muggle-remote-auth-status`
117
- 2. If **authenticated and not expired** → gate `autoLogin` (per `preference-gates/README.md`):
118
- - `always` → reuse saved session.
116
+ 1. Call `muggle-remote-auth-status`. Three states: **valid** (`authenticated: true`), **expired** (`authenticated: false` + `isExpired: true`, `email` still present), **absent** (`authenticated: false`, no `email`).
117
+ 2. **Valid OR expired** (any stored identity) → gate `autoLogin` (per `preference-gates/README.md`). An expired token is NOT a reason to silently re-login the same account — surface the switch choice:
118
+ - `always` → reuse if valid; if expired, re-login the **same** account (`muggle-remote-auth-login`, then `muggle-remote-auth-poll`).
119
119
  - `never` → `muggle-remote-auth-login` with `forceNewSession: true`, then `muggle-remote-auth-poll`.
120
120
  - `ask` → run Picker 1 from `preference-gates/autoLogin.md` via `AskUserQuestion`; map the answer back to one of the actions above.
121
- 3. If **not authenticated or expired** → call `muggle-remote-auth-login`
122
- 4. If login pending → call `muggle-remote-auth-poll`
121
+ 3. **Absent** (no stored identity) → `muggle-remote-auth-login` directly, then `muggle-remote-auth-poll`.
122
+ 4. If login pending → call `muggle-remote-auth-poll`.
123
+
124
+ **Account-switch caveat (`never` / "Switch account").** The device flow has no `prompt=select_account`; switching relies on `forceNewSession` first clearing the Auth0 session via `/v2/logout?returnTo=<device-activation URL>`. That redirect only works if the activation URL is in the app's Auth0 *Allowed Logout URLs* — otherwise the browser shows an Auth0 error page and the session is silently reused. If that happens, tell the user to complete login in a **fresh incognito window** (no live SSO session) so Auth0 presents an account login.
123
125
 
124
126
  If auth fails repeatedly, suggest: `muggle logout && muggle login` from terminal.
125
127
 
@@ -413,53 +415,15 @@ Use `AskUserQuestion`:
413
415
 
414
416
  This is a suggestion, not automatic invocation. Skip silently if every test passed cleanly.
415
417
 
416
- ## Tool Reference
417
-
418
- | Phase | Tool | Mode |
419
- |:------|:-----|:-----|
420
- | Auth | `muggle-remote-auth-status` | Both |
421
- | Auth | `muggle-remote-auth-login` | Both |
422
- | Auth | `muggle-remote-auth-poll` | Both |
423
- | Project | `muggle-remote-project-list` | Both |
424
- | Project | `muggle-remote-project-create` | Both |
425
- | Use Case | `muggle-remote-use-case-list` | Both |
426
- | Use Case | `muggle-remote-use-case-create-from-prompts` | Both |
427
- | Test Case | `muggle-remote-test-case-list-by-use-case` | Both |
428
- | Test Case | `muggle-remote-test-case-generate-from-prompt` | Both |
429
- | Test Case | `muggle-remote-test-case-create` | Both |
430
- | Test Case | `muggle-remote-test-case-get` | Both |
431
- | Execute (regen) | `muggle-local-execute-test-generation` | Local |
432
- | Execute (replay) | `muggle-local-execute-replay` | Local |
433
- | Replay action script fetch | `muggle-remote-test-script-get`, `muggle-remote-action-script-get` | Local replay |
434
- | Execute (regen) | `muggle-remote-workflow-start-test-script-generation` | Remote |
435
- | Execute (replay) | `muggle-remote-workflow-start-test-script-replay` | Remote |
436
- | Failure-mode telemetry | `muggle-local-telemetry-event-emit` | Both |
437
- | Results | `muggle-local-run-result-get` | Local |
438
- | Results | `muggle-remote-wf-get-ts-gen-latest-run`, `muggle-remote-wf-get-ts-replay-latest-run` | Remote |
439
- | Publish | `muggle-local-publish-test-script` | Local |
440
- | Per-step screenshots (for walkthrough) | `muggle-remote-test-script-get` | Both |
441
- | Browser | `open` (shell command) | Both |
442
- | PR walkthrough | `muggle-pr-visual-walkthrough` (shared skill) | Both |
443
-
444
- ## Guardrails
445
-
446
- - **Always confirm intent first** — never assume local vs remote without asking
447
- - **PR URLs always run in a dedicated worktree** — never switch the user's main checkout. Materialize per [`_shared/pr-branch-worktree.md`](../_shared/pr-branch-worktree.md) and pass that path as `cwd` to local execute tools; the cross-worktree single-flight lock relies on it to serialize concurrent runs from different branches.
448
- - **User MUST select project** — present clickable options via `AskUserQuestion`, wait for explicit choice, never auto-select
449
- - **Best-effort shortlist use cases** — use the change summary to narrow the list to the most relevant 1–5 use cases and pre-check them; never dump every use case in the project on the user. Always leave an escape hatch to reveal the full list.
450
- - **Best-effort shortlist test cases** — same idea: pre-check the test cases most relevant to the change summary; never enumerate every test case attached to a use case. Always leave an escape hatch to reveal the full list.
451
- - **Use `AskUserQuestion` for every selection** — never ask the user to type a number; always present clickable options
452
- - **Auto-detect localhost URL when possible**; only fall back to free-text when nothing is listening on a common port
453
- - **Parallelize independent cloud jobs** — when creating N use cases, generating/creating N test cases, fetching N test case details, starting N remote workflows, polling N workflow runtimes, publishing N local runs, or fetching N per-step test scripts, issue all N calls in a single message so they fan out in parallel. The only tolerated sequential loop is local Electron execution (one browser, one test at a time). For use case creation specifically, use the native batch form of `muggle-remote-use-case-create-from-prompts` (all descriptions in one `instructions` array) instead of parallel calls.
454
- - **One atomic behavior per test case** — every test case verifies exactly one user-observable behavior. Never bundle signup/login/navigation/bootstrap/teardown into a test case body. Ordering and dependencies are Muggle Test's service responsibility, not the skill's.
455
- - **Never consolidate the generator's output** — if `muggle-remote-test-case-generate-from-prompt` returns N micro-tests, accept all N; never merge them into fewer test cases, even if "the plan" says 4 UC / 4 TC.
456
- - **Never skip the generate→review cycle** — always present generated test cases to the user before calling `muggle-remote-test-case-create`, even when you're confident. "I'll skip the review and create directly" is always wrong.
457
- - **Never silently drop test cases** — log failures and continue, then report them
458
- - **Never guess the URL** — always ask the user for localhost or preview URL
459
- - **Always publish before opening browser** — the dashboard needs the published data to show results
460
- - **Delegate PR posting to `muggle-pr-visual-walkthrough`** — never inline the walkthrough markdown or call `gh pr comment` directly from this skill; ask the user and hand off
461
- - **Can be invoked at any state** — if the user already has a project or use cases set up, skip to the relevant step rather than re-doing everything
462
-
463
- ## Agent Dispatch
464
-
465
- When used in a multi-agent team (e.g., muggle-ai-teams), this skill is available through the **acceptance-tester** agent at `plugin/agents/acceptance-tester.md`. Orchestrators can dispatch it via `Agent()` instead of invoking this skill directly. The agent wraps this skill and four others (muggle-test-import, muggle-preferences, muggle-repair, muggle-status) and returns structured test results with blocking issues and suggested fixes for coding agents to act on.
418
+ ## Non-negotiables
419
+
420
+ Each rule below is covered in-step above; these are the ones this skill most often violates, kept here as reinforcement:
421
+
422
+ - **Test-case shape** — never skip the generate→review cycle, never consolidate the generator's micro-tests, one atomic behavior per test case. Creating test cases directly or merging the generator's output is the single most frequent mistake.
423
+ - **Confirm intent before acting** — local vs remote; never guess the localhost/preview URL.
424
+ - **PR URLs run in a dedicated worktree** — never switch the user's main checkout; pass that worktree as `cwd`.
425
+ - **Every selection uses `AskUserQuestion`** — never ask the user to type a number; the user picks the project (never auto-select).
426
+ - **Parallelize independent cloud jobs**; the only sequential loop is local Electron execution (one browser).
427
+ - **Publish before opening the browser**, and delegate PR posting to `muggle-pr-visual-walkthrough` — never inline the walkthrough or call `gh pr comment` here.
428
+
429
+ Phase→tool map and multi-agent (acceptance-tester) dispatch: [`reference.md`](reference.md).
@@ -0,0 +1,35 @@
1
+ # muggle-test reference
2
+
3
+ Lookup material pulled out of `SKILL.md` to keep the always-loaded body lean. Every tool here is also named inline in the step that uses it — consult this only when you want the full phase→tool map in one place.
4
+
5
+ ## Tool Reference
6
+
7
+ | Phase | Tool | Mode |
8
+ |:------|:-----|:-----|
9
+ | Auth | `muggle-remote-auth-status` | Both |
10
+ | Auth | `muggle-remote-auth-login` | Both |
11
+ | Auth | `muggle-remote-auth-poll` | Both |
12
+ | Project | `muggle-remote-project-list` | Both |
13
+ | Project | `muggle-remote-project-create` | Both |
14
+ | Use Case | `muggle-remote-use-case-list` | Both |
15
+ | Use Case | `muggle-remote-use-case-create-from-prompts` | Both |
16
+ | Test Case | `muggle-remote-test-case-list-by-use-case` | Both |
17
+ | Test Case | `muggle-remote-test-case-generate-from-prompt` | Both |
18
+ | Test Case | `muggle-remote-test-case-create` | Both |
19
+ | Test Case | `muggle-remote-test-case-get` | Both |
20
+ | Execute (regen) | `muggle-local-execute-test-generation` | Local |
21
+ | Execute (replay) | `muggle-local-execute-replay` | Local |
22
+ | Replay action script fetch | `muggle-remote-test-script-get`, `muggle-remote-action-script-get` | Local replay |
23
+ | Execute (regen) | `muggle-remote-workflow-start-test-script-generation` | Remote |
24
+ | Execute (replay) | `muggle-remote-workflow-start-test-script-replay` | Remote |
25
+ | Failure-mode telemetry | `muggle-local-telemetry-event-emit` | Both |
26
+ | Results | `muggle-local-run-result-get` | Local |
27
+ | Results | `muggle-remote-wf-get-ts-gen-latest-run`, `muggle-remote-wf-get-ts-replay-latest-run` | Remote |
28
+ | Publish | `muggle-local-publish-test-script` | Local |
29
+ | Per-step screenshots (for walkthrough) | `muggle-remote-test-script-get` | Both |
30
+ | Browser | `open` (shell command) | Both |
31
+ | PR walkthrough | `muggle-pr-visual-walkthrough` (shared skill) | Both |
32
+
33
+ ## Agent Dispatch
34
+
35
+ In a multi-agent team (e.g. muggle-ai-teams), this skill is reachable through the **acceptance-tester** agent at `plugin/agents/acceptance-tester.md`. Orchestrators dispatch it via `Agent()` instead of invoking the skill directly. The agent wraps this skill and four others (muggle-test-import, muggle-preferences, muggle-repair, muggle-status) and returns structured test results with blocking issues and suggested fixes for coding agents to act on.
@@ -147,14 +147,16 @@ Run the shared loop in [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md
147
147
 
148
148
  Caller glue: `mode` is the path chosen in §5; `localUrl` from §4; `cwd` = the repo root, or the prepared worktree when one is in use.
149
149
 
150
- ### 7. Execute (no approval prompt; `showUi` gated by `showElectronBrowser`)
150
+ ### 7. Execute (`showUi` gated by `showElectronBrowser`)
151
151
 
152
- Call `muggle-local-execute-test-generation` or `muggle-local-execute-replay` directly. **Do not** ask the user to re-approve the Electron launch — the user choosing this skill in the first place is the approval.
152
+ Resolve the `showElectronBrowser` gate **first**, then call `muggle-local-execute-test-generation` or `muggle-local-execute-replay`. **Do not** ask the user to re-approve the Electron launch itself — choosing this skill is the approval. That run-approval suppression does **not** extend to the gate below: when `showElectronBrowser=ask` you must still fire its picker.
153
153
 
154
- Gate `showElectronBrowser` (per `preference-gates/README.md`). Reuse choice within a session.
155
- - `always` → omit `showUi`.
154
+ Gate `showElectronBrowser` (per `preference-gates/README.md`). Reuse the choice within a session.
155
+ - `always` → omit `showUi` (the browser shows by default).
156
156
  - `never` → pass `showUi: false`.
157
- - `ask` → run Picker 1 from `preference-gates/showElectronBrowser.md` via `AskUserQuestion`; map the answer back to one of the actions above.
157
+ - `ask` → you **must** call `AskUserQuestion` (Picker 1 from `preference-gates/showElectronBrowser.md`) **before** the execute call, then map the answer to the `always`/`never` action above. Do not decide for the user.
158
+
159
+ `showUi` is only ever omitted or `false` — never pass `showUi: true`.
158
160
 
159
161
  ### 8. Upload run to cloud (every completed run; open `viewUrl` gated by `openTestResultsAfterRun`)
160
162
 
@@ -1,15 +1,6 @@
1
1
  ---
2
2
  name: muggle-test-import
3
- description: >
4
- Bring existing tests and test artifacts INTO Muggle Test — from Playwright, Cypress, PRDs,
5
- Gherkin feature files, test plan docs, Notion exports, or any source.
6
- TRIGGER when: user wants to import/migrate/load/upload/add/convert existing test files or
7
- test docs into Muggle Test — e.g. "import my playwright tests", "migrate from cypress to muggle",
8
- "upload my PRD to muggle", "add my e2e specs to our muggle project", "load these test cases
9
- into muggle", "turn this feature file into muggle test cases", "create muggle test cases from
10
- my PRD", "track my specs in muggle", or any .spec.ts/.cy.js/.feature/.md file + muggle.
11
- DO NOT TRIGGER when: user wants to run/replay Muggle Test scripts, scan a site, generate new
12
- tests from scratch, or check existing test results.
3
+ description: "Bring existing tests and test artifacts INTO Muggle Test — from Playwright, Cypress, PRDs, Gherkin feature files, test-plan docs, Notion exports, or any source. TRIGGER when the user wants to import, migrate, load, or convert existing test files or docs into Muggle Test — import my playwright tests, migrate from cypress to muggle, upload my PRD to muggle, turn this feature file into muggle test cases, or any .spec.ts/.cy.js/.feature/.md file plus muggle. DO NOT trigger for running or replaying scripts, scanning a site, generating new tests from scratch, or checking results."
13
4
  ---
14
5
 
15
6
  # Muggle Test Import
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-test-prepare
3
- description: "Use this skill to get a user's local environment ready before running E2E acceptance tests — verifying that the dev servers, APIs, and sibling services they need are actually up and responding, and offering to start whatever is missing (with approval at each step). Trigger whenever the user wants to confirm that specific ports or localhost URLs are listening/up before testing (e.g. 'check if localhost:3000 and the api on 8080 are listening', 'are my services up?'), make sure required services are running, spin up or prepare their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not listening on the expected ports. This is environment readiness and service startup, not running the tests themselves."
3
+ description: "Get a user's local environment ready before running E2E acceptance tests — verify the dev servers, APIs, and sibling services they need are up and responding, and offer to start whatever is missing (with approval per step). Trigger when the user wants to confirm specific ports or localhost URLs are listening before testing (check if localhost:3000 and the api on 8080 are up, are my services running), spin up their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not. This is environment readiness and service startup, not running the tests."
4
4
  ---
5
5
 
6
6
  # Muggle Test Prepare
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-test-regenerate-missing
3
- description: "Bulk-regenerate test scripts for every test case in a Muggle AI project that doesn't currently have an active script. Scans the project, finds test cases stuck in DRAFT or GENERATION_PENDING (no usable script attached), shows the user the list, and on approval kicks off bulk remote test script generation via the Muggle Test cloud. Use this skill whenever the user asks to 'regenerate missing scripts', 'fill in missing test scripts', 'generate scripts for test cases without one', 'regen all the test cases that don't have scripts', 'rebuild scripts for stale test cases', 'fix test cases with no script', 'bulk regenerate', or any phrasing that means 'kick off script generation across a project for the cases that need it'. Triggers on: 'regenerate missing test scripts', 'generate scripts for all empty test cases', 'fill the gaps in my test scripts', 'bulk test script regen', 'all my test cases without active scripts'. This is the go-to skill for project-wide script catch-up — it handles discovery, filtering, confirmation, and remote workflow dispatch end-to-end."
3
+ description: "Bulk-regenerate test scripts for every test case in a Muggle AI project that has no active script. Scans the project, finds test cases stuck in DRAFT or GENERATION_PENDING, shows the user the list, and on approval kicks off bulk remote script generation via the Muggle Test cloud. Use when the user wants to regenerate missing scripts, fill in missing test scripts, generate scripts for test cases without one, rebuild scripts for stale test cases, or bulk regenerate across a project. Handles discovery, filtering, confirmation, and remote dispatch end-to-end."
4
4
  ---
5
5
 
6
6
  # Muggle Test — Regenerate Missing Test Scripts
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "5.0.0",
3
- "buildId": "run-48-1",
4
- "commitSha": "31c2dbefd3e75f56ea239b5953efbef859290db9",
5
- "buildTime": "2026-06-03T19:09:10Z",
2
+ "release": "5.0.2",
3
+ "buildId": "run-50-1",
4
+ "commitSha": "9893215c2e48b50b132e223dbfa952531b7d2442",
5
+ "buildTime": "2026-06-08T07:17:59Z",
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-YKR2TQ24.js';
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-KDRSEHK5.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": "5.0.0",
4
+ "version": "5.0.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.113",
44
+ "electronAppVersion": "1.1.0",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "f3edf2d40ae81c88ae579c9a5835cd8a84b5864610926a4ca31c4b62478103a8",
49
- "darwin-x64": "3f13399eb957a214dabaab3bdd921c9c2293205972b84b7f788a2cb862ba55b9",
50
- "linux-x64": "dfbbd32eca72903f5cfd7545caf0583bb609de8feb47ebf0d4580f3d1cdffbf2",
51
- "win32-x64": "0e4838e12a99ec86bc66289503cfb43de018cb518c952b2fb72fbe5e6233f1d4"
48
+ "darwin-arm64": "1df66af13de18e90b53a0dfad7b329358265a7380bc8f61b6bfcfaaefdce2825",
49
+ "darwin-x64": "3d350547f398c09e485d6b33bb3493d50698ab19a63890792a7a03aeee4a93f2",
50
+ "linux-x64": "93bed227dee0c52cff3cdc6e2a346c86d1902ce0ca93bced5632d4d8e7ae290e",
51
+ "win32-x64": "c2971e824fea4637ce520b3ee8a2fd8bd8562f1f826ac3674a80931791007088"
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": "5.0.0",
4
+ "version": "5.0.2",
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.0.0",
5
+ "version": "5.0.2",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -64,12 +64,13 @@ function shouldRunE2E(state) {
64
64
 
65
65
  // src/guardrails/detectBuildIntent.ts
66
66
  var BUILD = /\b(implement|build|add|create|write|fix|refactor|wire up|hook up|make (a|the|it)|change the)\b/i;
67
+ var DEVCYCLE = /\bresolve\b[^.?!]{0,40}\bconflicts?\b|\bget\b[^.?!]{0,40}\bpr\b[^.?!]{0,40}\b(green|merged?|passing)\b/i;
67
68
  var QUESTION = /^\s*(why|what|how|when|where|who|is|are|does|do|can you (explain|tell)|explain)\b/i;
68
69
  function detectBuildIntent(prompt) {
69
70
  const p = (prompt ?? "").trim();
70
71
  if (!p || p.startsWith("/")) return false;
71
72
  if (QUESTION.test(p)) return false;
72
- return BUILD.test(p);
73
+ return BUILD.test(p) || DEVCYCLE.test(p);
73
74
  }
74
75
 
75
76
  // src/guardrails/emit.ts
@@ -1,16 +1,24 @@
1
- # Submitted reviews past a cursor
1
+ # Submitted reviews
2
2
 
3
- For the watcher's poll and the address-reviews fetch.
3
+ Two consumers (this recipe links to neither — it is a shared primitive):
4
+
5
+ - the watcher's **body-only-review** check — a submitted review carrying a summary body but **no** line comments. Line-comment threads are dispatched from live thread state, not here.
6
+ - the address-reviews fetch of a **specific** review id.
4
7
 
5
8
  ```bash
6
9
  gh api repos/<owner>/<repo>/pulls/<n>/reviews --paginate
7
10
  ```
8
11
 
9
- Filter client-side:
12
+ Common filter:
10
13
 
11
14
  - `submitted_at != null` (skip PENDING drafts)
12
- - `id > last_seen.reviewId`
13
- - `id` not in `last_seen.escalated_review_ids`
14
15
  - `user.login` in the resolved allow-list
15
16
  - `state` in `{CHANGES_REQUESTED, COMMENTED}`, OR `APPROVED` with a non-empty body or at least one line comment
16
- - **Not a loop echo.** `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 **only if every comment is a reply (`in_reply_to_id != null`) and carries the loop marker `<!-- muggle-do:bot -->`** (see [`../pr-followup-helpers/loop-signature.md`](../pr-followup-helpers/loop-signature.md)). A reply-only wrapper with any comment **lacking** the marker is a human follow-up — keep it; the round addresses it. Matching the marker, not structure, is what skips the loop's own replies (posted under the author's identity in single-account workflows) without dropping genuine follow-ups.
17
+
18
+ The **watcher's body-only check** adds:
19
+
20
+ - the review has **no line comments** — `gh api repos/<owner>/<repo>/pulls/<n>/reviews/<id>/comments` returns `[]`. A review with line comments is dispatched from thread state, not here.
21
+ - `id > last_seen.lastBodyReviewId`
22
+ - `id` not in `last_seen.escalated_review_ids`
23
+
24
+ A reply posted by the loop surfaces as an implicit review, but it always carries the reply as a line comment, so it can never be body-only — the body-only filter excludes it structurally, no marker check needed. Thread-level echo protection is intrinsic to the marker rule in [`unresolved-threads.md`](unresolved-threads.md).
@@ -1,6 +1,6 @@
1
1
  # Unresolved comment threads
2
2
 
3
- For the resolve-reminder stage. GraphQL only — REST does not expose `isResolved`.
3
+ For the watcher's dispatch trigger and the resolve-reminder stage. GraphQL only — REST does not expose `isResolved`/`isOutdated`.
4
4
 
5
5
  ```bash
6
6
  gh api graphql -F owner=<owner> -F name=<repo> -F number=<n> -f query='
@@ -11,9 +11,11 @@ query($owner: String!, $name: String!, $number: Int!) {
11
11
  nodes {
12
12
  id
13
13
  isResolved
14
+ isOutdated
14
15
  comments(first: 100) {
15
16
  nodes {
16
17
  databaseId
18
+ pullRequestReview { databaseId }
17
19
  author { login }
18
20
  body
19
21
  createdAt
@@ -29,7 +31,9 @@ query($owner: String!, $name: String!, $number: Int!) {
29
31
  Filter client-side to `isResolved == false`. Walk each thread's comments in `createdAt` order and classify by the loop marker (see [`../pr-followup-helpers/loop-signature.md`](../pr-followup-helpers/loop-signature.md)), not by `author.login` — the login is ambiguous under a shared account:
30
32
 
31
33
  - **Addressed, awaiting resolve** — the **newest** comment carries the loop marker `<!-- muggle-do:bot -->`. The loop has replied and nothing newer is waiting. → resolve-reminder.
32
- - **Unaddressed human comment** — the newest comment lacks the marker and is newer than the thread's newest loop-marked comment (or the thread has no loop comment yet). → actionable: the round should address it.
34
+ - **Unaddressed human comment** — the newest comment lacks the marker and is newer than the thread's newest loop-marked comment (or the thread has no loop comment yet). → actionable: the round should address it. The **watcher's dispatch trigger** additionally requires `isOutdated == false` — a thread whose anchored line has since changed is skipped, since re-surfacing a stale anchor risks answering a concern the change already mooted. The resolve-reminder stage ignores `isOutdated`.
33
35
  - **Not addressed** — indeterminate (e.g. no comments).
34
36
 
37
+ Each comment exposes its owning review as `pullRequestReview.databaseId` — the watcher collects this from an actionable thread's newest comment to build its dispatch list.
38
+
35
39
  A loop comment also cites a `<short-sha>` from `last_seen.pushed_shas[]` in its body, which tells *which* push addressed the thread.
@@ -9,10 +9,10 @@ Skills assume a working `gh auth status`. Auth errors surface verbatim from `gh`
9
9
  | Recipe | Use case |
10
10
  | :----- | :------- |
11
11
  | [`pr-metadata`](github-cli-recipes/pr-metadata.md) | Snapshot PR state, head SHA, branch — watcher + bootstrap. |
12
- | [`submitted-reviews`](github-cli-recipes/submitted-reviews.md) | Fetch reviews past a cursor — watcher's poll. |
12
+ | [`submitted-reviews`](github-cli-recipes/submitted-reviews.md) | Fetch a review by id / watcher's body-only-review check. |
13
13
  | [`pr-checks`](github-cli-recipes/pr-checks.md) | Check-run rollup for the head SHA — watcher's CI poll. |
14
14
  | [`line-comments-for-review`](github-cli-recipes/line-comments-for-review.md) | Pull a review's line comments — `/muggle-do` per-comment routing. |
15
- | [`unresolved-threads`](github-cli-recipes/unresolved-threads.md) | GraphQL fetch of unresolved comment threads — resolve-reminder. |
15
+ | [`unresolved-threads`](github-cli-recipes/unresolved-threads.md) | GraphQL unresolved-thread state — watcher's dispatch trigger + resolve-reminder. |
16
16
  | [`reply-line-comment`](github-cli-recipes/reply-line-comment.md) | POST a threaded reply on a line comment. |
17
17
  | [`top-level-comment`](github-cli-recipes/top-level-comment.md) | POST a top-level PR comment — resolve-reminder + overflow. |
18
18
  | [`push-to-branch`](github-cli-recipes/push-to-branch.md) | Push + capture new SHA after address-reviews work. |
@@ -10,7 +10,7 @@ A review is a **self-loop** iff **every** line comment under it is a reply (`in_
10
10
 
11
11
  If any comment in a reply-only wrapper **lacks** the marker, it is a **human follow-up** on an existing thread — not a self-loop. It carries reviewer intent; treat it as actionable and address it in this round (the caller's unresolved-thread sweep picks up the thread context).
12
12
 
13
- Self-loops bypass the actionable/ambiguous decision entirely. Action: advance the cursor silently. No push, no reply, no resolve-reminder, no escalation, no entry in `escalated_review_ids`. Telemetry: emit one `cycle` event with `outcome: "self-loop-skip"`.
13
+ Self-loops bypass the actionable/ambiguous decision entirely. Action: skip silently — a body-only echo folds its id into `lastBodyReviewId`; a line-comment echo already drops out of the actionable set via the marker. No push, no reply, no resolve-reminder, no escalation, no entry in `escalated_review_ids`. Telemetry: emit one `cycle` event with `outcome: "self-loop-skip"`.
14
14
 
15
15
  Only reviews that survive the self-loop check proceed to classify below.
16
16
 
@@ -51,7 +51,7 @@ Reply shape (all replies for one review reference the same SHA):
51
51
  | 1 comment: "won't this break the prod migration we did last week?" | Implicit change request gated on knowledge the loop can't access |
52
52
  | Mixed: 2 concrete directives + 1 "rethink the whole approach" | The "rethink" subverts the others; escalate to confirm scope |
53
53
 
54
- Escalate per the caller's procedure (add the review id to the cursor's escalated set, emit one terminal message, pause the PR).
54
+ Escalate per the caller's procedure (add the review id to `escalated_review_ids`, emit one terminal message, pause the PR).
55
55
 
56
56
  ## Borderline rule
57
57
 
@@ -1,16 +1,10 @@
1
- # Reply-echo skip
1
+ # Echo protection (intrinsic under thread-state)
2
2
 
3
- When `/muggle-do` posts a threaded reply to a review comment, GitHub surfaces that reply as a **new submitted review** under the same account. Left unchecked, the next watcher tick reads that review as fresh feedback and dispatches another cycle — which posts another reply, which becomes another review. The loop never converges.
3
+ When `/muggle-do` posts a threaded reply to a review comment, GitHub surfaces that reply as a **new submitted review** under the same account, and the reply becomes the newest comment in its thread. The watcher must never read that as fresh feedback, or it replies to itself forever.
4
4
 
5
- ## Rule
5
+ Under the thread-state dispatch trigger this is **intrinsic** — there is no "advance past the echo" step to get wrong:
6
6
 
7
- A submitted review is an **echo** when **every** comment in it carries the loop marker `<!-- muggle-do:bot -->` (see [`loop-signature.md`](loop-signature.md)). An echo is the loop's own reply wearing a review's clothing, never human intent.
7
+ - **Line-comment threads.** A thread is actionable only when its newest comment lacks the loop marker `<!-- muggle-do:bot -->` (see [`loop-signature.md`](loop-signature.md)). After the loop replies, the newest comment is the loop's own and carries the marker, so the thread drops out of the actionable set on its own.
8
+ - **Body-only reviews.** A loop reply always carries a line comment, so it is never body-only; the body-only check (no line comments, `id > lastBodyReviewId` — see [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md)) excludes echoes structurally.
8
9
 
9
- On an echo review, the watcher must:
10
-
11
- 1. Advance `last_seen.reviewId` past the echo's id (so it is not seen again), and
12
- 2. **Skip it** — never dispatch `/muggle-do` for it.
13
-
14
- ## Detection
15
-
16
- Classify by the marker, never by `author.login` — under a shared account the loop posts as the PR author, so the login cannot tell echo from human. Fetch the review's comments; if the set is non-empty and every comment body contains `<!-- muggle-do:bot -->`, it is an echo. A review with at least one marker-less comment is human feedback and must be processed normally.
10
+ Classify by the marker, never by `author.login` — under a shared account the loop posts as the PR author, so the login cannot tell echo from human.
@@ -37,4 +37,4 @@ fix(ci): lint — remove unused import
37
37
 
38
38
  - Never post a top-level comment in reply to a line-level comment. It loses thread context.
39
39
  - Never `gh pr review --comment` for replies — that endpoint is for *new* reviews.
40
- - Never reply twice to the same comment. The cursor in `last_seen.json` is the only re-entry guard; advance it after every reply.
40
+ - Never reply twice to the same comment. The loop marker on each posted reply is the re-entry guard — a thread whose newest comment is loop-marked is no longer actionable, so the next round won't re-reply.
@@ -9,7 +9,7 @@ One per watcher iteration (idle or not).
9
9
  "session_slug": "<slug>",
10
10
  "repo": "<owner>/<repo>",
11
11
  "pr_number": <int>,
12
- "reviews_seen": <int>,
12
+ "actionable_threads": <int>,
13
13
  "dispatched_review_ids": [<int>, ...],
14
14
  "checks_red": <int>,
15
15
  "dispatched_ci_fix": true | false,
@@ -19,9 +19,9 @@ One per watcher iteration (idle or not).
19
19
  }
20
20
  ```
21
21
 
22
- - `reviews_seen`: count of new submitted reviews past the cursor, **after** filtering by the escalated set.
23
- - `dispatched_review_ids`: review ids handed to `/muggle-do`. Empty when idle.
22
+ - `actionable_threads`: count of actionable items this tick — unresolved, non-outdated threads whose newest comment is unmarked, plus body-only reviews past `lastBodyReviewId` — **after** filtering by the escalated set.
23
+ - `dispatched_review_ids`: owning review ids handed to `/muggle-do`. Empty when idle.
24
24
  - `checks_red`: count of failing checks on the head SHA. `0` when reviews were dispatched (reviews preempt the CI poll) or CI was green/pending.
25
25
  - `dispatched_ci_fix`: true when this tick dispatched `/muggle-do` with a fix-ci directive.
26
26
  - `terminal`: true when this tick observed the PR merged or closed and wrote `result.md`.
27
- - `idle`: true when no reviews were dispatched this tick.
27
+ - `idle`: true when nothing was dispatched this tick.
@@ -13,16 +13,16 @@ The entry procedure for `/muggle-do`'s **address-reviews** mode — invoked by t
13
13
  `$ARGUMENTS` carries:
14
14
  - PR URL: `<owner>/<repo>#<n>` derivable from the URL.
15
15
  - Session slug: `<slug>`.
16
- - List of review ids: one or more integers.
16
+ - Owning review ids: one or more integers (the reviews whose actionable threads or body-only feedback the watcher flagged).
17
17
 
18
- Exact phrasing comes from the watcher's dispatch (see [`../muggle-pr-followup/contract.md`](../muggle-pr-followup/contract.md#step-5-if-one-or-more-new-reviews-dispatch)). Parse all three out of the directive text.
18
+ Exact phrasing comes from the watcher's dispatch (see [`../muggle-pr-followup/contract.md`](../muggle-pr-followup/contract.md)). Parse all three out of the directive text.
19
19
 
20
20
  ## Inputs from disk
21
21
 
22
22
  Read from `~/.muggle-ai/muggle-do/sessions/<slug>/`:
23
23
 
24
24
  - `prs.json` — to locate the PR's local checkout path (the `repo` field maps to a configured local repo) and capture `head_sha_before`.
25
- - `last_seen.json` — for `pushed_shas[]` (used by the resolve-reminder stage) and to update the cursor.
25
+ - `last_seen.json` — for `pushed_shas[]` (used by the resolve-reminder stage) and to update `lastBodyReviewId`.
26
26
  - `state.md` — for the cached `loop_user` login (used by resolve-reminder thread classification).
27
27
 
28
28
  ## Procedure
@@ -37,10 +37,10 @@ Two sources, combined into one batch (dedupe by comment id):
37
37
 
38
38
  **(a) The dispatched reviews.** For each review id in the input:
39
39
 
40
- - Fetch reviews per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md) (cursor 0; filter to the specific id).
40
+ - Fetch reviews per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md) (no watermark; filter to the specific id).
41
41
  - Fetch its line comments per [`../_shared/github-cli-recipes/line-comments-for-review.md`](../_shared/github-cli-recipes/line-comments-for-review.md).
42
42
 
43
- **(b) Unaddressed comments on every unresolved thread.** Fetch unresolved threads per [`../_shared/github-cli-recipes/unresolved-threads.md`](../_shared/github-cli-recipes/unresolved-threads.md). For each thread classified **unaddressed human comment** — newest comment lacks the loop marker `<!-- muggle-do:bot -->` ([`loop-signature.md`](../_shared/pr-followup-helpers/loop-signature.md)) and post-dates the loop's last marked reply — add it to the batch, even if its review predates the cursor. This is how a human thread follow-up (a marker-less reply) gets addressed. **Exclude** comments whose review id is in `last_seen.escalated_review_ids` — paused awaiting the user, not re-work.
43
+ **(b) Unaddressed comments on every unresolved thread.** Fetch unresolved threads per [`../_shared/github-cli-recipes/unresolved-threads.md`](../_shared/github-cli-recipes/unresolved-threads.md). For each thread classified **unaddressed human comment** — newest comment lacks the loop marker `<!-- muggle-do:bot -->` ([`loop-signature.md`](../_shared/pr-followup-helpers/loop-signature.md)) and post-dates the loop's last marked reply — add it to the batch — unresolved thread state, not any review-id watermark, is the authority here. This is how a human thread follow-up (a marker-less reply) gets addressed. **Exclude** comments whose review id is in `last_seen.escalated_review_ids` — paused awaiting the user, not re-work.
44
44
 
45
45
  Group (a) and (b) into one combined batch.
46
46
 
@@ -101,7 +101,7 @@ Invoke [`per-comment-replies.md`](per-comment-replies.md) with the actionable re
101
101
 
102
102
  - `last_seen.cycles_completed` += 1
103
103
  - `last_seen.last_pushed_sha` = the new head SHA (update.md already wrote this; verify)
104
- - `last_seen.reviewId` = max(input review ids ∪ last_seen.reviewId)
104
+ - `last_seen.lastBodyReviewId` = max(body-only input review ids ∪ last_seen.lastBodyReviewId) — line-comment threads need no watermark; they fall out of the actionable set once the per-comment reply carries the loop marker.
105
105
 
106
106
  ### Step 5.5 — Resolve-reminder (runs every round)
107
107
 
@@ -145,5 +145,5 @@ Do **not** push, do **not** post replies, do **not** run resolve-reminder. The c
145
145
  ## Invariants
146
146
 
147
147
  - One `/muggle-do` invocation = at most one push and one resolve-reminder, regardless of how many reviews are in the batch.
148
- - Every input review id ends up in either the cursor (handled) or `escalated_review_ids` (skipped) — never both, never neither.
148
+ - Every input review id ends up either handled (its thread answered with a loop-marked reply, or — for a body-only review — folded into `lastBodyReviewId`) or in `escalated_review_ids` (skipped) — never both, never neither.
149
149
  - The watcher is respawned exactly when the PR is still open at the end of the cycle.
@@ -46,7 +46,7 @@ Write `~/.muggle-ai/muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-fo
46
46
  [{ "repo": "owner/repo", "number": 142, "url": "...", "head_sha": "...", "state": "open" }]
47
47
  ```
48
48
 
49
- Seed `~/.muggle-ai/muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty cursor shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `reviewId: 0`.
49
+ Seed `~/.muggle-ai/muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty-watermark shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `lastBodyReviewId: 0`.
50
50
 
51
51
  **Do not** seed `cycle.json` or `requirements.md`. The watcher is a dumb pipe; `/muggle-do` reads reviews off GitHub.
52
52
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-feedback
3
- description: Use when the user wants to flag that a generated Muggle Test action script — or one specific step in it — did the wrong thing, and have it captured so Muggle can analyze and regenerate affected scripts. Covers any report that a script or step is wrong, broken, or misbehaving (clicked the wrong element, bad summary, "step N didn't work", "broken at the submit step"), whether the user just ran a test locally or remotely or pastes a Muggle dashboard run/script URL and points at what failed. Also use to view, list, or delete previously submitted feedback. Triggers on '/muggle-feedback', 'give feedback on this run', 'the test was wrong', 'flag this run', 'show/list/delete my feedback'. Auto-detects run context from a recent local run, a remote run, or a dashboard URL in the prompt.
3
+ description: "Use when the user wants to flag that a generated Muggle Test action script — or one specific step in it — did the wrong thing, so Muggle can analyze and regenerate affected scripts. Covers any report that a script or step is wrong, broken, or misbehaving (clicked the wrong element, step N did not work, broken at the submit step), whether from a recent local/remote run or a pasted Muggle dashboard run/script URL. Also lists, views, or deletes previously submitted feedback. Triggers on /muggle-feedback, give feedback on this run, the test was wrong, flag this run."
4
4
  ---
5
5
 
6
6
  # Muggle Test Feedback
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-pr-followup
3
- description: Use this skill when the user wants a pull request's incoming review feedback handled for them — it watches one PR's review thread and, each time a reviewer submits new comments, dispatches the work to address them. Engage on PR-review-follow-up intent: "watch my PR and address review comments as they come in", "keep an eye on PR #123 and respond to reviewer feedback", "follow up on my PR's reviews", "babysit my PR's review thread", "auto-handle reviews on the PR I just opened", "I'm stepping away — handle my PR's reviews while I'm gone". Run with no args to track every PR you pushed this session (any repo); pass a PR URL to start watching a specific one. This is PR-review-specific automation: when the recurring thing the user wants handled is a PR's review comments, use this — not the generic `loop` skill. It only watches and dispatches; the actual edits and replies are `muggle-do`. Not for posting test results to a PR (use muggle-pr-visual-walkthrough).
3
+ description: "Use when the user wants a pull request's incoming review feedback handled for them — it watches one PR's review thread and, each time a reviewer submits new comments, dispatches the work to address them. Engage on PR-review-follow-up intent: \"watch my PR and address review comments as they come in\", \"keep an eye on PR #123 and respond to reviewer feedback\", \"babysit my PR's review thread\", \"I'm stepping away — handle my PR's reviews while I'm gone\". This is PR-review-specific automation — prefer it over the generic loop skill. It only watches and dispatches; the actual edits and replies are muggle-do. Not for posting test results to a PR (use muggle-pr-visual-walkthrough)."
4
4
  ---
5
5
 
6
6
  # muggle-pr-followup
@@ -34,7 +34,7 @@ Bootstrap accepts three optional trailing flags:
34
34
 
35
35
  - `--slug=<name>` — override the default `<repo>-pr<n>` slug
36
36
  - `--resume` — opt in to reusing an existing session slot (default is refuse on conflict)
37
- - `--forward-only` — pin cursor past existing reviews (skip history). Default is cursor 0, which processes prior submitted reviews on the first tick.
37
+ - `--forward-only` — pin `lastBodyReviewId` past existing **body-only** reviews (skip history on those). Line-comment threads are always picked up from live thread state, regardless of this flag.
38
38
 
39
39
  ## Preferences
40
40
 
@@ -51,7 +51,7 @@ For each PR URL in the track list, run the [`bootstrap.md`](bootstrap.md) proced
51
51
  - **Existing slot → skip silently** (never the slot-conflict abort); add it to the *skipped* list.
52
52
  - **`caller = "auto-track"`** in the bootstrap telemetry event.
53
53
 
54
- Everything else is unchanged: URL parse, metadata + terminal-PR abort, slug, cursor 0 (process prior reviews on the first tick), and the `prs.json`/`last_seen.json`/`state.md` writes minus the pre-flight block.
54
+ Everything else is unchanged: URL parse, metadata + terminal-PR abort, slug, `lastBodyReviewId` 0 (line-comment threads are picked up live from thread state; body-only reviews from id 0), and the `prs.json`/`last_seen.json`/`state.md` writes minus the pre-flight block.
55
55
 
56
56
  ### Step 5 — Print the summary
57
57