@lanjak/council 0.0.0-stage → 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 +512 -2
- package/dist/artifacts.d.ts +24 -0
- package/dist/artifacts.js +227 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/blocks.d.ts +12 -0
- package/dist/blocks.js +197 -0
- package/dist/blocks.js.map +1 -0
- package/dist/chairman.d.ts +7 -0
- package/dist/chairman.js +51 -0
- package/dist/chairman.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +109 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/debate.d.ts +15 -0
- package/dist/commands/debate.js +172 -0
- package/dist/commands/debate.js.map +1 -0
- package/dist/commands/home.d.ts +1 -0
- package/dist/commands/home.js +27 -0
- package/dist/commands/home.js.map +1 -0
- package/dist/commands/hook.d.ts +3 -0
- package/dist/commands/hook.js +138 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/plan.d.ts +6 -0
- package/dist/commands/plan.js +23 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/review.d.ts +18 -0
- package/dist/commands/review.js +37 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +23 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +101 -0
- package/dist/config.js.map +1 -0
- package/dist/council.d.ts +3 -0
- package/dist/council.js +61 -0
- package/dist/council.js.map +1 -0
- package/dist/debate/loop.d.ts +28 -0
- package/dist/debate/loop.js +188 -0
- package/dist/debate/loop.js.map +1 -0
- package/dist/debate/prompts.d.ts +10 -0
- package/dist/debate/prompts.js +47 -0
- package/dist/debate/prompts.js.map +1 -0
- package/dist/debate/render.d.ts +22 -0
- package/dist/debate/render.js +112 -0
- package/dist/debate/render.js.map +1 -0
- package/dist/debate/session.d.ts +7 -0
- package/dist/debate/session.js +85 -0
- package/dist/debate/session.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/exit.d.ts +7 -0
- package/dist/exit.js +13 -0
- package/dist/exit.js.map +1 -0
- package/dist/hooks/gate.d.ts +12 -0
- package/dist/hooks/gate.js +41 -0
- package/dist/hooks/gate.js.map +1 -0
- package/dist/hooks/payload.d.ts +8 -0
- package/dist/hooks/payload.js +63 -0
- package/dist/hooks/payload.js.map +1 -0
- package/dist/hooks/state.d.ts +6 -0
- package/dist/hooks/state.js +73 -0
- package/dist/hooks/state.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +14 -0
- package/dist/input.js +30 -0
- package/dist/input.js.map +1 -0
- package/dist/output.d.ts +3 -0
- package/dist/output.js +80 -0
- package/dist/output.js.map +1 -0
- package/dist/prompts.d.ts +3 -0
- package/dist/prompts.js +48 -0
- package/dist/prompts.js.map +1 -0
- package/dist/providers/anthropic.d.ts +12 -0
- package/dist/providers/anthropic.js +98 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +35 -0
- package/dist/providers/base.js +7 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/constants.d.ts +2 -0
- package/dist/providers/constants.js +11 -0
- package/dist/providers/constants.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +20 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +12 -0
- package/dist/providers/openai-compatible.js +68 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/runners/plan.d.ts +14 -0
- package/dist/runners/plan.js +43 -0
- package/dist/runners/plan.js.map +1 -0
- package/dist/runners/review.d.ts +14 -0
- package/dist/runners/review.js +45 -0
- package/dist/runners/review.js.map +1 -0
- package/dist/stdin.d.ts +9 -0
- package/dist/stdin.js +51 -0
- package/dist/stdin.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +2 -0
- package/dist/verdict.js +12 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +54 -4
- package/skills/council/SKILL.md +82 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { execFileSync, execSync } from 'node:child_process';
|
|
4
|
+
import ignore from 'ignore';
|
|
5
|
+
import { CouncilError } from './errors.js';
|
|
6
|
+
// Prefix recognized on a --file value to source artifact content from a
|
|
7
|
+
// command's stdout instead of the filesystem - for content that has no
|
|
8
|
+
// physical file at all (e.g. docs stored in a database and fetched through
|
|
9
|
+
// a CLI), so callers don't need a "write to a temp file, pass --file,
|
|
10
|
+
// remember to clean it up" workaround.
|
|
11
|
+
const CMD_PREFIX = 'cmd:';
|
|
12
|
+
export const DEFAULT_CAP_BYTES = 400_000;
|
|
13
|
+
const ALWAYS_SKIP = new Set(['node_modules', '.git']);
|
|
14
|
+
export function assembleArtifacts(options) {
|
|
15
|
+
const cwd = options.cwd ?? process.cwd();
|
|
16
|
+
const warnings = [];
|
|
17
|
+
const explicit = [];
|
|
18
|
+
const expanded = [];
|
|
19
|
+
for (const input of options.files ?? []) {
|
|
20
|
+
if (input.startsWith(CMD_PREFIX)) {
|
|
21
|
+
const block = cmdArtifactBlock(input.slice(CMD_PREFIX.length), cwd, warnings);
|
|
22
|
+
if (block)
|
|
23
|
+
explicit.push(block);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const full = path.resolve(cwd, input);
|
|
27
|
+
if (!fs.existsSync(full)) {
|
|
28
|
+
warnings.push(`not found: ${input}`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const stat = fs.statSync(full);
|
|
32
|
+
if (stat.isDirectory()) {
|
|
33
|
+
for (const file of expandDirectory(full, cwd)) {
|
|
34
|
+
const block = readFileBlock(file, cwd, warnings);
|
|
35
|
+
if (block)
|
|
36
|
+
expanded.push(block);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const block = readFileBlock(full, cwd, warnings);
|
|
41
|
+
if (block)
|
|
42
|
+
explicit.push(block);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (options.stdin) {
|
|
46
|
+
explicit.push({
|
|
47
|
+
label: '--- stdin ---',
|
|
48
|
+
content: options.stdin,
|
|
49
|
+
truncated: false,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const diffBlocks = [];
|
|
53
|
+
if (options.diff !== undefined) {
|
|
54
|
+
const diffBlock = gitDiffBlock(options.diff, cwd);
|
|
55
|
+
if (diffBlock)
|
|
56
|
+
diffBlocks.push(diffBlock);
|
|
57
|
+
}
|
|
58
|
+
// Priority order: explicit --file blocks, diff, then directory expansions.
|
|
59
|
+
// Cap: each block truncated to 25% of the remaining budget; when the budget
|
|
60
|
+
// is exhausted the rest are omitted and named in warnings.
|
|
61
|
+
const capBytes = options.capBytes ?? DEFAULT_CAP_BYTES;
|
|
62
|
+
let remaining = capBytes;
|
|
63
|
+
const blocks = [];
|
|
64
|
+
const applyBudget = (block) => {
|
|
65
|
+
if (remaining <= 0)
|
|
66
|
+
return false;
|
|
67
|
+
const size = Buffer.byteLength(block.content);
|
|
68
|
+
const perFileCap = Math.max(1, Math.floor(remaining * 0.25));
|
|
69
|
+
if (size > perFileCap) {
|
|
70
|
+
const cut = Buffer.from(block.content).subarray(0, perFileCap).toString('utf8');
|
|
71
|
+
const marker = `\n[truncated at ${perFileCap} of ${size} bytes]`;
|
|
72
|
+
blocks.push({
|
|
73
|
+
label: block.label.replace(' ---', ', truncated ---'),
|
|
74
|
+
content: cut + marker,
|
|
75
|
+
truncated: true,
|
|
76
|
+
});
|
|
77
|
+
remaining -= Buffer.byteLength(cut + marker);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
blocks.push(block);
|
|
81
|
+
remaining -= size;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
const ordered = [...explicit, ...diffBlocks, ...expanded];
|
|
86
|
+
for (const block of ordered) {
|
|
87
|
+
if (!applyBudget(block)) {
|
|
88
|
+
const omittedFrom = ordered.indexOf(block);
|
|
89
|
+
for (const skipped of ordered.slice(omittedFrom)) {
|
|
90
|
+
warnings.push(`omitted (artifact cap ${formatBytes(capBytes)} reached): ${labelName(skipped.label)}`);
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
blocks,
|
|
97
|
+
totalBytes: blocks.reduce((n, b) => n + Buffer.byteLength(b.content), 0),
|
|
98
|
+
warnings,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function labelName(label) {
|
|
102
|
+
return label.replace(/^--- /, '').replace(/ ---$/, '');
|
|
103
|
+
}
|
|
104
|
+
function readFileBlock(full, cwd, warnings) {
|
|
105
|
+
const rel = path.relative(cwd, full);
|
|
106
|
+
const fd = fs.openSync(full, 'r');
|
|
107
|
+
try {
|
|
108
|
+
const head = Buffer.alloc(8192);
|
|
109
|
+
const read = fs.readSync(fd, head, 0, 8192, 0);
|
|
110
|
+
if (isBinary(head.subarray(0, read))) {
|
|
111
|
+
warnings.push(`skipped binary file: ${rel}`);
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const content = fs.readFileSync(full, 'utf8');
|
|
115
|
+
const size = Buffer.byteLength(content);
|
|
116
|
+
return { label: `--- ${rel} (${formatBytes(size)}) ---`, content, truncated: false };
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
fs.closeSync(fd);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function isBinary(head) {
|
|
123
|
+
if (head.length >= 2) {
|
|
124
|
+
const bom = head[0] === 0xff && head[1] === 0xfe;
|
|
125
|
+
const beBom = head[0] === 0xfe && head[1] === 0xff;
|
|
126
|
+
if (bom || beBom)
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return head.includes(0x00);
|
|
130
|
+
}
|
|
131
|
+
function expandDirectory(dir, cwd) {
|
|
132
|
+
const rules = [];
|
|
133
|
+
const results = [];
|
|
134
|
+
function loadRule(directory) {
|
|
135
|
+
const file = path.join(directory, '.gitignore');
|
|
136
|
+
if (fs.existsSync(file)) {
|
|
137
|
+
rules.push({ base: directory, ig: ignore().add(fs.readFileSync(file, 'utf8')) });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function ignored(full, isDir) {
|
|
141
|
+
for (const rule of rules) {
|
|
142
|
+
if (full.startsWith(rule.base + path.sep)) {
|
|
143
|
+
const rel = path.relative(rule.base, full);
|
|
144
|
+
if (rule.ig.ignores(rel + (isDir ? '/' : '')))
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
function walk(current) {
|
|
151
|
+
loadRule(current);
|
|
152
|
+
const entries = fs.readdirSync(current, { withFileTypes: true })
|
|
153
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
154
|
+
for (const entry of entries) {
|
|
155
|
+
if (ALWAYS_SKIP.has(entry.name))
|
|
156
|
+
continue;
|
|
157
|
+
const full = path.join(current, entry.name);
|
|
158
|
+
if (ignored(full, entry.isDirectory()))
|
|
159
|
+
continue;
|
|
160
|
+
if (entry.isDirectory())
|
|
161
|
+
walk(full);
|
|
162
|
+
else if (entry.isFile())
|
|
163
|
+
results.push(full);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
walk(dir);
|
|
167
|
+
return results;
|
|
168
|
+
}
|
|
169
|
+
function cmdArtifactBlock(command, cwd, warnings) {
|
|
170
|
+
const trimmed = command.trim();
|
|
171
|
+
if (!trimmed) {
|
|
172
|
+
warnings.push('cmd: artifact given an empty command');
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
let content;
|
|
176
|
+
try {
|
|
177
|
+
// A shell string, not execFileSync's argv array: the whole point is to
|
|
178
|
+
// let the user's own command use quoting, pipes, etc. This is their own
|
|
179
|
+
// local invocation - equivalent trust level to them running it directly
|
|
180
|
+
// in a terminal, not untrusted input crossing a privilege boundary.
|
|
181
|
+
content = execSync(trimmed, { cwd, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
185
|
+
warnings.push(`cmd failed: ${trimmed}: ${message}`);
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
if (content.trim().length === 0)
|
|
189
|
+
return undefined;
|
|
190
|
+
const size = Buffer.byteLength(content);
|
|
191
|
+
return { label: `--- cmd:${trimmed} (${formatBytes(size)}) ---`, content, truncated: false };
|
|
192
|
+
}
|
|
193
|
+
function gitDiffBlock(spec, cwd) {
|
|
194
|
+
const range = spec.range ?? 'HEAD';
|
|
195
|
+
const args = ['diff', range];
|
|
196
|
+
if (spec.paths && spec.paths.length > 0) {
|
|
197
|
+
args.push('--', ...spec.paths);
|
|
198
|
+
}
|
|
199
|
+
let content;
|
|
200
|
+
try {
|
|
201
|
+
content = execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
// Covers both "not a git repository" (exit 128) and a missing git binary
|
|
205
|
+
// (ENOENT) - both surface as the same user-facing error.
|
|
206
|
+
throw new CouncilError(`--diff requires a git repository and the git binary (cwd: ${cwd})`, 'NOT_A_REPO');
|
|
207
|
+
}
|
|
208
|
+
if (content.trim().length === 0)
|
|
209
|
+
return undefined;
|
|
210
|
+
const size = Buffer.byteLength(content);
|
|
211
|
+
return { label: `--- git diff ${range} (${formatBytes(size)}) ---`, content, truncated: false };
|
|
212
|
+
}
|
|
213
|
+
export function formatArtifactPreamble(bundle) {
|
|
214
|
+
if (bundle.blocks.length === 0)
|
|
215
|
+
return '';
|
|
216
|
+
let out = '## Artifacts\n\n';
|
|
217
|
+
for (const block of bundle.blocks) {
|
|
218
|
+
out += `${block.label}\n${block.content}\n\n`;
|
|
219
|
+
}
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
export function formatBytes(bytes) {
|
|
223
|
+
if (bytes < 1024)
|
|
224
|
+
return `${bytes} B`;
|
|
225
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"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"}
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AttributedHardBlock, BlockParse, JudgeResult, UnknownJudge } from './types.js';
|
|
2
|
+
export declare const KEY_LABEL = "COUNCIL-BLOCKS-KEY";
|
|
3
|
+
export declare function newBlockKey(): string;
|
|
4
|
+
export declare function parseHardBlocks(text: string, key: string): BlockParse;
|
|
5
|
+
export declare function stripBlockFooter(text: string, key: string): string;
|
|
6
|
+
export interface BlockAggregate {
|
|
7
|
+
blocked: boolean;
|
|
8
|
+
hardBlocks: AttributedHardBlock[];
|
|
9
|
+
diagnosticBlocks: AttributedHardBlock[];
|
|
10
|
+
unknownJudges: UnknownJudge[];
|
|
11
|
+
}
|
|
12
|
+
export declare function aggregateBlocks(judges: JudgeResult[]): BlockAggregate;
|
package/dist/blocks.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
// The reviewed artifact is untrusted input and judges routinely quote it back.
|
|
3
|
+
// A per-run key marks where the judge's own footer starts, so quoted artifact
|
|
4
|
+
// content can never be read as a verdict. See the spec's threat model for what
|
|
5
|
+
// this does not defend against.
|
|
6
|
+
export const KEY_LABEL = 'COUNCIL-BLOCKS-KEY';
|
|
7
|
+
export function newBlockKey() {
|
|
8
|
+
return randomBytes(4).toString('hex');
|
|
9
|
+
}
|
|
10
|
+
const SEVERITY_MAP = {
|
|
11
|
+
critical: 'critical',
|
|
12
|
+
blocker: 'critical',
|
|
13
|
+
severe: 'critical',
|
|
14
|
+
high: 'high',
|
|
15
|
+
major: 'high',
|
|
16
|
+
};
|
|
17
|
+
export function parseHardBlocks(text, key) {
|
|
18
|
+
const lines = text.replace(/\r\n?/g, '\n').split('\n');
|
|
19
|
+
const keyLine = new RegExp(`^\\s*${escapeRegExp(KEY_LABEL)}:\\s*${escapeRegExp(key)}\\s*$`, 'i');
|
|
20
|
+
let keyIdx = -1;
|
|
21
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
22
|
+
if (keyLine.test(lines[i])) {
|
|
23
|
+
keyIdx = i;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (keyIdx === -1) {
|
|
28
|
+
return { status: 'unparseable', reason: 'no-key', diagnosticBlocks: [] };
|
|
29
|
+
}
|
|
30
|
+
const blocks = [];
|
|
31
|
+
let headerSeen = false;
|
|
32
|
+
let declared;
|
|
33
|
+
let badHeaderDetail;
|
|
34
|
+
for (const line of lines.slice(keyIdx + 1)) {
|
|
35
|
+
if (!headerSeen) {
|
|
36
|
+
const header = /^\s*BLOCKERS:\s*(.*)$/i.exec(line);
|
|
37
|
+
if (header) {
|
|
38
|
+
headerSeen = true;
|
|
39
|
+
const value = header[1].trim();
|
|
40
|
+
if (/^none$/i.test(value))
|
|
41
|
+
declared = 0;
|
|
42
|
+
else if (/^\d+$/.test(value))
|
|
43
|
+
declared = Number.parseInt(value, 10);
|
|
44
|
+
else
|
|
45
|
+
badHeaderDetail = value;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const entry = /^\s*BLOCKER:\s*(.+)$/i.exec(line);
|
|
50
|
+
if (entry) {
|
|
51
|
+
const block = parseBlockLine(entry[1]);
|
|
52
|
+
if (block)
|
|
53
|
+
blocks.push(block);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!headerSeen) {
|
|
57
|
+
return { status: 'unparseable', reason: 'no-header', diagnosticBlocks: blocks };
|
|
58
|
+
}
|
|
59
|
+
if (declared === undefined) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'unparseable',
|
|
62
|
+
reason: 'bad-header',
|
|
63
|
+
detail: badHeaderDetail,
|
|
64
|
+
diagnosticBlocks: blocks,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (declared !== blocks.length) {
|
|
68
|
+
return {
|
|
69
|
+
status: 'unparseable',
|
|
70
|
+
reason: 'count-mismatch',
|
|
71
|
+
detail: `declared ${declared}, parsed ${blocks.length}`,
|
|
72
|
+
diagnosticBlocks: blocks,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { status: 'parsed', blocks };
|
|
76
|
+
}
|
|
77
|
+
// Strip the machine footer so the human-facing synthesis does not restate what
|
|
78
|
+
// the structured result already carries. Only safe to call when the footer
|
|
79
|
+
// parsed cleanly - for an unparseable judge the raw tail is the evidence a
|
|
80
|
+
// reader needs to see.
|
|
81
|
+
//
|
|
82
|
+
// Judges frequently wrap their footer in a code fence (the instruction's own
|
|
83
|
+
// example is fenced), so slicing at the key line can leave a dangling opening
|
|
84
|
+
// fence at the end of the kept prose. dropOrphanFence() cleans that up.
|
|
85
|
+
export function stripBlockFooter(text, key) {
|
|
86
|
+
const normalised = text.replace(/\r\n?/g, '\n');
|
|
87
|
+
const lines = normalised.split('\n');
|
|
88
|
+
const keyLine = new RegExp(`^\\s*${escapeRegExp(KEY_LABEL)}:\\s*${escapeRegExp(key)}\\s*$`, 'i');
|
|
89
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
90
|
+
if (keyLine.test(lines[i])) {
|
|
91
|
+
return dropOrphanFence(lines.slice(0, i).join('\n').trimEnd());
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return text;
|
|
95
|
+
}
|
|
96
|
+
// A fence marker line: ``` optionally followed by a language tag.
|
|
97
|
+
const FENCE = /^\s*```/;
|
|
98
|
+
// Judges often wrap the footer in a code fence, because the instruction's own
|
|
99
|
+
// example is fenced. Slicing at the key line takes the closing fence with it
|
|
100
|
+
// and leaves the opener dangling, which in a markdown renderer swallows
|
|
101
|
+
// everything that follows. Drop a trailing orphan opener - but only when the
|
|
102
|
+
// kept text is genuinely unbalanced, so a legitimate closing fence survives.
|
|
103
|
+
function dropOrphanFence(text) {
|
|
104
|
+
const lines = text.split('\n');
|
|
105
|
+
const fenceCount = lines.filter((l) => FENCE.test(l)).length;
|
|
106
|
+
if (fenceCount % 2 === 0)
|
|
107
|
+
return text;
|
|
108
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
109
|
+
if (lines[i].trim().length === 0)
|
|
110
|
+
continue;
|
|
111
|
+
if (FENCE.test(lines[i])) {
|
|
112
|
+
return [...lines.slice(0, i), ...lines.slice(i + 1)].join('\n').trimEnd();
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
return text;
|
|
117
|
+
}
|
|
118
|
+
// Field splitting is deliberately forgiving: judges write pipes inside titles
|
|
119
|
+
// (`use foo | bar instead`), so the last field is taken as the location and
|
|
120
|
+
// everything between the severity and it is rejoined as the title.
|
|
121
|
+
function parseBlockLine(rest) {
|
|
122
|
+
const fields = rest.split('|').map((f) => f.trim());
|
|
123
|
+
if (fields.length < 2)
|
|
124
|
+
return undefined;
|
|
125
|
+
const rawSeverity = fields[0];
|
|
126
|
+
const severity = normaliseSeverity(rawSeverity);
|
|
127
|
+
let title;
|
|
128
|
+
let location;
|
|
129
|
+
if (fields.length === 2) {
|
|
130
|
+
title = fields[1];
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
location = fields[fields.length - 1];
|
|
134
|
+
title = fields.slice(1, -1).join(' | ');
|
|
135
|
+
}
|
|
136
|
+
if (title.length === 0)
|
|
137
|
+
return undefined;
|
|
138
|
+
const block = { severity, title };
|
|
139
|
+
if (rawSeverity.toLowerCase() !== severity)
|
|
140
|
+
block.rawSeverity = rawSeverity;
|
|
141
|
+
if (location !== undefined && location.length > 0)
|
|
142
|
+
block.location = location;
|
|
143
|
+
return block;
|
|
144
|
+
}
|
|
145
|
+
// Severity is never checksum-critical. An unrecognised word must not cost the
|
|
146
|
+
// whole judge, so it degrades to 'high' with the original preserved.
|
|
147
|
+
function normaliseSeverity(raw) {
|
|
148
|
+
return SEVERITY_MAP[raw.toLowerCase().replace(/[^a-z]/g, '')] ?? 'high';
|
|
149
|
+
}
|
|
150
|
+
function escapeRegExp(text) {
|
|
151
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
152
|
+
}
|
|
153
|
+
const SEVERITY_RANK = { critical: 0, high: 1 };
|
|
154
|
+
// Union, never majority: one judge seeing a real problem blocks even if the
|
|
155
|
+
// others would talk it down. A safety gate wants the opposite of consensus.
|
|
156
|
+
//
|
|
157
|
+
// Salvage from an unparseable judge never sets `blocked`, so that signal stays
|
|
158
|
+
// honest. The finding is not lost either: it lands in diagnosticBlocks and the
|
|
159
|
+
// judge lands in unknownJudges, which a gating consumer already parks on.
|
|
160
|
+
//
|
|
161
|
+
// NOTE for direct callers: a judge with no `blockParse` at all is skipped, not
|
|
162
|
+
// treated as unknown. That is correct for results produced with a `blockKey`,
|
|
163
|
+
// where every successful judge always carries a parse. If you call this with
|
|
164
|
+
// results from a `runCouncil` invocation that had NO `blockKey`, every judge is
|
|
165
|
+
// skipped and you get `blocked: false` - which is indistinguishable from a
|
|
166
|
+
// clean council. Always pass a `blockKey` if you intend to gate on the result.
|
|
167
|
+
export function aggregateBlocks(judges) {
|
|
168
|
+
const hardBlocks = [];
|
|
169
|
+
const diagnosticBlocks = [];
|
|
170
|
+
const unknownJudges = [];
|
|
171
|
+
for (const judge of judges) {
|
|
172
|
+
if (judge.status !== 'success' || !judge.blockParse)
|
|
173
|
+
continue;
|
|
174
|
+
const parse = judge.blockParse;
|
|
175
|
+
if (parse.status === 'parsed') {
|
|
176
|
+
hardBlocks.push(...attribute(judge.provider, parse.blocks));
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
diagnosticBlocks.push(...attribute(judge.provider, parse.diagnosticBlocks));
|
|
180
|
+
unknownJudges.push({
|
|
181
|
+
provider: judge.provider,
|
|
182
|
+
reason: parse.reason,
|
|
183
|
+
...(parse.detail === undefined ? {} : { detail: parse.detail }),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { blocked: hardBlocks.length > 0, hardBlocks, diagnosticBlocks, unknownJudges };
|
|
188
|
+
}
|
|
189
|
+
// Judge order is preserved (callers pass judges in configured provider order),
|
|
190
|
+
// so sorting within a judge is enough to make the whole list deterministic and
|
|
191
|
+
// keep TOON snapshots stable.
|
|
192
|
+
function attribute(provider, blocks) {
|
|
193
|
+
return blocks
|
|
194
|
+
.map((b) => ({ ...b, provider }))
|
|
195
|
+
.sort((x, y) => SEVERITY_RANK[x.severity] - SEVERITY_RANK[y.severity] || x.title.localeCompare(y.title));
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CouncilRequest, JudgeResult, DebateTurn } from './types.js';
|
|
2
|
+
export declare function synthesize(request: CouncilRequest, judges: JudgeResult[]): string;
|
|
3
|
+
export declare function synthesizeDebate(args: {
|
|
4
|
+
judges: DebateTurn[];
|
|
5
|
+
totalRounds: number;
|
|
6
|
+
consensus: boolean;
|
|
7
|
+
}): string;
|
package/dist/chairman.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function synthesize(request, judges) {
|
|
2
|
+
const successful = judges.filter((j) => j.status === 'success' && j.response);
|
|
3
|
+
if (successful.length === 0) {
|
|
4
|
+
return 'No judges were available to review this request.';
|
|
5
|
+
}
|
|
6
|
+
const lines = [];
|
|
7
|
+
if (successful.length === 1) {
|
|
8
|
+
lines.push(`## Single-judge ${request.mode} (${successful[0].provider}, 1 judge)`);
|
|
9
|
+
lines.push('');
|
|
10
|
+
lines.push(successful[0].response ?? '');
|
|
11
|
+
return lines.join('\n');
|
|
12
|
+
}
|
|
13
|
+
lines.push(`## Council ${request.mode} synthesis (${successful.length} judges)`);
|
|
14
|
+
lines.push('');
|
|
15
|
+
for (const judge of successful) {
|
|
16
|
+
lines.push(`### ${judge.provider} (${judge.model})`);
|
|
17
|
+
lines.push(judge.response ?? '');
|
|
18
|
+
lines.push('');
|
|
19
|
+
}
|
|
20
|
+
const verdicts = successful.map((j) => firstLine(j.response ?? ''));
|
|
21
|
+
lines.push('**Key points:**');
|
|
22
|
+
for (const v of verdicts) {
|
|
23
|
+
lines.push(`- ${v}`);
|
|
24
|
+
}
|
|
25
|
+
return lines.join('\n').trim();
|
|
26
|
+
}
|
|
27
|
+
function firstLine(text) {
|
|
28
|
+
return text.split('\n')[0]?.trim() ?? '';
|
|
29
|
+
}
|
|
30
|
+
export function synthesizeDebate(args) {
|
|
31
|
+
const lines = [];
|
|
32
|
+
const outcome = args.consensus
|
|
33
|
+
? 'consensus reached'
|
|
34
|
+
: `no consensus after ${args.totalRounds} rounds`;
|
|
35
|
+
lines.push(`## Council debate (${args.judges.length} judges, ${args.totalRounds} rounds, ${outcome})`);
|
|
36
|
+
lines.push('');
|
|
37
|
+
for (const judge of args.judges) {
|
|
38
|
+
lines.push(`### ${judge.provider} (${judge.model})`);
|
|
39
|
+
lines.push(judge.response ?? '');
|
|
40
|
+
lines.push('');
|
|
41
|
+
}
|
|
42
|
+
const dissenters = args.judges.filter((j) => j.verdict !== 'agree');
|
|
43
|
+
if (!args.consensus && dissenters.length > 0) {
|
|
44
|
+
lines.push('**Dissent:**');
|
|
45
|
+
for (const d of dissenters) {
|
|
46
|
+
lines.push(`- ${d.provider}: ${firstLine(d.response ?? '')}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return lines.join('\n').trim();
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=chairman.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chairman.js","sourceRoot":"","sources":["../src/chairman.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { program, CommanderError } from 'commander';
|
|
6
|
+
import { reviewCommand } from './commands/review.js';
|
|
7
|
+
import { planCommand } from './commands/plan.js';
|
|
8
|
+
import { debateCommand, debateTurnCommand, debateAbortCommand } from './commands/debate.js';
|
|
9
|
+
import { setupCommand } from './commands/setup.js';
|
|
10
|
+
import { homeCommand } from './commands/home.js';
|
|
11
|
+
import { hookCommand } from './commands/hook.js';
|
|
12
|
+
import { formatError } from './errors.js';
|
|
13
|
+
// Read from package.json at runtime rather than hardcoding a copy of the
|
|
14
|
+
// version string here - a hardcoded literal silently drifts from
|
|
15
|
+
// package.json on every release (it did, on the 0.4.1 release).
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
|
|
18
|
+
program
|
|
19
|
+
.name('council')
|
|
20
|
+
.description('Multi-LLM adversarial review council - an AXI')
|
|
21
|
+
.version(pkg.version)
|
|
22
|
+
.exitOverride()
|
|
23
|
+
.configureOutput({
|
|
24
|
+
writeOut: (str) => process.stdout.write(str),
|
|
25
|
+
writeErr: () => { },
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command('setup')
|
|
29
|
+
.description('Check provider authentication status')
|
|
30
|
+
.action(setupCommand);
|
|
31
|
+
function collect(value, previous) {
|
|
32
|
+
return previous.concat([value]);
|
|
33
|
+
}
|
|
34
|
+
program
|
|
35
|
+
.command('review <prompt>')
|
|
36
|
+
.description('Run an adversarial review of an artifact or question')
|
|
37
|
+
.option('-m, --models <models>', 'Comma-separated provider list')
|
|
38
|
+
.option('--max-tokens <n>', 'Positive per-judge token budget; caller picks per task: small for a finished plan, large for a codebase scan')
|
|
39
|
+
.option('--effort <level>', 'Reasoning effort: low|medium|high|xhigh (overrides env; omitted when unconfigured)')
|
|
40
|
+
.option('-f, --file <path>', 'Attach a file, directory, or cmd:<command> for its stdout (repeatable)', collect, [])
|
|
41
|
+
.option('--diff [range]', 'Attach git diff (default: HEAD)')
|
|
42
|
+
.option('--stdin', 'Attach artifact content from stdin')
|
|
43
|
+
.option('--fail-on-block', 'Exit 3 when the council reports a hard block')
|
|
44
|
+
.option('--fail-on-unknown', 'Exit 4 when a judge response could not be parsed')
|
|
45
|
+
.option('--strict', 'Shorthand for --fail-on-block and --fail-on-unknown')
|
|
46
|
+
.action(reviewCommand);
|
|
47
|
+
program
|
|
48
|
+
.command('plan <prompt>')
|
|
49
|
+
.description('Pressure-test a plan or decision')
|
|
50
|
+
.option('-m, --models <models>', 'Comma-separated provider list')
|
|
51
|
+
.option('--max-tokens <n>', 'Positive per-judge token budget; caller picks per task: small for a finished plan, large for a codebase scan')
|
|
52
|
+
.option('--effort <level>', 'Reasoning effort: low|medium|high|xhigh (overrides env; omitted when unconfigured)')
|
|
53
|
+
.option('-f, --file <path>', 'Attach a file, directory, or cmd:<command> for its stdout (repeatable)', collect, [])
|
|
54
|
+
.option('--diff [range]', 'Attach git diff (default: HEAD)')
|
|
55
|
+
.option('--stdin', 'Attach artifact content from stdin')
|
|
56
|
+
.option('--fail-on-block', 'Exit 3 when the council reports a hard block')
|
|
57
|
+
.option('--fail-on-unknown', 'Exit 4 when a judge response could not be parsed')
|
|
58
|
+
.option('--strict', 'Shorthand for --fail-on-block and --fail-on-unknown')
|
|
59
|
+
.action(planCommand);
|
|
60
|
+
const debate = program
|
|
61
|
+
.command('debate')
|
|
62
|
+
.description('Run a sequential adversarial debate until consensus or round cap')
|
|
63
|
+
.addHelpText('after', '\nRun options: --max-tokens <n> (positive per-judge budget; small for a finished plan, large for a codebase scan), --effort <level> (low|medium|high|xhigh).\nWith nothing configured, the request omits effort. Set COUNCIL_EFFORT=medium to use medium effort by default.\nUse council debate run --help for all run options.');
|
|
64
|
+
debate
|
|
65
|
+
.command('run <prompt>', { isDefault: true, hidden: true })
|
|
66
|
+
.option('-m, --models <models>', 'Comma-separated provider list')
|
|
67
|
+
.option('--max-tokens <n>', 'Positive per-judge token budget; caller picks per task: small for a finished plan, large for a codebase scan')
|
|
68
|
+
.option('--effort <level>', 'Reasoning effort: low|medium|high|xhigh (overrides env; omitted when unconfigured)')
|
|
69
|
+
.option('--max-rounds <n>', 'Maximum debate rounds (default: 5)')
|
|
70
|
+
.option('--full', 'Include the complete round-by-round transcript')
|
|
71
|
+
.option('--no-participate', 'Judges only; never pause for your turn (for unattended runs)')
|
|
72
|
+
.option('-f, --file <path>', 'Attach a file, directory, or cmd:<command> for its stdout (repeatable)', collect, [])
|
|
73
|
+
.option('--diff [range]', 'Attach git diff (default: HEAD)')
|
|
74
|
+
.option('--stdin', 'Attach artifact content from stdin')
|
|
75
|
+
.action(debateCommand);
|
|
76
|
+
debate
|
|
77
|
+
.command('turn <session-id> [response]')
|
|
78
|
+
.description('Submit your turn in a paused participating debate')
|
|
79
|
+
.option('--stdin', 'Read the turn from stdin')
|
|
80
|
+
.option('--full', 'Include the complete transcript in the final output')
|
|
81
|
+
.action(debateTurnCommand);
|
|
82
|
+
debate
|
|
83
|
+
.command('abort <session-id>')
|
|
84
|
+
.description('Delete a paused debate session')
|
|
85
|
+
.action(debateAbortCommand);
|
|
86
|
+
program
|
|
87
|
+
.command('hook [event]')
|
|
88
|
+
.description('Harness lifecycle hook entrypoint (session-start|post-edit|stop)')
|
|
89
|
+
.option('--payload <json>', 'hook payload as JSON (alternative to stdin)')
|
|
90
|
+
.action(hookCommand);
|
|
91
|
+
async function main() {
|
|
92
|
+
if (process.argv.length <= 2) {
|
|
93
|
+
await homeCommand();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await program.parseAsync(process.argv);
|
|
97
|
+
}
|
|
98
|
+
main().catch((err) => {
|
|
99
|
+
if (err instanceof CommanderError) {
|
|
100
|
+
if (err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
console.log(`${err.message.trim()}\nhelp: npx -y @lanjak/council --help`);
|
|
104
|
+
process.exit(2);
|
|
105
|
+
}
|
|
106
|
+
console.log(formatError(err));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|