@muggleai/works 5.9.0 → 5.11.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.
- package/README.md +8 -0
- package/dist/{chunk-LVUJ4E62.js → chunk-MSPMXBO5.js} +638 -468
- package/dist/{chunk-5PYK7DWB.js → chunk-WUMAJOBT.js} +17 -6
- 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/README.md +19 -13
- package/dist/plugin/agents/test-prepare-runner.md +4 -1
- package/dist/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/dist/plugin/commands/mtest.md +1 -1
- package/dist/plugin/hooks/README.md +15 -3
- package/dist/plugin/hooks/hooks.json +79 -0
- package/dist/plugin/scripts/ensure-electron-app.sh +62 -47
- package/dist/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/dist/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/dist/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/dist/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/dist/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/dist/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/dist/plugin/scripts/guardrail-report-format.sh +9 -5
- package/dist/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/dist/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/dist/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/dist/plugin/scripts/guardrails.mjs +474 -80
- package/dist/plugin/scripts/pr-watch-events.sh +116 -0
- package/dist/plugin/scripts/pr-watch-guards.sh +8 -2
- package/dist/plugin/scripts/pr-watch-loop.sh +254 -0
- package/dist/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/dist/plugin/scripts/sign-body.sh +88 -0
- package/dist/plugin/skills/CLAUDE.md +16 -0
- package/dist/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/dist/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/dist/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/dist/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/dist/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/dist/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/dist/plugin/skills/do/open-prs/forward.md +2 -2
- package/dist/plugin/skills/do/per-comment-replies.md +2 -15
- package/dist/plugin/skills/muggle/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/dist/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/dist/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/dist/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/dist/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/dist/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/dist/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/dist/plugin/skills/muggle-test/SKILL.md +23 -3
- package/dist/plugin/skills/muggle-test/execute-local.md +2 -0
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/dist/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/dist/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/dist/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/release-manifest.json +4 -4
- package/dist/src-B5OTAZKM.js +1 -0
- package/package.json +7 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/README.md +19 -13
- package/plugin/agents/test-prepare-runner.md +4 -1
- package/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/plugin/commands/mtest.md +1 -1
- package/plugin/hooks/README.md +15 -3
- package/plugin/hooks/hooks.json +79 -0
- package/plugin/scripts/ensure-electron-app.sh +62 -47
- package/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/plugin/scripts/guardrail-report-format.sh +9 -5
- package/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/plugin/scripts/guardrails.mjs +474 -80
- package/plugin/scripts/pr-watch-events.sh +116 -0
- package/plugin/scripts/pr-watch-guards.sh +8 -2
- package/plugin/scripts/pr-watch-loop.sh +254 -0
- package/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/plugin/scripts/sign-body.sh +88 -0
- package/plugin/skills/CLAUDE.md +16 -0
- package/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/plugin/skills/do/open-prs/forward.md +2 -2
- package/plugin/skills/do/per-comment-replies.md +2 -15
- package/plugin/skills/muggle/SKILL.md +1 -1
- package/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/plugin/skills/muggle-test/SKILL.md +23 -3
- package/plugin/skills/muggle-test/execute-local.md +2 -0
- package/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/src-FDK2KQSZ.js +0 -1
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: muggle-test
|
|
3
|
-
description: "Change-driven E2E acceptance testing
|
|
3
|
+
description: "Change-driven E2E acceptance testing: detects the user's recent changes (local diff or PR), maps them to affected user flows, and runs real-browser tests on localhost or a preview/staging URL. Invoke it before inspecting anything — what changed and what it affects is its own first step; reading the diff by hand duplicates it. Use when the user wants to test or regression-test their own work — \"make sure I didn't break anything\", \"did my recent commits break any user flows?\", \"test before I push\" — the pre-merge acceptance gate. The signal: validation tied to a commit, push, PR, or merge; unstated scope (a chunk of work, a refactor, a sprint, a deploy preview) is this skill's input, not a reason to investigate first. Beyond a Playwright/Cypress runner: plain-English tests, self-healing scripts, login/pay-wall flows, parallel cloud replay, test-plan-graph prerequisites, grouped dashboard results, and a PR visual walkthrough. One named flow: muggle-test-feature-local; importing spec files: muggle-test-import."
|
|
4
|
+
mandatoryStages:
|
|
5
|
+
- ../_shared/failure-mode-handling.md
|
|
6
|
+
- ../_shared/debug-failed-run.md
|
|
4
7
|
---
|
|
5
8
|
|
|
6
9
|
# Muggle Test — Change-Driven E2E Acceptance Router
|
|
@@ -9,6 +12,20 @@ description: "Change-driven E2E acceptance testing with Muggle AI: detect the us
|
|
|
9
12
|
|
|
10
13
|
A router skill that detects code changes, resolves impacted test cases, executes them locally or remotely, reads the cloud results from the Muggle AI dashboard (local runs are published by the studio during execution; remote runs publish cloud-side), and posts E2E acceptance summaries to the PR. The user can invoke this at any moment, in any state.
|
|
11
14
|
|
|
15
|
+
## Beyond a Playwright/Cypress runner
|
|
16
|
+
|
|
17
|
+
Reach for these when the user is weighing Muggle Test against hand-written specs.
|
|
18
|
+
|
|
19
|
+
| Capability | Mechanism |
|
|
20
|
+
| :--------- | :-------- |
|
|
21
|
+
| Flows behind login and pay walls | Per-project encrypted credentials and managed login profiles, injected at replay as `secretInput` steps — `muggle-remote-secret-*` |
|
|
22
|
+
| Self-healing scripts | UI-drift or stale-script signals route the run to regen instead of a doomed replay, then re-replay — [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) sections A and B |
|
|
23
|
+
| Parallel replay at scale | `muggle-remote-workflow-start-test-script-replay-bulk` replays a whole suite cloud-side in one dispatch; its `intervalSec` makes the batch recurring |
|
|
24
|
+
| Test-graph resolution | `muggle-remote-test-case-ancestors-get` walks the backend's test-plan graph root-first, so a dependent flow runs only once its prerequisites have ready scripts — [`_shared/test-case-chain-readiness.md`](../_shared/test-case-chain-readiness.md) |
|
|
25
|
+
| Grouped results and reports | Dashboard groups runs by use case and project; `muggle-remote-report-final-generate` exports the run report |
|
|
26
|
+
| PR visual walkthrough | Per-step screenshots and per-test-case dashboard links posted to the PR — [`../muggle-pr-visual-walkthrough/SKILL.md`](../muggle-pr-visual-walkthrough/SKILL.md) |
|
|
27
|
+
| Unattended runs | `muggle-remote-auth-api-key-create` issues long-lived keys for headless auth; `muggle-remote-recommend-cicd-setup` emits GitHub Actions / GitLab CI / Azure DevOps templates |
|
|
28
|
+
|
|
12
29
|
## UX Guidelines — Minimize Typing
|
|
13
30
|
|
|
14
31
|
**Every selection-based question MUST use the `AskUserQuestion` tool** (or the platform's equivalent structured selection tool). Never ask the user to "reply with a number" in a plain text message — always present clickable options.
|
|
@@ -128,7 +145,7 @@ If auth fails repeatedly, suggest: `muggle logout && muggle login` from terminal
|
|
|
128
145
|
|
|
129
146
|
A **project** is where all your test results, use cases, and test scripts are grouped on the Muggle AI dashboard. Pick the project that matches what you're working on.
|
|
130
147
|
|
|
131
|
-
The per-repo cache lives
|
|
148
|
+
The per-repo cache lives in `~/.muggle-ai/last-project.json`, in the entry keyed on `<cwd>` (managed via the `muggle-local-last-project-get` / `muggle-local-last-project-set` MCP tools). Look for the `Muggle Test Last Project: id=… url=… name="…"` line in session context — if present, that's this repo's cached pick.
|
|
132
149
|
|
|
133
150
|
Gate `autoSelectProject` (per `preference-gates/README.md`). Cache: `Muggle Test Last Project` session line.
|
|
134
151
|
- `always` + cache → use cached `projectId`, skip to Step 5. No cache → fall through to `ask`.
|
|
@@ -253,6 +270,8 @@ For every run with `status: "failed"` (or any non-passing terminal state) return
|
|
|
253
270
|
|
|
254
271
|
Pass it per failed run: the `runId` (local) or workflow runtime id (remote), the `mode` that failed, `testCaseId`, `projectId`, and the execution handle (local: [`execute-local.md`](execute-local.md); remote: [`execute-remote.md`](execute-remote.md)) so a rerun re-enters the same path. Process failures one at a time so the user isn't drowning in pickers.
|
|
255
272
|
|
|
273
|
+
**This step is not an exit.** Whatever the user picks — feedback, rerun, or skip — control returns to Steps 8 and 9. A failed run is the *highest-value* walkthrough: a reviewer needs the screenshots of what broke far more than confirmation that a passing flow passed. Ending the turn inside this step with results unposted is what the walkthrough Stop gate blocks.
|
|
274
|
+
|
|
256
275
|
## Step 8: Open Results in Browser
|
|
257
276
|
|
|
258
277
|
After execution, open the Muggle AI dashboard so the user can inspect results and screenshots. The studio published every local run during execution, so each run result already carries its `viewUrl` (read it from `muggle-local-run-result-get`). Key off the uniform runs list:
|
|
@@ -271,7 +290,7 @@ Tell the user:
|
|
|
271
290
|
|
|
272
291
|
## Step 9: Offer to Post Visual Walkthrough to PR
|
|
273
292
|
|
|
274
|
-
After reporting results:
|
|
293
|
+
Posts **every** run from Step 7 — failed and inconclusive as readily as passed. After reporting results:
|
|
275
294
|
|
|
276
295
|
1. Fire [`postPRVisualWalkthrough`](../muggle-preferences/preference-gates/postPRVisualWalkthrough.md). On skip → Step 9.5.
|
|
277
296
|
2. `gh pr view --json number,title,url 2>/dev/null` — find the PR.
|
|
@@ -312,5 +331,6 @@ Each rule below is covered in-step above; these are the ones this skill most oft
|
|
|
312
331
|
- **Every selection uses `AskUserQuestion`** — never ask the user to type a number; the user picks the project (never auto-select).
|
|
313
332
|
- **Parallelize independent cloud jobs**; the only sequential loop is local Electron execution (one browser).
|
|
314
333
|
- **Read cloud refs off the run result** (the studio published during execution) and delegate PR posting to `muggle-pr-visual-walkthrough` — never inline the walkthrough or call `gh pr comment` here.
|
|
334
|
+
- **Results reach the PR, pass or fail** — Step 7C's debug path never terminates the run; Step 9 posts every run. A Stop gate holds the turn open while an acceptance run has no walkthrough on its PR, so a result that genuinely shouldn't be posted needs `echo "MUGGLE_WALKTHROUGH_SKIP: <reason>"` rather than silence.
|
|
315
335
|
|
|
316
336
|
Phase→tool map and multi-agent (acceptance-tester) dispatch: [`reference.md`](reference.md).
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
Before anything else, invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md) — the readiness/service-start owner (idempotent; halt on what it surfaces). The URL gate below only *selects* the target; prepare is what guarantees something is listening and compiled.
|
|
14
14
|
|
|
15
|
+
Then read `~/.muggle-ai/e2e-instructions/<key>.md` when it exists — this stack's recorded startup order, manual steps, and local gotchas. Use it to interpret what you see: a gotcha listed there explains a symptom that would otherwise read as a failure. Absent is normal.
|
|
16
|
+
|
|
15
17
|
## Pre-flight question — Local URL (gated by `autoSelectLocalHost`)
|
|
16
18
|
|
|
17
19
|
Skill responsibilities (the rest is in `preference-gates/autoSelectLocalHost.md`):
|
|
@@ -29,6 +29,8 @@ Three gates apply, each per the standard procedure in [`preference-gates/README.
|
|
|
29
29
|
|
|
30
30
|
Before any workflow step, invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md). Halt on what it surfaces.
|
|
31
31
|
|
|
32
|
+
Then read `~/.muggle-ai/e2e-instructions/<key>.md` when it exists — this stack's recorded startup order, manual steps, and local gotchas. A gotcha listed there explains a symptom that would otherwise read as a failure. Absent is normal.
|
|
33
|
+
|
|
32
34
|
## UX Guidelines — Minimize Typing
|
|
33
35
|
|
|
34
36
|
**Every selection-based question MUST use the `AskUserQuestion` tool** (or the platform's equivalent structured selection tool). Never ask the user to "reply with a number" in a plain text message — always present clickable options.
|
|
@@ -67,7 +69,7 @@ Gates run per `preference-gates/README.md`.
|
|
|
67
69
|
|
|
68
70
|
### 2. Targets (user must confirm)
|
|
69
71
|
|
|
70
|
-
The per-repo project cache lives
|
|
72
|
+
The per-repo project cache lives in `~/.muggle-ai/last-project.json`, in the entry keyed on `<cwd>` (via the `muggle-local-last-project-get` / `muggle-local-last-project-set` MCP tools). Look for `Muggle Test Last Project: id=… url=… name="…"` in session context.
|
|
71
73
|
|
|
72
74
|
Gate `autoSelectProject` (per `preference-gates/README.md`). Cache: `Muggle Test Last Project` session line.
|
|
73
75
|
- `always` + cache → use cached `projectId`, skip to use case selection. No cache → fall through to `ask`.
|
|
@@ -182,6 +184,8 @@ Pass it: the `runId`, the `mode` that failed (replay if the user picked an exist
|
|
|
182
184
|
|
|
183
185
|
Skip only when the run passed cleanly — the debug path is by definition about failures.
|
|
184
186
|
|
|
187
|
+
**This step is not an exit.** Whatever the user picks — feedback, rerun, or skip — control returns to the reporting and walkthrough steps. A failed run is the *highest-value* walkthrough: a reviewer needs the screenshots of what broke far more than confirmation that a passing flow passed. Ending the turn inside this step with results unposted is what the walkthrough Stop gate blocks.
|
|
188
|
+
|
|
185
189
|
### 9b. Remind the user to guide the agent (every Electron invocation)
|
|
186
190
|
|
|
187
191
|
Fires after **every** Electron run, pass or fail. A run can technically pass while still containing steps the user would correct — a misclick, wrong element, or a summary that doesn't match intent. This is the user's chance to flag it before regeneration picks up elsewhere.
|
|
@@ -220,6 +224,7 @@ The `/mprfollowup` shortcut starts the same watcher manually at any time.
|
|
|
220
224
|
## Non-negotiables
|
|
221
225
|
|
|
222
226
|
- No silent auth skip.
|
|
227
|
+
- **Results reach the PR, pass or fail** — the debug path never terminates the run, and the walkthrough covers every run. A Stop gate holds the turn open while an acceptance run has no walkthrough on its PR, so a result that genuinely shouldn't be posted needs `echo "MUGGLE_WALKTHROUGH_SKIP: <reason>"` rather than silence.
|
|
223
228
|
- **Never prompt for Electron launch approval** before execution — invoking this skill is the approval. Just run.
|
|
224
229
|
- **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.
|
|
225
230
|
- Satisfy the prerequisite chain (Step 4a) before generating or replaying the target. Read it from `muggle-remote-test-case-ancestors-get` — never infer parents from `precondition` text. Generate any not-ready ancestor test-generation-only, root-first.
|
|
@@ -151,7 +151,7 @@ If **not authenticated**:
|
|
|
151
151
|
|
|
152
152
|
A **project** is where all your imported use cases, test cases, and future test results are grouped on the Muggle AI dashboard.
|
|
153
153
|
|
|
154
|
-
The per-repo project cache lives
|
|
154
|
+
The per-repo project cache lives in `~/.muggle-ai/last-project.json`, in the entry keyed on `<cwd>` (via the `muggle-local-last-project-get` / `muggle-local-last-project-set` MCP tools). Look for `Muggle Test Last Project: id=… url=… name="…"` in session context.
|
|
155
155
|
|
|
156
156
|
Gate `autoSelectProject` (per `preference-gates/README.md`). Cache: `Muggle Test Last Project` session line.
|
|
157
157
|
- `always` + cache → use cached `projectId`, skip to Step 6. No cache → fall through to `ask`.
|
|
@@ -18,8 +18,8 @@ The skill runs in two phases because a dispatched agent has no channel back to t
|
|
|
18
18
|
|
|
19
19
|
This skill touches the user's local machine — processes, ports, directories outside the current repo. Every action is explicit and confirmed.
|
|
20
20
|
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
21
|
+
- **Reading is granted, never assumed.** [derive-service-graph](./steps/derive-service-graph.md) asks first: scan a folder the user names, to a depth they set, or skip the scan and take their list of paths and services instead. The granted scope is recorded with the recipe so later runs reuse the permission rather than re-asking; widening it needs a fresh ask.
|
|
22
|
+
- **Outside the granted scope, names only.** You may list directory names to offer them as candidates, but never read inside one the user hasn't named. Once they name it, its top-level indicator files (`package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `docker-compose.yml`) are readable to determine the start command.
|
|
23
23
|
- **Never traverse upward more than one level** from the current working directory to list folders.
|
|
24
24
|
|
|
25
25
|
## PID Tracking
|
|
@@ -48,7 +48,11 @@ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
|
|
|
48
48
|
|
|
49
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
50
|
|
|
51
|
-
This file is **ephemeral runtime state**, not the saved recipe. The durable plan lives
|
|
51
|
+
This file is **ephemeral runtime state**, not the saved recipe. The durable plan lives in `~/.muggle-ai/prepare-plans.json`, under the entry keyed on this stack, 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
|
+
The prose companion to the plan is `~/.muggle-ai/e2e-instructions/<key>.md`, written by [e2e-instructions](./steps/e2e-instructions.md), holding startup order, manual steps, and local gotchas. The plan remains the single source of truth for each service's start command; the markdown never restates one.
|
|
54
|
+
|
|
55
|
+
**Everything this skill saves is machine-local, user-level data and lives under the Muggle home directory — never inside the user's project.** A project directory is shared, versioned, and cloned onto machines set up differently; a local run recipe is none of those things. Both files are keyed on the same stack identity, so they stay in lockstep.
|
|
52
56
|
|
|
53
57
|
**On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
|
|
54
58
|
- Option 1: "Keep them running — skip to testing"
|
|
@@ -64,26 +68,34 @@ Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-ga
|
|
|
64
68
|
| Preference | Gates |
|
|
65
69
|
|------------|-------|
|
|
66
70
|
| `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 |
|
|
71
|
+
| `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover; also [e2e-instructions](./steps/e2e-instructions.md), which goes stale for the same reason |
|
|
68
72
|
| `autoSelectLocalHost` | [check-running](./steps/check-running.md) — reuse the recorded dev-server URL silently, or confirm it each run |
|
|
69
73
|
|
|
70
74
|
## Workflow
|
|
71
75
|
|
|
72
|
-
**
|
|
76
|
+
**The skill learns once, then replays.** [replay-or-learn](./steps/replay-or-learn.md) decides which, and owns what each mode may do.
|
|
77
|
+
|
|
78
|
+
A **replay** executes the saved recipe and asks nothing. A **learning run** works through the Decide stages below, then the execute phase, then a single gate — [confirm-recipe](./steps/confirm-recipe.md) — which is the only thing that persists anything.
|
|
73
79
|
|
|
74
|
-
|
|
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 |
|
|
80
|
+
Decide stages, in order; read each detail file when you reach it:
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
| Stage | Summary |
|
|
83
|
+
|:------|:--------|
|
|
84
|
+
| [replay-or-learn](./steps/replay-or-learn.md) | Replay the saved recipe, or learn a new one |
|
|
85
|
+
| [derive-service-graph](./steps/derive-service-graph.md) | Derive services from workspace manifests |
|
|
86
|
+
| [rebase-check](./steps/rebase-check.md) | Rebase onto default branch |
|
|
87
|
+
| [scope](./steps/scope.md) | Frontend / backend / full stack |
|
|
88
|
+
| [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
|
|
89
|
+
| [identify-services](./steps/identify-services.md) | Confirm the derived graph; fill the gaps |
|
|
90
|
+
| [e2e-instructions](./steps/e2e-instructions.md) | Startup order, manual steps, local gotchas |
|
|
91
|
+
|
|
92
|
+
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, the E2E run instructions, and resolved gate outcomes.
|
|
83
93
|
|
|
84
94
|
**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
95
|
|
|
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.
|
|
96
|
+
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. That path is also how a problem hit mid-preparation reaches the user when it can't be resolved autonomously, per [record-resolution](./steps/record-resolution.md).
|
|
97
|
+
|
|
98
|
+
The agent also returns the problems it hit and what cleared them. On a learning run those feed [confirm-recipe](./steps/confirm-recipe.md); on a replay they are already in the recipe and are applied without asking.
|
|
87
99
|
|
|
88
100
|
## Cleanup
|
|
89
101
|
|
|
@@ -114,12 +126,13 @@ After a test run, the caller can re-invoke for cleanup or leave services running
|
|
|
114
126
|
|
|
115
127
|
## Guardrails
|
|
116
128
|
|
|
117
|
-
- **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess.
|
|
129
|
+
- **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess. Read it from the last-host cache via `muggle-local-last-host-get` (the [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md) cache) before probing ports; a framework default like `:3000` is never a fallback. The cache's own storage location belongs to that tool — don't restate it here. See [check-running](./steps/check-running.md).
|
|
118
130
|
- **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
131
|
- **Verify first, offer to start second** — check what's already running before proposing to start anything.
|
|
120
132
|
- **The user may prefer to start services themselves** — always offer that option.
|
|
121
133
|
- **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
134
|
- **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
|
|
135
|
+
- **Never write a credential into the E2E run instructions** — plaintext notes are not a secret store, and this is the file a user pastes when asking why their stack won't start. Record the env-var or secret name, never its value.
|
|
123
136
|
- **Never leave orphan processes untracked** — every background PID goes into the tracking file.
|
|
124
137
|
- **Never kill a process the user started independently** — `external: true` survives cleanup.
|
|
125
138
|
- **Never assume start commands** — verify via indicator file; confirm with user.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
The dev-server URL the tests will hit is a **recorded value, not a guess** — resolve it before probing anything.
|
|
6
6
|
|
|
7
|
-
1. Read the cached host with `muggle-local-last-host-get`. It reads `<cwd
|
|
7
|
+
1. Read the cached host with `muggle-local-last-host-get`. It reads the entry keyed on `<cwd>` in `~/.muggle-ai/last-host.json`; a worktree usually has **no cache of its own**, so when the worktree returns nothing, pass the **main** working-tree root as `cwd` — `git rev-parse --git-common-dir`, then its parent directory.
|
|
8
8
|
2. Apply the [`autoSelectLocalHost`](../../muggle-preferences/preference-gates/autoSelectLocalHost.md) gate (read its value from the `Muggle Test Preferences` session-context line; absent → `ask`):
|
|
9
9
|
- `always` **and** a cache exists → use it silently: `Using saved local URL {lastHost}`.
|
|
10
10
|
- otherwise (`ask` / `never`, or no cache) → **confirm before using any host.** Run the gate's Picker 1 with `{lastHost}` (cached URL, omitted when absent) and `{suggestedHost}` (a port you actually detect listening). Never auto-pick, and never fall back to a framework default like `:3000`; if nothing is cached or detected, ask the user to type the URL.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Confirm the recipe
|
|
2
|
+
|
|
3
|
+
The one gate of a learning run. Everything the run discovered is held until here, so the user makes a single decision instead of approving facts one at a time.
|
|
4
|
+
|
|
5
|
+
Needs a verified-ready environment — a recipe for a preparation that did not work is worth nothing.
|
|
6
|
+
|
|
7
|
+
## Show what was done
|
|
8
|
+
|
|
9
|
+
Summarise the actual run, not the plan that preceded it:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Prepared your environment. Here's what it took:
|
|
13
|
+
|
|
14
|
+
Services started, in order
|
|
15
|
+
1. api pnpm --filter api dev :8080
|
|
16
|
+
2. worker pnpm --filter worker dev —
|
|
17
|
+
3. ui pnpm dev :3999
|
|
18
|
+
|
|
19
|
+
Manual steps
|
|
20
|
+
• pnpm db:migrate — run once before the api comes up
|
|
21
|
+
|
|
22
|
+
Problems hit, and what fixed them
|
|
23
|
+
• ui — HTTP 500 on /dashboard while api was still booting
|
|
24
|
+
→ started api first and waited for its ready signal
|
|
25
|
+
• worker — exited immediately, missing .env.local
|
|
26
|
+
→ copied .env.example, you filled in QUEUE_URL
|
|
27
|
+
|
|
28
|
+
Not running locally
|
|
29
|
+
• payment-gateway — needs production certificates
|
|
30
|
+
|
|
31
|
+
Remember this as your prepare recipe, so future runs just do it?
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`AskUserQuestion`:
|
|
35
|
+
|
|
36
|
+
- `Remember it` — `Future E2E runs prepare this way without asking.`
|
|
37
|
+
- `Don't remember` — `Prepare from scratch again next time.`
|
|
38
|
+
|
|
39
|
+
## On accept
|
|
40
|
+
|
|
41
|
+
Write both halves of the recipe together, so they cannot drift:
|
|
42
|
+
|
|
43
|
+
- The machine-readable service graph to `~/.muggle-ai/prepare-plans.json`, keyed on the stack, per [readiness-report](./readiness-report.md).
|
|
44
|
+
- The prose — startup order, manual steps, gotchas, and the recorded resolutions from [record-resolution](./record-resolution.md) — to `~/.muggle-ai/e2e-instructions/<key>.md`, per [e2e-instructions](./e2e-instructions.md).
|
|
45
|
+
|
|
46
|
+
## On decline
|
|
47
|
+
|
|
48
|
+
Write nothing. The next run learns again. Do not ask a second time in the same run, and do not record the refusal as a preference — the user is declining this recipe, not the idea of recipes.
|
|
49
|
+
|
|
50
|
+
## Hard block
|
|
51
|
+
|
|
52
|
+
The only thing that lets a replay deviate: **a failure the recipe's recorded resolutions do not cover, which autonomous attempts cannot clear.**
|
|
53
|
+
|
|
54
|
+
Anything the recipe already handles is not a hard block, however loudly it fails. Neither is a transient that clears on retry. The bar is deliberately high, because every re-prompt undoes the learning.
|
|
55
|
+
|
|
56
|
+
On a hard block: resolve it with the user, then offer to update the recipe with the new resolution — the same accept/decline, scoped to the one addition. Otherwise the recipe changes only when the user asks for it.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Derive the service graph
|
|
2
|
+
|
|
3
|
+
Derive the service graph from what the workspace declares, so the interview only covers what a scan cannot know. Reading manifests beats interrogating the user about their own repo layout.
|
|
4
|
+
|
|
5
|
+
Applies only to a [learning run](./replay-or-learn.md). A replay never scans.
|
|
6
|
+
|
|
7
|
+
## Ask before reading anything
|
|
8
|
+
|
|
9
|
+
Nothing is read until the user says where. `AskUserQuestion`:
|
|
10
|
+
|
|
11
|
+
> "To work out your services, I can scan the code — or you can just tell me. Which?"
|
|
12
|
+
|
|
13
|
+
- `Scan <cwd>` — `Read manifests here, 2 levels deep, to find services and their start commands.`
|
|
14
|
+
- `Scan a different folder` — `Name the folder and how deep to look.`
|
|
15
|
+
- `I'll list them` — `Give me the service paths yourself; I won't read anything you haven't named.`
|
|
16
|
+
|
|
17
|
+
The default depth is **2 levels**, which reaches `packages/*` and `services/*` without walking a whole disk. The user may set it higher or lower when naming the folder.
|
|
18
|
+
|
|
19
|
+
`I'll list them` skips the scan entirely: take the paths and service names from the user and continue to the interview with those as the graph. Read only the top-level indicator files of the paths they named, and only to determine the start command.
|
|
20
|
+
|
|
21
|
+
Record the granted scope — folder and depth — with the recipe, so a later run reuses the same permission rather than asking again. Widening it needs a fresh ask.
|
|
22
|
+
|
|
23
|
+
## Read, in this order
|
|
24
|
+
|
|
25
|
+
Within the granted scope only:
|
|
26
|
+
|
|
27
|
+
1. **Workspace manifests** — `pnpm-workspace.yaml`, the `workspaces` field of a root `package.json`, `turbo.json`, `lerna.json`, `nx.json`, `Cargo.toml` `[workspace]`, `go.work`. These name the members directly, so a monorepo needs no guessing.
|
|
28
|
+
2. **Compose and process files** — `docker-compose.yml`, `Procfile`, `Makefile`, `Tiltfile`, `skaffold.yaml`. These carry service names, ports, and often the dependency order outright (`depends_on`).
|
|
29
|
+
3. **Per-service manifests** for each member found — `package.json` scripts (`dev`, `start`, `serve`), `Cargo.toml`, `go.mod`, `pyproject.toml`. This is where the start command comes from.
|
|
30
|
+
4. **Port declarations** — `.env.example`, `vite.config.*`, `next.config.*`, a `PORT` in the start script. Never a framework default: an undeclared port is unknown, not `:3000`.
|
|
31
|
+
|
|
32
|
+
## Emit
|
|
33
|
+
|
|
34
|
+
A proposed service graph — for each: name, directory, start command with its source, expected port with its source, and whether the scan believes it is required for the declared scope.
|
|
35
|
+
|
|
36
|
+
Plus what the scan **could not** determine. That list is the interview's agenda; everything else is already settled.
|
|
37
|
+
|
|
38
|
+
Show the user what was found before asking anything else. A scan they can see is a scan they can correct.
|
|
39
|
+
|
|
40
|
+
## What a scan cannot know
|
|
41
|
+
|
|
42
|
+
State these as unknowns rather than guessing, because each is a judgement about intent rather than a fact in a file:
|
|
43
|
+
|
|
44
|
+
- Which services this user actually needs running for the tests they care about.
|
|
45
|
+
- Which cannot run locally at all (a payment gateway needing production certificates).
|
|
46
|
+
- Startup ordering that no `depends_on` declares but which the app requires anyway.
|
|
47
|
+
- Anything that has to happen by hand before a service is usable.
|
|
48
|
+
|
|
49
|
+
## Boundaries
|
|
50
|
+
|
|
51
|
+
Read only inside the folder the user granted, to the depth they set. A directory outside that scope may have its name listed to offer it as a candidate; its contents stay unread until the user names it.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# E2E run instructions
|
|
2
|
+
|
|
3
|
+
Capture what `prepare-plan.json` cannot express: the order services must come up in, steps that aren't a single command, and the local gotchas that make a healthy stack look broken. Persisted under `~/.muggle-ai/e2e-instructions/` and reused on later runs.
|
|
4
|
+
|
|
5
|
+
Needs the resolved service list from [identify-services](./identify-services.md): startup order and per-service gotchas are unanswerable until the service set is known.
|
|
6
|
+
|
|
7
|
+
## Scope boundary
|
|
8
|
+
|
|
9
|
+
`prepare-plan.json` owns the per-service start command. Never restate a command here; reference the plan. This file holds only what the plan has no field for:
|
|
10
|
+
|
|
11
|
+
| Belongs here | Belongs in `prepare-plan.json` |
|
|
12
|
+
|:-------------|:-------------------------------|
|
|
13
|
+
| Order and dependencies between services | Each service's `name`, `dir`, `command`, `port` |
|
|
14
|
+
| Steps that aren't one command (a migration to run first, a tunnel to open, a container to bring up by hand) | — |
|
|
15
|
+
| Gotchas — slow first build, a port that isn't the framework default, a rate limit, a warning that is safe to ignore | — |
|
|
16
|
+
|
|
17
|
+
## Resolve the saved file
|
|
18
|
+
|
|
19
|
+
This is machine-local, user-level data. It lives under the Muggle home directory and never inside the user's project — a project directory is shared, versioned, and cloned by people whose machines are set up differently, and none of that is true of a local run recipe.
|
|
20
|
+
|
|
21
|
+
One file per stack:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
~/.muggle-ai/e2e-instructions/<key>.md
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`<key>` is the absolute path of the working directory's parent — the same stack identity the global prepare plan keys its entries on — reduced to a filename-safe token by replacing every path separator, and any drive-letter colon, with `-`. Derive it from the resolved absolute path rather than assuming a separator character; they differ per platform.
|
|
28
|
+
|
|
29
|
+
Missing → no saved instructions; run the capture below.
|
|
30
|
+
|
|
31
|
+
## Gate `reusePreparePlan`
|
|
32
|
+
|
|
33
|
+
Same gate as [reuse-plan](./reuse-plan.md) — this content goes stale for the same reason the service plan does, so one answer governs both. Only fires when a saved file was loaded.
|
|
34
|
+
|
|
35
|
+
- `always` → reuse silently. Print `Reusing saved E2E run instructions`.
|
|
36
|
+
- `never` → discard and run the capture.
|
|
37
|
+
- `ask` → print the saved file, then Picker 1 from the gate contract. Reuse on `Reuse this plan`, capture on `Rediscover from scratch`.
|
|
38
|
+
|
|
39
|
+
On the [reuse-plan](./reuse-plan.md) short-circuit path this stage is skipped along with the rest of the Decide phase; the saved file is loaded there and carried forward unchanged.
|
|
40
|
+
|
|
41
|
+
## Capture
|
|
42
|
+
|
|
43
|
+
Print the resolved service list first so the user answers against concrete names, then ask one `AskUserQuestion`, multi-select:
|
|
44
|
+
|
|
45
|
+
> "Anything Muggle should know about running these locally?"
|
|
46
|
+
|
|
47
|
+
- `Startup order matters` — `One service must be up before another, or something fails.`
|
|
48
|
+
- `Manual steps` — `Something has to happen that isn't one of the start commands.`
|
|
49
|
+
- `Known gotchas` — `Behaviour that looks like a failure but isn't, or a trap to avoid.`
|
|
50
|
+
- `Nothing special` — `They start independently and just work.`
|
|
51
|
+
|
|
52
|
+
`Nothing special` (or no selection) → write the sentinel from [Sentinel](#sentinel) and return. Do not re-ask on later runs; the sentinel is a recorded answer, not an empty file.
|
|
53
|
+
|
|
54
|
+
Otherwise ask once more, free-text, naming only the selected categories. One turn — never a question per category.
|
|
55
|
+
|
|
56
|
+
## Written format
|
|
57
|
+
|
|
58
|
+
Fixed headings. Omit a section the user had nothing for; never emit an empty one.
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
# E2E run instructions
|
|
62
|
+
|
|
63
|
+
<!-- Managed by muggle-test-prepare. Hand-edits are preserved — re-run the skill to revise. -->
|
|
64
|
+
|
|
65
|
+
**Updated:** 2026-08-04T12:00:00Z
|
|
66
|
+
|
|
67
|
+
## Startup order
|
|
68
|
+
|
|
69
|
+
api → worker → ui. The UI 500s on /dashboard when api isn't listening yet.
|
|
70
|
+
|
|
71
|
+
## Manual steps
|
|
72
|
+
|
|
73
|
+
Run `pnpm db:migrate` once after a fresh clone; the dev servers don't migrate on boot.
|
|
74
|
+
|
|
75
|
+
## Local gotchas
|
|
76
|
+
|
|
77
|
+
- First build after a clean install takes ~4 min. It is not hung.
|
|
78
|
+
- UI is on :3999, not the Next.js default :3000.
|
|
79
|
+
- Auth0 dev tenant rate-limits past ~20 logins/hour.
|
|
80
|
+
|
|
81
|
+
## Resolutions
|
|
82
|
+
|
|
83
|
+
Observed by prepare runs. Each is a signal that occurred and the fix that cleared it, applied automatically when the same signal recurs.
|
|
84
|
+
|
|
85
|
+
- **ui** — HTTP 500 on `/dashboard` while api was still booting
|
|
86
|
+
→ start api first and wait for its ready signal *(user-directed, 2026-08-04)*
|
|
87
|
+
- **worker** — exited immediately, `.env.local` absent
|
|
88
|
+
→ copy `.env.example`, user supplies `QUEUE_URL` *(user-directed, 2026-08-04)*
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The sections above the Resolutions heading are the user's own words and are never rewritten by a run. Resolutions are what the machine observed, kept separate so the user can tell which is which and delete either with confidence.
|
|
92
|
+
|
|
93
|
+
### Sentinel
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
# E2E run instructions
|
|
97
|
+
|
|
98
|
+
<!-- Managed by muggle-test-prepare. Hand-edits are preserved — re-run the skill to revise. -->
|
|
99
|
+
|
|
100
|
+
**Updated:** 2026-08-04T12:00:00Z
|
|
101
|
+
|
|
102
|
+
Nothing special — services start independently.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Secrets
|
|
106
|
+
|
|
107
|
+
Never write a credential value. A password, token, API key, or connection string with embedded credentials belongs in a secret store or an env file — not in plaintext notes. Living outside the project keeps this file out of version control, but it is still readable on disk and is exactly the kind of file a user pastes into an issue when asking why their stack won't come up.
|
|
108
|
+
|
|
109
|
+
Record a **pointer** instead: the env-var name, or the name of the Muggle secret. `Set LOCAL_TEST_PASSWORD before running` is fine; the password is not.
|
|
110
|
+
|
|
111
|
+
If the user's free text contains something that looks like a credential, drop it, write the pointer form, and say so in one line.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Identify required services & startup mode
|
|
2
2
|
|
|
3
|
-
> Skipped
|
|
3
|
+
> Skipped entirely on a replay run — the recipe supplies the service list and startup mode. See [replay-or-learn](./replay-or-learn.md).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Start from the scan.** [derive-service-graph](./derive-service-graph.md) has already derived services, directories, start commands and ports from the workspace's own manifests. Present that graph for confirmation and ask only about what the scan listed as undetermined — which services this user actually needs, what can't run locally, ordering no manifest declares, and steps that happen by hand. Re-asking something the scan established wastes the scan.
|
|
6
|
+
|
|
7
|
+
When the scan found nothing (no workspace manifests, an unfamiliar layout), fall back to listing folder names in the **parent directory** of the current working directory:
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
ls -d "$(dirname "$PWD")"/*/ | xargs -I{} basename {}
|
|
@@ -27,7 +27,9 @@ Cleanup: say "stop services" or re-invoke this skill.
|
|
|
27
27
|
|
|
28
28
|
## Save the plan
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Only on a learning run, and only once the user has accepted the gate in [confirm-recipe](./confirm-recipe.md). Nothing is persisted before that — a recipe the user didn't agree to is a recipe they'll have to undo, and a recipe for a preparation that failed is worse than none.
|
|
31
|
+
|
|
32
|
+
A replay run writes nothing here; it already has the recipe.
|
|
31
33
|
|
|
32
34
|
Build the JSON from the in-memory tracking file, dropping runtime fields:
|
|
33
35
|
|
|
@@ -41,10 +43,7 @@ jq '{
|
|
|
41
43
|
}' /tmp/muggle-test-prepare.json
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- If `git rev-parse --show-toplevel` succeeds (call the result `$REPO`) → write `$REPO/.muggle-ai/prepare-plan.json`. Create `$REPO/.muggle-ai/` if missing.
|
|
47
|
-
- Else → upsert the entry under key `$(dirname "$PWD")` (absolute) in `~/.muggle-ai/prepare-plans.json`. Create the file as `{}` if missing.
|
|
46
|
+
Upsert it under the stack's key — the absolute path of the working directory's parent — in `~/.muggle-ai/prepare-plans.json`, creating the file as `{}` if missing. The plan is machine-local, user-level data: it never goes inside the user's project, and resolving it requires no version-control tool.
|
|
48
47
|
|
|
49
48
|
Then print, once:
|
|
50
49
|
|
|
@@ -54,3 +53,11 @@ Then print, once:
|
|
|
54
53
|
```
|
|
55
54
|
|
|
56
55
|
If this run short-circuited via [reuse-plan](./reuse-plan.md), don't rewrite — but **do** refresh `updated` and any `command` that was re-derived during validation. Skip the announcement on the refresh path.
|
|
56
|
+
|
|
57
|
+
## Save the E2E run instructions
|
|
58
|
+
|
|
59
|
+
The instructions arrive resolved in the dispatch prompt — captured while the user was present, in [e2e-instructions](./e2e-instructions.md). Write them verbatim, in that stage's format, to the location it resolves: `~/.muggle-ai/e2e-instructions/<key>.md`. Create the directory if missing. This file is machine-local and never goes inside the user's project.
|
|
60
|
+
|
|
61
|
+
Nothing resolved in the plan → write nothing. An absent file is a stage that has not run yet; an empty one would read as "nothing to say" and suppress the question forever.
|
|
62
|
+
|
|
63
|
+
Never write a credential value here — pointers only, per that stage's Secrets rule.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Recording a resolution
|
|
2
|
+
|
|
3
|
+
How a problem hit during preparation becomes something the next run already knows. Referenced by [start-services](./start-services.md), [smoke-test](./smoke-test.md), and [fresh-install](./fresh-install.md) — every stage that can fail.
|
|
4
|
+
|
|
5
|
+
## On a replay: consult before attempting
|
|
6
|
+
|
|
7
|
+
When a step fails and the recipe holds a resolution for the same signal, apply that resolution first. A problem solved before is solved the same way again, silently. Re-deriving a fix the user already sat through is the failure this whole mechanism exists to prevent.
|
|
8
|
+
|
|
9
|
+
Only when no recorded resolution matches, or the recorded one does not clear it, does the failure become a [hard block](./confirm-recipe.md#hard-block).
|
|
10
|
+
|
|
11
|
+
## Resolving
|
|
12
|
+
|
|
13
|
+
1. **Attempt autonomously** where the fix is known and safe — a clean restart, a fresh install, waiting out a slow boot that is still making progress.
|
|
14
|
+
2. **Escalate** when it is not. During execution that means returning `needs-input:` naming the service and the concrete signal; the dispatching skill resolves it with the user and re-dispatches. Never guess at a fix that could destroy state.
|
|
15
|
+
|
|
16
|
+
## What to record
|
|
17
|
+
|
|
18
|
+
Per resolved problem, three things and nothing else:
|
|
19
|
+
|
|
20
|
+
- The **signal** — the concrete observation, not a paraphrase. An HTTP status, a matched log line, an exit code.
|
|
21
|
+
- The **service** it occurred on.
|
|
22
|
+
- The **resolution** that actually cleared it, and whether it was autonomous or user-directed.
|
|
23
|
+
|
|
24
|
+
A problem that was never cleared is not a resolution. Record it as an exclusion with its reason instead, so the next run does not retry something known to be hopeless.
|
|
25
|
+
|
|
26
|
+
## What not to record
|
|
27
|
+
|
|
28
|
+
- A transient that cleared on retry with no intervention. Nothing was learned; it was a blip.
|
|
29
|
+
- A signal already recorded for the same service with the same resolution. Update the existing entry rather than appending a duplicate.
|
|
30
|
+
- Anything containing a credential. Record the pointer form per [e2e-instructions](./e2e-instructions.md#secrets).
|
|
31
|
+
|
|
32
|
+
Resolutions accumulate through the run and are written **only** when the user accepts the gate in [confirm-recipe](./confirm-recipe.md). Nothing is persisted mid-run.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Replay or learn
|
|
2
|
+
|
|
3
|
+
One decision, made before anything else: does a prepare recipe already exist for this stack?
|
|
4
|
+
|
|
5
|
+
Resolve the recipe location per [confirm-recipe](./confirm-recipe.md).
|
|
6
|
+
|
|
7
|
+
- **Recipe exists** → **replay run**. Skip straight to the execute phase and run it. No scan, no interview, no questions. The whole point of having learned is not to ask again.
|
|
8
|
+
- **No recipe** → **learning run**. Run the Decide stages in order, then the single gate at the end.
|
|
9
|
+
|
|
10
|
+
A recipe the user declined to save is the same as no recipe: the next run learns again. Declining is not a permanent no, it just means nothing was written.
|
|
11
|
+
|
|
12
|
+
## What a replay is allowed to do
|
|
13
|
+
|
|
14
|
+
Execute the recorded steps, in the recorded order, using the recorded commands. When a step fails, consult the recipe's recorded resolutions **first** — a problem solved before is solved the same way again, without asking.
|
|
15
|
+
|
|
16
|
+
Only a [hard block](./confirm-recipe.md#hard-block) permits a replay to deviate or prompt.
|
|
17
|
+
|
|
18
|
+
## Reuse gate
|
|
19
|
+
|
|
20
|
+
`reusePreparePlan` still governs whether a found recipe is used at all. `never` forces a learning run even when a recipe exists — the escape hatch for a stack that has been re-architected.
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Resolving the saved plan
|
|
2
2
|
|
|
3
|
-
A previously saved **prepare plan** is the durable recipe for this stack
|
|
3
|
+
How [replay-or-learn](./replay-or-learn.md) finds the machine-readable half of the recipe. A previously saved **prepare plan** is the durable recipe for this stack, paired with the prose half in `~/.muggle-ai/e2e-instructions/<key>.md`. Distinct from the ephemeral `/tmp/muggle-test-prepare.json` tracker — that file holds live PIDs/logs and is rebuilt every run.
|
|
4
|
+
|
|
5
|
+
Finding a plan means this is a **replay run**: execute it, ask nothing. Finding none means a **learning run**.
|
|
4
6
|
|
|
5
7
|
## Resolve
|
|
6
8
|
|
|
7
9
|
In order; first hit wins.
|
|
8
10
|
|
|
9
|
-
1. **
|
|
10
|
-
2. **
|
|
11
|
-
3. **No plan found** → exit this step; the workflow continues at [rebase-check](./rebase-check.md).
|
|
11
|
+
1. **Saved plan.** If `~/.muggle-ai/prepare-plans.json` exists, read the entry keyed on this stack — the absolute path of the working directory's parent. If present → load that entry's value. The plan is machine-local and is never read from, or written to, the user's project.
|
|
12
|
+
2. **No plan found** → exit this step; the workflow continues at [rebase-check](./rebase-check.md).
|
|
12
13
|
|
|
13
14
|
A loaded plan is a JSON object with `version`, `updated`, `testing_scope`, `excluded_services`, `services`. Reject and treat as "no plan" if `version != 1` or `services` is empty.
|
|
14
15
|
|
|
16
|
+
Load the prose companion per [e2e-instructions](./e2e-instructions.md) — `~/.muggle-ai/e2e-instructions/<key>.md`, keyed on the same stack identity as the global plan entry. It is independent of the plan: a missing companion is not a missing plan, and vice versa.
|
|
17
|
+
|
|
15
18
|
## Gate `reusePreparePlan`
|
|
16
19
|
|
|
17
20
|
Per [`muggle-preferences/preference-gates/README.md`](../../muggle-preferences/preference-gates/README.md). Read the current value from the `Muggle Test Preferences` session-context line; absent → `ask`.
|
|
@@ -37,7 +40,7 @@ Per [`muggle-preferences/preference-gates/README.md`](../../muggle-preferences/p
|
|
|
37
40
|
- The indicator file that produced `command` still exists in `dir` (e.g. `package.json` for an `npm`/`node` command; see the indicator table in [start-commands](./start-commands.md)) → keep. Else re-derive **just that one entry** by running the indicator-detection from [start-commands](./start-commands.md) against `dir`, and replace its `command`. Log `"Re-derived <name>: <old> → <new>"`.
|
|
38
41
|
2. **All entries dropped** → discard the plan; continue at [rebase-check](./rebase-check.md). Otherwise proceed with surviving + re-derived entries.
|
|
39
42
|
3. **Hydrate** `/tmp/muggle-test-prepare.json` with the surviving entries (no PIDs yet, `testing_scope` from the plan, `excluded_services` from the plan).
|
|
40
|
-
4. **Short-circuit** to [check-running](./check-running.md). The skipped stages are [scope](./scope.md), [viability-check](./viability-check.md), [identify-services](./identify-services.md), [start-commands](./start-commands.md) — the reused plan
|
|
43
|
+
4. **Short-circuit** to [check-running](./check-running.md). The skipped stages are [scope](./scope.md), [viability-check](./viability-check.md), [identify-services](./identify-services.md), [start-commands](./start-commands.md), [e2e-instructions](./e2e-instructions.md) — the reused plan and its companion supply their answers. Carry the loaded instructions forward unchanged; the user is not re-asked. When the companion is absent, run [e2e-instructions](./e2e-instructions.md) once to capture it, then continue the short-circuit. The remaining stages run normally: [env-file](./env-file.md), [fresh-install](./fresh-install.md), [start-services](./start-services.md) (only for entries not already listening), [smoke-test](./smoke-test.md), [readiness-report](./readiness-report.md).
|
|
41
44
|
|
|
42
45
|
## Rediscover path
|
|
43
46
|
|
|
@@ -12,7 +12,9 @@ Use the primitives in `dev-server-readiness.md`. Don't re-implement.
|
|
|
12
12
|
|
|
13
13
|
## Diagnose-and-fix loop
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**Consult the recipe first.** When a recorded resolution matches this signal on this service, apply it without asking, per [record-resolution](./record-resolution.md). The user already answered this question once.
|
|
16
|
+
|
|
17
|
+
Otherwise show the concrete signal (HTTP code, sniff hit, or log line) and `AskUserQuestion`:
|
|
16
18
|
|
|
17
19
|
> "**<service-name>** isn't healthy: `<signal>`. How do you want to proceed?"
|
|
18
20
|
|
|
@@ -23,4 +25,6 @@ On failure, show the concrete signal (HTTP code, sniff hit, or log line) and `As
|
|
|
23
25
|
|
|
24
26
|
Loop per service until pass or skip. Cap at **3 iterations** — then force a manual-intervention pause.
|
|
25
27
|
|
|
28
|
+
Whatever cleared the failure is a resolution: capture the signal, the service, and the fix per [record-resolution](./record-resolution.md), so the next run applies it silently instead of asking again. A service skipped instead of fixed is recorded as an exclusion with its reason, not as a resolution.
|
|
29
|
+
|
|
26
30
|
For `external: true`, only Options 3 and 4 apply.
|