@clipboard-health/ai-rules 2.29.10 → 2.30.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/package.json +1 -1
- package/skills/cb-babysit/SKILL.md +306 -0
- package/skills/{babysit-pr → cb-babysit}/scripts/_sentinel.sh +8 -7
- package/skills/{babysit-pr → cb-babysit}/scripts/fetchFailedLogs.sh +7 -8
- package/skills/{babysit-pr → cb-babysit}/scripts/postSentinelPrComment.sh +1 -1
- package/skills/{babysit-pr → cb-babysit}/scripts/postSentinelReply.sh +1 -1
- package/skills/{babysit-pr → cb-babysit}/scripts/unresolvedPrComments.sh +9 -9
- package/skills/cb-ship/SKILL.md +32 -0
- package/skills/cb-ship/references/pr-template.md +21 -0
- package/skills/cb-ship/references/simplify.md +49 -0
- package/skills/cb-work/SKILL.md +38 -0
- package/skills/create-groundcrew-ticket/SKILL.md +2 -2
- package/skills/frontend-ui-verification/SKILL.md +1 -1
- package/skills/babysit-pr/SKILL.md +0 -392
- package/skills/commit-push-pr/SKILL.md +0 -53
- package/skills/commit-push-pr/scripts/find-session-id.sh +0 -39
- package/skills/go/SKILL.md +0 -46
- package/skills/simplify/SKILL.md +0 -57
- /package/skills/{babysit-pr → cb-babysit}/scripts/commitAndPush.sh +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cb-babysit
|
|
3
|
+
description: Watch a PR through CI and review feedback. Auto-fix high-confidence failures and address review comments. Use when the user says 'babysit <PR>' or 'respond to PR comments'.
|
|
4
|
+
argument-hint: "[pr-number-or-url]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
The user invokes this skill with an optional PR number or URL. Parse in this order and stop at the first match:
|
|
10
|
+
|
|
11
|
+
1. **Full PR URL**: if the user's text contains `https?://github\.com/[^/\s]+/[^/\s]+/pull/\d+`, capture the URL.
|
|
12
|
+
2. **Explicit PR token**: match `(?:PR|pr|pull request)\s*#?(\d+)` or a bare `#(\d+)` in the user's text.
|
|
13
|
+
3. **Bare numeric argument**: only when the complete text is a positive integer without surrounding prose.
|
|
14
|
+
4. **None of the above**: operate on the PR for the current branch.
|
|
15
|
+
|
|
16
|
+
Resolve bundled "./scripts" paths relative to SKILL.md.
|
|
17
|
+
|
|
18
|
+
## Sentinels
|
|
19
|
+
|
|
20
|
+
The skill uses two sentinels with visible footer lines.
|
|
21
|
+
|
|
22
|
+
**Addressed sentinel**: `<sub>🤖 <code>cb-babysit:addressed v1 core@3.11.0</code></sub>`. Appended on its own line at the end of every reply the skill posts so re-runs know which threads and review-body comments are already handled. Dedupe also recognizes the legacy `babysit-pr:addressed v1` prefix from before this skill was renamed.
|
|
23
|
+
|
|
24
|
+
**Follow-up sentinel**: `<sub>🤖 <code>cb-babysit:followup v1 core@3.11.0</code></sub>`. Attached to replies that defer an out-of-scope comment as a tracked follow-up. The sentinel is additive: the post-reply scripts still append the `addressed` sentinel at the end.
|
|
25
|
+
|
|
26
|
+
**Sentinel recency rules.** The script emits a per-thread `activityState` with three values. Step 6a owns the handling rules for each state.
|
|
27
|
+
|
|
28
|
+
- **`active`**: no sentinel yet, OR at least one human commented after the last sentinel.
|
|
29
|
+
- **`uncertain`**: a sentinel exists AND one or more bot comments appeared after it. The thread carries a `postSentinelBotComments` array listing EVERY such comment.
|
|
30
|
+
- **`addressed`**: the sentinel is the newest relevant activity on the thread.
|
|
31
|
+
|
|
32
|
+
Automated review bodies and top-level Conversation-tab comments each carry a stable `fingerprint` (sha256 of the normalized body); prior sentinel bodies embed them, and steps 4 and 7 do the dedupe.
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
### 1. Preflight
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git status --short
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If non-empty, classify the dirty files against the target PR's changed paths (`gh pr diff --name-only`):
|
|
43
|
+
|
|
44
|
+
- Any dirty file overlaps the PR's surface, or you cannot confidently classify → stop and report. The skill never starts where it might sweep up related in-progress work.
|
|
45
|
+
- All dirty files are clearly unrelated (disjoint paths, pre-existing edits) → stash exactly those files by name with a labeled stash (`git stash push -m "cb-babysit: pre-existing unrelated work (auto-restored)" -- <paths>`), proceed, and `git stash pop` as the final step of the pass, including on early exits. Report the stash/restore in the summary.
|
|
46
|
+
|
|
47
|
+
If a PR number or URL was parsed from inputs, check out that PR now:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gh pr checkout <pr-number-or-url>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If the command fails, stop and report.
|
|
54
|
+
|
|
55
|
+
### 2. Locate the PR
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
gh pr view --json number,url,headRefName,statusCheckRollup,mergeable,mergeStateStatus 2>/dev/null
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If no PR exists for the current branch, stop and report.
|
|
62
|
+
|
|
63
|
+
#### Resolve merge conflicts, if any
|
|
64
|
+
|
|
65
|
+
If `mergeable == "CONFLICTING"` (or `mergeStateStatus == "DIRTY"`), merge the base into the PR branch locally:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
BASE=$(gh pr view --json baseRefName --jq .baseRefName)
|
|
69
|
+
git fetch origin "$BASE"
|
|
70
|
+
git merge --no-edit "origin/$BASE"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Resolve directly only for lockfile/generated regenerations, additive non-overlapping edits, or trivial textual conflicts in PR-touched files. `git merge --abort` for anything semantic, ambiguous, or outside the PR's intentional surface, and skip to step 10 to exit **stuck** with a diagnosis. After a clean resolution, commit the merge and `git push origin HEAD`.
|
|
74
|
+
|
|
75
|
+
### 3. Wait for CI
|
|
76
|
+
|
|
77
|
+
Wrap the watch call with a timeout so a hung check doesn't wedge the turn:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
rc=0
|
|
81
|
+
if command -v gtimeout >/dev/null 2>&1; then
|
|
82
|
+
gtimeout 600 gh pr checks --watch || rc=$?
|
|
83
|
+
elif command -v timeout >/dev/null 2>&1; then
|
|
84
|
+
timeout 600 gh pr checks --watch || rc=$?
|
|
85
|
+
else
|
|
86
|
+
gh pr checks --watch || rc=$?
|
|
87
|
+
fi
|
|
88
|
+
case $rc in 0|1|8|124) ;; *) exit $rc;; esac
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Exit codes 0 (pass), 1 (fail), 8 (pending), and 124 (timeout) are expected and handled next. Other codes (auth errors, etc.) re-raise.
|
|
92
|
+
|
|
93
|
+
### 4. Fetch review data
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
bash scripts/unresolvedPrComments.sh
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The output JSON has:
|
|
100
|
+
|
|
101
|
+
- `threads`: every unresolved review thread, with `threadId`, `replyToCommentDatabaseId`, `comments[]`, `lastBabysitSentinelAt`, `lastHumanCommentAt`, `lastBotCommentAt`, `postSentinelBotComments[]`, `postSentinelHumanComments[]`, and `activityState` (`"active"` / `"uncertain"` / `"addressed"`).
|
|
102
|
+
- `activeThreads`: threads where `activityState != "addressed"`; these need attention this pass (active AND uncertain).
|
|
103
|
+
- `uncertainThreads`: just the uncertain subset. For each, read EVERY entry in `postSentinelBotComments` before deciding.
|
|
104
|
+
- `reviewBodyComments`: every review from a known automated reviewer (CodeRabbit, Mendral, Dependabot, etc.), with the raw body and a stable per-review `fingerprint`. The agent reads each body directly to extract findings.
|
|
105
|
+
- `issueComments`: every top-level Conversation-tab comment, each with `isBabysitSentinel`, `isKnownBot`, and a per-comment `fingerprint`.
|
|
106
|
+
- `activeIssueComments`: the subset of `issueComments` that are NOT cb-babysit sentinels, NOT from a known bot, and whose `fingerprint` is NOT already listed in any prior cb-babysit summary. These are the human Conversation-tab comments still needing a reply.
|
|
107
|
+
- `priorBabysitSentinels`: prior cb-babysit summary comments posted as PR issue-comments. The script does the dedupe lookup for `activeIssueComments` automatically; the agent uses this array for `reviewBodyComments` dedupe.
|
|
108
|
+
- `truncated`: array naming any GraphQL connection that hit GitHub's 100-item cap (`reviewThreads`, `thread-comments`, `reviews`, `issueComments`). Non-empty means some comments may not be in this JSON; surface this in the final summary.
|
|
109
|
+
- `totalActiveThreads`, `totalUncertainThreads`, `totalActiveIssueComments`, `totalReviewBodyComments`, `totalUnresolvedComments` for quick checks.
|
|
110
|
+
|
|
111
|
+
### Scope
|
|
112
|
+
|
|
113
|
+
This PR's review-feedback scope is strict by default. Steps 6a (threads), 6b (top-level conversation comments), and 7 (automated review bodies) classify each comment as in-scope or out-of-scope using this rule before choosing a verdict. Step 5 (CI) uses the broader CI-scope rule in that step, not this one. CI can legitimately fail on unchanged lines because the PR changed a contract or dependency path.
|
|
114
|
+
|
|
115
|
+
Build the changed-line set from `gh pr diff` once per pass. Count changed diff lines on both sides: added lines in the new version, removed lines in the old version, and modified code represented by adjacent remove/add pairs. Do not count diff context lines. A reviewer comment or automated review-body comment is **in scope** when its anchor falls on a changed diff line on either side of the hunk. Deleted-line comments like "why remove this?" or "please add this back" are in scope by definition. For a range like `12-14`, any overlap with a changed diff line is in scope.
|
|
116
|
+
|
|
117
|
+
When matching review comments to hunks, use the anchor line provided by `unresolvedPrComments.sh`; it may be the current `line` or the script's fallback to `originalLine`. Compare that anchor against both new-side added ranges and old-side removed ranges.
|
|
118
|
+
|
|
119
|
+
Comments on unchanged/context lines, touched files outside changed lines, or untouched files are **out of scope by default**.
|
|
120
|
+
|
|
121
|
+
Narrow escape hatch: treat an unchanged/context-line comment as in scope only when there is an explicit external signal that this PR caused or requires the issue. Acceptable signals:
|
|
122
|
+
|
|
123
|
+
- The reviewer explicitly ties the concern to this PR's change.
|
|
124
|
+
- The comment points to an unchanged line directly used by a changed diff line, and you can name the changed `file:line` that creates the coupling.
|
|
125
|
+
- CI, test, or typecheck output proves the PR changed the contract or behavior for the symbol, API, or execution path named by the comment.
|
|
126
|
+
|
|
127
|
+
If you cannot name one of those signals, classify the comment as out of scope. Do not use broad judgment phrases like "related", "nearby", "maintainability", or "review confidence" to widen scope.
|
|
128
|
+
|
|
129
|
+
Default posture: focus on in-scope feedback. For out-of-scope feedback, apply the fix **only** if it meets the out-of-scope bar below. Otherwise defer with a follow-up reply.
|
|
130
|
+
|
|
131
|
+
**Out-of-scope fix bar** (apply the fix even though it's out of scope):
|
|
132
|
+
|
|
133
|
+
- Security vulnerability, data loss, or crash in the PR's execution path.
|
|
134
|
+
- Obvious correctness bug (wrong output, broken invariant) confirmed by reading the referenced code.
|
|
135
|
+
- One-line or trivial change that obviously cannot regress anything (typo, missing null check matching surrounding style, etc.).
|
|
136
|
+
|
|
137
|
+
**All other out-of-scope fix requests → Defer**: post a Defer reply tagged with the follow-up sentinel (see step 9). Do not expand the PR. Defer is specifically for "this is a real but out-of-scope ask we are choosing not to act on here."
|
|
138
|
+
|
|
139
|
+
### 5. Handle CI failures
|
|
140
|
+
|
|
141
|
+
Run `bash scripts/fetchFailedLogs.sh` to stream failed output for every failing check on the PR. The first line is either:
|
|
142
|
+
|
|
143
|
+
- `# cb-babysit: no failing checks` → skip to step 6a.
|
|
144
|
+
- `# cb-babysit: failing checks` → followed by one delimited block per failing job or external check:
|
|
145
|
+
- `# --- run=<id> job=<id> ---` blocks carry the job's `--log-failed` output (GitHub Actions).
|
|
146
|
+
- `# --- external check: <name> (<url>) ---` blocks carry no logs, the check isn't a GitHub Actions run (e.g., Nx Cloud, semgrep, CodeRabbit). Treat these like "External checks with no inspectable logs" in the diagnosis-only list below: stop and report, don't guess a fix.
|
|
147
|
+
|
|
148
|
+
Read the logs and diagnose: **build/type errors first** (they cause cascading test failures), then lint/format, then tests.
|
|
149
|
+
|
|
150
|
+
**Apply a fix directly** only when the cause is high-confidence and inside the PR's changed surface:
|
|
151
|
+
|
|
152
|
+
- Compile/type errors in files the PR touched.
|
|
153
|
+
- Deterministic lint/format violations.
|
|
154
|
+
- Tests that the PR broke by renaming/removing symbols they reference.
|
|
155
|
+
- Missing test updates for intentional behavior changes.
|
|
156
|
+
|
|
157
|
+
**Stop and report a diagnosis** (do not guess a fix) for:
|
|
158
|
+
|
|
159
|
+
- Flaky/intermittent failures.
|
|
160
|
+
- Infrastructure or provider outages.
|
|
161
|
+
- Permission/auth/missing-secret failures.
|
|
162
|
+
- Unrelated failures (touching code this PR didn't modify).
|
|
163
|
+
- Ambiguous test intent.
|
|
164
|
+
- External checks with no inspectable logs.
|
|
165
|
+
|
|
166
|
+
Scope check for CI: scope is the PR's changed files plus failures directly caused by those changes in the PR's execution path. Use `gh pr diff --name-only` as the first signal. Allow fixes outside changed files only when the logs and code make causality clear (e.g., the PR renamed a symbol that a sibling test references). CI failures outside that surface are out of scope. Report the diagnosis, don't apply speculative fixes. CI fixes are never Deferred as follow-ups: CI needs to pass on this PR.
|
|
167
|
+
|
|
168
|
+
### 6a. Assess active review threads
|
|
169
|
+
|
|
170
|
+
For every thread in `activeThreads` (this includes both `"active"` and `"uncertain"`):
|
|
171
|
+
|
|
172
|
+
- Group comments by file; read each file once (not per comment).
|
|
173
|
+
- If the referenced file no longer exists, record "comment may be outdated" and classify as **Already fixed**.
|
|
174
|
+
- If `activityState == "uncertain"`, read EVERY entry in `postSentinelBotComments` (not just the newest):
|
|
175
|
+
- If EVERY entry is a non-actionable acknowledgement (e.g., `"Thanks, resolved"`, `"LGTM"`, `"Learnings added"`) → mark the thread **Skip-reply** (the existing sentinel already covers the thread; posting again would be noise). Do not classify it Agree/Disagree/Already-fixed. Record this in the final summary so the skip is visible.
|
|
176
|
+
- If ANY entry carries new actionable content (new nit, new finding, corrected diagnosis) → treat the thread as new feedback and proceed below. Note in the final summary that an uncertain thread was reactivated, citing the specific comment.
|
|
177
|
+
- If you cannot confidently classify every entry → default to treating it as new feedback.
|
|
178
|
+
- Each remaining thread (i.e., NOT marked Skip-reply) gets a scope classification first. Use the Scope subsection to label it in-scope or out-of-scope. For comments on deleted lines, record that the anchor is on the removed side of the diff. For any unchanged/context-line comment classified in scope via the narrow escape hatch, record the external signal and the changed `file:line` when applicable.
|
|
179
|
+
- Then pick one verdict; each of these (except Skip-reply) will get a reply posted in step 9:
|
|
180
|
+
- **In-scope** threads use the original three verdicts:
|
|
181
|
+
- **Agree**: the comment identifies a real issue. Apply the fix. Record the thread ID and a one-line what-changed.
|
|
182
|
+
- **Disagree**: the current code is acceptable. Record a short reasoning.
|
|
183
|
+
- **Already fixed**: a prior commit addresses the concern. Record a pointer (commit SHA, file:line).
|
|
184
|
+
- **Out-of-scope** threads apply the out-of-scope fix bar from the Scope subsection:
|
|
185
|
+
- Meets the bar → **Agree** (apply the fix, and note in the reply that it was fixed despite being out of scope because it met the bar).
|
|
186
|
+
- Does not meet the bar → **Defer** (new verdict). Record a one-line rationale and, if relevant, a pointer to where the concern lives.
|
|
187
|
+
- Disagree and Already-fixed can still apply to out-of-scope comments (e.g., reviewer asks for a refactor that's already landed on main, or misreads the code).
|
|
188
|
+
|
|
189
|
+
### 6b. Assess top-level Conversation-tab comments
|
|
190
|
+
|
|
191
|
+
For every entry in `activeIssueComments`, humans commenting on the PR Conversation tab without anchoring to a file/line:
|
|
192
|
+
|
|
193
|
+
- Apply the **Scope** subsection's rules. A top-level comment is in scope when the reviewer explicitly ties it to a changed file/line, behavior the PR introduced, or a contract the PR altered. Otherwise out of scope by default.
|
|
194
|
+
- Pick a verdict the same way as a thread: Agree / Disagree / Already fixed (in-scope), or Agree-meets-bar / Defer (out-of-scope). Apply fixes for Agree verdicts.
|
|
195
|
+
- Replies are NOT posted as individual top-level comments. That would clutter the conversation. Instead, every issue-comment verdict goes into the **same step-9 PR-level summary** as the review-body findings, under its own `## Conversation-tab comments` heading. Per-comment fingerprints join the fenced fingerprint block so future runs dedupe.
|
|
196
|
+
- If `activeIssueComments` is empty AND `reviewBodyComments` is empty (or all dedupe), skip the PR-level summary comment entirely in step 9.
|
|
197
|
+
|
|
198
|
+
### 7. Assess automated review bodies
|
|
199
|
+
|
|
200
|
+
For every entry in `reviewBodyComments`:
|
|
201
|
+
|
|
202
|
+
- Dedupe first: if its `fingerprint` already appears in any `priorBabysitSentinels[].body`, skip; already covered.
|
|
203
|
+
- Otherwise, READ THE BODY IN FULL. Automated reviewers (CodeRabbit, Mendral, etc.) pack findings into nested `<details>/<blockquote>` HTML with file paths, line ranges, and titles inline. Identify each individual finding the body contains.
|
|
204
|
+
- For each finding, **classify scope** (in / out) using the Scope subsection. For ranges like `12-14`, any overlap with changed diff lines on either side of the hunk is in scope; no overlap is out of scope unless one of the explicit escape-hatch signals applies.
|
|
205
|
+
- Pick a verdict per finding:
|
|
206
|
+
- In-scope → Agree / Disagree / Already fixed (as with threads). If Agree, apply the fix.
|
|
207
|
+
- Out-of-scope → apply the out-of-scope fix bar. Meets the bar → Agree and apply the fix, noting in the summary that it was fixed despite being out of scope. Does not meet the bar → **Defer**. A Deferred finding does not get its own top-level comment; it goes into the summary under the **Deferred (out of scope)** heading (see step 9).
|
|
208
|
+
|
|
209
|
+
The whole-body `fingerprint` (not per-finding) goes in the fenced fingerprint block at the end of the summary. If the review body later changes (new findings, edits), the fingerprint changes and the next pass will post the summary again. It's slightly noisier but never silently drops a new finding.
|
|
210
|
+
|
|
211
|
+
If `reviewBodyComments` is empty (or all entries dedupe), skip ONLY the review-body section of the summary in step 9. Still post thread replies for every non-Skip-reply thread from step 6a and handle issue comments per step 6b.
|
|
212
|
+
|
|
213
|
+
### 8. Commit and push (if any edits)
|
|
214
|
+
|
|
215
|
+
If steps 5, 6, or 7 modified any files, decide:
|
|
216
|
+
|
|
217
|
+
- **Which files are yours this pass.** The worktree may contain unrelated in-progress work. Only stage files this pass touched. If in doubt, run `git diff --name-only` and pick from that list deliberately.
|
|
218
|
+
- **A focused commit message.** Prefer something like `cb-babysit: <one-line what-changed>`; the project's commitlint expects conventional-commit form, so a `fix(core): ...` or `docs(core): ...` prefix is usually right.
|
|
219
|
+
|
|
220
|
+
Then run:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
bash scripts/commitAndPush.sh "<message>" <file1> [<file2> ...]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The script enforces explicit staging (never `git add -A`), never skips hooks, and prints:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
sha=<commit-sha>
|
|
230
|
+
url=https://github.com/<owner>/<repo>/commit/<sha>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Capture the `url=` line for the reply templates in step 9.
|
|
234
|
+
|
|
235
|
+
### 9. Post replies
|
|
236
|
+
|
|
237
|
+
For every thread assessed in step 6a that was NOT marked **Skip-reply** (i.e., one of Agree / Disagree / Already fixed / Defer):
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
bash scripts/postSentinelReply.sh "$THREAD_ID" "$BODY"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Skip-reply threads are left alone as the existing sentinel already covers them.
|
|
244
|
+
|
|
245
|
+
Body templates (the script appends the `addressed` sentinel if missing):
|
|
246
|
+
|
|
247
|
+
- **Agree**: `Addressed in <commit-url>. <one-line what-changed>.`
|
|
248
|
+
- **Disagree**: `Leaving current behavior. <reasoning>.`
|
|
249
|
+
- **Already fixed**: `Already handled by <commit-url-or-file:line>. <brief pointer>.`
|
|
250
|
+
- **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>🤖 <code>cb-babysit:followup v1 core@3.11.0</code></sub>`
|
|
251
|
+
|
|
252
|
+
For Defer replies, include the follow-up sentinel on its own line as shown. The script will append the `addressed` sentinel after it on its own line, so the final body ends with the follow-up sentinel followed by a blank line followed by the `addressed` sentinel. `grep cb-babysit:followup` finds the deferral and `grep cb-babysit:addressed` still marks the thread handled for dedupe.
|
|
253
|
+
|
|
254
|
+
The script uses the `addPullRequestReviewThreadReply` GraphQL mutation. It does NOT resolve the thread.
|
|
255
|
+
|
|
256
|
+
If any automated review bodies were assessed in step 7 OR any active issue comments were assessed in step 6b, post ONE top-level PR comment summarizing all of them:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
bash scripts/postSentinelPrComment.sh "$PR_NUMBER" "$BODY"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The PR-level summary should:
|
|
263
|
+
|
|
264
|
+
- Group by source. Use `## Review-body findings` for step-7 work and `## Conversation-tab comments` for step-6b work. Omit a section if its list is empty.
|
|
265
|
+
- Inside each section, group verdicts under **Agree / Disagree / Already fixed / Deferred (out of scope)** subheadings. Omit a subheading if its list is empty.
|
|
266
|
+
- Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>🤖 <code>cb-babysit:followup v1 core@3.11.0</code></sub>` so grep catches them individually.
|
|
267
|
+
- Include the commit URL for fixes.
|
|
268
|
+
- End with a fenced fingerprint block listing every current fingerprint (addressed and deferred) one per line. Include both `reviewBodyComments[].fingerprint` (whole-body, one per automated review) and `activeIssueComments[].fingerprint` (per Conversation-tab comment). Future runs dedupe by matching these against `priorBabysitSentinels`.
|
|
269
|
+
|
|
270
|
+
### 10. Summarize
|
|
271
|
+
|
|
272
|
+
Report:
|
|
273
|
+
|
|
274
|
+
- Commits made (with URLs).
|
|
275
|
+
- Merge conflict status if relevant (resolved or aborted with reason).
|
|
276
|
+
- CI checks fixed / still failing / skipped-with-diagnosis.
|
|
277
|
+
- Review threads replied to, grouped by verdict (including any Defer count: "X threads deferred as follow-ups").
|
|
278
|
+
- Conversation-tab comments addressed, grouped by verdict (e.g. "Z conversation comments deferred as follow-ups").
|
|
279
|
+
- Review-body findings summarized (or skipped because already covered), including the Deferred count: "Y review-body findings deferred as follow-ups".
|
|
280
|
+
- Threads left active because of bot-acknowledgement uncertainty (flag by thread URL).
|
|
281
|
+
- If `truncated` is non-empty: explicitly call out which connection hit GitHub's 100-item GraphQL cap (e.g. "`truncated: ['thread-comments']`, at least one review thread has more than 100 comments; this pass may have missed the tail. Investigate before relying on it for completeness.").
|
|
282
|
+
- The stop condition triggered for this pass (clean / progressing / stuck).
|
|
283
|
+
|
|
284
|
+
When the report mentions any deferrals, include a one-liner the user can run later to enumerate them, e.g.:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){repository(owner:$o,name:$r){pullRequest(number:$n){reviewThreads(first:100){nodes{comments(first:50){nodes{body url}}}}comments(first:100){nodes{body url}}}}}' -F o=<owner> -F r=<repo> -F n=<pr> | grep -B1 cb-babysit:followup
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Do not rely only on `gh pr view --json comments,reviews`. That view can miss inline review-thread replies, which is where most Defer replies live.
|
|
291
|
+
|
|
292
|
+
## Loop control
|
|
293
|
+
|
|
294
|
+
After the single pass completes, pick exactly one outcome:
|
|
295
|
+
|
|
296
|
+
- **Exit clean**: all CI checks passed AND every thread in `activeThreads` was either marked Skip-reply during step 6a's inspection or has already received a fresh sentinel reply in this pass (Agree / Disagree / Already-fixed / **Defer** all count. A Defer reply is a sentinel reply), AND every entry in `activeIssueComments` is covered by this pass's PR-level summary, AND every current review-body fingerprint is covered by an existing sentinel comment (deferred review-body and conversation-comment fingerprints count; they're in the summary's fenced block). Do not use raw `totalActiveThreads` / `totalActiveIssueComments` from the script output. They're pre-inspection and will stay non-zero for Skip-reply or post-summary cases. A PR with Deferred items is still clean from babysit's perspective: the skill has done what it can without widening scope. Report success and stop.
|
|
297
|
+
- **Exit progressing**: pass made commits, posted new replies, or both, and the PR is not yet clean (CI is still pending, a new CI run was triggered by this pass's commits, or more work remains). There is real work still in flight that another run would pick up. Report what was done and what is pending, and tell the user to re-run `/cb-babysit` once CI settles, or to wrap the call with `/loop <cadence> /cb-babysit` (or a shell `while true; do ...; done`) for automatic re-runs.
|
|
298
|
+
- **Exit stuck**: pass made no commits and posted no new replies, and the PR is still not clean. Nothing actionable happened this pass. Use this whenever progress is blocked on something outside the skill's scope, including:
|
|
299
|
+
- Merge conflict in step 2 that exceeded the high-confidence resolution bar.
|
|
300
|
+
- CI still running (`gh pr checks --watch` timed out with pending checks).
|
|
301
|
+
- CI failing with a diagnosis-only verdict from Step 5 (flaky / infra / auth / external check / ambiguous / out-of-scope failure).
|
|
302
|
+
- Only Skip-reply threads remained AND CI was already red or pending.
|
|
303
|
+
|
|
304
|
+
Report the specific blocker (pending vs. diagnosed-failure, with the diagnosis text) and tell the user to investigate or re-run once state may have changed.
|
|
305
|
+
|
|
306
|
+
This skill never waits or repeats internally.
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
#
|
|
5
5
|
# SENTINEL is the literal emitted on new replies: a visible footer (robot mark +
|
|
6
6
|
# token in `<code>`, wrapped in `<sub>`). SENTINEL_PREFIX is the wrapper-free
|
|
7
|
-
# substring used for matching/dedupe
|
|
8
|
-
#
|
|
9
|
-
# substituted at build time by embedPluginVersion.mts.
|
|
7
|
+
# substring used for matching/dedupe. LEGACY_SENTINEL_PREFIX keeps old
|
|
8
|
+
# `babysit-pr:addressed v1` comments from being reprocessed after the rename.
|
|
9
|
+
# The `core@X.Y.Z` suffix is substituted at build time by embedPluginVersion.mts.
|
|
10
10
|
|
|
11
|
-
SENTINEL_PREFIX='babysit
|
|
12
|
-
|
|
11
|
+
SENTINEL_PREFIX='cb-babysit:addressed v1 '
|
|
12
|
+
LEGACY_SENTINEL_PREFIX='babysit-pr:addressed v1 '
|
|
13
|
+
SENTINEL='<sub>🤖 <code>cb-babysit:addressed v1 core@3.11.0</code></sub>'
|
|
13
14
|
|
|
14
15
|
# Bot author allowlist (JSON array literal). Used by unresolvedPrComments.sh
|
|
15
16
|
# as a fallback when GraphQL's `author.__typename == "Bot"` misses a GitHub
|
|
@@ -18,11 +19,11 @@ SENTINEL='<sub>🤖 <code>babysit-pr:addressed v1 core@3.10.1</code></sub>'
|
|
|
18
19
|
BOTS_JSON='["coderabbitai","coderabbitai[bot]","mendral-app","mendral-app[bot]","dependabot","dependabot[bot]","github-actions","github-actions[bot]","github-advanced-security","github-advanced-security[bot]","renovate","renovate[bot]","renovate-bot","pre-commit-ci","pre-commit-ci[bot]","codecov","codecov[bot]","sonarcloud","sonarcloud[bot]"]'
|
|
19
20
|
|
|
20
21
|
# Echo $1 with SENTINEL appended on its own trailing paragraph, unless the
|
|
21
|
-
# body already contains any version of the sentinel
|
|
22
|
+
# body already contains any version of the sentinel.
|
|
22
23
|
ensure_sentinel() {
|
|
23
24
|
local body="$1"
|
|
24
25
|
case "$body" in
|
|
25
|
-
*"$SENTINEL_PREFIX"*) printf '%s' "$body" ;;
|
|
26
|
+
*"$SENTINEL_PREFIX"* | *"$LEGACY_SENTINEL_PREFIX"*) printf '%s' "$body" ;;
|
|
26
27
|
*) printf '%s\n\n%s' "$body" "$SENTINEL" ;;
|
|
27
28
|
esac
|
|
28
29
|
}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# pr-number: optional; defaults to the PR on the current branch.
|
|
6
6
|
#
|
|
7
7
|
# Output (plain text on stdout). First line is either:
|
|
8
|
-
# # babysit
|
|
8
|
+
# # cb-babysit: no failing checks
|
|
9
9
|
# or:
|
|
10
|
-
# # babysit
|
|
10
|
+
# # cb-babysit: failing checks
|
|
11
11
|
# followed by one delimited block per failing job:
|
|
12
12
|
# # --- run=<id> job=<id> ---
|
|
13
13
|
# <log body>
|
|
@@ -16,10 +16,9 @@
|
|
|
16
16
|
# first line). Exit 1 on infrastructure errors (gh missing, not authed, no PR).
|
|
17
17
|
# Exit 2 on usage errors.
|
|
18
18
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# `gh run view --json jobs` returns lower (REST). `bucket` sidesteps it.
|
|
19
|
+
# Failing-check detection normalizes `bucket`, `.conclusion`, and `.state`
|
|
20
|
+
# because gh's PR GraphQL and Actions REST payloads expose different fields and
|
|
21
|
+
# casing, and some status contexts have a null `bucket`.
|
|
23
22
|
#
|
|
24
23
|
# Requires: gh, jq.
|
|
25
24
|
|
|
@@ -74,7 +73,7 @@ FAILING_RAW="$(printf '%s' "$ROLLUP" \
|
|
|
74
73
|
')"
|
|
75
74
|
|
|
76
75
|
if [ -z "$FAILING_RAW" ]; then
|
|
77
|
-
echo "# babysit
|
|
76
|
+
echo "# cb-babysit: no failing checks"
|
|
78
77
|
exit 0
|
|
79
78
|
fi
|
|
80
79
|
|
|
@@ -98,7 +97,7 @@ $FAILING_RAW
|
|
|
98
97
|
EOF
|
|
99
98
|
RUN_IDS="$(printf '%s\n' $RUN_IDS | sort -u | tr '\n' ' ')"
|
|
100
99
|
|
|
101
|
-
echo "# babysit
|
|
100
|
+
echo "# cb-babysit: failing checks"
|
|
102
101
|
|
|
103
102
|
for RUN_ID in $RUN_IDS; do
|
|
104
103
|
for JOB_ID in $(gh run view "$RUN_ID" --json jobs \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# postSentinelPrComment.sh — Post a top-level PR comment (used for nitpick summaries).
|
|
3
|
-
# Appends the babysit
|
|
3
|
+
# Appends the cb-babysit sentinel if missing.
|
|
4
4
|
#
|
|
5
5
|
# Usage: bash postSentinelPrComment.sh <pr-number> <body>
|
|
6
6
|
#
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# postSentinelReply.sh — Post a threaded reply to a PR review thread.
|
|
3
|
-
# The body MUST end with the babysit
|
|
3
|
+
# The body MUST end with the cb-babysit sentinel; this script enforces that.
|
|
4
4
|
# Does NOT resolve the thread — that stays with the human.
|
|
5
5
|
#
|
|
6
6
|
# Usage: bash postSentinelReply.sh <thread-id> <body>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# unresolvedPrComments.sh — Fetch review data for babysit
|
|
2
|
+
# unresolvedPrComments.sh — Fetch review data for cb-babysit.
|
|
3
3
|
#
|
|
4
4
|
# Returns one JSON document with:
|
|
5
5
|
# - threads / activeThreads / uncertainThreads — review threads with
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
# - issueComments — every top-level PR conversation comment, tagged with
|
|
11
11
|
# isBabysitSentinel and isKnownBot flags.
|
|
12
12
|
# - activeIssueComments — non-sentinel, non-bot issue comments whose
|
|
13
|
-
# per-comment fingerprint is NOT already listed in any prior babysit
|
|
13
|
+
# per-comment fingerprint is NOT already listed in any prior cb-babysit
|
|
14
14
|
# summary. These are the human Conversation-tab comments needing a reply.
|
|
15
15
|
# - priorBabysitSentinels — issue comments whose body contains the
|
|
16
|
-
# babysit
|
|
16
|
+
# cb-babysit sentinel prefix. Used for review-body + issue-comment dedupe.
|
|
17
17
|
# - truncated — array naming any GraphQL connection that hit GitHub's
|
|
18
18
|
# 100-item cap (reviewThreads, thread-comments, reviews, issueComments).
|
|
19
19
|
# Agent must surface this in the final summary.
|
|
@@ -258,9 +258,9 @@ main() {
|
|
|
258
258
|
# - postSentinelHumanComments: ARRAY of every human comment after the sentinel
|
|
259
259
|
# - activityState: "active" / "uncertain" / "addressed"
|
|
260
260
|
local threads_json
|
|
261
|
-
threads_json="$(printf '%s' "$response" | jq --arg sentinel_prefix "$SENTINEL_PREFIX" --argjson bots "$BOTS_JSON" '
|
|
261
|
+
threads_json="$(printf '%s' "$response" | jq --arg sentinel_prefix "$SENTINEL_PREFIX" --arg legacy_sentinel_prefix "$LEGACY_SENTINEL_PREFIX" --argjson bots "$BOTS_JSON" '
|
|
262
262
|
def is_bot: ((.author.__typename // "") == "Bot") or ((.author.login // "") | IN($bots[]));
|
|
263
|
-
def is_sentinel: ((.body // "") | contains($sentinel_prefix));
|
|
263
|
+
def is_sentinel: ((.body // "") | contains($sentinel_prefix) or contains($legacy_sentinel_prefix));
|
|
264
264
|
[
|
|
265
265
|
.data.repository.pullRequest.reviewThreads.nodes[]
|
|
266
266
|
| select(.isResolved == false)
|
|
@@ -416,8 +416,8 @@ main() {
|
|
|
416
416
|
|
|
417
417
|
# All issue comments (top-level Conversation-tab comments).
|
|
418
418
|
local raw_issue_comments
|
|
419
|
-
raw_issue_comments="$(printf '%s' "$response" | jq --arg sentinel_prefix "$SENTINEL_PREFIX" --argjson bots "$BOTS_JSON" '
|
|
420
|
-
def is_sentinel_body: ((.body // "") | contains($sentinel_prefix));
|
|
419
|
+
raw_issue_comments="$(printf '%s' "$response" | jq --arg sentinel_prefix "$SENTINEL_PREFIX" --arg legacy_sentinel_prefix "$LEGACY_SENTINEL_PREFIX" --argjson bots "$BOTS_JSON" '
|
|
420
|
+
def is_sentinel_body: ((.body // "") | contains($sentinel_prefix) or contains($legacy_sentinel_prefix));
|
|
421
421
|
def is_bot_author: ((.author.__typename // "") == "Bot") or ((.author.login // "") | IN($bots[]));
|
|
422
422
|
[
|
|
423
423
|
.data.repository.pullRequest.comments.nodes[]
|
|
@@ -443,12 +443,12 @@ main() {
|
|
|
443
443
|
|
|
444
444
|
# Concatenate prior sentinel bodies into one blob — used as a haystack for
|
|
445
445
|
# fingerprint dedupe (both review-body and issue-comment fingerprints land
|
|
446
|
-
# in the fenced block at the end of a babysit
|
|
446
|
+
# in the fenced block at the end of a cb-babysit summary).
|
|
447
447
|
local prior_sentinel_blob
|
|
448
448
|
prior_sentinel_blob="$(printf '%s' "$prior_sentinels" | jq -r '[.[].body] | join("\n")')"
|
|
449
449
|
|
|
450
450
|
# activeIssueComments: non-sentinel, non-bot comments whose fingerprint is
|
|
451
|
-
# NOT already listed in any prior babysit
|
|
451
|
+
# NOT already listed in any prior cb-babysit summary.
|
|
452
452
|
local active_issue_comments
|
|
453
453
|
active_issue_comments="$(printf '%s' "$issue_comments" | jq --arg blob "$prior_sentinel_blob" '
|
|
454
454
|
[.[]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cb-ship
|
|
3
|
+
description: Ship changes. Simplify the diff, commit, push, and open or update a PR. Use when the user says 'ship it', 'commit and push', or wants a PR created or updated.
|
|
4
|
+
argument-hint: "[--draft]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
- If `gh auth status` fails, stop and tell the user.
|
|
10
|
+
- If `git rev-parse --verify origin/HEAD` fails, `origin/HEAD` is unset. Stop and tell the user to run `git remote set-head origin -a`.
|
|
11
|
+
- If `git status --short`, `git log --oneline origin/HEAD..HEAD`, and `gh pr view --json url --jq .url 2>/dev/null` are all empty, stop and reply "nothing to ship."
|
|
12
|
+
|
|
13
|
+
Resolve bundled "./references" paths relative to SKILL.md.
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
|
|
17
|
+
1. Create a new branch if on the default branch (e.g., `feat/add-user-validation`, `fix/null-check-in-parser`).
|
|
18
|
+
2. Use ./references/simplify.md on the full PR diff: `git diff $(git merge-base HEAD origin/HEAD)..HEAD` and any uncommitted changes.
|
|
19
|
+
3. Inspect `git status --short`, identify intended files, ask if ambiguous, then git add them. If uncommitted changes, create a conventional commit with `git commit --no-gpg-sign`.
|
|
20
|
+
4. Push changes to origin.
|
|
21
|
+
5. Create or update the PR using ./references/pr-template.md:
|
|
22
|
+
a. If the host exposes a session ID (e.g., CODEX_THREAD_ID, CLAUDE_CODE_SESSION_ID), include the resume command in the PR body in backticks: ``Agent session: `codex resume <id>` `` or ``Agent session: `claude --resume <id>` ``. Preserve existing `Agent session:` lines, append only.
|
|
23
|
+
b. If a PR exists, update the title and body if the new changes aren't reflected.
|
|
24
|
+
c. Otherwise, create one with `gh pr create`; make it a draft if the user passed `--draft`.
|
|
25
|
+
6. Output:
|
|
26
|
+
|
|
27
|
+
```plaintext
|
|
28
|
+
- Directory: [Absolute path]
|
|
29
|
+
- Branch: [Branch name]
|
|
30
|
+
- Session: [Resume command from 5a] (omit if none)
|
|
31
|
+
- PR: [Complete url] (e.g., `https://github.com/clipboardhealth/core-utils/pull/123`)
|
|
32
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Title
|
|
2
|
+
|
|
3
|
+
Conventional commit type and description with no scope, followed by the issue tracker ID in parentheses if you can derive it from the branch name or session context (e.g., `feat: add resume command (STAFF-123)`).
|
|
4
|
+
|
|
5
|
+
## Body
|
|
6
|
+
|
|
7
|
+
```md
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
Concisely explain the user intent from session history and the meaningful behavior/system change.
|
|
11
|
+
|
|
12
|
+
## Validation
|
|
13
|
+
|
|
14
|
+
- List proof of validation: commands, screenshots, telemetry, Loom, or `Not run: <reason>`.
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
Optional, don't fabricate: ticket links, rollout plan, residual risk, or specific areas for reviewers to focus.
|
|
19
|
+
|
|
20
|
+
<sub>🤖 <code>cb-ship:created v1 core@3.11.0</code></sub>
|
|
21
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Simplify
|
|
2
|
+
|
|
3
|
+
If the host supports it, launch three review agents concurrently, passing each the full diff. Otherwise, perform the reviews inline.
|
|
4
|
+
|
|
5
|
+
## Agents
|
|
6
|
+
|
|
7
|
+
### 1: Code reuse review
|
|
8
|
+
|
|
9
|
+
Review each change:
|
|
10
|
+
|
|
11
|
+
1. **Search for existing utilities and helpers** that could replace newly written code. Look for similar patterns elsewhere in the codebase. Common locations are utility directories, shared modules, library monorepos `cbh-core` and `core-utils`, and files adjacent to the changed ones.
|
|
12
|
+
2. **Flag any new function that duplicates existing functionality.** Suggest the existing function to use instead.
|
|
13
|
+
3. **Flag any inline logic that could use an existing utility.** Hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns are common candidates.
|
|
14
|
+
|
|
15
|
+
### 2: Code quality review
|
|
16
|
+
|
|
17
|
+
Review each change for hacky patterns:
|
|
18
|
+
|
|
19
|
+
1. **Redundant state** that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls.
|
|
20
|
+
2. **Parameter sprawl**: Adding new parameters to a function instead of generalizing or restructuring existing ones.
|
|
21
|
+
3. **Copy-paste with slight variation**: near-duplicate code blocks that should be unified with a shared abstraction.
|
|
22
|
+
4. **Leaky abstractions**: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries.
|
|
23
|
+
5. **Stringly-typed code**: using raw strings where constants, enums (string unions), or branded types already exist in the codebase.
|
|
24
|
+
6. **Unnecessary JSX nesting**: wrapper Boxes/elements that add no layout value. Check if inner component props (flexShrink, alignItems, etc.) already provide the needed behavior.
|
|
25
|
+
7. **Nested conditionals**: ternary chains (`a ? x : b ? y : ...`), nested if/else, or nested switch 3+ levels deep. Flatten with early returns, guard clauses, a lookup table, or an if/else-if cascade.
|
|
26
|
+
8. **Unnecessary comments**: Delete comments explaining WHAT the code does (well-named identifiers already do that), narrating the change, or referencing the task/caller. Keep only non-obvious WHY (hidden constraints, subtle invariants, workarounds).
|
|
27
|
+
9. **Defensive code on trusted inputs**: null/empty/type guards on inputs already guaranteed upstream (a validated DTO, the type system, a controller that already checked), optional chaining where the types guarantee presence, fallbacks that mask bugs (`?? ''`, `|| []`, `?? 0` on values that should never be absent), and try/catch that only logs and rethrows or guards an impossible state. Leave guards at genuine trust boundaries (raw request bodies, webhook payloads, third-party responses) and any error handling around real I/O, network, parsing, or payments — removing those changes behavior.
|
|
28
|
+
10. **Type escapes**: `as any`, `: any`, `as unknown as X`, gratuitous non-null `!`, `@ts-ignore`/`@ts-expect-error` added to dodge a type error — replace with the real type when it is determinable from the call site, the imported type, or the shape in use; if it is not, leave it and flag it rather than deleting it (breaks the build) or swapping in a TODO (more clutter).
|
|
29
|
+
11. **Leftover debug statements**: stray `console.log`/print-style output used to debug; keep intentional logging that goes through the repo's logger.
|
|
30
|
+
|
|
31
|
+
### 3: Efficiency review
|
|
32
|
+
|
|
33
|
+
Review each change for:
|
|
34
|
+
|
|
35
|
+
1. **Unnecessary work**: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns.
|
|
36
|
+
2. **Missed concurrency**: independent operations run sequentially when they could run in parallel.
|
|
37
|
+
3. **Hot-path bloat**: new blocking work added to startup or per-request/per-render hot paths.
|
|
38
|
+
4. **Recurring no-op updates**: state/store updates inside polling loops, intervals, or event handlers that fire unconditionally. Add a change-detection guard so downstream consumers aren't notified when nothing changed. If a wrapper function takes an updater/reducer callback, verify it honors same-reference returns (or whatever the "no change" signal is), otherwise callers' early-return no-ops are silently defeated.
|
|
39
|
+
5. **Unnecessary existence checks**: pre-checking file/resource existence before operating (TOCTOU anti-pattern); operate directly and handle the error.
|
|
40
|
+
6. **Memory**: unbounded data structures, missing cleanup, event listener leaks.
|
|
41
|
+
7. **Overly broad operations**: reading entire files when only a portion is needed, loading all items when filtering for one.
|
|
42
|
+
|
|
43
|
+
## Fix issues
|
|
44
|
+
|
|
45
|
+
Once all three reviews are complete, aggregate their findings and fix each issue directly. If a finding is a false positive or not worth addressing, note it and move on.
|
|
46
|
+
|
|
47
|
+
## Validate fixes
|
|
48
|
+
|
|
49
|
+
Find validation commands in, e.g., `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, or pre-commit/pre-push hooks and fix any failures.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cb-work
|
|
3
|
+
description: Implement a plan file or direct request end-to-end, validate, and ship via cb-ship. Use when the user says 'implement the plan' or clearly wants a change implemented and shipped.
|
|
4
|
+
argument-hint: "[--draft] [plan path or implementation request]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
- **Path-like input** (absolute or relative): Resolve the path. If it doesn't resolve to a readable file, stop and tell the user. Do not reinterpret a missing path as a direct request.
|
|
10
|
+
- **Natural-language request**: Treat as the implementation task.
|
|
11
|
+
- **No argument**: Ask for either a plan path or the implementation request.
|
|
12
|
+
|
|
13
|
+
## Prepare
|
|
14
|
+
|
|
15
|
+
Unless instructed otherwise:
|
|
16
|
+
|
|
17
|
+
- Create and `cd` into a git worktree based on a freshly fetched `origin/HEAD` using the host's worktree mechanism if it has one; use a descriptive branch name (e.g., `feat/add-user-validation`, `fix/null-check-in-parser`).
|
|
18
|
+
- Install dependencies according to repo docs and detected lock files, e.g., `npm ci`.
|
|
19
|
+
|
|
20
|
+
## Implement
|
|
21
|
+
|
|
22
|
+
The plan or request is the source of truth for scope:
|
|
23
|
+
|
|
24
|
+
- Make exactly the changes requested, no extra refactors or cleanup.
|
|
25
|
+
- On any drift from the plan (e.g. referenced files or utilities missing, an assumption invalid, a constraint missed) stop and report. Do not silently rewrite the approach.
|
|
26
|
+
- Do not modify the plan file itself unless asked.
|
|
27
|
+
|
|
28
|
+
Run the relevant checks after each meaningful unit of work, not only at the end.
|
|
29
|
+
|
|
30
|
+
## Validate
|
|
31
|
+
|
|
32
|
+
If the plan names specific checks, use those; skip clearly slow or CI-only suites. Otherwise find validation commands in, e.g., `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, or pre-commit/pre-push hooks.
|
|
33
|
+
|
|
34
|
+
Done when every check passes or the user has explicitly accepted a failure.
|
|
35
|
+
|
|
36
|
+
## Hand off
|
|
37
|
+
|
|
38
|
+
Invoke the `cb-ship` skill, passing `--draft` if it was passed to this skill. Relay `cb-ship`'s reply to the user.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-groundcrew-ticket
|
|
3
|
-
description: "Create Linear tickets that Groundcrew can pick up: assigned to the current Linear user, labeled with agent-*, tied to an implementation repository in the description, optionally linked to parent and blocker tickets, and written to use the core:
|
|
3
|
+
description: "Create Linear tickets that Groundcrew can pick up: assigned to the current Linear user, labeled with agent-*, tied to an implementation repository in the description, optionally linked to parent and blocker tickets, and written to use the core:cb-work implementation workflow."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Create Groundcrew Ticket
|
|
@@ -53,7 +53,7 @@ Use a direct implementation-shaped ticket. Keep the repository line near the top
|
|
|
53
53
|
## Groundcrew
|
|
54
54
|
|
|
55
55
|
Repository: <repo>
|
|
56
|
-
Implementation workflow: use the `core:
|
|
56
|
+
Implementation workflow: use the `core:cb-work`/`cb-work` skill when available. If that skill is unavailable, follow this repo's AGENTS.md/CLAUDE.md implementation workflow and run the documented verification.
|
|
57
57
|
|
|
58
58
|
## Task
|
|
59
59
|
|