@muggleai/works 4.12.2 → 4.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{chunk-I4VLYJ7M.js → chunk-CPF6AR2I.js} +499 -147
  2. package/dist/{chunk-2DVZ2LYO.js → chunk-JNI7INIO.js} +2 -2
  3. package/dist/cli.js +2 -2
  4. package/dist/index.js +2 -2
  5. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  6. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  7. package/dist/plugin/skills/_shared/dev-server-readiness.md +39 -0
  8. package/dist/plugin/skills/_shared/failure-mode-handling.md +19 -4
  9. package/dist/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +1 -0
  10. package/dist/plugin/skills/_shared/pr-branch-worktree.md +31 -0
  11. package/dist/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
  12. package/dist/plugin/skills/muggle-feedback/ops/submit.md +1 -1
  13. package/dist/plugin/skills/muggle-pr-followup/contract.md +3 -2
  14. package/dist/plugin/skills/muggle-test/SKILL.md +7 -3
  15. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
  16. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +40 -256
  17. package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +31 -0
  18. package/dist/plugin/skills/muggle-test-prepare/steps/env-file.md +18 -0
  19. package/dist/plugin/skills/muggle-test-prepare/steps/fresh-install.md +20 -0
  20. package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +28 -0
  21. package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +26 -0
  22. package/dist/plugin/skills/muggle-test-prepare/steps/rebase-check.md +3 -0
  23. package/dist/plugin/skills/muggle-test-prepare/steps/scope.md +11 -0
  24. package/dist/plugin/skills/muggle-test-prepare/steps/smoke-test.md +26 -0
  25. package/dist/plugin/skills/muggle-test-prepare/steps/start-commands.md +29 -0
  26. package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +21 -0
  27. package/dist/plugin/skills/muggle-test-prepare/steps/viability-check.md +21 -0
  28. package/dist/release-manifest.json +4 -4
  29. package/dist/{src-ARTTHWNP.js → src-YR5UKLPC.js} +1 -1
  30. package/package.json +6 -6
  31. package/plugin/.claude-plugin/plugin.json +1 -1
  32. package/plugin/.cursor-plugin/plugin.json +1 -1
  33. package/plugin/skills/_shared/dev-server-readiness.md +39 -0
  34. package/plugin/skills/_shared/failure-mode-handling.md +19 -4
  35. package/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +1 -0
  36. package/plugin/skills/_shared/pr-branch-worktree.md +31 -0
  37. package/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
  38. package/plugin/skills/muggle-feedback/ops/submit.md +1 -1
  39. package/plugin/skills/muggle-pr-followup/contract.md +3 -2
  40. package/plugin/skills/muggle-test/SKILL.md +7 -3
  41. package/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
  42. package/plugin/skills/muggle-test-prepare/SKILL.md +40 -256
  43. package/plugin/skills/muggle-test-prepare/steps/check-running.md +31 -0
  44. package/plugin/skills/muggle-test-prepare/steps/env-file.md +18 -0
  45. package/plugin/skills/muggle-test-prepare/steps/fresh-install.md +20 -0
  46. package/plugin/skills/muggle-test-prepare/steps/identify-services.md +28 -0
  47. package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +26 -0
  48. package/plugin/skills/muggle-test-prepare/steps/rebase-check.md +3 -0
  49. package/plugin/skills/muggle-test-prepare/steps/scope.md +11 -0
  50. package/plugin/skills/muggle-test-prepare/steps/smoke-test.md +26 -0
  51. package/plugin/skills/muggle-test-prepare/steps/start-commands.md +29 -0
  52. package/plugin/skills/muggle-test-prepare/steps/start-services.md +21 -0
  53. package/plugin/skills/muggle-test-prepare/steps/viability-check.md +21 -0
@@ -43,266 +43,52 @@ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
43
43
  }
44
44
  ```
45
45
 
46
- The `testing_scope` field records what the user is testing (from Step 1). The `excluded_services` field records services the user said can't run locally (from Step 2), so other skills understand what's intentionally absent vs. forgotten.
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
- **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), present the running services and ask:
49
-
50
- Use `AskUserQuestion`:
48
+ **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
51
49
  - Option 1: "Keep them running — skip to testing"
52
50
  - Option 2: "Tear down and start fresh"
53
51
  - Option 3: "Add more services to the running set"
54
52
 
55
- Prune any dead PIDs silently (the process crashed on its own — no point asking about it).
53
+ Prune dead PIDs silently.
56
54
 
57
55
  ## Preferences
58
56
 
59
57
  Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-gates/README.md).
60
58
 
61
- | Preference | Step | Decision it gates |
62
- |------------|------|-------------------|
63
- | `autoRebase` | 0 | Rebase onto `origin/<default>` before starting dev servers (see [`_shared/rebase-before-e2e.md`](../_shared/rebase-before-e2e.md)) |
59
+ | Preference | Gates |
60
+ |------------|-------|
61
+ | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
64
62
 
65
63
  ## Workflow
66
64
 
67
- ### Step 0: Rebase check (gated by `autoRebase`)
68
-
69
- Fire per [`_shared/rebase-before-e2e.md`](../_shared/rebase-before-e2e.md) when `behind > 0`. Otherwise skip silently.
70
-
71
- ### Step 1: What Are You Testing?
72
-
73
- Before discovering services, understand the shape of the testing so you can scope correctly. Use `AskUserQuestion`:
74
-
75
- > "What are you testing locally?"
76
-
77
- - Option 1: "A frontend feature — I need the UI and its backend dependencies running"
78
- - Option 2: "A backend API — I just need the API server running"
79
- - Option 3: "The full stack — everything needs to be up"
80
-
81
- This scopes the rest of the workflow. If the user is testing a backend API, they probably don't need a frontend dev server. If they're testing a frontend feature, they need the frontend plus whatever backends it talks to. Keep this answer in mind when presenting service candidates in Step 3 — pre-check the ones that match and leave the rest unchecked.
82
-
83
- ### Step 2: Viability Check
84
-
85
- Some services can't run on a developer's machine by design — they need production secrets, HSMs, specific certificates, or cloud-only infrastructure. Don't waste time trying to discover or start them.
86
-
87
- **If the user already volunteered this information** in their initial message (e.g., "the payment-gateway can't run locally"), acknowledge it and skip the question — don't re-ask what they already answered.
88
-
89
- Otherwise, use `AskUserQuestion`:
90
-
91
- > "Are there any services in your stack that **can't** run locally? (e.g., needs production secrets, specific certificates, or cloud-only infra)"
92
-
93
- - Option 1: "All my services can run locally"
94
- - Option 2: "Some can't — I'll tell you which"
95
-
96
- If the user picks option 2, collect the names. Acknowledge them and exclude from discovery.
97
-
98
- If an excluded service is a hard dependency for the app under test, **suggest testing in a preview/staging environment instead** — the user can merge first and use `/muggle-test` in remote mode, where everything is already up and running. Frame it as an alternative, not a dead end:
99
-
100
- > "Since **payment-gateway** can't run locally, you might get better coverage by merging and running `/muggle-test` against your preview environment — everything's wired up there. Want to continue with a partial local setup, or switch to remote testing?"
101
-
102
- - Option 1: "Continue locally — I'll work around the missing service"
103
- - Option 2: "Switch to remote — I'll merge and test on preview"
104
-
105
- If the user chooses remote, hand off to `/muggle-test` in remote mode and exit this skill.
106
-
107
- ### Step 3: Identify Required Services & How to Start Them
108
-
109
- Figure out which services need to be running. Start by listing folder names in the **parent directory** of the current working directory — these are the most likely candidates.
110
-
111
- ```bash
112
- ls -d "$(dirname "$PWD")"/*/ | xargs -I{} basename {}
113
- ```
114
-
115
- Present folder names only (not contents) as candidates. Use `AskUserQuestion` with `multiSelect: true`:
116
-
117
- > "Which of these need to be running for your tests?"
118
-
119
- List each folder name as an option. Pre-check the ones that match the testing scope from Step 1 (e.g., if testing a frontend feature, pre-check the frontend and likely backends). Always include these fixed tail options:
120
- - "Just the current project (no other services needed)"
121
- - "None of these — I'll tell you what I need"
122
-
123
- If the user provides manual paths, verify they exist before continuing. If a path doesn't exist, report it and ask for correction.
124
-
125
- **Include the current working directory as a candidate** — the user might be editing the backend but also need the frontend (a sibling) started, or vice versa.
126
-
127
- **Immediately after the user selects services**, ask how they want to handle startup. This avoids making someone who prefers their own scripts wait through command detection before they get to say "I'll handle it."
128
-
129
- Use `AskUserQuestion`:
130
-
131
- > "How do you want to handle these?"
132
-
133
- - Option 1: "Check what's running, start what's missing for me"
134
- - Option 2: "I'll start them myself — just verify they're up when I'm done"
135
-
136
- If the user picks **option 2**: skip Steps 4-6. Wait for them to confirm they're ready, then go straight to Step 4 (Check What's Already Running) to verify everything is listening, and report readiness (Step 7).
137
-
138
- If the user picks **option 1**: proceed through Steps 4-7 as normal.
139
-
140
- ### Step 4: Check What's Already Running
141
-
142
- Run port detection and (when the app declares a backend URL) backend-health probe per [`_shared/dev-server-readiness.md`](../_shared/dev-server-readiness.md). Cross-reference hits against the selected service directories. If a selected service appears to already be running (match by port or by the process's working directory), report it as ready:
143
-
144
- > "**backend-api** is already listening on port 3001 (PID 54321) — looks good."
145
-
146
- If **all** required services are already running, report readiness and skip straight to Step 7. No need to go through Steps 5-6.
147
-
148
- If some are running and some aren't, acknowledge the running ones and continue to Step 5 only for the missing services. Use `AskUserQuestion` for any already-running service the user might want restarted:
149
- - Option 1: "It's fine, keep it"
150
- - Option 2: "Restart it"
151
-
152
- For services that are already running and the user wants to keep, add them to the PID tracking file so cleanup can find them later, but mark them as `external: true` so cleanup knows not to kill them (the user started them independently).
153
-
154
- **Port already held** — when the user wants a port that is currently held by a process they did **not** select (typically a stale dev server from a sibling worktree). Surface the conflict via `AskUserQuestion`:
155
-
156
- > "Port 3999 is held by PID 87421 (you didn't select this process). How do you want to proceed?"
157
-
158
- - Option 1: "Use the next available port" (recommended — non-destructive)
159
- - Option 2: "Force-kill PID 87421 and claim port 3999"
160
- - Option 3: "Abort"
161
-
162
- **Option 1 — next available port:** probe `3999 + N` for `N = 1, 2, 3, ...` until `Test-NetConnection`/`lsof -i :<port>` returns nothing listening. Record the new port (and the env file edit, if `PORT=` is set in `.env.local` etc.) so downstream steps use it. The dev server may need a restart to pick up the new value.
163
-
164
- **Option 2 — force-kill (destructive):**
165
- - **Windows PowerShell:** `Get-NetTCPConnection -LocalPort <port> -ErrorAction SilentlyContinue | ForEach-Object { try { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue } catch { } }`
166
- - **POSIX:** `lsof -ti:<port> 2>/dev/null | xargs -r kill -9`
167
-
168
- Re-verify the port is free before continuing.
169
-
170
- ### Step 4.5: Environment File Sanity
171
-
172
- The env file is **per-repo** — don't hardcode `.env.local`. Detect it: scan `package.json` `scripts/*` for `.env*` literals and known port vars (`PORT=`, `VITE_PORT=`); check framework config (`next.config.*`, `vite.config.*`).
173
-
174
- When a dependency on an env file exists:
175
-
176
- 1. Check whether `<cwd>/<envfile>` exists. If yes, no-op.
177
- 2. If absent, `git worktree list --porcelain` and check each sibling for the same filename.
178
- 3. If found, surface via `AskUserQuestion`:
179
-
180
- > "`<envfile>` is missing in this worktree but exists at `<sibling>/<envfile>`. Copy it before starting services?"
181
-
182
- - Option 1: "Yes — copy from `<sibling>`"
183
- - Option 2: "No — I'll provide it another way"
184
-
185
- 4. If not found anywhere, report and ask how to proceed.
186
-
187
- Skip silently when no env file is referenced. The point is to catch the common worktree-bootstrap miss, not to mandate any specific file.
188
-
189
- ### Step 5: Determine Start Commands
190
-
191
- For each required service that isn't already running, figure out how to start it. Propose the command so there's a shared understanding.
192
-
193
- Read **only** the indicator file that exists — don't read additional files.
194
-
195
- **Detection order:**
196
-
197
- | Indicator | Stack | Default command | What to check |
198
- |:----------|:------|:----------------|:--------------|
199
- | `package.json` | Node.js | `npm run dev` | Read `scripts` field: prefer `dev` > `start` > `serve` |
200
- | `Makefile` | Various | `make dev` | Just check existence; propose `make dev` or `make run` |
201
- | `Cargo.toml` | Rust | `cargo run` | Just check existence |
202
- | `go.mod` | Go | `go run .` | Just check existence |
203
- | `pyproject.toml` | Python | Check for framework | Read `[project.scripts]` or `[tool.poetry.scripts]` if present |
204
- | `requirements.txt` | Python | `python app.py` | Just check existence |
205
- | `docker-compose.yml` | Docker | `docker compose up` | Just check existence |
206
-
207
- If no indicator file is found, tell the user and ask them to provide the start command manually.
208
-
209
- **Present all proposed commands in a single summary:**
210
-
211
- ```
212
- Service Directory Command
213
- ────────────────────────────────────────────────────────────────
214
- backend-api ~/Github/backend-api npm run dev
215
- auth-service ~/Github/auth-service go run .
216
- frontend ~/Github/frontend npm run dev
217
- ────────────────────────────────────────────────────────────────
218
- ```
219
-
220
- Use `AskUserQuestion`:
221
- - Option 1: "Looks good, start them"
222
- - Option 2: "I need to edit some commands"
223
-
224
- If the user needs edits, collect corrections and re-present.
225
-
226
- ### Step 5.5: Fresh-Worktree Install Probe
227
-
228
- Before launching `npm run dev` (or equivalent) in a Node service, check whether `node_modules/` is present and current. Stale or missing `node_modules/` causes silent runtime failures that look like the service is broken when actually the install is just missing.
229
-
230
- For each Node service the user selected:
231
-
232
- 1. If `<service-dir>/node_modules/` is missing entirely → install is required.
233
- 2. If `<service-dir>/package-lock.json` is newer than `<service-dir>/node_modules/.package-lock.json` → install is stale.
234
- 3. Otherwise → install is current, no action needed.
235
-
236
- When install is required or stale, propose via `AskUserQuestion`:
237
-
238
- > "`<service-name>` needs a fresh `npm install` before starting (node_modules is missing/stale). Run `npm install --prefer-offline --no-audit --no-fund` now?"
239
-
240
- - Option 1: "Yes — install now"
241
- - Option 2: "No — skip; I know it's fine"
242
-
243
- **Never symlink `node_modules/` from a sibling worktree.** webpack's `resolve.symlinks: true` default rewrites paths to the shared real location; asset-identity tracking fails with `Can't handle conflicting asset info for sourceFilename`. Run a real per-worktree install.
244
-
245
- For non-Node services (Go, Rust, Python), skip this probe — their build systems handle dependency caching differently.
246
-
247
- ### Step 6: Start Services
248
-
249
- For each service, launch in the background:
250
-
251
- ```bash
252
- cd "<service-dir>" && nohup <command> > /tmp/muggle-prepare-<service-name>.log 2>&1 &
253
- echo $!
254
- ```
255
-
256
- Capture the PID. Write all service entries to `/tmp/muggle-test-prepare.json`.
257
-
258
- **Startup verification** — first confirm the PID is alive (`kill -0 <pid> 2>/dev/null`), then run the two-stage readiness probe per [`_shared/dev-server-readiness.md`](../_shared/dev-server-readiness.md) against `/tmp/muggle-prepare-<service-name>.log`. Cap log-tail at 60s. Halt on whatever it surfaces; do not re-implement the ready-signal patterns here.
259
-
260
- If a service's PID dies immediately, read the last 20 lines of its log and show the user:
261
-
262
- > "**backend-api** exited right after starting. Here's the tail of its log:"
263
-
264
- Then ask how to proceed:
265
- - Option 1: "Skip it and continue with the others"
266
- - Option 2: "Let me fix it — I'll re-invoke later"
267
-
268
- **Port discovery** — if the port isn't known upfront, after the service starts, re-scan listening ports and try to identify which new port appeared. Record it in the tracking file if found. If not found within ~10 seconds, note the port as unknown — the service may take longer to boot.
269
-
270
- ### Step 7: Report Readiness
271
-
272
- Whether you started the services or the user did, confirm that everything is listening:
273
-
274
- ```
275
- Service PID Port Status
276
- ──────────────────────────────────────────────
277
- backend-api 12345 3001 Running
278
- auth-service 12346 8080 Running
279
- frontend 12347 3000 Running
280
- ──────────────────────────────────────────────
281
- All 3 services verified. Ready for E2E testing.
282
- ```
283
-
284
- If you launched the services, also show:
285
- ```
286
- Logs: /tmp/muggle-prepare-*.log
287
- Cleanup: say "stop services" or re-invoke this skill.
288
- ```
65
+ Run the stages in this order. The sequence number is display-only — it lives only in this table for at-a-glance ordering; detail files and cross-references use slugs. Each row links to its detail file; read the file when you reach the stage.
66
+
67
+ | # | Stage | Summary |
68
+ |:--|:------|:--------|
69
+ | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
70
+ | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
71
+ | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
72
+ | 4 | [identify-services](./steps/identify-services.md) | Pick required services + startup mode |
73
+ | 5 | [check-running](./steps/check-running.md) | Detect what's already listening |
74
+ | 6 | [env-file](./steps/env-file.md) | Env file present + correct |
75
+ | 7 | [start-commands](./steps/start-commands.md) | Determine per-service start command |
76
+ | 8 | [fresh-install](./steps/fresh-install.md) | Auto-install deps if missing/stale |
77
+ | 9 | [start-services](./steps/start-services.md) | Launch + two-stage readiness |
78
+ | 10 | [smoke-test](./steps/smoke-test.md) | HTTP + body sniff + log tail; clean-restart on fail |
79
+ | 11 | [readiness-report](./steps/readiness-report.md) | Final ready table |
289
80
 
290
81
  ## Cleanup
291
82
 
292
- Cleanup is triggered when:
293
- - The user says "stop services", "tear down", "clean up", or "I'm done testing"
294
- - Another skill signals that a test run is complete
295
- - This skill is re-invoked and the user chooses "tear down and start fresh"
296
-
297
- **Cleanup steps:**
83
+ Triggered when the user says "stop services", "tear down", "clean up", "I'm done testing", another skill signals run complete, or this skill is re-invoked with "tear down and start fresh".
298
84
 
299
85
  1. Read `/tmp/muggle-test-prepare.json`
300
- 2. Skip any services marked `external: true` (the user started them independently)
301
- 3. For each managed service, send `SIGTERM`: `kill <pid>`
302
- 4. Wait ~2 seconds, verify with `kill -0`
303
- 5. If still alive, `kill -9 <pid>`
304
- 6. Remove log files: `rm -f /tmp/muggle-prepare-*.log`
305
- 7. Remove the tracking file: `rm -f /tmp/muggle-test-prepare.json`
86
+ 2. Skip services marked `external: true`
87
+ 3. For each managed service: `kill <pid>` (SIGTERM)
88
+ 4. Wait ~2 s, verify with `kill -0`
89
+ 5. If still alive: `kill -9 <pid>`
90
+ 6. `rm -f /tmp/muggle-prepare-*.log`
91
+ 7. `rm -f /tmp/muggle-test-prepare.json`
306
92
 
307
93
  Report:
308
94
 
@@ -315,23 +101,21 @@ Stopped 3 services:
315
101
 
316
102
  ## Integration Contract (for other skills)
317
103
 
318
- When `muggle-test`, `muggle-do`, or `muggle-test-feature-local` want to check if services are ready:
319
-
320
- 1. Check if `/tmp/muggle-test-prepare.json` exists
321
- 2. Verify PIDs are alive with `kill -0`
322
- 3. If all live → services are ready, proceed to test execution
323
- 4. If missing or stale → invoke `muggle-test-prepare`
104
+ `muggle-test-feature-local`, `muggle-do`, and local-mode `muggle-test` MUST invoke this skill before any workflow step. Idempotent — fast exit when healthy. Treat success as short-lived; re-invoke if more than a few minutes pass before testing. Never bypass on "the user knows their stack is up" — that assumption is why this skill exists.
324
105
 
325
- After a test run completes, the calling skill can invoke cleanup by re-invoking this skill with cleanup intent, or leave services running for the next run (the user chose lifecycle management, not clean-state resets).
106
+ After a test run, the caller can re-invoke for cleanup or leave services running for the next run.
326
107
 
327
108
  ## Guardrails
328
109
 
329
- - **Verify first, offer to start second** — always check what's already running before proposing to start anything. If everything is up, just confirm readiness and move on.
330
- - **The user may prefer to start services themselves** — always offer that option. Some developers have their own startup scripts, tmux layouts, or docker-compose setups they'd rather use.
331
- - **Never start a process the user didn't approve** — every command is presented and confirmed before execution.
110
+ - **Verify first, offer to start second** — check what's already running before proposing to start anything.
111
+ - **The user may prefer to start services themselves** — always offer that option.
112
+ - **Never start a process the user didn't approve.**
332
113
  - **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
333
114
  - **Never leave orphan processes untracked** — every background PID goes into the tracking file.
334
- - **Never kill a process the user started independently** — services marked `external: true` survive cleanup.
335
- - **Never assume start commands** — always verify by checking project indicator files; always confirm with the user.
336
- - **Bail early on non-viable services** — don't attempt to start something the user said can't run locally.
337
- - **Idempotent** — if services are already tracked and alive, offer to keep them rather than double-starting.
115
+ - **Never kill a process the user started independently** — `external: true` survives cleanup.
116
+ - **Never assume start commands** — verify via indicator file; confirm with user.
117
+ - **Bail early on non-viable services** — don't start what can't run locally.
118
+ - **Idempotent** — already-tracked alive services are kept; [smoke-test](./steps/smoke-test.md) still runs against them.
119
+ - **Port-listening is never enough** — smoke-test (HTTP + body sniff + log tail) is mandatory before the final report.
120
+ - **Clean Restart is the recommended fix** — first option in the smoke-test diagnose-and-fix loop; lint/build/missing-deps issues need nuke-and-reinstall.
121
+ - **Fresh install is automatic** — [fresh-install](./steps/fresh-install.md) notifies, doesn't ask.
@@ -0,0 +1,31 @@
1
+ # Check what's already running
2
+
3
+ Run port detection and (when an app declares a backend URL) backend-health probe per [`../../_shared/dev-server-readiness.md`](../../_shared/dev-server-readiness.md). Cross-reference hits against selected service directories.
4
+
5
+ > "**backend-api** is already listening on port 3001 (PID 54321) — looks good."
6
+
7
+ If **all** required services are running, skip straight to [smoke-test](./smoke-test.md) — don't trust port-listening alone.
8
+
9
+ If some are running, acknowledge and continue to [start-commands](./start-commands.md) only for the missing ones. For already-running services:
10
+ - Option 1: "It's fine, keep it"
11
+ - Option 2: "Restart it"
12
+
13
+ Mark kept services as `external: true` in the tracking file so cleanup leaves them alone.
14
+
15
+ ## Port already held
16
+
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
+
19
+ > "Port 3999 is held by PID 87421 (you didn't select this process). How do you want to proceed?"
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"
24
+
25
+ **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
+
27
+ **Option 2 — force-kill (destructive):**
28
+ - **Windows PowerShell:** `Get-NetTCPConnection -LocalPort <port> -ErrorAction SilentlyContinue | ForEach-Object { try { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue } catch { } }`
29
+ - **POSIX:** `lsof -ti:<port> 2>/dev/null | xargs -r kill -9`
30
+
31
+ Re-verify the port is free before continuing.
@@ -0,0 +1,18 @@
1
+ # Environment file sanity
2
+
3
+ The env file is **per-repo** — don't hardcode `.env.local`. Detect by scanning `package.json` `scripts/*` for `.env*` literals and known port vars (`PORT=`, `VITE_PORT=`); check framework config (`next.config.*`, `vite.config.*`).
4
+
5
+ When a dependency on an env file exists:
6
+
7
+ 1. Check `<cwd>/<envfile>` exists — if yes, no-op.
8
+ 2. If absent, `git worktree list --porcelain` and check each sibling for the same filename.
9
+ 3. If found:
10
+
11
+ > "`<envfile>` is missing in this worktree but exists at `<sibling>/<envfile>`. Copy it before starting services?"
12
+
13
+ - Option 1: "Yes — copy from `<sibling>`"
14
+ - Option 2: "No — I'll provide it another way"
15
+
16
+ 4. If not found anywhere, report and ask.
17
+
18
+ Skip silently when no env file is referenced.
@@ -0,0 +1,20 @@
1
+ # Fresh install (clean-start default)
2
+
3
+ Detect stack by indicator file, decide if install is missing/stale, run automatically (notify, don't ask). Only opt-out is aborting the skill.
4
+
5
+ | Indicator | Stack | Stale check | Install command |
6
+ |:----------|:------|:------------|:----------------|
7
+ | `package.json` | Node | `node_modules/` missing OR `package-lock.json` newer than `node_modules/.package-lock.json` | `npm install --prefer-offline --no-audit --no-fund` |
8
+ | `pyproject.toml` w/ `[tool.poetry]` | Poetry | `poetry.lock` newer than `.venv/pyvenv.cfg` (or `.venv/` missing) | `poetry install --no-interaction` |
9
+ | `pyproject.toml` (PEP 621) + `uv.lock` | uv | `uv.lock` newer than `.venv/pyvenv.cfg` | `uv sync` |
10
+ | `requirements.txt` | pip | `requirements.txt` newer than `.venv/pyvenv.cfg` (or `.venv/` missing) | `pip install -r requirements.txt` |
11
+ | `Gemfile` | Bundler | `Gemfile.lock` newer than `vendor/bundle/` mtime | `bundle install` |
12
+ | `composer.json` | Composer | `composer.lock` newer than `vendor/autoload.php` | `composer install --no-interaction` |
13
+ | `pom.xml` | Maven | always (heavy — opt-in via `AskUserQuestion`) | `mvn -DskipTests install` |
14
+ | `build.gradle*` | Gradle | always (heavy — opt-in via `AskUserQuestion`) | `gradle build -x test` |
15
+ | `go.mod` | Go | skip — `go run`/`go build` handle deps | |
16
+ | `Cargo.toml` | Rust | skip — `cargo run`/`cargo build` handle deps | |
17
+
18
+ Notify one-liner: `Installing <service-name> (<stack>: <missing|stale>)…`.
19
+
20
+ **Never symlink dep dirs** (`node_modules/`, `.venv/`, `vendor/bundle/`) from a sibling worktree — webpack rewrites paths via `resolve.symlinks: true` and Python/Ruby tooling has analogous issues. Run a real per-worktree install.
@@ -0,0 +1,28 @@
1
+ # Identify required services & startup mode
2
+
3
+ List folder names in the **parent directory** of the current working directory:
4
+
5
+ ```bash
6
+ ls -d "$(dirname "$PWD")"/*/ | xargs -I{} basename {}
7
+ ```
8
+
9
+ Present folder names only (not contents). `AskUserQuestion` with `multiSelect: true`:
10
+
11
+ > "Which of these need to be running for your tests?"
12
+
13
+ Pre-check the ones matching the testing scope from [scope](./scope.md). Always include:
14
+ - "Just the current project (no other services needed)"
15
+ - "None of these — I'll tell you what I need"
16
+
17
+ Include the current working directory as a candidate. If the user provides manual paths, verify they exist.
18
+
19
+ **Immediately after selection**, ask startup mode:
20
+
21
+ > "How do you want to handle these?"
22
+
23
+ - Option 1: "Check what's running, start what's missing for me"
24
+ - Option 2: "I'll start them myself — just verify they're up when I'm done"
25
+
26
+ **Option 2**: skip [start-commands](./start-commands.md), [fresh-install](./fresh-install.md), [start-services](./start-services.md). Wait for ready signal, then [check-running](./check-running.md), run [smoke-test](./smoke-test.md) against everything (the user-started case is exactly where the smoke test matters most), then [readiness-report](./readiness-report.md).
27
+
28
+ **Option 1**: proceed through the normal flow.
@@ -0,0 +1,26 @@
1
+ # Final readiness report
2
+
3
+ Only after every service passes [smoke-test](./smoke-test.md) or is skipped.
4
+
5
+ ```
6
+ Service PID Port Status Smoke Test
7
+ ─────────────────────────────────────────────────────────────────
8
+ backend-api 12345 3001 Running ✓
9
+ auth-service 12346 8080 Running ✓
10
+ frontend 12347 3000 Running ✓
11
+ ─────────────────────────────────────────────────────────────────
12
+ All services verified. Ready for E2E.
13
+ ```
14
+
15
+ Surface skipped services so the caller knows the gap:
16
+
17
+ ```
18
+ Skipped: payment-gateway — HTTP 500 on /
19
+ ```
20
+
21
+ If you launched the services:
22
+
23
+ ```
24
+ Logs: /tmp/muggle-prepare-*.log
25
+ Cleanup: say "stop services" or re-invoke this skill.
26
+ ```
@@ -0,0 +1,3 @@
1
+ # Rebase check
2
+
3
+ Gated by `autoRebase`. Fire per [`../../_shared/rebase-before-e2e.md`](../../_shared/rebase-before-e2e.md) when `behind > 0`. Otherwise skip silently.
@@ -0,0 +1,11 @@
1
+ # Scope (what are you testing?)
2
+
3
+ `AskUserQuestion`:
4
+
5
+ > "What are you testing locally?"
6
+
7
+ - Option 1: "A frontend feature — I need the UI and its backend dependencies running"
8
+ - Option 2: "A backend API — I just need the API server running"
9
+ - Option 3: "The full stack — everything needs to be up"
10
+
11
+ Scopes the rest of the workflow. Record under `testing_scope` in the tracking file. Use it later to pre-check matching service candidates in [identify-services](./identify-services.md).
@@ -0,0 +1,26 @@
1
+ # Comprehensive smoke test
2
+
3
+ Runs for **every** service in the tracking file, including `external: true`. Port-listening is not proof a service works — a stale dev server binds and returns 200 with a webpack error overlay.
4
+
5
+ All three probes must pass:
6
+
7
+ 1. **HTTP** — `GET <serviceUrl>`, 3 s timeout, accept `2xx`/`3xx` (one redirect).
8
+ 2. **Body sniff** — match response body against broken-build markers in [`../../_shared/dev-server-readiness.md`](../../_shared/dev-server-readiness.md) → "Body sniff patterns".
9
+ 3. **Log tail** — scan last 200 lines of `/tmp/muggle-prepare-<service-name>.log` for failure patterns after the latest ready signal. Skip for `external: true` (no log).
10
+
11
+ Use the primitives in `dev-server-readiness.md`. Don't re-implement.
12
+
13
+ ## Diagnose-and-fix loop
14
+
15
+ On failure, show the concrete signal (HTTP code, sniff hit, or log line) and `AskUserQuestion`:
16
+
17
+ > "**<service-name>** isn't healthy: `<signal>`. How do you want to proceed?"
18
+
19
+ - Option 1: **Clean restart** (Recommended) — kill + [fresh-install](./fresh-install.md) + [start-services](./start-services.md) + re-run this step
20
+ - Option 2: **Restart only** — kill + start-services + re-run this step
21
+ - Option 3: **I'll fix it manually** — pause; re-run on user signal
22
+ - Option 4: **Skip** — append to `excluded_services` with reason, continue
23
+
24
+ Loop per service until pass or skip. Cap at **3 iterations** — then force a manual-intervention pause.
25
+
26
+ For `external: true`, only Options 3 and 4 apply.
@@ -0,0 +1,29 @@
1
+ # Determine start commands
2
+
3
+ For each required service not already running, figure out how to start it. Read **only** the indicator file that exists.
4
+
5
+ | Indicator | Stack | Default command | What to check |
6
+ |:----------|:------|:----------------|:--------------|
7
+ | `package.json` | Node.js | `npm run dev` | Read `scripts`: prefer `dev` > `start` > `serve` |
8
+ | `Makefile` | Various | `make dev` | Existence; propose `make dev` or `make run` |
9
+ | `Cargo.toml` | Rust | `cargo run` | Existence |
10
+ | `go.mod` | Go | `go run .` | Existence |
11
+ | `pyproject.toml` | Python | Check for framework | Read `[project.scripts]` or `[tool.poetry.scripts]` if present |
12
+ | `requirements.txt` | Python | `python app.py` | Existence |
13
+ | `docker-compose.yml` | Docker | `docker compose up` | Existence |
14
+
15
+ If no indicator found, ask the user for the start command.
16
+
17
+ Present all commands in a single summary:
18
+
19
+ ```
20
+ Service Directory Command
21
+ ────────────────────────────────────────────────────────────────
22
+ backend-api ~/Github/backend-api npm run dev
23
+ auth-service ~/Github/auth-service go run .
24
+ frontend ~/Github/frontend npm run dev
25
+ ────────────────────────────────────────────────────────────────
26
+ ```
27
+
28
+ - Option 1: "Looks good, start them"
29
+ - Option 2: "I need to edit some commands"
@@ -0,0 +1,21 @@
1
+ # Start services
2
+
3
+ For each service, launch in the background:
4
+
5
+ ```bash
6
+ cd "<service-dir>" && nohup <command> > /tmp/muggle-prepare-<service-name>.log 2>&1 &
7
+ echo $!
8
+ ```
9
+
10
+ Capture the PID. Write all service entries to `/tmp/muggle-test-prepare.json`.
11
+
12
+ **Startup verification** — confirm PID alive (`kill -0 <pid> 2>/dev/null`), then run the two-stage readiness probe per [`../../_shared/dev-server-readiness.md`](../../_shared/dev-server-readiness.md) against the log. Cap log-tail at 60 s. Halt on whatever surfaces.
13
+
14
+ If a PID dies immediately, show the last 20 log lines:
15
+
16
+ > "**backend-api** exited right after starting. Here's the tail of its log:"
17
+
18
+ - Option 1: "Skip it and continue with the others"
19
+ - Option 2: "Let me fix it — I'll re-invoke later"
20
+
21
+ **Port discovery** — if the port wasn't known upfront, re-scan listening ports after startup. Record in tracking file. If not found within ~10 s, mark port unknown.
@@ -0,0 +1,21 @@
1
+ # Viability check
2
+
3
+ Some services can't run on a developer's machine by design — production secrets, HSMs, specific certificates, cloud-only infra. Don't waste time trying to start them.
4
+
5
+ If the user volunteered this in their initial message, acknowledge and skip the question. Otherwise:
6
+
7
+ > "Are there any services in your stack that **can't** run locally? (e.g., needs production secrets, specific certificates, or cloud-only infra)"
8
+
9
+ - Option 1: "All my services can run locally"
10
+ - Option 2: "Some can't — I'll tell you which"
11
+
12
+ If option 2, collect names and exclude from discovery.
13
+
14
+ If an excluded service is a hard dependency for the app under test, suggest remote testing:
15
+
16
+ > "Since **payment-gateway** can't run locally, you might get better coverage by merging and running `/muggle-test` against your preview environment. Want to continue with a partial local setup, or switch to remote testing?"
17
+
18
+ - Option 1: "Continue locally — I'll work around the missing service"
19
+ - Option 2: "Switch to remote — I'll merge and test on preview"
20
+
21
+ If remote, hand off to `/muggle-test` in remote mode and exit.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "4.12.2",
3
- "buildId": "run-40-1",
4
- "commitSha": "9039582dcc85172dff58bcebc185d8aaa495f947",
5
- "buildTime": "2026-05-22T04:16:07Z",
2
+ "release": "4.12.4",
3
+ "buildId": "run-42-1",
4
+ "commitSha": "184a2b0b2eec344362e3ebb2a909684c4790f5d5",
5
+ "buildTime": "2026-05-22T23:47:18Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
@@ -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-I4VLYJ7M.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-CPF6AR2I.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@muggleai/works",
3
3
  "mcpName": "io.github.multiplex-ai/muggle",
4
- "version": "4.12.2",
4
+ "version": "4.12.4",
5
5
  "description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -41,14 +41,14 @@
41
41
  "test:watch": "vitest"
42
42
  },
43
43
  "muggleConfig": {
44
- "electronAppVersion": "1.0.93",
44
+ "electronAppVersion": "1.0.94",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "79edb82904ff247a3176d7f25e6aea879bde0befe9f50ae1c977f9de01e09278",
49
- "darwin-x64": "2b13541aee90eec7cff3e0d92a963fa2508f91a195aee3774edd851f69a45442",
50
- "linux-x64": "438d8c80602c6c9746a2b5a11c9236d11997827ca74376e0e0fef1952f38640c",
51
- "win32-x64": "6ccac8d05d40ce6d6b976f3079cbc7ca4bb3714d3d5b67776a72cd9bbf324f53"
48
+ "darwin-arm64": "22731d8fac9b3ce7dc0490932a099fad0b7bab901e4efe3c2f8e44b4dd165bdb",
49
+ "darwin-x64": "0965f1a3f7b0db6a976650e26de024f0baea58102cf9acc93e8c69c6dfd8709f",
50
+ "linux-x64": "5280ae8ac73215f1c4f92d3b280eee0918341179485993493bd04f3f5a95b5b5",
51
+ "win32-x64": "a02bf08ba6f5463b1dad354824c6369738248e86ce5ef02644d2185fdc2d047f"
52
52
  }
53
53
  },
54
54
  "dependencies": {