synabun 2026.4.20-beta.7 → 2026.4.20-beta.8

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.
@@ -1080,6 +1080,7 @@ function buildSetupTab(setupStatus) {
1080
1080
  const claudeConnected = setupStatus.claude?.connected || false;
1081
1081
  const geminiConnected = setupStatus.gemini?.connected || false;
1082
1082
  const codexConnected = setupStatus.codex?.connected || false;
1083
+ const opencodeConnected = setupStatus.opencode?.connected || false;
1083
1084
 
1084
1085
  const statusBadge = (on) => `<span class="setup-status-badge ${on ? 'active' : 'inactive'}">${on ? 'Connected' : 'Off'}</span>`;
1085
1086
 
@@ -1184,6 +1185,40 @@ function buildSetupTab(setupStatus) {
1184
1185
  </div>
1185
1186
  </div>
1186
1187
 
1188
+ <!-- OPENCODE -->
1189
+ <div class="iface-section collapsed" data-collapsible id="setup-opencode">
1190
+ <div class="gfx-group-title">
1191
+ <span style="display:flex;align-items:center;gap:8px">
1192
+ ${CHEVRON_ICON}
1193
+ ${OPENCODE_ICON}
1194
+ <span>OpenCode</span>
1195
+ ${statusBadge(opencodeConnected)}
1196
+ </span>
1197
+ </div>
1198
+ <div class="cc-section-body">
1199
+ <div class="cc-integration-item${opencodeConnected ? ' enabled' : ''}" id="setup-opencode-mcp-row">
1200
+ <div class="cc-integration-info">
1201
+ <div class="cc-integration-label">SynaBun MCP</div>
1202
+ <div class="cc-integration-path" id="setup-opencode-mcp-status">${opencodeConnected ? 'Registered in ~/.config/opencode/config.json' : 'Not connected'}</div>
1203
+ </div>
1204
+ <button class="cc-toggle${opencodeConnected ? ' on' : ''}" id="setup-opencode-mcp-toggle"></button>
1205
+ </div>
1206
+
1207
+ <div style="margin-top:12px">
1208
+ <div class="cc-greeting-label" style="margin-bottom:4px">Manual Config <span style="color:var(--t-faint)">(~/.config/opencode/config.json)</span></div>
1209
+ <div class="cc-ruleset-preview" id="setup-opencode-config-preview" style="max-height:120px">Loading...</div>
1210
+ <button class="cc-copy-btn" id="setup-opencode-config-copy" style="margin-top:4px">${COPY_ICON} Copy JSON Config</button>
1211
+ </div>
1212
+
1213
+ <div style="margin-top:12px">
1214
+ <div class="cc-greeting-label" style="margin-bottom:4px">AGENTS.md Ruleset</div>
1215
+ <div class="cc-ruleset-preview" id="setup-opencode-ruleset-preview">Loading...</div>
1216
+ <button class="cc-copy-btn" id="setup-opencode-ruleset-copy" style="margin-top:4px">${COPY_ICON} Copy Ruleset</button>
1217
+ <div class="setup-hint">Paste into your project's <code>AGENTS.md</code></div>
1218
+ </div>
1219
+ </div>
1220
+ </div>
1221
+
1187
1222
  <!-- COEXISTENCE RULES -->
1188
1223
  <div class="iface-section collapsed" data-collapsible id="setup-coexistence">
1189
1224
  <div class="gfx-group-title">
@@ -2855,7 +2890,7 @@ export async function openSettingsModal() {
2855
2890
  let greetingConfig = { defaults: {}, projects: {}, global: {} };
2856
2891
  let codexGreetingConfig = { enabled: true, defaults: {}, projects: {}, global: {} };
2857
2892
  let opencodeGreetingConfig = { enabled: false, defaults: {}, projects: {}, global: {} };
2858
- let setupStatus = { claude: {}, gemini: {}, codex: {}, paths: {} };
2893
+ let setupStatus = { claude: {}, gemini: {}, codex: {}, opencode: {}, paths: {} };
2859
2894
  let cliConfig = {};
2860
2895
  let toolPermissions = {};
2861
2896
  let toolCategories = [];
@@ -2944,7 +2979,7 @@ export async function openSettingsModal() {
2944
2979
  <nav class="settings-nav">
2945
2980
  ${buildNavHTML(variantTabs, {
2946
2981
  server: settings.storage === 'sqlite' ? 'connected' : 'disconnected',
2947
- setup: (setupStatus.claude?.connected || setupStatus.gemini?.connected || setupStatus.codex?.connected) ? 'connected' : 'disconnected',
2982
+ setup: (setupStatus.claude?.connected || setupStatus.gemini?.connected || setupStatus.codex?.connected || setupStatus.opencode?.connected) ? 'connected' : 'disconnected',
2948
2983
  discord: discordConfig.botToken ? 'connected' : 'disconnected',
2949
2984
  })}
2950
2985
  </nav>
@@ -4989,6 +5024,38 @@ export async function openSettingsModal() {
4989
5024
  }
4990
5025
  wireRulesetPreview('codex', 'codex');
4991
5026
 
5027
+ // ── OpenCode ──
5028
+ wireSetupMcpToggle('opencode', '/api/opencode/mcp', '~/.config/opencode/config.json');
5029
+ // Config preview — OpenCode stores MCP servers under the "mcp" key of config.json
5030
+ {
5031
+ const preview = overlay.querySelector('#setup-opencode-config-preview');
5032
+ let cachedConfig = '';
5033
+ if (preview) {
5034
+ const mp = setupStatus.paths?.mcpIndexPath || '<path-to>/mcp-server/run.mjs';
5035
+ const ep = setupStatus.paths?.envPath || '<path-to>/synabun/.env';
5036
+ fetch('/api/opencode/mcp').then(r => r.json()).then(data => {
5037
+ if (data.ok && data.data && Object.keys(data.data).length) {
5038
+ cachedConfig = JSON.stringify({ mcp: data.data }, null, 2);
5039
+ preview.textContent = cachedConfig;
5040
+ } else if (data.ok) {
5041
+ cachedConfig = JSON.stringify({
5042
+ mcp: {
5043
+ SynaBun: {
5044
+ type: 'stdio',
5045
+ command: 'node',
5046
+ args: [mp],
5047
+ env: { DOTENV_PATH: ep },
5048
+ },
5049
+ },
5050
+ }, null, 2);
5051
+ preview.textContent = cachedConfig;
5052
+ } else { preview.textContent = 'Could not load config.'; }
5053
+ }).catch(() => { preview.textContent = 'Failed to load.'; });
5054
+ }
5055
+ wireCopyBtn('setup-opencode-config-copy', () => cachedConfig, 'Copy JSON Config');
5056
+ }
5057
+ wireRulesetPreview('opencode', 'generic');
5058
+
4992
5059
  // ── Coexistence rules ──
4993
5060
  wireRulesetPreview('coexistence', 'coexistence');
4994
5061
  }
@@ -13887,7 +13887,17 @@ app.get('/api/setup/status', (req, res) => {
13887
13887
  } catch {}
13888
13888
  codex.cliCommand = `codex --full-auto mcp add -- node "${mcpIndexPath}"`;
13889
13889
 
13890
- res.json({ ok: true, claude, gemini, codex, paths: { mcpIndexPath, envPath } });
13890
+ // OpenCode
13891
+ let opencode = { connected: false };
13892
+ try {
13893
+ const ocPath = getOpencodeConfigPath();
13894
+ if (existsSync(ocPath)) {
13895
+ const oc = JSON.parse(readFileSync(ocPath, 'utf-8'));
13896
+ opencode.connected = !!(oc?.mcp && oc.mcp.SynaBun);
13897
+ }
13898
+ } catch {}
13899
+
13900
+ res.json({ ok: true, claude, gemini, codex, opencode, paths: { mcpIndexPath, envPath } });
13891
13901
  } catch (err) {
13892
13902
  res.status(500).json({ error: err.message });
13893
13903
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synabun",
3
- "version": "2026.4.20-beta.7",
3
+ "version": "2026.4.20-beta.8",
4
4
  "description": "Persistent vector memory for AI assistants",
5
5
  "license": "Apache-2.0",
6
6
  "author": "The SynaBun Authors",