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 ピアレビュー
|
||||
|
||||
**コマンド:** `/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 を検出しなければならない
|
||||
|
||||
@@ -1049,9 +1049,9 @@ fix(03-01): correct auth token expiry
|
||||
|
||||
### 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를 감지해야 합니다.
|
||||
|
||||
@@ -56,6 +56,9 @@ Determine which CLI to skip based on the current runtime environment:
|
||||
if [ "$ANTIGRAVITY_AGENT" = "1" ]; then
|
||||
# Antigravity is a separate client — all CLIs are external, skip 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
|
||||
# Running inside Claude Code CLI — skip claude for independence
|
||||
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
|
||||
|
||||
{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