@groupby/ai-dev 0.5.0 → 0.5.3
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/teams/snpd/github/PULL_REQUEST_TEMPLATE.md +20 -0
- package/teams/snpd/skills/README.md +306 -0
- package/teams/snpd/skills/council-review/SKILL.md +243 -0
- package/teams/snpd/skills/council-review/references/output-format.md +108 -0
- package/teams/snpd/skills/council-review/references/reviewer-prompt.md +99 -0
- package/teams/snpd/skills/council-review/references/technology-profiles.md +54 -0
- package/teams/snpd/skills/council-review/scripts/summarize_review_config.py +226 -0
- package/teams/snpd/skills/docs-init/SKILL.md +403 -0
- package/teams/snpd/skills/draft-plan/SKILL.md +201 -0
- package/teams/snpd/skills/draft-pr/SKILL.md +252 -0
- package/teams/snpd/skills/jira-spec/SKILL.md +216 -0
- package/teams/snpd/skills/tdd-implement/SKILL.md +320 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Reviewer Prompt Template
|
|
2
|
+
|
|
3
|
+
You are one member of a 3-model code review council. Your job is to independently
|
|
4
|
+
review the code changes below and produce high-signal findings. Another process
|
|
5
|
+
will compare your review against two other models' reviews to find consensus.
|
|
6
|
+
|
|
7
|
+
## Your Review Constraints
|
|
8
|
+
|
|
9
|
+
- **Only flag things that genuinely matter.** Bugs, security issues, logic errors,
|
|
10
|
+
performance problems, missing error handling, test gaps for changed code.
|
|
11
|
+
- **Never comment on style, formatting, naming preferences, or trivial matters**
|
|
12
|
+
unless they cause a real problem (e.g., a misleading variable name that could
|
|
13
|
+
cause a bug).
|
|
14
|
+
- **Be specific.** Always include the file path, approximate line range, and a
|
|
15
|
+
concrete description of the problem.
|
|
16
|
+
- **Suggest a fix** when possible. Don't just say "this is wrong" — say what to do.
|
|
17
|
+
- **Don't be redundant.** If two issues share the same root cause, report it once.
|
|
18
|
+
- **Respect repo-specific rules.** The project context below includes this repo's
|
|
19
|
+
own conventions, technology profile, and CI expectations. Review against THOSE
|
|
20
|
+
rules, not generic best practices. Do not assume patterns from other repos.
|
|
21
|
+
|
|
22
|
+
## Project Context
|
|
23
|
+
|
|
24
|
+
{PROJECT_CONTEXT}
|
|
25
|
+
|
|
26
|
+
This context was discovered from the repo's own guidance files, CI workflows,
|
|
27
|
+
build configuration, and technology markers. If the context mentions specific
|
|
28
|
+
patterns (e.g., Micronaut DI, tenant isolation, cache key format), verify the
|
|
29
|
+
diff follows them. If the context is silent on something, don't invent rules.
|
|
30
|
+
|
|
31
|
+
## Technology Profile
|
|
32
|
+
|
|
33
|
+
{TECHNOLOGY_PROFILE}
|
|
34
|
+
|
|
35
|
+
## Change Classification
|
|
36
|
+
|
|
37
|
+
{CHANGE_CLASSIFICATION}
|
|
38
|
+
|
|
39
|
+
## Review Focus Areas (from repo's CI/review config)
|
|
40
|
+
|
|
41
|
+
Review against these standard areas, but weight them based on the change
|
|
42
|
+
classification above:
|
|
43
|
+
|
|
44
|
+
1. **Code quality:** single responsibility, clarity, maintainability, unnecessary
|
|
45
|
+
complexity/nesting, redundant abstractions, local style conventions.
|
|
46
|
+
2. **Security:** auth, authorization, tenant isolation, input validation, secrets,
|
|
47
|
+
sensitive data exposure.
|
|
48
|
+
3. **Performance:** database/query shape, cache behavior, external calls,
|
|
49
|
+
async/blocking boundaries, memory/resource lifecycle.
|
|
50
|
+
4. **Testing:** adequate coverage for changed code, edge cases, missing scenarios.
|
|
51
|
+
5. **Documentation:** README/docs/OpenAPI/API docs accuracy when behavior changes.
|
|
52
|
+
|
|
53
|
+
## Changed Files Summary
|
|
54
|
+
|
|
55
|
+
{DIFF_STAT}
|
|
56
|
+
|
|
57
|
+
## Full Diff
|
|
58
|
+
|
|
59
|
+
{DIFF}
|
|
60
|
+
|
|
61
|
+
## Output Format
|
|
62
|
+
|
|
63
|
+
Return your findings as a structured list. Each finding must follow this exact format:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
### Finding <N>
|
|
67
|
+
- **File:** <path/to/file>
|
|
68
|
+
- **Lines:** <start>-<end> (approximate)
|
|
69
|
+
- **Severity:** P1 | P2 | P3
|
|
70
|
+
- **Category:** bug | security | performance | design | test-gap | error-handling | concurrency | data-integrity
|
|
71
|
+
- **Summary:** <one-line summary>
|
|
72
|
+
- **Details:** <1-3 sentences explaining the issue>
|
|
73
|
+
- **Suggestion:** <concrete fix or action>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Severity Guide
|
|
77
|
+
|
|
78
|
+
- **P1 — Critical:** Likely bug, security vulnerability, data loss, crash, race condition,
|
|
79
|
+
or production incident. Must fix before merge.
|
|
80
|
+
- **P2 — Important:** Behavior regression, missing important test, incorrect error handling,
|
|
81
|
+
performance issue under realistic load. Should fix before merge.
|
|
82
|
+
- **P3 — Minor:** Low-risk test gap, minor inefficiency, documentation inaccuracy.
|
|
83
|
+
Nice to fix but not blocking.
|
|
84
|
+
|
|
85
|
+
### What NOT to Report
|
|
86
|
+
|
|
87
|
+
- Style or formatting preferences
|
|
88
|
+
- "Consider renaming X" suggestions
|
|
89
|
+
- "Add a comment explaining Y" suggestions
|
|
90
|
+
- Import ordering
|
|
91
|
+
- Trailing whitespace
|
|
92
|
+
- Suggestions that don't prevent a real problem
|
|
93
|
+
|
|
94
|
+
If you find zero genuine issues, return:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
### No Issues Found
|
|
98
|
+
The changes look correct. No bugs, security issues, or significant concerns identified.
|
|
99
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Technology Profiles
|
|
2
|
+
|
|
3
|
+
Apply a profile **only** when discovered in the current repo's files.
|
|
4
|
+
Do not carry assumptions from one repo to another.
|
|
5
|
+
|
|
6
|
+
## Java / Micronaut
|
|
7
|
+
|
|
8
|
+
- Check the Java version from workflow and Gradle config (do not assume 21 — some repos use 17).
|
|
9
|
+
- Use Micronaut compile-time DI patterns; avoid Spring Boot assumptions unless the repo is Spring-based.
|
|
10
|
+
- Prefer constructor injection and the Lombok annotations already used locally.
|
|
11
|
+
- Follow the repo's `var` rule (many Rezolve Java repos use `var` for new variables created with `new`).
|
|
12
|
+
- Check `@Singleton` vs `@Context` scope, `@Named` qualifiers, `@ExecuteOn` boundaries.
|
|
13
|
+
- Verify blocking operations are not on the event loop thread.
|
|
14
|
+
|
|
15
|
+
## JOOQ / Flyway / Database
|
|
16
|
+
|
|
17
|
+
- Migration names and generated classes matter — check naming conventions.
|
|
18
|
+
- Check tenant isolation on queries and mutation side effects (events, audit logs).
|
|
19
|
+
- Verify transaction boundaries and connection management.
|
|
20
|
+
|
|
21
|
+
## Search Services
|
|
22
|
+
|
|
23
|
+
- Check strategy and engine selection order.
|
|
24
|
+
- Ensure request builders, filters, refinements, biasing, pagination, and response builders preserve behavior.
|
|
25
|
+
- For Google Retail: check proto conversion, request fields, fallback behavior.
|
|
26
|
+
- For Mongo Atlas Search: check aggregation stages, index assumptions, field paths, unsupported Google-only features.
|
|
27
|
+
- For Redis caches: check key composition, tenant/collection/area isolation, TTLs, skip-cache paths.
|
|
28
|
+
|
|
29
|
+
## Mongo Data / Indexing
|
|
30
|
+
|
|
31
|
+
- Check collection and tenant scoping.
|
|
32
|
+
- Check aggregation pipeline correctness, projections, variant/inventory handling.
|
|
33
|
+
- Check index definition generation, conditional indexing, feature flags.
|
|
34
|
+
|
|
35
|
+
## Authentication / Security
|
|
36
|
+
|
|
37
|
+
- Check token validation, claims, expiration, signature algorithms, public endpoint boundaries.
|
|
38
|
+
- Check Redis key storage, key rotation, secret handling.
|
|
39
|
+
- Check Pub/Sub credential update idempotency.
|
|
40
|
+
|
|
41
|
+
## Go / Python / Node
|
|
42
|
+
|
|
43
|
+
- Prefer repo-provided commands from Makefile, package files, workflow files, or docs.
|
|
44
|
+
- Keep tests close to the changed package/module.
|
|
45
|
+
- Check schema/serialization compatibility and environment variable handling.
|
|
46
|
+
- Do not import Java/Micronaut assumptions into these repos.
|
|
47
|
+
|
|
48
|
+
## General (all profiles)
|
|
49
|
+
|
|
50
|
+
- **Code quality:** Single responsibility, clarity, maintainability, unnecessary complexity.
|
|
51
|
+
- **Security:** Auth, authorization, tenant isolation, input validation, secrets.
|
|
52
|
+
- **Performance:** Database/query shape, cache behavior, external calls, async/blocking.
|
|
53
|
+
- **Testing:** Adequate coverage for changed code, edge cases, no superfluous tests.
|
|
54
|
+
- **Documentation:** README/docs/OpenAPI accuracy when behavior changes.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Summarize PR review and CI configuration for a repository.
|
|
3
|
+
|
|
4
|
+
Repo-agnostic: takes the repository root as its argument (defaults to the current
|
|
5
|
+
directory) and works on any project. Uses only the Python standard library so it
|
|
6
|
+
can run in sandboxes without installing PyYAML or other dependencies.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
GUIDANCE_FILES = [
|
|
17
|
+
".github/copilot-instructions.md",
|
|
18
|
+
"CLAUDE.md",
|
|
19
|
+
"AGENTS.md",
|
|
20
|
+
"README.md",
|
|
21
|
+
"docs/conventions.md",
|
|
22
|
+
"docs/project-rule.md",
|
|
23
|
+
"docs/source-control.md",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
REVIEW_FILES = [
|
|
27
|
+
".github/workflows/claude-pr-review.yml",
|
|
28
|
+
".github/workflows/claude.yml",
|
|
29
|
+
".github/workflows/build-pr.yaml",
|
|
30
|
+
".github/PULL_REQUEST_TEMPLATE.md",
|
|
31
|
+
".github/CODEOWNERS",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
BUILD_FILES = [
|
|
35
|
+
"build.gradle",
|
|
36
|
+
"build.gradle.kts",
|
|
37
|
+
"settings.gradle",
|
|
38
|
+
"gradle.properties",
|
|
39
|
+
"pom.xml",
|
|
40
|
+
"go.mod",
|
|
41
|
+
"Makefile",
|
|
42
|
+
"pyproject.toml",
|
|
43
|
+
"requirements.txt",
|
|
44
|
+
"package.json",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
KEYWORDS = [
|
|
48
|
+
"Micronaut",
|
|
49
|
+
"Java 21",
|
|
50
|
+
"Java 17",
|
|
51
|
+
"Spring",
|
|
52
|
+
"Lombok",
|
|
53
|
+
"Spock",
|
|
54
|
+
"JUnit",
|
|
55
|
+
"Mockito",
|
|
56
|
+
"Testcontainers",
|
|
57
|
+
"JOOQ",
|
|
58
|
+
"jOOQ",
|
|
59
|
+
"Flyway",
|
|
60
|
+
"PostgreSQL",
|
|
61
|
+
"Mongo",
|
|
62
|
+
"Redis",
|
|
63
|
+
"Google Retail",
|
|
64
|
+
"Command Center",
|
|
65
|
+
"Pub/Sub",
|
|
66
|
+
"BigQuery",
|
|
67
|
+
"LaunchDarkly",
|
|
68
|
+
"ANTLR",
|
|
69
|
+
"Kafka",
|
|
70
|
+
"JWT",
|
|
71
|
+
"Docker",
|
|
72
|
+
"Jib",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def read(path: Path) -> str:
|
|
77
|
+
try:
|
|
78
|
+
return path.read_text(errors="replace")
|
|
79
|
+
except FileNotFoundError:
|
|
80
|
+
return ""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def existing(root: Path, paths: list[str]) -> list[Path]:
|
|
84
|
+
return [root / path for path in paths if (root / path).exists()]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def first_match(pattern: str, text: str) -> str | None:
|
|
88
|
+
match = re.search(pattern, text, re.MULTILINE)
|
|
89
|
+
return match.group(1).strip() if match else None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def command_lines(text: str) -> list[str]:
|
|
93
|
+
commands: list[str] = []
|
|
94
|
+
for line in text.splitlines():
|
|
95
|
+
stripped = line.strip()
|
|
96
|
+
candidate = stripped
|
|
97
|
+
if stripped.startswith("run:"):
|
|
98
|
+
candidate = stripped.removeprefix("run:").strip()
|
|
99
|
+
if re.match(r"^(\.?/gradlew|gradle|mvn|make|go\s+test|pytest|npm|pnpm|yarn|docker)\b", candidate):
|
|
100
|
+
commands.append(candidate)
|
|
101
|
+
return commands
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def pr_checkboxes(text: str) -> list[str]:
|
|
105
|
+
checks = []
|
|
106
|
+
for line in text.splitlines():
|
|
107
|
+
if re.match(r"\s*-\s+\[[ xX]\]", line):
|
|
108
|
+
checks.append(line.strip())
|
|
109
|
+
return checks
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def collect_keywords(text: str) -> list[str]:
|
|
113
|
+
found = []
|
|
114
|
+
lower_text = text.lower()
|
|
115
|
+
for keyword in KEYWORDS:
|
|
116
|
+
if keyword.lower() in lower_text:
|
|
117
|
+
found.append(keyword)
|
|
118
|
+
normalized = []
|
|
119
|
+
seen = set()
|
|
120
|
+
for keyword in found:
|
|
121
|
+
key = keyword.lower()
|
|
122
|
+
if key not in seen:
|
|
123
|
+
seen.add(key)
|
|
124
|
+
normalized.append(keyword)
|
|
125
|
+
return sorted(normalized, key=str.lower)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def main() -> int:
|
|
129
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
130
|
+
parser.add_argument("repo", nargs="?", default=".", help="Repository root")
|
|
131
|
+
args = parser.parse_args()
|
|
132
|
+
|
|
133
|
+
root = Path(args.repo).resolve()
|
|
134
|
+
print(f"# PR Review Configuration Summary\n")
|
|
135
|
+
print(f"Repository: `{root}`\n")
|
|
136
|
+
|
|
137
|
+
review_files = existing(root, REVIEW_FILES)
|
|
138
|
+
guidance_files = existing(root, GUIDANCE_FILES)
|
|
139
|
+
build_files = existing(root, BUILD_FILES)
|
|
140
|
+
|
|
141
|
+
print("## Files Found\n")
|
|
142
|
+
for title, files in [
|
|
143
|
+
("Review/CI", review_files),
|
|
144
|
+
("Guidance", guidance_files),
|
|
145
|
+
("Build", build_files),
|
|
146
|
+
]:
|
|
147
|
+
print(f"### {title}")
|
|
148
|
+
if files:
|
|
149
|
+
for path in files:
|
|
150
|
+
print(f"- `{path.relative_to(root)}`")
|
|
151
|
+
else:
|
|
152
|
+
print("- none")
|
|
153
|
+
print()
|
|
154
|
+
|
|
155
|
+
claude_text = read(root / ".github/workflows/claude-pr-review.yml")
|
|
156
|
+
if not claude_text:
|
|
157
|
+
claude_text = read(root / ".github/workflows/claude.yml")
|
|
158
|
+
build_text = read(root / ".github/workflows/build-pr.yaml")
|
|
159
|
+
pr_template = read(root / ".github/PULL_REQUEST_TEMPLATE.md")
|
|
160
|
+
codeowners = read(root / ".github/CODEOWNERS")
|
|
161
|
+
guidance_text = "\n\n".join(read(path) for path in guidance_files)
|
|
162
|
+
build_texts = "\n\n".join(read(path) for path in build_files)
|
|
163
|
+
|
|
164
|
+
print("## Claude Review\n")
|
|
165
|
+
if claude_text:
|
|
166
|
+
triggers = re.findall(r"types:\s*\[([^\]]+)\]", claude_text)
|
|
167
|
+
model = first_match(r"--model\s+([^\s]+)", claude_text)
|
|
168
|
+
print(f"- Workflow present: yes")
|
|
169
|
+
print(f"- Trigger type lists: {', '.join(triggers) if triggers else 'not parsed'}")
|
|
170
|
+
print(f"- Model: {model or 'not parsed'}")
|
|
171
|
+
print("- Standard focus areas present:")
|
|
172
|
+
for area in ["Code Quality", "Security", "Performance", "Testing", "Documentation"]:
|
|
173
|
+
print(f" - {area}: {'yes' if area in claude_text else 'not found'}")
|
|
174
|
+
else:
|
|
175
|
+
print("- Workflow present: no")
|
|
176
|
+
print()
|
|
177
|
+
|
|
178
|
+
print("## PR CI Commands\n")
|
|
179
|
+
commands = command_lines(build_text)
|
|
180
|
+
if commands:
|
|
181
|
+
for command in commands:
|
|
182
|
+
print(f"- `{command}`")
|
|
183
|
+
else:
|
|
184
|
+
print("- none parsed")
|
|
185
|
+
print()
|
|
186
|
+
|
|
187
|
+
java_version = first_match(r"java-version:\s*['\"]?([^'\"\n]+)", build_text)
|
|
188
|
+
if java_version:
|
|
189
|
+
print(f"Java version from PR workflow: `{java_version}`\n")
|
|
190
|
+
|
|
191
|
+
print("## PR Template Checks\n")
|
|
192
|
+
checks = pr_checkboxes(pr_template)
|
|
193
|
+
if checks:
|
|
194
|
+
for check in checks:
|
|
195
|
+
print(f"- {check}")
|
|
196
|
+
else:
|
|
197
|
+
print("- none")
|
|
198
|
+
print()
|
|
199
|
+
|
|
200
|
+
print("## CODEOWNERS\n")
|
|
201
|
+
owners = [line.strip() for line in codeowners.splitlines() if line.strip() and not line.strip().startswith("#")]
|
|
202
|
+
if owners:
|
|
203
|
+
for owner in owners:
|
|
204
|
+
print(f"- `{owner}`")
|
|
205
|
+
else:
|
|
206
|
+
print("- none")
|
|
207
|
+
print()
|
|
208
|
+
|
|
209
|
+
print("## Detected Keywords\n")
|
|
210
|
+
keywords = collect_keywords("\n\n".join([guidance_text, build_texts, claude_text, build_text]))
|
|
211
|
+
if keywords:
|
|
212
|
+
for keyword in keywords:
|
|
213
|
+
print(f"- {keyword}")
|
|
214
|
+
else:
|
|
215
|
+
print("- none")
|
|
216
|
+
print()
|
|
217
|
+
|
|
218
|
+
print("## Suggested Next Steps\n")
|
|
219
|
+
print("- Review changed files against the discovered keywords and guidance files.")
|
|
220
|
+
print("- Run targeted tests first, then the PR build command if feasible.")
|
|
221
|
+
print("- Run `git diff --check` before final output.")
|
|
222
|
+
return 0
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
if __name__ == "__main__":
|
|
226
|
+
raise SystemExit(main())
|