mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +00:00
feat(copilot): add raw settings API and model mapping routes
- add GET/PUT /api/copilot/settings/raw for copilot.settings.json - update PUT /api/copilot/config to handle model mapping fields - sync model mappings between settings file and unified config
This commit is contained in:
@@ -1675,6 +1675,13 @@ apiRoutes.put('/copilot/config', (req: Request, res: Response): void => {
|
||||
config.copilot?.wait_on_limit ??
|
||||
DEFAULT_COPILOT_CONFIG.wait_on_limit,
|
||||
model: updates.model ?? config.copilot?.model ?? DEFAULT_COPILOT_CONFIG.model,
|
||||
// Model mapping for opus/sonnet/haiku tiers
|
||||
opus_model:
|
||||
updates.opus_model !== undefined ? updates.opus_model : config.copilot?.opus_model,
|
||||
sonnet_model:
|
||||
updates.sonnet_model !== undefined ? updates.sonnet_model : config.copilot?.sonnet_model,
|
||||
haiku_model:
|
||||
updates.haiku_model !== undefined ? updates.haiku_model : config.copilot?.haiku_model,
|
||||
};
|
||||
|
||||
saveUnifiedConfig(config);
|
||||
@@ -1756,3 +1763,97 @@ apiRoutes.post('/copilot/daemon/stop', async (_req: Request, res: Response): Pro
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/copilot/settings/raw - Get raw copilot.settings.json
|
||||
* Returns the raw JSON content for editing in the code editor
|
||||
*/
|
||||
apiRoutes.get('/copilot/settings/raw', (_req: Request, res: Response): void => {
|
||||
try {
|
||||
const settingsPath = path.join(getCcsDir(), 'copilot.settings.json');
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
const copilotConfig = config.copilot ?? DEFAULT_COPILOT_CONFIG;
|
||||
|
||||
// Default model for all tiers
|
||||
const defaultModel = copilotConfig.model;
|
||||
|
||||
// If file doesn't exist, return default structure with all model mappings
|
||||
if (!fs.existsSync(settingsPath)) {
|
||||
// Create settings structure matching CLIProxy pattern - always include all model mappings
|
||||
const defaultSettings = {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: `http://localhost:${copilotConfig.port}`,
|
||||
ANTHROPIC_AUTH_TOKEN: 'copilot-managed',
|
||||
ANTHROPIC_MODEL: defaultModel,
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: copilotConfig.opus_model || defaultModel,
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: copilotConfig.sonnet_model || defaultModel,
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: copilotConfig.haiku_model || defaultModel,
|
||||
},
|
||||
};
|
||||
|
||||
res.json({
|
||||
settings: defaultSettings,
|
||||
mtime: Date.now(),
|
||||
path: `~/.ccs/copilot.settings.json`,
|
||||
exists: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(settingsPath, 'utf-8');
|
||||
const settings = JSON.parse(content);
|
||||
const stat = fs.statSync(settingsPath);
|
||||
|
||||
res.json({
|
||||
settings,
|
||||
mtime: stat.mtimeMs,
|
||||
path: `~/.ccs/copilot.settings.json`,
|
||||
exists: true,
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT /api/copilot/settings/raw - Save raw copilot.settings.json
|
||||
* Saves the raw JSON content from the code editor
|
||||
*/
|
||||
apiRoutes.put('/copilot/settings/raw', (req: Request, res: Response): void => {
|
||||
try {
|
||||
const { settings, expectedMtime } = req.body;
|
||||
const settingsPath = path.join(getCcsDir(), 'copilot.settings.json');
|
||||
|
||||
// Check for conflict if file exists and expectedMtime provided
|
||||
if (fs.existsSync(settingsPath) && expectedMtime) {
|
||||
const stat = fs.statSync(settingsPath);
|
||||
if (Math.abs(stat.mtimeMs - expectedMtime) > 1000) {
|
||||
res.status(409).json({ error: 'File modified externally', mtime: stat.mtimeMs });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Write settings file atomically
|
||||
const tempPath = settingsPath + '.tmp';
|
||||
fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n');
|
||||
fs.renameSync(tempPath, settingsPath);
|
||||
|
||||
// Also sync model mappings back to unified config
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
const env = settings.env || {};
|
||||
|
||||
config.copilot = {
|
||||
...(config.copilot ?? DEFAULT_COPILOT_CONFIG),
|
||||
model: env.ANTHROPIC_MODEL || config.copilot?.model || DEFAULT_COPILOT_CONFIG.model,
|
||||
opus_model: env.ANTHROPIC_DEFAULT_OPUS_MODEL || undefined,
|
||||
sonnet_model: env.ANTHROPIC_DEFAULT_SONNET_MODEL || undefined,
|
||||
haiku_model: env.ANTHROPIC_DEFAULT_HAIKU_MODEL || undefined,
|
||||
};
|
||||
saveUnifiedConfig(config);
|
||||
|
||||
const stat = fs.statSync(settingsPath);
|
||||
res.json({ success: true, mtime: stat.mtimeMs });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user