opencode-studio-server 1.3.9 → 1.4.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/index.js +67 -8
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -7,6 +7,9 @@ const os = require('os');
|
|
|
7
7
|
const crypto = require('crypto');
|
|
8
8
|
const { spawn, exec } = require('child_process');
|
|
9
9
|
|
|
10
|
+
const pkg = require('./package.json');
|
|
11
|
+
const SERVER_VERSION = pkg.version;
|
|
12
|
+
|
|
10
13
|
// Atomic file write: write to temp file then rename to prevent corruption
|
|
11
14
|
const atomicWriteFileSync = (filePath, data, options = 'utf8') => {
|
|
12
15
|
const dir = path.dirname(filePath);
|
|
@@ -436,7 +439,7 @@ const saveConfig = (config) => {
|
|
|
436
439
|
atomicWriteFileSync(configPath, JSON.stringify(config, null, 2));
|
|
437
440
|
};
|
|
438
441
|
|
|
439
|
-
app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
|
|
442
|
+
app.get('/api/health', (req, res) => res.json({ status: 'ok', version: SERVER_VERSION }));
|
|
440
443
|
|
|
441
444
|
app.post('/api/shutdown', (req, res) => {
|
|
442
445
|
res.json({ success: true });
|
|
@@ -445,6 +448,56 @@ app.post('/api/shutdown', (req, res) => {
|
|
|
445
448
|
|
|
446
449
|
app.get('/api/paths', (req, res) => res.json(getPaths()));
|
|
447
450
|
|
|
451
|
+
app.get('/api/debug/auth', (req, res) => {
|
|
452
|
+
const paths = getPaths();
|
|
453
|
+
const studio = loadStudioConfig();
|
|
454
|
+
const activePlugin = studio.activeGooglePlugin;
|
|
455
|
+
|
|
456
|
+
// Check auth.json in all candidate locations
|
|
457
|
+
const authLocations = [];
|
|
458
|
+
paths.candidates.forEach(p => {
|
|
459
|
+
const ap = path.join(path.dirname(p), 'auth.json');
|
|
460
|
+
authLocations.push({
|
|
461
|
+
path: ap,
|
|
462
|
+
exists: fs.existsSync(ap),
|
|
463
|
+
keys: fs.existsSync(ap) ? Object.keys(JSON.parse(fs.readFileSync(ap, 'utf8'))) : []
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Check current auth.json
|
|
468
|
+
if (paths.current) {
|
|
469
|
+
const ap = path.join(path.dirname(paths.current), 'auth.json');
|
|
470
|
+
if (!authLocations.some(l => l.path === ap)) {
|
|
471
|
+
authLocations.push({
|
|
472
|
+
path: ap,
|
|
473
|
+
exists: fs.existsSync(ap),
|
|
474
|
+
keys: fs.existsSync(ap) ? Object.keys(JSON.parse(fs.readFileSync(ap, 'utf8'))) : []
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Check profile directories
|
|
480
|
+
const namespaces = ['google', 'google.gemini', 'google.antigravity', 'openai', 'anthropic'];
|
|
481
|
+
const profileDirs = {};
|
|
482
|
+
namespaces.forEach(ns => {
|
|
483
|
+
const dir = path.join(AUTH_PROFILES_DIR, ns);
|
|
484
|
+
profileDirs[ns] = {
|
|
485
|
+
path: dir,
|
|
486
|
+
exists: fs.existsSync(dir),
|
|
487
|
+
profiles: fs.existsSync(dir) ? fs.readdirSync(dir).filter(f => f.endsWith('.json')) : []
|
|
488
|
+
};
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
res.json({
|
|
492
|
+
configPath: paths.current,
|
|
493
|
+
activeGooglePlugin: activePlugin,
|
|
494
|
+
activeProfiles: studio.activeProfiles || {},
|
|
495
|
+
authLocations,
|
|
496
|
+
profileDirs,
|
|
497
|
+
authProfilesDir: AUTH_PROFILES_DIR
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
448
501
|
app.post('/api/paths', (req, res) => {
|
|
449
502
|
const { configPath } = req.body;
|
|
450
503
|
const studioConfig = loadStudioConfig();
|
|
@@ -476,9 +529,11 @@ const getSkillDir = () => {
|
|
|
476
529
|
app.get('/api/skills', (req, res) => {
|
|
477
530
|
const sd = getSkillDir();
|
|
478
531
|
if (!sd || !fs.existsSync(sd)) return res.json([]);
|
|
532
|
+
const studio = loadStudioConfig();
|
|
533
|
+
const disabledSkills = studio.disabledSkills || [];
|
|
479
534
|
const skills = fs.readdirSync(sd, { withFileTypes: true })
|
|
480
535
|
.filter(e => e.isDirectory() && fs.existsSync(path.join(sd, e.name, 'SKILL.md')))
|
|
481
|
-
.map(e => ({ name: e.name, path: path.join(sd, e.name, 'SKILL.md'), enabled: !e.name
|
|
536
|
+
.map(e => ({ name: e.name, path: path.join(sd, e.name, 'SKILL.md'), enabled: !disabledSkills.includes(e.name) }));
|
|
482
537
|
res.json(skills);
|
|
483
538
|
});
|
|
484
539
|
|
|
@@ -538,9 +593,13 @@ app.get('/api/plugins', (req, res) => {
|
|
|
538
593
|
const pd = getPluginDir();
|
|
539
594
|
const cp = getConfigPath();
|
|
540
595
|
const cr = cp ? path.dirname(cp) : null;
|
|
596
|
+
const studio = loadStudioConfig();
|
|
597
|
+
const disabledPlugins = studio.disabledPlugins || [];
|
|
541
598
|
const plugins = [];
|
|
542
|
-
const add = (name, p,
|
|
543
|
-
if (!plugins.some(pl => pl.name === name))
|
|
599
|
+
const add = (name, p, type = 'file') => {
|
|
600
|
+
if (!plugins.some(pl => pl.name === name)) {
|
|
601
|
+
plugins.push({ name, path: p, type, enabled: !disabledPlugins.includes(name) });
|
|
602
|
+
}
|
|
544
603
|
};
|
|
545
604
|
|
|
546
605
|
if (pd && fs.existsSync(pd)) {
|
|
@@ -549,9 +608,9 @@ app.get('/api/plugins', (req, res) => {
|
|
|
549
608
|
const st = fs.lstatSync(fp);
|
|
550
609
|
if (st.isDirectory()) {
|
|
551
610
|
const j = path.join(fp, 'index.js'), t = path.join(fp, 'index.ts');
|
|
552
|
-
if (fs.existsSync(j) || fs.existsSync(t)) add(e.name, fs.existsSync(j) ? j : t);
|
|
611
|
+
if (fs.existsSync(j) || fs.existsSync(t)) add(e.name, fs.existsSync(j) ? j : t, 'file');
|
|
553
612
|
} else if ((st.isFile() || st.isSymbolicLink()) && /\.(js|ts)$/.test(e.name)) {
|
|
554
|
-
add(e.name.replace(/\.(js|ts)$/, ''), fp);
|
|
613
|
+
add(e.name.replace(/\.(js|ts)$/, ''), fp, 'file');
|
|
555
614
|
}
|
|
556
615
|
});
|
|
557
616
|
}
|
|
@@ -559,14 +618,14 @@ app.get('/api/plugins', (req, res) => {
|
|
|
559
618
|
if (cr && fs.existsSync(cr)) {
|
|
560
619
|
['oh-my-opencode', 'superpowers', 'opencode-gemini-auth'].forEach(n => {
|
|
561
620
|
const fp = path.join(cr, n);
|
|
562
|
-
if (fs.existsSync(fp) && fs.statSync(fp).isDirectory()) add(n, fp);
|
|
621
|
+
if (fs.existsSync(fp) && fs.statSync(fp).isDirectory()) add(n, fp, 'file');
|
|
563
622
|
});
|
|
564
623
|
}
|
|
565
624
|
|
|
566
625
|
const cfg = loadConfig();
|
|
567
626
|
if (cfg && Array.isArray(cfg.plugin)) {
|
|
568
627
|
cfg.plugin.forEach(n => {
|
|
569
|
-
if (!n.includes('/') && !n.includes('\\') && !/\.(js|ts)$/.test(n)) add(n, 'npm');
|
|
628
|
+
if (!n.includes('/') && !n.includes('\\') && !/\.(js|ts)$/.test(n)) add(n, 'npm', 'npm');
|
|
570
629
|
});
|
|
571
630
|
}
|
|
572
631
|
res.json(plugins);
|