@muggleai/works 5.7.0 → 5.8.1
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-LTULYOOW.js → chunk-5PYK7DWB.js} +15 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/agents/test-prepare-runner.md +47 -0
- package/dist/plugin/agents/visual-walkthrough-builder.md +58 -0
- package/dist/plugin/hooks/README.md +11 -2
- package/dist/plugin/hooks/hooks.json +7 -1
- package/dist/plugin/scripts/gc-state.sh +66 -0
- package/dist/plugin/scripts/guard-run-job-object.ps1 +256 -0
- package/dist/plugin/scripts/guard-run.mjs +327 -0
- package/dist/plugin/scripts/guardrail-record-tests.sh +5 -4
- package/dist/plugin/scripts/guardrails.mjs +6 -3
- package/dist/plugin/scripts/pr-watch-guards.sh +46 -0
- package/dist/plugin/skills/CLAUDE.md +39 -36
- package/dist/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +3 -3
- package/dist/plugin/skills/_shared/vcs/CLAUDE.md +2 -1
- package/dist/plugin/skills/_shared/vcs/common/branch-standing.md +19 -0
- package/dist/plugin/skills/_shared/vcs/common/ci-rollup.md +16 -0
- package/dist/plugin/skills/_shared/vcs/common/push-to-branch.md +16 -0
- package/{plugin/skills/_shared/vcs/github → dist/plugin/skills/_shared/vcs/common}/verify-working-tree.md +4 -4
- package/dist/plugin/skills/_shared/vcs/github/pr-edit.md +2 -0
- package/dist/plugin/skills/_shared/vcs/github/reply-line-comment.md +2 -0
- package/dist/plugin/skills/_shared/vcs/github/signed-commits.md +28 -0
- package/dist/plugin/skills/_shared/vcs/github/top-level-comment.md +2 -0
- package/dist/plugin/skills/_shared/vcs/github/unresolved-threads.md +39 -39
- package/dist/plugin/skills/_shared/vcs/github.md +5 -2
- package/dist/plugin/skills/_shared/vcs/gitlab/loop-user-identity.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-create.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-discussions.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-metadata.md +2 -2
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-pipeline.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +1 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/signed-commits.md +15 -0
- package/dist/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +2 -2
- package/dist/plugin/skills/_shared/vcs/gitlab.md +6 -3
- package/dist/plugin/skills/_shared/vcs/post-signature.md +31 -0
- package/dist/plugin/skills/do/build.md +58 -56
- package/dist/plugin/skills/do/open-prs/forward.md +85 -84
- package/dist/plugin/skills/do/open-prs/update.md +3 -3
- package/dist/plugin/skills/do/per-comment-replies.md +2 -2
- package/dist/plugin/skills/do/resolve-conflicts.md +59 -58
- package/dist/plugin/skills/do/unit-tests.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +1 -0
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +11 -4
- package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +29 -5
- package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +3 -1
- package/dist/plugin/skills/muggle-pr-followup/contract.md +171 -158
- package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +221 -101
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +2 -2
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/reconcile.md +9 -5
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +191 -175
- package/dist/plugin/skills/muggle-pr-followup/stop.md +31 -0
- package/dist/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -227
- package/dist/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
- package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +2 -2
- package/dist/release-manifest.json +4 -4
- package/package.json +7 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/agents/test-prepare-runner.md +47 -0
- package/plugin/agents/visual-walkthrough-builder.md +58 -0
- package/plugin/hooks/README.md +11 -2
- package/plugin/hooks/hooks.json +7 -1
- package/plugin/scripts/gc-state.sh +66 -0
- package/plugin/scripts/guard-run-job-object.ps1 +256 -0
- package/plugin/scripts/guard-run.mjs +327 -0
- package/plugin/scripts/guardrail-record-tests.sh +5 -4
- package/plugin/scripts/guardrails.mjs +6 -3
- package/plugin/scripts/pr-watch-guards.sh +46 -0
- package/plugin/skills/CLAUDE.md +39 -36
- package/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +3 -3
- package/plugin/skills/_shared/vcs/CLAUDE.md +2 -1
- package/plugin/skills/_shared/vcs/common/branch-standing.md +19 -0
- package/plugin/skills/_shared/vcs/common/ci-rollup.md +16 -0
- package/plugin/skills/_shared/vcs/common/push-to-branch.md +16 -0
- package/{dist/plugin/skills/_shared/vcs/github → plugin/skills/_shared/vcs/common}/verify-working-tree.md +4 -4
- package/plugin/skills/_shared/vcs/github/pr-edit.md +2 -0
- package/plugin/skills/_shared/vcs/github/reply-line-comment.md +2 -0
- package/plugin/skills/_shared/vcs/github/signed-commits.md +28 -0
- package/plugin/skills/_shared/vcs/github/top-level-comment.md +2 -0
- package/plugin/skills/_shared/vcs/github/unresolved-threads.md +39 -39
- package/plugin/skills/_shared/vcs/github.md +5 -2
- package/plugin/skills/_shared/vcs/gitlab/loop-user-identity.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-create.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-discussions.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-metadata.md +2 -2
- package/plugin/skills/_shared/vcs/gitlab/mr-pipeline.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/resolve-discussion.md +1 -1
- package/plugin/skills/_shared/vcs/gitlab/signed-commits.md +15 -0
- package/plugin/skills/_shared/vcs/gitlab/unresolved-discussions.md +2 -2
- package/plugin/skills/_shared/vcs/gitlab.md +6 -3
- package/plugin/skills/_shared/vcs/post-signature.md +31 -0
- package/plugin/skills/do/build.md +58 -56
- package/plugin/skills/do/open-prs/forward.md +85 -84
- package/plugin/skills/do/open-prs/update.md +3 -3
- package/plugin/skills/do/per-comment-replies.md +2 -2
- package/plugin/skills/do/resolve-conflicts.md +59 -58
- package/plugin/skills/do/unit-tests.md +1 -1
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +1 -0
- package/plugin/skills/muggle-pr-followup/SKILL.md +11 -4
- package/plugin/skills/muggle-pr-followup/arm-watcher.md +29 -5
- package/plugin/skills/muggle-pr-followup/bootstrap.md +3 -1
- package/plugin/skills/muggle-pr-followup/contract.md +171 -158
- package/plugin/skills/muggle-pr-followup/evals/evals.json +221 -101
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +2 -2
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -1
- package/plugin/skills/muggle-pr-followup/reconcile.md +9 -5
- package/plugin/skills/muggle-pr-followup/state-schemas.md +191 -175
- package/plugin/skills/muggle-pr-followup/stop.md +31 -0
- package/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -227
- package/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
- package/plugin/skills/muggle-test-prepare/steps/start-services.md +2 -2
- package/dist/plugin/skills/_shared/vcs/github/push-to-branch.md +0 -10
- package/plugin/skills/_shared/vcs/github/push-to-branch.md +0 -10
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Signed commits without local signing
|
|
2
|
+
|
|
3
|
+
**Never push unsigned commits.** When the machine has no working signing setup, do not fall back to unsigned `git commit` + `git push` — create the commits **remotely** with GraphQL `createCommitOnBranch`, which GitHub signs server-side. And never "fix" a signing failure by disabling it: no `--no-gpg-sign`, no `-c commit.gpgsign=false` — a broken signing setup is fixed or routed around via the remote path, not turned off.
|
|
4
|
+
|
|
5
|
+
## Preflight
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git -C <repo-path> log --format='%G?' origin/<branch>..HEAD # unpushed branch: <base>..HEAD
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Any `N` (no signature) among the commits about to leave the machine → the push is blocked; use the remote path below. `G`/`E`/`U` are signed commits (locally unverifiable is fine — GitHub-signed commits show `E` without GitHub's key in the local keyring). Signing configured and working → commit and push normally.
|
|
12
|
+
|
|
13
|
+
## Remote signed commit
|
|
14
|
+
|
|
15
|
+
1. The branch must exist on the remote; create it at the base if absent: `gh api repos/<owner>/<repo>/git/refs -f ref=refs/heads/<branch> -f sha=<base-sha>`.
|
|
16
|
+
2. Stage the change (`git add <files>`), then take each file's canonical bytes from the **index** — `git cat-file blob :<path>` — and base64 them. Index blobs, never working-copy reads: the index holds git's normalized content (line endings, filters), so the remote tree matches what a local commit would have produced.
|
|
17
|
+
3. One `createCommitOnBranch` mutation per commit: `branch {repositoryNameWithOwner, branchName}`, `message {headline, body}`, `expectedHeadOid` = the branch's current remote head (a concurrency lease — a concurrent push 409s instead of being clobbered), `fileChanges.additions` (path + base64 contents; removals via `fileChanges.deletions`).
|
|
18
|
+
4. Sync the local branch to the result: `git fetch origin <branch>`, verify `git diff --cached origin/<branch>` is **empty** (remote tree identical to what was staged), then `git reset --hard origin/<branch>`. A non-empty diff means the payload missed a file — fix and re-commit; never leave local and remote diverged.
|
|
19
|
+
|
|
20
|
+
## Rebase / force-push
|
|
21
|
+
|
|
22
|
+
A local rebase mints new local commits — unsigned on this machine — so the `--force-with-lease` path is equally blocked. Replay instead:
|
|
23
|
+
|
|
24
|
+
1. Create a temp ref at the new base tip.
|
|
25
|
+
2. Re-create each branch commit on it via `createCommitOnBranch` (same per-commit file snapshots from `git cat-file blob <commit>:<path>`; conflicted files carry the resolved content).
|
|
26
|
+
3. Move the branch ref with a lease: verify the branch's current remote head is still the expected pre-rebase SHA, then `gh api -X PATCH repos/<owner>/<repo>/git/refs/heads/<branch> -f sha=<new-head> -F force=true`. Delete the temp ref.
|
|
27
|
+
|
|
28
|
+
The replayed commits are GitHub-signed; the guarded ref move is the only force operation.
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
# Unresolved comment threads
|
|
2
|
-
|
|
3
|
-
For the watcher's dispatch trigger and the resolve-reminder stage. GraphQL only — REST does not expose `isResolved`/`isOutdated`.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
gh api graphql -F owner=<owner> -F name=<repo> -F number=<n> -f query='
|
|
7
|
-
query($owner: String!, $name: String!, $number: Int!) {
|
|
8
|
-
repository(owner: $owner, name: $name) {
|
|
9
|
-
pullRequest(number: $number) {
|
|
10
|
-
reviewThreads(first: 100) {
|
|
11
|
-
nodes {
|
|
12
|
-
id
|
|
13
|
-
isResolved
|
|
14
|
-
isOutdated
|
|
15
|
-
comments(first: 100) {
|
|
16
|
-
nodes {
|
|
17
|
-
databaseId
|
|
18
|
-
pullRequestReview { databaseId }
|
|
19
|
-
author { login }
|
|
20
|
-
body
|
|
21
|
-
createdAt
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}'
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
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:
|
|
32
|
-
|
|
33
|
-
- **Addressed, awaiting resolve** — the **newest** comment carries the loop marker `<!-- muggle-do:bot -->`. The loop has replied and nothing newer is waiting. → resolve-reminder.
|
|
34
|
-
- **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.
|
|
35
|
-
- **Not addressed** — indeterminate (e.g. no comments).
|
|
36
|
-
|
|
37
|
-
Each comment exposes its owning review as `pullRequestReview.databaseId` — the watcher collects this from an actionable thread's newest comment to build its dispatch list.
|
|
38
|
-
|
|
39
|
-
A loop comment also cites a `<short-sha>` from `last_seen.pushed_shas[]` in its body, which tells *which* push addressed the thread.
|
|
1
|
+
# Unresolved comment threads
|
|
2
|
+
|
|
3
|
+
For the watcher's dispatch trigger and the resolve-reminder stage. GraphQL only — REST does not expose `isResolved`/`isOutdated`.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
gh api graphql -F owner=<owner> -F name=<repo> -F number=<n> -f query='
|
|
7
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
8
|
+
repository(owner: $owner, name: $name) {
|
|
9
|
+
pullRequest(number: $number) {
|
|
10
|
+
reviewThreads(first: 100) {
|
|
11
|
+
nodes {
|
|
12
|
+
id
|
|
13
|
+
isResolved
|
|
14
|
+
isOutdated
|
|
15
|
+
comments(first: 100) {
|
|
16
|
+
nodes {
|
|
17
|
+
databaseId
|
|
18
|
+
pullRequestReview { databaseId }
|
|
19
|
+
author { login }
|
|
20
|
+
body
|
|
21
|
+
createdAt
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
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:
|
|
32
|
+
|
|
33
|
+
- **Addressed, awaiting resolve** — the **newest** comment carries the loop marker `<!-- muggle-do:bot -->`. The loop has replied and nothing newer is waiting. → resolve-reminder.
|
|
34
|
+
- **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. This holds **regardless of `isOutdated`** — a thread whose anchored line has since moved (a rebase or a later push) still carries its unanswered question, and skipping it leaves that question unanswered for good. Whether the moved code already mooted the concern is a judgment for the round to make and reply to, not a reason to skip; the marker rule then stops re-dispatch on the next poll. Both the watcher's dispatch trigger and the resolve-reminder stage ignore `isOutdated`.
|
|
35
|
+
- **Not addressed** — indeterminate (e.g. no comments).
|
|
36
|
+
|
|
37
|
+
Each comment exposes its owning review as `pullRequestReview.databaseId` — the watcher collects this from an actionable thread's newest comment to build its dispatch list.
|
|
38
|
+
|
|
39
|
+
A loop comment also cites a `<short-sha>` from `last_seen.pushed_shas[]` in its body, which tells *which* push addressed the thread.
|
|
@@ -11,11 +11,14 @@ Skills assume a working `gh auth status`. Auth errors surface verbatim from `gh`
|
|
|
11
11
|
| [`pr-metadata`](github/pr-metadata.md) | Snapshot PR state, head SHA, branch, conflict + `behind_by` out-of-date detection — watcher + bootstrap. |
|
|
12
12
|
| [`submitted-reviews`](github/submitted-reviews.md) | Fetch a review by id / watcher's body-only-review check. |
|
|
13
13
|
| [`pr-checks`](github/pr-checks.md) | Check-run rollup for the head SHA — watcher's CI poll. |
|
|
14
|
+
| [`ci-rollup`](common/ci-rollup.md) | Tool-agnostic CI poll — dispatches to `pr-checks` / `mr-pipeline`, folds into red/pending/green. |
|
|
15
|
+
| [`branch-standing`](common/branch-standing.md) | Tool-agnostic conflict + out-of-date detection — dispatches to `pr-metadata` / `mr-metadata`. |
|
|
14
16
|
| [`line-comments-for-review`](github/line-comments-for-review.md) | Pull a review's line comments — `/muggle-do` per-comment routing. |
|
|
15
17
|
| [`unresolved-threads`](github/unresolved-threads.md) | GraphQL unresolved-thread state — watcher's dispatch trigger + resolve-reminder. |
|
|
16
18
|
| [`reply-line-comment`](github/reply-line-comment.md) | POST a threaded reply on a line comment. |
|
|
17
19
|
| [`top-level-comment`](github/top-level-comment.md) | POST a top-level PR comment — resolve-reminder + overflow. |
|
|
18
|
-
| [`push-to-branch`](
|
|
19
|
-
| [`
|
|
20
|
+
| [`push-to-branch`](common/push-to-branch.md) | Signing-gated push + capture new SHA after address-reviews work. |
|
|
21
|
+
| [`signed-commits`](github/signed-commits.md) | Never-push-unsigned rule: `%G?` preflight, server-signed commits via `createCommitOnBranch`, rebase replay. |
|
|
22
|
+
| [`verify-working-tree`](common/verify-working-tree.md) | Three checks bootstrap runs before seeding state. |
|
|
20
23
|
| [`pr-edit`](github/pr-edit.md) | Refresh title or body when address-reviews mode flips state. |
|
|
21
24
|
| [`loop-user-identity`](github/loop-user-identity.md) | Resolve the GitHub login of the loop user. |
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The GitLab identity that owns the authenticated `glab` token. Resolve-reminder thread classification and reply attribution need this.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
glab api user
|
|
6
|
+
glab api user | jq -r '.username'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Cache in `state.md` under `Loop user:`; re-resolve only when missing.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Open a merge request
|
|
2
2
|
|
|
3
|
-
For `open-prs`. Push the branch first (see [`../
|
|
3
|
+
For `open-prs`. Push the branch first (see [`../common/push-to-branch.md`](../common/push-to-branch.md)), then open the MR.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
glab mr create -R <group>/<project> \
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Incoming feedback for the watcher's poll and the address-reviews fetch. GitLab has **no review envelope** — there is no submitted-review object grouping a summary body with line comments. Feedback arrives as individual notes, each belonging to a discussion (a thread). This recipe is the `submitted-reviews` analogue.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
glab api projects/:id/merge_requests
|
|
6
|
+
glab api projects/:id/merge_requests/<iid>/discussions --paginate
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Each discussion has `id` and a `notes[]` array; each note has `id`, `author.username`, `body`, `created_at`, `system` (a `true` flag marks GitLab's own activity entries — skip them).
|
|
@@ -16,7 +16,7 @@ glab mr view <iid> -R <group>/<project> -F json
|
|
|
16
16
|
`detailed_merge_status == "need_rebase"` reports a behind branch only when the project enforces "fast-forward merge"; otherwise it stays `mergeable` while behind. Detect out-of-date straight from commit ancestry instead — independent of merge-method config:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
glab api projects/:id/repository/compare?from=<
|
|
19
|
+
glab api "projects/:id/repository/compare?from=<head_sha>&to=<target_branch>" | jq '.commits | length'
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Compare lists the commits reachable from `to` but not `from`, so `from=<head_sha>&to=<target_branch>` yields exactly the base commits the head lacks — non-zero ⇒ out of date; zero ⇒ current with base.
|
|
@@ -9,7 +9,7 @@ glab ci status -R <group>/<project> -b <source_branch>
|
|
|
9
9
|
Or straight from the API for the latest pipeline and its jobs:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
glab api projects/:id/merge_requests
|
|
12
|
+
glab api projects/:id/merge_requests/<iid>/pipelines | jq -r '.[0].id'
|
|
13
13
|
glab api projects/:id/pipelines/<pipeline-id>/jobs --paginate
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -4,6 +4,6 @@ Used by `/muggle-do` per-comment inline replies. A threaded reply is a new note
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
glab api --method POST \
|
|
7
|
-
projects/:id/merge_requests
|
|
7
|
+
projects/:id/merge_requests/<iid>/discussions/<discussion-id>/notes \
|
|
8
8
|
-f body="<reply-text>"
|
|
9
9
|
```
|
|
@@ -4,7 +4,7 @@ Mark a thread resolved once the loop's reply has addressed it — the resolve-re
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
glab api --method PUT \
|
|
7
|
-
"projects/:id/merge_requests
|
|
7
|
+
"projects/:id/merge_requests/<iid>/discussions/<discussion-id>?resolved=true"
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
Resolves every resolvable note in the thread at once. Only resolvable (diff/line) threads accept this; a non-resolvable discussion returns an error.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Signed commits without local signing
|
|
2
|
+
|
|
3
|
+
**Never push unsigned commits.** GitLab has no server-side signing analogue — commits created through its commits API are unsigned, so a broken local signing setup has no remote route around it. And never "fix" a signing failure by disabling it: no `--no-gpg-sign`, no `-c commit.gpgsign=false`.
|
|
4
|
+
|
|
5
|
+
## Preflight
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git -C <repo-path> log --format='%G?' origin/<branch>..HEAD # unpushed branch: <base>..HEAD
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Any `N` (no signature) among the commits about to leave the machine → the push is blocked. `G`/`E`/`U` are signed commits (locally unverifiable is fine). Signing configured and working → commit and push normally.
|
|
12
|
+
|
|
13
|
+
## Blocked
|
|
14
|
+
|
|
15
|
+
Unsigned commits bound for an MR branch → stop and escalate to the owner to configure local signing. A local rebase mints new unsigned commits, so the force-push path is equally blocked. Never push unsigned.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
For the watcher's dispatch trigger and the resolve-reminder stage. REST exposes resolution directly — no GraphQL needed, unlike GitHub.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
glab api projects/:id/merge_requests
|
|
7
|
-
|
|
6
|
+
glab api projects/:id/merge_requests/<iid>/discussions --paginate \
|
|
7
|
+
| jq '[.[] | select(.notes[0].resolvable == true) | select(any(.notes[]; .resolved == false))]'
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
A discussion is resolvable when its notes carry `resolvable == true` (diff/line threads are; the MR description and system notes are not). A thread is **unresolved** when any of its notes has `resolved == false`.
|
|
@@ -4,7 +4,7 @@ Reusable `glab` / `git` snippets used by `muggle-pr-followup` (watcher + bootstr
|
|
|
4
4
|
|
|
5
5
|
Skills assume a working `glab auth status`. Auth errors surface verbatim from `glab`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`glab api` fills `:id` itself with the URL-encoded path of the current directory's project — run recipes from the MR worktree and leave `:id` as written (elsewhere, substitute the encoded path yourself: `mygroup/myproj` → `mygroup%2Fmyproj`). `<iid>` is the MR's per-project internal id (the `!123` number), not the global id; glab has no placeholder for it — substitute it. `glab api` has no `--jq` flag — pipe to `jq`.
|
|
8
8
|
|
|
9
9
|
## Index
|
|
10
10
|
|
|
@@ -12,6 +12,8 @@ The project ref `:id` is `<group>/<project>` — URL-encode it for `glab api` (`
|
|
|
12
12
|
| :----- | :------- |
|
|
13
13
|
| [`mr-metadata`](gitlab/mr-metadata.md) | Snapshot MR state, head SHA, branch, conflict + out-of-date detection — watcher + bootstrap. |
|
|
14
14
|
| [`mr-pipeline`](gitlab/mr-pipeline.md) | Pipeline-job rollup for the head SHA — watcher's CI poll. |
|
|
15
|
+
| [`ci-rollup`](common/ci-rollup.md) | Tool-agnostic CI poll — dispatches to `pr-checks` / `mr-pipeline`, folds into red/pending/green. |
|
|
16
|
+
| [`branch-standing`](common/branch-standing.md) | Tool-agnostic conflict + out-of-date detection — dispatches to `pr-metadata` / `mr-metadata`. |
|
|
15
17
|
| [`mr-discussions`](gitlab/mr-discussions.md) | Fetch incoming notes/discussions — watcher's feedback poll. |
|
|
16
18
|
| [`unresolved-discussions`](gitlab/unresolved-discussions.md) | Unresolved-discussion state — watcher's dispatch trigger + resolve-reminder. |
|
|
17
19
|
| [`reply-discussion`](gitlab/reply-discussion.md) | POST a threaded reply on a discussion. |
|
|
@@ -20,5 +22,6 @@ The project ref `:id` is `<group>/<project>` — URL-encode it for `glab api` (`
|
|
|
20
22
|
| [`mr-edit`](gitlab/mr-edit.md) | Refresh title or description when address-reviews mode flips state. |
|
|
21
23
|
| [`mr-create`](gitlab/mr-create.md) | Open an MR + capture its URL for handoff. |
|
|
22
24
|
| [`loop-user-identity`](gitlab/loop-user-identity.md) | Resolve the GitLab username of the loop user. |
|
|
23
|
-
| [`push-to-branch`](
|
|
24
|
-
| [`
|
|
25
|
+
| [`push-to-branch`](common/push-to-branch.md) | Signing-gated push + capture new SHA after address-reviews work. |
|
|
26
|
+
| [`signed-commits`](gitlab/signed-commits.md) | Never-push-unsigned rule: `%G?` preflight; no server-side signing analogue → stop and escalate. |
|
|
27
|
+
| [`verify-working-tree`](common/verify-working-tree.md) | Three checks bootstrap runs before seeding state. |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# PR post signature
|
|
2
|
+
|
|
3
|
+
Every pull-request / merge-request body, comment, and review-thread reply that muggle works posts ends with a signature line. Under a single-account workflow the automation posts as the repo owner, so the signature is what tells a reader — and a reviewer — that the post came from Muggle Works and which command produced it.
|
|
4
|
+
|
|
5
|
+
## The line
|
|
6
|
+
|
|
7
|
+
Append this as the last line of the posted body:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
🤖 _Posted by `<command>` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`<command>` is the slash-command of the skill whose `gh` / `glab` call posts the body:
|
|
14
|
+
|
|
15
|
+
- `/muggle-do` — PR/MR descriptions, per-comment thread replies, top-level reference replies, and resolve-reminders.
|
|
16
|
+
- `/muggle-pr-visual-walkthrough` — a walkthrough comment the walkthrough skill posts itself (Mode A).
|
|
17
|
+
|
|
18
|
+
Name the command that owns the post, not the one that generated the content. When the walkthrough hands its rendered block back for embedding (Mode B/C), the caller owns the post, so the caller's command is what the signature names.
|
|
19
|
+
|
|
20
|
+
## Editable bodies (PR / MR description)
|
|
21
|
+
|
|
22
|
+
A description is re-posted whenever state changes, so its signature must not stack. Precede the line with a hidden marker and treat the pair as one unit:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
<!-- muggle-works:signature -->
|
|
26
|
+
🤖 _Posted by `/muggle-do` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Before writing an edited body, delete everything from the `<!-- muggle-works:signature -->` marker to the end of the body, then append the block fresh. This keeps exactly one signature no matter how many times the description is refreshed.
|
|
30
|
+
|
|
31
|
+
A comment or reply is posted once and never edited, so it needs no dedup marker — append the line alone. A loop-authored reply already carries the `<!-- muggle-do:bot -->` detection marker (defined in loop-signature.md) directly above this line; that marker stays, and this line replaces the old visible text.
|
|
@@ -1,56 +1,58 @@
|
|
|
1
|
-
# Build Agent (Stage 3)
|
|
2
|
-
|
|
3
|
-
Implement the code change for this dev cycle. Read the frozen requirements from stage 2, produce the edits in each affected repo's worktree, and commit.
|
|
4
|
-
|
|
5
|
-
## Turn preamble
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
**Stage 3 — Build** — implementing the change per the frozen requirements.
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Inputs
|
|
12
|
-
|
|
13
|
-
- `requirements.md` from stage 2: goal, acceptance criteria, affected repos.
|
|
14
|
-
- `state.md` from pre-flight: worktree path per repo, target branch, anything else the build needs to know about the environment.
|
|
15
|
-
|
|
16
|
-
## Your job
|
|
17
|
-
|
|
18
|
-
For each affected repo:
|
|
19
|
-
|
|
20
|
-
1. **Re-read `requirements.md`.** Treat goal + AC as frozen. If something is unclear at this stage, that's a pre-flight bug — escalate, do not improvise.
|
|
21
|
-
2. **Apply the change** in the repo's worktree. Edit existing files first; create new files only when the requirements demand it. Match the surrounding code's style, naming, and file layout.
|
|
22
|
-
3. **Don't add what wasn't asked for.** No speculative abstractions, no extra logging, no "while I'm here" refactors. Three similar lines is better than a premature abstraction.
|
|
23
|
-
4. **Cover new logic with tests.** If you added or changed non-trivial logic (a hook, reducer, parser, state machine, branching util), write its unit tests now — Stage 5 only *runs* the suite, it never authors tests. Untested new logic is a Definition-of-Done failure, not a Stage-5 gap.
|
|
24
|
-
5. **Commit** with a conventional-commit subject:
|
|
25
|
-
- `feat(<scope>): <short>` for new behavior
|
|
26
|
-
- `fix(<scope>): <short>` for bug fixes
|
|
27
|
-
- `refactor(<scope>): <short>` for reshape
|
|
28
|
-
- `docs(...)`, `chore(...)`, `test(...)` as appropriate
|
|
29
|
-
|
|
30
|
-
The body explains *why* when the why is non-obvious. The diff already says *what*.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
1
|
+
# Build Agent (Stage 3)
|
|
2
|
+
|
|
3
|
+
Implement the code change for this dev cycle. Read the frozen requirements from stage 2, produce the edits in each affected repo's worktree, and commit.
|
|
4
|
+
|
|
5
|
+
## Turn preamble
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
**Stage 3 — Build** — implementing the change per the frozen requirements.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Inputs
|
|
12
|
+
|
|
13
|
+
- `requirements.md` from stage 2: goal, acceptance criteria, affected repos.
|
|
14
|
+
- `state.md` from pre-flight: worktree path per repo, target branch, anything else the build needs to know about the environment.
|
|
15
|
+
|
|
16
|
+
## Your job
|
|
17
|
+
|
|
18
|
+
For each affected repo:
|
|
19
|
+
|
|
20
|
+
1. **Re-read `requirements.md`.** Treat goal + AC as frozen. If something is unclear at this stage, that's a pre-flight bug — escalate, do not improvise.
|
|
21
|
+
2. **Apply the change** in the repo's worktree. Edit existing files first; create new files only when the requirements demand it. Match the surrounding code's style, naming, and file layout.
|
|
22
|
+
3. **Don't add what wasn't asked for.** No speculative abstractions, no extra logging, no "while I'm here" refactors. Three similar lines is better than a premature abstraction.
|
|
23
|
+
4. **Cover new logic with tests.** If you added or changed non-trivial logic (a hook, reducer, parser, state machine, branching util), write its unit tests now — Stage 5 only *runs* the suite, it never authors tests. Untested new logic is a Definition-of-Done failure, not a Stage-5 gap.
|
|
24
|
+
5. **Commit** with a conventional-commit subject:
|
|
25
|
+
- `feat(<scope>): <short>` for new behavior
|
|
26
|
+
- `fix(<scope>): <short>` for bug fixes
|
|
27
|
+
- `refactor(<scope>): <short>` for reshape
|
|
28
|
+
- `docs(...)`, `chore(...)`, `test(...)` as appropriate
|
|
29
|
+
|
|
30
|
+
The body explains *why* when the why is non-obvious. The diff already says *what*.
|
|
31
|
+
|
|
32
|
+
**Signing:** never an unsigned commit. Commit through the signing gate in [`../_shared/vcs/common/push-to-branch.md`](../_shared/vcs/common/push-to-branch.md) — it routes a broken local signing setup to the provider's signed-commits recipe. Never `--no-gpg-sign` or disable signing to work around the failure.
|
|
33
|
+
|
|
34
|
+
## Delegation
|
|
35
|
+
|
|
36
|
+
For a non-trivial change — multiple files, real design surface, or anything you would otherwise brainstorm before coding — run the implementation through superpowers' design → plan → subagent-driven build, then return to this stage's Output. That is a runtime hand-off (an action), not a doc dependency; do not encode superpowers' internals here. Routing a build request into this pipeline (the `autoRouteBuildToMuggleDo` front-door guardrail) exists to combine superpowers' design rigor with this pipeline's impact analysis, E2E, PR, and watcher — neither delivers both alone.
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
|
|
40
|
+
Per repo:
|
|
41
|
+
|
|
42
|
+
**Repo:** name
|
|
43
|
+
- Files edited / created: list
|
|
44
|
+
- Commit subject: `<conventional commit>`
|
|
45
|
+
- Notable choices: anything that needed a judgment call (briefly)
|
|
46
|
+
|
|
47
|
+
**Overall:** READY for impact analysis | BLOCKED — reason
|
|
48
|
+
|
|
49
|
+
If a requirement is fundamentally unimplementable as written, halt and escalate with the specific blocker — do not ship a half-finished implementation.
|
|
50
|
+
|
|
51
|
+
## Re-entry from the address-reviews flow
|
|
52
|
+
|
|
53
|
+
The address-reviews orchestrator ([`address-reviews.md`](address-reviews.md)) invokes this stage when reviewers submit comments that require code/design changes. When re-entered:
|
|
54
|
+
|
|
55
|
+
- The orchestrator passes the actionable reviews' bodies + line comments as the requirements amendment for this iteration. Treat them as additions to the goal/AC.
|
|
56
|
+
- Continue on the existing branch — do not re-create the worktree.
|
|
57
|
+
- After this stage, the orchestrator runs unit-tests → ONE E2E pass → create-or-update PR (push to the existing branch; refresh title/desc if state changed) → per-comment inline replies → resolve-reminder → respawn the watcher.
|
|
58
|
+
- If the requested work cannot be implemented without rethinking design (e.g. a load-bearing invariant must change), return `failed: design-adjustment` and let the orchestrator escalate via the design-adjustment terminal message. Do not partially implement.
|
|
@@ -1,84 +1,85 @@
|
|
|
1
|
-
# Open PR — forward mode
|
|
2
|
-
|
|
3
|
-
Forward pipeline's Stage 7. Invoked by `/muggle-do` after stages 1–6 of a fresh feature. Opens the change — a PR on GitHub (`gh pr create`) or an MR on GitLab (`glab mr create`), provider resolved in Step 4 — then seeds session state and dispatches the first watcher.
|
|
4
|
-
|
|
5
|
-
## Turn preamble
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
**Stage 7 — Create PR** — pushing the branch and opening the PR.
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Inputs
|
|
12
|
-
|
|
13
|
-
- Per-repo: name, path, branch.
|
|
14
|
-
- Requirements: goal, acceptance criteria.
|
|
15
|
-
- **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).
|
|
16
|
-
|
|
17
|
-
## Per repo
|
|
18
|
-
|
|
19
|
-
0. **`autoCreatePR` gate** — apply per [`../../muggle-preferences/preference-gates/autoCreatePR.md`](../../muggle-preferences/preference-gates/autoCreatePR.md). On skip, record the reason in `result.md` and move on.
|
|
20
|
-
|
|
21
|
-
1. **Push:**
|
|
22
|
-
|
|
23
|
-
2. **Title** (under 70 chars):
|
|
24
|
-
- E2E report exists and has failures → `[E2E FAILING] <goal>`
|
|
25
|
-
- No E2E report (validation was `unit-only` or `skip`) → `[UNVERIFIED] <goal>` or `[UNIT-ONLY] <goal>` to match the validation strategy
|
|
26
|
-
- Otherwise → `<goal>`
|
|
27
|
-
|
|
28
|
-
3. **Body** — assemble in order:
|
|
29
|
-
- `## Goal` — from requirements.
|
|
30
|
-
- `## Acceptance Criteria` — bulleted; omit if empty.
|
|
31
|
-
- `## Changes` — summary of what changed in this repo.
|
|
32
|
-
- `## Validation` — one line: link to E2E report, `unit-only`, or `skip — <reason>`.
|
|
33
|
-
- **Walkthrough block** — only when an E2E report exists. Fire [`postPRVisualWalkthrough`](../../muggle-preferences/preference-gates/postPRVisualWalkthrough.md); on skip, omit this block. Otherwise invoke [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) Mode B and embed the returned `body` verbatim. No report → skip the block.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- `
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
**
|
|
70
|
-
**
|
|
71
|
-
**
|
|
72
|
-
**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- `
|
|
82
|
-
- `
|
|
83
|
-
|
|
84
|
-
|
|
1
|
+
# Open PR — forward mode
|
|
2
|
+
|
|
3
|
+
Forward pipeline's Stage 7. Invoked by `/muggle-do` after stages 1–6 of a fresh feature. Opens the change — a PR on GitHub (`gh pr create`) or an MR on GitLab (`glab mr create`), provider resolved in Step 4 — then seeds session state and dispatches the first watcher.
|
|
4
|
+
|
|
5
|
+
## Turn preamble
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
**Stage 7 — Create PR** — pushing the branch and opening the PR.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Inputs
|
|
12
|
+
|
|
13
|
+
- Per-repo: name, path, branch.
|
|
14
|
+
- Requirements: goal, acceptance criteria.
|
|
15
|
+
- **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).
|
|
16
|
+
|
|
17
|
+
## Per repo
|
|
18
|
+
|
|
19
|
+
0. **`autoCreatePR` gate** — apply per [`../../muggle-preferences/preference-gates/autoCreatePR.md`](../../muggle-preferences/preference-gates/autoCreatePR.md). On skip, record the reason in `result.md` and move on.
|
|
20
|
+
|
|
21
|
+
1. **Push:** Execute per [`../../_shared/vcs/common/push-to-branch.md`](../../_shared/vcs/common/push-to-branch.md) — the tool-agnostic instruction for pushing commits (handles the signing gate and directs to provider-specific recipes).
|
|
22
|
+
|
|
23
|
+
2. **Title** (under 70 chars):
|
|
24
|
+
- E2E report exists and has failures → `[E2E FAILING] <goal>`
|
|
25
|
+
- No E2E report (validation was `unit-only` or `skip`) → `[UNVERIFIED] <goal>` or `[UNIT-ONLY] <goal>` to match the validation strategy
|
|
26
|
+
- Otherwise → `<goal>`
|
|
27
|
+
|
|
28
|
+
3. **Body** — assemble in order:
|
|
29
|
+
- `## Goal` — from requirements.
|
|
30
|
+
- `## Acceptance Criteria` — bulleted; omit if empty.
|
|
31
|
+
- `## Changes` — summary of what changed in this repo.
|
|
32
|
+
- `## Validation` — one line: link to E2E report, `unit-only`, or `skip — <reason>`.
|
|
33
|
+
- **Walkthrough block** — only when an E2E report exists. Fire [`postPRVisualWalkthrough`](../../muggle-preferences/preference-gates/postPRVisualWalkthrough.md); on skip, omit this block. Otherwise invoke [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) Mode B and embed the returned `body` verbatim. No report → skip the block.
|
|
34
|
+
- **Signature** — end the body with the Muggle Works signature, editable-body form (the `<!-- muggle-works:signature -->` marker + line, command `/muggle-do`) per [`../../_shared/vcs/post-signature.md`](../../_shared/vcs/post-signature.md). It is the last thing in the body, after the walkthrough block.
|
|
35
|
+
|
|
36
|
+
4. **Create:** resolve the provider per [`../../_shared/vcs/detect-vcs.md`](../../_shared/vcs/detect-vcs.md).
|
|
37
|
+
- `github` → `gh pr create --title "..." --body "..." --head <branch>`. Capture the PR URL and number.
|
|
38
|
+
- `gitlab` → open the change via [`../../_shared/vcs/gitlab/mr-create.md`](../../_shared/vcs/gitlab/mr-create.md): `glab mr create --source-branch <branch> --target-branch <base> --title "..." --description "..."`. Capture the MR URL and iid.
|
|
39
|
+
|
|
40
|
+
5. **Overflow comment:** if the walkthrough skill returned a non-null `comment`, post it once using the provider resolved in Step 4 — `github` per [`../../_shared/vcs/github/top-level-comment.md`](../../_shared/vcs/github/top-level-comment.md), `gitlab` per [`../../_shared/vcs/gitlab/mr-note.md`](../../_shared/vcs/gitlab/mr-note.md). End the posted body with the signature line (command `/muggle-do`) per [`../../_shared/vcs/post-signature.md`](../../_shared/vcs/post-signature.md). Never post when `comment` is `null`.
|
|
41
|
+
|
|
42
|
+
## Stage 8 handoff
|
|
43
|
+
|
|
44
|
+
After every repo is processed, build the watcher manifest and dispatch one watcher loop per opened PR. The dispatches are the LAST action this stage takes.
|
|
45
|
+
|
|
46
|
+
Write `~/.muggle-ai/muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#prsjson):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
[{ "repo": "owner/repo", "number": 142, "url": "...", "head_sha": "...", "state": "open" }]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Seed `~/.muggle-ai/muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty-watermark shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `lastBodyReviewId: 0`.
|
|
53
|
+
|
|
54
|
+
**Do not** seed `cycle.json` or `requirements.md`. The watcher is a dumb pipe; `/muggle-do` reads reviews off GitHub.
|
|
55
|
+
|
|
56
|
+
For each entry in `prs.json`, dispatch its watcher:
|
|
57
|
+
```
|
|
58
|
+
/loop 1m /muggle:muggle-pr-followup <slug> <pr-number>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If `prs.json` is empty, **do not dispatch** — record the reason in `result.md` and exit.
|
|
62
|
+
|
|
63
|
+
## Invariants
|
|
64
|
+
|
|
65
|
+
- PR creation per non-skipped repo; walkthrough block via Mode B; `prs.json`+`last_seen.json` seeded (no `cycle.json`, no `requirements.md`); `/loop` dispatch is the last action.
|
|
66
|
+
|
|
67
|
+
## Output
|
|
68
|
+
|
|
69
|
+
**PRs Created:** repo → URL
|
|
70
|
+
**Skipped:** repo → reason (when `autoCreatePR` short-circuited)
|
|
71
|
+
**Overflow comments posted:** repo → PR #
|
|
72
|
+
**Stage 8:** `Watching <N> PR(s) — one /loop 1m /muggle:muggle-pr-followup <slug> <pr#> per PR` | `No PRs to watch — stage 8 not dispatched`
|
|
73
|
+
**Errors:** repo → message
|
|
74
|
+
|
|
75
|
+
## Post-merge cleanup
|
|
76
|
+
|
|
77
|
+
Gated by `autoCleanup`. Triggered when the watcher's terminal tick observes the merge and dispatches `/muggle-do`'s cleanup directive ([`../cleanup.md`](../cleanup.md)) — never from this stage. See [`../../_shared/post-merge-cleanup.md`](../../_shared/post-merge-cleanup.md).
|
|
78
|
+
|
|
79
|
+
Append one short reminder tied to the gate value:
|
|
80
|
+
|
|
81
|
+
- `always` → `Once merged, I'll run the cleanup sequence automatically.`
|
|
82
|
+
- `never` → omit.
|
|
83
|
+
- `ask` / absent → `Once merged, I'll check with you about cleanup.`
|
|
84
|
+
|
|
85
|
+
Regardless of the gate, also append: `Once it's merged or closed, I'll move to the next plan item — or ask where to go next if there's no plan.`
|