cc-reviewer 5.1.1 → 5.3.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/commands/codex-review.md +2 -2
- package/commands/codex-xhigh-review.md +1 -1
- package/commands/multi-review.md +2 -2
- package/dist/adapters/base.d.ts +1 -1
- package/dist/adapters/claude.js +15 -13
- package/dist/adapters/codex.js +23 -20
- package/dist/adapters/gemini.js +17 -12
- package/dist/config.d.ts +222 -0
- package/dist/config.js +174 -0
- package/dist/index.js +12 -0
- package/dist/schema.d.ts +6 -6
- package/dist/tools/feedback.d.ts +4 -4
- package/dist/tools/feedback.js +3 -3
- package/package.json +1 -1
package/commands/codex-review.md
CHANGED
|
@@ -49,9 +49,9 @@ Call `codex_review` with:
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### Service Tier (from $ARGUMENTS)
|
|
52
|
-
- If user says "fast mode", "fast", or "priority" → set `serviceTier: "fast"` (priority processing, ~2x cost)
|
|
53
52
|
- If user says "flex", "cheap", or "budget" → set `serviceTier: "flex"` (50% cheaper, slower)
|
|
54
|
-
-
|
|
53
|
+
- If user says "default tier" or "standard tier" → set `serviceTier: "default"` (API default)
|
|
54
|
+
- Otherwise → omit `serviceTier` (defaults to `"fast"` — priority processing, ~2x cost)
|
|
55
55
|
|
|
56
56
|
### Structure your ccOutput:
|
|
57
57
|
|
|
@@ -18,7 +18,7 @@ Use the `codex_review` MCP tool with `reasoningEffort: "xhigh"` for deeper analy
|
|
|
18
18
|
- `workingDir`: current working directory
|
|
19
19
|
- `ccOutput`: brief summary of recent changes or context
|
|
20
20
|
- `reasoningEffort`: "xhigh" (this is the key difference from /codex-review)
|
|
21
|
-
- `serviceTier`: if user says "
|
|
21
|
+
- `serviceTier`: if user says "flex"/"cheap"/"budget" → "flex"; if "default tier"/"standard tier" → "default"; otherwise omit (defaults to "fast" — priority processing, ~2x cost)
|
|
22
22
|
- `focusAreas`: extracted from $ARGUMENTS if it's a known focus area
|
|
23
23
|
- `customPrompt`: $ARGUMENTS if it's custom text
|
|
24
24
|
|
package/commands/multi-review.md
CHANGED
|
@@ -58,9 +58,9 @@ Call `multi_review` with:
|
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
### Service Tier (from $ARGUMENTS, applies to Codex only)
|
|
61
|
-
- If user says "fast mode", "fast", or "priority" → set `serviceTier: "fast"`
|
|
62
61
|
- If user says "flex", "cheap", or "budget" → set `serviceTier: "flex"`
|
|
63
|
-
-
|
|
62
|
+
- If user says "default tier" or "standard tier" → set `serviceTier: "default"`
|
|
63
|
+
- Otherwise → omit `serviceTier` (defaults to `"fast"` — priority processing, ~2x cost)
|
|
64
64
|
|
|
65
65
|
### Structure your ccOutput:
|
|
66
66
|
|
package/dist/adapters/base.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface ReviewRequest {
|
|
|
39
39
|
customPrompt?: string;
|
|
40
40
|
/** Reasoning effort level (for models that support it) */
|
|
41
41
|
reasoningEffort?: ReasoningEffort;
|
|
42
|
-
/** Service tier (for
|
|
42
|
+
/** Service tier (Codex). Omit for the review chain's default 'fast' (priority). Pass 'flex' for cheap/slow or 'default' for the Codex API default tier. */
|
|
43
43
|
serviceTier?: ServiceTier;
|
|
44
44
|
/** Review mode: standard finds bugs, adversarial challenges assumptions */
|
|
45
45
|
reviewMode?: 'standard' | 'adversarial';
|
package/dist/adapters/claude.js
CHANGED
|
@@ -16,12 +16,7 @@ import { registerAdapter, } from './base.js';
|
|
|
16
16
|
import { CliExecutor } from '../executor.js';
|
|
17
17
|
import { ClaudeEventDecoder } from '../decoders/index.js';
|
|
18
18
|
import { buildSimpleHandoff, buildHandoffPrompt, buildAdversarialHandoffPrompt, selectRole, } from '../handoff.js';
|
|
19
|
-
|
|
20
|
-
// CONFIGURATION
|
|
21
|
-
// =============================================================================
|
|
22
|
-
const INACTIVITY_TIMEOUT_MS = 300_000; // 5 min — Opus has long thinking phases
|
|
23
|
-
const MAX_TIMEOUT_MS = 3_600_000; // 60 min absolute max
|
|
24
|
-
const MAX_BUFFER_SIZE = 1024 * 1024; // 1MB max buffer
|
|
19
|
+
import { getConfig } from '../config.js';
|
|
25
20
|
// Write tools explicitly blocked as defense-in-depth
|
|
26
21
|
const DISALLOWED_TOOLS = 'Edit Write NotebookEdit';
|
|
27
22
|
// =============================================================================
|
|
@@ -43,12 +38,18 @@ export class ClaudeAdapter {
|
|
|
43
38
|
}
|
|
44
39
|
async isAvailable() {
|
|
45
40
|
return new Promise((resolve) => {
|
|
41
|
+
let settled = false;
|
|
42
|
+
const done = (result) => { if (!settled) {
|
|
43
|
+
settled = true;
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
resolve(result);
|
|
46
|
+
} };
|
|
46
47
|
const proc = spawn('claude', ['--version'], {
|
|
47
48
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
48
49
|
});
|
|
49
|
-
proc.on('close', (code) =>
|
|
50
|
-
proc.on('error', () =>
|
|
51
|
-
setTimeout(() => { proc.kill();
|
|
50
|
+
proc.on('close', (code) => done(code === 0));
|
|
51
|
+
proc.on('error', () => done(false));
|
|
52
|
+
const timer = setTimeout(() => { proc.kill(); done(false); }, 5000);
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
55
|
async runReview(request) {
|
|
@@ -86,9 +87,10 @@ export class ClaudeAdapter {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
async runCli(prompt, workingDir) {
|
|
90
|
+
const cfg = getConfig().claude;
|
|
89
91
|
const args = [
|
|
90
92
|
'-p', // Non-interactive, print and exit
|
|
91
|
-
'--model',
|
|
93
|
+
'--model', cfg.model, // Model from config (default: opus)
|
|
92
94
|
'--setting-sources', '', // Skip hooks, plugins, CLAUDE.md (preserves OAuth auth; --bare kills keychain)
|
|
93
95
|
'--permission-mode', 'plan', // Read-only enforcement (layer 1)
|
|
94
96
|
'--verbose', // Required for stream-json
|
|
@@ -111,9 +113,9 @@ export class ClaudeAdapter {
|
|
|
111
113
|
args,
|
|
112
114
|
cwd: workingDir,
|
|
113
115
|
stdin: prompt,
|
|
114
|
-
inactivityTimeoutMs:
|
|
115
|
-
maxTimeoutMs:
|
|
116
|
-
maxBufferSize:
|
|
116
|
+
inactivityTimeoutMs: cfg.inactivityTimeoutMs,
|
|
117
|
+
maxTimeoutMs: cfg.maxTimeoutMs,
|
|
118
|
+
maxBufferSize: cfg.maxBufferSize,
|
|
117
119
|
onLine: (line) => {
|
|
118
120
|
decoder.processLine(line);
|
|
119
121
|
},
|
package/dist/adapters/codex.js
CHANGED
|
@@ -11,15 +11,7 @@ import { registerAdapter, } from './base.js';
|
|
|
11
11
|
import { CliExecutor } from '../executor.js';
|
|
12
12
|
import { CodexEventDecoder } from '../decoders/index.js';
|
|
13
13
|
import { buildSimpleHandoff, buildHandoffPrompt, buildAdversarialHandoffPrompt, selectRole, } from '../handoff.js';
|
|
14
|
-
|
|
15
|
-
// CONFIGURATION
|
|
16
|
-
// =============================================================================
|
|
17
|
-
const INACTIVITY_TIMEOUT_MS = {
|
|
18
|
-
high: 180_000, // 3 min — covers reasoning gaps between tool use bursts
|
|
19
|
-
xhigh: 300_000, // 5 min — xhigh has longer reasoning phases
|
|
20
|
-
};
|
|
21
|
-
const MAX_TIMEOUT_MS = 3_600_000; // 60 min absolute max
|
|
22
|
-
const MAX_BUFFER_SIZE = 1024 * 1024; // 1MB max buffer
|
|
14
|
+
import { getConfig } from '../config.js';
|
|
23
15
|
// =============================================================================
|
|
24
16
|
// CODEX ADAPTER
|
|
25
17
|
// =============================================================================
|
|
@@ -39,12 +31,18 @@ export class CodexAdapter {
|
|
|
39
31
|
}
|
|
40
32
|
async isAvailable() {
|
|
41
33
|
return new Promise((resolve) => {
|
|
34
|
+
let settled = false;
|
|
35
|
+
const done = (result) => { if (!settled) {
|
|
36
|
+
settled = true;
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
resolve(result);
|
|
39
|
+
} };
|
|
42
40
|
const proc = spawn('codex', ['--version'], {
|
|
43
41
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
44
42
|
});
|
|
45
|
-
proc.on('close', (code) =>
|
|
46
|
-
proc.on('error', () =>
|
|
47
|
-
setTimeout(() => { proc.kill();
|
|
43
|
+
proc.on('close', (code) => done(code === 0));
|
|
44
|
+
proc.on('error', () => done(false));
|
|
45
|
+
const timer = setTimeout(() => { proc.kill(); done(false); }, 5000);
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
48
|
async runReview(request) {
|
|
@@ -62,7 +60,8 @@ export class CodexAdapter {
|
|
|
62
60
|
const prompt = request.reviewMode === 'adversarial'
|
|
63
61
|
? buildAdversarialHandoffPrompt({ handoff })
|
|
64
62
|
: buildHandoffPrompt({ handoff, role: selectRole(request.focusAreas) });
|
|
65
|
-
const
|
|
63
|
+
const cfg = getConfig().codex;
|
|
64
|
+
const result = await this.runCli(prompt, request.workingDir, request.reasoningEffort ?? cfg.reasoningEffort, request.serviceTier);
|
|
66
65
|
if (result.exitCode !== 0) {
|
|
67
66
|
const error = this.categorizeError(result.stderr);
|
|
68
67
|
return { success: false, error, suggestion: this.getSuggestion(error), executionTimeMs: Date.now() - startTime };
|
|
@@ -82,10 +81,11 @@ export class CodexAdapter {
|
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
async runCli(prompt, workingDir, reasoningEffort, serviceTier) {
|
|
84
|
+
const cfg = getConfig().codex;
|
|
85
85
|
const args = [
|
|
86
86
|
'exec',
|
|
87
87
|
'--json', // JSONL streaming events
|
|
88
|
-
'-m',
|
|
88
|
+
'-m', cfg.model,
|
|
89
89
|
'-c', `model_reasoning_effort=${reasoningEffort}`,
|
|
90
90
|
'-c', 'model_reasoning_summary_format=experimental',
|
|
91
91
|
'--full-auto',
|
|
@@ -94,12 +94,15 @@ export class CodexAdapter {
|
|
|
94
94
|
'-C', workingDir,
|
|
95
95
|
'-', // Read prompt from stdin
|
|
96
96
|
];
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// Caller-supplied serviceTier overrides config. Explicit 'default' is an
|
|
98
|
+
// opt-out and emits no flag (uses Codex API default).
|
|
99
|
+
const effectiveTier = serviceTier ?? cfg.serviceTier;
|
|
100
|
+
if (effectiveTier !== 'default') {
|
|
101
|
+
args.push('-c', `service_tier=${effectiveTier}`);
|
|
99
102
|
}
|
|
100
103
|
const decoder = new CodexEventDecoder();
|
|
101
104
|
const cliStartTime = Date.now();
|
|
102
|
-
const tierLabel =
|
|
105
|
+
const tierLabel = effectiveTier !== 'default' ? ` [${effectiveTier}]` : '';
|
|
103
106
|
console.error(`[codex] Running with ${reasoningEffort} reasoning${tierLabel}...`);
|
|
104
107
|
decoder.onProgress = (eventType, detail) => {
|
|
105
108
|
const elapsed = Math.round((Date.now() - cliStartTime) / 1000);
|
|
@@ -111,9 +114,9 @@ export class CodexAdapter {
|
|
|
111
114
|
args,
|
|
112
115
|
cwd: workingDir,
|
|
113
116
|
stdin: prompt,
|
|
114
|
-
inactivityTimeoutMs:
|
|
115
|
-
maxTimeoutMs:
|
|
116
|
-
maxBufferSize:
|
|
117
|
+
inactivityTimeoutMs: cfg.inactivityTimeoutMs[reasoningEffort] ?? cfg.inactivityTimeoutMs.high,
|
|
118
|
+
maxTimeoutMs: cfg.maxTimeoutMs,
|
|
119
|
+
maxBufferSize: cfg.maxBufferSize,
|
|
117
120
|
onLine: (line) => {
|
|
118
121
|
decoder.processLine(line);
|
|
119
122
|
},
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -11,12 +11,7 @@ import { registerAdapter, } from './base.js';
|
|
|
11
11
|
import { CliExecutor } from '../executor.js';
|
|
12
12
|
import { GeminiEventDecoder } from '../decoders/index.js';
|
|
13
13
|
import { buildSimpleHandoff, buildHandoffPrompt, buildAdversarialHandoffPrompt, selectRole, } from '../handoff.js';
|
|
14
|
-
|
|
15
|
-
// CONFIGURATION
|
|
16
|
-
// =============================================================================
|
|
17
|
-
const INACTIVITY_TIMEOUT_MS = 300_000; // 5 min — covers reasoning gaps between tool use
|
|
18
|
-
const MAX_TIMEOUT_MS = 3_600_000; // 60 min absolute max
|
|
19
|
-
const MAX_BUFFER_SIZE = 1024 * 1024; // 1MB max buffer
|
|
14
|
+
import { getConfig } from '../config.js';
|
|
20
15
|
// =============================================================================
|
|
21
16
|
// GEMINI ADAPTER
|
|
22
17
|
// =============================================================================
|
|
@@ -36,12 +31,18 @@ export class GeminiAdapter {
|
|
|
36
31
|
}
|
|
37
32
|
async isAvailable() {
|
|
38
33
|
return new Promise((resolve) => {
|
|
34
|
+
let settled = false;
|
|
35
|
+
const done = (result) => { if (!settled) {
|
|
36
|
+
settled = true;
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
resolve(result);
|
|
39
|
+
} };
|
|
39
40
|
const proc = spawn('gemini', ['--version'], {
|
|
40
41
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
42
|
});
|
|
42
|
-
proc.on('close', (code) =>
|
|
43
|
-
proc.on('error', () =>
|
|
44
|
-
setTimeout(() => { proc.kill();
|
|
43
|
+
proc.on('close', (code) => done(code === 0));
|
|
44
|
+
proc.on('error', () => done(false));
|
|
45
|
+
const timer = setTimeout(() => { proc.kill(); done(false); }, 5000);
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
async runReview(request) {
|
|
@@ -79,6 +80,7 @@ export class GeminiAdapter {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
async runCli(prompt, workingDir) {
|
|
83
|
+
const cfg = getConfig().gemini;
|
|
82
84
|
const args = [
|
|
83
85
|
'--sandbox',
|
|
84
86
|
'--approval-mode', 'plan',
|
|
@@ -86,6 +88,9 @@ export class GeminiAdapter {
|
|
|
86
88
|
'--include-directories', workingDir,
|
|
87
89
|
'-p', '',
|
|
88
90
|
];
|
|
91
|
+
if (cfg.model) {
|
|
92
|
+
args.push('--model', cfg.model);
|
|
93
|
+
}
|
|
89
94
|
const decoder = new GeminiEventDecoder();
|
|
90
95
|
const cliStartTime = Date.now();
|
|
91
96
|
console.error('[gemini] Running...');
|
|
@@ -99,9 +104,9 @@ export class GeminiAdapter {
|
|
|
99
104
|
args,
|
|
100
105
|
cwd: workingDir,
|
|
101
106
|
stdin: prompt,
|
|
102
|
-
inactivityTimeoutMs:
|
|
103
|
-
maxTimeoutMs:
|
|
104
|
-
maxBufferSize:
|
|
107
|
+
inactivityTimeoutMs: cfg.inactivityTimeoutMs,
|
|
108
|
+
maxTimeoutMs: cfg.maxTimeoutMs,
|
|
109
|
+
maxBufferSize: cfg.maxBufferSize,
|
|
105
110
|
onLine: (line) => {
|
|
106
111
|
decoder.processLine(line);
|
|
107
112
|
},
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration for cc-reviewer.
|
|
3
|
+
*
|
|
4
|
+
* Config file: ~/.config/cc-reviewer/config.json
|
|
5
|
+
*
|
|
6
|
+
* Semantics:
|
|
7
|
+
* - Lazy, cached load. `getConfig()` returns the cached config or reads once.
|
|
8
|
+
* - Missing file → defaults in memory (no write). Use `initConfig()` from the
|
|
9
|
+
* server entry point to create the file with defaults on first launch.
|
|
10
|
+
* - Invalid JSON or schema violations → fall back to defaults, warn on stderr.
|
|
11
|
+
* - Partial user configs are deep-merged against defaults via Zod `.default()`.
|
|
12
|
+
* - Tool-call arguments still override config (e.g. `reasoningEffort` on a
|
|
13
|
+
* single `codex_review` call). Config only sets defaults.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
export declare const CodexConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
17
|
+
model: z.ZodDefault<z.ZodString>;
|
|
18
|
+
reasoningEffort: z.ZodDefault<z.ZodEnum<["high", "xhigh"]>>;
|
|
19
|
+
serviceTier: z.ZodDefault<z.ZodEnum<["default", "fast", "flex"]>>;
|
|
20
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodObject<{
|
|
21
|
+
high: z.ZodDefault<z.ZodNumber>;
|
|
22
|
+
xhigh: z.ZodDefault<z.ZodNumber>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
high: number;
|
|
25
|
+
xhigh: number;
|
|
26
|
+
}, {
|
|
27
|
+
high?: number | undefined;
|
|
28
|
+
xhigh?: number | undefined;
|
|
29
|
+
}>>;
|
|
30
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
31
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
model: string;
|
|
34
|
+
reasoningEffort: "high" | "xhigh";
|
|
35
|
+
serviceTier: "default" | "fast" | "flex";
|
|
36
|
+
inactivityTimeoutMs: {
|
|
37
|
+
high: number;
|
|
38
|
+
xhigh: number;
|
|
39
|
+
};
|
|
40
|
+
maxTimeoutMs: number;
|
|
41
|
+
maxBufferSize: number;
|
|
42
|
+
}, {
|
|
43
|
+
model?: string | undefined;
|
|
44
|
+
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
45
|
+
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
46
|
+
inactivityTimeoutMs?: {
|
|
47
|
+
high?: number | undefined;
|
|
48
|
+
xhigh?: number | undefined;
|
|
49
|
+
} | undefined;
|
|
50
|
+
maxTimeoutMs?: number | undefined;
|
|
51
|
+
maxBufferSize?: number | undefined;
|
|
52
|
+
}>>;
|
|
53
|
+
export declare const ClaudeConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
54
|
+
model: z.ZodDefault<z.ZodString>;
|
|
55
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
56
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
57
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
58
|
+
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
model: string;
|
|
60
|
+
inactivityTimeoutMs: number;
|
|
61
|
+
maxTimeoutMs: number;
|
|
62
|
+
maxBufferSize: number;
|
|
63
|
+
}, {
|
|
64
|
+
model?: string | undefined;
|
|
65
|
+
inactivityTimeoutMs?: number | undefined;
|
|
66
|
+
maxTimeoutMs?: number | undefined;
|
|
67
|
+
maxBufferSize?: number | undefined;
|
|
68
|
+
}>>;
|
|
69
|
+
export declare const GeminiConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
70
|
+
model: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
71
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
72
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
73
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
74
|
+
}, "strip", z.ZodTypeAny, {
|
|
75
|
+
model: string | null;
|
|
76
|
+
inactivityTimeoutMs: number;
|
|
77
|
+
maxTimeoutMs: number;
|
|
78
|
+
maxBufferSize: number;
|
|
79
|
+
}, {
|
|
80
|
+
model?: string | null | undefined;
|
|
81
|
+
inactivityTimeoutMs?: number | undefined;
|
|
82
|
+
maxTimeoutMs?: number | undefined;
|
|
83
|
+
maxBufferSize?: number | undefined;
|
|
84
|
+
}>>;
|
|
85
|
+
export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
86
|
+
codex: z.ZodDefault<z.ZodObject<{
|
|
87
|
+
model: z.ZodDefault<z.ZodString>;
|
|
88
|
+
reasoningEffort: z.ZodDefault<z.ZodEnum<["high", "xhigh"]>>;
|
|
89
|
+
serviceTier: z.ZodDefault<z.ZodEnum<["default", "fast", "flex"]>>;
|
|
90
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodObject<{
|
|
91
|
+
high: z.ZodDefault<z.ZodNumber>;
|
|
92
|
+
xhigh: z.ZodDefault<z.ZodNumber>;
|
|
93
|
+
}, "strip", z.ZodTypeAny, {
|
|
94
|
+
high: number;
|
|
95
|
+
xhigh: number;
|
|
96
|
+
}, {
|
|
97
|
+
high?: number | undefined;
|
|
98
|
+
xhigh?: number | undefined;
|
|
99
|
+
}>>;
|
|
100
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
101
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
model: string;
|
|
104
|
+
reasoningEffort: "high" | "xhigh";
|
|
105
|
+
serviceTier: "default" | "fast" | "flex";
|
|
106
|
+
inactivityTimeoutMs: {
|
|
107
|
+
high: number;
|
|
108
|
+
xhigh: number;
|
|
109
|
+
};
|
|
110
|
+
maxTimeoutMs: number;
|
|
111
|
+
maxBufferSize: number;
|
|
112
|
+
}, {
|
|
113
|
+
model?: string | undefined;
|
|
114
|
+
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
115
|
+
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
116
|
+
inactivityTimeoutMs?: {
|
|
117
|
+
high?: number | undefined;
|
|
118
|
+
xhigh?: number | undefined;
|
|
119
|
+
} | undefined;
|
|
120
|
+
maxTimeoutMs?: number | undefined;
|
|
121
|
+
maxBufferSize?: number | undefined;
|
|
122
|
+
}>>;
|
|
123
|
+
claude: z.ZodDefault<z.ZodObject<{
|
|
124
|
+
model: z.ZodDefault<z.ZodString>;
|
|
125
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
126
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
127
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
128
|
+
}, "strip", z.ZodTypeAny, {
|
|
129
|
+
model: string;
|
|
130
|
+
inactivityTimeoutMs: number;
|
|
131
|
+
maxTimeoutMs: number;
|
|
132
|
+
maxBufferSize: number;
|
|
133
|
+
}, {
|
|
134
|
+
model?: string | undefined;
|
|
135
|
+
inactivityTimeoutMs?: number | undefined;
|
|
136
|
+
maxTimeoutMs?: number | undefined;
|
|
137
|
+
maxBufferSize?: number | undefined;
|
|
138
|
+
}>>;
|
|
139
|
+
gemini: z.ZodDefault<z.ZodObject<{
|
|
140
|
+
model: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
141
|
+
inactivityTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
142
|
+
maxTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
143
|
+
maxBufferSize: z.ZodDefault<z.ZodNumber>;
|
|
144
|
+
}, "strip", z.ZodTypeAny, {
|
|
145
|
+
model: string | null;
|
|
146
|
+
inactivityTimeoutMs: number;
|
|
147
|
+
maxTimeoutMs: number;
|
|
148
|
+
maxBufferSize: number;
|
|
149
|
+
}, {
|
|
150
|
+
model?: string | null | undefined;
|
|
151
|
+
inactivityTimeoutMs?: number | undefined;
|
|
152
|
+
maxTimeoutMs?: number | undefined;
|
|
153
|
+
maxBufferSize?: number | undefined;
|
|
154
|
+
}>>;
|
|
155
|
+
}, "strip", z.ZodTypeAny, {
|
|
156
|
+
codex: {
|
|
157
|
+
model: string;
|
|
158
|
+
reasoningEffort: "high" | "xhigh";
|
|
159
|
+
serviceTier: "default" | "fast" | "flex";
|
|
160
|
+
inactivityTimeoutMs: {
|
|
161
|
+
high: number;
|
|
162
|
+
xhigh: number;
|
|
163
|
+
};
|
|
164
|
+
maxTimeoutMs: number;
|
|
165
|
+
maxBufferSize: number;
|
|
166
|
+
};
|
|
167
|
+
claude: {
|
|
168
|
+
model: string;
|
|
169
|
+
inactivityTimeoutMs: number;
|
|
170
|
+
maxTimeoutMs: number;
|
|
171
|
+
maxBufferSize: number;
|
|
172
|
+
};
|
|
173
|
+
gemini: {
|
|
174
|
+
model: string | null;
|
|
175
|
+
inactivityTimeoutMs: number;
|
|
176
|
+
maxTimeoutMs: number;
|
|
177
|
+
maxBufferSize: number;
|
|
178
|
+
};
|
|
179
|
+
}, {
|
|
180
|
+
codex?: {
|
|
181
|
+
model?: string | undefined;
|
|
182
|
+
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
183
|
+
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
184
|
+
inactivityTimeoutMs?: {
|
|
185
|
+
high?: number | undefined;
|
|
186
|
+
xhigh?: number | undefined;
|
|
187
|
+
} | undefined;
|
|
188
|
+
maxTimeoutMs?: number | undefined;
|
|
189
|
+
maxBufferSize?: number | undefined;
|
|
190
|
+
} | undefined;
|
|
191
|
+
claude?: {
|
|
192
|
+
model?: string | undefined;
|
|
193
|
+
inactivityTimeoutMs?: number | undefined;
|
|
194
|
+
maxTimeoutMs?: number | undefined;
|
|
195
|
+
maxBufferSize?: number | undefined;
|
|
196
|
+
} | undefined;
|
|
197
|
+
gemini?: {
|
|
198
|
+
model?: string | null | undefined;
|
|
199
|
+
inactivityTimeoutMs?: number | undefined;
|
|
200
|
+
maxTimeoutMs?: number | undefined;
|
|
201
|
+
maxBufferSize?: number | undefined;
|
|
202
|
+
} | undefined;
|
|
203
|
+
}>>;
|
|
204
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
205
|
+
export type CodexConfig = z.infer<typeof CodexConfigSchema>;
|
|
206
|
+
export type ClaudeConfig = z.infer<typeof ClaudeConfigSchema>;
|
|
207
|
+
export type GeminiConfig = z.infer<typeof GeminiConfigSchema>;
|
|
208
|
+
export declare const DEFAULT_CONFIG: Config;
|
|
209
|
+
export declare function getConfigPath(): string;
|
|
210
|
+
export declare function getConfig(): Config;
|
|
211
|
+
/**
|
|
212
|
+
* Create the config file with defaults if it does not exist.
|
|
213
|
+
* Uses the exclusive `wx` flag for atomic creation — safe against TOCTOU races
|
|
214
|
+
* when multiple server instances start concurrently.
|
|
215
|
+
* Refreshes the cached config so subsequent `getConfig()` calls see disk state.
|
|
216
|
+
*/
|
|
217
|
+
export declare function initConfig(): {
|
|
218
|
+
path: string;
|
|
219
|
+
created: boolean;
|
|
220
|
+
};
|
|
221
|
+
/** Test-only hook. Redirects the config path and clears the cache. */
|
|
222
|
+
export declare function setConfigPathForTesting(path: string | null): void;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration for cc-reviewer.
|
|
3
|
+
*
|
|
4
|
+
* Config file: ~/.config/cc-reviewer/config.json
|
|
5
|
+
*
|
|
6
|
+
* Semantics:
|
|
7
|
+
* - Lazy, cached load. `getConfig()` returns the cached config or reads once.
|
|
8
|
+
* - Missing file → defaults in memory (no write). Use `initConfig()` from the
|
|
9
|
+
* server entry point to create the file with defaults on first launch.
|
|
10
|
+
* - Invalid JSON or schema violations → fall back to defaults, warn on stderr.
|
|
11
|
+
* - Partial user configs are deep-merged against defaults via Zod `.default()`.
|
|
12
|
+
* - Tool-call arguments still override config (e.g. `reasoningEffort` on a
|
|
13
|
+
* single `codex_review` call). Config only sets defaults.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
17
|
+
import { dirname, join } from 'path';
|
|
18
|
+
import { homedir } from 'os';
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// SCHEMA
|
|
21
|
+
// =============================================================================
|
|
22
|
+
export const CodexConfigSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
model: z.string().default('gpt-5.4'),
|
|
25
|
+
reasoningEffort: z.enum(['high', 'xhigh']).default('high'),
|
|
26
|
+
serviceTier: z.enum(['default', 'fast', 'flex']).default('fast'),
|
|
27
|
+
inactivityTimeoutMs: z
|
|
28
|
+
.object({
|
|
29
|
+
high: z.number().int().positive().default(180_000),
|
|
30
|
+
xhigh: z.number().int().positive().default(300_000),
|
|
31
|
+
})
|
|
32
|
+
.default({}),
|
|
33
|
+
maxTimeoutMs: z.number().int().positive().default(3_600_000),
|
|
34
|
+
maxBufferSize: z.number().int().positive().default(1_048_576),
|
|
35
|
+
})
|
|
36
|
+
.default({});
|
|
37
|
+
export const ClaudeConfigSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
model: z.string().default('opus'),
|
|
40
|
+
inactivityTimeoutMs: z.number().int().positive().default(300_000),
|
|
41
|
+
maxTimeoutMs: z.number().int().positive().default(3_600_000),
|
|
42
|
+
maxBufferSize: z.number().int().positive().default(1_048_576),
|
|
43
|
+
})
|
|
44
|
+
.default({});
|
|
45
|
+
export const GeminiConfigSchema = z
|
|
46
|
+
.object({
|
|
47
|
+
model: z.string().nullable().default('gemini-3.1-pro-preview'),
|
|
48
|
+
inactivityTimeoutMs: z.number().int().positive().default(300_000),
|
|
49
|
+
maxTimeoutMs: z.number().int().positive().default(3_600_000),
|
|
50
|
+
maxBufferSize: z.number().int().positive().default(1_048_576),
|
|
51
|
+
})
|
|
52
|
+
.default({});
|
|
53
|
+
export const ConfigSchema = z
|
|
54
|
+
.object({
|
|
55
|
+
codex: CodexConfigSchema,
|
|
56
|
+
claude: ClaudeConfigSchema,
|
|
57
|
+
gemini: GeminiConfigSchema,
|
|
58
|
+
})
|
|
59
|
+
.default({});
|
|
60
|
+
export const DEFAULT_CONFIG = ConfigSchema.parse({});
|
|
61
|
+
// =============================================================================
|
|
62
|
+
// STATE
|
|
63
|
+
// =============================================================================
|
|
64
|
+
const DEFAULT_CONFIG_PATH = join(homedir(), '.config', 'cc-reviewer', 'config.json');
|
|
65
|
+
let _configPath = DEFAULT_CONFIG_PATH;
|
|
66
|
+
let _cached = null;
|
|
67
|
+
let _cachedMtimeMs = 0;
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// PUBLIC API
|
|
70
|
+
// =============================================================================
|
|
71
|
+
export function getConfigPath() {
|
|
72
|
+
return _configPath;
|
|
73
|
+
}
|
|
74
|
+
export function getConfig() {
|
|
75
|
+
// Hot-reload: re-read if the file's mtime has changed since last load.
|
|
76
|
+
if (_cached) {
|
|
77
|
+
try {
|
|
78
|
+
if (existsSync(_configPath)) {
|
|
79
|
+
const mtime = statSync(_configPath).mtimeMs;
|
|
80
|
+
if (mtime !== _cachedMtimeMs) {
|
|
81
|
+
_cached = loadConfigFromDisk(_configPath);
|
|
82
|
+
_cachedMtimeMs = mtime;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// statSync failure is non-fatal — keep using the cached config.
|
|
88
|
+
}
|
|
89
|
+
return _cached;
|
|
90
|
+
}
|
|
91
|
+
_cached = loadConfigFromDisk(_configPath);
|
|
92
|
+
if (existsSync(_configPath)) {
|
|
93
|
+
try {
|
|
94
|
+
_cachedMtimeMs = statSync(_configPath).mtimeMs;
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore */ }
|
|
97
|
+
}
|
|
98
|
+
return _cached;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create the config file with defaults if it does not exist.
|
|
102
|
+
* Uses the exclusive `wx` flag for atomic creation — safe against TOCTOU races
|
|
103
|
+
* when multiple server instances start concurrently.
|
|
104
|
+
* Refreshes the cached config so subsequent `getConfig()` calls see disk state.
|
|
105
|
+
*/
|
|
106
|
+
export function initConfig() {
|
|
107
|
+
const path = _configPath;
|
|
108
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
109
|
+
try {
|
|
110
|
+
writeFileSync(path, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\n', { encoding: 'utf-8', flag: 'wx' });
|
|
111
|
+
_cached = DEFAULT_CONFIG;
|
|
112
|
+
_cachedMtimeMs = statSync(path).mtimeMs;
|
|
113
|
+
return { path, created: true };
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error.code === 'EEXIST') {
|
|
117
|
+
_cached = loadConfigFromDisk(path);
|
|
118
|
+
try {
|
|
119
|
+
_cachedMtimeMs = statSync(path).mtimeMs;
|
|
120
|
+
}
|
|
121
|
+
catch { /* ignore */ }
|
|
122
|
+
return { path, created: false };
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Test-only hook. Redirects the config path and clears the cache. */
|
|
128
|
+
export function setConfigPathForTesting(path) {
|
|
129
|
+
_configPath = path ?? DEFAULT_CONFIG_PATH;
|
|
130
|
+
_cached = null;
|
|
131
|
+
_cachedMtimeMs = 0;
|
|
132
|
+
}
|
|
133
|
+
// =============================================================================
|
|
134
|
+
// INTERNAL
|
|
135
|
+
// =============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* Parse each adapter's config independently so a typo in one section only
|
|
138
|
+
* resets that adapter to defaults — the other adapters' settings survive.
|
|
139
|
+
*/
|
|
140
|
+
function loadConfigFromDisk(path) {
|
|
141
|
+
if (!existsSync(path))
|
|
142
|
+
return DEFAULT_CONFIG;
|
|
143
|
+
let raw;
|
|
144
|
+
try {
|
|
145
|
+
raw = JSON.parse(readFileSync(path, 'utf-8'));
|
|
146
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
147
|
+
console.error(`[cc-reviewer] Config at ${path} is not a JSON object — using defaults.`);
|
|
148
|
+
return DEFAULT_CONFIG;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
153
|
+
console.error(`[cc-reviewer] Invalid JSON in ${path} — using defaults. Error: ${msg}`);
|
|
154
|
+
return DEFAULT_CONFIG;
|
|
155
|
+
}
|
|
156
|
+
const adapters = [
|
|
157
|
+
{ key: 'codex', schema: CodexConfigSchema },
|
|
158
|
+
{ key: 'claude', schema: ClaudeConfigSchema },
|
|
159
|
+
{ key: 'gemini', schema: GeminiConfigSchema },
|
|
160
|
+
];
|
|
161
|
+
const result = {};
|
|
162
|
+
for (const { key, schema } of adapters) {
|
|
163
|
+
const section = raw[key];
|
|
164
|
+
try {
|
|
165
|
+
result[key] = schema.parse(section);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
169
|
+
console.error(`[cc-reviewer] Invalid "${key}" config — using ${key} defaults. Error: ${msg}`);
|
|
170
|
+
result[key] = schema.parse(undefined);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextpro
|
|
|
21
21
|
import { handleCodexReview, handleGeminiReview, handleClaudeReview, handleMultiReview, ReviewInputSchema, TOOL_DEFINITIONS } from './tools/feedback.js';
|
|
22
22
|
import { logCliStatus } from './cli/check.js';
|
|
23
23
|
import { installCommands } from './commands.js';
|
|
24
|
+
import { initConfig } from './config.js';
|
|
24
25
|
// Read version from package.json
|
|
25
26
|
import { readFileSync } from 'fs';
|
|
26
27
|
import { join, dirname } from 'path';
|
|
@@ -111,6 +112,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
111
112
|
});
|
|
112
113
|
// Start the server
|
|
113
114
|
async function main() {
|
|
115
|
+
// Initialize config (writes defaults to ~/.config/cc-reviewer/config.json on first run)
|
|
116
|
+
try {
|
|
117
|
+
const cfg = initConfig();
|
|
118
|
+
console.error(cfg.created
|
|
119
|
+
? `[cc-reviewer] Initialized config at ${cfg.path}`
|
|
120
|
+
: `[cc-reviewer] Loaded config from ${cfg.path}`);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
124
|
+
console.error(`[cc-reviewer] Warning: Could not initialize config: ${msg}`);
|
|
125
|
+
}
|
|
114
126
|
// Auto-install slash commands
|
|
115
127
|
const result = installCommands();
|
|
116
128
|
if (result.success) {
|
package/dist/schema.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export declare const ReviewFinding: z.ZodObject<{
|
|
|
63
63
|
owasp_category: z.ZodOptional<z.ZodString>;
|
|
64
64
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
65
65
|
}, "strip", z.ZodTypeAny, {
|
|
66
|
-
severity: "
|
|
66
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
67
67
|
title: string;
|
|
68
68
|
description: string;
|
|
69
69
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
|
@@ -82,7 +82,7 @@ export declare const ReviewFinding: z.ZodObject<{
|
|
|
82
82
|
owasp_category?: string | undefined;
|
|
83
83
|
tags?: string[] | undefined;
|
|
84
84
|
}, {
|
|
85
|
-
severity: "
|
|
85
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
86
86
|
title: string;
|
|
87
87
|
description: string;
|
|
88
88
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
|
@@ -266,7 +266,7 @@ export declare const ReviewOutput: z.ZodObject<{
|
|
|
266
266
|
owasp_category: z.ZodOptional<z.ZodString>;
|
|
267
267
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
268
268
|
}, "strip", z.ZodTypeAny, {
|
|
269
|
-
severity: "
|
|
269
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
270
270
|
title: string;
|
|
271
271
|
description: string;
|
|
272
272
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
|
@@ -285,7 +285,7 @@ export declare const ReviewOutput: z.ZodObject<{
|
|
|
285
285
|
owasp_category?: string | undefined;
|
|
286
286
|
tags?: string[] | undefined;
|
|
287
287
|
}, {
|
|
288
|
-
severity: "
|
|
288
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
289
289
|
title: string;
|
|
290
290
|
description: string;
|
|
291
291
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
|
@@ -431,7 +431,7 @@ export declare const ReviewOutput: z.ZodObject<{
|
|
|
431
431
|
execution_notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
432
432
|
}, "strip", z.ZodTypeAny, {
|
|
433
433
|
findings: {
|
|
434
|
-
severity: "
|
|
434
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
435
435
|
title: string;
|
|
436
436
|
description: string;
|
|
437
437
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
|
@@ -499,7 +499,7 @@ export declare const ReviewOutput: z.ZodObject<{
|
|
|
499
499
|
execution_notes?: string | null | undefined;
|
|
500
500
|
}, {
|
|
501
501
|
findings: {
|
|
502
|
-
severity: "
|
|
502
|
+
severity: "high" | "info" | "critical" | "medium" | "low";
|
|
503
503
|
title: string;
|
|
504
504
|
description: string;
|
|
505
505
|
category: "other" | "performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation" | "best-practice";
|
package/dist/tools/feedback.d.ts
CHANGED
|
@@ -18,20 +18,20 @@ export declare const ReviewInputSchema: z.ZodObject<{
|
|
|
18
18
|
workingDir: string;
|
|
19
19
|
ccOutput: string;
|
|
20
20
|
outputType: "findings" | "analysis" | "plan" | "proposal";
|
|
21
|
+
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
22
|
+
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
21
23
|
focusAreas?: ("performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation")[] | undefined;
|
|
22
24
|
analyzedFiles?: string[] | undefined;
|
|
23
25
|
customPrompt?: string | undefined;
|
|
24
|
-
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
25
|
-
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
26
26
|
}, {
|
|
27
27
|
workingDir: string;
|
|
28
28
|
ccOutput: string;
|
|
29
29
|
outputType: "findings" | "analysis" | "plan" | "proposal";
|
|
30
|
+
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
31
|
+
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
30
32
|
focusAreas?: ("performance" | "security" | "testing" | "architecture" | "correctness" | "maintainability" | "scalability" | "documentation")[] | undefined;
|
|
31
33
|
analyzedFiles?: string[] | undefined;
|
|
32
34
|
customPrompt?: string | undefined;
|
|
33
|
-
reasoningEffort?: "high" | "xhigh" | undefined;
|
|
34
|
-
serviceTier?: "default" | "fast" | "flex" | undefined;
|
|
35
35
|
}>;
|
|
36
36
|
export type ReviewInput = z.infer<typeof ReviewInputSchema>;
|
|
37
37
|
export declare function handleCodexReview(input: ReviewInput): Promise<{
|
package/dist/tools/feedback.js
CHANGED
|
@@ -20,7 +20,7 @@ export const ReviewInputSchema = z.object({
|
|
|
20
20
|
])).optional().describe('Areas to focus the review on'),
|
|
21
21
|
customPrompt: z.string().optional().describe('Custom instructions for the reviewer'),
|
|
22
22
|
reasoningEffort: z.enum(['high', 'xhigh']).optional().describe('Codex reasoning effort level (default: high, use xhigh for deeper analysis)'),
|
|
23
|
-
serviceTier: z.enum(['default', 'fast', 'flex']).optional().describe('Codex service tier (default:
|
|
23
|
+
serviceTier: z.enum(['default', 'fast', 'flex']).optional().describe('Codex service tier (default when omitted: fast = priority processing, ~2x cost; flex = 50% cheaper/slower; default = API default tier)')
|
|
24
24
|
});
|
|
25
25
|
// =============================================================================
|
|
26
26
|
// HELPERS
|
|
@@ -143,7 +143,7 @@ export const TOOL_DEFINITIONS = {
|
|
|
143
143
|
focusAreas: { type: 'array', items: { type: 'string', enum: ['security', 'performance', 'architecture', 'correctness', 'maintainability', 'scalability', 'testing', 'documentation'] }, description: 'Areas to focus the review on' },
|
|
144
144
|
customPrompt: { type: 'string', description: 'Custom instructions for the reviewer' },
|
|
145
145
|
reasoningEffort: { type: 'string', enum: ['high', 'xhigh'], description: 'Codex reasoning effort (default: high, use xhigh for deeper analysis)' },
|
|
146
|
-
serviceTier: { type: 'string', enum: ['default', 'fast', 'flex'], description: 'Codex service tier (fast = priority
|
|
146
|
+
serviceTier: { type: 'string', enum: ['default', 'fast', 'flex'], description: 'Codex service tier (omit for fast default; fast = priority ~2x cost, flex = 50% cheaper/slower, default = API default tier)' }
|
|
147
147
|
},
|
|
148
148
|
required: ['workingDir', 'ccOutput', 'outputType']
|
|
149
149
|
}
|
|
@@ -192,7 +192,7 @@ export const TOOL_DEFINITIONS = {
|
|
|
192
192
|
analyzedFiles: { type: 'array', items: { type: 'string' }, description: 'File paths that CC analyzed' },
|
|
193
193
|
focusAreas: { type: 'array', items: { type: 'string', enum: ['security', 'performance', 'architecture', 'correctness', 'maintainability', 'scalability', 'testing', 'documentation'] }, description: 'Areas to focus the review on' },
|
|
194
194
|
customPrompt: { type: 'string', description: 'Custom instructions for standard review + adversarial focus steering' },
|
|
195
|
-
serviceTier: { type: 'string', enum: ['default', 'fast', 'flex'], description: 'Codex service tier
|
|
195
|
+
serviceTier: { type: 'string', enum: ['default', 'fast', 'flex'], description: 'Codex service tier — only applies to Codex. Omit for fast default; fast = priority ~2x cost, flex = 50% cheaper/slower, default = API default tier.' }
|
|
196
196
|
},
|
|
197
197
|
required: ['workingDir', 'ccOutput', 'outputType']
|
|
198
198
|
}
|