second-opinion-mcp 0.4.1 → 0.5.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 +64 -90
- package/dist/config.js +14 -1
- package/dist/context/bundler.d.ts +39 -1
- package/dist/context/bundler.js +431 -219
- package/dist/context/git.d.ts +17 -1
- package/dist/context/git.js +84 -1
- package/dist/output/consensus-formatter.js +28 -7
- package/dist/providers/base.d.ts +6 -1
- package/dist/providers/base.js +22 -16
- package/dist/providers/consensus.d.ts +1 -2
- package/dist/providers/consensus.js +5 -26
- package/dist/tools/review.js +2 -1
- package/dist/utils/tokens.d.ts +8 -0
- package/dist/utils/tokens.js +8 -0
- package/package.json +1 -1
- package/second-opinion.skill.md +9 -8
- package/templates/second-opinion.md +17 -1
package/README.md
CHANGED
|
@@ -21,14 +21,59 @@ Then in Claude Code:
|
|
|
21
21
|
|
|
22
22
|
That's it. The review appears in `second-opinions/`.
|
|
23
23
|
|
|
24
|
+
## How It Works
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ Claude Code │
|
|
29
|
+
│ │
|
|
30
|
+
│ You: "Add user authentication" │
|
|
31
|
+
│ Claude: [reads files, writes code, runs tests] │
|
|
32
|
+
│ You: "/second-opinion" │
|
|
33
|
+
│ │
|
|
34
|
+
└─────────────────────┬───────────────────────────────────────────┘
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
38
|
+
│ Second Opinion MCP │
|
|
39
|
+
│ │
|
|
40
|
+
│ 1. Parse Claude Code session logs │
|
|
41
|
+
│ 2. Collect files read/written + their content │
|
|
42
|
+
│ 3. Resolve dependencies and dependents │
|
|
43
|
+
│ 4. Find related tests and types │
|
|
44
|
+
│ 5. Collect branch diff (feature branch vs base) │
|
|
45
|
+
│ 6. Bundle within token budget │
|
|
46
|
+
│ 7. Send to Gemini + GPT (consensus mode) │
|
|
47
|
+
│ 8. Write response to second-opinions/ │
|
|
48
|
+
│ │
|
|
49
|
+
└─────────────────────┬───────────────────────────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
52
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ second-opinions/add-auth.consensus.review.md │
|
|
54
|
+
│ │
|
|
55
|
+
│ # Consensus Code Review │
|
|
56
|
+
│ │
|
|
57
|
+
│ ## Synthesis │
|
|
58
|
+
│ [Claude merges both perspectives with full context] │
|
|
59
|
+
│ │
|
|
60
|
+
│ ## Gemini's Review │
|
|
61
|
+
│ [BLOCKING] Missing rate limiting on login endpoint │
|
|
62
|
+
│ │
|
|
63
|
+
│ ## OpenAI's Review │
|
|
64
|
+
│ [SUGGESTION] Consider adding refresh token rotation │
|
|
65
|
+
│ │
|
|
66
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
67
|
+
```
|
|
68
|
+
|
|
24
69
|
## Features
|
|
25
70
|
|
|
26
71
|
### Automatic Context Collection
|
|
27
72
|
|
|
28
|
-
|
|
73
|
+
Your session is the context. Second Opinion reads it automatically:
|
|
29
74
|
|
|
30
75
|
- **Session files** — Files you read, edited, or created
|
|
31
|
-
- **Conversation** — What you asked Claude to do
|
|
76
|
+
- **Conversation** — What you asked Claude to do
|
|
32
77
|
- **Dependencies** — Files imported by your modified code
|
|
33
78
|
- **Dependents** — Files that import your modified code
|
|
34
79
|
- **Tests** — Test files related to your changes
|
|
@@ -47,44 +92,31 @@ Don't just get code reviews—ask for anything:
|
|
|
47
92
|
/second-opinion openai Identify potential performance bottlenecks
|
|
48
93
|
```
|
|
49
94
|
|
|
50
|
-
###
|
|
95
|
+
### Consensus & Providers
|
|
51
96
|
|
|
52
|
-
|
|
97
|
+
By default, Second Opinion calls both Gemini and OpenAI in parallel. Claude then synthesizes the findings using its full session context—merging agreements, surfacing unique insights, and resolving disagreements.
|
|
53
98
|
|
|
54
99
|
```
|
|
55
|
-
/second-opinion
|
|
56
|
-
/second-opinion gemini Review this
|
|
57
|
-
/second-opinion openai Review this
|
|
100
|
+
/second-opinion # Consensus (default) — both providers
|
|
101
|
+
/second-opinion gemini Review this # Gemini only
|
|
102
|
+
/second-opinion openai Review this # GPT only
|
|
58
103
|
```
|
|
59
104
|
|
|
60
|
-
|
|
105
|
+
Consensus mode:
|
|
106
|
+
- Calls both providers simultaneously
|
|
107
|
+
- Claude synthesizes findings using the unified review framework
|
|
108
|
+
- **Smart fallback**: if only one API key is configured, uses that single provider
|
|
61
109
|
|
|
62
|
-
|
|
110
|
+
### Diff-Scoped Reviews
|
|
63
111
|
|
|
64
|
-
|
|
65
|
-
/second-opinion consensus
|
|
66
|
-
```
|
|
112
|
+
On feature branches, Second Opinion automatically includes the git diff (branch vs base). Reviewers distinguish issues introduced by your changes from pre-existing issues in the codebase:
|
|
67
113
|
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
- Returns combined output with each model's perspective
|
|
71
|
-
- Highlights areas of agreement and differences
|
|
72
|
-
- **Smart fallback**: if only one API key is configured, automatically uses that single provider instead of failing
|
|
73
|
-
- Requires both `GEMINI_API_KEY` and `OPENAI_API_KEY` for true consensus; works with just one key via fallback
|
|
114
|
+
- **Findings** — Issues in the diff (your changes)
|
|
115
|
+
- **Pre-existing Issues** — Legitimate issues NOT introduced by this change (lower priority)
|
|
74
116
|
|
|
75
117
|
### Smart Token Budgeting
|
|
76
118
|
|
|
77
|
-
Context is prioritized to fit
|
|
78
|
-
|
|
79
|
-
1. Explicitly included files (highest priority)
|
|
80
|
-
2. Session files (what you worked on)
|
|
81
|
-
3. Git changes
|
|
82
|
-
4. Dependencies
|
|
83
|
-
5. Dependents
|
|
84
|
-
6. Tests
|
|
85
|
-
7. Type definitions
|
|
86
|
-
|
|
87
|
-
Files that don't fit are listed in the output so you know what was omitted.
|
|
119
|
+
Context is prioritized by category: explicitly included files first, then session files, git changes, dependencies, dependents, tests, and type definitions. Unused budget spills over to later categories. Files that don't fit are listed so you know what was omitted.
|
|
88
120
|
|
|
89
121
|
### Include Additional Files
|
|
90
122
|
|
|
@@ -130,21 +162,9 @@ Analysis complete! Written to second-opinions/add-auth-flow.openai.security-audi
|
|
|
130
162
|
Include request/response examples.
|
|
131
163
|
```
|
|
132
164
|
|
|
133
|
-
###
|
|
165
|
+
### Single Provider
|
|
134
166
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
> /second-opinion consensus Review this implementation
|
|
139
|
-
|
|
140
|
-
Consensus review complete! Written to second-opinions/auth-flow.consensus.review.md
|
|
141
|
-
- Both models analyzed 14 files
|
|
142
|
-
- Agreement: Both flagged the missing null check on line 42
|
|
143
|
-
- Gemini highlighted: Performance concern with nested loops
|
|
144
|
-
- OpenAI highlighted: Inconsistent error message formats
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Or separately:
|
|
167
|
+
When you want one model's perspective:
|
|
148
168
|
|
|
149
169
|
```
|
|
150
170
|
> /second-opinion gemini Review this implementation
|
|
@@ -327,57 +347,11 @@ When calling the MCP tool directly:
|
|
|
327
347
|
| `includeDependents` | No | `true` | Include importing files |
|
|
328
348
|
| `includeTests` | No | `true` | Include test files |
|
|
329
349
|
| `includeTypes` | No | `true` | Include type definitions |
|
|
330
|
-
| `maxInputTokens` | No | `
|
|
350
|
+
| `maxInputTokens` | No | `200000` | Context token budget |
|
|
331
351
|
| `maxOutputTokens` | No | `32768` | Max tokens for reviewer's response |
|
|
332
352
|
| `temperature` | No | `0.3` | LLM temperature (0-1) |
|
|
333
353
|
| `focusAreas` | No | — | Specific areas to focus on |
|
|
334
354
|
|
|
335
|
-
## How It Works
|
|
336
|
-
|
|
337
|
-
```
|
|
338
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
339
|
-
│ Claude Code │
|
|
340
|
-
│ │
|
|
341
|
-
│ You: "Add user authentication" │
|
|
342
|
-
│ Claude: [reads files, writes code, runs tests] │
|
|
343
|
-
│ You: "/second-opinion" │
|
|
344
|
-
│ │
|
|
345
|
-
└─────────────────────┬───────────────────────────────────────────┘
|
|
346
|
-
│
|
|
347
|
-
▼
|
|
348
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
349
|
-
│ Second Opinion MCP │
|
|
350
|
-
│ │
|
|
351
|
-
│ 1. Parse Claude Code session logs │
|
|
352
|
-
│ 2. Collect files read/written + their content │
|
|
353
|
-
│ 3. Resolve dependencies and dependents │
|
|
354
|
-
│ 4. Find related tests and types │
|
|
355
|
-
│ 5. Bundle within token budget │
|
|
356
|
-
│ 6. Send to Gemini/GPT │
|
|
357
|
-
│ 7. Write response to second-opinions/ │
|
|
358
|
-
│ │
|
|
359
|
-
└─────────────────────┬───────────────────────────────────────────┘
|
|
360
|
-
│
|
|
361
|
-
▼
|
|
362
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
363
|
-
│ second-opinions/add-auth.gemini.review.md │
|
|
364
|
-
│ │
|
|
365
|
-
│ # Code Review - add-auth │
|
|
366
|
-
│ **Provider:** gemini │
|
|
367
|
-
│ │
|
|
368
|
-
│ ## Summary │
|
|
369
|
-
│ The authentication implementation is solid... │
|
|
370
|
-
│ │
|
|
371
|
-
│ ## Findings │
|
|
372
|
-
│ [BLOCKING] Missing rate limiting on login endpoint │
|
|
373
|
-
│ [SUGGESTION] Consider adding refresh token rotation │
|
|
374
|
-
│ │
|
|
375
|
-
│ ## What's Done Well │
|
|
376
|
-
│ [PRAISE] Clean separation of auth concerns │
|
|
377
|
-
│ │
|
|
378
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
379
|
-
```
|
|
380
|
-
|
|
381
355
|
## Requirements
|
|
382
356
|
|
|
383
357
|
- Node.js 18+
|
package/dist/config.js
CHANGED
|
@@ -34,7 +34,7 @@ export function loadConfig() {
|
|
|
34
34
|
fileConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
|
-
console.error(`Warning: Invalid JSON in config file ${configPath}. Using defaults
|
|
37
|
+
console.error(`Warning: Invalid JSON in config file ${configPath}. Using defaults.`, error instanceof Error ? error.message : String(error));
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
const config = ConfigSchema.parse({
|
|
@@ -95,6 +95,12 @@ Work through these phases in order:
|
|
|
95
95
|
### Phase 3: Detailed Analysis
|
|
96
96
|
- Correctness, security, performance, error handling, edge cases
|
|
97
97
|
|
|
98
|
+
When a branch diff is provided:
|
|
99
|
+
- Primary focus: code that appears in the diff (new/changed lines)
|
|
100
|
+
- Use the diff to determine if an issue is newly introduced or pre-existing
|
|
101
|
+
- Findings section = only issues in the diff
|
|
102
|
+
- Pre-existing Issues section = legitimate issues NOT in the diff
|
|
103
|
+
|
|
98
104
|
### Phase 4: Self-Interrogation
|
|
99
105
|
For each finding: form it as a question, search the code for evidence, then:
|
|
100
106
|
- Confirmed → include as a finding with evidence
|
|
@@ -119,11 +125,18 @@ Brief overall assessment.
|
|
|
119
125
|
|
|
120
126
|
### Findings
|
|
121
127
|
Ordered by severity, every finding grounded in specific code.
|
|
128
|
+
When a branch diff is provided, only include issues introduced by the diff.
|
|
129
|
+
|
|
130
|
+
### Pre-existing Issues
|
|
131
|
+
(Include only when a branch diff is provided and pre-existing issues are found.)
|
|
132
|
+
Issues found in reviewed files that were NOT introduced by this change.
|
|
133
|
+
Same severity labels and evidence requirements as Findings.
|
|
122
134
|
|
|
123
135
|
### Questions
|
|
124
136
|
Findings that couldn't be fully grounded.
|
|
125
137
|
|
|
126
138
|
### Upstream/Downstream Opportunities
|
|
139
|
+
Architectural suggestions beyond the current change.
|
|
127
140
|
- **What/Where** · **Why** · **Risk Level**: Safe / Worth Investigating / Bold
|
|
128
141
|
|
|
129
142
|
### What's Done Well
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BudgetCategory } from "../utils/tokens.js";
|
|
1
2
|
export interface BlockedFile {
|
|
2
3
|
path: string;
|
|
3
4
|
reason: "sensitive_path" | "outside_project_requires_allowExternalFiles";
|
|
@@ -48,6 +49,8 @@ export interface ContextBundle {
|
|
|
48
49
|
commentsCount: number;
|
|
49
50
|
reviewsCount: number;
|
|
50
51
|
};
|
|
52
|
+
/** Unified diff of branch changes (from base branch), kept separate from file markdown */
|
|
53
|
+
branchDiff?: string;
|
|
51
54
|
files: FileEntry[];
|
|
52
55
|
omittedFiles: OmittedFile[];
|
|
53
56
|
totalTokens: number;
|
|
@@ -74,8 +77,43 @@ export interface ContextBundle {
|
|
|
74
77
|
message: string;
|
|
75
78
|
};
|
|
76
79
|
}
|
|
80
|
+
export interface CandidateFile {
|
|
81
|
+
path: string;
|
|
82
|
+
content: string;
|
|
83
|
+
category: FileEntry["category"];
|
|
84
|
+
tokenEstimate: number;
|
|
85
|
+
annotation?: string;
|
|
86
|
+
redactionCount: number;
|
|
87
|
+
redactedTypes: string[];
|
|
88
|
+
}
|
|
89
|
+
export interface CategoryCandidates {
|
|
90
|
+
category: BudgetCategory;
|
|
91
|
+
files: CandidateFile[];
|
|
92
|
+
totalDemand: number;
|
|
93
|
+
}
|
|
94
|
+
export interface AllocationResult {
|
|
95
|
+
included: FileEntry[];
|
|
96
|
+
omitted: OmittedFile[];
|
|
97
|
+
categoryTokens: Record<BudgetCategory, number>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Two-pass budget allocator.
|
|
101
|
+
*
|
|
102
|
+
* If total demand <= filePool, include everything (common case, fixes the original bug).
|
|
103
|
+
* If total demand > filePool, redistribute surplus from low-demand categories to high-demand ones.
|
|
104
|
+
*
|
|
105
|
+
* Within each category:
|
|
106
|
+
* - explicit/session: preserve insertion order (user intent)
|
|
107
|
+
* - all others: sort smallest first (maximize file count)
|
|
108
|
+
*/
|
|
109
|
+
export declare function allocateBudget(candidates: CategoryCandidates[], filePool: number, budgetWeights: Record<BudgetCategory, number>, priorityOrder: BudgetCategory[]): AllocationResult;
|
|
77
110
|
/**
|
|
78
|
-
* Collect and bundle all context for review
|
|
111
|
+
* Collect and bundle all context for review.
|
|
112
|
+
*
|
|
113
|
+
* Two-pass architecture:
|
|
114
|
+
* Pass 1 (Collection): Gather all candidate files per category without committing budget.
|
|
115
|
+
* Deduplication: Assign each file to its highest-priority category.
|
|
116
|
+
* Pass 2 (Allocation): Distribute the file pool across categories via allocateBudget().
|
|
79
117
|
*/
|
|
80
118
|
export declare function bundleContext(options: BundleOptions): Promise<ContextBundle>;
|
|
81
119
|
/**
|