@muggleai/works 4.13.1 → 4.15.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 (137) hide show
  1. package/README.md +3 -3
  2. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  3. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  4. package/dist/plugin/README.md +1 -1
  5. package/dist/plugin/agents/acceptance-tester.md +2 -0
  6. package/dist/plugin/commands/mbt.md +7 -0
  7. package/dist/plugin/commands/mdo.md +3 -3
  8. package/dist/plugin/commands/mprfollowup.md +7 -0
  9. package/dist/plugin/skills/CLAUDE.md +15 -0
  10. package/dist/plugin/skills/_aliases.json +2 -1
  11. package/dist/plugin/skills/_shared/ci-check-to-command.md +10 -0
  12. package/dist/plugin/skills/_shared/dev-loop/action-script.md +3 -0
  13. package/dist/plugin/skills/_shared/dev-loop/failures.md +14 -0
  14. package/dist/plugin/skills/_shared/dev-loop/fresh-session.md +10 -0
  15. package/dist/plugin/skills/_shared/dev-loop/publish.md +13 -0
  16. package/dist/plugin/skills/_shared/dev-loop/run.md +34 -0
  17. package/dist/plugin/skills/_shared/dev-loop/timeouts.md +6 -0
  18. package/dist/plugin/skills/_shared/failure-mode-handling.md +2 -2
  19. package/dist/plugin/skills/_shared/github-cli-recipes/pr-checks.md +22 -0
  20. package/dist/plugin/skills/_shared/github-cli-recipes.md +1 -0
  21. package/dist/plugin/skills/_shared/post-merge-cleanup.md +1 -1
  22. package/dist/plugin/skills/_shared/pr-branch-worktree.md +1 -1
  23. package/dist/plugin/skills/_shared/rebase-before-e2e.md +7 -1
  24. package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  25. package/dist/plugin/skills/_shared/resolve-rebase-conflicts.md +60 -0
  26. package/dist/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +8 -1
  27. package/dist/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +2 -1
  28. package/dist/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -0
  29. package/dist/plugin/skills/_shared/use-worktrees.md +2 -1
  30. package/dist/plugin/skills/do/address-reviews.md +7 -1
  31. package/dist/plugin/skills/do/build.md +2 -1
  32. package/dist/plugin/skills/do/cleanup.md +14 -0
  33. package/dist/plugin/skills/do/e2e-acceptance.md +5 -66
  34. package/dist/plugin/skills/do/fix-ci.md +60 -0
  35. package/dist/plugin/skills/do/input-routing.md +12 -0
  36. package/dist/plugin/skills/do/open-prs/forward.md +3 -3
  37. package/dist/plugin/skills/do/open-prs/update.md +1 -1
  38. package/dist/plugin/skills/do/pre-flight.md +3 -3
  39. package/dist/plugin/skills/mbt/SKILL.md +8 -0
  40. package/dist/plugin/skills/mdo/SKILL.md +3 -3
  41. package/dist/plugin/skills/mprfollowup/SKILL.md +8 -0
  42. package/dist/plugin/skills/muggle/SKILL.md +1 -0
  43. package/{plugin/skills/muggle-do-task → dist/plugin/skills/muggle-browser-task}/SKILL.md +1 -1
  44. package/dist/plugin/skills/muggle-do/SKILL.md +29 -10
  45. package/dist/plugin/skills/muggle-feedback/SKILL.md +1 -1
  46. package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +4 -5
  47. package/dist/plugin/skills/muggle-pr-followup/SKILL.md +5 -3
  48. package/dist/plugin/skills/muggle-pr-followup/auto-track.md +5 -1
  49. package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +5 -3
  50. package/dist/plugin/skills/muggle-pr-followup/contract.md +34 -17
  51. package/dist/plugin/skills/muggle-pr-followup/finalize.md +29 -0
  52. package/dist/plugin/skills/muggle-pr-followup/reconcile.md +33 -0
  53. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +10 -2
  54. package/dist/plugin/skills/muggle-preferences/ops/configure.md +2 -1
  55. package/dist/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +11 -0
  56. package/dist/plugin/skills/muggle-preferences/preference-gates/autoWatchPR.md +13 -0
  57. package/dist/plugin/skills/muggle-preferences/preference-gates/reusePreparePlan.md +11 -0
  58. package/dist/plugin/skills/muggle-status/SKILL.md +1 -1
  59. package/dist/plugin/skills/muggle-test/SKILL.md +30 -48
  60. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +20 -44
  61. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +5 -1
  62. package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +7 -5
  63. package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +2 -0
  64. package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +30 -0
  65. package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +44 -0
  66. package/dist/release-manifest.json +4 -4
  67. package/package.json +7 -6
  68. package/plugin/.claude-plugin/plugin.json +1 -1
  69. package/plugin/.cursor-plugin/plugin.json +1 -1
  70. package/plugin/README.md +1 -1
  71. package/plugin/agents/acceptance-tester.md +2 -0
  72. package/plugin/commands/mbt.md +7 -0
  73. package/plugin/commands/mdo.md +3 -3
  74. package/plugin/commands/mprfollowup.md +7 -0
  75. package/plugin/skills/CLAUDE.md +15 -0
  76. package/plugin/skills/_aliases.json +2 -1
  77. package/plugin/skills/_shared/ci-check-to-command.md +10 -0
  78. package/plugin/skills/_shared/dev-loop/action-script.md +3 -0
  79. package/plugin/skills/_shared/dev-loop/failures.md +14 -0
  80. package/plugin/skills/_shared/dev-loop/fresh-session.md +10 -0
  81. package/plugin/skills/_shared/dev-loop/publish.md +13 -0
  82. package/plugin/skills/_shared/dev-loop/run.md +34 -0
  83. package/plugin/skills/_shared/dev-loop/timeouts.md +6 -0
  84. package/plugin/skills/_shared/failure-mode-handling.md +2 -2
  85. package/plugin/skills/_shared/github-cli-recipes/pr-checks.md +22 -0
  86. package/plugin/skills/_shared/github-cli-recipes.md +1 -0
  87. package/plugin/skills/_shared/post-merge-cleanup.md +1 -1
  88. package/plugin/skills/_shared/pr-branch-worktree.md +1 -1
  89. package/plugin/skills/_shared/rebase-before-e2e.md +7 -1
  90. package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  91. package/plugin/skills/_shared/resolve-rebase-conflicts.md +60 -0
  92. package/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +8 -1
  93. package/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +2 -1
  94. package/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -0
  95. package/plugin/skills/_shared/use-worktrees.md +2 -1
  96. package/plugin/skills/do/address-reviews.md +7 -1
  97. package/plugin/skills/do/build.md +2 -1
  98. package/plugin/skills/do/cleanup.md +14 -0
  99. package/plugin/skills/do/e2e-acceptance.md +5 -66
  100. package/plugin/skills/do/fix-ci.md +60 -0
  101. package/plugin/skills/do/input-routing.md +12 -0
  102. package/plugin/skills/do/open-prs/forward.md +3 -3
  103. package/plugin/skills/do/open-prs/update.md +1 -1
  104. package/plugin/skills/do/pre-flight.md +3 -3
  105. package/plugin/skills/mbt/SKILL.md +8 -0
  106. package/plugin/skills/mdo/SKILL.md +3 -3
  107. package/plugin/skills/mprfollowup/SKILL.md +8 -0
  108. package/plugin/skills/muggle/SKILL.md +1 -0
  109. package/{dist/plugin/skills/muggle-do-task → plugin/skills/muggle-browser-task}/SKILL.md +1 -1
  110. package/plugin/skills/muggle-do/SKILL.md +29 -10
  111. package/plugin/skills/muggle-feedback/SKILL.md +1 -1
  112. package/plugin/skills/muggle-pr-followup/CLAUDE.md +4 -5
  113. package/plugin/skills/muggle-pr-followup/SKILL.md +5 -3
  114. package/plugin/skills/muggle-pr-followup/auto-track.md +5 -1
  115. package/plugin/skills/muggle-pr-followup/bootstrap.md +5 -3
  116. package/plugin/skills/muggle-pr-followup/contract.md +34 -17
  117. package/plugin/skills/muggle-pr-followup/finalize.md +29 -0
  118. package/plugin/skills/muggle-pr-followup/reconcile.md +33 -0
  119. package/plugin/skills/muggle-pr-followup/state-schemas.md +10 -2
  120. package/plugin/skills/muggle-preferences/ops/configure.md +2 -1
  121. package/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +11 -0
  122. package/plugin/skills/muggle-preferences/preference-gates/autoWatchPR.md +13 -0
  123. package/plugin/skills/muggle-preferences/preference-gates/reusePreparePlan.md +11 -0
  124. package/plugin/skills/muggle-status/SKILL.md +1 -1
  125. package/plugin/skills/muggle-test/SKILL.md +30 -48
  126. package/plugin/skills/muggle-test-feature-local/SKILL.md +20 -44
  127. package/plugin/skills/muggle-test-prepare/SKILL.md +5 -1
  128. package/plugin/skills/muggle-test-prepare/steps/check-running.md +7 -5
  129. package/plugin/skills/muggle-test-prepare/steps/identify-services.md +2 -0
  130. package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +30 -0
  131. package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +44 -0
  132. package/dist/plugin/commands/mrelease.md +0 -7
  133. package/dist/plugin/skills/mrelease/SKILL.md +0 -8
  134. package/dist/plugin/skills/muggle-works-npm-release/SKILL.md +0 -200
  135. package/plugin/commands/mrelease.md +0 -7
  136. package/plugin/skills/mrelease/SKILL.md +0 -8
  137. package/plugin/skills/muggle-works-npm-release/SKILL.md +0 -200
@@ -0,0 +1,33 @@
1
+ # Reconcile Procedure
2
+
3
+ The procedure for the **reconcile mode** of `muggle-pr-followup` — a sweep that finalizes session slots whose PR went terminal while polling was lapsed. Routing is in [`SKILL.md`](SKILL.md#routing).
4
+
5
+ Termination is otherwise tick-driven ([`contract.md`](contract.md) Step 2): a slot finalizes only when a tick fires and observes `MERGED` / `CLOSED`. If the tick stream stops first — the recurring `/loop` cron auto-expires after 7 days, the session ends, or the machine is off when the PR merges — no tick catches the transition, and the slot is left un-finalized: no `result.md`, no post-merge cleanup, and a surviving cron would keep polling a dead PR. Reconcile is the catch-up.
6
+
7
+ ## Input
8
+
9
+ `$ARGUMENTS` is `reconcile` (or `sweep`), optionally followed by a `<slug>` to scope the sweep to one slot.
10
+
11
+ ## Procedure
12
+
13
+ ### Step 1 — Enumerate slots
14
+
15
+ List `~/.muggle-ai/muggle-do/sessions/*/` dirs that contain a `prs.json`. Skip any that already have a `result.md` — those are finalized. Scope to a single `<slug>` if the arg gave one.
16
+
17
+ ### Step 2 — Refresh live state
18
+
19
+ For each candidate, fetch the PR per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md) using `prs.json[0].url`. A `gh` failure on one slot (deleted repo, missing auth) → log it to that slot's `followup.log` and skip; never abort the whole sweep.
20
+
21
+ ### Step 3 — Finalize the terminal ones
22
+
23
+ For each candidate whose live `state` is `MERGED` or `CLOSED`, run [`finalize.md`](finalize.md). `finalize.md` dispatches nothing, so a backfilled merge gets no post-merge cleanup — its branch is typically long gone, and the `autoCleanup` gate governs if the user runs cleanup later. Slots still `open` are left untouched — reconcile finalizes, it does not re-arm a watcher (re-arming an open PR is [`auto-track.md`](auto-track.md)'s job).
24
+
25
+ ### Step 4 — Report
26
+
27
+ One line: slots scanned, finalized (with final state each), and left open. Silent only when zero slots exist.
28
+
29
+ ## Invariants
30
+
31
+ - **Idempotent.** A slot with `result.md` is never re-finalized; once everything terminal is swept, re-running is a no-op.
32
+ - **Finalize-only.** Reconcile never seeds, re-arms, or dispatches a watcher. Open slots pass through untouched.
33
+ - **Per-slot isolation.** One slot's `gh` failure never blocks finalizing the others.
@@ -1,9 +1,13 @@
1
1
  # Session State Schemas
2
2
 
3
- Canonical shapes for the JSON files in a PR-follow-up session slot. The slot path is `.muggle-do/sessions/<slug>/` (the caller's session dir; `muggle-do` is the current and only caller).
3
+ Canonical shapes for the JSON files in a PR-follow-up session slot. The slot path is `~/.muggle-ai/muggle-do/sessions/<slug>/` (under the user's home, shared across repos; `muggle-do` is the current and only caller).
4
4
 
5
5
  All files are atomic writes — the caller rewrites the whole file each time, never mutates in place. Use a temp file + rename if the platform supports it.
6
6
 
7
+ ## Legacy location
8
+
9
+ Before the move to the user's home, slots lived at the repo-relative `.muggle-do/sessions/<slug>/` (one per working tree, still gitignored). Bootstrap's Step 5 migrates a legacy slot to the home-dir location on the next run for that PR; nothing else reads the old path. The state is ephemeral and reconstructible from GitHub, so an un-migrated slot costs only a re-bootstrap, not data.
10
+
7
11
  ## `prs.json`
8
12
 
9
13
  A list of one entry. (Historical: the file is an array for forward-compat with the original session-wide model. Today, each PR has its own session slot, so the array always has exactly one entry.)
@@ -35,7 +39,9 @@ Keyed by `"<owner>/<repo>#<n>"`. One key per PR in the slot.
35
39
  "idle_tick_count": <int>,
36
40
  "cycles_completed": <int>,
37
41
  "escalated_review_ids": [<int>, ...],
38
- "pushed_shas": ["<sha>", ...]
42
+ "pushed_shas": ["<sha>", ...],
43
+ "ci_fix_attempts": { "<sha>": <int> },
44
+ "ci_escalated_shas": ["<sha>", ...]
39
45
  }
40
46
  }
41
47
  ```
@@ -46,6 +52,8 @@ Keyed by `"<owner>/<repo>#<n>"`. One key per PR in the slot.
46
52
  - `cycles_completed`: incremented each time `/muggle-do` completes an address-reviews invocation (regardless of actionable/ambiguous/mixed).
47
53
  - `escalated_review_ids`: review ids classified as ambiguous by `/muggle-do`. The watcher excludes these from future review fetches so the same ambiguous review is never re-dispatched.
48
54
  - `pushed_shas`: every SHA `/muggle-do` has pushed for this PR. Append-only. Used by the resolve-reminder stage to recognize threads addressed by the loop.
55
+ - `ci_fix_attempts`: per-SHA count of fix-ci cycles `/muggle-do` has run. The watcher stops dispatching fix-ci for a SHA once its count reaches 3. Keyed by head SHA.
56
+ - `ci_escalated_shas`: head SHAs whose CI the fix-ci stage gave up on (attempts exhausted or only out-of-scope checks). The watcher excludes these from CI dispatch so a hopeless SHA is never re-fixed.
49
57
 
50
58
  ## `state.md`
51
59
 
@@ -28,7 +28,8 @@ For each option: label = key name, description = first paragraph of `preference-
28
28
  - `multiSelect: true`, `header: "Auth & session"` — `autoLogin`, `autoSelectProject`, `checkForUpdates`, `verboseOutput`
29
29
  - `multiSelect: true`, `header: "Test setup"` — `autoSelectLocalHost`, `autoDetectChanges`, `autoReuseValidationContext`
30
30
  - `multiSelect: true`, `header: "Test run"` — `showElectronBrowser`, `openTestResultsAfterRun`, `autoPublishLocalResults`
31
- - `multiSelect: true`, `header: "Suggestions & PR"` — `suggestRelatedUseCases`, `suggestRelatedTestCases`, `postPRVisualWalkthrough`, `autoCreatePR`
31
+ - `multiSelect: true`, `header: "Suggestions"` — `suggestRelatedUseCases`, `suggestRelatedTestCases`
32
+ - `multiSelect: true`, `header: "PR"` — `postPRVisualWalkthrough`, `autoCreatePR`, `autoWatchPR`
32
33
  - `multiSelect: true`, `header: "Branch hygiene"` — `autoUseWorktree`, `autoRebase`, `autoCleanup`
33
34
  - `multiSelect: false`, `header: "E2E acceptance"` — `autoE2ETest`. Options: `Always run Stage 6 at the end` (`always` — default), `Ask each cycle` (`ask`). No `never` option.
34
35
  - `multiSelect: false`, `header: "Default mode"` — `defaultExecutionMode`. Options: `Local — run on my computer` (`local`), `Remote — run in the Muggle Test cloud` (`remote`), `Ask each time` (don't change).
@@ -0,0 +1,11 @@
1
+ # `autoResolveConflicts`
2
+
3
+ When a rebase onto `origin/{default}` hits conflicts, resolve them autonomously behind a verify-or-rollback gate, or stop and escalate. Default `never` — the loop aborts the rebase and escalates exactly as before. Opt in with `always` to resolve conflicts without a human.
4
+
5
+ **Picker 1** — header `Resolve rebase conflicts?`, question `"Rebase onto origin/{default} hit conflicts in {conflicted} file(s) — resolve them autonomously?"`
6
+ - `Resolve autonomously` — `Resolve the conflicts, then re-verify (build + unit + E2E) before any push; roll back and escalate if verification fails.` → `always`
7
+ - `Stop and escalate` — `Abort the rebase, restore the branch, and hand the conflict to me.` → `never`
8
+
9
+ **Silent action**
10
+ - `always` → `Resolving rebase conflicts autonomously (verify-or-rollback)`
11
+ - `never` → `Aborting rebase and escalating — conflicts in {conflicted} file(s)`
@@ -0,0 +1,13 @@
1
+ # `autoWatchPR`
2
+
3
+ After a PR is sent at the end of a test run, controls whether Muggle starts a `muggle-pr-followup` watcher on it — a loop that polls the PR for newly submitted reviews and hands them to `/muggle-do` to address — or leaves you to start one yourself with `/mprfollowup`. Fires once a PR exists (muggle-test, muggle-test-feature-local), reusing the E2E validation context from that run so the watcher never re-prompts. Substitute `{pr}`.
4
+
5
+ **Picker 1** — header `Watch PR?`, question `"Watch '{pr}' for review follow-ups and address them as they land?"`
6
+ - `Watch it` — `Start a muggle-pr-followup loop on this PR.` → `always`
7
+ - `Ask me next time` — `Decide per run.` → `ask`
8
+ - `Skip — I'll watch it myself` — `Leave it; run /mprfollowup later if you want.` → `never`
9
+
10
+ **Silent action**
11
+ - `always` → `Watching {pr} for review follow-ups`
12
+ - `ask` → `Asking about PR watching`
13
+ - `never` → `Not watching {pr}`
@@ -0,0 +1,11 @@
1
+ # `reusePreparePlan`
2
+
3
+ Reuse the saved prepare plan for this stack (skip scope / viability / service-selection / start-commands and jump straight to check-running + smoke-test), or rediscover from scratch. Substitute `{services}` with a comma-separated list of saved service names.
4
+
5
+ **Picker 1** — header `Reuse prepare plan`, question `"Found a saved plan for this stack ({services}) — reuse it, or rediscover from scratch?"`
6
+ - `Reuse this plan` — `Skip the discovery questions; verify and start what's missing.` → `always`
7
+ - `Rediscover from scratch` — `Re-ask scope, services, and start commands.` → `never`
8
+
9
+ **Silent action**
10
+ - `always` → `Reusing saved prepare plan ({services})`
11
+ - `never` → `Rediscovering this stack from scratch`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-status
3
- description: Check health of the Muggle AI installation. Use when user types muggle status, asks for Muggle Test health, MCP health, or auth validity.
3
+ description: Use this skill to check the health of the user's Muggle AI installation and diagnose why it's misbehaving — MCP server connectivity, tool loading, login/auth validity, and overall setup. Engage on an explicit "muggle status", but also on any diagnostic question about Muggle itself: "is muggle working / healthy / set up right?", "why does muggle keep failing / timing out / saying it can't connect?", "are the muggle MCP tools actually loading?", "is my muggle login/auth still valid?", "muggle's been acting up — take a look / what's wrong?", "muggle commands fail silently — is the install unhealthy?". This is diagnosis and reporting: prefer it over answering from memory whenever the user is unsure Muggle itself is functioning. Boundary: checking/diagnosing is muggle-status; actually fixing a broken install is muggle-repair (a clear "fix it" goes there). Not for the health of the user's own app, CI, or infrastructure.
4
4
  ---
5
5
 
6
6
  # Muggle Test Status
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-test
3
- description: "Run change-driven E2E acceptance testing using Muggle AI — detects local code changes, maps them to use cases, and generates test scripts either locally (real browser on localhost) or remotely (cloud execution on a preview/staging URL). Publishes results to Muggle Test dashboard, opens them in the browser, and posts E2E acceptance summaries with screenshots to the PR. Use this skill whenever the user wants to test their changes, run E2E acceptance tests on recent work, validate what they've been working on, or check if their code changes broke anything. Triggers on: 'test my changes', 'run tests on my changes', 'acceptance test my work', 'check my changes', 'validate my changes', 'test before I push', 'make sure my changes work', 'regression test my changes', 'test on preview', 'test on staging'. This is the go-to skill for change-driven E2E acceptance testing — it handles everything from change detection to test execution to result reporting."
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."
4
4
  ---
5
5
 
6
6
  # Muggle Test — Change-Driven E2E Acceptance Router
@@ -49,6 +49,7 @@ Gates run per `preference-gates/README.md`.
49
49
  | `showElectronBrowser` | 7A | Show the Electron browser window during local test execution (vs. run headless) |
50
50
  | `postPRVisualWalkthrough` | 9 | Post visual walkthrough to PR after results are available |
51
51
  | `autoCreatePR` | 9 (if no PR) | Auto-create the PR when posting the walkthrough has no PR to target |
52
+ | `autoWatchPR` | 9.5 (if a PR exists) | Start a `muggle-pr-followup` watcher on the PR after the run |
52
53
 
53
54
  ## Step 1: Confirm Scope of Work (Always First)
54
55
 
@@ -234,6 +235,10 @@ If the user picks "Override one or more", let them flip the mode for any test ca
234
235
 
235
236
  ## Step 7A: Execute — Local Mode
236
237
 
238
+ ### Local environment readiness
239
+
240
+ 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
+
237
242
  ### Pre-flight question — Local URL (gated by `autoSelectLocalHost`)
238
243
 
239
244
  Skill responsibilities (the rest is in `preference-gates/autoSelectLocalHost.md`):
@@ -254,45 +259,18 @@ Gate `showElectronBrowser` (per `preference-gates/README.md`). Resolve once; app
254
259
 
255
260
  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).
256
261
 
257
- ### Determine `freshSession` per test case
258
-
259
- Before executing each test case, inspect its content (title, goal, instructions, preconditions) for signals that it requires a **clean browser state** — no prior cookies, localStorage, or logged-in session. Set `freshSession: true` when the test case involves any of:
260
-
261
- - **Registration / sign-up** — creating a new account
262
- - **Login / authentication** — verifying the login flow itself (not a test that merely *uses* login as a prerequisite)
263
- - **Cookie consent / GDPR banners** — verifying first-visit consent prompts
264
- - **Onboarding flows** — first-time user experiences that only appear on a fresh session
265
-
266
- If none of the above apply, omit `freshSession` (defaults to `false`, preserving any existing session state). Evaluate this per test case — in a batch, some may need it and others may not.
267
-
268
- ### Run sequentially (Electron constraint)
269
-
270
- Execution itself **must** be sequential because there is only one local Electron browser. For each test case, in the order chosen, branch on the mode picked in Step 6f:
271
-
272
- **Regen-mode test case:**
273
- 1. Call `muggle-local-execute-test-generation`:
274
- - `testCase`: Full test case object from the parallel fetch above
275
- - `localUrl`: User's local URL from the pre-flight question
276
- - `cwd`: Absolute path of the active working directory — the PR-branch worktree if one was created in Step 2, otherwise the user's repo root. Drives the cross-worktree single-flight lock so concurrent muggle-test runs from different branches serialize.
277
- - `showUi`: from the `showElectronBrowser` resolution — omit (default visible) for `always`, pass `false` for `never`
278
- - `freshSession`: `true` if the test case requires a clean browser state (see above), omit otherwise
279
- 2. Store the returned `runId` and tag the result `mode: "regen"`.
262
+ ### Run the dev loop
280
263
 
281
- **Replay-mode test case:**
282
- 1. Fetch the action script: `muggle-remote-test-script-get` (latest replayable script id) → `muggle-remote-action-script-get` (full `actionScript` — use as-is, never edit). For batches, fan these calls out in parallel before the sequential execution loop begins.
283
- 2. Call `muggle-local-execute-replay`:
284
- - `testScript`: from `muggle-remote-test-script-get`
285
- - `actionScript`: from `muggle-remote-action-script-get`
286
- - `localUrl`, `cwd`, `showUi`, `freshSession`: same resolution as regen
287
- 3. Store the returned `runId` and tag the result `mode: "replay"`.
264
+ 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).
288
265
 
289
- If a run fails, log it and continue to the next — do not abort the batch. Failures are routed through Step 7C's post-failure handler after the batch completes.
266
+ Caller glue:
267
+ - `mode` per test case comes from Step 6f; `localUrl` from the pre-flight question; `showUi` from the `showElectronBrowser` resolution.
268
+ - `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.
269
+ - On a failed run, continue the batch and route it through Step 7C after completion.
290
270
 
291
- ### Collect results (in parallel)
271
+ ### Collect results
292
272
 
293
- For every `runId`, issue all `muggle-local-run-result-get` calls in parallel. Extract from the **structured response only** (not from `execute`'s stdout tail, which is a truncated display excerpt): `Status`, `Error`, `Duration`, and the `Artifacts` section (always present after a run completes — names `artifactsDir` and lists the files actually on disk).
294
-
295
- For passed runs, `results.md` inside `artifactsDir` is the step-by-step verdict — read it before summarizing. For failed runs, `stdout.log` + `stderr.log` are always present and `action-script.json` is present when generation reached the step-emission stage (typical for `goal_not_achievable`); use `Error` as the headline verdict and route through Step 7C.
273
+ 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.
296
274
 
297
275
  ### Publish each run to cloud (gated by `autoPublishLocalResults`)
298
276
 
@@ -303,15 +281,7 @@ Gate `autoPublishLocalResults` (per `preference-gates/README.md`):
303
281
 
304
282
  ### Publish logic (when publishing is enabled)
305
283
 
306
- For every completed run, issue all `muggle-local-publish-test-script` calls in parallel (single message, multiple tool calls):
307
- - `runId`: The local run ID
308
- - `cloudTestCaseId`: The cloud test case ID
309
-
310
- This returns:
311
- - `viewUrl`: Direct link to view this test run on the Muggle AI dashboard
312
- - `testScriptId`, `actionScriptId`, `workflowRuntimeId`
313
-
314
- Store every `viewUrl` — these are used in the next steps.
284
+ 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.
315
285
 
316
286
  ### Report summary
317
287
 
@@ -413,12 +383,24 @@ Tell the user:
413
383
 
414
384
  After reporting results:
415
385
 
416
- 1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → Step 10.
386
+ 1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → Step 9.5.
417
387
  2. `gh pr view --json number,title,url 2>/dev/null` — find the PR.
418
- 3. If no PR: fire [`autoCreatePR`](../muggle-preferences/preference-gates/autoCreatePR.md). On skip → Step 10.
388
+ 3. If no PR: fire [`autoCreatePR`](../muggle-preferences/preference-gates/autoCreatePR.md). On skip → Step 9.5.
419
389
  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).
420
390
  5. Invoke [`../muggle-pr-visual-walkthrough/SKILL.md`](../muggle-pr-visual-walkthrough/SKILL.md) Mode A with the `E2eReport`.
421
391
 
392
+ ## Step 9.5: Offer to watch the PR for review follow-ups
393
+
394
+ Once a PR exists for this work, offer to keep watching its review thread.
395
+
396
+ 1. Identify the PR — reuse the `gh pr view --json number,title,url` result from Step 9 if available, else run it now. No PR (none exists, none created) → Step 10.
397
+ 2. Fire [`autoWatchPR`](../muggle-preferences/preference-gates/autoWatchPR.md) with `{pr}` = `<owner>/<repo>#<number>`. On skip → Step 10.
398
+ 3. On proceed: start the watcher reusing this run's context so it never re-prompts —
399
+ - Seed the `muggle-pr-followup` session slot and dispatch its loop per the stage-8 seeding in [`../do/open-prs/forward.md`](../do/open-prs/forward.md) (default slug `<repo>-pr<number>`).
400
+ - Additionally write `state.md`'s `## Pre-flight answers` block from the context resolved this run — validation strategy, local URL, project, credentials, auth, working tree — per [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md#persisted-fields). Strategy = `local-e2e` (local run), `staging-replay` (remote), or `unit-only`/`skip` if no E2E ran.
401
+
402
+ The `/mprfollowup` shortcut starts the same watcher manually at any time.
403
+
422
404
  ## Step 10: Offer feedback on failures
423
405
 
424
406
  After the report is complete, if **any** test in the run had a `failed` or unexpected status (or the user verbally flags something looked off), suggest the feedback skill:
@@ -462,7 +444,7 @@ This is a suggestion, not automatic invocation. Skip silently if every test pass
462
444
  ## Guardrails
463
445
 
464
446
  - **Always confirm intent first** — never assume local vs remote without asking
465
- - **PR URLs always run in a dedicated worktree** — never switch the user's main checkout. Create or reuse `<repo>/.claude/worktrees/<sanitized-branch>` and pass that path as the `cwd` parameter to local execute tools. The cross-worktree single-flight lock relies on this to serialize concurrent runs from different branches.
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.
466
448
  - **User MUST select project** — present clickable options via `AskUserQuestion`, wait for explicit choice, never auto-select
467
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.
468
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.
@@ -51,6 +51,7 @@ Gates run per `preference-gates/README.md`.
51
51
  | `openTestResultsAfterRun` | 8 | Open results page on Muggle Test dashboard after run |
52
52
  | `postPRVisualWalkthrough` | 10 | Post visual walkthrough to PR after results |
53
53
  | `autoCreatePR` | 10 (if no PR) | Auto-create the PR when posting the walkthrough has no PR to target |
54
+ | `autoWatchPR` | 10.5 (if a PR exists) | Start a `muggle-pr-followup` watcher on the PR after the run |
54
55
  | `autoCleanup` | post-merge | Run cleanup after the PR for this work is merged (see [`_shared/post-merge-cleanup.md`](../_shared/post-merge-cleanup.md)) |
55
56
 
56
57
  ## Workflow
@@ -142,41 +143,9 @@ Before deciding the target's script, resolve its prerequisite chain from the bac
142
143
 
143
144
  ### 6. Load data for the chosen path
144
145
 
145
- **Determine `freshSession`**
146
+ Run the shared loop in [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md): [`freshSession`](../_shared/dev-loop/fresh-session.md), [replay vs regen](../_shared/dev-loop/run.md), [`actionScript` as-is](../_shared/dev-loop/action-script.md), [`timeoutMs`](../_shared/dev-loop/timeouts.md), and [failure interpretation](../_shared/dev-loop/failures.md).
146
147
 
147
- Before calling either execution tool, inspect the test case content (title, goal, instructions, preconditions) for signals that the test requires a **clean browser state** — no prior cookies, localStorage, or logged-in session. Pass `freshSession: true` when the test case involves any of:
148
-
149
- - **Registration / sign-up** — creating a new account
150
- - **Login / authentication** — verifying the login flow itself (not a test that merely *uses* login as a prerequisite)
151
- - **Cookie consent / GDPR banners** — verifying first-visit consent prompts
152
- - **Onboarding flows** — first-time user experiences that only appear on a fresh session
153
-
154
- If none of the above apply, omit `freshSession` (defaults to `false`, preserving any existing session state).
155
-
156
- **Generate**
157
-
158
- 1. `muggle-remote-test-case-get`
159
- 2. `muggle-local-execute-test-generation` with that test case + `localUrl` (optional: `showUi: false` for headless — defaults to visible; **`freshSession`** — see above; **`timeoutMs`** — see below)
160
-
161
- **Replay**
162
-
163
- 1. `muggle-remote-test-script-get` — note `actionScriptId`
164
- 2. `muggle-remote-action-script-get` with that id — full `actionScript`
165
- **Use the API response as-is.** Do not edit, shorten, or rebuild `actionScript`; replay needs full `label` paths for element lookup.
166
- 3. `muggle-local-execute-replay` with `testScript`, `actionScript`, `localUrl` (optional: `showUi: false` for headless — defaults to visible; **`freshSession`** — see above; **`timeoutMs`** — see below)
167
-
168
- ### Local execution timeout (`timeoutMs`)
169
-
170
- The MCP client often uses a **default wait of 300000 ms (5 minutes)** for `muggle-local-execute-test-generation` and `muggle-local-execute-replay`. **Exploratory script generation** (Auth0 login, dashboards, multi-step wizards, many LLM iterations) routinely **runs longer than 5 minutes** while Electron is still healthy.
171
-
172
- - **Always pass `timeoutMs`** for flows that may be long — for example **`600000` (10 min)** or **`900000` (15 min)** — unless the user explicitly wants a short cap.
173
- - If the tool reports **`Electron execution timed out after 300000ms`** (or similar) **but** Electron logs show the run still progressing (steps, screenshots, LLM calls), treat it as **orchestration timeout**, not an Electron app defect: **increase `timeoutMs` and retry**.
174
- - **Test case design:** Preconditions like "a test run has already completed" on an **empty account** can force many steps (sign-up, new project, crawl). Prefer an account/project that **already has** the needed state, or narrow the test goal so generation does not try to create a full project from scratch unless that is intentional.
175
-
176
- ### Interpreting `failed` / non-zero Electron exit
177
-
178
- - **`Electron execution timed out after 300000ms`:** Orchestration wait too short — see **`timeoutMs`** above.
179
- - **Exit code 26** (and messages like **LLM failed to generate / replay action script**): Often corresponds to a completed exploration whose **outcome was goal not achievable** (`goal_not_achievable`, summary with `halt`) — e.g. verifying "view script after a successful run" when **no run or script exists yet** in the UI. Use `muggle-local-run-result-get` and read the **summary / structured summary**; do not assume an Electron crash. **Fix:** choose a **project that already has** completed runs and scripts, or **change the test case** so preconditions match what localhost can satisfy (e.g. include steps to create and run a test first, or assert only empty-state UI when no runs exist).
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.
180
149
 
181
150
  ### 7. Execute (no approval prompt; `showUi` gated by `showElectronBrowser`)
182
151
 
@@ -191,21 +160,16 @@ Gate `showElectronBrowser` (per `preference-gates/README.md`). Reuse choice with
191
160
 
192
161
  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).
193
162
 
194
- - `muggle-local-publish-test-script`
163
+ - Publish per [`../_shared/dev-loop/publish.md`](../_shared/dev-loop/publish.md) — includes the zero-step `muggle-remote-local-run-upload` fallback.
195
164
  - Gate `openTestResultsAfterRun` (per `preference-gates/README.md`):
196
165
  - `always` → open `viewUrl` automatically (`open "<viewUrl>"` on macOS or OS equivalent).
197
166
  - `never` → print the URL only.
198
167
  - `ask` → run Picker 1 from `preference-gates/openTestResultsAfterRun.md` via `AskUserQuestion`; map the answer back to one of the actions above.
199
168
 
200
- If publish rejects with `has no generated actionScript steps to publish` (true zero-step runs — Electron never produced an action), fall back to `muggle-remote-local-run-upload` directly with whatever data exists (`summaryStep`, `errorMessage`, empty `actionScript`). This still gets the failure summary and any goal-not-achievable verdict onto the dashboard so reviewers can see why the run failed. Capture the returned `actionScriptId` and `viewUrl` from this fallback path the same way you would from publish.
201
-
202
169
  ### 9. Report
203
170
 
204
- **Do not diagnose from `execute`'s response stdout tail.** That tail is a truncated excerpt for human display and routinely cuts off mid-sentence. The only ground truth is the run record.
171
+ 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.
205
172
 
206
- - `muggle-local-run-result-get` with the run id from execute.
207
- - **Read in this order:** `Status` → `Error` → **`Artifacts` section** (always present after a run completes; names `artifactsDir` and lists the files actually on disk: `action-script.json`, `results.md`, `screenshots/`, `stdout.log`, `stderr.log`). On a `passed` run, `results.md` is the step-by-step verdict with screenshot links — read it before summarizing.
208
- - **On failure**, the `Artifacts` section is still present. `stdout.log` + `stderr.log` are always there. `action-script.json` is there when generation got far enough to emit it (typical for `goal_not_achievable` / mid-progress crashes — the file holds the agent's attempted steps + halt summary). `results.md` and per-step screenshots are absent on failure (electron-app only emits those on the successful completion path) — don't hunt elsewhere on disk for them.
209
173
  - 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.
210
174
 
211
175
  ### 9a. Route failures through the failure-mode handler
@@ -242,12 +206,24 @@ Non-blocking — one click to dismiss. Do not re-ask for the same `runId` within
242
206
 
243
207
  After reporting results:
244
208
 
245
- 1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → end.
209
+ 1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → 10.5.
246
210
  2. `gh pr view --json number,title,url 2>/dev/null` — find the PR.
247
- 3. If no PR: fire [`autoCreatePR`](../muggle-preferences/preference-gates/autoCreatePR.md). On skip → end.
211
+ 3. If no PR: fire [`autoCreatePR`](../muggle-preferences/preference-gates/autoCreatePR.md). On skip → 10.5.
248
212
  4. Assemble the `E2eReport` — see [`../muggle-pr-visual-walkthrough/e2e-report-assembly.md`](../muggle-pr-visual-walkthrough/e2e-report-assembly.md).
249
213
  5. Invoke [`../muggle-pr-visual-walkthrough/SKILL.md`](../muggle-pr-visual-walkthrough/SKILL.md) Mode A with the `E2eReport`.
250
214
 
215
+ ### 10.5. Offer to watch the PR for review follow-ups
216
+
217
+ Once a PR exists for this work, offer to keep watching its review thread.
218
+
219
+ 1. Identify the PR — reuse the `gh pr view --json number,title,url` result from section 10 if available, else run it now. No PR (none exists, none created) → end.
220
+ 2. Fire [`autoWatchPR`](../muggle-preferences/preference-gates/autoWatchPR.md) with `{pr}` = `<owner>/<repo>#<number>`. On skip → end.
221
+ 3. On proceed: start the watcher reusing this run's context so it never re-prompts —
222
+ - Seed the `muggle-pr-followup` session slot and dispatch its loop per the stage-8 seeding in [`../do/open-prs/forward.md`](../do/open-prs/forward.md) (default slug `<repo>-pr<number>`).
223
+ - Additionally write `state.md`'s `## Pre-flight answers` block from the context resolved this run — validation strategy, local URL, project, credentials, auth, working tree — per [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md#persisted-fields). Strategy = `local-e2e` for this local E2E run.
224
+
225
+ The `/mprfollowup` shortcut starts the same watcher manually at any time.
226
+
251
227
  ## Non-negotiables
252
228
 
253
229
  - No silent auth skip.
@@ -257,7 +233,7 @@ After reporting results:
257
233
  - If replayable scripts exist, do not default to generation without user choice.
258
234
  - No hiding failures: surface errors and artifact paths.
259
235
  - **Always offer the agent-guidance reminder after every Electron run** (Step 9b) — pass or fail — unless 9a already routed the user into `muggle-feedback`. Never silently end a run without giving the user a one-click path to flag what was wrong.
260
- - Replay: never hand-built or simplified `actionScript` — only from `muggle-remote-action-script-get`.
236
+ - Replay/timeout discipline per [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md) — never hand-build `actionScript`; always pass `timeoutMs`.
261
237
  - Use `AskUserQuestion` for every selection — project, use case, test case, script. Never ask the user to type a number.
262
238
  - Project, use case, and test case selection lists must always include "Create new ...". Include "Show full list" whenever the API returned at least one row for that step; omit "Show full list" when the list is empty (offer "Create new ..." only). For creates, use preview tools (`muggle-remote-use-case-prompt-preview`, `muggle-remote-test-case-generate-from-prompt`) before persisting.
263
239
  - PR posting is always optional and always delegated to the `muggle:muggle-pr-visual-walkthrough` skill — never inline the walkthrough markdown or call `gh pr comment` directly from this skill.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-test-prepare
3
- description: "Make sure dev servers and sibling services are ready on the user's machine before running E2E acceptance tests. Checks which services need to be running, discovers sibling directories by folder name, verifies what's already listening, and offers to start anything that's missing — with the user's approval at every step. Use this skill whenever the user needs to prepare their local environment for E2E testing, verify their services are up, get their local dev stack ready, or when other muggle skills detect that required services are not listening on common ports. Triggers on: 'prepare for testing', 'make sure my services are running', 'check my local env', 'get ready for tests', 'are my services up', 'prepare local environment', 'spin up services', 'set up for E2E', 'verify my setup'. Also use when muggle-test, muggle-do, or muggle-test-feature-local need services running."
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."
4
4
  ---
5
5
 
6
6
  # Muggle Test Prepare
@@ -45,6 +45,8 @@ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
45
45
 
46
46
  `testing_scope` records what the user is testing (from [scope](./steps/scope.md)). `excluded_services` records services the user said can't run locally (from [viability-check](./steps/viability-check.md)).
47
47
 
48
+ This file is **ephemeral runtime state**, not the saved recipe. The durable plan lives at `<repo>/.muggle-ai/prepare-plan.json` (or the parent-dir-keyed entry in `~/.muggle-ai/prepare-plans.json`) and is consulted in [reuse-plan](./steps/reuse-plan.md) before any other stage. The two files never merge.
49
+
48
50
  **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
49
51
  - Option 1: "Keep them running — skip to testing"
50
52
  - Option 2: "Tear down and start fresh"
@@ -59,6 +61,7 @@ Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-ga
59
61
  | Preference | Gates |
60
62
  |------------|-------|
61
63
  | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
64
+ | `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover |
62
65
 
63
66
  ## Workflow
64
67
 
@@ -66,6 +69,7 @@ Run the stages in this order. The sequence number is display-only — it lives o
66
69
 
67
70
  | # | Stage | Summary |
68
71
  |:--|:------|:--------|
72
+ | 0 | [reuse-plan](./steps/reuse-plan.md) | Reuse saved prepare plan (gated); short-circuits to check-running on reuse |
69
73
  | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
70
74
  | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
71
75
  | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
@@ -6,7 +6,7 @@ Run port detection and (when an app declares a backend URL) backend-health probe
6
6
 
7
7
  If **all** required services are running, skip straight to [smoke-test](./smoke-test.md) — don't trust port-listening alone.
8
8
 
9
- If some are running, acknowledge and continue to [start-commands](./start-commands.md) only for the missing ones. For already-running services:
9
+ If some are running, acknowledge and continue to [start-commands](./start-commands.md) only for the missing ones. **Exception:** when this stage is entered via the [reuse-plan](./reuse-plan.md) short-circuit, the missing entries already have their `command` populated in `/tmp/muggle-test-prepare.json` from the reused plan — skip `start-commands` and go straight to [env-file](./env-file.md). For already-running services:
10
10
  - Option 1: "It's fine, keep it"
11
11
  - Option 2: "Restart it"
12
12
 
@@ -16,11 +16,13 @@ Mark kept services as `external: true` in the tracking file so cleanup leaves th
16
16
 
17
17
  When the user wants a port held by a process they did **not** select (typically a stale dev server from a sibling worktree):
18
18
 
19
- > "Port 3999 is held by PID 87421 (you didn't select this process). How do you want to proceed?"
19
+ The held process is likely something the user is still using — a current test or dev server they value more than this prepare run. Don't auto-decide; leave the kill-vs-pause call to them.
20
20
 
21
- - Option 1: "Use the next available port" (recommended — non-destructive)
22
- - Option 2: "Force-kill PID 87421 and claim port 3999"
23
- - Option 3: "Abort"
21
+ > "Port 3999 is held by PID 87421 (you didn't select this process — it may be a test or dev server you're still using). How do you want to proceed?"
22
+
23
+ - Option 1: "Use the next available port" (recommended — non-destructive, leaves the existing process running)
24
+ - Option 2: "Force-kill PID 87421 and claim port 3999" (kill-switch — only if you don't need that process)
25
+ - Option 3: "Pause — leave it running, I'll finish up and re-run prepare later"
24
26
 
25
27
  **Option 1**: probe `3999 + N` for `N = 1, 2, …` until nothing listens. Record the new port and any env file edit (`PORT=` in `.env.local` etc.). Dev server may need restart to pick up.
26
28
 
@@ -1,5 +1,7 @@
1
1
  # Identify required services & startup mode
2
2
 
3
+ > Skipped when [reuse-plan](./reuse-plan.md) short-circuits — a reused plan supplies the service list and startup mode.
4
+
3
5
  List folder names in the **parent directory** of the current working directory:
4
6
 
5
7
  ```bash
@@ -24,3 +24,33 @@ If you launched the services:
24
24
  Logs: /tmp/muggle-prepare-*.log
25
25
  Cleanup: say "stop services" or re-invoke this skill.
26
26
  ```
27
+
28
+ ## Save the plan
29
+
30
+ If this run came through discovery (i.e. Stage 0 [reuse-plan](./reuse-plan.md) did **not** short-circuit), persist the plan so the next run can skip the questions.
31
+
32
+ Build the JSON from the in-memory tracking file, dropping runtime fields:
33
+
34
+ ```bash
35
+ jq '{
36
+ version: 1,
37
+ updated: now | todate,
38
+ testing_scope: .testing_scope,
39
+ excluded_services: .excluded_services,
40
+ services: [.services[] | {name, dir, command, port}]
41
+ }' /tmp/muggle-test-prepare.json
42
+ ```
43
+
44
+ Resolve the write location:
45
+
46
+ - If `git rev-parse --show-toplevel` succeeds (call the result `$REPO`) → write `$REPO/.muggle-ai/prepare-plan.json`. Create `$REPO/.muggle-ai/` if missing.
47
+ - Else → upsert the entry under key `$(dirname "$PWD")` (absolute) in `~/.muggle-ai/prepare-plans.json`. Create the file as `{}` if missing.
48
+
49
+ Then print, once:
50
+
51
+ ```
52
+ ✓ Saved this stack as your prepare plan — next run can skip the questions.
53
+ (Disable with `/muggle-preferences reusePreparePlan`.)
54
+ ```
55
+
56
+ If this run short-circuited via [reuse-plan](./reuse-plan.md), don't rewrite — but **do** refresh `updated` and any `command` that was re-derived during validation. Skip the announcement on the refresh path.
@@ -0,0 +1,44 @@
1
+ # Stage 0 — reuse saved plan (or fall through)
2
+
3
+ A previously saved **prepare plan** is the durable recipe for this stack. Distinct from the ephemeral `/tmp/muggle-test-prepare.json` tracker — that file holds live PIDs/logs and is rebuilt every run.
4
+
5
+ ## Resolve
6
+
7
+ In order; first hit wins.
8
+
9
+ 1. **Project plan.** If `git rev-parse --show-toplevel` succeeds (call the result `$REPO`) and `$REPO/.muggle-ai/prepare-plan.json` exists → load it.
10
+ 2. **Global plan.** Else if `~/.muggle-ai/prepare-plans.json` exists, read the entry keyed by `$(dirname "$PWD")` (absolute path). If present → load that entry's value.
11
+ 3. **No plan found** → exit this step; the workflow continues at [rebase-check](./rebase-check.md).
12
+
13
+ A loaded plan is a JSON object with `version`, `updated`, `testing_scope`, `excluded_services`, `services`. Reject and treat as "no plan" if `version != 1` or `services` is empty.
14
+
15
+ ## Gate `reusePreparePlan`
16
+
17
+ Per [`muggle-preferences/preference-gates/README.md`](../../muggle-preferences/preference-gates/README.md). Read the current value from the `Muggle Test Preferences` session-context line; absent → `ask`.
18
+
19
+ - `always` → silently take the **reuse path** (below). Print the silent footer (substitute `{services}` with the comma-separated names from the loaded plan).
20
+ - `never` → take the **rediscover path**: exit this step; continue at [rebase-check](./rebase-check.md).
21
+ - `ask` → print the loaded plan as a table:
22
+
23
+ ```
24
+ Service Directory Command Port
25
+ ──────────────────────────────────────────────────────────────────────────────
26
+ backend-api ~/Github/backend-api npm run dev 3001
27
+ …
28
+ ──────────────────────────────────────────────────────────────────────────────
29
+ ```
30
+
31
+ Run Picker 1 from the gate file (substitute `{services}`). Then Picker 2 ("Remember this choice?") per the shared template. Branch by Picker 1.
32
+
33
+ ## Reuse path
34
+
35
+ 1. **Validate per service entry.** For each `{name, dir, command, port}`:
36
+ - `dir` exists → keep. Else drop the entry and log `"Dropped <name>: directory <dir> no longer exists"`.
37
+ - The indicator file that produced `command` still exists in `dir` (e.g. `package.json` for an `npm`/`node` command; see the indicator table in [start-commands](./start-commands.md)) → keep. Else re-derive **just that one entry** by running the indicator-detection from [start-commands](./start-commands.md) against `dir`, and replace its `command`. Log `"Re-derived <name>: <old> → <new>"`.
38
+ 2. **All entries dropped** → discard the plan; continue at [rebase-check](./rebase-check.md). Otherwise proceed with surviving + re-derived entries.
39
+ 3. **Hydrate** `/tmp/muggle-test-prepare.json` with the surviving entries (no PIDs yet, `testing_scope` from the plan, `excluded_services` from the plan).
40
+ 4. **Short-circuit** to [check-running](./check-running.md). The skipped stages are [scope](./scope.md), [viability-check](./viability-check.md), [identify-services](./identify-services.md), [start-commands](./start-commands.md) — the reused plan supplies their answers. The remaining stages run normally: [env-file](./env-file.md), [fresh-install](./fresh-install.md), [start-services](./start-services.md) (only for entries not already listening), [smoke-test](./smoke-test.md), [readiness-report](./readiness-report.md).
41
+
42
+ ## Rediscover path
43
+
44
+ Continue at [rebase-check](./rebase-check.md). The full normal flow runs.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "4.13.1",
3
- "buildId": "run-44-1",
4
- "commitSha": "2a73f80aae062cd7e19babb81f87727ccbd9aff7",
5
- "buildTime": "2026-05-28T07:33:33Z",
2
+ "release": "4.15.0",
3
+ "buildId": "run-46-1",
4
+ "commitSha": "59c2e1e75b899d5bbf78e7bbb2e2a0318c2e7e96",
5
+ "buildTime": "2026-06-02T05:38:12Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@muggleai/works",
3
3
  "mcpName": "io.github.multiplex-ai/muggle",
4
- "version": "4.13.1",
4
+ "version": "4.15.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.0.101",
44
+ "electronAppVersion": "1.0.109",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "2c73d9aa22740b6fc90f8dadccdc137c6fa87f1ce17ad5bcfd3f721b305c4807",
49
- "darwin-x64": "dcc5e05b8382a15058c691c109af313b07f91e6470bc4a5b7f789ba82e6b7fa3",
50
- "linux-x64": "24eeb304e5d302372984f1d2d0a15e337dcf949f7cfcd7b8c351c7d0d9d6e784",
51
- "win32-x64": "6a391b516eaf30052f84277b90fa12393d32c1428e3f87c2f0eca241e6504a93"
48
+ "darwin-arm64": "9c2fa21b4e090c8b6f1acedf1bdbd824f0032a5d91d6f9abd3ca25cebee7f417",
49
+ "darwin-x64": "3369988c627be5d362d5d9c8312f9902063a98a53d308695b40873211960501c",
50
+ "linux-x64": "a986757132b45a4299a44c3dd1f3945ba6814d299e677380e2061f18da44b511",
51
+ "win32-x64": "29ab5400d7dca049e4a3e75b76bc3e06398b88743f0a49d38fa6ae531fc980fe"
52
52
  }
53
53
  },
54
54
  "dependencies": {
@@ -71,6 +71,7 @@
71
71
  "@types/uuid": "^11.0.0",
72
72
  "@typescript-eslint/eslint-plugin": "^8.34.0",
73
73
  "@typescript-eslint/parser": "^8.34.0",
74
+ "@vitest/coverage-v8": "4.1.5",
74
75
  "eslint": "^10.2.0",
75
76
  "eslint-plugin-unused-imports": "^4.2.0",
76
77
  "rimraf": "^6.0.1",