cc-reviewer 2.1.0 → 3.0.0
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/README.md +15 -35
- package/commands/{codex-xhigh.md → codex-xhigh-review.md} +3 -3
- package/commands/{multi.md → multi-review.md} +1 -1
- package/dist/adapters/base.d.ts +1 -36
- package/dist/adapters/codex.d.ts +1 -2
- package/dist/adapters/codex.js +6 -45
- package/dist/adapters/gemini.d.ts +1 -2
- package/dist/adapters/gemini.js +4 -43
- package/dist/commands.d.ts +2 -3
- package/dist/commands.js +33 -11
- package/dist/handoff.d.ts +0 -14
- package/dist/handoff.js +0 -32
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -22
- package/dist/schema.d.ts +0 -189
- package/dist/schema.js +0 -189
- package/dist/tools/feedback.js +5 -5
- package/dist/types.d.ts +0 -1
- package/package.json +2 -3
- package/commands/ask-codex.md +0 -36
- package/commands/ask-gemini.md +0 -35
- package/commands/ask-multi.md +0 -39
- package/dist/setup.d.ts +0 -7
- package/dist/setup.js +0 -27
- package/dist/tools/peer.d.ts +0 -192
- package/dist/tools/peer.js +0 -264
- /package/commands/{codex.md → codex-review.md} +0 -0
- /package/commands/{gemini.md → gemini-review.md} +0 -0
package/README.md
CHANGED
|
@@ -11,11 +11,11 @@ claude mcp add -s user cc-reviewer -- npx -y cc-reviewer
|
|
|
11
11
|
|
|
12
12
|
**Step 2: Restart Claude Code**
|
|
13
13
|
|
|
14
|
-
The MCP tools and slash commands (`/codex`, `/gemini`, `/multi
|
|
14
|
+
The MCP tools and slash commands (`/codex-review`, `/gemini-review`, `/multi-review`) are automatically installed.
|
|
15
15
|
|
|
16
16
|
**Manual command install** (if needed):
|
|
17
17
|
```bash
|
|
18
|
-
npx cc-reviewer
|
|
18
|
+
npx cc-reviewer update
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Verify with:
|
|
@@ -52,14 +52,10 @@ gemini # follow auth prompts
|
|
|
52
52
|
These tools provide **external second-opinion reviews** from Codex and Gemini CLIs. They are designed to complement Claude Code's native review capabilities, not replace them.
|
|
53
53
|
|
|
54
54
|
**Review tools** (external second-opinion on your work):
|
|
55
|
-
- `/codex` or "review with codex" - Get external Codex review
|
|
56
|
-
- `/
|
|
57
|
-
- `/
|
|
58
|
-
|
|
59
|
-
**Ask tools** (get help from a peer engineer):
|
|
60
|
-
- `/ask-codex` - Ask Codex for help (planning, debugging, explaining, fixing)
|
|
61
|
-
- `/ask-gemini` - Ask Gemini for help (architecture, patterns, scalability)
|
|
62
|
-
- `/ask-multi` - Ask both models in parallel
|
|
55
|
+
- `/codex-review` or "review with codex" - Get external Codex review
|
|
56
|
+
- `/codex-xhigh-review` - Deep-thinking Codex review with xhigh reasoning
|
|
57
|
+
- `/gemini-review` or "review with gemini" - Get external Gemini review
|
|
58
|
+
- `/multi-review` - Get parallel reviews from both CLIs
|
|
63
59
|
|
|
64
60
|
**For regular reviews:** Just say "review" and Claude Code will use its native capabilities. These external tools are only invoked when explicitly requested.
|
|
65
61
|
|
|
@@ -68,24 +64,18 @@ These tools provide **external second-opinion reviews** from Codex and Gemini CL
|
|
|
68
64
|
These commands are available after restart:
|
|
69
65
|
|
|
70
66
|
```bash
|
|
71
|
-
# Review
|
|
72
|
-
/codex
|
|
73
|
-
/codex
|
|
74
|
-
/
|
|
75
|
-
/gemini
|
|
76
|
-
/
|
|
77
|
-
/multi # Both models in parallel
|
|
78
|
-
|
|
79
|
-
# Ask tools (peer engineer)
|
|
80
|
-
/ask-codex # Ask Codex for help
|
|
81
|
-
/ask-gemini # Ask Gemini for help
|
|
82
|
-
/ask-multi # Ask both in parallel
|
|
67
|
+
/codex-review # Review with Codex
|
|
68
|
+
/codex-review security # Focus on security
|
|
69
|
+
/codex-xhigh-review # Codex with xhigh reasoning effort
|
|
70
|
+
/gemini-review # Review with Gemini
|
|
71
|
+
/gemini-review architecture # Focus on architecture
|
|
72
|
+
/multi-review # Both models in parallel
|
|
83
73
|
```
|
|
84
74
|
|
|
85
75
|
## How It Works
|
|
86
76
|
|
|
87
77
|
```
|
|
88
|
-
CC does work → User: /codex → External CLI reviews → CC synthesizes → Updated output
|
|
78
|
+
CC does work → User: /codex-review → External CLI reviews → CC synthesizes → Updated output
|
|
89
79
|
```
|
|
90
80
|
|
|
91
81
|
**Key Principles:**
|
|
@@ -108,33 +98,23 @@ CC does work → User: /codex → External CLI reviews → CC synthesizes → Up
|
|
|
108
98
|
|
|
109
99
|
## MCP Tools
|
|
110
100
|
|
|
111
|
-
The plugin exposes
|
|
101
|
+
The plugin exposes three MCP tools:
|
|
112
102
|
|
|
113
103
|
| Tool | Description |
|
|
114
104
|
|------|-------------|
|
|
115
105
|
| `codex_review` | Get Codex review (correctness, edge cases, performance) |
|
|
116
106
|
| `gemini_review` | Get Gemini review (design patterns, scalability, tech debt) |
|
|
117
107
|
| `multi_review` | Parallel review from both models |
|
|
118
|
-
| `ask_codex` | Ask Codex for help (planning, debugging, explaining, fixing) |
|
|
119
|
-
| `ask_gemini` | Ask Gemini for help (architecture, patterns, scalability) |
|
|
120
|
-
| `ask_multi` | Ask both models in parallel |
|
|
121
108
|
|
|
122
109
|
## Output Format
|
|
123
110
|
|
|
124
|
-
**Review tools** return structured
|
|
111
|
+
**Review tools** return structured feedback from the external CLIs. Claude Code parses this feedback to identify:
|
|
125
112
|
- **Findings**: Issues with severity, confidence, location, and suggestions
|
|
126
113
|
- **Agreements**: Validations of CC's correct assessments
|
|
127
114
|
- **Disagreements**: Challenges to CC's claims with corrections
|
|
128
115
|
- **Alternatives**: Different approaches with tradeoffs
|
|
129
116
|
- **Risk Assessment**: Overall risk level with top concerns
|
|
130
117
|
|
|
131
|
-
**Ask tools** return structured JSON responses with:
|
|
132
|
-
- **Answer**: Main response text (markdown)
|
|
133
|
-
- **Key Points**: Bullet summary of main points
|
|
134
|
-
- **Suggested Actions**: Recommended actions with priority and rationale
|
|
135
|
-
- **File References**: Files examined with line ranges and relevance
|
|
136
|
-
- **Alternatives**: Alternative approaches considered
|
|
137
|
-
|
|
138
118
|
## Development
|
|
139
119
|
|
|
140
120
|
```bash
|
|
@@ -17,10 +17,10 @@ Use the `codex_review` MCP tool with `reasoningEffort: "xhigh"` for deeper analy
|
|
|
17
17
|
2. Call the `codex_review` tool with:
|
|
18
18
|
- `workingDir`: current working directory
|
|
19
19
|
- `ccOutput`: brief summary of recent changes or context
|
|
20
|
-
- `reasoningEffort`: "xhigh" (this is the key difference from /codex)
|
|
20
|
+
- `reasoningEffort`: "xhigh" (this is the key difference from /codex-review)
|
|
21
21
|
- `serviceTier`: if user says "fast mode"/"fast"/"priority" → "fast"; if "flex"/"cheap"/"budget" → "flex"; otherwise omit
|
|
22
|
-
- `
|
|
23
|
-
- `
|
|
22
|
+
- `focusAreas`: extracted from $ARGUMENTS if it's a known focus area
|
|
23
|
+
- `customPrompt`: $ARGUMENTS if it's custom text
|
|
24
24
|
|
|
25
25
|
3. After receiving feedback - VALIDATE before accepting:
|
|
26
26
|
|
|
@@ -7,7 +7,7 @@ Get parallel reviews from both Codex and Gemini, raw output for manual synthesis
|
|
|
7
7
|
|
|
8
8
|
## When to Use
|
|
9
9
|
|
|
10
|
-
Use `/multi` when you want parallel reviews from both Codex and Gemini.
|
|
10
|
+
Use `/multi-review` when you want parallel reviews from both Codex and Gemini.
|
|
11
11
|
|
|
12
12
|
## Before Calling - PREPARE THE HANDOFF
|
|
13
13
|
|
package/dist/adapters/base.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Makes it easy to add new models (Ollama, Azure, etc.) without
|
|
6
6
|
* changing the core orchestration logic.
|
|
7
7
|
*/
|
|
8
|
-
import { FocusArea, OutputType, ReasoningEffort, ServiceTier
|
|
8
|
+
import { FocusArea, OutputType, ReasoningEffort, ServiceTier } from '../types.js';
|
|
9
9
|
export interface ReviewerCapabilities {
|
|
10
10
|
/** Display name for this reviewer */
|
|
11
11
|
name: string;
|
|
@@ -54,26 +54,6 @@ export interface ExpertRole {
|
|
|
54
54
|
export declare const EXPERT_ROLES: Record<string, ExpertRole>;
|
|
55
55
|
/** @deprecated Use handoff.ts selectRole() instead */
|
|
56
56
|
export declare function selectExpertRole(focusAreas?: FocusArea[]): ExpertRole;
|
|
57
|
-
export interface PeerRequest {
|
|
58
|
-
/** Working directory containing the code */
|
|
59
|
-
workingDir: string;
|
|
60
|
-
/** The question or request from CC */
|
|
61
|
-
prompt: string;
|
|
62
|
-
/** Hint about the type of task */
|
|
63
|
-
taskType?: TaskType;
|
|
64
|
-
/** Files the peer should focus on */
|
|
65
|
-
relevantFiles?: string[];
|
|
66
|
-
/** Additional context (error messages, prior analysis) */
|
|
67
|
-
context?: string;
|
|
68
|
-
/** Areas to focus on */
|
|
69
|
-
focusAreas?: FocusArea[];
|
|
70
|
-
/** Custom instructions from the user */
|
|
71
|
-
customPrompt?: string;
|
|
72
|
-
/** Reasoning effort level (for models that support it) */
|
|
73
|
-
reasoningEffort?: ReasoningEffort;
|
|
74
|
-
/** Service tier (for models that support it: priority = fast, flex = cheap) */
|
|
75
|
-
serviceTier?: ServiceTier;
|
|
76
|
-
}
|
|
77
57
|
export interface ReviewSuccess {
|
|
78
58
|
success: true;
|
|
79
59
|
output: string;
|
|
@@ -92,19 +72,6 @@ export interface ReviewError {
|
|
|
92
72
|
message: string;
|
|
93
73
|
details?: Record<string, unknown>;
|
|
94
74
|
}
|
|
95
|
-
export interface PeerSuccess {
|
|
96
|
-
success: true;
|
|
97
|
-
output: string;
|
|
98
|
-
executionTimeMs: number;
|
|
99
|
-
}
|
|
100
|
-
export interface PeerFailure {
|
|
101
|
-
success: false;
|
|
102
|
-
error: ReviewError;
|
|
103
|
-
suggestion?: string;
|
|
104
|
-
rawOutput?: string;
|
|
105
|
-
executionTimeMs: number;
|
|
106
|
-
}
|
|
107
|
-
export type PeerResult = PeerSuccess | PeerFailure;
|
|
108
75
|
/**
|
|
109
76
|
* Base interface that all reviewer adapters must implement.
|
|
110
77
|
* This allows easy addition of new AI CLIs without changing orchestration logic.
|
|
@@ -118,8 +85,6 @@ export interface ReviewerAdapter {
|
|
|
118
85
|
isAvailable(): Promise<boolean>;
|
|
119
86
|
/** Run a review and return structured output */
|
|
120
87
|
runReview(request: ReviewRequest): Promise<ReviewResult>;
|
|
121
|
-
/** Run a general-purpose peer request and return structured output */
|
|
122
|
-
runPeerRequest(request: PeerRequest): Promise<PeerResult>;
|
|
123
88
|
/**
|
|
124
89
|
* Optional: Run peer review of another model's output
|
|
125
90
|
* Future capability - not currently implemented by any adapter
|
package/dist/adapters/codex.d.ts
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* Returns raw text — no JSON parsing or schema enforcement.
|
|
6
6
|
* CC handles interpretation of the reviewer's response.
|
|
7
7
|
*/
|
|
8
|
-
import { ReviewerAdapter, ReviewerCapabilities, ReviewRequest, ReviewResult
|
|
8
|
+
import { ReviewerAdapter, ReviewerCapabilities, ReviewRequest, ReviewResult } from './base.js';
|
|
9
9
|
export declare class CodexAdapter implements ReviewerAdapter {
|
|
10
10
|
readonly id = "codex";
|
|
11
11
|
getCapabilities(): ReviewerCapabilities;
|
|
12
12
|
isAvailable(): Promise<boolean>;
|
|
13
13
|
runReview(request: ReviewRequest): Promise<ReviewResult>;
|
|
14
|
-
runPeerRequest(request: PeerRequest): Promise<PeerResult>;
|
|
15
14
|
private runCli;
|
|
16
15
|
private handleException;
|
|
17
16
|
private categorizeError;
|
package/dist/adapters/codex.js
CHANGED
|
@@ -10,7 +10,7 @@ import { existsSync } from 'fs';
|
|
|
10
10
|
import { registerAdapter, } from './base.js';
|
|
11
11
|
import { CliExecutor } from '../executor.js';
|
|
12
12
|
import { CodexEventDecoder } from '../decoders/index.js';
|
|
13
|
-
import { buildSimpleHandoff, buildHandoffPrompt,
|
|
13
|
+
import { buildSimpleHandoff, buildHandoffPrompt, selectRole, } from '../handoff.js';
|
|
14
14
|
// =============================================================================
|
|
15
15
|
// CONFIGURATION
|
|
16
16
|
// =============================================================================
|
|
@@ -70,46 +70,7 @@ export class CodexAdapter {
|
|
|
70
70
|
return {
|
|
71
71
|
success: false,
|
|
72
72
|
error: { type: 'cli_error', message: 'Codex returned empty response' },
|
|
73
|
-
suggestion: 'Try again or use /gemini instead',
|
|
74
|
-
executionTimeMs: Date.now() - startTime,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return { success: true, output: result.stdout, executionTimeMs: Date.now() - startTime };
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
return this.handleException(error, startTime);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async runPeerRequest(request) {
|
|
84
|
-
const startTime = Date.now();
|
|
85
|
-
if (!existsSync(request.workingDir)) {
|
|
86
|
-
return {
|
|
87
|
-
success: false,
|
|
88
|
-
error: { type: 'cli_error', message: `Working directory does not exist: ${request.workingDir}` },
|
|
89
|
-
suggestion: 'Check that the working directory path is correct',
|
|
90
|
-
executionTimeMs: Date.now() - startTime,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
try {
|
|
94
|
-
const prompt = buildPeerPrompt({
|
|
95
|
-
workingDir: request.workingDir,
|
|
96
|
-
prompt: request.prompt,
|
|
97
|
-
taskType: request.taskType,
|
|
98
|
-
relevantFiles: request.relevantFiles,
|
|
99
|
-
context: request.context,
|
|
100
|
-
focusAreas: request.focusAreas,
|
|
101
|
-
customInstructions: request.customPrompt,
|
|
102
|
-
});
|
|
103
|
-
const result = await this.runCli(prompt, request.workingDir, request.reasoningEffort || 'high', request.serviceTier);
|
|
104
|
-
if (result.exitCode !== 0) {
|
|
105
|
-
const error = this.categorizeError(result.stderr);
|
|
106
|
-
return { success: false, error, suggestion: this.getSuggestion(error), executionTimeMs: Date.now() - startTime };
|
|
107
|
-
}
|
|
108
|
-
if (!result.stdout.trim()) {
|
|
109
|
-
return {
|
|
110
|
-
success: false,
|
|
111
|
-
error: { type: 'cli_error', message: 'Codex returned empty response' },
|
|
112
|
-
suggestion: 'Try again or use /ask-gemini instead',
|
|
73
|
+
suggestion: 'Try again or use /gemini-review instead',
|
|
113
74
|
executionTimeMs: Date.now() - startTime,
|
|
114
75
|
};
|
|
115
76
|
}
|
|
@@ -178,11 +139,11 @@ export class CodexAdapter {
|
|
|
178
139
|
const err = error;
|
|
179
140
|
if (err.code === 'ENOENT') {
|
|
180
141
|
return { success: false, error: { type: 'cli_not_found', message: 'Codex CLI not found' },
|
|
181
|
-
suggestion: 'Install with: npm install -g @openai/codex', executionTimeMs: Date.now() - startTime };
|
|
142
|
+
suggestion: 'Install with: npm install -g @openai/codex-cli', executionTimeMs: Date.now() - startTime };
|
|
182
143
|
}
|
|
183
144
|
if (err.message === 'TIMEOUT') {
|
|
184
145
|
return { success: false, error: { type: 'timeout', message: 'Codex timed out — no events received' },
|
|
185
|
-
suggestion: 'Try a smaller scope or use /gemini', executionTimeMs: Date.now() - startTime };
|
|
146
|
+
suggestion: 'Try a smaller scope or use /gemini-review', executionTimeMs: Date.now() - startTime };
|
|
186
147
|
}
|
|
187
148
|
if (err.message === 'MAX_TIMEOUT') {
|
|
188
149
|
return { success: false, error: { type: 'timeout', message: 'Task exceeded 60 minute maximum' },
|
|
@@ -205,9 +166,9 @@ export class CodexAdapter {
|
|
|
205
166
|
}
|
|
206
167
|
getSuggestion(error) {
|
|
207
168
|
switch (error.type) {
|
|
208
|
-
case 'rate_limit': return 'Wait and retry, or use /gemini instead';
|
|
169
|
+
case 'rate_limit': return 'Wait and retry, or use /gemini-review instead';
|
|
209
170
|
case 'auth_error': return 'Run `codex login` to authenticate';
|
|
210
|
-
case 'cli_not_found': return 'Install with: npm install -g @openai/codex';
|
|
171
|
+
case 'cli_not_found': return 'Install with: npm install -g @openai/codex-cli';
|
|
211
172
|
default: return 'Check the error message and try again';
|
|
212
173
|
}
|
|
213
174
|
}
|
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* Returns raw text — no JSON parsing or schema enforcement.
|
|
6
6
|
* CC handles interpretation of the reviewer's response.
|
|
7
7
|
*/
|
|
8
|
-
import { ReviewerAdapter, ReviewerCapabilities, ReviewRequest, ReviewResult
|
|
8
|
+
import { ReviewerAdapter, ReviewerCapabilities, ReviewRequest, ReviewResult } from './base.js';
|
|
9
9
|
export declare class GeminiAdapter implements ReviewerAdapter {
|
|
10
10
|
readonly id = "gemini";
|
|
11
11
|
getCapabilities(): ReviewerCapabilities;
|
|
12
12
|
isAvailable(): Promise<boolean>;
|
|
13
13
|
runReview(request: ReviewRequest): Promise<ReviewResult>;
|
|
14
|
-
runPeerRequest(request: PeerRequest): Promise<PeerResult>;
|
|
15
14
|
private runCli;
|
|
16
15
|
private handleException;
|
|
17
16
|
private categorizeError;
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -10,7 +10,7 @@ import { existsSync } from 'fs';
|
|
|
10
10
|
import { registerAdapter, } from './base.js';
|
|
11
11
|
import { CliExecutor } from '../executor.js';
|
|
12
12
|
import { GeminiEventDecoder } from '../decoders/index.js';
|
|
13
|
-
import { buildSimpleHandoff, buildHandoffPrompt,
|
|
13
|
+
import { buildSimpleHandoff, buildHandoffPrompt, selectRole, } from '../handoff.js';
|
|
14
14
|
// =============================================================================
|
|
15
15
|
// CONFIGURATION
|
|
16
16
|
// =============================================================================
|
|
@@ -67,46 +67,7 @@ export class GeminiAdapter {
|
|
|
67
67
|
return {
|
|
68
68
|
success: false,
|
|
69
69
|
error: { type: 'cli_error', message: 'Gemini returned empty response' },
|
|
70
|
-
suggestion: 'Try again or use /codex instead',
|
|
71
|
-
executionTimeMs: Date.now() - startTime,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
return { success: true, output: result.stdout, executionTimeMs: Date.now() - startTime };
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
return this.handleException(error, startTime);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
async runPeerRequest(request) {
|
|
81
|
-
const startTime = Date.now();
|
|
82
|
-
if (!existsSync(request.workingDir)) {
|
|
83
|
-
return {
|
|
84
|
-
success: false,
|
|
85
|
-
error: { type: 'cli_error', message: `Working directory does not exist: ${request.workingDir}` },
|
|
86
|
-
suggestion: 'Check that the working directory path is correct',
|
|
87
|
-
executionTimeMs: Date.now() - startTime,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
try {
|
|
91
|
-
const prompt = buildPeerPrompt({
|
|
92
|
-
workingDir: request.workingDir,
|
|
93
|
-
prompt: request.prompt,
|
|
94
|
-
taskType: request.taskType,
|
|
95
|
-
relevantFiles: request.relevantFiles,
|
|
96
|
-
context: request.context,
|
|
97
|
-
focusAreas: request.focusAreas,
|
|
98
|
-
customInstructions: request.customPrompt,
|
|
99
|
-
});
|
|
100
|
-
const result = await this.runCli(prompt, request.workingDir);
|
|
101
|
-
if (result.exitCode !== 0) {
|
|
102
|
-
const error = this.categorizeError(result.stderr);
|
|
103
|
-
return { success: false, error, suggestion: this.getSuggestion(error), executionTimeMs: Date.now() - startTime };
|
|
104
|
-
}
|
|
105
|
-
if (!result.stdout.trim()) {
|
|
106
|
-
return {
|
|
107
|
-
success: false,
|
|
108
|
-
error: { type: 'cli_error', message: 'Gemini returned empty response' },
|
|
109
|
-
suggestion: 'Try again or use /ask-codex instead',
|
|
70
|
+
suggestion: 'Try again or use /codex-review instead',
|
|
110
71
|
executionTimeMs: Date.now() - startTime,
|
|
111
72
|
};
|
|
112
73
|
}
|
|
@@ -162,7 +123,7 @@ export class GeminiAdapter {
|
|
|
162
123
|
}
|
|
163
124
|
if (err.message === 'TIMEOUT') {
|
|
164
125
|
return { success: false, error: { type: 'timeout', message: 'Gemini timed out — no events received' },
|
|
165
|
-
suggestion: 'Try a smaller scope or use /codex', executionTimeMs: Date.now() - startTime };
|
|
126
|
+
suggestion: 'Try a smaller scope or use /codex-review', executionTimeMs: Date.now() - startTime };
|
|
166
127
|
}
|
|
167
128
|
if (err.message === 'MAX_TIMEOUT') {
|
|
168
129
|
return { success: false, error: { type: 'timeout', message: 'Task exceeded 60 minute maximum' },
|
|
@@ -182,7 +143,7 @@ export class GeminiAdapter {
|
|
|
182
143
|
}
|
|
183
144
|
getSuggestion(error) {
|
|
184
145
|
switch (error.type) {
|
|
185
|
-
case 'rate_limit': return 'Wait and retry, or use /codex instead';
|
|
146
|
+
case 'rate_limit': return 'Wait and retry, or use /codex-review instead';
|
|
186
147
|
case 'auth_error': return 'Run `gemini` and follow auth prompts, or set GEMINI_API_KEY';
|
|
187
148
|
case 'cli_not_found': return 'Install with: npm install -g @google/gemini-cli';
|
|
188
149
|
default: return 'Check the error message and try again';
|
package/dist/commands.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared module for slash command installation
|
|
3
3
|
*
|
|
4
|
-
* Used by
|
|
5
|
-
* - setup.ts (manual CLI tool: npx cc-reviewer-setup)
|
|
6
|
-
* - index.ts (auto-install on MCP server startup)
|
|
4
|
+
* Used by index.ts (auto-install on MCP server startup and `update` subcommand)
|
|
7
5
|
*/
|
|
8
6
|
export interface InstallResult {
|
|
9
7
|
success: boolean;
|
|
10
8
|
installed: string[];
|
|
9
|
+
removed: string[];
|
|
11
10
|
error?: string;
|
|
12
11
|
}
|
|
13
12
|
/**
|
package/dist/commands.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared module for slash command installation
|
|
3
3
|
*
|
|
4
|
-
* Used by
|
|
5
|
-
* - setup.ts (manual CLI tool: npx cc-reviewer-setup)
|
|
6
|
-
* - index.ts (auto-install on MCP server startup)
|
|
4
|
+
* Used by index.ts (auto-install on MCP server startup and `update` subcommand)
|
|
7
5
|
*/
|
|
8
|
-
import { existsSync, mkdirSync, copyFileSync, readdirSync, statSync } from 'fs';
|
|
6
|
+
import { existsSync, mkdirSync, copyFileSync, readdirSync, statSync, unlinkSync } from 'fs';
|
|
9
7
|
import { join, dirname } from 'path';
|
|
10
8
|
import { homedir } from 'os';
|
|
11
9
|
import { fileURLToPath } from 'url';
|
|
12
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
11
|
const __dirname = dirname(__filename);
|
|
12
|
+
/** Old command filenames that should be pruned on upgrade */
|
|
13
|
+
const DEPRECATED_COMMANDS = [
|
|
14
|
+
'codex.md',
|
|
15
|
+
'gemini.md',
|
|
16
|
+
'multi.md',
|
|
17
|
+
'codex-xhigh.md',
|
|
18
|
+
'ask-codex.md',
|
|
19
|
+
'ask-gemini.md',
|
|
20
|
+
'ask-multi.md',
|
|
21
|
+
];
|
|
14
22
|
/**
|
|
15
23
|
* Get source and target paths for command files
|
|
16
24
|
*/
|
|
@@ -29,13 +37,13 @@ export function installCommands() {
|
|
|
29
37
|
const { source, target } = getCommandPaths();
|
|
30
38
|
// Check source exists
|
|
31
39
|
if (!existsSync(source)) {
|
|
32
|
-
return { success: false, installed: [], error: 'Commands directory not found' };
|
|
40
|
+
return { success: false, installed: [], removed: [], error: 'Commands directory not found' };
|
|
33
41
|
}
|
|
34
42
|
// Create target directory, handle errors (not a dir, permission denied)
|
|
35
43
|
try {
|
|
36
44
|
if (existsSync(target)) {
|
|
37
45
|
if (!statSync(target).isDirectory()) {
|
|
38
|
-
return { success: false, installed: [], error: `${target} exists but is not a directory` };
|
|
46
|
+
return { success: false, installed: [], removed: [], error: `${target} exists but is not a directory` };
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
else {
|
|
@@ -44,13 +52,27 @@ export function installCommands() {
|
|
|
44
52
|
}
|
|
45
53
|
catch (err) {
|
|
46
54
|
const msg = err instanceof Error ? err.message : String(err);
|
|
47
|
-
return { success: false, installed: [], error: `Cannot create target directory: ${msg}` };
|
|
55
|
+
return { success: false, installed: [], removed: [], error: `Cannot create target directory: ${msg}` };
|
|
48
56
|
}
|
|
49
57
|
const files = readdirSync(source).filter(f => f.endsWith('.md'));
|
|
50
58
|
if (files.length === 0) {
|
|
51
|
-
return { success: false, installed: [], error: 'No command files found' };
|
|
59
|
+
return { success: false, installed: [], removed: [], error: 'No command files found' };
|
|
52
60
|
}
|
|
53
|
-
//
|
|
61
|
+
// Prune deprecated commands from target
|
|
62
|
+
const removed = [];
|
|
63
|
+
for (const oldFile of DEPRECATED_COMMANDS) {
|
|
64
|
+
const oldPath = join(target, oldFile);
|
|
65
|
+
if (existsSync(oldPath)) {
|
|
66
|
+
try {
|
|
67
|
+
unlinkSync(oldPath);
|
|
68
|
+
removed.push(oldFile.replace('.md', ''));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Best-effort removal — don't fail the install
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Copy current files
|
|
54
76
|
const installed = [];
|
|
55
77
|
try {
|
|
56
78
|
for (const file of files) {
|
|
@@ -60,7 +82,7 @@ export function installCommands() {
|
|
|
60
82
|
}
|
|
61
83
|
catch (err) {
|
|
62
84
|
const msg = err instanceof Error ? err.message : String(err);
|
|
63
|
-
return { success: false, installed, error: `Copy failed: ${msg}` };
|
|
85
|
+
return { success: false, installed, removed, error: `Copy failed: ${msg}` };
|
|
64
86
|
}
|
|
65
|
-
return { success: true, installed };
|
|
87
|
+
return { success: true, installed, removed };
|
|
66
88
|
}
|
package/dist/handoff.d.ts
CHANGED
|
@@ -229,17 +229,3 @@ export declare function buildSimpleHandoff(workingDir: string, ccOutput: string,
|
|
|
229
229
|
* CC should call this to add its specific concerns
|
|
230
230
|
*/
|
|
231
231
|
export declare function enhanceHandoff(handoff: Handoff, uncertainties?: Uncertainty[], questions?: Question[], decisions?: Decision[]): Handoff;
|
|
232
|
-
export interface PeerPromptOptions {
|
|
233
|
-
workingDir: string;
|
|
234
|
-
prompt: string;
|
|
235
|
-
taskType?: string;
|
|
236
|
-
relevantFiles?: string[];
|
|
237
|
-
context?: string;
|
|
238
|
-
focusAreas?: FocusArea[];
|
|
239
|
-
customInstructions?: string;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Build a prompt for general-purpose peer assistance (not review).
|
|
243
|
-
* No output format constraints — peer responds naturally, CC interprets.
|
|
244
|
-
*/
|
|
245
|
-
export declare function buildPeerPrompt(options: PeerPromptOptions): string;
|
package/dist/handoff.js
CHANGED
|
@@ -227,35 +227,3 @@ export function enhanceHandoff(handoff, uncertainties, questions, decisions) {
|
|
|
227
227
|
decisions: decisions || handoff.decisions,
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Build a prompt for general-purpose peer assistance (not review).
|
|
232
|
-
* No output format constraints — peer responds naturally, CC interprets.
|
|
233
|
-
*/
|
|
234
|
-
export function buildPeerPrompt(options) {
|
|
235
|
-
const { workingDir, prompt, taskType, relevantFiles, context, focusAreas, customInstructions } = options;
|
|
236
|
-
const role = selectRole(focusAreas);
|
|
237
|
-
const sections = [];
|
|
238
|
-
// SECTION 1: ROLE
|
|
239
|
-
sections.push(`# ROLE: ${role.name} — Peer Engineer
|
|
240
|
-
|
|
241
|
-
${role.systemPrompt}
|
|
242
|
-
Be direct and actionable.`);
|
|
243
|
-
// SECTION 2: TASK
|
|
244
|
-
const taskLabel = taskType ? ` [${taskType.toUpperCase()}]` : '';
|
|
245
|
-
sections.push(`## YOUR TASK${taskLabel}
|
|
246
|
-
|
|
247
|
-
**Request:** ${prompt}${context ? `\n**Context:** ${context}` : ''}`);
|
|
248
|
-
// SECTION 3: RELEVANT FILES
|
|
249
|
-
if (relevantFiles && relevantFiles.length > 0) {
|
|
250
|
-
sections.push(`## RELEVANT FILES\n${relevantFiles.map(f => `- \`${f}\``).join('\n')}`);
|
|
251
|
-
}
|
|
252
|
-
// SECTION 4: FOCUS AREAS
|
|
253
|
-
if (focusAreas && focusAreas.length > 0) {
|
|
254
|
-
sections.push(`## FOCUS AREAS\n\n${focusAreas.join(', ')}`);
|
|
255
|
-
}
|
|
256
|
-
// SECTION 5: CUSTOM INSTRUCTIONS
|
|
257
|
-
if (customInstructions) {
|
|
258
|
-
sections.push(`## ADDITIONAL INSTRUCTIONS\n\n${customInstructions}`);
|
|
259
|
-
}
|
|
260
|
-
return sections.join('\n\n');
|
|
261
|
-
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -13,21 +13,31 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Usage:
|
|
15
15
|
* - npx cc-reviewer # Run MCP server (normal usage)
|
|
16
|
-
* - npx cc-reviewer
|
|
16
|
+
* - npx cc-reviewer update # Install/update slash commands
|
|
17
17
|
*/
|
|
18
18
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
19
19
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
20
20
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
21
21
|
import { handleCodexReview, handleGeminiReview, handleMultiReview, ReviewInputSchema, TOOL_DEFINITIONS } from './tools/feedback.js';
|
|
22
|
-
import { handleAskCodex, handleAskGemini, handleAskMulti, PEER_TOOL_DEFINITIONS, } from './tools/peer.js';
|
|
23
|
-
import { PeerInputSchema } from './schema.js';
|
|
24
22
|
import { logCliStatus } from './cli/check.js';
|
|
25
23
|
import { installCommands } from './commands.js';
|
|
26
|
-
//
|
|
27
|
-
|
|
24
|
+
// Read version from package.json
|
|
25
|
+
import { readFileSync } from 'fs';
|
|
26
|
+
import { join, dirname } from 'path';
|
|
27
|
+
import { fileURLToPath } from 'url';
|
|
28
|
+
const __pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
29
|
+
const __pkg = JSON.parse(readFileSync(__pkgPath, 'utf-8'));
|
|
30
|
+
const VERSION = __pkg.version;
|
|
31
|
+
// Handle subcommands
|
|
32
|
+
const subcommand = process.argv[2];
|
|
33
|
+
if (subcommand === 'update' || subcommand === '--setup' || subcommand === '--commands') {
|
|
28
34
|
const result = installCommands();
|
|
29
35
|
if (result.success) {
|
|
30
|
-
console.log(
|
|
36
|
+
console.log(`cc-reviewer v${VERSION}`);
|
|
37
|
+
if (result.removed.length > 0) {
|
|
38
|
+
console.log(`✓ Removed ${result.removed.length} deprecated commands: ${result.removed.map(c => `/${c}`).join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
console.log(`✓ Installed ${result.installed.length} slash commands: ${result.installed.map(c => `/${c}`).join(', ')}`);
|
|
31
41
|
process.exit(0);
|
|
32
42
|
}
|
|
33
43
|
else {
|
|
@@ -40,7 +50,7 @@ import './adapters/index.js';
|
|
|
40
50
|
// Create the MCP server
|
|
41
51
|
const server = new Server({
|
|
42
52
|
name: 'ai-reviewer',
|
|
43
|
-
version:
|
|
53
|
+
version: VERSION,
|
|
44
54
|
}, {
|
|
45
55
|
capabilities: {
|
|
46
56
|
tools: {},
|
|
@@ -53,9 +63,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
53
63
|
TOOL_DEFINITIONS.codex_review,
|
|
54
64
|
TOOL_DEFINITIONS.gemini_review,
|
|
55
65
|
TOOL_DEFINITIONS.multi_review,
|
|
56
|
-
PEER_TOOL_DEFINITIONS.ask_codex,
|
|
57
|
-
PEER_TOOL_DEFINITIONS.ask_gemini,
|
|
58
|
-
PEER_TOOL_DEFINITIONS.ask_multi,
|
|
59
66
|
],
|
|
60
67
|
};
|
|
61
68
|
});
|
|
@@ -76,18 +83,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
76
83
|
const input = ReviewInputSchema.parse(args);
|
|
77
84
|
return await handleMultiReview(input);
|
|
78
85
|
}
|
|
79
|
-
case 'ask_codex': {
|
|
80
|
-
const input = PeerInputSchema.parse(args);
|
|
81
|
-
return await handleAskCodex(input);
|
|
82
|
-
}
|
|
83
|
-
case 'ask_gemini': {
|
|
84
|
-
const input = PeerInputSchema.parse(args);
|
|
85
|
-
return await handleAskGemini(input);
|
|
86
|
-
}
|
|
87
|
-
case 'ask_multi': {
|
|
88
|
-
const input = PeerInputSchema.parse(args);
|
|
89
|
-
return await handleAskMulti(input);
|
|
90
|
-
}
|
|
91
86
|
default:
|
|
92
87
|
return {
|
|
93
88
|
content: [{
|