@yemi33/minions 0.1.2156 → 0.1.2158
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/dashboard/js/render-work-items.js +20 -2
- package/docs/completion-reports.md +39 -0
- package/engine/playbook.js +21 -1
- package/engine.js +8 -0
- package/package.json +1 -1
- package/playbooks/_pr-description-audit.md +142 -0
- package/playbooks/fix.md +71 -0
- package/playbooks/implement.md +71 -0
|
@@ -885,8 +885,26 @@ function viewAgentOutput(logPath) {
|
|
|
885
885
|
function openInboxNote(filename) {
|
|
886
886
|
var idx = (inboxData || []).findIndex(function(item) { return item.name === filename; });
|
|
887
887
|
if (idx >= 0) { openModal(idx); return; }
|
|
888
|
-
|
|
889
|
-
|
|
888
|
+
// Not in the live inbox — it's an archived note (the common case for a
|
|
889
|
+
// completed work item's note pill, which the rewriter re-encodes as an
|
|
890
|
+
// 'archive:<name>' token). Fetch it from notes/archive/ and show it in the
|
|
891
|
+
// modal instead of bouncing to the inbox page. Falls back to the inbox page
|
|
892
|
+
// only if the file is genuinely gone (e.g. merged into notes.md).
|
|
893
|
+
fetch('/state/notes/archive/' + encodeURIComponent(filename))
|
|
894
|
+
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); })
|
|
895
|
+
.then(function(content) {
|
|
896
|
+
var titleEl = document.getElementById('modal-title');
|
|
897
|
+
var bodyEl = document.getElementById('modal-body');
|
|
898
|
+
if (!titleEl || !bodyEl) return;
|
|
899
|
+
titleEl.textContent = filename + ' (archived)';
|
|
900
|
+
// eslint-disable-next-line no-unsanitized/property -- reason: renderMd() escapes note content before assembling HTML; filename is set via textContent
|
|
901
|
+
bodyEl.innerHTML = '<div style="font-size:var(--text-md);line-height:1.7;color:var(--muted)">' + renderMd(content) + '</div>';
|
|
902
|
+
document.getElementById('modal').classList.add('open');
|
|
903
|
+
})
|
|
904
|
+
.catch(function() {
|
|
905
|
+
closeModal();
|
|
906
|
+
switchPage('inbox');
|
|
907
|
+
});
|
|
890
908
|
}
|
|
891
909
|
|
|
892
910
|
if (typeof window !== 'undefined') {
|
|
@@ -86,6 +86,7 @@ Do **not** invent, regenerate, or share the nonce across dispatches — each spa
|
|
|
86
86
|
| `followups` | array | Optional. PR-comment follow-up work items the agent dispatched via `POST /api/work-items` with `meta.pr_followup` set. Each entry: `{wi_id, title, reason, parent_comment_id}`. See [PR-comment follow-ups](#pr-comment-follow-ups). |
|
|
87
87
|
| `meta.review` | object | Optional, review tasks only. Records project-local review-skill outcome — see [Review skill outcomes](#review-skill-outcomes). Aliased by the generalized `meta.skill` (W-mq1cczi90006b21f). |
|
|
88
88
|
| `meta.skill` | object | Optional. Records project-local skill outcome for ANY playbook type that surfaces a `## Project skills` block (implement / fix / plan / review / etc.). See [Project skill outcomes](#project-skill-outcomes). |
|
|
89
|
+
| `meta.descriptionAudit` | object | Optional, `fix` / `implement` dispatches that push commits. Records the PR description audit + screenshot-refresh outcome — see [PR description audit](#pr-description-audit). |
|
|
89
90
|
|
|
90
91
|
## Project skill outcomes
|
|
91
92
|
|
|
@@ -150,6 +151,44 @@ All `meta.review` fields are optional and backward-compatible — older agents t
|
|
|
150
151
|
|
|
151
152
|
Dispatchers can suppress the block entirely by setting `meta.skipProjectReviewSkills: true` on the review work item — the playbook then renders identically to the pre-W-mq16xtdx 8-step contract. Use this for meta-reviews of the review skill itself; the engine still accepts `meta.review.skillSkipped` in the report regardless. (W-mq1cczi90006b21f generalized this to `meta.skipProjectSkills`, which suppresses the block on every dispatch type — both flags are honored.)
|
|
152
153
|
|
|
154
|
+
## PR description audit
|
|
155
|
+
|
|
156
|
+
W-mq5l3f2u000i9045. The `fix` and `implement` playbooks inline a `## PR description audit` section that the agent runs **after** pushing commits to the PR's source branch and **before** marking the work item done. The audit re-reads the PR description, compares it against the diff of the newly-pushed commits, and patches stale sections (feature lists, config tables, file/line counts, ASCII diagrams, embedded screenshots) so reviewers don't end up reading outdated prose.
|
|
157
|
+
|
|
158
|
+
The audit is best-effort:
|
|
159
|
+
|
|
160
|
+
- Screenshot recapture requires a runnable dev server (detected via `package.json` scripts named `dev`, `start`, or `serve`) and Playwright MCP. When either is missing or fails, the agent skips the recapture without failing the work item.
|
|
161
|
+
- GitHub does not expose a documented REST endpoint for PR-comment image uploads; the agent skips the recapture on GitHub with `result: "screenshots-refreshed-skipped (gh-attachment-unavailable)"` instead of failing.
|
|
162
|
+
- Raw PNGs are saved under `agents/<id>/screenshots/` only. **Screenshots NEVER land in the repo** — adding any code path that `git add`s a PNG is a release-blocker bug.
|
|
163
|
+
- The audit never introduces screenshots to a PR that didn't already have any (refresh only), never modifies the PR title, never toggles draft state, and never posts a separate PR comment narrating the description change.
|
|
164
|
+
|
|
165
|
+
Record the outcome under `meta.descriptionAudit`. All fields are optional and backward-compatible — older agents that never set them stay valid.
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"status": "success",
|
|
170
|
+
"meta": {
|
|
171
|
+
"descriptionAudit": {
|
|
172
|
+
"ran": true,
|
|
173
|
+
"result": "description-patched",
|
|
174
|
+
"oldScreenshots": [],
|
|
175
|
+
"newScreenshots": [],
|
|
176
|
+
"patchedSections": ["feature-bullets", "config-table"]
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
| Field | Type | Notes |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `meta.descriptionAudit.ran` | boolean | `true` if the agent executed the audit (whether or not it edited the description). `false` when the audit was suppressed (no commits pushed, no-op completion, `meta.skipDescriptionAudit` set, or the playbook skipped the audit for any reason). Omit `meta.descriptionAudit` entirely when the audit was not even considered. |
|
|
185
|
+
| `meta.descriptionAudit.result` | string | One of: `"no-changes-needed"`, `"description-patched"`, `"screenshots-refreshed"`, `"description-patched+screenshots-refreshed"`, or `"skipped:<reason>"` (e.g. `"skipped:meta-flag"`, `"skipped:no-commits"`, `"skipped:noop"`). The `"screenshots-refreshed-skipped (gh-attachment-unavailable)"` shape is also valid when GitHub's attachment limitation forces a partial-skip. |
|
|
186
|
+
| `meta.descriptionAudit.oldScreenshots` | string[] | URLs of image refs the agent replaced. Omit or `[]` when no screenshots changed. |
|
|
187
|
+
| `meta.descriptionAudit.newScreenshots` | string[] | URLs of newly uploaded image attachments. Omit or `[]` when no screenshots changed. |
|
|
188
|
+
| `meta.descriptionAudit.patchedSections` | string[] | Human-readable identifiers of the description sections that changed (e.g. `"feature-bullets"`, `"config-table"`, `"file-list"`, `"line-counts"`, `"ascii-diagram"`, `"screenshots"`). Omit or `[]` when no sections changed. |
|
|
189
|
+
|
|
190
|
+
Dispatchers can suppress the audit entirely by setting `meta.skipDescriptionAudit: true` on the work item — the playbook then renders an explicit "audit suppressed" notice instead of the audit steps. Use this for skill-meta updates, doc-only fixes whose PR description text won't be affected by the diff, and follow-up dispatches that explicitly own the description themselves.
|
|
191
|
+
|
|
153
192
|
## `failure_class` enum
|
|
154
193
|
|
|
155
194
|
Defined in `engine/shared.js` as `FAILURE_CLASS`. Use the canonical hyphenated string.
|
package/engine/playbook.js
CHANGED
|
@@ -307,6 +307,14 @@ const PLAYBOOK_OPTIONAL_VARS = new Set([
|
|
|
307
307
|
// projects legitimately resolve it to ''.
|
|
308
308
|
'project_review_skills_block',
|
|
309
309
|
'skip_project_review_skills',
|
|
310
|
+
// W-mq5l3f2u000i9045 — opt-out flag for the PR description audit + screenshot
|
|
311
|
+
// refresh fragment inlined into fix.md / implement.md. Truthy (set when
|
|
312
|
+
// item.meta.skipDescriptionAudit is true) renders the "audit suppressed"
|
|
313
|
+
// notice; falsy/empty leaves the notice block out and the agent runs the
|
|
314
|
+
// standard audit. Optional because (a) every other playbook ignores the var
|
|
315
|
+
// and (b) the default state is the empty string, which the playbook's
|
|
316
|
+
// conditional block treats as "not skipped".
|
|
317
|
+
'skip_description_audit',
|
|
310
318
|
// P-e6b3c2d8 — QA Session template vars. session_id / target_kind /
|
|
311
319
|
// flows_raw / managed_spawn_name are required (declared in
|
|
312
320
|
// PLAYBOOK_REQUIRED_VARS['qa-session-setup']); these target_* sub-fields
|
|
@@ -435,7 +443,12 @@ function isSafePlaybookType(playbookType) {
|
|
|
435
443
|
!name.includes('..') &&
|
|
436
444
|
!/[\\/]/.test(name) &&
|
|
437
445
|
!path.isAbsolute(name) &&
|
|
438
|
-
!/^[a-zA-Z]:/.test(name)
|
|
446
|
+
!/^[a-zA-Z]:/.test(name) &&
|
|
447
|
+
// W-mq5l3f2u000i9045 — files named `_*.md` are shared fragments inlined
|
|
448
|
+
// into dispatching playbooks (e.g. `_pr-description-audit.md`). They are
|
|
449
|
+
// not standalone playbooks; reject `_…` types so a dispatch can never
|
|
450
|
+
// resolve to a fragment file.
|
|
451
|
+
!name.startsWith('_');
|
|
439
452
|
}
|
|
440
453
|
|
|
441
454
|
function resolvePlaybookPath(projectName, playbookType) {
|
|
@@ -1171,7 +1184,14 @@ function buildPrDispatch(agentId, config, project, pr, type, extraVars, taskLabe
|
|
|
1171
1184
|
// (skipProjectReviewSkills is the PR-82 alias). Default OFF: review/fix
|
|
1172
1185
|
// dispatches surface the project-local skills block.
|
|
1173
1186
|
skip_project_review_skills: !!(meta && meta.skipProjectReviewSkills),
|
|
1187
|
+
// W-mq1cczi90006b21f — generalized project-skills suppression flag.
|
|
1188
|
+
// Honors either the new `meta.skipProjectSkills` or the PR-82
|
|
1189
|
+
// `meta.skipProjectReviewSkills` alias so older work items keep working.
|
|
1174
1190
|
skip_project_skills: !!(meta && (meta.skipProjectSkills || meta.skipProjectReviewSkills)),
|
|
1191
|
+
// W-mq5l3f2u000i9045 — opt-out for the inlined PR description audit
|
|
1192
|
+
// section in fix.md. Truthy renders the "audit suppressed" notice; falsy
|
|
1193
|
+
// (the default) leaves the standard audit instructions in place.
|
|
1194
|
+
skip_description_audit: !!(meta && meta.skipDescriptionAudit),
|
|
1175
1195
|
...extraVars,
|
|
1176
1196
|
task_id: dispatchId,
|
|
1177
1197
|
};
|
package/engine.js
CHANGED
|
@@ -6121,6 +6121,14 @@ function renderProjectWorkItemPromptForAgent(item, workType, agentId, config, pr
|
|
|
6121
6121
|
managed_spawn_ttl_minutes: item.meta && Number.isFinite(Number(item.meta.managed_spawn_ttl_minutes))
|
|
6122
6122
|
? Math.floor(Number(item.meta.managed_spawn_ttl_minutes))
|
|
6123
6123
|
: '',
|
|
6124
|
+
// W-mq5l3f2u000i9045 — opt-out flag for the inlined PR description audit
|
|
6125
|
+
// section in fix.md / implement.md. When the dispatcher sets
|
|
6126
|
+
// item.meta.skipDescriptionAudit (skill-meta updates, doc-only fixes,
|
|
6127
|
+
// follow-up dispatches that explicitly own the description), the playbook
|
|
6128
|
+
// renders the "audit suppressed" notice instead of the standard audit
|
|
6129
|
+
// steps. Default off — every fix/implement dispatch that pushes commits
|
|
6130
|
+
// audits the PR description by default.
|
|
6131
|
+
skip_description_audit: !!(item.meta && item.meta.skipDescriptionAudit),
|
|
6124
6132
|
// W-mpeiwz6k0005bf34-c — opt-in qa-validate context. The dispatch handler
|
|
6125
6133
|
// POST /api/qa/runbooks/run stamps meta.qaRunId + meta.qaRunbook (full
|
|
6126
6134
|
// spec) + meta.qaTarget (managed-process snapshot) on the work item;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2158",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# PR description audit + screenshot refresh (shared fragment)
|
|
2
|
+
|
|
3
|
+
> **Naming convention.** Files named `_*.md` under `playbooks/` are **shared
|
|
4
|
+
> fragments**. The engine renderer (`engine/playbook.js`) does not (yet)
|
|
5
|
+
> implement an `<include>` directive, so each consuming playbook inlines this
|
|
6
|
+
> fragment verbatim and the two copies are kept in sync by hand. If you change
|
|
7
|
+
> this file, also update the inlined copies in `playbooks/fix.md` and
|
|
8
|
+
> `playbooks/implement.md` (and any other playbook that pushes commits to a
|
|
9
|
+
> tracked PR). The matching test in `test/unit/config-and-playbooks.test.js`
|
|
10
|
+
> ("PR description audit fragment is inlined consistently") fails fast when the
|
|
11
|
+
> copies drift.
|
|
12
|
+
|
|
13
|
+
## When to run
|
|
14
|
+
|
|
15
|
+
Run this audit **after** you push new commits to the PR's source branch and
|
|
16
|
+
**before** you mark the work item done.
|
|
17
|
+
|
|
18
|
+
Skip the audit entirely when:
|
|
19
|
+
|
|
20
|
+
- This dispatch was invoked with `meta.skipDescriptionAudit: true` (the
|
|
21
|
+
engine renders an explicit "audit suppressed" notice when the flag is set).
|
|
22
|
+
- You did not push any new commits this dispatch (no behavior change → no
|
|
23
|
+
description drift).
|
|
24
|
+
- The dispatch produced a no-op completion (`noop: true`).
|
|
25
|
+
|
|
26
|
+
When you skip, still report it: set `meta.descriptionAudit.ran = false` and
|
|
27
|
+
`meta.descriptionAudit.result = "skipped:<reason>"` in the completion JSON.
|
|
28
|
+
|
|
29
|
+
## Audit steps
|
|
30
|
+
|
|
31
|
+
1. **Fetch the current PR description.**
|
|
32
|
+
- GitHub: `gh pr view <num> --repo <owner>/<repo> --json body --jq .body`
|
|
33
|
+
- Azure DevOps: `az repos pr show --id <num> --query description -o tsv`
|
|
34
|
+
2. **Compute the diff for the commits you just pushed.**
|
|
35
|
+
- `git log --stat <baseline>..HEAD` where `<baseline>` is `origin/main` for
|
|
36
|
+
the first push or `origin/<branch>@{1}` (pre-push tip) for follow-up
|
|
37
|
+
pushes. `git log --oneline <baseline>..HEAD` if you only need the SHA list.
|
|
38
|
+
3. **Compare description sections against the diff.** For each section,
|
|
39
|
+
evaluate whether the new commits change anything it claims. Focus
|
|
40
|
+
specifically on:
|
|
41
|
+
- Feature lists / "what changed" bullet points
|
|
42
|
+
- Config / option / matrix tables
|
|
43
|
+
- File or path lists
|
|
44
|
+
- Line counts, before/after metrics, perf numbers, table cell values
|
|
45
|
+
- ASCII diagrams that depict layout the diff touched
|
|
46
|
+
- Embedded markdown image refs (``) — see the screenshot
|
|
47
|
+
subsection below
|
|
48
|
+
4. **Decide the result.**
|
|
49
|
+
- Description is consistent with the diff → no-op. Record
|
|
50
|
+
`meta.descriptionAudit = { ran: true, result: "no-changes-needed" }`
|
|
51
|
+
in the completion report and stop here.
|
|
52
|
+
- Description needs targeted edits → build the patched body. **Preserve prose voice**. Edit only the stale parts. Do **not** rewrite. Do **not**
|
|
53
|
+
add new sections that weren't there before. Do **not** change the PR
|
|
54
|
+
title. Do **not** flip draft state, close/reopen, or post a separate PR
|
|
55
|
+
comment narrating the description edit.
|
|
56
|
+
5. **Push the patched description.**
|
|
57
|
+
- GitHub: write the new body to a temp file, then
|
|
58
|
+
`gh pr edit <num> --repo <owner>/<repo> --body-file <file>`
|
|
59
|
+
- Azure DevOps:
|
|
60
|
+
`az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`
|
|
61
|
+
(PowerShell) or the POSIX equivalent. ADO's description field also
|
|
62
|
+
truncates around ~4 KB on the `--description` flag — if you hit that,
|
|
63
|
+
fall back to `az rest --method patch` against
|
|
64
|
+
`…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
|
|
65
|
+
6. **GET-verify the description post-patch** by re-running the fetch from
|
|
66
|
+
step 1 and confirming the body matches what you sent.
|
|
67
|
+
|
|
68
|
+
## Screenshot handling
|
|
69
|
+
|
|
70
|
+
This applies only when the **existing** description embeds markdown image
|
|
71
|
+
refs. **Never introduce screenshots to a PR that didn't already have any** —
|
|
72
|
+
this audit is a refresh, not an introduction.
|
|
73
|
+
|
|
74
|
+
1. Extract every `` from the current description.
|
|
75
|
+
2. For each image, decide whether it depicts a view this dispatch's diff
|
|
76
|
+
touched. Heuristics (any one is enough):
|
|
77
|
+
- `alt` text or filename mentions a component / route / view name that
|
|
78
|
+
appears in the changed files.
|
|
79
|
+
- The image URL path contains an issue/PR id matching this PR.
|
|
80
|
+
- The description text immediately around the image references files
|
|
81
|
+
present in the diff.
|
|
82
|
+
3. If the view was touched **and** the project has a runnable dev server
|
|
83
|
+
(detect via `package.json` scripts named `dev`, `start`, or `serve`)
|
|
84
|
+
**and** Playwright MCP is available, recapture:
|
|
85
|
+
1. Spin up the dev server with a detached handoff (see
|
|
86
|
+
`shared-rules.md` → "Long-Running Commands"). Capture PID + log path +
|
|
87
|
+
URL + stop command.
|
|
88
|
+
2. Drive Playwright MCP to the relevant route and screenshot the same
|
|
89
|
+
view. Save raw PNGs to `agents/<id>/screenshots/` only. **NEVER `git add` a PNG** — adding any code path that commits a screenshot is a
|
|
90
|
+
release-blocker bug.
|
|
91
|
+
3. Upload as a PR attachment:
|
|
92
|
+
- **ADO**: `PUT /pullRequests/<id>/attachments/<filename>` with the
|
|
93
|
+
PNG bytes, then reference the returned URL in the description.
|
|
94
|
+
- **GitHub**: there is no documented REST endpoint for PR-comment
|
|
95
|
+
image uploads. The browser drag-drop path uses
|
|
96
|
+
`github.com/upload/asset`, which `gh` does not wrap. If you cannot
|
|
97
|
+
find a reliable scripted upload path, **skip** this screenshot,
|
|
98
|
+
leave the old image URL in place, and record
|
|
99
|
+
`meta.descriptionAudit.result = "screenshots-refreshed-skipped (gh-attachment-unavailable)"`.
|
|
100
|
+
4. Patch the description to swap old image URLs for new.
|
|
101
|
+
5. Stop the dev server using the recorded stop command.
|
|
102
|
+
4. If the dev server fails to start, the route 404s, Playwright fails, or
|
|
103
|
+
the host's attachment API is unreachable → **skip that screenshot**
|
|
104
|
+
without failing the work item. Record the skip and the reason in
|
|
105
|
+
`meta.descriptionAudit`.
|
|
106
|
+
|
|
107
|
+
## Out-of-scope guardrails
|
|
108
|
+
|
|
109
|
+
- Don't add screenshots that weren't already there.
|
|
110
|
+
- Don't rewrite description prose beyond the targeted stale edits.
|
|
111
|
+
- Don't modify the PR title.
|
|
112
|
+
- Don't toggle draft state, close/reopen the PR, or post a separate PR
|
|
113
|
+
comment narrating the description change.
|
|
114
|
+
- Don't fail the work item on a screenshot or attachment failure — degrade
|
|
115
|
+
gracefully and record the skip.
|
|
116
|
+
- Screenshots **never** land in the repo. Save raw PNGs only under
|
|
117
|
+
`agents/<id>/screenshots/`. No `git add` of any PNG, ever.
|
|
118
|
+
|
|
119
|
+
## Completion-report shape
|
|
120
|
+
|
|
121
|
+
When the audit ran (whether it edited the description or no-op'd), include
|
|
122
|
+
this block in the JSON completion report (see
|
|
123
|
+
`docs/completion-reports.md` → "PR description audit"):
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"meta": {
|
|
128
|
+
"descriptionAudit": {
|
|
129
|
+
"ran": true,
|
|
130
|
+
"result": "description-patched",
|
|
131
|
+
"oldScreenshots": [],
|
|
132
|
+
"newScreenshots": [],
|
|
133
|
+
"patchedSections": ["feature-bullets", "config-table"]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Omit `meta.descriptionAudit` entirely when the audit did not run (no
|
|
140
|
+
commits pushed, no-op completion, etc.). When `meta.skipDescriptionAudit`
|
|
141
|
+
suppressed the audit, set `ran: false` and
|
|
142
|
+
`result: "skipped:meta-flag"` so the audit history stays auditable.
|
package/playbooks/fix.md
CHANGED
|
@@ -99,6 +99,77 @@ Do NOT remove the worktree — the engine handles cleanup automatically.
|
|
|
99
99
|
- content: Explain what was fixed, reference each review finding, include build/test status
|
|
100
100
|
- Sign: `Fixed by Minions ({{agent_name}} — {{agent_role}} · {{agent_model}})`
|
|
101
101
|
|
|
102
|
+
## PR description audit (mandatory unless `meta.skipDescriptionAudit`)
|
|
103
|
+
|
|
104
|
+
<!-- Inlined from playbooks/_pr-description-audit.md — keep in sync (enforced by test/unit/config-and-playbooks.test.js). -->
|
|
105
|
+
|
|
106
|
+
{{#skip_description_audit}}
|
|
107
|
+
> **Audit suppressed.** This dispatch was invoked with `meta.skipDescriptionAudit: true`.
|
|
108
|
+
> Record `meta.descriptionAudit = { ran: false, result: "skipped:meta-flag" }` in your completion report
|
|
109
|
+
> and skip the audit steps below entirely.
|
|
110
|
+
{{/skip_description_audit}}
|
|
111
|
+
|
|
112
|
+
After you push commits to the PR's source branch and BEFORE you mark the work item done, audit the PR description and refresh it to match the new diff. Skip the audit when you pushed no commits this dispatch or when the dispatch is a no-op completion; record the skip in `meta.descriptionAudit`.
|
|
113
|
+
|
|
114
|
+
**Audit steps**
|
|
115
|
+
|
|
116
|
+
1. Fetch the current PR description.
|
|
117
|
+
- GitHub: `gh pr view <num> --repo <owner>/<repo> --json body --jq .body`
|
|
118
|
+
- Azure DevOps: `az repos pr show --id <num> --query description -o tsv`
|
|
119
|
+
2. Compute the diff for the commits you just pushed: `git log --stat <baseline>..HEAD` where `<baseline>` is `origin/<branch>@{1}` for follow-up pushes (or `origin/main` for the very first push).
|
|
120
|
+
3. For each section of the description, evaluate whether the new diff invalidates anything it claims. Focus on: feature lists / "what changed" bullets, config/option tables, file or path lists, line counts, before/after metrics, ASCII diagrams, and embedded markdown image refs.
|
|
121
|
+
4. **No drift** → record `meta.descriptionAudit = { ran: true, result: "no-changes-needed" }` and stop.
|
|
122
|
+
5. **Drift detected** → build a patched body. **Preserve prose voice.** Edit only the stale parts. Do NOT rewrite. Do NOT add new sections. Do NOT change the PR title. Do NOT toggle draft state. Do NOT post a separate PR comment narrating the description change.
|
|
123
|
+
6. Push the patched description.
|
|
124
|
+
- GitHub: write the new body to a temp file, then `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
125
|
+
- Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
|
|
126
|
+
7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
|
|
127
|
+
|
|
128
|
+
**Screenshot handling (refresh-only — never introduce screenshots)**
|
|
129
|
+
|
|
130
|
+
This applies only when the **existing** description embeds markdown image refs (``). NEVER add screenshots to a PR that didn't already have any.
|
|
131
|
+
|
|
132
|
+
1. Extract every `` from the current description.
|
|
133
|
+
2. Decide which images depict views this dispatch's diff touched (heuristic: alt text / filename / surrounding prose mentions a component / route / view name present in the changed files).
|
|
134
|
+
3. If the view was touched AND the project has a runnable dev server (detect via `package.json` scripts named `dev`, `start`, or `serve`) AND Playwright MCP is available, recapture:
|
|
135
|
+
- Spin up the dev server with a detached handoff per `shared-rules.md` → "Long-Running Commands". Record PID + log path + URL + stop command.
|
|
136
|
+
- Drive Playwright MCP to the relevant route and screenshot the view. Save raw PNGs to `agents/<id>/screenshots/` ONLY. **NEVER `git add` a PNG** — committing a screenshot is a release-blocker bug.
|
|
137
|
+
- Upload as a PR attachment:
|
|
138
|
+
- **ADO**: `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description.
|
|
139
|
+
- **GitHub**: no documented REST endpoint exists for PR-comment image uploads (the browser drag-drop uses `github.com/upload/asset`, which `gh` does not wrap). If you cannot find a reliable scripted upload path, **skip** the recapture, leave the old image URL in place, and record `meta.descriptionAudit.result = "screenshots-refreshed-skipped (gh-attachment-unavailable)"`.
|
|
140
|
+
- Patch the description to swap old image URLs for new.
|
|
141
|
+
- Stop the dev server using the recorded stop command.
|
|
142
|
+
4. If the dev server fails to start, the route 404s, Playwright fails, or the host's attachment API is unreachable → **skip that screenshot** without failing the work item. Record the skip and the reason in `meta.descriptionAudit`.
|
|
143
|
+
|
|
144
|
+
**Out-of-scope guardrails**
|
|
145
|
+
|
|
146
|
+
- Don't add screenshots that weren't already there. Refresh only.
|
|
147
|
+
- Don't rewrite description prose beyond the targeted stale edits.
|
|
148
|
+
- Don't modify the PR title; don't toggle draft state, close/reopen the PR.
|
|
149
|
+
- Don't post a separate PR comment summarizing the description change.
|
|
150
|
+
- Don't fail the work item on a screenshot or attachment failure — degrade gracefully and record the skip.
|
|
151
|
+
- Screenshots NEVER land in the repo. `agents/<id>/screenshots/` only; never `git add` a PNG.
|
|
152
|
+
|
|
153
|
+
**Completion-report shape**
|
|
154
|
+
|
|
155
|
+
When the audit ran (whether it edited the description or no-op'd), include this in the completion JSON (full schema: `docs/completion-reports.md` → "PR description audit"):
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"meta": {
|
|
160
|
+
"descriptionAudit": {
|
|
161
|
+
"ran": true,
|
|
162
|
+
"result": "description-patched",
|
|
163
|
+
"oldScreenshots": [],
|
|
164
|
+
"newScreenshots": [],
|
|
165
|
+
"patchedSections": ["feature-bullets", "config-table"]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Omit `meta.descriptionAudit` entirely when the audit did not run (no commits pushed, no-op completion). When `meta.skipDescriptionAudit` suppressed the audit, set `ran: false` and `result: "skipped:meta-flag"`.
|
|
172
|
+
|
|
102
173
|
## Resolve Review Comments
|
|
103
174
|
|
|
104
175
|
After pushing, respond to each review comment/thread. **Every disposition requires a reply before you resolve, close, or mark-fixed the thread — no exceptions.** Resolving a thread silently is a process violation (see "Resolving Review Threads — No Silent Closures" in `shared-rules.md`).
|
package/playbooks/implement.md
CHANGED
|
@@ -101,6 +101,77 @@ Create the PR for implement tasks — the engine tracks review and completion fr
|
|
|
101
101
|
|
|
102
102
|
Include build/test status and run instructions in the PR description. If the project has a runnable app, include the localhost URL.
|
|
103
103
|
|
|
104
|
+
## PR description audit (mandatory unless `meta.skipDescriptionAudit`)
|
|
105
|
+
|
|
106
|
+
<!-- Inlined from playbooks/_pr-description-audit.md — keep in sync (enforced by test/unit/config-and-playbooks.test.js). -->
|
|
107
|
+
|
|
108
|
+
{{#skip_description_audit}}
|
|
109
|
+
> **Audit suppressed.** This dispatch was invoked with `meta.skipDescriptionAudit: true`.
|
|
110
|
+
> Record `meta.descriptionAudit = { ran: false, result: "skipped:meta-flag" }` in your completion report
|
|
111
|
+
> and skip the audit steps below entirely.
|
|
112
|
+
{{/skip_description_audit}}
|
|
113
|
+
|
|
114
|
+
After you push commits to the PR's source branch and BEFORE you mark the work item done, audit the PR description and refresh it to match the new diff. Skip the audit when you pushed no commits this dispatch or when the dispatch is a no-op completion; record the skip in `meta.descriptionAudit`.
|
|
115
|
+
|
|
116
|
+
**Audit steps**
|
|
117
|
+
|
|
118
|
+
1. Fetch the current PR description.
|
|
119
|
+
- GitHub: `gh pr view <num> --repo <owner>/<repo> --json body --jq .body`
|
|
120
|
+
- Azure DevOps: `az repos pr show --id <num> --query description -o tsv`
|
|
121
|
+
2. Compute the diff for the commits you just pushed: `git log --stat <baseline>..HEAD` where `<baseline>` is `origin/<branch>@{1}` for follow-up pushes (or `origin/main` for the very first push).
|
|
122
|
+
3. For each section of the description, evaluate whether the new diff invalidates anything it claims. Focus on: feature lists / "what changed" bullets, config/option tables, file or path lists, line counts, before/after metrics, ASCII diagrams, and embedded markdown image refs.
|
|
123
|
+
4. **No drift** → record `meta.descriptionAudit = { ran: true, result: "no-changes-needed" }` and stop.
|
|
124
|
+
5. **Drift detected** → build a patched body. **Preserve prose voice.** Edit only the stale parts. Do NOT rewrite. Do NOT add new sections. Do NOT change the PR title. Do NOT toggle draft state. Do NOT post a separate PR comment narrating the description change.
|
|
125
|
+
6. Push the patched description.
|
|
126
|
+
- GitHub: write the new body to a temp file, then `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
127
|
+
- Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
|
|
128
|
+
7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
|
|
129
|
+
|
|
130
|
+
**Screenshot handling (refresh-only — never introduce screenshots)**
|
|
131
|
+
|
|
132
|
+
This applies only when the **existing** description embeds markdown image refs (``). NEVER add screenshots to a PR that didn't already have any.
|
|
133
|
+
|
|
134
|
+
1. Extract every `` from the current description.
|
|
135
|
+
2. Decide which images depict views this dispatch's diff touched (heuristic: alt text / filename / surrounding prose mentions a component / route / view name present in the changed files).
|
|
136
|
+
3. If the view was touched AND the project has a runnable dev server (detect via `package.json` scripts named `dev`, `start`, or `serve`) AND Playwright MCP is available, recapture:
|
|
137
|
+
- Spin up the dev server with a detached handoff per `shared-rules.md` → "Long-Running Commands". Record PID + log path + URL + stop command.
|
|
138
|
+
- Drive Playwright MCP to the relevant route and screenshot the view. Save raw PNGs to `agents/<id>/screenshots/` ONLY. **NEVER `git add` a PNG** — committing a screenshot is a release-blocker bug.
|
|
139
|
+
- Upload as a PR attachment:
|
|
140
|
+
- **ADO**: `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description.
|
|
141
|
+
- **GitHub**: no documented REST endpoint exists for PR-comment image uploads (the browser drag-drop uses `github.com/upload/asset`, which `gh` does not wrap). If you cannot find a reliable scripted upload path, **skip** the recapture, leave the old image URL in place, and record `meta.descriptionAudit.result = "screenshots-refreshed-skipped (gh-attachment-unavailable)"`.
|
|
142
|
+
- Patch the description to swap old image URLs for new.
|
|
143
|
+
- Stop the dev server using the recorded stop command.
|
|
144
|
+
4. If the dev server fails to start, the route 404s, Playwright fails, or the host's attachment API is unreachable → **skip that screenshot** without failing the work item. Record the skip and the reason in `meta.descriptionAudit`.
|
|
145
|
+
|
|
146
|
+
**Out-of-scope guardrails**
|
|
147
|
+
|
|
148
|
+
- Don't add screenshots that weren't already there. Refresh only.
|
|
149
|
+
- Don't rewrite description prose beyond the targeted stale edits.
|
|
150
|
+
- Don't modify the PR title; don't toggle draft state, close/reopen the PR.
|
|
151
|
+
- Don't post a separate PR comment summarizing the description change.
|
|
152
|
+
- Don't fail the work item on a screenshot or attachment failure — degrade gracefully and record the skip.
|
|
153
|
+
- Screenshots NEVER land in the repo. `agents/<id>/screenshots/` only; never `git add` a PNG.
|
|
154
|
+
|
|
155
|
+
**Completion-report shape**
|
|
156
|
+
|
|
157
|
+
When the audit ran (whether it edited the description or no-op'd), include this in the completion JSON (full schema: `docs/completion-reports.md` → "PR description audit"):
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"meta": {
|
|
162
|
+
"descriptionAudit": {
|
|
163
|
+
"ran": true,
|
|
164
|
+
"result": "description-patched",
|
|
165
|
+
"oldScreenshots": [],
|
|
166
|
+
"newScreenshots": [],
|
|
167
|
+
"patchedSections": ["feature-bullets", "config-table"]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Omit `meta.descriptionAudit` entirely when the audit did not run (no commits pushed, no-op completion). When `meta.skipDescriptionAudit` suppressed the audit, set `ran: false` and `result: "skipped:meta-flag"`.
|
|
174
|
+
|
|
104
175
|
## When to Stop
|
|
105
176
|
|
|
106
177
|
Your task is complete when the requested implementation is delivered, the validation story is truthful and sufficient for review, the branch is pushed, and the PR exists. Include the PR URL in your final message so the engine can track it.
|