review-council 1.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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/dist/config/defaults.d.ts +17 -0
  4. package/dist/config/defaults.js +27 -0
  5. package/dist/config/defaults.js.map +1 -0
  6. package/dist/config/loader.d.ts +2 -0
  7. package/dist/config/loader.js +66 -0
  8. package/dist/config/loader.js.map +1 -0
  9. package/dist/config/schema.d.ts +79 -0
  10. package/dist/config/schema.js +49 -0
  11. package/dist/config/schema.js.map +1 -0
  12. package/dist/consensus/deduper.d.ts +6 -0
  13. package/dist/consensus/deduper.js +127 -0
  14. package/dist/consensus/deduper.js.map +1 -0
  15. package/dist/consensus/parser.d.ts +6 -0
  16. package/dist/consensus/parser.js +90 -0
  17. package/dist/consensus/parser.js.map +1 -0
  18. package/dist/consensus/types.d.ts +57 -0
  19. package/dist/consensus/types.js +2 -0
  20. package/dist/consensus/types.js.map +1 -0
  21. package/dist/consensus/voter.d.ts +3 -0
  22. package/dist/consensus/voter.js +198 -0
  23. package/dist/consensus/voter.js.map +1 -0
  24. package/dist/dispatch/adapter.d.ts +15 -0
  25. package/dist/dispatch/adapter.js +24 -0
  26. package/dist/dispatch/adapter.js.map +1 -0
  27. package/dist/dispatch/anthropic.d.ts +9 -0
  28. package/dist/dispatch/anthropic.js +132 -0
  29. package/dist/dispatch/anthropic.js.map +1 -0
  30. package/dist/dispatch/google.d.ts +9 -0
  31. package/dist/dispatch/google.js +87 -0
  32. package/dist/dispatch/google.js.map +1 -0
  33. package/dist/dispatch/openai-compat.d.ts +18 -0
  34. package/dist/dispatch/openai-compat.js +90 -0
  35. package/dist/dispatch/openai-compat.js.map +1 -0
  36. package/dist/dispatch/openai.d.ts +9 -0
  37. package/dist/dispatch/openai.js +90 -0
  38. package/dist/dispatch/openai.js.map +1 -0
  39. package/dist/dispatch/runner.d.ts +11 -0
  40. package/dist/dispatch/runner.js +67 -0
  41. package/dist/dispatch/runner.js.map +1 -0
  42. package/dist/dispatch/utils.d.ts +6 -0
  43. package/dist/dispatch/utils.js +15 -0
  44. package/dist/dispatch/utils.js.map +1 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/index.js +262 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/output/github.d.ts +3 -0
  49. package/dist/output/github.js +95 -0
  50. package/dist/output/github.js.map +1 -0
  51. package/dist/output/json.d.ts +3 -0
  52. package/dist/output/json.js +8 -0
  53. package/dist/output/json.js.map +1 -0
  54. package/dist/output/markdown.d.ts +3 -0
  55. package/dist/output/markdown.js +81 -0
  56. package/dist/output/markdown.js.map +1 -0
  57. package/dist/output/terminal.d.ts +2 -0
  58. package/dist/output/terminal.js +141 -0
  59. package/dist/output/terminal.js.map +1 -0
  60. package/dist/prepare/chunker.d.ts +9 -0
  61. package/dist/prepare/chunker.js +62 -0
  62. package/dist/prepare/chunker.js.map +1 -0
  63. package/dist/prepare/language.d.ts +1 -0
  64. package/dist/prepare/language.js +99 -0
  65. package/dist/prepare/language.js.map +1 -0
  66. package/dist/prepare/prompt-builder.d.ts +11 -0
  67. package/dist/prepare/prompt-builder.js +65 -0
  68. package/dist/prepare/prompt-builder.js.map +1 -0
  69. package/dist/prompts/base.d.ts +3 -0
  70. package/dist/prompts/base.js +53 -0
  71. package/dist/prompts/base.js.map +1 -0
  72. package/dist/prompts/hardening.d.ts +7 -0
  73. package/dist/prompts/hardening.js +30 -0
  74. package/dist/prompts/hardening.js.map +1 -0
  75. package/dist/prompts/languages/elixir.d.ts +1 -0
  76. package/dist/prompts/languages/elixir.js +13 -0
  77. package/dist/prompts/languages/elixir.js.map +1 -0
  78. package/dist/prompts/languages/generic.d.ts +1 -0
  79. package/dist/prompts/languages/generic.js +11 -0
  80. package/dist/prompts/languages/generic.js.map +1 -0
  81. package/dist/prompts/languages/python.d.ts +1 -0
  82. package/dist/prompts/languages/python.js +14 -0
  83. package/dist/prompts/languages/python.js.map +1 -0
  84. package/dist/prompts/languages/typescript.d.ts +1 -0
  85. package/dist/prompts/languages/typescript.js +13 -0
  86. package/dist/prompts/languages/typescript.js.map +1 -0
  87. package/dist/resolver/github.d.ts +8 -0
  88. package/dist/resolver/github.js +70 -0
  89. package/dist/resolver/github.js.map +1 -0
  90. package/dist/resolver/local.d.ts +3 -0
  91. package/dist/resolver/local.js +75 -0
  92. package/dist/resolver/local.js.map +1 -0
  93. package/dist/resolver/types.d.ts +28 -0
  94. package/dist/resolver/types.js +2 -0
  95. package/dist/resolver/types.js.map +1 -0
  96. package/dist/roles/builtin.d.ts +4 -0
  97. package/dist/roles/builtin.js +234 -0
  98. package/dist/roles/builtin.js.map +1 -0
  99. package/dist/roles/dispatcher.d.ts +23 -0
  100. package/dist/roles/dispatcher.js +87 -0
  101. package/dist/roles/dispatcher.js.map +1 -0
  102. package/dist/roles/loader.d.ts +11 -0
  103. package/dist/roles/loader.js +107 -0
  104. package/dist/roles/loader.js.map +1 -0
  105. package/dist/roles/types.d.ts +13 -0
  106. package/dist/roles/types.js +2 -0
  107. package/dist/roles/types.js.map +1 -0
  108. package/package.json +67 -0
@@ -0,0 +1,87 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import { parseReviewOutput } from '../consensus/parser.js';
3
+ import { stripKnownProviderPrefix } from './utils.js';
4
+ const RETRY_DELAYS = [1000, 2000, 4000];
5
+ export class GoogleAdapter {
6
+ name = 'google';
7
+ provider = 'google';
8
+ client;
9
+ constructor(apiKey) {
10
+ this.client = new GoogleGenAI({
11
+ apiKey: apiKey ?? process.env['GOOGLE_API_KEY'] ?? process.env['GEMINI_API_KEY'],
12
+ });
13
+ }
14
+ async review(model, role, systemPrompt, userPrompt, options) {
15
+ const start = Date.now();
16
+ let lastErr = new Error('no attempts made');
17
+ const modelId = stripKnownProviderPrefix(model);
18
+ for (let attempt = 0; attempt <= (options.maxRetries ?? 3); attempt++) {
19
+ try {
20
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), options.timeoutMs));
21
+ const callPromise = this.client.models.generateContent({
22
+ model: modelId,
23
+ contents: [
24
+ {
25
+ role: 'user',
26
+ parts: [{ text: userPrompt }],
27
+ },
28
+ ],
29
+ config: {
30
+ systemInstruction: systemPrompt,
31
+ responseMimeType: 'application/json',
32
+ maxOutputTokens: 4096,
33
+ },
34
+ });
35
+ const response = await Promise.race([callPromise, timeoutPromise]);
36
+ const rawOutput = response.text ?? '';
37
+ const { findings, warnings } = parseReviewOutput(rawOutput, model, role);
38
+ for (const w of warnings)
39
+ console.warn(w);
40
+ return {
41
+ model,
42
+ role,
43
+ provider: 'google',
44
+ findings,
45
+ durationMs: Date.now() - start,
46
+ status: 'success',
47
+ };
48
+ }
49
+ catch (err) {
50
+ lastErr = err;
51
+ if (err instanceof Error && err.message === 'TIMEOUT') {
52
+ return {
53
+ model,
54
+ role,
55
+ provider: 'google',
56
+ findings: [],
57
+ durationMs: Date.now() - start,
58
+ status: 'timeout',
59
+ error: 'Request timed out',
60
+ };
61
+ }
62
+ const errStr = String(err);
63
+ const isRetryable = errStr.includes('429') ||
64
+ errStr.includes('500') ||
65
+ errStr.includes('503') ||
66
+ errStr.includes('RESOURCE_EXHAUSTED');
67
+ if (isRetryable && attempt < (options.maxRetries ?? 3)) {
68
+ const delay = RETRY_DELAYS[attempt] ?? 4000;
69
+ await new Promise((r) => setTimeout(r, delay));
70
+ continue;
71
+ }
72
+ break;
73
+ }
74
+ }
75
+ const errMsg = lastErr instanceof Error ? `${lastErr.name}: ${lastErr.message}` : String(lastErr);
76
+ return {
77
+ model,
78
+ role,
79
+ provider: 'google',
80
+ findings: [],
81
+ durationMs: Date.now() - start,
82
+ status: 'error',
83
+ error: errMsg,
84
+ };
85
+ }
86
+ }
87
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/dispatch/google.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ModelReview } from '../consensus/types.js';
2
+ import type { ReviewAdapter, AdapterOptions } from './adapter.js';
3
+ /**
4
+ * Generic OpenAI-compatible adapter for local models (Ollama, LM Studio, etc.)
5
+ * and other OpenAI-compatible APIs.
6
+ */
7
+ export declare class OpenAICompatAdapter implements ReviewAdapter {
8
+ name: string;
9
+ provider: string;
10
+ private client;
11
+ private useJsonMode;
12
+ constructor(opts?: {
13
+ apiKey?: string;
14
+ baseUrl?: string;
15
+ useJsonMode?: boolean;
16
+ });
17
+ review(model: string, role: string, systemPrompt: string, userPrompt: string, options: AdapterOptions): Promise<ModelReview>;
18
+ }
@@ -0,0 +1,90 @@
1
+ import OpenAI from 'openai';
2
+ import { parseReviewOutput } from '../consensus/parser.js';
3
+ const RETRY_DELAYS = [1000, 2000, 4000];
4
+ /**
5
+ * Generic OpenAI-compatible adapter for local models (Ollama, LM Studio, etc.)
6
+ * and other OpenAI-compatible APIs.
7
+ */
8
+ export class OpenAICompatAdapter {
9
+ name = 'openai-compat';
10
+ provider = 'openai-compat';
11
+ client;
12
+ useJsonMode;
13
+ constructor(opts) {
14
+ this.client = new OpenAI({
15
+ apiKey: opts?.apiKey ?? process.env['OPENAI_COMPAT_API_KEY'] ?? 'local',
16
+ baseURL: opts?.baseUrl ?? process.env['OPENAI_COMPAT_BASE_URL'] ?? 'http://localhost:11434/v1',
17
+ });
18
+ this.useJsonMode = opts?.useJsonMode ?? true;
19
+ }
20
+ async review(model, role, systemPrompt, userPrompt, options) {
21
+ const start = Date.now();
22
+ const controller = new AbortController();
23
+ const timeoutHandle = setTimeout(() => controller.abort(), options.timeoutMs);
24
+ let lastErr = new Error('no attempts made');
25
+ for (let attempt = 0; attempt <= (options.maxRetries ?? 3); attempt++) {
26
+ try {
27
+ const createParams = {
28
+ model,
29
+ messages: [
30
+ { role: 'system', content: systemPrompt },
31
+ { role: 'user', content: userPrompt },
32
+ ],
33
+ max_tokens: 4096,
34
+ };
35
+ if (this.useJsonMode) {
36
+ createParams.response_format = { type: 'json_object' };
37
+ }
38
+ const response = await this.client.chat.completions.create(createParams, { signal: controller.signal });
39
+ clearTimeout(timeoutHandle);
40
+ const rawOutput = response.choices[0]?.message?.content ?? '';
41
+ const { findings, warnings } = parseReviewOutput(rawOutput, model, role);
42
+ for (const w of warnings)
43
+ console.warn(w);
44
+ return {
45
+ model,
46
+ role,
47
+ provider: 'openai-compat',
48
+ findings,
49
+ durationMs: Date.now() - start,
50
+ status: 'success',
51
+ };
52
+ }
53
+ catch (err) {
54
+ lastErr = err;
55
+ if (err instanceof Error && err.name === 'AbortError') {
56
+ clearTimeout(timeoutHandle);
57
+ return {
58
+ model,
59
+ role,
60
+ provider: 'openai-compat',
61
+ findings: [],
62
+ durationMs: Date.now() - start,
63
+ status: 'timeout',
64
+ error: 'Request timed out',
65
+ };
66
+ }
67
+ if (err instanceof OpenAI.APIError &&
68
+ (err.status === 429 || err.status === 500 || err.status === 503) &&
69
+ attempt < (options.maxRetries ?? 3)) {
70
+ const delay = RETRY_DELAYS[attempt] ?? 4000;
71
+ await new Promise((r) => setTimeout(r, delay));
72
+ continue;
73
+ }
74
+ break;
75
+ }
76
+ }
77
+ clearTimeout(timeoutHandle);
78
+ const errMsg = lastErr instanceof Error ? `${lastErr.name}: ${lastErr.message}` : String(lastErr);
79
+ return {
80
+ model,
81
+ role,
82
+ provider: 'openai-compat',
83
+ findings: [],
84
+ durationMs: Date.now() - start,
85
+ status: 'error',
86
+ error: errMsg,
87
+ };
88
+ }
89
+ }
90
+ //# sourceMappingURL=openai-compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compat.js","sourceRoot":"","sources":["../../src/dispatch/openai-compat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ModelReview } from '../consensus/types.js';
2
+ import type { ReviewAdapter, AdapterOptions } from './adapter.js';
3
+ export declare class OpenAIAdapter implements ReviewAdapter {
4
+ name: string;
5
+ provider: string;
6
+ private client;
7
+ constructor(apiKey?: string, baseUrl?: string);
8
+ review(model: string, role: string, systemPrompt: string, userPrompt: string, options: AdapterOptions): Promise<ModelReview>;
9
+ }
@@ -0,0 +1,90 @@
1
+ import OpenAI from 'openai';
2
+ import { parseReviewOutput } from '../consensus/parser.js';
3
+ import { stripKnownProviderPrefix } from './utils.js';
4
+ const RETRY_DELAYS = [1000, 2000, 4000];
5
+ function isRetryable(status) {
6
+ return status === 429 || status === 500 || status === 503;
7
+ }
8
+ export class OpenAIAdapter {
9
+ name = 'openai';
10
+ provider = 'openai';
11
+ client;
12
+ constructor(apiKey, baseUrl) {
13
+ this.client = new OpenAI({
14
+ apiKey: apiKey ?? process.env['OPENAI_API_KEY'],
15
+ baseURL: baseUrl,
16
+ });
17
+ }
18
+ async review(model, role, systemPrompt, userPrompt, options) {
19
+ const start = Date.now();
20
+ const controller = new AbortController();
21
+ const timeoutHandle = setTimeout(() => controller.abort(), options.timeoutMs);
22
+ let lastErr = new Error('no attempts made');
23
+ const modelId = stripKnownProviderPrefix(model);
24
+ // Use max_completion_tokens for gpt-5.x and o-series; max_tokens for everything else
25
+ const usesCompletionTokens = modelId.startsWith('gpt-5') || /^o[134]/.test(modelId);
26
+ for (let attempt = 0; attempt <= (options.maxRetries ?? 3); attempt++) {
27
+ try {
28
+ const response = await this.client.chat.completions.create({
29
+ model: modelId,
30
+ messages: [
31
+ { role: 'system', content: systemPrompt },
32
+ { role: 'user', content: userPrompt },
33
+ ],
34
+ response_format: { type: 'json_object' },
35
+ ...(usesCompletionTokens
36
+ ? { max_completion_tokens: 4096 }
37
+ : { max_tokens: 4096 }),
38
+ }, { signal: controller.signal });
39
+ clearTimeout(timeoutHandle);
40
+ const rawOutput = response.choices[0]?.message?.content ?? '';
41
+ const { findings, warnings } = parseReviewOutput(rawOutput, model, role);
42
+ for (const w of warnings)
43
+ console.warn(w);
44
+ return {
45
+ model,
46
+ role,
47
+ provider: 'openai',
48
+ findings,
49
+ durationMs: Date.now() - start,
50
+ status: 'success',
51
+ };
52
+ }
53
+ catch (err) {
54
+ lastErr = err;
55
+ if (err instanceof Error && err.name === 'AbortError') {
56
+ clearTimeout(timeoutHandle);
57
+ return {
58
+ model,
59
+ role,
60
+ provider: 'openai',
61
+ findings: [],
62
+ durationMs: Date.now() - start,
63
+ status: 'timeout',
64
+ error: 'Request timed out',
65
+ };
66
+ }
67
+ if (err instanceof OpenAI.APIError &&
68
+ isRetryable(err.status ?? 0) &&
69
+ attempt < (options.maxRetries ?? 3)) {
70
+ const delay = RETRY_DELAYS[attempt] ?? 4000;
71
+ await new Promise((r) => setTimeout(r, delay));
72
+ continue;
73
+ }
74
+ break;
75
+ }
76
+ }
77
+ clearTimeout(timeoutHandle);
78
+ const errMsg = lastErr instanceof Error ? `${lastErr.name}: ${lastErr.message}` : String(lastErr);
79
+ return {
80
+ model,
81
+ role,
82
+ provider: 'openai',
83
+ findings: [],
84
+ durationMs: Date.now() - start,
85
+ status: 'error',
86
+ error: errMsg,
87
+ };
88
+ }
89
+ }
90
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/dispatch/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ModelReview } from '../consensus/types.js';
2
+ import type { ReviewAssignment } from '../roles/types.js';
3
+ import type { BuiltPrompt } from '../prepare/prompt-builder.js';
4
+ export interface RunnerOptions {
5
+ timeoutMs: number;
6
+ maxRetries: number;
7
+ concurrency: number;
8
+ verbose?: boolean;
9
+ onReviewComplete?: (review: ModelReview) => void;
10
+ }
11
+ export declare function runReviews(assignments: ReviewAssignment[], prompts: BuiltPrompt[], options: RunnerOptions): Promise<ModelReview[]>;
@@ -0,0 +1,67 @@
1
+ import { AnthropicAdapter } from './anthropic.js';
2
+ import { OpenAIAdapter } from './openai.js';
3
+ import { GoogleAdapter } from './google.js';
4
+ import { OpenAICompatAdapter } from './openai-compat.js';
5
+ function getAdapter(provider) {
6
+ switch (provider) {
7
+ case 'anthropic':
8
+ return new AnthropicAdapter();
9
+ case 'openai':
10
+ return new OpenAIAdapter();
11
+ case 'google':
12
+ return new GoogleAdapter();
13
+ default:
14
+ return new OpenAICompatAdapter();
15
+ }
16
+ }
17
+ async function runBatch(calls, options) {
18
+ const adapterOpts = {
19
+ timeoutMs: options.timeoutMs,
20
+ maxRetries: options.maxRetries,
21
+ };
22
+ const results = await Promise.allSettled(calls.map(async (call) => {
23
+ const adapter = getAdapter(call.provider);
24
+ const review = await adapter.review(call.model, call.role, call.systemPrompt, call.userPrompt, adapterOpts);
25
+ if (review.status === 'error' && options.verbose) {
26
+ console.error(`${call.model}/${call.role}: ${review.error}`);
27
+ }
28
+ options.onReviewComplete?.(review);
29
+ return review;
30
+ }));
31
+ return results.map((r, i) => {
32
+ if (r.status === 'fulfilled')
33
+ return r.value;
34
+ const call = calls[i];
35
+ return {
36
+ model: call.model,
37
+ role: call.role,
38
+ provider: call.provider,
39
+ findings: [],
40
+ durationMs: 0,
41
+ status: 'error',
42
+ error: String(r.reason),
43
+ };
44
+ });
45
+ }
46
+ export async function runReviews(assignments, prompts, options) {
47
+ if (assignments.length !== prompts.length) {
48
+ throw new Error('assignments and prompts arrays must have same length');
49
+ }
50
+ const calls = assignments.map((a, i) => ({
51
+ model: a.model,
52
+ role: a.role.name,
53
+ provider: a.provider,
54
+ systemPrompt: prompts[i].systemPrompt,
55
+ userPrompt: prompts[i].userPrompt,
56
+ }));
57
+ // Process in batches of concurrency size
58
+ const { concurrency } = options;
59
+ const allResults = [];
60
+ for (let i = 0; i < calls.length; i += concurrency) {
61
+ const batch = calls.slice(i, i + concurrency);
62
+ const batchResults = await runBatch(batch, options);
63
+ allResults.push(...batchResults);
64
+ }
65
+ return allResults;
66
+ }
67
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/dispatch/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Strip a known provider prefix from a model name.
3
+ * Only removes anthropic/, openai/, or google/ prefixes.
4
+ * Returns the model name unchanged if no known prefix is found.
5
+ */
6
+ export declare function stripKnownProviderPrefix(model: string): string;
@@ -0,0 +1,15 @@
1
+ const KNOWN_PROVIDER_PREFIXES = ['anthropic/', 'openai/', 'google/'];
2
+ /**
3
+ * Strip a known provider prefix from a model name.
4
+ * Only removes anthropic/, openai/, or google/ prefixes.
5
+ * Returns the model name unchanged if no known prefix is found.
6
+ */
7
+ export function stripKnownProviderPrefix(model) {
8
+ for (const prefix of KNOWN_PROVIDER_PREFIXES) {
9
+ if (model.startsWith(prefix)) {
10
+ return model.slice(prefix.length);
11
+ }
12
+ }
13
+ return model;
14
+ }
15
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/dispatch/utils.ts"],"names":[],"mappings":"AAAA,MAAM,uBAAuB,GAAG,CAAC,YAAY,EAAE,SAAS,EAAE,SAAS,CAAU,CAAC;AAE9E;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAa;IACpD,KAAK,MAAM,MAAM,IAAI,uBAAuB,EAAE,CAAC;QAC7C,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};