@muggleai/works 5.8.0 → 5.9.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 (38) hide show
  1. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  2. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  3. package/dist/plugin/agents/test-prepare-runner.md +47 -0
  4. package/dist/plugin/agents/visual-walkthrough-builder.md +58 -0
  5. package/dist/plugin/hooks/hooks.json +6 -0
  6. package/dist/plugin/scripts/guardrail-watch-gate.sh +40 -0
  7. package/dist/plugin/scripts/guardrails.mjs +84 -2
  8. package/dist/plugin/scripts/pr-watch-guards.sh +17 -0
  9. package/dist/plugin/skills/CLAUDE.md +39 -36
  10. package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +5 -3
  11. package/dist/plugin/skills/muggle-pr-followup/blocked-tick.md +2 -2
  12. package/dist/plugin/skills/muggle-pr-followup/cancel-cron.md +5 -3
  13. package/dist/plugin/skills/muggle-pr-followup/contract.md +8 -2
  14. package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +30 -3
  15. package/dist/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  16. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +3 -1
  17. package/dist/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -236
  18. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
  19. package/dist/release-manifest.json +4 -4
  20. package/package.json +7 -6
  21. package/plugin/.claude-plugin/plugin.json +1 -1
  22. package/plugin/.cursor-plugin/plugin.json +1 -1
  23. package/plugin/agents/test-prepare-runner.md +47 -0
  24. package/plugin/agents/visual-walkthrough-builder.md +58 -0
  25. package/plugin/hooks/hooks.json +6 -0
  26. package/plugin/scripts/guardrail-watch-gate.sh +40 -0
  27. package/plugin/scripts/guardrails.mjs +84 -2
  28. package/plugin/scripts/pr-watch-guards.sh +17 -0
  29. package/plugin/skills/CLAUDE.md +39 -36
  30. package/plugin/skills/muggle-pr-followup/arm-watcher.md +5 -3
  31. package/plugin/skills/muggle-pr-followup/blocked-tick.md +2 -2
  32. package/plugin/skills/muggle-pr-followup/cancel-cron.md +5 -3
  33. package/plugin/skills/muggle-pr-followup/contract.md +8 -2
  34. package/plugin/skills/muggle-pr-followup/evals/evals.json +30 -3
  35. package/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  36. package/plugin/skills/muggle-pr-followup/state-schemas.md +3 -1
  37. package/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -236
  38. package/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
@@ -1,129 +1,130 @@
1
- ---
2
- name: muggle-test-prepare
3
- model: opus
4
- description: "Get a user's local environment ready before running E2E acceptance tests — verify the dev servers, APIs, and sibling services they need are up and responding, and offer to start whatever is missing (with approval per step). Trigger when the user wants to confirm specific ports or localhost URLs are listening before testing (check if localhost:3000 and the api on 8080 are up, are my services running), spin up their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not. This is environment readiness and service startup, not running the tests."
5
- ---
6
-
7
- # Muggle Test Prepare
8
-
9
- > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-test-prepare"`.
10
-
11
- Make sure the local services a user needs for E2E acceptance testing are up and ready. Check what's already running, discover sibling service directories by folder name, and offer to start anything that's missing — always with the user in control.
12
-
13
- Some users start their own services (tmux scripts, docker-compose, a terminal per service). Others want help launching them. This skill handles both: it verifies readiness first, and only offers to start things when something is missing.
14
-
15
- ## Privacy Boundary
16
-
17
- This skill touches the user's local machine — processes, ports, directories outside the current repo. Every action is explicit and confirmed.
18
-
19
- - **Folder names are public.** You may list directory names in a parent folder to discover sibling services.
20
- - **File contents are private until confirmed.** Never read files inside a directory the user hasn't explicitly identified as a service to start. Once confirmed, you may inspect only top-level project indicator files (`package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `docker-compose.yml`) to determine the start command.
21
- - **Never traverse upward more than one level** from the current working directory to list folders.
22
-
23
- ## PID Tracking
24
-
25
- All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
26
-
27
- ```json
28
- {
29
- "session_started": "2025-01-15T10:30:00Z",
30
- "testing_scope": "frontend",
31
- "excluded_services": [
32
- {"name": "payment-gateway", "reason": "Needs production certificates"}
33
- ],
34
- "services": [
35
- {
36
- "name": "backend-api",
37
- "dir": "/Users/user/Github/backend-api",
38
- "command": "npm run dev",
39
- "pid": 12345,
40
- "port": 3001,
41
- "log": "/tmp/muggle-prepare-backend-api.log"
42
- }
43
- ]
44
- }
45
- ```
46
-
47
- `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)).
48
-
49
- 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.
50
-
51
- **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
52
- - Option 1: "Keep them running — skip to testing"
53
- - Option 2: "Tear down and start fresh"
54
- - Option 3: "Add more services to the running set"
55
-
56
- Prune dead PIDs silently.
57
-
58
- ## Preferences
59
-
60
- Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-gates/README.md).
61
-
62
- | Preference | Gates |
63
- |------------|-------|
64
- | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
65
- | `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover |
66
- | `autoSelectLocalHost` | [check-running](./steps/check-running.md) — reuse the recorded dev-server URL silently, or confirm it each run |
67
-
68
- ## Workflow
69
-
70
- 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.
71
-
72
- | # | Stage | Summary |
73
- |:--|:------|:--------|
74
- | 0 | [reuse-plan](./steps/reuse-plan.md) | Reuse saved prepare plan (gated); short-circuits to check-running on reuse |
75
- | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
76
- | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
77
- | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
78
- | 4 | [identify-services](./steps/identify-services.md) | Pick required services + startup mode |
79
- | 5 | [check-running](./steps/check-running.md) | Detect what's already listening |
80
- | 6 | [env-file](./steps/env-file.md) | Env file present + correct |
81
- | 7 | [start-commands](./steps/start-commands.md) | Determine per-service start command |
82
- | 8 | [fresh-install](./steps/fresh-install.md) | Auto-install deps if missing/stale |
83
- | 9 | [start-services](./steps/start-services.md) | Launch + two-stage readiness |
84
- | 10 | [smoke-test](./steps/smoke-test.md) | HTTP + body sniff + log tail; clean-restart on fail |
85
- | 11 | [readiness-report](./steps/readiness-report.md) | Final ready table |
86
-
87
- ## Cleanup
88
-
89
- 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".
90
-
91
- 1. Read `/tmp/muggle-test-prepare.json`
92
- 2. Skip services marked `external: true`
93
- 3. For each managed service: `kill <pid>` (SIGTERM)
94
- 4. Wait ~2 s, verify with `kill -0`
95
- 5. If still alive: `kill -9 <pid>`
96
- 6. `rm -f /tmp/muggle-prepare-*.log`
97
- 7. `rm -f /tmp/muggle-test-prepare.json`
98
-
99
- Report:
100
-
101
- ```
102
- Stopped 3 services:
103
- backend-api (PID 12345)
104
- auth-service (PID 12346)
105
- frontend (PID 12347)
106
- ```
107
-
108
- ## Integration Contract (for other skills)
109
-
110
- `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.
111
-
112
- After a test run, the caller can re-invoke for cleanup or leave services running for the next run.
113
-
114
- ## Guardrails
115
-
116
- - **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess. Resolve it from `<repo>/.muggle-ai/last-host.json` (the [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md) cache) before probing ports; a framework default like `:3000` is never a fallback. See [check-running](./steps/check-running.md).
117
- - **No silent auto-selection without a gate** — when no preference authorizes a silent choice (host, restart, kill), confirm with the user. A gate set to `always` is the only license to skip the question; absent that, ask.
118
- - **Verify first, offer to start second** — check what's already running before proposing to start anything.
119
- - **The user may prefer to start services themselves** — always offer that option.
120
- - **Never start a process the user didn't approve.**
121
- - **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
122
- - **Never leave orphan processes untracked** — every background PID goes into the tracking file.
123
- - **Never kill a process the user started independently** — `external: true` survives cleanup.
124
- - **Never assume start commands** — verify via indicator file; confirm with user.
125
- - **Bail early on non-viable services** — don't start what can't run locally.
126
- - **Idempotent** — already-tracked alive services are kept; [smoke-test](./steps/smoke-test.md) still runs against them.
127
- - **Port-listening is never enough** — smoke-test (HTTP + body sniff + log tail) is mandatory before the final report.
128
- - **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.
129
- - **Fresh install is automatic** — [fresh-install](./steps/fresh-install.md) notifies, doesn't ask.
1
+ ---
2
+ name: muggle-test-prepare
3
+ model: opus
4
+ description: "Get a user's local environment ready before running E2E acceptance tests — verify the dev servers, APIs, and sibling services they need are up and responding, and offer to start whatever is missing (with approval per step). Trigger when the user wants to confirm specific ports or localhost URLs are listening before testing (check if localhost:3000 and the api on 8080 are up, are my services running), spin up their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not. This is environment readiness and service startup, not running the tests."
5
+ ---
6
+
7
+ # Muggle Test Prepare
8
+
9
+ > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-test-prepare"`.
10
+
11
+ Make sure the local services a user needs for E2E acceptance testing are up and ready. Check what's already running, discover sibling service directories by folder name, and offer to start anything that's missing — always with the user in control.
12
+
13
+ Some users start their own services (tmux scripts, docker-compose, a terminal per service). Others want help launching them. This skill handles both: it verifies readiness first, and only offers to start things when something is missing.
14
+
15
+ The skill runs in two phases because a dispatched agent has no channel back to the user. **Decide (in-session):** resolve every choice that needs a human — plan reuse, scope, exclusions, service selection, start approvals. **Execute (agent):** hand the fully-resolved plan to the `test-prepare-runner` agent (`plugin/agents/test-prepare-runner.md`); it runs the mechanical stages headless and returns the readiness verdict, or a `needs-input:` line for any decision the plan left open.
16
+
17
+ ## Privacy Boundary
18
+
19
+ This skill touches the user's local machine — processes, ports, directories outside the current repo. Every action is explicit and confirmed.
20
+
21
+ - **Folder names are public.** You may list directory names in a parent folder to discover sibling services.
22
+ - **File contents are private until confirmed.** Never read files inside a directory the user hasn't explicitly identified as a service to start. Once confirmed, you may inspect only top-level project indicator files (`package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `docker-compose.yml`) to determine the start command.
23
+ - **Never traverse upward more than one level** from the current working directory to list folders.
24
+
25
+ ## PID Tracking
26
+
27
+ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
28
+
29
+ ```json
30
+ {
31
+ "session_started": "2025-01-15T10:30:00Z",
32
+ "testing_scope": "frontend",
33
+ "excluded_services": [
34
+ {"name": "payment-gateway", "reason": "Needs production certificates"}
35
+ ],
36
+ "services": [
37
+ {
38
+ "name": "backend-api",
39
+ "dir": "/Users/user/Github/backend-api",
40
+ "command": "npm run dev",
41
+ "pid": 12345,
42
+ "port": 3001,
43
+ "log": "/tmp/muggle-prepare-backend-api.log"
44
+ }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ `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)).
50
+
51
+ 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. The `test-prepare-runner` agent writes this file during execution; the triage below and Cleanup read it.
52
+
53
+ **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
54
+ - Option 1: "Keep them running — skip to testing"
55
+ - Option 2: "Tear down and start fresh"
56
+ - Option 3: "Add more services to the running set"
57
+
58
+ Prune dead PIDs silently.
59
+
60
+ ## Preferences
61
+
62
+ Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-gates/README.md). All three resolve in the Decide phase; the agent receives outcomes, never gates.
63
+
64
+ | Preference | Gates |
65
+ |------------|-------|
66
+ | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
67
+ | `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover |
68
+ | `autoSelectLocalHost` | [check-running](./steps/check-running.md) — reuse the recorded dev-server URL silently, or confirm it each run |
69
+
70
+ ## Workflow
71
+
72
+ **Decide (in-session).** Run these stages in order; read each detail file when you reach it:
73
+
74
+ | # | Stage | Summary |
75
+ |:--|:------|:--------|
76
+ | 0 | [reuse-plan](./steps/reuse-plan.md) | Reuse saved prepare plan (gated); on reuse, skip straight to dispatch |
77
+ | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
78
+ | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
79
+ | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
80
+ | 4 | [identify-services](./steps/identify-services.md) | Pick required services + startup mode |
81
+
82
+ The Decide phase's output is the **resolved prepare plan**: `services[]` (name, dir, start command, expected port, `external` flag, approval granted), `testingScope`, `excludedServices[]`, the recorded dev-server URL, and resolved gate outcomes.
83
+
84
+ **Execute (agent).** Dispatch the `test-prepare-runner` agent (subagent type `muggle:test-prepare-runner`; bare `test-prepare-runner` where the plugin namespace is absent), synchronously, passing the resolved plan; it returns `READY` / `DEGRADED` plus the readiness table. The agent's own definition lists its stage files; in a harness with no agent/subagent facility, run the execute-phase stages ([check-running](./steps/check-running.md) through [readiness-report](./steps/readiness-report.md)) inline instead.
85
+
86
+ Relay the readiness table to the user or calling skill verbatim. A `needs-input:` line from the agent names an unresolved decision — resolve it here (asking the user if needed) and re-dispatch; the agent never asks.
87
+
88
+ ## Cleanup
89
+
90
+ 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". Runs in-session, not in the agent.
91
+
92
+ 1. Read `/tmp/muggle-test-prepare.json`
93
+ 2. Skip services marked `external: true`
94
+ 3. For each managed service: `kill <pid>` (SIGTERM)
95
+ 4. Wait ~2 s, verify with `kill -0`
96
+ 5. If still alive: `kill -9 <pid>`
97
+ 6. `rm -f /tmp/muggle-prepare-*.log`
98
+ 7. `rm -f /tmp/muggle-test-prepare.json`
99
+
100
+ Report:
101
+
102
+ ```
103
+ Stopped 3 services:
104
+ backend-api (PID 12345)
105
+ auth-service (PID 12346)
106
+ frontend (PID 12347)
107
+ ```
108
+
109
+ ## Integration Contract (for other skills)
110
+
111
+ `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.
112
+
113
+ After a test run, the caller can re-invoke for cleanup or leave services running for the next run.
114
+
115
+ ## Guardrails
116
+
117
+ - **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess. Resolve it from `<repo>/.muggle-ai/last-host.json` (the [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md) cache) before probing ports; a framework default like `:3000` is never a fallback. See [check-running](./steps/check-running.md).
118
+ - **No silent auto-selection without a gate** — when no preference authorizes a silent choice (host, restart, kill), confirm with the user. A gate set to `always` is the only license to skip the question; absent that, ask.
119
+ - **Verify first, offer to start second** — check what's already running before proposing to start anything.
120
+ - **The user may prefer to start services themselves** — always offer that option.
121
+ - **Never start a process the user didn't approve** — approvals are granted in Decide and travel in the plan; the agent starts nothing outside it.
122
+ - **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
123
+ - **Never leave orphan processes untracked** — every background PID goes into the tracking file.
124
+ - **Never kill a process the user started independently** — `external: true` survives cleanup.
125
+ - **Never assume start commands** — verify via indicator file; confirm with user.
126
+ - **Bail early on non-viable services** — don't start what can't run locally.
127
+ - **Idempotent** — already-tracked alive services are kept; [smoke-test](./steps/smoke-test.md) still runs against them.
128
+ - **Port-listening is never enough** — smoke-test (HTTP + body sniff + log tail) is mandatory before the final report.
129
+ - **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.
130
+ - **Fresh install is automatic** — [fresh-install](./steps/fresh-install.md) notifies, doesn't ask.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "5.8.0",
3
- "buildId": "run-67-1",
4
- "commitSha": "f0fbb486a0d7886d880eaec3129bc53964524f01",
5
- "buildTime": "2026-08-01T07:54:45Z",
2
+ "release": "5.9.0",
3
+ "buildId": "run-69-1",
4
+ "commitSha": "65137194ea9b71fb5eb97ae290869357a826b51d",
5
+ "buildTime": "2026-08-04T22:00:43Z",
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": "5.8.0",
4
+ "version": "5.9.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",
@@ -43,17 +43,18 @@
43
43
  "test": "vitest run",
44
44
  "test:watch": "vitest",
45
45
  "test:gates:behavioral": "tsx internal/skill-gate-eval/src/run.ts",
46
+ "test:agents:behavioral": "tsx internal/agent-gate-eval/src/run.ts",
46
47
  "eval:studio-gen": "tsx internal/studio-gen-eval/src/run.ts"
47
48
  },
48
49
  "muggleConfig": {
49
- "electronAppVersion": "1.6.11",
50
+ "electronAppVersion": "1.6.12",
50
51
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
51
52
  "runtimeTargetDefault": "production",
52
53
  "checksums": {
53
- "darwin-arm64": "97f7f5ba622dc3baf86457184bc44030c777d7dbac58b8c1c5418970662e7a07",
54
- "darwin-x64": "c8c2745282583144b34110ef45c4745e03c03c4ac2e020c820daa51124c3fc50",
55
- "linux-x64": "d85e14ed38cb8035b932aef26148934e3aec6e036b6bb80ff8927cbde901a935",
56
- "win32-x64": "6e38a5b017ee5756985e1507def6c5a92d357a4bbd4e4032b6e490ad05dd09a2"
54
+ "darwin-arm64": "d313b881b6f448b968c838a3b9bea4d8f226c60b703c377514d37f33d0dacd66",
55
+ "darwin-x64": "31f316bdcc97dbc764a9656fc3003a2640c613d6ce1f8ba1a73564987235f2f1",
56
+ "linux-x64": "1d06dfbf66ea97f55abfb6e3cd8a3edbea2c7c6bf75acbbd607039e7c6dae69b",
57
+ "win32-x64": "ff1150431afad2717e30d419d4ba15df79d20e10ae48a6293f71a723c7b3159a"
57
58
  }
58
59
  },
59
60
  "dependencies": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "muggle",
3
3
  "description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
4
- "version": "5.8.0",
4
+ "version": "5.9.0",
5
5
  "author": {
6
6
  "name": "Muggle AI",
7
7
  "email": "support@muggle-ai.com"
@@ -2,7 +2,7 @@
2
2
  "name": "muggle",
3
3
  "displayName": "Muggle AI",
4
4
  "description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
5
- "version": "5.8.0",
5
+ "version": "5.9.0",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: test-prepare-runner
3
+ description: "Executes a fully-resolved Muggle Test prepare plan — detects what's listening, verifies env files, fresh-installs stale deps, starts approved services, smoke-tests, and returns the readiness table. Dispatched by the muggle-test-prepare skill after all user decisions are resolved; carries the opus pin so execution never runs below its reliability floor on a cheaper session model."
4
+ model: opus
5
+ ---
6
+
7
+ # Test Prepare Runner
8
+
9
+ You bring a local dev stack to verified readiness for E2E testing: detect what's already listening, verify env files, install stale dependencies, start approved services, smoke-test them, and report the readiness table. Every decision — which services, their directories, start commands and approvals, scope, exclusions, the dev-server URL — arrives resolved in the dispatch prompt from the muggle-test-prepare skill. You have no channel to the user: when the plan is missing a decision you need, return one `needs-input:` line naming it and stop — the dispatching skill resolves it (asking the user if needed) and re-dispatches.
10
+
11
+ ## Input contract
12
+
13
+ The dispatch prompt carries the resolved prepare plan:
14
+
15
+ - `services[]` — name, dir, start command, expected port, `external` flag, approval already granted.
16
+ - `testingScope` and `excludedServices[]` (with reasons).
17
+ - The recorded dev-server URL (from the `autoSelectLocalHost` resolution) — never invent or default a host/port; a framework default like `:3000` is not a fallback.
18
+ - Resolved gate values the stages read (`autoRebase` outcome already applied or explicitly skipped upstream).
19
+
20
+ ## Stages
21
+
22
+ Run these stage files from the skill, in order, exactly as written — they are the single source of truth for each stage's procedure:
23
+
24
+ 1. [`../skills/muggle-test-prepare/steps/check-running.md`](../skills/muggle-test-prepare/steps/check-running.md)
25
+ 2. [`../skills/muggle-test-prepare/steps/env-file.md`](../skills/muggle-test-prepare/steps/env-file.md)
26
+ 3. [`../skills/muggle-test-prepare/steps/start-commands.md`](../skills/muggle-test-prepare/steps/start-commands.md)
27
+ 4. [`../skills/muggle-test-prepare/steps/fresh-install.md`](../skills/muggle-test-prepare/steps/fresh-install.md)
28
+ 5. [`../skills/muggle-test-prepare/steps/start-services.md`](../skills/muggle-test-prepare/steps/start-services.md)
29
+ 6. [`../skills/muggle-test-prepare/steps/smoke-test.md`](../skills/muggle-test-prepare/steps/smoke-test.md)
30
+ 7. [`../skills/muggle-test-prepare/steps/readiness-report.md`](../skills/muggle-test-prepare/steps/readiness-report.md)
31
+
32
+ Where a stage file offers the user a choice, take the branch the plan resolved; where the plan doesn't cover it, return `needs-input:` — never guess, never start anything unapproved.
33
+
34
+ ## PID tracking
35
+
36
+ Track every launched process in `/tmp/muggle-test-prepare.json` exactly per the skill's schema (`session_started`, `testing_scope`, `excluded_services`, `services[]` with pid/port/log). Processes the user started independently stay `external: true` and are never killed. Prune dead PIDs silently.
37
+
38
+ ## Output contract
39
+
40
+ Return the readiness-report table verbatim as your report, prefixed by one line: `READY` (all services green), `DEGRADED: <which service, why>` (something is up but failed its smoke test after the clean-restart loop), or `needs-input: <decision>`. The dispatcher relays this to its caller — other skills gate on it, so a wrong `READY` is expensive; when in doubt between READY and DEGRADED, pick DEGRADED and say why. `needs-input:` is only for a decision the plan failed to resolve (a missing URL, an unapproved start, an unknown directory) — a service that stays broken after the loop is `DEGRADED` with the diagnosis, never `needs-input:`, even when no further automated fix exists. Repairing the app's own source code is out of scope entirely: a source-level bug surfaced by the smoke test is a `DEGRADED` diagnosis to report, not a decision to escalate.
41
+
42
+ ## Guardrails
43
+
44
+ - Privacy boundary as the skill defines it: file contents only inside directories the plan names; never traverse upward past one level.
45
+ - Port-listening is never enough — smoke-test (HTTP + body sniff + log tail) is mandatory before the report.
46
+ - Clean Restart is the first fix in the smoke-test loop; fresh-install notifies, doesn't ask.
47
+ - Never leave an orphan process untracked; never kill an `external` one.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: visual-walkthrough-builder
3
+ description: "Renders the Muggle Test E2E visual walkthrough for a PR — assembles the E2eReport, runs `muggle build-pr-section`, and either posts to the PR (Mode A) or returns the rendered block to the dispatcher (Modes B/C). Dispatched by the muggle-pr-visual-walkthrough skill; carries its sonnet pin so the render runs on sonnet regardless of the session model."
4
+ model: sonnet
5
+ ---
6
+
7
+ # Visual Walkthrough Builder
8
+
9
+ You render and (in Mode A) post the Muggle Test E2E visual walkthrough. The dispatching skill has already resolved the mode, the PR, and user consent. You have no channel to the user: if an input you need is missing, return a single `needs-input:` line naming it and stop — the dispatching skill resolves it and re-dispatches.
10
+
11
+ ## Input contract
12
+
13
+ The dispatch prompt carries:
14
+
15
+ - `mode` — `post` (Mode A), `render-for-new-pr` (Mode B), or `embed` (Mode C).
16
+ - `prNumber` + repo — Mode A only, already verified to exist.
17
+ - The `E2eReport` JSON inline, **or** the run identifiers (`projectId`, per-test `runId`/`testCaseId` list) to assemble it from.
18
+
19
+ When assembling from identifiers, follow [`../skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md`](../skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md). The `E2eReport` schema, required fields, and the inconclusive rule live there and in the CLI's Zod schema (`src/cli/pr-section/types.ts`) — a run that couldn't produce pass/fail is `inconclusive` with a `reason`, never dropped.
20
+
21
+ ## Render
22
+
23
+ Pipe the report to the CLI; it writes `{"body": "...", "comment": "..." | null}`:
24
+
25
+ ```bash
26
+ echo "$REPORT_JSON" | muggle build-pr-section > /tmp/muggle-pr-section.json
27
+ ```
28
+
29
+ - Non-zero exit → surface the CLI's stderr verbatim; do not swallow or retry blindly.
30
+ - `comment` is non-null only in the overflow case; the CLI owns fit-vs-overflow.
31
+
32
+ ## Deliver
33
+
34
+ **Mode A (`post`)** — post `body` as a PR comment, then `comment` only if non-null. Append the Muggle Works signature to each posted body per [`../skills/_shared/vcs/post-signature.md`](../skills/_shared/vcs/post-signature.md) — this post is the walkthrough's own, so the command it names is `/muggle-pr-visual-walkthrough`:
35
+
36
+ ```bash
37
+ sig='🤖 _Posted by `/muggle-pr-visual-walkthrough` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_'
38
+ { jq -r '.body' /tmp/muggle-pr-section.json; printf '\n\n%s\n' "$sig"; } | gh pr comment <prNumber> --body-file -
39
+ { jq -r '.comment' /tmp/muggle-pr-section.json; printf '\n\n%s\n' "$sig"; } | gh pr comment <prNumber> --body-file - # skip when null
40
+ ```
41
+
42
+ Report back: PR URL + whether an overflow comment was posted.
43
+
44
+ **Modes B/C (`render-for-new-pr` / `embed`)** — do not post, do not touch `gh`. Return the CLI output verbatim as your report:
45
+
46
+ ```
47
+ body:
48
+ <body>
49
+ comment:
50
+ <comment or null>
51
+ ```
52
+
53
+ ## Guardrails
54
+
55
+ - Never hand-write or modify the walkthrough markdown — the CLI is the single source of truth. No custom tables, no added "Verdict" lines, no `Tested on:`/`Project:` footers; the CLI computes the verdict and emits per-test dashboard links.
56
+ - Never invent report fields — missing `projectId`, `viewUrl`, or `screenshotUrl` → `needs-input:`, never a placeholder.
57
+ - Never post the overflow comment when `comment` is null.
58
+ - Never create a PR, never choose a mode — both belong to the dispatcher.
@@ -110,6 +110,12 @@
110
110
  "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/guardrail-terminal-gate.sh\"",
111
111
  "async": false,
112
112
  "timeout": 10
113
+ },
114
+ {
115
+ "type": "command",
116
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/guardrail-watch-gate.sh\"",
117
+ "async": false,
118
+ "timeout": 10
113
119
  }
114
120
  ]
115
121
  }
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+
4
+ # watcher-arm gate (Stop). When a PR was opened this session but no watcher was
5
+ # armed for it, block the turn end and point at the Stage-8 hand-off (or the
6
+ # MUGGLE_WATCH_SKIP escape hatch). Mirrors guardrail-e2e-gate.sh: synchronous
7
+ # (only a sync Stop hook can block the turn end), fires on EVERY turn end, and
8
+ # pre-filters in shell so Node spawns only when a PR was opened this session and
9
+ # no skip was recorded. The real owed-vs-armed decision (a sessions/*/ slot scan)
10
+ # runs in guardrails.mjs. On the overwhelming majority of turns no PR was opened,
11
+ # so the state file is absent or prsHandled is empty and we return {} in-shell,
12
+ # never paying Node cold-start. Degrades to {}.
13
+ payload="$(cat)"
14
+
15
+ raw_sid="$(printf '%s' "$payload" | grep -oE '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/')"
16
+ [ -n "$raw_sid" ] || raw_sid="unknown"
17
+ sid="$(printf '%s' "$raw_sid" | sed 's/[^A-Za-z0-9_-]/_/g')"
18
+
19
+ # Resolve the same home dir Node's os.homedir() uses. HOME is correct on
20
+ # macOS/Linux and on most Git Bash setups; fall back to converting USERPROFILE
21
+ # when HOME doesn't hold the state dir (some Windows shells point HOME elsewhere).
22
+ home="${HOME:-}"
23
+ if [ ! -d "$home/.muggle-ai" ] && command -v cygpath >/dev/null 2>&1 && [ -n "${USERPROFILE:-}" ]; then
24
+ home="$(cygpath -u "$USERPROFILE" 2>/dev/null || printf '%s' "$home")"
25
+ fi
26
+
27
+ # Empty array serializes as `"prsHandled": []` (one line); a non-empty array spans
28
+ # lines, so the empty match reliably tells them apart. Skip Node unless a PR was
29
+ # opened this session and no watcher skip was recorded.
30
+ state_file="$home/.muggle-ai/guardrails/$sid.json"
31
+ if [ ! -f "$state_file" ] \
32
+ || ! grep -q '"prsHandled"' "$state_file" \
33
+ || grep -q '"prsHandled": \[\]' "$state_file" \
34
+ || grep -q '"watchSkipped": true' "$state_file"; then
35
+ printf '{}'
36
+ exit 0
37
+ fi
38
+
39
+ root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
40
+ printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" watch-gate 2>/dev/null || printf '{}'