coder-config 0.53.3-beta → 0.53.5-beta
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/lib/constants.js
CHANGED
package/lib/router.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Router (CCR) configuration management
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const CCR_DIR_NAME = '.claude-code-router';
|
|
10
|
+
const CONFIG_FILE = 'config.json';
|
|
11
|
+
const PRESET_DIR_NAME = 'coder-config-presets';
|
|
12
|
+
const CCR_PORT = 3456;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get path to CCR config file
|
|
16
|
+
*/
|
|
17
|
+
function getConfigPath() {
|
|
18
|
+
const homeDir = process.env.HOME || '';
|
|
19
|
+
return path.join(homeDir, CCR_DIR_NAME, CONFIG_FILE);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Read and parse CCR config, return {} if missing or invalid
|
|
24
|
+
*/
|
|
25
|
+
function getConfig() {
|
|
26
|
+
const configPath = getConfigPath();
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(configPath)) return {};
|
|
29
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
30
|
+
} catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Write config JSON, creating directory if needed
|
|
37
|
+
*/
|
|
38
|
+
function saveConfig(config) {
|
|
39
|
+
const configPath = getConfigPath();
|
|
40
|
+
const dir = path.dirname(configPath);
|
|
41
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
42
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Return Providers array from config, or []
|
|
47
|
+
*/
|
|
48
|
+
function listProviders() {
|
|
49
|
+
const config = getConfig();
|
|
50
|
+
return Array.isArray(config.Providers) ? config.Providers : [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Add or replace a provider by name
|
|
55
|
+
*/
|
|
56
|
+
function addProvider(name, providerConfig) {
|
|
57
|
+
const config = getConfig();
|
|
58
|
+
if (!Array.isArray(config.Providers)) {
|
|
59
|
+
config.Providers = [];
|
|
60
|
+
}
|
|
61
|
+
// Remove existing provider with same name
|
|
62
|
+
config.Providers = config.Providers.filter(p => p.name !== name);
|
|
63
|
+
config.Providers.push({ name, ...providerConfig });
|
|
64
|
+
saveConfig(config);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Remove a provider by name
|
|
69
|
+
*/
|
|
70
|
+
function removeProvider(name) {
|
|
71
|
+
const config = getConfig();
|
|
72
|
+
if (!Array.isArray(config.Providers)) return;
|
|
73
|
+
config.Providers = config.Providers.filter(p => p.name !== name);
|
|
74
|
+
saveConfig(config);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Return Router rules object or {}
|
|
79
|
+
*/
|
|
80
|
+
function getRouterRules() {
|
|
81
|
+
const config = getConfig();
|
|
82
|
+
return config.Router || {};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Set a single router rule (task -> providerModel string)
|
|
87
|
+
*/
|
|
88
|
+
function setRouterRule(task, providerModel) {
|
|
89
|
+
const config = getConfig();
|
|
90
|
+
if (!config.Router) {
|
|
91
|
+
config.Router = {};
|
|
92
|
+
}
|
|
93
|
+
config.Router[task] = providerModel;
|
|
94
|
+
saveConfig(config);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Return environment variables needed to activate CCR proxy
|
|
99
|
+
*/
|
|
100
|
+
function getActivationEnv() {
|
|
101
|
+
const config = getConfig();
|
|
102
|
+
return {
|
|
103
|
+
ANTHROPIC_BASE_URL: `http://127.0.0.1:${CCR_PORT}`,
|
|
104
|
+
ANTHROPIC_AUTH_TOKEN: config.APIKEY || '',
|
|
105
|
+
NO_PROXY: '127.0.0.1',
|
|
106
|
+
DISABLE_TELEMETRY: '1',
|
|
107
|
+
DISABLE_COST_WARNINGS: '1',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check CCR installation and running status
|
|
113
|
+
*/
|
|
114
|
+
function getStatus() {
|
|
115
|
+
let installed = false;
|
|
116
|
+
try {
|
|
117
|
+
execSync('which ccr', { stdio: 'pipe' });
|
|
118
|
+
installed = true;
|
|
119
|
+
} catch {
|
|
120
|
+
// not installed
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let running = false;
|
|
124
|
+
try {
|
|
125
|
+
execSync(`lsof -i :${CCR_PORT}`, { stdio: 'pipe' });
|
|
126
|
+
running = true;
|
|
127
|
+
} catch {
|
|
128
|
+
// not running
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const configExists = fs.existsSync(getConfigPath());
|
|
132
|
+
|
|
133
|
+
return { installed, running, configExists };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get presets directory path
|
|
138
|
+
*/
|
|
139
|
+
function getPresetsDir() {
|
|
140
|
+
const homeDir = process.env.HOME || '';
|
|
141
|
+
return path.join(homeDir, CCR_DIR_NAME, PRESET_DIR_NAME);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* List saved presets (names without .json extension)
|
|
146
|
+
*/
|
|
147
|
+
function listPresets() {
|
|
148
|
+
const presetsDir = getPresetsDir();
|
|
149
|
+
if (!fs.existsSync(presetsDir)) return [];
|
|
150
|
+
return fs.readdirSync(presetsDir)
|
|
151
|
+
.filter(f => f.endsWith('.json'))
|
|
152
|
+
.map(f => f.replace(/\.json$/, ''));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Snapshot current config to a named preset
|
|
157
|
+
*/
|
|
158
|
+
function savePreset(name) {
|
|
159
|
+
const config = getConfig();
|
|
160
|
+
const presetsDir = getPresetsDir();
|
|
161
|
+
fs.mkdirSync(presetsDir, { recursive: true });
|
|
162
|
+
fs.writeFileSync(path.join(presetsDir, `${name}.json`), JSON.stringify(config, null, 2) + '\n');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Restore config from a named preset
|
|
167
|
+
*/
|
|
168
|
+
function loadPreset(name) {
|
|
169
|
+
const presetPath = path.join(getPresetsDir(), `${name}.json`);
|
|
170
|
+
if (!fs.existsSync(presetPath)) {
|
|
171
|
+
throw new Error(`Preset "${name}" not found`);
|
|
172
|
+
}
|
|
173
|
+
const config = JSON.parse(fs.readFileSync(presetPath, 'utf8'));
|
|
174
|
+
saveConfig(config);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
getConfigPath,
|
|
179
|
+
getConfig,
|
|
180
|
+
saveConfig,
|
|
181
|
+
listProviders,
|
|
182
|
+
addProvider,
|
|
183
|
+
removeProvider,
|
|
184
|
+
getRouterRules,
|
|
185
|
+
setRouterRule,
|
|
186
|
+
getActivationEnv,
|
|
187
|
+
getStatus,
|
|
188
|
+
listPresets,
|
|
189
|
+
savePreset,
|
|
190
|
+
loadPreset,
|
|
191
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coder-config",
|
|
3
|
-
"version": "0.53.
|
|
3
|
+
"version": "0.53.5-beta",
|
|
4
4
|
"description": "Configuration manager for AI coding tools - Claude Code, Gemini CLI, Codex CLI, Antigravity. Manage MCPs, rules, permissions, memory, and workstreams.",
|
|
5
5
|
"author": "regression.io",
|
|
6
6
|
"main": "config-loader.js",
|