ビルトインワークフロー: review-only(レビュー専用) #60 resolved
This commit is contained in:
parent
1e8909d512
commit
7d856287f0
14
CLAUDE.md
14
CLAUDE.md
@ -284,6 +284,20 @@ Files: `.takt/logs/{sessionId}.jsonl`, with `latest.json` pointer. Legacy `.json
|
||||
|
||||
**Instruction auto-injection over explicit placeholders.** The instruction builder auto-injects `{task}`, `{previous_response}`, `{user_inputs}`, and status rules. Templates should contain only step-specific instructions, not boilerplate.
|
||||
|
||||
**Agent prompts contain only domain knowledge.** Agent prompt files (`resources/global/{lang}/agents/**/*.md`) must contain only domain expertise and behavioral principles — never workflow-specific procedures. Workflow-specific details (which reports to read, step routing, specific templates with hardcoded step names) belong in the workflow YAML's `instruction_template`. This keeps agents reusable across different workflows.
|
||||
|
||||
What belongs in agent prompts:
|
||||
- Role definition ("You are a ... specialist")
|
||||
- Domain expertise, review criteria, judgment standards
|
||||
- Do / Don't behavioral rules
|
||||
- Tool usage knowledge (general, not workflow-specific)
|
||||
|
||||
What belongs in workflow `instruction_template`:
|
||||
- Step-specific procedures ("Read these specific reports")
|
||||
- References to other steps or their outputs
|
||||
- Specific report file names or formats
|
||||
- Comment/output templates with hardcoded review type names
|
||||
|
||||
## Isolated Execution (Shared Clone)
|
||||
|
||||
When tasks specify `worktree: true` or `worktree: "path"`, code runs in a `git clone --shared` (lightweight clone with independent `.git` directory). Clones are ephemeral: created before task execution, auto-committed + pushed after success, then deleted.
|
||||
|
||||
75
resources/global/en/agents/review/pr-commenter.md
Normal file
75
resources/global/en/agents/review/pr-commenter.md
Normal file
@ -0,0 +1,75 @@
|
||||
# PR Commenter Agent
|
||||
|
||||
You are a **PR comment posting specialist**. You post review findings to GitHub Pull Requests using the `gh` CLI.
|
||||
|
||||
## Role
|
||||
|
||||
- Post review findings as PR comments
|
||||
- Format findings clearly and concisely for developers
|
||||
- Filter findings by severity to reduce noise
|
||||
|
||||
**Don't:**
|
||||
- Review code yourself (reviewers already did that)
|
||||
- Make any file edits
|
||||
- Run tests or builds
|
||||
- Make judgments about code quality (post what reviewers found)
|
||||
|
||||
## Core Knowledge
|
||||
|
||||
### GitHub PR Comment API
|
||||
|
||||
**Inline review comments** (file/line-specific findings):
|
||||
|
||||
```bash
|
||||
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
|
||||
-f body="**[{category}]** {description}" \
|
||||
-f path="{file_path}" \
|
||||
-F line={line_number} \
|
||||
-f commit_id="$(gh pr view {pr_number} --json headRefOid -q .headRefOid)"
|
||||
```
|
||||
|
||||
- Use the HEAD commit of the PR for `commit_id`
|
||||
- Group multiple findings on the same line into a single comment
|
||||
|
||||
**Summary comments** (overall review):
|
||||
|
||||
```bash
|
||||
gh pr comment {pr_number} --body "{markdown_body}"
|
||||
```
|
||||
|
||||
- Use HEREDOC for multi-line bodies to avoid escaping issues
|
||||
|
||||
### PR Number Extraction
|
||||
|
||||
Extract PR number from task context using common patterns:
|
||||
- "PR #42", "#42", "pull/42", "pulls/42"
|
||||
- If no PR number is found, report this and finish without posting
|
||||
|
||||
## Comment Quality Principles
|
||||
|
||||
### Severity-Based Filtering
|
||||
|
||||
| Severity | Action |
|
||||
|----------|--------|
|
||||
| Critical / High | Always post as inline comment |
|
||||
| Medium | Post as inline comment |
|
||||
| Low | Include in summary only |
|
||||
| Informational | Include in summary only |
|
||||
|
||||
### Formatting
|
||||
|
||||
- **Be concise.** PR comments should be actionable and to the point
|
||||
- **Include location.** Always reference specific files and lines when available
|
||||
- **Categorize findings.** Use labels like `[Security]`, `[Architecture]`, `[AI Pattern]`
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If `gh` command fails, report the error but don't retry excessively
|
||||
- If PR number cannot be determined, output an informational message and complete
|
||||
- If no findings to post, post only the summary comment
|
||||
|
||||
## Important
|
||||
|
||||
- **Never modify files.** You only post comments.
|
||||
- **Respect rate limits.** Don't post too many individual comments; batch when possible.
|
||||
- **Use the review reports** as the source of truth for findings, not your own analysis.
|
||||
331
resources/global/en/workflows/review-only.yaml
Normal file
331
resources/global/en/workflows/review-only.yaml
Normal file
@ -0,0 +1,331 @@
|
||||
# Review-Only Workflow
|
||||
# Reviews code or PRs without making any edits
|
||||
# Local: console output only. PR specified: posts inline comments + summary to PR
|
||||
#
|
||||
# Flow:
|
||||
# plan -> reviewers (parallel: arch-review + security-review + ai-review) -> supervise
|
||||
# -> pr-comment -> COMPLETE (PR comment requested)
|
||||
# -> COMPLETE (local: console output only)
|
||||
# -> ABORT (rejected)
|
||||
#
|
||||
# All steps have edit: false (no file modifications)
|
||||
#
|
||||
# Template Variables:
|
||||
# {iteration} - Workflow-wide turn count
|
||||
# {max_iterations} - Maximum iterations allowed
|
||||
# {step_iteration} - Per-step iteration count
|
||||
# {task} - Original user request
|
||||
# {previous_response} - Output from the previous step
|
||||
# {user_inputs} - Accumulated user inputs
|
||||
# {report_dir} - Report directory name
|
||||
|
||||
name: review-only
|
||||
description: Review-only workflow - reviews code without making edits
|
||||
|
||||
max_iterations: 10
|
||||
|
||||
initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ../agents/default/planner.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: Review scope is clear
|
||||
next: reviewers
|
||||
- condition: User is asking a question (not a review task)
|
||||
next: COMPLETE
|
||||
- condition: Requirements unclear, insufficient info
|
||||
next: ABORT
|
||||
appendix: |
|
||||
Clarifications needed:
|
||||
- {Question 1}
|
||||
- {Question 2}
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## Previous Response (when returned from supervise)
|
||||
{previous_response}
|
||||
|
||||
Analyze the review request and create a review plan.
|
||||
|
||||
**This is a review-only workflow.** No code edits will be made.
|
||||
Focus on:
|
||||
1. Identify which files/modules to review
|
||||
2. Determine review focus areas (architecture, security, AI patterns, etc.)
|
||||
3. Note any specific concerns mentioned in the request
|
||||
|
||||
**If a PR number is mentioned** (e.g., "PR #42"), include it in your plan
|
||||
so reviewers can focus on the PR's changed files.
|
||||
|
||||
- name: reviewers
|
||||
parallel:
|
||||
- name: arch-review
|
||||
edit: false
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 01-architect-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# Architecture Review
|
||||
|
||||
## Result: APPROVE / IMPROVE / REJECT
|
||||
|
||||
## Summary
|
||||
{1-2 sentences summarizing result}
|
||||
|
||||
## Reviewed Perspectives
|
||||
- [x] Structure & Design
|
||||
- [x] Code Quality
|
||||
- [x] Change Scope
|
||||
|
||||
## Issues (if REJECT)
|
||||
| # | Location | Issue | Fix |
|
||||
|---|----------|-------|-----|
|
||||
| 1 | `src/file.ts:42` | Issue description | Fix method |
|
||||
|
||||
## Improvement Suggestions (optional, non-blocking)
|
||||
- {Future improvement suggestions}
|
||||
```
|
||||
|
||||
**Cognitive load reduction rules:**
|
||||
- APPROVE + no issues -> Summary only (5 lines or less)
|
||||
- APPROVE + minor suggestions -> Summary + suggestions (15 lines or less)
|
||||
- REJECT -> Issues in table format (30 lines or less)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
Focus on **architecture and design** review. Do NOT review AI-specific issues (that's the ai_review step).
|
||||
|
||||
Review the code and provide feedback.
|
||||
|
||||
- name: security-review
|
||||
edit: false
|
||||
agent: ../agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 02-security-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# Security Review
|
||||
|
||||
## Result: APPROVE / REJECT
|
||||
|
||||
## Severity: None / Low / Medium / High / Critical
|
||||
|
||||
## Check Results
|
||||
| Category | Result | Notes |
|
||||
|----------|--------|-------|
|
||||
| Injection | - | - |
|
||||
| Auth/Authz | - | - |
|
||||
| Data Protection | - | - |
|
||||
| Dependencies | - | - |
|
||||
|
||||
## Vulnerabilities (if REJECT)
|
||||
| # | Severity | Type | Location | Fix |
|
||||
|---|----------|------|----------|-----|
|
||||
| 1 | High | SQLi | `src/db.ts:42` | Use parameterized query |
|
||||
|
||||
## Warnings (non-blocking)
|
||||
- {Security recommendations}
|
||||
```
|
||||
|
||||
**Cognitive load reduction rules:**
|
||||
- No issues -> Check table only (10 lines or less)
|
||||
- Warnings -> + Warnings 1-2 lines (15 lines or less)
|
||||
- Vulnerabilities -> + Table format (30 lines or less)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
Perform security review on the code. Check for vulnerabilities including:
|
||||
- Injection attacks (SQL, Command, XSS)
|
||||
- Authentication/Authorization issues
|
||||
- Data exposure risks
|
||||
- Cryptographic weaknesses
|
||||
|
||||
- name: ai-review
|
||||
edit: false
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# AI-Generated Code Review
|
||||
|
||||
## Result: APPROVE / REJECT
|
||||
|
||||
## Summary
|
||||
{One sentence summarizing result}
|
||||
|
||||
## Verified Items
|
||||
| Aspect | Result | Notes |
|
||||
|--------|--------|-------|
|
||||
| Assumption validity | - | - |
|
||||
| API/Library existence | - | - |
|
||||
| Context fit | - | - |
|
||||
| Scope | - | - |
|
||||
|
||||
## Issues (if REJECT)
|
||||
| # | Category | Location | Issue |
|
||||
|---|----------|----------|-------|
|
||||
| 1 | Hallucinated API | `src/file.ts:23` | Non-existent method |
|
||||
```
|
||||
|
||||
**Cognitive load reduction rules:**
|
||||
- No issues -> Summary 1 line + check table only (10 lines or less)
|
||||
- Issues found -> + Issues in table format (25 lines or less)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
Review the code for AI-specific issues:
|
||||
- Assumption validation
|
||||
- Plausible but wrong patterns
|
||||
- Context fit with existing codebase
|
||||
- Scope creep detection
|
||||
rules:
|
||||
- condition: all("approved")
|
||||
next: supervise
|
||||
- condition: any("needs_fix")
|
||||
next: supervise
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Review Summary: 04-review-summary.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved, PR comment requested
|
||||
next: pr-comment
|
||||
- condition: approved
|
||||
next: COMPLETE
|
||||
- condition: rejected
|
||||
next: ABORT
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## Review Results
|
||||
{previous_response}
|
||||
|
||||
**This is a review-only workflow.** Do NOT run tests or builds.
|
||||
Your role is to synthesize the review results and produce a final summary.
|
||||
|
||||
**Tasks:**
|
||||
1. Read all review reports in the Report Directory
|
||||
2. Synthesize findings from architecture, security, and AI reviews
|
||||
3. Produce a consolidated review summary with overall verdict
|
||||
4. Determine routing:
|
||||
- If the task mentions posting to a PR (e.g., "post comments to PR", "comment on PR"),
|
||||
route to `pr-comment` step (condition: "approved, PR comment requested")
|
||||
- If local review only, route to COMPLETE (condition: "approved")
|
||||
- If critical issues found, route to ABORT (condition: "rejected")
|
||||
|
||||
**Review Summary report format:**
|
||||
```markdown
|
||||
# Review Summary
|
||||
|
||||
## Overall Verdict: APPROVE / REJECT
|
||||
|
||||
## Summary
|
||||
{2-3 sentences consolidating all review results}
|
||||
|
||||
## Review Results
|
||||
| Review | Result | Key Findings |
|
||||
|--------|--------|--------------|
|
||||
| Architecture | APPROVE/REJECT | {Brief finding} |
|
||||
| Security | APPROVE/REJECT | {Brief finding} |
|
||||
| AI Antipattern | APPROVE/REJECT | {Brief finding} |
|
||||
|
||||
## Issues Requiring Attention
|
||||
| # | Severity | Source | Location | Issue |
|
||||
|---|----------|--------|----------|-------|
|
||||
| 1 | High | Security | `file:line` | Description |
|
||||
|
||||
## Improvement Suggestions
|
||||
- {Consolidated suggestions from all reviews}
|
||||
```
|
||||
|
||||
- name: pr-comment
|
||||
edit: false
|
||||
agent: ../agents/review/pr-commenter.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Bash
|
||||
rules:
|
||||
- condition: Comments posted
|
||||
next: COMPLETE
|
||||
- condition: Failed to post comments
|
||||
next: COMPLETE
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## Review Summary
|
||||
{previous_response}
|
||||
|
||||
Post the review results to the PR as comments.
|
||||
|
||||
**Procedure:**
|
||||
1. Extract the PR number from the task description
|
||||
2. Read all review reports in the Report Directory:
|
||||
- `01-architect-review.md` (Architecture review)
|
||||
- `02-security-review.md` (Security review)
|
||||
- `03-ai-review.md` (AI antipattern review)
|
||||
- `04-review-summary.md` (Consolidated summary)
|
||||
3. Filter findings by severity and post inline comments for Critical/High/Medium
|
||||
4. Post a summary comment with the following format:
|
||||
|
||||
```
|
||||
## Automated Review Summary
|
||||
|
||||
{Overall verdict and summary from 04-review-summary.md}
|
||||
|
||||
### Review Results
|
||||
| Review | Result |
|
||||
|--------|--------|
|
||||
| Architecture | {result} |
|
||||
| Security | {result} |
|
||||
| AI Antipattern | {result} |
|
||||
|
||||
### Key Findings
|
||||
{Bulleted list of important findings}
|
||||
|
||||
### Improvement Suggestions
|
||||
{Consolidated suggestions}
|
||||
|
||||
---
|
||||
*Generated by [takt](https://github.com/toruticas/takt) review-only workflow*
|
||||
```
|
||||
75
resources/global/ja/agents/review/pr-commenter.md
Normal file
75
resources/global/ja/agents/review/pr-commenter.md
Normal file
@ -0,0 +1,75 @@
|
||||
# PR Commenter Agent
|
||||
|
||||
あなたは**PRコメント投稿の専門家**です。`gh` CLIを使用してレビューの指摘をGitHub Pull Requestに投稿します。
|
||||
|
||||
## 役割
|
||||
|
||||
- レビューの指摘をPRコメントとして投稿
|
||||
- 開発者向けに指摘を明確かつ簡潔にフォーマット
|
||||
- 重要度によるフィルタリングでノイズを削減
|
||||
|
||||
**やらないこと:**
|
||||
- 自分でコードをレビューする(レビュアーが既に実施済み)
|
||||
- ファイルの編集
|
||||
- テストやビルドの実行
|
||||
- コード品質の判断(レビュアーの結果をそのまま投稿する)
|
||||
|
||||
## コア知識
|
||||
|
||||
### GitHub PR Comment API
|
||||
|
||||
**インラインレビューコメント**(ファイル・行番号ごとの指摘):
|
||||
|
||||
```bash
|
||||
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
|
||||
-f body="**[{category}]** {description}" \
|
||||
-f path="{file_path}" \
|
||||
-F line={line_number} \
|
||||
-f commit_id="$(gh pr view {pr_number} --json headRefOid -q .headRefOid)"
|
||||
```
|
||||
|
||||
- `commit_id` にはPRのHEADコミットを使用
|
||||
- 同一行に複数の指摘がある場合は1つのコメントにまとめる
|
||||
|
||||
**サマリーコメント**(全体レビュー):
|
||||
|
||||
```bash
|
||||
gh pr comment {pr_number} --body "{markdown_body}"
|
||||
```
|
||||
|
||||
- 複数行のbodyにはHEREDOCを使用してエスケープ問題を回避
|
||||
|
||||
### PR番号の抽出
|
||||
|
||||
タスクコンテキストから一般的なパターンでPR番号を抽出:
|
||||
- "PR #42"、"#42"、"pull/42"、"pulls/42"
|
||||
- PR番号が見つからない場合は報告して投稿せずに終了
|
||||
|
||||
## コメント品質の原則
|
||||
|
||||
### 重要度ベースのフィルタリング
|
||||
|
||||
| 重大度 | アクション |
|
||||
|--------|-----------|
|
||||
| Critical / High | 必ずインラインコメントとして投稿 |
|
||||
| Medium | インラインコメントとして投稿 |
|
||||
| Low | サマリーにのみ含める |
|
||||
| Informational | サマリーにのみ含める |
|
||||
|
||||
### フォーマット
|
||||
|
||||
- **簡潔に。** PRコメントはアクション可能で要点を押さえたものにする
|
||||
- **場所を含める。** 可能な限り具体的なファイルと行番号を参照
|
||||
- **指摘を分類する。** `[Security]`、`[Architecture]`、`[AI Pattern]` のようなラベルを使用
|
||||
|
||||
## エラーハンドリング
|
||||
|
||||
- `gh` コマンドが失敗した場合はエラーを報告するが、過度にリトライしない
|
||||
- PR番号が特定できない場合は情報メッセージを出力して完了
|
||||
- 投稿する指摘がない場合はサマリーコメントのみ投稿
|
||||
|
||||
## 重要
|
||||
|
||||
- **ファイルを変更しない。** コメント投稿のみ行う。
|
||||
- **レート制限を尊重。** 個別コメントを大量投稿しない。可能な限りまとめる。
|
||||
- **レビューレポートを情報源とする。** 自分の分析ではなく、レビュアーの結果を投稿する。
|
||||
332
resources/global/ja/workflows/review-only.yaml
Normal file
332
resources/global/ja/workflows/review-only.yaml
Normal file
@ -0,0 +1,332 @@
|
||||
# レビュー専用ワークフロー
|
||||
# コードやPRをレビューするだけで編集は行わない
|
||||
# ローカル: コンソール出力のみ。PR指定時: PRにインラインコメント+サマリを投稿
|
||||
#
|
||||
# フロー:
|
||||
# plan -> reviewers (parallel: arch-review + security-review + ai-review) -> supervise
|
||||
# -> pr-comment -> COMPLETE (PRコメント要求時)
|
||||
# -> COMPLETE (ローカル: コンソール出力のみ)
|
||||
# -> ABORT (rejected)
|
||||
#
|
||||
# 全ステップ edit: false(ファイル変更なし)
|
||||
#
|
||||
# テンプレート変数:
|
||||
# {iteration} - ワークフロー全体のターン数
|
||||
# {max_iterations} - 最大イテレーション数
|
||||
# {step_iteration} - ステップごとのイテレーション数
|
||||
# {task} - 元のユーザー要求
|
||||
# {previous_response} - 前のステップの出力
|
||||
# {user_inputs} - 蓄積されたユーザー入力
|
||||
# {report_dir} - レポートディレクトリ名
|
||||
|
||||
name: review-only
|
||||
description: レビュー専用ワークフロー - コードをレビューするだけで編集は行わない
|
||||
|
||||
max_iterations: 10
|
||||
|
||||
initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ../agents/default/planner.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: レビュー対象が明確
|
||||
next: reviewers
|
||||
- condition: ユーザーが質問をしている(レビュータスクではない)
|
||||
next: COMPLETE
|
||||
- condition: 要件が不明確、情報不足
|
||||
next: ABORT
|
||||
appendix: |
|
||||
確認事項:
|
||||
- {質問1}
|
||||
- {質問2}
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## Previous Response (superviseからの差し戻し時)
|
||||
{previous_response}
|
||||
|
||||
レビュー依頼を分析し、レビュー方針を立ててください。
|
||||
|
||||
**これはレビュー専用ワークフローです。** コード編集は行いません。
|
||||
以下に集中してください:
|
||||
1. レビュー対象のファイル/モジュールを特定
|
||||
2. レビューの重点領域を決定(アーキテクチャ、セキュリティ、AIパターン等)
|
||||
3. 依頼に記載された特定の懸念事項を整理
|
||||
|
||||
**PR番号が記載されている場合**(例: "PR #42")、レビュアーが
|
||||
PRの変更ファイルに集中できるよう計画に含めてください。
|
||||
|
||||
- name: reviewers
|
||||
parallel:
|
||||
- name: arch-review
|
||||
edit: false
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 01-architect-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# アーキテクチャレビュー
|
||||
|
||||
## 結果: APPROVE / IMPROVE / REJECT
|
||||
|
||||
## サマリー
|
||||
{1-2文で結果を要約}
|
||||
|
||||
## 確認した観点
|
||||
- [x] 構造・設計
|
||||
- [x] コード品質
|
||||
- [x] 変更スコープ
|
||||
|
||||
## 問題点(REJECTの場合)
|
||||
| # | 場所 | 問題 | 修正案 |
|
||||
|---|------|------|--------|
|
||||
| 1 | `src/file.ts:42` | 問題の説明 | 修正方法 |
|
||||
|
||||
## 改善提案(任意・ブロッキングではない)
|
||||
- {将来的な改善提案}
|
||||
```
|
||||
|
||||
**認知負荷軽減ルール:**
|
||||
- APPROVE + 問題なし → サマリーのみ(5行以内)
|
||||
- APPROVE + 軽微な提案 → サマリー + 改善提案(15行以内)
|
||||
- REJECT → 問題点を表形式で(30行以内)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
**アーキテクチャと設計**のレビューに集中してください。AI特有の問題はレビューしないでください(ai_reviewステップで行います)。
|
||||
|
||||
コードをレビューしてフィードバックを提供してください。
|
||||
|
||||
- name: security-review
|
||||
edit: false
|
||||
agent: ../agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 02-security-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# セキュリティレビュー
|
||||
|
||||
## 結果: APPROVE / REJECT
|
||||
|
||||
## 重大度: None / Low / Medium / High / Critical
|
||||
|
||||
## チェック結果
|
||||
| カテゴリ | 結果 | 備考 |
|
||||
|---------|------|------|
|
||||
| インジェクション | - | - |
|
||||
| 認証・認可 | - | - |
|
||||
| データ保護 | - | - |
|
||||
| 依存関係 | - | - |
|
||||
|
||||
## 脆弱性(REJECTの場合)
|
||||
| # | 重大度 | 種類 | 場所 | 修正案 |
|
||||
|---|--------|------|------|--------|
|
||||
| 1 | High | SQLi | `src/db.ts:42` | パラメータ化クエリを使用 |
|
||||
|
||||
## 警告(ブロッキングではない)
|
||||
- {セキュリティに関する推奨事項}
|
||||
```
|
||||
|
||||
**認知負荷軽減ルール:**
|
||||
- 問題なし → チェック表のみ(10行以内)
|
||||
- 警告あり → + 警告を1-2行(15行以内)
|
||||
- 脆弱性あり → + 表形式で(30行以内)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
コードに対してセキュリティレビューを行ってください。以下の脆弱性を確認してください:
|
||||
- インジェクション攻撃(SQL, コマンド, XSS)
|
||||
- 認証・認可の問題
|
||||
- データ露出リスク
|
||||
- 暗号化の弱点
|
||||
|
||||
- name: ai-review
|
||||
edit: false
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
```markdown
|
||||
# AI生成コードレビュー
|
||||
|
||||
## 結果: APPROVE / REJECT
|
||||
|
||||
## サマリー
|
||||
{1文で結果を要約}
|
||||
|
||||
## 検証した項目
|
||||
| 観点 | 結果 | 備考 |
|
||||
|------|------|------|
|
||||
| 仮定の妥当性 | - | - |
|
||||
| API/ライブラリの実在 | - | - |
|
||||
| コンテキスト適合 | - | - |
|
||||
| スコープ | - | - |
|
||||
|
||||
## 問題点(REJECTの場合)
|
||||
| # | カテゴリ | 場所 | 問題 |
|
||||
|---|---------|------|------|
|
||||
| 1 | 幻覚API | `src/file.ts:23` | 存在しないメソッド |
|
||||
```
|
||||
|
||||
**認知負荷軽減ルール:**
|
||||
- 問題なし → サマリー1文 + チェック表のみ(10行以内)
|
||||
- 問題あり → + 問題を表形式で(25行以内)
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved
|
||||
- condition: needs_fix
|
||||
instruction_template: |
|
||||
AI特有の問題についてコードをレビューしてください:
|
||||
- 仮定の検証
|
||||
- もっともらしいが間違っているパターン
|
||||
- 既存コードベースとの適合性
|
||||
- スコープクリープの検出
|
||||
rules:
|
||||
- condition: all("approved")
|
||||
next: supervise
|
||||
- condition: any("needs_fix")
|
||||
next: supervise
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Review Summary: 04-review-summary.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
rules:
|
||||
- condition: approved, PR comment requested
|
||||
next: pr-comment
|
||||
- condition: approved
|
||||
next: COMPLETE
|
||||
- condition: rejected
|
||||
next: ABORT
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## レビュー結果
|
||||
{previous_response}
|
||||
|
||||
**これはレビュー専用ワークフローです。** テスト実行やビルドは行わないでください。
|
||||
レビュー結果を統合し、最終サマリーを作成する役割です。
|
||||
|
||||
**やること:**
|
||||
1. Report Directory内の全レビューレポートを読む
|
||||
2. アーキテクチャ・セキュリティ・AIレビューの結果を統合
|
||||
3. 統合レビューサマリーと総合判定を作成
|
||||
4. ルーティング判断:
|
||||
- タスクにPRへのコメント投稿が含まれている場合
|
||||
(例: "PRにコメントして"、"PRにレビュー結果を投稿")
|
||||
→ `pr-comment` ステップへ(condition: "approved, PR comment requested")
|
||||
- ローカルレビューのみ → COMPLETE(condition: "approved")
|
||||
- 重大な問題が見つかった場合 → ABORT(condition: "rejected")
|
||||
|
||||
**Review Summaryレポートフォーマット:**
|
||||
```markdown
|
||||
# レビューサマリー
|
||||
|
||||
## 総合判定: APPROVE / REJECT
|
||||
|
||||
## サマリー
|
||||
{2-3文で全レビュー結果を統合}
|
||||
|
||||
## レビュー結果
|
||||
| レビュー | 結果 | 主要な発見 |
|
||||
|---------|------|-----------|
|
||||
| アーキテクチャ | APPROVE/REJECT | {概要} |
|
||||
| セキュリティ | APPROVE/REJECT | {概要} |
|
||||
| AIアンチパターン | APPROVE/REJECT | {概要} |
|
||||
|
||||
## 要注意の問題
|
||||
| # | 重大度 | ソース | 場所 | 問題 |
|
||||
|---|--------|--------|------|------|
|
||||
| 1 | High | セキュリティ | `file:line` | 説明 |
|
||||
|
||||
## 改善提案
|
||||
- {全レビューからの統合提案}
|
||||
```
|
||||
|
||||
- name: pr-comment
|
||||
edit: false
|
||||
agent: ../agents/review/pr-commenter.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Bash
|
||||
rules:
|
||||
- condition: コメント投稿完了
|
||||
next: COMPLETE
|
||||
- condition: コメント投稿失敗
|
||||
next: COMPLETE
|
||||
pass_previous_response: true
|
||||
instruction_template: |
|
||||
## レビューサマリー
|
||||
{previous_response}
|
||||
|
||||
レビュー結果をPRにコメントとして投稿してください。
|
||||
|
||||
**手順:**
|
||||
1. タスク説明からPR番号を抽出
|
||||
2. Report Directory内の全レビューレポートを読む:
|
||||
- `01-architect-review.md`(アーキテクチャレビュー)
|
||||
- `02-security-review.md`(セキュリティレビュー)
|
||||
- `03-ai-review.md`(AIアンチパターンレビュー)
|
||||
- `04-review-summary.md`(統合サマリー)
|
||||
3. 重要度でフィルタリングし、Critical/High/Mediumの指摘をインラインコメントとして投稿
|
||||
4. 以下のフォーマットでサマリーコメントを投稿:
|
||||
|
||||
```
|
||||
## 自動レビューサマリー
|
||||
|
||||
{04-review-summary.mdからの総合判定とサマリー}
|
||||
|
||||
### レビュー結果
|
||||
| レビュー | 結果 |
|
||||
|---------|------|
|
||||
| アーキテクチャ | {結果} |
|
||||
| セキュリティ | {結果} |
|
||||
| AIアンチパターン | {結果} |
|
||||
|
||||
### 主要な発見
|
||||
{重要な指摘のリスト}
|
||||
|
||||
### 改善提案
|
||||
{統合された提案}
|
||||
|
||||
---
|
||||
*[takt](https://github.com/toruticas/takt) review-only ワークフローで生成*
|
||||
```
|
||||
250
src/__tests__/review-only-workflow.test.ts
Normal file
250
src/__tests__/review-only-workflow.test.ts
Normal file
@ -0,0 +1,250 @@
|
||||
/**
|
||||
* Tests for review-only workflow
|
||||
*
|
||||
* Covers:
|
||||
* - Workflow YAML files (EN/JA) load and pass schema validation
|
||||
* - Workflow structure: plan -> reviewers (parallel) -> supervise -> pr-comment
|
||||
* - All steps have edit: false
|
||||
* - pr-commenter agent has Bash in allowed_tools
|
||||
* - Routing rules for local vs PR comment flows
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
import { WorkflowConfigRawSchema } from '../models/schemas.js';
|
||||
|
||||
const RESOURCES_DIR = join(import.meta.dirname, '../../resources/global');
|
||||
|
||||
function loadReviewOnlyYaml(lang: 'en' | 'ja') {
|
||||
const filePath = join(RESOURCES_DIR, lang, 'workflows', 'review-only.yaml');
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
return parseYaml(content);
|
||||
}
|
||||
|
||||
describe('review-only workflow (EN)', () => {
|
||||
const raw = loadReviewOnlyYaml('en');
|
||||
|
||||
it('should pass schema validation', () => {
|
||||
const result = WorkflowConfigRawSchema.safeParse(raw);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should have correct name and initial_step', () => {
|
||||
expect(raw.name).toBe('review-only');
|
||||
expect(raw.initial_step).toBe('plan');
|
||||
});
|
||||
|
||||
it('should have max_iterations of 10', () => {
|
||||
expect(raw.max_iterations).toBe(10);
|
||||
});
|
||||
|
||||
it('should have 4 steps: plan, reviewers, supervise, pr-comment', () => {
|
||||
const stepNames = raw.steps.map((s: { name: string }) => s.name);
|
||||
expect(stepNames).toEqual(['plan', 'reviewers', 'supervise', 'pr-comment']);
|
||||
});
|
||||
|
||||
it('should have all steps with edit: false', () => {
|
||||
for (const step of raw.steps) {
|
||||
if (step.edit !== undefined) {
|
||||
expect(step.edit).toBe(false);
|
||||
}
|
||||
if (step.parallel) {
|
||||
for (const sub of step.parallel) {
|
||||
if (sub.edit !== undefined) {
|
||||
expect(sub.edit).toBe(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should have reviewers step with 3 parallel sub-steps', () => {
|
||||
const reviewers = raw.steps.find((s: { name: string }) => s.name === 'reviewers');
|
||||
expect(reviewers).toBeDefined();
|
||||
expect(reviewers.parallel).toHaveLength(3);
|
||||
|
||||
const subNames = reviewers.parallel.map((s: { name: string }) => s.name);
|
||||
expect(subNames).toEqual(['arch-review', 'security-review', 'ai-review']);
|
||||
});
|
||||
|
||||
it('should have reviewers step with aggregate rules', () => {
|
||||
const reviewers = raw.steps.find((s: { name: string }) => s.name === 'reviewers');
|
||||
expect(reviewers.rules).toHaveLength(2);
|
||||
expect(reviewers.rules[0].condition).toBe('all("approved")');
|
||||
expect(reviewers.rules[0].next).toBe('supervise');
|
||||
expect(reviewers.rules[1].condition).toBe('any("needs_fix")');
|
||||
expect(reviewers.rules[1].next).toBe('supervise');
|
||||
});
|
||||
|
||||
it('should have supervise step with routing rules for local and PR flows', () => {
|
||||
const supervise = raw.steps.find((s: { name: string }) => s.name === 'supervise');
|
||||
expect(supervise.rules).toHaveLength(3);
|
||||
|
||||
const conditions = supervise.rules.map((r: { condition: string }) => r.condition);
|
||||
expect(conditions).toContain('approved, PR comment requested');
|
||||
expect(conditions).toContain('approved');
|
||||
expect(conditions).toContain('rejected');
|
||||
|
||||
const prRule = supervise.rules.find((r: { condition: string }) => r.condition === 'approved, PR comment requested');
|
||||
expect(prRule.next).toBe('pr-comment');
|
||||
|
||||
const localRule = supervise.rules.find((r: { condition: string }) => r.condition === 'approved');
|
||||
expect(localRule.next).toBe('COMPLETE');
|
||||
|
||||
const rejectRule = supervise.rules.find((r: { condition: string }) => r.condition === 'rejected');
|
||||
expect(rejectRule.next).toBe('ABORT');
|
||||
});
|
||||
|
||||
it('should have pr-comment step with Bash in allowed_tools', () => {
|
||||
const prComment = raw.steps.find((s: { name: string }) => s.name === 'pr-comment');
|
||||
expect(prComment).toBeDefined();
|
||||
expect(prComment.allowed_tools).toContain('Bash');
|
||||
});
|
||||
|
||||
it('should have pr-comment step using pr-commenter agent', () => {
|
||||
const prComment = raw.steps.find((s: { name: string }) => s.name === 'pr-comment');
|
||||
expect(prComment.agent).toContain('review/pr-commenter.md');
|
||||
});
|
||||
|
||||
it('should have plan step reusing default planner agent', () => {
|
||||
const plan = raw.steps.find((s: { name: string }) => s.name === 'plan');
|
||||
expect(plan.agent).toContain('default/planner.md');
|
||||
});
|
||||
|
||||
it('should have supervise step reusing default supervisor agent', () => {
|
||||
const supervise = raw.steps.find((s: { name: string }) => s.name === 'supervise');
|
||||
expect(supervise.agent).toContain('default/supervisor.md');
|
||||
});
|
||||
|
||||
it('should not have any step with edit: true', () => {
|
||||
for (const step of raw.steps) {
|
||||
expect(step.edit).not.toBe(true);
|
||||
if (step.parallel) {
|
||||
for (const sub of step.parallel) {
|
||||
expect(sub.edit).not.toBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('reviewer sub-steps should not have Bash in allowed_tools', () => {
|
||||
const reviewers = raw.steps.find((s: { name: string }) => s.name === 'reviewers');
|
||||
for (const sub of reviewers.parallel) {
|
||||
expect(sub.allowed_tools).not.toContain('Bash');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('review-only workflow (JA)', () => {
|
||||
const raw = loadReviewOnlyYaml('ja');
|
||||
|
||||
it('should pass schema validation', () => {
|
||||
const result = WorkflowConfigRawSchema.safeParse(raw);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should have correct name and initial_step', () => {
|
||||
expect(raw.name).toBe('review-only');
|
||||
expect(raw.initial_step).toBe('plan');
|
||||
});
|
||||
|
||||
it('should have same step structure as EN version', () => {
|
||||
const stepNames = raw.steps.map((s: { name: string }) => s.name);
|
||||
expect(stepNames).toEqual(['plan', 'reviewers', 'supervise', 'pr-comment']);
|
||||
});
|
||||
|
||||
it('should have reviewers step with 3 parallel sub-steps', () => {
|
||||
const reviewers = raw.steps.find((s: { name: string }) => s.name === 'reviewers');
|
||||
expect(reviewers.parallel).toHaveLength(3);
|
||||
|
||||
const subNames = reviewers.parallel.map((s: { name: string }) => s.name);
|
||||
expect(subNames).toEqual(['arch-review', 'security-review', 'ai-review']);
|
||||
});
|
||||
|
||||
it('should have all steps with edit: false or undefined', () => {
|
||||
for (const step of raw.steps) {
|
||||
expect(step.edit).not.toBe(true);
|
||||
if (step.parallel) {
|
||||
for (const sub of step.parallel) {
|
||||
expect(sub.edit).not.toBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should have pr-comment step with Bash in allowed_tools', () => {
|
||||
const prComment = raw.steps.find((s: { name: string }) => s.name === 'pr-comment');
|
||||
expect(prComment.allowed_tools).toContain('Bash');
|
||||
});
|
||||
|
||||
it('should have same aggregate rules on reviewers', () => {
|
||||
const reviewers = raw.steps.find((s: { name: string }) => s.name === 'reviewers');
|
||||
expect(reviewers.rules[0].condition).toBe('all("approved")');
|
||||
expect(reviewers.rules[1].condition).toBe('any("needs_fix")');
|
||||
});
|
||||
});
|
||||
|
||||
describe('pr-commenter agent files', () => {
|
||||
it('should exist for EN with domain knowledge', () => {
|
||||
const filePath = join(RESOURCES_DIR, 'en', 'agents', 'review', 'pr-commenter.md');
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
expect(content).toContain('PR Commenter');
|
||||
expect(content).toContain('gh api');
|
||||
expect(content).toContain('gh pr comment');
|
||||
});
|
||||
|
||||
it('should exist for JA with domain knowledge', () => {
|
||||
const filePath = join(RESOURCES_DIR, 'ja', 'agents', 'review', 'pr-commenter.md');
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
expect(content).toContain('PR Commenter');
|
||||
expect(content).toContain('gh api');
|
||||
expect(content).toContain('gh pr comment');
|
||||
});
|
||||
|
||||
it('should NOT contain workflow-specific report names (EN)', () => {
|
||||
const filePath = join(RESOURCES_DIR, 'en', 'agents', 'review', 'pr-commenter.md');
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
// Agent should not reference specific review-only workflow report files
|
||||
expect(content).not.toContain('01-architect-review.md');
|
||||
expect(content).not.toContain('02-security-review.md');
|
||||
expect(content).not.toContain('03-ai-review.md');
|
||||
expect(content).not.toContain('04-review-summary.md');
|
||||
// Agent should not reference specific reviewer names from review-only workflow
|
||||
expect(content).not.toContain('Architecture review report');
|
||||
expect(content).not.toContain('Security review report');
|
||||
expect(content).not.toContain('AI antipattern review report');
|
||||
});
|
||||
|
||||
it('should NOT contain workflow-specific report names (JA)', () => {
|
||||
const filePath = join(RESOURCES_DIR, 'ja', 'agents', 'review', 'pr-commenter.md');
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
expect(content).not.toContain('01-architect-review.md');
|
||||
expect(content).not.toContain('02-security-review.md');
|
||||
expect(content).not.toContain('03-ai-review.md');
|
||||
expect(content).not.toContain('04-review-summary.md');
|
||||
});
|
||||
});
|
||||
|
||||
describe('pr-comment instruction_template contains workflow-specific procedures', () => {
|
||||
it('EN: should reference specific report files', () => {
|
||||
const raw = loadReviewOnlyYaml('en');
|
||||
const prComment = raw.steps.find((s: { name: string }) => s.name === 'pr-comment');
|
||||
const template = prComment.instruction_template;
|
||||
expect(template).toContain('01-architect-review.md');
|
||||
expect(template).toContain('02-security-review.md');
|
||||
expect(template).toContain('03-ai-review.md');
|
||||
expect(template).toContain('04-review-summary.md');
|
||||
});
|
||||
|
||||
it('JA: should reference specific report files', () => {
|
||||
const raw = loadReviewOnlyYaml('ja');
|
||||
const prComment = raw.steps.find((s: { name: string }) => s.name === 'pr-comment');
|
||||
const template = prComment.instruction_template;
|
||||
expect(template).toContain('01-architect-review.md');
|
||||
expect(template).toContain('02-security-review.md');
|
||||
expect(template).toContain('03-ai-review.md');
|
||||
expect(template).toContain('04-review-summary.md');
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user