@muggleai/works 5.0.4 → 5.1.0

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 (130) hide show
  1. package/README.md +2 -3
  2. package/dist/{chunk-XO5BQZM3.js → chunk-2BHC6TQR.js} +3 -4
  3. package/dist/{chunk-KDRSEHK5.js → chunk-MOHR7QUN.js} +197 -291
  4. package/dist/cli.js +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  7. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  8. package/dist/plugin/scripts/ensure-electron-app.sh +1 -1
  9. package/dist/plugin/scripts/guardrails.mjs +4 -2
  10. package/dist/plugin/skills/_shared/dev-loop/publish.md +4 -8
  11. package/dist/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
  12. package/dist/plugin/skills/_shared/pr-followup-helpers/echo-skip.md +1 -1
  13. package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  14. package/dist/plugin/skills/_shared/test-case-chain-readiness.md +1 -2
  15. package/dist/plugin/skills/_shared/vcs/CLAUDE.md +9 -0
  16. package/dist/plugin/skills/_shared/vcs/detect-vcs.md +28 -0
  17. package/{plugin/skills/_shared/github-cli-recipes → dist/plugin/skills/_shared/vcs/github}/unresolved-threads.md +1 -1
  18. package/{plugin/skills/_shared/github-cli-recipes → dist/plugin/skills/_shared/vcs/github}/verify-working-tree.md +1 -1
  19. package/dist/plugin/skills/_shared/vcs/github.md +21 -0
  20. package/dist/plugin/skills/_shared/vcs/gitlab/loop-user-identity.md +9 -0
  21. package/dist/plugin/skills/_shared/vcs/gitlab/mr-create.md +11 -0
  22. package/dist/plugin/skills/_shared/vcs/gitlab/mr-discussions.md +18 -0
  23. package/dist/plugin/skills/_shared/vcs/gitlab/mr-edit.md +8 -0
  24. package/dist/plugin/skills/_shared/vcs/gitlab/mr-metadata.md +22 -0
  25. package/dist/plugin/skills/_shared/vcs/gitlab/mr-note.md +7 -0
  26. package/dist/plugin/skills/_shared/vcs/gitlab/mr-pipeline.md +27 -0
  27. package/dist/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +9 -0
  28. package/dist/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +10 -0
  29. package/dist/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +18 -0
  30. package/dist/plugin/skills/_shared/vcs/gitlab.md +24 -0
  31. package/dist/plugin/skills/do/address-reviews.md +10 -6
  32. package/dist/plugin/skills/do/e2e-acceptance.md +4 -4
  33. package/dist/plugin/skills/do/fix-ci.md +1 -1
  34. package/dist/plugin/skills/do/input-routing.md +4 -4
  35. package/dist/plugin/skills/do/open-prs/forward.md +6 -4
  36. package/dist/plugin/skills/do/open-prs/update.md +8 -6
  37. package/dist/plugin/skills/do/per-comment-replies.md +22 -13
  38. package/dist/plugin/skills/do/resolve-conflicts.md +1 -1
  39. package/dist/plugin/skills/do/resolve-reminder.md +8 -6
  40. package/dist/plugin/skills/muggle-browser-task/SKILL.md +1 -1
  41. package/dist/plugin/skills/muggle-do/SKILL.md +2 -2
  42. package/dist/plugin/skills/muggle-feedback/ops/submit.md +4 -4
  43. package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -2
  44. package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +13 -11
  45. package/dist/plugin/skills/muggle-pr-followup/contract.md +13 -9
  46. package/dist/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  47. package/dist/plugin/skills/muggle-pr-followup/reconcile.md +1 -1
  48. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +4 -1
  49. package/dist/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +13 -13
  50. package/dist/plugin/skills/muggle-preferences/ops/configure.md +2 -2
  51. package/dist/plugin/skills/muggle-test/SKILL.md +23 -126
  52. package/dist/plugin/skills/muggle-test/execute-local.md +60 -0
  53. package/dist/plugin/skills/muggle-test/execute-remote.md +49 -0
  54. package/dist/plugin/skills/muggle-test/reference.md +1 -2
  55. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +5 -5
  56. package/dist/release-manifest.json +4 -4
  57. package/dist/{src-2O5UH4FA.js → src-SS2AL3O7.js} +1 -1
  58. package/package.json +6 -6
  59. package/plugin/.claude-plugin/plugin.json +1 -1
  60. package/plugin/.cursor-plugin/plugin.json +1 -1
  61. package/plugin/scripts/ensure-electron-app.sh +1 -1
  62. package/plugin/scripts/guardrails.mjs +4 -2
  63. package/plugin/skills/_shared/dev-loop/publish.md +4 -8
  64. package/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
  65. package/plugin/skills/_shared/pr-followup-helpers/echo-skip.md +1 -1
  66. package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  67. package/plugin/skills/_shared/test-case-chain-readiness.md +1 -2
  68. package/plugin/skills/_shared/vcs/CLAUDE.md +9 -0
  69. package/plugin/skills/_shared/vcs/detect-vcs.md +28 -0
  70. package/{dist/plugin/skills/_shared/github-cli-recipes → plugin/skills/_shared/vcs/github}/unresolved-threads.md +1 -1
  71. package/{dist/plugin/skills/_shared/github-cli-recipes → plugin/skills/_shared/vcs/github}/verify-working-tree.md +1 -1
  72. package/plugin/skills/_shared/vcs/github.md +21 -0
  73. package/plugin/skills/_shared/vcs/gitlab/loop-user-identity.md +9 -0
  74. package/plugin/skills/_shared/vcs/gitlab/mr-create.md +11 -0
  75. package/plugin/skills/_shared/vcs/gitlab/mr-discussions.md +18 -0
  76. package/plugin/skills/_shared/vcs/gitlab/mr-edit.md +8 -0
  77. package/plugin/skills/_shared/vcs/gitlab/mr-metadata.md +22 -0
  78. package/plugin/skills/_shared/vcs/gitlab/mr-note.md +7 -0
  79. package/plugin/skills/_shared/vcs/gitlab/mr-pipeline.md +27 -0
  80. package/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +9 -0
  81. package/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +10 -0
  82. package/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +18 -0
  83. package/plugin/skills/_shared/vcs/gitlab.md +24 -0
  84. package/plugin/skills/do/address-reviews.md +10 -6
  85. package/plugin/skills/do/e2e-acceptance.md +4 -4
  86. package/plugin/skills/do/fix-ci.md +1 -1
  87. package/plugin/skills/do/input-routing.md +4 -4
  88. package/plugin/skills/do/open-prs/forward.md +6 -4
  89. package/plugin/skills/do/open-prs/update.md +8 -6
  90. package/plugin/skills/do/per-comment-replies.md +22 -13
  91. package/plugin/skills/do/resolve-conflicts.md +1 -1
  92. package/plugin/skills/do/resolve-reminder.md +8 -6
  93. package/plugin/skills/muggle-browser-task/SKILL.md +1 -1
  94. package/plugin/skills/muggle-do/SKILL.md +2 -2
  95. package/plugin/skills/muggle-feedback/ops/submit.md +4 -4
  96. package/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -2
  97. package/plugin/skills/muggle-pr-followup/bootstrap.md +13 -11
  98. package/plugin/skills/muggle-pr-followup/contract.md +13 -9
  99. package/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  100. package/plugin/skills/muggle-pr-followup/reconcile.md +1 -1
  101. package/plugin/skills/muggle-pr-followup/state-schemas.md +4 -1
  102. package/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +13 -13
  103. package/plugin/skills/muggle-preferences/ops/configure.md +2 -2
  104. package/plugin/skills/muggle-test/SKILL.md +23 -126
  105. package/plugin/skills/muggle-test/execute-local.md +60 -0
  106. package/plugin/skills/muggle-test/execute-remote.md +49 -0
  107. package/plugin/skills/muggle-test/reference.md +1 -2
  108. package/plugin/skills/muggle-test-feature-local/SKILL.md +5 -5
  109. package/dist/plugin/skills/_shared/github-cli-recipes.md +0 -21
  110. package/dist/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +0 -11
  111. package/plugin/skills/_shared/github-cli-recipes.md +0 -21
  112. package/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +0 -11
  113. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/line-comments-for-review.md +0 -0
  114. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/loop-user-identity.md +0 -0
  115. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-checks.md +0 -0
  116. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-edit.md +0 -0
  117. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-metadata.md +0 -0
  118. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/push-to-branch.md +0 -0
  119. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/reply-line-comment.md +0 -0
  120. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/submitted-reviews.md +0 -0
  121. /package/dist/plugin/skills/_shared/{github-cli-recipes → vcs/github}/top-level-comment.md +0 -0
  122. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/line-comments-for-review.md +0 -0
  123. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/loop-user-identity.md +0 -0
  124. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-checks.md +0 -0
  125. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-edit.md +0 -0
  126. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/pr-metadata.md +0 -0
  127. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/push-to-branch.md +0 -0
  128. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/reply-line-comment.md +0 -0
  129. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/submitted-reviews.md +0 -0
  130. /package/plugin/skills/_shared/{github-cli-recipes → vcs/github}/top-level-comment.md +0 -0
@@ -7,7 +7,7 @@ description: "Change-driven E2E acceptance testing with Muggle AI: detect the us
7
7
 
8
8
  > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-test"`.
9
9
 
10
- A router skill that detects code changes, resolves impacted test cases, executes them locally or remotely, publishes results to the Muggle AI dashboard, and posts E2E acceptance summaries to the PR. The user can invoke this at any moment, in any state.
10
+ A router skill that detects code changes, resolves impacted test cases, executes them locally or remotely, reads the cloud results from the Muggle AI dashboard (local runs are published by the studio during execution; remote runs publish cloud-side), and posts E2E acceptance summaries to the PR. The user can invoke this at any moment, in any state.
11
11
 
12
12
  ## UX Guidelines — Minimize Typing
13
13
 
@@ -42,11 +42,10 @@ Gates run per `preference-gates/README.md`.
42
42
  |------------|------|-------------------|
43
43
  | `autoLogin` | 3 | Reuse saved credentials when auth is required |
44
44
  | `autoSelectProject` | 4 | Reuse last-used Muggle Test project for this repo |
45
- | `autoSelectLocalHost` | 7A | Reuse last-used local dev server URL for this repo |
45
+ | `autoSelectLocalHost` | execute-local | Reuse last-used local dev server URL for this repo |
46
46
  | `autoDetectChanges` | 2 | Scan local git changes and map to affected test cases |
47
47
  | `defaultExecutionMode` | 1 | Default to local or remote test execution |
48
- | `autoPublishLocalResults` | 7A | Upload local results to Muggle Test cloud after run |
49
- | `showElectronBrowser` | 7A | Show the Electron browser window during local test execution (vs. run headless) |
48
+ | `showElectronBrowser` | execute-local | Show the Electron browser window during local test execution (vs. run headless) |
50
49
  | `postPRVisualWalkthrough` | 9 | Post visual walkthrough to PR after results are available |
51
50
  | `autoCreatePR` | 9 (if no PR) | Auto-create the PR when posting the walkthrough has no PR to target |
52
51
  | `autoWatchPR` | 9.5 (if a PR exists) | Start a `muggle-pr-followup` watcher on the PR after the run |
@@ -235,139 +234,37 @@ Then show the per-case decision in one `AskUserQuestion`:
235
234
 
236
235
  If the user picks "Override one or more", let them flip the mode for any test case via a second multi-select `AskUserQuestion`. Emit a follow-up `pre-execution-classification` event with `userAction` set whenever the user overrides.
237
236
 
238
- ## Step 7A: Execute — Local Mode
237
+ ## Step 7: Execute
239
238
 
240
- ### Local environment readiness
239
+ ### Fetch test case details (both modes)
241
240
 
242
- Before anything else, invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md) — the readiness/service-start owner (idempotent; halt on what it surfaces). The URL gate below only *selects* the target; prepare is what guarantees something is listening and compiled.
241
+ Hydrate every selected test case **once**, before dispatch: issue **all** `muggle-remote-test-case-get` calls in parallel (single message, multiple tool calls). Both paths consume the result — never re-fetch inside a path.
243
242
 
244
- ### Pre-flight question — Local URL (gated by `autoSelectLocalHost`)
243
+ ### Dispatch by mode
245
244
 
246
- Skill responsibilities (the rest is in `preference-gates/autoSelectLocalHost.md`):
247
- - **Read the cache**: `Muggle Test Last Host: <url>` session-context line, or `muggle-local-last-host-get`. Pass as `{lastHost}` substitution.
248
- - **Auto-detect a suggested URL**: `lsof -iTCP -sTCP:LISTEN -nP | grep -E ':(3000|3001|4200|5173|8080)'`. Pass as `{suggestedHost}`.
249
- - **Save the cache**: call `muggle-local-last-host-set` after the user picks (the gate file requires this on every pick).
245
+ Run the path matching the mode confirmed in Step 1. Each path owns its own process and returns a **uniform runs list** — `[{ testCaseId, mode, runId | runtimeId, status, viewUrl? }]` — that Steps 7C–10 consume mode-agnostically.
250
246
 
251
- Gate `autoSelectLocalHost` per `preference-gates/README.md` + `preference-gates/autoSelectLocalHost.md`.
252
-
253
- ### Pre-flight visibility (gated by `showElectronBrowser`)
254
-
255
- Gate `showElectronBrowser` (per `preference-gates/README.md`). Resolve once; apply same `showUi` to every test case.
256
- - `always` → omit `showUi` (defaults visible).
257
- - `never` → pass `showUi: false`.
258
- - `ask` → run Picker 1 from `preference-gates/showElectronBrowser.md` via `AskUserQuestion`; map the answer back to one of the actions above.
259
-
260
- ### Fetch test case details (in parallel)
261
-
262
- Before execution, fetch full test case details for all selected test cases by issuing **all** `muggle-remote-test-case-get` calls in parallel (single message, multiple tool calls).
263
-
264
- ### Run the dev loop
265
-
266
- Execute each selected test case via the shared loop in [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md): [sequential replay/regen](../_shared/dev-loop/run.md), [`actionScript` as-is](../_shared/dev-loop/action-script.md), [`freshSession`](../_shared/dev-loop/fresh-session.md), and [`timeoutMs`](../_shared/dev-loop/timeouts.md).
267
-
268
- Caller glue:
269
- - `mode` per test case comes from Step 6f; `localUrl` from the pre-flight question; `showUi` from the `showElectronBrowser` resolution.
270
- - `cwd` = the PR-branch worktree from Step 2 if one was created, else the user's repo root — it drives the cross-worktree single-flight lock so concurrent muggle-test runs from different branches serialize.
271
- - On a failed run, continue the batch and route it through Step 7C after completion.
272
-
273
- ### Collect results
274
-
275
- Fetch every `runId` per [`../_shared/dev-loop/failures.md`](../_shared/dev-loop/failures.md), reading structured fields and [interpreting failures](../_shared/dev-loop/failures.md) — never `execute`'s stdout tail. Issue the `muggle-local-run-result-get` calls in parallel; use `Error` as the headline for failures and route through Step 7C.
276
-
277
- ### Publish each run to cloud (gated by `autoPublishLocalResults`)
278
-
279
- Gate `autoPublishLocalResults` (per `preference-gates/README.md`):
280
- - `always` → proceed to publish logic below.
281
- - `never` → skip to report summary; tell user Steps 8/9 and per-step screenshots are unavailable without publishing.
282
- - `ask` → run Picker 1 from `preference-gates/autoPublishLocalResults.md` via `AskUserQuestion`; map the answer back to one of the actions above.
283
-
284
- ### Publish logic (when publishing is enabled)
285
-
286
- Publish every completed run per [`../_shared/dev-loop/publish.md`](../_shared/dev-loop/publish.md) — parallel `muggle-local-publish-test-script` with the zero-step `muggle-remote-local-run-upload` fallback. Store every `viewUrl`, `testScriptId`, `actionScriptId` — used in the next steps.
287
-
288
- ### Report summary
289
-
290
- ```
291
- Test Case Status Duration Steps View Steps on Muggle AI
292
- ─────────────────────────────────────────────────────────────────────────
293
- Login with valid creds PASSED 12.3s 8 https://www.muggle-ai.com/...
294
- Login with invalid creds PASSED 9.1s 6 https://www.muggle-ai.com/...
295
- Checkout flow FAILED 15.7s 12 https://www.muggle-ai.com/...
296
- ─────────────────────────────────────────────────────────────────────────
297
- Total: 3 tests | 2 passed | 1 failed | 37.1s
298
- ```
299
-
300
- For failures, don't hand-write a verdict in the summary — route each through the debug path (Step 7C).
301
-
302
- ## Step 7B: Execute — Remote Mode
303
-
304
- ### Ask for target URL
305
-
306
- > "What's the preview/staging URL to test against?"
307
-
308
- ### Fetch test case details (in parallel)
309
-
310
- Issue all `muggle-remote-test-case-get` calls in parallel (single message, multiple tool calls) to hydrate the test case bodies.
311
-
312
- ### Trigger remote workflows (in parallel)
313
-
314
- Branch each test case on the mode chosen in Step 6f, then issue **all** workflow-start calls in parallel — never loop them sequentially. Mix regen and replay starts in the same parallel batch.
315
-
316
- **Regen-mode test case** — `muggle-remote-workflow-start-test-script-generation`:
317
-
318
- - `projectId`: The project ID
319
- - `useCaseId`: The use case ID
320
- - `testCaseId`: The test case ID
321
- - `name`: `"muggle-test: {test case title}"`
322
- - `url`: The preview/staging URL
323
- - `goal`: From the test case
324
- - `precondition`: From the test case (use `"None"` if empty)
325
- - `instructions`: From the test case
326
- - `expectedResult`: From the test case
327
-
328
- **Replay-mode test case** — `muggle-remote-workflow-start-test-script-replay` against the latest replayable script for that test case (resolve via `muggle-remote-test-script-list` if not already in hand from Step 6f). Tag results with `mode: "replay"` so Step 7C can route failures correctly.
329
-
330
- Store each returned workflow runtime ID along with its mode tag.
331
-
332
- ### Monitor and report (in parallel)
333
-
334
- Issue all `muggle-remote-wf-get-ts-gen-latest-run` calls in parallel, one per runtime ID.
335
-
336
- ```
337
- Test Case Workflow Status Runtime ID
338
- ────────────────────────────────────────────────────────
339
- Login with valid creds RUNNING rt-abc123
340
- Login with invalid creds COMPLETED rt-def456
341
- Checkout flow QUEUED rt-ghi789
342
- ```
247
+ - **Mode A (Local)** → [`execute-local.md`](execute-local.md). Inputs: the hydrated test cases, per-case `mode` from Step 6f, and `cwd` (the PR-branch worktree from Step 2 if one exists, else the repo root).
248
+ - **Mode B (Remote)** → [`execute-remote.md`](execute-remote.md). Inputs: the hydrated test cases, per-case `mode` from Step 6f, `projectId` / `useCaseId`.
343
249
 
344
250
  ## Step 7C: Route every failed run through the debug path
345
251
 
346
- For every run with `status: "failed"` (or any non-passing terminal state) from 7A or 7B, route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md). This is **mandatory** — a failure is never reported without it. The debug path gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always an option and "skip" is never the default.
252
+ For every run with `status: "failed"` (or any non-passing terminal state) returned by Step 7 (either path), route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md). This is **mandatory** — a failure is never reported without it. The debug path gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always an option and "skip" is never the default.
347
253
 
348
- Pass it per failed run: the `runId` (local) or workflow runtime id (remote), the `mode` that failed, `testCaseId`, `projectId`, and the execution handle (local: the dev loop from "Run the dev loop"; remote: 7B's workflow-start) so a rerun re-enters the same path. Process failures one at a time so the user isn't drowning in pickers.
254
+ Pass it per failed run: the `runId` (local) or workflow runtime id (remote), the `mode` that failed, `testCaseId`, `projectId`, and the execution handle (local: [`execute-local.md`](execute-local.md); remote: [`execute-remote.md`](execute-remote.md)) so a rerun re-enters the same path. Process failures one at a time so the user isn't drowning in pickers.
349
255
 
350
256
  ## Step 8: Open Results in Browser
351
257
 
352
- After execution and publishing are complete, open the Muggle AI dashboard so the user can visually inspect results and screenshots.
353
-
354
- ### Mode A (Local) — open each published viewUrl
355
-
356
- For each published run's `viewUrl`:
357
- ```bash
358
- open "https://www.muggle-ai.com/muggleTestV0/dashboard/projects/{projectId}/scripts?modal=script-details&testCaseId={testCaseId}"
359
- ```
360
-
361
- If there are many runs (>3), open just the project-level runs page instead of individual tabs:
362
- ```bash
363
- open "https://www.muggle-ai.com/muggleTestV0/dashboard/projects/{projectId}/runs"
364
- ```
365
-
366
- ### Mode B (Remote) — open the project runs page
258
+ After execution, open the Muggle AI dashboard so the user can inspect results and screenshots. The studio published every local run during execution, so each run result already carries its `viewUrl` (read it from `muggle-local-run-result-get`). Key off the uniform runs list:
367
259
 
368
- ```bash
369
- open "https://www.muggle-ai.com/muggleTestV0/dashboard/projects/{projectId}/runs"
370
- ```
260
+ - **Runs carry a `viewUrl` and there are ≤3** — open each:
261
+ ```bash
262
+ open "https://www.muggle-ai.com/muggleTestV0/dashboard/projects/{projectId}/scripts?modal=script-details&testCaseId={testCaseId}"
263
+ ```
264
+ - **Otherwise** (more than 3 runs, or a run with no `viewUrl`) — open the project runs page:
265
+ ```bash
266
+ open "https://www.muggle-ai.com/muggleTestV0/dashboard/projects/{projectId}/runs"
267
+ ```
371
268
 
372
269
  Tell the user:
373
270
  > "I've opened the Muggle AI dashboard in your browser — you can see the test results, step-by-step screenshots, and action scripts there."
@@ -379,7 +276,7 @@ After reporting results:
379
276
  1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → Step 9.5.
380
277
  2. `gh pr view --json number,title,url 2>/dev/null` — find the PR.
381
278
  3. If no PR: fire [`autoCreatePR`](../muggle-preferences/preference-gates/autoCreatePR.md). On skip → Step 9.5.
382
- 4. Assemble the `E2eReport` — see [`../muggle-pr-visual-walkthrough/e2e-report-assembly.md`](../muggle-pr-visual-walkthrough/e2e-report-assembly.md). Include all runs from Step 7A (passed and failed).
279
+ 4. Assemble the `E2eReport` — see [`../muggle-pr-visual-walkthrough/e2e-report-assembly.md`](../muggle-pr-visual-walkthrough/e2e-report-assembly.md). Include all runs from Step 7 (passed and failed).
383
280
  5. Invoke [`../muggle-pr-visual-walkthrough/SKILL.md`](../muggle-pr-visual-walkthrough/SKILL.md) Mode A with the `E2eReport`.
384
281
 
385
282
  ## Step 9.5: Offer to watch the PR for review follow-ups
@@ -414,6 +311,6 @@ Each rule below is covered in-step above; these are the ones this skill most oft
414
311
  - **PR URLs run in a dedicated worktree** — never switch the user's main checkout; pass that worktree as `cwd`.
415
312
  - **Every selection uses `AskUserQuestion`** — never ask the user to type a number; the user picks the project (never auto-select).
416
313
  - **Parallelize independent cloud jobs**; the only sequential loop is local Electron execution (one browser).
417
- - **Publish before opening the browser**, and delegate PR posting to `muggle-pr-visual-walkthrough` — never inline the walkthrough or call `gh pr comment` here.
314
+ - **Read cloud refs off the run result** (the studio published during execution) and delegate PR posting to `muggle-pr-visual-walkthrough` — never inline the walkthrough or call `gh pr comment` here.
418
315
 
419
316
  Phase→tool map and multi-agent (acceptance-tester) dispatch: [`reference.md`](reference.md).
@@ -0,0 +1,60 @@
1
+ # Muggle Test — Local Execution Path (Mode A)
2
+
3
+ > The Local execution process for the `muggle-test` router: run the selected test cases against localhost via the Electron browser and collect results. The studio publishes each run to the cloud during execution, so the run result already carries the cloud refs. Returns a uniform runs list to the router. Per-test-case mechanics are shared with [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md).
4
+
5
+ ## Inputs (the router passes these in)
6
+
7
+ - The hydrated test cases (fetched once by the router before dispatch).
8
+ - Per-case `mode` — `replay` or `regen`, chosen during replay-vs-regen classification.
9
+ - `cwd` — the PR-branch worktree if one exists, else the repo root.
10
+
11
+ ## Local environment readiness
12
+
13
+ Before anything else, invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md) — the readiness/service-start owner (idempotent; halt on what it surfaces). The URL gate below only *selects* the target; prepare is what guarantees something is listening and compiled.
14
+
15
+ ## Pre-flight question — Local URL (gated by `autoSelectLocalHost`)
16
+
17
+ Skill responsibilities (the rest is in `preference-gates/autoSelectLocalHost.md`):
18
+ - **Read the cache**: `Muggle Test Last Host: <url>` session-context line, or `muggle-local-last-host-get`. Pass as `{lastHost}` substitution.
19
+ - **Auto-detect a suggested URL**: `lsof -iTCP -sTCP:LISTEN -nP | grep -E ':(3000|3001|4200|5173|8080)'`. Pass as `{suggestedHost}`.
20
+ - **Save the cache**: call `muggle-local-last-host-set` after the user picks (the gate file requires this on every pick).
21
+
22
+ Gate `autoSelectLocalHost` per `preference-gates/README.md` + `preference-gates/autoSelectLocalHost.md`.
23
+
24
+ ## Pre-flight visibility (gated by `showElectronBrowser`)
25
+
26
+ Gate `showElectronBrowser` (per `preference-gates/README.md`). Resolve once; apply same `showUi` to every test case.
27
+ - `always` → omit `showUi` (defaults visible).
28
+ - `never` → pass `showUi: false`.
29
+ - `ask` → run Picker 1 from `preference-gates/showElectronBrowser.md` via `AskUserQuestion`; map the answer back to one of the actions above.
30
+
31
+ ## Run the dev loop
32
+
33
+ Execute each test case via the shared loop in [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md): [sequential replay/regen](../_shared/dev-loop/run.md), [`actionScript` as-is](../_shared/dev-loop/action-script.md), [`freshSession`](../_shared/dev-loop/fresh-session.md), and [`timeoutMs`](../_shared/dev-loop/timeouts.md).
34
+
35
+ Caller glue:
36
+ - `mode` per test case is the input from the router; `localUrl` from the pre-flight question; `showUi` from the `showElectronBrowser` resolution.
37
+ - `cwd` is the input from the router — it drives the cross-worktree single-flight lock so concurrent muggle-test runs from different branches serialize.
38
+ - On a failed run, continue the batch; the router routes failures through the debug path after this path returns.
39
+
40
+ ## Collect results
41
+
42
+ Fetch every `runId` per [`../_shared/dev-loop/failures.md`](../_shared/dev-loop/failures.md), reading structured fields and [interpreting failures](../_shared/dev-loop/failures.md) — never `execute`'s stdout tail. Issue the `muggle-local-run-result-get` calls in parallel; use `Error` as the headline for failures. The studio already published each run, so the same call surfaces `viewUrl` / `cloudTestScriptId` / `cloudActionScriptId` — retain them per [`../_shared/dev-loop/publish.md`](../_shared/dev-loop/publish.md) for the dashboard and walkthrough.
43
+
44
+ ## Report summary
45
+
46
+ ```
47
+ Test Case Status Duration Steps View Steps on Muggle AI
48
+ ─────────────────────────────────────────────────────────────────────────
49
+ Login with valid creds PASSED 12.3s 8 https://www.muggle-ai.com/...
50
+ Login with invalid creds PASSED 9.1s 6 https://www.muggle-ai.com/...
51
+ Checkout flow FAILED 15.7s 12 https://www.muggle-ai.com/...
52
+ ─────────────────────────────────────────────────────────────────────────
53
+ Total: 3 tests | 2 passed | 1 failed | 37.1s
54
+ ```
55
+
56
+ For failures, don't hand-write a verdict — the router routes each through the debug path.
57
+
58
+ ## Output
59
+
60
+ Return the uniform runs list the router consumes: `[{ testCaseId, mode, runId, status, viewUrl?, cloudTestScriptId?, cloudActionScriptId? }]`. The studio published each run during execution, so `viewUrl` / `cloudTestScriptId` / `cloudActionScriptId` come straight off the run result (`muggle-local-run-result-get`).
@@ -0,0 +1,49 @@
1
+ # Muggle Test — Remote Execution Path (Mode B)
2
+
3
+ > The Remote execution process for the `muggle-test` router: trigger cloud test-script generation/replay against a preview/staging URL and monitor. Returns a uniform runs list to the router.
4
+
5
+ ## Inputs (the router passes these in)
6
+
7
+ - The hydrated test cases (fetched once by the router before dispatch).
8
+ - Per-case `mode` — `replay` or `regen`, chosen during replay-vs-regen classification.
9
+ - `projectId`, `useCaseId`.
10
+
11
+ ## Ask for target URL
12
+
13
+ > "What's the preview/staging URL to test against?"
14
+
15
+ ## Trigger remote workflows (in parallel)
16
+
17
+ Branch each test case on its `mode`, then issue **all** workflow-start calls in parallel — never loop them sequentially. Mix regen and replay starts in the same parallel batch.
18
+
19
+ **Regen-mode test case** — `muggle-remote-workflow-start-test-script-generation`:
20
+
21
+ - `projectId`: The project ID
22
+ - `useCaseId`: The use case ID
23
+ - `testCaseId`: The test case ID
24
+ - `name`: `"muggle-test: {test case title}"`
25
+ - `url`: The preview/staging URL
26
+ - `goal`: From the test case
27
+ - `precondition`: From the test case (use `"None"` if empty)
28
+ - `instructions`: From the test case
29
+ - `expectedResult`: From the test case
30
+
31
+ **Replay-mode test case** — `muggle-remote-workflow-start-test-script-replay` against the latest replayable script for that test case (resolve via `muggle-remote-test-script-list` if not already in hand from the classification step). Tag results with `mode: "replay"` so the router routes failures correctly.
32
+
33
+ Store each returned workflow runtime ID along with its mode tag.
34
+
35
+ ## Monitor and report (in parallel)
36
+
37
+ Issue all `muggle-remote-wf-get-ts-gen-latest-run` calls in parallel, one per runtime ID.
38
+
39
+ ```
40
+ Test Case Workflow Status Runtime ID
41
+ ────────────────────────────────────────────────────────
42
+ Login with valid creds RUNNING rt-abc123
43
+ Login with invalid creds COMPLETED rt-def456
44
+ Checkout flow QUEUED rt-ghi789
45
+ ```
46
+
47
+ ## Output
48
+
49
+ Return the uniform runs list the router consumes: `[{ testCaseId, mode, runtimeId, status }]`.
@@ -23,9 +23,8 @@ Lookup material pulled out of `SKILL.md` to keep the always-loaded body lean. Ev
23
23
  | Execute (regen) | `muggle-remote-workflow-start-test-script-generation` | Remote |
24
24
  | Execute (replay) | `muggle-remote-workflow-start-test-script-replay` | Remote |
25
25
  | Failure-mode telemetry | `muggle-local-telemetry-event-emit` | Both |
26
- | Results | `muggle-local-run-result-get` | Local |
26
+ | Results + cloud refs (studio-published `viewUrl` / `cloudTestScriptId` / `cloudActionScriptId`) | `muggle-local-run-result-get` | Local |
27
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
28
  | Per-step screenshots (for walkthrough) | `muggle-remote-test-script-get` | Both |
30
29
  | Browser | `open` (shell command) | Both |
31
30
  | PR walkthrough | `muggle-pr-visual-walkthrough` (shared skill) | Both |
@@ -12,7 +12,7 @@ description: Run a real-browser end-to-end (E2E) acceptance test against localho
12
12
  | Scope | MCP tools |
13
13
  | :---- | :-------- |
14
14
  | Cloud (projects, cases, scripts, auth) | `muggle-remote-*` |
15
- | Local (Electron run, publish, results) | `muggle-local-*` |
15
+ | Local (Electron run, results — the studio publishes during the run) | `muggle-local-*` |
16
16
  | Create new entities (preview / create) | `muggle-remote-project-create`, `muggle-remote-use-case-prompt-preview`, `muggle-remote-use-case-create-from-prompts`, `muggle-remote-test-case-generate-from-prompt`, `muggle-remote-test-case-create` |
17
17
 
18
18
  The local URL only changes where the browser opens; it does not change the remote project or test definitions.
@@ -158,11 +158,11 @@ Gate `showElectronBrowser` (per `preference-gates/README.md`). Reuse the choice
158
158
 
159
159
  `showUi` is only ever omitted or `false` — never pass `showUi: true`.
160
160
 
161
- ### 8. Upload run to cloud (every completed run; open `viewUrl` gated by `openTestResultsAfterRun`)
161
+ ### 8. Open the run on the dashboard (`viewUrl` gated by `openTestResultsAfterRun`)
162
162
 
163
- Upload pass-or-fail. Failed runs still need cloud-hosted screenshots and per-step actions for the PR walkthrough — without them reviewers see only a generic "failed" link. The `status` field in the upload payload tells the backend whether to promote the run's action script as the test case's canonical replay script (passed → promote; failed → record only).
163
+ The studio publishes every completed run — pass or fail — to the cloud during execution, so the run result already carries the cloud refs. Failed runs are published too, so reviewers get the per-step screenshots, not just a generic "failed" link.
164
164
 
165
- - Publish per [`../_shared/dev-loop/publish.md`](../_shared/dev-loop/publish.md) — includes the zero-step `muggle-remote-local-run-upload` fallback.
165
+ - Read the cloud refs per [`../_shared/dev-loop/publish.md`](../_shared/dev-loop/publish.md): `viewUrl` / `cloudTestScriptId` / `cloudActionScriptId` from `muggle-local-run-result-get`.
166
166
  - Gate `openTestResultsAfterRun` (per `preference-gates/README.md`):
167
167
  - `always` → open `viewUrl` automatically (`open "<viewUrl>"` on macOS or OS equivalent).
168
168
  - `never` → print the URL only.
@@ -172,7 +172,7 @@ Upload pass-or-fail. Failed runs still need cloud-hosted screenshots and per-ste
172
172
 
173
173
  Read the run record per [`../_shared/dev-loop/failures.md`](../_shared/dev-loop/failures.md) and [failure interpretation](../_shared/dev-loop/failures.md) — never diagnose from `execute`'s stdout tail.
174
174
 
175
- - Include in the report: status, duration, pass/fail summary, per-step summary (passed runs), artifact paths, errors if failed, and script view URL when publishing ran.
175
+ - Include in the report: status, duration, pass/fail summary, per-step summary (passed runs), artifact paths, errors if failed, and the `viewUrl` from the run result.
176
176
 
177
177
  ### 9a. Route a failed run through the debug path
178
178
 
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "5.0.4",
3
- "buildId": "run-52-1",
4
- "commitSha": "d27f03da1295aa4e58c8e2ba6a26a0e76c7700c9",
5
- "buildTime": "2026-06-09T21:46:24Z",
2
+ "release": "5.1.0",
3
+ "buildId": "run-53-1",
4
+ "commitSha": "3a0e7525c2c606afb9a64c2d78baffa5b400cf50",
5
+ "buildTime": "2026-06-11T20:57: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-KDRSEHK5.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-MOHR7QUN.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.4",
4
+ "version": "5.1.0",
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.2.3",
44
+ "electronAppVersion": "1.4.0",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "f46cfc5f052021f13de7d7721276d58863b958ec717631e98b97b7cd3d0fe4fa",
49
- "darwin-x64": "e2254373a0bb3fffa46b236629c5d54a611ab05e138104a98f6f60a5d1280805",
50
- "linux-x64": "ff5698fdbc1d65f436b75d860ebe50ee7171c7726565fa0ab2149a6f1cde4d13",
51
- "win32-x64": "35ffa7af1767e802c7670c85205ea11961cb5583aa5dc30947d142eb7c734ff5"
48
+ "darwin-arm64": "9dd7ac0a378a1d5db908a102aec4f596741e943572a7d55b08e2a62f336981bc",
49
+ "darwin-x64": "70c9c6df21e03ad1529682e6cf8150ddfef306e1019e4b3bd2a4e7d025a98d64",
50
+ "linux-x64": "14ee27b3c22988bf72f13f3734e1594dcbb0fb94f699d5ad789ea8cf452dc7a1",
51
+ "win32-x64": "9e059917ba4605527b47d23b43bd78438cf59e7df38c4c9698f6b9487ed64a97"
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.4",
4
+ "version": "5.1.0",
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.4",
5
+ "version": "5.1.0",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -104,7 +104,7 @@ if [ -f "$prefs_global_file" ]; then
104
104
  const defaults = {
105
105
  autoLogin:'ask', autoSelectProject:'ask', autoSelectLocalHost:'ask',
106
106
  showElectronBrowser:'ask', openTestResultsAfterRun:'ask',
107
- defaultExecutionMode:'ask', autoPublishLocalResults:'ask',
107
+ defaultExecutionMode:'ask',
108
108
  suggestRelatedUseCases:'ask', suggestRelatedTestCases:'ask', autoDetectChanges:'ask',
109
109
  postPRVisualWalkthrough:'ask', autoCreatePR:'ask',
110
110
  checkForUpdates:'ask', verboseOutput:'ask',
@@ -27,14 +27,16 @@ function markPrHandled(sessionId2, prUrl, dirOverride) {
27
27
 
28
28
  // src/guardrails/prOpened.ts
29
29
  var PR_URL = /https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/pull\/\d+/;
30
+ var MR_URL = /https?:\/\/[^/\s]+\/[^\s]+\/-\/merge_requests\/\d+/;
30
31
  var CREATE_CMD = /\bgh\s+pr\s+(create|ready)\b/;
32
+ var MR_CREATE_CMD = /\bglab\s+mr\s+create\b|\bglab\s+mr\s+update\b.*--ready\b/;
31
33
  function detectPrOpened(input2) {
32
34
  if (input2.tool_name !== "Bash") return null;
33
35
  const cmd = input2.tool_input?.command ?? "";
34
- if (!CREATE_CMD.test(cmd)) return null;
36
+ if (!CREATE_CMD.test(cmd) && !MR_CREATE_CMD.test(cmd)) return null;
35
37
  const out = `${input2.tool_response?.stdout ?? ""}
36
38
  ${input2.tool_response?.output ?? ""}`;
37
- const m = out.match(PR_URL);
39
+ const m = out.match(PR_URL) ?? out.match(MR_URL);
38
40
  return m ? m[0] : null;
39
41
  }
40
42
 
@@ -1,13 +1,9 @@
1
- # Dev Loop — Publish & Screenshots
1
+ # Dev Loop — Cloud Refs & Screenshots
2
2
 
3
- ## Publish
3
+ ## Cloud refs
4
4
 
5
- After every completed run — pass or fail — publish: failed runs still need cloud-hosted screenshots and per-step actions for the walkthrough, and the upload `status` tells the backend whether to promote the action script as the canonical replay script (pass → promote; fail → record only).
6
-
7
- `muggle-local-publish-test-script` with `runId` and `cloudTestCaseId`. Retain `testScriptId`, `actionScriptId`, `viewUrl`. Batch publishes in parallel.
8
-
9
- If publish rejects with `has no generated actionScript steps to publish` (a true zero-step run), fall back to `muggle-remote-local-run-upload` with whatever exists (`summaryStep`, `errorMessage`, empty `actionScript`); capture `actionScriptId` and `viewUrl` the same way.
5
+ The studio publishes every completed run — pass or fail — to the cloud during execution. There is no publish step to run. The run result already carries the cloud identifiers: read `viewUrl`, `cloudTestScriptId`, and `cloudActionScriptId` from `muggle-local-run-result-get` for the run. (`cloudTestScriptId` is absent for a failed generation — the backend records the action script and `viewUrl` but no test script.)
10
6
 
11
7
  ## Screenshots
12
8
 
13
- Per published script, `muggle-remote-test-script-get` with the `testScriptId` from publish → per step `operation.screenshotUrl` and `operation.action`. Retain `{ stepIndex, action, screenshotUrl }`. Batch in parallel. These feed the `E2eReport` consumed by [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) — the dev loop does not post to the PR.
9
+ Per run, `muggle-remote-test-script-get` with the `cloudTestScriptId` from the run result → per step `operation.screenshotUrl` and `operation.action`. Retain `{ stepIndex, action, screenshotUrl }`. Batch in parallel. These feed the `E2eReport` consumed by [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) — the dev loop does not post to the PR.
@@ -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. 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 loop-echo clause in [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md) — matched by the loop signature ([`loop-signature.md`](loop-signature.md)), so the author's *genuine* reviews and thread replies still get through. Including the PR author in this allow-list is therefore safe.
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 loop-echo clause in [`../vcs/github/submitted-reviews.md`](../vcs/github/submitted-reviews.md) — matched by the loop signature ([`loop-signature.md`](loop-signature.md)), so the author's *genuine* reviews and thread replies still get through. Including the PR author in this allow-list is therefore safe.
6
6
 
7
7
  ## Step 1: requested reviewers
8
8
 
@@ -5,6 +5,6 @@ When `/muggle-do` posts a threaded reply to a review comment, GitHub surfaces th
5
5
  Under the thread-state dispatch trigger this is **intrinsic** — there is no "advance past the echo" step to get wrong:
6
6
 
7
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
+ - **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 [`../vcs/github/submitted-reviews.md`](../vcs/github/submitted-reviews.md)) excludes echoes structurally.
9
9
 
10
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.
@@ -53,4 +53,4 @@ Write to `state.md` under a `## Pre-flight answers` block:
53
53
  - `Auth status: <ok | re-authed | N/A>`
54
54
  - `Working tree: <path>` — the verified checkout the cycle runs against
55
55
 
56
- Missing any required field is a seeding bug: escalate with the session path and halt. Never silently skip E2E.
56
+ Once the strategy is `local-e2e`, missing any of its required fields (`Local URL`, `Muggle Test project`) is a seeding bug — escalate with the session path and halt; don't silently downgrade a chosen `local-e2e` to a skip. But `unit-only` and `skip` are valid first-class strategies for a PR with no testable surface — they need none of those fields, and a session seeded with no block at all is itself a clean skip.
@@ -19,8 +19,7 @@ Run once the target `testCaseId` is chosen and the local URL + services are conf
19
19
  - Not ready → **generate its script only (never replay):**
20
20
  1. `muggle-remote-test-case-get` for the ancestor.
21
21
  2. Determine `freshSession` for that ancestor from its own content — same rules as Step 6.
22
- 3. `muggle-local-execute-test-generation` with the ancestor test case, `localUrl`, `cwd`, and a long `timeoutMs` (see Step 6's timeout guidance). Do **not** call `muggle-local-execute-replay`.
23
- 4. `muggle-local-publish-test-script` (`runId`, `cloudTestCaseId` = ancestor) so the generated script is promoted as that ancestor's canonical replay script — it now reads as ready for any case downstream.
22
+ 3. `muggle-local-execute-test-generation` with the ancestor test case, `localUrl`, `cwd`, and a long `timeoutMs` (see Step 6's timeout guidance). Do **not** call `muggle-local-execute-replay`. The studio publishes the generated run during execution, promoting its script as that ancestor's canonical replay script — it now reads as ready for any case downstream (confirm via `muggle-local-run-result-get` carrying a `cloudActionScriptId`).
24
23
 
25
24
  3. **All ancestors ready** → continue to Step 5 for the target test case.
26
25
 
@@ -0,0 +1,9 @@
1
+ # VCS provider recipes
2
+
3
+ Provider-agnostic seam for the watcher and dev-cycle skills. A caller resolves one provider token via [`detect-vcs.md`](detect-vcs.md) — `github` (`gh`) or `gitlab` (`glab`) — then loads the matching provider's recipe for each agnostic step. The two recipe sets mirror each other call-for-call; callers branch on the token, never fork procedure.
4
+
5
+ ## Index
6
+
7
+ - [`detect-vcs.md`](detect-vcs.md) — resolve `github` | `gitlab` from a URL argument or the origin remote.
8
+ - [`github.md`](github.md) — `gh` / `git` recipe TOC; per-recipe files in [`github/`](github/).
9
+ - [`gitlab.md`](gitlab.md) — `glab` / `git` recipe TOC; per-recipe files in [`gitlab/`](gitlab/).
@@ -0,0 +1,28 @@
1
+ # Detect VCS provider
2
+
3
+ Resolve a single provider token — `github` or `gitlab` — before a caller picks its recipe set. GitHub uses `gh`; GitLab uses `glab`. Auth errors from either surface verbatim.
4
+
5
+ ## Resolution order
6
+
7
+ 1. **From a URL argument**, if one was passed:
8
+ - `github.com/<owner>/<repo>/pull/<n>` → `github`.
9
+ - `<host>/<group>/<project>/-/merge_requests/<iid>` → `gitlab`. The `/-/merge_requests/` segment is the tell, on any host.
10
+
11
+ 2. **From the repo**, when no URL — parse the origin remote:
12
+
13
+ ```bash
14
+ git remote get-url origin
15
+ ```
16
+
17
+ - Host `github.com` → `github`.
18
+ - Host `gitlab.com`, **or** any other host where `glab auth status` succeeds → `gitlab`.
19
+
20
+ ## GitLab wrinkles
21
+
22
+ - **Nested namespaces.** The path between host and `/-/` can be `group/subgroup/project`, any depth. Do not assume two segments — split on `/-/`, the project path is everything before it.
23
+ - **The `/-/` segment** separates the project path from the resource (`/-/merge_requests/<iid>`). GitHub has no equivalent; its `/pull/<n>` sits directly under `<owner>/<repo>`.
24
+ - **Self-hosted hosts.** GitLab is not just `gitlab.com` — `git.acme.com`, `gitlab.internal`, etc. Resolve the host from the remote and confirm it against `glab`'s configured host (`GITLAB_HOST`, or `glab auth status`'s active host). A remote host that matches `glab`'s host → `gitlab`, even when unknown to this doc.
25
+
26
+ ## Output
27
+
28
+ The bare token `github` or `gitlab` — nothing else.
@@ -28,7 +28,7 @@ query($owner: String!, $name: String!, $number: Int!) {
28
28
  }'
29
29
  ```
30
30
 
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:
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:
32
32
 
33
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.
34
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`.
@@ -14,4 +14,4 @@ Accept any remote URL form for `<owner>/<repo>` (with or without trailing `.git`
14
14
  - `git@github.com:<owner>/<repo>`
15
15
  - `ssh://git@github.com/<owner>/<repo>`
16
16
 
17
- Any mismatch → bootstrap aborts using the wrong-checkout template in [`../../muggle-pr-followup/output-templates/bootstrap.md`](../../muggle-pr-followup/output-templates/bootstrap.md).
17
+ Any mismatch → bootstrap aborts using the wrong-checkout template in [`../../../muggle-pr-followup/output-templates/bootstrap.md`](../../../muggle-pr-followup/output-templates/bootstrap.md).
@@ -0,0 +1,21 @@
1
+ # GitHub CLI Recipes
2
+
3
+ Reusable `gh` / `git` snippets used by `muggle-pr-followup` (watcher + bootstrap) and `/muggle-do` (address-reviews + open-prs). Each recipe is one file — load only what you need.
4
+
5
+ Skills assume a working `gh auth status`. Auth errors surface verbatim from `gh`.
6
+
7
+ ## Index
8
+
9
+ | Recipe | Use case |
10
+ | :----- | :------- |
11
+ | [`pr-metadata`](github/pr-metadata.md) | Snapshot PR state, head SHA, branch, conflict + `behind_by` out-of-date detection — watcher + bootstrap. |
12
+ | [`submitted-reviews`](github/submitted-reviews.md) | Fetch a review by id / watcher's body-only-review check. |
13
+ | [`pr-checks`](github/pr-checks.md) | Check-run rollup for the head SHA — watcher's CI poll. |
14
+ | [`line-comments-for-review`](github/line-comments-for-review.md) | Pull a review's line comments — `/muggle-do` per-comment routing. |
15
+ | [`unresolved-threads`](github/unresolved-threads.md) | GraphQL unresolved-thread state — watcher's dispatch trigger + resolve-reminder. |
16
+ | [`reply-line-comment`](github/reply-line-comment.md) | POST a threaded reply on a line comment. |
17
+ | [`top-level-comment`](github/top-level-comment.md) | POST a top-level PR comment — resolve-reminder + overflow. |
18
+ | [`push-to-branch`](github/push-to-branch.md) | Push + capture new SHA after address-reviews work. |
19
+ | [`verify-working-tree`](github/verify-working-tree.md) | Three checks bootstrap runs before seeding state. |
20
+ | [`pr-edit`](github/pr-edit.md) | Refresh title or body when address-reviews mode flips state. |
21
+ | [`loop-user-identity`](github/loop-user-identity.md) | Resolve the GitHub login of the loop user. |