opencode-studio-server 1.3.9 → 1.4.1

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.
Files changed (2) hide show
  1. package/index.js +72 -11
  2. 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);
@@ -219,9 +222,7 @@ function processLogLine(line) {
219
222
  }
220
223
  }
221
224
 
222
- // Start watcher on server start
223
- setupLogWatcher();
224
- importExistingAuth();
225
+
225
226
 
226
227
  let pendingActionMemory = null;
227
228
 
@@ -436,7 +437,7 @@ const saveConfig = (config) => {
436
437
  atomicWriteFileSync(configPath, JSON.stringify(config, null, 2));
437
438
  };
438
439
 
439
- app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
440
+ app.get('/api/health', (req, res) => res.json({ status: 'ok', version: SERVER_VERSION }));
440
441
 
441
442
  app.post('/api/shutdown', (req, res) => {
442
443
  res.json({ success: true });
@@ -445,6 +446,56 @@ app.post('/api/shutdown', (req, res) => {
445
446
 
446
447
  app.get('/api/paths', (req, res) => res.json(getPaths()));
447
448
 
449
+ app.get('/api/debug/auth', (req, res) => {
450
+ const paths = getPaths();
451
+ const studio = loadStudioConfig();
452
+ const activePlugin = studio.activeGooglePlugin;
453
+
454
+ // Check auth.json in all candidate locations
455
+ const authLocations = [];
456
+ paths.candidates.forEach(p => {
457
+ const ap = path.join(path.dirname(p), 'auth.json');
458
+ authLocations.push({
459
+ path: ap,
460
+ exists: fs.existsSync(ap),
461
+ keys: fs.existsSync(ap) ? Object.keys(JSON.parse(fs.readFileSync(ap, 'utf8'))) : []
462
+ });
463
+ });
464
+
465
+ // Check current auth.json
466
+ if (paths.current) {
467
+ const ap = path.join(path.dirname(paths.current), 'auth.json');
468
+ if (!authLocations.some(l => l.path === ap)) {
469
+ authLocations.push({
470
+ path: ap,
471
+ exists: fs.existsSync(ap),
472
+ keys: fs.existsSync(ap) ? Object.keys(JSON.parse(fs.readFileSync(ap, 'utf8'))) : []
473
+ });
474
+ }
475
+ }
476
+
477
+ // Check profile directories
478
+ const namespaces = ['google', 'google.gemini', 'google.antigravity', 'openai', 'anthropic'];
479
+ const profileDirs = {};
480
+ namespaces.forEach(ns => {
481
+ const dir = path.join(AUTH_PROFILES_DIR, ns);
482
+ profileDirs[ns] = {
483
+ path: dir,
484
+ exists: fs.existsSync(dir),
485
+ profiles: fs.existsSync(dir) ? fs.readdirSync(dir).filter(f => f.endsWith('.json')) : []
486
+ };
487
+ });
488
+
489
+ res.json({
490
+ configPath: paths.current,
491
+ activeGooglePlugin: activePlugin,
492
+ activeProfiles: studio.activeProfiles || {},
493
+ authLocations,
494
+ profileDirs,
495
+ authProfilesDir: AUTH_PROFILES_DIR
496
+ });
497
+ });
498
+
448
499
  app.post('/api/paths', (req, res) => {
449
500
  const { configPath } = req.body;
450
501
  const studioConfig = loadStudioConfig();
@@ -476,9 +527,11 @@ const getSkillDir = () => {
476
527
  app.get('/api/skills', (req, res) => {
477
528
  const sd = getSkillDir();
478
529
  if (!sd || !fs.existsSync(sd)) return res.json([]);
530
+ const studio = loadStudioConfig();
531
+ const disabledSkills = studio.disabledSkills || [];
479
532
  const skills = fs.readdirSync(sd, { withFileTypes: true })
480
533
  .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.endsWith('.disabled') }));
534
+ .map(e => ({ name: e.name, path: path.join(sd, e.name, 'SKILL.md'), enabled: !disabledSkills.includes(e.name) }));
482
535
  res.json(skills);
483
536
  });
484
537
 
@@ -538,9 +591,13 @@ app.get('/api/plugins', (req, res) => {
538
591
  const pd = getPluginDir();
539
592
  const cp = getConfigPath();
540
593
  const cr = cp ? path.dirname(cp) : null;
594
+ const studio = loadStudioConfig();
595
+ const disabledPlugins = studio.disabledPlugins || [];
541
596
  const plugins = [];
542
- const add = (name, p, enabled = true) => {
543
- if (!plugins.some(pl => pl.name === name)) plugins.push({ name, path: p, enabled });
597
+ const add = (name, p, type = 'file') => {
598
+ if (!plugins.some(pl => pl.name === name)) {
599
+ plugins.push({ name, path: p, type, enabled: !disabledPlugins.includes(name) });
600
+ }
544
601
  };
545
602
 
546
603
  if (pd && fs.existsSync(pd)) {
@@ -549,9 +606,9 @@ app.get('/api/plugins', (req, res) => {
549
606
  const st = fs.lstatSync(fp);
550
607
  if (st.isDirectory()) {
551
608
  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);
609
+ if (fs.existsSync(j) || fs.existsSync(t)) add(e.name, fs.existsSync(j) ? j : t, 'file');
553
610
  } else if ((st.isFile() || st.isSymbolicLink()) && /\.(js|ts)$/.test(e.name)) {
554
- add(e.name.replace(/\.(js|ts)$/, ''), fp);
611
+ add(e.name.replace(/\.(js|ts)$/, ''), fp, 'file');
555
612
  }
556
613
  });
557
614
  }
@@ -559,14 +616,14 @@ app.get('/api/plugins', (req, res) => {
559
616
  if (cr && fs.existsSync(cr)) {
560
617
  ['oh-my-opencode', 'superpowers', 'opencode-gemini-auth'].forEach(n => {
561
618
  const fp = path.join(cr, n);
562
- if (fs.existsSync(fp) && fs.statSync(fp).isDirectory()) add(n, fp);
619
+ if (fs.existsSync(fp) && fs.statSync(fp).isDirectory()) add(n, fp, 'file');
563
620
  });
564
621
  }
565
622
 
566
623
  const cfg = loadConfig();
567
624
  if (cfg && Array.isArray(cfg.plugin)) {
568
625
  cfg.plugin.forEach(n => {
569
- if (!n.includes('/') && !n.includes('\\') && !/\.(js|ts)$/.test(n)) add(n, 'npm');
626
+ if (!n.includes('/') && !n.includes('\\') && !/\.(js|ts)$/.test(n)) add(n, 'npm', 'npm');
570
627
  });
571
628
  }
572
629
  res.json(plugins);
@@ -2194,4 +2251,8 @@ app.post('/api/presets/:id/apply', (req, res) => {
2194
2251
  res.json({ success: true });
2195
2252
  });
2196
2253
 
2254
+ // Start watcher on server start
2255
+ setupLogWatcher();
2256
+ importExistingAuth();
2257
+
2197
2258
  app.listen(PORT, () => console.log(`Server running at http://localhost:${PORT}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-studio-server",
3
- "version": "1.3.9",
3
+ "version": "1.4.1",
4
4
  "description": "Backend server for OpenCode Studio - manages opencode configurations",
5
5
  "main": "index.js",
6
6
  "bin": {