@muggleai/works 4.12.4 → 4.13.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/dist/{chunk-JNI7INIO.js → chunk-QUWM3JQY.js} +2 -2
- package/dist/{chunk-CPF6AR2I.js → chunk-TWILR37J.js} +37 -37
- 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/github-cli-recipes/submitted-reviews.md +1 -1
- package/dist/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +6 -4
- package/dist/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
- package/dist/plugin/skills/_shared/pr-followup-helpers/classify.md +3 -4
- package/dist/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +22 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers.md +1 -0
- package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +56 -0
- package/dist/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +1 -1
- package/dist/plugin/skills/do/address-reviews.md +14 -8
- package/dist/plugin/skills/do/e2e-acceptance.md +7 -3
- package/dist/plugin/skills/do/per-comment-replies.md +8 -2
- package/dist/plugin/skills/do/resolve-reminder.md +16 -18
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +5 -3
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +10 -3
- package/dist/plugin/skills/muggle-pr-followup/auto-track.md +91 -0
- package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +11 -4
- package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +2 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +7 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +6 -3
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +12 -0
- package/dist/plugin/skills/muggle-preferences/ops/configure.md +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoReuseValidationContext.md +11 -0
- package/dist/release-manifest.json +4 -4
- package/dist/{src-YR5UKLPC.js → src-BD5AM6OH.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/github-cli-recipes/submitted-reviews.md +1 -1
- package/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +6 -4
- package/plugin/skills/_shared/pr-followup-helpers/allow-list.md +1 -1
- package/plugin/skills/_shared/pr-followup-helpers/classify.md +3 -4
- package/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +22 -0
- package/plugin/skills/_shared/pr-followup-helpers.md +1 -0
- package/plugin/skills/_shared/resolve-e2e-validation-context.md +56 -0
- package/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +1 -1
- package/plugin/skills/do/address-reviews.md +14 -8
- package/plugin/skills/do/e2e-acceptance.md +7 -3
- package/plugin/skills/do/per-comment-replies.md +8 -2
- package/plugin/skills/do/resolve-reminder.md +16 -18
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +5 -3
- package/plugin/skills/muggle-pr-followup/SKILL.md +10 -3
- package/plugin/skills/muggle-pr-followup/auto-track.md +91 -0
- package/plugin/skills/muggle-pr-followup/bootstrap.md +11 -4
- package/plugin/skills/muggle-pr-followup/output-templates/help.md +2 -1
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +7 -1
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +6 -3
- package/plugin/skills/muggle-pr-followup/state-schemas.md +12 -0
- package/plugin/skills/muggle-preferences/ops/configure.md +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/autoReuseValidationContext.md +11 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Auto-Track Procedure
|
|
2
|
+
|
|
3
|
+
The procedure for the **auto-track mode** of `muggle-pr-followup` — invoked when the skill is dispatched with **no arguments**. Routing is in [`SKILL.md`](SKILL.md#routing).
|
|
4
|
+
|
|
5
|
+
Auto-track discovers the PRs you pushed or opened during this Claude Code session — across **any repo** — and starts one **poll-only watcher** per PR. The watcher only watches: it seeds nothing about E2E. Running and posting E2E is `/muggle-do`'s job; a watcher with no validation context yields a `SKIPPED` E2E verdict when `/muggle-do` runs — see [`../do/e2e-acceptance.md`](../do/e2e-acceptance.md) Step 0.
|
|
6
|
+
|
|
7
|
+
## Turn preamble
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
**muggle-pr-followup auto-track** — tracking PRs from this session.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
|
|
15
|
+
`$ARGUMENTS` is empty.
|
|
16
|
+
|
|
17
|
+
## Procedure
|
|
18
|
+
|
|
19
|
+
### Step 1 — Discover candidate PRs from session context
|
|
20
|
+
|
|
21
|
+
A PR counts as **pushed this session** if, earlier in this conversation, you:
|
|
22
|
+
|
|
23
|
+
- opened it (`gh pr create`), or
|
|
24
|
+
- pushed commits to a branch that has an open PR, or
|
|
25
|
+
- acted on it as the active PR (its URL appeared and you worked it).
|
|
26
|
+
|
|
27
|
+
Collect each candidate's canonical URL (`https://github.com/<owner>/<repo>/pull/<n>`); candidates may span repos.
|
|
28
|
+
|
|
29
|
+
### Step 2 — Decide confident vs. uncertain
|
|
30
|
+
|
|
31
|
+
- **Confident** — context clearly identifies one or more PRs pushed this session. Use that set; go to Step 4. **Do not prompt.**
|
|
32
|
+
- **Uncertain** — nothing clearly attributable, or several candidates are plausible. Go to Step 3.
|
|
33
|
+
|
|
34
|
+
### Step 3 — Picker (uncertain only)
|
|
35
|
+
|
|
36
|
+
Build a candidate list from the Step 1 URLs, plus — if the current working directory is a git repo — `gh pr list --author @me --state open --json number,title,url,headRefName` for that repo. Present an `AskUserQuestion` **multi-select** picker of the candidates (PR number + title + repo).
|
|
37
|
+
|
|
38
|
+
- Empty selection → exit with a one-line note (`No PRs selected; nothing to track.`). Write nothing.
|
|
39
|
+
- One or more selected → use them as the track list and go to Step 4.
|
|
40
|
+
|
|
41
|
+
### Step 4 — Seed one poll-only watcher per PR
|
|
42
|
+
|
|
43
|
+
For each PR URL in the track list, run the [`bootstrap.md`](bootstrap.md) procedure with these auto-track overrides:
|
|
44
|
+
|
|
45
|
+
- **Skip Step 3 (verify working tree).** The PR's checkout need not be the current tree. If you know which directory it was pushed from, record `Working tree: <path>` in `state.md`; else omit it — `/muggle-do` resolves the tree when it runs.
|
|
46
|
+
- **Skip Step 6.5 (E2E validation context).** The watcher owns no E2E concern; do **not** write a `## Pre-flight answers` block.
|
|
47
|
+
- **Existing slot → skip silently** (never the slot-conflict abort); add it to the *skipped* list.
|
|
48
|
+
- **`caller = "auto-track"`** in the bootstrap telemetry event.
|
|
49
|
+
|
|
50
|
+
Everything else is unchanged: URL parse, metadata + terminal-PR abort, slug, cursor 0 (process prior reviews on the first tick), and the `prs.json`/`last_seen.json`/`state.md` writes minus the pre-flight block.
|
|
51
|
+
|
|
52
|
+
### Step 5 — Print the summary
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
muggle-pr-followup auto-track
|
|
56
|
+
|
|
57
|
+
Tracked (new):
|
|
58
|
+
<slug> → <owner>/<repo>#<n>
|
|
59
|
+
...
|
|
60
|
+
(or "none")
|
|
61
|
+
Already tracking (skipped):
|
|
62
|
+
<slug> → <owner>/<repo>#<n>
|
|
63
|
+
...
|
|
64
|
+
(or "none")
|
|
65
|
+
|
|
66
|
+
Dispatching:
|
|
67
|
+
/loop 1m /muggle:muggle-pr-followup <slug> <n>
|
|
68
|
+
...
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Print the summary **before** the `/loop` dispatches so it stays visible.
|
|
72
|
+
|
|
73
|
+
### Step 6 — Dispatch the watchers
|
|
74
|
+
|
|
75
|
+
As the last action of the turn, emit one `/loop` line per **newly tracked** PR (not the skipped ones):
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
/loop 1m /muggle:muggle-pr-followup <slug> <n>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Each registers an independent cron — the N-independent-watchers model from [`SKILL.md`](SKILL.md).
|
|
82
|
+
|
|
83
|
+
### Step 7 — Emit telemetry
|
|
84
|
+
|
|
85
|
+
One bootstrap event per **newly tracked** PR per [`../_shared/telemetry-events/pr-followup-bootstrap.md`](../_shared/telemetry-events/pr-followup-bootstrap.md), with `caller = "auto-track"`. Fire-and-forget per [`../_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Skipped PRs emit nothing.
|
|
86
|
+
|
|
87
|
+
## Invariants
|
|
88
|
+
|
|
89
|
+
- **Tracking depends only on the PR.** No E2E context is gathered, prompted for, or required.
|
|
90
|
+
- **Idempotent.** Existing slots are skipped; re-running never double-tracks.
|
|
91
|
+
- **No-op is silent.** Empty discovery followed by an empty picker writes nothing and dispatches nothing.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The procedure for the **bootstrap mode** of `muggle-pr-followup` — invoked when a user dispatches the skill with a GitHub PR URL. Routing into this mode is documented in [`SKILL.md`](SKILL.md#routing).
|
|
4
4
|
|
|
5
|
-
Bootstrap
|
|
5
|
+
Bootstrap asks **one** questionnaire — the E2E validation context the loop will reuse — then runs through to the first watcher dispatch. The user is present at launch, so this is the only place to gather it; every later tick reads it from `state.md`. Without it, a URL-bootstrapped watcher has no `localUrl`/`projectId` and Stage 6 hard-halts instead of running E2E.
|
|
6
6
|
|
|
7
7
|
## Turn preamble
|
|
8
8
|
|
|
@@ -44,13 +44,19 @@ Default: `<repo>-pr<n>` (e.g. `muggle-ai-works-pr154`). Override: `--slug=<name>
|
|
|
44
44
|
If `.muggle-do/sessions/<slug>/` exists:
|
|
45
45
|
|
|
46
46
|
- Without `--resume` → exit with the slot-conflict abort. Both remedies (delete + re-run, or pass `--resume`) are spelled out in the message.
|
|
47
|
-
- With `--resume` → refresh `prs.json[0].head_sha` to the current `headRefOid` from Step 2
|
|
47
|
+
- With `--resume` → refresh `prs.json[0].head_sha` to the current `headRefOid` from Step 2; leave `last_seen.json` and the cursor untouched. If `state.md` already has a `## Pre-flight answers` block, skip to Step 8; if not (older session), run Step 6.5 to backfill it, then skip to Step 8.
|
|
48
48
|
|
|
49
49
|
### Step 6 — Resolve the initial cursor
|
|
50
50
|
|
|
51
51
|
- **Default (no `--forward-only`):** cursor is `0`. The watcher will pick up every existing submitted review on its first tick. This matches the common case where the user opened the PR, left review comments they want addressed, and is now running bootstrap.
|
|
52
52
|
- **With `--forward-only`:** fetch reviews per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md), then take `max(id)`. The watcher only acts on later submissions. Use when bootstrapping a PR with stale/already-handled prior reviews you don't want re-processed.
|
|
53
53
|
|
|
54
|
+
### Step 6.5 — Resolve E2E validation context
|
|
55
|
+
|
|
56
|
+
The only step that may prompt the user. Run the gather in [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md): reuse an existing context if one is found (gated by `autoReuseValidationContext`), else silent detection + one `AskUserQuestion` (strategy, local URL, backend, project, credentials, re-auth). Record Step 3's verified working tree as `Working tree`.
|
|
57
|
+
|
|
58
|
+
Capture the fields for Step 7. Do **not** run E2E now — the first watcher tick that dispatches `/muggle-do` does that.
|
|
59
|
+
|
|
54
60
|
### Step 7 — Seed state files
|
|
55
61
|
|
|
56
62
|
Identify the loop user once per [`../_shared/github-cli-recipes/loop-user-identity.md`](../_shared/github-cli-recipes/loop-user-identity.md); cache in `state.md`.
|
|
@@ -61,7 +67,7 @@ Write under `.muggle-do/sessions/<slug>/`:
|
|
|
61
67
|
|
|
62
68
|
**`last_seen.json`** — see [`state-schemas.md`](state-schemas.md#last_seenjson). One key (`"<owner>/<repo>#<n>"`), `reviewId` from Step 6, `last_pushed_sha: null`, `idle_tick_count: 0`, `cycles_completed: 0`, `escalated_review_ids: []`, `pushed_shas: []`.
|
|
63
69
|
|
|
64
|
-
**`state.md`** — see [`state-schemas.md`](state-schemas.md#statemd). `Bootstrapped from URL: yes`. Cache the loop-user login.
|
|
70
|
+
**`state.md`** — see [`state-schemas.md`](state-schemas.md#statemd). `Bootstrapped from URL: yes`. Cache the loop-user login. Append the `## Pre-flight answers` block with the fields resolved in Step 6.5, per [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md#persisted-fields).
|
|
65
71
|
|
|
66
72
|
Do **not** write `cycle.json` or `requirements.md` — those files are no longer part of the session slot.
|
|
67
73
|
|
|
@@ -85,6 +91,7 @@ Emit one event per [`../_shared/telemetry-events/pr-followup-bootstrap.md`](../_
|
|
|
85
91
|
|
|
86
92
|
## Invariants
|
|
87
93
|
|
|
88
|
-
-
|
|
94
|
+
- Step 6.5 is the **only** user prompt. If the user cancels it, abort leaving nothing on disk.
|
|
95
|
+
- All state writes happen in Step 7 — earlier aborts (including a cancelled Step 6.5) leave nothing on disk.
|
|
89
96
|
- If Step 7 fails mid-write, surface the OS error and tell the user to `rm -rf <slot>` and re-run; do not dispatch the watcher.
|
|
90
97
|
- Bootstrap never retries.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Help output
|
|
2
2
|
|
|
3
|
-
For `/muggle:muggle-pr-followup`
|
|
3
|
+
For `/muggle:muggle-pr-followup help` or `?` (no args runs **auto-track** instead — see [`../auto-track.md`](../auto-track.md)):
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
muggle-pr-followup — watcher loop for PR review follow-ups
|
|
@@ -11,6 +11,7 @@ Active loops:
|
|
|
11
11
|
(or "no active loops")
|
|
12
12
|
|
|
13
13
|
Usage:
|
|
14
|
+
/muggle:muggle-pr-followup → auto-track every PR you pushed this session
|
|
14
15
|
/muggle:muggle-pr-followup <pr-url> → bootstrap a new loop
|
|
15
16
|
/muggle:muggle-pr-followup <slug> <pr-number> → run one tick (called by /loop)
|
|
16
17
|
/muggle:muggle-pr-followup <pr-number> → run one tick (slug inferred from on-disk state)
|
|
@@ -4,9 +4,12 @@ Posted via `gh api .../comments/<comment-id>/replies` per cycle, one per line co
|
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
Addressed in <short-sha>: <one-line summary of the change made for THIS comment>.
|
|
7
|
+
|
|
8
|
+
<!-- muggle-do:bot -->
|
|
9
|
+
🤖 _Automated reply from muggle-do._
|
|
7
10
|
```
|
|
8
11
|
|
|
9
|
-
`<short-sha>` is the first 7 chars of the new SHA
|
|
12
|
+
`<short-sha>` is the first 7 chars of the new SHA; the body must contain that substring so the resolve-reminder stage knows *which push* addressed the thread. The trailing signature block — defined in [`../../_shared/pr-followup-helpers/loop-signature.md`](../../_shared/pr-followup-helpers/loop-signature.md) — is mandatory; its `<!-- muggle-do:bot -->` marker is what identifies the comment as loop-authored.
|
|
10
13
|
|
|
11
14
|
## Top-level fallback (review-body-only)
|
|
12
15
|
|
|
@@ -14,4 +17,7 @@ When an actionable review has a non-empty body but zero line comments, GitHub ha
|
|
|
14
17
|
|
|
15
18
|
```
|
|
16
19
|
Re: review #<review_id> — addressed in <short-sha>: <one-line summary>.
|
|
20
|
+
|
|
21
|
+
<!-- muggle-do:bot -->
|
|
22
|
+
🤖 _Automated reply from muggle-do._
|
|
17
23
|
```
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Resolve-reminder top-level PR comment
|
|
2
2
|
|
|
3
|
-
Posted via `gh pr comment`
|
|
3
|
+
Posted via `gh pr comment` once per review round, when at least one unresolved thread is addressed-by-loop with no newer human reply.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
|
|
6
|
+
These threads are addressed and still open — mark them resolved if satisfied, or reply if more is needed:
|
|
7
7
|
- #<thread-id-1>
|
|
8
8
|
- #<thread-id-2>
|
|
9
9
|
- ...
|
|
10
|
+
|
|
11
|
+
<!-- muggle-do:bot -->
|
|
12
|
+
🤖 _Automated reply from muggle-do._
|
|
10
13
|
```
|
|
11
14
|
|
|
12
|
-
If
|
|
15
|
+
If no such thread exists, no comment is posted (silent). The trailing signature block ([`loop-signature.md`](../../_shared/pr-followup-helpers/loop-signature.md)) keeps the loop from later mistaking its own reminder for a human comment.
|
|
@@ -60,9 +60,21 @@ Free-form markdown. No required schema beyond a few well-known fields the caller
|
|
|
60
60
|
**Created:** <ISO-8601>
|
|
61
61
|
**Bootstrapped from URL:** <yes | no>
|
|
62
62
|
|
|
63
|
+
## Pre-flight answers
|
|
64
|
+
|
|
65
|
+
- Validation: <local-e2e | staging-replay | unit-only | skip>
|
|
66
|
+
- Local URL: <url | N/A>
|
|
67
|
+
- Backend status: <up | down | N/A>
|
|
68
|
+
- Muggle Test project: <name> (<uuid>)
|
|
69
|
+
- Test credentials: <existing | new | skip>
|
|
70
|
+
- Auth status: <ok | re-authed | N/A>
|
|
71
|
+
- Working tree: <path>
|
|
72
|
+
|
|
63
73
|
...free-form notes added by /muggle-do and bootstrap...
|
|
64
74
|
```
|
|
65
75
|
|
|
76
|
+
The `## Pre-flight answers` block is the **E2E validation context** consumed by `do/e2e-acceptance.md` Step 0 — seeded by bootstrap (Step 6.5) or by pre-flight's output block. Fields: [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md#persisted-fields).
|
|
77
|
+
|
|
66
78
|
The watcher does **not** read or write `state.md`. Only bootstrap, `/muggle-do`, and the caller's stages touch it.
|
|
67
79
|
|
|
68
80
|
## `followup.log`
|
|
@@ -26,7 +26,7 @@ you can tell me which (if any) should instead be set to `never`.
|
|
|
26
26
|
For each option: label = key name, description = first paragraph of `preference-gates/<key>.md`. Multi-select question text = `Which of these should auto-proceed (set to "always")?`; selected = `always`.
|
|
27
27
|
|
|
28
28
|
- `multiSelect: true`, `header: "Auth & session"` — `autoLogin`, `autoSelectProject`, `checkForUpdates`, `verboseOutput`
|
|
29
|
-
- `multiSelect: true`, `header: "Test setup"` — `autoSelectLocalHost`, `autoDetectChanges`
|
|
29
|
+
- `multiSelect: true`, `header: "Test setup"` — `autoSelectLocalHost`, `autoDetectChanges`, `autoReuseValidationContext`
|
|
30
30
|
- `multiSelect: true`, `header: "Test run"` — `showElectronBrowser`, `openTestResultsAfterRun`, `autoPublishLocalResults`
|
|
31
31
|
- `multiSelect: true`, `header: "Suggestions & PR"` — `suggestRelatedUseCases`, `suggestRelatedTestCases`, `postPRVisualWalkthrough`, `autoCreatePR`
|
|
32
32
|
- `multiSelect: true`, `header: "Branch hygiene"` — `autoUseWorktree`, `autoRebase`, `autoCleanup`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# `autoReuseValidationContext`
|
|
2
|
+
|
|
3
|
+
Reuse an existing E2E validation context (a prior session's `## Pre-flight answers` block for this working tree) instead of asking the validation questions again. Substitute `{contextSource}` (the slug + age of the block being offered). Fires only when such a block exists; with none, the calling skill runs the full gather and never reaches this gate.
|
|
4
|
+
|
|
5
|
+
**Picker 1** — header `Validation context`, question `"Reuse the validation context from {contextSource}?"`
|
|
6
|
+
- `Reuse it` — `Same local URL, project, strategy, and credentials as {contextSource}.` → copy the block into this session
|
|
7
|
+
- `Re-gather` — `Ask the validation questions fresh.` → run the full gather
|
|
8
|
+
|
|
9
|
+
**Silent action**
|
|
10
|
+
- `always` → `Reusing validation context from {contextSource}`
|
|
11
|
+
- `never` → no footer; the gather is the visible step.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release": "4.
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-05-
|
|
2
|
+
"release": "4.13.0",
|
|
3
|
+
"buildId": "run-43-1",
|
|
4
|
+
"commitSha": "a3ec4b55712543c6d821193998ef49ee93ad42bb",
|
|
5
|
+
"buildTime": "2026-05-27T22:40:42Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-
|
|
1
|
+
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-TWILR37J.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muggleai/works",
|
|
3
3
|
"mcpName": "io.github.multiplex-ai/muggle",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.13.0",
|
|
5
5
|
"description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"test:watch": "vitest"
|
|
42
42
|
},
|
|
43
43
|
"muggleConfig": {
|
|
44
|
-
"electronAppVersion": "1.0.
|
|
44
|
+
"electronAppVersion": "1.0.99",
|
|
45
45
|
"downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
|
|
46
46
|
"runtimeTargetDefault": "production",
|
|
47
47
|
"checksums": {
|
|
48
|
-
"darwin-arm64": "
|
|
49
|
-
"darwin-x64": "
|
|
50
|
-
"linux-x64": "
|
|
51
|
-
"win32-x64": "
|
|
48
|
+
"darwin-arm64": "6bfad4f1db8ecabdf78c73094b6c10e1554b540a964ad3a545d7f13706aaa0ec",
|
|
49
|
+
"darwin-x64": "2f8450becd36482842afa5059254e04229533999693feed99f77e4c87d01f2b1",
|
|
50
|
+
"linux-x64": "302fd730e2ff3ef2f1d70ffbb86f0861ea3b4b1c1fdd81887c86c5172b20d9b6",
|
|
51
|
+
"win32-x64": "c62660fd08eed2337ead48e60ff365a785e40fe36f8695bcc342aa83b1fc267c"
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.13.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.13.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -13,4 +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
|
|
16
|
+
- **Not a loop echo.** `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 **only if every comment is a reply (`in_reply_to_id != null`) and carries the loop marker `<!-- muggle-do:bot -->`** (see [`../pr-followup-helpers/loop-signature.md`](../pr-followup-helpers/loop-signature.md)). A reply-only wrapper with any comment **lacking** the marker is a human follow-up — keep it; the round addresses it. Matching the marker, not structure, is what skips the loop's own replies (posted under the author's identity in single-account workflows) without dropping genuine follow-ups.
|
|
@@ -26,8 +26,10 @@ query($owner: String!, $name: String!, $number: Int!) {
|
|
|
26
26
|
}'
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Filter client-side to `isResolved == false`.
|
|
29
|
+
Filter client-side to `isResolved == false`. Walk each thread's comments in `createdAt` order and classify by the loop marker (see [`../pr-followup-helpers/loop-signature.md`](../pr-followup-helpers/loop-signature.md)), not by `author.login` — the login is ambiguous under a shared account:
|
|
30
30
|
|
|
31
|
-
- **Addressed
|
|
32
|
-
- **
|
|
33
|
-
- **Not addressed** —
|
|
31
|
+
- **Addressed, awaiting resolve** — the **newest** comment carries the loop marker `<!-- muggle-do:bot -->`. The loop has replied and nothing newer is waiting. → resolve-reminder.
|
|
32
|
+
- **Unaddressed human comment** — the newest comment lacks the marker and is newer than the thread's newest loop-marked comment (or the thread has no loop comment yet). → actionable: the round should address it.
|
|
33
|
+
- **Not addressed** — indeterminate (e.g. no comments).
|
|
34
|
+
|
|
35
|
+
A loop comment also cites a `<short-sha>` from `last_seen.pushed_shas[]` in its body, which tells *which* push addressed the thread.
|
|
@@ -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. 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
|
|
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 loop-echo clause in [`../github-cli-recipes/submitted-reviews.md`](../github-cli-recipes/submitted-reviews.md) — matched by the loop signature ([`loop-signature.md`](loop-signature.md)), so the author's *genuine* reviews and thread replies still get through. Including the PR author in this allow-list is therefore safe.
|
|
6
6
|
|
|
7
7
|
## Step 1: requested reviewers
|
|
8
8
|
|
|
@@ -4,12 +4,11 @@ Classify the **review as a unit** — but reply per line comment (threaded), not
|
|
|
4
4
|
|
|
5
5
|
## Pre-check: self-loop filter
|
|
6
6
|
|
|
7
|
-
GitHub auto-creates a synthetic review every time the agent posts `POST /comments/<id>/replies`.
|
|
7
|
+
GitHub auto-creates a synthetic review every time the agent posts `POST /comments/<id>/replies`. In single-account workflows the loop posts under the PR author's own identity, so that synthetic review is indistinguishable from a human's thread reply by author or structure alone — both are reply-only wrappers. The **loop signature** is what separates them (see [`loop-signature.md`](loop-signature.md)).
|
|
8
8
|
|
|
9
|
-
A review is a **self-loop** iff:
|
|
9
|
+
A review is a **self-loop** iff **every** line comment under it is a reply (`in_reply_to_id != null`) **and** carries the loop marker `<!-- muggle-do:bot -->`.
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
- every line comment under it has `in_reply_to_id != null`
|
|
11
|
+
If any comment in a reply-only wrapper **lacks** the marker, it is a **human follow-up** on an existing thread — not a self-loop. It carries reviewer intent; treat it as actionable and address it in this round (the caller's unresolved-thread sweep picks up the thread context).
|
|
13
12
|
|
|
14
13
|
Self-loops bypass the actionable/ambiguous decision entirely. Action: advance the cursor silently. No push, no reply, no resolve-reminder, no escalation, no entry in `escalated_review_ids`. Telemetry: emit one `cycle` event with `outcome: "self-loop-skip"`.
|
|
15
14
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Loop comment signature
|
|
2
|
+
|
|
3
|
+
Every GitHub comment `/muggle-do` posts — inline thread replies, top-level reference comments, resolve-reminders — **must** end with the signature block below. It is the only reliable way to tell loop-authored comments from human comments: in single-account workflows the loop posts under the PR author's own identity, so `author.login` cannot distinguish them. Echo-protection and addressed-by-loop classification both depend on this marker.
|
|
4
|
+
|
|
5
|
+
## The signature
|
|
6
|
+
|
|
7
|
+
Append these two lines as the end of every loop-posted comment body:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<!-- muggle-do:bot -->
|
|
11
|
+
🤖 _Automated reply from muggle-do._
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- `<!-- muggle-do:bot -->` — hidden HTML marker; GitHub renders it invisibly and humans never type it. This is the **detection token**.
|
|
15
|
+
- The visible line makes the automation clear to a reader.
|
|
16
|
+
|
|
17
|
+
## Detection
|
|
18
|
+
|
|
19
|
+
- **Loop-authored** — the comment body contains the literal `<!-- muggle-do:bot -->`.
|
|
20
|
+
- **Human** — the body does not contain the marker.
|
|
21
|
+
|
|
22
|
+
Classify by the marker, never by `author.login` alone — the login is ambiguous under a shared account. A comment that carries the marker is the loop's own and must never re-trigger a cycle; a comment without it is human intent to act on.
|
|
@@ -11,3 +11,4 @@ Each section is its own file — load only what the current step needs.
|
|
|
11
11
|
| [`allow-list`](pr-followup-helpers/allow-list.md) | Resolve who counts as a reviewer (requested reviewers ∪ CODEOWNERS − bots − author). |
|
|
12
12
|
| [`reply-routing`](pr-followup-helpers/reply-routing.md) | Pick the right reply endpoint per comment type (line, body-only, CI failure). |
|
|
13
13
|
| [`classify`](pr-followup-helpers/classify.md) | Per-review binary label: actionable vs ambiguous, with worked examples + borderline rule. |
|
|
14
|
+
| [`loop-signature`](pr-followup-helpers/loop-signature.md) | The signature every loop-posted comment carries, and how to detect loop vs human comments by it. |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Resolving the E2E Validation Context
|
|
2
|
+
|
|
3
|
+
**How-to procedure.** Followed by any seeder that prepares a session for unattended Stage 6 (E2E acceptance) runs.
|
|
4
|
+
|
|
5
|
+
**Goal:** resolve — once, while the user is present — everything Stage 6 needs to run without further prompts (validation strategy, local URL, backend status, Muggle Test project, test credentials, auth), and persist it to `state.md` so every later non-interactive run reads it instead of asking.
|
|
6
|
+
|
|
7
|
+
The sections below are the steps in order: reuse an existing context if one is on disk, else detect what's resolvable silently, ask the rest in one question, and write the result. The final [`## Persisted fields`](#persisted-fields) section doubles as the schema the cycle reads back.
|
|
8
|
+
|
|
9
|
+
## Reuse an existing context
|
|
10
|
+
|
|
11
|
+
If a `## Pre-flight answers` block already exists for this working tree — the current session slot, or the most recent sibling session under `.muggle-do/sessions/*` — fire the [`autoReuseValidationContext`](../muggle-preferences/preference-gates/autoReuseValidationContext.md) gate before gathering anything:
|
|
12
|
+
|
|
13
|
+
- `always` → copy the existing block into this session; skip the questionnaire.
|
|
14
|
+
- `never` → ignore it; run the full gather below.
|
|
15
|
+
- `ask` → prompt reuse-vs-re-gather.
|
|
16
|
+
|
|
17
|
+
Run the gather only when no block exists or the user chose to re-gather.
|
|
18
|
+
|
|
19
|
+
## Silent detection
|
|
20
|
+
|
|
21
|
+
Resolve without prompting; use as questionnaire defaults:
|
|
22
|
+
|
|
23
|
+
1. Dev server + backend health — per [`dev-server-readiness.md`](dev-server-readiness.md).
|
|
24
|
+
2. Muggle Test MCP auth — `muggle-remote-auth-status`.
|
|
25
|
+
3. Candidate projects — `muggle-remote-project-list`, ranked against the repo's dev URL and the PR title.
|
|
26
|
+
4. Existing test-user secrets — `muggle-remote-secret-list` per candidate project (`managed_profile_email` / `managed_profile_password`).
|
|
27
|
+
5. Auth0 tenant for local dev — grep the repo env file for `*AUTH0_DOMAIN*`.
|
|
28
|
+
|
|
29
|
+
## Questions
|
|
30
|
+
|
|
31
|
+
One `AskUserQuestion` for the validation subset, detected values as defaults. Canonical wording lives in [`../do/pre-flight.md`](../do/pre-flight.md) — reference, don't fork:
|
|
32
|
+
|
|
33
|
+
- Validation strategy — pre-flight Q4
|
|
34
|
+
- Local URL — pre-flight Q5 (defers to [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md))
|
|
35
|
+
- Backend reachable — pre-flight Q6
|
|
36
|
+
- Muggle Test project — pre-flight Q7 (defers to [`autoSelectProject`](../muggle-preferences/preference-gates/autoSelectProject.md))
|
|
37
|
+
- Test-user credentials — pre-flight Q8
|
|
38
|
+
- Re-auth Muggle Test MCP — pre-flight Q10
|
|
39
|
+
|
|
40
|
+
The chosen **validation strategy is the standing decision for every cycle** — no per-tick re-prompt. It subsumes the [`autoE2ETest`](../muggle-preferences/preference-gates/autoE2ETest.md) gate (pre-flight Q13), meaningless in a loop: `local-e2e` runs Stage 6 each cycle; `unit-only` / `skip` stands down. The gate's `always` default makes `local-e2e` the default when a dev server is detected.
|
|
41
|
+
|
|
42
|
+
Skip the forward-only questions (task scope, repo, branch, PR target, worktree, rebase) — the targeted repo and head branch are already checked out.
|
|
43
|
+
|
|
44
|
+
## Persisted fields
|
|
45
|
+
|
|
46
|
+
Write to `state.md` under a `## Pre-flight answers` block:
|
|
47
|
+
|
|
48
|
+
- `Validation: <local-e2e | staging-replay | unit-only | skip>`
|
|
49
|
+
- `Local URL: <url | N/A>`
|
|
50
|
+
- `Backend status: <up | down | N/A>`
|
|
51
|
+
- `Muggle Test project: <name> (<uuid>)`
|
|
52
|
+
- `Test credentials: <existing | new | skip>`
|
|
53
|
+
- `Auth status: <ok | re-authed | N/A>`
|
|
54
|
+
- `Working tree: <path>` — the verified checkout the cycle runs against
|
|
55
|
+
|
|
56
|
+
Missing any required field is a seeding bug: escalate with the session path and halt. Never silently skip E2E.
|
|
@@ -23,4 +23,4 @@ One per address-reviews invocation, regardless of outcome.
|
|
|
23
23
|
- `"escalated"` — all reviews were ambiguous; no push.
|
|
24
24
|
- `"mixed"` — both branches happened in the same invocation.
|
|
25
25
|
- `"no-op"` — every input id was already in the escalated set; no work.
|
|
26
|
-
- `"self-loop-skip"` — review was a synthetic wrapper around the agent's own reply (
|
|
26
|
+
- `"self-loop-skip"` — review was a synthetic wrapper around the agent's own reply (every line comment is a reply carrying the loop marker `<!-- muggle-do:bot -->`). Cursor advanced silently; no work, no escalation.
|
|
@@ -27,14 +27,18 @@ Read from `.muggle-do/sessions/<slug>/`:
|
|
|
27
27
|
|
|
28
28
|
## Procedure
|
|
29
29
|
|
|
30
|
-
### Step 1 —
|
|
30
|
+
### Step 1 — Assemble the work set
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Two sources, combined into one batch (dedupe by comment id):
|
|
33
|
+
|
|
34
|
+
**(a) The dispatched reviews.** For each review id in the input:
|
|
33
35
|
|
|
34
36
|
- Fetch reviews per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md) (cursor 0; filter to the specific id).
|
|
35
37
|
- Fetch its line comments per [`../_shared/github-cli-recipes/line-comments-for-review.md`](../_shared/github-cli-recipes/line-comments-for-review.md).
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
**(b) Unaddressed comments on every unresolved thread.** Fetch unresolved threads per [`../_shared/github-cli-recipes/unresolved-threads.md`](../_shared/github-cli-recipes/unresolved-threads.md). For each thread classified **unaddressed human comment** — newest comment lacks the loop marker `<!-- muggle-do:bot -->` ([`loop-signature.md`](../_shared/pr-followup-helpers/loop-signature.md)) and post-dates the loop's last marked reply — add it to the batch, even if its review predates the cursor. This is how a human thread follow-up (a marker-less reply) gets addressed. **Exclude** comments whose review id is in `last_seen.escalated_review_ids` — paused awaiting the user, not re-work.
|
|
40
|
+
|
|
41
|
+
Group (a) and (b) into one combined batch.
|
|
38
42
|
|
|
39
43
|
### Step 2 — Classify each review
|
|
40
44
|
|
|
@@ -57,7 +61,7 @@ The user clarifies on GitHub by submitting a new review. The next watcher tick p
|
|
|
57
61
|
|
|
58
62
|
### Step 4 — Handle actionables (if any)
|
|
59
63
|
|
|
60
|
-
If `actionable_review_ids` is empty, skip
|
|
64
|
+
If `actionable_review_ids` is empty, skip the rest of Step 4 and Step 5; proceed to Step 5.5 (resolve-reminder) then Step 6. Otherwise:
|
|
61
65
|
|
|
62
66
|
#### 4a. Flatten the work
|
|
63
67
|
|
|
@@ -75,7 +79,7 @@ Invoke [`unit-tests.md`](unit-tests.md). Cover the surface that just changed; re
|
|
|
75
79
|
|
|
76
80
|
#### 4d. Run ONE E2E acceptance pass
|
|
77
81
|
|
|
78
|
-
Invoke [`e2e-acceptance.md`](e2e-acceptance.md). One pass covering all related test cases for this PR, not one
|
|
82
|
+
Invoke [`e2e-acceptance.md`](e2e-acceptance.md). One pass covering all related test cases for this PR, not one per comment. The stage reads the persisted validation context (seeded by pre-flight or by bootstrap Step 6.5); a poll-only session with no context (e.g. auto-track) is reported `SKIPPED`. The persisted `Validation` strategy is the standing decision — no per-tick `autoE2ETest` prompt. See [`e2e-acceptance.md`](e2e-acceptance.md) Step 0 and [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md).
|
|
79
83
|
|
|
80
84
|
#### 4e. Create or update the PR
|
|
81
85
|
|
|
@@ -85,9 +89,7 @@ Invoke [`open-prs/update.md`](open-prs/update.md) (pass the PR URL + slug + exis
|
|
|
85
89
|
|
|
86
90
|
Invoke [`per-comment-replies.md`](per-comment-replies.md) with the actionable reviews and the new SHA. One reply per comment, in its own thread, describing what was done for it.
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Invoke [`resolve-reminder.md`](resolve-reminder.md). Scans unresolved threads, classifies, and posts a top-level PR comment listing addressed-by-loop thread ids.
|
|
92
|
+
(The resolve-reminder runs once per round in Step 5.5 below — not only after a push — so a round that pushed nothing still nudges addressed-but-unresolved threads.)
|
|
91
93
|
|
|
92
94
|
### Step 5 — Update session state
|
|
93
95
|
|
|
@@ -95,6 +97,10 @@ Invoke [`resolve-reminder.md`](resolve-reminder.md). Scans unresolved threads, c
|
|
|
95
97
|
- `last_seen.last_pushed_sha` = the new head SHA (update.md already wrote this; verify)
|
|
96
98
|
- `last_seen.reviewId` = max(input review ids ∪ last_seen.reviewId)
|
|
97
99
|
|
|
100
|
+
### Step 5.5 — Resolve-reminder (runs every round)
|
|
101
|
+
|
|
102
|
+
Invoke [`resolve-reminder.md`](resolve-reminder.md) once, regardless of whether this round pushed. It scans unresolved threads, finds those whose newest comment is loop-marked (addressed, awaiting resolve), and posts one top-level PR comment nudging the reviewer to resolve them — or stays silent if there are none. Threads with a newer human comment were already pulled into this round's work set in Step 1(b).
|
|
103
|
+
|
|
98
104
|
### Step 6 — Respawn the watcher
|
|
99
105
|
|
|
100
106
|
Refresh PR state per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). If the PR is now merged or closed:
|
|
@@ -44,11 +44,15 @@ You receive everything from `state.md` already — pre-flight resolved it:
|
|
|
44
44
|
|
|
45
45
|
## Your Job
|
|
46
46
|
|
|
47
|
-
### Step 0: Consume
|
|
47
|
+
### Step 0: Consume the validation context (no user questions)
|
|
48
48
|
|
|
49
|
-
Read `state.md`.
|
|
49
|
+
Read `state.md`.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
**No `## Pre-flight answers` block at all** → the session was seeded poll-only (e.g. by auto-track, [`../muggle-pr-followup/auto-track.md`](../muggle-pr-followup/auto-track.md)). Treat `Validation` as `skip`: emit a `SKIPPED` report with reason `no validation context seeded` and exit cleanly. The watcher owns no E2E context by design; "no context" is a clean skip, not a failure.
|
|
52
|
+
|
|
53
|
+
Otherwise the block was seeded by pre-flight or bootstrap per [`../_shared/resolve-e2e-validation-context.md`](../_shared/resolve-e2e-validation-context.md) — read it the same way regardless of seeder. The persisted `Validation` field (`local-e2e`, `staging-replay`, `unit-only`, `skip`) picks execution vs early-exit below. In a forward run, [`autoE2ETest`](../muggle-preferences/preference-gates/autoE2ETest.md) `ask` was resolved by pre-flight Q13; in a watcher cycle there is no per-tick pre-flight, so `Validation` **is** the standing decision — don't re-resolve `ask`.
|
|
54
|
+
|
|
55
|
+
For a `local-e2e` block, use `localUrl`, `projectId`, and the working-tree path from `state.md`. Missing any → seeding bug; escalate with the session path and halt; do not ask the user.
|
|
52
56
|
|
|
53
57
|
### Step 0.5: Pre-flight verification probes
|
|
54
58
|
|
|
@@ -36,9 +36,12 @@ Reply body uses the template in [`../muggle-pr-followup/output-templates/inline-
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
Addressed in <short-sha>: <one-line summary of the change made for THIS comment>.
|
|
39
|
+
|
|
40
|
+
<!-- muggle-do:bot -->
|
|
41
|
+
🤖 _Automated reply from muggle-do._
|
|
39
42
|
```
|
|
40
43
|
|
|
41
|
-
`<short-sha>` is the first 7 chars of `new_sha
|
|
44
|
+
`<short-sha>` is the first 7 chars of `new_sha`; the body must contain that substring so the resolve-reminder stage knows which push addressed the thread. The trailing signature block is mandatory — its `<!-- muggle-do:bot -->` marker is what identifies the reply as loop-authored (see [`../_shared/pr-followup-helpers/loop-signature.md`](../_shared/pr-followup-helpers/loop-signature.md)).
|
|
42
45
|
|
|
43
46
|
### Step 3 — Handle review-body-only comments
|
|
44
47
|
|
|
@@ -46,6 +49,9 @@ If an actionable review has a non-empty `body` and **zero** line comments, GitHu
|
|
|
46
49
|
|
|
47
50
|
```
|
|
48
51
|
Re: review #<review_id> — addressed in <short-sha>: <one-line summary>.
|
|
52
|
+
|
|
53
|
+
<!-- muggle-do:bot -->
|
|
54
|
+
🤖 _Automated reply from muggle-do._
|
|
49
55
|
```
|
|
50
56
|
|
|
51
57
|
Posted per [`../_shared/github-cli-recipes/top-level-comment.md`](../_shared/github-cli-recipes/top-level-comment.md). Fires at most once per actionable review-with-no-line-comments. Does not fire if the review has line comments — Step 2 covers those.
|
|
@@ -58,4 +64,4 @@ Posted per [`../_shared/github-cli-recipes/top-level-comment.md`](../_shared/git
|
|
|
58
64
|
## Invariants
|
|
59
65
|
|
|
60
66
|
- One reply per line comment. No per-review summary reply anywhere.
|
|
61
|
-
- Every reply body contains the new SHA's 7-char prefix — the
|
|
67
|
+
- Every reply body contains the new SHA's 7-char prefix (which push addressed it) and ends with the loop signature block — the `<!-- muggle-do:bot -->` marker, not the author login, is what identifies loop-authored comments.
|