council-cli 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.
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Council CLI
2
+
3
+ AI-powered implementation planning using multiple LLMs that debate and synthesize the best approach.
4
+
5
+ ## How It Works
6
+
7
+ 1. **Propose** - 4 different LLMs generate implementation plans for your task
8
+ 2. **Rank** - Each LLM blindly scores all plans on simplicity, correctness, security, and performance
9
+ 3. **Synthesize** - A chairman model creates the final plan by combining the best ideas
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # Clone the repository
15
+ git clone https://github.com/your-username/council.git
16
+ cd council
17
+
18
+ # Install dependencies
19
+ bun install
20
+ # or
21
+ npm install
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ # Basic usage
28
+ bun run src/index.ts "your task description"
29
+
30
+ # With custom output file
31
+ bun run src/index.ts "add JWT auth" --output auth-plan.md
32
+
33
+ # Show help
34
+ bun run src/index.ts --help
35
+ ```
36
+
37
+ ### Options
38
+
39
+ | Option | Description |
40
+ |--------|-------------|
41
+ | `-o, --output` | Output file path (default: `plan.md`) |
42
+ | `-h, --help` | Show help message |
43
+
44
+ ## Configuration
45
+
46
+ On first run, Council will prompt you for your OpenRouter API key. The configuration is saved to `~/.config/council/config.yaml`.
47
+
48
+ ### Get an API Key
49
+
50
+ 1. Go to [OpenRouter](https://openrouter.ai/keys)
51
+ 2. Create an account and generate an API key
52
+ 3. Enter the key when prompted
53
+
54
+ ### Config File
55
+
56
+ ```yaml
57
+ openrouter_api_key: sk-or-v1-xxxxx
58
+ proposer_models:
59
+ - anthropic/claude-3.5-sonnet
60
+ - openai/gpt-4o
61
+ - google/gemini-2.0-flash-exp
62
+ - deepseek/deepseek-chat
63
+ chairman_model: anthropic/claude-sonnet-4
64
+ ```
65
+
66
+ ## Example
67
+
68
+ ```bash
69
+ $ bun run src/index.ts "add user authentication with JWT tokens"
70
+
71
+ šŸ›ļø Council CLI
72
+
73
+ Task: "add user authentication with JWT tokens"
74
+
75
+ [1/3] Generating proposals from models...
76
+ Calling 4 models in parallel...
77
+ āœ“ anthropic/claude-3.5-sonnet āœ“
78
+ āœ“ openai/gpt-4o āœ“
79
+ āœ“ google/gemini-2.0-flash-exp āœ“
80
+ āœ“ deepseek/deepseek-chat āœ“
81
+
82
+ [2/3] Models ranking all plans blindly...
83
+ 4 models ranking 4 plans blindly...
84
+ āœ“ All models ranked āœ“
85
+
86
+ [3/3] Chairman synthesizing final plan...
87
+ āœ“ anthropic/claude-sonnet-4 synthesis complete āœ“
88
+
89
+ āœ“ Plan saved to plan.md
90
+ ```
91
+
92
+ ## Output Format
93
+
94
+ The generated `plan.md` includes:
95
+
96
+ - Task description
97
+ - Synthesized implementation plan
98
+ - Metadata (chairman model, proposal count, ranker count)
99
+
100
+ ## License
101
+
102
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function run(): Promise<void>;
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA2QA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA+DzC"}
package/dist/cli.js ADDED
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ // Main CLI orchestration
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.run = run;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const config_1 = require("./config");
41
+ const propose_1 = require("./stages/propose");
42
+ const rank_1 = require("./stages/rank");
43
+ const synthesize_1 = require("./stages/synthesize");
44
+ const logger = __importStar(require("./logger"));
45
+ function parseArgs(argv) {
46
+ const args = {
47
+ task: null,
48
+ output: "councilplan.md",
49
+ help: false,
50
+ extraArgs: [],
51
+ };
52
+ for (let i = 0; i < argv.length; i++) {
53
+ const arg = argv[i];
54
+ if (arg === "-h" || arg === "--help") {
55
+ args.help = true;
56
+ }
57
+ else if (arg === "-o" || arg === "--output") {
58
+ args.output = argv[++i] || "councilplan.md";
59
+ }
60
+ else if (!arg.startsWith("-")) {
61
+ if (!args.task) {
62
+ args.task = arg;
63
+ }
64
+ else {
65
+ // Extra args = user forgot quotes
66
+ args.extraArgs.push(arg);
67
+ }
68
+ }
69
+ }
70
+ return args;
71
+ }
72
+ function showHelp() {
73
+ console.log(`
74
+ council - AI-powered implementation planning
75
+
76
+ Usage:
77
+ council "your task description"
78
+ council "add login" --output myplan.md
79
+
80
+ Options:
81
+ -o, --output Output file name (default: councilplan.md)
82
+ -h, --help Show this help
83
+
84
+ Examples:
85
+ council "add JWT authentication to my Express app"
86
+ council "refactor the database layer to use Prisma" -o prisma-plan.md
87
+
88
+ Setup:
89
+ On first run, you'll be prompted for your OpenRouter API key.
90
+ Get your key at: https://openrouter.ai/keys
91
+
92
+ Config is saved to: ~/.config/council/config.yaml
93
+
94
+ Output:
95
+ All files are saved to ./llmcouncil/ folder:
96
+ stage1.md - All proposals from each model
97
+ stage2.md - Rankings table and each model's evaluation
98
+ stage3.md - Chairman's analysis and thinking process
99
+ councilplan.md - Final synthesized implementation plan
100
+
101
+ Note: Always wrap your task in quotes to avoid shell parsing issues.
102
+ `);
103
+ }
104
+ function ensureOutputDir() {
105
+ const outputDir = path.join(process.cwd(), "llmcouncil");
106
+ if (!fs.existsSync(outputDir)) {
107
+ fs.mkdirSync(outputDir, { recursive: true });
108
+ }
109
+ return outputDir;
110
+ }
111
+ function writeStage1(outputDir, task, proposals) {
112
+ let content = `# Stage 1: Proposals\n\n`;
113
+ content += `> **Task:** ${task}\n\n`;
114
+ content += `---\n\n`;
115
+ for (const proposal of proposals) {
116
+ content += `## Proposal ${proposal.proposalId}: ${proposal.model}\n\n`;
117
+ content += `${proposal.content}\n\n`;
118
+ content += `---\n\n`;
119
+ }
120
+ content += `*${proposals.length} proposals generated*\n`;
121
+ fs.writeFileSync(path.join(outputDir, "stage1.md"), content, "utf-8");
122
+ }
123
+ function writeStage2(outputDir, task, proposals, rankings) {
124
+ let content = `# Stage 2: Rankings\n\n`;
125
+ content += `> **Task:** ${task}\n\n`;
126
+ // Build aggregate scores table
127
+ content += `## Aggregate Scores\n\n`;
128
+ content += `| Plan | Model | Avg Simplicity | Avg Correctness | Avg Security | Avg Performance | **Total Avg** |\n`;
129
+ content += `|------|-------|----------------|-----------------|--------------|-----------------|---------------|\n`;
130
+ const aggregates = proposals.map((proposal) => {
131
+ let totalSimplicity = 0, totalCorrectness = 0, totalSecurity = 0, totalPerformance = 0;
132
+ let count = 0;
133
+ for (const ranker of rankings) {
134
+ const ranking = ranker.rankings.find((r) => r.planId === proposal.proposalId);
135
+ if (ranking) {
136
+ totalSimplicity += ranking.scores.simplicity;
137
+ totalCorrectness += ranking.scores.correctness;
138
+ totalSecurity += ranking.scores.security;
139
+ totalPerformance += ranking.scores.performance;
140
+ count++;
141
+ }
142
+ }
143
+ const avgSimplicity = count > 0 ? totalSimplicity / count : 0;
144
+ const avgCorrectness = count > 0 ? totalCorrectness / count : 0;
145
+ const avgSecurity = count > 0 ? totalSecurity / count : 0;
146
+ const avgPerformance = count > 0 ? totalPerformance / count : 0;
147
+ const totalAvg = avgSimplicity + avgCorrectness + avgSecurity + avgPerformance;
148
+ return {
149
+ proposal,
150
+ avgSimplicity,
151
+ avgCorrectness,
152
+ avgSecurity,
153
+ avgPerformance,
154
+ totalAvg,
155
+ };
156
+ });
157
+ // Sort by total average descending
158
+ aggregates.sort((a, b) => b.totalAvg - a.totalAvg);
159
+ for (const agg of aggregates) {
160
+ content += `| ${agg.proposal.proposalId} | ${agg.proposal.model} | ${agg.avgSimplicity.toFixed(1)} | ${agg.avgCorrectness.toFixed(1)} | ${agg.avgSecurity.toFixed(1)} | ${agg.avgPerformance.toFixed(1)} | **${agg.totalAvg.toFixed(1)}/40** |\n`;
161
+ }
162
+ content += `\n---\n\n`;
163
+ // Each ranker's detailed evaluation
164
+ content += `## Individual Ranker Evaluations\n\n`;
165
+ for (const ranker of rankings) {
166
+ content += `### ${ranker.rankerModel}\n\n`;
167
+ content += `| Plan | Simplicity | Correctness | Security | Performance | Total | Critique |\n`;
168
+ content += `|------|------------|-------------|----------|-------------|-------|----------|\n`;
169
+ for (const ranking of ranker.rankings) {
170
+ const proposal = proposals.find((p) => p.proposalId === ranking.planId);
171
+ const modelName = proposal?.model || `Plan ${ranking.planId}`;
172
+ content += `| ${ranking.planId} (${modelName}) | ${ranking.scores.simplicity} | ${ranking.scores.correctness} | ${ranking.scores.security} | ${ranking.scores.performance} | ${ranking.totalScore}/40 | ${ranking.critique} |\n`;
173
+ }
174
+ content += `\n`;
175
+ }
176
+ content += `---\n\n`;
177
+ content += `*${rankings.length} rankers evaluated ${proposals.length} plans*\n`;
178
+ fs.writeFileSync(path.join(outputDir, "stage2.md"), content, "utf-8");
179
+ }
180
+ function writeStage3(outputDir, task, proposals, rankings, result) {
181
+ let content = `# Stage 3: Chairman's Analysis\n\n`;
182
+ content += `> **Task:** ${task}\n\n`;
183
+ content += `> **Chairman Model:** ${result.chairmanModel}\n\n`;
184
+ content += `---\n\n`;
185
+ // Summary of what chairman received
186
+ content += `## Input Summary\n\n`;
187
+ content += `The chairman received ${proposals.length} proposals ranked by ${rankings.length} models.\n\n`;
188
+ // Build ranked summary
189
+ const aggregates = proposals.map((proposal) => {
190
+ let total = 0, count = 0;
191
+ const critiques = [];
192
+ for (const ranker of rankings) {
193
+ const ranking = ranker.rankings.find((r) => r.planId === proposal.proposalId);
194
+ if (ranking) {
195
+ total += ranking.totalScore;
196
+ count++;
197
+ if (ranking.critique) {
198
+ critiques.push(`- **${ranker.rankerModel}:** ${ranking.critique}`);
199
+ }
200
+ }
201
+ }
202
+ return {
203
+ proposal,
204
+ avgScore: count > 0 ? total / count : 0,
205
+ critiques,
206
+ };
207
+ });
208
+ aggregates.sort((a, b) => b.avgScore - a.avgScore);
209
+ content += `### Plans by Ranking\n\n`;
210
+ for (let i = 0; i < aggregates.length; i++) {
211
+ const agg = aggregates[i];
212
+ content += `**#${i + 1}: ${agg.proposal.model}** (Avg: ${agg.avgScore.toFixed(1)}/40)\n\n`;
213
+ content += `Critiques received:\n`;
214
+ content += agg.critiques.join("\n") + "\n\n";
215
+ }
216
+ content += `---\n\n`;
217
+ // Chairman's synthesis
218
+ content += `## Chairman's Synthesis\n\n`;
219
+ content += `${result.finalPlan}\n`;
220
+ fs.writeFileSync(path.join(outputDir, "stage3.md"), content, "utf-8");
221
+ }
222
+ function writeFinalPlan(outputPath, task, result, proposalCount, rankerCount) {
223
+ const content = `# Implementation Plan
224
+
225
+ > **Task:** ${task}
226
+
227
+ ## Plan
228
+
229
+ ${result.finalPlan}
230
+
231
+ ---
232
+
233
+ *Generated by Council • Chairman: ${result.chairmanModel} • ${proposalCount} proposals • ${rankerCount} rankers*
234
+
235
+ ## Additional Files
236
+
237
+ - \`stage1.md\` - All proposals from each model
238
+ - \`stage2.md\` - Rankings table and evaluations
239
+ - \`stage3.md\` - Chairman's analysis process
240
+ `;
241
+ fs.writeFileSync(outputPath, content, "utf-8");
242
+ }
243
+ async function run() {
244
+ const args = parseArgs(process.argv.slice(2));
245
+ if (args.help) {
246
+ showHelp();
247
+ return;
248
+ }
249
+ if (!args.task) {
250
+ showHelp();
251
+ process.exit(1);
252
+ }
253
+ // Check for unquoted task (extra args detected)
254
+ if (args.extraArgs.length > 0) {
255
+ console.error("\nāœ— Error: Your task appears to be unquoted!\n");
256
+ console.error(" You typed:");
257
+ console.error(` council ${args.task} ${args.extraArgs.join(" ")}\n`);
258
+ console.error(" But you should type:");
259
+ console.error(` council "${args.task} ${args.extraArgs.join(" ")}"\n`);
260
+ console.error(" Wrap your entire task in quotes to avoid this issue.");
261
+ console.error(" Run 'council --help' for more info.\n");
262
+ process.exit(1);
263
+ }
264
+ console.log("\nšŸ›ļø Council CLI\n");
265
+ console.log(`Task: "${args.task}"\n`);
266
+ // Load config (prompts for key if needed)
267
+ const config = await (0, config_1.loadConfig)();
268
+ // Create output directory
269
+ const outputDir = ensureOutputDir();
270
+ const outputPath = path.join(outputDir, args.output);
271
+ console.log(`Output folder: ./llmcouncil/\n`);
272
+ // Stage 1: Propose
273
+ logger.stageHeader(1, 3, "Generating proposals from models...");
274
+ const proposals = await (0, propose_1.propose)(args.task, config);
275
+ writeStage1(outputDir, args.task, proposals);
276
+ logger.info(`Saved to llmcouncil/stage1.md`);
277
+ // Stage 2: Rank
278
+ logger.stageHeader(2, 3, "Models ranking all plans blindly...");
279
+ const rankings = await (0, rank_1.rank)(proposals, config);
280
+ writeStage2(outputDir, args.task, proposals, rankings);
281
+ logger.info(`Saved to llmcouncil/stage2.md`);
282
+ // Stage 3: Synthesize
283
+ logger.stageHeader(3, 3, "Chairman synthesizing final plan...");
284
+ const result = await (0, synthesize_1.synthesize)(args.task, proposals, rankings, config);
285
+ writeStage3(outputDir, args.task, proposals, rankings, result);
286
+ logger.info(`Saved to llmcouncil/stage3.md`);
287
+ // Write final plan
288
+ writeFinalPlan(outputPath, args.task, result, proposals.length, rankings.length);
289
+ logger.success(`\nAll files saved to ./llmcouncil/:`);
290
+ logger.info(` - stage1.md (proposals)`);
291
+ logger.info(` - stage2.md (rankings)`);
292
+ logger.info(` - stage3.md (chairman analysis)`);
293
+ logger.info(` - ${args.output} (final plan)`);
294
+ }
295
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Config } from "./types";
2
+ export declare function loadConfig(): Promise<Config>;
3
+ export declare function getConfigFilePath(): string;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAsDtC,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA8BlD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
package/dist/config.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ // Config loading + interactive key prompt
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.loadConfig = loadConfig;
38
+ exports.getConfigFilePath = getConfigFilePath;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ const yaml = __importStar(require("js-yaml"));
43
+ const readline = __importStar(require("readline"));
44
+ const DEFAULT_PROPOSERS = [
45
+ "anthropic/claude-sonnet-4.5",
46
+ "openai/gpt-5.2-codex",
47
+ "google/gemini-3-pro-preview",
48
+ "moonshotai/kimi-k2.5",
49
+ ];
50
+ const DEFAULT_CHAIRMAN = "anthropic/claude-opus-4.5";
51
+ function getConfigPath() {
52
+ return path.join(os.homedir(), ".config", "council", "config.yaml");
53
+ }
54
+ function ensureConfigDir(configPath) {
55
+ const configDir = path.dirname(configPath);
56
+ if (!fs.existsSync(configDir)) {
57
+ fs.mkdirSync(configDir, { recursive: true });
58
+ }
59
+ }
60
+ function tryLoadYaml(configPath) {
61
+ try {
62
+ if (fs.existsSync(configPath)) {
63
+ const content = fs.readFileSync(configPath, "utf-8");
64
+ return yaml.load(content);
65
+ }
66
+ }
67
+ catch {
68
+ // Config file doesn't exist or is invalid
69
+ }
70
+ return null;
71
+ }
72
+ function saveConfig(configPath, config) {
73
+ ensureConfigDir(configPath);
74
+ const content = yaml.dump(config);
75
+ fs.writeFileSync(configPath, content, "utf-8");
76
+ }
77
+ async function promptForInput(prompt) {
78
+ const rl = readline.createInterface({
79
+ input: process.stdin,
80
+ output: process.stdout,
81
+ });
82
+ return new Promise((resolve) => {
83
+ rl.question(prompt, (answer) => {
84
+ rl.close();
85
+ resolve(answer.trim());
86
+ });
87
+ });
88
+ }
89
+ async function loadConfig() {
90
+ const configPath = getConfigPath();
91
+ let config = tryLoadYaml(configPath);
92
+ if (!config?.openrouter_api_key) {
93
+ console.log("No OpenRouter API key found.");
94
+ console.log("Get your key at: https://openrouter.ai/keys\n");
95
+ const key = await promptForInput("Enter your OpenRouter API key: ");
96
+ if (!key) {
97
+ throw new Error("API key is required");
98
+ }
99
+ const newConfig = {
100
+ openrouter_api_key: key,
101
+ proposer_models: config?.proposer_models || DEFAULT_PROPOSERS,
102
+ chairman_model: config?.chairman_model || DEFAULT_CHAIRMAN,
103
+ };
104
+ saveConfig(configPath, newConfig);
105
+ console.log(`\nConfig saved to ${configPath}\n`);
106
+ return newConfig;
107
+ }
108
+ return {
109
+ openrouter_api_key: config.openrouter_api_key,
110
+ proposer_models: config.proposer_models || DEFAULT_PROPOSERS,
111
+ chairman_model: config.chairman_model || DEFAULT_CHAIRMAN,
112
+ };
113
+ }
114
+ function getConfigFilePath() {
115
+ return getConfigPath();
116
+ }
117
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("./cli");
5
+ (0, cli_1.run)().catch((error) => {
6
+ console.error(`\nāœ— Error: ${error.message}`);
7
+ process.exit(1);
8
+ });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,+BAA4B;AAE5B,IAAA,SAAG,GAAE,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Message } from "../types";
2
+ export declare function callLLM(apiKey: string, model: string, messages: Message[]): Promise<string>;
3
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAsBxC,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,MAAM,CAAC,CA6EjB"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ // OpenRouter API client
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.callLLM = callLLM;
5
+ const OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions";
6
+ const MAX_RETRIES = 3;
7
+ const TIMEOUT_MS = 60000;
8
+ function sleep(ms) {
9
+ return new Promise((resolve) => setTimeout(resolve, ms));
10
+ }
11
+ async function callLLM(apiKey, model, messages) {
12
+ let lastError = null;
13
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
14
+ try {
15
+ const controller = new AbortController();
16
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
17
+ const response = await fetch(OPENROUTER_API_URL, {
18
+ method: "POST",
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ Authorization: `Bearer ${apiKey}`,
22
+ "HTTP-Referer": "https://github.com/council-cli",
23
+ "X-Title": "Council CLI",
24
+ },
25
+ body: JSON.stringify({
26
+ model,
27
+ messages,
28
+ }),
29
+ signal: controller.signal,
30
+ });
31
+ clearTimeout(timeoutId);
32
+ if (!response.ok) {
33
+ const errorBody = await response.text();
34
+ // Handle rate limits
35
+ if (response.status === 429) {
36
+ const retryAfter = response.headers.get("retry-after");
37
+ const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
38
+ await sleep(waitTime);
39
+ continue;
40
+ }
41
+ // Handle auth errors
42
+ if (response.status === 401 || response.status === 403) {
43
+ throw new Error(`Authentication failed: ${errorBody}`);
44
+ }
45
+ throw new Error(`API error ${response.status}: ${errorBody}`);
46
+ }
47
+ const data = await response.json();
48
+ if (data.error) {
49
+ throw new Error(`OpenRouter error: ${data.error.message}`);
50
+ }
51
+ if (!data.choices?.[0]?.message?.content) {
52
+ throw new Error("Invalid response: no content in response");
53
+ }
54
+ return data.choices[0].message.content;
55
+ }
56
+ catch (error) {
57
+ lastError = error;
58
+ // Don't retry on auth errors
59
+ if (lastError.message.includes("Authentication failed")) {
60
+ throw lastError;
61
+ }
62
+ // Don't retry on abort (timeout)
63
+ if (lastError.name === "AbortError") {
64
+ throw new Error(`Request timed out after ${TIMEOUT_MS}ms`);
65
+ }
66
+ // Exponential backoff for other errors
67
+ if (attempt < MAX_RETRIES - 1) {
68
+ const waitTime = Math.pow(2, attempt) * 1000;
69
+ await sleep(waitTime);
70
+ }
71
+ }
72
+ }
73
+ throw lastError || new Error("Failed after max retries");
74
+ }
75
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"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"}