@simonren/quorum 0.7.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/LICENSE +21 -0
- package/README.md +144 -0
- package/commands/multi-consult.md +109 -0
- package/commands/multi-review.md +139 -0
- package/dist/adapters/base.d.ts +120 -0
- package/dist/adapters/base.js +98 -0
- package/dist/adapters/claude.d.ts +25 -0
- package/dist/adapters/claude.js +217 -0
- package/dist/adapters/codex.d.ts +20 -0
- package/dist/adapters/codex.js +227 -0
- package/dist/adapters/gemini.d.ts +20 -0
- package/dist/adapters/gemini.js +197 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.js +15 -0
- package/dist/cli/check.d.ts +20 -0
- package/dist/cli/check.js +78 -0
- package/dist/cli/codex.d.ts +11 -0
- package/dist/cli/codex.js +255 -0
- package/dist/cli/gemini.d.ts +12 -0
- package/dist/cli/gemini.js +253 -0
- package/dist/commands.d.ts +28 -0
- package/dist/commands.js +105 -0
- package/dist/config.d.ts +244 -0
- package/dist/config.js +179 -0
- package/dist/consult-prompt.d.ts +10 -0
- package/dist/consult-prompt.js +72 -0
- package/dist/context.d.ts +1538 -0
- package/dist/context.js +383 -0
- package/dist/decoders/claude.d.ts +53 -0
- package/dist/decoders/claude.js +106 -0
- package/dist/decoders/codex.d.ts +71 -0
- package/dist/decoders/codex.js +145 -0
- package/dist/decoders/gemini.d.ts +33 -0
- package/dist/decoders/gemini.js +58 -0
- package/dist/decoders/index.d.ts +6 -0
- package/dist/decoders/index.js +3 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.js +192 -0
- package/dist/executor.d.ts +103 -0
- package/dist/executor.js +244 -0
- package/dist/handoff.d.ts +270 -0
- package/dist/handoff.js +599 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +134 -0
- package/dist/pipeline.d.ts +135 -0
- package/dist/pipeline.js +462 -0
- package/dist/prompt-v2.d.ts +38 -0
- package/dist/prompt-v2.js +391 -0
- package/dist/prompt.d.ts +71 -0
- package/dist/prompt.js +309 -0
- package/dist/schema.d.ts +660 -0
- package/dist/schema.js +536 -0
- package/dist/tools/consult.d.ts +104 -0
- package/dist/tools/consult.js +220 -0
- package/dist/tools/feedback.d.ts +91 -0
- package/dist/tools/feedback.js +117 -0
- package/dist/types.d.ts +105 -0
- package/dist/types.js +31 -0
- package/package.json +54 -0
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder for AI Review
|
|
3
|
+
*
|
|
4
|
+
* Builds structured prompts that request JSON output from external CLIs.
|
|
5
|
+
* Supports expert roles for specialized reviews.
|
|
6
|
+
*/
|
|
7
|
+
import { FOCUS_AREA_DESCRIPTIONS } from './types.js';
|
|
8
|
+
import { getReviewOutputJsonSchema } from './schema.js';
|
|
9
|
+
import { selectExpertRole, EXPERT_ROLES } from './adapters/base.js';
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// JSON SCHEMA PROMPT SECTION
|
|
12
|
+
// =============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Generate the JSON schema section for the prompt
|
|
15
|
+
*/
|
|
16
|
+
function buildJsonSchemaSection() {
|
|
17
|
+
const schema = getReviewOutputJsonSchema();
|
|
18
|
+
return `OUTPUT FORMAT (JSON):
|
|
19
|
+
You MUST respond with valid JSON matching this schema:
|
|
20
|
+
\`\`\`json
|
|
21
|
+
${JSON.stringify(schema, null, 2)}
|
|
22
|
+
\`\`\`
|
|
23
|
+
|
|
24
|
+
IMPORTANT:
|
|
25
|
+
- Output ONLY the JSON object, no markdown wrapping, no explanation before/after
|
|
26
|
+
- All fields marked "required" MUST be present
|
|
27
|
+
- Use empty arrays [] for sections with no findings
|
|
28
|
+
- Confidence scores are 0-1 (e.g., 0.85 for 85% confident)
|
|
29
|
+
- Severity levels: critical > high > medium > low > info
|
|
30
|
+
- Include file:line in location when you reference specific code`;
|
|
31
|
+
}
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// EXPERT ROLE PROMPT
|
|
34
|
+
// =============================================================================
|
|
35
|
+
/**
|
|
36
|
+
* Build the expert role section of the prompt
|
|
37
|
+
*/
|
|
38
|
+
function buildExpertSection(role) {
|
|
39
|
+
return `ROLE: ${role.name}
|
|
40
|
+
|
|
41
|
+
${role.systemPrompt}
|
|
42
|
+
|
|
43
|
+
EVALUATION CRITERIA:
|
|
44
|
+
${role.evaluationCriteria.map((c, i) => `${i + 1}. ${c}`).join('\n')}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build the main review prompt
|
|
48
|
+
*/
|
|
49
|
+
export function buildReviewPrompt(options) {
|
|
50
|
+
const { request, expertRole, reviewerName, useJsonOutput = true, retryContext, } = options;
|
|
51
|
+
const role = expertRole || selectExpertRole(request.focusAreas);
|
|
52
|
+
const focusDescription = request.focusAreas && request.focusAreas.length > 0
|
|
53
|
+
? request.focusAreas.map(f => `${f} (${FOCUS_AREA_DESCRIPTIONS[f]})`).join(', ')
|
|
54
|
+
: 'General review';
|
|
55
|
+
const filesAnalyzed = request.analyzedFiles && request.analyzedFiles.length > 0
|
|
56
|
+
? request.analyzedFiles.join(', ')
|
|
57
|
+
: 'Not specified';
|
|
58
|
+
const sections = [];
|
|
59
|
+
// Section 1: Expert Role
|
|
60
|
+
sections.push(buildExpertSection(role));
|
|
61
|
+
// Section 2: Task Description
|
|
62
|
+
sections.push(`
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
TASK: Review Claude Code's ${request.outputType} and provide structured feedback.
|
|
66
|
+
|
|
67
|
+
You are reviewing another AI assistant's (Claude Code) analysis of a codebase.
|
|
68
|
+
Your job is to:
|
|
69
|
+
1. VALIDATE correct findings (agreements)
|
|
70
|
+
2. CHALLENGE incorrect assessments (disagreements)
|
|
71
|
+
3. ADD issues they missed (new findings)
|
|
72
|
+
4. SUGGEST alternatives where applicable
|
|
73
|
+
5. ASSESS overall risk`);
|
|
74
|
+
// Section 3: Context
|
|
75
|
+
sections.push(`
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
CONTEXT:
|
|
79
|
+
Working Directory: ${request.workingDir}
|
|
80
|
+
Output Type: ${request.outputType}
|
|
81
|
+
Focus Areas: ${focusDescription}
|
|
82
|
+
Files Analyzed: ${filesAnalyzed}
|
|
83
|
+
Reviewer ID: ${reviewerName}
|
|
84
|
+
|
|
85
|
+
CLAUDE CODE'S OUTPUT TO REVIEW:
|
|
86
|
+
\`\`\`
|
|
87
|
+
${request.ccOutput}
|
|
88
|
+
\`\`\``);
|
|
89
|
+
// Section 4: Custom Instructions
|
|
90
|
+
if (request.customPrompt) {
|
|
91
|
+
sections.push(`
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
ADDITIONAL INSTRUCTIONS:
|
|
95
|
+
${request.customPrompt}`);
|
|
96
|
+
}
|
|
97
|
+
// Section 5: Constraints
|
|
98
|
+
sections.push(`
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
CONSTRAINTS:
|
|
102
|
+
• You have filesystem access - READ files to verify claims
|
|
103
|
+
• Do NOT modify any files (advisory mode only)
|
|
104
|
+
• Do NOT assume a git repository exists - do NOT run git commands
|
|
105
|
+
• Reference specific file:line when making claims
|
|
106
|
+
• Do NOT hallucinate file paths - verify they exist
|
|
107
|
+
• Be skeptical - verify before agreeing with CC's findings`);
|
|
108
|
+
// Section 6: Output Format
|
|
109
|
+
if (useJsonOutput) {
|
|
110
|
+
sections.push(`
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
${buildJsonSchemaSection()}`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Legacy markdown format for backwards compatibility
|
|
117
|
+
sections.push(`
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
OUTPUT FORMAT (Markdown):
|
|
121
|
+
## Agreements
|
|
122
|
+
- [Finding]: [Why correct]
|
|
123
|
+
|
|
124
|
+
## Disagreements
|
|
125
|
+
- [Finding]: [Why wrong] - [Correct assessment]
|
|
126
|
+
|
|
127
|
+
## Additions
|
|
128
|
+
- [New finding]: [File:line] - [Impact]
|
|
129
|
+
|
|
130
|
+
## Alternatives
|
|
131
|
+
- [Topic]: [Alternative] - [Tradeoffs]
|
|
132
|
+
|
|
133
|
+
## Risk Assessment
|
|
134
|
+
[Low/Medium/High] - [Reason]`);
|
|
135
|
+
}
|
|
136
|
+
// Section 7: Retry Context (if applicable)
|
|
137
|
+
if (retryContext) {
|
|
138
|
+
sections.push(`
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
⚠️ RETRY ATTEMPT ${retryContext.attemptNumber}/3
|
|
142
|
+
|
|
143
|
+
Previous attempt failed with: ${retryContext.previousError}
|
|
144
|
+
|
|
145
|
+
Previous output (truncated):
|
|
146
|
+
${retryContext.previousOutput.slice(0, 500)}...
|
|
147
|
+
|
|
148
|
+
Please ensure your response is valid JSON matching the schema exactly.`);
|
|
149
|
+
}
|
|
150
|
+
return sections.join('\n');
|
|
151
|
+
}
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// PEER REVIEW PROMPT
|
|
154
|
+
// =============================================================================
|
|
155
|
+
/**
|
|
156
|
+
* Build a prompt for peer review (one model reviewing another's output)
|
|
157
|
+
*/
|
|
158
|
+
export function buildPeerReviewPrompt(reviewerName, anonymizedReviewerId, reviewToScore, originalCcOutput) {
|
|
159
|
+
return `ROLE: Peer Reviewer
|
|
160
|
+
|
|
161
|
+
You are evaluating another AI reviewer's analysis for accuracy and quality.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
ORIGINAL TASK:
|
|
166
|
+
Claude Code produced this output that was being reviewed:
|
|
167
|
+
\`\`\`
|
|
168
|
+
${originalCcOutput}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
REVIEW TO EVALUATE (from ${anonymizedReviewerId}):
|
|
174
|
+
\`\`\`
|
|
175
|
+
${reviewToScore}
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
TASK: Score each finding in the review above.
|
|
181
|
+
|
|
182
|
+
For each finding, assess:
|
|
183
|
+
1. Is the finding valid? (Does the issue actually exist in the code?)
|
|
184
|
+
2. Is it correctly categorized and described?
|
|
185
|
+
3. Is the evidence accurate?
|
|
186
|
+
|
|
187
|
+
OUTPUT FORMAT (JSON):
|
|
188
|
+
{
|
|
189
|
+
"reviewer": "${reviewerName}",
|
|
190
|
+
"reviewed_model": "${anonymizedReviewerId}",
|
|
191
|
+
"scores": [
|
|
192
|
+
{
|
|
193
|
+
"finding_id": "<id from the review>",
|
|
194
|
+
"validity": "valid" | "questionable" | "invalid" | "cannot_assess",
|
|
195
|
+
"confidence": 0.0-1.0,
|
|
196
|
+
"notes": "<optional explanation>"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"overall_quality": 0.0-1.0,
|
|
200
|
+
"summary": "<brief assessment of the review quality>"
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
Output ONLY the JSON, no other text.`;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Legacy function - builds old-style 7-section prompt
|
|
207
|
+
* @deprecated Use buildReviewPrompt instead
|
|
208
|
+
*/
|
|
209
|
+
export function build7SectionPrompt(request) {
|
|
210
|
+
return buildReviewPrompt({
|
|
211
|
+
request: {
|
|
212
|
+
workingDir: request.workingDir,
|
|
213
|
+
ccOutput: request.ccOutput,
|
|
214
|
+
outputType: request.outputType,
|
|
215
|
+
analyzedFiles: request.analyzedFiles,
|
|
216
|
+
focusAreas: request.focusAreas,
|
|
217
|
+
customPrompt: request.customPrompt,
|
|
218
|
+
},
|
|
219
|
+
reviewerName: 'external',
|
|
220
|
+
useJsonOutput: false, // Legacy uses markdown
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Legacy function - builds developer instructions
|
|
225
|
+
* @deprecated Use buildReviewPrompt with expertRole instead
|
|
226
|
+
*/
|
|
227
|
+
export function buildDeveloperInstructions(cli) {
|
|
228
|
+
const roleMap = {
|
|
229
|
+
codex: EXPERT_ROLES.correctness_analyst,
|
|
230
|
+
gemini: EXPERT_ROLES.architect,
|
|
231
|
+
};
|
|
232
|
+
return buildExpertSection(roleMap[cli]);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Legacy function - builds retry prompt
|
|
236
|
+
* @deprecated Use buildReviewPrompt with retryContext instead
|
|
237
|
+
*/
|
|
238
|
+
export function buildRetryPrompt(request, attemptNumber, previousError, previousOutput) {
|
|
239
|
+
return buildReviewPrompt({
|
|
240
|
+
request: {
|
|
241
|
+
workingDir: request.workingDir,
|
|
242
|
+
ccOutput: request.ccOutput,
|
|
243
|
+
outputType: request.outputType,
|
|
244
|
+
analyzedFiles: request.analyzedFiles,
|
|
245
|
+
focusAreas: request.focusAreas,
|
|
246
|
+
customPrompt: request.customPrompt,
|
|
247
|
+
},
|
|
248
|
+
reviewerName: 'external',
|
|
249
|
+
useJsonOutput: false,
|
|
250
|
+
retryContext: {
|
|
251
|
+
attemptNumber,
|
|
252
|
+
previousError,
|
|
253
|
+
previousOutput,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Validate feedback output structure
|
|
259
|
+
* Now supports both JSON and legacy markdown formats
|
|
260
|
+
*/
|
|
261
|
+
export function isValidFeedbackOutput(output) {
|
|
262
|
+
// Try JSON first
|
|
263
|
+
try {
|
|
264
|
+
const jsonMatch = output.match(/```(?:json)?\s*([\s\S]*?)```/) || [null, output];
|
|
265
|
+
let jsonStr = jsonMatch[1] || output;
|
|
266
|
+
const jsonStart = jsonStr.indexOf('{');
|
|
267
|
+
const jsonEnd = jsonStr.lastIndexOf('}');
|
|
268
|
+
if (jsonStart !== -1 && jsonEnd !== -1) {
|
|
269
|
+
jsonStr = jsonStr.slice(jsonStart, jsonEnd + 1);
|
|
270
|
+
const parsed = JSON.parse(jsonStr);
|
|
271
|
+
// Check for required fields
|
|
272
|
+
if (parsed.findings !== undefined &&
|
|
273
|
+
parsed.agreements !== undefined &&
|
|
274
|
+
parsed.disagreements !== undefined &&
|
|
275
|
+
parsed.risk_assessment !== undefined) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// Not valid JSON, try markdown
|
|
282
|
+
}
|
|
283
|
+
// Legacy markdown validation
|
|
284
|
+
const requiredSections = [
|
|
285
|
+
/^## Agreements$/m,
|
|
286
|
+
/^## Disagreements$/m,
|
|
287
|
+
/^## Additions$/m,
|
|
288
|
+
/^## Alternatives$/m,
|
|
289
|
+
/^## Risk Assessment$/m
|
|
290
|
+
];
|
|
291
|
+
const hasRequiredSections = requiredSections.every(regex => regex.test(output));
|
|
292
|
+
const hasContent = output.length > 100;
|
|
293
|
+
return hasRequiredSections && hasContent;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Detect output type from CC's output content
|
|
297
|
+
*/
|
|
298
|
+
export function detectOutputType(ccOutput) {
|
|
299
|
+
if (/\b(vulnerab|injection|XSS|CSRF|SSRF|auth.*issue|security)/i.test(ccOutput)) {
|
|
300
|
+
return 'findings';
|
|
301
|
+
}
|
|
302
|
+
if (/\b(fix|bug|issue|error|proposed fix|solution|patch)/i.test(ccOutput)) {
|
|
303
|
+
return 'proposal';
|
|
304
|
+
}
|
|
305
|
+
if (/\b(architect|design|plan|implement|phase|step \d|structure)/i.test(ccOutput)) {
|
|
306
|
+
return 'plan';
|
|
307
|
+
}
|
|
308
|
+
return 'analysis';
|
|
309
|
+
}
|