@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.
- package/dist/{chunk-I4VLYJ7M.js → chunk-CPF6AR2I.js} +499 -147
- package/dist/{chunk-2DVZ2LYO.js → chunk-JNI7INIO.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/skills/_shared/dev-server-readiness.md +39 -0
- package/dist/plugin/skills/_shared/failure-mode-handling.md +19 -4
- package/dist/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +1 -0
- package/dist/plugin/skills/_shared/pr-branch-worktree.md +31 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
- package/dist/plugin/skills/muggle-feedback/ops/submit.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/contract.md +3 -2
- package/dist/plugin/skills/muggle-test/SKILL.md +7 -3
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/dist/plugin/skills/muggle-test-prepare/SKILL.md +40 -256
- package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +31 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/env-file.md +18 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/fresh-install.md +20 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +28 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +26 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/rebase-check.md +3 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/scope.md +11 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/smoke-test.md +26 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/start-commands.md +29 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +21 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/viability-check.md +21 -0
- package/dist/release-manifest.json +4 -4
- package/dist/{src-ARTTHWNP.js → src-YR5UKLPC.js} +1 -1
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/skills/_shared/dev-server-readiness.md +39 -0
- package/plugin/skills/_shared/failure-mode-handling.md +19 -4
- package/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +1 -0
- package/plugin/skills/_shared/pr-branch-worktree.md +31 -0
- package/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
- package/plugin/skills/muggle-feedback/ops/submit.md +1 -1
- package/plugin/skills/muggle-pr-followup/contract.md +3 -2
- package/plugin/skills/muggle-test/SKILL.md +7 -3
- package/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/plugin/skills/muggle-test-prepare/SKILL.md +40 -256
- package/plugin/skills/muggle-test-prepare/steps/check-running.md +31 -0
- package/plugin/skills/muggle-test-prepare/steps/env-file.md +18 -0
- package/plugin/skills/muggle-test-prepare/steps/fresh-install.md +20 -0
- package/plugin/skills/muggle-test-prepare/steps/identify-services.md +28 -0
- package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +26 -0
- package/plugin/skills/muggle-test-prepare/steps/rebase-check.md +3 -0
- package/plugin/skills/muggle-test-prepare/steps/scope.md +11 -0
- package/plugin/skills/muggle-test-prepare/steps/smoke-test.md +26 -0
- package/plugin/skills/muggle-test-prepare/steps/start-commands.md +29 -0
- package/plugin/skills/muggle-test-prepare/steps/start-services.md +21 -0
- package/plugin/skills/muggle-test-prepare/steps/viability-check.md +21 -0
|
@@ -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": "4.12.
|
|
4
|
+
"version": "4.12.4",
|
|
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": "4.12.
|
|
5
|
+
"version": "4.12.4",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -49,6 +49,45 @@ netstat -ano | findstr /R /C:":3000 " /C:":3001 " /C:":4200 " /C:":5173 " /C:":8
|
|
|
49
49
|
|
|
50
50
|
If the app declares a backend URL in its env file, probe the backend's health endpoint before treating the dev server as usable. 5xx or unreachable → halt; the frontend may render but its data layer is dead, so any query against it is meaningless.
|
|
51
51
|
|
|
52
|
+
## Body sniff patterns
|
|
53
|
+
|
|
54
|
+
A `200 OK` can still be a build-error overlay or stack trace. Search the response body (case-insensitive) for broken-build markers — a match means unhealthy regardless of status.
|
|
55
|
+
|
|
56
|
+
| Stack | Pattern (regex) |
|
|
57
|
+
|:------|:----------------|
|
|
58
|
+
| Next.js | `__next_error__\|Failed to compile\|webpack-internal://` |
|
|
59
|
+
| Vite | `vite-error-overlay\|Internal server error\|\[plugin:` |
|
|
60
|
+
| Node / Express | `MODULE_NOT_FOUND\|Cannot find module\|npm ERR!\|Cannot GET /\|Cannot POST /\|Error: ENOENT\|EACCES\|EADDRINUSE` |
|
|
61
|
+
| Django | `TemplateSyntaxError\|ProgrammingError at /\|<h1>Server Error \(500\)</h1>` |
|
|
62
|
+
| Flask | `Werkzeug Debugger\|werkzeug-debug` |
|
|
63
|
+
| FastAPI / Python | `Traceback \(most recent call last\)\|ModuleNotFoundError\|ImportError` |
|
|
64
|
+
| Rails | `Better Errors\|ActionController::RoutingError\|<title>Action Controller:` |
|
|
65
|
+
| Spring Boot | `Whitelabel Error Page` |
|
|
66
|
+
| Tomcat | `HTTP Status 500.*Apache Tomcat` |
|
|
67
|
+
| Laravel / PHP | `Whoops\\\\|<b>Fatal error</b>\|Parse error:\|Stack trace:` |
|
|
68
|
+
| JS stack frame | `at .*\(.*\.[jt]sx?:\d+:\d+\)` |
|
|
69
|
+
| Java stack frame | `at \w+(\.\w+)+\(\w+\.java:\d+\)` |
|
|
70
|
+
| Python stack frame | `File ".*", line \d+, in ` |
|
|
71
|
+
| Ruby stack frame | `\.rb:\d+:in ` |
|
|
72
|
+
|
|
73
|
+
The bash/PowerShell snippets below use the union of all patterns above. Trim per-stack when you know the target.
|
|
74
|
+
|
|
75
|
+
#### bash/zsh
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
BODY=$(curl -sS -L --max-redirs 1 --max-time 3 "$URL")
|
|
79
|
+
PATTERN='__next_error__|Failed to compile|webpack-internal://|vite-error-overlay|Internal server error|MODULE_NOT_FOUND|Cannot find module|Cannot GET /|npm ERR!|Error: ENOENT|EACCES|EADDRINUSE|TemplateSyntaxError|Werkzeug Debugger|Traceback \(most recent call last\)|ModuleNotFoundError|ImportError|Better Errors|ActionController::RoutingError|Whitelabel Error Page|Apache Tomcat|Whoops|<b>Fatal error</b>|Parse error:|Stack trace:|at .*\(.*\.[jt]sx?:[0-9]+:[0-9]+\)|at \w+(\.\w+)+\(\w+\.java:[0-9]+\)|File ".*", line [0-9]+, in |\.rb:[0-9]+:in '
|
|
80
|
+
echo "$BODY" | grep -qiE "$PATTERN" && { echo "BODY-SNIFF FAIL"; echo "$BODY" | grep -iE "$PATTERN" | head -3; exit 1; }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### PowerShell
|
|
84
|
+
|
|
85
|
+
```powershell
|
|
86
|
+
$body = (Invoke-WebRequest -Uri $url -TimeoutSec 3 -MaximumRedirection 1 -ErrorAction Stop).Content
|
|
87
|
+
$pattern = '__next_error__|Failed to compile|webpack-internal://|vite-error-overlay|Internal server error|MODULE_NOT_FOUND|Cannot find module|Cannot GET /|npm ERR!|Error: ENOENT|EACCES|EADDRINUSE|TemplateSyntaxError|Werkzeug Debugger|Traceback \(most recent call last\)|ModuleNotFoundError|ImportError|Better Errors|ActionController::RoutingError|Whitelabel Error Page|Apache Tomcat|Whoops|<b>Fatal error</b>|Parse error:|Stack trace:|at .*\(.*\.[jt]sx?:\d+:\d+\)|at \w+(\.\w+)+\(\w+\.java:\d+\)|File ".*", line \d+, in |\.rb:\d+:in '
|
|
88
|
+
if ($body -imatch $pattern) { Write-Host "BODY-SNIFF FAIL"; [regex]::Matches($body, $pattern, 'IgnoreCase') | Select-Object -First 3 | ForEach-Object { $_.Value }; exit 1 }
|
|
89
|
+
```
|
|
90
|
+
|
|
52
91
|
## Two-stage readiness — after starting a dev server
|
|
53
92
|
|
|
54
93
|
Network reachability is necessary but not sufficient. Many dev servers bind to a port before build/startup work is complete. Wait for **both** network readiness and application readiness before issuing requests.
|
|
@@ -109,9 +109,15 @@ Triggered when `muggle-local-execute-replay` returns `status: "failed"` (or non-
|
|
|
109
109
|
| **stale-script** | The test script no longer matches the live UI (selectors moved, label paths changed, page renamed). The product still works; the script is out of date. |
|
|
110
110
|
| **product-defect** | The script and infra are fine; the user's app actually misbehaved (assertion failure on previously-passing step, unexpected error, wrong page after action). This is the failure mode acceptance testing exists to catch. |
|
|
111
111
|
|
|
112
|
-
###
|
|
112
|
+
### Where to read signals
|
|
113
|
+
|
|
114
|
+
Call `muggle-local-run-result-get` (local) or the remote equivalent and read **structured fields**, not `execute`'s response stdout tail (it's a truncated display excerpt and routinely cuts off mid-sentence). Order:
|
|
113
115
|
|
|
114
|
-
|
|
116
|
+
1. `Status` + `Error` — the verdict and the one-line cause.
|
|
117
|
+
2. `Artifacts` section, when present — opens `artifactsDir`. Read `results.md` (step-by-step + screenshot links) for the per-step verdict, then `action-script.json` for what the agent attempted.
|
|
118
|
+
3. `stdout.log` / `stderr.log` only when the Artifacts section is absent or `results.md` doesn't exist (e.g. early Electron failure).
|
|
119
|
+
|
|
120
|
+
### Initial signal heuristics
|
|
115
121
|
|
|
116
122
|
- **infra** signals: `electron-crash`, `chromium-error`, `click-no-effect-on-clickable-element`, `timeout-on-trivial-wait`, `internal-error-in-mcp-output`.
|
|
117
123
|
- **stale-script** signals: `element-not-found`, `selector-timeout`, `label-path-mismatch`, `nav-target-404`, `aria-label-changed`.
|
|
@@ -189,9 +195,18 @@ Triggered when `muggle-local-execute-test-generation` (or the remote equivalent)
|
|
|
189
195
|
| **agent-course** | The generation agent went down a wrong path (chose the wrong button, misread the goal, looped on a blocking modal). The product is fine and the test case is fine — the agent's *course* needs steering. |
|
|
190
196
|
| **product-uxux** | The product itself blocks the test (broken page, missing element, server error). Agent can't proceed because the feature doesn't actually work. |
|
|
191
197
|
|
|
192
|
-
###
|
|
198
|
+
### Where to read signals
|
|
193
199
|
|
|
194
|
-
|
|
200
|
+
Same rule as section B: read **structured fields** from `muggle-local-run-result-get`, not `execute`'s response stdout tail. The `Artifacts` section is present on failed regen too — `action-script.json` is included when generation reached the step-emission stage (typical for `goal_not_achievable`: the agent's attempted steps + halt summary). `results.md` and per-step screenshots are absent on failure (electron-app emits those only on the successful completion path).
|
|
201
|
+
|
|
202
|
+
Order:
|
|
203
|
+
|
|
204
|
+
1. `Status` + `Error` — the verdict and one-line cause. `Error: Electron exited with code 26` typically means `goal_not_achievable`.
|
|
205
|
+
2. `action-script.json` in `artifactsDir` when present — read the steps the agent attempted and the `summaryStep` (halt reason, goal-not-achievable verdict).
|
|
206
|
+
3. `stdout.log` / `stderr.log` at `artifactsDir/` — last 100 lines is usually enough; look for the final structured summary the generation agent emitted (it appears near the end as a JSON-ish block, not in the truncated execute tail).
|
|
207
|
+
4. Remote regen — fetch the workflow run with `muggle-remote-wf-get-ts-gen-latest-run`; signals live in `summaryStep` and the per-step list there.
|
|
208
|
+
|
|
209
|
+
### Initial signal heuristics
|
|
195
210
|
|
|
196
211
|
- **transient**: `network-error`, `llm-rate-limit`, `single-tool-call-error`, run had partial progress then died.
|
|
197
212
|
- **infra**: `electron-mcp-handler-crash`, `internal-validation-error`, `pipeline-stuck`, identical failure repeated more than twice.
|
|
@@ -13,3 +13,4 @@ Filter client-side:
|
|
|
13
13
|
- `id` not in `last_seen.escalated_review_ids`
|
|
14
14
|
- `user.login` in the resolved allow-list
|
|
15
15
|
- `state` in `{CHANGES_REQUESTED, COMMENTED}`, OR `APPROVED` with a non-empty body or at least one line comment
|
|
16
|
+
- **Not a reply-wrapper.** `POST /pulls/<n>/comments/<id>/replies` creates an implicit review whose comments all have `in_reply_to_id` set. Fetch each candidate review's comments via `gh api repos/<owner>/<repo>/pulls/<n>/reviews/<id>/comments` and drop the review if every comment has a non-null `in_reply_to_id` (no new top-level critique). Without this clause, the loop's own threaded replies — submitted under the PR author's identity in single-account workflows — pass the allow-list and re-dispatch `/muggle-do` on a no-op cycle.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# PR-Branch Worktree — Shared Reference
|
|
2
|
+
|
|
3
|
+
> Source of truth for materializing a PR's branch in an isolated worktree so the user's main checkout is never disturbed. Used by `muggle-test` (and any future skill that takes a GitHub PR URL). Skills MUST link here rather than restate the steps.
|
|
4
|
+
|
|
5
|
+
## When this applies
|
|
6
|
+
|
|
7
|
+
A skill receives a GitHub PR URL of the form `github.com/<org>/<repo>/pull/<n>` and needs the PR's branch checked out to test against it locally.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. **Resolve the PR's head branch:**
|
|
12
|
+
`gh pr view <n> --repo <org>/<repo> --json headRefName -q .headRefName`
|
|
13
|
+
2. **Sanitize the branch name** for filesystem use — replace `/` and other path separators with `-`. Example: `claude/regen-test-replay-flow-ZSScQ` → `claude-regen-test-replay-flow-ZSScQ`.
|
|
14
|
+
3. **Build the target worktree path:** `<repo>/.claude/worktrees/<sanitized-branch>`.
|
|
15
|
+
4. **Materialize the worktree:**
|
|
16
|
+
- If the target path does NOT exist:
|
|
17
|
+
- `git -C <repo> fetch origin <branch>`
|
|
18
|
+
- `git -C <repo> worktree add <target-path> <branch>`
|
|
19
|
+
- If the target path EXISTS (reused from a prior run):
|
|
20
|
+
- `git -C <target-path> fetch`
|
|
21
|
+
- `git -C <target-path> reset --hard origin/<branch>` — picks up new pushes, drops any local cruft.
|
|
22
|
+
5. **Use the worktree path as the working directory** for the rest of the run, including:
|
|
23
|
+
- Passing it as the **`cwd` parameter** to `muggle-local-execute-test-generation` and `muggle-local-execute-replay`. This is required, not optional — see `_shared/failure-mode-handling.md` and the lock identity discussion in those tools' MCP source.
|
|
24
|
+
- Resolving any `npm install` / dev-server start commands inside the worktree (it has its own `node_modules/` and `.env*` files).
|
|
25
|
+
6. **Tell the user** where the worktree lives so they can clean it up later with `git -C <repo> worktree remove <target-path>`.
|
|
26
|
+
|
|
27
|
+
## Invariants
|
|
28
|
+
|
|
29
|
+
- **Never switch the user's main checkout.** The whole point of this flow is isolation; `git checkout <branch>` on the main checkout is forbidden.
|
|
30
|
+
- **Never share `node_modules/` via symlink** across worktrees. Each worktree runs its own `npm install` (or `pnpm install`) — webpack's `resolve.symlinks: true` rewrites paths and breaks asset-identity tracking.
|
|
31
|
+
- **`.env*` files do not propagate.** A freshly created worktree has no env files unless the repo commits them. If the parent skill's dev server fails to boot, check whether `.env.local` (or framework equivalent) needs to be copied from the main checkout before launching.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The address-reviews flow only acts on reviews submitted by users in the **allow-list** = (requested reviewers ∪ CODEOWNERS ∪ {PR author}) − bots. Re-resolve every invocation — never cache across cycles.
|
|
4
4
|
|
|
5
|
-
The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews.
|
|
5
|
+
The PR author is implicitly a valid reviewer: in single-account workflows, the human running the agent and the PR's author are the same identity, and the agent must honor their reviews. Self-loop is prevented at the watcher's filter layer rather than here: `POST /pulls/<n>/comments/<id>/replies` does create an implicit review under the loop user's identity, and the watcher drops it via the reply-wrapper clause in [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md). Including the PR author in this allow-list is therefore safe.
|
|
6
6
|
|
|
7
7
|
## Step 1: requested reviewers
|
|
8
8
|
|
|
@@ -8,7 +8,7 @@ Pick the first applicable path. Stop at the first that yields an `actionScriptId
|
|
|
8
8
|
|
|
9
9
|
### 1a. Dashboard URL in user's prompt
|
|
10
10
|
|
|
11
|
-
A Muggle dashboard URL looks like `https://
|
|
11
|
+
A Muggle dashboard URL looks like `https://www.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://www.muggle-ai.com/...` URL.
|
|
12
12
|
|
|
13
13
|
- Extract any UUID-shaped path segments. If `/projects/<uuid>` is present, capture as `projectId`. If `/test-scripts/<uuid>` is present, capture as `testScriptId`.
|
|
14
14
|
- If a `testScriptId` was captured: call `muggle-remote-test-script-get` to get the script and read `actionScriptId` off it. Done — proceed to step 2.
|
|
@@ -37,7 +37,8 @@ If `state` is `MERGED` or `CLOSED`:
|
|
|
37
37
|
2. Write `result.md` per [`state-schemas.md`](state-schemas.md#resultmd).
|
|
38
38
|
3. Append a terminal line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
|
|
39
39
|
4. Emit a `tick` event with `terminal: true` per [`../_shared/telemetry-events/pr-followup-tick.md`](../_shared/telemetry-events/pr-followup-tick.md).
|
|
40
|
-
5.
|
|
40
|
+
5. **Cancel the cron schedule that fires this watcher.** `/loop 1m ...` from bootstrap was registered via `CronCreate`; a fixed-interval cron keeps firing regardless of whether the skill re-dispatches. Call `CronList`, find any job whose command ends with `/muggle:muggle-pr-followup <slug> <pr-number>` (exact two-arg match), and `CronDelete` it. No-op if none matches — the tick may have been invoked manually rather than via `/loop`.
|
|
41
|
+
6. Exit. The watcher has now unscheduled itself; no future ticks will fire for this PR.
|
|
41
42
|
|
|
42
43
|
### Step 3 — Fetch new submitted reviews
|
|
43
44
|
|
|
@@ -66,7 +67,7 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
|
|
|
66
67
|
```
|
|
67
68
|
3. Append a dispatching line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
|
|
68
69
|
4. Emit a `tick` event with `reviews_seen: <count>`, `dispatched_review_ids: [<id>, ...]`.
|
|
69
|
-
5. Exit.
|
|
70
|
+
5. Exit. The cron schedule from bootstrap keeps firing the watcher every minute, so the next tick still arrives even though this turn dispatched `/muggle-do`. The watcher only self-unschedules in Step 2 (terminal).
|
|
70
71
|
|
|
71
72
|
## Output
|
|
72
73
|
|
|
@@ -96,7 +96,7 @@ Analyze the changes to understand what's impacted. Two sources, picked by what t
|
|
|
96
96
|
**PR URL** (user passed `github.com/<org>/<repo>/pull/<n>`):
|
|
97
97
|
1. `gh pr diff <n> --repo <org>/<repo> --name-only` for the changed file list
|
|
98
98
|
2. `gh pr diff <n> --repo <org>/<repo>` for the actual diff
|
|
99
|
-
3.
|
|
99
|
+
3. Materialize the PR branch in a dedicated worktree per [`_shared/pr-branch-worktree.md`](../_shared/pr-branch-worktree.md). Use that worktree path as the `cwd` for the rest of the run (including the `cwd` parameter on local execute tools).
|
|
100
100
|
|
|
101
101
|
Either way:
|
|
102
102
|
1. Identify impacted feature areas:
|
|
@@ -273,6 +273,7 @@ Execution itself **must** be sequential because there is only one local Electron
|
|
|
273
273
|
1. Call `muggle-local-execute-test-generation`:
|
|
274
274
|
- `testCase`: Full test case object from the parallel fetch above
|
|
275
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.
|
|
276
277
|
- `showUi`: from the `showElectronBrowser` resolution — omit (default visible) for `always`, pass `false` for `never`
|
|
277
278
|
- `freshSession`: `true` if the test case requires a clean browser state (see above), omit otherwise
|
|
278
279
|
2. Store the returned `runId` and tag the result `mode: "regen"`.
|
|
@@ -282,14 +283,16 @@ Execution itself **must** be sequential because there is only one local Electron
|
|
|
282
283
|
2. Call `muggle-local-execute-replay`:
|
|
283
284
|
- `testScript`: from `muggle-remote-test-script-get`
|
|
284
285
|
- `actionScript`: from `muggle-remote-action-script-get`
|
|
285
|
-
- `localUrl`, `showUi`, `freshSession`: same resolution as regen
|
|
286
|
+
- `localUrl`, `cwd`, `showUi`, `freshSession`: same resolution as regen
|
|
286
287
|
3. Store the returned `runId` and tag the result `mode: "replay"`.
|
|
287
288
|
|
|
288
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.
|
|
289
290
|
|
|
290
291
|
### Collect results (in parallel)
|
|
291
292
|
|
|
292
|
-
For every `runId`, issue all `muggle-local-run-result-get` calls in parallel. Extract
|
|
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.
|
|
293
296
|
|
|
294
297
|
### Publish each run to cloud (gated by `autoPublishLocalResults`)
|
|
295
298
|
|
|
@@ -459,6 +462,7 @@ This is a suggestion, not automatic invocation. Skip silently if every test pass
|
|
|
459
462
|
## Guardrails
|
|
460
463
|
|
|
461
464
|
- **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.
|
|
462
466
|
- **User MUST select project** — present clickable options via `AskUserQuestion`, wait for explicit choice, never auto-select
|
|
463
467
|
- **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.
|
|
464
468
|
- **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.
|
|
@@ -195,8 +195,12 @@ If publish rejects with `has no generated actionScript steps to publish` (true z
|
|
|
195
195
|
|
|
196
196
|
### 9. Report
|
|
197
197
|
|
|
198
|
+
**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.
|
|
199
|
+
|
|
198
200
|
- `muggle-local-run-result-get` with the run id from execute.
|
|
199
|
-
-
|
|
201
|
+
- **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.
|
|
202
|
+
- **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.
|
|
203
|
+
- 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.
|
|
200
204
|
|
|
201
205
|
### 9a. Route failures through the failure-mode handler
|
|
202
206
|
|
|
@@ -242,6 +246,7 @@ After reporting results:
|
|
|
242
246
|
|
|
243
247
|
- No silent auth skip.
|
|
244
248
|
- **Never prompt for Electron launch approval** before execution — invoking this skill is the approval. Just run.
|
|
249
|
+
- **Never diagnose a failed run from `execute`'s response stdout tail.** Always call `muggle-local-run-result-get` first; classify only from its structured fields and (when present) the artifacts it names. The execute tail is an excerpt and routinely truncates the failure cause.
|
|
245
250
|
- If replayable scripts exist, do not default to generation without user choice.
|
|
246
251
|
- No hiding failures: surface errors and artifact paths.
|
|
247
252
|
- **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.
|
|
@@ -43,266 +43,52 @@ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
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
|
-
**On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`),
|
|
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
|
|
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 |
|
|
62
|
-
|
|
63
|
-
| `autoRebase` |
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
301
|
-
3. For each managed service
|
|
302
|
-
4. Wait ~2
|
|
303
|
-
5. If still alive
|
|
304
|
-
6.
|
|
305
|
-
7.
|
|
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
|
-
|
|
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
|
|
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** —
|
|
330
|
-
- **The user may prefer to start services themselves** — always offer that option.
|
|
331
|
-
- **Never start a process the user didn't approve
|
|
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** —
|
|
335
|
-
- **Never assume start commands** —
|
|
336
|
-
- **Bail early on non-viable services** — don't
|
|
337
|
-
- **Idempotent** —
|
|
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.
|