mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
feat(review): add Cursor CLI self-detection and complete REVIEWS.md template (#1960)
Add CURSOR_SESSION_ID env var detection in review.md so Cursor skips itself as a reviewer (matching the CLAUDE_CODE_ENTRYPOINT pattern). Add Qwen Review and Cursor Review sections to the REVIEWS.md template. Update ja-JP and ko-KR FEATURES.md to include --opencode, --qwen, and --cursor flags in the /gsd-review command signature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1049,9 +1049,9 @@ fix(03-01): correct auth token expiry
|
|||||||
|
|
||||||
### 42. クロス AI ピアレビュー
|
### 42. クロス AI ピアレビュー
|
||||||
|
|
||||||
**コマンド:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--all]`
|
**コマンド:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--all]`
|
||||||
|
|
||||||
**目的:** 外部の AI CLI(Gemini、Claude、Codex、CodeRabbit)を呼び出して、フェーズプランを独立してレビューします。レビュアーごとのフィードバックを含む構造化された REVIEWS.md を生成します。
|
**目的:** 外部の AI CLI(Gemini、Claude、Codex、CodeRabbit、OpenCode、Qwen Code、Cursor)を呼び出して、フェーズプランを独立してレビューします。レビュアーごとのフィードバックを含む構造化された REVIEWS.md を生成します。
|
||||||
|
|
||||||
**要件:**
|
**要件:**
|
||||||
- REQ-REVIEW-01: システムはシステム上で利用可能な AI CLI を検出しなければならない
|
- REQ-REVIEW-01: システムはシステム上で利用可能な AI CLI を検出しなければならない
|
||||||
|
|||||||
@@ -1049,9 +1049,9 @@ fix(03-01): correct auth token expiry
|
|||||||
|
|
||||||
### 42. Cross-AI Peer Review
|
### 42. Cross-AI Peer Review
|
||||||
|
|
||||||
**명령어:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--all]`
|
**명령어:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--all]`
|
||||||
|
|
||||||
**목적:** 외부 AI CLI(Gemini, Claude, Codex, CodeRabbit)를 호출하여 페이즈 계획을 독립적으로 검토합니다. 검토자별 피드백이 담긴 구조화된 REVIEWS.md를 생성합니다.
|
**목적:** 외부 AI CLI(Gemini, Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor)를 호출하여 페이즈 계획을 독립적으로 검토합니다. 검토자별 피드백이 담긴 구조화된 REVIEWS.md를 생성합니다.
|
||||||
|
|
||||||
**요구사항.**
|
**요구사항.**
|
||||||
- REQ-REVIEW-01: 시스템에서 사용 가능한 AI CLI를 감지해야 합니다.
|
- REQ-REVIEW-01: 시스템에서 사용 가능한 AI CLI를 감지해야 합니다.
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ Determine which CLI to skip based on the current runtime environment:
|
|||||||
if [ "$ANTIGRAVITY_AGENT" = "1" ]; then
|
if [ "$ANTIGRAVITY_AGENT" = "1" ]; then
|
||||||
# Antigravity is a separate client — all CLIs are external, skip none
|
# Antigravity is a separate client — all CLIs are external, skip none
|
||||||
SELF_CLI="none"
|
SELF_CLI="none"
|
||||||
|
elif [ -n "$CURSOR_SESSION_ID" ]; then
|
||||||
|
# Running inside Cursor agent — skip cursor for independence
|
||||||
|
SELF_CLI="cursor"
|
||||||
elif [ -n "$CLAUDE_CODE_ENTRYPOINT" ]; then
|
elif [ -n "$CLAUDE_CODE_ENTRYPOINT" ]; then
|
||||||
# Running inside Claude Code CLI — skip claude for independence
|
# Running inside Claude Code CLI — skip claude for independence
|
||||||
SELF_CLI="claude"
|
SELF_CLI="claude"
|
||||||
@@ -275,6 +278,18 @@ plans_reviewed: [{list of PLAN.md files}]
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Qwen Review
|
||||||
|
|
||||||
|
{qwen review content}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cursor Review
|
||||||
|
|
||||||
|
{cursor review content}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Consensus Summary
|
## Consensus Summary
|
||||||
|
|
||||||
{synthesize common concerns across all reviewers}
|
{synthesize common concerns across all reviewers}
|
||||||
|
|||||||
222
tests/cursor-reviewer.test.cjs
Normal file
222
tests/cursor-reviewer.test.cjs
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/**
|
||||||
|
* Cursor CLI Reviewer Tests (#1960)
|
||||||
|
*
|
||||||
|
* Verifies that /gsd-review includes Cursor CLI as a peer reviewer:
|
||||||
|
* - review.md workflow contains cursor detection, flag parsing, self-detection, invocation
|
||||||
|
* - commands/gsd/review.md command file mentions --cursor flag
|
||||||
|
* - help.md lists --cursor in the /gsd-review signature
|
||||||
|
* - docs/COMMANDS.md has --cursor flag row
|
||||||
|
* - docs/FEATURES.md has Cursor in the review section
|
||||||
|
* - i18n docs mirror the same content
|
||||||
|
* - REVIEWS.md template includes Cursor Review section
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { test, describe } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const ROOT = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
describe('Cursor CLI reviewer in /gsd-review (#1960)', () => {
|
||||||
|
|
||||||
|
// --- review.md workflow ---
|
||||||
|
|
||||||
|
describe('review.md workflow', () => {
|
||||||
|
const reviewPath = path.join(ROOT, 'get-shit-done', 'workflows', 'review.md');
|
||||||
|
let content;
|
||||||
|
|
||||||
|
test('review.md exists', () => {
|
||||||
|
assert.ok(fs.existsSync(reviewPath), 'review.md should exist');
|
||||||
|
content = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('contains cursor CLI detection via command -v', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('command -v cursor'),
|
||||||
|
'review.md should detect cursor CLI via "command -v cursor"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('contains --cursor flag parsing', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'review.md should parse --cursor flag'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('contains CURSOR_SESSION_ID self-detection', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('CURSOR_SESSION_ID'),
|
||||||
|
'review.md should detect self-CLI via CURSOR_SESSION_ID env var'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('contains cursor agent invocation command', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('cursor agent -p --mode ask --trust'),
|
||||||
|
'review.md should invoke cursor via "cursor agent -p --mode ask --trust"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('contains Cursor Review section in REVIEWS.md template', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('Cursor Review'),
|
||||||
|
'review.md should include a "Cursor Review" section in the REVIEWS.md template'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('lists cursor in the reviewers frontmatter array', () => {
|
||||||
|
const c = fs.readFileSync(reviewPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
/reviewers:.*cursor/.test(c),
|
||||||
|
'review.md should list cursor in the reviewers array'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- commands/gsd/review.md ---
|
||||||
|
|
||||||
|
describe('commands/gsd/review.md', () => {
|
||||||
|
const cmdPath = path.join(ROOT, 'commands', 'gsd', 'review.md');
|
||||||
|
|
||||||
|
test('mentions --cursor flag', () => {
|
||||||
|
const c = fs.readFileSync(cmdPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'commands/gsd/review.md should mention --cursor flag'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mentions Cursor in objective or context', () => {
|
||||||
|
const c = fs.readFileSync(cmdPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('Cursor'),
|
||||||
|
'commands/gsd/review.md should mention Cursor'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- help.md ---
|
||||||
|
|
||||||
|
describe('help.md', () => {
|
||||||
|
const helpPath = path.join(ROOT, 'get-shit-done', 'workflows', 'help.md');
|
||||||
|
|
||||||
|
test('lists --cursor in /gsd-review signature', () => {
|
||||||
|
const c = fs.readFileSync(helpPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'help.md should list --cursor in the /gsd-review command signature'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- docs/COMMANDS.md ---
|
||||||
|
|
||||||
|
describe('docs/COMMANDS.md', () => {
|
||||||
|
const docsPath = path.join(ROOT, 'docs', 'COMMANDS.md');
|
||||||
|
|
||||||
|
test('has --cursor flag row', () => {
|
||||||
|
const c = fs.readFileSync(docsPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/COMMANDS.md should have a --cursor flag row'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- docs/FEATURES.md ---
|
||||||
|
|
||||||
|
describe('docs/FEATURES.md', () => {
|
||||||
|
const featPath = path.join(ROOT, 'docs', 'FEATURES.md');
|
||||||
|
|
||||||
|
test('has --cursor in review command signature', () => {
|
||||||
|
const c = fs.readFileSync(featPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/FEATURES.md should include --cursor in the review command signature'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mentions Cursor in the review purpose', () => {
|
||||||
|
const c = fs.readFileSync(featPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('Cursor'),
|
||||||
|
'docs/FEATURES.md should mention Cursor in the review section'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- i18n: ja-JP ---
|
||||||
|
|
||||||
|
describe('docs/ja-JP/COMMANDS.md', () => {
|
||||||
|
const jaPath = path.join(ROOT, 'docs', 'ja-JP', 'COMMANDS.md');
|
||||||
|
|
||||||
|
test('has --cursor flag row', () => {
|
||||||
|
const c = fs.readFileSync(jaPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/ja-JP/COMMANDS.md should have a --cursor flag row'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('docs/ja-JP/FEATURES.md', () => {
|
||||||
|
const jaPath = path.join(ROOT, 'docs', 'ja-JP', 'FEATURES.md');
|
||||||
|
|
||||||
|
test('has --cursor in review command signature', () => {
|
||||||
|
const c = fs.readFileSync(jaPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/ja-JP/FEATURES.md should include --cursor in the review command signature'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mentions Cursor in the review section', () => {
|
||||||
|
const c = fs.readFileSync(jaPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
/Cursor/i.test(fs.readFileSync(jaPath, 'utf-8')),
|
||||||
|
'docs/ja-JP/FEATURES.md should mention Cursor in the review section'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- i18n: ko-KR ---
|
||||||
|
|
||||||
|
describe('docs/ko-KR/COMMANDS.md', () => {
|
||||||
|
const koPath = path.join(ROOT, 'docs', 'ko-KR', 'COMMANDS.md');
|
||||||
|
|
||||||
|
test('has --cursor flag row', () => {
|
||||||
|
const c = fs.readFileSync(koPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/ko-KR/COMMANDS.md should have a --cursor flag row'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('docs/ko-KR/FEATURES.md', () => {
|
||||||
|
const koPath = path.join(ROOT, 'docs', 'ko-KR', 'FEATURES.md');
|
||||||
|
|
||||||
|
test('has --cursor in review command signature', () => {
|
||||||
|
const c = fs.readFileSync(koPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
c.includes('--cursor'),
|
||||||
|
'docs/ko-KR/FEATURES.md should include --cursor in the review command signature'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mentions Cursor in the review section', () => {
|
||||||
|
const c = fs.readFileSync(koPath, 'utf-8');
|
||||||
|
assert.ok(
|
||||||
|
/Cursor/i.test(fs.readFileSync(koPath, 'utf-8')),
|
||||||
|
'docs/ko-KR/FEATURES.md should mention Cursor in the review section'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user