opencode-antigravity-config 1.0.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/README.md +111 -0
- package/app.png +0 -0
- package/cli.js +17 -0
- package/config-data.js +23 -0
- package/i18n.js +198 -0
- package/index.html +432 -0
- package/main.js +307 -0
- package/package.json +27 -0
- package/preload.js +22 -0
- package/renderer.js +316 -0
- package/styles.css +1086 -0
- package/templates/dcp.jsonc +81 -0
- package/templates/oh-my-opencode.jsonc +173 -0
- package/templates/opencode-sync.jsonc +12 -0
- package/templates/opencode.json +236 -0
- package/templates/package.json +6 -0
- package/templates/supermemory.jsonc +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# ⚡ Opencode Antigravity Config
|
|
2
|
+
|
|
3
|
+
GUI installer for [Antigravity OpenCode](https://opencode.ai) configuration stack — distributed as an npm package.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repository
|
|
9
|
+
git clone https://github.com/kliverz1337/opencode-antigravity-config.git
|
|
10
|
+
cd opencode-antigravity-config
|
|
11
|
+
|
|
12
|
+
# Install dependencies and link globally
|
|
13
|
+
npm install
|
|
14
|
+
npm link
|
|
15
|
+
|
|
16
|
+
# Launch the installer GUI
|
|
17
|
+
opencode-agc
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## What It Installs
|
|
21
|
+
|
|
22
|
+
The installer deploys **6 configuration files** to `~/.config/opencode/`:
|
|
23
|
+
|
|
24
|
+
| File | Description |
|
|
25
|
+
|------|-------------|
|
|
26
|
+
| `opencode.json` | Core config — models, providers, plugins |
|
|
27
|
+
| `oh-my-opencode.jsonc` | oMo agent overrides & categories |
|
|
28
|
+
| `dcp.jsonc` | Dynamic Context Pruning settings |
|
|
29
|
+
| `supermemory.jsonc` | Supermemory plugin config |
|
|
30
|
+
| `opencode-sync.jsonc` | OpenSync plugin config |
|
|
31
|
+
| `package.json` | Plugin dependencies |
|
|
32
|
+
|
|
33
|
+
## Available Models
|
|
34
|
+
|
|
35
|
+
| Model | Context | Thinking |
|
|
36
|
+
|-------|---------|----------|
|
|
37
|
+
| Gemini 3.1 Pro | 1M tokens | standard / low / high |
|
|
38
|
+
| Gemini 3 Flash | 1M tokens | standard / minimal / low / medium / high |
|
|
39
|
+
| Claude 4.6 Sonnet | 200K tokens | standard |
|
|
40
|
+
| Claude 4.6 Sonnet Thinking | 200K tokens | low (8K) / max (32K) |
|
|
41
|
+
| Claude 4.6 Opus Thinking | 200K tokens | low (8K) / max (32K) |
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Global Templates (Presets)
|
|
45
|
+
|
|
46
|
+
The installer provides one-click AI stack preset configurations under the **"✨ Load Template"** dropdown.
|
|
47
|
+
|
|
48
|
+
| Preset Name | Heavy Group | Standard Group | Light Group | Use Case |
|
|
49
|
+
|-------------|-------------|----------------|-------------|----------|
|
|
50
|
+
| **Antigravity Default** | Gemini 3.1 Pro | Gemini 3.1 Pro | Gemini 3 Flash | Best balanced setup for general projects |
|
|
51
|
+
| **Max Reasoning (O1 Class)** | Claude Opus 4.6 Thinking | Gemini 3 Deep Think | Claude Sonnet 4.6 | Highly complex logic, deep architecture fixes |
|
|
52
|
+
| **Fast & Cheap** | Gemini 3 Flash | Gemini 3 Flash | Gemini 3 Flash | Rapid prototyping, straightforward refactoring |
|
|
53
|
+
| **Claude Ecosystem** | Claude Opus 4.6 Thinking | Claude Sonnet 4.6 | Claude Sonnet 4.6 | Pure Anthropic behavior everywhere |
|
|
54
|
+
|
|
55
|
+
## GUI Features
|
|
56
|
+
|
|
57
|
+
- **6-Step Setup Wizard** — intuitive UI guided setup process.
|
|
58
|
+
- **oMo AI Model config** — native config tab to assign distinct AI models per oMo agent group.
|
|
59
|
+
- **i18n Multi-language** — flip between English and Indonesian natively.
|
|
60
|
+
- **System Check** — verifies Node.js, npm, OpenCode, bundled configs.
|
|
61
|
+
- **API Key Management** — auto-detects existing keys, live validation.
|
|
62
|
+
- **Selective Install** — choose which config files to install.
|
|
63
|
+
- **Config Preview** — view decoded config content before installing.
|
|
64
|
+
- **Diff View** — compare bundled vs existing config (line-by-line).
|
|
65
|
+
- **Export / Import Settings** — save/load API keys & preferences to JSON.
|
|
66
|
+
- **Version Check** — check for installer updates (configurable endpoint)
|
|
67
|
+
- **Uninstall / Reset** — safely remove configs with automatic backup
|
|
68
|
+
- **Backup** — auto-backup existing configs before overwrite
|
|
69
|
+
- **Streaming npm install** — real-time output during dependency installation
|
|
70
|
+
|
|
71
|
+
## After Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 1. Authenticate with Antigravity
|
|
75
|
+
opencode auth login
|
|
76
|
+
|
|
77
|
+
# 2. Start OpenCode
|
|
78
|
+
opencode
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## API Keys (Optional)
|
|
82
|
+
|
|
83
|
+
The installer can inject API keys into config files during installation:
|
|
84
|
+
|
|
85
|
+
| Service | Config File | Get Key From |
|
|
86
|
+
|---------|------------|--------------|
|
|
87
|
+
| Supermemory | `supermemory.jsonc` | [console.supermemory.ai/keys](https://console.supermemory.ai/keys) |
|
|
88
|
+
| OpenSync | `opencode-sync.jsonc` | [opensync.dev](https://opensync.dev) → Settings |
|
|
89
|
+
|
|
90
|
+
Keys can also be added manually to the config files after installation.
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Clone and install
|
|
96
|
+
git clone <repo-url>
|
|
97
|
+
cd opencode-config
|
|
98
|
+
npm install
|
|
99
|
+
|
|
100
|
+
# Run locally
|
|
101
|
+
npm start
|
|
102
|
+
|
|
103
|
+
# Register global command for testing
|
|
104
|
+
npm link
|
|
105
|
+
opencode-agc
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
ISC
|
package/app.png
ADDED
|
Binary file
|
package/cli.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// CLI launcher — spawns Electron with the GUI
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const electronPath = require('electron');
|
|
8
|
+
const appPath = path.join(__dirname);
|
|
9
|
+
|
|
10
|
+
const child = spawn(electronPath, [appPath], {
|
|
11
|
+
stdio: 'inherit',
|
|
12
|
+
windowsHide: false
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
child.on('close', (code) => {
|
|
16
|
+
process.exit(code);
|
|
17
|
+
});
|
package/config-data.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function getBase64Config(filename) {
|
|
5
|
+
const filePath = path.join(__dirname, 'templates', filename);
|
|
6
|
+
try {
|
|
7
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
8
|
+
return Buffer.from(content).toString('base64');
|
|
9
|
+
} catch (e) {
|
|
10
|
+
console.error(`Failed to read template ${filename}:`, e.message);
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Export Base64 encoded configs, read dynamically from the templates/ folder
|
|
16
|
+
module.exports = {
|
|
17
|
+
dcp_jsonc: getBase64Config('dcp.jsonc'),
|
|
18
|
+
oh_my_opencode_jsonc: getBase64Config('oh-my-opencode.jsonc'),
|
|
19
|
+
opencode_sync_jsonc: getBase64Config('opencode-sync.jsonc'),
|
|
20
|
+
opencode_json: getBase64Config('opencode.json'),
|
|
21
|
+
package_json: getBase64Config('package.json'),
|
|
22
|
+
supermemory_jsonc: getBase64Config('supermemory.jsonc')
|
|
23
|
+
};
|
package/i18n.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const translations = {
|
|
2
|
+
// Top Bar & Steps
|
|
3
|
+
'Welcome': { EN: 'Welcome', ID: 'Menu Utama' },
|
|
4
|
+
'oMo Model': { EN: 'oMo Model', ID: 'oMo Model' },
|
|
5
|
+
'System': { EN: 'System', ID: 'Sistem' },
|
|
6
|
+
'Config': { EN: 'Config', ID: 'Konfigurasi' },
|
|
7
|
+
'Install': { EN: 'Install', ID: 'Instal' },
|
|
8
|
+
'Done': { EN: 'Done', ID: 'Selesai' },
|
|
9
|
+
|
|
10
|
+
// Page 0: Welcome
|
|
11
|
+
'Install konfigurasi lengkap Opencode Antigravity stack:': { EN: 'Install full Opencode Antigravity stack config:', ID: 'Install konfigurasi lengkap Opencode Antigravity stack:' },
|
|
12
|
+
'Get Started →': { EN: 'Get Started →', ID: 'Mulai →' },
|
|
13
|
+
'🔄 Updates': { EN: '🔄 Updates', ID: '🔄 Cek Update' },
|
|
14
|
+
'🗑 Uninstall': { EN: '🗑 Uninstall', ID: '🗑 Copot' },
|
|
15
|
+
|
|
16
|
+
// Page 1: oMo Agent Model
|
|
17
|
+
'oMo Agent Model': { EN: 'oMo Agent Model', ID: 'Model AI oMo Agent' },
|
|
18
|
+
'Konfigurasi model AI untuk setiap agent': { EN: 'Configure AI model for each agent', ID: 'Konfigurasi model AI untuk setiap agent' },
|
|
19
|
+
|
|
20
|
+
// Page 2: System Check
|
|
21
|
+
'System Check': { EN: 'System Check', ID: 'Cek Sistem' },
|
|
22
|
+
'Checking environment...': { EN: 'Checking environment...', ID: 'Memeriksa system...' },
|
|
23
|
+
'🔄 Re-check': { EN: '🔄 Re-check', ID: '🔄 Cek Ulang' },
|
|
24
|
+
'← Back': { EN: '← Back', ID: '← Kembali' },
|
|
25
|
+
'Continue →': { EN: 'Continue →', ID: 'Lanjutkan →' },
|
|
26
|
+
|
|
27
|
+
// Page 3: Config
|
|
28
|
+
'Configuration': { EN: 'Configuration', ID: 'Konfigurasi' },
|
|
29
|
+
'API Keys & file selection': { EN: 'API Keys & file selection', ID: 'API Key & pemilihan file' },
|
|
30
|
+
'📥 Import': { EN: '📥 Import', ID: '📥 Ambil' },
|
|
31
|
+
'📤 Export': { EN: '📤 Export', ID: '📤 Simpan' },
|
|
32
|
+
'(Optional)': { EN: '(Optional)', ID: '(Opsional)' },
|
|
33
|
+
'API Key (console.supermemory.ai/keys)': { EN: 'API Key (console.supermemory.ai/keys)', ID: 'API Key (console.supermemory.ai/keys)' },
|
|
34
|
+
'API Key (opensync.dev → Settings)': { EN: 'API Key (opensync.dev → Settings)', ID: 'API Key (opensync.dev → Pengaturan)' },
|
|
35
|
+
'Convex URL': { EN: 'Convex URL', ID: 'URL Convex' },
|
|
36
|
+
'FILES TO INSTALL': { EN: 'FILES TO INSTALL', ID: 'FILE UNTUK DIINSTAL' },
|
|
37
|
+
'All': { EN: 'All', ID: 'Semua' },
|
|
38
|
+
'None': { EN: 'None', ID: 'Kosong' },
|
|
39
|
+
'OPTIONS': { EN: 'OPTIONS', ID: 'PILIHAN' },
|
|
40
|
+
'PLUGINS': { EN: 'PLUGINS', ID: 'PLUGIN' },
|
|
41
|
+
'Backup konfigurasi lama': { EN: 'Backup old configuration', ID: 'Backup konfigurasi lama' },
|
|
42
|
+
'Jalankan npm install': { EN: 'Run npm install', ID: 'Jalankan npm install' },
|
|
43
|
+
'Install Now →': { EN: 'Install Now →', ID: 'Mulai Instal →' },
|
|
44
|
+
|
|
45
|
+
// Page 4: Installing
|
|
46
|
+
'Installing...': { EN: 'Installing...', ID: 'Menginstal...' },
|
|
47
|
+
'Menyalin konfigurasi...': { EN: 'Copying configurations...', ID: 'Menyalin konfigurasi...' },
|
|
48
|
+
'Log': { EN: 'Log', ID: 'Log' },
|
|
49
|
+
'Finish ✓': { EN: 'Finish ✓', ID: 'Selesai ✓' },
|
|
50
|
+
|
|
51
|
+
// Page 5: Done
|
|
52
|
+
'Installation Complete!': { EN: 'Installation Complete!', ID: 'Instalasi Selesai!' },
|
|
53
|
+
'Antigravity OpenCode siap digunakan': { EN: 'Antigravity OpenCode is ready to use', ID: 'Antigravity OpenCode siap digunakan' },
|
|
54
|
+
'📁 Config Location': { EN: '📁 Config Location', ID: '📁 Lokasi Config' },
|
|
55
|
+
'🚀 Next Steps': { EN: '🚀 Next Steps', ID: '🚀 Langkah Berikut' },
|
|
56
|
+
'📂 Config': { EN: '📂 Config', ID: '📂 Buka Config' },
|
|
57
|
+
'🔑 Auth': { EN: '🔑 Auth', ID: '🔑 Login' },
|
|
58
|
+
'Close': { EN: 'Close', ID: 'Tutup' },
|
|
59
|
+
|
|
60
|
+
// Modals & Dynamic
|
|
61
|
+
'✓ Set': { EN: '✓ Set', ID: '✓ Diisi' },
|
|
62
|
+
'✗ Invalid': { EN: '✗ Invalid', ID: '✗ Tidak Valid' },
|
|
63
|
+
'Checking...': { EN: 'Checking...', ID: 'Memeriksa...' },
|
|
64
|
+
'Not found — npm i -g opencode@latest': { EN: 'Not found — run npm i -g opencode@latest', ID: 'Tidak ada — jalankan npm i -g opencode@latest' },
|
|
65
|
+
'🔒 Core (Required)': { EN: '🔒 Core (Required)', ID: '🔒 Wajib (Core)' },
|
|
66
|
+
'⚙️ Optional': { EN: '⚙️ Optional', ID: '⚙️ Opsional' },
|
|
67
|
+
'⚠ No key': { EN: '⚠ No key', ID: '⚠ Tanpa key' },
|
|
68
|
+
'👁 Preview opencode.json': { EN: '👁 Preview opencode.json', ID: '👁 Pratinjau opencode.json' },
|
|
69
|
+
|
|
70
|
+
// Close Modal
|
|
71
|
+
'Close confirm title': { EN: 'Close Application', ID: 'Tutup Aplikasi' },
|
|
72
|
+
'Close confirm text': { EN: 'Are you sure you want to exit the setup?', ID: 'Apakah Anda yakin ingin keluar dari program?' },
|
|
73
|
+
'Close cancel': { EN: 'No', ID: 'Tidak' },
|
|
74
|
+
'Close exit': { EN: 'Yes, Exit', ID: 'Ya, Keluar' }
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
let currentLang = 'ID'; // Default
|
|
78
|
+
|
|
79
|
+
function t(key) {
|
|
80
|
+
if (!translations[key]) return key;
|
|
81
|
+
return translations[key][currentLang] || key;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Elements mapping explicitly for DOM nodes
|
|
85
|
+
// Page layout: 0=Welcome, 1=oMo Model, 2=System, 3=Config, 4=Install, 5=Done
|
|
86
|
+
const tMap = [
|
|
87
|
+
// Step indicators (6 steps)
|
|
88
|
+
{ selector: '#step0 span', key: 'Welcome' },
|
|
89
|
+
{ selector: '#step1 span', key: 'oMo Model' },
|
|
90
|
+
{ selector: '#step2 span', key: 'System' },
|
|
91
|
+
{ selector: '#step3 span', key: 'Config' },
|
|
92
|
+
{ selector: '#step4 span', key: 'Install' },
|
|
93
|
+
{ selector: '#step5 span', key: 'Done' },
|
|
94
|
+
|
|
95
|
+
// Page 0: Welcome
|
|
96
|
+
{ selector: '#page0 .subtitle', key: 'Install konfigurasi lengkap Opencode Antigravity stack:' },
|
|
97
|
+
{ selector: '#btnStart', key: 'Get Started →', isNode: true },
|
|
98
|
+
{ selector: '#btnVersionCheck', key: '🔄 Updates' },
|
|
99
|
+
{ selector: '#btnUninstall', key: '🗑 Uninstall' },
|
|
100
|
+
|
|
101
|
+
// Page 1: oMo Agent Model
|
|
102
|
+
{ selector: '#page1 .page-header h2', key: 'oMo Agent Model' },
|
|
103
|
+
{ selector: '#page1 .page-header p', key: 'Konfigurasi model AI untuk setiap agent' },
|
|
104
|
+
{ selector: '#btnPrev1', key: '← Back' },
|
|
105
|
+
{ selector: '#btnNext1', key: 'Continue →' },
|
|
106
|
+
|
|
107
|
+
// Page 2: System Check
|
|
108
|
+
{ selector: '#page2 .page-header h2', key: 'System Check' },
|
|
109
|
+
{ selector: '#page2 .page-header p', key: 'Checking environment...' },
|
|
110
|
+
{ selector: '#btnRecheck', key: '🔄 Re-check' },
|
|
111
|
+
{ selector: '#btnPrev2', key: '← Back' },
|
|
112
|
+
{ selector: '#btnNext2', key: 'Continue →' },
|
|
113
|
+
|
|
114
|
+
// Page 3: Config
|
|
115
|
+
{ selector: '#page3 .page-header h2', key: 'Configuration' },
|
|
116
|
+
{ selector: '#page3 .page-header p', key: 'API Keys & file selection' },
|
|
117
|
+
{ selector: '#btnImport', key: '📥 Import' },
|
|
118
|
+
{ selector: '#btnExport', key: '📤 Export' },
|
|
119
|
+
{ selector: '#page3 .form-group:nth-of-type(2) .help-text', key: 'API Key (console.supermemory.ai/keys)' },
|
|
120
|
+
{ selector: '#page3 .form-group:nth-of-type(3) .help-text:nth-of-type(1)', key: 'API Key (opensync.dev → Settings)' },
|
|
121
|
+
{ selector: '#page3 .form-group:nth-of-type(3) .label-row:nth-of-type(2) .help-text', key: 'Convex URL' },
|
|
122
|
+
{ selector: '#page3 .grey-label:nth-of-type(1)', key: 'FILES TO INSTALL' },
|
|
123
|
+
{ selector: '#btnSelectAll', key: 'All' },
|
|
124
|
+
{ selector: '#btnDeselectAll', key: 'None' },
|
|
125
|
+
|
|
126
|
+
{ selector: '#page3 .grey-label:nth-of-type(2)', key: 'OPTIONS' },
|
|
127
|
+
{ selector: '#chkBackup + .checkmark', nextSibText: 'Backup konfigurasi lama' },
|
|
128
|
+
{ selector: '#chkNpmInstall + .checkmark', nextSibText: 'Jalankan npm install' },
|
|
129
|
+
|
|
130
|
+
{ selector: '#lblCorePlugins', key: '🔒 Core (Required)' },
|
|
131
|
+
{ selector: '#lblOptionalPlugins', key: '⚙️ Optional' },
|
|
132
|
+
{ selector: '#warnSupermemory', key: '⚠ No key' },
|
|
133
|
+
{ selector: '#warnOpenSync', key: '⚠ No key' },
|
|
134
|
+
{ selector: '#btnPreviewConfig', key: '👁 Preview opencode.json' },
|
|
135
|
+
|
|
136
|
+
{ selector: '#btnPrev3', key: '← Back' },
|
|
137
|
+
{ selector: '#btnNext3', key: 'Install Now →' },
|
|
138
|
+
|
|
139
|
+
// Page 4: Installing
|
|
140
|
+
{ selector: '#installTitle', key: 'Installing...' },
|
|
141
|
+
{ selector: '#installSubtitle', key: 'Menyalin konfigurasi...' },
|
|
142
|
+
{ selector: '.log-title', key: 'Log' },
|
|
143
|
+
{ selector: '#btnNext4', key: 'Finish ✓' },
|
|
144
|
+
|
|
145
|
+
// Page 5: Done
|
|
146
|
+
{ selector: '#page5 h2', key: 'Installation Complete!' },
|
|
147
|
+
{ selector: '#page5 .success-text', key: 'Antigravity OpenCode siap digunakan' },
|
|
148
|
+
{ selector: '#page5 .cyan-label', key: '📁 Config Location' },
|
|
149
|
+
{ selector: '#page5 .purple-label', key: '🚀 Next Steps' },
|
|
150
|
+
{ selector: '#btnOpenFolder', key: '📂 Config' },
|
|
151
|
+
{ selector: '#btnAuthLogin', key: '🔑 Auth' },
|
|
152
|
+
{ selector: '#btnFinish', key: 'Close' }
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
function updateLanguage(lang) {
|
|
156
|
+
currentLang = lang;
|
|
157
|
+
window.currentLang = lang;
|
|
158
|
+
document.getElementById('btnLang').textContent = lang === 'EN' ? 'EN / id' : 'ID / en';
|
|
159
|
+
|
|
160
|
+
tMap.forEach(item => {
|
|
161
|
+
const el = document.querySelector(item.selector);
|
|
162
|
+
if (el) {
|
|
163
|
+
if (item.nextSibText) {
|
|
164
|
+
// For label checkboxes, the text is the next sibling after checkmark
|
|
165
|
+
const textNode = Array.from(el.parentNode.childNodes).find(n => n.nodeType === 3 && n.textContent.trim().length > 0);
|
|
166
|
+
if (textNode) textNode.textContent = t(item.nextSibText);
|
|
167
|
+
} else {
|
|
168
|
+
el.innerText = t(item.key);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Update dynamic placeholders/indicators
|
|
174
|
+
const vsm = document.getElementById('valSupermemory');
|
|
175
|
+
if (vsm && vsm.classList.contains('val-empty')) vsm.textContent = t('(Optional)');
|
|
176
|
+
if (vsm && vsm.classList.contains('val-ok')) vsm.textContent = t('✓ Set');
|
|
177
|
+
if (vsm && vsm.classList.contains('val-bad')) vsm.textContent = t('✗ Invalid');
|
|
178
|
+
|
|
179
|
+
const vos = document.getElementById('valOpenSyncKey');
|
|
180
|
+
if (vos && vos.classList.contains('val-empty')) vos.textContent = t('(Optional)');
|
|
181
|
+
if (vos && vos.classList.contains('val-ok')) vos.textContent = t('✓ Set');
|
|
182
|
+
if (vos && vos.classList.contains('val-bad')) vos.textContent = t('✗ Invalid');
|
|
183
|
+
|
|
184
|
+
const vou = document.getElementById('valOpenSyncUrl');
|
|
185
|
+
if (vou && vou.classList.contains('val-empty')) vou.textContent = t('(Optional)');
|
|
186
|
+
if (vou && vou.classList.contains('val-ok')) vou.textContent = t('✓ Set');
|
|
187
|
+
if (vou && vou.classList.contains('val-bad')) vou.textContent = t('✗ Invalid');
|
|
188
|
+
|
|
189
|
+
// Trigger re-render of currently visible modal if needed
|
|
190
|
+
window._lastLangUpdate = Date.now();
|
|
191
|
+
|
|
192
|
+
// Also re-run validation logic text updates
|
|
193
|
+
if (typeof window.reValInputs === 'function') window.reValInputs();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
window.t = t;
|
|
197
|
+
window.updateLanguage = updateLanguage;
|
|
198
|
+
window.currentLang = currentLang;
|