diff --git a/CLAUDE.md b/CLAUDE.md index 8fdcc0b..b146b5e 100644 --- a/CLAUDE.md +++ b/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. diff --git a/resources/global/en/agents/review/pr-commenter.md b/resources/global/en/agents/review/pr-commenter.md new file mode 100644 index 0000000..e2317d7 --- /dev/null +++ b/resources/global/en/agents/review/pr-commenter.md @@ -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. diff --git a/resources/global/en/workflows/review-only.yaml b/resources/global/en/workflows/review-only.yaml new file mode 100644 index 0000000..cfe566b --- /dev/null +++ b/resources/global/en/workflows/review-only.yaml @@ -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* + ``` diff --git a/resources/global/ja/agents/review/pr-commenter.md b/resources/global/ja/agents/review/pr-commenter.md new file mode 100644 index 0000000..be339f2 --- /dev/null +++ b/resources/global/ja/agents/review/pr-commenter.md @@ -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番号が特定できない場合は情報メッセージを出力して完了 +- 投稿する指摘がない場合はサマリーコメントのみ投稿 + +## 重要 + +- **ファイルを変更しない。** コメント投稿のみ行う。 +- **レート制限を尊重。** 個別コメントを大量投稿しない。可能な限りまとめる。 +- **レビューレポートを情報源とする。** 自分の分析ではなく、レビュアーの結果を投稿する。 diff --git a/resources/global/ja/workflows/review-only.yaml b/resources/global/ja/workflows/review-only.yaml new file mode 100644 index 0000000..14e78b3 --- /dev/null +++ b/resources/global/ja/workflows/review-only.yaml @@ -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 ワークフローで生成* + ``` diff --git a/src/__tests__/review-only-workflow.test.ts b/src/__tests__/review-only-workflow.test.ts new file mode 100644 index 0000000..617c790 --- /dev/null +++ b/src/__tests__/review-only-workflow.test.ts @@ -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'); + }); +});