opencode-studio-server 1.28.0 → 1.28.2
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/index.js +197 -119
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -341,8 +341,9 @@ function loadStudioConfig() {
|
|
|
341
341
|
"variants": {
|
|
342
342
|
"low": { "options": { "thinkingConfig": { "thinkingLevel": "low", "includeThoughts": true } } },
|
|
343
343
|
"medium": { "options": { "thinkingConfig": { "thinkingLevel": "medium", "includeThoughts": true } } },
|
|
344
|
-
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } }
|
|
345
|
-
|
|
344
|
+
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } },
|
|
345
|
+
"xhigh": { "options": { "thinkingConfig": { "thinkingLevel": "xhigh", "includeThoughts": true } } }
|
|
346
|
+
}
|
|
346
347
|
},
|
|
347
348
|
"gemini-3-flash": {
|
|
348
349
|
"id": "gemini-3-flash",
|
|
@@ -359,8 +360,9 @@ function loadStudioConfig() {
|
|
|
359
360
|
"minimal": { "options": { "thinkingConfig": { "thinkingLevel": "minimal", "includeThoughts": true } } },
|
|
360
361
|
"low": { "options": { "thinkingConfig": { "thinkingLevel": "low", "includeThoughts": true } } },
|
|
361
362
|
"medium": { "options": { "thinkingConfig": { "thinkingLevel": "medium", "includeThoughts": true } } },
|
|
362
|
-
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } }
|
|
363
|
-
|
|
363
|
+
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } },
|
|
364
|
+
"xhigh": { "options": { "thinkingConfig": { "thinkingLevel": "xhigh", "includeThoughts": true } } }
|
|
365
|
+
}
|
|
364
366
|
},
|
|
365
367
|
"gemini-2.5-flash-lite": {
|
|
366
368
|
"id": "gemini-2.5-flash-lite",
|
|
@@ -381,8 +383,9 @@ function loadStudioConfig() {
|
|
|
381
383
|
"minimal": { "options": { "thinkingConfig": { "thinkingLevel": "minimal", "includeThoughts": true } } },
|
|
382
384
|
"low": { "options": { "thinkingConfig": { "thinkingLevel": "low", "includeThoughts": true } } },
|
|
383
385
|
"medium": { "options": { "thinkingConfig": { "thinkingLevel": "medium", "includeThoughts": true } } },
|
|
384
|
-
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } }
|
|
385
|
-
|
|
386
|
+
"high": { "options": { "thinkingConfig": { "thinkingLevel": "high", "includeThoughts": true } } },
|
|
387
|
+
"xhigh": { "options": { "thinkingConfig": { "thinkingLevel": "xhigh", "includeThoughts": true } } }
|
|
388
|
+
}
|
|
386
389
|
},
|
|
387
390
|
"opencode/glm-4.7-free": {
|
|
388
391
|
"id": "opencode/glm-4.7-free",
|
|
@@ -408,8 +411,9 @@ function loadStudioConfig() {
|
|
|
408
411
|
"none": { "reasoning": false, "options": { "thinkingConfig": { "includeThoughts": false } } },
|
|
409
412
|
"low": { "options": { "thinkingConfig": { "thinkingBudget": 4000, "includeThoughts": true } } },
|
|
410
413
|
"medium": { "options": { "thinkingConfig": { "thinkingBudget": 16000, "includeThoughts": true } } },
|
|
411
|
-
"high": { "options": { "thinkingConfig": { "thinkingBudget": 32000, "includeThoughts": true } } }
|
|
412
|
-
|
|
414
|
+
"high": { "options": { "thinkingConfig": { "thinkingBudget": 32000, "includeThoughts": true } } },
|
|
415
|
+
"xhigh": { "options": { "thinkingConfig": { "thinkingBudget": 64000, "includeThoughts": true } } }
|
|
416
|
+
}
|
|
413
417
|
},
|
|
414
418
|
"gemini-claude-opus-4-5-thinking": {
|
|
415
419
|
"id": "gemini-claude-opus-4-5-thinking",
|
|
@@ -424,8 +428,9 @@ function loadStudioConfig() {
|
|
|
424
428
|
"variants": {
|
|
425
429
|
"low": { "options": { "thinkingConfig": { "thinkingBudget": 4000, "includeThoughts": true } } },
|
|
426
430
|
"medium": { "options": { "thinkingConfig": { "thinkingBudget": 16000, "includeThoughts": true } } },
|
|
427
|
-
"high": { "options": { "thinkingConfig": { "thinkingBudget": 32000, "includeThoughts": true } } }
|
|
428
|
-
|
|
431
|
+
"high": { "options": { "thinkingConfig": { "thinkingBudget": 32000, "includeThoughts": true } } },
|
|
432
|
+
"xhigh": { "options": { "thinkingConfig": { "thinkingBudget": 64000, "includeThoughts": true } } }
|
|
433
|
+
}
|
|
429
434
|
}
|
|
430
435
|
}
|
|
431
436
|
}
|
|
@@ -490,8 +495,15 @@ const getPaths = () => {
|
|
|
490
495
|
}
|
|
491
496
|
}
|
|
492
497
|
|
|
493
|
-
const studioConfig = loadStudioConfig();
|
|
494
|
-
|
|
498
|
+
const studioConfig = loadStudioConfig();
|
|
499
|
+
let manualPath = studioConfig.configPath;
|
|
500
|
+
|
|
501
|
+
if (manualPath && fs.existsSync(manualPath) && fs.statSync(manualPath).isDirectory()) {
|
|
502
|
+
const potentialFile = path.join(manualPath, 'opencode.json');
|
|
503
|
+
if (fs.existsSync(potentialFile)) {
|
|
504
|
+
manualPath = potentialFile;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
495
507
|
|
|
496
508
|
let detected = null;
|
|
497
509
|
for (const p of candidates) {
|
|
@@ -597,13 +609,20 @@ app.get('/api/debug/auth', (req, res) => {
|
|
|
597
609
|
});
|
|
598
610
|
});
|
|
599
611
|
|
|
600
|
-
app.post('/api/paths', (req, res) => {
|
|
601
|
-
const { configPath } = req.body;
|
|
602
|
-
const studioConfig = loadStudioConfig();
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
612
|
+
app.post('/api/paths', (req, res) => {
|
|
613
|
+
const { configPath } = req.body;
|
|
614
|
+
const studioConfig = loadStudioConfig();
|
|
615
|
+
|
|
616
|
+
if (configPath && fs.existsSync(configPath) && fs.statSync(configPath).isDirectory()) {
|
|
617
|
+
const potentialFile = path.join(configPath, 'opencode.json');
|
|
618
|
+
studioConfig.configPath = potentialFile;
|
|
619
|
+
} else {
|
|
620
|
+
studioConfig.configPath = configPath;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
saveStudioConfig(studioConfig);
|
|
624
|
+
res.json({ success: true, current: getConfigPath() });
|
|
625
|
+
});
|
|
607
626
|
|
|
608
627
|
app.get('/api/config', (req, res) => {
|
|
609
628
|
const config = loadConfig();
|
|
@@ -611,14 +630,15 @@ app.get('/api/config', (req, res) => {
|
|
|
611
630
|
res.json(config);
|
|
612
631
|
});
|
|
613
632
|
|
|
614
|
-
app.post('/api/config', (req, res) => {
|
|
615
|
-
try {
|
|
616
|
-
saveConfig(req.body);
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}
|
|
633
|
+
app.post('/api/config', (req, res) => {
|
|
634
|
+
try {
|
|
635
|
+
saveConfig(req.body);
|
|
636
|
+
triggerGitHubAutoSync();
|
|
637
|
+
res.json({ success: true });
|
|
638
|
+
} catch (err) {
|
|
639
|
+
res.status(500).json({ error: err.message });
|
|
640
|
+
}
|
|
641
|
+
});
|
|
622
642
|
|
|
623
643
|
app.get('/api/backup', (req, res) => {
|
|
624
644
|
try {
|
|
@@ -1074,10 +1094,11 @@ app.post('/api/ohmyopencode', (req, res) => {
|
|
|
1074
1094
|
|
|
1075
1095
|
saveOhMyOpenCodeConfig(currentConfig);
|
|
1076
1096
|
|
|
1077
|
-
const ohMyPath = getOhMyOpenCodeConfigPath();
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1097
|
+
const ohMyPath = getOhMyOpenCodeConfigPath();
|
|
1098
|
+
triggerGitHubAutoSync();
|
|
1099
|
+
res.json({
|
|
1100
|
+
success: true,
|
|
1101
|
+
path: ohMyPath,
|
|
1081
1102
|
exists: true,
|
|
1082
1103
|
config: currentConfig,
|
|
1083
1104
|
preferences,
|
|
@@ -1181,6 +1202,107 @@ function execPromise(cmd, opts = {}) {
|
|
|
1181
1202
|
});
|
|
1182
1203
|
}
|
|
1183
1204
|
|
|
1205
|
+
|
|
1206
|
+
let autoSyncTimer = null;
|
|
1207
|
+
|
|
1208
|
+
async function performGitHubBackup(options = {}) {
|
|
1209
|
+
const { owner, repo, branch } = options;
|
|
1210
|
+
let tempDir = null;
|
|
1211
|
+
try {
|
|
1212
|
+
const token = await getGitHubToken();
|
|
1213
|
+
if (!token) throw new Error('Not logged in to gh CLI. Run: gh auth login');
|
|
1214
|
+
|
|
1215
|
+
const user = await getGitHubUser(token);
|
|
1216
|
+
if (!user) throw new Error('Failed to get GitHub user');
|
|
1217
|
+
|
|
1218
|
+
const studio = loadStudioConfig();
|
|
1219
|
+
|
|
1220
|
+
const finalOwner = owner || studio.githubBackup?.owner || user.login;
|
|
1221
|
+
const finalRepo = repo || studio.githubBackup?.repo;
|
|
1222
|
+
const finalBranch = branch || studio.githubBackup?.branch || 'main';
|
|
1223
|
+
|
|
1224
|
+
if (!finalRepo) throw new Error('No repo name provided');
|
|
1225
|
+
|
|
1226
|
+
const repoName = `${finalOwner}/${finalRepo}`;
|
|
1227
|
+
|
|
1228
|
+
await ensureGitHubRepo(token, repoName);
|
|
1229
|
+
|
|
1230
|
+
const opencodeConfig = getConfigPath();
|
|
1231
|
+
if (!opencodeConfig) throw new Error('No opencode config path found');
|
|
1232
|
+
|
|
1233
|
+
const opencodeDir = path.dirname(opencodeConfig);
|
|
1234
|
+
const studioDir = path.join(HOME_DIR, '.config', 'opencode-studio');
|
|
1235
|
+
|
|
1236
|
+
tempDir = path.join(os.tmpdir(), `opencode-backup-${Date.now()}`);
|
|
1237
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
1238
|
+
|
|
1239
|
+
// Clone or init
|
|
1240
|
+
try {
|
|
1241
|
+
await execPromise(`git clone --depth 1 https://x-access-token:${token}@github.com/${repoName}.git .`, { cwd: tempDir });
|
|
1242
|
+
} catch (e) {
|
|
1243
|
+
// If clone fails (empty repo?), try init
|
|
1244
|
+
await execPromise('git init', { cwd: tempDir });
|
|
1245
|
+
await execPromise(`git remote add origin https://x-access-token:${token}@github.com/${repoName}.git`, { cwd: tempDir });
|
|
1246
|
+
await execPromise(`git checkout -b ${finalBranch}`, { cwd: tempDir });
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
const backupOpencodeDir = path.join(tempDir, 'opencode');
|
|
1250
|
+
const backupStudioDir = path.join(tempDir, 'opencode-studio');
|
|
1251
|
+
|
|
1252
|
+
if (fs.existsSync(backupOpencodeDir)) fs.rmSync(backupOpencodeDir, { recursive: true });
|
|
1253
|
+
if (fs.existsSync(backupStudioDir)) fs.rmSync(backupStudioDir, { recursive: true });
|
|
1254
|
+
|
|
1255
|
+
copyDirContents(opencodeDir, backupOpencodeDir);
|
|
1256
|
+
copyDirContents(studioDir, backupStudioDir);
|
|
1257
|
+
|
|
1258
|
+
await execPromise('git add -A', { cwd: tempDir });
|
|
1259
|
+
|
|
1260
|
+
const timestamp = new Date().toISOString();
|
|
1261
|
+
const commitMessage = `OpenCode Studio backup ${timestamp}`;
|
|
1262
|
+
|
|
1263
|
+
let result = { success: true, timestamp, url: `https://github.com/${repoName}` };
|
|
1264
|
+
|
|
1265
|
+
try {
|
|
1266
|
+
await execPromise(`git commit -m "${commitMessage}"`, { cwd: tempDir });
|
|
1267
|
+
await execPromise(`git push origin ${finalBranch}`, { cwd: tempDir });
|
|
1268
|
+
} catch (e) {
|
|
1269
|
+
if (e.message.includes('nothing to commit')) {
|
|
1270
|
+
result.message = 'No changes to backup';
|
|
1271
|
+
} else {
|
|
1272
|
+
throw e;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
studio.githubBackup = { owner: finalOwner, repo: finalRepo, branch: finalBranch };
|
|
1277
|
+
studio.lastGithubBackup = timestamp;
|
|
1278
|
+
saveStudioConfig(studio);
|
|
1279
|
+
|
|
1280
|
+
return result;
|
|
1281
|
+
} finally {
|
|
1282
|
+
if (tempDir && fs.existsSync(tempDir)) {
|
|
1283
|
+
try { fs.rmSync(tempDir, { recursive: true }); } catch (e) {}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
function triggerGitHubAutoSync() {
|
|
1289
|
+
const studio = loadStudioConfig();
|
|
1290
|
+
if (!studio.githubAutoSync) return;
|
|
1291
|
+
|
|
1292
|
+
if (autoSyncTimer) clearTimeout(autoSyncTimer);
|
|
1293
|
+
|
|
1294
|
+
console.log('[AutoSync] Change detected, scheduling GitHub backup in 15s...');
|
|
1295
|
+
autoSyncTimer = setTimeout(async () => {
|
|
1296
|
+
console.log('[AutoSync] Starting GitHub backup...');
|
|
1297
|
+
try {
|
|
1298
|
+
const result = await performGitHubBackup();
|
|
1299
|
+
console.log(`[AutoSync] Backup completed: ${result.message || 'Pushed to GitHub'}`);
|
|
1300
|
+
} catch (err) {
|
|
1301
|
+
console.error('[AutoSync] Backup failed:', err.message);
|
|
1302
|
+
}
|
|
1303
|
+
}, 15000); // 15s debounce
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1184
1306
|
app.get('/api/github/backup/status', async (req, res) => {
|
|
1185
1307
|
try {
|
|
1186
1308
|
const token = await getGitHubToken();
|
|
@@ -1212,77 +1334,15 @@ app.get('/api/github/backup/status', async (req, res) => {
|
|
|
1212
1334
|
}
|
|
1213
1335
|
});
|
|
1214
1336
|
|
|
1215
|
-
app.post('/api/github/backup', async (req, res) => {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
const { owner, repo, branch } = req.body;
|
|
1225
|
-
const studio = loadStudioConfig();
|
|
1226
|
-
|
|
1227
|
-
const finalOwner = owner || studio.githubBackup?.owner || user.login;
|
|
1228
|
-
const finalRepo = repo || studio.githubBackup?.repo;
|
|
1229
|
-
const finalBranch = branch || studio.githubBackup?.branch || 'main';
|
|
1230
|
-
|
|
1231
|
-
if (!finalRepo) return res.status(400).json({ error: 'No repo name provided' });
|
|
1232
|
-
|
|
1233
|
-
const repoName = `${finalOwner}/${finalRepo}`;
|
|
1234
|
-
|
|
1235
|
-
await ensureGitHubRepo(token, repoName);
|
|
1236
|
-
|
|
1237
|
-
const opencodeConfig = getConfigPath();
|
|
1238
|
-
if (!opencodeConfig) return res.status(400).json({ error: 'No opencode config path found' });
|
|
1239
|
-
|
|
1240
|
-
const opencodeDir = path.dirname(opencodeConfig);
|
|
1241
|
-
const studioDir = path.join(HOME_DIR, '.config', 'opencode-studio');
|
|
1242
|
-
|
|
1243
|
-
tempDir = path.join(os.tmpdir(), `opencode-backup-${Date.now()}`);
|
|
1244
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
1245
|
-
|
|
1246
|
-
await execPromise(`git clone --depth 1 https://x-access-token:${token}@github.com/${repoName}.git .`, { cwd: tempDir });
|
|
1247
|
-
|
|
1248
|
-
const backupOpencodeDir = path.join(tempDir, 'opencode');
|
|
1249
|
-
const backupStudioDir = path.join(tempDir, 'opencode-studio');
|
|
1250
|
-
|
|
1251
|
-
if (fs.existsSync(backupOpencodeDir)) fs.rmSync(backupOpencodeDir, { recursive: true });
|
|
1252
|
-
if (fs.existsSync(backupStudioDir)) fs.rmSync(backupStudioDir, { recursive: true });
|
|
1253
|
-
|
|
1254
|
-
copyDirContents(opencodeDir, backupOpencodeDir);
|
|
1255
|
-
copyDirContents(studioDir, backupStudioDir);
|
|
1256
|
-
|
|
1257
|
-
await execPromise('git add -A', { cwd: tempDir });
|
|
1258
|
-
|
|
1259
|
-
const timestamp = new Date().toISOString();
|
|
1260
|
-
const commitMessage = `OpenCode Studio backup ${timestamp}`;
|
|
1261
|
-
|
|
1262
|
-
try {
|
|
1263
|
-
await execPromise(`git commit -m "${commitMessage}"`, { cwd: tempDir });
|
|
1264
|
-
await execPromise(`git push origin ${finalBranch}`, { cwd: tempDir });
|
|
1265
|
-
} catch (e) {
|
|
1266
|
-
if (e.message.includes('nothing to commit')) {
|
|
1267
|
-
fs.rmSync(tempDir, { recursive: true });
|
|
1268
|
-
return res.json({ success: true, timestamp, message: 'No changes to backup', url: `https://github.com/${repoName}` });
|
|
1269
|
-
}
|
|
1270
|
-
throw e;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
fs.rmSync(tempDir, { recursive: true });
|
|
1274
|
-
|
|
1275
|
-
studio.githubBackup = { owner: finalOwner, repo: finalRepo, branch: finalBranch };
|
|
1276
|
-
studio.lastGithubBackup = timestamp;
|
|
1277
|
-
saveStudioConfig(studio);
|
|
1278
|
-
|
|
1279
|
-
res.json({ success: true, timestamp, url: `https://github.com/${repoName}` });
|
|
1280
|
-
} catch (err) {
|
|
1281
|
-
if (tempDir && fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true });
|
|
1282
|
-
console.error('GitHub backup error:', err);
|
|
1283
|
-
res.status(500).json({ error: err.message });
|
|
1284
|
-
}
|
|
1285
|
-
});
|
|
1337
|
+
app.post('/api/github/backup', async (req, res) => {
|
|
1338
|
+
try {
|
|
1339
|
+
const result = await performGitHubBackup(req.body);
|
|
1340
|
+
res.json(result);
|
|
1341
|
+
} catch (err) {
|
|
1342
|
+
console.error('GitHub backup error:', err);
|
|
1343
|
+
res.status(500).json({ error: err.message });
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1286
1346
|
|
|
1287
1347
|
app.post('/api/github/restore', async (req, res) => {
|
|
1288
1348
|
let tempDir = null;
|
|
@@ -1341,9 +1401,10 @@ app.post('/api/github/restore', async (req, res) => {
|
|
|
1341
1401
|
app.post('/api/github/autosync', async (req, res) => {
|
|
1342
1402
|
const studio = loadStudioConfig();
|
|
1343
1403
|
const enabled = req.body.enabled;
|
|
1344
|
-
studio.githubAutoSync = enabled;
|
|
1345
|
-
saveStudioConfig(studio);
|
|
1346
|
-
|
|
1404
|
+
studio.githubAutoSync = enabled;
|
|
1405
|
+
saveStudioConfig(studio);
|
|
1406
|
+
if (enabled) triggerGitHubAutoSync();
|
|
1407
|
+
res.json({ success: true, enabled });
|
|
1347
1408
|
});
|
|
1348
1409
|
|
|
1349
1410
|
const getSkillDir = () => {
|
|
@@ -1380,8 +1441,9 @@ app.post('/api/skills/:name', (req, res) => {
|
|
|
1380
1441
|
if (!sd) return res.status(404).json({ error: 'No config' });
|
|
1381
1442
|
const dp = path.join(sd, req.params.name);
|
|
1382
1443
|
if (!fs.existsSync(dp)) fs.mkdirSync(dp, { recursive: true });
|
|
1383
|
-
fs.writeFileSync(path.join(dp, 'SKILL.md'), req.body.content, 'utf8');
|
|
1384
|
-
|
|
1444
|
+
fs.writeFileSync(path.join(dp, 'SKILL.md'), req.body.content, 'utf8');
|
|
1445
|
+
triggerGitHubAutoSync();
|
|
1446
|
+
res.json({ success: true });
|
|
1385
1447
|
});
|
|
1386
1448
|
|
|
1387
1449
|
app.delete('/api/skills/:name', (req, res) => {
|
|
@@ -1390,8 +1452,9 @@ app.delete('/api/skills/:name', (req, res) => {
|
|
|
1390
1452
|
}
|
|
1391
1453
|
const sd = getSkillDir();
|
|
1392
1454
|
const dp = sd ? path.join(sd, req.params.name) : null;
|
|
1393
|
-
if (dp && fs.existsSync(dp)) fs.rmSync(dp, { recursive: true, force: true });
|
|
1394
|
-
|
|
1455
|
+
if (dp && fs.existsSync(dp)) fs.rmSync(dp, { recursive: true, force: true });
|
|
1456
|
+
triggerGitHubAutoSync();
|
|
1457
|
+
res.json({ success: true });
|
|
1395
1458
|
});
|
|
1396
1459
|
|
|
1397
1460
|
app.post('/api/skills/:name/toggle', (req, res) => {
|
|
@@ -1405,8 +1468,9 @@ app.post('/api/skills/:name/toggle', (req, res) => {
|
|
|
1405
1468
|
studio.disabledSkills.push(name);
|
|
1406
1469
|
}
|
|
1407
1470
|
|
|
1408
|
-
saveStudioConfig(studio);
|
|
1409
|
-
|
|
1471
|
+
saveStudioConfig(studio);
|
|
1472
|
+
triggerGitHubAutoSync();
|
|
1473
|
+
res.json({ success: true, enabled: !studio.disabledSkills.includes(name) });
|
|
1410
1474
|
});
|
|
1411
1475
|
|
|
1412
1476
|
const getPluginDir = () => {
|
|
@@ -1483,9 +1547,10 @@ app.post('/api/plugins/:name', (req, res) => {
|
|
|
1483
1547
|
if (!fs.existsSync(pd)) fs.mkdirSync(pd, { recursive: true });
|
|
1484
1548
|
|
|
1485
1549
|
// Default to .js if new
|
|
1486
|
-
const filePath = path.join(pd, name.endsWith('.js') || name.endsWith('.ts') ? name : name + '.js');
|
|
1487
|
-
atomicWriteFileSync(filePath, content);
|
|
1488
|
-
|
|
1550
|
+
const filePath = path.join(pd, name.endsWith('.js') || name.endsWith('.ts') ? name : name + '.js');
|
|
1551
|
+
atomicWriteFileSync(filePath, content);
|
|
1552
|
+
triggerGitHubAutoSync();
|
|
1553
|
+
res.json({ success: true });
|
|
1489
1554
|
});
|
|
1490
1555
|
|
|
1491
1556
|
app.delete('/api/plugins/:name', (req, res) => {
|
|
@@ -1510,8 +1575,10 @@ app.delete('/api/plugins/:name', (req, res) => {
|
|
|
1510
1575
|
}
|
|
1511
1576
|
}
|
|
1512
1577
|
|
|
1513
|
-
if (deleted)
|
|
1514
|
-
|
|
1578
|
+
if (deleted) {
|
|
1579
|
+
triggerGitHubAutoSync();
|
|
1580
|
+
res.json({ success: true });
|
|
1581
|
+
} else res.status(404).json({ error: 'Plugin not found' });
|
|
1515
1582
|
});
|
|
1516
1583
|
|
|
1517
1584
|
app.post('/api/plugins/:name/toggle', (req, res) => {
|
|
@@ -1525,8 +1592,9 @@ app.post('/api/plugins/:name/toggle', (req, res) => {
|
|
|
1525
1592
|
studio.disabledPlugins.push(name);
|
|
1526
1593
|
}
|
|
1527
1594
|
|
|
1528
|
-
saveStudioConfig(studio);
|
|
1529
|
-
|
|
1595
|
+
saveStudioConfig(studio);
|
|
1596
|
+
triggerGitHubAutoSync();
|
|
1597
|
+
res.json({ success: true, enabled: !studio.disabledPlugins.includes(name) });
|
|
1530
1598
|
});
|
|
1531
1599
|
|
|
1532
1600
|
const getActiveGooglePlugin = () => {
|
|
@@ -3423,7 +3491,17 @@ app.post('/api/presets/:id/apply', (req, res) => {
|
|
|
3423
3491
|
// Start watcher on server start
|
|
3424
3492
|
function startServer() {
|
|
3425
3493
|
['google', 'anthropic', 'openai', 'xai', 'openrouter', 'together', 'mistral', 'deepseek', 'amazon-bedrock', 'azure', 'github-copilot'].forEach(p => importCurrentAuthToPool(p));
|
|
3426
|
-
app.listen(PORT, () =>
|
|
3494
|
+
app.listen(PORT, () => {
|
|
3495
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
|
3496
|
+
// Initial sync on startup if enabled
|
|
3497
|
+
setTimeout(() => {
|
|
3498
|
+
const studio = loadStudioConfig();
|
|
3499
|
+
if (studio.githubAutoSync) {
|
|
3500
|
+
console.log('[AutoSync] Triggering initial sync...');
|
|
3501
|
+
triggerGitHubAutoSync();
|
|
3502
|
+
}
|
|
3503
|
+
}, 5000);
|
|
3504
|
+
});
|
|
3427
3505
|
}
|
|
3428
3506
|
|
|
3429
3507
|
if (require.main === module) {
|